Parcourir la source

merge with latest master, resolved conflict

Max Limper il y a 7 ans
Parent
commit
9386d19751
100 fichiers modifiés avec 298978 ajouts et 164096 suppressions
  1. 8 1
      .gitignore
  2. 34 8
      .travis.yml
  3. 15 1
      .vscode/launch.json
  4. 9 1
      .vscode/settings.json
  5. 13 6
      .vscode/tasks.json
  6. BIN
      Playground/LogoPBT.png
  7. 13136 6001
      Playground/babylon.d.txt
  8. 167 72
      Playground/debug.html
  9. 23 21
      Playground/frame.html
  10. 2 0
      Playground/index.html
  11. 4 0
      Playground/scenes/BoomBox/BoomBox.gltf
  12. 1 1
      Playground/scripts/instanced bones.js
  13. BIN
      Playground/textures/normal.png
  14. 9 1
      Tools/DevLoader/BabylonLoader.js
  15. 206 191
      Tools/Gulp/config.json
  16. 15 2
      Tools/Gulp/gulp-addDtsExport.js
  17. 79 0
      Tools/Gulp/gulp-addES6Exports.js
  18. 36 6
      Tools/Gulp/gulp-appendSrcToVariable.js
  19. 133 0
      Tools/Gulp/gulp-babylonModule.js
  20. 80 0
      Tools/Gulp/gulp-calculateDependencies.js
  21. 96 0
      Tools/Gulp/gulp-dtsModuleSupport.js
  22. 214 0
      Tools/Gulp/gulp-es6ModuleExports.js
  23. 725 0
      Tools/Gulp/gulp-validateTypedoc.js
  24. 525 41
      Tools/Gulp/gulpfile.js
  25. 21 6
      Tools/Gulp/package.json
  26. 134 10
      Tools/Publisher/index.js
  27. 4 0
      Tools/Publisher/package.json
  28. 4 3
      Viewer/dist/basicExample.html
  29. 5 0
      Viewer/dist/config.json
  30. 48 0
      Viewer/dist/loadModelManually.html
  31. 0 1
      Viewer/dist/viewer.min.js
  32. 6 13
      Viewer/package.json
  33. 190 116
      Viewer/src/configuration/configuration.ts
  34. 40 23
      Viewer/src/configuration/loader.ts
  35. 1 2
      Viewer/src/configuration/mappers.ts
  36. 17 15
      Viewer/src/configuration/types/default.ts
  37. 2 1
      Viewer/src/configuration/types/index.ts
  38. 40 0
      Viewer/src/eventManager.ts
  39. 3 1
      Viewer/src/index.ts
  40. 128 39
      Viewer/src/templateManager.ts
  41. 0 39
      Viewer/src/util/promiseObservable.ts
  42. 119 238
      Viewer/src/viewer/defaultViewer.ts
  43. 761 54
      Viewer/src/viewer/viewer.ts
  44. 1 1
      Viewer/src/viewer/viewerManager.ts
  45. 21 9
      Viewer/tsconfig.json
  46. 13 9
      Viewer/webpack.config.js
  47. 1 1
      Viewer/webpack.gulp.config.js
  48. 2 0
      assets/meshes/controllers/_redirects
  49. 5032 5032
      dist/babylon.d.ts
  50. 248 0
      dist/babylon.glTF2Interface.d.ts
  51. 16 16
      dist/babylon.js
  52. 51 47
      dist/babylon.max.js
  53. 16 16
      dist/babylon.worker.js
  54. 1 1
      dist/gui/package.json
  55. 1 1
      dist/inspector/package.json
  56. 1 1
      dist/loaders/package.json
  57. 1 1
      dist/materialsLibrary/package.json
  58. 1 1
      dist/postProcessesLibrary/package.json
  59. 14111 7106
      dist/preview release/babylon.d.ts
  60. 56 54
      dist/preview release/babylon.js
  61. 39591 30636
      dist/preview release/babylon.max.js
  62. 19088 0
      dist/preview release/babylon.module.d.ts
  63. 57 55
      dist/preview release/babylon.worker.js
  64. 18733 11630
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  65. 58 56
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  66. 40798 32076
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  67. 48882 64807
      Viewer/dist/viewer.js
  68. 89225 0
      dist/preview release/es6.js
  69. 104 2
      dist/preview release/gui/babylon.gui.d.ts
  70. 229 23
      dist/preview release/gui/babylon.gui.js
  71. 3 3
      dist/preview release/gui/babylon.gui.min.js
  72. 105 2
      dist/preview release/gui/babylon.gui.module.d.ts
  73. 2 2
      dist/preview release/gui/package.json
  74. 4 4
      dist/preview release/inspector/babylon.inspector.bundle.js
  75. 5 2
      dist/preview release/inspector/babylon.inspector.css
  76. 4 2
      dist/preview release/inspector/babylon.inspector.d.ts
  77. 24 3
      dist/preview release/inspector/babylon.inspector.js
  78. 4 4
      dist/preview release/inspector/babylon.inspector.min.js
  79. 2 2
      dist/preview release/inspector/package.json
  80. 93 22
      dist/preview release/loaders/babylon.glTF1FileLoader.d.ts
  81. 242 65
      dist/preview release/loaders/babylon.glTF1FileLoader.js
  82. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  83. 278 373
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  84. 1369 1429
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  85. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  86. 280 367
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  87. 1428 1468
      dist/preview release/loaders/babylon.glTFFileLoader.js
  88. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  89. 1 0
      dist/preview release/loaders/babylon.objFileLoader.d.ts
  90. 6 0
      dist/preview release/loaders/babylon.objFileLoader.js
  91. 1 1
      dist/preview release/loaders/babylon.objFileLoader.min.js
  92. 1 0
      dist/preview release/loaders/babylon.stlFileLoader.d.ts
  93. 6 0
      dist/preview release/loaders/babylon.stlFileLoader.js
  94. 1 1
      dist/preview release/loaders/babylon.stlFileLoader.min.js
  95. 1431 1468
      dist/preview release/loaders/babylonjs.loaders.js
  96. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  97. 283 367
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  98. 3 5
      dist/preview release/loaders/package.json
  99. 1 1
      dist/preview release/materialsLibrary/babylon.cellMaterial.js
  100. 0 0
      dist/preview release/materialsLibrary/babylon.cellMaterial.min.js

+ 8 - 1
.gitignore

@@ -24,9 +24,11 @@ postProcessLibrary/src/**/*.js
 inspector/src/**/*.js
 serializers/src/**/*.js
 gui/src/**/*.js
+viewer/src/**/*.js
+tests/unit/**/*.js
+!tests/unit/karma.conf.js
 
 # Build results
-[Dd]ebug/
 [Rr]elease/
 x64/
 *_i.c
@@ -167,3 +169,8 @@ localDev/src/*
 /dist/preview release/babylon.custom.max.js
 /localDev/src/index.js
 package-lock.json
+dist/preview release/package/
+
+# viewer dist files
+/Viewer/dist/viewer.js
+/Viewer/dist/viewer.min.js

+ 34 - 8
.travis.yml

@@ -1,8 +1,34 @@
-language: node_js
-node_js:
-  - "6"
-before_script:
-  - npm install -g gulp
-  - cd ./Tools/Gulp
-  - npm install
-script: gulp typescript
+sudo: required
+dist: trusty
+language: node_js
+node_js:
+- '6'
+cache:
+  directories:
+    - Tools/Gulp/node_modules
+    - Playground/node_modules
+    - tests/unit/node_modules
+git:
+  depth: 3
+before_script:
+- travis_retry npm install -g gulp
+- cd ./Tools/Gulp
+- travis_retry npm install
+- "export DISPLAY=:99.0"
+- "sh -e /etc/init.d/xvfb start"
+- sleep 3 # give xvfb some time to start
+script: 
+- gulp tests-whatsnew
+- set -e
+- gulp typescript-all
+- gulp typedoc-all
+- gulp tests-unit
+- travis_retry gulp tests-validation-virtualscreen
+- travis_retry gulp tests-validation-browserstack
+notifications:
+  slack:
+    secure: TBYDAN8Dlkx3dM+Q5ClAZem7agAhQ1oB/fGT665qn7D+j2YfWChvlfXegvXL4LPDmQgbI0UfazcjWId5a0EwmmPkRb+kMJItPiMt5jiIp2WKoZQ+qob6H9tBCRJbbpWM430wiPeKfBfbcZP/XSlpVMWhgU5ogAFDSUKjvHT7IuE=
+env:
+  global:
+  - secure: XVMhWPm3ByrZduLmbyBMsKU462bEbYPNRp+42HcdOuC3YOl2ODPvANrE/qZneZzGqlyiFAg6X4mDGD71Qw9ekbFt5q0PmvIxkRrX0KNJEJl9/gnFadOz3xFWEfFw4tiSHp36PUu9aT6ti9mn9gnM8C+vQZhqVpaMgkLpWzeEeXQ=
+  - secure: jaGc/NJwACWJPLfI/L1UfYvWKX6AGVjFwXA+31elOVNAmG4XRwaTUaugqP4FhjTw0g2pqTB1BlSML+Fs3dVaUGy3bpslQLL74iG06XZbFUqrtVV2/sOcJaoWxIc69ld0tcqLdPvMSrCIzGQYAWaNNllyMnBjsWBZ+0J0ghtbBDA=

+ 15 - 1
.vscode/launch.json

@@ -1,5 +1,5 @@
 {
-    "version": "0.1.0",
+    "version": "2.0.0",
     "configurations": [
         {
             "name": "Launch Viewer (Chrome)",
@@ -125,6 +125,20 @@
             ]
         },
         {
+            "name": "Launch Local Dev (Experimental Firefox)",
+            "type": "firefox",
+            "request": "launch",
+            "reAttach": true,
+            "url": "http://localhost:1338/localDev/index.html",
+            "pathMappings": [
+                {
+                    "url": "http://localhost:1338",
+                    "path": "${workspaceFolder}"
+                }
+            ],
+            "preLaunchTask": "run"
+        },
+        {
             "name": "Launch Build Validation (Chrome)",
             "type": "chrome",
             "request": "launch",

+ 9 - 1
.vscode/settings.json

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

+ 13 - 6
.vscode/tasks.json

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

BIN
Playground/LogoPBT.png


Fichier diff supprimé car celui-ci est trop grand
+ 13136 - 6001
Playground/babylon.d.txt


+ 167 - 72
Playground/debug.html

@@ -6,24 +6,24 @@
     <meta charset='utf-8' />
     <meta name="viewport" content="width=device-width, user-scalable=no">
     <link rel="shortcut icon" href="https://www.babylonjs.com/img/favicon/favicon.ico">
-	<link rel="apple-touch-icon" sizes="57x57" href="https://www.babylonjs.com/img/favicon/apple-icon-57x57.png">
-	<link rel="apple-touch-icon" sizes="60x60" href="https://www.babylonjs.com/img/favicon/apple-icon-60x60.png">
-	<link rel="apple-touch-icon" sizes="72x72" href="https://www.babylonjs.com/img/favicon/apple-icon-72x72.png">
-	<link rel="apple-touch-icon" sizes="76x76" href="https://www.babylonjs.com/img/favicon/apple-icon-76x76.png">
-	<link rel="apple-touch-icon" sizes="114x114" href="https://www.babylonjs.com/img/favicon/apple-icon-114x114.png">
-	<link rel="apple-touch-icon" sizes="120x120" href="https://www.babylonjs.com/img/favicon/apple-icon-120x120.png">
-	<link rel="apple-touch-icon" sizes="144x144" href="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png">
-	<link rel="apple-touch-icon" sizes="152x152" href="https://www.babylonjs.com/img/favicon/apple-icon-152x152.png">
-	<link rel="apple-touch-icon" sizes="180x180" href="https://www.babylonjs.com/img/favicon/apple-icon-180x180.png">
-	<link rel="icon" type="image/png" sizes="192x192"  href="https://www.babylonjs.com/img/favicon/android-icon-192x192.png">
-	<link rel="icon" type="image/png" sizes="32x32" href="https://www.babylonjs.com/img/favicon/favicon-32x32.png">
-	<link rel="icon" type="image/png" sizes="96x96" href="https://www.babylonjs.com/img/favicon/favicon-96x96.png">
-	<link rel="icon" type="image/png" sizes="16x16" href="https://www.babylonjs.com/img/favicon/favicon-16x16.png">
-	<link rel="manifest" href="https://www.babylonjs.com/img/favicon/manifest.json">
-	<meta name="msapplication-TileColor" content="#ffffff">
-	<meta name="msapplication-TileImage" content="https://www.babylonjs.com/img/favicon/ms-icon-144x144.png">
-	<meta name="msapplication-config" content="https://www.babylonjs.com/img/favicon/browserconfig.xml">
-	<meta name="theme-color" content="#ffffff">
+    <link rel="apple-touch-icon" sizes="57x57" href="https://www.babylonjs.com/img/favicon/apple-icon-57x57.png">
+    <link rel="apple-touch-icon" sizes="60x60" href="https://www.babylonjs.com/img/favicon/apple-icon-60x60.png">
+    <link rel="apple-touch-icon" sizes="72x72" href="https://www.babylonjs.com/img/favicon/apple-icon-72x72.png">
+    <link rel="apple-touch-icon" sizes="76x76" href="https://www.babylonjs.com/img/favicon/apple-icon-76x76.png">
+    <link rel="apple-touch-icon" sizes="114x114" href="https://www.babylonjs.com/img/favicon/apple-icon-114x114.png">
+    <link rel="apple-touch-icon" sizes="120x120" href="https://www.babylonjs.com/img/favicon/apple-icon-120x120.png">
+    <link rel="apple-touch-icon" sizes="144x144" href="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png">
+    <link rel="apple-touch-icon" sizes="152x152" href="https://www.babylonjs.com/img/favicon/apple-icon-152x152.png">
+    <link rel="apple-touch-icon" sizes="180x180" href="https://www.babylonjs.com/img/favicon/apple-icon-180x180.png">
+    <link rel="icon" type="image/png" sizes="192x192" href="https://www.babylonjs.com/img/favicon/android-icon-192x192.png">
+    <link rel="icon" type="image/png" sizes="32x32" href="https://www.babylonjs.com/img/favicon/favicon-32x32.png">
+    <link rel="icon" type="image/png" sizes="96x96" href="https://www.babylonjs.com/img/favicon/favicon-96x96.png">
+    <link rel="icon" type="image/png" sizes="16x16" href="https://www.babylonjs.com/img/favicon/favicon-16x16.png">
+    <link rel="manifest" href="https://www.babylonjs.com/img/favicon/manifest.json">
+    <meta name="msapplication-TileColor" content="#ffffff">
+    <meta name="msapplication-TileImage" content="https://www.babylonjs.com/img/favicon/ms-icon-144x144.png">
+    <meta name="msapplication-config" content="https://www.babylonjs.com/img/favicon/browserconfig.xml">
+    <meta name="theme-color" content="#ffffff">
 
     <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
     <!--For canvas/code separator-->
@@ -38,7 +38,7 @@
     <!-- Babylon.js -->
     <script src="https://preview.babylonjs.com/cannon.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/materialsLibrary/babylon.fireMaterial.min.js"></script>
@@ -73,6 +73,8 @@
 
     <script src="https://preview.babylonjs.com/gui/babylon.gui.js"></script>
 
+    <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
+
     <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>
     <script src="https://rawgit.com/BabylonJS/Extensions/master/canvas2D/dist/preview%20release/babylon.canvas2d.js"></script>
     <script src="https://rawgit.com/BabylonJS/Extensions/master/CompoundShader/src/babylonx.CompoundShader.js"></script>
@@ -90,30 +92,43 @@
         </div>
 
         <div class="category">
-            <div class="button run" id="runButton1600">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+            <div class="button run" id="runButton1600">Run
+                <i class="fa fa-play" aria-hidden="true"></i>
+            </div>
         </div>
 
 
         <div class="category">
-            <div class="button" id="newButton1600">New<i class="fa fa-file" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="clearButton1600">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+            <div class="button" id="newButton1600">New
+                <i class="fa fa-file" aria-hidden="true"></i>
+            </div>
+            <div class="button removeOnPhone" id="clearButton1600">Clear
+                <i class="fa fa-trash" aria-hidden="true"></i>
+            </div>
         </div>
 
         <div class="category">
-            <div class="button" id="saveButton1600">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="zipButton1600">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+            <div class="button" id="saveButton1600">Save
+                <i class="fa fa-floppy-o" aria-hidden="true"></i>
+            </div>
+            <div class="button removeOnPhone" id="zipButton1600">Zip
+                <i class="fa fa-download" aria-hidden="true"></i>
+            </div>
         </div>
 
         <div class="category">
             <div class="button select">Settings
                 <div class="toDisplay">
-                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                    <div class="option subSelect">Theme
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
                         <div class="toDisplaySub">
                             <div class="option" id="darkTheme1600">Dark</div>
                             <div class="option" id="lightTheme1600">Light</div>
                         </div>
                     </div>
-                    <div class="option subSelect"><span id="currentFontSize1600">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                    <div class="option subSelect">
+                        <span id="currentFontSize1600">Font: 14</span>
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
                         <div class="toDisplaySub">
                             <div class="option" onclick="setFontSize(12);">12</div>
                             <div class="option" onclick="setFontSize(14);">14</div>
@@ -123,8 +138,11 @@
                             <div class="option" onclick="setFontSize(22);">22</div>
                         </div>
                     </div>
-                    <div class="option" id="safemodeToggle1600">Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
-                    <div class="option checked" id="editorButton1600">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    <div class="option" id="safemodeToggle1600">Safe mode
+                        <i class="fa fa-square-o" aria-hidden="true"></i>
+                    </div>
+                    <div class="option checked" id="editorButton1600">Editor
+                        <i class="fa fa-check-square" aria-hidden="true"></i>
                     </div>
                     <div class="option" id="fullscreenButton1600">Fullscreen</div>
                     <div class="option" id="editorFullscreenButton1600">Editor Fullscreen</div>
@@ -135,20 +153,24 @@
                 </div>
             </div>
 
-            <div class="button uncheck" id="debugButton1600">Debug layer <i class="fa fa-square-o" aria-hidden="true"></i></div>
+            <div class="button uncheck" id="debugButton1600">Debug layer
+                <i class="fa fa-square-o" aria-hidden="true"></i>
+            </div>
             <div class="button" id="metadataButton1600">Metadata</div>
         </div>
 
 
 
         <div class="category right">
-            <div class="button select"><span id="currentVersion1600">Version: Latest</span>
+            <div class="button select">
+                <span id="currentVersion1600">Version: Latest</span>
                 <div class="toDisplay">
                     <div class="option" onclick="setVersion('latest');">Latest</div>
                     <div class="option" onclick="setVersion('2.5');">2.5</div>
                 </div>
             </div>
-            <div class="button select"> <span id="currentScript1600">Scenes</span>
+            <div class="button select">
+                <span id="currentScript1600">Scenes</span>
                 <div class="toDisplayBig">
                     <ul id="scriptsList1600">
                     </ul>
@@ -169,30 +191,43 @@
         </div>
 
         <div class="category">
-            <div class="button run" id="runButton1475">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+            <div class="button run" id="runButton1475">Run
+                <i class="fa fa-play" aria-hidden="true"></i>
+            </div>
         </div>
 
 
         <div class="category">
-            <div class="button" id="newButton1475">New<i class="fa fa-file" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="clearButton1475">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+            <div class="button" id="newButton1475">New
+                <i class="fa fa-file" aria-hidden="true"></i>
+            </div>
+            <div class="button removeOnPhone" id="clearButton1475">Clear
+                <i class="fa fa-trash" aria-hidden="true"></i>
+            </div>
         </div>
 
         <div class="category">
-            <div class="button" id="saveButton1475">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="zipButton1475">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+            <div class="button" id="saveButton1475">Save
+                <i class="fa fa-floppy-o" aria-hidden="true"></i>
+            </div>
+            <div class="button removeOnPhone" id="zipButton1475">Zip
+                <i class="fa fa-download" aria-hidden="true"></i>
+            </div>
         </div>
 
         <div class="category">
             <div class="button select">Settings
                 <div class="toDisplay">
-                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                    <div class="option subSelect">Theme
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
                         <div class="toDisplaySub">
                             <div class="option" id="darkTheme1475">Dark</div>
                             <div class="option" id="lightTheme1475">Light</div>
                         </div>
                     </div>
-                    <div class="option subSelect"><span id="currentFontSize1475">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                    <div class="option subSelect">
+                        <span id="currentFontSize1475">Font: 14</span>
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
                         <div class="toDisplaySub">
                             <div class="option" onclick="setFontSize(12);">12</div>
                             <div class="option" onclick="setFontSize(14);">14</div>
@@ -202,8 +237,11 @@
                             <div class="option" onclick="setFontSize(22);">22</div>
                         </div>
                     </div>
-                    <div class="option" id='safemodeToggle1475'>Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
-                    <div class="option checked" id="editorButton1475">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    <div class="option" id='safemodeToggle1475'>Safe mode
+                        <i class="fa fa-square-o" aria-hidden="true"></i>
+                    </div>
+                    <div class="option checked" id="editorButton1475">Editor
+                        <i class="fa fa-check-square" aria-hidden="true"></i>
                     </div>
                     <div class="option" id="fullscreenButton1475">Fullscreen</div>
                     <div class="option" id="editorFullscreenButton1475">Editor Fullscreen</div>
@@ -211,9 +249,13 @@
                     <div class="option" id="minimapToggle1475">Minimap
                         <i class="fa fa-square-o" aria-hidden="true"></i>
                     </div>
-                    <div class="option" id="debugButton1475">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option" id="debugButton1475">Debug layer
+                        <i class="fa fa-square-o" aria-hidden="true"></i>
+                    </div>
                     <div class="option" id="metadataButton1475">Metadata</div>
-                    <div class="option subSelect"><span id="currentVersion1475">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                    <div class="option subSelect">
+                        <span id="currentVersion1475">Vers. : Latest</span>
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
                         <div class="toDisplaySub">
                             <div class="option" onclick="setVersion('latest');">Latest</div>
                             <div class="option" onclick="setVersion('2.5');">2.5</div>
@@ -224,7 +266,8 @@
         </div>
 
         <div class="category right">
-            <div class="button select"> <span id="currentScript1475">Scenes</span>
+            <div class="button select">
+                <span id="currentScript1475">Scenes</span>
                 <div class="toDisplayBig">
                     <ul id="scriptsList1475">
                     </ul>
@@ -238,30 +281,43 @@
 
     <div class="navbar navBar1030">
         <div class="category">
-            <div class="button run" id="runButton1030">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+            <div class="button run" id="runButton1030">Run
+                <i class="fa fa-play" aria-hidden="true"></i>
+            </div>
         </div>
 
 
         <div class="category">
-            <div class="button" id="newButton1030">New<i class="fa fa-file" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="clearButton1030">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+            <div class="button" id="newButton1030">New
+                <i class="fa fa-file" aria-hidden="true"></i>
+            </div>
+            <div class="button removeOnPhone" id="clearButton1030">Clear
+                <i class="fa fa-trash" aria-hidden="true"></i>
+            </div>
         </div>
 
         <div class="category">
-            <div class="button" id="saveButton1030">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="zipButton1030">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+            <div class="button" id="saveButton1030">Save
+                <i class="fa fa-floppy-o" aria-hidden="true"></i>
+            </div>
+            <div class="button removeOnPhone" id="zipButton1030">Zip
+                <i class="fa fa-download" aria-hidden="true"></i>
+            </div>
         </div>
 
         <div class="category">
             <div class="button select">Settings
                 <div class="toDisplay">
-                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                    <div class="option subSelect">Theme
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
                         <div class="toDisplaySub">
                             <div class="option" id="darkTheme1030">Dark</div>
                             <div class="option" id="lightTheme1030">Light</div>
                         </div>
                     </div>
-                    <div class="option subSelect"><span id="currentFontSize1030">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                    <div class="option subSelect">
+                        <span id="currentFontSize1030">Font: 14</span>
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
                         <div class="toDisplaySub">
                             <div class="option" onclick="setFontSize(12);">12</div>
                             <div class="option" onclick="setFontSize(14);">14</div>
@@ -271,8 +327,11 @@
                             <div class="option" onclick="setFontSize(22);">22</div>
                         </div>
                     </div>
-                    <div class="option" id="safemodeToggle1030">Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
-                    <div class="option checked" id="editorButton1030">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    <div class="option" id="safemodeToggle1030">Safe mode
+                        <i class="fa fa-square-o" aria-hidden="true"></i>
+                    </div>
+                    <div class="option checked" id="editorButton1030">Editor
+                        <i class="fa fa-check-square" aria-hidden="true"></i>
                     </div>
                     <div class="option" id="fullscreenButton1030">Fullscreen</div>
                     <div class="option" id="editorFullscreenButton1030">Editor Fullscreen</div>
@@ -280,9 +339,13 @@
                     <div class="option" id="minimapToggle1030">Minimap
                         <i class="fa fa-square-o" aria-hidden="true"></i>
                     </div>
-                    <div class="option" id="debugButton1030">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option" id="debugButton1030">Debug layer
+                        <i class="fa fa-square-o" aria-hidden="true"></i>
+                    </div>
                     <div class="option" id="metadataButton1030">Metadata</div>
-                    <div class="option subSelect"><span id="currentVersion1030">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                    <div class="option subSelect">
+                        <span id="currentVersion1030">Vers. : Latest</span>
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
                         <div class="toDisplaySub">
                             <div class="option" onclick="setVersion('latest');">Latest</div>
                             <div class="option" onclick="setVersion('2.5');">2.5</div>
@@ -293,7 +356,8 @@
         </div>
 
         <div class="category right">
-            <div class="button select"> <span id="currentScript1030">Scenes</span>
+            <div class="button select">
+                <span id="currentScript1030">Scenes</span>
                 <div class="toDisplayBig">
                     <ul id="scriptsList1030">
                     </ul>
@@ -309,11 +373,21 @@
         <div class="category">
             <div class="button select">File
                 <div class="toDisplay">
-                    <div class="option" id="runButton750">Run <i class="fa fa-play" aria-hidden="true"></i></div>
-                    <div class="option" id="newButton750">New <i class="fa fa-file" aria-hidden="true"></i></div>
-                    <div class="option" id="clearButton750">Clear <i class="fa fa-trash" aria-hidden="true"></i></div>
-                    <div class="option" id="saveButton750">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
-                    <div class="option" id="zipButton750">Zip <i class="fa fa-download" aria-hidden="true"></i></div>
+                    <div class="option" id="runButton750">Run
+                        <i class="fa fa-play" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="newButton750">New
+                        <i class="fa fa-file" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="clearButton750">Clear
+                        <i class="fa fa-trash" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="saveButton750">Save
+                        <i class="fa fa-floppy-o" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="zipButton750">Zip
+                        <i class="fa fa-download" aria-hidden="true"></i>
+                    </div>
                 </div>
             </div>
         </div>
@@ -321,13 +395,16 @@
         <div class="category">
             <div class="button select">Settings
                 <div class="toDisplay">
-                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                    <div class="option subSelect">Theme
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
                         <div class="toDisplaySub">
                             <div class="option" id="darkTheme750">Dark</div>
                             <div class="option" id="lightTheme750">Light</div>
                         </div>
                     </div>
-                    <div class="option subSelect"><span id="currentFontSize750">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                    <div class="option subSelect">
+                        <span id="currentFontSize750">Font: 14</span>
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
                         <div class="toDisplaySub">
                             <div class="option" onclick="setFontSize(12);">12</div>
                             <div class="option" onclick="setFontSize(14);">14</div>
@@ -337,8 +414,11 @@
                             <div class="option" onclick="setFontSize(22);">22</div>
                         </div>
                     </div>
-                    <div class="option" id="safemodeToggle750">Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
-                    <div style="display:none;" class="option checked" id="editorButton750">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    <div class="option" id="safemodeToggle750">Safe mode
+                        <i class="fa fa-square-o" aria-hidden="true"></i>
+                    </div>
+                    <div style="display:none;" class="option checked" id="editorButton750">Editor
+                        <i class="fa fa-check-square" aria-hidden="true"></i>
                     </div>
                     <div class="option" id="fullscreenButton750">Fullscreen</div>
                     <div class="option" id="editorFullscreenButton750">Editor Fullscreen</div>
@@ -346,9 +426,13 @@
                     <div class="option" id="minimapToggle750">Minimap
                         <i class="fa fa-square-o" aria-hidden="true"></i>
                     </div>
-                    <div class="option" id="debugButton750">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option" id="debugButton750">Debug layer
+                        <i class="fa fa-square-o" aria-hidden="true"></i>
+                    </div>
                     <div class="option" id="metadataButton750">Metadata</div>
-                    <div class="option subSelect"><span id="currentVersion750">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                    <div class="option subSelect">
+                        <span id="currentVersion750">Vers. : Latest</span>
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
                         <div class="toDisplaySub">
                             <div class="option" onclick="setVersion('latest');">Latest</div>
                             <div class="option" onclick="setVersion('2.5');">2.5</div>
@@ -359,7 +443,8 @@
         </div>
 
         <div class="category right">
-            <div class="button select"> <span id="currentScript750">Scenes</span>
+            <div class="button select">
+                <span id="currentScript750">Scenes</span>
                 <div class="toDisplayBig">
                     <ul id="scriptsList750">
                     </ul>
@@ -386,11 +471,21 @@
     <div class="navbarBottom">
         <div id="statusBar"></div>
         <div class="links">
-            <div class='link'><a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a></div>
-            <div class='link'> <a target='_new' href="http://www.html5gamedevs.com/forum/16-babylonjs/">Forum</a></div>
-            <div class='link'><a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a></div>
-            <div class='link'><a target='_new' href="https://doc.babylonjs.com">Documentation</a></div>
-            <div class='link'><a target='_new' href="https://doc.babylonjs.com/playground">Search</a></div>
+            <div class='link'>
+                <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
+            </div>
+            <div class='link'>
+                <a target='_new' href="http://www.html5gamedevs.com/forum/16-babylonjs/">Forum</a>
+            </div>
+            <div class='link'>
+                <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
+            </div>
+            <div class='link'>
+                <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
+            </div>
+            <div class='link'>
+                <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
+            </div>
         </div>
     </div>
 

+ 23 - 21
Playground/frame.html

@@ -4,30 +4,30 @@
 <head>
     <title>Babylon.js Playground</title>
     <link rel="shortcut icon" href="https://www.babylonjs.com/img/favicon/favicon.ico">
-	<link rel="apple-touch-icon" sizes="57x57" href="https://www.babylonjs.com/img/favicon/apple-icon-57x57.png">
-	<link rel="apple-touch-icon" sizes="60x60" href="https://www.babylonjs.com/img/favicon/apple-icon-60x60.png">
-	<link rel="apple-touch-icon" sizes="72x72" href="https://www.babylonjs.com/img/favicon/apple-icon-72x72.png">
-	<link rel="apple-touch-icon" sizes="76x76" href="https://www.babylonjs.com/img/favicon/apple-icon-76x76.png">
-	<link rel="apple-touch-icon" sizes="114x114" href="https://www.babylonjs.com/img/favicon/apple-icon-114x114.png">
-	<link rel="apple-touch-icon" sizes="120x120" href="https://www.babylonjs.com/img/favicon/apple-icon-120x120.png">
-	<link rel="apple-touch-icon" sizes="144x144" href="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png">
-	<link rel="apple-touch-icon" sizes="152x152" href="https://www.babylonjs.com/img/favicon/apple-icon-152x152.png">
-	<link rel="apple-touch-icon" sizes="180x180" href="https://www.babylonjs.com/img/favicon/apple-icon-180x180.png">
-	<link rel="icon" type="image/png" sizes="192x192"  href="https://www.babylonjs.com/img/favicon/android-icon-192x192.png">
-	<link rel="icon" type="image/png" sizes="32x32" href="https://www.babylonjs.com/img/favicon/favicon-32x32.png">
-	<link rel="icon" type="image/png" sizes="96x96" href="https://www.babylonjs.com/img/favicon/favicon-96x96.png">
-	<link rel="icon" type="image/png" sizes="16x16" href="https://www.babylonjs.com/img/favicon/favicon-16x16.png">
-	<link rel="manifest" href="https://www.babylonjs.com/img/favicon/manifest.json">
-	<meta name="msapplication-TileColor" content="#ffffff">
-	<meta name="msapplication-TileImage" content="https://www.babylonjs.com/img/favicon/ms-icon-144x144.png">
-	<meta name="msapplication-config" content="https://www.babylonjs.com/img/favicon/browserconfig.xml">
-	<meta name="theme-color" content="#ffffff">
+    <link rel="apple-touch-icon" sizes="57x57" href="https://www.babylonjs.com/img/favicon/apple-icon-57x57.png">
+    <link rel="apple-touch-icon" sizes="60x60" href="https://www.babylonjs.com/img/favicon/apple-icon-60x60.png">
+    <link rel="apple-touch-icon" sizes="72x72" href="https://www.babylonjs.com/img/favicon/apple-icon-72x72.png">
+    <link rel="apple-touch-icon" sizes="76x76" href="https://www.babylonjs.com/img/favicon/apple-icon-76x76.png">
+    <link rel="apple-touch-icon" sizes="114x114" href="https://www.babylonjs.com/img/favicon/apple-icon-114x114.png">
+    <link rel="apple-touch-icon" sizes="120x120" href="https://www.babylonjs.com/img/favicon/apple-icon-120x120.png">
+    <link rel="apple-touch-icon" sizes="144x144" href="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png">
+    <link rel="apple-touch-icon" sizes="152x152" href="https://www.babylonjs.com/img/favicon/apple-icon-152x152.png">
+    <link rel="apple-touch-icon" sizes="180x180" href="https://www.babylonjs.com/img/favicon/apple-icon-180x180.png">
+    <link rel="icon" type="image/png" sizes="192x192" href="https://www.babylonjs.com/img/favicon/android-icon-192x192.png">
+    <link rel="icon" type="image/png" sizes="32x32" href="https://www.babylonjs.com/img/favicon/favicon-32x32.png">
+    <link rel="icon" type="image/png" sizes="96x96" href="https://www.babylonjs.com/img/favicon/favicon-96x96.png">
+    <link rel="icon" type="image/png" sizes="16x16" href="https://www.babylonjs.com/img/favicon/favicon-16x16.png">
+    <link rel="manifest" href="https://www.babylonjs.com/img/favicon/manifest.json">
+    <meta name="msapplication-TileColor" content="#ffffff">
+    <meta name="msapplication-TileImage" content="https://www.babylonjs.com/img/favicon/ms-icon-144x144.png">
+    <meta name="msapplication-config" content="https://www.babylonjs.com/img/favicon/browserconfig.xml">
+    <meta name="theme-color" content="#ffffff">
 
     <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
     <!-- Babylon.js -->
     <script src="https://preview.babylonjs.com/cannon.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/materialsLibrary/babylon.fireMaterial.min.js"></script>
@@ -60,9 +60,11 @@
     <script src="https://preview.babylonjs.com/loaders/babylon.objFileLoader.js"></script>
     <script src="https://preview.babylonjs.com/loaders/babylon.stlFileLoader.js"></script>
 
+    <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
+
     <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
-    
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>    
+
+    <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>
     <script src="https://rawgit.com/BabylonJS/Extensions/master/canvas2D/dist/preview%20release/babylon.canvas2d.min.js"></script>
     <script src="https://rawgit.com/BabylonJS/Extensions/master/CompoundShader/src/babylonx.CompoundShader.js"></script>
     <link href="frame.css" rel="stylesheet" />

+ 2 - 0
Playground/index.html

@@ -49,6 +49,8 @@
 
     <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.js"></script>
 
+    <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
+
     <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
 
     <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>

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

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

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

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

BIN
Playground/textures/normal.png


+ 9 - 1
Tools/DevLoader/BabylonLoader.js

@@ -39,7 +39,7 @@ var BABYLONDEVTOOLS;
             dependencies = [];
             callback = null;
             min = (document.location.href.toLowerCase().indexOf('dist=min') > 0);
-            useDist = (min || document.location.href.toLowerCase().indexOf('dist=true') > 0);            
+            useDist = (min || useDist || document.location.href.toLowerCase().indexOf('dist=true') > 0);            
             babylonJSPath = '';
         }
 
@@ -91,6 +91,11 @@ var BABYLONDEVTOOLS;
             return this;
         }
 
+        Loader.prototype.useDist = function() {
+            useDist = true;
+            return this;
+        }
+
         Loader.prototype.dequeue = function () {
             if (queue.length == 0) {
                 console.log('Scripts loaded');
@@ -236,6 +241,9 @@ var BABYLONDEVTOOLS;
             // Modules
             if (loadModules) {
                 for (var i = 0; i< settings.modules.length; i++) {
+                    if (settings.modules[i] === "viewer") {
+                        continue;
+                    }
                     this.loadModule(settings[settings.modules[i]]);
                 }
             }

+ 206 - 191
Tools/Gulp/config.json

@@ -14,11 +14,12 @@
         ],
         "outputCustomConfigurationsDirectory": "../../dist/preview release/customConfigurations",
         "srcOutputDirectory": "../../src/",
-        "currentConfig": "all"
+        "currentConfig": "all",
+        "typedocJSON": "../../.temp/babylon.typedoc.json",
+        "typedocValidationBaseline": "../../dist/preview release/typedocValidationBaseline.json"
     },
     "buildConfigurations": {
         "all": [
-            "standardMaterial",
             "pbrMaterial",
             "freeCamera",
             "arcRotateCamera",
@@ -56,7 +57,11 @@
             "geometryBufferRenderer",
             "additionalPostProcesses",
             "additionalPostProcess_blur",
+            "additionalPostProcess_depthOfFieldBlur",
             "additionalPostProcess_fxaa",
+            "additionalPostProcess_circleOfConfusion",
+            "additionalPostProcess_depthOfFieldMerge",
+            "additionalPostProcess_depthOfFieldEffect",
             "additionalPostProcess_imageProcessing",
             "bones",
             "hdr",
@@ -68,7 +73,6 @@
             "debug",
             "morphTargets",
             "octrees",
-            "simd",
             "vr",
             "virtualJoystick",
             "optimizations",
@@ -82,21 +86,19 @@
             "nullEngine",
             "instrumentation",
             "backgroundMaterial",
-            "environmentHelper"
+            "environmentHelper",
+            "videoDome"
         ],
         "minimal": [
-            "standardMaterial",
             "freeCamera",
             "hemisphericLight"
         ],
         "minimalWithBuilder": [
             "meshBuilder",
-            "standardMaterial",
             "freeCamera",
             "hemisphericLight"
         ],
         "minimalGLTFViewer": [
-            "standardMaterial",
             "pbrMaterial",
             "freeCamera",
             "arcRotateCamera",
@@ -145,7 +147,6 @@
             "debug",
             "morphTargets",
             "octrees",
-            "simd",
             "vr",
             "virtualJoystick",
             "optimizations",
@@ -169,16 +170,20 @@
     "workloads": {
         "core": {
             "files": [
+                "../../src/Materials/babylon.effect.js",
                 "../../src/babylon.types.js",
                 "../../src/Events/babylon.keyboardEvents.js",
                 "../../src/Events/babylon.pointerEvents.js",
                 "../../src/Math/babylon.math.js",
                 "../../src/Math/babylon.math.scalar.js",
                 "../../src/babylon.mixins.js",
+                "../../src/Engine/babylon.webgl2.js",
                 "../../src/Tools/babylon.decorators.js",
+                "../../src/Tools/babylon.deferred.js",
                 "../../src/Tools/babylon.observable.js",
                 "../../src/Tools/babylon.smartArray.js",
                 "../../src/Tools/babylon.tools.js",
+                "../../src/Tools/babylon.promise.js",
                 "../../src/States/babylon.alphaCullingState.js",
                 "../../src/States/babylon.depthCullingState.js",
                 "../../src/States/babylon.stencilState.js",
@@ -194,34 +199,83 @@
                 "../../src/Rendering/babylon.renderingManager.js",
                 "../../src/Rendering/babylon.renderingGroup.js",
                 "../../src/babylon.scene.js",
+                "../../src/babylon.assetContainer.js",
                 "../../src/Mesh/babylon.buffer.js",
                 "../../src/Mesh/babylon.vertexBuffer.js",
+                "../../src/Materials/Textures/babylon.internalTextureTracker.js",
                 "../../src/Materials/Textures/babylon.internalTexture.js",
                 "../../src/Materials/Textures/babylon.baseTexture.js",
                 "../../src/Materials/Textures/babylon.texture.js",
                 "../../src/Mesh/babylon.mesh.js",
                 "../../src/Mesh/babylon.subMesh.js",
-                "../../src/Materials/babylon.effect.js",
-                "../../src/Materials/babylon.materialHelper.js",
                 "../../src/Materials/babylon.material.js",
                 "../../src/Materials/babylon.uniformBuffer.js",
-                "../../src/Materials/babylon.pushMaterial.js",
                 "../../src/Mesh/babylon.mesh.vertexData.js",
                 "../../src/Mesh/babylon.geometry.js",
                 "../../src/PostProcess/babylon.postProcessManager.js",
                 "../../src/Tools/babylon.performanceMonitor.js",
                 "../../src/Materials/babylon.imageProcessingConfiguration.js",
                 "../../src/Materials/Textures/babylon.colorGradingTexture.js",
-                "../../src/Materials/babylon.colorCurves.js"
+                "../../src/Materials/babylon.colorCurves.js",
+                "../../src/Behaviors/babylon.behavior.js",
+                "../../src/Materials/babylon.materialHelper.js",
+                "../../src/Materials/babylon.pushMaterial.js",
+                "../../src/Materials/babylon.standardMaterial.js"
+            ],
+            "shaders": [
+                "default.vertex",
+                "default.fragment"
             ],
             "shaderIncludes": [
-                "depthPrePass"
+                "depthPrePass",
+                "bonesDeclaration",
+                "instancesDeclaration",
+                "pointCloudVertexDeclaration",
+                "bumpVertexDeclaration",
+                "clipPlaneVertexDeclaration",
+                "fogVertexDeclaration",
+                "morphTargetsVertexGlobalDeclaration",
+                "morphTargetsVertexDeclaration",
+                "logDepthDeclaration",
+                "morphTargetsVertex",
+                "instancesVertex",
+                "bonesVertex",
+                "bumpVertex",
+                "clipPlaneVertex",
+                "fogVertex",
+                "shadowsVertex",
+                "pointCloudVertex",
+                "logDepthVertex",
+                "helperFunctions",
+                "lightFragmentDeclaration",
+                "lightsFragmentFunctions",
+                "lightUboDeclaration",
+                "defaultVertexDeclaration",
+                "defaultFragmentDeclaration",
+                "defaultUboDeclaration",
+                "shadowsFragmentFunctions",
+                "fresnelFunction",
+                "reflectionFunction",
+                "imageProcessingDeclaration",
+                "imageProcessingFunctions",
+                "bumpFragmentFunctions",
+                "clipPlaneFragmentDeclaration",
+                "fogFragmentDeclaration",
+                "clipPlaneFragment",
+                "bumpFragment",
+                "lightFragment",
+                "logDepthFragment",
+                "fogFragment"
             ]
         },
         "particles": {
             "files": [
                 "../../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"
             ],
             "dependUpon": [
                 "core"
@@ -247,7 +301,9 @@
         },
         "nullEngine": {
             "files": [
-                "../../src/Engine/babylon.nullEngine.js"
+                "../../src/Engine/babylon.nullEngine.js",
+                "../../src/Engine/babylon.webgl2.js",
+                "../../src/babylon.mixins.js"
             ],
             "dependUpon": [
                 "core"
@@ -255,6 +311,7 @@
         },
         "instrumentation": {
             "files": [
+                "../../src/Engine/babylon.webgl2.js",
                 "../../src/Instrumentation/babylon.engineInstrumentation.js",
                 "../../src/Instrumentation/babylon.sceneInstrumentation.js",
                 "../../src/Instrumentation/babylon.timeToken.js"
@@ -325,6 +382,7 @@
         "animations": {
             "files": [
                 "../../src/Animations/babylon.animation.js",
+                "../../src/Animations/babylon.animationGroup.js",
                 "../../src/Animations/babylon.runtimeAnimation.js",
                 "../../src/Animations/babylon.animatable.js",
                 "../../src/Animations/babylon.easing.js"
@@ -352,7 +410,8 @@
                 "../../src/Mesh/babylon.linesMesh.js"
             ],
             "dependUpon": [
-                "core"
+                "core",
+                "shaderMaterial"
             ],
             "shaders": [
                 "color.vertex",
@@ -365,7 +424,7 @@
             ],
             "dependUpon": [
                 "core",
-                "shaderMaterial"
+                "additionalMeshes"
             ]
         },
         "shaderMaterial": {
@@ -376,59 +435,6 @@
                 "core"
             ]
         },
-        "standardMaterial": {
-            "files": [
-                "../../src/Materials/babylon.standardMaterial.js"
-            ],
-            "dependUpon": [
-                "core"
-            ],
-            "shaders": [
-                "default.vertex",
-                "default.fragment"
-            ],
-            "shaderIncludes": [
-                "bonesDeclaration",
-                "instancesDeclaration",
-                "pointCloudVertexDeclaration",
-                "bumpVertexDeclaration",
-                "clipPlaneVertexDeclaration",
-                "fogVertexDeclaration",
-                "morphTargetsVertexGlobalDeclaration",
-                "morphTargetsVertexDeclaration",
-                "logDepthDeclaration",
-                "morphTargetsVertex",
-                "instancesVertex",
-                "bonesVertex",
-                "bumpVertex",
-                "clipPlaneVertex",
-                "fogVertex",
-                "shadowsVertex",
-                "pointCloudVertex",
-                "logDepthVertex",
-                "helperFunctions",
-                "lightFragmentDeclaration",
-                "lightsFragmentFunctions",
-                "lightUboDeclaration",
-                "defaultVertexDeclaration",
-                "defaultFragmentDeclaration",
-                "defaultUboDeclaration",
-                "shadowsFragmentFunctions",
-                "fresnelFunction",
-                "reflectionFunction",
-                "imageProcessingDeclaration",
-                "imageProcessingFunctions",
-                "bumpFragmentFunctions",
-                "clipPlaneFragmentDeclaration",
-                "logDepthDeclaration",
-                "fogFragmentDeclaration",
-                "clipPlaneFragment",
-                "bumpFragment",
-                "lightFragment",
-                "logDepthFragment",
-                "fogFragment"
-            ]
-        },
         "pbrMaterial": {
             "files": [
                 "../../src/Materials/PBR/babylon.pbrBaseMaterial.js",
@@ -445,72 +451,44 @@
                 "pbr.fragment"
             ],
             "shaderIncludes": [
-                "bonesDeclaration",
-                "instancesDeclaration",
-                "bumpVertexDeclaration",
-                "clipPlaneVertexDeclaration",
-                "fogVertexDeclaration",
-                "morphTargetsVertexGlobalDeclaration",
-                "morphTargetsVertexDeclaration",
-                "logDepthDeclaration",
-                "morphTargetsVertex",
-                "instancesVertex",
-                "bonesVertex",
-                "bumpVertex",
-                "clipPlaneVertex",
-                "fogVertex",
-                "shadowsVertex",
-                "logDepthVertex",
-                "lightFragmentDeclaration",
-                "lightUboDeclaration",
                 "pbrVertexDeclaration",
                 "pbrFragmentDeclaration",
                 "pbrUboDeclaration",
-                "fresnelFunction",
-                "reflectionFunction",
-                "shadowsFragmentFunctions",
                 "pbrFunctions",
-                "imageProcessingDeclaration",
-                "imageProcessingFunctions",
                 "harmonicsFunctions",
-                "pbrLightFunctions",
-                "helperFunctions",
-                "bumpFragmentFunctions",
-                "clipPlaneFragmentDeclaration",
-                "logDepthDeclaration",
-                "fogFragmentDeclaration",
-                "clipPlaneFragment",
-                "bumpFragment",
-                "lightFragment",
-                "logDepthFragment",
-                "fogFragment"
+                "pbrLightFunctions"
             ]
         },
-        "freeCamera": {
+        "targetCamera": {
             "files": [
                 "../../src/Cameras/babylon.cameraInputsManager.js",
+                "../../src/Cameras/babylon.targetCamera.js"
+            ],
+            "dependUpon": [
+                "core"
+            ]
+        },
+        "freeCamera": {
+            "files": [
                 "../../src/Cameras/Inputs/babylon.freeCameraMouseInput.js",
                 "../../src/Cameras/Inputs/babylon.freeCameraKeyboardMoveInput.js",
                 "../../src/Cameras/babylon.freeCameraInputsManager.js",
-                "../../src/Cameras/babylon.targetCamera.js",
                 "../../src/Cameras/babylon.freeCamera.js"
             ],
             "dependUpon": [
-                "core"
+                "targetCamera"
             ]
         },
         "arcRotateCamera": {
             "files": [
-                "../../src/Cameras/babylon.cameraInputsManager.js",
-                "../../src/Cameras/babylon.targetCamera.js",
                 "../../src/Cameras/Inputs/babylon.arcRotateCameraKeyboardMoveInput.js",
                 "../../src/Cameras/Inputs/babylon.arcRotateCameraMouseWheelInput.js",
                 "../../src/Cameras/Inputs/babylon.arcRotateCameraPointersInput.js",
-                "../../src/Cameras/babylon.arcRotateCamera.js",
-                "../../src/Cameras/babylon.arcRotateCameraInputsManager.js"
+                "../../src/Cameras/babylon.arcRotateCameraInputsManager.js",
+                "../../src/Cameras/babylon.arcRotateCamera.js"
             ],
             "dependUpon": [
-                "core"
+                "targetCamera"
             ]
         },
         "hemisphericLight": {
@@ -612,7 +590,6 @@
                 "../../src/Tools/babylon.andOrNotEvaluator.js"
             ],
             "dependUpon": [
-                "core",
                 "stringDictionary"
             ]
         },
@@ -673,7 +650,8 @@
                 "../../src/Gamepad/Controllers/babylon.oculusTouchController.js",
                 "../../src/Gamepad/Controllers/babylon.viveController.js",
                 "../../src/Gamepad/Controllers/babylon.genericController.js",
-                "../../src/Gamepad/Controllers/babylon.windowsMotionController.js"
+                "../../src/Gamepad/Controllers/babylon.windowsMotionController.js",
+                "../../src/Gamepad/Controllers/babylon.gearVRController.js"
             ],
             "dependUpon": [
                 "core"
@@ -700,12 +678,7 @@
                 "depth.vertex",
                 "depth.fragment"
             ],
-            "shaderIncludes": [
-                "bonesDeclaration",
-                "instancesDeclaration",
-                "instancesVertex",
-                "bonesVertex"
-            ]
+            "shaderIncludes": []
         },
         "geometryBufferRenderer": {
             "files": [
@@ -721,9 +694,7 @@
             "shaderIncludes": [
                 "mrtFragmentDeclaration",
                 "bones300Declaration",
-                "instances300Declaration",
-                "instancesVertex",
-                "bonesVertex"
+                "instances300Declaration"
             ]
         },
         "postProcesses": {
@@ -757,6 +728,51 @@
                 "kernelBlurVertex"
             ]
         },
+        "additionalPostProcess_depthOfFieldBlur": {
+            "files": [
+                "../../src/PostProcess/babylon.depthOfFieldBlurPostProcess.js"
+            ],
+            "dependUpon": [
+                "postProcesses"
+            ],
+            "shaders": [
+                "kernelBlur.vertex",
+                "kernelBlur.fragment"
+            ],
+            "shaderIncludes": [
+                "kernelBlurFragment",
+                "kernelBlurFragment2",
+                "kernelBlurVaryingDeclaration",
+                "kernelBlurVertex"
+            ]
+        },
+        "additionalPostProcess_circleOfConfusion": {
+            "files": [
+                "../../src/PostProcess/babylon.circleOfConfusionPostProcess.js"
+            ],
+            "dependUpon": [
+                "postProcesses"
+            ],
+            "shaders": [
+                "circleOfConfusion.fragment"
+            ]
+        },
+        "additionalPostProcess_depthOfFieldMerge": {
+            "files": [
+                "../../src/PostProcess/babylon.depthOfFieldMergePostProcess.js"
+            ],
+            "dependUpon": [
+                "postProcesses"
+            ],
+            "shaders": [
+                "depthOfFieldMerge.fragment"
+            ]
+        },
+        "additionalPostProcess_depthOfFieldEffect": {
+            "files": [
+                "../../src/PostProcess/babylon.depthOfFieldEffect.js"
+            ]
+        },
         "additionalPostProcess_fxaa": {
             "files": [
                 "../../src/PostProcess/babylon.fxaaPostProcess.js"
@@ -790,10 +806,7 @@
             "shaders": [
                 "imageProcessing.fragment"
             ],
-            "shaderIncludes": [
-                "imageProcessingDeclaration",
-                "imageProcessingFunctions"
-            ]
+            "shaderIncludes": []
         },
         "additionalPostProcesses": {
             "files": [
@@ -830,7 +843,6 @@
         "renderingPipeline": {
             "files": [
                 "../../src/PostProcess/RenderPipeline/babylon.postProcessRenderPipelineManager.js",
-                "../../src/PostProcess/RenderPipeline/babylon.postProcessRenderPass.js",
                 "../../src/PostProcess/RenderPipeline/babylon.postProcessRenderEffect.js",
                 "../../src/PostProcess/RenderPipeline/babylon.postProcessRenderPipeline.js"
             ],
@@ -865,7 +877,10 @@
             ],
             "dependUpon": [
                 "renderingPipeline",
-                "additionalPostProcess_fxaa"
+                "additionalPostProcess_fxaa",
+                "additionalPostProcess_circleOfConfusion",
+                "additionalPostProcess_depthOfFieldMerge",
+                "additionalPostProcess_depthOfFieldEffect"
             ]
         },
         "bones": {
@@ -947,25 +962,19 @@
         },
         "debug": {
             "files": [
-                "../../src/Debug/babylon.skeletonViewer.js",
-                "../../src/Debug/babylon.axesViewer.js",
-                "../../src/Debug/babylon.boneAxesViewer.js",
+                "../../src/Debug/babylon.debugModules.js",
                 "../../src/Debug/babylon.rayHelper.js",
                 "../../src/Debug/babylon.debugLayer.js",
-                "../../src/Debug/babylon.physicsViewer.js",
                 "../../src/Rendering/babylon.boundingBoxRenderer.js"
             ],
             "dependUpon": [
                 "shaderMaterial",
                 "additionalMeshes",
-                "standardMaterial",
+                "core",
                 "stringDictionary",
                 "actions"
             ],
-            "shaders": [
-                "color.vertex",
-                "color.fragment"
-            ]
+            "shaders": []
         },
         "morphTargets": {
             "files": [
@@ -985,14 +994,6 @@
                 "core"
             ]
         },
-        "simd": {
-            "files": [
-                "../../src/Math/babylon.math.SIMD.js"
-            ],
-            "dependUpon": [
-                "core"
-            ]
-        },
         "vr": {
             "files": [
                 "../../src/PostProcess/babylon.vrDistortionCorrectionPostProcess.js",
@@ -1008,7 +1009,9 @@
                 "../../src/Cameras/VR/babylon.vrExperienceHelper.js"
             ],
             "dependUpon": [
-                "core"
+                "core",
+                "postProcesses",
+                "freeCamera"
             ],
             "shaders": [
                 "anaglyph.fragment",
@@ -1040,7 +1043,9 @@
             "files": [
                 "../../src/Rendering/babylon.outlineRenderer.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": [
                 "shaderMaterial"
@@ -1105,45 +1110,9 @@
                 "background.fragment"
             ],
             "shaderIncludes": [
-                "bonesDeclaration",
-                "instancesDeclaration",
-                "pointCloudVertexDeclaration",
-                "bumpVertexDeclaration",
-                "clipPlaneVertexDeclaration",
-                "fogVertexDeclaration",
-                "morphTargetsVertexGlobalDeclaration",
-                "morphTargetsVertexDeclaration",
-                "logDepthDeclaration",
-                "morphTargetsVertex",
-                "instancesVertex",
-                "bonesVertex",
-                "bumpVertex",
-                "clipPlaneVertex",
-                "fogVertex",
-                "shadowsVertex",
-                "pointCloudVertex",
-                "logDepthVertex",
-                "helperFunctions",
-                "lightFragmentDeclaration",
-                "lightsFragmentFunctions",
-                "lightUboDeclaration",
                 "backgroundVertexDeclaration",
                 "backgroundFragmentDeclaration",
-                "backgroundUboDeclaration",
-                "shadowsFragmentFunctions",
-                "fresnelFunction",
-                "reflectionFunction",
-                "imageProcessingDeclaration",
-                "imageProcessingFunctions",
-                "bumpFragmentFunctions",
-                "clipPlaneFragmentDeclaration",
-                "logDepthDeclaration",
-                "fogFragmentDeclaration",
-                "clipPlaneFragment",
-                "bumpFragment",
-                "lightFragment",
-                "logDepthFragment",
-                "fogFragment"
+                "backgroundUboDeclaration"
             ]
         },
         "environmentHelper": {
@@ -1155,6 +1124,16 @@
                 "backgroundMaterial",
                 "additionalTextures"
             ]
+        },
+        "videoDome": {
+            "files": [
+                "../../src/Helpers/babylon.videoDome.js"
+            ],
+            "dependUpon": [
+                "core",
+                "meshBuilder",
+                "additionalTextures"
+            ]
         }
     },
     "typescript": [
@@ -1495,12 +1474,13 @@
             {
                 "files": [
                     "../../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.glTFLoader.ts",
-                    "../../loaders/src/glTF/2.0/babylon.glTFLoaderUtils.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts",
                     "../../loaders/src/glTF/2.0/Extensions/MSFT_lod.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"
                 ],
                 "doNotIncludeInBundle": true,
                 "output": "babylon.glTF2FileLoader.js"
@@ -1514,12 +1494,13 @@
                     "../../loaders/src/glTF/1.0/babylon.glTFLoaderExtension.ts",
                     "../../loaders/src/glTF/1.0/babylon.glTFBinaryExtension.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.glTFLoader.ts",
-                    "../../loaders/src/glTF/2.0/babylon.glTFLoaderUtils.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts",
                     "../../loaders/src/glTF/2.0/Extensions/MSFT_lod.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"
                 ],
                 "output": "babylon.glTFFileLoader.js"
             }
@@ -1541,6 +1522,15 @@
                     "../../serializers/src/OBJ/babylon.objSerializer.ts"
                 ],
                 "output": "babylon.objSerializer.js"
+            },
+            {
+                "files": [
+                    "../../serializers/src/glTF/2.0/babylon.glTFSerializer.ts",
+                    "../../serializers/src/glTF/2.0/babylon.glTFExporter.ts",
+                    "../../serializers/src/glTF/2.0/babylon.glTFData.ts",
+                    "../../serializers/src/glTF/2.0/babylon.glTFMaterial.ts"
+                ],
+                "output": "babylon.glTF2Serializer.js"
             }
         ],
         "build": {
@@ -1548,6 +1538,9 @@
             "distOutputDirectory": "/serializers/",
             "buildAsModule": true,
             "moduleName": "babylonjs-serializers",
+            "extraDeclarations": [
+                "../../dist/babylon.glTF2Interface.d.ts"
+            ],
             "outputFilename": "babylonjs.serializers",
             "moduleDeclaration": "BJSSerializers",
             "extendsRoot": true
@@ -1677,7 +1670,29 @@
         ],
         "build": {
             "srcOutputDirectory": "../../Viewer/",
-            "distOutputDirectory": "/viewer/"
+            "outputs": [
+                {
+                    "destination": [
+                        {
+                            "filename": "viewer.min.js",
+                            "outputDirectory": "/../../Viewer/dist/"
+                        },
+                        {
+                            "filename": "babylon.viewer.js",
+                            "outputDirectory": "/viewer/"
+                        }
+                    ],
+                    "minified": true
+                },
+                {
+                    "destination": [
+                        {
+                            "filename": "viewer.js",
+                            "outputDirectory": "/../../Viewer/dist/"
+                        }
+                    ]
+                }
+            ]
         }
     }
-}
+}

+ 15 - 2
Tools/Gulp/gulp-addDtsExport.js

@@ -1,7 +1,7 @@
 var gutil = require('gulp-util');
 var through = require('through2');
 
-module.exports = function (varName, moduleName, subModule, extendsRoot) {
+module.exports = function (varName, moduleName, subModule, extendsRoot, dependencies) {
     return through.obj(function (file, enc, cb) {
 
         let exportText = "BABYLON";
@@ -9,8 +9,21 @@ module.exports = function (varName, moduleName, subModule, extendsRoot) {
             exportText += '.' + varName;
         }
 
+        let referenceText = '';
+        if (subModule) {
+            referenceText = '/// <reference types="babylonjs"/>\n';
+        }
+
+        if (dependencies) {
+            referenceText = '';
+            dependencies.forEach(element => {
+                referenceText += `/// <reference types="babylonjs/${element}"/>
+`
+            });
+        }
+
         var moduleExportsAddition =
-            `${subModule ? '/// <reference types="babylonjs"/>' : ''}
+            `${referenceText}
 
 declare module '${moduleName}' { 
     export = ${exportText}; 

+ 79 - 0
Tools/Gulp/gulp-addES6Exports.js

@@ -0,0 +1,79 @@
+var gutil = require('gulp-util');
+var through = require('through2');
+
+/**
+ * The parameters for this function has grown during development.
+ * Eventually, this function will need to be reorganized. 
+ */
+module.exports = function (baseModule, subModule, extendsRoot, externalUsingBabylon) {
+    return through.obj(function (file, enc, cb) {
+
+        var optionalRequire = `var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : this);
+var babylonDependency = (globalObject && globalObject.BABYLON) || BABYLON || (typeof require !== 'undefined' && require("babylonjs"));
+var BABYLON = babylonDependency;
+`;
+        let fileContent = file.contents.toString();
+        function moduleExportAddition(varName) {
+
+            let base = subModule ? 'BABYLON' : baseModule;
+
+            let sadGlobalPolution = (!subModule) ? `var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : this);
+globalObject["${base}"] = ${base}${(subModule && !extendsRoot) ? '.' + varName : ''};` : '';
+            /*if (extendsRoot) {
+                basicInit = `__extends(root["BABYLON"], factory()); `
+            }*/
+
+            let listOfExports = [];
+            // find the exported members. es6 exports can NOT be generated dynamically.
+            let matcher = new RegExp(base + "\\.(\\w*) = (\\w*);", "g");
+            let match = matcher.exec(fileContent);
+            while (match != null) {
+                if (match[1] && match[2] && match[1] === match[2]) {
+                    listOfExports.push(match[1]);
+                }
+                match = matcher.exec(fileContent);
+            }
+
+            let exportsText = '';
+            listOfExports.forEach(cls => {
+                exportsText += `var ${cls} = ${base}.${cls};`;
+            });
+            exportsText += `
+export { ${listOfExports.join(",")} };`
+
+            return `${sadGlobalPolution}
+${exportsText}
+`;
+        }
+
+        var extendsAddition = `var __extends=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,o){t.__proto__=o}||function(t,o){for(var n in o)o.hasOwnProperty(n)&&(t[n]=o[n])};return function(o,n){function r(){this.constructor=o}t(o,n),o.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();
+`;
+
+        var decorateAddition = 'var __decorate=this&&this.__decorate||function(e,t,r,c){var o,f=arguments.length,n=f<3?t:null===c?c=Object.getOwnPropertyDescriptor(t,r):c;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(e,t,r,c);else for(var l=e.length-1;l>=0;l--)(o=e[l])&&(n=(f<3?o(n):f>3?o(t,r,n):o(t,r))||n);return f>3&&n&&Object.defineProperty(t,r,n),n};\n';
+
+
+        if (file.isNull()) {
+            cb(null, file);
+            return;
+        }
+
+        if (file.isStream()) {
+            //streams not supported, no need for now.
+            return;
+        }
+
+        try {
+            if (externalUsingBabylon) {
+                //file.contents = new Buffer(optionalRequire.concat(String(file.contents)));
+                file.contents = new Buffer(optionalRequire.concat(new Buffer(String(file.contents).concat(moduleExportAddition(baseModule)))));
+            } else {
+                let pretext = subModule ? optionalRequire : '';
+                file.contents = new Buffer(pretext.concat(decorateAddition).concat(new Buffer(extendsAddition.concat(String(file.contents)).concat(moduleExportAddition(baseModule)))));
+            }
+            this.push(file);
+        } catch (err) {
+            this.emit('error', new gutil.PluginError('gulp-add-module-exports', err, { fileName: file.path }));
+        }
+        cb();
+    });
+};

