Browse Source

Merge branch 'master' into dev_support_webgl2_textures

Nicolas 7 years ago
parent
commit
189a3dba88
100 changed files with 36556 additions and 151942 deletions
  1. 6 0
      .gitignore
  2. 2 2
      .travis.yml
  3. 1 1
      .vscode/tasks.json
  4. 4877 4788
      Playground/babylon.d.txt
  5. 79 0
      Playground/css/color_ts.css
  6. 422 419
      Playground/debug.html
  7. 92 93
      Playground/frame.html
  8. 7 6
      Playground/full.html
  9. 3 2
      Playground/index-local.html
  10. 13 11
      Playground/index.html
  11. 23 7
      Playground/js/index.js
  12. BIN
      Playground/scenes/ufo.glb
  13. 29 4
      Playground/ts.html
  14. 0 1
      Playground/zipContent/index.html
  15. 32 25
      Tools/DevLoader/BabylonLoader.js
  16. 113 154
      Tools/Gulp/config.json
  17. 160 107
      Tools/Gulp/gulpfile.js
  18. 10 9
      Tools/Gulp/package.json
  19. 51 19
      Tools/Gulp/processViewerDeclaration.js
  20. 8 4
      Tools/Publisher/index.js
  21. 139 0
      Tools/WebpackShaderLoader/index.js
  22. 4 4
      Viewer/assets/templates/default/navbar.html
  23. 25 0
      Viewer/dist/printExample.html
  24. 6 4
      Viewer/package.json
  25. 2 2
      Viewer/src/configuration/configurationCompatibility.ts
  26. 4 2
      Viewer/src/configuration/types/default.ts
  27. 2 2
      Viewer/src/model/viewerModel.ts
  28. 62 0
      Viewer/src/templating/plugins/printButton.ts
  29. 25 11
      Viewer/src/viewer/defaultViewer.ts
  30. 48 30
      Viewer/src/viewer/viewer.ts
  31. 2 1
      Viewer/tests/unit/tsconfig.json
  32. 4 2
      Viewer/tests/unit/webpack.config.js
  33. 1 1
      Viewer/tests/validation/karma.conf.js
  34. 1 1
      Viewer/tsconfig-gulp.json
  35. 2 2
      Viewer/tsconfig.json
  36. 4 2
      Viewer/webpack.assets.config.js
  37. 4 3
      Viewer/webpack.config.js
  38. 9 10
      Viewer/webpack.gulp.config.js
  39. 10560 10128
      dist/preview release/babylon.d.ts
  40. 63 61
      dist/preview release/babylon.js
  41. 1860 848
      dist/preview release/babylon.max.js
  42. 1860 848
      dist/preview release/babylon.no-module.max.js
  43. 64 62
      dist/preview release/babylon.worker.js
  44. 1862 850
      dist/preview release/es6.js
  45. 1 1
      dist/preview release/glTF2Interface/package.json
  46. 2356 2665
      dist/preview release/gui/babylon.gui.d.ts
  47. 2 5
      dist/preview release/gui/babylon.gui.min.js
  48. 1 0
      dist/preview release/gui/babylon.gui.min.js.map
  49. 4917 2669
      dist/preview release/gui/babylon.gui.module.d.ts
  50. 2 3
      dist/preview release/gui/package.json
  51. 2 5
      dist/preview release/inspector/babylon.inspector.bundle.js
  52. 1 0
      dist/preview release/inspector/babylon.inspector.bundle.js.map
  53. 1040 1385
      dist/preview release/inspector/babylon.inspector.d.ts
  54. 2371 0
      dist/preview release/inspector/babylon.inspector.module.d.ts
  55. 4 1
      dist/preview release/inspector/package.json
  56. 11 0
      dist/preview release/loaders/babylon.glTF1FileLoader.d.ts
  57. 23 1
      dist/preview release/loaders/babylon.glTF1FileLoader.js
  58. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  59. 66 9
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  60. 391 94
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  61. 3 3
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  62. 66 9
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  63. 391 96
      dist/preview release/loaders/babylon.glTFFileLoader.js
  64. 4 4
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  65. 1 0
      dist/preview release/loaders/babylon.objFileLoader.d.ts
  66. 37 1
      dist/preview release/loaders/babylon.objFileLoader.js
  67. 1 1
      dist/preview release/loaders/babylon.objFileLoader.min.js
  68. 67 9
      dist/preview release/loaders/babylonjs.loaders.d.ts
  69. 419 97
      dist/preview release/loaders/babylonjs.loaders.js
  70. 4 4
      dist/preview release/loaders/babylonjs.loaders.min.js
  71. 67 9
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  72. 2 2
      dist/preview release/loaders/package.json
  73. 1 0
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.d.ts
  74. 6 3
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.js
  75. 1 1
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js
  76. 1 0
      dist/preview release/materialsLibrary/babylonjs.materials.d.ts
  77. 6 3
      dist/preview release/materialsLibrary/babylonjs.materials.js
  78. 2 2
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  79. 1 0
      dist/preview release/materialsLibrary/babylonjs.materials.module.d.ts
  80. 1 1
      dist/preview release/materialsLibrary/package.json
  81. 1 1
      dist/preview release/postProcessesLibrary/package.json
  82. 1 1
      dist/preview release/proceduralTexturesLibrary/package.json
  83. 7 0
      dist/preview release/serializers/babylon.glTF2Serializer.d.ts
  84. 113 91
      dist/preview release/serializers/babylon.glTF2Serializer.js
  85. 2 2
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  86. 7 0
      dist/preview release/serializers/babylonjs.serializers.d.ts
  87. 113 91
      dist/preview release/serializers/babylonjs.serializers.js
  88. 2 2
      dist/preview release/serializers/babylonjs.serializers.min.js
  89. 7 0
      dist/preview release/serializers/babylonjs.serializers.module.d.ts
  90. 2 2
      dist/preview release/serializers/package.json
  91. 2 99
      dist/preview release/typedocValidationBaseline.json
  92. 109 240
      dist/preview release/viewer/babylon.viewer.d.ts
  93. 55 75
      dist/preview release/viewer/babylon.viewer.js
  94. 560 125057
      dist/preview release/viewer/babylon.viewer.max.js
  95. 112 76
      dist/preview release/viewer/babylon.viewer.module.d.ts
  96. 18 2
      dist/preview release/what's new.md
  97. 41 0
      gui/package.json
  98. 3 3
      gui/readme.md
  99. 589 589
      gui/src/2D/advancedDynamicTexture.ts
  100. 0 0
      gui/src/2D/controls/button.ts

+ 6 - 0
.gitignore

@@ -13,6 +13,7 @@ TestResults
 *.user
 *.sln.docstates
 *.map
+!dist/**/*.map
 
 # javascript files
 src/**/*.js
@@ -161,8 +162,12 @@ node_modules
 *.js.fx
 *.d.ts
 !dist/**/*.d.ts
+!dist/**/*.js.map
 !lib.d.ts
 
+# Split declaration file
+!ISplit.d.ts
+
 # local dev
 localDev/src/*
 /dist/preview release/babylon.custom.js
@@ -183,3 +188,4 @@ Viewer/tests/unit/src/**/*.js
 Viewer/tests/Lib/**/*.js
 Viewer/tests/commons/**/*.js
 .sass-cache/
+gui/dist/

+ 2 - 2
.travis.yml

@@ -31,8 +31,8 @@ jobs:
     - set -e
     - gulp typescript-all
     - gulp tests-unit
-#    - travis_retry gulp tests-validation-virtualscreen
-#    - travis_retry gulp tests-validation-browserstack
+    - travis_retry gulp tests-validation-virtualscreen
+    - travis_retry gulp tests-validation-browserstack
     - travis_retry gulp tests-viewer-validation-virtualscreen
     - travis_retry gulp tests-viewer-validation-browserstack
 notifications:

+ 1 - 1
.vscode/tasks.json

@@ -66,7 +66,7 @@
                     "background": {
                         "activeOnStart": true,
                         "beginsPattern": "Project is running at",
-                        "endsPattern": "webpack: Compiled successfully."
+                        "endsPattern": "Compiled successfully."
                     }
                 }
             ],

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


+ 79 - 0
Playground/css/color_ts.css

@@ -0,0 +1,79 @@
+@import url("https://fonts.googleapis.com/css?family=Montserrat:300,400");
+@import url("https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css");
+#waitTitle {
+    color: rgb(208, 23, 211);
+}
+#exampleList #exampleBanner h1 {
+    color: #ae00ef;
+}
+#exampleList .horizontalSeparator {
+    border-top: 1px solid #ae00ef;
+}
+#exampleList .categoryContainer .itemLine .itemContent .itemLineDocLink {
+    color: #ae00ef;
+}
+#exampleList .categoryContainer .itemLine .itemContent .itemLinePGLink {
+    color: #ae00ef;
+}
+
+#fpsLabel {
+    background-color: #9147c9;
+}
+.navbar .title {
+    color: #bb47c9;
+}
+.navbar .version {
+    color: #9147c9;
+}
+
+.button {
+    background-color: #9147c9;
+}
+.button:hover {
+    background-color: #bb47c9;
+}
+.navbar .button.run {
+    background-color: #bb47c9;
+}
+.navbar .select .toDisplay {
+    border: 1px solid #9147c9;
+}
+.navbar .select .subSelect .toDisplaySub {
+    border: 1px solid #9147c9;
+}
+
+.navbar .select .toDisplay .option {
+    font-size: 0.9em;
+    height: 35px;
+    line-height: 35px;
+    padding: 0px 5px 0px 5px;
+    text-align: center;
+    border-bottom : 1px solid rgba(0,0,0,0.1);
+}
+
+.navbar .select .toDisplay .option.light:hover {
+    cursor: pointer;
+    background-color: #d9d9d9;
+}
+
+
+.navbar .select .toDisplay .option.dark {
+    background-color: #333;
+    color: white;
+}
+.navbar .select .toDisplay .option.light {
+    background-color: white;
+    color: #9147c9;
+}
+.navbar .select .toDisplayBig {
+    border: 1px solid #9147c9;
+}
+
+.navbar .select .toDisplayBig.light {    
+    color: #bb47c9;
+}
+.navbar .select .toDisplayBig a.light {
+    color: #9147c9;
+}
+
+

+ 422 - 419
Playground/debug.html

@@ -1,510 +1,513 @@
 <!DOCTYPE html>
 <html>
 
-<head>
-    <title>Babylon.js Playground</title>
-    <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">
-
-    <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-    <!--For canvas/code separator-->
-    <script src="js/libs/split.js"></script>
-
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
-    <!-- jszip -->
-    <script src="js/libs/jszip.min.js"></script>
-    <script src="js/libs/fileSaver.js"></script>
-    <!-- Monaco -->
-    <script src="node_modules/monaco-editor/min/vs/loader.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.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>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.waterMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.lavaMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.normalMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.skyMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.triPlanarMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.terrainMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gradientMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.furMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gridMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.shadowOnlyMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.customMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.cellMaterial.min.js"></script>
-
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.brickProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.cloudProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.fireProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.grassProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.marbleProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.roadProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.starfieldProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.woodProceduralTexture.min.js"></script>
-
-    <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.asciiArtPostProcess.min.js"></script>
-    <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.digitalRainPostProcess.min.js"></script>
-
-    <script src="https://preview.babylonjs.com/loaders/babylon.glTFFileLoader.js"></script>
-    <script src="https://preview.babylonjs.com/loaders/babylon.objFileLoader.js"></script>
-    <script src="https://preview.babylonjs.com/loaders/babylon.stlFileLoader.js"></script>
-
-    <script src="https://preview.babylonjs.com/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/CompoundShader/src/babylonx.CompoundShader.js"></script>
-    <link href="css/index.css" rel="stylesheet" />
-
-</head>
-
-<body>
-    <div class="navbar navBar1600">
-        <div class="title">
-            Babylon.js Playground
-        </div>
-        <div class="version" id="mainTitle">
-            v3.0-alpha
-        </div>
-
-        <div class="category">
-            <div class="button run" id="runButton1600">Run
-                <i class="fa fa-play" aria-hidden="true"></i>
+    <head>
+        <title>Babylon.js Playground</title>
+        <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">
+
+        <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
+        <!--For canvas/code separator-->
+        <script src="js/libs/split.js"></script>
+
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
+        <!-- jszip -->
+        <script src="js/libs/jszip.min.js"></script>
+        <script src="js/libs/fileSaver.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.max.js"></script>
+        <script src="https://preview.babylonjs.com/gui/babylon.gui.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>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.waterMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.lavaMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.normalMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.skyMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.triPlanarMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.terrainMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gradientMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.furMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gridMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.shadowOnlyMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.customMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.cellMaterial.min.js"></script>
+
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.brickProceduralTexture.min.js"></script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.cloudProceduralTexture.min.js"></script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.fireProceduralTexture.min.js"></script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.grassProceduralTexture.min.js"></script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.marbleProceduralTexture.min.js"></script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.roadProceduralTexture.min.js"></script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.starfieldProceduralTexture.min.js"></script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.woodProceduralTexture.min.js"></script>
+
+        <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.asciiArtPostProcess.min.js"></script>
+        <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.digitalRainPostProcess.min.js"></script>
+
+        <script src="https://preview.babylonjs.com/loaders/babylon.glTFFileLoader.js"></script>
+        <script src="https://preview.babylonjs.com/loaders/babylon.objFileLoader.js"></script>
+        <script src="https://preview.babylonjs.com/loaders/babylon.stlFileLoader.js"></script>
+
+
+
+        <script src="https://preview.babylonjs.com/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/CompoundShader/src/babylonx.CompoundShader.js"></script>
+        <link href="css/index.css" rel="stylesheet" />
+
+        <!-- Monaco -->
+        <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
+
+    </head>
+
+    <body>
+        <div class="navbar navBar1600">
+            <div class="title">
+                Babylon.js Playground
+            </div>
+            <div class="version" id="mainTitle">
+                v3.0-alpha
+            </div>
+
+            <div class="category">
+                <div class="button run" id="runButton1600">Run
+                    <i class="fa fa-play" aria-hidden="true"></i>
+                </div>
             </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 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>
-        </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 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>
-        </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="toDisplaySub">
-                            <div class="option" id="darkTheme1600">Dark</div>
-                            <div class="option" id="lightTheme1600">Light</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="toDisplaySub">
+                                <div class="option" id="darkTheme1600">Dark</div>
+                                <div class="option" id="lightTheme1600">Light</div>
+                            </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="toDisplaySub">
-                            <div class="option" onclick="setFontSize(12);">12</div>
-                            <div class="option" onclick="setFontSize(14);">14</div>
-                            <div class="option" onclick="setFontSize(16);">16</div>
-                            <div class="option" onclick="setFontSize(18);">18</div>
-                            <div class="option" onclick="setFontSize(20);">20</div>
-                            <div class="option" onclick="setFontSize(22);">22</div>
+                        <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>
+                                <div class="option" onclick="setFontSize(16);">16</div>
+                                <div class="option" onclick="setFontSize(18);">18</div>
+                                <div class="option" onclick="setFontSize(20);">20</div>
+                                <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>
+                        <div class="option" id="fullscreenButton1600">Fullscreen</div>
+                        <div class="option" id="editorFullscreenButton1600">Editor Fullscreen</div>
+                        <div class="option" id="formatButton1600">Format code</div>
+                        <div class="option" id="minimapToggle1600">Minimap
+                            <i class="fa fa-square-o" aria-hidden="true"></i>
                         </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>
-                    <div class="option" id="fullscreenButton1600">Fullscreen</div>
-                    <div class="option" id="editorFullscreenButton1600">Editor Fullscreen</div>
-                    <div class="option" id="formatButton1600">Format code</div>
-                    <div class="option" id="minimapToggle1600">Minimap
-                        <i class="fa fa-square-o" aria-hidden="true"></i>
                     </div>
                 </div>
-            </div>
 
-            <div class="button uncheck" id="debugButton1600">Inspector
-                <i class="fa fa-square-o" aria-hidden="true"></i>
+                <div class="button uncheck" id="debugButton1600">Inspector
+                    <i class="fa fa-square-o" aria-hidden="true"></i>
+                </div>
+                <div class="button" id="metadataButton1600">Metadata</div>
             </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="toDisplay">
-                    <div class="option" onclick="setVersion('latest');">Latest</div>
-                    <div class="option" onclick="setVersion('2.5');">2.5</div>
+            <div class="category right">
+                <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 class="examplesButton">Examples</span>
                 </div>
-            </div>
-            <div class="button select">
-                <span class="examplesButton">Examples</span>
             </div>
         </div>
-    </div>
 
-    <div class="navbar navBar1475">
-        <div class="title">
-            Babylon.js Playground
-        </div>
-        <div class="version" id="mainTitle">
-            v3.0-alpha
-        </div>
+        <div class="navbar navBar1475">
+            <div class="title">
+                Babylon.js Playground
+            </div>
+            <div class="version" id="mainTitle">
+                v3.0-alpha
+            </div>
 
-        <div class="category">
-            <div class="button run" id="runButton1475">Run
-                <i class="fa fa-play" aria-hidden="true"></i>
+            <div class="category">
+                <div class="button run" id="runButton1475">Run
+                    <i class="fa fa-play" aria-hidden="true"></i>
+                </div>
             </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 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>
-        </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 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>
-        </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="toDisplaySub">
-                            <div class="option" id="darkTheme1475">Dark</div>
-                            <div class="option" id="lightTheme1475">Light</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="toDisplaySub">
+                                <div class="option" id="darkTheme1475">Dark</div>
+                                <div class="option" id="lightTheme1475">Light</div>
+                            </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="toDisplaySub">
-                            <div class="option" onclick="setFontSize(12);">12</div>
-                            <div class="option" onclick="setFontSize(14);">14</div>
-                            <div class="option" onclick="setFontSize(16);">16</div>
-                            <div class="option" onclick="setFontSize(18);">18</div>
-                            <div class="option" onclick="setFontSize(20);">20</div>
-                            <div class="option" onclick="setFontSize(22);">22</div>
+                        <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>
+                                <div class="option" onclick="setFontSize(16);">16</div>
+                                <div class="option" onclick="setFontSize(18);">18</div>
+                                <div class="option" onclick="setFontSize(20);">20</div>
+                                <div class="option" onclick="setFontSize(22);">22</div>
+                            </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>
-                    <div class="option" id="fullscreenButton1475">Fullscreen</div>
-                    <div class="option" id="editorFullscreenButton1475">Editor Fullscreen</div>
-                    <div class="option" id="formatButton1475">Format code</div>
-                    <div class="option" id="minimapToggle1475">Minimap
-                        <i class="fa fa-square-o" aria-hidden="true"></i>
-                    </div>
-                    <div class="option" id="debugButton1475">Inspector
-                        <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="toDisplaySub">
-                            <div class="option" onclick="setVersion('latest');">Latest</div>
-                            <div class="option" onclick="setVersion('2.5');">2.5</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>
+                        <div class="option" id="fullscreenButton1475">Fullscreen</div>
+                        <div class="option" id="editorFullscreenButton1475">Editor Fullscreen</div>
+                        <div class="option" id="formatButton1475">Format code</div>
+                        <div class="option" id="minimapToggle1475">Minimap
+                            <i class="fa fa-square-o" aria-hidden="true"></i>
+                        </div>
+                        <div class="option" id="debugButton1475">Inspector
+                            <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="toDisplaySub">
+                                <div class="option" onclick="setVersion('latest');">Latest</div>
+                                <div class="option" onclick="setVersion('2.5');">2.5</div>
+                            </div>
                         </div>
                     </div>
                 </div>
             </div>
-        </div>
 
-        <div class="category right">
-            <div class="button select">
-                <span class="examplesButton">Examples</span>
+            <div class="category right">
+                <div class="button select">
+                    <span class="examplesButton">Examples</span>
+                </div>
             </div>
         </div>
-    </div>
 
-    <div class="navbar navBar1030">
-        <div class="category">
-            <div class="button run" id="runButton1030">Run
-                <i class="fa fa-play" aria-hidden="true"></i>
+        <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>
-        </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 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>
-        </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 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>
-        </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="toDisplaySub">
-                            <div class="option" id="darkTheme1030">Dark</div>
-                            <div class="option" id="lightTheme1030">Light</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="toDisplaySub">
+                                <div class="option" id="darkTheme1030">Dark</div>
+                                <div class="option" id="lightTheme1030">Light</div>
+                            </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="toDisplaySub">
-                            <div class="option" onclick="setFontSize(12);">12</div>
-                            <div class="option" onclick="setFontSize(14);">14</div>
-                            <div class="option" onclick="setFontSize(16);">16</div>
-                            <div class="option" onclick="setFontSize(18);">18</div>
-                            <div class="option" onclick="setFontSize(20);">20</div>
-                            <div class="option" onclick="setFontSize(22);">22</div>
+                        <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>
+                                <div class="option" onclick="setFontSize(16);">16</div>
+                                <div class="option" onclick="setFontSize(18);">18</div>
+                                <div class="option" onclick="setFontSize(20);">20</div>
+                                <div class="option" onclick="setFontSize(22);">22</div>
+                            </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>
-                    <div class="option" id="fullscreenButton1030">Fullscreen</div>
-                    <div class="option" id="editorFullscreenButton1030">Editor Fullscreen</div>
-                    <div class="option" id="formatButton1030">Format code</div>
-                    <div class="option" id="minimapToggle1030">Minimap
-                        <i class="fa fa-square-o" aria-hidden="true"></i>
-                    </div>
-                    <div class="option" id="debugButton1030">Inspector
-                        <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="toDisplaySub">
-                            <div class="option" onclick="setVersion('latest');">Latest</div>
-                            <div class="option" onclick="setVersion('2.5');">2.5</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>
+                        <div class="option" id="fullscreenButton1030">Fullscreen</div>
+                        <div class="option" id="editorFullscreenButton1030">Editor Fullscreen</div>
+                        <div class="option" id="formatButton1030">Format code</div>
+                        <div class="option" id="minimapToggle1030">Minimap
+                            <i class="fa fa-square-o" aria-hidden="true"></i>
+                        </div>
+                        <div class="option" id="debugButton1030">Inspector
+                            <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="toDisplaySub">
+                                <div class="option" onclick="setVersion('latest');">Latest</div>
+                                <div class="option" onclick="setVersion('2.5');">2.5</div>
+                            </div>
                         </div>
                     </div>
                 </div>
             </div>
-        </div>
 
-        <div class="category right">
-            <div class="button select">
-                <span class="examplesButton">Examples</span>
+            <div class="category right">
+                <div class="button select">
+                    <span class="examplesButton">Examples</span>
+                </div>
             </div>
         </div>
-    </div>
-
-    <div class="navbar navBar750">
-        <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 class="navbar navBar750">
+            <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>
                 </div>
             </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="toDisplaySub">
-                            <div class="option" id="darkTheme750">Dark</div>
-                            <div class="option" id="lightTheme750">Light</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="toDisplaySub">
+                                <div class="option" id="darkTheme750">Dark</div>
+                                <div class="option" id="lightTheme750">Light</div>
+                            </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="toDisplaySub">
-                            <div class="option" onclick="setFontSize(12);">12</div>
-                            <div class="option" onclick="setFontSize(14);">14</div>
-                            <div class="option" onclick="setFontSize(16);">16</div>
-                            <div class="option" onclick="setFontSize(18);">18</div>
-                            <div class="option" onclick="setFontSize(20);">20</div>
-                            <div class="option" onclick="setFontSize(22);">22</div>
+                        <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>
+                                <div class="option" onclick="setFontSize(16);">16</div>
+                                <div class="option" onclick="setFontSize(18);">18</div>
+                                <div class="option" onclick="setFontSize(20);">20</div>
+                                <div class="option" onclick="setFontSize(22);">22</div>
+                            </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>
-                    <div class="option" id="fullscreenButton750">Fullscreen</div>
-                    <div class="option" id="editorFullscreenButton750">Editor Fullscreen</div>
-                    <div class="option" id="formatButton750">Format code</div>
-                    <div class="option" id="minimapToggle750">Minimap
-                        <i class="fa fa-square-o" aria-hidden="true"></i>
-                    </div>
-                    <div class="option" id="debugButton750">Inspector
-                        <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="toDisplaySub">
-                            <div class="option" onclick="setVersion('latest');">Latest</div>
-                            <div class="option" onclick="setVersion('2.5');">2.5</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>
+                        <div class="option" id="fullscreenButton750">Fullscreen</div>
+                        <div class="option" id="editorFullscreenButton750">Editor Fullscreen</div>
+                        <div class="option" id="formatButton750">Format code</div>
+                        <div class="option" id="minimapToggle750">Minimap
+                            <i class="fa fa-square-o" aria-hidden="true"></i>
+                        </div>
+                        <div class="option" id="debugButton750">Inspector
+                            <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="toDisplaySub">
+                                <div class="option" onclick="setVersion('latest');">Latest</div>
+                                <div class="option" onclick="setVersion('2.5');">2.5</div>
+                            </div>
                         </div>
                     </div>
                 </div>
             </div>
-        </div>
 
-        <div class="category right">
-            <div class="button select">
-                <span class="examplesButton">Examples</span>
+            <div class="category right">
+                <div class="button select">
+                    <span class="examplesButton">Examples</span>
+                </div>
             </div>
         </div>
-    </div>
 
-    <div class="wrapper">
-        <div id="jsEditor"></div>
-        <div id="canvasZone">
-            <canvas touch-action="none" id="renderCanvas"></canvas>
+        <div class="wrapper">
+            <div id="jsEditor"></div>
+            <div id="canvasZone">
+                <canvas touch-action="none" id="renderCanvas"></canvas>
+            </div>
         </div>
-    </div>
-    <div id="exampleList">
-        <div id="exampleBanner">
-            <h1>Examples</h1>
+        <div id="exampleList">
+            <div id="exampleBanner">
+                <h1>Examples</h1>
+            </div>
+            <div class="horizontalSeparator"></div>
+            <input id="filterBar" type="text" placeholder="Filter examples...">
+            <img id="filterBarClear" src="https://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/clear_button.png">
         </div>
-        <div class="horizontalSeparator"></div>
-        <input id="filterBar" type="text" placeholder="Filter examples...">
-        <img id="filterBarClear" src="https://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/clear_button.png">
-    </div>
 
-    <span class="label" id="fpsLabel">FPS</span>
+        <span class="label" id="fpsLabel">FPS</span>
 
-    <div id="errorZone">
-    </div>
+        <div id="errorZone">
+        </div>
 
-    <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 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>
         </div>
-    </div>
 
-    <div id="saveLayer" class="save-layer">
-        <div class="save-form">
-            <label for="saveFormTitle">TITLE</label>
-            <div class="separator"></div>
-            <input type="text" maxlength="120" id="saveFormTitle" class="save-form-title">
+        <div id="saveLayer" class="save-layer">
+            <div class="save-form">
+                <label for="saveFormTitle">TITLE</label>
+                <div class="separator"></div>
+                <input type="text" maxlength="120" id="saveFormTitle" class="save-form-title">
 
-            <label for="saveFormDescription">DESCRIPTION</label>
-            <div class="separator"></div>
-            <textarea id="saveFormDescription" rows="4" cols="10"></textarea>
+                <label for="saveFormDescription">DESCRIPTION</label>
+                <div class="separator"></div>
+                <textarea id="saveFormDescription" rows="4" cols="10"></textarea>
 
-            <label for="saveFormTags">TAGS (separated by comma)</label>
-            <div class="separator"></div>
-            <textarea id="saveFormTags" rows="4" cols="10"></textarea>
+                <label for="saveFormTags">TAGS (separated by comma)</label>
+                <div class="separator"></div>
+                <textarea id="saveFormTags" rows="4" cols="10"></textarea>
 
-            <div class="save-form-buttons" id="saveFormButtons">
+                <div class="save-form-buttons" id="saveFormButtons">
 
-                <div id="saveFormButtonOk" class="button">OK</div>
-                <div id="saveFormButtonCancel" class="button">Cancel</div>
+                    <div id="saveFormButtonOk" class="button">OK</div>
+                    <div id="saveFormButtonCancel" class="button">Cancel</div>
+                </div>
             </div>
         </div>
-    </div>
 
-    <script src="https://code.jquery.com/jquery.js"></script>
+        <script src="https://code.jquery.com/jquery.js"></script>
 
-    <script src="js/actions.js"></script>
-    <script src="js/pbt.js"></script>
-    <script src="js/index.js"></script>
+        <script src="js/actions.js"></script>
+        <script src="js/pbt.js"></script>
+        <script src="js/index.js"></script>
 
-    <!-- Global site tag (gtag.js) - Google Analytics -->
-    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-41767310-2"></script>
-    <script>
-    window.dataLayer = window.dataLayer || [];
-    function gtag(){dataLayer.push(arguments);}
-    gtag('js', new Date());
+        <!-- Global site tag (gtag.js) - Google Analytics -->
+        <script async src="https://www.googletagmanager.com/gtag/js?id=UA-41767310-2"></script>
+        <script>
+            window.dataLayer = window.dataLayer || [];
+            function gtag() { dataLayer.push(arguments); }
+            gtag('js', new Date());
 
-    gtag('config', 'UA-41767310-2');
-    </script>    
-</body>
+            gtag('config', 'UA-41767310-2');
+        </script>
+    </body>
 
 </html>

+ 92 - 93
Playground/frame.html

@@ -1,98 +1,97 @@
 <!DOCTYPE html>
 <html>
 
-<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">
-    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
-
-    <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-    
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.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/earcut.min.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>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.waterMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.lavaMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.normalMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.skyMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.triPlanarMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.terrainMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gradientMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.furMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gridMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.shadowOnlyMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.customMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.cellMaterial.min.js"></script>
-
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.brickProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.cloudProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.fireProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.grassProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.marbleProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.roadProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.starfieldProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.woodProceduralTexture.min.js"></script>
-
-    <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.asciiArtPostProcess.min.js"></script>
-    <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.digitalRainPostProcess.min.js"></script>
-
-    <script src="https://preview.babylonjs.com/loaders/babylon.glTFFileLoader.js"></script>
-    <script src="https://preview.babylonjs.com/loaders/babylon.objFileLoader.js"></script>
-    <script src="https://preview.babylonjs.com/loaders/babylon.stlFileLoader.js"></script>
-
-    <script src="https://preview.babylonjs.com/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/CompoundShader/src/babylonx.CompoundShader.js"></script>
-    <link href="frame.css" rel="stylesheet" />
-</head>
-
-<body>
-    <canvas touch-action="none" id="renderCanvas" tabindex="1"></canvas>
-
-    <span class="label" id="fpsLabel">FPS</span>
-
-    <a class="link" id="refresh" href="#">Reload</a>
-    <a class="link" id="link" href="#" target="_blank">Edit</a>
-
-    <script src="https://code.jquery.com/jquery.js"></script>
-    <script src="js/frame.js"></script>
-
-    <!-- Global site tag (gtag.js) - Google Analytics -->
-    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-41767310-2"></script>
-    <script>
-    window.dataLayer = window.dataLayer || [];
-    function gtag(){dataLayer.push(arguments);}
-    gtag('js', new Date());
-
-    gtag('config', 'UA-41767310-2');
-    </script>    
-</body>
+    <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">
+        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
+
+        <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
+
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.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/earcut.min.js"></script>
+        <script src="https://preview.babylonjs.com/babylon.js"></script>
+        <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
+        <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
+
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.fireMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.waterMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.lavaMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.normalMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.skyMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.triPlanarMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.terrainMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gradientMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.furMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gridMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.shadowOnlyMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.customMaterial.min.js"></script>
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylon.cellMaterial.min.js"></script>
+
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.brickProceduralTexture.min.js"></script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.cloudProceduralTexture.min.js"></script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.fireProceduralTexture.min.js"></script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.grassProceduralTexture.min.js"></script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.marbleProceduralTexture.min.js"></script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.roadProceduralTexture.min.js"></script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.starfieldProceduralTexture.min.js"></script>
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.woodProceduralTexture.min.js"></script>
+
+        <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.asciiArtPostProcess.min.js"></script>
+        <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.digitalRainPostProcess.min.js"></script>
+
+        <script src="https://preview.babylonjs.com/loaders/babylon.glTFFileLoader.js"></script>
+        <script src="https://preview.babylonjs.com/loaders/babylon.objFileLoader.js"></script>
+        <script src="https://preview.babylonjs.com/loaders/babylon.stlFileLoader.js"></script>
+
+        <script src="https://preview.babylonjs.com/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/CompoundShader/src/babylonx.CompoundShader.js"></script>
+        <link href="frame.css" rel="stylesheet" />
+    </head>
+
+    <body>
+        <canvas touch-action="none" id="renderCanvas" tabindex="1"></canvas>
+
+        <span class="label" id="fpsLabel">FPS</span>
+
+        <a class="link" id="refresh" href="#">Reload</a>
+        <a class="link" id="link" href="#" target="_blank">Edit</a>
+
+        <script src="https://code.jquery.com/jquery.js"></script>
+        <script src="js/frame.js"></script>
+
+        <!-- Global site tag (gtag.js) - Google Analytics -->
+        <script async src="https://www.googletagmanager.com/gtag/js?id=UA-41767310-2"></script>
+        <script>
+            window.dataLayer = window.dataLayer || [];
+            function gtag() { dataLayer.push(arguments); }
+            gtag('js', new Date());
+
+            gtag('config', 'UA-41767310-2');
+        </script>
+    </body>
 
 </html>

+ 7 - 6
Playground/full.html

@@ -29,6 +29,7 @@
         <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/gui/babylon.gui.min.js"></script>
         <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
 
         <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
@@ -39,7 +40,7 @@
 
         <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.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/CompoundShader/src/babylonx.CompoundShader.js"></script>
@@ -54,12 +55,12 @@
         <!-- Global site tag (gtag.js) - Google Analytics -->
         <script async src="https://www.googletagmanager.com/gtag/js?id=UA-41767310-2"></script>
         <script>
-        window.dataLayer = window.dataLayer || [];
-        function gtag(){dataLayer.push(arguments);}
-        gtag('js', new Date());
+            window.dataLayer = window.dataLayer || [];
+            function gtag() { dataLayer.push(arguments); }
+            gtag('js', new Date());
 
-        gtag('config', 'UA-41767310-2');
-        </script>        
+            gtag('config', 'UA-41767310-2');
+        </script>
     </body>
 
 </html>

+ 3 - 2
Playground/index-local.html

@@ -18,7 +18,7 @@
         <script src="../dist/preview%20release/Oimo.js"></script>
         <script src="../dist/preview%20release/earcut.min.js"></script>
         <!-- Monaco -->
-        <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
+
         <!-- Babylon.js -->
         <script src="../tools/DevLoader/BabylonLoader.js"></script>
 
@@ -447,6 +447,7 @@
         <script src="js/pbt.js"></script>
         <script>
             BABYLONDEVTOOLS.Loader
+                .require('node_modules/monaco-editor/min/vs/loader.js')
                 .require('js/index.js')
                 .load(function () {
                     BABYLON.DracoCompression.Configuration.decoder = {
@@ -458,4 +459,4 @@
         </script>
     </body>
 
-</html>
+</html>

+ 13 - 11
Playground/index.html

@@ -37,24 +37,26 @@
         <script src="https://preview.babylonjs.com/cannon.js"></script>
         <script src="https://preview.babylonjs.com/Oimo.js"></script>
         <script src="https://preview.babylonjs.com/earcut.min.js"></script>
-        <!-- Monaco -->
-        <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
         <!-- Babylon.js -->
         <script src="https://preview.babylonjs.com/babylon.js"></script>
+        <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
         <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
         <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
         <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
         <script src="https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
         <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>
+
+        <!-- Monaco -->
+        <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
+
 
         <!-- Extensions -->
         <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js" async></script>
         <script src="https://rawgit.com/BabylonJS/Extensions/master/CompoundShader/src/babylonx.CompoundShader.js" async></script>
         <script src="https://www.babylontoolkit.com/playground/scripts/babylon.navmesh.js"></script>
         <script src="https://www.babylontoolkit.com/playground/scripts/babylon.manager.js"></script>
-                               
+
         <link href="css/index.css" rel="stylesheet" />
     </head>
 
@@ -408,7 +410,7 @@
                 <canvas touch-action="none" id="renderCanvas"></canvas>
             </div>
         </div>
-        <div id="exampleList">
+        <div id="exampleList" class="javascript">
             <div id="exampleBanner">
                 <h1>Examples</h1>
             </div>
@@ -479,16 +481,16 @@
         <script src="js/actions.js"></script>
         <script src="js/pbt.js"></script>
         <script src="js/index.js"></script>
-        
+
         <!-- Global site tag (gtag.js) - Google Analytics -->
         <script async src="https://www.googletagmanager.com/gtag/js?id=UA-41767310-2"></script>
         <script>
-        window.dataLayer = window.dataLayer || [];
-        function gtag(){dataLayer.push(arguments);}
-        gtag('js', new Date());
+            window.dataLayer = window.dataLayer || [];
+            function gtag() { dataLayer.push(arguments); }
+            gtag('js', new Date());
 
-        gtag('config', 'UA-41767310-2');
-        </script>        
+            gtag('config', 'UA-41767310-2');
+        </script>
     </body>
 
 </html>

+ 23 - 7
Playground/js/index.js

@@ -241,9 +241,17 @@ function showError(errorMessage, errorEvent) {
         };
 
         var loadScriptsList = function () {
-            var xhr = new XMLHttpRequest();
 
-            xhr.open('GET', 'https://raw.githubusercontent.com/BabylonJS/Documentation/master/examples/list.json', true);
+            var exampleList = document.getElementById("exampleList");
+           
+            var xhr = new XMLHttpRequest();
+            //Open Typescript or Javascript examples
+            if(exampleList.className != 'typescript') {
+                xhr.open('GET', 'https://raw.githubusercontent.com/BabylonJS/Documentation/master/examples/list.json', true);
+            }
+            else {
+                xhr.open('GET', 'https://raw.githubusercontent.com/BabylonJS/Documentation/master/examples/list_ts.json', true);
+            }
 
             xhr.onreadystatechange = function () {
                 if (xhr.readyState === 4) {
@@ -257,7 +265,7 @@ function showError(errorMessage, errorEvent) {
                         }
                         scripts.sort(sortScriptsList);
 
-                        var exampleList = document.getElementById("exampleList");
+                                                
 
                         if (exampleList) {
                             for (var i = 0; i < scripts.length; i++) {
@@ -550,7 +558,8 @@ function showError(errorMessage, errorEvent) {
                     }
     
                     var scene;
-    
+                    var defaultEngineZip = "new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true })";
+
                     if (code.indexOf("createEngine") !== -1) {
                         createEngineFunction = "createEngine";
                     }
@@ -573,7 +582,7 @@ function showError(errorMessage, errorEvent) {
                         eval("runScript = function(scene, canvas) {" + code + "}");
                         runScript(scene, canvas);
     
-                        zipCode = "var scene = new BABYLON.Scene(engine);\r\n\r\n" + code;
+                        zipCode = "var engine = " + defaultEngineZip + ";\r\nvar scene = new BABYLON.Scene(engine);\r\n\r\n" + code;
                     } else {
                         //execute the code
                         eval(code);
@@ -592,8 +601,15 @@ function showError(errorMessage, errorEvent) {
                             return;
                         }
     
-                        // update the scene code for the zip file
-                        zipCode = code + "\r\n\r\nvar scene = " + createSceneFunction + "()";
+                        var createEngineZip = (createEngineFunction === "createEngine")
+                            ? "createEngine()"
+                            : defaultEngineZip
+
+                        zipCode = 
+                            code + "\r\n\r\n" +
+                            "var engine = " + createEngineZip + ";\r\n" +
+                            "var scene = " + createSceneFunction + "();"
+
                     }
     
                     engine.runRenderLoop(function () {

BIN
Playground/scenes/ufo.glb


+ 29 - 4
Playground/ts.html

@@ -37,17 +37,18 @@
         <script src="https://preview.babylonjs.com/cannon.js"></script>
         <script src="https://preview.babylonjs.com/Oimo.js"></script>
         <script src="https://preview.babylonjs.com/earcut.min.js"></script>
-        <!-- Monaco -->
-        <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
         <!-- Babylon.js -->
         <script src="https://preview.babylonjs.com/babylon.js"></script>
+        <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
         <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
         <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
         <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
         <script src="https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
         <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>
+
+        <!-- Monaco -->
+        <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
 
         <!-- Extensions -->
         <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js" async></script>
@@ -56,6 +57,7 @@
         <script src="https://www.babylontoolkit.com/playground/scripts/babylon.manager.js"></script>
                                
         <link href="css/index.css" rel="stylesheet" />
+        <link href="css/color_ts.css" rel="stylesheet" />
     </head>
 
     <body>
@@ -144,6 +146,9 @@
                         <div class="option" onclick="setVersion('stable');">Stable</div>
                     </div>
                 </div>
+                <div class="button select">
+                    <span class="examplesButton">Examples</span>
+                </div>
             </div>
         </div>
 
@@ -228,6 +233,12 @@
                     </div>
                 </div>
             </div>
+
+            <div class="category right">
+                <div class="button select">
+                    <span class="examplesButton">Examples</span>
+                </div>
+            </div>
         </div>
 
         <div class="navbar navBar1030">
@@ -305,6 +316,12 @@
                     </div>
                 </div>
             </div>
+
+            <div class="category right">
+                <div class="button select">
+                    <span class="examplesButton">Examples</span>
+                </div>
+            </div>
         </div>
 
         <div class="navbar navBar750">
@@ -387,6 +404,14 @@
                 <canvas touch-action="none" id="renderCanvas"></canvas>
             </div>
         </div>
+        <div id="exampleList" class = "typescript">
+            <div id="exampleBanner">
+                <h1>Examples</h1>
+            </div>
+            <div class="horizontalSeparator"></div>
+            <input id="filterBar" type="text" placeholder="Filter examples...">
+            <img id="filterBarClear" src="https://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/clear_button.png">
+        </div>
 
         <span class="label" id="fpsLabel">FPS</span>
 
@@ -464,4 +489,4 @@
         </script>        
     </body>
 
-</html>
+</html>

+ 0 - 1
Playground/zipContent/index.html

@@ -40,7 +40,6 @@
     <canvas id="renderCanvas"></canvas>
     <script>
         var canvas = document.getElementById("renderCanvas");
-        var engine = new BABYLON.Engine(canvas, true);
 
 ####INJECT####
 

+ 32 - 25
Tools/DevLoader/BabylonLoader.js

@@ -130,7 +130,7 @@ var BABYLONDEVTOOLS;
             var style = document.createElement('link');
             style.href = url;
             style.rel = "stylesheet";
-            style.type = "text/css"
+            style.type = "text/css";
             document.head.appendChild(style);
         }
 
@@ -141,36 +141,44 @@ var BABYLONDEVTOOLS;
         }
 
         Loader.prototype.loadLibrary = function (library, module) {
+            if (library.preventLoadLibrary) {
+                return;
+            }
+
             if (!useDist) {
-                var i = 0;
-                for (; i < library.files.length; i++) {
-                    var file = library.files[i];
-                    if (file.indexOf('lib.d.ts') > 0) {
-                        continue;
-                    }
+                if (library.useOutputForDebugging) {
+                    this.loadScript(babylonJSPath + '/.temp' + module.build.distOutputDirectory + library.output);
+                } else {
+                    var i = 0;
+                    for (; i < library.files.length; i++) {
+                        var file = library.files[i];
+                        if (file.indexOf('lib.d.ts') > 0) {
+                            continue;
+                        }
 
-                    file = file.replace('.ts', '.js');
-                    file = file.replace('../', '');
-                    file = babylonJSPath + '/' + file;
-                    this.loadScript(file);
-                }
+                        file = file.replace('.ts', '.js');
+                        file = file.replace('../', '');
+                        file = babylonJSPath + '/' + file;
+                        this.loadScript(file);
+                    }
 
-                if (library.shaderFiles && library.shaderFiles.length > 0) {
-                    var shaderFile = library.shaderFiles[0];
-                    var endDirectoryIndex = shaderFile.lastIndexOf('/');
-                    shaderFile = shaderFile.substring(0, endDirectoryIndex + 1);
-                    shaderFile += library.output.replace('.js', '.js.fx');
-                    this.loadScript(shaderFile);
-                    if (library.shadersIncludeFiles) {
-                        var includeShaderFile = shaderFile.replace('.js.fx', '.js.include.fx');
-                        this.loadScript(includeShaderFile);
+                    if (library.shaderFiles && library.shaderFiles.length > 0) {
+                        var shaderFile = library.shaderFiles[0];
+                        var endDirectoryIndex = shaderFile.lastIndexOf('/');
+                        shaderFile = shaderFile.substring(0, endDirectoryIndex + 1);
+                        shaderFile += library.output.replace('.js', '.js.fx');
+                        this.loadScript(shaderFile);
+                        if (library.shadersIncludeFiles) {
+                            var includeShaderFile = shaderFile.replace('.js.fx', '.js.include.fx');
+                            this.loadScript(includeShaderFile);
+                        }
                     }
                 }
             }
             else if (min) {
                 if (library.webpack) {
                     if (module.build.distOutputDirectory)
-                        this.loadScript(babylonJSPath + '/dist/preview release' + module.build.distOutputDirectory + library.output.replace('.js', '.bundle.js'));
+                        this.loadScript(babylonJSPath + '/dist/preview release' + module.build.distOutputDirectory + library.output);
                 }
                 else {
                     this.loadScript(babylonJSPath + '/dist/preview release' + module.build.distOutputDirectory + library.output.replace('.js', '.min.js'));
@@ -181,6 +189,7 @@ var BABYLONDEVTOOLS;
                     this.loadScript(babylonJSPath + '/dist/preview release' + module.build.distOutputDirectory + library.output);
             }
 
+            // Currently not being used
             if (!min && library.sassFiles && library.sassFiles.length > 0) {
                 var cssFile = library.output.replace('.js', '.css');
                 cssFile = babylonJSPath + '/dist/preview release' + module.build.distOutputDirectory + cssFile;
@@ -242,10 +251,8 @@ 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]]);
                 }
             }

+ 113 - 154
Tools/Gulp/config.json

@@ -8,6 +8,7 @@
         "declarationModuleFilename": "babylon.module.d.ts",
         "outputDirectory": "../../dist/preview release",
         "playgroundDirectory": "../../Playground/",
+        "tempDirectory": "../../.temp/",
         "intellisenseFile": "babylon.d.txt",
         "intellisenseSources": [
             "../../dist/preview release/babylon.d.ts",
@@ -123,7 +124,8 @@
             "imageProcessing",
             "occlusionQuery",
             "transformFeedback",
-            "noise"
+            "noise",
+            "videoRecorder"
         ],
         "minimal": [
             "meshBuilder",
@@ -136,7 +138,7 @@
             "picking",
             "backgroundMaterial",
             "videoDome"
-        ]      
+        ]
     },
     "workloads": {
         "core": {
@@ -227,7 +229,7 @@
                 "fresnelFunction",
                 "reflectionFunction",
                 "imageProcessingDeclaration",
-                "imageProcessingFunctions",                
+                "imageProcessingFunctions",
                 "bumpFragmentFunctions",
                 "clipPlaneFragmentDeclaration",
                 "fogFragmentDeclaration",
@@ -246,7 +248,7 @@
                 "core",
                 "debug"
             ]
-        },          
+        },
         "occlusionQuery": {
             "files": [
                 "../../src/Engine/Extensions/babylon.engine.occlusionQuery.js"
@@ -255,7 +257,7 @@
                 "core",
                 "debug"
             ]
-        },          
+        },
         "behaviors": {
             "files": [
                 "../../src/Behaviors/babylon.behavior.js"
@@ -263,7 +265,7 @@
             "dependUpon": [
                 "core"
             ]
-        },   
+        },
         "imageProcessing": {
             "files": [
                 "../../src/Materials/babylon.imageProcessingConfiguration.js",
@@ -273,8 +275,8 @@
             "dependUpon": [
                 "core"
             ]
-        },  
-        "noise" : {
+        },
+        "noise": {
             "files": [
                 "../../src/Materials/Textures/Procedurals/babylon.noiseProceduralTexture.js"
             ],
@@ -285,14 +287,17 @@
             "shaders": [
                 "noise.fragment"
             ]
-        },      
+        },
         "particles": {
             "files": [
                 "../../src/Particles/babylon.particle.js",
+                "../../src/Particles/babylon.baseParticleSystem.js",
                 "../../src/Particles/babylon.particleSystem.js",
                 "../../src/Particles/EmitterTypes/babylon.boxParticleEmitter.js",
                 "../../src/Particles/EmitterTypes/babylon.coneParticleEmitter.js",
                 "../../src/Particles/EmitterTypes/babylon.sphereParticleEmitter.js",
+                "../../src/Particles/EmitterTypes/babylon.hemisphericParticleEmitter.js",
+                "../../src/Particles/EmitterTypes/babylon.pointParticleEmitter.js",
                 "../../src/Particles/babylon.particleSystemComponent.js"
             ],
             "dependUpon": [
@@ -571,7 +576,8 @@
                 "../../src/Audio/babylon.audioEngine.js",
                 "../../src/Audio/babylon.sound.js",
                 "../../src/Audio/babylon.soundtrack.js",
-                "../../src/Audio/babylon.analyser.js"
+                "../../src/Audio/babylon.analyser.js",
+                "../../src/Audio/babylon.weightedsound.js"
             ],
             "dependUpon": [
                 "core"
@@ -1083,7 +1089,7 @@
             ]
         },
         "textureFormats": {
-            "files": [ ],
+            "files": [],
             "dependUpon": [
                 "dds",
                 "tga",
@@ -1208,7 +1214,7 @@
             "shaders": [
                 "anaglyph.fragment"
             ]
-        },       
+        },
         "stereoscopic": {
             "files": [
                 "../../src/PostProcess/babylon.stereoscopicInterlacePostProcess.js",
@@ -1226,7 +1232,7 @@
             "shaders": [
                 "stereoscopicInterlace.fragment"
             ]
-        },           
+        },
         "vr": {
             "files": [
                 "../../src/PostProcess/babylon.vrDistortionCorrectionPostProcess.js",
@@ -1386,7 +1392,16 @@
                 "meshBuilder",
                 "additionalTextures"
             ]
+        },
+        "videoRecorder": {
+            "files": [
+                "../../src/Tools/babylon.videoRecorder.js"
+            ],
+            "dependUpon": [
+                "core"
+            ]
         }
+
     },
     "typescript": [
         "../../src/**/*.ts",
@@ -1409,8 +1424,8 @@
         "proceduralTexturesLibrary",
         "loaders",
         "serializers",
-        "inspector",
         "gui",
+        "inspector",
         "viewer",
         "viewer-assets"
     ],
@@ -1749,6 +1764,7 @@
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoader.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts",
+                    "../../loaders/src/glTF/2.0/Extensions/MSFT_audio_emitter.ts",
                     "../../loaders/src/glTF/2.0/Extensions/MSFT_lod.ts",
                     "../../loaders/src/glTF/2.0/Extensions/MSFT_minecraftMesh.ts",
                     "../../loaders/src/glTF/2.0/Extensions/MSFT_sRGBFactors.ts",
@@ -1774,6 +1790,7 @@
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoader.ts",
                     "../../loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts",
+                    "../../loaders/src/glTF/2.0/Extensions/MSFT_audio_emitter.ts",
                     "../../loaders/src/glTF/2.0/Extensions/MSFT_lod.ts",
                     "../../loaders/src/glTF/2.0/Extensions/MSFT_minecraftMesh.ts",
                     "../../loaders/src/glTF/2.0/Extensions/MSFT_sRGBFactors.ts",
@@ -1844,146 +1861,72 @@
     "gui": {
         "libraries": [
             {
-                "files": [
-                    "../../gui/src/2D/style.ts",
-                    "../../gui/src/2D/valueAndUnit.ts",
-                    "../../gui/src/2D/advancedDynamicTexture.ts",
-                    "../../gui/src/2D/measure.ts",
-                    "../../gui/src/2D/math2D.ts",
-                    "../../gui/src/2D/multiLinePoint.ts",
-                    "../../gui/src/2D/controls/control.ts",
-                    "../../gui/src/2D/controls/container.ts",
-                    "../../gui/src/2D/controls/stackPanel.ts",
-                    "../../gui/src/2D/controls/rectangle.ts",
-                    "../../gui/src/2D/controls/ellipse.ts",
-                    "../../gui/src/2D/controls/line.ts",
-                    "../../gui/src/2D/controls/slider.ts",
-                    "../../gui/src/2D/controls/checkbox.ts",
-                    "../../gui/src/2D/controls/radioButton.ts",
-                    "../../gui/src/2D/controls/textBlock.ts",
-                    "../../gui/src/2D/controls/image.ts",
-                    "../../gui/src/2D/controls/button.ts",
-                    "../../gui/src/2D/controls/colorpicker.ts",
-                    "../../gui/src/2D/controls/inputText.ts",
-                    "../../gui/src/2D/controls/inputPassword.ts",
-                    "../../gui/src/2D/controls/virtualKeyboard.ts",
-                    "../../gui/src/2D/controls/multiLine.ts",
-                    "../../gui/src/2D/controls/grid.ts",                    
-                    "../../gui/src/3D/gui3DManager.ts",
-                    "../../gui/src/3D/materials/fluentMaterial.ts",
-                    "../../gui/src/3D/vector3WithInfo.ts",
-                    "../../gui/src/3D/controls/control3D.ts",
-                    "../../gui/src/3D/controls/container3D.ts",
-                    "../../gui/src/3D/controls/abstractButton3D.ts",
-                    "../../gui/src/3D/controls/button3D.ts",
-                    "../../gui/src/3D/controls/meshButton3D.ts",
-                    "../../gui/src/3D/controls/holographicButton.ts",
-                    "../../gui/src/3D/controls/stackPanel3D.ts",
-                    "../../gui/src/3D/controls/volumeBasedPanel.ts",
-                    "../../gui/src/3D/controls/spherePanel.ts",
-                    "../../gui/src/3D/controls/planePanel.ts",
-                    "../../gui/src/3D/controls/scatterPanel.ts",
-                    "../../gui/src/3D/controls/cylinderPanel.ts"
-                ],
-                "shaderFiles": [
-                    "../../gui/src/3D/materials/shaders/fluent.vertex.fx",
-                    "../../gui/src/3D/materials/shaders/fluent.fragment.fx"
-                ],
-                "output": "babylon.gui.js",
-                "buildAsModule": true,
-                "moduleName": "babylonjs-gui",
-                "moduleDeclaration": {
-                    "name": "GUI",
-                    "module": "babylonjs-gui"
-                }
+                "files": [],
+                "noBundleInName": true,
+                "output": "babylon.gui.min.js",
+                "webpack": "../../gui/webpack.config.js",
+                "bundle": "true",
+                "babylonIncluded": false,
+                "useOutputForDebugging": true
             }
         ],
         "build": {
-            "srcOutputDirectory": "../../gui/",
-            "distOutputDirectory": "/gui/"
+            "srcOutputDirectory": "../../gui/src/",
+            "distOutputDirectory": "/gui/",
+            "dtsBundle": {
+                "name": "babylonjs-gui",
+                "main": "../../dist/preview release/gui/build/index.d.ts",
+                "out": "../babylon.gui.module.d.ts",
+                "baseDir": "../../dist/preview release/gui/build/",
+                "headerText": "BabylonJS GUI"
+            },
+            "processDeclaration": {
+                "filename": "babylon.gui.module.d.ts",
+                "packageName": "babylonjs-gui",
+                "moduleName": "BABYLON.GUI",
+                "importsToRemove": [],
+                "classMap": {
+                    "babylonjs": "BABYLON",
+                    "babylonjs-loaders": "BABYLON",
+                    "babylonjs-serializers": "BABYLON"
+                }
+            }
         }
     },
     "inspector": {
         "libraries": [
             {
-                "files": [
-                    "../../inspector/src/Inspector.ts",
-                    "../../inspector/src/properties.ts",
-                    "../../inspector/src/properties_gui.ts",
-                    "../../inspector/src/gui/BasicElement.ts",
-                    "../../inspector/src/adapters/Adapter.ts",
-                    "../../inspector/src/adapters/CameraAdapter.ts",
-                    "../../inspector/src/adapters/PhysicsImpostorAdapter.ts",
-                    "../../inspector/src/adapters/GUIAdapter.ts",
-                    "../../inspector/src/adapters/SoundAdapter.ts",
-                    "../../inspector/src/adapters/TextureAdapter.ts",
-                    "../../inspector/src/adapters/LightAdapter.ts",
-                    "../../inspector/src/adapters/MaterialAdapter.ts",
-                    "../../inspector/src/adapters/MeshAdapter.ts",
-                    "../../inspector/src/adapters/PhysicsImpostorAdapter.ts",
-                    "../../inspector/src/details/DetailPanel.ts",
-                    "../../inspector/src/details/Property.ts",
-                    "../../inspector/src/details/PropertyLine.ts",
-                    "../../inspector/src/gui/ColorElement.ts",
-                    "../../inspector/src/gui/ColorPickerElement.ts",
-                    "../../inspector/src/gui/CubeTextureElement.ts",
-                    "../../inspector/src/gui/HDRCubeTextureElement.ts",
-                    "../../inspector/src/gui/SearchBar.ts",
-                    "../../inspector/src/gui/TextureElement.ts",
-                    "../../inspector/src/gui/Tooltip.ts",
-                    "../../inspector/src/helpers/Helpers.ts",
-                    "../../inspector/src/scheduler/Scheduler.ts",
-                    "../../inspector/src/tabs/Tab.ts",
-                    "../../inspector/src/tabs/PropertyTab.ts",
-                    "../../inspector/src/tabs/CameraTab.ts",
-                    "../../inspector/src/tabs/GUITab.ts",
-                    "../../inspector/src/tabs/PhysicsTab.ts",
-                    "../../inspector/src/tabs/SoundTab.ts",
-                    "../../inspector/src/tabs/TextureTab.ts",
-                    "../../inspector/src/tabs/LightTab.ts",
-                    "../../inspector/src/tabs/MaterialTab.ts",
-                    "../../inspector/src/tabs/MeshTab.ts",
-                    "../../inspector/src/tabs/SceneTab.ts",
-                    "../../inspector/src/tabs/ConsoleTab.ts",
-                    "../../inspector/src/tabs/StatsTab.ts",
-                    "../../inspector/src/tabs/GLTFTab.ts",
-                    "../../inspector/src/tabs/ToolsTab.ts",
-                    "../../inspector/src/tabs/TabBar.ts",
-                    "../../inspector/src/tools/AbstractTool.ts",
-                    "../../inspector/src/tools/PauseScheduleTool.ts",
-                    "../../inspector/src/tools/PickTool.ts",
-                    "../../inspector/src/tools/PopupTool.ts",
-                    "../../inspector/src/tools/RefreshTool.ts",
-                    "../../inspector/src/tools/LabelTool.ts",
-                    "../../inspector/src/tools/Toolbar.ts",
-                    "../../inspector/src/tools/DisposeTool.ts",
-                    "../../inspector/src/tools/FullscreenTool.ts",
-                    "../../inspector/src/tree/TreeItem.ts",
-                    "../../inspector/src/treetools/AbstractTreeTool.ts",
-                    "../../inspector/src/treetools/BoundingBox.ts",
-                    "../../inspector/src/treetools/CameraPOV.ts",
-                    "../../inspector/src/treetools/SoundInteractions.ts",
-                    "../../inspector/src/treetools/Checkbox.ts",
-                    "../../inspector/src/treetools/DebugArea.ts",
-                    "../../inspector/src/treetools/Info.ts",
-                    "../../inspector/src/lib.d.ts"
-                ],
-                "sassFiles": [
-                    "../../inspector/sass/**/*.scss"
-                ],
-                "output": "babylon.inspector.js",
+                "files": [],
+                "sassFiles": [],
+                "output": "babylon.inspector.bundle.js",
                 "webpack": "../../inspector/webpack.config.js",
                 "bundle": "true",
-                "moduleDeclaration": {
-                    "name": "INSPECTOR",
-                    "module": "babylonjs-inspector"
-                },
-                "extendsRoot": true
+                "extendsRoot": true,
+                "useOutputForDebugging": true
             }
         ],
         "build": {
-            "srcOutputDirectory": "../../inspector/",
-            "distOutputDirectory": "/inspector/"
+            "srcOutputDirectory": "../../inspector/src/",
+            "distOutputDirectory": "/inspector/",
+            "dtsBundle": {
+                "name": "babylonjs-inspector",
+                "main": "../../dist/preview release/inspector/build/index.d.ts",
+                "out": "../babylon.inspector.module.d.ts",
+                "baseDir": "../../dist/preview release/inspector/build/",
+                "headerText": "BabylonJS Inspector"
+            },
+            "processDeclaration": {
+                "filename": "babylon.inspector.module.d.ts",
+                "packageName": "babylonjs-inspector",
+                "moduleName": "INSPECTOR",
+                "importsToRemove": [],
+                "classMap": {
+                    "babylonjs": "BABYLON",
+                    "babylonjs-loaders": "BABYLON",
+                    "babylonjs-serializers": "BABYLON",
+                    "babylonjs-gui": "BABYLON.GUI"
+                }
+            }
         }
     },
     "viewer": {
@@ -1998,21 +1941,35 @@
                     "name": "BabylonViewer",
                     "module": "babylonjs-viewer"
                 },
-                "babylonIncluded": true
+                "babylonIncluded": true,
+                "noWatch": true,
+                "preventLoadLibrary": true
             }
         ],
         "build": {
             "srcOutputDirectory": "../../Viewer/",
+            "distOutputDirectory": "/viewer/",
             "dtsBundle": {
                 "name": "babylonjs-viewer",
-                "main": "../../Viewer/dist/build/src/index.d.ts",
-                "out": "../../../../dist/preview release/viewer/babylon.viewer.module.d.ts",
-                "legacyDeclaration": true,
+                "main": "../../dist/preview release/viewer/build/src/index.d.ts",
+                "out": "../../babylon.viewer.module.d.ts",
                 "prependText": "/// <reference path=\"./babylon.d.ts\"/>\n/// <reference path=\"./babylon.glTF2Interface.d.ts\"/>\n/// <reference path=\"./babylonjs.loaders.d.ts\"/>\ndeclare module \"babylonjs-loaders\"{ export=BABYLON;}\n"
             },
+            "processDeclaration": {
+                "packageName": "babylonjs-viewer",
+                "moduleName": "BabylonViewer",
+                "importsToRemove": [
+                    "pep",
+                    "babylonjs-loaders"
+                ],
+                "classMap": {
+                    "babylonjs": "BABYLON",
+                    "babylonjs-loaders": "BABYLON"
+                }
+            },
             "outputs": [
                 {
-                    "destination": [
+                    "destinations": [
                         {
                             "filename": "viewer.js",
                             "outputDirectory": "/../../Viewer/dist/"
@@ -2030,7 +1987,7 @@
                     "minified": true
                 },
                 {
-                    "destination": [
+                    "destinations": [
                         {
                             "filename": "viewer.max.js",
                             "outputDirectory": "/../../Viewer/dist/"
@@ -2056,23 +2013,25 @@
                     "name": "BabylonViewerAssets",
                     "module": "babylonjs-viewer-assets"
                 },
-                "babylonIncluded": true
+                "babylonIncluded": true,
+                "noWatch": true,
+                "preventLoadLibrary": true
             }
         ],
         "build": {
             "srcOutputDirectory": "../../Viewer/",
+            "distOutputDirectory": "/viewer/",
             "dtsBundle": {
                 "name": "babylonjs-viewer-assets",
-                "baseDir": "../../Viewer/dist/build/src/assets/",
-                "main": "../../Viewer/dist/build/src/assets/index.d.ts",
-                "out": "../../../build/assets/babylon.viewer.assets.module.d.ts"
+                "main": "../../dist/preview release/viewer/build/src/assets/index.d.ts",
+                "out": "../../../../../../Viewer/build/assets/babylon.viewer.assets.module.d.ts"
             },
             "outputs": [
                 {
-                    "destination": [
+                    "destinations": [
                         {
                             "filename": "babylon.viewer.assets.js",
-                            "outputDirectory": "/../../Viewer/dist/build/assets/"
+                            "outputDirectory": "/../../Viewer/build/assets/"
                         }
                     ],
                     "minified": true
@@ -2080,4 +2039,4 @@
             ]
         }
     }
-}
+}

+ 160 - 107
Tools/Gulp/gulpfile.js

@@ -16,7 +16,6 @@ var merge2 = require("merge2");
 var concat = require("gulp-concat");
 var rename = require("gulp-rename");
 var cleants = require("gulp-clean-ts-extends");
-var changedInPlace = require("gulp-changed-in-place");
 var runSequence = require("run-sequence");
 var replace = require("gulp-replace");
 var uncommentShader = require("./gulp-removeShaderComments");
@@ -25,17 +24,17 @@ var optimisejs = require("gulp-optimize-js");
 var webserver = require("gulp-webserver");
 var path = require("path");
 var sass = require("gulp-sass");
-var webpack = require("webpack-stream");
+const webpack = require('webpack');
+var webpackStream = require("webpack-stream");
 var typedoc = require("gulp-typedoc");
 var validateTypedoc = require("./gulp-validateTypedoc");
-var request = require('request');
 var fs = require("fs");
 var dtsBundle = require('dts-bundle');
 const through = require('through2');
 var karmaServer = require('karma').Server;
 
 //viewer declaration
-var processViewerDeclaration = require('./processViewerDeclaration');
+var processDeclaration = require('./processViewerDeclaration');
 
 var config = require("./config.json");
 
@@ -448,107 +447,135 @@ var buildExternalLibrary = function (library, settings, watch) {
 
         if (library.webpack) {
             let sequence = [waitAll];
-            let wpBuild = webpack(require(library.webpack));
-            if (settings.build.outputs) {
-                //shoud dtsBundle create the declaration?
-                if (settings.build.dtsBundle) {
-                    let event = wpBuild
-                        .pipe(through.obj(function (file, enc, cb) {
-                            // only declaration files
-                            const isdts = /\.d\.ts$/.test(file.path);
-                            if (isdts) this.push(file);
-                            cb();
-                        }))
-                        .pipe(gulp.dest('.'));
-                    // dts-bundle does NOT support (gulp) streams, so files have to be saved and reloaded, 
-                    // until I fix it
-                    event.on("end", function () {
-                        // create the file
-                        dtsBundle.bundle(settings.build.dtsBundle);
-                        // prepend the needed reference
-                        let fileLocation = path.join(path.dirname(settings.build.dtsBundle.main), settings.build.dtsBundle.out);
-                        fs.readFile(fileLocation, function (err, data) {
-                            if (err) throw err;
-                            data = (settings.build.dtsBundle.prependText || "") + '\n' + data.toString();
-                            fs.writeFile(fileLocation, data);
-                            if (settings.build.dtsBundle.legacyDeclaration) {
-                                var newData = processViewerDeclaration(data);
-                                fs.writeFile(fileLocation.replace('.module', ''), newData);
-                            }
-                        });
-                    });
-                }
 
-                let build = wpBuild
-                    .pipe(through.obj(function (file, enc, cb) {
-                        // only pipe js files
-                        const isJs = /\.js$/.test(file.path);
-                        if (isJs) this.push(file);
-                        cb();
-                    }))
-                    .pipe(addModuleExports(library.moduleDeclaration, { subModule: false, extendsRoot: false, externalUsingBabylon: true, noBabylonInit: library.babylonIncluded }));
+            if (settings.build.outputs) {
 
-                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);
+                    let wpConfig = require(library.webpack);
+                    if (!out.minified) {
+                        wpConfig.mode = "development";
+                    }
+                    let wpBuild = webpackStream(wpConfig, webpack);
+
+                    //shoud dtsBundle create the declaration?
+                    if (settings.build.dtsBundle) {
+                        let event = wpBuild
+                            .pipe(through.obj(function (file, enc, cb) {
+                                // only declaration files
+                                const isdts = /\.d\.ts$/.test(file.path);
+                                if (isdts) this.push(file);
+                                cb();
+                            }))
+                            .pipe(gulp.dest(outputDirectory));
+                        // dts-bundle does NOT support (gulp) streams, so files have to be saved and reloaded, 
+                        // until I fix it
+                        event.on("end", function () {
+                            // create the file
+                            dtsBundle.bundle(settings.build.dtsBundle);
+                            // prepend the needed reference
+                            let fileLocation = path.join(path.dirname(settings.build.dtsBundle.main), settings.build.dtsBundle.out);
+                            fs.readFile(fileLocation, function (err, data) {
+                                if (err) throw err;
+                                data = (settings.build.dtsBundle.prependText || "") + '\n' + data.toString();
+                                fs.writeFile(fileLocation, data);
+                                if (settings.build.processDeclaration) {
+                                    var newData = processDeclaration(data, settings.build.processDeclaration);
+                                    fs.writeFile(fileLocation.replace('.module', ''), newData);
+                                }
+                            });
                         });
                     }
-                });
-
-                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));
 
-                    if (library.babylonIncluded && dest.addBabylonDeclaration) {
-                        // include the babylon declaration
-                        if (dest.addBabylonDeclaration === true) {
-                            dest.addBabylonDeclaration = [config.build.declarationFilename];
+                    let build = wpBuild
+                        .pipe(through.obj(function (file, enc, cb) {
+                            // only pipe js files
+                            const isJs = /\.js$/.test(file.path);
+                            if (isJs) this.push(file);
+                            cb();
+                        }))
+                        .pipe(addModuleExports(library.moduleDeclaration, { subModule: false, extendsRoot: false, externalUsingBabylon: true, noBabylonInit: library.babylonIncluded }));
+
+                    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));
+
+                        if (library.babylonIncluded && dest.addBabylonDeclaration) {
+                            // include the babylon declaration
+                            if (dest.addBabylonDeclaration === true) {
+                                dest.addBabylonDeclaration = [config.build.declarationFilename];
+                            }
+                            var decsToAdd = dest.addBabylonDeclaration.map(function (dec) {
+                                return config.build.outputDirectory + '/' + dec;
+                            });
+                            sequence.unshift(gulp.src(decsToAdd)
+                                .pipe(rename(function (path) {
+                                    path.dirname = '';
+                                }))
+                                .pipe(gulp.dest(outputDirectory)))
                         }
-                        var decsToAdd = dest.addBabylonDeclaration.map(function (dec) {
-                            return config.build.outputDirectory + '/' + dec;
-                        });
-                        sequence.unshift(gulp.src(decsToAdd)
-                            .pipe(rename(function (path) {
-                                path.dirname = '';
-                            }))
-                            .pipe(gulp.dest(outputDirectory)))
                     }
-                }
 
-                unminifiedOutpus.forEach(dest => {
-                    processDestination(dest);
-                });
+                    out.destinations.forEach(dest => {
+                        processDestination(dest);
+                    });
 
-                if (minifiedOutputs.length) {
-                    build = build
-                        .pipe(uglify())
-                        .pipe(optimisejs())
-                }
+                    sequence.push(build);
 
-                minifiedOutputs.forEach(dest => {
-                    processDestination(dest);
                 });
 
-                sequence.push(build);
+
 
             } else {
+
+                let wpBuild = webpackStream(require(library.webpack), webpack);
+
+                let buildEvent = wpBuild
+                    .pipe(gulp.dest(outputDirectory))
+                    //back-compat
+                    .pipe(through.obj(function (file, enc, cb) {
+                        // only js files
+                        const isjs = /\.js$/.test(file.path);
+                        if (isjs) this.push(file);
+                        cb();
+                    }))
+                    .pipe(rename(library.output.replace(".js", ".max.js")))
+                    .pipe(rename(library.output.replace(".min.max.", ".")))
+                    .pipe(rename(library.output.replace(".bundle.max.", ".")))
+                    .pipe(gulp.dest(outputDirectory));
                 sequence.push(
-                    wpBuild
-                        .pipe(rename(library.output.replace(".js", library.noBundleInName ? '.js' : ".bundle.js")))
-                        .pipe(addModuleExports(library.moduleDeclaration, { subModule: false, extendsRoot: library.extendsRoot, externalUsingBabylon: true }))
-                        .pipe(uglify())
-                        .pipe(optimisejs())
-                        .pipe(gulp.dest(outputDirectory))
-                )
+                    buildEvent
+                );
+                if (settings.build.dtsBundle || settings.build.processDeclaration) {
+                    buildEvent.on("end", function () {
+                        if (settings.build.dtsBundle) {
+                            dtsBundle.bundle(settings.build.dtsBundle);
+                        } if (settings.build.processDeclaration) {
+                            let fileLocation = path.join(outputDirectory, settings.build.processDeclaration.filename);
+                            fs.readFile(fileLocation, function (err, data) {
+                                if (err) throw err;
+                                var newData = processDeclaration(data, settings.build.processDeclaration);
+                                fs.writeFile(fileLocation.replace('.module', ''), newData);
+                                //legacy module support
+                                fs.writeFile(fileLocation, data + "\n" + newData);
+                            });
+                        }
+                    });
+                }
+                /*if (settings.build.processDeclaration) {
+                    sequence.push(
+                        wpBuild
+                            .pipe(through.obj(function (file, enc, cb) {
+                                // only js files
+                                const isDts = /\.d.ts$/.test(file.path);
+                                file.contents = new Buffer(processDeclaration(file.contents, settings.build.processDeclaration));
+                                if (isDts) this.push(file);
+                                cb();
+                            }))
+                            .pipe(gulp.dest(outputDirectory))
+                    )
+                }*/
             }
 
             return merge2(sequence);
@@ -600,7 +627,7 @@ gulp.task("build-custom", function (cb) {
  * Do it all.
  */
 gulp.task("typescript-all", function (cb) {
-    runSequence("typescript", "typescript-libraries", cb);
+    runSequence("typescript", "typescript-libraries", "netlify-cleanup", cb);
 });
 
 /**
@@ -623,22 +650,35 @@ gulp.task("watch", ["srcTscWatch"], function () {
     var tasks = [];
 
     config.modules.map(function (module) {
+
         config[module].libraries.map(function (library) {
-            tasks.push(gulp.watch(library.files, { interval: interval }, function () {
-                console.log(library.output);
-                return buildExternalLibrary(library, config[module], true)
-                    .pipe(debug());
-            }));
-            tasks.push(gulp.watch(library.shaderFiles, { interval: interval }, function () {
-                console.log(library.output);
-                return buildExternalLibrary(library, config[module], true)
-                    .pipe(debug())
-            }));
-            tasks.push(gulp.watch(library.sassFiles, { interval: interval }, function () {
-                console.log(library.output);
-                return buildExternalLibrary(library, config[module], true)
-                    .pipe(debug())
-            }));
+            if (library.webpack) {
+                if (library.noWatch) return;
+                var outputDirectory = config.build.tempDirectory + config[module].build.distOutputDirectory;
+                let wpconfig = require(library.webpack);
+                wpconfig.watch = true;
+                // dev mode and absolute path sourcemaps for debugging
+                wpconfig.mode = "development";
+                wpconfig.output.devtoolModuleFilenameTemplate = "[absolute-resource-path]";
+                //config.stats = "minimal";
+                tasks.push(webpackStream(wpconfig, webpack).pipe(gulp.dest(outputDirectory)))
+            } else {
+                tasks.push(gulp.watch(library.files, { interval: interval }, function () {
+                    console.log(library.output);
+                    return buildExternalLibrary(library, config[module], true)
+                        .pipe(debug());
+                }));
+                tasks.push(gulp.watch(library.shaderFiles, { interval: interval }, function () {
+                    console.log(library.output);
+                    return buildExternalLibrary(library, config[module], true)
+                        .pipe(debug())
+                }));
+                tasks.push(gulp.watch(library.sassFiles, { interval: interval }, function () {
+                    console.log(library.output);
+                    return buildExternalLibrary(library, config[module], true)
+                        .pipe(debug())
+                }));
+            }
         });
     });
 
@@ -696,6 +736,19 @@ gulp.task("clean-JS-MAP", function () {
     ], { force: true });
 });
 
+gulp.task("netlify-cleanup", function () {
+    //set by netlify
+    if (process.env.REPOSITORY_URL) {
+        return del([
+            "../../inspector/node_modules/**/*", "../../gui/node_modules/**/*",
+            "../../Viewer/node_modules/**/*"
+        ], { force: true });
+    }
+    else {
+        return true;
+    }
+})
+
 // this is needed for the modules for the declaration files.
 gulp.task("modules-compile", function () {
     var tsResult = gulp.src(config.typescript)
@@ -1131,7 +1184,7 @@ gulp.task("tests-viewer-validation-browserstack", ["tests-viewer-validation-tran
  */
 gulp.task("tests-viewer-validation-transpile", function (done) {
 
-    let wpBuild = webpack(require('../../Viewer//webpack.gulp.config.js'));
+    let wpBuild = webpackStream(require('../../Viewer/webpack.gulp.config.js'), webpack);
 
     // clean the built directory
     rmDir("../../Viewer/tests/build/");
@@ -1150,7 +1203,7 @@ gulp.task("tests-viewer-validation-transpile", function (done) {
  */
 gulp.task("tests-viewer-transpile", function (done) {
 
-    let wpBuild = webpack(require('../../Viewer/tests/unit/webpack.config.js'));
+    let wpBuild = webpackStream(require('../../Viewer/tests/unit/webpack.config.js'), webpack);
 
     // clean the built directory
     rmDir("../../Viewer/tests/build/");

+ 10 - 9
Tools/Gulp/package.json

@@ -9,13 +9,13 @@
     "readme": "https://github.com/BabylonJS/Babylon.js/edit/master/readme.md",
     "license": "(Apache-2.0)",
     "devDependencies": {
-        "@types/node": "^8.9.4",
+        "@types/node": "^8.10.21",
         "base64-font-loader": "0.0.4",
         "base64-image-loader": "^1.2.1",
         "chai": "^4.1.2",
         "color-support": "^1.1.3",
         "css-loader": "^0.25.0",
-        "deepmerge": "^2.0.1",
+        "deepmerge": "^2.1.1",
         "del": "2.2.2",
         "es6-promise": "^4.2.4",
         "exports-loader": "^0.6.4",
@@ -27,7 +27,7 @@
         "gulp-debug": "^3.2.0",
         "gulp-expect-file": "^0.0.7",
         "gulp-optimize-js": "^1.0.2",
-        "gulp-rename": "~1.2.2",
+        "gulp-rename": "^1.2.3",
         "gulp-replace": "~0.5.3",
         "gulp-sass": "3.1.0",
         "gulp-sourcemaps": "~1.9.1",
@@ -40,7 +40,7 @@
         "html-loader": "^0.5.5",
         "imports-loader": "^0.7.1",
         "json-loader": "^0.5.7",
-        "karma": "^2.0.0",
+        "karma": "^2.0.4",
         "karma-browserstack-launcher": "^1.3.0",
         "karma-chai": "^0.1.0",
         "karma-chrome-launcher": "^2.2.0",
@@ -53,20 +53,21 @@
         "mocha": "^4.0.1",
         "phantomjs": "^2.1.7",
         "run-sequence": "~1.1.0",
-        "sinon": "^4.3.0",
+        "sinon": "^4.5.0",
         "style-loader": "^0.13.2",
         "through2": "~0.6.5",
         "ts-loader": "^2.3.7",
         "typedoc": "^0.9.0",
-        "typescript": "~2.8.1",
-        "webpack-stream": "^4.0.1"
+        "typescript": "^2.8.4",
+        "webpack": "^4.16.1",
+        "webpack-stream": "^4.0.3"
     },
     "scripts": {
-        "install": "npm --prefix ../../Playground/ install ../../Playground/ && npm --prefix ../../tests/unit/ install ../../tests/unit/ && npm --prefix ../../Viewer/tests/ install ../../Viewer/tests/ && cd ../../Viewer && npm install && cd ../Tools/Gulp/ && gulp deployLocalDev"
+        "install": "cd ../../gui && npm install && cd ../Tools/Gulp/ &&  cd ../../inspector && npm install && cd ../Tools/Gulp/ && npm --prefix ../../Playground/ install ../../Playground/ && npm --prefix ../../tests/unit/ install ../../tests/unit/ && npm --prefix ../../Viewer/tests/ install ../../Viewer/tests/ && cd ../../Viewer && npm install && cd ../Tools/Gulp/ && gulp deployLocalDev"
     },
     "dependencies": {
         "dts-bundle": "^0.7.3",
         "gulp-clean": "^0.4.0",
-        "npm": "^5.8.0"
+        "npm": "^5.10.0"
     }
 }

+ 51 - 19
Tools/Gulp/processViewerDeclaration.js

@@ -1,4 +1,13 @@
-module.exports = function (data) {
+module.exports = function (data, options) {
+
+    /*
+    {
+        packageName: string,
+        moduleName: string,
+        importsToRemove: Array<string>,
+        classMap
+    }
+    */
 
     var str = "" + data;
 
@@ -6,35 +15,58 @@ module.exports = function (data) {
     // str = str.replace(/declare module 'babylonjs-viewer\/' {((?!(declare))(.|\n))*\n}/g, '');
 
     let lines = str.split('\n');
-    var firstIndex = lines.findIndex((line => { return line.indexOf("'babylonjs-viewer/'") !== -1 }));
+    var firstIndex = lines.findIndex((line => { return line.indexOf(`'${options.packageName}/'`) !== -1 }));
     var lastIndex = lines.findIndex(((line, idx) => { return line.trim() === '}' && idx > firstIndex }));
     lines.splice(firstIndex, lastIndex - firstIndex + 1);
     str = lines.join('\n');
 
-    str = str.replace(/declare module (.*) {/g, 'declare module BabylonViewer {').replace("import * as BABYLON from 'babylonjs';", "");
-    str = str.replace(/import {(.*)} from ['"]babylonjs-viewer(.*)['"];/g, '').replace(/import 'babylonjs-loaders';/, '').replace(/import 'pep';/, '');
+    str = str.replace(/declare module (.*) {/g, `declare module ${options.moduleName} {`);
+
+    str = str.replace("import * as BABYLON from 'babylonjs';", "");
+    let regexp = new RegExp(`import {(.*)} from ['"]${options.packageName}(.*)['"];`, 'g');
+    str = str.replace(regexp, '');
+
+    if (options.importsToRemove) {
+        while (options.importsToRemove.length) {
+            let remove = options.importsToRemove.pop();
+            str = str.replace(new RegExp(`import '${remove}';`), '');
+        }
+    }
 
     //find all used BABYLON and BABYLON-Loaders classes:
 
-    var babylonRegex = /import {(.*)} from ['"](babylonjs|babylonjs-loaders)['"];/g
+    if ((options.classMap)) {
+        Object.keys(options.classMap).forEach(package => {
+            var babylonRegex = new RegExp(`import {(.*)} from ['"](${package})['"];`, "g");
 
-    var match = babylonRegex.exec(str);
-    let classes = new Set();
-    while (match != null) {
-        if (match[1]) {
-            match[1].split(",").forEach(element => {
-                classes.add(element.trim());
+            var match = babylonRegex.exec(str);
+            let classes = new Set();
+            while (match != null) {
+                if (match[1]) {
+                    match[1].split(",").forEach(element => {
+                        classes.add(element.trim());
+                    });
+                }
+                match = babylonRegex.exec(str);
+            }
+            str = str.replace(babylonRegex, '');
+            classes.forEach(cls => {
+                let rg = new RegExp(`([ <])(${cls})([^\\w])`, "g")
+                str = str.replace(rg, `$1${options.classMap[package]}.$2$3`);
             });
-        }
-        match = babylonRegex.exec(str);
+        })
     }
-    str = str.replace(babylonRegex, '');
-    classes.forEach(cls => {
-        let rg = new RegExp(`([ <])(${cls})([^\\w])`, "g")
-        str = str.replace(rg, "$1BABYLON.$2$3");
-    });
 
-    str = str.replace(/export {(.*)};/g, '')
+    str = str.replace(/export {(.*)};/g, '');
+
+    str = str.replace(/import (.*);/g, "");
+
+    str = str.split("\n").filter(line => line.trim()).filter(line => line.indexOf("export * from") === -1).join("\n");
+
+    //empty declare regex
+    let emptyDeclareRegexp = new RegExp("declare module " + options.moduleName + " {\n}", "g");
+
+    str = str.replace(emptyDeclareRegexp, "");
 
     return str;
 }

+ 8 - 4
Tools/Publisher/index.js

@@ -51,12 +51,13 @@ let packages = [
         required: [
             basePath + '/viewer/readme.md',
             basePath + '/viewer/package.json',
-            basePath + '/viewer/babylon.viewer.js'
+            basePath + '/viewer/babylon.viewer.js',
+            basePath + '/viewer/babylon.viewer.max.js'
         ]
     },
     {
         name: 'viewer-assets',
-        path: basePath + '/../../Viewer/dist/build/assets/',
+        path: basePath + '/../../Viewer/build/assets/',
         required: [
             basePath + '/../../Viewer/assets/readme.md',
             basePath + '/../../Viewer/assets/package.json',
@@ -215,7 +216,7 @@ function processCore(package, version) {
 
 function processViewer(package, version) {
 
-    let buildPath = package.path + "dist/build/src/";
+    let buildPath = package.path + "build/src/";
     let projectPath = '../../Viewer';
 
     if (package.required) {
@@ -257,7 +258,10 @@ function publish(version, packageName, basePath) {
 
     //publish the respected package
     console.log("executing " + 'npm publish \"' + basePath + "\"" + ' ' + tagDef);
-    shelljs.exec('npm publish \"' + basePath + "\"" + ' ' + tagDef);
+    if (process.argv.indexOf('--no-publish') === -1) {
+        shelljs.exec('npm publish \"' + basePath + "\"" + ' ' + tagDef);
+    }
+
 }
 
 function getFiles(dir, files_) {

+ 139 - 0
Tools/WebpackShaderLoader/index.js

@@ -0,0 +1,139 @@
+//modified https://github.com/grieve/webpack-glsl-loader/blob/master/index.js
+'use strict';
+
+var fs = require('fs');
+var path = require('path');
+
+
+function parse(loader, source, context, cb) {
+    var imports = [];
+    var importPattern = /@import ([.\/\w_-]+);/gi;
+    var match = importPattern.exec(source);
+
+    while (match != null) {
+        imports.push({
+            key: match[1],
+            target: match[0],
+            content: ''
+        });
+        match = importPattern.exec(source);
+    }
+
+    source = uncomment(source);
+
+    processImports(loader, source, context, imports, cb);
+}
+
+var singleComment = 1;
+var multiComment = 2;
+
+function uncomment(str) {
+
+    var currentChar;
+    var nextChar;
+    var insideString = false;
+    var insideComment = 0;
+    var offset = 0;
+    var ret = '';
+
+    str = str.replace(/\r\n/g, '\n');
+    str = str.replace(/[ \f\t\v]+/g, ' ');
+    str = str.replace(/^\s*\n/gm, '');
+    str = str.replace(/ \+ /g, '+');
+    str = str.replace(/ \- /g, '-');
+    str = str.replace(/ \/ /g, '/');
+    str = str.replace(/ \* /g, '*');
+    str = str.replace(/ > /g, '>');
+    str = str.replace(/ < /g, '<');
+    str = str.replace(/ >= /g, '>=');
+    str = str.replace(/ <= /g, '<=');
+    str = str.replace(/ \+= /g, '+=');
+    str = str.replace(/ \-= /g, '-=');
+    str = str.replace(/ \/= /g, '/=');
+    str = str.replace(/ \*= /g, '*=');
+    str = str.replace(/ = /g, '=');
+    str = str.replace(/, /g, ',');
+    str = str.replace(/\n\n/g, '\n');
+    str = str.replace(/\n /g, '\n');
+
+    for (var i = 0; i < str.length; i++) {
+        currentChar = str[i];
+        nextChar = str[i + 1];
+
+        if (!insideComment && currentChar === '"') {
+            var escaped = str[i - 1] === '\\' && str[i - 2] !== '\\';
+            if (!escaped) {
+                insideString = !insideString;
+            }
+        }
+
+        if (insideString) {
+            continue;
+        }
+
+        if (!insideComment && currentChar + nextChar === '//') {
+            ret += str.slice(offset, i);
+            offset = i;
+            insideComment = singleComment;
+            i++;
+        } else if (insideComment === singleComment && currentChar === '\n') {
+            insideComment = 0;
+            offset = i;
+        } else if (!insideComment && currentChar + nextChar === '/*') {
+            ret += str.slice(offset, i);
+            offset = i;
+            insideComment = multiComment;
+            i++;
+            continue;
+        } else if (insideComment === multiComment && currentChar + nextChar === '*/') {
+            i++;
+            insideComment = 0;
+            offset = i + 1;
+            continue;
+        }
+    }
+
+    return ret + (insideComment ? '' : str.substr(offset));
+}
+
+function processImports(loader, source, context, imports, cb) {
+    if (imports.length === 0) {
+        return cb(null, source);
+    }
+
+    var imp = imports.pop();
+
+    loader.resolve(context, imp.key + '.fx', function (err, resolved) {
+        if (err) {
+            return cb(err);
+        }
+
+        loader.addDependency(resolved);
+        fs.readFile(resolved, 'utf-8', function (err, src) {
+            if (err) {
+                return cb(err);
+            }
+
+            parse(loader, src, path.dirname(resolved), function (err, bld) {
+                if (err) {
+                    return cb(err);
+                }
+
+                source = source.replace(imp.target, bld);
+                processImports(loader, source, context, imports, cb);
+            });
+        });
+    });
+}
+
+module.exports = function (source) {
+    this.cacheable();
+    var cb = this.async();
+    parse(this, source, this.context, function (err, bld) {
+        if (err) {
+            return cb(err);
+        }
+
+        cb(null, 'module.exports = ' + JSON.stringify(bld));
+    });
+};

+ 4 - 4
Viewer/assets/templates/default/navbar.html

@@ -457,7 +457,7 @@
             </button>
             <div class="menu-options">
                 {{#each animations}} {{#unless (eq ../selectedAnimation (add @index 1))}}
-                <button class="flex-container label-option-button animation-buttons" data-value="{{this.value}}">
+                <button class="flex-container label-option-button animation-buttons" data-value="{{this.value}} ">
                     <!-- <div> -->
                     <span class="icon types-icon"></span>
                     <span class="control-text animation-label">{{this.label}}</span>
@@ -494,15 +494,15 @@
     {{/unless}}
     <div class="default-control">
         {{#unless hideVr}}
-        <button class="vr vr-button" title="{{text.vrButton}}">
+        <button class="vr vr-button" title="{{text.vrButton}} ">
             <span class="icon vr-icon"></span>
         </button>
         {{/unless}}{{#unless hideHelp}}
-        <button class="help help-button" title="{{text.helpButton}}">
+        <button class="help help-button" title="{{text.helpButton}} ">
             <span class="icon help-icon"></span>
         </button>
         {{/unless}} {{#unless hideFullscreen}}
-        <button class="fullscreen fullscreen-button" title="{{text.fullscreenButton}}">
+        <button class="fullscreen fullscreen-button" title="{{text.fullscreenButton}} ">
             <span class="icon fullscreen-icon"></span>
         </button>
         {{/unless}}

+ 25 - 0
Viewer/dist/printExample.html

@@ -0,0 +1,25 @@
+<!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 - 3D Print usage</title>
+        <style>
+            babylon {
+                width: 800px;
+                height: 500px;
+            }
+        </style>
+    </head>
+
+    <body>
+        <babylon templates.nav-bar.params.hide-print="false">
+            <model url="https://playground.babylonjs.com/scenes/BoomBox.glb">
+            </model>
+        </babylon>
+        <script src="viewer.js"></script>
+    </body>
+
+</html>

+ 6 - 4
Viewer/package.json

@@ -27,15 +27,17 @@
         "@types/node": "^8.9.4",
         "base64-font-loader": "0.0.4",
         "base64-image-loader": "^1.2.1",
+        "base64-inline-loader": "^1.1.1",
         "deepmerge": "^2.1.1",
         "handlebars": "^4.0.11",
         "html-loader": "^0.5.5",
         "json-loader": "^0.5.7",
-        "ts-loader": "^2.3.7",
-        "typescript": "^2.7.2",
+        "ts-loader": "^4.4.0",
+        "typescript": "^2.9.2",
         "uglifyjs-webpack-plugin": "^1.2.2",
-        "webpack": "^3.11.0",
-        "webpack-dev-server": "^2.11.2"
+        "webpack": "^4.16.0",
+        "webpack-cli": "^3.0.8",
+        "webpack-dev-server": "^3.1.4"
     },
     "dependencies": {
         "pepjs": "^0.4.3"

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

@@ -43,7 +43,7 @@ export function processConfigurationCompatibility(configuration: ViewerConfigura
 
     if (configuration.lab) {
         if (configuration.lab.assetsRootURL) {
-            setKeyInObject(configuration, "scene.assetsRootURL", configuration.lab.assetsRootURL);
+            setKeyInObject(configuration, "scene.assetsRootURL", configuration.lab.assetsRootURL, true);
         }
         if (configuration.lab.environmentMap) {
             setKeyInObject(configuration, "environmentMap", configuration.lab.environmentMap, true);
@@ -63,4 +63,4 @@ function setKeyInObject(object: any, keys: string, value: any, shouldOverwrite?:
     });
     if (curObj[lastKey] !== undefined && !shouldOverwrite) return;
     curObj[lastKey] = value;
-}
+}

+ 4 - 2
Viewer/src/configuration/types/default.ts

@@ -51,12 +51,14 @@ export let defaultConfiguration: ViewerConfiguration = {
                 hideHelp: true,
                 hideHd: true,
                 hideVr: true,
+                hidePrint: true,
                 disableOnFullscreen: false,
                 text: {
                     hdButton: "Toggle HD",
-                    fullscreenButton: "Fullscreen",
+                    fullscreenButton: "Toggle Fullscreen",
                     helpButton: "Help",
-                    vrButton: "Toggle VR"
+                    vrButton: "Toggle VR",
+                    printButton: "3D Print Object"
                 }
             },
             events: {

+ 2 - 2
Viewer/src/model/viewerModel.ts

@@ -354,7 +354,7 @@ export class ViewerModel implements IDisposable {
      */
     protected _getAnimationByName(name: string): Nullable<IModelAnimation> {
         // can't use .find, noe available on IE
-        let filtered = this._animations.filter(a => a.name === name);
+        let filtered = this._animations.filter(a => a.name === name.trim());
         // what the next line means - if two animations have the same name, they will not be returned!
         if (filtered.length === 1) {
             return filtered[0];
@@ -377,7 +377,7 @@ export class ViewerModel implements IDisposable {
     }
 
     public setCurrentAnimationByName(name: string) {
-        let animation = this._getAnimationByName(name);
+        let animation = this._getAnimationByName(name.trim());
         if (animation) {
             if (this.currentAnimation && this.currentAnimation.state !== AnimationState.STOPPED) {
                 this.currentAnimation.stop();

+ 62 - 0
Viewer/src/templating/plugins/printButton.ts

@@ -0,0 +1,62 @@
+import { AbstractViewerNavbarButton } from "../viewerTemplatePlugin";
+import { DefaultViewer } from "../../viewer/defaultViewer";
+import { EventCallback } from "../templateManager";
+import { Tools } from "babylonjs";
+
+export class PrintButtonPlugin extends AbstractViewerNavbarButton {
+
+    private _currentModelUrl: string;
+
+    constructor(private _viewer: DefaultViewer) {
+        super("print", "print-button", PrintButtonPlugin.HtmlTemplate);
+
+        this._viewer.onModelLoadedObservable.add((model) => {
+            this._currentModelUrl = "";
+            if (model.configuration.url) {
+                let filename = Tools.GetFilename(model.configuration.url) || model.configuration.url;
+                let baseUrl = model.configuration.root || Tools.GetFolderPath(model.configuration.url);
+
+                //gltf, obj, stl
+                let extension = model.configuration.loader || filename.split(".").pop() || "";
+                let printable = false;
+                // not using .some sue to IE11
+                ["gltf", "glb", "obj", "stl"].forEach(ext => {
+                    if (extension.indexOf(ext) !== -1) {
+                        printable = true;
+                    }
+                })
+                if (printable) {
+                    this._currentModelUrl = baseUrl + filename;
+                }
+            }
+        })
+    }
+
+    onEvent(event: EventCallback): void {
+        if (this._currentModelUrl) {
+            let printUrl = this._currentModelUrl.replace(/https?:\/\//, "com.microsoft.builder3d://");
+            window.open(printUrl, "_self");
+        }
+    }
+
+    protected static HtmlTemplate: string = `
+{{#unless hidePrint}}
+<style>
+
+/* Show only if it's a windows 10 printer  */
+.print-icon.not-win-10 {
+    display: none;
+}
+
+.print-icon:after {
+    font-size: 16px;
+    content: "\\E914";
+}
+
+</style>
+<button class="print-button ${window.navigator.userAgent.indexOf("Windows NT 10.0") === -1 ? "no-win-10" : ""}" title="{{text.printButton}}">
+     <span class="icon print-icon"></span>
+ </button>
+ {{/unless}}
+`;
+}

+ 25 - 11
Viewer/src/viewer/defaultViewer.ts

@@ -8,6 +8,7 @@ import { ViewerModel } from '../model/viewerModel';
 import { IModelAnimation, AnimationState } from '../model/modelAnimation';
 import { IViewerTemplatePlugin } from '../templating/viewerTemplatePlugin';
 import { HDButtonPlugin } from '../templating/plugins/hdButtonPlugin';
+import { PrintButtonPlugin } from '../templating/plugins/printButton';
 
 /**
  * The Default viewer is the default implementation of the AbstractViewer.
@@ -148,6 +149,7 @@ export class DefaultViewer extends AbstractViewer {
             }
 
             this.registerTemplatePlugin(new HDButtonPlugin(this));
+            this.registerTemplatePlugin(new PrintButtonPlugin(this));
         }
     }
 
@@ -196,7 +198,7 @@ export class DefaultViewer extends AbstractViewer {
                 var value = element.dataset["value"];
                 var label = element.querySelector("span.animation-label");
                 if (label && value) {
-                    this._updateAnimationType({ value, label: label.innerHTML });
+                    this._updateAnimationType({ value: value.trim(), label: label.innerHTML });
                 }
                 break;
             case "speed-option-button":
@@ -326,19 +328,31 @@ export class DefaultViewer extends AbstractViewer {
         this._updateAnimationSpeed("1.0", paramsObject);
     }
 
-    public toggleVR() {
-        super.toggleVR();
+    protected _initVR() {
+        this.engine.onVRDisplayChangedObservable.add(() => {
+            let viewerTemplate = this.templateManager.getTemplate('viewer');
+            let viewerElement = viewerTemplate && viewerTemplate.parent;
 
-        let viewerTemplate = this.templateManager.getTemplate('viewer');
-        let viewerElement = viewerTemplate && viewerTemplate.parent;
-
-        if (viewerElement) {
-            if (this._vrToggled) {
-                viewerElement.classList.add("in-vr");
-            } else {
-                viewerElement.classList.remove("in-vr");
+            if (viewerElement) {
+                if (this.sceneManager.vrHelper!.isInVRMode) {
+                    viewerElement.classList.add("in-vr");
+                } else {
+                    viewerElement.classList.remove("in-vr");
+                }
             }
+        });
+        if (this.sceneManager.vrHelper) {
+            // due to the way the experience helper is exisintg VR, this must be added.
+            this.sceneManager.vrHelper.onExitingVR.add(() => {
+                let viewerTemplate = this.templateManager.getTemplate('viewer');
+                let viewerElement = viewerTemplate && viewerTemplate.parent;
+
+                if (viewerElement) {
+                    viewerElement.classList.remove("in-vr");
+                }
+            });
         }
+        super._initVR();
     }
 
     /**

+ 48 - 30
Viewer/src/viewer/viewer.ts

@@ -262,10 +262,14 @@ export abstract class AbstractViewer {
     private _vrModelRepositioning: number = 0;
     protected _vrScale: number = 1;
 
+    protected _vrInit: boolean = false;
+
     public toggleVR() {
-        this._vrToggled = !this._vrToggled;
+        if (!this._vrInit) {
+            this._initVR();
+        }
 
-        if (this._vrToggled && this.sceneManager.vrHelper) {
+        if (this.sceneManager.vrHelper && !this.sceneManager.vrHelper.isInVRMode) {
             // make sure the floor is set
             if (this.sceneManager.environmentHelper && this.sceneManager.environmentHelper.ground) {
                 this.sceneManager.vrHelper.addFloorMesh(this.sceneManager.environmentHelper.ground);
@@ -274,7 +278,7 @@ export abstract class AbstractViewer {
             this.sceneManager.vrHelper.enterVR();
 
             // position the vr camera to be in front of the object or wherever the user has configured it to be
-            if (this.sceneManager.vrHelper.currentVRCamera) {
+            if (this.sceneManager.vrHelper.currentVRCamera && this.sceneManager.vrHelper.currentVRCamera !== this.sceneManager.camera) {
                 if (this.configuration.vr && this.configuration.vr.cameraPosition !== undefined) {
                     this.sceneManager.vrHelper.currentVRCamera.position.copyFrom(this.configuration.vr.cameraPosition as Vector3);
                 } else {
@@ -291,42 +295,49 @@ export abstract class AbstractViewer {
                         this._vrModelRepositioning = 0;
                     }
                 }
-            } else {
-                this._vrModelRepositioning = 0;
-            }
 
-            // scale the model
-            if (this.sceneManager.models.length) {
-                let boundingVectors = this.sceneManager.models[0].rootMesh.getHierarchyBoundingVectors();
-                let sizeVec = boundingVectors.max.subtract(boundingVectors.min);
-                let maxDimension = Math.max(sizeVec.x, sizeVec.y, sizeVec.z);
-                this._vrScale = (1 / maxDimension);
-                if (this.configuration.vr && this.configuration.vr.objectScaleFactor) {
-                    this._vrScale *= this.configuration.vr.objectScaleFactor;
-                }
+                // scale the model
+                if (this.sceneManager.models.length) {
+                    let boundingVectors = this.sceneManager.models[0].rootMesh.getHierarchyBoundingVectors();
+                    let sizeVec = boundingVectors.max.subtract(boundingVectors.min);
+                    let maxDimension = Math.max(sizeVec.x, sizeVec.y, sizeVec.z);
+                    this._vrScale = (1 / maxDimension);
+                    if (this.configuration.vr && this.configuration.vr.objectScaleFactor) {
+                        this._vrScale *= this.configuration.vr.objectScaleFactor;
+                    }
 
-                this.sceneManager.models[0].rootMesh.scaling.scaleInPlace(this._vrScale);
+                    this.sceneManager.models[0].rootMesh.scaling.scaleInPlace(this._vrScale);
 
-                // reposition the object to "float" in front of the user
-                this.sceneManager.models[0].rootMesh.position.y += this._vrModelRepositioning;
-                this.sceneManager.models[0].rootMesh.rotationQuaternion = null;
-            }
+                    // reposition the object to "float" in front of the user
+                    this.sceneManager.models[0].rootMesh.position.y += this._vrModelRepositioning;
+                    this.sceneManager.models[0].rootMesh.rotationQuaternion = null;
+                }
 
-            // scale the environment to match the model
-            if (this.sceneManager.environmentHelper) {
-                this.sceneManager.environmentHelper.ground && this.sceneManager.environmentHelper.ground.scaling.scaleInPlace(this._vrScale);
-                this.sceneManager.environmentHelper.skybox && this.sceneManager.environmentHelper.skybox.scaling.scaleInPlace(this._vrScale);
-            }
+                // scale the environment to match the model
+                if (this.sceneManager.environmentHelper) {
+                    this.sceneManager.environmentHelper.ground && this.sceneManager.environmentHelper.ground.scaling.scaleInPlace(this._vrScale);
+                    this.sceneManager.environmentHelper.skybox && this.sceneManager.environmentHelper.skybox.scaling.scaleInPlace(this._vrScale);
+                }
 
-            // post processing
-            if (this.sceneManager.defaultRenderingPipelineEnabled && this.sceneManager.defaultRenderingPipeline) {
-                this.sceneManager.defaultRenderingPipeline.imageProcessingEnabled = false;
-                this.sceneManager.defaultRenderingPipeline.prepare();
+                // post processing
+                if (this.sceneManager.defaultRenderingPipelineEnabled && this.sceneManager.defaultRenderingPipeline) {
+                    this.sceneManager.defaultRenderingPipeline.imageProcessingEnabled = false;
+                    this.sceneManager.defaultRenderingPipeline.prepare();
+                }
+            } else {
+                this._vrModelRepositioning = 0;
             }
         } else {
             if (this.sceneManager.vrHelper) {
                 this.sceneManager.vrHelper.exitVR();
+            }
+        }
+    }
+
+    protected _initVR() {
 
+        if (this.sceneManager.vrHelper) {
+            this.sceneManager.vrHelper.onExitingVR.add(() => {
                 // undo the scaling of the model
                 if (this.sceneManager.models.length) {
                     this.sceneManager.models[0].rootMesh.scaling.scaleInPlace(1 / this._vrScale);
@@ -344,8 +355,15 @@ export abstract class AbstractViewer {
                     this.sceneManager.defaultRenderingPipeline.imageProcessingEnabled = true;
                     this.sceneManager.defaultRenderingPipeline.prepare();
                 }
-            }
+
+                // clear set height and eidth
+                this.canvas.removeAttribute("height");
+                this.canvas.removeAttribute("width");
+                this.engine.resize();
+            })
         }
+
+        this._vrInit = true;
     }
 
     /**

+ 2 - 1
Viewer/tests/unit/tsconfig.json

@@ -20,7 +20,7 @@
         "skipDefaultLibCheck": true,
         "skipLibCheck": true,
         "baseUrl": "./src/",
-        "rootDir": "./",
+        "rootDir": "../../",
         "paths": {
             "babylonjs": [
                 "../../../../dist/preview release/babylon.d.ts"
@@ -35,6 +35,7 @@
                 "../../src/assets/"
             ]
         },
+        "outDir": "./build"
     },
     "include": [
         "./src/**/*.ts"

+ 4 - 2
Viewer/tests/unit/webpack.config.js

@@ -1,6 +1,7 @@
 const path = require('path');
 
 module.exports = {
+    context: __dirname,
     entry: {
         'test': __dirname + '/src/index.ts'
     },
@@ -24,9 +25,10 @@ module.exports = {
         oimo: 'OIMO',
         "earcut": true
     },
+    mode: "development",
     devtool: 'source-map',
     module: {
-        loaders: [{
+        rules: [{
             test: /\.tsx?$/,
             loader: 'ts-loader',
             exclude: /node_modules/
@@ -46,7 +48,7 @@ module.exports = {
         },
         {
             test: /\.(woff|ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
-            loader: 'base64-font-loader'
+            loader: 'base64-inline-loader?limit=1000&name=[name].[ext]'
         }]
     },
     devServer: {

+ 1 - 1
Viewer/tests/validation/karma.conf.js

@@ -22,7 +22,7 @@ module.exports = function (config) {
         ],
         proxies: {
             '/tests/': '/base/tests/',
-            '/dist/assets/': '/base//dist/assets/'
+            '/dist/assets/': '/base/dist/assets/'
         },
 
         port: 3000,

+ 1 - 1
Viewer/tsconfig-gulp.json

@@ -41,7 +41,7 @@
                 "./assets/"
             ]
         },
-        "outDir": "./dist/build"
+        "outDir": "./build"
     },
     "exclude": [
         "node_modules",

+ 2 - 2
Viewer/tsconfig.json

@@ -1,6 +1,6 @@
 {
     "compilerOptions": {
-        "target": "es2015",
+        "target": "es5",
         "module": "commonjs",
         "declaration": true,
         "experimentalDecorators": true,
@@ -44,6 +44,6 @@
                 "./assets/*"
             ]
         },
-        "outDir": "./dist/build"
+        "outDir": "./build"
     }
 }

+ 4 - 2
Viewer/webpack.assets.config.js

@@ -1,4 +1,5 @@
 module.exports = {
+    context: __dirname,
     entry: [
         __dirname + '/src/assets/index.ts'
     ],
@@ -10,8 +11,9 @@ module.exports = {
     resolve: {
         extensions: ['.ts']
     },
+    mode: "production",
     module: {
-        loaders: [{
+        rules: [{
             test: /\.tsx?$/,
             use: {
                 loader: 'ts-loader',
@@ -36,7 +38,7 @@ module.exports = {
         },
         {
             test: /\.(woff|ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
-            loader: 'base64-font-loader'
+            loader: 'base64-inline-loader?limit=1000&name=[name].[ext]'
         }]
     }
 }

+ 4 - 3
Viewer/webpack.config.js

@@ -54,7 +54,7 @@ module.exports = /*[
             libraryTarget: 'umd',
             library: 'BabylonViewer',
             umdNamedDefine: true,
-            devtoolModuleFilenameTemplate: '[relative-resource-path]'
+            devtoolModuleFilenameTemplate: '[absolute-resource-path]'
         },
         resolve: {
             extensions: ['.ts', '.js'],
@@ -71,6 +71,7 @@ module.exports = /*[
             oimo: 'OIMO',
             earcut: true
         },
+        mode: "development",
         devtool: 'source-map',
         plugins: [
             new webpack.WatchIgnorePlugin([
@@ -78,7 +79,7 @@ module.exports = /*[
             ])
         ],
         module: {
-            loaders: [{
+            rules: [{
                 test: /\.tsx?$/,
                 loader: 'ts-loader',
                 exclude: /node_modules/
@@ -98,7 +99,7 @@ module.exports = /*[
             },
             {
                 test: /\.(woff|ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
-                loader: 'base64-font-loader'
+                loader: 'base64-inline-loader?limit=1000&name=[name].[ext]'
             }]
         },
         devServer: {

+ 9 - 10
Viewer/webpack.gulp.config.js

@@ -1,7 +1,10 @@
+const path = require('path');
+const webpack = require('webpack');
+
 module.exports = {
-    //context: __dirname,
+    context: __dirname,
     entry: [
-        __dirname + '/src/index.ts'
+        path.resolve(__dirname, './src/index.ts')
     ],
     output: {
         libraryTarget: 'var',
@@ -22,15 +25,11 @@ module.exports = {
             "babylonjs-viewer-assets": __dirname + '/src/assets/index.ts'
         }
     },
+    mode: "production",
     module: {
-        loaders: [{
+        rules: [{
             test: /\.tsx?$/,
-            use: {
-                loader: 'ts-loader',
-                options: {
-                    configFile: 'tsconfig-gulp.json'
-                }
-            },
+            loader: 'ts-loader',
             exclude: /node_modules/
         },
         {
@@ -48,7 +47,7 @@ module.exports = {
         },
         {
             test: /\.(woff|ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
-            loader: 'base64-font-loader'
+            loader: 'base64-inline-loader?limit=1000&name=[name].[ext]'
         }]
     }
 }

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


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


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


File diff suppressed because it is too large
+ 1860 - 848
dist/preview release/babylon.no-module.max.js


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


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


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

@@ -1,7 +1,7 @@
 {
     "name": "babylonjs-gltf2interface",
     "description": "A typescript declaration of babylon's gltf2 inteface.",
-    "version": "3.3.0-alpha.12",
+    "version": "3.3.0-alpha.13",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

File diff suppressed because it is too large
+ 2356 - 2665
dist/preview release/gui/babylon.gui.d.ts


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


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


File diff suppressed because it is too large
+ 4917 - 2669
dist/preview release/gui/babylon.gui.module.d.ts


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

@@ -4,16 +4,15 @@
     },
     "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.3.0-alpha.12",
+    "version": "3.3.0-alpha.13",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
     },
     "main": "babylon.gui.min.js",
     "files": [
-        "babylon.gui.js",
         "babylon.gui.min.js",
-        "babylon.gui.d.ts",
+        "babylon.gui.min.js.map",
         "babylon.gui.module.d.ts",
         "readme.md",
         "package.json"

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


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


File diff suppressed because it is too large
+ 1040 - 1385
dist/preview release/inspector/babylon.inspector.d.ts


File diff suppressed because it is too large
+ 2371 - 0
dist/preview release/inspector/babylon.inspector.module.d.ts


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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-inspector",
     "description": "The Babylon.js inspector.",
-    "version": "3.3.0-alpha.12",
+    "version": "3.3.0-alpha.13",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -12,9 +12,12 @@
     "main": "babylon.inspector.bundle.js",
     "files": [
         "babylon.inspector.bundle.js",
+        "babylon.inspector.bundle.js.map",
+        "babylon.inspector.module.d.ts",
         "readme.md",
         "package.json"
     ],
+    "typings": "babylon.inspector.module.d.ts",
     "keywords": [
         "3D",
         "javascript",

+ 11 - 0
dist/preview release/loaders/babylon.glTF1FileLoader.d.ts

@@ -191,9 +191,20 @@ declare module BABYLON {
         private _onCompleteObserver;
         /**
          * Callback 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 the loader resolves the returned promise.
          */
         onComplete: () => void;
         /**
+         * Observable raised when an error occurs.
+         */
+        readonly onErrorObservable: Observable<any>;
+        private _onErrorObserver;
+        /**
+         * Callback raised when an error occurs.
+         */
+        onError: (reason: any) => void;
+        /**
          * Observable raised after the loader is disposed.
          */
         readonly onDisposeObservable: Observable<void>;

+ 23 - 1
dist/preview release/loaders/babylon.glTF1FileLoader.js

@@ -118,6 +118,10 @@ var BABYLON;
              */
             this.onCompleteObservable = new BABYLON.Observable();
             /**
+             * Observable raised when an error occurs.
+             */
+            this.onErrorObservable = new BABYLON.Observable();
+            /**
              * Observable raised after the loader is disposed.
              */
             this.onDisposeObservable = new BABYLON.Observable();
@@ -217,6 +221,8 @@ var BABYLON;
         Object.defineProperty(GLTFFileLoader.prototype, "onComplete", {
             /**
              * Callback 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 the loader resolves the returned promise.
              */
             set: function (callback) {
                 if (this._onCompleteObserver) {
@@ -227,6 +233,19 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(GLTFFileLoader.prototype, "onError", {
+            /**
+             * Callback raised when an error occurs.
+             */
+            set: function (callback) {
+                if (this._onErrorObserver) {
+                    this.onErrorObservable.remove(this._onErrorObserver);
+                }
+                this._onErrorObserver = this.onErrorObservable.add(callback);
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(GLTFFileLoader.prototype, "onDispose", {
             /**
              * Callback raised after the loader is disposed.
@@ -259,10 +278,13 @@ var BABYLON;
          */
         GLTFFileLoader.prototype.whenCompleteAsync = function () {
             var _this = this;
-            return new Promise(function (resolve) {
+            return new Promise(function (resolve, reject) {
                 _this.onCompleteObservable.addOnce(function () {
                     resolve();
                 });
+                _this.onErrorObservable.addOnce(function (reason) {
+                    reject(reason);
+                });
             });
         };
         Object.defineProperty(GLTFFileLoader.prototype, "loaderState", {

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


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

@@ -191,9 +191,20 @@ declare module BABYLON {
         private _onCompleteObserver;
         /**
          * Callback 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 the loader resolves the returned promise.
          */
         onComplete: () => void;
         /**
+         * Observable raised when an error occurs.
+         */
+        readonly onErrorObservable: Observable<any>;
+        private _onErrorObserver;
+        /**
+         * Callback raised when an error occurs.
+         */
+        onError: (reason: any) => void;
+        /**
          * Observable raised after the loader is disposed.
          */
         readonly onDisposeObservable: Observable<void>;
@@ -449,7 +460,6 @@ declare module BABYLON.GLTF2 {
         _parent: GLTFFileLoader;
         _gltf: _ILoaderGLTF;
         _babylonScene: Scene;
-        _readyPromise: Promise<void>;
         _completePromises: Promise<void>[];
         private _disposed;
         private _state;
@@ -463,9 +473,6 @@ declare module BABYLON.GLTF2 {
         private static _ExtensionNames;
         private static _ExtensionFactories;
         static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void;
-        /**
-         * Loader state or null if the loader is not active.
-         */
         readonly state: Nullable<GLTFLoaderState>;
         constructor(parent: GLTFFileLoader);
         dispose(): void;
@@ -481,6 +488,7 @@ declare module BABYLON.GLTF2 {
         private _setupData();
         private _loadExtensions();
         private _checkExtensions();
+        private _setState(state);
         private _createRootNode();
         _loadSceneAsync(context: string, scene: _ILoaderScene): Promise<void>;
         private _forEachPrimitive(node, callback);
@@ -504,7 +512,7 @@ declare module BABYLON.GLTF2 {
         private _getNodeMatrix(node);
         private _loadCamera(context, camera, babylonMesh);
         private _loadAnimationsAsync();
-        private _loadAnimationAsync(context, animation);
+        _loadAnimationAsync(context: string, animation: _ILoaderAnimation): Promise<void>;
         private _loadAnimationChannelAsync(context, animationContext, animation, channel, babylonAnimationGroup);
         private _loadAnimationSamplerAsync(context, sampler);
         private _loadBufferAsync(context, buffer);
@@ -536,6 +544,7 @@ declare module BABYLON.GLTF2 {
         private _compileMaterialsAsync();
         private _compileShadowGeneratorsAsync();
         _applyExtensions<T>(actionAsync: (extension: GLTFLoaderExtension) => Nullable<Promise<T>>): Nullable<Promise<T>>;
+        _forEachExtensions(action: (extension: GLTFLoaderExtension) => void): void;
     }
 }
 
@@ -564,6 +573,14 @@ declare module BABYLON.GLTF2 {
          */
         dispose(): void;
         /**
+         * Override this method to do work after the state changes to LOADING.
+         */
+        protected _onLoading(): void;
+        /**
+         * Override this method to do work after the state changes to READY.
+         */
+        protected _onReady(): void;
+        /**
          * Override this method to modify the default behavior for loading scenes.
          * @hidden
          */
@@ -603,6 +620,8 @@ declare module BABYLON.GLTF2 {
          * @hidden
          */
         protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
+        /** Override this method to modify the default behavior for loading animations. */
+        protected _loadAnimationAsync(context: string, animation: _ILoaderAnimation): Nullable<Promise<void>>;
         /**
          * Helper method called by a loader extension to load an glTF extension.
          * @hidden
@@ -614,6 +633,16 @@ declare module BABYLON.GLTF2 {
          */
         protected _loadExtrasValueAsync<TProperty, TResult = void>(context: string, property: IProperty, actionAsync: (extensionContext: string, value: TProperty) => Nullable<Promise<TResult>>): Nullable<Promise<TResult>>;
         /**
+         * Helper method called by the loader after the state changes to LOADING.
+         * @hidden
+         */
+        static _OnLoading(loader: GLTFLoader): void;
+        /**
+         * Helper method called by the loader after the state changes to READY.
+         * @hidden
+         */
+        static _OnReady(loader: GLTFLoader): void;
+        /**
          * Helper method called by the loader to allow extensions to override loading scenes.
          * @hidden
          */
@@ -653,6 +682,11 @@ declare module BABYLON.GLTF2 {
          * @hidden
          */
         static _LoadUriAsync(loader: GLTFLoader, context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
+        /**
+         * Helper method called by the loader to allow extensions to override loading animations.
+         * @hidden
+         */
+        static _LoadAnimationAsync(loader: GLTFLoader, context: string, animation: _ILoaderAnimation): Nullable<Promise<void>>;
     }
 }
 /**
@@ -664,6 +698,26 @@ declare module BABYLON.GLTF2.Extensions {
 
 declare module BABYLON.GLTF2.Extensions {
     /**
+     * [Specification](https://github.com/najadojo/glTF/tree/MSFT_audio_emitter/extensions/2.0/Vendor/MSFT_audio_emitter)
+     */
+    class MSFT_audio_emitter extends GLTFLoaderExtension {
+        readonly name: string;
+        private _loadClipAsync(context, clip);
+        private _loadEmitterAsync(context, emitter);
+        protected _loadSceneAsync(context: string, scene: _ILoaderScene): Nullable<Promise<void>>;
+        protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
+        protected _loadAnimationAsync(context: string, animation: _ILoaderAnimation): Nullable<Promise<void>>;
+        private _getEventAction(context, sound, action, time, startOffset?);
+        private _loadAnimationEventAsync(context, animationContext, animation, event, babylonAnimationGroup);
+        private readonly _extension;
+        private readonly _clips;
+        private readonly _emitters;
+    }
+}
+
+
+declare module BABYLON.GLTF2.Extensions {
+    /**
      * [Specification](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_lod)
      */
     class MSFT_lod extends GLTFLoaderExtension {
@@ -690,8 +744,8 @@ declare module BABYLON.GLTF2.Extensions {
         private _materialIndexLOD;
         private _materialSignalLODs;
         private _materialPromiseLODs;
-        constructor(loader: GLTFLoader);
         dispose(): void;
+        protected _onReady(): void;
         protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
         protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
         protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
@@ -717,7 +771,8 @@ declare module BABYLON.GLTF2.Extensions {
     /** @hidden */
     class MSFT_sRGBFactors extends GLTFLoaderExtension {
         readonly name: string;
-        protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
+        protected _loadMaterialPropertiesAsync(context: string, material: _ILoaderMaterial, babylonMaterial: Material): Nullable<Promise<void>>;
+        private _convertColorsToLinear(babylonMaterial);
     }
 }
 
@@ -766,9 +821,10 @@ declare module BABYLON.GLTF2.Extensions {
      */
     class KHR_lights extends GLTFLoaderExtension {
         readonly name: string;
+        private _lights?;
+        protected _onLoading(): void;
         protected _loadSceneAsync(context: string, scene: _ILoaderScene): Nullable<Promise<void>>;
         protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
-        private readonly _lights;
     }
 }
 
@@ -790,8 +846,9 @@ declare module BABYLON.GLTF2.Extensions {
      */
     class EXT_lights_imageBased extends GLTFLoaderExtension {
         readonly name: string;
+        private _lights?;
+        protected _onLoading(): void;
         protected _loadSceneAsync(context: string, scene: _ILoaderScene): Nullable<Promise<void>>;
         private _loadLightAsync(context, light);
-        private readonly _lights;
     }
 }

+ 391 - 94
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -118,6 +118,10 @@ var BABYLON;
              */
             this.onCompleteObservable = new BABYLON.Observable();
             /**
+             * Observable raised when an error occurs.
+             */
+            this.onErrorObservable = new BABYLON.Observable();
+            /**
              * Observable raised after the loader is disposed.
              */
             this.onDisposeObservable = new BABYLON.Observable();
@@ -217,6 +221,8 @@ var BABYLON;
         Object.defineProperty(GLTFFileLoader.prototype, "onComplete", {
             /**
              * Callback 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 the loader resolves the returned promise.
              */
             set: function (callback) {
                 if (this._onCompleteObserver) {
@@ -227,6 +233,19 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(GLTFFileLoader.prototype, "onError", {
+            /**
+             * Callback raised when an error occurs.
+             */
+            set: function (callback) {
+                if (this._onErrorObserver) {
+                    this.onErrorObservable.remove(this._onErrorObserver);
+                }
+                this._onErrorObserver = this.onErrorObservable.add(callback);
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(GLTFFileLoader.prototype, "onDispose", {
             /**
              * Callback raised after the loader is disposed.
@@ -259,10 +278,13 @@ var BABYLON;
          */
         GLTFFileLoader.prototype.whenCompleteAsync = function () {
             var _this = this;
-            return new Promise(function (resolve) {
+            return new Promise(function (resolve, reject) {
                 _this.onCompleteObservable.addOnce(function () {
                     resolve();
                 });
+                _this.onErrorObservable.addOnce(function (reason) {
+                    reject(reason);
+                });
             });
         };
         Object.defineProperty(GLTFFileLoader.prototype, "loaderState", {
@@ -713,9 +735,6 @@ var BABYLON;
                 GLTFLoader._ExtensionNames.push(name);
             };
             Object.defineProperty(GLTFLoader.prototype, "state", {
-                /**
-                 * Loader state or null if the loader is not active.
-                 */
                 get: function () {
                     return this._state;
                 },
@@ -734,7 +753,6 @@ var BABYLON;
                 this._requests.length = 0;
                 delete this._gltf;
                 delete this._babylonScene;
-                delete this._readyPromise;
                 this._completePromises.length = 0;
                 for (var name_1 in this._extensions) {
                     this._extensions[name_1].dispose();
@@ -794,14 +812,14 @@ var BABYLON;
             GLTFLoader.prototype._loadAsync = function (nodes) {
                 var _this = this;
                 return Promise.resolve().then(function () {
-                    _this._parent._startPerformanceCounter("Loading => Ready");
-                    _this._parent._startPerformanceCounter("Loading => Complete");
-                    _this._state = BABYLON.GLTFLoaderState.LOADING;
-                    _this._parent._log("Loading");
-                    var readyDeferred = new BABYLON.Deferred();
-                    _this._readyPromise = readyDeferred.promise;
                     _this._loadExtensions();
                     _this._checkExtensions();
+                    var loadingToReadyCounterName = BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.LOADING] + " => " + BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.READY];
+                    var loadingToCompleteCounterName = BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.LOADING] + " => " + BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.COMPLETE];
+                    _this._parent._startPerformanceCounter(loadingToReadyCounterName);
+                    _this._parent._startPerformanceCounter(loadingToCompleteCounterName);
+                    _this._setState(BABYLON.GLTFLoaderState.LOADING);
+                    GLTF2.GLTFLoaderExtension._OnLoading(_this);
                     var promises = new Array();
                     if (nodes) {
                         promises.push(_this._loadSceneAsync("#/nodes", { nodes: nodes, _index: -1 }));
@@ -817,33 +835,33 @@ var BABYLON;
                         promises.push(_this._compileShadowGeneratorsAsync());
                     }
                     var resultPromise = Promise.all(promises).then(function () {
-                        _this._state = BABYLON.GLTFLoaderState.READY;
-                        _this._parent._log("Ready");
-                        readyDeferred.resolve();
+                        _this._setState(BABYLON.GLTFLoaderState.READY);
+                        GLTF2.GLTFLoaderExtension._OnReady(_this);
                         _this._startAnimations();
                     });
                     resultPromise.then(function () {
-                        _this._parent._endPerformanceCounter("Loading => Ready");
+                        _this._parent._endPerformanceCounter(loadingToReadyCounterName);
                         BABYLON.Tools.SetImmediate(function () {
                             if (!_this._disposed) {
                                 Promise.all(_this._completePromises).then(function () {
-                                    _this._parent._endPerformanceCounter("Loading => Complete");
-                                    _this._state = BABYLON.GLTFLoaderState.COMPLETE;
-                                    _this._parent._log("Complete");
+                                    _this._parent._endPerformanceCounter(loadingToCompleteCounterName);
+                                    _this._setState(BABYLON.GLTFLoaderState.COMPLETE);
                                     _this._parent.onCompleteObservable.notifyObservers(undefined);
                                     _this._parent.onCompleteObservable.clear();
                                     _this.dispose();
-                                }).catch(function (error) {
-                                    BABYLON.Tools.Error("glTF Loader: " + error.message);
+                                }, function (error) {
+                                    _this._parent.onErrorObservable.notifyObservers(error);
+                                    _this._parent.onErrorObservable.clear();
                                     _this.dispose();
                                 });
                             }
                         });
                     });
                     return resultPromise;
-                }).catch(function (error) {
+                }, function (error) {
                     if (!_this._disposed) {
-                        BABYLON.Tools.Error("glTF Loader: " + error.message);
+                        _this._parent.onErrorObservable.notifyObservers(error);
+                        _this._parent.onErrorObservable.clear();
                         _this.dispose();
                         throw error;
                     }
@@ -919,6 +937,10 @@ var BABYLON;
                     }
                 }
             };
+            GLTFLoader.prototype._setState = function (state) {
+                this._state = state;
+                this._parent._log(BABYLON.GLTFLoaderState[this._state]);
+            };
             GLTFLoader.prototype._createRootNode = function () {
                 this._rootBabylonMesh = new BABYLON.Mesh("__root__", this._babylonScene);
                 var rootNode = { _babylonMesh: this._rootBabylonMesh };
@@ -1409,6 +1431,10 @@ var BABYLON;
             };
             GLTFLoader.prototype._loadAnimationAsync = function (context, animation) {
                 var _this = this;
+                var promise = GLTF2.GLTFLoaderExtension._LoadAnimationAsync(this, context, animation);
+                if (promise) {
+                    return promise;
+                }
                 var babylonAnimationGroup = new BABYLON.AnimationGroup(animation.name || "animation" + animation._index, this._babylonScene);
                 animation._babylonAnimationGroup = babylonAnimationGroup;
                 var promises = new Array();
@@ -2173,6 +2199,15 @@ var BABYLON;
                 }
                 return null;
             };
+            GLTFLoader.prototype._forEachExtensions = function (action) {
+                for (var _i = 0, _a = GLTFLoader._ExtensionNames; _i < _a.length; _i++) {
+                    var name_6 = _a[_i];
+                    var extension = this._extensions[name_6];
+                    if (extension.enabled) {
+                        action(extension);
+                    }
+                }
+            };
             GLTFLoader._ExtensionNames = new Array();
             GLTFLoader._ExtensionFactories = {};
             return GLTFLoader;
@@ -2212,6 +2247,14 @@ var BABYLON;
             };
             // #region Overridable Methods
             /**
+             * Override this method to do work after the state changes to LOADING.
+             */
+            GLTFLoaderExtension.prototype._onLoading = function () { };
+            /**
+             * Override this method to do work after the state changes to READY.
+             */
+            GLTFLoaderExtension.prototype._onReady = function () { };
+            /**
              * Override this method to modify the default behavior for loading scenes.
              * @hidden
              */
@@ -2251,6 +2294,8 @@ var BABYLON;
              * @hidden
              */
             GLTFLoaderExtension.prototype._loadUriAsync = function (context, uri) { return null; };
+            /** Override this method to modify the default behavior for loading animations. */
+            GLTFLoaderExtension.prototype._loadAnimationAsync = function (context, animation) { return null; };
             // #endregion
             /**
              * Helper method called by a loader extension to load an glTF extension.
@@ -2299,6 +2344,20 @@ var BABYLON;
                 }
             };
             /**
+             * Helper method called by the loader after the state changes to LOADING.
+             * @hidden
+             */
+            GLTFLoaderExtension._OnLoading = function (loader) {
+                loader._forEachExtensions(function (extension) { return extension._onLoading(); });
+            };
+            /**
+             * Helper method called by the loader after the state changes to READY.
+             * @hidden
+             */
+            GLTFLoaderExtension._OnReady = function (loader) {
+                loader._forEachExtensions(function (extension) { return extension._onReady(); });
+            };
+            /**
              * Helper method called by the loader to allow extensions to override loading scenes.
              * @hidden
              */
@@ -2354,6 +2413,13 @@ var BABYLON;
             GLTFLoaderExtension._LoadUriAsync = function (loader, context, uri) {
                 return loader._applyExtensions(function (extension) { return extension._loadUriAsync(context, uri); });
             };
+            /**
+             * Helper method called by the loader to allow extensions to override loading animations.
+             * @hidden
+             */
+            GLTFLoaderExtension._LoadAnimationAsync = function (loader, context, animation) {
+                return loader._applyExtensions(function (extension) { return extension._loadAnimationAsync(context, animation); });
+            };
             return GLTFLoaderExtension;
         }());
         GLTF2.GLTFLoaderExtension = GLTFLoaderExtension;
@@ -2379,14 +2445,246 @@ var BABYLON;
     (function (GLTF2) {
         var Extensions;
         (function (Extensions) {
+            var NAME = "MSFT_audio_emitter";
+            /**
+             * [Specification](https://github.com/najadojo/glTF/tree/MSFT_audio_emitter/extensions/2.0/Vendor/MSFT_audio_emitter)
+             */
+            var MSFT_audio_emitter = /** @class */ (function (_super) {
+                __extends(MSFT_audio_emitter, _super);
+                function MSFT_audio_emitter() {
+                    var _this = _super !== null && _super.apply(this, arguments) || this;
+                    _this.name = NAME;
+                    return _this;
+                }
+                MSFT_audio_emitter.prototype._loadClipAsync = function (context, clip) {
+                    if (clip._objectURL) {
+                        return clip._objectURL;
+                    }
+                    var promise;
+                    if (clip.uri) {
+                        promise = this._loader._loadUriAsync(context, clip.uri);
+                    }
+                    else {
+                        var bufferView = GLTF2.GLTFLoader._GetProperty(context + "/bufferView", this._loader._gltf.bufferViews, clip.bufferView);
+                        promise = this._loader._loadBufferViewAsync("#/bufferViews/" + bufferView._index, bufferView);
+                    }
+                    clip._objectURL = promise.then(function (data) {
+                        return URL.createObjectURL(new Blob([data], { type: clip.mimeType }));
+                    });
+                    return clip._objectURL;
+                };
+                MSFT_audio_emitter.prototype._loadEmitterAsync = function (context, emitter) {
+                    var _this = this;
+                    emitter._babylonSounds = emitter._babylonSounds || [];
+                    if (!emitter._babylonData) {
+                        var clipPromises = new Array();
+                        var name_1 = emitter.name || "emitter" + emitter._index;
+                        var options_1 = {
+                            loop: false,
+                            autoplay: false,
+                            volume: emitter.volume == undefined ? 1 : emitter.volume,
+                        };
+                        GLTF2._ArrayItem.Assign(this._clips);
+                        var _loop_1 = function (i) {
+                            var clipContext = "#/extensions/" + NAME + "/clips";
+                            var clip = GLTF2.GLTFLoader._GetProperty(clipContext, this_1._clips, emitter.clips[i].clip);
+                            clipPromises.push(this_1._loadClipAsync(clipContext + "/" + emitter.clips[i].clip, clip).then(function (objectURL) {
+                                var sound = emitter._babylonSounds[i] = new BABYLON.Sound(name_1, objectURL, _this._loader._babylonScene, null, options_1);
+                                sound.refDistance = emitter.refDistance || 1;
+                                sound.maxDistance = emitter.maxDistance || 256;
+                                sound.rolloffFactor = emitter.rolloffFactor || 1;
+                                sound.distanceModel = emitter.distanceModel || 'exponential';
+                                sound._positionInEmitterSpace = true;
+                            }));
+                        };
+                        var this_1 = this;
+                        for (var i = 0; i < emitter.clips.length; i++) {
+                            _loop_1(i);
+                        }
+                        var promise = Promise.all(clipPromises).then(function () {
+                            var weights = emitter.clips.map(function (clip) { return clip.weight || 1; });
+                            var weightedSound = new BABYLON.WeightedSound(emitter.loop || false, emitter._babylonSounds, weights);
+                            if (emitter.innerAngle)
+                                weightedSound.directionalConeInnerAngle = 2 * BABYLON.Tools.ToDegrees(emitter.innerAngle);
+                            if (emitter.outerAngle)
+                                weightedSound.directionalConeOuterAngle = 2 * BABYLON.Tools.ToDegrees(emitter.outerAngle);
+                            if (emitter.volume)
+                                weightedSound.volume = emitter.volume;
+                            emitter._babylonData.sound = weightedSound;
+                        });
+                        emitter._babylonData = {
+                            loaded: promise
+                        };
+                    }
+                    return emitter._babylonData.loaded;
+                };
+                MSFT_audio_emitter.prototype._loadSceneAsync = function (context, scene) {
+                    var _this = this;
+                    return this._loadExtensionAsync(context, scene, function (extensionContext, extension) {
+                        return _this._loader._loadSceneAsync(context, scene).then(function () {
+                            var promises = new Array();
+                            GLTF2._ArrayItem.Assign(_this._emitters);
+                            for (var _i = 0, _a = extension.emitters; _i < _a.length; _i++) {
+                                var emitterIndex = _a[_i];
+                                var emitter = GLTF2.GLTFLoader._GetProperty(extensionContext + "/emitters", _this._emitters, emitterIndex);
+                                if (emitter.refDistance != undefined || emitter.maxDistance != undefined || emitter.rolloffFactor != undefined ||
+                                    emitter.distanceModel != undefined || emitter.innerAngle != undefined || emitter.outerAngle != undefined) {
+                                    throw new Error(extensionContext + ": Direction or Distance properties are not allowed on emitters attached to a scene");
+                                }
+                                promises.push(_this._loadEmitterAsync(extensionContext + "/emitters/" + emitter._index, emitter));
+                            }
+                            return Promise.all(promises).then(function () { });
+                        });
+                    });
+                };
+                MSFT_audio_emitter.prototype._loadNodeAsync = function (context, node) {
+                    var _this = this;
+                    return this._loadExtensionAsync(context, node, function (extensionContext, extension) {
+                        return _this._loader._loadNodeAsync(extensionContext, node).then(function () {
+                            var promises = new Array();
+                            GLTF2._ArrayItem.Assign(_this._emitters);
+                            var _loop_2 = function (emitterIndex) {
+                                var emitter = GLTF2.GLTFLoader._GetProperty(extensionContext + "/emitters", _this._emitters, emitterIndex);
+                                promises.push(_this._loadEmitterAsync(extensionContext + "/emitters/" + emitter._index, emitter).then(function () {
+                                    if (node._babylonMesh) {
+                                        for (var _i = 0, _a = emitter._babylonSounds; _i < _a.length; _i++) {
+                                            var sound = _a[_i];
+                                            sound.attachToMesh(node._babylonMesh);
+                                            if (emitter.innerAngle != undefined || emitter.outerAngle != undefined) {
+                                                sound.setLocalDirectionToMesh(new BABYLON.Vector3(0, 0, 1));
+                                                sound.setDirectionalCone(2 * BABYLON.Tools.ToDegrees(emitter.innerAngle == undefined ? Math.PI : emitter.innerAngle), 2 * BABYLON.Tools.ToDegrees(emitter.outerAngle == undefined ? Math.PI : emitter.outerAngle), 0);
+                                            }
+                                        }
+                                    }
+                                }));
+                            };
+                            for (var _i = 0, _a = extension.emitters; _i < _a.length; _i++) {
+                                var emitterIndex = _a[_i];
+                                _loop_2(emitterIndex);
+                            }
+                            return Promise.all(promises).then(function () { });
+                        });
+                    });
+                };
+                MSFT_audio_emitter.prototype._loadAnimationAsync = function (context, animation) {
+                    var _this = this;
+                    return this._loadExtensionAsync(context, animation, function (extensionContext, extension) {
+                        return _this._loader._loadAnimationAsync(extensionContext, animation).then(function () {
+                            var promises = new Array();
+                            var babylonAnimationGroup = animation._babylonAnimationGroup;
+                            GLTF2._ArrayItem.Assign(extension.events);
+                            for (var _i = 0, _a = extension.events; _i < _a.length; _i++) {
+                                var event_1 = _a[_i];
+                                promises.push(_this._loadAnimationEventAsync(extensionContext + "/events/" + event_1._index, context, animation, event_1, babylonAnimationGroup));
+                            }
+                            return Promise.all(promises).then(function () { });
+                        });
+                    });
+                };
+                MSFT_audio_emitter.prototype._getEventAction = function (context, sound, action, time, startOffset) {
+                    if (action == "play" /* play */) {
+                        return function (currentFrame) {
+                            var frameOffset = (startOffset || 0) + (currentFrame - time);
+                            sound.play(frameOffset);
+                        };
+                    }
+                    else if (action == "stop" /* stop */) {
+                        return function (currentFrame) {
+                            sound.stop();
+                        };
+                    }
+                    else if (action == "pause" /* pause */) {
+                        return function (currentFrame) {
+                            sound.pause();
+                        };
+                    }
+                    else {
+                        throw new Error(context + ": Unsupported action " + action);
+                    }
+                };
+                MSFT_audio_emitter.prototype._loadAnimationEventAsync = function (context, animationContext, animation, event, babylonAnimationGroup) {
+                    var _this = this;
+                    if (babylonAnimationGroup.targetedAnimations.length == 0) {
+                        return Promise.resolve();
+                    }
+                    var babylonAnimation = babylonAnimationGroup.targetedAnimations[0];
+                    var emitterIndex = event.emitter;
+                    var emitter = GLTF2.GLTFLoader._GetProperty("#/extensions/" + NAME + "/emitters", this._emitters, emitterIndex);
+                    return this._loadEmitterAsync(context, emitter).then(function () {
+                        var sound = emitter._babylonData.sound;
+                        if (sound) {
+                            var babylonAnimationEvent = new BABYLON.AnimationEvent(event.time, _this._getEventAction(context, sound, event.action, event.time, event.startOffset));
+                            babylonAnimation.animation.addEvent(babylonAnimationEvent);
+                            // Make sure all started audio stops when this animation is terminated.
+                            babylonAnimationGroup.onAnimationGroupEndObservable.add(function () {
+                                sound.stop();
+                            });
+                            babylonAnimationGroup.onAnimationGroupPauseObservable.add(function () {
+                                sound.pause();
+                            });
+                        }
+                    });
+                };
+                Object.defineProperty(MSFT_audio_emitter.prototype, "_extension", {
+                    get: function () {
+                        var extensions = this._loader._gltf.extensions;
+                        if (!extensions || !extensions[this.name]) {
+                            throw new Error("#/extensions: '" + this.name + "' not found");
+                        }
+                        return extensions[this.name];
+                    },
+                    enumerable: true,
+                    configurable: true
+                });
+                Object.defineProperty(MSFT_audio_emitter.prototype, "_clips", {
+                    get: function () {
+                        return this._extension.clips;
+                    },
+                    enumerable: true,
+                    configurable: true
+                });
+                Object.defineProperty(MSFT_audio_emitter.prototype, "_emitters", {
+                    get: function () {
+                        return this._extension.emitters;
+                    },
+                    enumerable: true,
+                    configurable: true
+                });
+                return MSFT_audio_emitter;
+            }(GLTF2.GLTFLoaderExtension));
+            Extensions.MSFT_audio_emitter = MSFT_audio_emitter;
+            GLTF2.GLTFLoader._Register(NAME, function (loader) { return new MSFT_audio_emitter(loader); });
+        })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
+    })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=MSFT_audio_emitter.js.map
+
+/// <reference path="../../../../../dist/preview release/babylon.d.ts"/>
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = Object.setPrototypeOf ||
+        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+var BABYLON;
+(function (BABYLON) {
+    var GLTF2;
+    (function (GLTF2) {
+        var Extensions;
+        (function (Extensions) {
             var NAME = "MSFT_lod";
             /**
              * [Specification](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_lod)
              */
             var MSFT_lod = /** @class */ (function (_super) {
                 __extends(MSFT_lod, _super);
-                function MSFT_lod(loader) {
-                    var _this = _super.call(this, loader) || this;
+                function MSFT_lod() {
+                    var _this = _super !== null && _super.apply(this, arguments) || this;
                     _this.name = NAME;
                     /**
                      * Maximum number of LODs to load, starting from the lowest LOD.
@@ -2410,42 +2708,6 @@ var BABYLON;
                     _this._materialIndexLOD = null;
                     _this._materialSignalLODs = new Array();
                     _this._materialPromiseLODs = new Array();
-                    _this._loader._readyPromise.then(function () {
-                        var _loop_1 = function (indexLOD) {
-                            var promise = Promise.all(_this._nodePromiseLODs[indexLOD]).then(function () {
-                                if (indexLOD !== 0) {
-                                    _this._loader._parent._endPerformanceCounter("Node LOD " + indexLOD);
-                                }
-                                _this._loader._parent._log("Loaded node LOD " + indexLOD);
-                                _this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
-                                if (indexLOD !== _this._nodePromiseLODs.length - 1) {
-                                    _this._loader._parent._startPerformanceCounter("Node LOD " + (indexLOD + 1));
-                                    _this._nodeSignalLODs[indexLOD].resolve();
-                                }
-                            });
-                            _this._loader._completePromises.push(promise);
-                        };
-                        for (var indexLOD = 0; indexLOD < _this._nodePromiseLODs.length; indexLOD++) {
-                            _loop_1(indexLOD);
-                        }
-                        var _loop_2 = function (indexLOD) {
-                            var promise = Promise.all(_this._materialPromiseLODs[indexLOD]).then(function () {
-                                if (indexLOD !== 0) {
-                                    _this._loader._parent._endPerformanceCounter("Material LOD " + indexLOD);
-                                }
-                                _this._loader._parent._log("Loaded material LOD " + indexLOD);
-                                _this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
-                                if (indexLOD !== _this._materialPromiseLODs.length - 1) {
-                                    _this._loader._parent._startPerformanceCounter("Material LOD " + (indexLOD + 1));
-                                    _this._materialSignalLODs[indexLOD].resolve();
-                                }
-                            });
-                            _this._loader._completePromises.push(promise);
-                        };
-                        for (var indexLOD = 0; indexLOD < _this._materialPromiseLODs.length; indexLOD++) {
-                            _loop_2(indexLOD);
-                        }
-                    });
                     return _this;
                 }
                 MSFT_lod.prototype.dispose = function () {
@@ -2459,6 +2721,49 @@ var BABYLON;
                     this.onMaterialLODsLoadedObservable.clear();
                     this.onNodeLODsLoadedObservable.clear();
                 };
+                MSFT_lod.prototype._onReady = function () {
+                    var _this = this;
+                    var _loop_1 = function (indexLOD) {
+                        var promise = Promise.all(this_1._nodePromiseLODs[indexLOD]).then(function () {
+                            if (indexLOD !== 0) {
+                                _this._loader._parent._endPerformanceCounter("Node LOD " + indexLOD);
+                            }
+                            _this._loader._parent._log("Loaded node LOD " + indexLOD);
+                            _this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
+                            if (indexLOD !== _this._nodePromiseLODs.length - 1) {
+                                _this._loader._parent._startPerformanceCounter("Node LOD " + (indexLOD + 1));
+                                if (_this._nodeSignalLODs[indexLOD]) {
+                                    _this._nodeSignalLODs[indexLOD].resolve();
+                                }
+                            }
+                        });
+                        this_1._loader._completePromises.push(promise);
+                    };
+                    var this_1 = this;
+                    for (var indexLOD = 0; indexLOD < this._nodePromiseLODs.length; indexLOD++) {
+                        _loop_1(indexLOD);
+                    }
+                    var _loop_2 = function (indexLOD) {
+                        var promise = Promise.all(this_2._materialPromiseLODs[indexLOD]).then(function () {
+                            if (indexLOD !== 0) {
+                                _this._loader._parent._endPerformanceCounter("Material LOD " + indexLOD);
+                            }
+                            _this._loader._parent._log("Loaded material LOD " + indexLOD);
+                            _this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
+                            if (indexLOD !== _this._materialPromiseLODs.length - 1) {
+                                _this._loader._parent._startPerformanceCounter("Material LOD " + (indexLOD + 1));
+                                if (_this._materialSignalLODs[indexLOD]) {
+                                    _this._materialSignalLODs[indexLOD].resolve();
+                                }
+                            }
+                        });
+                        this_2._loader._completePromises.push(promise);
+                    };
+                    var this_2 = this;
+                    for (var indexLOD = 0; indexLOD < this._materialPromiseLODs.length; indexLOD++) {
+                        _loop_2(indexLOD);
+                    }
+                };
                 MSFT_lod.prototype._loadNodeAsync = function (context, node) {
                     var _this = this;
                     return this._loadExtensionAsync(context, node, function (extensionContext, extension) {
@@ -2683,23 +2988,25 @@ var BABYLON;
                     _this.name = NAME;
                     return _this;
                 }
-                MSFT_sRGBFactors.prototype._loadMaterialAsync = function (context, material, mesh, babylonMesh, babylonDrawMode, assign) {
+                MSFT_sRGBFactors.prototype._loadMaterialPropertiesAsync = function (context, material, babylonMaterial) {
                     var _this = this;
                     return this._loadExtrasValueAsync(context, material, function (extensionContext, value) {
                         if (value) {
-                            return _this._loader._loadMaterialAsync(context, material, mesh, babylonMesh, babylonDrawMode, function (babylonMaterial) {
-                                if (!babylonMaterial.albedoTexture) {
-                                    babylonMaterial.albedoColor.toLinearSpaceToRef(babylonMaterial.albedoColor);
-                                }
-                                if (!babylonMaterial.reflectivityTexture) {
-                                    babylonMaterial.reflectivityColor.toLinearSpaceToRef(babylonMaterial.reflectivityColor);
-                                }
-                                assign(babylonMaterial);
-                            });
+                            var promise = _this._loader._loadMaterialPropertiesAsync(context, material, babylonMaterial);
+                            _this._convertColorsToLinear(babylonMaterial);
+                            return promise;
                         }
                         return null;
                     });
                 };
+                MSFT_sRGBFactors.prototype._convertColorsToLinear = function (babylonMaterial) {
+                    if (!babylonMaterial.albedoTexture) {
+                        babylonMaterial.albedoColor.toLinearSpaceToRef(babylonMaterial.albedoColor);
+                    }
+                    if (!babylonMaterial.reflectivityTexture) {
+                        babylonMaterial.reflectivityColor.toLinearSpaceToRef(babylonMaterial.reflectivityColor);
+                    }
+                };
                 return MSFT_sRGBFactors;
             }(GLTF2.GLTFLoaderExtension));
             Extensions.MSFT_sRGBFactors = MSFT_sRGBFactors;
@@ -2990,6 +3297,13 @@ var BABYLON;
                     _this.name = NAME;
                     return _this;
                 }
+                KHR_lights.prototype._onLoading = function () {
+                    var extensions = this._loader._gltf.extensions;
+                    if (extensions && extensions[this.name]) {
+                        var extension = extensions[this.name];
+                        this._lights = extension.lights;
+                    }
+                };
                 KHR_lights.prototype._loadSceneAsync = function (context, scene) {
                     var _this = this;
                     return this._loadExtensionAsync(context, scene, function (extensionContext, extension) {
@@ -3038,18 +3352,6 @@ var BABYLON;
                         return promise;
                     });
                 };
-                Object.defineProperty(KHR_lights.prototype, "_lights", {
-                    get: function () {
-                        var extensions = this._loader._gltf.extensions;
-                        if (!extensions || !extensions[this.name]) {
-                            throw new Error("#/extensions: '" + this.name + "' not found");
-                        }
-                        var extension = extensions[this.name];
-                        return extension.lights;
-                    },
-                    enumerable: true,
-                    configurable: true
-                });
                 return KHR_lights;
             }(GLTF2.GLTFLoaderExtension));
             Extensions.KHR_lights = KHR_lights;
@@ -3151,6 +3453,13 @@ var BABYLON;
                     _this.name = NAME;
                     return _this;
                 }
+                EXT_lights_imageBased.prototype._onLoading = function () {
+                    var extensions = this._loader._gltf.extensions;
+                    if (extensions && extensions[this.name]) {
+                        var extension = extensions[this.name];
+                        this._lights = extension.lights;
+                    }
+                };
                 EXT_lights_imageBased.prototype._loadSceneAsync = function (context, scene) {
                     var _this = this;
                     return this._loadExtensionAsync(context, scene, function (extensionContext, extension) {
@@ -3220,18 +3529,6 @@ var BABYLON;
                         return light._babylonTexture;
                     });
                 };
-                Object.defineProperty(EXT_lights_imageBased.prototype, "_lights", {
-                    get: function () {
-                        var extensions = this._loader._gltf.extensions;
-                        if (!extensions || !extensions[this.name]) {
-                            throw new Error("#/extensions: '" + this.name + "' not found");
-                        }
-                        var extension = extensions[this.name];
-                        return extension.lights;
-                    },
-                    enumerable: true,
-                    configurable: true
-                });
                 return EXT_lights_imageBased;
             }(GLTF2.GLTFLoaderExtension));
             Extensions.EXT_lights_imageBased = EXT_lights_imageBased;

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


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

@@ -191,9 +191,20 @@ declare module BABYLON {
         private _onCompleteObserver;
         /**
          * Callback 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 the loader resolves the returned promise.
          */
         onComplete: () => void;
         /**
+         * Observable raised when an error occurs.
+         */
+        readonly onErrorObservable: Observable<any>;
+        private _onErrorObserver;
+        /**
+         * Callback raised when an error occurs.
+         */
+        onError: (reason: any) => void;
+        /**
          * Observable raised after the loader is disposed.
          */
         readonly onDisposeObservable: Observable<void>;
@@ -1011,7 +1022,6 @@ declare module BABYLON.GLTF2 {
         _parent: GLTFFileLoader;
         _gltf: _ILoaderGLTF;
         _babylonScene: Scene;
-        _readyPromise: Promise<void>;
         _completePromises: Promise<void>[];
         private _disposed;
         private _state;
@@ -1025,9 +1035,6 @@ declare module BABYLON.GLTF2 {
         private static _ExtensionNames;
         private static _ExtensionFactories;
         static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void;
-        /**
-         * Loader state or null if the loader is not active.
-         */
         readonly state: Nullable<GLTFLoaderState>;
         constructor(parent: GLTFFileLoader);
         dispose(): void;
@@ -1043,6 +1050,7 @@ declare module BABYLON.GLTF2 {
         private _setupData();
         private _loadExtensions();
         private _checkExtensions();
+        private _setState(state);
         private _createRootNode();
         _loadSceneAsync(context: string, scene: _ILoaderScene): Promise<void>;
         private _forEachPrimitive(node, callback);
@@ -1066,7 +1074,7 @@ declare module BABYLON.GLTF2 {
         private _getNodeMatrix(node);
         private _loadCamera(context, camera, babylonMesh);
         private _loadAnimationsAsync();
-        private _loadAnimationAsync(context, animation);
+        _loadAnimationAsync(context: string, animation: _ILoaderAnimation): Promise<void>;
         private _loadAnimationChannelAsync(context, animationContext, animation, channel, babylonAnimationGroup);
         private _loadAnimationSamplerAsync(context, sampler);
         private _loadBufferAsync(context, buffer);
@@ -1098,6 +1106,7 @@ declare module BABYLON.GLTF2 {
         private _compileMaterialsAsync();
         private _compileShadowGeneratorsAsync();
         _applyExtensions<T>(actionAsync: (extension: GLTFLoaderExtension) => Nullable<Promise<T>>): Nullable<Promise<T>>;
+        _forEachExtensions(action: (extension: GLTFLoaderExtension) => void): void;
     }
 }
 
@@ -1126,6 +1135,14 @@ declare module BABYLON.GLTF2 {
          */
         dispose(): void;
         /**
+         * Override this method to do work after the state changes to LOADING.
+         */
+        protected _onLoading(): void;
+        /**
+         * Override this method to do work after the state changes to READY.
+         */
+        protected _onReady(): void;
+        /**
          * Override this method to modify the default behavior for loading scenes.
          * @hidden
          */
@@ -1165,6 +1182,8 @@ declare module BABYLON.GLTF2 {
          * @hidden
          */
         protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
+        /** Override this method to modify the default behavior for loading animations. */
+        protected _loadAnimationAsync(context: string, animation: _ILoaderAnimation): Nullable<Promise<void>>;
         /**
          * Helper method called by a loader extension to load an glTF extension.
          * @hidden
@@ -1176,6 +1195,16 @@ declare module BABYLON.GLTF2 {
          */
         protected _loadExtrasValueAsync<TProperty, TResult = void>(context: string, property: IProperty, actionAsync: (extensionContext: string, value: TProperty) => Nullable<Promise<TResult>>): Nullable<Promise<TResult>>;
         /**
+         * Helper method called by the loader after the state changes to LOADING.
+         * @hidden
+         */
+        static _OnLoading(loader: GLTFLoader): void;
+        /**
+         * Helper method called by the loader after the state changes to READY.
+         * @hidden
+         */
+        static _OnReady(loader: GLTFLoader): void;
+        /**
          * Helper method called by the loader to allow extensions to override loading scenes.
          * @hidden
          */
@@ -1215,6 +1244,11 @@ declare module BABYLON.GLTF2 {
          * @hidden
          */
         static _LoadUriAsync(loader: GLTFLoader, context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
+        /**
+         * Helper method called by the loader to allow extensions to override loading animations.
+         * @hidden
+         */
+        static _LoadAnimationAsync(loader: GLTFLoader, context: string, animation: _ILoaderAnimation): Nullable<Promise<void>>;
     }
 }
 /**
@@ -1226,6 +1260,26 @@ declare module BABYLON.GLTF2.Extensions {
 
 declare module BABYLON.GLTF2.Extensions {
     /**
+     * [Specification](https://github.com/najadojo/glTF/tree/MSFT_audio_emitter/extensions/2.0/Vendor/MSFT_audio_emitter)
+     */
+    class MSFT_audio_emitter extends GLTFLoaderExtension {
+        readonly name: string;
+        private _loadClipAsync(context, clip);
+        private _loadEmitterAsync(context, emitter);
+        protected _loadSceneAsync(context: string, scene: _ILoaderScene): Nullable<Promise<void>>;
+        protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
+        protected _loadAnimationAsync(context: string, animation: _ILoaderAnimation): Nullable<Promise<void>>;
+        private _getEventAction(context, sound, action, time, startOffset?);
+        private _loadAnimationEventAsync(context, animationContext, animation, event, babylonAnimationGroup);
+        private readonly _extension;
+        private readonly _clips;
+        private readonly _emitters;
+    }
+}
+
+
+declare module BABYLON.GLTF2.Extensions {
+    /**
      * [Specification](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_lod)
      */
     class MSFT_lod extends GLTFLoaderExtension {
@@ -1252,8 +1306,8 @@ declare module BABYLON.GLTF2.Extensions {
         private _materialIndexLOD;
         private _materialSignalLODs;
         private _materialPromiseLODs;
-        constructor(loader: GLTFLoader);
         dispose(): void;
+        protected _onReady(): void;
         protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
         protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
         protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
@@ -1279,7 +1333,8 @@ declare module BABYLON.GLTF2.Extensions {
     /** @hidden */
     class MSFT_sRGBFactors extends GLTFLoaderExtension {
         readonly name: string;
-        protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
+        protected _loadMaterialPropertiesAsync(context: string, material: _ILoaderMaterial, babylonMaterial: Material): Nullable<Promise<void>>;
+        private _convertColorsToLinear(babylonMaterial);
     }
 }
 
@@ -1328,9 +1383,10 @@ declare module BABYLON.GLTF2.Extensions {
      */
     class KHR_lights extends GLTFLoaderExtension {
         readonly name: string;
+        private _lights?;
+        protected _onLoading(): void;
         protected _loadSceneAsync(context: string, scene: _ILoaderScene): Nullable<Promise<void>>;
         protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
-        private readonly _lights;
     }
 }
 
@@ -1352,8 +1408,9 @@ declare module BABYLON.GLTF2.Extensions {
      */
     class EXT_lights_imageBased extends GLTFLoaderExtension {
         readonly name: string;
+        private _lights?;
+        protected _onLoading(): void;
         protected _loadSceneAsync(context: string, scene: _ILoaderScene): Nullable<Promise<void>>;
         private _loadLightAsync(context, light);
-        private readonly _lights;
     }
 }

+ 391 - 96
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -118,6 +118,10 @@ var BABYLON;
              */
             this.onCompleteObservable = new BABYLON.Observable();
             /**
+             * Observable raised when an error occurs.
+             */
+            this.onErrorObservable = new BABYLON.Observable();
+            /**
              * Observable raised after the loader is disposed.
              */
             this.onDisposeObservable = new BABYLON.Observable();
@@ -217,6 +221,8 @@ var BABYLON;
         Object.defineProperty(GLTFFileLoader.prototype, "onComplete", {
             /**
              * Callback 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 the loader resolves the returned promise.
              */
             set: function (callback) {
                 if (this._onCompleteObserver) {
@@ -227,6 +233,19 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(GLTFFileLoader.prototype, "onError", {
+            /**
+             * Callback raised when an error occurs.
+             */
+            set: function (callback) {
+                if (this._onErrorObserver) {
+                    this.onErrorObservable.remove(this._onErrorObserver);
+                }
+                this._onErrorObserver = this.onErrorObservable.add(callback);
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(GLTFFileLoader.prototype, "onDispose", {
             /**
              * Callback raised after the loader is disposed.
@@ -259,10 +278,13 @@ var BABYLON;
          */
         GLTFFileLoader.prototype.whenCompleteAsync = function () {
             var _this = this;
-            return new Promise(function (resolve) {
+            return new Promise(function (resolve, reject) {
                 _this.onCompleteObservable.addOnce(function () {
                     resolve();
                 });
+                _this.onErrorObservable.addOnce(function (reason) {
+                    reject(reason);
+                });
             });
         };
         Object.defineProperty(GLTFFileLoader.prototype, "loaderState", {
@@ -2914,9 +2936,6 @@ var BABYLON;
                 GLTFLoader._ExtensionNames.push(name);
             };
             Object.defineProperty(GLTFLoader.prototype, "state", {
-                /**
-                 * Loader state or null if the loader is not active.
-                 */
                 get: function () {
                     return this._state;
                 },
@@ -2935,7 +2954,6 @@ var BABYLON;
                 this._requests.length = 0;
                 delete this._gltf;
                 delete this._babylonScene;
-                delete this._readyPromise;
                 this._completePromises.length = 0;
                 for (var name_1 in this._extensions) {
                     this._extensions[name_1].dispose();
@@ -2995,14 +3013,14 @@ var BABYLON;
             GLTFLoader.prototype._loadAsync = function (nodes) {
                 var _this = this;
                 return Promise.resolve().then(function () {
-                    _this._parent._startPerformanceCounter("Loading => Ready");
-                    _this._parent._startPerformanceCounter("Loading => Complete");
-                    _this._state = BABYLON.GLTFLoaderState.LOADING;
-                    _this._parent._log("Loading");
-                    var readyDeferred = new BABYLON.Deferred();
-                    _this._readyPromise = readyDeferred.promise;
                     _this._loadExtensions();
                     _this._checkExtensions();
+                    var loadingToReadyCounterName = BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.LOADING] + " => " + BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.READY];
+                    var loadingToCompleteCounterName = BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.LOADING] + " => " + BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.COMPLETE];
+                    _this._parent._startPerformanceCounter(loadingToReadyCounterName);
+                    _this._parent._startPerformanceCounter(loadingToCompleteCounterName);
+                    _this._setState(BABYLON.GLTFLoaderState.LOADING);
+                    GLTF2.GLTFLoaderExtension._OnLoading(_this);
                     var promises = new Array();
                     if (nodes) {
                         promises.push(_this._loadSceneAsync("#/nodes", { nodes: nodes, _index: -1 }));
@@ -3018,33 +3036,33 @@ var BABYLON;
                         promises.push(_this._compileShadowGeneratorsAsync());
                     }
                     var resultPromise = Promise.all(promises).then(function () {
-                        _this._state = BABYLON.GLTFLoaderState.READY;
-                        _this._parent._log("Ready");
-                        readyDeferred.resolve();
+                        _this._setState(BABYLON.GLTFLoaderState.READY);
+                        GLTF2.GLTFLoaderExtension._OnReady(_this);
                         _this._startAnimations();
                     });
                     resultPromise.then(function () {
-                        _this._parent._endPerformanceCounter("Loading => Ready");
+                        _this._parent._endPerformanceCounter(loadingToReadyCounterName);
                         BABYLON.Tools.SetImmediate(function () {
                             if (!_this._disposed) {
                                 Promise.all(_this._completePromises).then(function () {
-                                    _this._parent._endPerformanceCounter("Loading => Complete");
-                                    _this._state = BABYLON.GLTFLoaderState.COMPLETE;
-                                    _this._parent._log("Complete");
+                                    _this._parent._endPerformanceCounter(loadingToCompleteCounterName);
+                                    _this._setState(BABYLON.GLTFLoaderState.COMPLETE);
                                     _this._parent.onCompleteObservable.notifyObservers(undefined);
                                     _this._parent.onCompleteObservable.clear();
                                     _this.dispose();
-                                }).catch(function (error) {
-                                    BABYLON.Tools.Error("glTF Loader: " + error.message);
+                                }, function (error) {
+                                    _this._parent.onErrorObservable.notifyObservers(error);
+                                    _this._parent.onErrorObservable.clear();
                                     _this.dispose();
                                 });
                             }
                         });
                     });
                     return resultPromise;
-                }).catch(function (error) {
+                }, function (error) {
                     if (!_this._disposed) {
-                        BABYLON.Tools.Error("glTF Loader: " + error.message);
+                        _this._parent.onErrorObservable.notifyObservers(error);
+                        _this._parent.onErrorObservable.clear();
                         _this.dispose();
                         throw error;
                     }
@@ -3120,6 +3138,10 @@ var BABYLON;
                     }
                 }
             };
+            GLTFLoader.prototype._setState = function (state) {
+                this._state = state;
+                this._parent._log(BABYLON.GLTFLoaderState[this._state]);
+            };
             GLTFLoader.prototype._createRootNode = function () {
                 this._rootBabylonMesh = new BABYLON.Mesh("__root__", this._babylonScene);
                 var rootNode = { _babylonMesh: this._rootBabylonMesh };
@@ -3610,6 +3632,10 @@ var BABYLON;
             };
             GLTFLoader.prototype._loadAnimationAsync = function (context, animation) {
                 var _this = this;
+                var promise = GLTF2.GLTFLoaderExtension._LoadAnimationAsync(this, context, animation);
+                if (promise) {
+                    return promise;
+                }
                 var babylonAnimationGroup = new BABYLON.AnimationGroup(animation.name || "animation" + animation._index, this._babylonScene);
                 animation._babylonAnimationGroup = babylonAnimationGroup;
                 var promises = new Array();
@@ -4374,6 +4400,15 @@ var BABYLON;
                 }
                 return null;
             };
+            GLTFLoader.prototype._forEachExtensions = function (action) {
+                for (var _i = 0, _a = GLTFLoader._ExtensionNames; _i < _a.length; _i++) {
+                    var name_6 = _a[_i];
+                    var extension = this._extensions[name_6];
+                    if (extension.enabled) {
+                        action(extension);
+                    }
+                }
+            };
             GLTFLoader._ExtensionNames = new Array();
             GLTFLoader._ExtensionFactories = {};
             return GLTFLoader;
@@ -4413,6 +4448,14 @@ var BABYLON;
             };
             // #region Overridable Methods
             /**
+             * Override this method to do work after the state changes to LOADING.
+             */
+            GLTFLoaderExtension.prototype._onLoading = function () { };
+            /**
+             * Override this method to do work after the state changes to READY.
+             */
+            GLTFLoaderExtension.prototype._onReady = function () { };
+            /**
              * Override this method to modify the default behavior for loading scenes.
              * @hidden
              */
@@ -4452,6 +4495,8 @@ var BABYLON;
              * @hidden
              */
             GLTFLoaderExtension.prototype._loadUriAsync = function (context, uri) { return null; };
+            /** Override this method to modify the default behavior for loading animations. */
+            GLTFLoaderExtension.prototype._loadAnimationAsync = function (context, animation) { return null; };
             // #endregion
             /**
              * Helper method called by a loader extension to load an glTF extension.
@@ -4500,6 +4545,20 @@ var BABYLON;
                 }
             };
             /**
+             * Helper method called by the loader after the state changes to LOADING.
+             * @hidden
+             */
+            GLTFLoaderExtension._OnLoading = function (loader) {
+                loader._forEachExtensions(function (extension) { return extension._onLoading(); });
+            };
+            /**
+             * Helper method called by the loader after the state changes to READY.
+             * @hidden
+             */
+            GLTFLoaderExtension._OnReady = function (loader) {
+                loader._forEachExtensions(function (extension) { return extension._onReady(); });
+            };
+            /**
              * Helper method called by the loader to allow extensions to override loading scenes.
              * @hidden
              */
@@ -4555,6 +4614,13 @@ var BABYLON;
             GLTFLoaderExtension._LoadUriAsync = function (loader, context, uri) {
                 return loader._applyExtensions(function (extension) { return extension._loadUriAsync(context, uri); });
             };
+            /**
+             * Helper method called by the loader to allow extensions to override loading animations.
+             * @hidden
+             */
+            GLTFLoaderExtension._LoadAnimationAsync = function (loader, context, animation) {
+                return loader._applyExtensions(function (extension) { return extension._loadAnimationAsync(context, animation); });
+            };
             return GLTFLoaderExtension;
         }());
         GLTF2.GLTFLoaderExtension = GLTFLoaderExtension;
@@ -4580,14 +4646,246 @@ var BABYLON;
     (function (GLTF2) {
         var Extensions;
         (function (Extensions) {
+            var NAME = "MSFT_audio_emitter";
+            /**
+             * [Specification](https://github.com/najadojo/glTF/tree/MSFT_audio_emitter/extensions/2.0/Vendor/MSFT_audio_emitter)
+             */
+            var MSFT_audio_emitter = /** @class */ (function (_super) {
+                __extends(MSFT_audio_emitter, _super);
+                function MSFT_audio_emitter() {
+                    var _this = _super !== null && _super.apply(this, arguments) || this;
+                    _this.name = NAME;
+                    return _this;
+                }
+                MSFT_audio_emitter.prototype._loadClipAsync = function (context, clip) {
+                    if (clip._objectURL) {
+                        return clip._objectURL;
+                    }
+                    var promise;
+                    if (clip.uri) {
+                        promise = this._loader._loadUriAsync(context, clip.uri);
+                    }
+                    else {
+                        var bufferView = GLTF2.GLTFLoader._GetProperty(context + "/bufferView", this._loader._gltf.bufferViews, clip.bufferView);
+                        promise = this._loader._loadBufferViewAsync("#/bufferViews/" + bufferView._index, bufferView);
+                    }
+                    clip._objectURL = promise.then(function (data) {
+                        return URL.createObjectURL(new Blob([data], { type: clip.mimeType }));
+                    });
+                    return clip._objectURL;
+                };
+                MSFT_audio_emitter.prototype._loadEmitterAsync = function (context, emitter) {
+                    var _this = this;
+                    emitter._babylonSounds = emitter._babylonSounds || [];
+                    if (!emitter._babylonData) {
+                        var clipPromises = new Array();
+                        var name_1 = emitter.name || "emitter" + emitter._index;
+                        var options_1 = {
+                            loop: false,
+                            autoplay: false,
+                            volume: emitter.volume == undefined ? 1 : emitter.volume,
+                        };
+                        GLTF2._ArrayItem.Assign(this._clips);
+                        var _loop_1 = function (i) {
+                            var clipContext = "#/extensions/" + NAME + "/clips";
+                            var clip = GLTF2.GLTFLoader._GetProperty(clipContext, this_1._clips, emitter.clips[i].clip);
+                            clipPromises.push(this_1._loadClipAsync(clipContext + "/" + emitter.clips[i].clip, clip).then(function (objectURL) {
+                                var sound = emitter._babylonSounds[i] = new BABYLON.Sound(name_1, objectURL, _this._loader._babylonScene, null, options_1);
+                                sound.refDistance = emitter.refDistance || 1;
+                                sound.maxDistance = emitter.maxDistance || 256;
+                                sound.rolloffFactor = emitter.rolloffFactor || 1;
+                                sound.distanceModel = emitter.distanceModel || 'exponential';
+                                sound._positionInEmitterSpace = true;
+                            }));
+                        };
+                        var this_1 = this;
+                        for (var i = 0; i < emitter.clips.length; i++) {
+                            _loop_1(i);
+                        }
+                        var promise = Promise.all(clipPromises).then(function () {
+                            var weights = emitter.clips.map(function (clip) { return clip.weight || 1; });
+                            var weightedSound = new BABYLON.WeightedSound(emitter.loop || false, emitter._babylonSounds, weights);
+                            if (emitter.innerAngle)
+                                weightedSound.directionalConeInnerAngle = 2 * BABYLON.Tools.ToDegrees(emitter.innerAngle);
+                            if (emitter.outerAngle)
+                                weightedSound.directionalConeOuterAngle = 2 * BABYLON.Tools.ToDegrees(emitter.outerAngle);
+                            if (emitter.volume)
+                                weightedSound.volume = emitter.volume;
+                            emitter._babylonData.sound = weightedSound;
+                        });
+                        emitter._babylonData = {
+                            loaded: promise
+                        };
+                    }
+                    return emitter._babylonData.loaded;
+                };
+                MSFT_audio_emitter.prototype._loadSceneAsync = function (context, scene) {
+                    var _this = this;
+                    return this._loadExtensionAsync(context, scene, function (extensionContext, extension) {
+                        return _this._loader._loadSceneAsync(context, scene).then(function () {
+                            var promises = new Array();
+                            GLTF2._ArrayItem.Assign(_this._emitters);
+                            for (var _i = 0, _a = extension.emitters; _i < _a.length; _i++) {
+                                var emitterIndex = _a[_i];
+                                var emitter = GLTF2.GLTFLoader._GetProperty(extensionContext + "/emitters", _this._emitters, emitterIndex);
+                                if (emitter.refDistance != undefined || emitter.maxDistance != undefined || emitter.rolloffFactor != undefined ||
+                                    emitter.distanceModel != undefined || emitter.innerAngle != undefined || emitter.outerAngle != undefined) {
+                                    throw new Error(extensionContext + ": Direction or Distance properties are not allowed on emitters attached to a scene");
+                                }
+                                promises.push(_this._loadEmitterAsync(extensionContext + "/emitters/" + emitter._index, emitter));
+                            }
+                            return Promise.all(promises).then(function () { });
+                        });
+                    });
+                };
+                MSFT_audio_emitter.prototype._loadNodeAsync = function (context, node) {
+                    var _this = this;
+                    return this._loadExtensionAsync(context, node, function (extensionContext, extension) {
+                        return _this._loader._loadNodeAsync(extensionContext, node).then(function () {
+                            var promises = new Array();
+                            GLTF2._ArrayItem.Assign(_this._emitters);
+                            var _loop_2 = function (emitterIndex) {
+                                var emitter = GLTF2.GLTFLoader._GetProperty(extensionContext + "/emitters", _this._emitters, emitterIndex);
+                                promises.push(_this._loadEmitterAsync(extensionContext + "/emitters/" + emitter._index, emitter).then(function () {
+                                    if (node._babylonMesh) {
+                                        for (var _i = 0, _a = emitter._babylonSounds; _i < _a.length; _i++) {
+                                            var sound = _a[_i];
+                                            sound.attachToMesh(node._babylonMesh);
+                                            if (emitter.innerAngle != undefined || emitter.outerAngle != undefined) {
+                                                sound.setLocalDirectionToMesh(new BABYLON.Vector3(0, 0, 1));
+                                                sound.setDirectionalCone(2 * BABYLON.Tools.ToDegrees(emitter.innerAngle == undefined ? Math.PI : emitter.innerAngle), 2 * BABYLON.Tools.ToDegrees(emitter.outerAngle == undefined ? Math.PI : emitter.outerAngle), 0);
+                                            }
+                                        }
+                                    }
+                                }));
+                            };
+                            for (var _i = 0, _a = extension.emitters; _i < _a.length; _i++) {
+                                var emitterIndex = _a[_i];
+                                _loop_2(emitterIndex);
+                            }
+                            return Promise.all(promises).then(function () { });
+                        });
+                    });
+                };
+                MSFT_audio_emitter.prototype._loadAnimationAsync = function (context, animation) {
+                    var _this = this;
+                    return this._loadExtensionAsync(context, animation, function (extensionContext, extension) {
+                        return _this._loader._loadAnimationAsync(extensionContext, animation).then(function () {
+                            var promises = new Array();
+                            var babylonAnimationGroup = animation._babylonAnimationGroup;
+                            GLTF2._ArrayItem.Assign(extension.events);
+                            for (var _i = 0, _a = extension.events; _i < _a.length; _i++) {
+                                var event_1 = _a[_i];
+                                promises.push(_this._loadAnimationEventAsync(extensionContext + "/events/" + event_1._index, context, animation, event_1, babylonAnimationGroup));
+                            }
+                            return Promise.all(promises).then(function () { });
+                        });
+                    });
+                };
+                MSFT_audio_emitter.prototype._getEventAction = function (context, sound, action, time, startOffset) {
+                    if (action == "play" /* play */) {
+                        return function (currentFrame) {
+                            var frameOffset = (startOffset || 0) + (currentFrame - time);
+                            sound.play(frameOffset);
+                        };
+                    }
+                    else if (action == "stop" /* stop */) {
+                        return function (currentFrame) {
+                            sound.stop();
+                        };
+                    }
+                    else if (action == "pause" /* pause */) {
+                        return function (currentFrame) {
+                            sound.pause();
+                        };
+                    }
+                    else {
+                        throw new Error(context + ": Unsupported action " + action);
+                    }
+                };
+                MSFT_audio_emitter.prototype._loadAnimationEventAsync = function (context, animationContext, animation, event, babylonAnimationGroup) {
+                    var _this = this;
+                    if (babylonAnimationGroup.targetedAnimations.length == 0) {
+                        return Promise.resolve();
+                    }
+                    var babylonAnimation = babylonAnimationGroup.targetedAnimations[0];
+                    var emitterIndex = event.emitter;
+                    var emitter = GLTF2.GLTFLoader._GetProperty("#/extensions/" + NAME + "/emitters", this._emitters, emitterIndex);
+                    return this._loadEmitterAsync(context, emitter).then(function () {
+                        var sound = emitter._babylonData.sound;
+                        if (sound) {
+                            var babylonAnimationEvent = new BABYLON.AnimationEvent(event.time, _this._getEventAction(context, sound, event.action, event.time, event.startOffset));
+                            babylonAnimation.animation.addEvent(babylonAnimationEvent);
+                            // Make sure all started audio stops when this animation is terminated.
+                            babylonAnimationGroup.onAnimationGroupEndObservable.add(function () {
+                                sound.stop();
+                            });
+                            babylonAnimationGroup.onAnimationGroupPauseObservable.add(function () {
+                                sound.pause();
+                            });
+                        }
+                    });
+                };
+                Object.defineProperty(MSFT_audio_emitter.prototype, "_extension", {
+                    get: function () {
+                        var extensions = this._loader._gltf.extensions;
+                        if (!extensions || !extensions[this.name]) {
+                            throw new Error("#/extensions: '" + this.name + "' not found");
+                        }
+                        return extensions[this.name];
+                    },
+                    enumerable: true,
+                    configurable: true
+                });
+                Object.defineProperty(MSFT_audio_emitter.prototype, "_clips", {
+                    get: function () {
+                        return this._extension.clips;
+                    },
+                    enumerable: true,
+                    configurable: true
+                });
+                Object.defineProperty(MSFT_audio_emitter.prototype, "_emitters", {
+                    get: function () {
+                        return this._extension.emitters;
+                    },
+                    enumerable: true,
+                    configurable: true
+                });
+                return MSFT_audio_emitter;
+            }(GLTF2.GLTFLoaderExtension));
+            Extensions.MSFT_audio_emitter = MSFT_audio_emitter;
+            GLTF2.GLTFLoader._Register(NAME, function (loader) { return new MSFT_audio_emitter(loader); });
+        })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
+    })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=MSFT_audio_emitter.js.map
+
+/// <reference path="../../../../../dist/preview release/babylon.d.ts"/>
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = Object.setPrototypeOf ||
+        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+var BABYLON;
+(function (BABYLON) {
+    var GLTF2;
+    (function (GLTF2) {
+        var Extensions;
+        (function (Extensions) {
             var NAME = "MSFT_lod";
             /**
              * [Specification](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_lod)
              */
             var MSFT_lod = /** @class */ (function (_super) {
                 __extends(MSFT_lod, _super);
-                function MSFT_lod(loader) {
-                    var _this = _super.call(this, loader) || this;
+                function MSFT_lod() {
+                    var _this = _super !== null && _super.apply(this, arguments) || this;
                     _this.name = NAME;
                     /**
                      * Maximum number of LODs to load, starting from the lowest LOD.
@@ -4611,42 +4909,6 @@ var BABYLON;
                     _this._materialIndexLOD = null;
                     _this._materialSignalLODs = new Array();
                     _this._materialPromiseLODs = new Array();
-                    _this._loader._readyPromise.then(function () {
-                        var _loop_1 = function (indexLOD) {
-                            var promise = Promise.all(_this._nodePromiseLODs[indexLOD]).then(function () {
-                                if (indexLOD !== 0) {
-                                    _this._loader._parent._endPerformanceCounter("Node LOD " + indexLOD);
-                                }
-                                _this._loader._parent._log("Loaded node LOD " + indexLOD);
-                                _this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
-                                if (indexLOD !== _this._nodePromiseLODs.length - 1) {
-                                    _this._loader._parent._startPerformanceCounter("Node LOD " + (indexLOD + 1));
-                                    _this._nodeSignalLODs[indexLOD].resolve();
-                                }
-                            });
-                            _this._loader._completePromises.push(promise);
-                        };
-                        for (var indexLOD = 0; indexLOD < _this._nodePromiseLODs.length; indexLOD++) {
-                            _loop_1(indexLOD);
-                        }
-                        var _loop_2 = function (indexLOD) {
-                            var promise = Promise.all(_this._materialPromiseLODs[indexLOD]).then(function () {
-                                if (indexLOD !== 0) {
-                                    _this._loader._parent._endPerformanceCounter("Material LOD " + indexLOD);
-                                }
-                                _this._loader._parent._log("Loaded material LOD " + indexLOD);
-                                _this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
-                                if (indexLOD !== _this._materialPromiseLODs.length - 1) {
-                                    _this._loader._parent._startPerformanceCounter("Material LOD " + (indexLOD + 1));
-                                    _this._materialSignalLODs[indexLOD].resolve();
-                                }
-                            });
-                            _this._loader._completePromises.push(promise);
-                        };
-                        for (var indexLOD = 0; indexLOD < _this._materialPromiseLODs.length; indexLOD++) {
-                            _loop_2(indexLOD);
-                        }
-                    });
                     return _this;
                 }
                 MSFT_lod.prototype.dispose = function () {
@@ -4660,6 +4922,49 @@ var BABYLON;
                     this.onMaterialLODsLoadedObservable.clear();
                     this.onNodeLODsLoadedObservable.clear();
                 };
+                MSFT_lod.prototype._onReady = function () {
+                    var _this = this;
+                    var _loop_1 = function (indexLOD) {
+                        var promise = Promise.all(this_1._nodePromiseLODs[indexLOD]).then(function () {
+                            if (indexLOD !== 0) {
+                                _this._loader._parent._endPerformanceCounter("Node LOD " + indexLOD);
+                            }
+                            _this._loader._parent._log("Loaded node LOD " + indexLOD);
+                            _this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
+                            if (indexLOD !== _this._nodePromiseLODs.length - 1) {
+                                _this._loader._parent._startPerformanceCounter("Node LOD " + (indexLOD + 1));
+                                if (_this._nodeSignalLODs[indexLOD]) {
+                                    _this._nodeSignalLODs[indexLOD].resolve();
+                                }
+                            }
+                        });
+                        this_1._loader._completePromises.push(promise);
+                    };
+                    var this_1 = this;
+                    for (var indexLOD = 0; indexLOD < this._nodePromiseLODs.length; indexLOD++) {
+                        _loop_1(indexLOD);
+                    }
+                    var _loop_2 = function (indexLOD) {
+                        var promise = Promise.all(this_2._materialPromiseLODs[indexLOD]).then(function () {
+                            if (indexLOD !== 0) {
+                                _this._loader._parent._endPerformanceCounter("Material LOD " + indexLOD);
+                            }
+                            _this._loader._parent._log("Loaded material LOD " + indexLOD);
+                            _this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
+                            if (indexLOD !== _this._materialPromiseLODs.length - 1) {
+                                _this._loader._parent._startPerformanceCounter("Material LOD " + (indexLOD + 1));
+                                if (_this._materialSignalLODs[indexLOD]) {
+                                    _this._materialSignalLODs[indexLOD].resolve();
+                                }
+                            }
+                        });
+                        this_2._loader._completePromises.push(promise);
+                    };
+                    var this_2 = this;
+                    for (var indexLOD = 0; indexLOD < this._materialPromiseLODs.length; indexLOD++) {
+                        _loop_2(indexLOD);
+                    }
+                };
                 MSFT_lod.prototype._loadNodeAsync = function (context, node) {
                     var _this = this;
                     return this._loadExtensionAsync(context, node, function (extensionContext, extension) {
@@ -4884,23 +5189,25 @@ var BABYLON;
                     _this.name = NAME;
                     return _this;
                 }
-                MSFT_sRGBFactors.prototype._loadMaterialAsync = function (context, material, mesh, babylonMesh, babylonDrawMode, assign) {
+                MSFT_sRGBFactors.prototype._loadMaterialPropertiesAsync = function (context, material, babylonMaterial) {
                     var _this = this;
                     return this._loadExtrasValueAsync(context, material, function (extensionContext, value) {
                         if (value) {
-                            return _this._loader._loadMaterialAsync(context, material, mesh, babylonMesh, babylonDrawMode, function (babylonMaterial) {
-                                if (!babylonMaterial.albedoTexture) {
-                                    babylonMaterial.albedoColor.toLinearSpaceToRef(babylonMaterial.albedoColor);
-                                }
-                                if (!babylonMaterial.reflectivityTexture) {
-                                    babylonMaterial.reflectivityColor.toLinearSpaceToRef(babylonMaterial.reflectivityColor);
-                                }
-                                assign(babylonMaterial);
-                            });
+                            var promise = _this._loader._loadMaterialPropertiesAsync(context, material, babylonMaterial);
+                            _this._convertColorsToLinear(babylonMaterial);
+                            return promise;
                         }
                         return null;
                     });
                 };
+                MSFT_sRGBFactors.prototype._convertColorsToLinear = function (babylonMaterial) {
+                    if (!babylonMaterial.albedoTexture) {
+                        babylonMaterial.albedoColor.toLinearSpaceToRef(babylonMaterial.albedoColor);
+                    }
+                    if (!babylonMaterial.reflectivityTexture) {
+                        babylonMaterial.reflectivityColor.toLinearSpaceToRef(babylonMaterial.reflectivityColor);
+                    }
+                };
                 return MSFT_sRGBFactors;
             }(GLTF2.GLTFLoaderExtension));
             Extensions.MSFT_sRGBFactors = MSFT_sRGBFactors;
@@ -5154,8 +5461,6 @@ var BABYLON;
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
 })(BABYLON || (BABYLON = {}));
 
-//# sourceMappingURL=KHR_materials_unlit.js.map
-
 /// <reference path="../../../../../dist/preview release/babylon.d.ts"/>
 var __extends = (this && this.__extends) || (function () {
     var extendStatics = Object.setPrototypeOf ||
@@ -5191,6 +5496,13 @@ var BABYLON;
                     _this.name = NAME;
                     return _this;
                 }
+                KHR_lights.prototype._onLoading = function () {
+                    var extensions = this._loader._gltf.extensions;
+                    if (extensions && extensions[this.name]) {
+                        var extension = extensions[this.name];
+                        this._lights = extension.lights;
+                    }
+                };
                 KHR_lights.prototype._loadSceneAsync = function (context, scene) {
                     var _this = this;
                     return this._loadExtensionAsync(context, scene, function (extensionContext, extension) {
@@ -5239,18 +5551,6 @@ var BABYLON;
                         return promise;
                     });
                 };
-                Object.defineProperty(KHR_lights.prototype, "_lights", {
-                    get: function () {
-                        var extensions = this._loader._gltf.extensions;
-                        if (!extensions || !extensions[this.name]) {
-                            throw new Error("#/extensions: '" + this.name + "' not found");
-                        }
-                        var extension = extensions[this.name];
-                        return extension.lights;
-                    },
-                    enumerable: true,
-                    configurable: true
-                });
                 return KHR_lights;
             }(GLTF2.GLTFLoaderExtension));
             Extensions.KHR_lights = KHR_lights;
@@ -5348,6 +5648,13 @@ var BABYLON;
                     _this.name = NAME;
                     return _this;
                 }
+                EXT_lights_imageBased.prototype._onLoading = function () {
+                    var extensions = this._loader._gltf.extensions;
+                    if (extensions && extensions[this.name]) {
+                        var extension = extensions[this.name];
+                        this._lights = extension.lights;
+                    }
+                };
                 EXT_lights_imageBased.prototype._loadSceneAsync = function (context, scene) {
                     var _this = this;
                     return this._loadExtensionAsync(context, scene, function (extensionContext, extension) {
@@ -5417,18 +5724,6 @@ var BABYLON;
                         return light._babylonTexture;
                     });
                 };
-                Object.defineProperty(EXT_lights_imageBased.prototype, "_lights", {
-                    get: function () {
-                        var extensions = this._loader._gltf.extensions;
-                        if (!extensions || !extensions[this.name]) {
-                            throw new Error("#/extensions: '" + this.name + "' not found");
-                        }
-                        var extension = extensions[this.name];
-                        return extension.lights;
-                    },
-                    enumerable: true,
-                    configurable: true
-                });
                 return EXT_lights_imageBased;
             }(GLTF2.GLTFLoaderExtension));
             Extensions.EXT_lights_imageBased = EXT_lights_imageBased;

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


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

@@ -45,6 +45,7 @@ declare module BABYLON {
         facePattern2: RegExp;
         facePattern3: RegExp;
         facePattern4: RegExp;
+        facePattern5: RegExp;
         /**
          * Calls synchronously the MTL file attached to this obj.
          * Load function or importMesh function don't enable to load 2 files in the same time asynchronously.

+ 37 - 1
dist/preview release/loaders/babylon.objFileLoader.js

@@ -231,6 +231,8 @@ var BABYLON;
             this.facePattern3 = /f\s+((([\d]{1,}\/[\d]{1,}\/[\d]{1,}[\s]?){3,})+)/;
             // f vertex//normal vertex//normal vertex//normal ...
             this.facePattern4 = /f\s+((([\d]{1,}\/\/[\d]{1,}[\s]?){3,})+)/;
+            // f -vertex/-uvs/-normal -vertex/-uvs/-normal -vertex/-uvs/-normal ...
+            this.facePattern5 = /f\s+(((-[\d]{1,}\/-[\d]{1,}\/-[\d]{1,}[\s]?){3,})+)/;
         }
         /**
          * Calls synchronously the MTL file attached to this obj.
@@ -413,11 +415,12 @@ var BABYLON;
              * Create triangles from polygons by recursion
              * The best to understand how it works is to draw it in the same time you get the recursion.
              * It is important to notice that a triangle is a polygon
-             * We get 4 patterns of face defined in OBJ File :
+             * We get 5 patterns of face defined in OBJ File :
              * facePattern1 = ["1","2","3","4","5","6"]
              * facePattern2 = ["1/1","2/2","3/3","4/4","5/5","6/6"]
              * facePattern3 = ["1/1/1","2/2/2","3/3/3","4/4/4","5/5/5","6/6/6"]
              * facePattern4 = ["1//1","2//2","3//3","4//4","5//5","6//6"]
+             * facePattern5 = ["-1/-1/-1","-2/-2/-2","-3/-3/-3","-4/-4/-4","-5/-5/-5","-6/-6/-6"]
              * Each pattern is divided by the same method
              * @param face Array[String] The indices of elements
              * @param v Integer The variable to increment
@@ -437,6 +440,7 @@ var BABYLON;
                 //Pattern2 => triangle = ["1/1","2/2","3/3","1/1","3/3","4/4"];
                 //Pattern3 => triangle = ["1/1/1","2/2/2","3/3/3","1/1/1","3/3/3","4/4/4"];
                 //Pattern4 => triangle = ["1//1","2//2","3//3","1//1","3//3","4//4"];
+                //Pattern5 => triangle = ["-1/-1/-1","-2/-2/-2","-3/-3/-3","-1/-1/-1","-3/-3/-3","-4/-4/-4"];
             };
             /**
              * Create triangles and push the data for each polygon for the pattern 1
@@ -532,6 +536,31 @@ var BABYLON;
                 //Reset variable for the next line
                 triangles = [];
             };
+            /**
+             * Create triangles and push the data for each polygon for the pattern 3
+             * In this pattern we get vertice positions, uvs and normals
+             * @param face
+             * @param v
+             */
+            var setDataForCurrentFaceWithPattern5 = function (face, v) {
+                //Get the indices of triangles for each polygon
+                getTriangles(face, v);
+                for (var k = 0; k < triangles.length; k++) {
+                    //triangle[k] = "-1/-1/-1"
+                    //Split the data for getting position, uv, and normals
+                    var point = triangles[k].split("/"); // ["-1", "-1", "-1"]
+                    // Set position indice
+                    var indicePositionFromObj = positions.length + parseInt(point[0]);
+                    // Set uv indice
+                    var indiceUvsFromObj = uvs.length + parseInt(point[1]);
+                    // Set normal indice
+                    var indiceNormalFromObj = normals.length + parseInt(point[2]);
+                    setData(indicePositionFromObj, indiceUvsFromObj, indiceNormalFromObj, positions[indicePositionFromObj], uvs[indiceUvsFromObj], normals[indiceNormalFromObj] //Set the vector for each component
+                    );
+                }
+                //Reset variable for the next line
+                triangles = [];
+            };
             var addPreviousObjMesh = function () {
                 //Check if it is not the first mesh. Otherwise we don't have data.
                 if (meshesFromObj.length > 0) {
@@ -604,6 +633,13 @@ var BABYLON;
                     setDataForCurrentFaceWithPattern4(result[1].trim().split(" "), // ["1//1", "2//2", "3//3"]
                     1);
                 }
+                else if ((result = this.facePattern5.exec(line)) !== null) {
+                    //Value of result:
+                    //["f -1/-1/-1 -2/-2/-2 -3/-3/-3", "-1/-1/-1 -2/-2/-2 -3/-3/-3"...]
+                    //Set the data for this face
+                    setDataForCurrentFaceWithPattern5(result[1].trim().split(" "), // ["-1/-1/-1", "-2/-2/-2", "-3/-3/-3"]
+                    1);
+                }
                 else if ((result = this.facePattern2.exec(line)) !== null) {
                     //Value of result:
                     //["f 1/1 2/2 3/3", "1/1 2/2 3/3"...]

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


+ 67 - 9
dist/preview release/loaders/babylonjs.loaders.d.ts

@@ -63,6 +63,7 @@ declare module BABYLON {
         facePattern2: RegExp;
         facePattern3: RegExp;
         facePattern4: RegExp;
+        facePattern5: RegExp;
         /**
          * Calls synchronously the MTL file attached to this obj.
          * Load function or importMesh function don't enable to load 2 files in the same time asynchronously.
@@ -292,9 +293,20 @@ declare module BABYLON {
         private _onCompleteObserver;
         /**
          * Callback 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 the loader resolves the returned promise.
          */
         onComplete: () => void;
         /**
+         * Observable raised when an error occurs.
+         */
+        readonly onErrorObservable: Observable<any>;
+        private _onErrorObserver;
+        /**
+         * Callback raised when an error occurs.
+         */
+        onError: (reason: any) => void;
+        /**
          * Observable raised after the loader is disposed.
          */
         readonly onDisposeObservable: Observable<void>;
@@ -1112,7 +1124,6 @@ declare module BABYLON.GLTF2 {
         _parent: GLTFFileLoader;
         _gltf: _ILoaderGLTF;
         _babylonScene: Scene;
-        _readyPromise: Promise<void>;
         _completePromises: Promise<void>[];
         private _disposed;
         private _state;
@@ -1126,9 +1137,6 @@ declare module BABYLON.GLTF2 {
         private static _ExtensionNames;
         private static _ExtensionFactories;
         static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void;
-        /**
-         * Loader state or null if the loader is not active.
-         */
         readonly state: Nullable<GLTFLoaderState>;
         constructor(parent: GLTFFileLoader);
         dispose(): void;
@@ -1144,6 +1152,7 @@ declare module BABYLON.GLTF2 {
         private _setupData();
         private _loadExtensions();
         private _checkExtensions();
+        private _setState(state);
         private _createRootNode();
         _loadSceneAsync(context: string, scene: _ILoaderScene): Promise<void>;
         private _forEachPrimitive(node, callback);
@@ -1167,7 +1176,7 @@ declare module BABYLON.GLTF2 {
         private _getNodeMatrix(node);
         private _loadCamera(context, camera, babylonMesh);
         private _loadAnimationsAsync();
-        private _loadAnimationAsync(context, animation);
+        _loadAnimationAsync(context: string, animation: _ILoaderAnimation): Promise<void>;
         private _loadAnimationChannelAsync(context, animationContext, animation, channel, babylonAnimationGroup);
         private _loadAnimationSamplerAsync(context, sampler);
         private _loadBufferAsync(context, buffer);
@@ -1199,6 +1208,7 @@ declare module BABYLON.GLTF2 {
         private _compileMaterialsAsync();
         private _compileShadowGeneratorsAsync();
         _applyExtensions<T>(actionAsync: (extension: GLTFLoaderExtension) => Nullable<Promise<T>>): Nullable<Promise<T>>;
+        _forEachExtensions(action: (extension: GLTFLoaderExtension) => void): void;
     }
 }
 
@@ -1227,6 +1237,14 @@ declare module BABYLON.GLTF2 {
          */
         dispose(): void;
         /**
+         * Override this method to do work after the state changes to LOADING.
+         */
+        protected _onLoading(): void;
+        /**
+         * Override this method to do work after the state changes to READY.
+         */
+        protected _onReady(): void;
+        /**
          * Override this method to modify the default behavior for loading scenes.
          * @hidden
          */
@@ -1266,6 +1284,8 @@ declare module BABYLON.GLTF2 {
          * @hidden
          */
         protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
+        /** Override this method to modify the default behavior for loading animations. */
+        protected _loadAnimationAsync(context: string, animation: _ILoaderAnimation): Nullable<Promise<void>>;
         /**
          * Helper method called by a loader extension to load an glTF extension.
          * @hidden
@@ -1277,6 +1297,16 @@ declare module BABYLON.GLTF2 {
          */
         protected _loadExtrasValueAsync<TProperty, TResult = void>(context: string, property: IProperty, actionAsync: (extensionContext: string, value: TProperty) => Nullable<Promise<TResult>>): Nullable<Promise<TResult>>;
         /**
+         * Helper method called by the loader after the state changes to LOADING.
+         * @hidden
+         */
+        static _OnLoading(loader: GLTFLoader): void;
+        /**
+         * Helper method called by the loader after the state changes to READY.
+         * @hidden
+         */
+        static _OnReady(loader: GLTFLoader): void;
+        /**
          * Helper method called by the loader to allow extensions to override loading scenes.
          * @hidden
          */
@@ -1316,6 +1346,11 @@ declare module BABYLON.GLTF2 {
          * @hidden
          */
         static _LoadUriAsync(loader: GLTFLoader, context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
+        /**
+         * Helper method called by the loader to allow extensions to override loading animations.
+         * @hidden
+         */
+        static _LoadAnimationAsync(loader: GLTFLoader, context: string, animation: _ILoaderAnimation): Nullable<Promise<void>>;
     }
 }
 /**
@@ -1327,6 +1362,26 @@ declare module BABYLON.GLTF2.Extensions {
 
 declare module BABYLON.GLTF2.Extensions {
     /**
+     * [Specification](https://github.com/najadojo/glTF/tree/MSFT_audio_emitter/extensions/2.0/Vendor/MSFT_audio_emitter)
+     */
+    class MSFT_audio_emitter extends GLTFLoaderExtension {
+        readonly name: string;
+        private _loadClipAsync(context, clip);
+        private _loadEmitterAsync(context, emitter);
+        protected _loadSceneAsync(context: string, scene: _ILoaderScene): Nullable<Promise<void>>;
+        protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
+        protected _loadAnimationAsync(context: string, animation: _ILoaderAnimation): Nullable<Promise<void>>;
+        private _getEventAction(context, sound, action, time, startOffset?);
+        private _loadAnimationEventAsync(context, animationContext, animation, event, babylonAnimationGroup);
+        private readonly _extension;
+        private readonly _clips;
+        private readonly _emitters;
+    }
+}
+
+
+declare module BABYLON.GLTF2.Extensions {
+    /**
      * [Specification](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_lod)
      */
     class MSFT_lod extends GLTFLoaderExtension {
@@ -1353,8 +1408,8 @@ declare module BABYLON.GLTF2.Extensions {
         private _materialIndexLOD;
         private _materialSignalLODs;
         private _materialPromiseLODs;
-        constructor(loader: GLTFLoader);
         dispose(): void;
+        protected _onReady(): void;
         protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
         protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
         protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
@@ -1380,7 +1435,8 @@ declare module BABYLON.GLTF2.Extensions {
     /** @hidden */
     class MSFT_sRGBFactors extends GLTFLoaderExtension {
         readonly name: string;
-        protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
+        protected _loadMaterialPropertiesAsync(context: string, material: _ILoaderMaterial, babylonMaterial: Material): Nullable<Promise<void>>;
+        private _convertColorsToLinear(babylonMaterial);
     }
 }
 
@@ -1429,9 +1485,10 @@ declare module BABYLON.GLTF2.Extensions {
      */
     class KHR_lights extends GLTFLoaderExtension {
         readonly name: string;
+        private _lights?;
+        protected _onLoading(): void;
         protected _loadSceneAsync(context: string, scene: _ILoaderScene): Nullable<Promise<void>>;
         protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
-        private readonly _lights;
     }
 }
 
@@ -1453,8 +1510,9 @@ declare module BABYLON.GLTF2.Extensions {
      */
     class EXT_lights_imageBased extends GLTFLoaderExtension {
         readonly name: string;
+        private _lights?;
+        protected _onLoading(): void;
         protected _loadSceneAsync(context: string, scene: _ILoaderScene): Nullable<Promise<void>>;
         private _loadLightAsync(context, light);
-        private readonly _lights;
     }
 }

+ 419 - 97
dist/preview release/loaders/babylonjs.loaders.js

@@ -430,6 +430,8 @@ var BABYLON;
             this.facePattern3 = /f\s+((([\d]{1,}\/[\d]{1,}\/[\d]{1,}[\s]?){3,})+)/;
             // f vertex//normal vertex//normal vertex//normal ...
             this.facePattern4 = /f\s+((([\d]{1,}\/\/[\d]{1,}[\s]?){3,})+)/;
+            // f -vertex/-uvs/-normal -vertex/-uvs/-normal -vertex/-uvs/-normal ...
+            this.facePattern5 = /f\s+(((-[\d]{1,}\/-[\d]{1,}\/-[\d]{1,}[\s]?){3,})+)/;
         }
         /**
          * Calls synchronously the MTL file attached to this obj.
@@ -612,11 +614,12 @@ var BABYLON;
              * Create triangles from polygons by recursion
              * The best to understand how it works is to draw it in the same time you get the recursion.
              * It is important to notice that a triangle is a polygon
-             * We get 4 patterns of face defined in OBJ File :
+             * We get 5 patterns of face defined in OBJ File :
              * facePattern1 = ["1","2","3","4","5","6"]
              * facePattern2 = ["1/1","2/2","3/3","4/4","5/5","6/6"]
              * facePattern3 = ["1/1/1","2/2/2","3/3/3","4/4/4","5/5/5","6/6/6"]
              * facePattern4 = ["1//1","2//2","3//3","4//4","5//5","6//6"]
+             * facePattern5 = ["-1/-1/-1","-2/-2/-2","-3/-3/-3","-4/-4/-4","-5/-5/-5","-6/-6/-6"]
              * Each pattern is divided by the same method
              * @param face Array[String] The indices of elements
              * @param v Integer The variable to increment
@@ -636,6 +639,7 @@ var BABYLON;
                 //Pattern2 => triangle = ["1/1","2/2","3/3","1/1","3/3","4/4"];
                 //Pattern3 => triangle = ["1/1/1","2/2/2","3/3/3","1/1/1","3/3/3","4/4/4"];
                 //Pattern4 => triangle = ["1//1","2//2","3//3","1//1","3//3","4//4"];
+                //Pattern5 => triangle = ["-1/-1/-1","-2/-2/-2","-3/-3/-3","-1/-1/-1","-3/-3/-3","-4/-4/-4"];
             };
             /**
              * Create triangles and push the data for each polygon for the pattern 1
@@ -731,6 +735,31 @@ var BABYLON;
                 //Reset variable for the next line
                 triangles = [];
             };
+            /**
+             * Create triangles and push the data for each polygon for the pattern 3
+             * In this pattern we get vertice positions, uvs and normals
+             * @param face
+             * @param v
+             */
+            var setDataForCurrentFaceWithPattern5 = function (face, v) {
+                //Get the indices of triangles for each polygon
+                getTriangles(face, v);
+                for (var k = 0; k < triangles.length; k++) {
+                    //triangle[k] = "-1/-1/-1"
+                    //Split the data for getting position, uv, and normals
+                    var point = triangles[k].split("/"); // ["-1", "-1", "-1"]
+                    // Set position indice
+                    var indicePositionFromObj = positions.length + parseInt(point[0]);
+                    // Set uv indice
+                    var indiceUvsFromObj = uvs.length + parseInt(point[1]);
+                    // Set normal indice
+                    var indiceNormalFromObj = normals.length + parseInt(point[2]);
+                    setData(indicePositionFromObj, indiceUvsFromObj, indiceNormalFromObj, positions[indicePositionFromObj], uvs[indiceUvsFromObj], normals[indiceNormalFromObj] //Set the vector for each component
+                    );
+                }
+                //Reset variable for the next line
+                triangles = [];
+            };
             var addPreviousObjMesh = function () {
                 //Check if it is not the first mesh. Otherwise we don't have data.
                 if (meshesFromObj.length > 0) {
@@ -803,6 +832,13 @@ var BABYLON;
                     setDataForCurrentFaceWithPattern4(result[1].trim().split(" "), // ["1//1", "2//2", "3//3"]
                     1);
                 }
+                else if ((result = this.facePattern5.exec(line)) !== null) {
+                    //Value of result:
+                    //["f -1/-1/-1 -2/-2/-2 -3/-3/-3", "-1/-1/-1 -2/-2/-2 -3/-3/-3"...]
+                    //Set the data for this face
+                    setDataForCurrentFaceWithPattern5(result[1].trim().split(" "), // ["-1/-1/-1", "-2/-2/-2", "-3/-3/-3"]
+                    1);
+                }
                 else if ((result = this.facePattern2.exec(line)) !== null) {
                     //Value of result:
                     //["f 1/1 2/2 3/3", "1/1 2/2 3/3"...]
@@ -1137,6 +1173,10 @@ var BABYLON;
              */
             this.onCompleteObservable = new BABYLON.Observable();
             /**
+             * Observable raised when an error occurs.
+             */
+            this.onErrorObservable = new BABYLON.Observable();
+            /**
              * Observable raised after the loader is disposed.
              */
             this.onDisposeObservable = new BABYLON.Observable();
@@ -1236,6 +1276,8 @@ var BABYLON;
         Object.defineProperty(GLTFFileLoader.prototype, "onComplete", {
             /**
              * Callback 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 the loader resolves the returned promise.
              */
             set: function (callback) {
                 if (this._onCompleteObserver) {
@@ -1246,6 +1288,19 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(GLTFFileLoader.prototype, "onError", {
+            /**
+             * Callback raised when an error occurs.
+             */
+            set: function (callback) {
+                if (this._onErrorObserver) {
+                    this.onErrorObservable.remove(this._onErrorObserver);
+                }
+                this._onErrorObserver = this.onErrorObservable.add(callback);
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(GLTFFileLoader.prototype, "onDispose", {
             /**
              * Callback raised after the loader is disposed.
@@ -1278,10 +1333,13 @@ var BABYLON;
          */
         GLTFFileLoader.prototype.whenCompleteAsync = function () {
             var _this = this;
-            return new Promise(function (resolve) {
+            return new Promise(function (resolve, reject) {
                 _this.onCompleteObservable.addOnce(function () {
                     resolve();
                 });
+                _this.onErrorObservable.addOnce(function (reason) {
+                    reject(reason);
+                });
             });
         };
         Object.defineProperty(GLTFFileLoader.prototype, "loaderState", {
@@ -3915,9 +3973,6 @@ var BABYLON;
                 GLTFLoader._ExtensionNames.push(name);
             };
             Object.defineProperty(GLTFLoader.prototype, "state", {
-                /**
-                 * Loader state or null if the loader is not active.
-                 */
                 get: function () {
                     return this._state;
                 },
@@ -3936,7 +3991,6 @@ var BABYLON;
                 this._requests.length = 0;
                 delete this._gltf;
                 delete this._babylonScene;
-                delete this._readyPromise;
                 this._completePromises.length = 0;
                 for (var name_1 in this._extensions) {
                     this._extensions[name_1].dispose();
@@ -3996,14 +4050,14 @@ var BABYLON;
             GLTFLoader.prototype._loadAsync = function (nodes) {
                 var _this = this;
                 return Promise.resolve().then(function () {
-                    _this._parent._startPerformanceCounter("Loading => Ready");
-                    _this._parent._startPerformanceCounter("Loading => Complete");
-                    _this._state = BABYLON.GLTFLoaderState.LOADING;
-                    _this._parent._log("Loading");
-                    var readyDeferred = new BABYLON.Deferred();
-                    _this._readyPromise = readyDeferred.promise;
                     _this._loadExtensions();
                     _this._checkExtensions();
+                    var loadingToReadyCounterName = BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.LOADING] + " => " + BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.READY];
+                    var loadingToCompleteCounterName = BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.LOADING] + " => " + BABYLON.GLTFLoaderState[BABYLON.GLTFLoaderState.COMPLETE];
+                    _this._parent._startPerformanceCounter(loadingToReadyCounterName);
+                    _this._parent._startPerformanceCounter(loadingToCompleteCounterName);
+                    _this._setState(BABYLON.GLTFLoaderState.LOADING);
+                    GLTF2.GLTFLoaderExtension._OnLoading(_this);
                     var promises = new Array();
                     if (nodes) {
                         promises.push(_this._loadSceneAsync("#/nodes", { nodes: nodes, _index: -1 }));
@@ -4019,33 +4073,33 @@ var BABYLON;
                         promises.push(_this._compileShadowGeneratorsAsync());
                     }
                     var resultPromise = Promise.all(promises).then(function () {
-                        _this._state = BABYLON.GLTFLoaderState.READY;
-                        _this._parent._log("Ready");
-                        readyDeferred.resolve();
+                        _this._setState(BABYLON.GLTFLoaderState.READY);
+                        GLTF2.GLTFLoaderExtension._OnReady(_this);
                         _this._startAnimations();
                     });
                     resultPromise.then(function () {
-                        _this._parent._endPerformanceCounter("Loading => Ready");
+                        _this._parent._endPerformanceCounter(loadingToReadyCounterName);
                         BABYLON.Tools.SetImmediate(function () {
                             if (!_this._disposed) {
                                 Promise.all(_this._completePromises).then(function () {
-                                    _this._parent._endPerformanceCounter("Loading => Complete");
-                                    _this._state = BABYLON.GLTFLoaderState.COMPLETE;
-                                    _this._parent._log("Complete");
+                                    _this._parent._endPerformanceCounter(loadingToCompleteCounterName);
+                                    _this._setState(BABYLON.GLTFLoaderState.COMPLETE);
                                     _this._parent.onCompleteObservable.notifyObservers(undefined);
                                     _this._parent.onCompleteObservable.clear();
                                     _this.dispose();
-                                }).catch(function (error) {
-                                    BABYLON.Tools.Error("glTF Loader: " + error.message);
+                                }, function (error) {
+                                    _this._parent.onErrorObservable.notifyObservers(error);
+                                    _this._parent.onErrorObservable.clear();
                                     _this.dispose();
                                 });
                             }
                         });
                     });
                     return resultPromise;
-                }).catch(function (error) {
+                }, function (error) {
                     if (!_this._disposed) {
-                        BABYLON.Tools.Error("glTF Loader: " + error.message);
+                        _this._parent.onErrorObservable.notifyObservers(error);
+                        _this._parent.onErrorObservable.clear();
                         _this.dispose();
                         throw error;
                     }
@@ -4121,6 +4175,10 @@ var BABYLON;
                     }
                 }
             };
+            GLTFLoader.prototype._setState = function (state) {
+                this._state = state;
+                this._parent._log(BABYLON.GLTFLoaderState[this._state]);
+            };
             GLTFLoader.prototype._createRootNode = function () {
                 this._rootBabylonMesh = new BABYLON.Mesh("__root__", this._babylonScene);
                 var rootNode = { _babylonMesh: this._rootBabylonMesh };
@@ -4611,6 +4669,10 @@ var BABYLON;
             };
             GLTFLoader.prototype._loadAnimationAsync = function (context, animation) {
                 var _this = this;
+                var promise = GLTF2.GLTFLoaderExtension._LoadAnimationAsync(this, context, animation);
+                if (promise) {
+                    return promise;
+                }
                 var babylonAnimationGroup = new BABYLON.AnimationGroup(animation.name || "animation" + animation._index, this._babylonScene);
                 animation._babylonAnimationGroup = babylonAnimationGroup;
                 var promises = new Array();
@@ -5375,6 +5437,15 @@ var BABYLON;
                 }
                 return null;
             };
+            GLTFLoader.prototype._forEachExtensions = function (action) {
+                for (var _i = 0, _a = GLTFLoader._ExtensionNames; _i < _a.length; _i++) {
+                    var name_6 = _a[_i];
+                    var extension = this._extensions[name_6];
+                    if (extension.enabled) {
+                        action(extension);
+                    }
+                }
+            };
             GLTFLoader._ExtensionNames = new Array();
             GLTFLoader._ExtensionFactories = {};
             return GLTFLoader;
@@ -5414,6 +5485,14 @@ var BABYLON;
             };
             // #region Overridable Methods
             /**
+             * Override this method to do work after the state changes to LOADING.
+             */
+            GLTFLoaderExtension.prototype._onLoading = function () { };
+            /**
+             * Override this method to do work after the state changes to READY.
+             */
+            GLTFLoaderExtension.prototype._onReady = function () { };
+            /**
              * Override this method to modify the default behavior for loading scenes.
              * @hidden
              */
@@ -5453,6 +5532,8 @@ var BABYLON;
              * @hidden
              */
             GLTFLoaderExtension.prototype._loadUriAsync = function (context, uri) { return null; };
+            /** Override this method to modify the default behavior for loading animations. */
+            GLTFLoaderExtension.prototype._loadAnimationAsync = function (context, animation) { return null; };
             // #endregion
             /**
              * Helper method called by a loader extension to load an glTF extension.
@@ -5501,6 +5582,20 @@ var BABYLON;
                 }
             };
             /**
+             * Helper method called by the loader after the state changes to LOADING.
+             * @hidden
+             */
+            GLTFLoaderExtension._OnLoading = function (loader) {
+                loader._forEachExtensions(function (extension) { return extension._onLoading(); });
+            };
+            /**
+             * Helper method called by the loader after the state changes to READY.
+             * @hidden
+             */
+            GLTFLoaderExtension._OnReady = function (loader) {
+                loader._forEachExtensions(function (extension) { return extension._onReady(); });
+            };
+            /**
              * Helper method called by the loader to allow extensions to override loading scenes.
              * @hidden
              */
@@ -5556,6 +5651,13 @@ var BABYLON;
             GLTFLoaderExtension._LoadUriAsync = function (loader, context, uri) {
                 return loader._applyExtensions(function (extension) { return extension._loadUriAsync(context, uri); });
             };
+            /**
+             * Helper method called by the loader to allow extensions to override loading animations.
+             * @hidden
+             */
+            GLTFLoaderExtension._LoadAnimationAsync = function (loader, context, animation) {
+                return loader._applyExtensions(function (extension) { return extension._loadAnimationAsync(context, animation); });
+            };
             return GLTFLoaderExtension;
         }());
         GLTF2.GLTFLoaderExtension = GLTFLoaderExtension;
@@ -5572,14 +5674,237 @@ var BABYLON;
     (function (GLTF2) {
         var Extensions;
         (function (Extensions) {
+            var NAME = "MSFT_audio_emitter";
+            /**
+             * [Specification](https://github.com/najadojo/glTF/tree/MSFT_audio_emitter/extensions/2.0/Vendor/MSFT_audio_emitter)
+             */
+            var MSFT_audio_emitter = /** @class */ (function (_super) {
+                __extends(MSFT_audio_emitter, _super);
+                function MSFT_audio_emitter() {
+                    var _this = _super !== null && _super.apply(this, arguments) || this;
+                    _this.name = NAME;
+                    return _this;
+                }
+                MSFT_audio_emitter.prototype._loadClipAsync = function (context, clip) {
+                    if (clip._objectURL) {
+                        return clip._objectURL;
+                    }
+                    var promise;
+                    if (clip.uri) {
+                        promise = this._loader._loadUriAsync(context, clip.uri);
+                    }
+                    else {
+                        var bufferView = GLTF2.GLTFLoader._GetProperty(context + "/bufferView", this._loader._gltf.bufferViews, clip.bufferView);
+                        promise = this._loader._loadBufferViewAsync("#/bufferViews/" + bufferView._index, bufferView);
+                    }
+                    clip._objectURL = promise.then(function (data) {
+                        return URL.createObjectURL(new Blob([data], { type: clip.mimeType }));
+                    });
+                    return clip._objectURL;
+                };
+                MSFT_audio_emitter.prototype._loadEmitterAsync = function (context, emitter) {
+                    var _this = this;
+                    emitter._babylonSounds = emitter._babylonSounds || [];
+                    if (!emitter._babylonData) {
+                        var clipPromises = new Array();
+                        var name_1 = emitter.name || "emitter" + emitter._index;
+                        var options_1 = {
+                            loop: false,
+                            autoplay: false,
+                            volume: emitter.volume == undefined ? 1 : emitter.volume,
+                        };
+                        GLTF2._ArrayItem.Assign(this._clips);
+                        var _loop_1 = function (i) {
+                            var clipContext = "#/extensions/" + NAME + "/clips";
+                            var clip = GLTF2.GLTFLoader._GetProperty(clipContext, this_1._clips, emitter.clips[i].clip);
+                            clipPromises.push(this_1._loadClipAsync(clipContext + "/" + emitter.clips[i].clip, clip).then(function (objectURL) {
+                                var sound = emitter._babylonSounds[i] = new BABYLON.Sound(name_1, objectURL, _this._loader._babylonScene, null, options_1);
+                                sound.refDistance = emitter.refDistance || 1;
+                                sound.maxDistance = emitter.maxDistance || 256;
+                                sound.rolloffFactor = emitter.rolloffFactor || 1;
+                                sound.distanceModel = emitter.distanceModel || 'exponential';
+                                sound._positionInEmitterSpace = true;
+                            }));
+                        };
+                        var this_1 = this;
+                        for (var i = 0; i < emitter.clips.length; i++) {
+                            _loop_1(i);
+                        }
+                        var promise = Promise.all(clipPromises).then(function () {
+                            var weights = emitter.clips.map(function (clip) { return clip.weight || 1; });
+                            var weightedSound = new BABYLON.WeightedSound(emitter.loop || false, emitter._babylonSounds, weights);
+                            if (emitter.innerAngle)
+                                weightedSound.directionalConeInnerAngle = 2 * BABYLON.Tools.ToDegrees(emitter.innerAngle);
+                            if (emitter.outerAngle)
+                                weightedSound.directionalConeOuterAngle = 2 * BABYLON.Tools.ToDegrees(emitter.outerAngle);
+                            if (emitter.volume)
+                                weightedSound.volume = emitter.volume;
+                            emitter._babylonData.sound = weightedSound;
+                        });
+                        emitter._babylonData = {
+                            loaded: promise
+                        };
+                    }
+                    return emitter._babylonData.loaded;
+                };
+                MSFT_audio_emitter.prototype._loadSceneAsync = function (context, scene) {
+                    var _this = this;
+                    return this._loadExtensionAsync(context, scene, function (extensionContext, extension) {
+                        return _this._loader._loadSceneAsync(context, scene).then(function () {
+                            var promises = new Array();
+                            GLTF2._ArrayItem.Assign(_this._emitters);
+                            for (var _i = 0, _a = extension.emitters; _i < _a.length; _i++) {
+                                var emitterIndex = _a[_i];
+                                var emitter = GLTF2.GLTFLoader._GetProperty(extensionContext + "/emitters", _this._emitters, emitterIndex);
+                                if (emitter.refDistance != undefined || emitter.maxDistance != undefined || emitter.rolloffFactor != undefined ||
+                                    emitter.distanceModel != undefined || emitter.innerAngle != undefined || emitter.outerAngle != undefined) {
+                                    throw new Error(extensionContext + ": Direction or Distance properties are not allowed on emitters attached to a scene");
+                                }
+                                promises.push(_this._loadEmitterAsync(extensionContext + "/emitters/" + emitter._index, emitter));
+                            }
+                            return Promise.all(promises).then(function () { });
+                        });
+                    });
+                };
+                MSFT_audio_emitter.prototype._loadNodeAsync = function (context, node) {
+                    var _this = this;
+                    return this._loadExtensionAsync(context, node, function (extensionContext, extension) {
+                        return _this._loader._loadNodeAsync(extensionContext, node).then(function () {
+                            var promises = new Array();
+                            GLTF2._ArrayItem.Assign(_this._emitters);
+                            var _loop_2 = function (emitterIndex) {
+                                var emitter = GLTF2.GLTFLoader._GetProperty(extensionContext + "/emitters", _this._emitters, emitterIndex);
+                                promises.push(_this._loadEmitterAsync(extensionContext + "/emitters/" + emitter._index, emitter).then(function () {
+                                    if (node._babylonMesh) {
+                                        for (var _i = 0, _a = emitter._babylonSounds; _i < _a.length; _i++) {
+                                            var sound = _a[_i];
+                                            sound.attachToMesh(node._babylonMesh);
+                                            if (emitter.innerAngle != undefined || emitter.outerAngle != undefined) {
+                                                sound.setLocalDirectionToMesh(new BABYLON.Vector3(0, 0, 1));
+                                                sound.setDirectionalCone(2 * BABYLON.Tools.ToDegrees(emitter.innerAngle == undefined ? Math.PI : emitter.innerAngle), 2 * BABYLON.Tools.ToDegrees(emitter.outerAngle == undefined ? Math.PI : emitter.outerAngle), 0);
+                                            }
+                                        }
+                                    }
+                                }));
+                            };
+                            for (var _i = 0, _a = extension.emitters; _i < _a.length; _i++) {
+                                var emitterIndex = _a[_i];
+                                _loop_2(emitterIndex);
+                            }
+                            return Promise.all(promises).then(function () { });
+                        });
+                    });
+                };
+                MSFT_audio_emitter.prototype._loadAnimationAsync = function (context, animation) {
+                    var _this = this;
+                    return this._loadExtensionAsync(context, animation, function (extensionContext, extension) {
+                        return _this._loader._loadAnimationAsync(extensionContext, animation).then(function () {
+                            var promises = new Array();
+                            var babylonAnimationGroup = animation._babylonAnimationGroup;
+                            GLTF2._ArrayItem.Assign(extension.events);
+                            for (var _i = 0, _a = extension.events; _i < _a.length; _i++) {
+                                var event_1 = _a[_i];
+                                promises.push(_this._loadAnimationEventAsync(extensionContext + "/events/" + event_1._index, context, animation, event_1, babylonAnimationGroup));
+                            }
+                            return Promise.all(promises).then(function () { });
+                        });
+                    });
+                };
+                MSFT_audio_emitter.prototype._getEventAction = function (context, sound, action, time, startOffset) {
+                    if (action == "play" /* play */) {
+                        return function (currentFrame) {
+                            var frameOffset = (startOffset || 0) + (currentFrame - time);
+                            sound.play(frameOffset);
+                        };
+                    }
+                    else if (action == "stop" /* stop */) {
+                        return function (currentFrame) {
+                            sound.stop();
+                        };
+                    }
+                    else if (action == "pause" /* pause */) {
+                        return function (currentFrame) {
+                            sound.pause();
+                        };
+                    }
+                    else {
+                        throw new Error(context + ": Unsupported action " + action);
+                    }
+                };
+                MSFT_audio_emitter.prototype._loadAnimationEventAsync = function (context, animationContext, animation, event, babylonAnimationGroup) {
+                    var _this = this;
+                    if (babylonAnimationGroup.targetedAnimations.length == 0) {
+                        return Promise.resolve();
+                    }
+                    var babylonAnimation = babylonAnimationGroup.targetedAnimations[0];
+                    var emitterIndex = event.emitter;
+                    var emitter = GLTF2.GLTFLoader._GetProperty("#/extensions/" + NAME + "/emitters", this._emitters, emitterIndex);
+                    return this._loadEmitterAsync(context, emitter).then(function () {
+                        var sound = emitter._babylonData.sound;
+                        if (sound) {
+                            var babylonAnimationEvent = new BABYLON.AnimationEvent(event.time, _this._getEventAction(context, sound, event.action, event.time, event.startOffset));
+                            babylonAnimation.animation.addEvent(babylonAnimationEvent);
+                            // Make sure all started audio stops when this animation is terminated.
+                            babylonAnimationGroup.onAnimationGroupEndObservable.add(function () {
+                                sound.stop();
+                            });
+                            babylonAnimationGroup.onAnimationGroupPauseObservable.add(function () {
+                                sound.pause();
+                            });
+                        }
+                    });
+                };
+                Object.defineProperty(MSFT_audio_emitter.prototype, "_extension", {
+                    get: function () {
+                        var extensions = this._loader._gltf.extensions;
+                        if (!extensions || !extensions[this.name]) {
+                            throw new Error("#/extensions: '" + this.name + "' not found");
+                        }
+                        return extensions[this.name];
+                    },
+                    enumerable: true,
+                    configurable: true
+                });
+                Object.defineProperty(MSFT_audio_emitter.prototype, "_clips", {
+                    get: function () {
+                        return this._extension.clips;
+                    },
+                    enumerable: true,
+                    configurable: true
+                });
+                Object.defineProperty(MSFT_audio_emitter.prototype, "_emitters", {
+                    get: function () {
+                        return this._extension.emitters;
+                    },
+                    enumerable: true,
+                    configurable: true
+                });
+                return MSFT_audio_emitter;
+            }(GLTF2.GLTFLoaderExtension));
+            Extensions.MSFT_audio_emitter = MSFT_audio_emitter;
+            GLTF2.GLTFLoader._Register(NAME, function (loader) { return new MSFT_audio_emitter(loader); });
+        })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
+    })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=MSFT_audio_emitter.js.map
+
+
+
+var BABYLON;
+(function (BABYLON) {
+    var GLTF2;
+    (function (GLTF2) {
+        var Extensions;
+        (function (Extensions) {
             var NAME = "MSFT_lod";
             /**
              * [Specification](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_lod)
              */
             var MSFT_lod = /** @class */ (function (_super) {
                 __extends(MSFT_lod, _super);
-                function MSFT_lod(loader) {
-                    var _this = _super.call(this, loader) || this;
+                function MSFT_lod() {
+                    var _this = _super !== null && _super.apply(this, arguments) || this;
                     _this.name = NAME;
                     /**
                      * Maximum number of LODs to load, starting from the lowest LOD.
@@ -5603,42 +5928,6 @@ var BABYLON;
                     _this._materialIndexLOD = null;
                     _this._materialSignalLODs = new Array();
                     _this._materialPromiseLODs = new Array();
-                    _this._loader._readyPromise.then(function () {
-                        var _loop_1 = function (indexLOD) {
-                            var promise = Promise.all(_this._nodePromiseLODs[indexLOD]).then(function () {
-                                if (indexLOD !== 0) {
-                                    _this._loader._parent._endPerformanceCounter("Node LOD " + indexLOD);
-                                }
-                                _this._loader._parent._log("Loaded node LOD " + indexLOD);
-                                _this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
-                                if (indexLOD !== _this._nodePromiseLODs.length - 1) {
-                                    _this._loader._parent._startPerformanceCounter("Node LOD " + (indexLOD + 1));
-                                    _this._nodeSignalLODs[indexLOD].resolve();
-                                }
-                            });
-                            _this._loader._completePromises.push(promise);
-                        };
-                        for (var indexLOD = 0; indexLOD < _this._nodePromiseLODs.length; indexLOD++) {
-                            _loop_1(indexLOD);
-                        }
-                        var _loop_2 = function (indexLOD) {
-                            var promise = Promise.all(_this._materialPromiseLODs[indexLOD]).then(function () {
-                                if (indexLOD !== 0) {
-                                    _this._loader._parent._endPerformanceCounter("Material LOD " + indexLOD);
-                                }
-                                _this._loader._parent._log("Loaded material LOD " + indexLOD);
-                                _this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
-                                if (indexLOD !== _this._materialPromiseLODs.length - 1) {
-                                    _this._loader._parent._startPerformanceCounter("Material LOD " + (indexLOD + 1));
-                                    _this._materialSignalLODs[indexLOD].resolve();
-                                }
-                            });
-                            _this._loader._completePromises.push(promise);
-                        };
-                        for (var indexLOD = 0; indexLOD < _this._materialPromiseLODs.length; indexLOD++) {
-                            _loop_2(indexLOD);
-                        }
-                    });
                     return _this;
                 }
                 MSFT_lod.prototype.dispose = function () {
@@ -5652,6 +5941,49 @@ var BABYLON;
                     this.onMaterialLODsLoadedObservable.clear();
                     this.onNodeLODsLoadedObservable.clear();
                 };
+                MSFT_lod.prototype._onReady = function () {
+                    var _this = this;
+                    var _loop_1 = function (indexLOD) {
+                        var promise = Promise.all(this_1._nodePromiseLODs[indexLOD]).then(function () {
+                            if (indexLOD !== 0) {
+                                _this._loader._parent._endPerformanceCounter("Node LOD " + indexLOD);
+                            }
+                            _this._loader._parent._log("Loaded node LOD " + indexLOD);
+                            _this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
+                            if (indexLOD !== _this._nodePromiseLODs.length - 1) {
+                                _this._loader._parent._startPerformanceCounter("Node LOD " + (indexLOD + 1));
+                                if (_this._nodeSignalLODs[indexLOD]) {
+                                    _this._nodeSignalLODs[indexLOD].resolve();
+                                }
+                            }
+                        });
+                        this_1._loader._completePromises.push(promise);
+                    };
+                    var this_1 = this;
+                    for (var indexLOD = 0; indexLOD < this._nodePromiseLODs.length; indexLOD++) {
+                        _loop_1(indexLOD);
+                    }
+                    var _loop_2 = function (indexLOD) {
+                        var promise = Promise.all(this_2._materialPromiseLODs[indexLOD]).then(function () {
+                            if (indexLOD !== 0) {
+                                _this._loader._parent._endPerformanceCounter("Material LOD " + indexLOD);
+                            }
+                            _this._loader._parent._log("Loaded material LOD " + indexLOD);
+                            _this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
+                            if (indexLOD !== _this._materialPromiseLODs.length - 1) {
+                                _this._loader._parent._startPerformanceCounter("Material LOD " + (indexLOD + 1));
+                                if (_this._materialSignalLODs[indexLOD]) {
+                                    _this._materialSignalLODs[indexLOD].resolve();
+                                }
+                            }
+                        });
+                        this_2._loader._completePromises.push(promise);
+                    };
+                    var this_2 = this;
+                    for (var indexLOD = 0; indexLOD < this._materialPromiseLODs.length; indexLOD++) {
+                        _loop_2(indexLOD);
+                    }
+                };
                 MSFT_lod.prototype._loadNodeAsync = function (context, node) {
                     var _this = this;
                     return this._loadExtensionAsync(context, node, function (extensionContext, extension) {
@@ -5858,23 +6190,25 @@ var BABYLON;
                     _this.name = NAME;
                     return _this;
                 }
-                MSFT_sRGBFactors.prototype._loadMaterialAsync = function (context, material, mesh, babylonMesh, babylonDrawMode, assign) {
+                MSFT_sRGBFactors.prototype._loadMaterialPropertiesAsync = function (context, material, babylonMaterial) {
                     var _this = this;
                     return this._loadExtrasValueAsync(context, material, function (extensionContext, value) {
                         if (value) {
-                            return _this._loader._loadMaterialAsync(context, material, mesh, babylonMesh, babylonDrawMode, function (babylonMaterial) {
-                                if (!babylonMaterial.albedoTexture) {
-                                    babylonMaterial.albedoColor.toLinearSpaceToRef(babylonMaterial.albedoColor);
-                                }
-                                if (!babylonMaterial.reflectivityTexture) {
-                                    babylonMaterial.reflectivityColor.toLinearSpaceToRef(babylonMaterial.reflectivityColor);
-                                }
-                                assign(babylonMaterial);
-                            });
+                            var promise = _this._loader._loadMaterialPropertiesAsync(context, material, babylonMaterial);
+                            _this._convertColorsToLinear(babylonMaterial);
+                            return promise;
                         }
                         return null;
                     });
                 };
+                MSFT_sRGBFactors.prototype._convertColorsToLinear = function (babylonMaterial) {
+                    if (!babylonMaterial.albedoTexture) {
+                        babylonMaterial.albedoColor.toLinearSpaceToRef(babylonMaterial.albedoColor);
+                    }
+                    if (!babylonMaterial.reflectivityTexture) {
+                        babylonMaterial.reflectivityColor.toLinearSpaceToRef(babylonMaterial.reflectivityColor);
+                    }
+                };
                 return MSFT_sRGBFactors;
             }(GLTF2.GLTFLoaderExtension));
             Extensions.MSFT_sRGBFactors = MSFT_sRGBFactors;
@@ -6101,8 +6435,6 @@ var BABYLON;
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
 })(BABYLON || (BABYLON = {}));
 
-//# sourceMappingURL=KHR_materials_unlit.js.map
-
 
 
 var BABYLON;
@@ -6129,6 +6461,13 @@ var BABYLON;
                     _this.name = NAME;
                     return _this;
                 }
+                KHR_lights.prototype._onLoading = function () {
+                    var extensions = this._loader._gltf.extensions;
+                    if (extensions && extensions[this.name]) {
+                        var extension = extensions[this.name];
+                        this._lights = extension.lights;
+                    }
+                };
                 KHR_lights.prototype._loadSceneAsync = function (context, scene) {
                     var _this = this;
                     return this._loadExtensionAsync(context, scene, function (extensionContext, extension) {
@@ -6177,18 +6516,6 @@ var BABYLON;
                         return promise;
                     });
                 };
-                Object.defineProperty(KHR_lights.prototype, "_lights", {
-                    get: function () {
-                        var extensions = this._loader._gltf.extensions;
-                        if (!extensions || !extensions[this.name]) {
-                            throw new Error("#/extensions: '" + this.name + "' not found");
-                        }
-                        var extension = extensions[this.name];
-                        return extension.lights;
-                    },
-                    enumerable: true,
-                    configurable: true
-                });
                 return KHR_lights;
             }(GLTF2.GLTFLoaderExtension));
             Extensions.KHR_lights = KHR_lights;
@@ -6268,6 +6595,13 @@ var BABYLON;
                     _this.name = NAME;
                     return _this;
                 }
+                EXT_lights_imageBased.prototype._onLoading = function () {
+                    var extensions = this._loader._gltf.extensions;
+                    if (extensions && extensions[this.name]) {
+                        var extension = extensions[this.name];
+                        this._lights = extension.lights;
+                    }
+                };
                 EXT_lights_imageBased.prototype._loadSceneAsync = function (context, scene) {
                     var _this = this;
                     return this._loadExtensionAsync(context, scene, function (extensionContext, extension) {
@@ -6337,18 +6671,6 @@ var BABYLON;
                         return light._babylonTexture;
                     });
                 };
-                Object.defineProperty(EXT_lights_imageBased.prototype, "_lights", {
-                    get: function () {
-                        var extensions = this._loader._gltf.extensions;
-                        if (!extensions || !extensions[this.name]) {
-                            throw new Error("#/extensions: '" + this.name + "' not found");
-                        }
-                        var extension = extensions[this.name];
-                        return extension.lights;
-                    },
-                    enumerable: true,
-                    configurable: true
-                });
                 return EXT_lights_imageBased;
             }(GLTF2.GLTFLoaderExtension));
             Extensions.EXT_lights_imageBased = EXT_lights_imageBased;

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


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

@@ -70,6 +70,7 @@ declare module BABYLON {
         facePattern2: RegExp;
         facePattern3: RegExp;
         facePattern4: RegExp;
+        facePattern5: RegExp;
         /**
          * Calls synchronously the MTL file attached to this obj.
          * Load function or importMesh function don't enable to load 2 files in the same time asynchronously.
@@ -299,9 +300,20 @@ declare module BABYLON {
         private _onCompleteObserver;
         /**
          * Callback 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 the loader resolves the returned promise.
          */
         onComplete: () => void;
         /**
+         * Observable raised when an error occurs.
+         */
+        readonly onErrorObservable: Observable<any>;
+        private _onErrorObserver;
+        /**
+         * Callback raised when an error occurs.
+         */
+        onError: (reason: any) => void;
+        /**
          * Observable raised after the loader is disposed.
          */
         readonly onDisposeObservable: Observable<void>;
@@ -1119,7 +1131,6 @@ declare module BABYLON.GLTF2 {
         _parent: GLTFFileLoader;
         _gltf: _ILoaderGLTF;
         _babylonScene: Scene;
-        _readyPromise: Promise<void>;
         _completePromises: Promise<void>[];
         private _disposed;
         private _state;
@@ -1133,9 +1144,6 @@ declare module BABYLON.GLTF2 {
         private static _ExtensionNames;
         private static _ExtensionFactories;
         static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void;
-        /**
-         * Loader state or null if the loader is not active.
-         */
         readonly state: Nullable<GLTFLoaderState>;
         constructor(parent: GLTFFileLoader);
         dispose(): void;
@@ -1151,6 +1159,7 @@ declare module BABYLON.GLTF2 {
         private _setupData();
         private _loadExtensions();
         private _checkExtensions();
+        private _setState(state);
         private _createRootNode();
         _loadSceneAsync(context: string, scene: _ILoaderScene): Promise<void>;
         private _forEachPrimitive(node, callback);
@@ -1174,7 +1183,7 @@ declare module BABYLON.GLTF2 {
         private _getNodeMatrix(node);
         private _loadCamera(context, camera, babylonMesh);
         private _loadAnimationsAsync();
-        private _loadAnimationAsync(context, animation);
+        _loadAnimationAsync(context: string, animation: _ILoaderAnimation): Promise<void>;
         private _loadAnimationChannelAsync(context, animationContext, animation, channel, babylonAnimationGroup);
         private _loadAnimationSamplerAsync(context, sampler);
         private _loadBufferAsync(context, buffer);
@@ -1206,6 +1215,7 @@ declare module BABYLON.GLTF2 {
         private _compileMaterialsAsync();
         private _compileShadowGeneratorsAsync();
         _applyExtensions<T>(actionAsync: (extension: GLTFLoaderExtension) => Nullable<Promise<T>>): Nullable<Promise<T>>;
+        _forEachExtensions(action: (extension: GLTFLoaderExtension) => void): void;
     }
 }
 
@@ -1234,6 +1244,14 @@ declare module BABYLON.GLTF2 {
          */
         dispose(): void;
         /**
+         * Override this method to do work after the state changes to LOADING.
+         */
+        protected _onLoading(): void;
+        /**
+         * Override this method to do work after the state changes to READY.
+         */
+        protected _onReady(): void;
+        /**
          * Override this method to modify the default behavior for loading scenes.
          * @hidden
          */
@@ -1273,6 +1291,8 @@ declare module BABYLON.GLTF2 {
          * @hidden
          */
         protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
+        /** Override this method to modify the default behavior for loading animations. */
+        protected _loadAnimationAsync(context: string, animation: _ILoaderAnimation): Nullable<Promise<void>>;
         /**
          * Helper method called by a loader extension to load an glTF extension.
          * @hidden
@@ -1284,6 +1304,16 @@ declare module BABYLON.GLTF2 {
          */
         protected _loadExtrasValueAsync<TProperty, TResult = void>(context: string, property: IProperty, actionAsync: (extensionContext: string, value: TProperty) => Nullable<Promise<TResult>>): Nullable<Promise<TResult>>;
         /**
+         * Helper method called by the loader after the state changes to LOADING.
+         * @hidden
+         */
+        static _OnLoading(loader: GLTFLoader): void;
+        /**
+         * Helper method called by the loader after the state changes to READY.
+         * @hidden
+         */
+        static _OnReady(loader: GLTFLoader): void;
+        /**
          * Helper method called by the loader to allow extensions to override loading scenes.
          * @hidden
          */
@@ -1323,6 +1353,11 @@ declare module BABYLON.GLTF2 {
          * @hidden
          */
         static _LoadUriAsync(loader: GLTFLoader, context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
+        /**
+         * Helper method called by the loader to allow extensions to override loading animations.
+         * @hidden
+         */
+        static _LoadAnimationAsync(loader: GLTFLoader, context: string, animation: _ILoaderAnimation): Nullable<Promise<void>>;
     }
 }
 /**
@@ -1334,6 +1369,26 @@ declare module BABYLON.GLTF2.Extensions {
 
 declare module BABYLON.GLTF2.Extensions {
     /**
+     * [Specification](https://github.com/najadojo/glTF/tree/MSFT_audio_emitter/extensions/2.0/Vendor/MSFT_audio_emitter)
+     */
+    class MSFT_audio_emitter extends GLTFLoaderExtension {
+        readonly name: string;
+        private _loadClipAsync(context, clip);
+        private _loadEmitterAsync(context, emitter);
+        protected _loadSceneAsync(context: string, scene: _ILoaderScene): Nullable<Promise<void>>;
+        protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
+        protected _loadAnimationAsync(context: string, animation: _ILoaderAnimation): Nullable<Promise<void>>;
+        private _getEventAction(context, sound, action, time, startOffset?);
+        private _loadAnimationEventAsync(context, animationContext, animation, event, babylonAnimationGroup);
+        private readonly _extension;
+        private readonly _clips;
+        private readonly _emitters;
+    }
+}
+
+
+declare module BABYLON.GLTF2.Extensions {
+    /**
      * [Specification](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_lod)
      */
     class MSFT_lod extends GLTFLoaderExtension {
@@ -1360,8 +1415,8 @@ declare module BABYLON.GLTF2.Extensions {
         private _materialIndexLOD;
         private _materialSignalLODs;
         private _materialPromiseLODs;
-        constructor(loader: GLTFLoader);
         dispose(): void;
+        protected _onReady(): void;
         protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
         protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
         protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
@@ -1387,7 +1442,8 @@ declare module BABYLON.GLTF2.Extensions {
     /** @hidden */
     class MSFT_sRGBFactors extends GLTFLoaderExtension {
         readonly name: string;
-        protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
+        protected _loadMaterialPropertiesAsync(context: string, material: _ILoaderMaterial, babylonMaterial: Material): Nullable<Promise<void>>;
+        private _convertColorsToLinear(babylonMaterial);
     }
 }
 
@@ -1436,9 +1492,10 @@ declare module BABYLON.GLTF2.Extensions {
      */
     class KHR_lights extends GLTFLoaderExtension {
         readonly name: string;
+        private _lights?;
+        protected _onLoading(): void;
         protected _loadSceneAsync(context: string, scene: _ILoaderScene): Nullable<Promise<void>>;
         protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
-        private readonly _lights;
     }
 }
 
@@ -1460,8 +1517,9 @@ declare module BABYLON.GLTF2.Extensions {
      */
     class EXT_lights_imageBased extends GLTFLoaderExtension {
         readonly name: string;
+        private _lights?;
+        protected _onLoading(): void;
         protected _loadSceneAsync(context: string, scene: _ILoaderScene): Nullable<Promise<void>>;
         private _loadLightAsync(context, light);
-        private readonly _lights;
     }
 }

+ 2 - 2
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.3.0-alpha.12",
+    "version": "3.3.0-alpha.13",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs-gltf2interface": "3.3.0-alpha.12"
+        "babylonjs-gltf2interface": "3.3.0-alpha.13"
     },
     "peerDependencies": {
         "babylonjs": ">=3.2.0-alpha"

+ 1 - 0
dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.d.ts

@@ -4,6 +4,7 @@ declare module BABYLON {
         private _renderId;
         private _activeLight;
         constructor(name: string, scene: Scene);
+        shadowColor: Color3;
         needAlphaBlending(): boolean;
         needAlphaTesting(): boolean;
         getAlphaTestTexture(): Nullable<BaseTexture>;

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


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


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

@@ -4,6 +4,7 @@ declare module BABYLON {
         private _renderId;
         private _activeLight;
         constructor(name: string, scene: Scene);
+        shadowColor: Color3;
         needAlphaBlending(): boolean;
         needAlphaTesting(): boolean;
         getAlphaTestTexture(): Nullable<BaseTexture>;

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


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


+ 1 - 0
dist/preview release/materialsLibrary/babylonjs.materials.module.d.ts

@@ -9,6 +9,7 @@ declare module BABYLON {
         private _renderId;
         private _activeLight;
         constructor(name: string, scene: Scene);
+        shadowColor: Color3;
         needAlphaBlending(): boolean;
         needAlphaTesting(): boolean;
         getAlphaTestTexture(): Nullable<BaseTexture>;

+ 1 - 1
dist/preview release/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.3.0-alpha.12",
+    "version": "3.3.0-alpha.13",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

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

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

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

+ 7 - 0
dist/preview release/serializers/babylon.glTF2Serializer.d.ts

@@ -521,6 +521,13 @@ declare module BABYLON.GLTF2 {
          */
         private _resizeTexturesToSameDimensions(texture1, texture2, scene);
         /**
+         * Converts an array of pixels to a Float32Array
+         * Throws an error if the pixel format is not supported
+         * @param pixels - array buffer containing pixel values
+         * @returns Float32 of pixels
+         */
+        private _convertPixelArrayToFloat32(pixels);
+        /**
          * Convert Specular Glossiness Textures to Metallic Roughness
          * See link below for info on the material conversions from PBR Metallic/Roughness and Specular/Glossiness
          * @link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/examples/convert-between-workflows-bjs/js/babylon.pbrUtilities.js

+ 113 - 91
dist/preview release/serializers/babylon.glTF2Serializer.js

@@ -1821,6 +1821,28 @@ var BABYLON;
                 };
             };
             /**
+             * Converts an array of pixels to a Float32Array
+             * Throws an error if the pixel format is not supported
+             * @param pixels - array buffer containing pixel values
+             * @returns Float32 of pixels
+             */
+            _GLTFMaterialExporter.prototype._convertPixelArrayToFloat32 = function (pixels) {
+                if (pixels instanceof Uint8Array) {
+                    var length_1 = pixels.length;
+                    var buffer = new Float32Array(pixels.length);
+                    for (var i = 0; i < length_1; ++i) {
+                        buffer[i] = pixels[i] / 255;
+                    }
+                    return buffer;
+                }
+                else if (pixels instanceof Float32Array) {
+                    return pixels;
+                }
+                else {
+                    throw new Error('Unsupported pixel format!');
+                }
+            };
+            /**
              * Convert Specular Glossiness Textures to Metallic Roughness
              * See link below for info on the material conversions from PBR Metallic/Roughness and Specular/Glossiness
              * @link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/examples/convert-between-workflows-bjs/js/babylon.pbrUtilities.js
@@ -1843,99 +1865,99 @@ var BABYLON;
                     var specularGlossinessBuffer = void 0;
                     var width = diffuseSize.width;
                     var height = diffuseSize.height;
-                    var pixels = (resizedTextures.texture1.readPixels());
-                    if (pixels instanceof Uint8Array) {
-                        diffuseBuffer = (resizedTextures.texture1.readPixels());
-                        pixels = resizedTextures.texture2.readPixels();
-                        if (pixels instanceof Uint8Array) {
-                            specularGlossinessBuffer = (resizedTextures.texture2.readPixels());
-                            var byteLength = specularGlossinessBuffer.byteLength;
-                            var metallicRoughnessBuffer = new Uint8Array(byteLength);
-                            var baseColorBuffer = new Uint8Array(byteLength);
-                            var strideSize = 4;
-                            var maxBaseColor = BABYLON.Color3.Black();
-                            var maxMetallic = 0;
-                            var maxRoughness = 0;
-                            for (var h = 0; h < height; ++h) {
-                                for (var w = 0; w < width; ++w) {
-                                    var offset = (width * h + w) * strideSize;
-                                    var diffuseColor = BABYLON.Color3.FromInts(diffuseBuffer[offset], diffuseBuffer[offset + 1], diffuseBuffer[offset + 2]).toLinearSpace().multiply(factors.diffuseColor);
-                                    var specularColor = BABYLON.Color3.FromInts(specularGlossinessBuffer[offset], specularGlossinessBuffer[offset + 1], specularGlossinessBuffer[offset + 2]).toLinearSpace().multiply(factors.specularColor);
-                                    var glossiness = (specularGlossinessBuffer[offset + 3] / 255) * factors.glossiness;
-                                    var specularGlossiness = {
-                                        diffuseColor: diffuseColor,
-                                        specularColor: specularColor,
-                                        glossiness: glossiness
-                                    };
-                                    var metallicRoughness = this._convertSpecularGlossinessToMetallicRoughness(specularGlossiness);
-                                    maxBaseColor.r = Math.max(maxBaseColor.r, metallicRoughness.baseColor.r);
-                                    maxBaseColor.g = Math.max(maxBaseColor.g, metallicRoughness.baseColor.g);
-                                    maxBaseColor.b = Math.max(maxBaseColor.b, metallicRoughness.baseColor.b);
-                                    maxMetallic = Math.max(maxMetallic, metallicRoughness.metallic);
-                                    maxRoughness = Math.max(maxRoughness, metallicRoughness.roughness);
-                                    baseColorBuffer[offset] = metallicRoughness.baseColor.r * 255;
-                                    baseColorBuffer[offset + 1] = metallicRoughness.baseColor.g * 255;
-                                    baseColorBuffer[offset + 2] = metallicRoughness.baseColor.b * 255;
-                                    baseColorBuffer[offset + 3] = resizedTextures.texture1.hasAlpha ? diffuseBuffer[offset + 3] : 255;
-                                    metallicRoughnessBuffer[offset] = 0;
-                                    metallicRoughnessBuffer[offset + 1] = metallicRoughness.roughness * 255;
-                                    metallicRoughnessBuffer[offset + 2] = metallicRoughness.metallic * 255;
-                                    metallicRoughnessBuffer[offset + 3] = 255;
-                                }
-                            }
-                            // Retrieves the metallic roughness factors from the maximum texture values.
-                            var metallicRoughnessFactors_1 = {
-                                baseColor: maxBaseColor,
-                                metallic: maxMetallic,
-                                roughness: maxRoughness
-                            };
-                            var writeOutMetallicRoughnessTexture = false;
-                            var writeOutBaseColorTexture = false;
-                            for (var h = 0; h < height; ++h) {
-                                for (var w = 0; w < width; ++w) {
-                                    var destinationOffset = (width * h + w) * strideSize;
-                                    baseColorBuffer[destinationOffset] /= metallicRoughnessFactors_1.baseColor.r > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.r : 1;
-                                    baseColorBuffer[destinationOffset + 1] /= metallicRoughnessFactors_1.baseColor.g > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.g : 1;
-                                    baseColorBuffer[destinationOffset + 2] /= metallicRoughnessFactors_1.baseColor.b > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.b : 1;
-                                    var linearBaseColorPixel = BABYLON.Color3.FromInts(baseColorBuffer[destinationOffset], baseColorBuffer[destinationOffset + 1], baseColorBuffer[destinationOffset + 2]);
-                                    var sRGBBaseColorPixel = linearBaseColorPixel.toGammaSpace();
-                                    baseColorBuffer[destinationOffset] = sRGBBaseColorPixel.r * 255;
-                                    baseColorBuffer[destinationOffset + 1] = sRGBBaseColorPixel.g * 255;
-                                    baseColorBuffer[destinationOffset + 2] = sRGBBaseColorPixel.b * 255;
-                                    if (!_GLTFMaterialExporter.FuzzyEquals(sRGBBaseColorPixel, BABYLON.Color3.White(), _GLTFMaterialExporter._Epsilon)) {
-                                        writeOutBaseColorTexture = true;
-                                    }
-                                    metallicRoughnessBuffer[destinationOffset + 1] /= metallicRoughnessFactors_1.roughness > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.roughness : 1;
-                                    metallicRoughnessBuffer[destinationOffset + 2] /= metallicRoughnessFactors_1.metallic > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.metallic : 1;
-                                    var metallicRoughnessPixel = BABYLON.Color3.FromInts(255, metallicRoughnessBuffer[destinationOffset + 1], metallicRoughnessBuffer[destinationOffset + 2]);
-                                    if (!_GLTFMaterialExporter.FuzzyEquals(metallicRoughnessPixel, BABYLON.Color3.White(), _GLTFMaterialExporter._Epsilon)) {
-                                        writeOutMetallicRoughnessTexture = true;
-                                    }
-                                }
-                            }
-                            if (writeOutMetallicRoughnessTexture) {
-                                var promise = this._createBase64FromCanvasAsync(metallicRoughnessBuffer, width, height, mimeType).then(function (metallicRoughnessBase64) {
-                                    metallicRoughnessFactors_1.metallicRoughnessTextureBase64 = metallicRoughnessBase64;
-                                });
-                                promises.push(promise);
-                            }
-                            if (writeOutBaseColorTexture) {
-                                var promise = this._createBase64FromCanvasAsync(baseColorBuffer, width, height, mimeType).then(function (baseColorBase64) {
-                                    metallicRoughnessFactors_1.baseColorTextureBase64 = baseColorBase64;
-                                });
-                                promises.push(promise);
-                            }
-                            return Promise.all(promises).then(function () {
-                                return metallicRoughnessFactors_1;
-                            });
-                        }
-                        else {
-                            return Promise.reject("_ConvertSpecularGlossinessTexturesToMetallicRoughness: Pixel array buffer type not supported for texture: " + resizedTextures.texture2.name);
-                        }
+                    var diffusePixels = resizedTextures.texture1.readPixels();
+                    var specularPixels = resizedTextures.texture2.readPixels();
+                    if (diffusePixels) {
+                        diffuseBuffer = this._convertPixelArrayToFloat32(diffusePixels);
                     }
                     else {
-                        return Promise.reject("_ConvertSpecularGlossinessTexturesToMetallicRoughness: Pixel array buffer type not supported for texture: " + resizedTextures.texture1.name);
+                        return Promise.reject("Failed to retrieve pixels from diffuse texture!");
                     }
+                    if (specularPixels) {
+                        specularGlossinessBuffer = this._convertPixelArrayToFloat32(specularPixels);
+                    }
+                    else {
+                        return Promise.reject("Failed to retrieve pixels from specular glossiness texture!");
+                    }
+                    var byteLength = specularGlossinessBuffer.byteLength;
+                    var metallicRoughnessBuffer = new Uint8Array(byteLength);
+                    var baseColorBuffer = new Uint8Array(byteLength);
+                    var strideSize = 4;
+                    var maxBaseColor = BABYLON.Color3.Black();
+                    var maxMetallic = 0;
+                    var maxRoughness = 0;
+                    for (var h = 0; h < height; ++h) {
+                        for (var w = 0; w < width; ++w) {
+                            var offset = (width * h + w) * strideSize;
+                            var diffuseColor = new BABYLON.Color3(diffuseBuffer[offset], diffuseBuffer[offset + 1], diffuseBuffer[offset + 2]).toLinearSpace().multiply(factors.diffuseColor);
+                            var specularColor = new BABYLON.Color3(specularGlossinessBuffer[offset], specularGlossinessBuffer[offset + 1], specularGlossinessBuffer[offset + 2]).toLinearSpace().multiply(factors.specularColor);
+                            var glossiness = (specularGlossinessBuffer[offset + 3]) * factors.glossiness;
+                            var specularGlossiness = {
+                                diffuseColor: diffuseColor,
+                                specularColor: specularColor,
+                                glossiness: glossiness
+                            };
+                            var metallicRoughness = this._convertSpecularGlossinessToMetallicRoughness(specularGlossiness);
+                            maxBaseColor.r = Math.max(maxBaseColor.r, metallicRoughness.baseColor.r);
+                            maxBaseColor.g = Math.max(maxBaseColor.g, metallicRoughness.baseColor.g);
+                            maxBaseColor.b = Math.max(maxBaseColor.b, metallicRoughness.baseColor.b);
+                            maxMetallic = Math.max(maxMetallic, metallicRoughness.metallic);
+                            maxRoughness = Math.max(maxRoughness, metallicRoughness.roughness);
+                            baseColorBuffer[offset] = metallicRoughness.baseColor.r * 255;
+                            baseColorBuffer[offset + 1] = metallicRoughness.baseColor.g * 255;
+                            baseColorBuffer[offset + 2] = metallicRoughness.baseColor.b * 255;
+                            baseColorBuffer[offset + 3] = resizedTextures.texture1.hasAlpha ? diffuseBuffer[offset + 3] * 255 : 255;
+                            metallicRoughnessBuffer[offset] = 0;
+                            metallicRoughnessBuffer[offset + 1] = metallicRoughness.roughness * 255;
+                            metallicRoughnessBuffer[offset + 2] = metallicRoughness.metallic * 255;
+                            metallicRoughnessBuffer[offset + 3] = 255;
+                        }
+                    }
+                    // Retrieves the metallic roughness factors from the maximum texture values.
+                    var metallicRoughnessFactors_1 = {
+                        baseColor: maxBaseColor,
+                        metallic: maxMetallic,
+                        roughness: maxRoughness
+                    };
+                    var writeOutMetallicRoughnessTexture = false;
+                    var writeOutBaseColorTexture = false;
+                    for (var h = 0; h < height; ++h) {
+                        for (var w = 0; w < width; ++w) {
+                            var destinationOffset = (width * h + w) * strideSize;
+                            baseColorBuffer[destinationOffset] /= metallicRoughnessFactors_1.baseColor.r > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.r : 1;
+                            baseColorBuffer[destinationOffset + 1] /= metallicRoughnessFactors_1.baseColor.g > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.g : 1;
+                            baseColorBuffer[destinationOffset + 2] /= metallicRoughnessFactors_1.baseColor.b > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.b : 1;
+                            var linearBaseColorPixel = BABYLON.Color3.FromInts(baseColorBuffer[destinationOffset], baseColorBuffer[destinationOffset + 1], baseColorBuffer[destinationOffset + 2]);
+                            var sRGBBaseColorPixel = linearBaseColorPixel.toGammaSpace();
+                            baseColorBuffer[destinationOffset] = sRGBBaseColorPixel.r * 255;
+                            baseColorBuffer[destinationOffset + 1] = sRGBBaseColorPixel.g * 255;
+                            baseColorBuffer[destinationOffset + 2] = sRGBBaseColorPixel.b * 255;
+                            if (!_GLTFMaterialExporter.FuzzyEquals(sRGBBaseColorPixel, BABYLON.Color3.White(), _GLTFMaterialExporter._Epsilon)) {
+                                writeOutBaseColorTexture = true;
+                            }
+                            metallicRoughnessBuffer[destinationOffset + 1] /= metallicRoughnessFactors_1.roughness > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.roughness : 1;
+                            metallicRoughnessBuffer[destinationOffset + 2] /= metallicRoughnessFactors_1.metallic > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.metallic : 1;
+                            var metallicRoughnessPixel = BABYLON.Color3.FromInts(255, metallicRoughnessBuffer[destinationOffset + 1], metallicRoughnessBuffer[destinationOffset + 2]);
+                            if (!_GLTFMaterialExporter.FuzzyEquals(metallicRoughnessPixel, BABYLON.Color3.White(), _GLTFMaterialExporter._Epsilon)) {
+                                writeOutMetallicRoughnessTexture = true;
+                            }
+                        }
+                    }
+                    if (writeOutMetallicRoughnessTexture) {
+                        var promise = this._createBase64FromCanvasAsync(metallicRoughnessBuffer, width, height, mimeType).then(function (metallicRoughnessBase64) {
+                            metallicRoughnessFactors_1.metallicRoughnessTextureBase64 = metallicRoughnessBase64;
+                        });
+                        promises.push(promise);
+                    }
+                    if (writeOutBaseColorTexture) {
+                        var promise = this._createBase64FromCanvasAsync(baseColorBuffer, width, height, mimeType).then(function (baseColorBase64) {
+                            metallicRoughnessFactors_1.baseColorTextureBase64 = baseColorBase64;
+                        });
+                        promises.push(promise);
+                    }
+                    return Promise.all(promises).then(function () {
+                        return metallicRoughnessFactors_1;
+                    });
                 }
                 else {
                     return Promise.reject("_ConvertSpecularGlossinessTexturesToMetallicRoughness: Scene from textures is missing!");
@@ -2363,7 +2385,7 @@ var BABYLON;
                 var binStr = atob(base64Texture.split(',')[1]);
                 var arrBuff = new ArrayBuffer(binStr.length);
                 var arr = new Uint8Array(arrBuff);
-                for (var i = 0, length_1 = binStr.length; i < length_1; ++i) {
+                for (var i = 0, length_2 = binStr.length; i < length_2; ++i) {
                     arr[i] = binStr.charCodeAt(i);
                 }
                 var imageValues = { data: arr, mimeType: mimeType };

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


+ 7 - 0
dist/preview release/serializers/babylonjs.serializers.d.ts

@@ -529,6 +529,13 @@ declare module BABYLON.GLTF2 {
          */
         private _resizeTexturesToSameDimensions(texture1, texture2, scene);
         /**
+         * Converts an array of pixels to a Float32Array
+         * Throws an error if the pixel format is not supported
+         * @param pixels - array buffer containing pixel values
+         * @returns Float32 of pixels
+         */
+        private _convertPixelArrayToFloat32(pixels);
+        /**
          * Convert Specular Glossiness Textures to Metallic Roughness
          * See link below for info on the material conversions from PBR Metallic/Roughness and Specular/Glossiness
          * @link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/examples/convert-between-workflows-bjs/js/babylon.pbrUtilities.js

+ 113 - 91
dist/preview release/serializers/babylonjs.serializers.js

@@ -1982,6 +1982,28 @@ var BABYLON;
                 };
             };
             /**
+             * Converts an array of pixels to a Float32Array
+             * Throws an error if the pixel format is not supported
+             * @param pixels - array buffer containing pixel values
+             * @returns Float32 of pixels
+             */
+            _GLTFMaterialExporter.prototype._convertPixelArrayToFloat32 = function (pixels) {
+                if (pixels instanceof Uint8Array) {
+                    var length_1 = pixels.length;
+                    var buffer = new Float32Array(pixels.length);
+                    for (var i = 0; i < length_1; ++i) {
+                        buffer[i] = pixels[i] / 255;
+                    }
+                    return buffer;
+                }
+                else if (pixels instanceof Float32Array) {
+                    return pixels;
+                }
+                else {
+                    throw new Error('Unsupported pixel format!');
+                }
+            };
+            /**
              * Convert Specular Glossiness Textures to Metallic Roughness
              * See link below for info on the material conversions from PBR Metallic/Roughness and Specular/Glossiness
              * @link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/examples/convert-between-workflows-bjs/js/babylon.pbrUtilities.js
@@ -2004,99 +2026,99 @@ var BABYLON;
                     var specularGlossinessBuffer = void 0;
                     var width = diffuseSize.width;
                     var height = diffuseSize.height;
-                    var pixels = (resizedTextures.texture1.readPixels());
-                    if (pixels instanceof Uint8Array) {
-                        diffuseBuffer = (resizedTextures.texture1.readPixels());
-                        pixels = resizedTextures.texture2.readPixels();
-                        if (pixels instanceof Uint8Array) {
-                            specularGlossinessBuffer = (resizedTextures.texture2.readPixels());
-                            var byteLength = specularGlossinessBuffer.byteLength;
-                            var metallicRoughnessBuffer = new Uint8Array(byteLength);
-                            var baseColorBuffer = new Uint8Array(byteLength);
-                            var strideSize = 4;
-                            var maxBaseColor = BABYLON.Color3.Black();
-                            var maxMetallic = 0;
-                            var maxRoughness = 0;
-                            for (var h = 0; h < height; ++h) {
-                                for (var w = 0; w < width; ++w) {
-                                    var offset = (width * h + w) * strideSize;
-                                    var diffuseColor = BABYLON.Color3.FromInts(diffuseBuffer[offset], diffuseBuffer[offset + 1], diffuseBuffer[offset + 2]).toLinearSpace().multiply(factors.diffuseColor);
-                                    var specularColor = BABYLON.Color3.FromInts(specularGlossinessBuffer[offset], specularGlossinessBuffer[offset + 1], specularGlossinessBuffer[offset + 2]).toLinearSpace().multiply(factors.specularColor);
-                                    var glossiness = (specularGlossinessBuffer[offset + 3] / 255) * factors.glossiness;
-                                    var specularGlossiness = {
-                                        diffuseColor: diffuseColor,
-                                        specularColor: specularColor,
-                                        glossiness: glossiness
-                                    };
-                                    var metallicRoughness = this._convertSpecularGlossinessToMetallicRoughness(specularGlossiness);
-                                    maxBaseColor.r = Math.max(maxBaseColor.r, metallicRoughness.baseColor.r);
-                                    maxBaseColor.g = Math.max(maxBaseColor.g, metallicRoughness.baseColor.g);
-                                    maxBaseColor.b = Math.max(maxBaseColor.b, metallicRoughness.baseColor.b);
-                                    maxMetallic = Math.max(maxMetallic, metallicRoughness.metallic);
-                                    maxRoughness = Math.max(maxRoughness, metallicRoughness.roughness);
-                                    baseColorBuffer[offset] = metallicRoughness.baseColor.r * 255;
-                                    baseColorBuffer[offset + 1] = metallicRoughness.baseColor.g * 255;
-                                    baseColorBuffer[offset + 2] = metallicRoughness.baseColor.b * 255;
-                                    baseColorBuffer[offset + 3] = resizedTextures.texture1.hasAlpha ? diffuseBuffer[offset + 3] : 255;
-                                    metallicRoughnessBuffer[offset] = 0;
-                                    metallicRoughnessBuffer[offset + 1] = metallicRoughness.roughness * 255;
-                                    metallicRoughnessBuffer[offset + 2] = metallicRoughness.metallic * 255;
-                                    metallicRoughnessBuffer[offset + 3] = 255;
-                                }
-                            }
-                            // Retrieves the metallic roughness factors from the maximum texture values.
-                            var metallicRoughnessFactors_1 = {
-                                baseColor: maxBaseColor,
-                                metallic: maxMetallic,
-                                roughness: maxRoughness
-                            };
-                            var writeOutMetallicRoughnessTexture = false;
-                            var writeOutBaseColorTexture = false;
-                            for (var h = 0; h < height; ++h) {
-                                for (var w = 0; w < width; ++w) {
-                                    var destinationOffset = (width * h + w) * strideSize;
-                                    baseColorBuffer[destinationOffset] /= metallicRoughnessFactors_1.baseColor.r > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.r : 1;
-                                    baseColorBuffer[destinationOffset + 1] /= metallicRoughnessFactors_1.baseColor.g > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.g : 1;
-                                    baseColorBuffer[destinationOffset + 2] /= metallicRoughnessFactors_1.baseColor.b > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.b : 1;
-                                    var linearBaseColorPixel = BABYLON.Color3.FromInts(baseColorBuffer[destinationOffset], baseColorBuffer[destinationOffset + 1], baseColorBuffer[destinationOffset + 2]);
-                                    var sRGBBaseColorPixel = linearBaseColorPixel.toGammaSpace();
-                                    baseColorBuffer[destinationOffset] = sRGBBaseColorPixel.r * 255;
-                                    baseColorBuffer[destinationOffset + 1] = sRGBBaseColorPixel.g * 255;
-                                    baseColorBuffer[destinationOffset + 2] = sRGBBaseColorPixel.b * 255;
-                                    if (!_GLTFMaterialExporter.FuzzyEquals(sRGBBaseColorPixel, BABYLON.Color3.White(), _GLTFMaterialExporter._Epsilon)) {
-                                        writeOutBaseColorTexture = true;
-                                    }
-                                    metallicRoughnessBuffer[destinationOffset + 1] /= metallicRoughnessFactors_1.roughness > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.roughness : 1;
-                                    metallicRoughnessBuffer[destinationOffset + 2] /= metallicRoughnessFactors_1.metallic > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.metallic : 1;
-                                    var metallicRoughnessPixel = BABYLON.Color3.FromInts(255, metallicRoughnessBuffer[destinationOffset + 1], metallicRoughnessBuffer[destinationOffset + 2]);
-                                    if (!_GLTFMaterialExporter.FuzzyEquals(metallicRoughnessPixel, BABYLON.Color3.White(), _GLTFMaterialExporter._Epsilon)) {
-                                        writeOutMetallicRoughnessTexture = true;
-                                    }
-                                }
-                            }
-                            if (writeOutMetallicRoughnessTexture) {
-                                var promise = this._createBase64FromCanvasAsync(metallicRoughnessBuffer, width, height, mimeType).then(function (metallicRoughnessBase64) {
-                                    metallicRoughnessFactors_1.metallicRoughnessTextureBase64 = metallicRoughnessBase64;
-                                });
-                                promises.push(promise);
-                            }
-                            if (writeOutBaseColorTexture) {
-                                var promise = this._createBase64FromCanvasAsync(baseColorBuffer, width, height, mimeType).then(function (baseColorBase64) {
-                                    metallicRoughnessFactors_1.baseColorTextureBase64 = baseColorBase64;
-                                });
-                                promises.push(promise);
-                            }
-                            return Promise.all(promises).then(function () {
-                                return metallicRoughnessFactors_1;
-                            });
-                        }
-                        else {
-                            return Promise.reject("_ConvertSpecularGlossinessTexturesToMetallicRoughness: Pixel array buffer type not supported for texture: " + resizedTextures.texture2.name);
-                        }
+                    var diffusePixels = resizedTextures.texture1.readPixels();
+                    var specularPixels = resizedTextures.texture2.readPixels();
+                    if (diffusePixels) {
+                        diffuseBuffer = this._convertPixelArrayToFloat32(diffusePixels);
                     }
                     else {
-                        return Promise.reject("_ConvertSpecularGlossinessTexturesToMetallicRoughness: Pixel array buffer type not supported for texture: " + resizedTextures.texture1.name);
+                        return Promise.reject("Failed to retrieve pixels from diffuse texture!");
                     }
+                    if (specularPixels) {
+                        specularGlossinessBuffer = this._convertPixelArrayToFloat32(specularPixels);
+                    }
+                    else {
+                        return Promise.reject("Failed to retrieve pixels from specular glossiness texture!");
+                    }
+                    var byteLength = specularGlossinessBuffer.byteLength;
+                    var metallicRoughnessBuffer = new Uint8Array(byteLength);
+                    var baseColorBuffer = new Uint8Array(byteLength);
+                    var strideSize = 4;
+                    var maxBaseColor = BABYLON.Color3.Black();
+                    var maxMetallic = 0;
+                    var maxRoughness = 0;
+                    for (var h = 0; h < height; ++h) {
+                        for (var w = 0; w < width; ++w) {
+                            var offset = (width * h + w) * strideSize;
+                            var diffuseColor = new BABYLON.Color3(diffuseBuffer[offset], diffuseBuffer[offset + 1], diffuseBuffer[offset + 2]).toLinearSpace().multiply(factors.diffuseColor);
+                            var specularColor = new BABYLON.Color3(specularGlossinessBuffer[offset], specularGlossinessBuffer[offset + 1], specularGlossinessBuffer[offset + 2]).toLinearSpace().multiply(factors.specularColor);
+                            var glossiness = (specularGlossinessBuffer[offset + 3]) * factors.glossiness;
+                            var specularGlossiness = {
+                                diffuseColor: diffuseColor,
+                                specularColor: specularColor,
+                                glossiness: glossiness
+                            };
+                            var metallicRoughness = this._convertSpecularGlossinessToMetallicRoughness(specularGlossiness);
+                            maxBaseColor.r = Math.max(maxBaseColor.r, metallicRoughness.baseColor.r);
+                            maxBaseColor.g = Math.max(maxBaseColor.g, metallicRoughness.baseColor.g);
+                            maxBaseColor.b = Math.max(maxBaseColor.b, metallicRoughness.baseColor.b);
+                            maxMetallic = Math.max(maxMetallic, metallicRoughness.metallic);
+                            maxRoughness = Math.max(maxRoughness, metallicRoughness.roughness);
+                            baseColorBuffer[offset] = metallicRoughness.baseColor.r * 255;
+                            baseColorBuffer[offset + 1] = metallicRoughness.baseColor.g * 255;
+                            baseColorBuffer[offset + 2] = metallicRoughness.baseColor.b * 255;
+                            baseColorBuffer[offset + 3] = resizedTextures.texture1.hasAlpha ? diffuseBuffer[offset + 3] * 255 : 255;
+                            metallicRoughnessBuffer[offset] = 0;
+                            metallicRoughnessBuffer[offset + 1] = metallicRoughness.roughness * 255;
+                            metallicRoughnessBuffer[offset + 2] = metallicRoughness.metallic * 255;
+                            metallicRoughnessBuffer[offset + 3] = 255;
+                        }
+                    }
+                    // Retrieves the metallic roughness factors from the maximum texture values.
+                    var metallicRoughnessFactors_1 = {
+                        baseColor: maxBaseColor,
+                        metallic: maxMetallic,
+                        roughness: maxRoughness
+                    };
+                    var writeOutMetallicRoughnessTexture = false;
+                    var writeOutBaseColorTexture = false;
+                    for (var h = 0; h < height; ++h) {
+                        for (var w = 0; w < width; ++w) {
+                            var destinationOffset = (width * h + w) * strideSize;
+                            baseColorBuffer[destinationOffset] /= metallicRoughnessFactors_1.baseColor.r > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.r : 1;
+                            baseColorBuffer[destinationOffset + 1] /= metallicRoughnessFactors_1.baseColor.g > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.g : 1;
+                            baseColorBuffer[destinationOffset + 2] /= metallicRoughnessFactors_1.baseColor.b > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.baseColor.b : 1;
+                            var linearBaseColorPixel = BABYLON.Color3.FromInts(baseColorBuffer[destinationOffset], baseColorBuffer[destinationOffset + 1], baseColorBuffer[destinationOffset + 2]);
+                            var sRGBBaseColorPixel = linearBaseColorPixel.toGammaSpace();
+                            baseColorBuffer[destinationOffset] = sRGBBaseColorPixel.r * 255;
+                            baseColorBuffer[destinationOffset + 1] = sRGBBaseColorPixel.g * 255;
+                            baseColorBuffer[destinationOffset + 2] = sRGBBaseColorPixel.b * 255;
+                            if (!_GLTFMaterialExporter.FuzzyEquals(sRGBBaseColorPixel, BABYLON.Color3.White(), _GLTFMaterialExporter._Epsilon)) {
+                                writeOutBaseColorTexture = true;
+                            }
+                            metallicRoughnessBuffer[destinationOffset + 1] /= metallicRoughnessFactors_1.roughness > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.roughness : 1;
+                            metallicRoughnessBuffer[destinationOffset + 2] /= metallicRoughnessFactors_1.metallic > _GLTFMaterialExporter._Epsilon ? metallicRoughnessFactors_1.metallic : 1;
+                            var metallicRoughnessPixel = BABYLON.Color3.FromInts(255, metallicRoughnessBuffer[destinationOffset + 1], metallicRoughnessBuffer[destinationOffset + 2]);
+                            if (!_GLTFMaterialExporter.FuzzyEquals(metallicRoughnessPixel, BABYLON.Color3.White(), _GLTFMaterialExporter._Epsilon)) {
+                                writeOutMetallicRoughnessTexture = true;
+                            }
+                        }
+                    }
+                    if (writeOutMetallicRoughnessTexture) {
+                        var promise = this._createBase64FromCanvasAsync(metallicRoughnessBuffer, width, height, mimeType).then(function (metallicRoughnessBase64) {
+                            metallicRoughnessFactors_1.metallicRoughnessTextureBase64 = metallicRoughnessBase64;
+                        });
+                        promises.push(promise);
+                    }
+                    if (writeOutBaseColorTexture) {
+                        var promise = this._createBase64FromCanvasAsync(baseColorBuffer, width, height, mimeType).then(function (baseColorBase64) {
+                            metallicRoughnessFactors_1.baseColorTextureBase64 = baseColorBase64;
+                        });
+                        promises.push(promise);
+                    }
+                    return Promise.all(promises).then(function () {
+                        return metallicRoughnessFactors_1;
+                    });
                 }
                 else {
                     return Promise.reject("_ConvertSpecularGlossinessTexturesToMetallicRoughness: Scene from textures is missing!");
@@ -2524,7 +2546,7 @@ var BABYLON;
                 var binStr = atob(base64Texture.split(',')[1]);
                 var arrBuff = new ArrayBuffer(binStr.length);
                 var arr = new Uint8Array(arrBuff);
-                for (var i = 0, length_1 = binStr.length; i < length_1; ++i) {
+                for (var i = 0, length_2 = binStr.length; i < length_2; ++i) {
                     arr[i] = binStr.charCodeAt(i);
                 }
                 var imageValues = { data: arr, mimeType: mimeType };

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


+ 7 - 0
dist/preview release/serializers/babylonjs.serializers.module.d.ts

@@ -536,6 +536,13 @@ declare module BABYLON.GLTF2 {
          */
         private _resizeTexturesToSameDimensions(texture1, texture2, scene);
         /**
+         * Converts an array of pixels to a Float32Array
+         * Throws an error if the pixel format is not supported
+         * @param pixels - array buffer containing pixel values
+         * @returns Float32 of pixels
+         */
+        private _convertPixelArrayToFloat32(pixels);
+        /**
          * Convert Specular Glossiness Textures to Metallic Roughness
          * See link below for info on the material conversions from PBR Metallic/Roughness and Specular/Glossiness
          * @link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/examples/convert-between-workflows-bjs/js/babylon.pbrUtilities.js

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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-serializers",
     "description": "The Babylon.js serializers library is an extension you can use to serialize Babylon scenes.",
-    "version": "3.3.0-alpha.12",
+    "version": "3.3.0-alpha.13",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs-gltf2interface": "3.3.0-alpha.12"
+        "babylonjs-gltf2interface": "3.3.0-alpha.13"
     },
     "peerDependencies": {
         "babylonjs": ">=3.2.0-alpha"

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

@@ -1,7 +1,7 @@
 {
-  "errors": 4239,
+  "errors": 4222,
   "babylon.typedoc.json": {
-    "errors": 4239,
+    "errors": 4222,
     "AbstractMesh": {
       "Property": {
         "showBoundingBox": {
@@ -2930,11 +2930,6 @@
             "MissingText": true
           }
         },
-        "getTranformationMatrix": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
         "getViewMatrix": {
           "Comments": {
             "MissingText": true
@@ -14147,98 +14142,6 @@
         }
       }
     },
-    "ReflectionProbe": {
-      "Class": {
-        "Comments": {
-          "MissingText": true
-        }
-      },
-      "Constructor": {
-        "new ReflectionProbe": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "name": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "size": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "scene": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "generateMipMaps": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        }
-      },
-      "Property": {
-        "cubeTexture": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "name": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "position": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "refreshRate": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "renderList": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "samples": {
-          "Comments": {
-            "MissingText": true
-          }
-        }
-      },
-      "Method": {
-        "attachToMesh": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "mesh": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "dispose": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "getScene": {
-          "Comments": {
-            "MissingText": true
-          }
-        }
-      }
-    },
     "RefractionPostProcess": {
       "Class": {
         "Comments": {

+ 109 - 240
dist/preview release/viewer/babylon.viewer.d.ts

@@ -2,46 +2,24 @@
 /// <reference path="./babylon.glTF2Interface.d.ts"/>
 /// <reference path="./babylonjs.loaders.d.ts"/>
 declare module "babylonjs-loaders"{ export=BABYLON;}
-
 // Generated by dts-bundle v0.7.3
 // Dependencies for this module:
-//   ../../../../Tools/Gulp/babylonjs
-//   ../../../../Tools/Gulp/babylonjs-loaders
-
+//   ../../../../../Tools/Gulp/babylonjs
+//   ../../../../../Tools/Gulp/babylonjs-loaders
 declare module BabylonViewer {
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
     /**
         * BabylonJS Viewer
         *
         * An HTML-Based viewer for 3D models, based on BabylonJS and its extensions.
         */
-    
-    
-    import 'pepjs';
-    
     let disableInit: boolean;
     /**
         * Dispose all viewers currently registered
         */
     function disposeAll(): void;
     const Version: string;
-    
-    export * from 'babylonjs-viewer/configuration';
 }
-
 declare module BabylonViewer {
-    
     /**
         * This is the mapper's interface. Implement this function to create your own mapper and register it at the mapper manager
         */
@@ -83,7 +61,6 @@ declare module BabylonViewer {
         */
     export let mapperManager: MapperManager;
 }
-
 declare module BabylonViewer {
     export class ViewerGlobals {
         disableInit: boolean;
@@ -92,10 +69,7 @@ declare module BabylonViewer {
     }
     export let viewerGlobals: ViewerGlobals;
 }
-
 declare module BabylonViewer {
-    
-    
     /**
         * The viewer manager is the container for all viewers currently registered on this page.
         * It is possible to have more than one viewer on a single page.
@@ -148,13 +122,7 @@ declare module BabylonViewer {
     }
     export let viewerManager: ViewerManager;
 }
-
 declare module BabylonViewer {
-    
-    
-    
-    
-    
     /**
         * The Default viewer is the default implementation of the AbstractViewer.
         * It uses the templating system to render a new canvas and controls.
@@ -173,7 +141,7 @@ declare module BabylonViewer {
                 * This will be executed when the templates initialize.
                 */
             protected _onTemplatesLoaded(): Promise<AbstractViewer>;
-            toggleVR(): void;
+            protected _initVR(): void;
             /**
                 * Toggle fullscreen of the entire viewer
                 */
@@ -230,17 +198,7 @@ declare module BabylonViewer {
             protected _onConfigurationLoaded(configuration: ViewerConfiguration): void;
     }
 }
-
 declare module BabylonViewer {
-    
-    
-    
-    
-    
-    
-    
-    
-    
     /**
         * The AbstractViewr is the center of Babylon's viewer.
         * It is the basic implementation of the default viewer and is responsible of loading and showing the model and the templates
@@ -359,8 +317,8 @@ declare module BabylonViewer {
                 */
             isCanvasInDOM(): boolean;
             /**
-                * Set the viewer's background rendering flag.
-                */
+             * Set the viewer's background rendering flag.
+             */
             renderInBackground: boolean;
             /**
                 * Get the configuration object. This is a reference only.
@@ -376,7 +334,9 @@ declare module BabylonViewer {
             toggleHD(): void;
             protected _vrToggled: boolean;
             protected _vrScale: number;
+            protected _vrInit: boolean;
             toggleVR(): void;
+            protected _initVR(): void;
             /**
                 * The resize function that will be registered with the window object
                 */
@@ -468,9 +428,7 @@ declare module BabylonViewer {
             protected _injectCustomShaders(): void;
     }
 }
-
 declare module BabylonViewer {
-    
     /**
         * The data structure of a telemetry event.
         */
@@ -515,13 +473,7 @@ declare module BabylonViewer {
     }
     export const telemetryManager: TelemetryManager;
 }
-
 declare module BabylonViewer {
-    
-    
-    
-    
-    
     /**
         * An instance of the class is in charge of loading the model correctly.
         * This class will continously be expended with tasks required from the specific loaders Babylon has.
@@ -554,14 +506,7 @@ declare module BabylonViewer {
             dispose(): void;
     }
 }
-
 declare module BabylonViewer {
-    
-    
-    
-    
-    
-    
     /**
         * The current state of the model
         */
@@ -573,7 +518,7 @@ declare module BabylonViewer {
             ENTRYDONE = 4,
             COMPLETE = 5,
             CANCELED = 6,
-            ERROR = 7,
+            ERROR = 7
     }
     /**
         * The viewer model is a container for all assets representing a sngle loaded model.
@@ -638,8 +583,8 @@ declare module BabylonViewer {
             shadowsRenderedAfterLoad: boolean;
             getViewerId(): string | undefined;
             /**
-                * Set whether this model is enabled or not.
-                */
+             * Set whether this model is enabled or not.
+             */
             enabled: boolean;
             loaderDone: boolean;
             /**
@@ -655,9 +600,9 @@ declare module BabylonViewer {
                 */
             readonly meshes: BABYLON.AbstractMesh[];
             /**
-                * (Re-)set the model's entire configuration
-                * @param newConfiguration the new configuration to replace the new one
-                */
+             * (Re-)set the model's entire configuration
+             * @param newConfiguration the new configuration to replace the new one
+             */
             configuration: IModelConfiguration;
             /**
                 * Update the current configuration with new values.
@@ -719,15 +664,13 @@ declare module BabylonViewer {
             dispose(): void;
     }
 }
-
 declare module BabylonViewer {
-    
     /**
         * BABYLON.Animation play mode enum - is the animation looping or playing once
         */
     export const enum AnimationPlayMode {
             ONCE = 0,
-            LOOP = 1,
+            LOOP = 1
     }
     /**
         * An enum representing the current state of an animation object
@@ -737,7 +680,7 @@ declare module BabylonViewer {
             PLAYING = 1,
             PAUSED = 2,
             STOPPED = 3,
-            ENDED = 4,
+            ENDED = 4
     }
     /**
         * The different type of easing functions available
@@ -754,7 +697,7 @@ declare module BabylonViewer {
             QuadraticEase = 8,
             QuarticEase = 9,
             QuinticEase = 10,
-            SineEase = 11,
+            SineEase = 11
     }
     /**
         * Defines a simple animation to be applied to a model (scale).
@@ -867,8 +810,8 @@ declare module BabylonViewer {
                 */
             readonly state: AnimationState;
             /**
-                * Sets the speed ratio to use for all animations
-                */
+             * Sets the speed ratio to use for all animations
+             */
             speedRatio: number;
             /**
                 * Get the max numbers of frame available in the animation group
@@ -888,10 +831,10 @@ declare module BabylonViewer {
                 */
             readonly fps: number;
             /**
-                * Set the play mode.
-                * If the animation is played, it will continue playing at least once more, depending on the new play mode set.
-                * If the animation is not set, the will be initialized and will wait for the user to start playing it.
-                */
+             * Set the play mode.
+             * If the animation is played, it will continue playing at least once more, depending on the new play mode set.
+             * If the animation is not set, the will be initialized and will wait for the user to start playing it.
+             */
             playMode: AnimationPlayMode;
             /**
                 * Reset the animation group
@@ -925,11 +868,7 @@ declare module BabylonViewer {
             dispose(): void;
     }
 }
-
 declare module BabylonViewer {
-    
-    
-    
     /**
       * This interface defines the structure of a loader plugin.
       * Any of those functions will be called if (!) the loader supports those callbacks.
@@ -948,9 +887,7 @@ declare module BabylonViewer {
         onComplete?: () => void;
     }
 }
-
 declare module BabylonViewer {
-    
     export interface IViewerTemplatePlugin {
         readonly templateName: string;
         readonly eventsToAttach?: Array<string>;
@@ -972,9 +909,7 @@ declare module BabylonViewer {
         protected _generateHTMLElement(template: Template): Element | DocumentFragment;
     }
 }
-
 declare module BabylonViewer {
-    
     /**
       *
       * @param name the name of the custom optimizer configuration
@@ -983,7 +918,6 @@ declare module BabylonViewer {
     export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
-
 declare module BabylonViewer {
     /**
         * Will attach an init function the the DOMContentLoaded event.
@@ -997,15 +931,9 @@ declare module BabylonViewer {
         */
     export function InitTags(selector?: string): void;
 }
-
 declare module BabylonViewer {
-    export * from 'babylonjs-viewer/configuration/configuration';
-    export * from 'babylonjs-viewer/configuration/interfaces';
 }
-
 declare module BabylonViewer {
-    
-    
     export function getConfigurationKey(key: string, configObject: any): any;
     export interface ViewerConfiguration {
             version?: string;
@@ -1054,6 +982,7 @@ declare module BabylonViewer {
                     minecraft?: boolean;
                     [propName: string]: boolean | undefined;
             };
+            environmentMap?: IEnvironmentMapConfiguration;
             vr?: IVRConfiguration;
             lab?: {
                     flashlight?: boolean | {
@@ -1072,12 +1001,14 @@ declare module BabylonViewer {
                             };
                     };
                     hideLoadingDelay?: number;
+                    /** Deprecated */
                     assetsRootURL?: string;
                     environmentMainColor?: {
                             r: number;
                             g: number;
                             b: number;
                     };
+                    /** Deprecated */
                     environmentMap?: {
                             /**
                                 * Environment map texture path in relative to the asset folder.
@@ -1097,11 +1028,7 @@ declare module BabylonViewer {
             };
     }
 }
-
 declare module BabylonViewer {
-    
-    
-    
     /**
         * The object sent when an event is triggered
         */
@@ -1266,10 +1193,7 @@ declare module BabylonViewer {
             dispose(): void;
     }
 }
-
 declare module BabylonViewer {
-    
-    
     export class ConfigurationContainer {
         configuration: ViewerConfiguration;
         viewerId: string;
@@ -1278,9 +1202,7 @@ declare module BabylonViewer {
         scene?: BABYLON.Scene;
     }
 }
-
 declare module BabylonViewer {
-    
     /**
         * The configuration loader will load the configuration object from any source and will use the defined mapper to
         * parse the object and return a conform ViewerConfiguration.
@@ -1303,10 +1225,7 @@ declare module BabylonViewer {
             dispose(): void;
     }
 }
-
 declare module BabylonViewer {
-    
-    
     export class ObservablesManager {
             /**
                 * Will notify when the scene was initialized
@@ -1361,14 +1280,7 @@ declare module BabylonViewer {
             dispose(): void;
     }
 }
-
 declare module BabylonViewer {
-    
-    
-    
-    
-    
-    
     /**
         * This interface describes the structure of the variable sent with the configuration observables of the scene manager.
         * O - the type of object we are dealing with (Light, BABYLON.ArcRotateCamera, BABYLON.Scene, etc')
@@ -1466,17 +1378,17 @@ declare module BabylonViewer {
             animationBlendingEnabled: boolean;
             readonly observablesManager: ObservablesManager | undefined;
             /**
-                * Should shadows be rendered every frame, or only once and stop.
-                * This can be used to optimize a scene.
-                *
-                * Not that the shadows will NOT disapear but will remain in place.
-                * @param process if true shadows will be updated once every frame. if false they will stop being updated.
-                */
+             * Should shadows be rendered every frame, or only once and stop.
+             * This can be used to optimize a scene.
+             *
+             * Not that the shadows will NOT disapear but will remain in place.
+             * @param process if true shadows will be updated once every frame. if false they will stop being updated.
+             */
             processShadows: boolean;
             groundEnabled: boolean;
             /**
-                * sets wether the reflection is disabled.
-                */
+             * sets wether the reflection is disabled.
+             */
             groundMirrorEnabled: boolean;
             defaultRenderingPipelineEnabled: boolean;
             /**
@@ -1514,6 +1426,7 @@ declare module BabylonViewer {
                 * @param modelConfiguration the configuration to use to reconfigure the models
                 */
             protected _configureVR(vrConfig: IVRConfiguration): void;
+            protected _configureEnvironmentMap(environmentMapConfiguration: IEnvironmentMapConfiguration): any;
             /**
                 * (Re) configure the camera. The camera will only be created once and from this point will only be reconfigured.
                 * @param cameraConfig the new camera configuration
@@ -1548,9 +1461,7 @@ declare module BabylonViewer {
             dispose(): void;
     }
 }
-
 declare module BabylonViewer {
-    
     export interface IModelConfiguration {
             id?: string;
             url?: string;
@@ -1616,14 +1527,7 @@ declare module BabylonViewer {
             };
     }
 }
-
 declare module BabylonViewer {
-    
-    
-    
-    
-    
-    
     /**
         * Get a loader plugin according to its name.
         * The plugin will be cached and will be reused if called for again.
@@ -1636,26 +1540,33 @@ declare module BabylonViewer {
         */
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
-
 declare module BabylonViewer {
-    export * from 'babylonjs-viewer/configuration/interfaces/cameraConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/defaultRenderingPipelineConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/groundConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/imageProcessingConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/lightConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/modelAnimationConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/modelConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/observersConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/sceneConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/sceneOptimizerConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/skyboxConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/templateConfiguration';
-    export * from 'babylonjs-viewer/configuration/interfaces/vrConfiguration';
 }
-
 declare module BabylonViewer {
-    
+    export interface IEnvironmentMapConfiguration {
+            /**
+                * Environment map texture path in relative to the asset folder.
+                */
+            texture: string;
+            /**
+                * Default rotation to apply to the environment map.
+                */
+            rotationY: number;
+            /**
+                * Tint level of the main color on the environment map.
+                */
+            tintLevel: number;
+            /**
+                * The environment's main color.
+                */
+            mainColor?: {
+                    r?: number;
+                    g?: number;
+                    b?: number;
+            };
+    }
+}
+declare module BabylonViewer {
     /**
         * The EventManager is in charge of registering user interctions with the viewer.
         * It is used in the TemplateManager
@@ -1688,10 +1599,7 @@ declare module BabylonViewer {
             dispose(): void;
     }
 }
-
 declare module BabylonViewer {
-    
-    
     /**
         * The ViewerLabs class will hold functions that are not (!) backwards compatible.
         * The APIs in all labs-related classes and configuration  might change.
@@ -1739,7 +1647,6 @@ declare module BabylonViewer {
             rotateShadowLight(shadowLight: BABYLON.ShadowLight, amount: number, point?: BABYLON.Vector3, axis?: BABYLON.Vector3, target?: BABYLON.Vector3): void;
     }
 }
-
 declare module BabylonViewer {
     /**
         * Defines an animation to be applied to a model (translation, scale or rotation).
@@ -1768,11 +1675,7 @@ declare module BabylonViewer {
             easingMode?: number;
     }
 }
-
 declare module BabylonViewer {
-    
-    
-    
     export class TelemetryLoaderPlugin implements ILoaderPlugin {
         onInit(loader: BABYLON.ISceneLoaderPlugin | BABYLON.ISceneLoaderPluginAsync, model: ViewerModel): void;
         onLoaded(model: ViewerModel): void;
@@ -1780,12 +1683,7 @@ declare module BabylonViewer {
         onComplete(): void;
     }
 }
-
 declare module BabylonViewer {
-    
-    
-    
-    
     /**
       * A loder plugin to use MSFT_lod extension correctly (glTF)
       */
@@ -1794,11 +1692,7 @@ declare module BabylonViewer {
         onExtensionLoaded(extension: BABYLON.IGLTFLoaderExtension): void;
     }
 }
-
 declare module BabylonViewer {
-    
-    
-    
     /**
       * Force-apply material configuration right after a material was loaded.
       */
@@ -1807,10 +1701,7 @@ declare module BabylonViewer {
         onMaterialLoaded(material: BABYLON.Material): void;
     }
 }
-
 declare module BabylonViewer {
-    
-    
     /**
       * A (PBR) material will be extended using this function.
       * This function will hold extra default configuration for the viewer, if not implemented in Babylon itself.
@@ -1819,7 +1710,6 @@ declare module BabylonViewer {
         onMaterialLoaded(baseMaterial: BABYLON.Material): void;
     }
 }
-
 declare module BabylonViewer {
     export interface ICameraConfiguration {
         position?: {
@@ -1853,7 +1743,6 @@ declare module BabylonViewer {
         [propName: string]: any;
     }
 }
-
 declare module BabylonViewer {
     /**
         * The Color Grading Configuration groups the different settings used to define the color grading used in the viewer.
@@ -1937,9 +1826,7 @@ declare module BabylonViewer {
             exposureHighlights: number;
     }
 }
-
 declare module BabylonViewer {
-    
     export interface IDefaultRenderingPipelineConfiguration {
         sharpenEnabled?: boolean;
         bloomEnabled?: boolean;
@@ -1960,7 +1847,6 @@ declare module BabylonViewer {
         glowLayerEnabled?: boolean;
     }
 }
-
 declare module BabylonViewer {
     export interface IGroundConfiguration {
         size?: number;
@@ -1987,7 +1873,6 @@ declare module BabylonViewer {
         };
     }
 }
-
 declare module BabylonViewer {
     export interface IImageProcessingConfiguration {
         colorGradingEnabled?: boolean;
@@ -2033,7 +1918,6 @@ declare module BabylonViewer {
         isEnabled?: boolean;
     }
 }
-
 declare module BabylonViewer {
     export interface ILightConfiguration {
         type: number;
@@ -2096,7 +1980,6 @@ declare module BabylonViewer {
         };
     }
 }
-
 declare module BabylonViewer {
     export interface IObserversConfiguration {
         onEngineInit?: string;
@@ -2104,58 +1987,55 @@ declare module BabylonViewer {
         onModelLoaded?: string;
     }
 }
-
 declare module BabylonViewer {
-    
-    
-    
     export interface ISceneConfiguration {
-        debug?: boolean;
-        clearColor?: {
-            r: number;
-            g: number;
-            b: number;
-            a: number;
-        };
-        mainColor?: {
-            r?: number;
-            g?: number;
-            b?: number;
-        };
-        imageProcessingConfiguration?: IImageProcessingConfiguration;
-        environmentTexture?: string;
-        colorGrading?: IColorGradingConfiguration;
-        environmentRotationY?: number;
-        /**
-          * Deprecated, please use default rendering pipeline
-          */
-        glow?: boolean | BABYLON.IGlowLayerOptions;
-        disableHdr?: boolean;
-        renderInBackground?: boolean;
-        disableCameraControl?: boolean;
-        animationPropertiesOverride?: {
-            [propName: string]: any;
-        };
-        defaultMaterial?: {
-            materialType: "standard" | "pbr";
-            [propName: string]: any;
-        };
-        flags?: {
-            shadowsEnabled?: boolean;
-            particlesEnabled?: boolean;
-            collisionsEnabled?: boolean;
-            lightsEnabled?: boolean;
-            texturesEnabled?: boolean;
-            lensFlaresEnabled?: boolean;
-            proceduralTexturesEnabled?: boolean;
-            renderTargetsEnabled?: boolean;
-            spritesEnabled?: boolean;
-            skeletonsEnabled?: boolean;
-            audioEnabled?: boolean;
-        };
+            debug?: boolean;
+            clearColor?: {
+                    r: number;
+                    g: number;
+                    b: number;
+                    a: number;
+            };
+            /** Deprecated, use environmentMap.mainColor instead. */
+            mainColor?: {
+                    r?: number;
+                    g?: number;
+                    b?: number;
+            };
+            imageProcessingConfiguration?: IImageProcessingConfiguration;
+            environmentTexture?: string;
+            colorGrading?: IColorGradingConfiguration;
+            environmentRotationY?: number;
+            /**
+                * Deprecated, please use default rendering pipeline
+                */
+            glow?: boolean | BABYLON.IGlowLayerOptions;
+            disableHdr?: boolean;
+            renderInBackground?: boolean;
+            disableCameraControl?: boolean;
+            animationPropertiesOverride?: {
+                    [propName: string]: any;
+            };
+            defaultMaterial?: {
+                    materialType: "standard" | "pbr";
+                    [propName: string]: any;
+            };
+            flags?: {
+                    shadowsEnabled?: boolean;
+                    particlesEnabled?: boolean;
+                    collisionsEnabled?: boolean;
+                    lightsEnabled?: boolean;
+                    texturesEnabled?: boolean;
+                    lensFlaresEnabled?: boolean;
+                    proceduralTexturesEnabled?: boolean;
+                    renderTargetsEnabled?: boolean;
+                    spritesEnabled?: boolean;
+                    skeletonsEnabled?: boolean;
+                    audioEnabled?: boolean;
+            };
+            assetsRootURL?: string;
     }
 }
-
 declare module BabylonViewer {
     export interface ISceneOptimizerConfiguration {
         targetFrameRate?: number;
@@ -2181,9 +2061,7 @@ declare module BabylonViewer {
         step?: number;
     }
 }
-
 declare module BabylonViewer {
-    
     export interface ISkyboxConfiguration {
         cubeTexture?: {
             noMipMap?: boolean;
@@ -2205,7 +2083,6 @@ declare module BabylonViewer {
         infiniteDistance?: boolean;
     }
 }
-
 declare module BabylonViewer {
     /**
         * A single template configuration object
@@ -2275,9 +2152,7 @@ declare module BabylonViewer {
             };
     }
 }
-
 declare module BabylonViewer {
-    
     export interface IVRConfiguration {
         disabled?: boolean;
         objectScaleFactor?: number;
@@ -2294,10 +2169,7 @@ declare module BabylonViewer {
         };
     }
 }
-
 declare module BabylonViewer {
-    
-    
     /**
         * Spherical polynomial coefficients (counter part to spherical harmonic coefficients used in shader irradiance calculation)
         * @ignoreChildren
@@ -2403,9 +2275,7 @@ declare module BabylonViewer {
             static Parse(arrayBuffer: ArrayBuffer): PBREnvironment;
     }
 }
-
 declare module BabylonViewer {
-    
     /**
         * WebGL Pixel Formats
         */
@@ -2415,7 +2285,7 @@ declare module BabylonViewer {
             RGB = 6407,
             RGBA = 6408,
             LUMINANCE = 6409,
-            LUMINANCE_ALPHA = 6410,
+            LUMINANCE_ALPHA = 6410
     }
     /**
         * WebGL Pixel Types
@@ -2424,14 +2294,14 @@ declare module BabylonViewer {
             UNSIGNED_BYTE = 5121,
             UNSIGNED_SHORT_4_4_4_4 = 32819,
             UNSIGNED_SHORT_5_5_5_1 = 32820,
-            UNSIGNED_SHORT_5_6_5 = 33635,
+            UNSIGNED_SHORT_5_6_5 = 33635
     }
     /**
         * WebGL Texture Magnification Filter
         */
     export const enum TextureMagFilter {
             NEAREST = 9728,
-            LINEAR = 9729,
+            LINEAR = 9729
     }
     /**
         * WebGL Texture Minification Filter
@@ -2442,7 +2312,7 @@ declare module BabylonViewer {
             NEAREST_MIPMAP_NEAREST = 9984,
             LINEAR_MIPMAP_NEAREST = 9985,
             NEAREST_MIPMAP_LINEAR = 9986,
-            LINEAR_MIPMAP_LINEAR = 9987,
+            LINEAR_MIPMAP_LINEAR = 9987
     }
     /**
         * WebGL Texture Wrap Modes
@@ -2450,7 +2320,7 @@ declare module BabylonViewer {
     export const enum TextureWrapMode {
             REPEAT = 10497,
             CLAMP_TO_EDGE = 33071,
-            MIRRORED_REPEAT = 33648,
+            MIRRORED_REPEAT = 33648
     }
     /**
         * Raw texture data and descriptor sufficient for WebGL texture upload
@@ -2585,5 +2455,4 @@ declare module BabylonViewer {
                 */
             static EnvironmentLODOffset: number;
     }
-}
-
+}

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


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


+ 112 - 76
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -5,8 +5,8 @@ declare module "babylonjs-loaders"{ export=BABYLON;}
 
 // Generated by dts-bundle v0.7.3
 // Dependencies for this module:
-//   ../../../../Tools/Gulp/babylonjs
-//   ../../../../Tools/Gulp/babylonjs-loaders
+//   ../../../../../Tools/Gulp/babylonjs
+//   ../../../../../Tools/Gulp/babylonjs-loaders
 
 declare module 'babylonjs-viewer' {
     import { mapperManager } from 'babylonjs-viewer/configuration/mappers';
@@ -173,7 +173,7 @@ declare module 'babylonjs-viewer/viewer/defaultViewer' {
                 * This will be executed when the templates initialize.
                 */
             protected _onTemplatesLoaded(): Promise<AbstractViewer>;
-            toggleVR(): void;
+            protected _initVR(): void;
             /**
                 * Toggle fullscreen of the entire viewer
                 */
@@ -359,8 +359,8 @@ declare module 'babylonjs-viewer/viewer/viewer' {
                 */
             isCanvasInDOM(): boolean;
             /**
-                * Set the viewer's background rendering flag.
-                */
+             * Set the viewer's background rendering flag.
+             */
             renderInBackground: boolean;
             /**
                 * Get the configuration object. This is a reference only.
@@ -376,7 +376,9 @@ declare module 'babylonjs-viewer/viewer/viewer' {
             toggleHD(): void;
             protected _vrToggled: boolean;
             protected _vrScale: number;
+            protected _vrInit: boolean;
             toggleVR(): void;
+            protected _initVR(): void;
             /**
                 * The resize function that will be registered with the window object
                 */
@@ -573,7 +575,7 @@ declare module 'babylonjs-viewer/model/viewerModel' {
             ENTRYDONE = 4,
             COMPLETE = 5,
             CANCELED = 6,
-            ERROR = 7,
+            ERROR = 7
     }
     /**
         * The viewer model is a container for all assets representing a sngle loaded model.
@@ -638,8 +640,8 @@ declare module 'babylonjs-viewer/model/viewerModel' {
             shadowsRenderedAfterLoad: boolean;
             getViewerId(): string | undefined;
             /**
-                * Set whether this model is enabled or not.
-                */
+             * Set whether this model is enabled or not.
+             */
             enabled: boolean;
             loaderDone: boolean;
             /**
@@ -655,9 +657,9 @@ declare module 'babylonjs-viewer/model/viewerModel' {
                 */
             readonly meshes: AbstractMesh[];
             /**
-                * (Re-)set the model's entire configuration
-                * @param newConfiguration the new configuration to replace the new one
-                */
+             * (Re-)set the model's entire configuration
+             * @param newConfiguration the new configuration to replace the new one
+             */
             configuration: IModelConfiguration;
             /**
                 * Update the current configuration with new values.
@@ -727,7 +729,7 @@ declare module 'babylonjs-viewer/model/modelAnimation' {
         */
     export const enum AnimationPlayMode {
             ONCE = 0,
-            LOOP = 1,
+            LOOP = 1
     }
     /**
         * An enum representing the current state of an animation object
@@ -737,7 +739,7 @@ declare module 'babylonjs-viewer/model/modelAnimation' {
             PLAYING = 1,
             PAUSED = 2,
             STOPPED = 3,
-            ENDED = 4,
+            ENDED = 4
     }
     /**
         * The different type of easing functions available
@@ -754,7 +756,7 @@ declare module 'babylonjs-viewer/model/modelAnimation' {
             QuadraticEase = 8,
             QuarticEase = 9,
             QuinticEase = 10,
-            SineEase = 11,
+            SineEase = 11
     }
     /**
         * Defines a simple animation to be applied to a model (scale).
@@ -867,8 +869,8 @@ declare module 'babylonjs-viewer/model/modelAnimation' {
                 */
             readonly state: AnimationState;
             /**
-                * Sets the speed ratio to use for all animations
-                */
+             * Sets the speed ratio to use for all animations
+             */
             speedRatio: number;
             /**
                 * Get the max numbers of frame available in the animation group
@@ -888,10 +890,10 @@ declare module 'babylonjs-viewer/model/modelAnimation' {
                 */
             readonly fps: number;
             /**
-                * Set the play mode.
-                * If the animation is played, it will continue playing at least once more, depending on the new play mode set.
-                * If the animation is not set, the will be initialized and will wait for the user to start playing it.
-                */
+             * Set the play mode.
+             * If the animation is played, it will continue playing at least once more, depending on the new play mode set.
+             * If the animation is not set, the will be initialized and will wait for the user to start playing it.
+             */
             playMode: AnimationPlayMode;
             /**
                 * Reset the animation group
@@ -1006,6 +1008,7 @@ declare module 'babylonjs-viewer/configuration' {
 declare module 'babylonjs-viewer/configuration/configuration' {
     import { EngineOptions } from 'babylonjs';
     import { ICameraConfiguration, IDefaultRenderingPipelineConfiguration, IGroundConfiguration, ILightConfiguration, IModelConfiguration, IObserversConfiguration, ISceneConfiguration, ISceneOptimizerConfiguration, ISkyboxConfiguration, ITemplateConfiguration, IVRConfiguration } from 'babylonjs-viewer/configuration/interfaces';
+    import { IEnvironmentMapConfiguration } from 'babylonjs-viewer/configuration/interfaces/environmentMapConfiguration';
     export function getConfigurationKey(key: string, configObject: any): any;
     export interface ViewerConfiguration {
             version?: string;
@@ -1054,6 +1057,7 @@ declare module 'babylonjs-viewer/configuration/configuration' {
                     minecraft?: boolean;
                     [propName: string]: boolean | undefined;
             };
+            environmentMap?: IEnvironmentMapConfiguration;
             vr?: IVRConfiguration;
             lab?: {
                     flashlight?: boolean | {
@@ -1072,12 +1076,14 @@ declare module 'babylonjs-viewer/configuration/configuration' {
                             };
                     };
                     hideLoadingDelay?: number;
+                    /** Deprecated */
                     assetsRootURL?: string;
                     environmentMainColor?: {
                             r: number;
                             g: number;
                             b: number;
                     };
+                    /** Deprecated */
                     environmentMap?: {
                             /**
                                 * Environment map texture path in relative to the asset folder.
@@ -1369,6 +1375,7 @@ declare module 'babylonjs-viewer/managers/sceneManager' {
     import { ViewerLabs } from 'babylonjs-viewer/labs/viewerLabs';
     import { ObservablesManager } from 'babylonjs-viewer/managers/observablesManager';
     import { ConfigurationContainer } from 'babylonjs-viewer/configuration/configurationContainer';
+    import { IEnvironmentMapConfiguration } from 'babylonjs-viewer/configuration/interfaces/environmentMapConfiguration';
     /**
         * This interface describes the structure of the variable sent with the configuration observables of the scene manager.
         * O - the type of object we are dealing with (Light, ArcRotateCamera, Scene, etc')
@@ -1466,17 +1473,17 @@ declare module 'babylonjs-viewer/managers/sceneManager' {
             animationBlendingEnabled: boolean;
             readonly observablesManager: ObservablesManager | undefined;
             /**
-                * Should shadows be rendered every frame, or only once and stop.
-                * This can be used to optimize a scene.
-                *
-                * Not that the shadows will NOT disapear but will remain in place.
-                * @param process if true shadows will be updated once every frame. if false they will stop being updated.
-                */
+             * Should shadows be rendered every frame, or only once and stop.
+             * This can be used to optimize a scene.
+             *
+             * Not that the shadows will NOT disapear but will remain in place.
+             * @param process if true shadows will be updated once every frame. if false they will stop being updated.
+             */
             processShadows: boolean;
             groundEnabled: boolean;
             /**
-                * sets wether the reflection is disabled.
-                */
+             * sets wether the reflection is disabled.
+             */
             groundMirrorEnabled: boolean;
             defaultRenderingPipelineEnabled: boolean;
             /**
@@ -1514,6 +1521,7 @@ declare module 'babylonjs-viewer/managers/sceneManager' {
                 * @param modelConfiguration the configuration to use to reconfigure the models
                 */
             protected _configureVR(vrConfig: IVRConfiguration): void;
+            protected _configureEnvironmentMap(environmentMapConfiguration: IEnvironmentMapConfiguration): any;
             /**
                 * (Re) configure the camera. The camera will only be created once and from this point will only be reconfigured.
                 * @param cameraConfig the new camera configuration
@@ -1652,6 +1660,32 @@ declare module 'babylonjs-viewer/configuration/interfaces' {
     export * from 'babylonjs-viewer/configuration/interfaces/skyboxConfiguration';
     export * from 'babylonjs-viewer/configuration/interfaces/templateConfiguration';
     export * from 'babylonjs-viewer/configuration/interfaces/vrConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/environmentMapConfiguration';
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/environmentMapConfiguration' {
+    export interface IEnvironmentMapConfiguration {
+            /**
+                * Environment map texture path in relative to the asset folder.
+                */
+            texture: string;
+            /**
+                * Default rotation to apply to the environment map.
+                */
+            rotationY: number;
+            /**
+                * Tint level of the main color on the environment map.
+                */
+            tintLevel: number;
+            /**
+                * The environment's main color.
+                */
+            mainColor?: {
+                    r?: number;
+                    g?: number;
+                    b?: number;
+            };
+    }
 }
 
 declare module 'babylonjs-viewer/templating/eventManager' {
@@ -2110,49 +2144,51 @@ declare module 'babylonjs-viewer/configuration/interfaces/sceneConfiguration' {
     import { IColorGradingConfiguration } from "babylonjs-viewer/configuration/interfaces/colorGradingConfiguration";
     import { IGlowLayerOptions } from "babylonjs";
     export interface ISceneConfiguration {
-        debug?: boolean;
-        clearColor?: {
-            r: number;
-            g: number;
-            b: number;
-            a: number;
-        };
-        mainColor?: {
-            r?: number;
-            g?: number;
-            b?: number;
-        };
-        imageProcessingConfiguration?: IImageProcessingConfiguration;
-        environmentTexture?: string;
-        colorGrading?: IColorGradingConfiguration;
-        environmentRotationY?: number;
-        /**
-          * Deprecated, please use default rendering pipeline
-          */
-        glow?: boolean | IGlowLayerOptions;
-        disableHdr?: boolean;
-        renderInBackground?: boolean;
-        disableCameraControl?: boolean;
-        animationPropertiesOverride?: {
-            [propName: string]: any;
-        };
-        defaultMaterial?: {
-            materialType: "standard" | "pbr";
-            [propName: string]: any;
-        };
-        flags?: {
-            shadowsEnabled?: boolean;
-            particlesEnabled?: boolean;
-            collisionsEnabled?: boolean;
-            lightsEnabled?: boolean;
-            texturesEnabled?: boolean;
-            lensFlaresEnabled?: boolean;
-            proceduralTexturesEnabled?: boolean;
-            renderTargetsEnabled?: boolean;
-            spritesEnabled?: boolean;
-            skeletonsEnabled?: boolean;
-            audioEnabled?: boolean;
-        };
+            debug?: boolean;
+            clearColor?: {
+                    r: number;
+                    g: number;
+                    b: number;
+                    a: number;
+            };
+            /** Deprecated, use environmentMap.mainColor instead. */
+            mainColor?: {
+                    r?: number;
+                    g?: number;
+                    b?: number;
+            };
+            imageProcessingConfiguration?: IImageProcessingConfiguration;
+            environmentTexture?: string;
+            colorGrading?: IColorGradingConfiguration;
+            environmentRotationY?: number;
+            /**
+                * Deprecated, please use default rendering pipeline
+                */
+            glow?: boolean | IGlowLayerOptions;
+            disableHdr?: boolean;
+            renderInBackground?: boolean;
+            disableCameraControl?: boolean;
+            animationPropertiesOverride?: {
+                    [propName: string]: any;
+            };
+            defaultMaterial?: {
+                    materialType: "standard" | "pbr";
+                    [propName: string]: any;
+            };
+            flags?: {
+                    shadowsEnabled?: boolean;
+                    particlesEnabled?: boolean;
+                    collisionsEnabled?: boolean;
+                    lightsEnabled?: boolean;
+                    texturesEnabled?: boolean;
+                    lensFlaresEnabled?: boolean;
+                    proceduralTexturesEnabled?: boolean;
+                    renderTargetsEnabled?: boolean;
+                    spritesEnabled?: boolean;
+                    skeletonsEnabled?: boolean;
+                    audioEnabled?: boolean;
+            };
+            assetsRootURL?: string;
     }
 }
 
@@ -2415,7 +2451,7 @@ declare module 'babylonjs-viewer/labs/texture' {
             RGB = 6407,
             RGBA = 6408,
             LUMINANCE = 6409,
-            LUMINANCE_ALPHA = 6410,
+            LUMINANCE_ALPHA = 6410
     }
     /**
         * WebGL Pixel Types
@@ -2424,14 +2460,14 @@ declare module 'babylonjs-viewer/labs/texture' {
             UNSIGNED_BYTE = 5121,
             UNSIGNED_SHORT_4_4_4_4 = 32819,
             UNSIGNED_SHORT_5_5_5_1 = 32820,
-            UNSIGNED_SHORT_5_6_5 = 33635,
+            UNSIGNED_SHORT_5_6_5 = 33635
     }
     /**
         * WebGL Texture Magnification Filter
         */
     export const enum TextureMagFilter {
             NEAREST = 9728,
-            LINEAR = 9729,
+            LINEAR = 9729
     }
     /**
         * WebGL Texture Minification Filter
@@ -2442,7 +2478,7 @@ declare module 'babylonjs-viewer/labs/texture' {
             NEAREST_MIPMAP_NEAREST = 9984,
             LINEAR_MIPMAP_NEAREST = 9985,
             NEAREST_MIPMAP_LINEAR = 9986,
-            LINEAR_MIPMAP_LINEAR = 9987,
+            LINEAR_MIPMAP_LINEAR = 9987
     }
     /**
         * WebGL Texture Wrap Modes
@@ -2450,7 +2486,7 @@ declare module 'babylonjs-viewer/labs/texture' {
     export const enum TextureWrapMode {
             REPEAT = 10497,
             CLAMP_TO_EDGE = 33071,
-            MIRRORED_REPEAT = 33648,
+            MIRRORED_REPEAT = 33648
     }
     /**
         * Raw texture data and descriptor sufficient for WebGL texture upload

+ 18 - 2
dist/preview release/what's new.md

@@ -7,7 +7,7 @@
 - New GUI 3D controls toolset. [Complete doc + demos](http://doc.babylonjs.com/how_to/gui3d) ([Deltakosh](https://github.com/deltakosh))
 - Added [Environment Texture Tools](https://doc.babylonjs.com/how_to/physically_based_rendering#creating-a-compressed-environment-texture) to reduce the size of the usual .DDS file ([sebavan](http://www.github.com/sebavan))
 - New GUI control: the [Grid](http://doc.babylonjs.com/how_to/gui#grid) ([Deltakosh](https://github.com/deltakosh))
-- Gizmo and GizmoManager classes used to manipulate meshes in a scene. Gizmo types include: position, rotation, scale and bounding box. [Doc](http://doc.babylonjs.com/how_to/gizmo) ([TrevorDev](https://github.com/TrevorDev))
+- Gizmo and GizmoManager classes used to manipulate meshes in a scene. Gizmo types include: position, scale, rotation and bounding box. [Doc](http://doc.babylonjs.com/how_to/gizmo) ([TrevorDev](https://github.com/TrevorDev))
 - New behaviors: PointerDragBehavior, SixDofDragBehavior and MultiPointerScaleBehavior to enable smooth drag and drop/scaling with mouse or 6dof controller on a mesh. [Doc](http://doc.babylonjs.com/how_to/meshbehavior) ([TrevorDev](https://github.com/TrevorDev))
 - Particle system improvements ([Deltakosh](https://github.com/deltakosh))
   - Added a ParticleHelper class to create some pre-configured particle systems in a one-liner method style. [Doc](https://doc.babylonjs.com/How_To/ParticleHelper) ([Deltakosh](https://github.com/deltakosh)) / ([DevChris](https://github.com/yovanoc))
@@ -17,6 +17,8 @@
   - Added support for `minScaleX`, `minScaleY`, `maxScaleX`, `maxScaleY`. [Doc](https://doc.babylonjs.com/babylon101/particles#size)
   - Added support for `radiusRange` for sphere emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#sphere-emitter)
   - Added support for `radiusRange` and `heightRange` for cone emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#cone-emitter)
+  - Added new point emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#point-emitter)
+  - Added new hemispheric emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#hemispheric-emitter)
   - Added support for `ParticleSystem.BLENDMODE_ADD` alpha mode. [Doc](https://doc.babylonjs.com/babylon101/particles#particle-blending)
   - Added support for color gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#particle-colors)
   - Added support for pre-warming. [Doc](https://doc.babylonjs.com/babylon101/particles#pre-warming)
@@ -24,10 +26,15 @@
   - Added support for size gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#size)
   - Added support for life time gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#lifetime)
   - Added support for angular speed gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#rotation)
-- Added SceneComponent to help decoupling Scene from its components ([sebavan](http://www.github.com/sebavan))
+  - Added support for velocty gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#velocity-over-time)
+  - Added support for limit velocty gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#limit-velocity-over-time)
+  - Added support for noise textures. [Doc](http://doc.babylonjs.com/babylon101/particles#noise-texture)
+- Added SceneComponent to help decoupling Scene from its components. ([sebavan](http://www.github.com/sebavan))
 - Playground can now be used with TypeScript directly!. [Demo](https://www.babylonjs-playground.com/ts.html) ([Deltakosh](https://github.com/deltakosh), [NasimiAsl](https://github.com/NasimiAsl))
 - New GUI control: [InputPassword](https://doc.babylonjs.com/how_to/gui#inputpassword) ([theom](https://github.com/theom))
 - Added dead key support and before key add observable to InputText. [Doc](https://doc.babylonjs.com/how_to/gui#using-onbeforekeyaddobservable-for-extended-keyboard-layouts-and-input-masks)([theom](https://github.com/theom))
+- GUI and Inspector are now ES-Modules ([RaananW](https://github.com/RaananW))
+- Added support for noise procedural textures. [Doc](http://doc.babylonjs.com/how_to/how_to_use_procedural_textures#noise-procedural-texture) ([Deltakosh](https://github.com/deltakosh))
 
 ## Updates
 
@@ -75,6 +82,11 @@
 - Added attachToBoxBehavior to attach UI to a bounding box ([TrevorDev](https://github.com/TrevorDev))
 - Gizmo manager's internal gizmos are now public ([TrevorDev](https://github.com/TrevorDev))
 - Ability to customize meshes on gizmos ([TrevorDev](https://github.com/TrevorDev))
+- Added gltf light falloff [Issue 4148](https://github.com/BabylonJS/Babylon.js/issues/4148) ([sebavan](http://www.github.com/sebavan))
+- Added falloff type per light to prevent material only inconsistencies [Issue 4148](https://github.com/BabylonJS/Babylon.js/issues/4148) ([sebavan](http://www.github.com/sebavan))
+- Added WeightedSound; selects one from many Sounds with random weight for playback. ([najadojo](https://github.com/najadojo))
+- Added HDR support to ReflectionProbe ([Deltakosh](https://github.com/deltakosh))
+- Added Video Recorder [Issue 4708](https://github.com/BabylonJS/Babylon.js/issues/4708) ([sebavan](http://www.github.com/sebavan))
 
 ### glTF Loader
 
@@ -83,6 +95,7 @@
 - Added glTF loader settings to the GLTF tab in the debug layer ([bghgary](http://www.github.com/bghgary))
 - Added debug logging and performance counters ([bghgary](http://www.github.com/bghgary))
 - Added support for EXT_lights_imageBased ([bghgary](http://www.github.com/bghgary))
+- Added support for MSFT_audio_emitter ([najadojo](http://www.github.com/najadojo))
 
 ### Viewer
 
@@ -99,6 +112,7 @@
 - The default viewer has a plugin system with which new buttons can be added externally ([RaananW](https://github.com/RaananW))
 - The extended configuration is now the default when not providing the "extended" parameter ([RaananW](https://github.com/RaananW))
 - viewer.updateConfiguration also accepts a URL to download configuration remotely ([RaananW](https://github.com/RaananW))
+- Viewer supports 3D printing on windows 10 ([RaananW](https://github.com/RaananW))
 - The viewer's environment map is using the new .env feature ([RaananW](https://github.com/RaananW))
 
 ### Documentation
@@ -151,6 +165,8 @@
 - Template location was ignored if html was defined ([RaananW](https://github.com/RaananW))
 - Drag and Drop only worked if a model was already loaded before ([RaananW](https://github.com/RaananW))
 - It was not possible to add new custom optimizers, only use existing ones ([RaananW](https://github.com/RaananW))
+- Button texts were truncated incorrectly ([RaananW](https://github.com/RaananW))
+- Animation names with more than one word didn't work correctly ([RaananW](https://github.com/RaananW))
 
 ### Loaders
 

+ 41 - 0
gui/package.json

@@ -0,0 +1,41 @@
+{
+    "name": "babylonjs-gui",
+    "version": "1.0.0",
+    "description": "The js GUI library is an extension you can use to generate interactive user interface.\r It is build on top of the DynamicTexture.",
+    "scripts": {
+        "start:server": "webpack-dev-server",
+        "start:watch": "webpack -w",
+        "build:dev": "webpack",
+        "build:prod": "webpack --mode=production",
+        "test": "echo \"Error: no test specified\" && exit 1"
+    },
+    "repository": {
+        "type": "git",
+        "url": "git+https://github.com/BabylonJS/Babylon.js.git"
+    },
+    "keywords": [
+        "3d",
+        "webgl",
+        "viewer"
+    ],
+    "license": "Apache2",
+    "bugs": {
+        "url": "https://github.com/BabylonJS/Babylon.js/issues"
+    },
+    "homepage": "https://github.com/BabylonJS/Babylon.js#readme",
+    "devDependencies": {
+        "@types/node": "^10.5.2",
+        "clean-webpack-plugin": "^0.1.19",
+        "ts-loader": "^4.0.0",
+        "typescript": "^2.9.2",
+        "webpack": "^4.16.0",
+        "webpack-cli": "^3.0.8",
+        "webpack-dev-server": "^3.1.4"
+    },
+    "peerDependencies": {
+        "babylonjs": ">3.2.0"
+    },
+    "dependencies": {
+        "dts-bundle-webpack": "^1.0.0"
+    }
+}

+ 3 - 3
gui/readme.md

@@ -1,6 +1,6 @@
-# Babylon.js GUI library
-The Babylon.js GUI library is an extension you can use to generate interactive user interface.
+# js GUI library
+The js GUI library is an extension you can use to generate interactive user interface.
 It is build on top of the DynamicTexture.
 
 Documentation: http://doc.babylonjs.com/how_to/gui
-API: http://doc.babylonjs.com/api/modules/babylon.gui
+API: http://doc.babylonjs.com/api/modules/gui

File diff suppressed because it is too large
+ 589 - 589
gui/src/2D/advancedDynamicTexture.ts


+ 0 - 0
gui/src/2D/controls/button.ts


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