+ 36 - 6
Tools/Gulp/gulp-appendSrcToVariable.js

@@ -7,7 +7,7 @@ var File = gutil.File;
 // Consts
 const PLUGIN_NAME = 'gulp-appendSrcToVariable';
 
-var appendSrcToVariable = function appendSrcToVariable(varName, namingCallback, output) {
+var appendSrcToVariable = function appendSrcToVariable(varName, namingCallback, output, moduleType) {
 
     var content;
     var firstFile;
@@ -28,17 +28,47 @@ var appendSrcToVariable = function appendSrcToVariable(varName, namingCallback,
             return;
         }
 
+        // construct concat instance
+        if (!content) {
+            content = "";
+        }
+
         // set first file if not already set
         if (!firstFile) {
+            if (moduleType === "es6") {
+                content += `
+// import * as BABYLON from 'babylonjs/core/es6';
+`;
+            }
             firstFile = file;
         }
 
-        // construct concat instance
-        if (!content) {
-            content = "";
-        }
+
         var name = namingCallback(file.relative);
-        content += varName + "['" + name + "'] = " + JSON.stringify(file.contents.toString()) + ";\r\n";
+        if (moduleType) {
+            let vars = varName.split(".");
+            // shader support when using modules
+            if (moduleType === "es6") {
+                content += `
+let ${name} = ${JSON.stringify(file.contents.toString())};
+// ${varName}["${name}"] = ${varName}["${name}"] || ${name};
+export { ${name}  };
+`;
+            } else {
+                // commonjs
+                content += `
+if(typeof require !== 'undefined'){
+var BABYLON = require("babylonjs/core");
+let data = ${JSON.stringify(file.contents.toString())};
+${varName}["${name}"] = ${varName}["${name}"] || data;
+module.exports = module.exports || {};
+module.exports["${name}"] = data;
+}
+`;
+            }
+        } else {
+            content += varName + "['" + name + "'] = " + JSON.stringify(file.contents.toString()) + ";\r\n";
+        }
         cb();
     }
 

+ 133 - 0
Tools/Gulp/gulp-babylonModule.js

@@ -0,0 +1,133 @@
+var gutil = require('gulp-util');
+var through = require('through2');
+var path = require('path');
+
+module.exports = function (moduleName, dependencyTree, generateIndex, perFile, shaders, shaderIncludes) {
+    return through.obj(function (file, enc, cb) {
+
+        let basename = (path.basename(file.path, ".js"));
+
+        //console.log("Compiling module: " + moduleName + "/" + basename.replace("babylon.", ""));
+
+        var extendsAddition =
+            `var __extends=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,o){t.__proto__=o}||function(t,o){for(var n in o)o.hasOwnProperty(n)&&(t[n]=o[n])};return function(o,n){function r(){this.constructor=o}t(o,n),o.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();
+`;
+
+        var decorateAddition =
+            'var __decorate=this&&this.__decorate||function(e,t,r,c){var o,f=arguments.length,n=f<3?t:null===c?c=Object.getOwnPropertyDescriptor(t,r):c;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(e,t,r,c);else for(var l=e.length-1;l>=0;l--)(o=e[l])&&(n=(f<3?o(n):f>3?o(t,r,n):o(t,r))||n);return f>3&&n&&Object.defineProperty(t,r,n),n};\n';
+
+        let content = file.contents.toString();
+        if (content.indexOf('__extends') === -1 && !dependencyTree.length) {
+            extendsAddition = '';
+        }
+
+        if (content.indexOf('__decorate') === -1) {
+            decorateAddition = '';
+        }
+
+        let dependenciesText = `${extendsAddition}
+${decorateAddition}
+if(typeof require !== 'undefined'){
+    var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : this);
+    var BABYLON = globalObject["BABYLON"] || {}; 
+    var EXPORTS = {};
+`;
+        let exportsText = '';
+        if (!generateIndex) {
+            let loadedFiles = [];
+            dependencyTree[basename].forEach(function (d, idx) {
+                if (d.module.indexOf("core") !== -1) return;
+                let name = d.file.split(".").pop();
+
+                if (loadedFiles.indexOf(name) === -1) {
+                    if (d.main)
+                        dependenciesText += `var ${name}Module = require('babylonjs/${d.module[0]}/${name}');
+`;
+                    else
+                        exportsText += `var ${name}Module = require('babylonjs/${d.module[0]}/${name}');
+`;
+                    loadedFiles.push(name);
+                }
+
+                dependenciesText += `BABYLON["${d.name}"] = ${name}Module["${d.name}"];
+`;
+                //dependenciesText += `if(BABYLON !== BABYLON${idx}) __extends(BABYLON, BABYLON${idx});
+            });
+            perFile[basename].declarations.forEach(dec => {
+                exportsText += `EXPORTS['${dec}'] = BABYLON["${dec}"];
+`;
+            });
+            if (shaders) {
+                dependenciesText += `require("babylonjs/${moduleName}/shaders");
+`;
+            }
+            if (shaderIncludes) {
+                dependenciesText += `require("babylonjs/${moduleName}/shaderIncludes");
+`;
+            }
+        } else {
+            content = '';
+            let basenames = Object.keys(perFile).filter(basefilename => {
+                return perFile[basefilename].module.indexOf(moduleName) !== -1;
+            });
+
+            basenames.forEach(bname => {
+                let name = bname.split(".").pop();
+                dependenciesText += `var ${name} = require("babylonjs/${moduleName}/${name}");
+`;
+                // now add the internal dependencies to EXPORTS
+                perFile[bname].declarations.forEach(dec => {
+                    dependenciesText += `EXPORTS['${dec}'] = BABYLON["${dec}"] = ${name}["${dec}"];
+`;
+                });
+            })
+        }
+
+        exportsText += `(function() {
+    globalObject["BABYLON"] = globalObject["BABYLON"] || BABYLON;
+    module.exports = EXPORTS;
+    })();
+}`;
+
+
+
+        /*let exportRegex = /BABYLON.([0-9A-Za-z-_]*) = .*;\n/g
+
+        var match = exportRegex.exec(content);
+
+        let exportsArray = [];
+        while (match != null) {
+            if (match[1]) {
+                exportsArray.push(match[1])
+            }
+            match = exportRegex.exec(content);
+        }*/
+
+
+        /*if (moduleName === "core") {
+            exportsText = `(function() {
+    globalObject["BABYLON"] = globalObject["BABYLON"] || BABYLON;
+    module.exports = BABYLON; 
+})();
+}`
+        }*/
+
+        if (file.isNull()) {
+            cb(null, file);
+            return;
+        }
+
+        if (file.isStream()) {
+            //streams not supported, no need for now.
+            return;
+        }
+
+        try {
+            file.contents = new Buffer(dependenciesText.concat(new Buffer(String(content).concat(exportsText))));
+            this.push(file);
+        } catch (err) {
+            this.emit('error', new gutil.PluginError('gulp-add-babylon-module', err, { fileName: file.path }));
+        }
+        cb();
+    });
+}

+ 80 - 0
Tools/Gulp/gulp-calculateDependencies.js

@@ -0,0 +1,80 @@
+var gutil = require('gulp-util');
+var through = require('through2');
+var path = require('path');
+
+module.exports = function (moduleName, perFile, declared, depTree) {
+    return through.obj(function (file, enc, cb) {
+        let basename = (path.basename(file.path, ".ts"));
+        depTree[basename] = depTree[basename] || [];
+        // detect dependencies
+        let depReg1 = /[:,][ ]{0,1}([A-Z]\w*)/g;
+        let depReg2 = /<([A-Z]\w*)(\[\]){0,1}>/g;
+        let depReg3 = /[\s(]([A-Z]\w*)\./g;
+        let depReg4 = /[extends|implements] ([A-Z]\w*)/g;
+        let depReg5 = /new ([A-Z]\w*)/g;
+
+        let dependencies = [];
+        fileContent = file.contents.toString().replace(/(\/\*([\s\S]*?)\*\/)|(\/\/(.*)$)/gm, "");
+        function findWhereDeclared(objectName) {
+            let fileLocator;
+            Object.keys(perFile).some((filename => {
+                filedec = perFile[filename];
+                if (filedec.declarations.indexOf(objectName) !== -1) {
+                    fileLocator = filename;
+                    return true;
+                }
+                return false;
+            }))
+            return fileLocator;
+        }
+
+        //if (basename === "babylon.webVRCamera") {
+        [depReg4, depReg1, depReg5, depReg3, depReg2].forEach((reg, idx) => {
+            var match = reg.exec(fileContent);
+            while (match != null) {
+                if (match[1]) {
+                    let dep = match[1];
+                    if (basename === "babylon.poseEnabledController") {
+                        console.log(dep, idx);
+                    }
+                    //find if it is declared internally
+                    if (perFile[basename].declarations.indexOf(dep) === -1) {
+                        // not internally? maybe it is in core?
+                        //if (declared.core.indexOf(dep) === -1) {
+                        // seems like a legit dependency! was it already added?
+                        if (perFile[basename].dependencies.indexOf(dep) === -1) {
+                            //no! add it.
+                            let whereDeclared = (findWhereDeclared(dep));
+                            if (whereDeclared) {
+                                perFile[basename].dependencies.push(dep);
+                                if (basename === "babylon.poseEnabledController") {
+                                    console.log("adding ", dep, idx === 2);
+                                }
+                                depTree[basename].push({
+                                    name: dep,
+                                    file: whereDeclared,
+                                    module: perFile[whereDeclared].module,
+                                    main: idx === 0, // is it a main import
+                                    newDec: idx === 2 // is it "new"
+                                });
+                            }
+                        }
+                        //}
+                    }
+                }
+                match = reg.exec(fileContent);
+            }
+        });
+        //}
+
+
+        try {
+            this.push(file);
+
+        } catch (err) {
+            this.emit('error', new gutil.PluginError('gulp-calculateDependencies', err, { fileName: file.path }));
+        }
+        cb();
+    });
+};
+

+ 96 - 0
Tools/Gulp/gulp-dtsModuleSupport.js

@@ -0,0 +1,96 @@
+var gutil = require('gulp-util');
+var through = require('through2');
+var path = require('path');
+
+// inject - if set to true, it will add all declarations as imports.
+module.exports = function (moduleName, inject, declarations, perFile, dependencyTree) {
+    return through.obj(function (file, enc, cb) {
+        let basename = (path.basename(file.path, ".d.ts"));
+        let fileContent = file.contents.toString();
+        let importsString = '';
+
+        if (!inject) {
+            perFile[basename] = perFile[basename] || {
+                module: [moduleName],
+                dependencies: [],
+                declarations: []
+            };
+            if (perFile[basename].module.indexOf(moduleName) === -1) {
+                perFile[basename].module.push(moduleName);
+            }
+            declarations[moduleName] = declarations[moduleName] || [];
+            let regexp = /    (abstract class|function|class|interface|type|const|enum|var) ([\w]*)/g;
+
+            var match = regexp.exec(fileContent);
+            while (match != null) {
+                if (match[2]) {
+                    // check it is not SIMD:
+                    let simdMatch = /    interface (\w*\dx\d{1,2}\w*)/.exec(match[0]);
+                    if (!simdMatch && match[2] !== 'earcut' && match[2] !== 'deviation' && match[2] !== 'flatten') {
+                        declarations[moduleName].push(match[2]);
+                        perFile[basename].declarations.push(match[2]);
+                    }
+                }
+                match = regexp.exec(fileContent);
+            }
+        } else {
+            /*let declared = [];
+            Object.keys(declarations).forEach(name => {
+                if (name === moduleName) return;
+                let imports = declarations[name].filter(obj => {
+                    let exists = declared.indexOf(obj) !== -1;
+                    if (!exists) {
+                        declared.push(obj);
+                    }
+                    return !exists;
+                });
+                if (imports.length)
+                    importsString += `import {${imports.join(',')}} from 'babylonjs/${name}';
+`;
+            });*/
+
+            // find all of the related files for the dependency tree integration
+            let basenames = Object.keys(perFile).filter(basefilename => {
+                return perFile[basefilename].module.indexOf(moduleName) !== -1;
+            });
+
+            let classesForImports = {} // key : module name, content - array of objects
+            basenames.forEach(bname => {
+                dependencyTree[bname].forEach(dep => {
+                    if (dep.module.indexOf(moduleName) !== -1) return;
+                    let depModule = dep.module.indexOf("core") === -1 ? dep.module[0] : "core";
+                    classesForImports[depModule] = classesForImports[depModule] || [];
+                    if (classesForImports[depModule].indexOf(dep.name) === -1) {
+                        //babylon.imageProcessingPostProcess
+                        classesForImports[depModule].push(dep.name);
+                    }
+                });
+            });
+
+            Object.keys(classesForImports).forEach(modName => {
+                importsString += `import {${classesForImports[modName].join(',')}} from 'babylonjs/${modName}';
+`;
+            });
+        }
+
+        if (file.isNull()) {
+            cb(null, file);
+            return;
+        }
+
+        if (file.isStream()) {
+            //streams not supported, no need for now.
+            return;
+        }
+
+        try {
+            file.contents = new Buffer(String(file.contents) + '\n' + importsString);
+            this.push(file);
+
+        } catch (err) {
+            this.emit('error', new gutil.PluginError('gulp-add-module-exports', err, { fileName: file.path }));
+        }
+        cb();
+    });
+};
+

+ 214 - 0
Tools/Gulp/gulp-es6ModuleExports.js

@@ -0,0 +1,214 @@
+var gutil = require('gulp-util');
+var through = require('through2');
+var path = require('path');
+
+module.exports = function (moduleName, dependencyTree, generateIndex, perFile, shaders, shaderIncludes) {
+    return through.obj(function (file, enc, cb) {
+
+        let basename = (path.basename(file.path, ".js"));
+
+        //console.log("Compiling es6 module: " + moduleName + "/" + basename.replace("babylon.", ""));
+
+        var extendsAddition =
+            `var __extends=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,o){t.__proto__=o}||function(t,o){for(var n in o)o.hasOwnProperty(n)&&(t[n]=o[n])};return function(o,n){function r(){this.constructor=o}t(o,n),o.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();
+`;
+
+        var decorateAddition =
+            'var __decorate=this&&this.__decorate||function(e,t,r,c){var o,f=arguments.length,n=f<3?t:null===c?c=Object.getOwnPropertyDescriptor(t,r):c;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(e,t,r,c);else for(var l=e.length-1;l>=0;l--)(o=e[l])&&(n=(f<3?o(n):f>3?o(t,r,n):o(t,r))||n);return f>3&&n&&Object.defineProperty(t,r,n),n};\n';
+
+        let content = file.contents.toString();
+        if (content.indexOf('__extends') === -1 && !dependencyTree.length) {
+            extendsAddition = '';
+        }
+
+        if (content.indexOf('__decorate') === -1) {
+            decorateAddition = '';
+        }
+
+        let dependenciesText = `${extendsAddition}
+${decorateAddition}
+`;
+        //if (moduleName !== 'core') {
+        dependenciesText += `var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : this);
+            var BABYLON = globalObject["BABYLON"] || {};
+`;
+        /*} else {
+            dependenciesText += `var BABYLON;
+`;
+        }*/
+
+        let exportsText = '';
+        if (!generateIndex) {
+
+            // process parenting!
+            let parentRegex = /__extends\(([A-Z]\w*), _super\)/g;
+            var match = parentRegex.exec(content);
+            while (match != null) {
+                let extendingClass = match[1];
+                // find the first row
+                let extendedMatcher = new RegExp("}\\([BABYLON\\.]*([A-Z]\\w*)\\)\\);\\n\\s*BABYLON." + extendingClass + " = " + extendingClass + ";");
+
+                let extendedArray = extendedMatcher.exec(content);
+                if (extendedArray) {
+                    let firstRowReg = new RegExp("var " + extendingClass + " = .* \\(function");
+                    content = content.replace(firstRowReg, "var " + extendingClass + " = function");
+
+                    extended = extendedArray[1];
+                    content = content.replace(extendedMatcher, `};
+    var CLS${extendingClass};
+    BABYLON.__${extendingClass} = function() {
+        CLS${extendingClass} = CLS${extendingClass} || ${extendingClass}.call(null, BABYLON.__${extended} && BABYLON.__${extended}() || BABYLON.${extended});
+    }
+    Object.defineProperty(BABYLON, "${extendingClass}", {
+        get: function () {
+            BABYLON.__${extendingClass}();
+            return CLS${extendingClass};
+        },
+        enumerable: true,
+        configurable: true
+    });`);
+                    console.log(extendingClass, extended);
+                } else {
+                    console.log(extendingClass + " is not exported");
+                }
+
+                match = parentRegex.exec(content);
+            }
+
+            let loadedFiles = [];
+            dependencyTree[basename].forEach(function (d, idx) {
+                //if (d.module.indexOf("core") !== -1) return;
+                let name = d.file.split(".").pop();
+
+                if (loadedFiles.indexOf(name) === -1/* && !d.newDec*/) {
+                    let regexp = new RegExp("BABYLON." + d.name);
+                    let match = regexp.exec(content);
+                    if (!match) return;
+                    if (d.main)
+                        dependenciesText += `import {${d.name}} from 'babylonjs/${d.module[0]}/es6/${name}';
+`;
+                    else
+                        exportsText += `import {${d.name}} from 'babylonjs/${d.module[0]}/es6/${name}';
+`;
+                    loadedFiles.push(name);
+                }
+                //dependenciesText += `if(BABYLON !== BABYLON${idx}) __extends(BABYLON, BABYLON${idx});
+            });
+            let exported = [];
+            perFile[basename].declarations.forEach(dec => {
+                if (exported.indexOf(dec) !== -1) return;
+                exported.push(dec);
+                exportsText += `var ${dec} = BABYLON.${dec}; export {${dec}};
+`;
+            });
+            if (shaders) {
+                dependenciesText += `import * as Shaders from "babylonjs/${moduleName}/es6/shaders";
+if(BABYLON.Effect) Object.keys(Shaders).forEach(function(shaderName) {BABYLON.Effect.ShadersStore[shaderName] = Shaders[shaderName]})
+`;
+            }
+            if (shaderIncludes) {
+                dependenciesText += `import * as ShaderIncludes from "babylonjs/${moduleName}/es6/shaderIncludes";
+if(BABYLON.Effect) Object.keys(ShaderIncludes).forEach(function(shaderName) {BABYLON.Effect.IncludesShadersStore[shaderName] = ShaderIncludes[shaderName]})
+`;
+            }
+
+            //if (moduleName === "core") {
+            exportsText += `(function() {
+    //var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : this);
+    globalObject["BABYLON"] = globalObject["BABYLON"] || BABYLON;
+})();
+`;
+            //}
+        } else {
+            content = '';
+            let basenames = Object.keys(perFile).filter(basefilename => {
+                return perFile[basefilename].module.indexOf(moduleName) !== -1;
+            });
+
+            basenames.forEach(bname => {
+                let name = bname.split(".").pop();
+                dependenciesText += `export * from "babylonjs/${moduleName}/es6/${name}";
+`;
+            })
+        }
+
+
+
+        /*exportsText += `(function() {
+    globalObject["BABYLON"] = globalObject["BABYLON"] || BABYLON;
+    })();
+`;*/
+
+        /*if (dependencies) {
+            dependencies.forEach(function (d, idx) {
+                if (d === 'core') return;
+                dependenciesText += `import * as ${d} from 'babylonjs/${d}/es6';
+`;
+                //if (idx > 0) {
+                dependenciesText += `__extends(BABYLON, ${d});
+`;
+                //}
+            });
+        }
+ 
+ 
+ 
+        let exportRegex = /BABYLON.([0-9A-Za-z-_]*) = .*;\n/g
+ 
+        var match = exportRegex.exec(content);
+ 
+        let exportsArray = [];
+        while (match != null) {
+            if (match[1]) {
+                exportsArray.push(match[1])
+            }
+            match = exportRegex.exec(content);
+        }
+ 
+        let exportsText = '';
+        if (moduleName === "core") {
+            exportsText = `(function() {
+    var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : this);
+    globalObject["BABYLON"] = BABYLON;
+})();
+`
+        }
+ 
+        let exportedItems = '';
+        exportsArray.forEach((e, idx) => {
+            if (e.indexOf('.') === -1) {
+                exportedItems += `${idx ? ',' : ''}${e}`
+                exportsText += `var ${e} = BABYLON.${e};
+`
+            }
+        });
+ 
+        exportsText += `
+export { ${exportedItems} };`*/
+
+        /*if (moduleName === "core") {
+            exportsText = `(function() {
+var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : this);
+globalObject["BABYLON"] = BABYLON;
+})();
+`*/
+
+        if (file.isNull()) {
+            cb(null, file);
+            return;
+        }
+
+        if (file.isStream()) {
+            //streams not supported, no need for now.
+            return;
+        }
+
+        try {
+            file.contents = new Buffer(dependenciesText.concat(new Buffer(String(content).concat(exportsText))));
+            this.push(file);
+        } catch (err) {
+            this.emit('error', new gutil.PluginError('gulp-es6-module-exports', err, { fileName: file.path }));
+        }
+        cb();
+    });
+}

+ 725 - 0
Tools/Gulp/gulp-validateTypedoc.js

@@ -0,0 +1,725 @@
+'use strict';
+
+var fs = require('fs');
+var Vinyl = require('vinyl');
+var path = require('path');
+var through = require('through2');
+var PluginError = require('plugin-error');
+var supportsColor = require('color-support');
+
+// ______________________________________________ LOGS ______________________________________________
+
+var hasColors = supportsColor();
+
+var red =       hasColors ? '\x1b[31m' : '';
+var yellow =    hasColors ? '\x1b[33m' : '';
+var green =     hasColors ? '\x1b[32m' : '';
+var gray =      hasColors ? '\x1b[90m' : '';
+var white =     hasColors ? '\x1b[97m' : '';
+var clear =     hasColors ? '\x1b[0m' : '';
+
+var currentColor = undefined;
+
+function getTimestamp() {
+    var time = new Date();
+    var timeInString = ("0" + time.getHours()).slice(-2) + ":" + 
+        ("0" + time.getMinutes()).slice(-2) + ":" + 
+        ("0" + time.getSeconds()).slice(-2);
+
+    if (currentColor) {
+        return white + '[' + currentColor + timeInString + clear + white + ']';
+    }
+    else {
+        return white + '[' + gray + timeInString + white + ']';
+    }
+}
+
+function log() {
+    currentColor = gray;
+    var time = getTimestamp();
+    process.stdout.write(time + ' ');
+    currentColor = undefined;
+
+    console.log.apply(console, arguments);
+    return this;
+}
+
+function warn() {
+    currentColor = yellow;
+    var time = getTimestamp();
+    process.stdout.write(time + ' ');
+    currentColor = undefined;
+
+    console.warn.apply(console, arguments);
+    return this;
+}
+
+function err() {
+    currentColor = red;
+    var time = getTimestamp();
+    process.stderr.write(time + ' ');
+    currentColor = undefined;
+    
+    console.error.apply(console, arguments);
+    return this;
+}
+
+function success() {
+    currentColor = green;
+    var time = getTimestamp();
+    process.stdout.write(time + ' ');
+    currentColor = undefined;
+
+    console.log.apply(console, arguments);
+    return this;
+}
+
+// ______________________________________________ VALIDATION ____________________________________________
+
+function unixStylePath(filePath) {
+    return filePath.replace(/\\/g, '/');
+}
+
+function Validate(validationBaselineFileName, namespaceName, validateNamingConvention, generateBaseLine) {
+    this.validationBaselineFileName = validationBaselineFileName;
+    this.namespaceName = namespaceName;
+    this.validateNamingConvention = validateNamingConvention;
+    this.generateBaseLine = generateBaseLine;
+
+    this.previousResults = { };
+    this.results = {
+        errors: 0
+    };
+}
+
+Validate.hasTag = function(node, tagName) {
+    tagName = tagName.trim().toLowerCase();
+
+    if (node.comment && node.comment.tags) {
+        for (var i = 0; i < node.comment.tags.length; i++) {
+            if (node.comment.tags[i].tag === tagName) {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+Validate.position = function(node) {
+    if (!node.sources) {
+        log(node);
+    }
+    return node.sources[0].fileName + ':' + node.sources[0].line;
+}
+
+Validate.upperCase = new RegExp("^[A-Z_]*$");
+Validate.pascalCase = new RegExp("^[A-Z][a-zA-Z0-9_]*$");
+Validate.camelCase = new RegExp("^[a-z][a-zA-Z0-9_]*$");
+Validate.underscoreCamelCase = new RegExp("^_[a-z][a-zA-Z0-9_]*$");
+Validate.underscorePascalCase = new RegExp("^_[A-Z][a-zA-Z0-9_]*$");
+
+Validate.prototype.errorCallback = function (parent, node, nodeKind, category, type, msg, position) {
+    this.results[this.filePath] = this.results[this.filePath] || { errors: 0 };
+    var results = this.results[this.filePath];
+
+    if (node === "toString") {
+        node = "ToString";
+    }
+    
+    // Checks against previous results.
+    var previousResults = this.previousResults[this.filePath];
+    if (previousResults) {
+        var previousRootName = parent ? parent : node;
+        var needCheck = true; 
+
+        if (Array.isArray(previousRootName)) {
+            while (previousRootName.length > 1) {
+                var previousFirst = previousRootName.shift();
+                previousResults = previousResults[previousFirst];
+                if (!previousResults) {
+                    needCheck = false;
+                    break;
+                }
+            }
+            previousRootName = previousRootName.shift();
+        }
+
+        if (needCheck) {
+            var previousNode = previousResults[previousRootName];
+            if (previousNode) {
+                var previousNodeKind = previousNode[nodeKind];
+                if (previousNodeKind) {
+
+                    if (parent) {
+                        previousNode = previousNodeKind[node];
+                    }
+                    else {
+                        previousNode = previousNodeKind;
+                    }
+
+                    if (previousNode) {
+                        var previousCategory = previousNode[category];
+                        if (previousCategory) {
+                            var previousType = previousCategory[type];
+                            if (previousType) {
+                                // Early exit as it was already in the previous build.
+                                return;
+                            }    
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // Write Error in output JSON.
+    var rootName = parent ? parent : node;
+    var current = results;
+    if (Array.isArray(rootName)) {
+        while (rootName.length > 1) {
+            var first = rootName.shift();
+            current = current[first] = current[first] || { };
+        }
+        rootName = rootName.shift();
+    }
+
+    current = current[rootName] = current[rootName] || { };
+    current = current[nodeKind] = current[nodeKind] || { };    
+    if (parent) {
+        current = current[node] = current[node] || { };
+    }
+    current = current[category] = current[category] || { };
+    current = current[type] = true;
+    
+    results.errors++;
+
+    if (!this.generateBaseLine) {
+        err(msg, position);
+    }
+}
+
+Validate.prototype.init = function (cb) {
+    var self = this;
+    if (!this.generateBaseLine && fs.existsSync(this.validationBaselineFileName)) {
+        fs.readFile(this.validationBaselineFileName, "utf-8", function (err, data) {
+            self.previousResults = JSON.parse(data);
+            cb();
+        });
+    }
+    else {
+        cb();
+    }
+}
+
+Validate.prototype.add = function (filePath, content) {
+    this.filePath = filePath && unixStylePath(filePath);
+
+    if (!Buffer.isBuffer(content)) {
+        content = new Buffer(content);
+    }
+
+    var contentString = content.toString();
+    var json = JSON.parse(contentString);
+
+    this.validateTypedoc(json);
+    this.results.errors += this.results[this.filePath].errors;
+}
+
+Validate.prototype.getResults = function () {
+    return this.results;
+}
+
+Validate.prototype.getContents = function () {
+    return Buffer.from(JSON.stringify(this.results));
+}
+
+/**
+ * Validate a TypeDoc JSON file
+ */
+Validate.prototype.validateTypedoc = function (json) {
+    for (var i = 0; i < json.children.length; i++) {
+        var namespaces = json.children[i].children;
+        this.validateTypedocNamespaces(namespaces);
+    }
+}
+/**
+ * Validate namespaces attach to a declaration file from a TypeDoc JSON file
+ */
+Validate.prototype.validateTypedocNamespaces = function (namespaces) {
+    var namespace = null;
+
+    var containerNode;
+    var childNode;
+    var children;
+    var signatures;
+    var signatureNode;
+    var tags;
+    var isPublic;
+
+    // Check for BABYLON namespace
+    for (var child in namespaces) {
+        if (namespaces[child].name === this.namespaceName) {
+            namespace = namespaces[child];
+            break;
+        }
+    }
+
+    // Exit if not BABYLON related.
+    if (!namespace || !namespace.children) {
+        return;
+    }
+
+    // Validate Classes
+    for (var a in namespace.children) {
+        containerNode = namespace.children[a];
+
+        // If comment contains @ignore then skip validation completely
+        if (Validate.hasTag(containerNode, 'ignore')) continue;
+
+        // Account for undefined access modifiers.
+        if (!containerNode.flags.isPublic &&
+            !containerNode.flags.isPrivate &&
+            !containerNode.flags.isProtected) {
+                containerNode.flags.isPublic = true;
+        }
+        isPublic = containerNode.flags.isPublic;
+
+        // Validate naming.
+        this.validateNaming(null, containerNode);
+
+        // Validate Comments.
+        if (isPublic && !this.validateComment(containerNode)) {            
+            this.errorCallback(null,
+                containerNode.name,
+                containerNode.kindString,
+                "Comments",
+                "MissingText",
+                "Missing text for " + containerNode.kindString + " : " + containerNode.name + " (id: " + containerNode.id + ")", Validate.position(containerNode));
+        }
+
+        //if comment contains tag @ignoreChildren, then don't validate children
+        var validateChildren = !Validate.hasTag(containerNode, 'ignoreChildren');
+        children = containerNode.children;
+
+        //Validate Properties
+        if (validateChildren && children) {
+            for (var b in children) {
+                childNode = children[b];
+
+                // Account for undefined access modifiers.
+                if (!childNode.flags.isPublic &&
+                    !childNode.flags.isPrivate &&
+                    !childNode.flags.isProtected) {
+                    childNode.flags.isPublic = true;
+                }
+                isPublic = childNode.flags.isPublic;
+
+                // Validate Naming.
+                this.validateNaming(containerNode, childNode);
+
+                //if comment contains @ignore then skip validation completely
+                if (Validate.hasTag(childNode, 'ignore')) continue;                
+
+                if (isPublic) {
+                    tags = this.validateTags(childNode);
+                    if (tags) {
+                        this.errorCallback(containerNode.name,
+                            childNode.name,
+                            childNode.kindString,
+                            "Tags",
+                            tags,
+                            "Unrecognized tag " + tags + " at " + childNode.name + " (id: " + childNode.id + ") in " + containerNode.name + " (id: " + containerNode.id + ")", Validate.position(childNode));
+                    }
+                }
+
+                if (!this.validateComment(childNode)) {
+                    //Validate Signatures
+                    signatures = childNode.signatures;
+                    if (signatures) {
+                        for (var c in signatures) {
+                            signatureNode = signatures[c];
+
+                            //if node contains @ignore then skip validation completely
+                            if (Validate.hasTag(signatureNode, 'ignore')) continue;
+
+                            if (isPublic) {
+                                if (!this.validateComment(signatureNode)) {
+                                    this.errorCallback(containerNode.name,
+                                        signatureNode.name,
+                                        childNode.kindString,
+                                        "Comments",
+                                        "MissingText",
+                                        "Missing text for " + childNode.kindString + " : " + signatureNode.name + " (id: " + signatureNode.id + ") in " + containerNode.name + " (id: " + containerNode.id + ")", Validate.position(childNode));
+                                }
+
+                                tags = this.validateTags(signatureNode);
+                                if (tags) {
+                                    this.errorCallback(containerNode.name,
+                                        signatureNode.name,
+                                        childNode.kindString,
+                                        "Tags",
+                                        tags,
+                                        "Unrecognized tag " + tags + " at " + signatureNode.name + " (id: " + signatureNode.id + ") in " + containerNode.name + " (id: " + containerNode.id + ")", Validate.position(childNode));
+                                }
+
+                                if (signatureNode.type.name !== "void" && signatureNode.comment && !signatureNode.comment.returns) {
+                                    this.errorCallback(containerNode.name,
+                                        signatureNode.name,
+                                        childNode.kindString,
+                                        "Comments",
+                                        "MissingReturn",
+                                        "No Return Comment at " + signatureNode.name + " (id: " + signatureNode.id + ") in " + containerNode.name + " (id: " + containerNode.id + ")", Validate.position(childNode));
+                                }
+
+                                if (signatureNode.type.name === "void" && signatureNode.comment && signatureNode.comment.returns) {
+                                    this.errorCallback(containerNode.name,
+                                        signatureNode.name,
+                                        childNode.kindString,
+                                        "Comments",
+                                        "UselessReturn",
+                                        "No Return Comment Needed at " + signatureNode.name + " (id: " + signatureNode.id + ") in " + containerNode.name + " (id: " + containerNode.id + ")", Validate.position(childNode));
+                                }
+                            }
+
+                            this.validateParameters(containerNode, childNode, signatureNode, signatureNode.parameters, isPublic);
+                        }
+                    } else {
+                        this.errorCallback(containerNode.name,
+                            childNode.name,
+                            childNode.kindString,
+                            "Comments",
+                            "MissingText",
+                            "Missing text for " + childNode.kindString + " : " + childNode.name + " (id: " + childNode.id + ") in " + containerNode.name + " (id: " + containerNode.id + ")", Validate.position(childNode));
+                    }
+                }
+
+                // this.validateParameters(containerNode, childNode, childNode.parameters, isPublic);
+            }
+        }
+    }
+}
+
+/**
+ * Validate that tags are recognized
+ */
+Validate.prototype.validateTags = function(node) {
+    var tags;
+    var errorTags = [];
+
+    if (node.comment) {
+
+        tags = node.comment.tags;
+        if (tags) {
+            for (var i = 0; i < tags.length; i++) {
+                var tag = tags[i];
+                var validTags = ["constructor", "throw", "type", "deprecated", "example", "examples", "remark", "see", "remarks"]
+                if (validTags.indexOf(tag.tag) === -1) {
+                    errorTags.push(tag.tag);
+                }
+            }
+        }
+
+    }
+
+    return errorTags.join(",");
+}
+
+/**
+ * Validate that a JSON node has the correct TypeDoc comments
+ */
+Validate.prototype.validateComment = function(node) {
+
+    // Return-only methods are allowed to just have a @return tag
+    if ((node.kindString === "Call signature" || node.kindString === "Accessor") && !node.parameters && node.comment && node.comment.returns) {
+        return true;
+    }
+
+    // Return true for private properties (dont validate)
+    if ((node.kindString === "Property" || node.kindString === "Object literal") && (node.flags.isPrivate || node.flags.isProtected)) {
+        return true;
+    }
+
+    // Return true for inherited properties
+    if (node.inheritedFrom) {
+        return true;
+    }
+
+    // Return true for overwrited properties
+    if (node.overwrites) {
+        return true;
+    }
+    
+
+    if (node.comment) {
+
+        if (node.comment.text || node.comment.shortText) {
+            return true;
+        }
+
+        return false;
+    }
+
+    return false;
+}
+
+/**
+ * Validate comments for paramters on a node
+ */
+Validate.prototype.validateParameters = function(containerNode, method, signature, parameters, isPublic) {
+    var parametersNode;
+    for (var parameter in parameters) {
+        parametersNode = parameters[parameter];
+
+        if (isPublic && !this.validateComment(parametersNode)) {
+            // throw containerNode.name + " " + method.kindString + " " + method.name + " " + parametersNode.name + " " + parametersNode.kindString;
+            this.errorCallback([containerNode.name, method.kindString, signature.name],
+                parametersNode.name,
+                parametersNode.kindString,
+                "Comments",
+                "MissingText",
+                "Missing text for parameter " + parametersNode.name + " (id: " + parametersNode.id + ") of " + method.name + " (id: " + method.id + ")", Validate.position(method));
+        }
+
+        if (this.validateNamingConvention && !Validate.camelCase.test(parametersNode.name)) {
+            this.errorCallback([containerNode.name, method.kindString, signature.name],
+                parametersNode.name,
+                parametersNode.kindString,
+                "Naming",
+                "NotCamelCase",
+                "Parameter " + parametersNode.name + " should be Camel Case (id: " + method.id + ")", Validate.position(method));
+        }
+    }
+}
+
+/**
+ * Validate naming conventions of a node
+ */
+Validate.prototype.validateNaming = function(parent, node) {
+    if (!this.validateNamingConvention) {
+        return;
+    }
+
+    if (node.inheritedFrom) {
+        return;
+    }
+
+    // Internals are not subject to the public visibility policy.
+    if (node.name && node.name.length > 0 && node.name[0] === "_") {
+        return;
+    }
+
+    if ((node.flags.isPrivate || node.flags.isProtected) && node.flags.isStatic) {
+        if (!Validate.underscorePascalCase.test(node.name)) {
+            this.errorCallback(parent ? parent.name : null,
+                node.name,
+                node.kindString,
+                "Naming",
+                "NotUnderscorePascalCase",
+                node.name + " should be Underscore Pascal Case (id: " + node.id + ")", Validate.position(node));
+        }
+    }
+    else if (node.flags.isPrivate || node.flags.isProtected) {
+        if (!Validate.underscoreCamelCase.test(node.name)) {
+            this.errorCallback(parent ? parent.name : null,
+                node.name,
+                node.kindString,
+                "Naming",
+                "NotUnderscoreCamelCase",
+                node.name + " should be Underscore Camel Case (id: " + node.id + ")", Validate.position(node));
+        }
+    }
+    else if (node.flags.isStatic) {
+        if (!Validate.pascalCase.test(node.name)) {
+            this.errorCallback(parent ? parent.name : null,
+                node.name,
+                node.kindString,
+                "Naming",
+                "NotPascalCase",
+                node.name + " should be Pascal Case (id: " + node.id + ")", Validate.position(node));
+        }
+    }
+    else if (node.kindString == "Module") {
+        if (!Validate.upperCase.test(node.name)) {
+            this.errorCallback(parent ? parent.name : null,
+                node.name,
+                node.kindString,
+                "Naming",
+                "NotUpperCase",
+                "Module is not Upper Case " + node.name + " (id: " + node.id + ")", Validate.position(node));
+        }
+    }
+    else if (node.kindString == "Interface" ||
+        node.kindString == "Class" ||
+        node.kindString == "Enumeration" ||
+        node.kindString == "Enumeration member" ||
+        node.kindString == "Accessor" ||
+        node.kindString == "Type alias") {
+        if (!Validate.pascalCase.test(node.name)) {
+            this.errorCallback(parent ? parent.name : null,
+                node.name,
+                node.kindString,
+                "Naming",
+                "NotPascalCase",
+                node.name + " should be Pascal Case (id: " + node.id + ")", Validate.position(node));
+        }
+    }
+    else if (node.kindString == "Method" ||
+        node.kindString == "Property" ||
+        node.kindString == "Object literal") {
+
+        // Only warn here as special properties such as FOV may be better capitalized 
+        if (!Validate.camelCase.test(node.name)) {
+            this.errorCallback(parent ? parent.name : null,
+                node.name,
+                node.kindString,
+                "Naming",
+                "NotCamelCase",
+                node.name + " should be Camel Case (id: " + node.id + ")", Validate.position(node));
+        }
+    }
+    else if (node.kindString == "Variable") {
+        this.errorCallback(parent ? parent.name : null,
+            node.name,
+            node.kindString,
+            "Naming",
+            "ShouldNotBeLooseVariable",
+            node.name + " should not be a variable (id: " + node.id + ")", Validate.position(node));
+    }
+    else if (node.kindString === "Function") {
+        if (!Validate.camelCase.test(node.name)) {
+            this.errorCallback(parent ? parent.name : null,
+                node.name,
+                node.kindString,
+                "Naming",
+                "NotCamelCase",
+                node.name + " should be Camel Case (id: " + node.id + ")", Validate.position(node));
+        }
+    }
+    else if (node.kindString == "Constructor") {
+        // Do Nothing Here, this is handled through the class name.
+    }
+    else {
+        this.errorCallback(parent ? parent.name : null,
+            node.name,
+            node.kindString,
+            "Naming",
+            "UnknownNamingConvention",
+            "Unknown naming convention for " + node.kindString + " at " + node.name + " (id: " + node.id + ")", Validate.position(node));
+    }
+}
+
+// ______________________________________________ PLUGIN ____________________________________________
+
+// consts
+const PLUGIN_NAME = 'gulp-validateTypedoc';
+
+// plugin level function (dealing with files)
+function gulpValidateTypedoc(validationBaselineFileName, namespaceName, validateNamingConvention, generateBaseLine) {
+
+    if (!validationBaselineFileName) {
+        throw new PluginError(PLUGIN_NAME, 'Missing validation filename!');
+    }
+    if (typeof validationBaselineFileName !== "string") {
+        throw new PluginError(PLUGIN_NAME, 'Validation filename must be a string!');
+    }
+
+    var validate;
+    var latestFile;
+
+    function bufferContents(file, enc, cb) {
+        // ignore empty files
+        if (file.isNull()) {
+            cb();
+            return;
+        }
+
+        // we don't do streams (yet)
+        if (file.isStream()) {
+            this.emit('error', new Error('gulp-validatTypedoc: Streaming not supported'));
+            cb();
+            return;
+        }
+
+        // set latest file if not already set,
+        // or if the current file was modified more recently.
+        latestFile = file;
+
+        // What will happen once all set.
+        var done = function () {
+            // add file to concat instance
+            validate.add(file.relative, file.contents);
+
+            cb();
+        }
+
+        // Do the validation.
+        if (!validate) {
+            validate = new Validate(validationBaselineFileName, namespaceName, validateNamingConvention, generateBaseLine);
+            validate.init(done);
+        }
+        else {
+            done();
+        }
+    }
+
+    function endStream(cb) {
+        // no files passed in, no file goes out
+        if (!latestFile) {
+            var error = new PluginError(PLUGIN_NAME, 'gulp-validatTypedoc: No Baseline found.');
+            this.emit('error', error);
+            cb();
+            return;
+        }
+
+        var results = validate.getResults();
+        var buffer = Buffer.from(JSON.stringify(results, null, 2))
+
+        if (generateBaseLine) {
+            fs.writeFileSync(validationBaselineFileName, buffer || '');
+        }
+
+        var jsFile = new Vinyl({
+            cwd: process.cwd,
+            base: null,
+            path: validationBaselineFileName,
+            contents: buffer
+        });
+
+        this.push(jsFile);
+
+        var action = generateBaseLine ? "baseline generation" : "validation";
+        var self = this;
+        var error = function(message) {
+            generateBaseLine ? warn : err;
+            if (generateBaseLine) {
+                warn(message);
+            }
+            else {
+                err(message);
+                var error = new PluginError(PLUGIN_NAME, message);
+                self.emit('error', error);
+            }
+        }
+
+        if (results.errors > 1) {
+            var message = results.errors + " errors have been detected during the " + action + " !";
+            error(message);
+        }
+        else if (results.errors === 1) {
+            var message = "1 error has been detected during the " + action + " !";
+            error(message);
+        }
+        else {
+            var message = "All formatting check passed successfully during the " + action + " !";
+            success(message);
+        }
+
+        cb();
+    }
+
+    return through.obj(bufferContents, endStream);
+};
+
+// exporting the plugin main function
+module.exports = gulpValidateTypedoc;

+ 525 - 41
Tools/Gulp/gulpfile.js

@@ -6,6 +6,11 @@ var srcToVariable = require("gulp-content-to-variable");
 var appendSrcToVariable = require("./gulp-appendSrcToVariable");
 var addDtsExport = require("./gulp-addDtsExport");
 var addModuleExports = require("./gulp-addModuleExports");
+var addES6Exports = require("./gulp-addES6Exports");
+var babylonModuleExports = require("./gulp-babylonModule");
+var babylonES6ModuleExports = require("./gulp-es6ModuleExports");
+var dtsModuleSupport = require("./gulp-dtsModuleSupport");
+let calculateDependencies = require("./gulp-calculateDependencies");
 var merge2 = require("merge2");
 var concat = require("gulp-concat");
 var rename = require("gulp-rename");
@@ -20,6 +25,11 @@ var webserver = require("gulp-webserver");
 var path = require("path");
 var sass = require("gulp-sass");
 var webpack = require("webpack-stream");
+var typedoc = require("gulp-typedoc");
+var validateTypedoc = require("./gulp-validateTypedoc");
+var request = require('request');
+var fs = require("fs");
+var karmaServer = require('karma').Server;
 
 var config = require("./config.json");
 
@@ -50,7 +60,12 @@ var tsConfig = {
     noUnusedLocals: true,
     strictNullChecks: true,
     strictFunctionTypes: true,
-    types: []
+    types: [],
+    lib: [
+        "dom",
+        "es2015.promise",
+        "es5"
+    ]
 };
 var tsProject = typescript.createProject(tsConfig);
 
@@ -66,7 +81,12 @@ var externalTsConfig = {
     noImplicitThis: true,
     noUnusedLocals: true,
     strictNullChecks: true,
-    types: []
+    types: [],
+    lib: [
+        "dom",
+        "es2015.promise",
+        "es5"
+    ]
 };
 
 var minimist = require("minimist");
@@ -74,8 +94,8 @@ var commandLineOptions = minimist(process.argv.slice(2), {
     boolean: "public"
 });
 
-function processDependency(kind, dependency, filesToLoad) {
-    if (dependency.dependUpon) {
+function processDependency(kind, dependency, filesToLoad, firstLevelOnly) {
+    if (!firstLevelOnly && dependency.dependUpon) {
         for (var i = 0; i < dependency.dependUpon.length; i++) {
             var dependencyName = dependency.dependUpon[i];
             var parent = config.workloads[dependencyName];
@@ -204,50 +224,50 @@ gulp.task("buildWorker", ["workers", "shaders"], function () {
 gulp.task("build", ["shaders"], function () {
     var filesToProcess = determineFilesToProcess("files");
     var directFilesToProcess = determineFilesToProcess("directFiles");
-    return merge2(
+    let mergedStreams = merge2(
         gulp.src(filesToProcess).
             pipe(expect.real({ errorOnFailure: true }, filesToProcess)),
         shadersStream,
         includeShadersStream,
         gulp.src(directFilesToProcess)
     )
-        .pipe(concat(config.build.filename))
-        .pipe(cleants())
-        .pipe(replace(extendsSearchRegex, ""))
-        .pipe(replace(decorateSearchRegex, ""))
-        .pipe(addModuleExports("BABYLON"))
-        .pipe(gulp.dest(config.build.outputDirectory))
-        .pipe(rename(config.build.minFilename))
-        .pipe(uglify())
-        .pipe(optimisejs())
-        .pipe(gulp.dest(config.build.outputDirectory));
+    return merge2(
+        mergedStreams
+            .pipe(concat(config.build.filename))
+            .pipe(cleants())
+            .pipe(replace(extendsSearchRegex, ""))
+            .pipe(replace(decorateSearchRegex, ""))
+            .pipe(addModuleExports("BABYLON"))
+            .pipe(gulp.dest(config.build.outputDirectory))
+            .pipe(rename(config.build.minFilename))
+            .pipe(uglify())
+            .pipe(optimisejs())
+            .pipe(gulp.dest(config.build.outputDirectory)),
+        mergedStreams
+            .pipe(concat("es6.js"))
+            .pipe(cleants())
+            .pipe(replace(extendsSearchRegex, ""))
+            .pipe(replace(decorateSearchRegex, ""))
+            .pipe(addES6Exports("BABYLON"))
+            .pipe(gulp.dest(config.build.outputDirectory))
+    );
 });
 
 /*
 * Compiles all typescript files and creating a js and a declaration file.
 */
-var alreadyCompiled = false;
-var forceCompile = false;
 gulp.task("typescript-compile", function () {
-    if (!forceCompile && alreadyCompiled) {
-        return;
-    }
-    alreadyCompiled = true;
-
     var tsResult = gulp.src(config.typescript)
         .pipe(sourcemaps.init())
         .pipe(tsProject());
 
     //If this gulp task is running on travis, file the build!
     if (process.env.TRAVIS) {
-        var error = false;
-        tsResult.on("error", function () {
-            error = true;
-        }).on("end", function () {
-            if (error) {
+        tsResult.once("error", function () {
+            tsResult.once("finish", function () {
                 console.log("Typescript compile failed");
                 process.exit(1);
-            }
+            });
         });
     }
 
@@ -305,7 +325,9 @@ var buildExternalLibraries = function (settings) {
             let dtsFiles = files.map(function (filename) {
                 return filename.replace(".js", ".d.ts");
             });
-
+            if (settings.build.extraDeclarations) {
+                settings.build.extraDeclarations.forEach(file => { dtsFiles.unshift(file) })
+            }
             let dtsTask = gulp.src(dtsFiles)
                 .pipe(concat(settings.build.outputFilename + ".module.d.ts"))
                 .pipe(replace(referenceSearchRegex, ""))
@@ -385,6 +407,8 @@ var buildExternalLibrary = function (library, settings, watch) {
             .pipe(gulp.dest(outputDirectory));
         /*}*/
 
+
+
         var dts = tsProcess.dts
             .pipe(concat(library.output))
             .pipe(replace(referenceSearchRegex, ""))
@@ -406,14 +430,60 @@ var buildExternalLibrary = function (library, settings, watch) {
         }
 
         if (library.webpack) {
-            return waitAll.on("end", function () {
-                return webpack(require(library.webpack))
-                    .pipe(rename(library.output.replace(".js", library.noBundleInName ? '.js' : ".bundle.js")))
-                    .pipe(addModuleExports(library.moduleDeclaration, false, false, true))
-                    .pipe(uglify())
-                    .pipe(optimisejs())
-                    .pipe(gulp.dest(outputDirectory))
-            });
+            let sequence = [waitAll];
+            let wpBuild = webpack(require(library.webpack));
+            if (settings.build.outputs) {
+                let build = wpBuild
+                    .pipe(addModuleExports(library.moduleDeclaration, false, false, true));
+
+                let unminifiedOutpus = [];
+                let minifiedOutputs = [];
+                settings.build.outputs.forEach(out => {
+                    if (out.minified) {
+                        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);
+                });
+
+                sequence.push(build);
+            } else {
+                sequence.push(
+                    wpBuild
+                        .pipe(rename(library.output.replace(".js", library.noBundleInName ? '.js' : ".bundle.js")))
+                        .pipe(addModuleExports(library.moduleDeclaration, false, false, true))
+                        .pipe(uglify())
+                        .pipe(optimisejs())
+                        .pipe(gulp.dest(outputDirectory))
+                )
+            }
+
+            return merge2(sequence);
         }
         else {
             return waitAll;
@@ -425,7 +495,7 @@ var buildExternalLibrary = function (library, settings, watch) {
  * The default task, concat and min the main BJS files.
  */
 gulp.task("default", function (cb) {
-    runSequence("typescript-all", "intellisense", cb);
+    runSequence("typescript-all", "intellisense", "typedoc-all", "tests-unit", "tests-validation-virtualscreen", "tests-validation-browserstack", cb);
 });
 
 gulp.task("mainBuild", function (cb) {
@@ -481,12 +551,23 @@ gulp.task("typescript-all", function (cb) {
 });
 
 /**
+ * Watch ts files from typescript .
+ */
+gulp.task("srcTscWatch", function () {
+    // Reuse The TSC CLI from gulp to enable -w.
+    process.argv[2] = "-w";
+    process.argv[3] = "-p";
+    process.argv[4] = "../../src/tsconfig.json";
+    require("./node_modules/typescript/lib/tsc.js");
+});
+
+/**
  * Watch ts files and fire repective tasks.
  */
-gulp.task("watch", [], function () {
-    forceCompile = true;
+gulp.task("watch", ["srcTscWatch"], function () {
     var interval = 1000;
-    var tasks = [gulp.watch(config.typescript, { interval: interval }, ["typescript-compile"])];
+
+    var tasks = [];
 
     config.modules.map(function (module) {
         config[module].libraries.map(function (library) {
@@ -553,8 +634,411 @@ gulp.task("webserver", function () {
 gulp.task("run", ["watch", "webserver"], function () {
 });
 
+/**
+ * Cleans map and js files from the src folder.
+ */
 gulp.task("clean-JS-MAP", function () {
     return del([
         "../../src/**/*.js.map", "../../src/**/*.js"
     ], { force: true });
 });
+
+// this is needed for the modules for the declaration files.
+gulp.task("modules-compile", function () {
+    var tsResult = gulp.src(config.typescript)
+        .pipe(sourcemaps.init())
+        .pipe(tsProject());
+
+    // If this gulp task is running on travis
+    if (process.env.TRAVIS) {
+        tsResult.once("error", function () {
+            tsResult.once("finish", function () {
+                console.log("Typescript compile failed");
+                process.exit(1);
+            });
+        });
+    }
+
+    return merge2([
+        tsResult.dts
+            .pipe(gulp.dest(config.build.srcOutputDirectory)),
+        tsResult.js
+            .pipe(sourcemaps.write("./",
+                {
+                    includeContent: false,
+                    sourceRoot: (filePath) => {
+                        return "";
+                    }
+                }))
+            .pipe(gulp.dest(config.build.srcOutputDirectory))
+    ]);
+});
+
+// this holds the declared objects in each module
+let declared = {}
+let perFile = {};
+let dependencyTree = {};
+
+gulp.task('prepare-for-modules', /*["modules-compile"],*/ function () {
+    let tasks = [];
+    Object.keys(config.workloads).forEach((moduleName) => {
+        let dtsFiles = config.workloads[moduleName].files.map(f => f.replace(".js", ".d.ts"))
+        let dtsTask = gulp.src(dtsFiles)
+            .pipe(dtsModuleSupport(moduleName, false, declared, perFile));
+
+        tasks.push(dtsTask);
+    });
+
+    // now calculate internal dependencies in the .ts files!
+    /*Object.keys(config.workloads).forEach((moduleName) => {
+        let tsFiles = config.workloads[moduleName].files.map(f => f.replace(".js", ".ts"))
+        let depTask = gulp.src(tsFiles)
+            .pipe(calculateDependencies(moduleName, perFile, dependencyTree));
+
+        tasks.push(depTask);
+    });*/
+
+    return merge2(tasks);
+});
+
+gulp.task('prepare-dependency-tree', ["prepare-for-modules"], function () {
+    let tasks = [];
+
+    // now calculate internal dependencies in the .ts files!
+    Object.keys(config.workloads).forEach((moduleName) => {
+        let tsFiles = config.workloads[moduleName].files.map(f => f.replace(".js", ".ts"))
+        let depTask = gulp.src(tsFiles)
+            .pipe(calculateDependencies(moduleName, perFile, declared, dependencyTree));
+
+        tasks.push(depTask);
+    });
+
+    return merge2(tasks);
+});
+
+// generate the modules directory, along with commonjs modules and es6 modules
+// Note - the generated modules are UNMINIFIED! The user will choose whether they want to minify or not.
+gulp.task("modules", ["prepare-dependency-tree"], function () {
+    let tasks = [];
+
+    Object.keys(config.workloads)
+        .forEach((moduleName) => {
+            let shadersFiles = [];
+            processDependency("shaders", config.workloads[moduleName], shadersFiles, true);
+            for (var index = 0; index < shadersFiles.length; index++) {
+                shadersFiles[index] = "../../src/Shaders/" + shadersFiles[index] + ".fx";
+            }
+
+            let shaderIncludeFiles = [];
+            processDependency("shaderIncludes", config.workloads[moduleName], shaderIncludeFiles, true);
+            for (var index = 0; index < shaderIncludeFiles.length; index++) {
+                shaderIncludeFiles[index] = "../../src/Shaders/ShadersInclude/" + shaderIncludeFiles[index] + ".fx";
+            }
+
+            let commonJsTask = merge2([
+                gulp.src(config.workloads[moduleName].files)
+                    .pipe(replace(extendsSearchRegex, ""))
+                    .pipe(replace(decorateSearchRegex, ""))
+                    .pipe(replace(referenceSearchRegex, ""))
+                    .pipe(replace(/var BABYLON;\n/g, ""))
+                    .pipe(babylonModuleExports(moduleName, dependencyTree, false, perFile, shadersFiles.length, shaderIncludeFiles.length))
+                    .pipe(rename(function (path) {
+                        path.basename = path.basename.split(".").pop()
+                        path.extname = ".js"
+                    })),
+                gulp.src(shadersFiles)
+                    .pipe(expect.real({ errorOnFailure: true }, shadersFiles))
+                    .pipe(uncommentShader())
+                    .pipe(appendSrcToVariable("BABYLON.Effect.ShadersStore", shadersName, config.build.outputDirectory + '/commonjs/' + moduleName + ".fx", "commonjs"))
+                    .pipe(rename("shaders.js")),
+                gulp.src(shaderIncludeFiles)
+                    .pipe(expect.real({ errorOnFailure: true }, shaderIncludeFiles))
+                    .pipe(uncommentShader())
+                    .pipe(appendSrcToVariable("BABYLON.Effect.IncludesShadersStore", includeShadersName, config.build.outputDirectory + '/commonjs/' + moduleName + ".include.fx", "commonjs"))
+                    .pipe(rename("shaderIncludes.js")),
+                gulp.src(config.workloads[moduleName].files)
+                    .pipe(concat('index.js'))
+                    .pipe(babylonModuleExports(moduleName, dependencyTree, true, perFile))
+
+            ]).pipe(gulp.dest(config.build.outputDirectory + '/modules/' + moduleName + '/'))
+
+            let es6Tasks = merge2([
+                gulp.src(config.workloads[moduleName].files)
+                    .pipe(replace(extendsSearchRegex, ""))
+                    .pipe(replace(decorateSearchRegex, ""))
+                    .pipe(replace(referenceSearchRegex, ""))
+                    .pipe(replace(/var BABYLON;\n/g, ""))
+                    .pipe(babylonES6ModuleExports(moduleName, dependencyTree, false, perFile, shadersFiles.length, shaderIncludeFiles.length))
+                    .pipe(rename(function (path) {
+                        path.basename = path.basename.split(".").pop()
+                        path.extname = ".js"
+                    })),
+                gulp.src(shadersFiles)
+                    .pipe(expect.real({ errorOnFailure: true }, shadersFiles))
+                    .pipe(uncommentShader())
+                    .pipe(appendSrcToVariable("BABYLON.Effect.ShadersStore", shadersName, config.build.outputDirectory + '/es6/' + moduleName + ".fx", "es6"))
+                    .pipe(rename("shaders.js")),
+                gulp.src(shaderIncludeFiles)
+                    .pipe(expect.real({ errorOnFailure: true }, shaderIncludeFiles))
+                    .pipe(uncommentShader())
+                    .pipe(appendSrcToVariable("BABYLON.Effect.IncludesShadersStore", includeShadersName, config.build.outputDirectory + '/es6/' + moduleName + ".include.fx", "es6"))
+                    .pipe(rename("shaderIncludes.js")),
+                gulp.src(config.workloads[moduleName].files)
+                    .pipe(concat('index.js'))
+                    .pipe(babylonES6ModuleExports(moduleName, dependencyTree, true, perFile))
+
+            ]).pipe(gulp.dest(config.build.outputDirectory + '/modules/' + moduleName + '/es6/'))
+
+            //commonjs js generation task
+            /*let jsTask = merge2([
+                gulp.src(config.workloads[moduleName].files),
+                gulp.src(shadersFiles).
+                    //pipe(expect.real({ errorOnFailure: true }, shadersFiles)).
+                    pipe(uncommentShader()).
+                    pipe(appendSrcToVariable("BABYLON.Effect.ShadersStore", shadersName, config.build.outputDirectory + '/commonjs/' + moduleName + ".fx", true)),
+                gulp.src(shaderIncludeFiles).
+                    //pipe(expect.real({ errorOnFailure: true }, shaderIncludeFiles)).
+                    pipe(uncommentShader()).
+                    pipe(appendSrcToVariable("BABYLON.Effect.IncludesShadersStore", includeShadersName, config.build.outputDirectory + '/commonjs/' + moduleName + ".include.fx", true))
+            ]).pipe(concat('index.js'))
+                .pipe(replace(extendsSearchRegex, ""))
+                .pipe(replace(decorateSearchRegex, ""))
+                .pipe(replace(referenceSearchRegex, ""))
+                .pipe(babylonModuleExports(moduleName, config.workloads[moduleName].dependUpon))
+                .pipe(gulp.dest(config.build.outputDirectory + '/modules/' + moduleName + '/'));*/
+
+
+            // es6 modules generation task
+            /*let es6Task = merge2([
+                gulp.src(config.workloads[moduleName].files),
+                gulp.src(shadersFiles).
+                    //pipe(expect.real({ errorOnFailure: true }, shadersFiles)).
+                    pipe(uncommentShader()).
+                    pipe(appendSrcToVariable("BABYLON.Effect.ShadersStore", shadersName, config.build.outputDirectory + '/commonjs/' + moduleName + ".fx", true)),
+                gulp.src(shaderIncludeFiles).
+                    //pipe(expect.real({ errorOnFailure: true }, shaderIncludeFiles)).
+                    pipe(uncommentShader()).
+                    pipe(appendSrcToVariable("BABYLON.Effect.IncludesShadersStore", includeShadersName, config.build.outputDirectory + '/commonjs/' + moduleName + ".include.fx", true))
+            ]).pipe(concat('es6.js'))
+                .pipe(replace(extendsSearchRegex, ""))
+                .pipe(replace(decorateSearchRegex, ""))
+                .pipe(replace(referenceSearchRegex, ""))
+                .pipe(replace(/var BABYLON;/g, ""))
+                .pipe(babylonES6ModuleExports(moduleName, config.workloads[moduleName].dependUpon))
+                .pipe(gulp.dest(config.build.outputDirectory + '/modules/' + moduleName + '/'));
+
+            // dts genration task
+            let dtsFiles = config.workloads[moduleName].files.map(f => f.replace(".js", ".d.ts"))
+            let dtsTask = gulp.src(dtsFiles)
+                .pipe(concat("index.d.ts"))
+                .pipe(replace(/declare module BABYLON {/g, `declare module 'babylonjs/${moduleName}' {`))
+                .pipe(replace(/\ninterface /g, `\nexport interface `))
+                .pipe(dtsModuleSupport(moduleName, true, declared, perFile, dependencyTree))
+                .pipe(gulp.dest(config.build.outputDirectory + '/modules/' + moduleName + '/'));
+*/
+            tasks.push(commonJsTask, es6Tasks);
+        });
+
+    // run da tasks man!
+    return merge2(tasks);
+})
+
+/**
+ * Generate the TypeDoc JSON output in order to create code metadata.
+ */
+gulp.task("typedoc-generate", function () {
+    return gulp
+        .src(["../../dist/preview release/babylon.d.ts"])
+        .pipe(typedoc({
+            // TypeScript options (see typescript docs)
+            mode: "modules",
+            module: "commonjs",
+            target: "es5",
+            includeDeclarations: true,
+
+            // Output options (see typedoc docs)
+            json: config.build.typedocJSON,
+
+            // TypeDoc options (see typedoc docs)
+            ignoreCompilerErrors: true,
+
+            readme: "none",
+
+            excludeExternals: true,
+            excludePrivate: true,
+            excludeProtected: true,
+
+            entryPoint: ["\"babylon.d\"", "BABYLON"]
+        }));
+});
+
+/**
+ * Validate the TypeDoc JSON output against the current baselin to ensure our code is correctly documented.
+ * (in the newly introduced areas)
+ */
+gulp.task("typedoc-validate", function () {
+    return gulp.src(config.build.typedocJSON)
+        .pipe(validateTypedoc(config.build.typedocValidationBaseline, "BABYLON", true, false));
+});
+
+/**
+ * Generate the validation reference to ensure our code is correctly documented.
+ */
+gulp.task("typedoc-generateValidationBaseline", function () {
+    return gulp.src(config.build.typedocJSON)
+        .pipe(validateTypedoc(config.build.typedocValidationBaseline, "BABYLON", true, true));
+});
+
+/**
+ * Validate the code comments and style case convention through typedoc and
+ * generate the new baseline.
+ */
+gulp.task("typedoc-all", function (cb) {
+    runSequence("typedoc-generate", "typedoc-validate", "typedoc-generateValidationBaseline", cb);
+});
+
+
+/**
+ * Validate compile the code and check the comments and style case convention through typedoc
+ */
+gulp.task("typedoc-check", function (cb) {
+    runSequence("typescript-compile", "typedoc-generate", "typedoc-validate", cb);
+});
+
+/**
+ * Launches the KARMA validation tests in chrome in order to debug them.
+ * (Can only be launch locally.)
+ */
+gulp.task("tests-validation-karma", function (done) {
+    var kamaServerOptions = {
+        configFile: __dirname + "/../../tests/validation/karma.conf.js",
+        singleRun: false
+    };
+
+    var server = new karmaServer(kamaServerOptions, done);
+    server.start();
+});
+
+/**
+ * Launches the KARMA validation tests in ff or virtual screen ff on travis for a quick analysis during the build.
+ * (Can only be launch on any branches.)
+ */
+gulp.task("tests-validation-virtualscreen", function (done) {
+    var kamaServerOptions = {
+        configFile: __dirname + "/../../tests/validation/karma.conf.js",
+        singleRun: true,
+        browsers: ['Firefox']
+    };
+
+    var server = new karmaServer(kamaServerOptions, done);
+    server.start();
+});
+
+/**
+ * Launches the KARMA validation tests in browser stack for remote and cross devices validation tests.
+ * (Can only be launch from secure branches.)
+ */
+gulp.task("tests-validation-browserstack", function (done) {
+    if (!process.env.BROWSER_STACK_USERNAME) {
+        done();
+        return;
+    }
+
+    var kamaServerOptions = {
+        configFile: __dirname + "/../../tests/validation/karma.conf.browserstack.js",
+        singleRun: true
+    };
+
+    var server = new karmaServer(kamaServerOptions, done);
+    server.start();
+});
+
+/**
+ * Transpiles typescript unit tests. 
+ */
+gulp.task("tests-unit-transpile", function (done) {
+    var tsProject = typescript.createProject('../../tests/unit/tsconfig.json');
+
+    var tsResult = gulp.src("../../tests/unit/**/*.ts", { base: "../../" })
+        .pipe(tsProject());
+
+    tsResult.once("error", function () {
+        tsResult.once("finish", function () {
+            console.log("Typescript compile failed");
+            process.exit(1);
+        });
+    });
+
+    return tsResult.js.pipe(gulp.dest("../../"));
+});
+
+/**
+ * Launches the KARMA unit tests in phantomJS.
+ * (Can only be launch on any branches.)
+ */
+gulp.task("tests-unit-debug", ["tests-unit-transpile"], function (done) {
+    var kamaServerOptions = {
+        configFile: __dirname + "/../../tests/unit/karma.conf.js",
+        singleRun: false,
+        browsers: ['Chrome']
+    };
+
+    var server = new karmaServer(kamaServerOptions, done);
+    server.start();
+});
+
+/**
+ * Launches the KARMA unit tests in phantomJS.
+ * (Can only be launch on any branches.)
+ */
+gulp.task("tests-unit", ["tests-unit-transpile"], function (done) {
+    var kamaServerOptions = {
+        configFile: __dirname + "/../../tests/unit/karma.conf.js",
+        singleRun: true
+    };
+
+    var server = new karmaServer(kamaServerOptions, done);
+    server.start();
+});
+
+gulp.task("tests-whatsnew", function (done) {
+    // Only checks on Travis
+    if (!process.env.TRAVIS) {
+        done();
+        return;
+    }
+
+    // Only checks on Pull Requests
+    if (process.env.TRAVIS_PULL_REQUEST == "false") {
+        done();
+        return;
+    }
+
+    // Do not check deploy
+    if (process.env.TRAVIS_BRANCH == "preview") {
+        done();
+        return;
+    }
+
+    // Compare what's new with the current one in the preview release folder.
+    const https = require("https");
+    const url = "https://rawgit.com/BabylonJS/Babylon.js/master/dist/preview%20release/what's%20new.md";
+    https.get(url, res => {
+        res.setEncoding("utf8");
+        let oldData = "";
+        res.on("data", data => {
+            oldData += data;
+        });
+        res.on("end", () => {
+            fs.readFile("../../dist/preview release/what's new.md", "utf-8", function (err, newData) {
+                if (err || oldData != newData) {
+                    done();
+                    return;
+                }
+
+                console.error("What's new file did not change.");
+                process.exit(1);
+            });
+        });
+    });
+});

+ 21 - 6
Tools/Gulp/package.json

@@ -1,6 +1,6 @@
 {
     "name": "BabylonJS",
-    "version": "3.0.0",
+    "version": "3.1.1",
     "description": "Babylon.js is a 3D engine based on webgl and javascript",
     "main": "",
     "repository": {
@@ -9,8 +9,10 @@
     "readme": "https://github.com/BabylonJS/Babylon.js/edit/master/readme.md",
     "license": "(Apache-2.0)",
     "devDependencies": {
-        "@types/node": "^8.0.53",
-        "base64-image-loader": "^1.2.0",
+        "@types/node": "^8.5.0",
+        "base64-image-loader": "^1.2.1",
+        "chai": "^4.1.2",
+        "color-support": "^1.1.3",
         "css-loader": "^0.25.0",
         "deepmerge": "^2.0.1",
         "del": "2.2.2",
@@ -28,6 +30,7 @@
         "gulp-replace": "~0.5.3",
         "gulp-sass": "3.1.0",
         "gulp-sourcemaps": "~1.9.1",
+        "gulp-typedoc": "^2.1.2",
         "gulp-typescript": "^3.2.3",
         "gulp-uglify": "^2.1.2",
         "gulp-util": "~3.0.4",
@@ -36,16 +39,28 @@
         "html-loader": "^0.5.1",
         "imports-loader": "^0.7.1",
         "json-loader": "^0.5.7",
+        "karma": "^2.0.0",
+        "karma-browserstack-launcher": "^1.3.0",
+        "karma-chai": "^0.1.0",
+        "karma-chrome-launcher": "^2.2.0",
+        "karma-firefox-launcher": "^1.1.0",
+        "karma-mocha": "^1.3.0",
+        "karma-phantomjs-launcher": "^1.0.4",
+        "karma-sinon": "^1.0.5",
         "merge2": "~0.3.5",
         "minimist": "^1.2.0",
+        "mocha": "^4.0.1",
+        "phantomjs": "^2.1.7",
         "run-sequence": "~1.1.0",
+        "sinon": "^4.1.3",
         "style-loader": "^0.13.2",
         "through2": "~0.6.5",
         "ts-loader": "^2.3.7",
-        "typescript": "~2.6.1",
+        "typedoc": "^0.9.0",
+        "typescript": "~2.6.2",
         "webpack-stream": "^4.0.0"
     },
     "scripts": {
-        "install": "npm --prefix ../../Playground/ install ../../Playground/ && gulp typescript-compile && gulp typescript-libraries && gulp deployLocalDev"
+        "install": "npm --prefix ../../Playground/ install ../../Playground/ && npm --prefix ../../tests/unit/ install ../../tests/unit/ && gulp deployLocalDev"
     }
-}
+}

+ 134 - 10
Tools/Publisher/index.js

@@ -1,11 +1,11 @@
 let prompt = require('prompt');
 let shelljs = require('shelljs');
-let fs = require('fs');
+let fs = require('fs-extra');
 
 let basePath = '../../dist/preview release';
 
 // This can be changed when we have a new major release.
-let minimumDependency = '>=3.1.0-alpha';
+let minimumDependency = '>=3.2.0-alpha';
 
 let packages = [
     {
@@ -46,15 +46,28 @@ let packages = [
     }
 ];
 
-//check if logged in
-let loginCheck = shelljs.exec('npm whoami');
+function updateEngineVersion(newVersion) {
+    console.log("updating version in babylon.engine.ts");
+    let engineContent = fs.readFileSync("../../src/Engine/babylon.engine.ts").toString();
+    let replaced = engineContent.replace(/(public static get Version\(\): string {\s*return ")(.*)(";\s*})/g, "$1" + newVersion + "$3");
+    fs.writeFileSync("../../src/Engine/babylon.engine.ts", replaced);
+}
 
-if (loginCheck.code === 0) {
-    prompt.start();
+function runGulp() {
+    // run gulp typescript-all
+    console.log("Running gulp compilation");
+    let exec = shelljs.exec("gulp typescript-all --gulpfile ../Gulp/gulpfile.js");
+    if (exec.code) {
+        console.log("error during compilation, aborting");
+        process.exit(1);
+    }
+}
 
-    prompt.get(['version'], function (err, result) {
-        let version = result.version;
-        packages.forEach((package) => {
+function processPackages(version) {
+    packages.forEach((package) => {
+        if (package.name === "core") {
+            processCore(package, version);
+        } else {
             let packageJson = require(package.path + 'package.json');
             packageJson.version = version;
             if (packageJson.peerDependencies) packageJson.peerDependencies.babylonjs = minimumDependency;
@@ -62,9 +75,120 @@ if (loginCheck.code === 0) {
             console.log('Publishing ' + package.name + " from " + package.path);
             //publish the respected package
             shelljs.exec('npm publish \"' + package.path + "\"");
-        });
+        }
+
+    });
+}
+
+//check if logged in
+console.log("Using npm user:");
+let loginCheck = shelljs.exec('npm whoami');
+if (loginCheck.code === 0) {
+    prompt.start();
+
+    prompt.get(['version'], function (err, result) {
+        let version = result.version;
+        updateEngineVersion(version);
+        runGulp();
+        processPackages(version);
+
+        console.log("done, please tag git with " + version);
     });
 } else {
     console.log('not logged in.');
 }
 
+function processCore(package, version) {
+    let packageJson = require(package.path + 'package.json');
+
+    // make a temporary directory
+    fs.ensureDirSync(basePath + '/package/');
+
+    let files = [
+        {
+            path: basePath + "/babylon.d.ts",
+            objectName: "babylon.d.ts"
+        },
+        {
+            path: basePath + "/es6.js",
+            objectName: "es6.js"
+        },
+        {
+            path: basePath + "/babylon.js",
+            objectName: "babylon.js"
+        },
+        {
+            path: basePath + "/babylon.max.js",
+            objectName: "babylon.max.js"
+        },
+        {
+            path: basePath + "/babylon.worker.js",
+            objectName: "babylon.worker.js"
+        },
+        {
+            path: basePath + "/Oimo.js",
+            objectName: "Oimo.js"
+        },
+        {
+            path: package.path + "readme.md",
+            objectName: "readme.md"
+        }
+    ];
+
+    // remove the modules for now
+    /*fs.readdirSync(basePath + '/modules/').forEach(object => {
+        console.log(object);
+        if (fs.statSync(basePath + '/modules/' + object).isDirectory) {
+            files.push({
+                path: basePath + '/modules/' + object,
+                objectName: object,
+                isDir: true
+            });
+        }
+    })*/
+
+    //copy them to the package path
+    files.forEach(file => {
+        fs.copySync(file.path, basePath + '/package/' + file.objectName);
+    });
+
+    // update package.json
+    packageJson.version = version;
+    console.log("generating file list");
+    let packageFiles = ["package.json"];
+    files.forEach(file => {
+        if (!file.isDir) {
+            packageFiles.push(file.objectName);
+        } else {
+            //todo is it better to read the content and add it? leave it like that ATM
+            packageFiles.push(file.objectName + "/index.js", file.objectName + "/index.d.ts", file.objectName + "/es6.js")
+        }
+    });
+    console.log("updating package.json");
+    packageJson.files = packageFiles;
+    packageJson.main = "babylon.js";
+    packageJson.typings = "babylon.d.ts";
+
+    fs.writeFileSync(basePath + '/package/' + 'package.json', JSON.stringify(packageJson, null, 4));
+
+    console.log('Publishing ' + package.name + " from " + basePath + '/package/');
+    //publish the respected package
+    shelljs.exec('npm publish \"' + basePath + '/package/' + "\"");
+
+    // remove package directory
+    fs.removeSync(basePath + '/package/');
+
+    // now update the main package.json
+    packageJson.files = packageJson.files.map(file => {
+        if (file !== 'package.json' && file !== 'readme.md') {
+            return 'dist/preview release/' + file;
+        } else {
+            return file;
+        }
+    });
+    packageJson.main = "dist/preview release/babylon.js";
+    packageJson.typings = "dist/preview release/babylon.d.ts";
+
+    fs.writeFileSync(package.path + 'package.json', JSON.stringify(packageJson, null, 4));
+}
+

+ 4 - 0
Tools/Publisher/package.json

@@ -9,7 +9,11 @@
   "author": "Raanan Weber",
   "license": "ISC",
   "dependencies": {
+    "fs-extra": "^5.0.0",
     "prompt": "^1.0.0",
     "shelljs": "^0.7.8"
+  },
+  "devDependencies": {
+    "gulp": "^3.9.1"
   }
 }

+ 4 - 3
Viewer/dist/basicExample.html

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

+ 5 - 0
Viewer/dist/config.json

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

+ 48 - 0
Viewer/dist/loadModelManually.html

@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html lang="en">
+
+    <head>
+        <meta charset="UTF-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1.0">
+        <meta http-equiv="X-UA-Compatible" content="ie=edge">
+        <title>BabylonJS Viewer - Basic usage</title>
+        <style>
+            babylon {
+                max-width: 800px;
+                max-height: 500px;
+                width: 100%;
+                height: 600px;
+            }
+        </style>
+    </head>
+
+    <body>
+        <babylon id="babylon-viewer" camera.behaviors.auto-rotate="0"></babylon>
+        <script src="viewer.js"></script>
+        <script>
+            BabylonViewer.viewerManager.getViewerPromiseById('babylon-viewer').then(function (viewer) {
+                // this will resolve only after the viewer with this specific ID is initialized
+
+                viewer.onEngineInitObservable.add(function (scene) {
+                    viewer.loadModel({
+                        title: "Helmet",
+                        subtitle: "BabylonJS",
+                        thumbnail: "https://www.babylonjs.com/img/favicon/apple-icon-144x144.png",
+                        url: "https://www.babylonjs.com/Assets/DamagedHelmet/glTF/DamagedHelmet.gltf"
+                    });
+                });
+
+                // load another model after 20 seconds. Just for fun.
+                setTimeout(() => {
+                    viewer.loadModel({
+                        title: "Rabbit",
+                        subtitle: "BabylonJS",
+                        thumbnail: "https://www.babylonjs.com/img/favicon/apple-icon-144x144.png",
+                        url: "https://playground.babylonjs.com/scenes/Rabbit.babylon"
+                    });
+                }, 20000)
+            });
+        </script>
+    </body>
+
+</html>

Fichier diff supprimé car celui-ci est trop grand
+ 0 - 1
Viewer/dist/viewer.min.js


+ 6 - 13
Viewer/package.json

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

+ 190 - 116
Viewer/src/configuration/configuration.ts

@@ -9,141 +9,215 @@ export interface ViewerConfiguration {
     pageUrl?: string; // will be used for sharing and other fun stuff. This is the page showing the model (not the model's url!)
 
     configuration?: string | {
-        url: string;
+        url?: string;
+        payload?: any;
         mapper?: string; // json (default), html, yaml, xml, etc'. if not provided, file extension will be used.
     };
 
-    // Deprecated
-    /*// native (!!!) javascript events. Mainly used in the JSON-format.
-    // those events will be triggered by the container element (the <babylon> tag);
-    events?: {
-        load: boolean | string;
-        init: boolean | string;
-        meshselected: boolean | string;
-        pointerdown: boolean | string;
-        pointerup: boolean | string;
-        pointermove: boolean | string;
-        // load: 'onViewerLoaded' // will trigger the event prefix-onViewerLoaded instead of prefix-onLoad (and ONLY this event).
-    } | boolean; //events: true - fire all events*/
-    //eventPrefix?: string;
-
     // names of functions in the window context.
-    observers?: {
-        onEngineInit?: string;
-        onSceneInit?: string;
-        onModelLoaded?: string;
-    }
+    observers?: IObserversConfiguration;
 
     canvasElement?: string; // if there is a need to override the standard implementation - ID of HTMLCanvasElement
 
-    model?: {
-        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.
-
-        title: string;
-        subtitle?: string;
-        thumbnail?: string; // URL or data-url
-
-        [propName: string]: any; // further configuration, like title and creator
-    } | string;
-
-    scene?: {
-        debug?: boolean;
-        autoRotate?: boolean;
-        rotationSpeed?: number;
-        defaultCamera?: boolean;
-        defaultLight?: boolean;
-        clearColor?: { r: number, g: number, b: number, a: number };
-        imageProcessingConfiguration?: IImageProcessingConfiguration;
-    },
+    model?: IModelConfiguration | string;
+
+    scene?: ISceneConfiguration;
+    optimizer?: ISceneOptimizerConfiguration | boolean;
     // at the moment, support only a single camera.
-    camera?: {
-        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;
-            };
-        };
+    camera?: ICameraConfiguration,
+    skybox?: boolean | ISkyboxConfiguration;
 
-        [propName: string]: any;
+    ground?: boolean | IGroundConfiguration;
+    lights?: { [name: string]: boolean | ILightConfiguration },
+    // engine configuration. optional!
+    engine?: {
+        antialiasing?: boolean;
+        disableResize?: boolean;
+        engineOptions?: { [key: string]: any };
+        adaptiveQuality?: boolean;
     },
-    skybox?: {
-        cubeTexture: {
-            noMipMap?: boolean;
-            gammaSpace?: boolean;
-            url: string | Array<string>;
-        };
-        pbr?: boolean;
-        scale?: number;
-        blur?: number;
-        material?: {
-            imageProcessingConfiguration?: IImageProcessingConfiguration;
+    //templateStructure?: ITemplateStructure,
+    templates?: {
+        main: ITemplateConfiguration,
+        [key: string]: ITemplateConfiguration
+    };
+
+    customShaders?: {
+        shaders?: {
+            [key: string]: string;
         };
-        infiniteDIstance?: boolean;
+        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;
+    };
+    infiniteDIstance?: boolean;
 
-    ground?: boolean | {
-        size?: number;
-        receiveShadows?: boolean;
-        shadowOnly?: boolean;
-        mirror?: boolean;
-        material?: {
-            [propName: string]: any;
-        }
+}
+
+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;
     };
-    lights?: {
-        [name: string]: {
+}
+
+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;
-            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;
-            radius?: number;
-            shadownEnabled?: boolean; // only on specific lights!
-            shadowConfig?: {
-                useBlurExponentialShadowMap?: boolean;
-                useKernelBlur?: boolean;
-                blurKernel?: number;
-                blurScale?: 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;
-                };
-            };
-        }
-    },
-    // engine configuration. optional!
-    engine?: {
-        antialiasing?: boolean;
-    },
-    //templateStructure?: ITemplateStructure,
-    templates?: {
-        main: ITemplateConfiguration,
-        [key: string]: ITemplateConfiguration
+    [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;
+        };
     };
-    // nodes?
+}
+
+export interface ISceneOptimizerParameters {
+    priority?: number;
+    maximumSize?: number;
+    step?: number;
 }
 
 export interface IImageProcessingConfiguration {

+ 40 - 23
Viewer/src/configuration/loader.ts

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

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

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

+ 17 - 15
Viewer/src/configuration/types/default.ts

@@ -1,9 +1,7 @@
 import { ViewerConfiguration } from './../configuration';
 
 export let defaultConfiguration: ViewerConfiguration = {
-    version: "0.1",
-    //eventPrefix: 'babylonviewer-',
-    //events: true,
+    version: "3.2.0-alpha4",
     templates: {
         main: {
             html: require("../../../assets/templates/default/defaultTemplate.html")
@@ -17,6 +15,11 @@ export let defaultConfiguration: ViewerConfiguration = {
         },
         viewer: {
             html: require("../../../assets/templates/default/defaultViewer.html"),
+            events: {
+                pointerout: true,
+                pointerdown: true,
+                pointerup: true
+            }
         },
         navBar: {
             html: require("../../../assets/templates/default/navbar.html"),
@@ -34,7 +37,8 @@ export let defaultConfiguration: ViewerConfiguration = {
                 visibilityTimeout: 2000
             },
             events: {
-                pointerdown: { 'fullscreen-button': true/*, '#help-button': true*/ }
+                pointerdown: { 'fullscreen-button': true/*, '#help-button': true*/ },
+                pointerover: true
             }
         },
         overlay: {
@@ -65,12 +69,12 @@ export let defaultConfiguration: ViewerConfiguration = {
             }
         }
     },
-    /*lights: [
-        {
+    /*lights: {
+        "default": {
             type: 1,
             shadowEnabled: true,
-            direction: { x: -0.2, y: -1, z: 0 },
-            position: { x: 0.017, y: 50, z: 0 },
+            direction: { x: -0.2, y: -0.8, z: 0 },
+            position: { x: 10, y: 10, z: 0 },
             intensity: 4.5,
             shadowConfig: {
                 useBlurExponentialShadowMap: true,
@@ -79,16 +83,16 @@ export let defaultConfiguration: ViewerConfiguration = {
                 blurScale: 4
             }
         }
-    ],*/
+    },*/
     skybox: {
-        cubeTexture: {
+        /*cubeTexture: {
             url: 'https://playground.babylonjs.com/textures/environment.dds',
             gammaSpace: false
-        },
+        },*/
         pbr: true,
         blur: 0.7,
         infiniteDIstance: false,
-        material: {
+        /*material: {
             imageProcessingConfiguration: {
                 colorCurves: {
                     globalDensity: 89,
@@ -104,7 +108,7 @@ export let defaultConfiguration: ViewerConfiguration = {
                 vignetteColor: { r: 0.8, g: 0.6, b: 0.4 },
                 vignetteM: true
             }
-        }
+        }*/
     },
     ground: true,
     engine: {
@@ -116,7 +120,5 @@ export let defaultConfiguration: ViewerConfiguration = {
             contrast: 1.66,
             toneMappingEnabled: true
         }
-        //autoRotate: true,
-        //rotationSpeed: 0.1
     }
 }

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

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

+ 40 - 0
Viewer/src/eventManager.ts

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

+ 3 - 1
Viewer/src/index.ts

@@ -15,10 +15,12 @@ import 'babylonjs';
 import 'babylonjs-loaders';
 import '../assets/pep.min';
 
+import { PromisePolyfill } from 'babylonjs';
+
 import { InitTags } from './initializer';
 
 // promise polyfill, if needed!
-global.Promise = typeof Promise === 'undefined' ? require('es6-promise').Promise : Promise;
+PromisePolyfill.Apply();
 
 export let disableInit: boolean = false;
 document.addEventListener("DOMContentLoaded", function (event) {

+ 128 - 39
Viewer/src/templateManager.ts

@@ -40,6 +40,9 @@ export class TemplateManager {
     public onLoaded: Observable<Template>;
     public onStateChange: Observable<Template>;
     public onAllLoaded: Observable<TemplateManager>;
+    public onEventTriggered: Observable<EventCallback>;
+
+    public eventManager: EventManager;
 
     private templates: { [name: string]: Template };
 
@@ -50,6 +53,9 @@ export class TemplateManager {
         this.onLoaded = new Observable<Template>();
         this.onStateChange = new Observable<Template>();
         this.onAllLoaded = new Observable<TemplateManager>();
+        this.onEventTriggered = new Observable<EventCallback>();
+
+        this.eventManager = new EventManager(this);
     }
 
     public initTemplate(templates: { [key: string]: ITemplateConfiguration }) {
@@ -83,8 +89,13 @@ export class TemplateManager {
         }
 
         //build the html tree
-        this.buildHTMLTree(templates).then(htmlTree => {
-            internalInit(htmlTree, 'main');
+        return this.buildHTMLTree(templates).then(htmlTree => {
+            if (this.templates['main']) {
+                internalInit(htmlTree, 'main');
+            } else {
+                this.checkLoadedState();
+            }
+            return;
         });
     }
 
@@ -99,8 +110,13 @@ export class TemplateManager {
      * @memberof TemplateManager
      */
     private buildHTMLTree(templates: { [key: string]: ITemplateConfiguration }): Promise<object> {
-        let promises = Object.keys(templates).map(name => {
+        let promises: Array<Promise<Template | boolean>> = Object.keys(templates).map(name => {
+            // if the template was overridden
+            if (!templates[name]) return Promise.resolve(false);
+            // else - we have a template, let's do our job!
             let template = new Template(name, templates[name]);
+            // make sure the global onEventTriggered is called as well
+            template.onEventTriggered.add(eventData => this.onEventTriggered.notifyObservers(eventData));
             this.templates[name] = template;
             return template.initPromise;
         });
@@ -115,8 +131,9 @@ export class TemplateManager {
                     buildTree(parentObject[element], element);
                 });
             }
-
-            buildTree(templateStructure, "main");
+            if (this.templates['main']) {
+                buildTree(templateStructure, "main");
+            }
             return templateStructure;
         });
     }
@@ -131,7 +148,7 @@ export class TemplateManager {
     }
 
     private checkLoadedState() {
-        let done = Object.keys(this.templates).every((key) => {
+        let done = Object.keys(this.templates).length === 0 || Object.keys(this.templates).every((key) => {
             return this.templates[key].isLoaded && !!this.templates[key].parent;
         });
 
@@ -140,10 +157,24 @@ export class TemplateManager {
         }
     }
 
+    public dispose() {
+        // dispose all templates
+        Object.keys(this.templates).forEach(template => {
+            this.templates[template].dispose();
+        });
+
+        this.onInit.clear();
+        this.onAllLoaded.clear();
+        this.onEventTriggered.clear();
+        this.onLoaded.clear();
+        this.onStateChange.clear();
+    }
+
 }
 
 
 import * as Handlebars from '../assets/handlebars.min.js';
+import { EventManager } from './eventManager';
 // register a new helper. modified https://stackoverflow.com/questions/9838925/is-there-any-method-to-iterate-a-map-with-handlebars-js
 Handlebars.registerHelper('eachInMap', function (map, block) {
     var out = '';
@@ -168,12 +199,18 @@ export class Template {
     public onEventTriggered: Observable<EventCallback>;
 
     public isLoaded: boolean;
+    /**
+     * This is meant to be used to track the show and hide functions.
+     * This is NOT (!!) a flag to check if the element is actually visible to the user.
+     */
+    public isShown: boolean;
 
     public parent: HTMLElement;
 
     public initPromise: Promise<Template>;
 
     private fragment: DocumentFragment;
+    private htmlTemplate: string;
 
     constructor(public name: string, private _configuration: ITemplateConfiguration) {
         this.onInit = new Observable<Template>();
@@ -183,6 +220,7 @@ export class Template {
         this.onEventTriggered = new Observable<EventCallback>();
 
         this.isLoaded = false;
+        this.isShown = false;
         /*
         if (configuration.id) {
             this.parent.id = configuration.id;
@@ -194,17 +232,34 @@ export class Template {
 
         this.initPromise = htmlContentPromise.then(htmlTemplate => {
             if (htmlTemplate) {
+                this.htmlTemplate = htmlTemplate;
                 let compiledTemplate = Handlebars.compile(htmlTemplate);
                 let config = this._configuration.params || {};
                 let rawHtml = compiledTemplate(config);
                 this.fragment = document.createRange().createContextualFragment(rawHtml);
                 this.isLoaded = true;
+                this.isShown = true;
                 this.onLoaded.notifyObservers(this);
             }
             return this;
         });
     }
 
+    public updateParams(params: { [key: string]: string | number | boolean | object }) {
+        this._configuration.params = params;
+        // update the template
+        if (this.isLoaded) {
+            this.dispose();
+        }
+        let compiledTemplate = Handlebars.compile(this.htmlTemplate);
+        let config = this._configuration.params || {};
+        let rawHtml = compiledTemplate(config);
+        this.fragment = document.createRange().createContextualFragment(rawHtml);
+        if (this.parent) {
+            this.appendTo(this.parent, true);
+        }
+    }
+
     public get configuration(): ITemplateConfiguration {
         return this._configuration;
     }
@@ -223,54 +278,81 @@ export class Template {
         return childrenArray;
     }
 
-    public appendTo(parent: HTMLElement) {
+    public appendTo(parent: HTMLElement, forceRemove?: boolean) {
         if (this.parent) {
-            console.error('Already appanded to ', this.parent);
-        } else {
-            this.parent = parent;
-
-            if (this._configuration.id) {
-                this.parent.id = this._configuration.id;
+            if (forceRemove) {
+                this.parent.removeChild(this.fragment);
+            } else {
+                return;
             }
-            this.parent.appendChild(this.fragment);
-            // appended only one frame after.
-            setTimeout(() => {
-                this.registerEvents();
-                this.onAppended.notifyObservers(this);
-            });
         }
+        this.parent = parent;
 
+        if (this._configuration.id) {
+            this.parent.id = this._configuration.id;
+        }
+        this.fragment = this.parent.appendChild(this.fragment);
+        // appended only one frame after.
+        setTimeout(() => {
+            this.registerEvents();
+            this.onAppended.notifyObservers(this);
+        });
     }
 
     public show(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template> {
-        if (visibilityFunction) {
-            return visibilityFunction(this).then(() => {
-                this.onStateChange.notifyObservers(this);
+        return Promise.resolve().then(() => {
+            if (visibilityFunction) {
+                return visibilityFunction(this);
+            } else {
+                // flex? box? should this be configurable easier than the visibilityFunction?
+                this.parent.style.display = 'flex';
                 return this;
-            });
-        } else {
-            // flex? box? should this be configurable easier than the visibilityFunction?
-            this.parent.style.display = 'flex';
+            }
+        }).then(() => {
+            this.isShown = true;
             this.onStateChange.notifyObservers(this);
-            return Promise.resolve(this);
-        }
+            return this;
+        });
     }
 
     public hide(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template> {
-        if (visibilityFunction) {
-            return visibilityFunction(this).then(() => {
-                this.onStateChange.notifyObservers(this);
+        return Promise.resolve().then(() => {
+            if (visibilityFunction) {
+                return visibilityFunction(this);
+            } else {
+                // flex? box? should this be configurable easier than the visibilityFunction?
+                this.parent.style.display = 'hide';
                 return this;
-            });
-        } else {
-            this.parent.style.display = 'none';
+            }
+        }).then(() => {
+            this.isShown = false;
             this.onStateChange.notifyObservers(this);
-            return Promise.resolve(this);
-        }
+            return this;
+        });
+    }
+
+    public dispose() {
+        this.onAppended.clear();
+        this.onEventTriggered.clear();
+        this.onInit.clear();
+        this.onLoaded.clear();
+        this.onStateChange.clear();
+        this.isLoaded = false;
+        // remove from parent
+        this.parent.removeChild(this.fragment);
     }
 
+    private registeredEvents: Array<{ htmlElement: HTMLElement, eventName: string, function: EventListenerOrEventListenerObject }>;
+
     // TODO - Should events be removed as well? when are templates disposed?
     private registerEvents() {
+        this.registeredEvents = this.registeredEvents || [];
+        if (this.registeredEvents.length) {
+            // first remove the registered events
+            this.registeredEvents.forEach(evt => {
+                evt.htmlElement.removeEventListener(evt.eventName, evt.function);
+            });
+        }
         if (this._configuration.events) {
             for (let eventName in this._configuration.events) {
                 if (this._configuration.events && this._configuration.events[eventName]) {
@@ -286,18 +368,25 @@ export class Template {
                         // strict null checl is working incorrectly, must override:
                         let event = this._configuration.events[eventName] || {};
                         selectorsArray.filter(selector => event[selector]).forEach(selector => {
-                            if (selector.indexOf('#') !== 0) {
+                            if (selector && selector.indexOf('#') !== 0) {
                                 selector = '#' + selector;
                             }
                             let htmlElement = <HTMLElement>this.parent.querySelector(selector);
-                            htmlElement && htmlElement.addEventListener(eventName, functionToFire.bind(this, selector), false)
+                            if (htmlElement) {
+                                let binding = functionToFire.bind(this, selector);
+                                htmlElement.addEventListener(eventName, binding, false);
+                                this.registeredEvents.push({
+                                    htmlElement: htmlElement,
+                                    eventName: eventName,
+                                    function: binding
+                                });
+                            }
                         });
                     }
                 }
             }
         }
     }
-
 }
 
 export function getTemplateAsHtml(templateConfig: ITemplateConfiguration): Promise<string> {

+ 0 - 39
Viewer/src/util/promiseObservable.ts

@@ -1,39 +0,0 @@
-import { Observable } from 'babylonjs';
-
-export class PromiseObservable<T> extends Observable<T> {
-
-    public notifyWithPromise(eventData: T, mask: number = -1, target?: any, currentTarget?: any): Promise<any> {
-
-        let p = Promise.resolve();
-
-        if (!this._observers.length) {
-            return p;
-        }
-
-        let state = this['_eventState'];
-        state.mask = mask;
-        state.target = target;
-        state.currentTarget = currentTarget;
-        state.skipNextObservers = false;
-
-        this._observers.forEach(obs => {
-            if (state.skipNextObservers) {
-                return;
-            }
-            if (obs.mask & mask) {
-                if (obs.scope) {
-                    // TODO - I can add the variable from the last function here. Requires changing callback sig
-                    p = p.then(() => {
-                        return obs.callback.apply(obs.scope, [eventData, state]);
-                    });
-                } else {
-                    p = p.then(() => {
-                        return obs.callback(eventData, state);
-                    });
-                }
-            }
-        });
-
-        return p;
-    }
-}

+ 119 - 238
Viewer/src/viewer/defaultViewer.ts

@@ -1,15 +1,13 @@
 
 
-import { ViewerConfiguration } from './../configuration/configuration';
-import { Template } from './../templateManager';
+import { ViewerConfiguration, IModelConfiguration, ILightConfiguration } from './../configuration/configuration';
+import { Template, EventCallback } from './../templateManager';
 import { AbstractViewer } from './viewer';
-import { MirrorTexture, Plane, ShadowGenerator, Texture, BackgroundMaterial, Observable, ShadowLight, CubeTexture, BouncingBehavior, FramingBehavior, Behavior, Light, Engine, Scene, AutoRotationBehavior, AbstractMesh, Quaternion, StandardMaterial, ArcRotateCamera, ImageProcessingConfiguration, Color3, Vector3, SceneLoader, Mesh, HemisphericLight } from 'babylonjs';
+import { SpotLight, MirrorTexture, Plane, ShadowGenerator, Texture, BackgroundMaterial, Observable, ShadowLight, CubeTexture, BouncingBehavior, FramingBehavior, Behavior, Light, Engine, Scene, AutoRotationBehavior, AbstractMesh, Quaternion, StandardMaterial, ArcRotateCamera, ImageProcessingConfiguration, Color3, Vector3, SceneLoader, Mesh, HemisphericLight } from 'babylonjs';
 import { CameraBehavior } from '../interfaces';
 
 export class DefaultViewer extends AbstractViewer {
 
-    public camera: ArcRotateCamera;
-
     constructor(public containerElement: HTMLElement, initialConfiguration: ViewerConfiguration = { extends: 'default' }) {
         super(containerElement, initialConfiguration);
         this.onModelLoadedObservable.add(this.onModelLoaded);
@@ -27,9 +25,22 @@ export class DefaultViewer extends AbstractViewer {
         this.showLoadingScreen();
 
         // navbar
-        let viewerElement = this.templateManager.getTemplate('viewer');
+        this.initNavbar();
+
+        // close overlay button
+        let closeButton = document.getElementById('close-button');
+        if (closeButton) {
+            closeButton.addEventListener('pointerdown', () => {
+                this.hideOverlayScreen();
+            })
+        }
+
+        return super.onTemplatesLoaded();
+    }
+
+    private initNavbar() {
         let navbar = this.templateManager.getTemplate('navBar');
-        if (viewerElement && navbar) {
+        if (navbar) {
             let navbarHeight = navbar.parent.clientHeight + 'px';
 
             let navbarShown: boolean = true;
@@ -61,69 +72,63 @@ export class DefaultViewer extends AbstractViewer {
                 }
             }
 
+            this.templateManager.eventManager.registerCallback('viewer', triggerNavbar.bind(this, false), 'pointerout');
+            this.templateManager.eventManager.registerCallback('viewer', triggerNavbar.bind(this, true), 'pointerdown');
+            this.templateManager.eventManager.registerCallback('viewer', triggerNavbar.bind(this, false), 'pointerup');
+            this.templateManager.eventManager.registerCallback('navBar', triggerNavbar.bind(this, true), 'pointerover');
+
+            // other events
+            let viewerTemplate = this.templateManager.getTemplate('viewer');
+            let viewerElement = viewerTemplate && viewerTemplate.parent;
+            // full screen
+            let triggerFullscren = (eventData: EventCallback) => {
+                if (viewerElement) {
+                    let fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement || (<any>document).mozFullScreenElement || (<any>document).msFullscreenElement;
+                    if (!fullscreenElement) {
+                        let requestFullScreen = viewerElement.requestFullscreen || viewerElement.webkitRequestFullscreen || (<any>viewerElement).msRequestFullscreen || (<any>viewerElement).mozRequestFullScreen;
+                        requestFullScreen.call(viewerElement);
+                    } else {
+                        let exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen || (<any>document).msExitFullscreen || (<any>document).mozCancelFullScreen
+                        exitFullscreen.call(document);
+                    }
+                }
+            }
 
-
-            viewerElement.parent.addEventListener('pointerout', triggerNavbar.bind(this, false));
-            viewerElement.parent.addEventListener('pointerdown', triggerNavbar.bind(this, true));
-            viewerElement.parent.addEventListener('pointerup', triggerNavbar.bind(this, false));
-            navbar.parent.addEventListener('pointerover', triggerNavbar.bind(this, true))
-            // triggerNavbar(false);
-
-            // events registration
-            this.registerNavbarButtons();
-        }
-
-        // close overlay button
-        let closeButton = document.getElementById('close-button');
-        if (closeButton) {
-            closeButton.addEventListener('pointerdown', () => {
-                this.hideOverlayScreen();
-            })
+            this.templateManager.eventManager.registerCallback('navBar', triggerFullscren, 'pointerdown', '#fullscreen-button');
         }
+    }
 
-        return super.onTemplatesLoaded();
+    protected prepareContainerElement() {
+        this.containerElement.style.position = 'relative';
+        this.containerElement.style.display = 'flex';
     }
 
-    private registerNavbarButtons() {
-        let isFullscreen = false;
+    protected configureModel(modelConfiguration: Partial<IModelConfiguration>) {
+        super.configureModel(modelConfiguration);
 
         let navbar = this.templateManager.getTemplate('navBar');
-        let viewerTemplate = this.templateManager.getTemplate('viewer');
-        if (!navbar || !viewerTemplate) return;
-
-        let viewerElement = viewerTemplate.parent;
-
-
-        navbar.onEventTriggered.add((data) => {
-            switch (data.event.type) {
-                case 'pointerdown':
-                    let event: PointerEvent = <PointerEvent>data.event;
-                    if (event.button === 0) {
-                        switch (data.selector) {
-                            case '#fullscreen-button':
-                                if (!isFullscreen) {
-                                    let requestFullScreen = viewerElement.requestFullscreen || viewerElement.webkitRequestFullscreen || (<any>viewerElement).msRequestFullscreen || (<any>viewerElement).mozRequestFullScreen;
-                                    requestFullScreen.call(viewerElement);
-                                } else {
-                                    let exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen || (<any>document).msExitFullscreen || (<any>document).mozCancelFullScreen
-                                    exitFullscreen.call(document);
-                                }
-
-                                isFullscreen = !isFullscreen;
-                                break;
-                            case '#help-button':
-                                this.showOverlayScreen('help');
-                                break;
-                        }
-                    }
-                    break;
+        if (!navbar) return;
+
+        let metadataContainer = navbar.parent.querySelector('#model-metadata');
+        if (metadataContainer) {
+            if (modelConfiguration.title !== undefined) {
+                let element = metadataContainer.querySelector('span.model-title');
+                if (element) {
+                    element.innerHTML = modelConfiguration.title;
+                }
             }
-        });
-    }
 
-    protected prepareContainerElement() {
-        this.containerElement.style.position = 'relative';
-        this.containerElement.style.display = 'flex';
+            if (modelConfiguration.subtitle !== undefined) {
+                let element = metadataContainer.querySelector('span.model-subtitle');
+                if (element) {
+                    element.innerHTML = modelConfiguration.subtitle;
+                }
+            }
+
+            if (modelConfiguration.thumbnail !== undefined) {
+                (<HTMLDivElement>metadataContainer.querySelector('.thumbnail')).style.backgroundImage = `url('${modelConfiguration.thumbnail}')`;
+            }
+        }
     }
 
     public loadModel(model: any = this.configuration.model): Promise<Scene> {
@@ -137,58 +142,21 @@ export class DefaultViewer extends AbstractViewer {
     }
 
     private onModelLoaded = (meshes: Array<AbstractMesh>) => {
-
-        // here we could set the navbar's model information:
-        this.setModelMetaData();
-
         // with a short timeout, making sure everything is there already.
+        let hideLoadingDelay = 500;
+        if (this.configuration.lab && this.configuration.lab.hideLoadingDelay !== undefined) {
+            hideLoadingDelay = this.configuration.lab.hideLoadingDelay;
+        }
         setTimeout(() => {
             this.hideLoadingScreen();
-        }, 500);
-
-
-        // recreate the camera
-        this.scene.createDefaultCameraOrLight(true, true, true);
-        this.camera = <ArcRotateCamera>this.scene.activeCamera;
+        }, hideLoadingDelay);
 
         meshes[0].rotation.y += Math.PI;
 
-        this.setupCamera(meshes);
-        this.setupLights(meshes);
-
-        return this.initEnvironment(meshes);
+        return; //this.initEnvironment(meshes);
     }
 
-    private setModelMetaData() {
-        let navbar = this.templateManager.getTemplate('navBar');
-        if (!navbar) return;
-
-        let metadataContainer = navbar.parent.querySelector('#model-metadata');
-
-        //title
-        if (metadataContainer && typeof this.configuration.model === 'object') {
-            if (this.configuration.model.title) {
-                let element = metadataContainer.querySelector('span.model-title');
-                if (element) {
-                    element.innerHTML = this.configuration.model.title;
-                }
-            }
-
-            if (this.configuration.model.subtitle) {
-                let element = metadataContainer.querySelector('span.model-subtitle');
-                if (element) {
-                    element.innerHTML = this.configuration.model.subtitle;
-                }
-            }
-
-            if (this.configuration.model.thumbnail) {
-                (<HTMLDivElement>metadataContainer.querySelector('.thumbnail')).style.backgroundImage = `url('${this.configuration.model.thumbnail}')`;
-            }
-        }
-
-    }
-
-    public initEnvironment(focusMeshes: Array<AbstractMesh> = []): Promise<Scene> {
+    /*protected initEnvironment(focusMeshes: Array<AbstractMesh> = []): Promise<Scene> {
         if (this.configuration.skybox) {
             // Define a general environment textue
             let texture;
@@ -228,6 +196,10 @@ export class DefaultViewer extends AbstractViewer {
             ground.rotation.x = Math.PI / 2; // Face up by default.
             ground.receiveShadows = groundConfig.receiveShadows || false;
 
+            // position the ground correctly
+            let groundPosition = focusMeshes[0].getHierarchyBoundingVectors().min.y;
+            ground.position.y = groundPosition;
+
             // default values
             backgroundMaterial.alpha = 0.9;
             backgroundMaterial.alphaMode = Engine.ALPHA_PREMULTIPLIED_PORTERDUFF;
@@ -284,7 +256,7 @@ export class DefaultViewer extends AbstractViewer {
         }
 
         return Promise.resolve(this.scene);
-    }
+    }*/
 
     public showOverlayScreen(subScreen: string) {
         let template = this.templateManager.getTemplate('overlay');
@@ -373,144 +345,53 @@ export class DefaultViewer extends AbstractViewer {
         }));
     }
 
-    private setupLights(focusMeshes: Array<AbstractMesh> = []) {
-
-        let sceneConfig = this.configuration.scene || { defaultLight: true };
-
-        if (!sceneConfig.defaultLight && (this.configuration.lights && Object.keys(this.configuration.lights).length)) {
-            // remove old lights
-            this.scene.lights.forEach(l => {
-                l.dispose();
-            });
-
-            Object.keys(this.configuration.lights).forEach((name, idx) => {
-                let lightConfig = this.configuration.lights && this.configuration.lights[name] || { name: name, type: 0 };
-                lightConfig.name = name;
-                let constructor = Light.GetConstructorFromName(lightConfig.type, lightConfig.name, this.scene);
-                if (!constructor) return;
-                let light = constructor();
-
-                //enabled
-                if (light.isEnabled() !== !lightConfig.disabled) {
-                    light.setEnabled(!lightConfig.disabled);
+    protected configureLights(lightsConfiguration: { [name: string]: ILightConfiguration | boolean } = {}, focusMeshes: Array<AbstractMesh> = this.scene.meshes) {
+        super.configureLights(lightsConfiguration, focusMeshes);
+        console.log("flashlight", this.configuration.lab);
+        // labs feature - flashlight
+        if (this.configuration.lab && this.configuration.lab.flashlight) {
+            let pointerPosition = BABYLON.Vector3.Zero();
+            let lightTarget;
+            let angle = 0.5;
+            let exponent = Math.PI / 2;
+            if (typeof this.configuration.lab.flashlight === "object") {
+                exponent = this.configuration.lab.flashlight.exponent || exponent;
+                angle = this.configuration.lab.flashlight.angle || angle;
+            }
+            var flashlight = new SpotLight("flashlight", Vector3.Zero(),
+                Vector3.Zero(), exponent, angle, this.scene);
+            if (typeof this.configuration.lab.flashlight === "object") {
+                flashlight.intensity = this.configuration.lab.flashlight.intensity || flashlight.intensity;
+                if (this.configuration.lab.flashlight.diffuse) {
+                    flashlight.diffuse.r = this.configuration.lab.flashlight.diffuse.r;
+                    flashlight.diffuse.g = this.configuration.lab.flashlight.diffuse.g;
+                    flashlight.diffuse.b = this.configuration.lab.flashlight.diffuse.b;
                 }
-
-                this.extendClassWithConfig(light, lightConfig);
-
-                //position. Some lights don't support shadows
-                if (light instanceof ShadowLight) {
-                    if (lightConfig.shadowEnabled) {
-                        var shadowGenerator = new ShadowGenerator(512, light);
-                        this.extendClassWithConfig(shadowGenerator, lightConfig.shadowConfig || {});
-                        // add the focues meshes to the shadow list
-                        let shadownMap = shadowGenerator.getShadowMap();
-                        if (!shadownMap) return;
-                        let renderList = shadownMap.renderList;
-                        for (var index = 0; index < focusMeshes.length; index++) {
-                            renderList && renderList.push(focusMeshes[index]);
-                        }
-                    }
+                if (this.configuration.lab.flashlight.specular) {
+                    flashlight.specular.r = this.configuration.lab.flashlight.specular.r;
+                    flashlight.specular.g = this.configuration.lab.flashlight.specular.g;
+                    flashlight.specular.b = this.configuration.lab.flashlight.specular.b;
                 }
-            });
-        }
-    }
-
-    private setupCamera(focusMeshes: Array<AbstractMesh> = []) {
 
-        let cameraConfig = this.configuration.camera || {};
-        let sceneConfig = this.configuration.scene || { autoRotate: false, defaultCamera: true };
-
-        if (!this.configuration.camera && sceneConfig.defaultCamera) {
-            if (sceneConfig.autoRotate) {
-                this.camera.useAutoRotationBehavior = true;
             }
-            return;
-        }
-
-        if (cameraConfig.position) {
-            this.camera.position.copyFromFloats(cameraConfig.position.x || 0, cameraConfig.position.y || 0, cameraConfig.position.z || 0);
-        }
-
-        if (cameraConfig.rotation) {
-            this.camera.rotationQuaternion = new Quaternion(cameraConfig.rotation.x || 0, cameraConfig.rotation.y || 0, cameraConfig.rotation.z || 0, cameraConfig.rotation.w || 0)
-        }
-
-        this.camera.minZ = cameraConfig.minZ || this.camera.minZ;
-        this.camera.maxZ = cameraConfig.maxZ || this.camera.maxZ;
-
-        if (cameraConfig.behaviors) {
-            for (let name in cameraConfig.behaviors) {
-                this.setCameraBehavior(cameraConfig.behaviors[name], focusMeshes);
-            }
-        };
-
-        if (sceneConfig.autoRotate) {
-            this.camera.useAutoRotationBehavior = true;
-        }
-    }
-
-    private setCameraBehavior(behaviorConfig: number | {
-        type: number;
-        [propName: string]: any;
-    }, payload: any) {
-
-        let behavior: Behavior<ArcRotateCamera> | null;
-        let type = (typeof behaviorConfig !== "object") ? behaviorConfig : behaviorConfig.type;
-
-        let config: { [propName: string]: any } = (typeof behaviorConfig === "object") ? behaviorConfig : {};
-
-        // constructing behavior
-        switch (type) {
-            case CameraBehavior.AUTOROTATION:
-                behavior = new AutoRotationBehavior();
-                break;
-            case CameraBehavior.BOUNCING:
-                behavior = new BouncingBehavior();
-                break;
-            case CameraBehavior.FRAMING:
-                behavior = new FramingBehavior();
-                break;
-            default:
-                behavior = null;
-                break;
-        }
-
-        if (behavior) {
-            if (typeof behaviorConfig === "object") {
-                this.extendClassWithConfig(behavior, behaviorConfig);
-            }
-            this.camera.addBehavior(behavior);
-        }
-
-        // post attach configuration. Some functionalities require the attached camera.
-        switch (type) {
-            case CameraBehavior.AUTOROTATION:
-                break;
-            case CameraBehavior.BOUNCING:
-                break;
-            case CameraBehavior.FRAMING:
-                if (config.zoomOnBoundingInfo) {
-                    //payload is an array of meshes
-                    let meshes = <Array<AbstractMesh>>payload;
-                    let bounding = meshes[0].getHierarchyBoundingVectors();
-                    (<FramingBehavior>behavior).zoomOnBoundingInfo(bounding.min, bounding.max);
-                }
-                break;
-        }
-    }
-
-    private extendClassWithConfig(object: any, config: any) {
-        if (!config) return;
-        Object.keys(config).forEach(key => {
-            if (key in object && typeof object[key] !== 'function') {
-                if (typeof object[key] === 'function') return;
-                // if it is an object, iterate internally until reaching basic types
-                if (typeof object[key] === 'object') {
-                    this.extendClassWithConfig(object[key], config[key]);
+            this.scene.constantlyUpdateMeshUnderPointer = true;
+            this.scene.onPointerObservable.add((eventData, eventState) => {
+                if (eventData.type === 4 && eventData.pickInfo) {
+                    lightTarget = (eventData.pickInfo.pickedPoint);
                 } else {
-                    object[key] = config[key];
+                    lightTarget = undefined;
+                }
+            });
+            let updateFlashlightFunction = () => {
+                if (this.camera && flashlight) {
+                    flashlight.position.copyFrom(this.camera.position);
+                    if (lightTarget) {
+                        lightTarget.subtractToRef(flashlight.position, flashlight.direction);
+                    }
                 }
             }
-        });
+            this.scene.registerBeforeRender(updateFlashlightFunction);
+            this.registeredOnBeforerenderFunctions.push(updateFlashlightFunction);
+        }
     }
 }

+ 761 - 54
Viewer/src/viewer/viewer.ts

@@ -1,9 +1,11 @@
 import { viewerManager } from './viewerManager';
 import { TemplateManager } from './../templateManager';
 import configurationLoader from './../configuration/loader';
-import { Observable, Engine, Scene, ArcRotateCamera, Vector3, SceneLoader, AbstractMesh, Mesh, HemisphericLight, Database } from 'babylonjs';
-import { ViewerConfiguration } from '../configuration/configuration';
-import { PromiseObservable } from '../util/promiseObservable';
+import { CubeTexture, Color3, IEnvironmentHelperOptions, EnvironmentHelper, Effect, SceneOptimizer, SceneOptimizerOptions, Observable, Engine, Scene, ArcRotateCamera, Vector3, SceneLoader, AbstractMesh, Mesh, HemisphericLight, Database, SceneLoaderProgressEvent, ISceneLoaderPlugin, ISceneLoaderPluginAsync, Quaternion, Light, ShadowLight, ShadowGenerator, Tags, AutoRotationBehavior, BouncingBehavior, FramingBehavior, Behavior } from 'babylonjs';
+import { ViewerConfiguration, ISceneConfiguration, ISceneOptimizerConfiguration, IObserversConfiguration, IModelConfiguration, ISkyboxConfiguration, IGroundConfiguration, ILightConfiguration, ICameraConfiguration } from '../configuration/configuration';
+
+import * as deepmerge from '../../assets/deepmerge.min.js';
+import { CameraBehavior } from 'src/interfaces';
 
 export abstract class AbstractViewer {
 
@@ -11,14 +13,39 @@ export abstract class AbstractViewer {
 
     public engine: Engine;
     public scene: Scene;
+    public camera: ArcRotateCamera;
+    public sceneOptimizer: SceneOptimizer;
     public baseId: string;
 
+    /**
+     * The last loader used to load a model. 
+     * 
+     * @type {(ISceneLoaderPlugin | ISceneLoaderPluginAsync)}
+     * @memberof AbstractViewer
+     */
+    public lastUsedLoader: ISceneLoaderPlugin | ISceneLoaderPluginAsync;
+
     protected configuration: ViewerConfiguration;
+    protected environmentHelper: EnvironmentHelper;
+
+    protected defaultHighpTextureType: number;
+    protected shadowGeneratorBias: number;
+    protected defaultPipelineTextureType: number;
+    protected maxShadows: number;
+
 
     // observables
-    public onSceneInitObservable: PromiseObservable<Scene>;
-    public onEngineInitObservable: PromiseObservable<Engine>;
-    public onModelLoadedObservable: PromiseObservable<AbstractMesh[]>;
+    public onSceneInitObservable: Observable<Scene>;
+    public onEngineInitObservable: Observable<Engine>;
+    public onModelLoadedObservable: Observable<AbstractMesh[]>;
+    public onModelLoadProgressObservable: Observable<SceneLoaderProgressEvent>;
+    public onModelLoadErrorObservable: Observable<{ message: string; exception: any }>;
+    public onLoaderInitObservable: Observable<ISceneLoaderPlugin | ISceneLoaderPluginAsync>;
+    public onInitDoneObservable: Observable<AbstractViewer>;
+
+    protected canvas: HTMLCanvasElement;
+
+    protected registeredOnBeforerenderFunctions: Array<() => void>;
 
     constructor(public containerElement: HTMLElement, initialConfiguration: ViewerConfiguration = {}) {
         // if exists, use the container id. otherwise, generate a random string.
@@ -28,9 +55,15 @@ export abstract class AbstractViewer {
             this.baseId = containerElement.id = 'bjs' + Math.random().toString(32).substr(2, 8);
         }
 
-        this.onSceneInitObservable = new PromiseObservable();
-        this.onEngineInitObservable = new PromiseObservable();
-        this.onModelLoadedObservable = new PromiseObservable();
+        this.onSceneInitObservable = new Observable();
+        this.onEngineInitObservable = new Observable();
+        this.onModelLoadedObservable = new Observable();
+        this.onModelLoadProgressObservable = new Observable();
+        this.onModelLoadErrorObservable = new Observable();
+        this.onInitDoneObservable = new Observable();
+        this.onLoaderInitObservable = new Observable();
+
+        this.registeredOnBeforerenderFunctions = [];
 
         // add this viewer to the viewer manager
         viewerManager.addViewer(this);
@@ -43,35 +76,523 @@ export abstract class AbstractViewer {
         // extend the configuration
         configurationLoader.loadConfiguration(initialConfiguration).then((configuration) => {
             this.configuration = configuration;
-
-            // adding preconfigured functions
             if (this.configuration.observers) {
-                if (this.configuration.observers.onEngineInit) {
-                    this.onEngineInitObservable.add(window[this.configuration.observers.onEngineInit]);
-                }
-                if (this.configuration.observers.onSceneInit) {
-                    this.onSceneInitObservable.add(window[this.configuration.observers.onSceneInit]);
-                }
-                if (this.configuration.observers.onModelLoaded) {
-                    this.onModelLoadedObservable.add(window[this.configuration.observers.onModelLoaded]);
-                }
+                this.configureObservers(this.configuration.observers);
             }
+            //this.updateConfiguration(configuration);
 
             // initialize the templates
             let templateConfiguration = this.configuration.templates || {};
             this.templateManager.initTemplate(templateConfiguration);
             // when done, execute onTemplatesLoaded()
             this.templateManager.onAllLoaded.add(() => {
-                this.onTemplatesLoaded();
+                let canvas = this.templateManager.getCanvas();
+                if (canvas) {
+                    this.canvas = canvas;
+                }
+                this._onTemplateLoaded();
             });
         });
 
+        //this.onModelLoadedObservable.add(this.initEnvironment.bind(this));
+
     }
 
     public getBaseId(): string {
         return this.baseId;
     }
 
+    public isCanvasInDOM(): boolean {
+        return !!this.canvas && !!this.canvas.parentElement;
+    }
+
+    protected resize = (): void => {
+        // Only resize if Canvas is in the DOM
+        if (!this.isCanvasInDOM()) {
+            return;
+        }
+
+        if (this.canvas.clientWidth <= 0 || this.canvas.clientHeight <= 0) {
+            return;
+        }
+
+        this.engine.resize();
+    }
+
+    protected render = (): void => {
+        this.scene && this.scene.activeCamera && this.scene.render();
+    }
+
+    /**
+     * Update the current viewer configuration with new values.
+     * Only provided information will be updated, old configuration values will be kept.
+     * If this.configuration was manually changed, you can trigger this function with no parameters, 
+     * and the entire configuration will be updated. 
+     * @param newConfiguration 
+     */
+    public updateConfiguration(newConfiguration: Partial<ViewerConfiguration> = this.configuration) {
+        // update scene configuration
+        if (newConfiguration.scene) {
+            this.configureScene(newConfiguration.scene);
+        }
+        // optimizer
+        if (newConfiguration.optimizer) {
+            this.configureOptimizer(newConfiguration.optimizer);
+        }
+
+        // observers in configuration
+        if (newConfiguration.observers) {
+            this.configureObservers(newConfiguration.observers);
+        }
+
+        // configure model
+        if (newConfiguration.model && typeof newConfiguration.model === 'object') {
+            this.configureModel(newConfiguration.model);
+        }
+
+        // lights
+        if (newConfiguration.lights) {
+            this.configureLights(newConfiguration.lights);
+        }
+
+        // environment
+        if (newConfiguration.skybox !== undefined || newConfiguration.ground !== undefined) {
+            this.configureEnvironment(newConfiguration.skybox, newConfiguration.ground);
+        }
+
+        // update this.configuration with the new data
+        this.configuration = deepmerge(this.configuration || {}, newConfiguration);
+    }
+
+    protected configureEnvironment(skyboxConifguration?: ISkyboxConfiguration | boolean, groundConfiguration?: IGroundConfiguration | boolean) {
+        if (!skyboxConifguration && !groundConfiguration) {
+            if (this.environmentHelper) {
+                this.environmentHelper.dispose();
+            };
+            return Promise.resolve(this.scene);
+        }
+
+        const options: Partial<IEnvironmentHelperOptions> = {
+            createGround: !!groundConfiguration,
+            createSkybox: !!skyboxConifguration,
+            setupImageProcessing: false // will be done at the scene level!
+        };
+
+        if (groundConfiguration) {
+            let groundConfig = (typeof groundConfiguration === 'boolean') ? {} : groundConfiguration;
+
+            let groundSize = groundConfig.size || (typeof skyboxConifguration === 'object' && skyboxConifguration.scale);
+            if (groundSize) {
+                options.groundSize = groundSize;
+            }
+
+            options.enableGroundShadow = groundConfig === true || groundConfig.receiveShadows;
+            if (groundConfig.shadowLevel) {
+                options.groundShadowLevel = groundConfig.shadowLevel;
+            }
+            options.enableGroundMirror = !!groundConfig.mirror;
+            if (groundConfig.texture) {
+                options.groundTexture = groundConfig.texture;
+            }
+            if (groundConfig.color) {
+                options.groundColor = new Color3(groundConfig.color.r, groundConfig.color.g, groundConfig.color.b)
+            }
+
+            if (groundConfig.mirror) {
+                options.enableGroundMirror = true;
+                // to prevent undefines
+                if (typeof groundConfig.mirror === "object") {
+                    if (groundConfig.mirror.amount)
+                        options.groundMirrorAmount = groundConfig.mirror.amount;
+                    if (groundConfig.mirror.sizeRatio)
+                        options.groundMirrorSizeRatio = groundConfig.mirror.sizeRatio;
+                    if (groundConfig.mirror.blurKernel)
+                        options.groundMirrorBlurKernel = groundConfig.mirror.blurKernel;
+                    if (groundConfig.mirror.fresnelWeight)
+                        options.groundMirrorFresnelWeight = groundConfig.mirror.fresnelWeight;
+                    if (groundConfig.mirror.fallOffDistance)
+                        options.groundMirrorFallOffDistance = groundConfig.mirror.fallOffDistance;
+                    if (this.defaultHighpTextureType !== undefined)
+                        options.groundMirrorTextureType = this.defaultHighpTextureType;
+                }
+            }
+
+        }
+
+        let postInitSkyboxMaterial = false;
+        if (skyboxConifguration) {
+            let conf = skyboxConifguration === true ? {} : skyboxConifguration;
+            if (conf.material && conf.material.imageProcessingConfiguration) {
+                options.setupImageProcessing = false; // will be configured later manually.
+            }
+            let skyboxSize = conf.scale;
+            if (skyboxSize) {
+                options.skyboxSize = skyboxSize;
+            }
+            options.sizeAuto = !options.skyboxSize;
+            if (conf.color) {
+                options.skyboxColor = new Color3(conf.color.r, conf.color.g, conf.color.b)
+            }
+            if (conf.cubeTexture && conf.cubeTexture.url) {
+                if (typeof conf.cubeTexture.url === "string") {
+                    options.skyboxTexture = conf.cubeTexture.url;
+                } else {
+                    // init later!
+                    postInitSkyboxMaterial = true;
+                }
+            }
+
+            if (conf.material && conf.material.imageProcessingConfiguration) {
+                postInitSkyboxMaterial = true;
+            }
+        }
+
+        if (!this.environmentHelper) {
+            this.environmentHelper = this.scene.createDefaultEnvironment(options)!;
+        } else {
+            // there might be a new scene! we need to dispose.
+
+            // get the scene used by the envHelper
+            let scene: Scene = this.environmentHelper.rootMesh.getScene();
+            // is it a different scene? Oh no!
+            if (scene !== this.scene) {
+                this.environmentHelper.dispose();
+                this.environmentHelper = this.scene.createDefaultEnvironment(options)!;
+            } else {
+                this.environmentHelper.updateOptions(options)!;
+            }
+        }
+
+        if (postInitSkyboxMaterial) {
+            let skyboxMaterial = this.environmentHelper.skyboxMaterial;
+            if (skyboxMaterial) {
+                if (typeof skyboxConifguration === 'object' && skyboxConifguration.material && skyboxConifguration.material.imageProcessingConfiguration) {
+                    this.extendClassWithConfig(skyboxMaterial.imageProcessingConfiguration, skyboxConifguration.material.imageProcessingConfiguration);
+                }
+            }
+        }
+    }
+
+    protected configureScene(sceneConfig: ISceneConfiguration, optimizerConfig?: ISceneOptimizerConfiguration) {
+        // sanity check!
+        if (!this.scene) {
+            return;
+        }
+        if (sceneConfig.debug) {
+            this.scene.debugLayer.show();
+        } else {
+            if (this.scene.debugLayer.isVisible()) {
+                this.scene.debugLayer.hide();
+            }
+        }
+
+        if (sceneConfig.clearColor) {
+            let cc = sceneConfig.clearColor;
+            let oldcc = this.scene.clearColor;
+            if (cc.r !== undefined) {
+                oldcc.r = cc.r;
+            }
+            if (cc.g !== undefined) {
+                oldcc.g = cc.g
+            }
+            if (cc.b !== undefined) {
+                oldcc.b = cc.b
+            }
+            if (cc.a !== undefined) {
+                oldcc.a = cc.a
+            }
+        }
+
+        // image processing configuration - optional.
+        if (sceneConfig.imageProcessingConfiguration) {
+            this.extendClassWithConfig(this.scene.imageProcessingConfiguration, sceneConfig.imageProcessingConfiguration);
+        }
+        if (sceneConfig.environmentTexture) {
+            if (this.scene.environmentTexture) {
+                this.scene.environmentTexture.dispose();
+            }
+            const environmentTexture = CubeTexture.CreateFromPrefilteredData(sceneConfig.environmentTexture, this.scene);
+            this.scene.environmentTexture = environmentTexture;
+        }
+
+        if (sceneConfig.autoRotate) {
+            this.camera.useAutoRotationBehavior = true;
+        }
+    }
+
+    protected configureOptimizer(optimizerConfig: ISceneOptimizerConfiguration | boolean) {
+        if (typeof optimizerConfig === 'boolean') {
+            if (this.sceneOptimizer) {
+                this.sceneOptimizer.stop();
+                this.sceneOptimizer.dispose();
+                delete this.sceneOptimizer;
+            }
+            if (optimizerConfig) {
+                this.sceneOptimizer = new SceneOptimizer(this.scene);
+                this.sceneOptimizer.start();
+            }
+        } else {
+            let optimizerOptions: SceneOptimizerOptions = new SceneOptimizerOptions(optimizerConfig.targetFrameRate, optimizerConfig.trackerDuration);
+            // check for degradation
+            if (optimizerConfig.degradation) {
+                switch (optimizerConfig.degradation) {
+                    case "low":
+                        optimizerOptions = SceneOptimizerOptions.LowDegradationAllowed(optimizerConfig.targetFrameRate);
+                        break;
+                    case "moderate":
+                        optimizerOptions = SceneOptimizerOptions.ModerateDegradationAllowed(optimizerConfig.targetFrameRate);
+                        break;
+                    case "hight":
+                        optimizerOptions = SceneOptimizerOptions.HighDegradationAllowed(optimizerConfig.targetFrameRate);
+                        break;
+                }
+            }
+            if (this.sceneOptimizer) {
+                this.sceneOptimizer.stop();
+                this.sceneOptimizer.dispose()
+            }
+            this.sceneOptimizer = new SceneOptimizer(this.scene, optimizerOptions, optimizerConfig.autoGeneratePriorities, optimizerConfig.improvementMode);
+            this.sceneOptimizer.start();
+        }
+    }
+
+    protected configureObservers(observersConfiguration: IObserversConfiguration) {
+        if (observersConfiguration.onEngineInit) {
+            this.onEngineInitObservable.add(window[observersConfiguration.onEngineInit]);
+        } else {
+            if (observersConfiguration.onEngineInit === '' && this.configuration.observers && this.configuration.observers!.onEngineInit) {
+                this.onEngineInitObservable.removeCallback(window[this.configuration.observers!.onEngineInit!]);
+            }
+        }
+        if (observersConfiguration.onSceneInit) {
+            this.onSceneInitObservable.add(window[observersConfiguration.onSceneInit]);
+        } else {
+            if (observersConfiguration.onSceneInit === '' && this.configuration.observers && this.configuration.observers!.onSceneInit) {
+                this.onSceneInitObservable.removeCallback(window[this.configuration.observers!.onSceneInit!]);
+            }
+        }
+        if (observersConfiguration.onModelLoaded) {
+            this.onModelLoadedObservable.add(window[observersConfiguration.onModelLoaded]);
+        } else {
+            if (observersConfiguration.onModelLoaded === '' && this.configuration.observers && this.configuration.observers!.onModelLoaded) {
+                this.onModelLoadedObservable.removeCallback(window[this.configuration.observers!.onModelLoaded!]);
+            }
+        }
+    }
+
+    protected configureCamera(cameraConfig: ICameraConfiguration, focusMeshes: Array<AbstractMesh> = this.scene.meshes) {
+        if (!this.scene.activeCamera) {
+            this.scene.createDefaultCamera(true, true, true);
+            this.camera = <ArcRotateCamera>this.scene.activeCamera!;
+        }
+        if (cameraConfig.position) {
+            this.camera.position.copyFromFloats(cameraConfig.position.x || 0, cameraConfig.position.y || 0, cameraConfig.position.z || 0);
+        }
+
+        if (cameraConfig.rotation) {
+            this.camera.rotationQuaternion = new Quaternion(cameraConfig.rotation.x || 0, cameraConfig.rotation.y || 0, cameraConfig.rotation.z || 0, cameraConfig.rotation.w || 0)
+        }
+
+        this.camera.minZ = cameraConfig.minZ || this.camera.minZ;
+        this.camera.maxZ = cameraConfig.maxZ || this.camera.maxZ;
+
+        if (cameraConfig.behaviors) {
+            for (let name in cameraConfig.behaviors) {
+                this.setCameraBehavior(cameraConfig.behaviors[name], focusMeshes);
+            }
+        };
+
+        const sceneExtends = this.scene.getWorldExtends();
+        const sceneDiagonal = sceneExtends.max.subtract(sceneExtends.min);
+        const sceneDiagonalLenght = sceneDiagonal.length();
+        this.camera.upperRadiusLimit = sceneDiagonalLenght * 3;
+    }
+
+    protected configureLights(lightsConfiguration: { [name: string]: ILightConfiguration | boolean } = {}, focusMeshes: Array<AbstractMesh> = this.scene.meshes) {
+        // sanity check!
+        if (!Object.keys(lightsConfiguration).length) return;
+
+        let lightsAvailable: Array<string> = this.scene.lights.map(light => light.name);
+
+        Object.keys(lightsConfiguration).forEach((name, idx) => {
+            let lightConfig: ILightConfiguration = { type: 0 };
+            if (typeof lightsConfiguration[name] === 'object') {
+                lightConfig = <ILightConfiguration>lightsConfiguration[name];
+            }
+
+            lightConfig.name = name;
+
+            let light;
+            // light is not already available
+            if (lightsAvailable.indexOf(name) === -1) {
+                let constructor = Light.GetConstructorFromName(lightConfig.type, lightConfig.name, this.scene);
+                if (!constructor) return;
+                light = constructor();
+            } else {
+                // available? get it from the scene
+                light = this.scene.getLightByName(name);
+                lightsAvailable = lightsAvailable.filter(ln => ln !== name);
+            }
+
+            // if config set the light to false, dispose it.
+            if (lightsConfiguration[name] === false) {
+                light.dispose();
+                return;
+            }
+
+            //enabled
+            if (light.isEnabled() !== !lightConfig.disabled) {
+                light.setEnabled(!lightConfig.disabled);
+            }
+
+            this.extendClassWithConfig(light, lightConfig);
+
+            //position. Some lights don't support shadows
+            if (light instanceof ShadowLight) {
+                let shadowGenerator = light.getShadowGenerator();
+                if (lightConfig.shadowEnabled && this.maxShadows) {
+                    if (!shadowGenerator) {
+                        shadowGenerator = new ShadowGenerator(512, light);
+                    }
+                    this.extendClassWithConfig(shadowGenerator, lightConfig.shadowConfig || {});
+                    // add the focues meshes to the shadow list
+                    let shadownMap = shadowGenerator.getShadowMap();
+                    if (!shadownMap) return;
+                    let renderList = shadownMap.renderList;
+                    for (var index = 0; index < focusMeshes.length; index++) {
+                        if (Tags.MatchesQuery(focusMeshes[index], 'castShadow')) {
+                            // renderList && renderList.push(focusMeshes[index]);
+                        }
+                    }
+                } else if (shadowGenerator) {
+                    shadowGenerator.dispose();
+                }
+            }
+        });
+
+        // remove the unneeded lights
+        /*lightsAvailable.forEach(name => {
+            let light = this.scene.getLightByName(name);
+            if (light) {
+                light.dispose();
+            }
+        });*/
+    }
+
+    protected configureModel(modelConfiguration: Partial<IModelConfiguration>, focusMeshes: Array<AbstractMesh> = this.scene.meshes) {
+        let meshesWithNoParent: Array<AbstractMesh> = focusMeshes.filter(m => !m.parent);
+        let updateMeshesWithNoParent = (variable: string, value: any, param?: string) => {
+            meshesWithNoParent.forEach(mesh => {
+                if (param) {
+                    mesh[variable][param] = value;
+                } else {
+                    mesh[variable] = value;
+                }
+            });
+        }
+        let updateXYZ = (variable: string, configValues: { x: number, y: number, z: number, w?: number }) => {
+            if (configValues.x !== undefined) {
+                updateMeshesWithNoParent(variable, configValues.x, 'x');
+            }
+            if (configValues.y !== undefined) {
+                updateMeshesWithNoParent(variable, configValues.y, 'y');
+            }
+            if (configValues.z !== undefined) {
+                updateMeshesWithNoParent(variable, configValues.z, 'z');
+            }
+            if (configValues.w !== undefined) {
+                updateMeshesWithNoParent(variable, configValues.w, 'w');
+            }
+        }
+        // position?
+        if (modelConfiguration.position) {
+            updateXYZ('position', modelConfiguration.position);
+        }
+        if (modelConfiguration.rotation) {
+            if (modelConfiguration.rotation.w) {
+                meshesWithNoParent.forEach(mesh => {
+                    if (!mesh.rotationQuaternion) {
+                        mesh.rotationQuaternion = new Quaternion();
+                    }
+                })
+                updateXYZ('rotationQuaternion', modelConfiguration.rotation);
+            } else {
+                updateXYZ('rotation', modelConfiguration.rotation);
+            }
+        }
+        if (modelConfiguration.scaling) {
+            updateXYZ('scaling', modelConfiguration.scaling);
+        }
+
+        if (modelConfiguration.castShadow) {
+            focusMeshes.forEach(mesh => {
+                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() {
+        window.removeEventListener('resize', this.resize);
+
+        this.sceneOptimizer.stop();
+        this.sceneOptimizer.dispose();
+
+        if (this.scene.activeCamera) {
+            this.scene.activeCamera.detachControl(this.canvas);
+        }
+
+        this.scene.dispose();
+        this.engine.dispose();
+
+        this.templateManager.dispose();
+    }
+
     protected abstract prepareContainerElement();
 
     /**
@@ -83,11 +604,33 @@ export abstract class AbstractViewer {
      * @memberof AbstractViewer
      */
     protected onTemplatesLoaded(): Promise<AbstractViewer> {
-        return this.initEngine().then(() => {
-            return this.loadModel();
-        }).then(() => {
-            return this;
-        });
+        return Promise.resolve(this);
+    }
+
+    /**
+     * This will force the creation of an engine and a scene.
+     * It will also load a model if preconfigured.
+     * But first - it will load the extendible onTemplateLoaded()!
+     */
+    private _onTemplateLoaded(): Promise<AbstractViewer> {
+        return this.onTemplatesLoaded().then(() => {
+            let autoLoadModel = !!this.configuration.model;
+            return this.initEngine().then((engine) => {
+                return this.onEngineInitObservable.notifyObserversWithPromise(engine);
+            }).then(() => {
+                if (autoLoadModel) {
+                    return this.loadModel();
+                } else {
+                    return this.scene || this.initScene();
+                }
+            }).then((scene) => {
+                return this.onSceneInitObservable.notifyObserversWithPromise(scene);
+            }).then(() => {
+                return this.onInitDoneObservable.notifyObserversWithPromise(this);
+            }).then(() => {
+                return this;
+            });
+        })
     }
 
     /**
@@ -98,31 +641,37 @@ export abstract class AbstractViewer {
      * @memberof Viewer
      */
     protected initEngine(): Promise<Engine> {
+
+        // init custom shaders
+        this.injectCustomShaders();
+
         let canvasElement = this.templateManager.getCanvas();
         if (!canvasElement) {
             return Promise.reject('Canvas element not found!');
         }
         let config = this.configuration.engine || {};
         // TDO enable further configuration
-        this.engine = new Engine(canvasElement, !!config.antialiasing);
+        this.engine = new Engine(canvasElement, !!config.antialiasing, config.engineOptions);
 
         // Disable manifest checking
         Database.IDBStorageEnabled = false;
 
-        window.addEventListener('resize', () => {
-            this.engine.resize();
-        });
+        if (!config.disableResize) {
+            window.addEventListener('resize', this.resize);
+        }
 
-        this.engine.runRenderLoop(() => {
-            this.scene && this.scene.render();
-        });
 
-        var scale = Math.max(0.5, 1 / (window.devicePixelRatio || 2));
-        this.engine.setHardwareScalingLevel(scale);
+        this.engine.runRenderLoop(this.render);
 
-        return this.onEngineInitObservable.notifyWithPromise(this.engine).then(() => {
-            return this.engine;
-        });
+        if (this.configuration.engine && this.configuration.engine.adaptiveQuality) {
+            var scale = Math.max(0.5, 1 / (window.devicePixelRatio || 2));
+            this.engine.setHardwareScalingLevel(scale);
+        }
+
+        // set hardware limitations for scene initialization
+        this.handleHardwareLimitations();
+
+        return Promise.resolve(this.engine);
     }
 
     protected initScene(): Promise<Scene> {
@@ -135,38 +684,196 @@ export abstract class AbstractViewer {
         // create a new scene
         this.scene = new Scene(this.engine);
         // make sure there is a default camera and light.
-        this.scene.createDefaultCameraOrLight(true, true, true);
-        if (this.configuration.scene && this.configuration.scene.debug) {
-            this.scene.debugLayer.show();
+        this.scene.createDefaultLight(true);
+
+        if (this.configuration.scene) {
+            this.configureScene(this.configuration.scene);
+
+            // Scene optimizer
+            if (this.configuration.optimizer) {
+                this.configureOptimizer(this.configuration.optimizer);
+            }
         }
-        return this.onSceneInitObservable.notifyWithPromise(this.scene).then(() => {
-            return this.scene;
-        });
+
+        return Promise.resolve(this.scene);
     }
 
     public loadModel(model: any = this.configuration.model, clearScene: boolean = true): Promise<Scene> {
+        this.configuration.model = model;
         let modelUrl = (typeof model === 'string') ? model : model.url;
         let parts = modelUrl.split('/');
         let filename = parts.pop();
         let base = parts.join('/') + '/';
         let plugin = (typeof model === 'string') ? undefined : model.loader;
 
-        return Promise.resolve().then(() => {
-            if (!this.scene || clearScene) return this.initScene();
-            else return this.scene;
+        return Promise.resolve(this.scene).then((scene) => {
+            if (!scene) return this.initScene();
+
+            if (clearScene) {
+                scene.meshes.forEach(mesh => {
+                    mesh.dispose();
+                });
+            }
+            return scene!;
         }).then(() => {
             return new Promise<Array<AbstractMesh>>((resolve, reject) => {
-                SceneLoader.ImportMesh(undefined, base, filename, this.scene, (meshes) => {
+                this.lastUsedLoader = SceneLoader.ImportMesh(undefined, base, filename, this.scene, (meshes) => {
                     resolve(meshes);
-                }, undefined, (e, m, exception) => {
-                    console.log(m, exception);
-                    reject(m);
-                }, plugin);
+                }, (progressEvent) => {
+                    this.onModelLoadProgressObservable.notifyObserversWithPromise(progressEvent);
+                }, (e, m, exception) => {
+                    // console.log(m, exception);
+                    this.onModelLoadErrorObservable.notifyObserversWithPromise({ message: m, exception: exception }).then(() => {
+                        reject(exception);
+                    });
+                }, plugin)!;
+                this.onLoaderInitObservable.notifyObserversWithPromise(this.lastUsedLoader);
             });
         }).then((meshes: Array<AbstractMesh>) => {
-            return this.onModelLoadedObservable.notifyWithPromise(meshes).then(() => {
-                return this.scene;
+            return this.onModelLoadedObservable.notifyObserversWithPromise(meshes)
+                .then(() => {
+                    // update the models' configuration
+                    this.configureModel(model, meshes);
+                    this.configureLights(this.configuration.lights);
+
+                    if (this.configuration.camera) {
+                        this.configureCamera(this.configuration.camera, meshes);
+                    }
+                    return this.initEnvironment(meshes);
+                }).then(() => {
+                    return this.scene;
+                });
+        });
+    }
+
+    protected initEnvironment(focusMeshes: Array<AbstractMesh> = []): Promise<Scene> {
+        this.configureEnvironment(this.configuration.skybox, this.configuration.ground);
+
+        return Promise.resolve(this.scene);
+    }
+
+    /**
+		 * Alters render settings to reduce features based on hardware feature limitations
+		 * @param options Viewer options to modify
+		 */
+    protected handleHardwareLimitations() {
+        //flip rendering settings switches based on hardware support
+        let maxVaryingRows = this.engine.getCaps().maxVaryingVectors;
+        let maxFragmentSamplers = this.engine.getCaps().maxTexturesImageUnits;
+
+        //shadows are disabled if there's not enough varyings for a single shadow
+        if ((maxVaryingRows < 8) || (maxFragmentSamplers < 8)) {
+            this.maxShadows = 0;
+        } else {
+            this.maxShadows = 3;
+        }
+
+        //can we render to any >= 16-bit targets (required for HDR)
+        let caps = this.engine.getCaps();
+        let linearHalfFloatTargets = caps.textureHalfFloatRender && caps.textureHalfFloatLinearFiltering;
+        let linearFloatTargets = caps.textureFloatRender && caps.textureFloatLinearFiltering;
+
+        let supportsHDR: boolean = !!(linearFloatTargets || linearHalfFloatTargets);
+
+        if (linearHalfFloatTargets) {
+            this.defaultHighpTextureType = Engine.TEXTURETYPE_HALF_FLOAT;
+            this.shadowGeneratorBias = 0.002;
+        } else if (linearFloatTargets) {
+            this.defaultHighpTextureType = Engine.TEXTURETYPE_FLOAT;
+            this.shadowGeneratorBias = 0.001;
+        } else {
+            this.defaultHighpTextureType = Engine.TEXTURETYPE_UNSIGNED_INT;
+            this.shadowGeneratorBias = 0.001;
+        }
+
+        this.defaultPipelineTextureType = supportsHDR ? this.defaultHighpTextureType : Engine.TEXTURETYPE_UNSIGNED_INT;
+    }
+
+    /**
+     * Injects all the spectre shader in the babylon shader store
+     */
+    protected injectCustomShaders(): void {
+        let customShaders = this.configuration.customShaders;
+        // Inject all the spectre shader in the babylon shader store.
+        if (!customShaders) {
+            return;
+        }
+        if (customShaders.shaders) {
+            Object.keys(customShaders.shaders).forEach(key => {
+                // typescript considers a callback "unsafe", so... '!'
+                Effect.ShadersStore[key] = customShaders!.shaders![key];
             });
+        }
+        if (customShaders.includes) {
+            Object.keys(customShaders.includes).forEach(key => {
+                // typescript considers a callback "unsafe", so... '!'
+                Effect.IncludesShadersStore[key] = customShaders!.includes![key];
+            });
+        }
+    }
+
+    protected extendClassWithConfig(object: any, config: any) {
+        if (!config) return;
+        Object.keys(config).forEach(key => {
+            if (key in object && typeof object[key] !== 'function') {
+                if (typeof object[key] === 'function') return;
+                // if it is an object, iterate internally until reaching basic types
+                if (typeof object[key] === 'object') {
+                    this.extendClassWithConfig(object[key], config[key]);
+                } else {
+                    object[key] = config[key];
+                }
+            }
         });
     }
+
+    private setCameraBehavior(behaviorConfig: number | {
+        type: number;
+        [propName: string]: any;
+    }, payload: any) {
+
+        let behavior: Behavior<ArcRotateCamera> | null;
+        let type = (typeof behaviorConfig !== "object") ? behaviorConfig : behaviorConfig.type;
+
+        let config: { [propName: string]: any } = (typeof behaviorConfig === "object") ? behaviorConfig : {};
+
+        // constructing behavior
+        switch (type) {
+            case CameraBehavior.AUTOROTATION:
+                behavior = new AutoRotationBehavior();
+                break;
+            case CameraBehavior.BOUNCING:
+                behavior = new BouncingBehavior();
+                break;
+            case CameraBehavior.FRAMING:
+                behavior = new FramingBehavior();
+                break;
+            default:
+                behavior = null;
+                break;
+        }
+
+        if (behavior) {
+            if (typeof behaviorConfig === "object") {
+                this.extendClassWithConfig(behavior, behaviorConfig);
+            }
+            this.camera.addBehavior(behavior);
+        }
+
+        // post attach configuration. Some functionalities require the attached camera.
+        switch (type) {
+            case CameraBehavior.AUTOROTATION:
+                break;
+            case CameraBehavior.BOUNCING:
+                break;
+            case CameraBehavior.FRAMING:
+                if (config.zoomOnBoundingInfo) {
+                    //payload is an array of meshes
+                    let meshes = <Array<AbstractMesh>>payload;
+                    let bounding = meshes[0].getHierarchyBoundingVectors();
+                    (<FramingBehavior>behavior).zoomOnBoundingInfo(bounding.min, bounding.max);
+                }
+                break;
+        }
+    }
 }

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

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

+ 21 - 9
Viewer/tsconfig.json

@@ -2,25 +2,37 @@
     "compilerOptions": {
         "target": "es5",
         "module": "commonjs",
-        "noResolve": true,
+        "noResolve": false,
         "noImplicitAny": false, //mainly due to usage of external libs without typings.
         "strictNullChecks": true,
         "removeComments": true,
         "preserveConstEnums": true,
-        "sourceMap": true,
+        "sourceMap": false,
         "experimentalDecorators": true,
         "isolatedModules": false,
+        "declaration": false,
         "lib": [
             "dom",
             "es2015.promise",
             "es5"
         ],
-        //"declaration": true,
-        "outDir": "./temp/",
         "types": [
-            "node",
-            "babylonjs",
-            "babylonjs-loaders"
-        ]
-    }
+            "node"
+        ],
+        "baseUrl": ".",
+        "paths": {
+            "babylonjs": [
+                "../dist/preview release/babylon.max.js",
+                "../dist/preview release/babylon.d.ts"
+            ],
+            "babylonjs-loaders": [
+                "../dist/preview release/loaders/babylonjs.loaders.js",
+                "../dist/preview release/loaders/babylonjs.loaders.module.d.ts"
+            ]
+        }
+    },
+    "exclude": [
+        "node_modules",
+        "dist"
+    ]
 }

+ 13 - 9
Viewer/webpack.config.js

@@ -1,11 +1,9 @@
-const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
 const path = require('path');
 const webpack = require('webpack');
 
 module.exports = {
     entry: {
-        'viewer': './src/index.ts',
-        'viewer.min': './src/index.ts',
+        'viewer': './src/index.ts'
     },
     output: {
         path: path.resolve(__dirname, 'dist'),
@@ -16,17 +14,23 @@ module.exports = {
         devtoolModuleFilenameTemplate: '[absolute-resource-path]'
     },
     resolve: {
-        extensions: ['.ts', '.tsx', '.js']
+        extensions: ['.ts', '.js'],
+        alias: {
+            "babylonjs": __dirname + '/../dist/preview release/babylon.max.js',
+            "babylonjs-materials": __dirname + '/../dist/preview release/materialsLibrary/babylonjs.materials.js',
+            "babylonjs-loaders": __dirname + '/../dist/preview release/loaders/babylonjs.loaders.js',
+            "deepmerge": __dirname + '/assets/deepmerge.min.js'
+        }
+    },
+    externals: {
+        // until physics will be integrated in the viewer, ignore cannon
+        cannon: 'CANNON'
     },
     devtool: 'source-map',
     plugins: [
         new webpack.WatchIgnorePlugin([
             /\.d\.ts$/
-        ]),
-        new UglifyJSPlugin({
-            parallel: true,
-            test: /\.min\.js$/i,
-        })
+        ])
     ],
     module: {
         loaders: [{

+ 1 - 1
Viewer/webpack.gulp.config.js

@@ -19,7 +19,7 @@ module.exports = {
             "babylonjs": __dirname + '/../dist/preview release/babylon.max.js',
             "babylonjs-materials": __dirname + '/../dist/preview release/materialsLibrary/babylonjs.materials.js',
             "babylonjs-loaders": __dirname + '/../dist/preview release/loaders/babylonjs.loaders.js',
-            "es6-promise": __dirname + '/assets/es6-promise.min.js',
+            // "es6-promise": __dirname + '/assets/es6-promise.min.js',
             "deepmerge": __dirname + '/assets/deepmerge.min.js',
         }
     },

+ 2 - 0
assets/meshes/controllers/_redirects

@@ -0,0 +1,2 @@
+# Redirect microsoft controllers if ID was not found on the server
+/microsoft/*/:controller.glb   /microsoft/default/:controller.glb   200

Fichier diff supprimé car celui-ci est trop grand
+ 5032 - 5032
dist/babylon.d.ts


+ 248 - 0
dist/babylon.glTF2Interface.d.ts

@@ -0,0 +1,248 @@
+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[];
+    }
+}

Fichier diff supprimé car celui-ci est trop grand
+ 16 - 16
dist/babylon.js


+ 51 - 47
dist/babylon.max.js

@@ -8601,7 +8601,7 @@ var BABYLON;
         });
         Object.defineProperty(Engine, "Version", {
             get: function () {
-                return "3.1";
+                return "3.1.1";
             },
             enumerable: true,
             configurable: true
@@ -14106,6 +14106,13 @@ var BABYLON;
              * True if the mesh must be rendered in any case.
              */
             _this.alwaysSelectAsActiveMesh = false;
+            /**
+             * This scene's action manager
+             * @type {BABYLON.ActionManager}
+            */
+            _this.actionManager = null;
+            // Physics
+            _this.physicsImpostor = null;
             // Collisions
             _this._checkCollisions = false;
             _this._collisionMask = -1;
@@ -36276,8 +36283,8 @@ var BABYLON;
                         defines.REFRACTION = true;
                         defines.REFRACTIONMAP_3D = refractionTexture.isCube;
                         defines.GAMMAREFRACTION = refractionTexture.gammaSpace;
-                        defines.REFRACTIONMAP_OPPOSITEZ = reflectionTexture.invertZ;
-                        defines.LODINREFRACTIONALPHA = reflectionTexture.lodLevelInAlpha;
+                        defines.REFRACTIONMAP_OPPOSITEZ = refractionTexture.invertZ;
+                        defines.LODINREFRACTIONALPHA = refractionTexture.lodLevelInAlpha;
                         if (this._linkRefractionWithTransparency) {
                             defines.LINKREFRACTIONTOTRANSPARENCY = true;
                         }
@@ -57259,10 +57266,6 @@ var BABYLON;
             };
             _this._buttons = new Array(vrGamepad.buttons.length);
             _this.hand = vrGamepad.hand;
-            if (!_this.hand) {
-                _this.hand = (WebVRController.handCounter % 2 == 0) ? "left" : "right";
-                WebVRController.handCounter++;
-            }
             return _this;
         }
         WebVRController.prototype.onButtonStateChange = function (callback) {
@@ -57328,7 +57331,6 @@ var BABYLON;
             this.onPadStateChangedObservable.clear();
             this.onPadValuesChangedObservable.clear();
         };
-        WebVRController.handCounter = 0;
         return WebVRController;
     }(BABYLON.PoseEnabledController));
     BABYLON.WebVRController = WebVRController;
@@ -71667,12 +71669,6 @@ var BABYLON;
                                     }
                                 });
                             }
-                            // Move starting headset position by standing matrix
-                            _this._deviceToWorld.multiplyToRef(_this._standingMatrix, _this._deviceToWorld);
-                            // Correct for default height added originally
-                            var pos = _this._deviceToWorld.getTranslation();
-                            pos.y -= _this._defaultHeight;
-                            _this._deviceToWorld.setTranslation(pos);
                             callback(true);
                         }
                     });
@@ -72015,23 +72011,23 @@ var BABYLON;
                     if (_this.controllers.indexOf(webVrController_1) === -1) {
                         //add to the controllers array
                         _this.controllers.push(webVrController_1);
-                        //did we find enough controllers? Great! let the developer know.
-                        if (_this.controllers.length >= 2) {
-                            // Forced to add some control code for Vive as it doesn't always fill properly the "hand" property
-                            // Sometimes, both controllers are set correctly (left and right), sometimes none, sometimes only one of them...
-                            // So we're overriding setting left & right manually to be sure
-                            var firstViveWandDetected = false;
-                            for (var i = 0; i < _this.controllers.length; i++) {
-                                if (_this.controllers[i].controllerType === BABYLON.PoseEnabledControllerType.VIVE) {
-                                    if (!firstViveWandDetected) {
-                                        firstViveWandDetected = true;
-                                        _this.controllers[i].hand = "left";
-                                    }
-                                    else {
-                                        _this.controllers[i].hand = "right";
-                                    }
+                        // Forced to add some control code for Vive as it doesn't always fill properly the "hand" property
+                        // Sometimes, both controllers are set correctly (left and right), sometimes none, sometimes only one of them...
+                        // So we're overriding setting left & right manually to be sure
+                        var firstViveWandDetected = false;
+                        for (var i = 0; i < _this.controllers.length; i++) {
+                            if (_this.controllers[i].controllerType === BABYLON.PoseEnabledControllerType.VIVE) {
+                                if (!firstViveWandDetected) {
+                                    firstViveWandDetected = true;
+                                    _this.controllers[i].hand = "left";
+                                }
+                                else {
+                                    _this.controllers[i].hand = "right";
                                 }
                             }
+                        }
+                        //did we find enough controllers? Great! let the developer know.
+                        if (_this.controllers.length >= 2) {
                             _this.onControllersAttachedObservable.notifyObservers(_this.controllers);
                         }
                     }
@@ -72391,6 +72387,31 @@ var BABYLON;
                         });
                     }
                 }
+                else {
+                    var webVRController = gamepad;
+                    _this._tryEnableInteractionOnController(webVRController);
+                }
+            };
+            // This only succeeds if the controller's mesh exists for the controller so this must be called whenever new controller is connected or when mesh is loaded
+            this._tryEnableInteractionOnController = function (webVRController) {
+                if (webVRController.hand === "left") {
+                    _this._leftControllerReady = true;
+                    if (_this._interactionsRequested && !_this._interactionsEnabledOnLeftController) {
+                        _this._enableInteractionOnController(webVRController);
+                    }
+                    if (_this._teleportationRequested && !_this._teleportationEnabledOnLeftController) {
+                        _this._enableTeleportationOnController(webVRController);
+                    }
+                }
+                if (webVRController.hand === "right") {
+                    _this._rightControllerReady = true;
+                    if (_this._interactionsRequested && !_this._interactionsEnabledOnRightController) {
+                        _this._enableInteractionOnController(webVRController);
+                    }
+                    if (_this._teleportationRequested && !_this._teleportationEnabledOnRightController) {
+                        _this._enableTeleportationOnController(webVRController);
+                    }
+                }
             };
             this._onNewGamepadDisconnected = function (gamepad) {
                 if (gamepad instanceof BABYLON.WebVRController) {
@@ -72654,24 +72675,7 @@ var BABYLON;
         });
         // Raised when one of the controller has loaded successfully its associated default mesh
         VRExperienceHelper.prototype._onDefaultMeshLoaded = function (webVRController) {
-            if (webVRController.hand === "left") {
-                this._leftControllerReady = true;
-                if (this._interactionsRequested && !this._interactionsEnabledOnLeftController) {
-                    this._enableInteractionOnController(webVRController);
-                }
-                if (this._teleportationRequested && !this._teleportationEnabledOnLeftController) {
-                    this._enableTeleportationOnController(webVRController);
-                }
-            }
-            if (webVRController.hand === "right") {
-                this._rightControllerReady = true;
-                if (this._interactionsRequested && !this._interactionsEnabledOnRightController) {
-                    this._enableInteractionOnController(webVRController);
-                }
-                if (this._teleportationRequested && !this._teleportationEnabledOnRightController) {
-                    this._enableTeleportationOnController(webVRController);
-                }
-            }
+            this._tryEnableInteractionOnController(webVRController);
             try {
                 this.onControllerMeshLoaded.notifyObservers(webVRController);
             }

Fichier diff supprimé car celui-ci est trop grand
+ 16 - 16
dist/babylon.worker.js


+ 1 - 1
dist/gui/package.json

@@ -4,7 +4,7 @@
     },
     "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.",
-    "version": "3.1.0-rc-0",
+    "version": "3.1.0",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/inspector/package.json

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

+ 1 - 1
dist/loaders/package.json

@@ -4,7 +4,7 @@
     },
     "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.",
-    "version": "3.1.0-rc-0",
+    "version": "3.1.0",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/materialsLibrary/package.json

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

+ 1 - 1
dist/postProcessesLibrary/package.json

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

Fichier diff supprimé car celui-ci est trop grand
+ 14111 - 7106
dist/preview release/babylon.d.ts


Fichier diff supprimé car celui-ci est trop grand
+ 56 - 54
dist/preview release/babylon.js


Fichier diff supprimé car celui-ci est trop grand
+ 39591 - 30636
dist/preview release/babylon.max.js


Fichier diff supprimé car celui-ci est trop grand
+ 19088 - 0
dist/preview release/babylon.module.d.ts


Fichier diff supprimé car celui-ci est trop grand
+ 57 - 55
dist/preview release/babylon.worker.js


Fichier diff supprimé car celui-ci est trop grand
+ 18733 - 11630
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


Fichier diff supprimé car celui-ci est trop grand
+ 58 - 56
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


Fichier diff supprimé car celui-ci est trop grand
+ 40798 - 32076
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js


Fichier diff supprimé car celui-ci est trop grand
+ 48882 - 64807
Viewer/dist/viewer.js


Fichier diff supprimé car celui-ci est trop grand
+ 89225 - 0
dist/preview release/es6.js


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

@@ -56,6 +56,17 @@ declare module BABYLON.GUI {
         private _manageFocus();
         private _attachToOnPointerOut(scene);
         static CreateForMesh(mesh: AbstractMesh, width?: number, height?: number, supportPointerMove?: boolean): AdvancedDynamicTexture;
+        /**
+         * FullScreenUI is created in a layer. This allows it to be treated like any other layer.
+         * As such, if you have a multi camera setup, you can set the layerMask on the GUI as well.
+         * When the GUI is not Created as FullscreenUI it does not respect the layerMask.
+         * layerMask is set through advancedTexture.layer.layerMask
+         * @param name name for the Texture
+         * @param foreground render in foreground (default is true)
+         * @param scene scene to be rendered in
+         * @param sampling method for scaling to fit screen
+         * @returns AdvancedDynamicTexture
+         */
         static CreateFullscreenUI(name: string, foreground?: boolean, scene?: Nullable<Scene>, sampling?: number): AdvancedDynamicTexture;
     }
 }
@@ -425,7 +436,19 @@ declare module BABYLON.GUI {
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _measure(): 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;
     }
 }
 
@@ -441,6 +464,7 @@ declare module BABYLON.GUI {
         private _borderColor;
         private _barOffset;
         private _isThumbCircle;
+        private _isThumbClamped;
         onValueChangedObservable: Observable<number>;
         borderColor: string;
         background: string;
@@ -452,6 +476,7 @@ declare module BABYLON.GUI {
         maximum: number;
         value: number;
         isThumbCircle: boolean;
+        isThumbClamped: boolean;
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
@@ -507,6 +532,9 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class TextBlock extends Control {
+        /**
+         * Defines the name of the control
+         */
         name: string | undefined;
         private _text;
         private _textWrapping;
@@ -514,20 +542,94 @@ declare module BABYLON.GUI {
         private _textVerticalAlignment;
         private _lines;
         private _resizeToFit;
+        private _lineSpacing;
+        private _outlineWidth;
+        private _outlineColor;
         /**
         * An event triggered after the text is changed
         * @type {BABYLON.Observable}
         */
         onTextChangedObservable: Observable<TextBlock>;
+        /**
+        * An event triggered after the text was broken up into lines
+        * @type {BABYLON.Observable}
+        */
+        onLinesReadyObservable: Observable<TextBlock>;
+        /**
+         * Return the line list (you may need to use the onLinesReadyObservable to make sure the list is ready)
+         */
+        readonly lines: any[];
+        /**
+         * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
+         */
+        /**
+         * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
+         */
         resizeToFit: boolean;
+        /**
+         * Gets or sets a boolean indicating if text must be wrapped
+         */
+        /**
+         * Gets or sets a boolean indicating if text must be wrapped
+         */
         textWrapping: boolean;
+        /**
+         * Gets or sets text to display
+         */
+        /**
+         * Gets or sets text to display
+         */
         text: string;
+        /**
+         * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
+         */
+        /**
+         * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
+         */
         textHorizontalAlignment: number;
+        /**
+         * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
+         */
+        /**
+         * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
+         */
         textVerticalAlignment: number;
-        constructor(name?: string | undefined, text?: string);
+        /**
+         * Gets or sets line spacing value
+         */
+        /**
+         * Gets or sets line spacing value
+         */
+        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
+         * @param name defines the name of the control
+         * @param text defines the text to display (emptry string by default)
+         */
+        constructor(
+            /**
+             * Defines the name of the control
+             */
+            name?: string | undefined, text?: string);
         protected _getTypeName(): string;
         private _drawText(text, textWidth, y, context);
+        /** @ignore */
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+        protected _applyStates(context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _parseLine(line: string | undefined, context: CanvasRenderingContext2D): object;
         protected _parseLineWithTextWrapping(line: string | undefined, context: CanvasRenderingContext2D): object;

+ 229 - 23
dist/preview release/gui/babylon.gui.js

@@ -476,6 +476,17 @@ var BABYLON;
                 result.attachToMesh(mesh, supportPointerMove);
                 return result;
             };
+            /**
+             * FullScreenUI is created in a layer. This allows it to be treated like any other layer.
+             * As such, if you have a multi camera setup, you can set the layerMask on the GUI as well.
+             * When the GUI is not Created as FullscreenUI it does not respect the layerMask.
+             * layerMask is set through advancedTexture.layer.layerMask
+             * @param name name for the Texture
+             * @param foreground render in foreground (default is true)
+             * @param scene scene to be rendered in
+             * @param sampling method for scaling to fit screen
+             * @returns AdvancedDynamicTexture
+             */
             AdvancedDynamicTexture.CreateFullscreenUI = function (name, foreground, scene, sampling) {
                 if (foreground === void 0) { foreground = true; }
                 if (scene === void 0) { scene = null; }
@@ -2589,11 +2600,48 @@ var BABYLON;
                 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;
             };
-            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;
         }(GUI.Control));
@@ -2622,6 +2670,7 @@ var BABYLON;
                 _this._borderColor = "white";
                 _this._barOffset = new GUI.ValueAndUnit(5, GUI.ValueAndUnit.UNITMODE_PIXEL, false);
                 _this._isThumbCircle = false;
+                _this._isThumbClamped = false;
                 _this.onValueChangedObservable = new BABYLON.Observable();
                 // Events
                 _this._pointerIsDown = false;
@@ -2760,6 +2809,20 @@ var BABYLON;
                 enumerable: true,
                 configurable: true
             });
+            Object.defineProperty(Slider.prototype, "isThumbClamped", {
+                get: function () {
+                    return this._isThumbClamped;
+                },
+                set: function (value) {
+                    if (this._isThumbClamped === value) {
+                        return;
+                    }
+                    this._isThumbClamped = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
             Slider.prototype._getTypeName = function () {
                 return "Slider";
             };
@@ -2770,12 +2833,6 @@ var BABYLON;
                     // Main bar
                     var effectiveThumbWidth;
                     var effectiveBarOffset;
-                    if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
-                        context.shadowColor = this.shadowColor;
-                        context.shadowBlur = this.shadowBlur;
-                        context.shadowOffsetX = this.shadowOffsetX;
-                        context.shadowOffsetY = this.shadowOffsetY;
-                    }
                     if (this._thumbWidth.isPixel) {
                         effectiveThumbWidth = Math.min(this._thumbWidth.getValue(this._host), this._currentMeasure.width);
                     }
@@ -2788,29 +2845,43 @@ var BABYLON;
                     else {
                         effectiveBarOffset = this._currentMeasure.height * this._barOffset.getValue(this._host);
                     }
-                    var left = this._currentMeasure.left + effectiveThumbWidth / 2;
+                    if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
+                        context.shadowColor = this.shadowColor;
+                        context.shadowBlur = this.shadowBlur;
+                        context.shadowOffsetX = this.shadowOffsetX;
+                        context.shadowOffsetY = this.shadowOffsetY;
+                    }
+                    var left = this._currentMeasure.left;
                     var width = this._currentMeasure.width - effectiveThumbWidth;
-                    var thumbPosition = (this._value - this._minimum) / (this._maximum - this._minimum) * width;
-                    // Bar
+                    var thumbPosition = ((this._value - this._minimum) / (this._maximum - this._minimum)) * width;
                     context.fillStyle = this._background;
-                    context.fillRect(left, this._currentMeasure.top + effectiveBarOffset, width, this._currentMeasure.height - effectiveBarOffset * 2);
+                    if (this.isThumbClamped) {
+                        context.fillRect(left, this._currentMeasure.top + effectiveBarOffset, width + effectiveThumbWidth, this._currentMeasure.height - effectiveBarOffset * 2);
+                    }
+                    else {
+                        context.fillRect(left + (effectiveThumbWidth / 2), this._currentMeasure.top + effectiveBarOffset, width, this._currentMeasure.height - effectiveBarOffset * 2);
+                    }
                     if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
                         context.shadowBlur = 0;
                         context.shadowOffsetX = 0;
                         context.shadowOffsetY = 0;
                     }
                     context.fillStyle = this.color;
-                    context.fillRect(left, this._currentMeasure.top + effectiveBarOffset, thumbPosition, this._currentMeasure.height - effectiveBarOffset * 2);
+                    if (this.isThumbClamped) {
+                        context.fillRect(left, this._currentMeasure.top + effectiveBarOffset, thumbPosition, this._currentMeasure.height - effectiveBarOffset * 2);
+                    }
+                    else {
+                        context.fillRect(left + (effectiveThumbWidth / 2), this._currentMeasure.top + effectiveBarOffset, thumbPosition, this._currentMeasure.height - effectiveBarOffset * 2);
+                    }
                     if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
                         context.shadowColor = this.shadowColor;
                         context.shadowBlur = this.shadowBlur;
                         context.shadowOffsetX = this.shadowOffsetX;
                         context.shadowOffsetY = this.shadowOffsetY;
                     }
-                    // Thumb
                     if (this._isThumbCircle) {
                         context.beginPath();
-                        context.arc(left + thumbPosition, this._currentMeasure.top + this._currentMeasure.height / 2, effectiveThumbWidth / 2, 0, 2 * Math.PI);
+                        context.arc(left + thumbPosition + (effectiveThumbWidth / 2), this._currentMeasure.top + this._currentMeasure.height / 2, effectiveThumbWidth / 2, 0, 2 * Math.PI);
                         context.fill();
                         if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
                             context.shadowBlur = 0;
@@ -2821,14 +2892,14 @@ var BABYLON;
                         context.stroke();
                     }
                     else {
-                        context.fillRect(left + thumbPosition - effectiveThumbWidth / 2, this._currentMeasure.top, effectiveThumbWidth, this._currentMeasure.height);
+                        context.fillRect(left + thumbPosition, this._currentMeasure.top, effectiveThumbWidth, this._currentMeasure.height);
                         if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
                             context.shadowBlur = 0;
                             context.shadowOffsetX = 0;
                             context.shadowOffsetY = 0;
                         }
                         context.strokeStyle = this._borderColor;
-                        context.strokeRect(left + thumbPosition - effectiveThumbWidth / 2, this._currentMeasure.top, effectiveThumbWidth, this._currentMeasure.height);
+                        context.strokeRect(left + thumbPosition, this._currentMeasure.top, effectiveThumbWidth, this._currentMeasure.height);
                     }
                 }
                 context.restore();
@@ -3151,7 +3222,16 @@ var BABYLON;
     (function (GUI) {
         var TextBlock = /** @class */ (function (_super) {
             __extends(TextBlock, _super);
-            function TextBlock(name, text) {
+            /**
+             * Creates a new TextBlock object
+             * @param name defines the name of the control
+             * @param text defines the text to display (emptry string by default)
+             */
+            function TextBlock(
+                /**
+                 * Defines the name of the control
+                 */
+                name, text) {
                 if (text === void 0) { text = ""; }
                 var _this = _super.call(this, name) || this;
                 _this.name = name;
@@ -3160,18 +3240,42 @@ var BABYLON;
                 _this._textHorizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_CENTER;
                 _this._textVerticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_CENTER;
                 _this._resizeToFit = false;
+                _this._lineSpacing = new GUI.ValueAndUnit(0);
+                _this._outlineWidth = 0;
+                _this._outlineColor = "white";
                 /**
                 * An event triggered after the text is changed
                 * @type {BABYLON.Observable}
                 */
                 _this.onTextChangedObservable = new BABYLON.Observable();
+                /**
+                * An event triggered after the text was broken up into lines
+                * @type {BABYLON.Observable}
+                */
+                _this.onLinesReadyObservable = new BABYLON.Observable();
                 _this.text = text;
                 return _this;
             }
+            Object.defineProperty(TextBlock.prototype, "lines", {
+                /**
+                 * Return the line list (you may need to use the onLinesReadyObservable to make sure the list is ready)
+                 */
+                get: function () {
+                    return this._lines;
+                },
+                enumerable: true,
+                configurable: true
+            });
             Object.defineProperty(TextBlock.prototype, "resizeToFit", {
+                /**
+                 * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
+                 */
                 get: function () {
                     return this._resizeToFit;
                 },
+                /**
+                 * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
+                 */
                 set: function (value) {
                     this._resizeToFit = value;
                     if (this._resizeToFit) {
@@ -3183,9 +3287,15 @@ var BABYLON;
                 configurable: true
             });
             Object.defineProperty(TextBlock.prototype, "textWrapping", {
+                /**
+                 * Gets or sets a boolean indicating if text must be wrapped
+                 */
                 get: function () {
                     return this._textWrapping;
                 },
+                /**
+                 * Gets or sets a boolean indicating if text must be wrapped
+                 */
                 set: function (value) {
                     if (this._textWrapping === value) {
                         return;
@@ -3197,9 +3307,15 @@ var BABYLON;
                 configurable: true
             });
             Object.defineProperty(TextBlock.prototype, "text", {
+                /**
+                 * Gets or sets text to display
+                 */
                 get: function () {
                     return this._text;
                 },
+                /**
+                 * Gets or sets text to display
+                 */
                 set: function (value) {
                     if (this._text === value) {
                         return;
@@ -3212,9 +3328,15 @@ var BABYLON;
                 configurable: true
             });
             Object.defineProperty(TextBlock.prototype, "textHorizontalAlignment", {
+                /**
+                 * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
+                 */
                 get: function () {
                     return this._textHorizontalAlignment;
                 },
+                /**
+                 * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
+                 */
                 set: function (value) {
                     if (this._textHorizontalAlignment === value) {
                         return;
@@ -3226,9 +3348,15 @@ var BABYLON;
                 configurable: true
             });
             Object.defineProperty(TextBlock.prototype, "textVerticalAlignment", {
+                /**
+                 * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
+                 */
                 get: function () {
                     return this._textVerticalAlignment;
                 },
+                /**
+                 * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
+                 */
                 set: function (value) {
                     if (this._textVerticalAlignment === value) {
                         return;
@@ -3239,6 +3367,64 @@ var BABYLON;
                 enumerable: true,
                 configurable: true
             });
+            Object.defineProperty(TextBlock.prototype, "lineSpacing", {
+                /**
+                 * Gets or sets line spacing value
+                 */
+                get: function () {
+                    return this._lineSpacing.toString(this._host);
+                },
+                /**
+                 * Gets or sets line spacing value
+                 */
+                set: function (value) {
+                    if (this._lineSpacing.fromString(value)) {
+                        this._markAsDirty();
+                    }
+                },
+                enumerable: 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 () {
                 return "TextBlock";
             };
@@ -3262,8 +3448,12 @@ var BABYLON;
                     context.shadowOffsetX = this.shadowOffsetX;
                     context.shadowOffsetY = this.shadowOffsetY;
                 }
+                if (this.outlineWidth) {
+                    context.strokeText(text, this._currentMeasure.left + x, y);
+                }
                 context.fillText(text, this._currentMeasure.left + x, y);
             };
+            /** @ignore */
             TextBlock.prototype._draw = function (parentMeasure, context) {
                 context.save();
                 this._applyStates(context);
@@ -3273,6 +3463,13 @@ var BABYLON;
                 }
                 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) {
                 this._lines = [];
                 var _lines = this.text.split("\n");
@@ -3288,6 +3485,7 @@ var BABYLON;
                         this._lines.push(this._parseLine(_line, context));
                     }
                 }
+                this.onLinesReadyObservable.notifyObservers(this);
             };
             TextBlock.prototype._parseLine = function (line, context) {
                 if (line === void 0) { line = ''; }
@@ -3333,8 +3531,16 @@ var BABYLON;
                 }
                 rootY += this._currentMeasure.top;
                 var maxLineWidth = 0;
-                for (var _i = 0, _a = this._lines; _i < _a.length; _i++) {
-                    var line = _a[_i];
+                for (var i = 0; i < this._lines.length; i++) {
+                    var line = this._lines[i];
+                    if (i !== 0 && this._lineSpacing.internalValue !== 0) {
+                        if (this._lineSpacing.isPixel) {
+                            rootY += this._lineSpacing.getValue(this._host);
+                        }
+                        else {
+                            rootY = rootY + (this._lineSpacing.getValue(this._host) * this._height.getValueInPixel(this._host, this._cachedParentMeasure.height));
+                        }
+                    }
                     this._drawText(line.text, line.width, rootY, context);
                     rootY += this._fontOffset.height;
                     if (line.width > maxLineWidth)

Fichier diff supprimé car celui-ci est trop grand
+ 3 - 3
dist/preview release/gui/babylon.gui.min.js


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

@@ -1,5 +1,6 @@
 /// <reference types="babylonjs"/>
 
+
 declare module 'babylonjs-gui' { 
     export = BABYLON.GUI; 
 }
@@ -61,6 +62,17 @@ declare module BABYLON.GUI {
         private _manageFocus();
         private _attachToOnPointerOut(scene);
         static CreateForMesh(mesh: AbstractMesh, width?: number, height?: number, supportPointerMove?: boolean): AdvancedDynamicTexture;
+        /**
+         * FullScreenUI is created in a layer. This allows it to be treated like any other layer.
+         * As such, if you have a multi camera setup, you can set the layerMask on the GUI as well.
+         * When the GUI is not Created as FullscreenUI it does not respect the layerMask.
+         * layerMask is set through advancedTexture.layer.layerMask
+         * @param name name for the Texture
+         * @param foreground render in foreground (default is true)
+         * @param scene scene to be rendered in
+         * @param sampling method for scaling to fit screen
+         * @returns AdvancedDynamicTexture
+         */
         static CreateFullscreenUI(name: string, foreground?: boolean, scene?: Nullable<Scene>, sampling?: number): AdvancedDynamicTexture;
     }
 }
@@ -430,7 +442,19 @@ declare module BABYLON.GUI {
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _measure(): 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;
     }
 }
 
@@ -446,6 +470,7 @@ declare module BABYLON.GUI {
         private _borderColor;
         private _barOffset;
         private _isThumbCircle;
+        private _isThumbClamped;
         onValueChangedObservable: Observable<number>;
         borderColor: string;
         background: string;
@@ -457,6 +482,7 @@ declare module BABYLON.GUI {
         maximum: number;
         value: number;
         isThumbCircle: boolean;
+        isThumbClamped: boolean;
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
@@ -512,6 +538,9 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class TextBlock extends Control {
+        /**
+         * Defines the name of the control
+         */
         name: string | undefined;
         private _text;
         private _textWrapping;
@@ -519,20 +548,94 @@ declare module BABYLON.GUI {
         private _textVerticalAlignment;
         private _lines;
         private _resizeToFit;
+        private _lineSpacing;
+        private _outlineWidth;
+        private _outlineColor;
         /**
         * An event triggered after the text is changed
         * @type {BABYLON.Observable}
         */
         onTextChangedObservable: Observable<TextBlock>;
+        /**
+        * An event triggered after the text was broken up into lines
+        * @type {BABYLON.Observable}
+        */
+        onLinesReadyObservable: Observable<TextBlock>;
+        /**
+         * Return the line list (you may need to use the onLinesReadyObservable to make sure the list is ready)
+         */
+        readonly lines: any[];
+        /**
+         * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
+         */
+        /**
+         * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
+         */
         resizeToFit: boolean;
+        /**
+         * Gets or sets a boolean indicating if text must be wrapped
+         */
+        /**
+         * Gets or sets a boolean indicating if text must be wrapped
+         */
         textWrapping: boolean;
+        /**
+         * Gets or sets text to display
+         */
+        /**
+         * Gets or sets text to display
+         */
         text: string;
+        /**
+         * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
+         */
+        /**
+         * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
+         */
         textHorizontalAlignment: number;
+        /**
+         * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
+         */
+        /**
+         * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
+         */
         textVerticalAlignment: number;
-        constructor(name?: string | undefined, text?: string);
+        /**
+         * Gets or sets line spacing value
+         */
+        /**
+         * Gets or sets line spacing value
+         */
+        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
+         * @param name defines the name of the control
+         * @param text defines the text to display (emptry string by default)
+         */
+        constructor(
+            /**
+             * Defines the name of the control
+             */
+            name?: string | undefined, text?: string);
         protected _getTypeName(): string;
         private _drawText(text, textWidth, y, context);
+        /** @ignore */
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+        protected _applyStates(context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _parseLine(line: string | undefined, context: CanvasRenderingContext2D): object;
         protected _parseLineWithTextWrapping(line: string | undefined, context: CanvasRenderingContext2D): object;

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

@@ -4,7 +4,7 @@
     },
     "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.",
-    "version": "3.1.0-rc-0",
+    "version": "3.2.0-alpha7",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     "license": "Apache-2.0",
     "peerDependencies": {
-        "babylonjs": ">=3.1.0-alpha"
+        "babylonjs": ">=3.2.0-alpha"
     },
     "engines": {
         "node": "*"

Fichier diff supprimé car celui-ci est trop grand
+ 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; }
         .insp-wrapper .insp-tree .line .line-content .line:hover:first-child {
           background-color: #383838; }
+    .insp-wrapper .insp-tree .line_invisible {
+      display: none; }
   .insp-wrapper .insp-details {
     background-color: #242424;
     overflow-y: auto;
@@ -303,7 +305,7 @@
         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 {
         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 {
           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 {
@@ -340,7 +342,8 @@
       display: inline-block;
       margin-left: 5px; }
     .insp-wrapper .insp-details .color-element {
-      top: 2px; }
+      width: 20px;
+      height: 15px; }
     .insp-wrapper .insp-details .texture-element {
       color: #f29766;
       margin-left: 10px; }

+ 4 - 2
dist/preview release/inspector/babylon.inspector.d.ts

@@ -301,7 +301,7 @@ declare module INSPECTOR {
     class PhysicsImpostorAdapter extends Adapter implements IToolVisible {
         private _viewer;
         private _isVisible;
-        constructor(obj: BABYLON.PhysicsImpostor, viewer: BABYLON.Debug.PhysicsViewer);
+        constructor(obj: BABYLON.PhysicsImpostor, viewer: any);
         /** Returns the name displayed in the tree */
         id(): string;
         /** Returns the type of this object - displayed in the tree */
@@ -780,6 +780,7 @@ declare module INSPECTOR {
         static REFRESH_TIME: number;
         /** The list of data to update */
         private _updatableProperties;
+        private interval;
         constructor();
         static getInstance(): Scheduler;
         /** Add a property line to be updated every X ms */
@@ -787,6 +788,7 @@ declare module INSPECTOR {
         /** Removes the given property from the list of properties to update */
         remove(prop: PropertyLine): void;
         private _update();
+        dispose(): void;
     }
 }
 
@@ -868,7 +870,7 @@ declare module INSPECTOR {
 
 declare module INSPECTOR {
     class PhysicsTab extends PropertyTab {
-        viewer: BABYLON.Debug.PhysicsViewer;
+        viewer: any;
         constructor(tabbar: TabBar, inspector: Inspector);
         protected _getTree(): Array<TreeItem>;
     }

+ 24 - 3
dist/preview release/inspector/babylon.inspector.js

@@ -289,6 +289,7 @@ var INSPECTOR;
                     }
                 }
             }
+            INSPECTOR.Scheduler.getInstance().dispose();
         };
         /** Open the inspector in a new popup
          * Set 'firstTime' to true if there is no inspector created beforehands
@@ -382,7 +383,7 @@ var INSPECTOR;
         },
         '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: {
                 r: { min: 0, max: 1, step: 0.01 },
                 g: { min: 0, max: 1, step: 0.01 },
@@ -2431,7 +2432,7 @@ var INSPECTOR;
             this.pause = false;
             /** The list of data to update */
             this._updatableProperties = [];
-            setInterval(this._update.bind(this), Scheduler.REFRESH_TIME);
+            this.interval = setInterval(this._update.bind(this), Scheduler.REFRESH_TIME);
         }
         Scheduler.getInstance = function () {
             if (!Scheduler._instance) {
@@ -2459,6 +2460,9 @@ var INSPECTOR;
                 }
             }
         };
+        Scheduler.prototype.dispose = function () {
+            window.clearInterval(this.interval);
+        };
         /** All properties are refreshed every 250ms */
         Scheduler.REFRESH_TIME = 250;
         return Scheduler;
@@ -3567,6 +3571,12 @@ var INSPECTOR;
                     elem: elemValue,
                     updateFct: function () { return _this._sceneInstrumentation.drawCallsCounter.current.toString(); }
                 });
+                _this._createStatLabel("Texture collisions", _this._panel);
+                elemValue = INSPECTOR.Helpers.CreateDiv('stat-value', _this._panel);
+                _this._updatableProperties.push({
+                    elem: elemValue,
+                    updateFct: function () { return _this._sceneInstrumentation.textureCollisionsCounter.current.toString(); }
+                });
                 _this._createStatLabel("Total lights", _this._panel);
                 elemValue = INSPECTOR.Helpers.CreateDiv('stat-value', _this._panel);
                 _this._updatableProperties.push({
@@ -4558,7 +4568,18 @@ var INSPECTOR;
         };
         /** Build the HTML of this item */
         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
             if (this.adapter instanceof INSPECTOR.MeshAdapter) {
                 var obj = this.adapter.object;

Fichier diff supprimé car celui-ci est trop grand
+ 4 - 4
dist/preview release/inspector/babylon.inspector.min.js


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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-inspector",
     "description": "The Babylon.js inspector.",
-    "version": "3.1.0-rc-0",
+    "version": "3.2.0-alpha7",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -25,7 +25,7 @@
     ],
     "license": "Apache-2.0",
     "peerDependencies": {
-        "babylonjs": ">=3.1.0-alpha"
+        "babylonjs": ">=3.2.0-alpha"
     },
     "engines": {
         "node": "*"

+ 93 - 22
dist/preview release/loaders/babylon.glTF1FileLoader.d.ts

@@ -28,19 +28,52 @@ declare module BABYLON {
         json: Object;
         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 {
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
+        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
+        animationStartMode: GLTFLoaderAnimationStartMode;
+        compileMaterials: boolean;
+        useClipPlane: boolean;
+        compileShadowGenerators: boolean;
+        onMeshLoadedObservable: Observable<AbstractMesh>;
+        onTextureLoadedObservable: Observable<BaseTexture>;
+        onMaterialLoadedObservable: Observable<Material>;
+        onCompleteObservable: Observable<IGLTFLoader>;
+        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 {
-        static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
-        static CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
+        static CreateGLTFLoaderV1: () => IGLTFLoader;
+        static CreateGLTFLoaderV2: () => IGLTFLoader;
         /**
          * Raised when the asset has been parsed.
          * The data.json property stores the glTF JSON.
          * The data.bin property stores the BIN chunk from a glTF binary or null if the input is not a glTF binary.
          */
-        onParsed: (data: IGLTFLoaderData) => void;
+        onParsedObservable: Observable<IGLTFLoaderData>;
+        private _onParsedObserver;
+        onParsed: (loaderData: IGLTFLoaderData) => void;
         static IncrementalLoading: boolean;
         static HomogeneousCoordinates: boolean;
         /**
@@ -66,21 +99,46 @@ declare module BABYLON {
         /**
          * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
          */
+        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
+        private _onMeshLoadedObserver;
         onMeshLoaded: (mesh: AbstractMesh) => void;
         /**
          * Raised when the loader creates a texture after parsing the glTF properties of the texture.
          */
-        onTextureLoaded: (texture: BaseTexture) => void;
+        readonly onTextureLoadedObservable: Observable<BaseTexture>;
+        private _onTextureLoadedObserver;
+        onTextureLoaded: (Texture: BaseTexture) => void;
         /**
          * Raised when the loader creates a material after parsing the glTF properties of the material.
          */
-        onMaterialLoaded: (material: Material) => void;
+        readonly onMaterialLoadedObservable: Observable<Material>;
+        private _onMaterialLoadedObserver;
+        onMaterialLoaded: (Material: Material) => void;
         /**
          * Raised when the asset is completely loaded, immediately before the loader is disposed.
          * 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.
          */
+        readonly onCompleteObservable: Observable<GLTFFileLoader>;
+        private _onCompleteObserver;
         onComplete: () => void;
+        /**
+        * Raised when the loader is disposed.
+        */
+        readonly onDisposeObservable: Observable<GLTFFileLoader>;
+        private _onDisposeObserver;
+        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;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
@@ -88,12 +146,17 @@ declare module BABYLON {
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => 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;
         rewriteRootURL: (rootUrl: string, responseURL?: string) => string;
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
-        private static _parse(data);
+        private _parse(data);
         private _getLoader(loaderData);
         private static _parseBinary(data);
         private static _parseV1(binaryReader);
@@ -497,9 +560,27 @@ declare module BABYLON.GLTF1 {
             [name: string]: GLTFLoaderExtension;
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
+        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
+        animationStartMode: GLTFLoaderAnimationStartMode;
+        compileMaterials: boolean;
+        useClipPlane: boolean;
+        compileShadowGenerators: boolean;
+        onDisposeObservable: Observable<IGLTFLoader>;
+        onMeshLoadedObservable: Observable<AbstractMesh>;
+        onTextureLoadedObservable: Observable<BaseTexture>;
+        onMaterialLoadedObservable: Observable<Material>;
+        onCompleteObservable: Observable<IGLTFLoader>;
+        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        state: Nullable<GLTFLoaderState>;
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): boolean;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => 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 _loadBuffersAsync(gltfRuntime, onLoad, onProgress?);
         private _createNodes(gltfRuntime);
@@ -530,16 +611,6 @@ declare module BABYLON.GLTF1 {
          */
         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
         * @param mode: the mode value
         */

+ 242 - 65
dist/preview release/loaders/babylon.glTF1FileLoader.js

@@ -27,8 +27,21 @@ var BABYLON;
          */
         GLTFLoaderAnimationStartMode[GLTFLoaderAnimationStartMode["ALL"] = 2] = "ALL";
     })(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 () {
         function GLTFFileLoader() {
+            // #region Common options
+            /**
+             * Raised when the asset has been parsed.
+             * The data.json property stores the glTF JSON.
+             * The data.bin property stores the BIN chunk from a glTF binary or null if the input is not a glTF binary.
+             */
+            this.onParsedObservable = new BABYLON.Observable();
             // #endregion
             // #region V2 options
             /**
@@ -51,45 +64,165 @@ var BABYLON;
              * Set to true to compile shadow generators before raising the success callback.
              */
             this.compileShadowGenerators = false;
+            /**
+             * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
+             */
+            this.onMeshLoadedObservable = new BABYLON.Observable();
+            /**
+             * Raised when the loader creates a texture after parsing the glTF properties of the texture.
+             */
+            this.onTextureLoadedObservable = new BABYLON.Observable();
+            /**
+             * Raised when the loader creates a material after parsing the glTF properties of the material.
+             */
+            this.onMaterialLoadedObservable = new BABYLON.Observable();
+            /**
+             * Raised when the asset is completely loaded, immediately before the loader is disposed.
+             * 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.
+             */
+            this.onCompleteObservable = new BABYLON.Observable();
+            /**
+            * Raised when the loader is disposed.
+            */
+            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
+            this._loader = null;
             this.name = "gltf";
             this.extensions = {
                 ".gltf": { isBinary: false },
                 ".glb": { isBinary: true }
             };
         }
+        Object.defineProperty(GLTFFileLoader.prototype, "onParsed", {
+            set: function (callback) {
+                if (this._onParsedObserver) {
+                    this.onParsedObservable.remove(this._onParsedObserver);
+                }
+                this._onParsedObserver = this.onParsedObservable.add(callback);
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(GLTFFileLoader.prototype, "onMeshLoaded", {
+            set: function (callback) {
+                if (this._onMeshLoadedObserver) {
+                    this.onMeshLoadedObservable.remove(this._onMeshLoadedObserver);
+                }
+                this._onMeshLoadedObserver = this.onMeshLoadedObservable.add(callback);
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(GLTFFileLoader.prototype, "onTextureLoaded", {
+            set: function (callback) {
+                if (this._onTextureLoadedObserver) {
+                    this.onTextureLoadedObservable.remove(this._onTextureLoadedObserver);
+                }
+                this._onTextureLoadedObserver = this.onTextureLoadedObservable.add(callback);
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(GLTFFileLoader.prototype, "onMaterialLoaded", {
+            set: function (callback) {
+                if (this._onMaterialLoadedObserver) {
+                    this.onMaterialLoadedObservable.remove(this._onMaterialLoadedObserver);
+                }
+                this._onMaterialLoadedObserver = this.onMaterialLoadedObservable.add(callback);
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(GLTFFileLoader.prototype, "onComplete", {
+            set: function (callback) {
+                if (this._onCompleteObserver) {
+                    this.onCompleteObservable.remove(this._onCompleteObserver);
+                }
+                this._onCompleteObserver = this.onCompleteObservable.add(callback);
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(GLTFFileLoader.prototype, "onDispose", {
+            set: function (callback) {
+                if (this._onDisposeObserver) {
+                    this.onDisposeObservable.remove(this._onDisposeObserver);
+                }
+                this._onDisposeObserver = this.onDisposeObservable.add(callback);
+            },
+            enumerable: 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.
          */
         GLTFFileLoader.prototype.dispose = function () {
             if (this._loader) {
                 this._loader.dispose();
+                this._loader = null;
             }
+            this.onMeshLoadedObservable.clear();
+            this.onTextureLoadedObservable.clear();
+            this.onMaterialLoadedObservable.clear();
+            this.onDisposeObservable.notifyObservers(this);
+            this.onDisposeObservable.clear();
         };
-        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
-            try {
-                var loaderData = GLTFFileLoader._parse(data);
-                if (this.onParsed) {
-                    this.onParsed(loaderData);
-                }
-                this._loader = this._getLoader(loaderData);
-                this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
-            }
-            catch (e) {
-                onError(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 = GLTFFileLoader._parse(data);
-                if (this.onParsed) {
-                    this.onParsed(loaderData);
-                }
-                this._loader = this._getLoader(loaderData);
-                this._loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
-            }
-            catch (e) {
-                onError(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.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);
+                    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();
+                    return container;
+                });
+            });
         };
         GLTFFileLoader.prototype.canDirectLoad = function (data) {
             return ((data.indexOf("scene") !== -1) && (data.indexOf("node") !== -1));
@@ -97,16 +230,23 @@ var BABYLON;
         GLTFFileLoader.prototype.createPlugin = function () {
             return new GLTFFileLoader();
         };
-        GLTFFileLoader._parse = function (data) {
+        GLTFFileLoader.prototype._parse = function (data) {
+            var parsedData;
             if (data instanceof ArrayBuffer) {
-                return GLTFFileLoader._parseBinary(data);
+                parsedData = GLTFFileLoader._parseBinary(data);
             }
-            return {
-                json: JSON.parse(data),
-                bin: null
-            };
+            else {
+                parsedData = {
+                    json: JSON.parse(data),
+                    bin: null
+                };
+            }
+            this.onParsedObservable.notifyObservers(parsedData);
+            this.onParsedObservable.clear();
+            return parsedData;
         };
         GLTFFileLoader.prototype._getLoader = function (loaderData) {
+            var _this = this;
             var loaderVersion = { major: 2, minor: 0 };
             var asset = loaderData.json.asset || {};
             var version = GLTFFileLoader._parseVersion(asset.version);
@@ -130,7 +270,24 @@ var BABYLON;
             if (!createLoader) {
                 throw new Error("Unsupported version: " + asset.version);
             }
-            return createLoader(this);
+            var loader = createLoader();
+            loader.coordinateSystemMode = this.coordinateSystemMode;
+            loader.animationStartMode = this.animationStartMode;
+            loader.compileMaterials = this.compileMaterials;
+            loader.useClipPlane = this.useClipPlane;
+            loader.compileShadowGenerators = this.compileShadowGenerators;
+            loader.onMeshLoadedObservable.add(function (mesh) { return _this.onMeshLoadedObservable.notifyObservers(mesh); });
+            loader.onTextureLoadedObservable.add(function (texture) { return _this.onTextureLoadedObservable.notifyObservers(texture); });
+            loader.onMaterialLoadedObservable.add(function (material) { return _this.onMaterialLoadedObservable.notifyObservers(material); });
+            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;
         };
         GLTFFileLoader._parseBinary = function (data) {
             var Binary = {
@@ -868,8 +1025,7 @@ var BABYLON;
                 return newMesh;
             }
             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 verticesCounts = new Array();
             var indexStarts = new Array();
@@ -953,7 +1109,12 @@ var BABYLON;
                         tempVertexData.indices = new Int32Array(indices);
                         indexCounts.push(tempVertexData.indices.length);
                     }
-                    vertexData.merge(tempVertexData);
+                    if (!vertexData) {
+                        vertexData = tempVertexData;
+                    }
+                    else {
+                        vertexData.merge(tempVertexData);
+                    }
                     // Sub material
                     var material_1 = gltfRuntime.scene.getMaterialByID(primitive.material);
                     subMaterials.push(material_1 === null ? GLTF1.GLTFUtils.GetDefaultMaterial(gltfRuntime.scene) : material_1);
@@ -977,7 +1138,7 @@ var BABYLON;
                 newMesh.material = material;
             }
             // Apply geometry
-            geometry.setAllVerticesData(vertexData, false);
+            new BABYLON.Geometry(id, gltfRuntime.scene, vertexData, false, newMesh);
             newMesh.computeWorldMatrix(true);
             // Apply submeshes
             newMesh.subMeshes = [];
@@ -1452,8 +1613,8 @@ var BABYLON;
             };
             GLTFLoaderBase.LoadBufferAsync = function (gltfRuntime, id, onSuccess, onError, onProgress) {
                 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 {
                     BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + buffer.uri, function (data) { return onSuccess(new Uint8Array(data)); }, onProgress, undefined, true, function (request) {
@@ -1474,8 +1635,8 @@ var BABYLON;
                     return;
                 }
                 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 {
                     BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + source.uri, function (data) { return onSuccess(new Uint8Array(data)); }, undefined, undefined, true, function (request) {
@@ -1513,7 +1674,7 @@ var BABYLON;
             };
             GLTFLoaderBase.LoadShaderStringAsync = function (gltfRuntime, id, onSuccess, onError) {
                 var shader = gltfRuntime.shaders[id];
-                if (GLTF1.GLTFUtils.IsBase64(shader.uri)) {
+                if (BABYLON.Tools.IsBase64(shader.uri)) {
                     var shaderString = atob(shader.uri.split(",")[1]);
                     onSuccess(shaderString);
                 }
@@ -1666,6 +1827,19 @@ var BABYLON;
         */
         var GLTFLoader = /** @class */ (function () {
             function GLTFLoader() {
+                // #region Stubs for IGLTFLoader interface
+                this.coordinateSystemMode = BABYLON.GLTFLoaderCoordinateSystemMode.AUTO;
+                this.animationStartMode = BABYLON.GLTFLoaderAnimationStartMode.FIRST;
+                this.compileMaterials = false;
+                this.useClipPlane = false;
+                this.compileShadowGenerators = false;
+                this.onDisposeObservable = new BABYLON.Observable();
+                this.onMeshLoadedObservable = new BABYLON.Observable();
+                this.onTextureLoadedObservable = new BABYLON.Observable();
+                this.onMaterialLoadedObservable = new BABYLON.Observable();
+                this.onCompleteObservable = new BABYLON.Observable();
+                this.onExtensionLoadedObservable = new BABYLON.Observable();
+                this.state = null;
             }
             GLTFLoader.RegisterExtension = function (extension) {
                 if (GLTFLoader.Extensions[extension.name]) {
@@ -1674,10 +1848,9 @@ var BABYLON;
                 }
                 GLTFLoader.Extensions[extension.name] = extension;
             };
-            GLTFLoader.prototype.dispose = function () {
-                // do nothing
-            };
-            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
+            GLTFLoader.prototype.dispose = function () { };
+            // #endregion
+            GLTFLoader.prototype._importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 scene.useRightHandedSystem = true;
                 GLTF1.GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, function (gltfRuntime) {
@@ -1728,7 +1901,21 @@ var BABYLON;
                 }, onError);
                 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;
                 scene.useRightHandedSystem = true;
                 GLTF1.GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, function (gltfRuntime) {
@@ -1752,6 +1939,16 @@ var BABYLON;
                     }, 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) {
                 var hasShaders = false;
                 var processShader = function (sha, shader) {
@@ -1943,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
             * @param mode: the mode value
             */

Fichier diff supprimé car celui-ci est trop grand
+ 2 - 2
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


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

@@ -28,19 +28,52 @@ declare module BABYLON {
         json: Object;
         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 {
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
+        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
+        animationStartMode: GLTFLoaderAnimationStartMode;
+        compileMaterials: boolean;
+        useClipPlane: boolean;
+        compileShadowGenerators: boolean;
+        onMeshLoadedObservable: Observable<AbstractMesh>;
+        onTextureLoadedObservable: Observable<BaseTexture>;
+        onMaterialLoadedObservable: Observable<Material>;
+        onCompleteObservable: Observable<IGLTFLoader>;
+        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 {
-        static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
-        static CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
+        static CreateGLTFLoaderV1: () => IGLTFLoader;
+        static CreateGLTFLoaderV2: () => IGLTFLoader;
         /**
          * Raised when the asset has been parsed.
          * The data.json property stores the glTF JSON.
          * The data.bin property stores the BIN chunk from a glTF binary or null if the input is not a glTF binary.
          */
-        onParsed: (data: IGLTFLoaderData) => void;
+        onParsedObservable: Observable<IGLTFLoaderData>;
+        private _onParsedObserver;
+        onParsed: (loaderData: IGLTFLoaderData) => void;
         static IncrementalLoading: boolean;
         static HomogeneousCoordinates: boolean;
         /**
@@ -66,21 +99,46 @@ declare module BABYLON {
         /**
          * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
          */
+        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
+        private _onMeshLoadedObserver;
         onMeshLoaded: (mesh: AbstractMesh) => void;
         /**
          * Raised when the loader creates a texture after parsing the glTF properties of the texture.
          */
-        onTextureLoaded: (texture: BaseTexture) => void;
+        readonly onTextureLoadedObservable: Observable<BaseTexture>;
+        private _onTextureLoadedObserver;
+        onTextureLoaded: (Texture: BaseTexture) => void;
         /**
          * Raised when the loader creates a material after parsing the glTF properties of the material.
          */
-        onMaterialLoaded: (material: Material) => void;
+        readonly onMaterialLoadedObservable: Observable<Material>;
+        private _onMaterialLoadedObserver;
+        onMaterialLoaded: (Material: Material) => void;
         /**
          * Raised when the asset is completely loaded, immediately before the loader is disposed.
          * 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.
          */
+        readonly onCompleteObservable: Observable<GLTFFileLoader>;
+        private _onCompleteObserver;
         onComplete: () => void;
+        /**
+        * Raised when the loader is disposed.
+        */
+        readonly onDisposeObservable: Observable<GLTFFileLoader>;
+        private _onDisposeObserver;
+        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;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
@@ -88,12 +146,17 @@ declare module BABYLON {
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => 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;
         rewriteRootURL: (rootUrl: string, responseURL?: string) => string;
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
-        private static _parse(data);
+        private _parse(data);
         private _getLoader(loaderData);
         private static _parseBinary(data);
         private static _parseV1(binaryReader);
@@ -106,417 +169,259 @@ declare module BABYLON {
 
 
 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;
-        targets: any[];
-    }
-    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;
-    }
-    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;
         samplingMode: number;
         wrapU: 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 {
     class GLTFLoader implements IGLTFLoader {
-        _gltf: IGLTF;
+        _gltf: ILoaderGLTF;
         _babylonScene: Scene;
+        _completePromises: Promise<void>[];
         private _disposed;
-        private _parent;
+        private _state;
+        private _extensions;
         private _rootUrl;
-        private _defaultMaterial;
+        private _rootBabylonMesh;
         private _defaultSampler;
-        private _rootNode;
-        private _successCallback;
-        private _progressCallback;
-        private _errorCallback;
-        private _renderReady;
+        private _progressCallback?;
         private _requests;
-        private _renderReadyObservable;
-        private _renderPendingCount;
-        private _loaderPendingCount;
-        private _loaderTrackers;
-        static Extensions: {
-            [name: string]: GLTFLoaderExtension;
-        };
-        static RegisterExtension(extension: GLTFLoaderExtension): void;
-        private static _progressEventFactory;
-        private static _createProgressEventByConstructor(name, data);
-        private static _createProgressEventByDocument(name, data);
-        constructor(parent: GLTFFileLoader);
+        private static _Names;
+        private static _Factories;
+        static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void;
+        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
+        animationStartMode: GLTFLoaderAnimationStartMode;
+        compileMaterials: boolean;
+        useClipPlane: boolean;
+        compileShadowGenerators: boolean;
+        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;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => 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 _setupData();
+        private _createRootNode();
+        private _loadNodesAsync(nodes);
+        _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void>;
         private _getMeshes();
         private _getSkeletons();
         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 _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 _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);
+        private _loadBufferViewAsync(context, bufferView);
+        private _loadAccessorAsync(context, accessor);
         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 _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 _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 _GetNumComponents(context, type);
-        private _compileMaterialAsync(babylonMaterial, babylonMesh, onSuccess);
-        private _compileMaterialsAsync(onSuccess);
-        private _compileShadowGeneratorsAsync(onSuccess);
-    }
-}
-
-
-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 {
-    abstract class GLTFLoaderExtension {
+    abstract class GLTFLoaderExtension implements IGLTFLoaderExtension {
         enabled: boolean;
         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 _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 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 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<T>(context: string, property: IProperty, actionAsync: (context: string, extension: T) => Promise<void>): Nullable<Promise<void>>;
+        /** 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 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 {
-    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_materials_pbrSpecularGlossiness extends GLTFLoaderExtension {
         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 _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        private _loadSpecularGlossinessPropertiesAsync(loader, context, material, properties);
     }
 }
 
 
 declare module BABYLON.GLTF2.Extensions {
-    class KHRMaterialsPbrSpecularGlossiness extends GLTFLoaderExtension {
+    class KHR_lights extends GLTFLoaderExtension {
         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 _loadSceneAsync(context: string, scene: ILoaderScene): Nullable<Promise<void>>;
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        private readonly _lights;
     }
 }

Fichier diff supprimé car celui-ci est trop grand
+ 1369 - 1429
dist/preview release/loaders/babylon.glTF2FileLoader.js


Fichier diff supprimé car celui-ci est trop grand
+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


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

@@ -28,19 +28,52 @@ declare module BABYLON {
         json: Object;
         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 {
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
+        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
+        animationStartMode: GLTFLoaderAnimationStartMode;
+        compileMaterials: boolean;
+        useClipPlane: boolean;
+        compileShadowGenerators: boolean;
+        onMeshLoadedObservable: Observable<AbstractMesh>;
+        onTextureLoadedObservable: Observable<BaseTexture>;
+        onMaterialLoadedObservable: Observable<Material>;
+        onCompleteObservable: Observable<IGLTFLoader>;
+        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 {
-        static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
-        static CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
+        static CreateGLTFLoaderV1: () => IGLTFLoader;
+        static CreateGLTFLoaderV2: () => IGLTFLoader;
         /**
          * Raised when the asset has been parsed.
          * The data.json property stores the glTF JSON.
          * The data.bin property stores the BIN chunk from a glTF binary or null if the input is not a glTF binary.
          */
-        onParsed: (data: IGLTFLoaderData) => void;
+        onParsedObservable: Observable<IGLTFLoaderData>;
+        private _onParsedObserver;
+        onParsed: (loaderData: IGLTFLoaderData) => void;
         static IncrementalLoading: boolean;
         static HomogeneousCoordinates: boolean;
         /**
@@ -66,21 +99,46 @@ declare module BABYLON {
         /**
          * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
          */
+        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
+        private _onMeshLoadedObserver;
         onMeshLoaded: (mesh: AbstractMesh) => void;
         /**
          * Raised when the loader creates a texture after parsing the glTF properties of the texture.
          */
-        onTextureLoaded: (texture: BaseTexture) => void;
+        readonly onTextureLoadedObservable: Observable<BaseTexture>;
+        private _onTextureLoadedObserver;
+        onTextureLoaded: (Texture: BaseTexture) => void;
         /**
          * Raised when the loader creates a material after parsing the glTF properties of the material.
          */
-        onMaterialLoaded: (material: Material) => void;
+        readonly onMaterialLoadedObservable: Observable<Material>;
+        private _onMaterialLoadedObserver;
+        onMaterialLoaded: (Material: Material) => void;
         /**
          * Raised when the asset is completely loaded, immediately before the loader is disposed.
          * 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.
          */
+        readonly onCompleteObservable: Observable<GLTFFileLoader>;
+        private _onCompleteObserver;
         onComplete: () => void;
+        /**
+        * Raised when the loader is disposed.
+        */
+        readonly onDisposeObservable: Observable<GLTFFileLoader>;
+        private _onDisposeObserver;
+        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;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
@@ -88,12 +146,17 @@ declare module BABYLON {
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => 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;
         rewriteRootURL: (rootUrl: string, responseURL?: string) => string;
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
-        private static _parse(data);
+        private _parse(data);
         private _getLoader(loaderData);
         private static _parseBinary(data);
         private static _parseV1(binaryReader);
@@ -497,9 +560,27 @@ declare module BABYLON.GLTF1 {
             [name: string]: GLTFLoaderExtension;
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
+        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
+        animationStartMode: GLTFLoaderAnimationStartMode;
+        compileMaterials: boolean;
+        useClipPlane: boolean;
+        compileShadowGenerators: boolean;
+        onDisposeObservable: Observable<IGLTFLoader>;
+        onMeshLoadedObservable: Observable<AbstractMesh>;
+        onTextureLoadedObservable: Observable<BaseTexture>;
+        onMaterialLoadedObservable: Observable<Material>;
+        onCompleteObservable: Observable<IGLTFLoader>;
+        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        state: Nullable<GLTFLoaderState>;
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): boolean;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => 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 _loadBuffersAsync(gltfRuntime, onLoad, onProgress?);
         private _createNodes(gltfRuntime);
@@ -530,16 +611,6 @@ declare module BABYLON.GLTF1 {
          */
         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
         * @param mode: the mode value
         */
@@ -653,417 +724,259 @@ declare module BABYLON.GLTF1 {
 
 
 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 TypedArray extends ArrayBufferView {
+        [index: number]: number;
     }
-    interface IGLTFAnimationSampler extends IGLTFProperty {
-        input: number;
-        interpolation?: string;
-        output: number;
+    interface IArrayItem {
+        _index: number;
     }
-    interface IGLTFAnimation extends IGLTFChildRootProperty {
-        channels: IGLTFAnimationChannel[];
-        samplers: IGLTFAnimationSampler[];
-        index: number;
-        targets: any[];
+    class ArrayItem {
+        static Assign(values?: IArrayItem[]): void;
     }
-    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>;
+}
+
+
+
+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;
+    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;
         samplingMode: number;
         wrapU: 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 {
     class GLTFLoader implements IGLTFLoader {
-        _gltf: IGLTF;
+        _gltf: ILoaderGLTF;
         _babylonScene: Scene;
+        _completePromises: Promise<void>[];
         private _disposed;
-        private _parent;
+        private _state;
+        private _extensions;
         private _rootUrl;
-        private _defaultMaterial;
+        private _rootBabylonMesh;
         private _defaultSampler;
-        private _rootNode;
-        private _successCallback;
-        private _progressCallback;
-        private _errorCallback;
-        private _renderReady;
+        private _progressCallback?;
         private _requests;
-        private _renderReadyObservable;
-        private _renderPendingCount;
-        private _loaderPendingCount;
-        private _loaderTrackers;
-        static Extensions: {
-            [name: string]: GLTFLoaderExtension;
-        };
-        static RegisterExtension(extension: GLTFLoaderExtension): void;
-        private static _progressEventFactory;
-        private static _createProgressEventByConstructor(name, data);
-        private static _createProgressEventByDocument(name, data);
-        constructor(parent: GLTFFileLoader);
+        private static _Names;
+        private static _Factories;
+        static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void;
+        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
+        animationStartMode: GLTFLoaderAnimationStartMode;
+        compileMaterials: boolean;
+        useClipPlane: boolean;
+        compileShadowGenerators: boolean;
+        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;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => 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 _setupData();
+        private _createRootNode();
+        private _loadNodesAsync(nodes);
+        _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void>;
         private _getMeshes();
         private _getSkeletons();
         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 _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 _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);
+        private _loadBufferViewAsync(context, bufferView);
+        private _loadAccessorAsync(context, accessor);
         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 _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 _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 _GetNumComponents(context, type);
-        private _compileMaterialAsync(babylonMaterial, babylonMesh, onSuccess);
-        private _compileMaterialsAsync(onSuccess);
-        private _compileShadowGeneratorsAsync(onSuccess);
-    }
-}
-
-
-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 {
-    abstract class GLTFLoaderExtension {
+    abstract class GLTFLoaderExtension implements IGLTFLoaderExtension {
         enabled: boolean;
         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 _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 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 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<T>(context: string, property: IProperty, actionAsync: (context: string, extension: T) => Promise<void>): Nullable<Promise<void>>;
+        /** 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 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 {
-    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_materials_pbrSpecularGlossiness extends GLTFLoaderExtension {
         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 _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        private _loadSpecularGlossinessPropertiesAsync(loader, context, material, properties);
     }
 }
 
 
 declare module BABYLON.GLTF2.Extensions {
-    class KHRMaterialsPbrSpecularGlossiness extends GLTFLoaderExtension {
+    class KHR_lights extends GLTFLoaderExtension {
         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 _loadSceneAsync(context: string, scene: ILoaderScene): Nullable<Promise<void>>;
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        private readonly _lights;
     }
 }

Fichier diff supprimé car celui-ci est trop grand
+ 1428 - 1468
dist/preview release/loaders/babylon.glTFFileLoader.js


Fichier diff supprimé car celui-ci est trop grand
+ 3 - 3
dist/preview release/loaders/babylon.glTFFileLoader.min.js


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

@@ -58,6 +58,7 @@ declare module BABYLON {
         private _loadMTL(url, rootUrl, onSuccess);
         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;
+        loadAssetContainer(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): AssetContainer;
         /**
          * Read the OBJ file and create an Array of meshes.
          * Each mesh contains all information given by the OBJ and the MTL file.

+ 6 - 0
dist/preview release/loaders/babylon.objFileLoader.js

@@ -260,6 +260,12 @@ var BABYLON;
             //Get the 3D model
             return this.importMesh(null, scene, data, rootUrl, null, null, null);
         };
+        OBJFileLoader.prototype.loadAssetContainer = function (scene, data, rootUrl, onError) {
+            var container = new BABYLON.AssetContainer(scene);
+            this.importMesh(null, scene, data, rootUrl, container.meshes, null, null);
+            container.removeAllFromScene();
+            return container;
+        };
         /**
          * Read the OBJ file and create an Array of meshes.
          * Each mesh contains all information given by the OBJ and the MTL file.

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/loaders/babylon.objFileLoader.min.js


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

@@ -9,6 +9,7 @@ declare module BABYLON {
         extensions: ISceneLoaderPluginExtensions;
         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;
+        loadAssetContainer(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): AssetContainer;
         private isBinary(data);
         private parseBinary(mesh, data);
         private parseASCII(mesh, solidData);

+ 6 - 0
dist/preview release/loaders/babylon.stlFileLoader.js

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

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/loaders/babylon.stlFileLoader.min.js


Fichier diff supprimé car celui-ci est trop grand
+ 1431 - 1468
dist/preview release/loaders/babylonjs.loaders.js


Fichier diff supprimé car celui-ci est trop grand
+ 3 - 3
dist/preview release/loaders/babylonjs.loaders.min.js


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

@@ -1,5 +1,6 @@
 /// <reference types="babylonjs"/>
 
+
 declare module 'babylonjs-loaders' { 
     export = BABYLON; 
 }
@@ -14,6 +15,7 @@ declare module BABYLON {
         extensions: ISceneLoaderPluginExtensions;
         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;
+        loadAssetContainer(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): AssetContainer;
         private isBinary(data);
         private parseBinary(mesh, data);
         private parseASCII(mesh, solidData);
@@ -80,6 +82,7 @@ declare module BABYLON {
         private _loadMTL(url, rootUrl, onSuccess);
         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;
+        loadAssetContainer(scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): AssetContainer;
         /**
          * Read the OBJ file and create an Array of meshes.
          * Each mesh contains all information given by the OBJ and the MTL file.
@@ -126,19 +129,52 @@ declare module BABYLON {
         json: Object;
         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 {
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
+        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
+        animationStartMode: GLTFLoaderAnimationStartMode;
+        compileMaterials: boolean;
+        useClipPlane: boolean;
+        compileShadowGenerators: boolean;
+        onMeshLoadedObservable: Observable<AbstractMesh>;
+        onTextureLoadedObservable: Observable<BaseTexture>;
+        onMaterialLoadedObservable: Observable<Material>;
+        onCompleteObservable: Observable<IGLTFLoader>;
+        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 {
-        static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
-        static CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
+        static CreateGLTFLoaderV1: () => IGLTFLoader;
+        static CreateGLTFLoaderV2: () => IGLTFLoader;
         /**
          * Raised when the asset has been parsed.
          * The data.json property stores the glTF JSON.
          * The data.bin property stores the BIN chunk from a glTF binary or null if the input is not a glTF binary.
          */
-        onParsed: (data: IGLTFLoaderData) => void;
+        onParsedObservable: Observable<IGLTFLoaderData>;
+        private _onParsedObserver;
+        onParsed: (loaderData: IGLTFLoaderData) => void;
         static IncrementalLoading: boolean;
         static HomogeneousCoordinates: boolean;
         /**
@@ -164,21 +200,46 @@ declare module BABYLON {
         /**
          * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
          */
+        readonly onMeshLoadedObservable: Observable<AbstractMesh>;
+        private _onMeshLoadedObserver;
         onMeshLoaded: (mesh: AbstractMesh) => void;
         /**
          * Raised when the loader creates a texture after parsing the glTF properties of the texture.
          */
-        onTextureLoaded: (texture: BaseTexture) => void;
+        readonly onTextureLoadedObservable: Observable<BaseTexture>;
+        private _onTextureLoadedObserver;
+        onTextureLoaded: (Texture: BaseTexture) => void;
         /**
          * Raised when the loader creates a material after parsing the glTF properties of the material.
          */
-        onMaterialLoaded: (material: Material) => void;
+        readonly onMaterialLoadedObservable: Observable<Material>;
+        private _onMaterialLoadedObserver;
+        onMaterialLoaded: (Material: Material) => void;
         /**
          * Raised when the asset is completely loaded, immediately before the loader is disposed.
          * 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.
          */
+        readonly onCompleteObservable: Observable<GLTFFileLoader>;
+        private _onCompleteObserver;
         onComplete: () => void;
+        /**
+        * Raised when the loader is disposed.
+        */
+        readonly onDisposeObservable: Observable<GLTFFileLoader>;
+        private _onDisposeObserver;
+        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;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
@@ -186,12 +247,17 @@ declare module BABYLON {
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => 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;
         rewriteRootURL: (rootUrl: string, responseURL?: string) => string;
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
-        private static _parse(data);
+        private _parse(data);
         private _getLoader(loaderData);
         private static _parseBinary(data);
         private static _parseV1(binaryReader);
@@ -595,9 +661,27 @@ declare module BABYLON.GLTF1 {
             [name: string]: GLTFLoaderExtension;
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
+        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
+        animationStartMode: GLTFLoaderAnimationStartMode;
+        compileMaterials: boolean;
+        useClipPlane: boolean;
+        compileShadowGenerators: boolean;
+        onDisposeObservable: Observable<IGLTFLoader>;
+        onMeshLoadedObservable: Observable<AbstractMesh>;
+        onTextureLoadedObservable: Observable<BaseTexture>;
+        onMaterialLoadedObservable: Observable<Material>;
+        onCompleteObservable: Observable<IGLTFLoader>;
+        onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
+        state: Nullable<GLTFLoaderState>;
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): boolean;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => 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 _loadBuffersAsync(gltfRuntime, onLoad, onProgress?);
         private _createNodes(gltfRuntime);
@@ -628,16 +712,6 @@ declare module BABYLON.GLTF1 {
          */
         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
         * @param mode: the mode value
         */
@@ -751,417 +825,259 @@ declare module BABYLON.GLTF1 {
 
 
 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 TypedArray extends ArrayBufferView {
+        [index: number]: number;
     }
-    interface IGLTFAnimationSampler extends IGLTFProperty {
-        input: number;
-        interpolation?: string;
-        output: number;
+    interface IArrayItem {
+        _index: number;
     }
-    interface IGLTFAnimation extends IGLTFChildRootProperty {
-        channels: IGLTFAnimationChannel[];
-        samplers: IGLTFAnimationSampler[];
-        index: number;
-        targets: any[];
+    class ArrayItem {
+        static Assign(values?: IArrayItem[]): void;
     }
-    interface IGLTFAsset extends IGLTFChildRootProperty {
-        copyright?: string;
-        generator?: string;
-        version: string;
-        minVersion?: string;
+}
+
+
+
+declare module BABYLON.GLTF2 {
+    interface ILoaderAccessor extends IAccessor, IArrayItem {
+        _data?: Promise<TypedArray>;
     }
-    interface IGLTFBuffer extends IGLTFChildRootProperty {
-        uri?: string;
-        byteLength: number;
-        index: number;
-        loadedData?: ArrayBufferView;
-        loadedObservable?: Observable<IGLTFBuffer>;
+    interface ILoaderAnimationChannel extends IAnimationChannel, IArrayItem {
+        _babylonAnimationGroup: AnimationGroup;
     }
-    interface IGLTFBufferView extends IGLTFChildRootProperty {
-        buffer: number;
-        byteOffset?: number;
-        byteLength: number;
-        byteStride?: number;
-        index: number;
+    interface ILoaderAnimationSamplerData {
+        input: Float32Array;
+        interpolation: AnimationSamplerInterpolation;
+        output: Float32Array;
     }
-    interface IGLTFCameraOrthographic extends IGLTFProperty {
-        xmag: number;
-        ymag: number;
-        zfar: number;
-        znear: number;
+    interface ILoaderAnimationSampler extends IAnimationSampler, IArrayItem {
+        _data: Promise<ILoaderAnimationSamplerData>;
     }
-    interface IGLTFCameraPerspective extends IGLTFProperty {
-        aspectRatio: number;
-        yfov: number;
-        zfar: number;
-        znear: number;
+    interface ILoaderAnimation extends IAnimation, IArrayItem {
+        channels: ILoaderAnimationChannel[];
+        samplers: ILoaderAnimationSampler[];
+        _babylonAnimationGroup: Nullable<AnimationGroup>;
     }
-    interface IGLTFCamera extends IGLTFChildRootProperty {
-        orthographic?: IGLTFCameraOrthographic;
-        perspective?: IGLTFCameraPerspective;
-        type: string;
+    interface ILoaderBuffer extends IBuffer, IArrayItem {
+        _data?: Promise<ArrayBufferView>;
     }
-    interface IGLTFImage extends IGLTFChildRootProperty {
-        uri?: string;
-        mimeType?: string;
-        bufferView?: number;
-        index: number;
+    interface ILoaderBufferView extends IBufferView, IArrayItem {
+        _data?: Promise<ArrayBufferView>;
     }
-    interface IGLTFMaterialNormalTextureInfo extends IGLTFTextureInfo {
-        scale: number;
+    interface ILoaderCamera extends ICamera, IArrayItem {
     }
-    interface IGLTFMaterialOcclusionTextureInfo extends IGLTFTextureInfo {
-        strength: number;
+    interface ILoaderImage extends IImage, IArrayItem {
+        _objectURL?: Promise<string>;
     }
-    interface IGLTFMaterialPbrMetallicRoughness {
-        baseColorFactor: number[];
-        baseColorTexture: IGLTFTextureInfo;
-        metallicFactor: number;
-        roughnessFactor: number;
-        metallicRoughnessTexture: IGLTFTextureInfo;
+    interface ILoaderMaterial extends IMaterial, IArrayItem {
+        _babylonMaterial?: Material;
+        _babylonMeshes?: AbstractMesh[];
+        _loaded?: Promise<void>;
     }
-    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 ILoaderMesh extends IMesh, IArrayItem {
+        primitives: ILoaderMeshPrimitive[];
     }
-    interface IGLTFMeshPrimitive extends IGLTFProperty {
-        attributes: {
-            [name: string]: number;
-        };
-        indices?: number;
-        material?: number;
-        mode?: EMeshPrimitiveMode;
-        targets?: {
-            [name: string]: number;
-        }[];
-        vertexData: VertexData;
-        targetsVertexData: VertexData[];
+    interface ILoaderMeshPrimitive extends IMeshPrimitive, IArrayItem {
     }
-    interface IGLTFMesh extends IGLTFChildRootProperty {
-        primitives: IGLTFMeshPrimitive[];
-        weights?: number[];
-        index: number;
+    interface ILoaderNode extends INode, IArrayItem {
+        _parent: ILoaderNode;
+        _babylonMesh?: Mesh;
+        _primitiveBabylonMeshes?: Mesh[];
+        _babylonAnimationTargets?: Node[];
+        _numMorphTargets?: number;
     }
-    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 ILoaderSamplerData {
         noMipMaps: boolean;
         samplingMode: number;
         wrapU: 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 {
     class GLTFLoader implements IGLTFLoader {
-        _gltf: IGLTF;
+        _gltf: ILoaderGLTF;
         _babylonScene: Scene;
+        _completePromises: Promise<void>[];
         private _disposed;
-        private _parent;
+        private _state;
+        private _extensions;
         private _rootUrl;
-        private _defaultMaterial;
+        private _rootBabylonMesh;
         private _defaultSampler;
-        private _rootNode;
-        private _successCallback;
-        private _progressCallback;
-        private _errorCallback;
-        private _renderReady;
+        private _progressCallback?;
         private _requests;
-        private _renderReadyObservable;
-        private _renderPendingCount;
-        private _loaderPendingCount;
-        private _loaderTrackers;
-        static Extensions: {
-            [name: string]: GLTFLoaderExtension;
-        };
-        static RegisterExtension(extension: GLTFLoaderExtension): void;
-        private static _progressEventFactory;
-        private static _createProgressEventByConstructor(name, data);
-        private static _createProgressEventByDocument(name, data);
-        constructor(parent: GLTFFileLoader);
+        private static _Names;
+        private static _Factories;
+        static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void;
+        coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
+        animationStartMode: GLTFLoaderAnimationStartMode;
+        compileMaterials: boolean;
+        useClipPlane: boolean;
+        compileShadowGenerators: boolean;
+        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;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => 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 _setupData();
+        private _createRootNode();
+        private _loadNodesAsync(nodes);
+        _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void>;
         private _getMeshes();
         private _getSkeletons();
         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 _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 _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);
+        private _loadBufferViewAsync(context, bufferView);
+        private _loadAccessorAsync(context, accessor);
         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 _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 _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 _GetNumComponents(context, type);
-        private _compileMaterialAsync(babylonMaterial, babylonMesh, onSuccess);
-        private _compileMaterialsAsync(onSuccess);
-        private _compileShadowGeneratorsAsync(onSuccess);
-    }
-}
-
-
-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 {
-    abstract class GLTFLoaderExtension {
+    abstract class GLTFLoaderExtension implements IGLTFLoaderExtension {
         enabled: boolean;
         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 _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 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 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<T>(context: string, property: IProperty, actionAsync: (context: string, extension: T) => Promise<void>): Nullable<Promise<void>>;
+        /** 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 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 {
-    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_materials_pbrSpecularGlossiness extends GLTFLoaderExtension {
         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 _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh): Nullable<Promise<void>>;
+        private _loadSpecularGlossinessPropertiesAsync(loader, context, material, properties);
     }
 }
 
 
 declare module BABYLON.GLTF2.Extensions {
-    class KHRMaterialsPbrSpecularGlossiness extends GLTFLoaderExtension {
+    class KHR_lights extends GLTFLoaderExtension {
         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 _loadSceneAsync(context: string, scene: ILoaderScene): Nullable<Promise<void>>;
+        protected _loadNodeAsync(context: string, node: ILoaderNode): Nullable<Promise<void>>;
+        private readonly _lights;
     }
 }

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

@@ -4,7 +4,7 @@
     },
     "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.",
-    "version": "3.1.0-rc-0",
+    "version": "3.2.0-alpha7",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,11 +27,9 @@
     ],
     "license": "Apache-2.0",
     "peerDependencies": {
-        "babylonjs": ">=3.1.0-alpha"
+        "babylonjs": ">=3.2.0-alpha"
     },
     "engines": {
         "node": "*"
-    },
-    "_id": "babylonjs-loaders@3.1.0-alpha1",
-    "_from": "babylonjs-loaders@"
+    }
 }

+ 1 - 1
dist/preview release/materialsLibrary/babylon.cellMaterial.js

@@ -98,7 +98,7 @@ var BABYLON;
             // High level
             defines.CELLBASIC = !this.computeHighLevel;
             // Misc.
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             // Lights
             defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
             // Values that need to be evaluated on every frame

+ 0 - 0
dist/preview release/materialsLibrary/babylon.cellMaterial.min.js


Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff