Sfoglia il codice sorgente

Merge remote-tracking branch 'BabylonJS/master'

MackeyK24 7 anni fa
parent
commit
cb1501e46d
100 ha cambiato i file con 917336 aggiunte e 23433 eliminazioni
  1. 14 1
      .vscode/launch.json
  2. 2798 2773
      Playground/babylon.d.txt
  3. 399 301
      Playground/index-local.html
  4. 417 416
      Playground/index.html
  5. 413 316
      Playground/indexStable.html
  6. 892574 0
      Playground/scenes/dummy2.babylon
  7. BIN
      Playground/sounds/cellolong.wav
  8. BIN
      Playground/sounds/violons18.wav
  9. 13 1
      Tools/Gulp/config.json
  10. 60 37
      Tools/Gulp/gulp-addModuleExports.js
  11. 11 7
      Tools/Gulp/gulpfile.js
  12. 1 1
      Viewer/dist/basicExample.html
  13. 1 0
      Viewer/src/configuration/configuration.ts
  14. 14 8
      Viewer/src/configuration/loader.ts
  15. 4 0
      Viewer/src/configuration/mappers.ts
  16. 4 0
      Viewer/src/eventManager.ts
  17. 16 3
      Viewer/src/index.ts
  18. 3 2
      Viewer/src/model/modelAnimation.ts
  19. 37 0
      Viewer/src/model/modelLoader.ts
  20. 222 49
      Viewer/src/model/viewerModel.ts
  21. 21 1
      Viewer/src/templateManager.ts
  22. 5 4
      Viewer/src/viewer/defaultViewer.ts
  23. 92 142
      Viewer/src/viewer/viewer.ts
  24. 14 2
      Viewer/src/viewer/viewerManager.ts
  25. 3 1
      Viewer/webpack.config.js
  26. 1 1
      dist/preview release/Oimo.js
  27. 7683 7662
      dist/preview release/babylon.d.ts
  28. 57 57
      dist/preview release/babylon.js
  29. 347 278
      dist/preview release/babylon.max.js
  30. 58 58
      dist/preview release/babylon.worker.js
  31. 9119 9098
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  32. 59 59
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  33. 347 279
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  34. 319 252
      dist/preview release/customConfigurations/minimalGLTFViewer/es6.js
  35. 319 251
      dist/preview release/es6.js
  36. 1 1
      dist/preview release/gltf2Interface/package.json
  37. 4 0
      dist/preview release/gui/babylon.gui.d.ts
  38. 72 26
      dist/preview release/gui/babylon.gui.js
  39. 4 4
      dist/preview release/gui/babylon.gui.min.js
  40. 4 0
      dist/preview release/gui/babylon.gui.module.d.ts
  41. 1 1
      dist/preview release/gui/package.json
  42. 3 3
      dist/preview release/inspector/babylon.inspector.bundle.js
  43. 1 1
      dist/preview release/inspector/package.json
  44. 1 0
      dist/preview release/loaders/babylon.glTF1FileLoader.js
  45. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  46. 5 2
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  47. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  48. 5 2
      dist/preview release/loaders/babylon.glTFFileLoader.js
  49. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  50. 27 28
      dist/preview release/loaders/babylonjs.loaders.js
  51. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  52. 2 2
      dist/preview release/loaders/package.json
  53. 22 26
      dist/preview release/materialsLibrary/babylonjs.materials.js
  54. 1 1
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  55. 1 1
      dist/preview release/materialsLibrary/package.json
  56. 22 26
      dist/preview release/postProcessesLibrary/babylonjs.postProcess.js
  57. 1 1
      dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js
  58. 1 1
      dist/preview release/postProcessesLibrary/package.json
  59. 22 26
      dist/preview release/proceduralTexturesLibrary/babylonjs.proceduralTextures.js
  60. 1 1
      dist/preview release/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js
  61. 1 1
      dist/preview release/proceduralTexturesLibrary/package.json
  62. 22 26
      dist/preview release/serializers/babylonjs.serializers.js
  63. 1 1
      dist/preview release/serializers/babylonjs.serializers.min.js
  64. 2 2
      dist/preview release/serializers/package.json
  65. 2 12
      dist/preview release/typedocValidationBaseline.json
  66. 30 1
      dist/preview release/viewer/babylon.viewer.d.ts
  67. 65 65
      dist/preview release/viewer/babylon.viewer.js
  68. 1013 736
      dist/preview release/viewer/babylon.viewer.max.js
  69. 1 1
      dist/preview release/viewer/package.json
  70. 3 2
      dist/preview release/what's new.md
  71. 56 0
      gui/src/controls/container.ts
  72. 1 2
      gui/src/tsconfig.json
  73. 1 2
      inspector/src/tsconfig.json
  74. 1 1
      loaders/src/glTF/2.0/Extensions/MSFT_lod.ts
  75. 1 0
      loaders/src/glTF/babylon.glTFFileLoader.ts
  76. 1 2
      loaders/src/tsconfig.json
  77. 1 2
      materialsLibrary/src/tsconfig.json
  78. 1 4
      package.json
  79. 1 2
      postProcessLibrary/src/tsconfig.json
  80. 1 2
      proceduralTexturesLibrary/src/tsconfig.json
  81. 1 11
      sandbox/index-local.html
  82. 3 6
      sandbox/index.html
  83. 137 64
      sandbox/index.js
  84. 1 2
      serializers/src/tsconfig.json
  85. 42 1
      src/Animations/babylon.animatable.ts
  86. 12 2
      src/Animations/babylon.animationGroup.ts
  87. 23 5
      src/Animations/babylon.runtimeAnimation.ts
  88. 88 73
      src/Audio/babylon.sound.ts
  89. 1 0
      src/Engine/babylon.engine.ts
  90. 18 2
      src/Layer/babylon.effectLayer.ts
  91. 18 2
      src/Lights/Shadows/babylon.shadowGenerator.ts
  92. 115 168
      src/Materials/babylon.effect.ts
  93. 1 1
      src/Mesh/Compression/babylon.dracoCompression.ts
  94. 1 1
      src/Mesh/babylon.mesh.ts
  95. 1 1
      src/Mesh/babylon.subMesh.ts
  96. 1 1
      src/Particles/EmitterTypes/babylon.coneParticleEmitter.ts
  97. 8 2
      src/Particles/babylon.gpuParticleSystem.ts
  98. 1 1
      src/Particles/babylon.particleSystem.ts
  99. 3 3
      src/Physics/Plugins/babylon.cannonJSPlugin.ts
  100. 0 0
      src/Physics/Plugins/babylon.oimoJSPlugin.ts

+ 14 - 1
.vscode/launch.json

@@ -158,6 +158,19 @@
             "reAttach": true,
             "reAttach": true,
             "webRoot": "${workspaceRoot}/",
             "webRoot": "${workspaceRoot}/",
             "url": "http://localhost:1338/tests/validation/index.html"
             "url": "http://localhost:1338/tests/validation/index.html"
-        }
+        },
+        {
+            "name": "Launch memory checks (Chrome)",
+            "type": "chrome",
+            "request": "launch",
+            "url": "http://localhost:1338/tests/memoryChecks/index.html",
+            "webRoot": "${workspaceRoot}/",
+            "sourceMaps": true,
+            "preLaunchTask": "run",
+            "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
+            "runtimeArgs": [
+                "--enable-unsafe-es3-apis"
+            ]
+        },        
     ]
     ]
 }
 }

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


+ 399 - 301
Playground/index-local.html

@@ -1,376 +1,474 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
 <html>
 <html>
 
 
-<head>
-    <title>Babylon.js Playground</title>
-    <meta charset='utf-8' />
-    <meta name="viewport" content="width=device-width, user-scalable=no">
-    <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="../dist/preview%20release/cannon.js"></script>
-    <script src="../dist/preview%20release/draco_decoder.js" type="text/x-draco-decoder"></script>
-    <script src="../dist/preview%20release/Oimo.js"></script>
-    <script src="../tools/DevLoader/BabylonLoader.js"></script>
-
-    <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">
-        </div>
+    <head>
+        <title>Babylon.js Playground</title>
+        <meta charset='utf-8' />
+        <meta name="viewport" content="width=device-width, user-scalable=no">
+        <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>
+        <!-- Physics -->
+        <script src="../dist/preview%20release/cannon.js"></script>
+        <script src="../dist/preview%20release/Oimo.js"></script>
+        <!--Monaco-->
+        <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
+        <!-- Babylon.js -->
+        <script src="../dist/preview%20release/draco_decoder.js" type="text/x-draco-decoder"></script>
+        <script src="../tools/DevLoader/BabylonLoader.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">
+            </div>
 
 
-        <div class="category">
-            <div class="button run" id="runButton1600">Run <i class="fa fa-play" aria-hidden="true"></i></div>
-        </div>
+            <div class="category">
+                <div class="button run" id="runButton1600">Run
+                    <i class="fa fa-play" aria-hidden="true"></i>
+                </div>
+            </div>
 
 
 
 
-        <div class="category">
-            <div class="button" id="newButton1600">New<i class="fa fa-file" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="clearButton1600">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
-        </div>
+            <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 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 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 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>
-                    <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>
-                    <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>
-            </div>
 
 
-            <div class="button uncheck" id="debugButton1600">Debug layer <i class="fa fa-square-o" aria-hidden="true"></i></div>
-            <div class="button" id="metadataButton1600">Metadata</div>
-        </div>
+                <div class="button uncheck" id="debugButton1600">Debug layer
+                    <i class="fa fa-square-o" aria-hidden="true"></i>
+                </div>
+                <div class="button" id="metadataButton1600">Metadata</div>
+            </div>
 
 
 
 
 
 
-        <div class="category right">
-            <div class="button select"><span id="currentVersion1600">Version: Latest</span>
-                <div class="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>
-            </div>
-            <div class="button select"> <span id="currentScript1600">Scenes</span>
-                <div class="toDisplayBig">
-                    <ul id="scriptsList1600">
-                    </ul>
+                <div class="button select">
+                    <span id="currentScript1600">Scenes</span>
+                    <div class="toDisplayBig">
+                        <ul id="scriptsList1600">
+                        </ul>
+                    </div>
                 </div>
                 </div>
             </div>
             </div>
+            <div class="save-message" id="saveMessage">
+                This PG has missing metadata. Click save to add them.
+            </div>
         </div>
         </div>
-        <div class="save-message" id="saveMessage">
-            This PG has missing metadata. Click save to add them.
-        </div>
-    </div>
 
 
-    <div class="navbar navBar1475">
-        <div class="title">
-            Babylon.js Playground
-        </div>
-        <div class="version" id="mainTitle">
-        </div>
+        <div class="navbar navBar1475">
+            <div class="title">
+                Babylon.js Playground
+            </div>
+            <div class="version" id="mainTitle">
+            </div>
 
 
-        <div class="category">
-            <div class="button run" id="runButton1475">Run <i class="fa fa-play" aria-hidden="true"></i></div>
-        </div>
+            <div class="category">
+                <div class="button run" id="runButton1475">Run
+                    <i class="fa fa-play" aria-hidden="true"></i>
+                </div>
+            </div>
 
 
 
 
-        <div class="category">
-            <div class="button" id="newButton1475">New<i class="fa fa-file" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="clearButton1475">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
-        </div>
+            <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 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 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 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>
-                    <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>
-                    <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">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
-                    <div class="option" id="metadataButton1475">Metadata</div>
-                    <div class="option subSelect"><span id="currentVersion1475">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="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">Debug layer
+                            <i class="fa fa-square-o" aria-hidden="true"></i>
+                        </div>
+                        <div class="option" id="metadataButton1475">Metadata</div>
+                        <div class="option subSelect">
+                            <span id="currentVersion1475">Vers. : Latest</span>
+                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="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>
             </div>
             </div>
-        </div>
 
 
-        <div class="category right">
-            <div class="button select"> <span id="currentScript1475">Scenes</span>
-                <div class="toDisplayBig">
-                    <ul id="scriptsList1475">
-                    </ul>
+            <div class="category right">
+                <div class="button select">
+                    <span id="currentScript1475">Scenes</span>
+                    <div class="toDisplayBig">
+                        <ul id="scriptsList1475">
+                        </ul>
+                    </div>
                 </div>
                 </div>
             </div>
             </div>
+            <div class="save-message" id="saveMessage">
+                This PG has missing metadata. Click save to add them.
+            </div>
         </div>
         </div>
-        <div class="save-message" id="saveMessage">
-            This PG has missing metadata. Click save to add them.
-        </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>
-        </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>
+            </div>
 
 
 
 
-        <div class="category">
-            <div class="button" id="newButton1030">New<i class="fa fa-file" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="clearButton1030">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
-        </div>
+            <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 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 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 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>
-                    <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>
-                    <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">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
-                    <div class="option" id="metadataButton1030">Metadata</div>
-                    <div class="option subSelect"><span id="currentVersion1030">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="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">Debug layer
+                            <i class="fa fa-square-o" aria-hidden="true"></i>
+                        </div>
+                        <div class="option" id="metadataButton1030">Metadata</div>
+                        <div class="option subSelect">
+                            <span id="currentVersion1030">Vers. : Latest</span>
+                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="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>
             </div>
             </div>
-        </div>
 
 
-        <div class="category right">
-            <div class="button select"> <span id="currentScript1030">Scenes</span>
-                <div class="toDisplayBig">
-                    <ul id="scriptsList1030">
-                    </ul>
+            <div class="category right">
+                <div class="button select">
+                    <span id="currentScript1030">Scenes</span>
+                    <div class="toDisplayBig">
+                        <ul id="scriptsList1030">
+                        </ul>
+                    </div>
                 </div>
                 </div>
             </div>
             </div>
-        </div>
-        <div class="save-message" id="saveMessage">
-            This PG has missing metadata. Click save to add them.
-        </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>
-                </div>
+            <div class="save-message" id="saveMessage">
+                This PG has missing metadata. Click save to add them.
             </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="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>
-                    </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" 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 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">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
-                    <div class="option" id="metadataButton750">Metadata</div>
-                    <div class="option subSelect"><span id="currentVersion750">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub">
-                            <div class="option" onclick="setVersion('latest');">Latest</div>
-                            <div class="option" onclick="setVersion('2.5');">2.5</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>
+                        </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 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">Debug layer
+                            <i class="fa fa-square-o" aria-hidden="true"></i>
+                        </div>
+                        <div class="option" id="metadataButton750">Metadata</div>
+                        <div class="option subSelect">
+                            <span id="currentVersion750">Vers. : Latest</span>
+                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="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>
             </div>
             </div>
-        </div>
 
 
-        <div class="category right">
-            <div class="button select"> <span id="currentScript750">Scenes</span>
-                <div class="toDisplayBig">
-                    <ul id="scriptsList750">
-                    </ul>
+            <div class="category right">
+                <div class="button select">
+                    <span id="currentScript750">Scenes</span>
+                    <div class="toDisplayBig">
+                        <ul id="scriptsList750">
+                        </ul>
+                    </div>
                 </div>
                 </div>
             </div>
             </div>
+            <div class="save-message" id="saveMessage">
+                This PG has missing metadata. Click save to add them.
+            </div>
         </div>
         </div>
-        <div class="save-message" id="saveMessage">
-            This PG has missing metadata. Click save to add them.
+
+        <div class="wrapper">
+            <div id="jsEditor"></div>
+            <div id="canvasZone">
+                <canvas touch-action="none" id="renderCanvas"></canvas>
+            </div>
         </div>
         </div>
-    </div>
-
-    <div class="wrapper">
-        <div id="jsEditor"></div>
-        <div id="canvasZone">
-            <canvas touch-action="none" id="renderCanvas"></canvas>
-        </div>          
-    </div>
-
-    <span class="label" id="fpsLabel">FPS</span>
-
-    <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>
+
+        <span class="label" id="fpsLabel">FPS</span>
+
+        <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>
+            </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>
         </div>
-    </div>
-
-    <div id="waitDiv">
-        <span id="waitTitle">Babylon.js Playground<BR><BR><BR></span>
-        <img src="waitlogo.png" id="waitLogo"/>
-    </div>   
-
-    <script src="https://code.jquery.com/jquery.js"></script>
-
-    <script src="js/actions.js"></script>
-    <script src="js/pbt.js"></script>
-    <script>
-        BABYLONDEVTOOLS.Loader.require('js/index.js')
-            .load();
-    </script>
-</body>
+
+        <div id="waitDiv">
+            <span id="waitTitle">Babylon.js Playground
+                <BR>
+                <BR>
+                <BR>
+            </span>
+            <img src="waitlogo.png" id="waitLogo" />
+        </div>
+
+        <script src="https://code.jquery.com/jquery.js"></script>
+
+        <script src="js/actions.js"></script>
+        <script src="js/pbt.js"></script>
+        <script>
+            BABYLONDEVTOOLS.Loader.require('js/index.js')
+                .load();
+        </script>
+    </body>
 
 
 </html>
 </html>

+ 417 - 416
Playground/index.html

@@ -1,506 +1,507 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
 <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/draco_decoder.js" type="text/x-draco-decoder"></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/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>
-
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/canvas2D/dist/preview%20release/babylon.canvas2d.min.js"></script>
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/CompoundShader/src/babylonx.CompoundShader.js"></script>
-    <link href="css/index.css" rel="stylesheet" />
-</head>
-
-<body>
-    <div class="navbar navBar1600">
-        <div class="title">
-            Babylon.js Playground
-        </div>
-        <div class="version" id="mainTitle">
-        </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>
+        <!-- Physics -->
+        <script src="https://preview.babylonjs.com/cannon.js"></script>
+        <script src="https://preview.babylonjs.com/Oimo.js"></script>
+        <!--Monaco-->
+        <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
+        <!-- Babylon.js -->
+        <script src="https://preview.babylonjs.com/draco_decoder.js" type="text/x-draco-decoder"></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/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>
+
+        <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>
+        <script src="https://rawgit.com/BabylonJS/Extensions/master/canvas2D/dist/preview%20release/babylon.canvas2d.min.js"></script>
+        <script src="https://rawgit.com/BabylonJS/Extensions/master/CompoundShader/src/babylonx.CompoundShader.js"></script>
+        <link href="css/index.css" rel="stylesheet" />
+    </head>
+
+    <body>
+        <div class="navbar navBar1600">
+            <div class="title">
+                Babylon.js Playground
+            </div>
+            <div class="version" id="mainTitle">
+            </div>
+
+            <div class="category">
+                <div class="button run" id="runButton1600">Run
+                    <i class="fa fa-play" aria-hidden="true"></i>
+                </div>
             </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>
 
 
-        <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>
 
 
-        <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>
-                    <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>
-                    <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>
-            </div>
 
 
-            <div class="button uncheck" id="debugButton1600">Debug layer
-                <i class="fa fa-square-o" aria-hidden="true"></i>
+                <div class="button uncheck" id="debugButton1600">Debug layer
+                    <i class="fa fa-square-o" aria-hidden="true"></i>
+                </div>
+                <div class="button" id="metadataButton1600">Metadata</div>
             </div>
             </div>
-            <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('stable');">Stable</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('stable');">Stable</div>
+                    </div>
                 </div>
                 </div>
-            </div>
-            <div class="button select">
-                <span id="currentScript1600">Scenes</span>
-                <div class="toDisplayBig">
-                    <ul id="scriptsList1600">
-                    </ul>
+                <div class="button select">
+                    <span id="currentScript1600">Scenes</span>
+                    <div class="toDisplayBig">
+                        <ul id="scriptsList1600">
+                        </ul>
+                    </div>
                 </div>
                 </div>
             </div>
             </div>
+            <div class="save-message" id="saveMessage">
+                This PG has missing metadata. Click save to add them.
+            </div>
         </div>
         </div>
-        <div class="save-message" id="saveMessage">
-            This PG has missing metadata. Click save to add them.
-        </div>
-    </div>
 
 
-    <div class="navbar navBar1475">
-        <div class="title">
-            Babylon.js Playground
-        </div>
-        <div class="version" id="mainTitle">
-        </div>
+        <div class="navbar navBar1475">
+            <div class="title">
+                Babylon.js Playground
+            </div>
+            <div class="version" id="mainTitle">
+            </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>
 
 
 
 
-        <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>
 
 
-        <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>
 
 
-        <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>
-                    <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>
-                    <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">Debug layer
-                        <i class="fa fa-square-o" aria-hidden="true"></i>
-                    </div>
-                    <div class="option" id="metadataButton1475">Metadata</div>
-                    <div class="option subSelect">
-                        <span id="currentVersion1475">Vers. : Latest</span>
-                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub">
-                            <div class="option" onclick="setVersion('latest');">Latest</div>
-                            <div class="option" onclick="setVersion('stable');">Stable</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">Debug layer
+                            <i class="fa fa-square-o" aria-hidden="true"></i>
+                        </div>
+                        <div class="option" id="metadataButton1475">Metadata</div>
+                        <div class="option subSelect">
+                            <span id="currentVersion1475">Vers. : Latest</span>
+                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub">
+                                <div class="option" onclick="setVersion('latest');">Latest</div>
+                                <div class="option" onclick="setVersion('stable');">Stable</div>
+                            </div>
                         </div>
                         </div>
                     </div>
                     </div>
                 </div>
                 </div>
             </div>
             </div>
-        </div>
 
 
-        <div class="category right">
-            <div class="button select">
-                <span id="currentScript1475">Scenes</span>
-                <div class="toDisplayBig">
-                    <ul id="scriptsList1475">
-                    </ul>
+            <div class="category right">
+                <div class="button select">
+                    <span id="currentScript1475">Scenes</span>
+                    <div class="toDisplayBig">
+                        <ul id="scriptsList1475">
+                        </ul>
+                    </div>
                 </div>
                 </div>
             </div>
             </div>
+            <div class="save-message" id="saveMessage">
+                This PG has missing metadata. Click save to add them.
+            </div>
         </div>
         </div>
-        <div class="save-message" id="saveMessage">
-            This PG has missing metadata. Click save to add them.
-        </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>
 
 
 
 
-        <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>
 
 
-        <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>
 
 
-        <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>
-                    <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>
-                    <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">Debug layer
-                        <i class="fa fa-square-o" aria-hidden="true"></i>
-                    </div>
-                    <div class="option" id="metadataButton1030">Metadata</div>
-                    <div class="option subSelect">
-                        <span id="currentVersion1030">Vers. : Latest</span>
-                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub">
-                            <div class="option" onclick="setVersion('latest');">Latest</div>
-                            <div class="option" onclick="setVersion('stable');">Stable</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">Debug layer
+                            <i class="fa fa-square-o" aria-hidden="true"></i>
+                        </div>
+                        <div class="option" id="metadataButton1030">Metadata</div>
+                        <div class="option subSelect">
+                            <span id="currentVersion1030">Vers. : Latest</span>
+                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub">
+                                <div class="option" onclick="setVersion('latest');">Latest</div>
+                                <div class="option" onclick="setVersion('stable');">Stable</div>
+                            </div>
                         </div>
                         </div>
                     </div>
                     </div>
                 </div>
                 </div>
             </div>
             </div>
-        </div>
 
 
-        <div class="category right">
-            <div class="button select">
-                <span id="currentScript1030">Scenes</span>
-                <div class="toDisplayBig">
-                    <ul id="scriptsList1030">
-                    </ul>
+            <div class="category right">
+                <div class="button select">
+                    <span id="currentScript1030">Scenes</span>
+                    <div class="toDisplayBig">
+                        <ul id="scriptsList1030">
+                        </ul>
+                    </div>
                 </div>
                 </div>
             </div>
             </div>
+            <div class="save-message" id="saveMessage">
+                This PG has missing metadata. Click save to add them.
+            </div>
         </div>
         </div>
-        <div class="save-message" id="saveMessage">
-            This PG has missing metadata. Click save to add them.
-        </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>
             </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>
-                    <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>
-                    <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">Debug layer
-                        <i class="fa fa-square-o" aria-hidden="true"></i>
-                    </div>
-                    <div class="option" id="metadataButton750">Metadata</div>
-                    <div class="option subSelect">
-                        <span id="currentVersion750">Vers. : Latest</span>
-                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub">
-                            <div class="option" onclick="setVersion('latest');">Latest</div>
-                            <div class="option" onclick="setVersion('stable');">Stable</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">Debug layer
+                            <i class="fa fa-square-o" aria-hidden="true"></i>
+                        </div>
+                        <div class="option" id="metadataButton750">Metadata</div>
+                        <div class="option subSelect">
+                            <span id="currentVersion750">Vers. : Latest</span>
+                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub">
+                                <div class="option" onclick="setVersion('latest');">Latest</div>
+                                <div class="option" onclick="setVersion('stable');">Stable</div>
+                            </div>
                         </div>
                         </div>
                     </div>
                     </div>
                 </div>
                 </div>
             </div>
             </div>
-        </div>
 
 
-        <div class="category right">
-            <div class="button select">
-                <span id="currentScript750">Scenes</span>
-                <div class="toDisplayBig">
-                    <ul id="scriptsList750">
-                    </ul>
+            <div class="category right">
+                <div class="button select">
+                    <span id="currentScript750">Scenes</span>
+                    <div class="toDisplayBig">
+                        <ul id="scriptsList750">
+                        </ul>
+                    </div>
                 </div>
                 </div>
             </div>
             </div>
+            <div class="save-message" id="saveMessage">
+                This PG has missing metadata. Click save to add them.
+            </div>
         </div>
         </div>
-        <div class="save-message" id="saveMessage">
-            This PG has missing metadata. Click save to add them.
-        </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>
 
 
-    <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>
-    </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>
         </div>
-    </div>
-
-    <div id="waitDiv">
-        <span id="waitTitle">Babylon.js Playground
-            <BR>
-            <BR>
-            <BR>
-        </span>
-        <img src="waitlogo.png" id="waitLogo" />
-    </div>
-
-    <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>
-</body>
+
+        <div id="waitDiv">
+            <span id="waitTitle">Babylon.js Playground
+                <BR>
+                <BR>
+                <BR>
+            </span>
+            <img src="waitlogo.png" id="waitLogo" />
+        </div>
+
+        <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>
+    </body>
 
 
 </html>
 </html>

+ 413 - 316
Playground/indexStable.html

@@ -1,395 +1,492 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
 <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://cdn.babylonjs.com/cannon.js"></script>
-    <script src="https://cdn.babylonjs.com/draco_decoder.js" type="text/x-draco-decoder"></script>
-    <script src="https://cdn.babylonjs.com/Oimo.js"></script>
-    <script src="https://cdn.babylonjs.com/babylon.js"></script>
-    <script src="https://cdn.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
-
-    <script src="https://cdn.babylonjs.com/loaders/babylon.glTFFileLoader.js"></script>
-    <script src="https://cdn.babylonjs.com/loaders/babylon.objFileLoader.js"></script>
-    <script src="https://cdn.babylonjs.com/loaders/babylon.stlFileLoader.js"></script>
-
-    <script src="https://cdn.babylonjs.com/gui/babylon.gui.min.js"></script>    
-
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.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">
-        </div>
+    <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>
+        <!-- Physics -->
+        <script src="https://cdn.babylonjs.com/cannon.js"></script>
+        <script src="https://cdn.babylonjs.com/Oimo.js"></script>
+        <!--Monaco-->
+        <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
+        <!-- Babylon.js -->
+        <script src="https://cdn.babylonjs.com/draco_decoder.js" type="text/x-draco-decoder"></script>
+        <script src="https://cdn.babylonjs.com/babylon.js"></script>
+        <script src="https://cdn.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
+
+        <script src="https://cdn.babylonjs.com/loaders/babylon.glTFFileLoader.js"></script>
+        <script src="https://cdn.babylonjs.com/loaders/babylon.objFileLoader.js"></script>
+        <script src="https://cdn.babylonjs.com/loaders/babylon.stlFileLoader.js"></script>
+
+        <script src="https://cdn.babylonjs.com/gui/babylon.gui.min.js"></script>
+
+        <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.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">
+            </div>
 
 
-        <div class="category">
-            <div class="button run" id="runButton1600">Run <i class="fa fa-play" aria-hidden="true"></i></div>
-        </div>
+            <div class="category">
+                <div class="button run" id="runButton1600">Run
+                    <i class="fa fa-play" aria-hidden="true"></i>
+                </div>
+            </div>
 
 
 
 
-        <div class="category">
-            <div class="button" id="newButton1600">New<i class="fa fa-file" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="clearButton1600">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
-        </div>
+            <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 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 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 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>
-                    <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>
-                    <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>
-            </div>
-
-            <div class="button uncheck" id="debugButton1600">Debug layer <i class="fa fa-square-o" aria-hidden="true"></i></div>
-            <div class="button" id="metadataButton1600">Metadata</div>
-        </div>
 
 
-        <div class="category right">
-            <div class="button select"><span id="currentVersion1600">Version: Latest</span>
-                <div class="toDisplay">
-                    <div class="option" onclick="setVersion('latest');">Latest</div>
-                    <div class="option" onclick="setVersion('stable');">Stable</div>
+                <div class="button uncheck" id="debugButton1600">Debug layer
+                    <i class="fa fa-square-o" aria-hidden="true"></i>
                 </div>
                 </div>
+                <div class="button" id="metadataButton1600">Metadata</div>
             </div>
             </div>
-            <div class="button select"> <span id="currentScript1600">Scenes</span>
-                <div class="toDisplayBig">
-                    <ul id="scriptsList1600">
-                    </ul>
+
+            <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('stable');">Stable</div>
+                    </div>
+                </div>
+                <div class="button select">
+                    <span id="currentScript1600">Scenes</span>
+                    <div class="toDisplayBig">
+                        <ul id="scriptsList1600">
+                        </ul>
+                    </div>
                 </div>
                 </div>
             </div>
             </div>
+            <div class="save-message" id="saveMessage">
+                This PG has missing metadata. Click save to add them.
+            </div>
         </div>
         </div>
-        <div class="save-message" id="saveMessage">
-            This PG has missing metadata. Click save to add them.
-        </div>
-    </div>
 
 
-    <div class="navbar navBar1475">
-        <div class="title">
-            Babylon.js Playground
-        </div>
-        <div class="version" id="mainTitle">
-        </div>
+        <div class="navbar navBar1475">
+            <div class="title">
+                Babylon.js Playground
+            </div>
+            <div class="version" id="mainTitle">
+            </div>
 
 
-        <div class="category">
-            <div class="button run" id="runButton1475">Run <i class="fa fa-play" aria-hidden="true"></i></div>
-        </div>
+            <div class="category">
+                <div class="button run" id="runButton1475">Run
+                    <i class="fa fa-play" aria-hidden="true"></i>
+                </div>
+            </div>
 
 
 
 
-        <div class="category">
-            <div class="button" id="newButton1475">New<i class="fa fa-file" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="clearButton1475">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
-        </div>
+            <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 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 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 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>
-                    <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>
-                    <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">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
-                    <div class="option" id="metadataButton1475">Metadata</div>
-                    <div class="option subSelect"><span id="currentVersion1475">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub">
-                            <div class="option" onclick="setVersion('latest');">Latest</div>
-                            <div class="option" onclick="setVersion('stable');">Stable</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">Debug layer
+                            <i class="fa fa-square-o" aria-hidden="true"></i>
+                        </div>
+                        <div class="option" id="metadataButton1475">Metadata</div>
+                        <div class="option subSelect">
+                            <span id="currentVersion1475">Vers. : Latest</span>
+                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub">
+                                <div class="option" onclick="setVersion('latest');">Latest</div>
+                                <div class="option" onclick="setVersion('stable');">Stable</div>
+                            </div>
                         </div>
                         </div>
                     </div>
                     </div>
                 </div>
                 </div>
             </div>
             </div>
-        </div>
 
 
-        <div class="category right">
-            <div class="button select"> <span id="currentScript1475">Scenes</span>
-                <div class="toDisplayBig">
-                    <ul id="scriptsList1475">
-                    </ul>
+            <div class="category right">
+                <div class="button select">
+                    <span id="currentScript1475">Scenes</span>
+                    <div class="toDisplayBig">
+                        <ul id="scriptsList1475">
+                        </ul>
+                    </div>
                 </div>
                 </div>
             </div>
             </div>
+            <div class="save-message" id="saveMessage">
+                This PG has missing metadata. Click save to add them.
+            </div>
         </div>
         </div>
-        <div class="save-message" id="saveMessage">
-            This PG has missing metadata. Click save to add them.
-        </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>
-        </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>
+            </div>
 
 
 
 
-        <div class="category">
-            <div class="button" id="newButton1030">New<i class="fa fa-file" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="clearButton1030">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
-        </div>
+            <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 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 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 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>
-                    <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>
-                    <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">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
-                    <div class="option" id="metadataButton1030">Metadata</div>
-                    <div class="option subSelect"><span id="currentVersion1030">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub">
-                            <div class="option" onclick="setVersion('latest');">Latest</div>
-                            <div class="option" onclick="setVersion('stable');">Stable</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">Debug layer
+                            <i class="fa fa-square-o" aria-hidden="true"></i>
+                        </div>
+                        <div class="option" id="metadataButton1030">Metadata</div>
+                        <div class="option subSelect">
+                            <span id="currentVersion1030">Vers. : Latest</span>
+                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub">
+                                <div class="option" onclick="setVersion('latest');">Latest</div>
+                                <div class="option" onclick="setVersion('stable');">Stable</div>
+                            </div>
                         </div>
                         </div>
                     </div>
                     </div>
                 </div>
                 </div>
             </div>
             </div>
-        </div>
 
 
-        <div class="category right">
-            <div class="button select"> <span id="currentScript1030">Scenes</span>
-                <div class="toDisplayBig">
-                    <ul id="scriptsList1030">
-                    </ul>
+            <div class="category right">
+                <div class="button select">
+                    <span id="currentScript1030">Scenes</span>
+                    <div class="toDisplayBig">
+                        <ul id="scriptsList1030">
+                        </ul>
+                    </div>
                 </div>
                 </div>
             </div>
             </div>
-        </div>
-        <div class="save-message" id="saveMessage">
-            This PG has missing metadata. Click save to add them.
-        </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>
-                </div>
+            <div class="save-message" id="saveMessage">
+                This PG has missing metadata. Click save to add them.
             </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="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>
-                    </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" 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 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">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
-                    <div class="option" id="metadataButton750">Metadata</div>
-                    <div class="option subSelect"><span id="currentVersion750">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub">
-                            <div class="option" onclick="setVersion('latest');">Latest</div>
-                            <div class="option" onclick="setVersion('stable');">Stable</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>
+                        </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 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">Debug layer
+                            <i class="fa fa-square-o" aria-hidden="true"></i>
+                        </div>
+                        <div class="option" id="metadataButton750">Metadata</div>
+                        <div class="option subSelect">
+                            <span id="currentVersion750">Vers. : Latest</span>
+                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub">
+                                <div class="option" onclick="setVersion('latest');">Latest</div>
+                                <div class="option" onclick="setVersion('stable');">Stable</div>
+                            </div>
                         </div>
                         </div>
                     </div>
                     </div>
                 </div>
                 </div>
             </div>
             </div>
-        </div>
 
 
-        <div class="category right">
-            <div class="button select"> <span id="currentScript750">Scenes</span>
-                <div class="toDisplayBig">
-                    <ul id="scriptsList750">
-                    </ul>
+            <div class="category right">
+                <div class="button select">
+                    <span id="currentScript750">Scenes</span>
+                    <div class="toDisplayBig">
+                        <ul id="scriptsList750">
+                        </ul>
+                    </div>
                 </div>
                 </div>
             </div>
             </div>
+            <div class="save-message" id="saveMessage">
+                This PG has missing metadata. Click save to add them.
+            </div>
         </div>
         </div>
-        <div class="save-message" id="saveMessage">
-            This PG has missing metadata. Click save to add them.
-        </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>
 
 
-    <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>
+        <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>
 
 
-    <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>
         </div>
-    </div>
 
 
-    <script src="https://code.jquery.com/jquery.js"></script>
+        <script src="https://code.jquery.com/jquery.js"></script>
 
 
-    <script>
-        Split(['#jsEditor', '#canvasZone']);
-    </script>
+        <script>
+            Split(['#jsEditor', '#canvasZone']);
+        </script>
 
 
-    <script src="js/actions.js"></script>
-    <script src="js/pbt.js"></script>
-    <script src="js/index.js"></script>
-</body>
+        <script src="js/actions.js"></script>
+        <script src="js/pbt.js"></script>
+        <script src="js/index.js"></script>
+    </body>
 
 
-</html>
+</html>

File diff suppressed because it is too large
+ 892574 - 0
Playground/scenes/dummy2.babylon


BIN
Playground/sounds/cellolong.wav


BIN
Playground/sounds/violons18.wav


+ 13 - 1
Tools/Gulp/config.json

@@ -16,7 +16,19 @@
         "srcOutputDirectory": "../../src/",
         "srcOutputDirectory": "../../src/",
         "currentConfig": "all",
         "currentConfig": "all",
         "typedocJSON": "../../.temp/babylon.typedoc.json",
         "typedocJSON": "../../.temp/babylon.typedoc.json",
-        "typedocValidationBaseline": "../../dist/preview release/typedocValidationBaseline.json"
+        "typedocValidationBaseline": "../../dist/preview release/typedocValidationBaseline.json",
+        "dependencies": [
+            {
+                "name": "CANNON",
+                "module": "cannon",
+                "optional": true
+            },
+            {
+                "name": "OIMO",
+                "module": "oimo",
+                "optional": true
+            }
+        ]
     },
     },
     "buildConfigurations": {
     "buildConfigurations": {
         "all": [
         "all": [

+ 60 - 37
Tools/Gulp/gulp-addModuleExports.js

@@ -5,8 +5,10 @@ var through = require('through2');
  * The parameters for this function has grown during development.
  * The parameters for this function has grown during development.
  * Eventually, this function will need to be reorganized. 
  * Eventually, this function will need to be reorganized. 
  */
  */
-module.exports = function (varName, subModule, extendsRoot, externalUsingBabylon, noBabylonInit) {
+//  subModule, extendsRoot, externalUsingBabylon, noBabylonInit
+module.exports = function (varName, config) {
     return through.obj(function (file, enc, cb) {
     return through.obj(function (file, enc, cb) {
+        config = config || {};
         if (typeof varName === 'string') {
         if (typeof varName === 'string') {
             varName = {
             varName = {
                 name: varName,
                 name: varName,
@@ -16,51 +18,74 @@ module.exports = function (varName, subModule, extendsRoot, externalUsingBabylon
                 varName.module = 'babylonjs';
                 varName.module = 'babylonjs';
             }
             }
         }
         }
+        if (!config.dependencies) {
+            if (config.subModule || config.extendsRoot) {
+                config.dependencies = [
+                    {
+                        name: "BABYLON",
+                        module: "babylonjs",
+                        optional: false
+                    }
+                ]
+            }
+        }
 
 
         function moduleExportAddition(varName) {
         function moduleExportAddition(varName) {
 
 
-            let base = subModule ? 'BABYLON' : varName.name;
+            let dependenciesDefinition = `var amdDependencies = [];`;
+            let functionVariables = '';
+            let requireText = '';
+            let amdText = '';
+            let afterInitText = '';
+            if (config.dependencies) {
+                config.dependencies.forEach(dep => {
+                    if (functionVariables) functionVariables += ',';
+                    functionVariables += dep.name;
+                    requireText += `        ${dep.optional ? ' try { ' : ''} ${dep.name} = ${dep.name} || require("${dep.module}"); ${dep.optional ? ' } catch(e) {} ' : ''}
+`;
+                    amdText += `        ${dep.optional ? ' if(require.specified && require.specified("' + dep.module + '"))' : ''} amdDependencies.push("${dep.module}");
+`;
+                    dependenciesDefinition += `
+    var ${dep.name} = root.${dep.name};`;
+                    afterInitText += `  ${dep.name} = ${dep.name} || this.${dep.name};
+`
+                });
+
+            }
+
+            let base = config.subModule ? 'BABYLON' : varName.name;
 
 
             return `\n\n(function universalModuleDefinition(root, factory) {
             return `\n\n(function universalModuleDefinition(root, factory) {
-    if(typeof exports === 'object' && typeof module === 'object')
-        module.exports = factory(${subModule || extendsRoot ? 'require("babylonjs")' : ''});
-    else if(typeof define === 'function' && define.amd)
-        define("${varName.module}", ${subModule || extendsRoot ? '["babylonjs"],' : '[],'} factory);
-    else if(typeof exports === 'object')
-        exports["${varName.module}"] = factory(${subModule || extendsRoot ? 'require("babylonjs")' : ''});
-    else {
-        root["${base}"]${(subModule && !extendsRoot) ? '["' + varName.name + '"]' : ''} = factory(root["BABYLON"]);
+    ${dependenciesDefinition}
+    if(typeof exports === 'object' && typeof module === 'object') {
+${requireText}
+        module.exports = factory(${functionVariables});
+    } else if(typeof define === 'function' && define.amd) {
+${amdText}
+        define("${varName.module}", amdDependencies, factory);
+    } else if(typeof exports === 'object') {
+${requireText}
+        exports["${varName.module}"] = factory(${functionVariables});
+    } else {
+        root["${base}"]${(config.subModule && !config.extendsRoot) ? '["' + varName.name + '"]' : ''} = factory(${functionVariables});
     }
     }
-})(this, function(${varName.name === 'BABYLON' || noBabylonInit ? '' : 'BABYLON'}) {
-    ${String(file.contents)}
+})(this, function(${functionVariables}) {
+${afterInitText}
+${String(file.contents)}
     ${varName.name === 'BABYLON' || varName.name === 'INSPECTOR' ? `
     ${varName.name === 'BABYLON' || varName.name === 'INSPECTOR' ? `
 var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : this);
 var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : this);
 globalObject["${varName.name}"] = ${varName.name}` : ''}
 globalObject["${varName.name}"] = ${varName.name}` : ''}
-    return ${base}${(subModule && !extendsRoot) ? '.' + varName.name : ''};
+    return ${base}${(config.subModule && !config.extendsRoot) ? '.' + varName.name : ''};
 });
 });
 `;
 `;
         }
         }
 
 
         var extendsAddition =
         var extendsAddition =
-            `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 __extends=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,o){t.__proto__=o}||function(t,o){for(var n in o)o.hasOwnProperty(n)&&(t[n]=o[n])};return function(o,n){function r(){this.constructor=o}t(o,n),o.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();
+`;
 
 
-        var decorateAddition =
-            'var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\n' +
-            'var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n' +
-            'if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);\n' +
-            'else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n' +
-            'return c > 3 && r && Object.defineProperty(target, key, r), r;\n' +
-            '};\n';
+        var decorateAddition = `var __decorate=this&&this.__decorate||function(e,t,r,c){var o,f=arguments.length,n=f<3?t:null===c?c=Object.getOwnPropertyDescriptor(t,r):c;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(e,t,r,c);else for(var l=e.length-1;l>=0;l--)(o=e[l])&&(n=(f<3?o(n):f>3?o(t,r,n):o(t,r))||n);return f>3&&n&&Object.defineProperty(t,r,n),n};
+`;
 
 
         if (file.isNull()) {
         if (file.isNull()) {
             cb(null, file);
             cb(null, file);
@@ -72,14 +97,12 @@ globalObject["${varName.name}"] = ${varName.name}` : ''}
             return;
             return;
         }
         }
 
 
-        var optionalRequire = '';
-
         try {
         try {
-            if (externalUsingBabylon) {
-                file.contents = new Buffer(optionalRequire.concat(new Buffer(String('').concat(moduleExportAddition(varName)))));
+            if (config.externalUsingBabylon) {
+                file.contents = new Buffer(String('').concat(moduleExportAddition(varName)));
             } else {
             } else {
-                let pretext = subModule ? optionalRequire : '';
-                file.contents = new Buffer(pretext.concat(decorateAddition).concat(new Buffer(extendsAddition.concat(String('')).concat(moduleExportAddition(varName)))));
+                let pretext = '';
+                file.contents = new Buffer(decorateAddition.concat(new Buffer(extendsAddition.concat(String('')).concat(moduleExportAddition(varName)))));
             }
             }
             this.push(file);
             this.push(file);
         } catch (err) {
         } catch (err) {

+ 11 - 7
Tools/Gulp/gulpfile.js

@@ -217,7 +217,9 @@ gulp.task("buildWorker", ["workers", "shaders"], function () {
         .pipe(cleants())
         .pipe(cleants())
         .pipe(replace(extendsSearchRegex, ""))
         .pipe(replace(extendsSearchRegex, ""))
         .pipe(replace(decorateSearchRegex, ""))
         .pipe(replace(decorateSearchRegex, ""))
-        .pipe(addModuleExports("BABYLON"))
+        .pipe(addModuleExports("BABYLON", {
+            dependencies: config.build.dependencies
+        }))
         .pipe(uglify())
         .pipe(uglify())
         .pipe(optimisejs())
         .pipe(optimisejs())
         .pipe(gulp.dest(config.build.outputDirectory));
         .pipe(gulp.dest(config.build.outputDirectory));
@@ -239,7 +241,9 @@ gulp.task("build", ["shaders"], function () {
             .pipe(cleants())
             .pipe(cleants())
             .pipe(replace(extendsSearchRegex, ""))
             .pipe(replace(extendsSearchRegex, ""))
             .pipe(replace(decorateSearchRegex, ""))
             .pipe(replace(decorateSearchRegex, ""))
-            .pipe(addModuleExports("BABYLON"))
+            .pipe(addModuleExports("BABYLON", {
+                dependencies: config.build.dependencies
+            }))
             .pipe(gulp.dest(config.build.outputDirectory))
             .pipe(gulp.dest(config.build.outputDirectory))
             .pipe(rename(config.build.minFilename))
             .pipe(rename(config.build.minFilename))
             .pipe(uglify())
             .pipe(uglify())
@@ -316,7 +320,7 @@ var buildExternalLibraries = function (settings) {
                 .pipe(replace(extendsSearchRegex, ""))
                 .pipe(replace(extendsSearchRegex, ""))
                 .pipe(replace(decorateSearchRegex, ""))
                 .pipe(replace(decorateSearchRegex, ""))
                 .pipe(replace(referenceSearchRegex, ""))
                 .pipe(replace(referenceSearchRegex, ""))
-                .pipe(addModuleExports(settings.build.moduleDeclaration, true, settings.build.extendsRoot))
+                .pipe(addModuleExports(settings.build.moduleDeclaration, { subModule: true, extendsRoot: settings.build.extendsRoot }))
                 .pipe(gulp.dest(outputDirectory))
                 .pipe(gulp.dest(outputDirectory))
                 .pipe(cleants())
                 .pipe(cleants())
                 .pipe(rename({ extname: ".min.js" }))
                 .pipe(rename({ extname: ".min.js" }))
@@ -395,7 +399,7 @@ var buildExternalLibrary = function (library, settings, watch) {
         if (library.buildAsModule) {
         if (library.buildAsModule) {
             code = code.pipe(replace(extendsSearchRegex, ""))
             code = code.pipe(replace(extendsSearchRegex, ""))
                 .pipe(replace(decorateSearchRegex, ""))
                 .pipe(replace(decorateSearchRegex, ""))
-                .pipe(addModuleExports(library.moduleDeclaration, true, library.extendsRoot))
+                .pipe(addModuleExports(library.moduleDeclaration, { subModule: true, extendsRoot: library.extendsRoot }))
         }
         }
 
 
         code = code.pipe(gulp.dest(outputDirectory))
         code = code.pipe(gulp.dest(outputDirectory))
@@ -433,7 +437,7 @@ var buildExternalLibrary = function (library, settings, watch) {
             let wpBuild = webpack(require(library.webpack));
             let wpBuild = webpack(require(library.webpack));
             if (settings.build.outputs) {
             if (settings.build.outputs) {
                 let build = wpBuild
                 let build = wpBuild
-                    .pipe(addModuleExports(library.moduleDeclaration, false, false, true, library.babylonIncluded));
+                    .pipe(addModuleExports(library.moduleDeclaration, { subModule: false, extendsRoot: false, externalUsingBabylon: true, noBabylonInit: library.babylonIncluded }));
 
 
                 let unminifiedOutpus = [];
                 let unminifiedOutpus = [];
                 let minifiedOutputs = [];
                 let minifiedOutputs = [];
@@ -482,7 +486,7 @@ var buildExternalLibrary = function (library, settings, watch) {
                 sequence.push(
                 sequence.push(
                     wpBuild
                     wpBuild
                         .pipe(rename(library.output.replace(".js", library.noBundleInName ? '.js' : ".bundle.js")))
                         .pipe(rename(library.output.replace(".js", library.noBundleInName ? '.js' : ".bundle.js")))
-                        .pipe(addModuleExports(library.moduleDeclaration, false, library.extendsRoot, true))
+                        .pipe(addModuleExports(library.moduleDeclaration, { subModule: false, extendsRoot: library.extendsRoot, externalUsingBabylon: true }))
                         .pipe(uglify())
                         .pipe(uglify())
                         .pipe(optimisejs())
                         .pipe(optimisejs())
                         .pipe(gulp.dest(outputDirectory))
                         .pipe(gulp.dest(outputDirectory))
@@ -625,7 +629,7 @@ gulp.task("webserver", function () {
     var options = {
     var options = {
         port: 1338,
         port: 1338,
         livereload: false,
         livereload: false,
-        
+
     };
     };
 
 
     if (commandLineOptions.public) {
     if (commandLineOptions.public) {

+ 1 - 1
Viewer/dist/basicExample.html

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

+ 1 - 0
Viewer/src/configuration/configuration.ts

@@ -68,6 +68,7 @@ export interface ViewerConfiguration {
 
 
 export interface IModelConfiguration {
 export interface IModelConfiguration {
     url?: string;
     url?: string;
+    root?: string; //optional
     loader?: string; // obj, gltf?
     loader?: string; // obj, gltf?
     position?: { x: number, y: number, z: number };
     position?: { x: number, y: number, z: number };
     rotation?: { x: number, y: number, z: number, w?: number };
     rotation?: { x: number, y: number, z: number, w?: number };

+ 14 - 8
Viewer/src/configuration/loader.ts

@@ -11,7 +11,7 @@ export class ConfigurationLoader {
 
 
     private loadRequests: Array<IFileRequest>;
     private loadRequests: Array<IFileRequest>;
 
 
-    constructor() {
+    constructor(private _enableCache: boolean = false) {
         this.configurationCache = {};
         this.configurationCache = {};
         this.loadRequests = [];
         this.loadRequests = [];
     }
     }
@@ -73,24 +73,30 @@ export class ConfigurationLoader {
         this.loadRequests.forEach(request => {
         this.loadRequests.forEach(request => {
             request.abort();
             request.abort();
         });
         });
+        this.loadRequests.length = 0;
     }
     }
 
 
     private loadFile(url: string): Promise<any> {
     private loadFile(url: string): Promise<any> {
         let cacheReference = this.configurationCache;
         let cacheReference = this.configurationCache;
-        if (cacheReference[url]) {
+        if (this._enableCache && cacheReference[url]) {
             return Promise.resolve(cacheReference[url]);
             return Promise.resolve(cacheReference[url]);
         }
         }
 
 
         return new Promise((resolve, reject) => {
         return new Promise((resolve, reject) => {
-            let fileRequest = Tools.LoadFile(url, resolve, undefined, undefined, false, (request, error: any) => {
+            let fileRequest = Tools.LoadFile(url, (result) => {
+                let idx = this.loadRequests.indexOf(fileRequest);
+                if (idx !== -1)
+                    this.loadRequests.splice(idx, 1);
+                if (this._enableCache) cacheReference[url] = result;
+                resolve(result);
+            }, undefined, undefined, false, (request, error: any) => {
+                let idx = this.loadRequests.indexOf(fileRequest);
+                if (idx !== -1)
+                    this.loadRequests.splice(idx, 1);
                 reject(error);
                 reject(error);
             });
             });
             this.loadRequests.push(fileRequest);
             this.loadRequests.push(fileRequest);
         });
         });
     }
     }
 
 
-}
-
-export let configurationLoader = new ConfigurationLoader();
-
-export default configurationLoader;
+}

+ 4 - 0
Viewer/src/configuration/mappers.ts

@@ -118,6 +118,10 @@ export class MapperManager {
         this.mappers[type] = mapper;
         this.mappers[type] = mapper;
     }
     }
 
 
+    public dispose() {
+        this.mappers = {};
+    }
+
 }
 }
 
 
 export let mapperManager = new MapperManager();
 export let mapperManager = new MapperManager();

+ 4 - 0
Viewer/src/eventManager.ts

@@ -37,4 +37,8 @@ export class EventManager {
             callbackDef.callback(data);
             callbackDef.callback(data);
         });
         });
     }
     }
+
+    public dispose() {
+        this.callbacksContainer = {};
+    }
 }
 }

+ 16 - 3
Viewer/src/index.ts

@@ -1,7 +1,13 @@
+/// <reference path="../../dist/preview release/babylon.d.ts"/>
+/// <reference path="../../dist/babylon.glTF2Interface.d.ts"/>
+/// <reference path="../../dist/preview release/loaders/babylon.glTFFileLoader.d.ts"/>
+
 import { mapperManager } from './configuration/mappers';
 import { mapperManager } from './configuration/mappers';
 import { viewerManager } from './viewer/viewerManager';
 import { viewerManager } from './viewer/viewerManager';
 import { DefaultViewer } from './viewer/defaultViewer';
 import { DefaultViewer } from './viewer/defaultViewer';
 import { AbstractViewer } from './viewer/viewer';
 import { AbstractViewer } from './viewer/viewer';
+import { ModelLoader } from './model/modelLoader';
+import { ViewerModel } from './model/viewerModel';
 
 
 /**
 /**
  * BabylonJS Viewer
  * BabylonJS Viewer
@@ -22,10 +28,17 @@ import { InitTags } from './initializer';
 PromisePolyfill.Apply();
 PromisePolyfill.Apply();
 
 
 export let disableInit: boolean = false;
 export let disableInit: boolean = false;
-document.addEventListener("DOMContentLoaded", function (event) {
+document.addEventListener("DOMContentLoaded", init);
+function init(event) {
+    document.removeEventListener("DOMContentLoaded", init);
     if (disableInit) return;
     if (disableInit) return;
     InitTags();
     InitTags();
-});
+}
+
+function disposeAll() {
+    viewerManager.dispose();
+    mapperManager.dispose();
+}
 
 
 // public API for initialization
 // public API for initialization
-export { InitTags, DefaultViewer, AbstractViewer, viewerManager, mapperManager };
+export { InitTags, DefaultViewer, AbstractViewer, viewerManager, mapperManager, disposeAll, ModelLoader, ViewerModel };

+ 3 - 2
Viewer/src/model/modelAnimation.ts

@@ -1,4 +1,4 @@
-import { AnimationGroup, Animatable, Skeleton, IDisposable } from "babylonjs";
+import { AnimationGroup, Animatable, Skeleton } from "babylonjs";
 
 
 export enum AnimationPlayMode {
 export enum AnimationPlayMode {
     ONCE,
     ONCE,
@@ -13,7 +13,7 @@ export enum AnimationState {
     ENDED
     ENDED
 }
 }
 
 
-export interface IModelAnimation extends IDisposable {
+export interface IModelAnimation {
     readonly state: AnimationState;
     readonly state: AnimationState;
     readonly name: string;
     readonly name: string;
     readonly frames: number;
     readonly frames: number;
@@ -27,6 +27,7 @@ export interface IModelAnimation extends IDisposable {
     reset();
     reset();
     restart();
     restart();
     goToFrame(frameNumber: number);
     goToFrame(frameNumber: number);
+    dispose();
 }
 }
 
 
 export class GroupModelAnimation implements IModelAnimation {
 export class GroupModelAnimation implements IModelAnimation {

+ 37 - 0
Viewer/src/model/modelLoader.ts

@@ -0,0 +1,37 @@
+import { AbstractViewer } from "..";
+import { ISceneLoaderPlugin, ISceneLoaderPluginAsync, Tools, SceneLoader, Tags, GLTFFileLoader } from "babylonjs";
+import { IModelConfiguration } from "../configuration/configuration";
+import { ViewerModel, ModelState } from "./viewerModel";
+
+export class ModelLoader {
+
+    private _loadId: number;
+    private _disposed = false;
+
+    private _loaders: Array<ISceneLoaderPlugin | ISceneLoaderPluginAsync>;
+
+    constructor(private _viewer: AbstractViewer) {
+        this._loaders = [];
+        this._loadId = 0;
+    }
+
+    public load(modelConfiguration: IModelConfiguration): ViewerModel {
+
+        const model = new ViewerModel(this._viewer.scene, modelConfiguration);
+
+        model.loadId = this._loadId++;
+        this._loaders.push(model.loader);
+
+        return model;
+    }
+
+    public dispose() {
+        this._loaders.forEach(loader => {
+            if (loader.name === "gltf") {
+                (<GLTFFileLoader>loader).dispose();
+            }
+        });
+        this._loaders.length = 0;
+        this._disposed = true;
+    }
+}

+ 222 - 49
Viewer/src/model/viewerModel.ts

@@ -1,25 +1,47 @@
-import { ISceneLoaderPlugin, ISceneLoaderPluginAsync, AnimationGroup, Animatable, AbstractMesh, Tools, Scene, SceneLoader, Observable, SceneLoaderProgressEvent, Tags, ParticleSystem, Skeleton, IDisposable, Nullable, Animation } from "babylonjs";
+import { ISceneLoaderPlugin, ISceneLoaderPluginAsync, AnimationGroup, Animatable, AbstractMesh, Tools, Scene, SceneLoader, Observable, SceneLoaderProgressEvent, Tags, ParticleSystem, Skeleton, IDisposable, Nullable, Animation, GLTFFileLoader, Quaternion } from "babylonjs";
 import { IModelConfiguration } from "../configuration/configuration";
 import { IModelConfiguration } from "../configuration/configuration";
 import { IModelAnimation, GroupModelAnimation, AnimationPlayMode } from "./modelAnimation";
 import { IModelAnimation, GroupModelAnimation, AnimationPlayMode } from "./modelAnimation";
 
 
+import * as deepmerge from '../../assets/deepmerge.min.js';
+
+export enum ModelState {
+    INIT,
+    LOADING,
+    LOADED,
+    CANCELED,
+    ERROR
+}
+
 export class ViewerModel implements IDisposable {
 export class ViewerModel implements IDisposable {
 
 
     public loader: ISceneLoaderPlugin | ISceneLoaderPluginAsync;
     public loader: ISceneLoaderPlugin | ISceneLoaderPluginAsync;
 
 
     private _animations: Array<IModelAnimation>;
     private _animations: Array<IModelAnimation>;
-    public meshes: Array<AbstractMesh>;
-    public particleSystems: Array<ParticleSystem>;
-    public skeletons: Array<Skeleton>;
+    public meshes: Array<AbstractMesh> = [];
+    public rootMesh: AbstractMesh;
+    public particleSystems: Array<ParticleSystem> = [];
+    public skeletons: Array<Skeleton> = [];
     public currentAnimation: IModelAnimation;
     public currentAnimation: IModelAnimation;
 
 
     public onLoadedObservable: Observable<ViewerModel>;
     public onLoadedObservable: Observable<ViewerModel>;
     public onLoadProgressObservable: Observable<SceneLoaderProgressEvent>;
     public onLoadProgressObservable: Observable<SceneLoaderProgressEvent>;
     public onLoadErrorObservable: Observable<{ message: string; exception: any }>;
     public onLoadErrorObservable: Observable<{ message: string; exception: any }>;
 
 
-    constructor(private _modelConfiguration: IModelConfiguration, private _scene: Scene, disableAutoLoad = false) {
+    public onAfterConfigure: Observable<ViewerModel>;
+
+    public state: ModelState;
+    public loadId: number;
+
+    private _loaderDisposed: boolean = false;
+    private _loadedUrl: string;
+
+    constructor(private _scene: Scene, private _modelConfiguration: IModelConfiguration, disableAutoLoad = false) {
         this.onLoadedObservable = new Observable();
         this.onLoadedObservable = new Observable();
         this.onLoadErrorObservable = new Observable();
         this.onLoadErrorObservable = new Observable();
         this.onLoadProgressObservable = new Observable();
         this.onLoadProgressObservable = new Observable();
+        this.onAfterConfigure = new Observable();
+
+        this.state = ModelState.INIT;
 
 
         this._animations = [];
         this._animations = [];
 
 
@@ -36,9 +58,71 @@ export class ViewerModel implements IDisposable {
         }
         }
     }
     }
 
 
-    //public getAnimations() {
-    //    return this._animations;
-    //}
+    public cancelLoad() {
+        // ATM only available in the GLTF Loader
+        if (this.loader && this.loader.name === "gltf") {
+            let gltfLoader = (<GLTFFileLoader>this.loader);
+            gltfLoader.dispose();
+            this.state = ModelState.CANCELED;
+        }
+    }
+
+    public get configuration(): IModelConfiguration {
+        return this._modelConfiguration;
+    }
+
+    public set configuration(newConfiguration: IModelConfiguration) {
+        this._modelConfiguration = newConfiguration;
+        this._configureModel();
+    }
+
+    public updateConfiguration(newConfiguration: Partial<IModelConfiguration>) {
+        this._modelConfiguration = deepmerge(this._modelConfiguration, newConfiguration);
+        this._configureModel();
+    }
+
+    public initAnimations() {
+        this._animations.forEach(a => {
+            a.dispose();
+        });
+        this._animations.length = 0;
+
+        // check if this is not a gltf loader and init the animations
+        if (this.loader.name !== 'gltf') {
+            this.skeletons.forEach((skeleton, idx) => {
+                let ag = new AnimationGroup("animation-" + idx, this._scene);
+                skeleton.getAnimatables().forEach(a => {
+                    if (a.animations[0]) {
+                        ag.addTargetedAnimation(a.animations[0], a);
+                    }
+                });
+                this.addAnimationGroup(ag);
+            });
+        }
+
+        if (!this._modelConfiguration) return;
+
+        if (this._modelConfiguration.animation) {
+            if (this._modelConfiguration.animation.playOnce) {
+                this._animations.forEach(a => {
+                    a.playMode = AnimationPlayMode.ONCE;
+                });
+            }
+            if (this._modelConfiguration.animation.autoStart && this._animations.length) {
+                let animationName = this._modelConfiguration.animation.autoStart === true ?
+                    this._animations[0].name : this._modelConfiguration.animation.autoStart;
+                this.playAnimation(animationName);
+            }
+        }
+    }
+
+    public addAnimationGroup(animationGroup: AnimationGroup) {
+        this._animations.push(new GroupModelAnimation(animationGroup));
+    }
+
+    public getAnimations() {
+        return this._animations;
+    }
 
 
     public getAnimationNames() {
     public getAnimationNames() {
         return this._animations.map(a => a.name);
         return this._animations.map(a => a.name);
@@ -69,18 +153,116 @@ export class ViewerModel implements IDisposable {
         }
         }
     }
     }
 
 
+    private _configureModel() {
+        let meshesWithNoParent: Array<AbstractMesh> = this.meshes.filter(m => !m.parent);
+        let updateMeshesWithNoParent = (variable: string, value: any, param?: string) => {
+            meshesWithNoParent.forEach(mesh => {
+                if (param) {
+                    mesh[variable][param] = value;
+                } else {
+                    mesh[variable] = value;
+                }
+            });
+        }
+        let updateXYZ = (variable: string, configValues: { x: number, y: number, z: number, w?: number }) => {
+            if (configValues.x !== undefined) {
+                updateMeshesWithNoParent(variable, configValues.x, 'x');
+            }
+            if (configValues.y !== undefined) {
+                updateMeshesWithNoParent(variable, configValues.y, 'y');
+            }
+            if (configValues.z !== undefined) {
+                updateMeshesWithNoParent(variable, configValues.z, 'z');
+            }
+            if (configValues.w !== undefined) {
+                updateMeshesWithNoParent(variable, configValues.w, 'w');
+            }
+        }
+        // position?
+        if (this._modelConfiguration.position) {
+            updateXYZ('position', this._modelConfiguration.position);
+        }
+        if (this._modelConfiguration.rotation) {
+            //quaternion?
+            if (this._modelConfiguration.rotation.w) {
+                meshesWithNoParent.forEach(mesh => {
+                    if (!mesh.rotationQuaternion) {
+                        mesh.rotationQuaternion = new Quaternion();
+                    }
+                })
+                updateXYZ('rotationQuaternion', this._modelConfiguration.rotation);
+            } else {
+                updateXYZ('rotation', this._modelConfiguration.rotation);
+            }
+        }
+        if (this._modelConfiguration.scaling) {
+            updateXYZ('scaling', this._modelConfiguration.scaling);
+        }
+
+        if (this._modelConfiguration.castShadow) {
+            this.meshes.forEach(mesh => {
+                Tags.AddTagsTo(mesh, 'castShadow');
+            });
+        }
+
+        if (this._modelConfiguration.normalize) {
+            let center = false;
+            let unitSize = false;
+            let parentIndex;
+            if (this._modelConfiguration.normalize === true) {
+                center = true;
+                unitSize = true;
+                parentIndex = 0;
+            } else {
+                center = !!this._modelConfiguration.normalize.center;
+                unitSize = !!this._modelConfiguration.normalize.unitSize;
+                parentIndex = this._modelConfiguration.normalize.parentIndex;
+            }
+
+            let meshesToNormalize: Array<AbstractMesh> = [];
+            if (parentIndex !== undefined) {
+                meshesToNormalize.push(this.meshes[parentIndex]);
+            } else {
+                meshesToNormalize = meshesWithNoParent;
+            }
+
+            if (unitSize) {
+                meshesToNormalize.forEach(mesh => {
+                    mesh.normalizeToUnitCube(true);
+                    mesh.computeWorldMatrix(true);
+                });
+            }
+            if (center) {
+                meshesToNormalize.forEach(mesh => {
+                    const boundingInfo = mesh.getHierarchyBoundingVectors(true);
+                    const sizeVec = boundingInfo.max.subtract(boundingInfo.min);
+                    const halfSizeVec = sizeVec.scale(0.5);
+                    const center = boundingInfo.min.add(halfSizeVec);
+                    mesh.position = center.scale(-1);
+
+                    // Set on ground.
+                    mesh.position.y += halfSizeVec.y;
+
+                    // Recompute Info.
+                    mesh.computeWorldMatrix(true);
+                });
+            }
+        }
+        this.onAfterConfigure.notifyObservers(this);
+    }
+
     private _initLoad() {
     private _initLoad() {
-        if (!this._modelConfiguration || !this._modelConfiguration.url) {
-            return Tools.Error("No model URL to load.");
+        if (!this._modelConfiguration.url) {
+            this.state = ModelState.ERROR;
+            Tools.Error("No URL provided");
+            return;
         }
         }
-        let parts = this._modelConfiguration.url.split('/');
-        let filename = parts.pop() || this._modelConfiguration.url;
-        let base = parts.length ? parts.join('/') + '/' : './';
 
 
+        let filename = Tools.GetFilename(this._modelConfiguration.url) || this._modelConfiguration.url;
+        let base = this._modelConfiguration.root || Tools.GetFolderPath(this._modelConfiguration.url);
         let plugin = this._modelConfiguration.loader;
         let plugin = this._modelConfiguration.loader;
+        this._loadedUrl = this._modelConfiguration.url;
 
 
-        //temp solution for animation group handling
-        let animationsArray = this._scene.animationGroups.slice();
 
 
         this.loader = SceneLoader.ImportMesh(undefined, base, filename, this._scene, (meshes, particleSystems, skeletons) => {
         this.loader = SceneLoader.ImportMesh(undefined, base, filename, this._scene, (meshes, particleSystems, skeletons) => {
             meshes.forEach(mesh => {
             meshes.forEach(mesh => {
@@ -90,53 +272,44 @@ export class ViewerModel implements IDisposable {
             this.particleSystems = particleSystems;
             this.particleSystems = particleSystems;
             this.skeletons = skeletons;
             this.skeletons = skeletons;
 
 
-            // check if this is a gltf loader and load the animations
-            if (this.loader.name === 'gltf') {
-                this._scene.animationGroups.forEach(ag => {
-                    // add animations that didn't exist before
-                    if (animationsArray.indexOf(ag) === -1) {
-                        this._animations.push(new GroupModelAnimation(ag));
-                    }
-                })
-            } else {
-                skeletons.forEach((skeleton, idx) => {
-                    let ag = new BABYLON.AnimationGroup("animation-" + idx, this._scene);
-                    skeleton.getAnimatables().forEach(a => {
-                        if (a.animations[0]) {
-                            ag.addTargetedAnimation(a.animations[0], a);
-                        }
-                    });
-                    this._animations.push(new GroupModelAnimation(ag));
-                });
-            }
-
-            if (this._modelConfiguration.animation) {
-                if (this._modelConfiguration.animation.playOnce) {
-                    this._animations.forEach(a => {
-                        a.playMode = AnimationPlayMode.ONCE;
-                    });
-                }
-                if (this._modelConfiguration.animation.autoStart && this._animations.length) {
-                    let animationName = this._modelConfiguration.animation.autoStart === true ?
-                        this._animations[0].name : this._modelConfiguration.animation.autoStart;
-                    this.playAnimation(animationName);
-                }
-            }
-
+            this.initAnimations();
             this.onLoadedObservable.notifyObserversWithPromise(this);
             this.onLoadedObservable.notifyObserversWithPromise(this);
         }, (progressEvent) => {
         }, (progressEvent) => {
             this.onLoadProgressObservable.notifyObserversWithPromise(progressEvent);
             this.onLoadProgressObservable.notifyObserversWithPromise(progressEvent);
         }, (e, m, exception) => {
         }, (e, m, exception) => {
+            this.state = ModelState.ERROR;
+            Tools.Error("Load Error: There was an error loading the model. " + m);
             this.onLoadErrorObservable.notifyObserversWithPromise({ message: m, exception: exception });
             this.onLoadErrorObservable.notifyObserversWithPromise({ message: m, exception: exception });
         }, plugin)!;
         }, plugin)!;
 
 
-        this.loader['animationStartMode'] = 0;
+        if (this.loader.name === "gltf") {
+            let gltfLoader = (<GLTFFileLoader>this.loader);
+            gltfLoader.animationStartMode = 0;
+            gltfLoader.onDispose = () => {
+                this._loaderDisposed = true;
+            }
+            gltfLoader.onAnimationGroupLoaded = ag => {
+                this.addAnimationGroup(ag);
+            }
+        }
+
     }
     }
 
 
     public dispose() {
     public dispose() {
+        this.onAfterConfigure.clear();
+        this.onLoadedObservable.clear();
+        this.onLoadErrorObservable.clear();
+        this.onLoadProgressObservable.clear();
+        if (this.loader && this.loader.name === "gltf") {
+            (<GLTFFileLoader>this.loader).dispose();
+        }
         this.particleSystems.forEach(ps => ps.dispose());
         this.particleSystems.forEach(ps => ps.dispose());
+        this.particleSystems.length = 0;
         this.skeletons.forEach(s => s.dispose());
         this.skeletons.forEach(s => s.dispose());
+        this.skeletons.length = 0;
         this._animations.forEach(ag => ag.dispose());
         this._animations.forEach(ag => ag.dispose());
+        this._animations.length = 0;
         this.meshes.forEach(m => m.dispose());
         this.meshes.forEach(m => m.dispose());
+        this.meshes.length = 0;
     }
     }
 }
 }

+ 21 - 1
Viewer/src/templateManager.ts

@@ -163,6 +163,8 @@ export class TemplateManager {
         Object.keys(this.templates).forEach(template => {
         Object.keys(this.templates).forEach(template => {
             this.templates[template].dispose();
             this.templates[template].dispose();
         });
         });
+        this.templates = {};
+        this.eventManager.dispose();
 
 
         this.onInit.clear();
         this.onInit.clear();
         this.onAllLoaded.clear();
         this.onAllLoaded.clear();
@@ -355,11 +357,23 @@ export class Template {
         this.onStateChange.clear();
         this.onStateChange.clear();
         this.isLoaded = false;
         this.isLoaded = false;
         // remove from parent
         // remove from parent
-        this.parent.removeChild(this.fragment);
+        try {
+            this.parent.removeChild(this.fragment);
+        } catch (e) {
+            //noop
+        }
 
 
         this.loadRequests.forEach(request => {
         this.loadRequests.forEach(request => {
             request.abort();
             request.abort();
         });
         });
+
+        if (this.registeredEvents) {
+            this.registeredEvents.forEach(evt => {
+                evt.htmlElement.removeEventListener(evt.eventName, evt.function);
+            });
+        }
+
+        delete this.fragment;
     }
     }
 
 
     private getTemplateAsHtml(templateConfig: ITemplateConfiguration): Promise<string> {
     private getTemplateAsHtml(templateConfig: ITemplateConfiguration): Promise<string> {
@@ -410,7 +424,13 @@ export class Template {
 
 
                     // if boolean, set the parent as the event listener
                     // if boolean, set the parent as the event listener
                     if (typeof this._configuration.events[eventName] === 'boolean') {
                     if (typeof this._configuration.events[eventName] === 'boolean') {
+                        let binding = functionToFire.bind(this, '#' + this.parent.id);
                         this.parent.addEventListener(eventName, functionToFire.bind(this, '#' + this.parent.id), false);
                         this.parent.addEventListener(eventName, functionToFire.bind(this, '#' + this.parent.id), false);
+                        this.registeredEvents.push({
+                            htmlElement: this.parent,
+                            eventName: eventName,
+                            function: binding
+                        });
                     } else if (typeof this._configuration.events[eventName] === 'object') {
                     } else if (typeof this._configuration.events[eventName] === 'object') {
                         let selectorsArray: Array<string> = Object.keys(this._configuration.events[eventName] || {});
                         let selectorsArray: Array<string> = Object.keys(this._configuration.events[eventName] || {});
                         // strict null checl is working incorrectly, must override:
                         // strict null checl is working incorrectly, must override:

+ 5 - 4
Viewer/src/viewer/defaultViewer.ts

@@ -104,12 +104,12 @@ export class DefaultViewer extends AbstractViewer {
         this.containerElement.style.display = 'flex';
         this.containerElement.style.display = 'flex';
     }
     }
 
 
-    protected configureModel(modelConfiguration: Partial<IModelConfiguration>, model: ViewerModel) {
-        super.configureModel(modelConfiguration, model);
-
+    protected configureTemplate(model: ViewerModel) {
         let navbar = this.templateManager.getTemplate('navBar');
         let navbar = this.templateManager.getTemplate('navBar');
         if (!navbar) return;
         if (!navbar) return;
 
 
+        let modelConfiguration = model.configuration;
+
         let metadataContainer = navbar.parent.querySelector('#model-metadata');
         let metadataContainer = navbar.parent.querySelector('#model-metadata');
         if (metadataContainer) {
         if (metadataContainer) {
             if (modelConfiguration.title !== undefined) {
             if (modelConfiguration.title !== undefined) {
@@ -143,6 +143,7 @@ export class DefaultViewer extends AbstractViewer {
     }
     }
 
 
     private onModelLoaded = (model: ViewerModel) => {
     private onModelLoaded = (model: ViewerModel) => {
+        this.configureTemplate(model);
         // with a short timeout, making sure everything is there already.
         // with a short timeout, making sure everything is there already.
         let hideLoadingDelay = 500;
         let hideLoadingDelay = 500;
         if (this.configuration.lab && this.configuration.lab.hideLoadingDelay !== undefined) {
         if (this.configuration.lab && this.configuration.lab.hideLoadingDelay !== undefined) {
@@ -246,7 +247,7 @@ export class DefaultViewer extends AbstractViewer {
         super.configureLights(lightsConfiguration, model);
         super.configureLights(lightsConfiguration, model);
         // labs feature - flashlight
         // labs feature - flashlight
         if (this.configuration.lab && this.configuration.lab.flashlight) {
         if (this.configuration.lab && this.configuration.lab.flashlight) {
-            let pointerPosition = BABYLON.Vector3.Zero();
+            let pointerPosition = Vector3.Zero();
             let lightTarget;
             let lightTarget;
             let angle = 0.5;
             let angle = 0.5;
             let exponent = Math.PI / 2;
             let exponent = Math.PI / 2;

+ 92 - 142
Viewer/src/viewer/viewer.ts

@@ -1,12 +1,14 @@
 import { viewerManager } from './viewerManager';
 import { viewerManager } from './viewerManager';
 import { TemplateManager } from './../templateManager';
 import { TemplateManager } from './../templateManager';
-import configurationLoader from './../configuration/loader';
-import { CubeTexture, Color3, IEnvironmentHelperOptions, EnvironmentHelper, Effect, SceneOptimizer, SceneOptimizerOptions, Observable, Engine, Scene, ArcRotateCamera, Vector3, SceneLoader, AbstractMesh, Mesh, HemisphericLight, Database, SceneLoaderProgressEvent, ISceneLoaderPlugin, ISceneLoaderPluginAsync, Quaternion, Light, ShadowLight, ShadowGenerator, Tags, AutoRotationBehavior, BouncingBehavior, FramingBehavior, Behavior, Tools } from 'babylonjs';
+import { ConfigurationLoader } from './../configuration/loader';
+import { Skeleton, AnimationGroup, ParticleSystem, CubeTexture, Color3, IEnvironmentHelperOptions, EnvironmentHelper, Effect, SceneOptimizer, SceneOptimizerOptions, Observable, Engine, Scene, ArcRotateCamera, Vector3, SceneLoader, AbstractMesh, Mesh, HemisphericLight, Database, SceneLoaderProgressEvent, ISceneLoaderPlugin, ISceneLoaderPluginAsync, Quaternion, Light, ShadowLight, ShadowGenerator, Tags, AutoRotationBehavior, BouncingBehavior, FramingBehavior, Behavior, Tools } from 'babylonjs';
 import { ViewerConfiguration, ISceneConfiguration, ISceneOptimizerConfiguration, IObserversConfiguration, IModelConfiguration, ISkyboxConfiguration, IGroundConfiguration, ILightConfiguration, ICameraConfiguration } from '../configuration/configuration';
 import { ViewerConfiguration, ISceneConfiguration, ISceneOptimizerConfiguration, IObserversConfiguration, IModelConfiguration, ISkyboxConfiguration, IGroundConfiguration, ILightConfiguration, ICameraConfiguration } from '../configuration/configuration';
 
 
 import * as deepmerge from '../../assets/deepmerge.min.js';
 import * as deepmerge from '../../assets/deepmerge.min.js';
 import { CameraBehavior } from 'src/interfaces';
 import { CameraBehavior } from 'src/interfaces';
 import { ViewerModel } from '../model/viewerModel';
 import { ViewerModel } from '../model/viewerModel';
+import { GroupModelAnimation } from '../model/modelAnimation';
+import { ModelLoader } from '../model/modelLoader';
 
 
 export abstract class AbstractViewer {
 export abstract class AbstractViewer {
 
 
@@ -23,6 +25,7 @@ export abstract class AbstractViewer {
      * The last loader used to load a model. 
      * The last loader used to load a model. 
      */
      */
     public lastUsedLoader: ISceneLoaderPlugin | ISceneLoaderPluginAsync;
     public lastUsedLoader: ISceneLoaderPlugin | ISceneLoaderPluginAsync;
+    public modelLoader: ModelLoader;
 
 
     protected configuration: ViewerConfiguration;
     protected configuration: ViewerConfiguration;
     public environmentHelper: EnvironmentHelper;
     public environmentHelper: EnvironmentHelper;
@@ -33,6 +36,8 @@ export abstract class AbstractViewer {
     protected maxShadows: number;
     protected maxShadows: number;
     private _hdrSupport: boolean;
     private _hdrSupport: boolean;
 
 
+    protected _isDisposed: boolean = false;
+
     public get isHdrSupported() {
     public get isHdrSupported() {
         return this._hdrSupport;
         return this._hdrSupport;
     }
     }
@@ -50,6 +55,7 @@ export abstract class AbstractViewer {
     public canvas: HTMLCanvasElement;
     public canvas: HTMLCanvasElement;
 
 
     protected registeredOnBeforerenderFunctions: Array<() => void>;
     protected registeredOnBeforerenderFunctions: Array<() => void>;
+    protected _configurationLoader: ConfigurationLoader;
 
 
     constructor(public containerElement: HTMLElement, initialConfiguration: ViewerConfiguration = {}) {
     constructor(public containerElement: HTMLElement, initialConfiguration: ViewerConfiguration = {}) {
         // if exists, use the container id. otherwise, generate a random string.
         // if exists, use the container id. otherwise, generate a random string.
@@ -69,6 +75,7 @@ export abstract class AbstractViewer {
 
 
         this.registeredOnBeforerenderFunctions = [];
         this.registeredOnBeforerenderFunctions = [];
         this.models = [];
         this.models = [];
+        this.modelLoader = new ModelLoader(this);
 
 
         // add this viewer to the viewer manager
         // add this viewer to the viewer manager
         viewerManager.addViewer(this);
         viewerManager.addViewer(this);
@@ -79,7 +86,8 @@ export abstract class AbstractViewer {
         this.prepareContainerElement();
         this.prepareContainerElement();
 
 
         // extend the configuration
         // extend the configuration
-        configurationLoader.loadConfiguration(initialConfiguration, (configuration) => {
+        this._configurationLoader = new ConfigurationLoader();
+        this._configurationLoader.loadConfiguration(initialConfiguration, (configuration) => {
             this.configuration = deepmerge(this.configuration || {}, configuration);
             this.configuration = deepmerge(this.configuration || {}, configuration);
             if (this.configuration.observers) {
             if (this.configuration.observers) {
                 this.configureObservers(this.configuration.observers);
                 this.configureObservers(this.configuration.observers);
@@ -522,117 +530,63 @@ export abstract class AbstractViewer {
     }
     }
 
 
     protected configureModel(modelConfiguration: Partial<IModelConfiguration>, model?: ViewerModel) {
     protected configureModel(modelConfiguration: Partial<IModelConfiguration>, model?: ViewerModel) {
-        let focusMeshes = model ? model.meshes : this.scene.meshes;
-        let meshesWithNoParent: Array<AbstractMesh> = focusMeshes.filter(m => !m.parent);
-        let updateMeshesWithNoParent = (variable: string, value: any, param?: string) => {
-            meshesWithNoParent.forEach(mesh => {
-                if (param) {
-                    mesh[variable][param] = value;
-                } else {
-                    mesh[variable] = value;
-                }
-            });
-        }
-        let updateXYZ = (variable: string, configValues: { x: number, y: number, z: number, w?: number }) => {
-            if (configValues.x !== undefined) {
-                updateMeshesWithNoParent(variable, configValues.x, 'x');
-            }
-            if (configValues.y !== undefined) {
-                updateMeshesWithNoParent(variable, configValues.y, 'y');
-            }
-            if (configValues.z !== undefined) {
-                updateMeshesWithNoParent(variable, configValues.z, 'z');
-            }
-            if (configValues.w !== undefined) {
-                updateMeshesWithNoParent(variable, configValues.w, 'w');
-            }
-        }
-        // position?
-        if (modelConfiguration.position) {
-            updateXYZ('position', modelConfiguration.position);
-        }
-        if (modelConfiguration.rotation) {
-            if (modelConfiguration.rotation.w) {
-                meshesWithNoParent.forEach(mesh => {
-                    if (!mesh.rotationQuaternion) {
-                        mesh.rotationQuaternion = new Quaternion();
-                    }
-                })
-                updateXYZ('rotationQuaternion', modelConfiguration.rotation);
-            } else {
-                updateXYZ('rotation', modelConfiguration.rotation);
-            }
-        }
-        if (modelConfiguration.scaling) {
-            updateXYZ('scaling', modelConfiguration.scaling);
-        }
-
-        if (modelConfiguration.castShadow) {
-            focusMeshes.forEach(mesh => {
-                Tags.AddTagsTo(mesh, 'castShadow');
-            });
-        }
-
-        if (modelConfiguration.normalize) {
-            let center = false;
-            let unitSize = false;
-            let parentIndex;
-            if (modelConfiguration.normalize === true) {
-                center = true;
-                unitSize = true;
-                parentIndex = 0;
-            } else {
-                center = !!modelConfiguration.normalize.center;
-                unitSize = !!modelConfiguration.normalize.unitSize;
-                parentIndex = modelConfiguration.normalize.parentIndex;
-            }
-
-            let meshesToNormalize: Array<AbstractMesh> = [];
-            if (parentIndex !== undefined) {
-                meshesToNormalize.push(focusMeshes[parentIndex]);
-            } else {
-                meshesToNormalize = meshesWithNoParent;
-            }
-
-            if (unitSize) {
-                meshesToNormalize.forEach(mesh => {
-                    mesh.normalizeToUnitCube(true);
-                    mesh.computeWorldMatrix(true);
-                });
-            }
-            if (center) {
-                meshesToNormalize.forEach(mesh => {
-                    const boundingInfo = mesh.getHierarchyBoundingVectors(true);
-                    const sizeVec = boundingInfo.max.subtract(boundingInfo.min);
-                    const halfSizeVec = sizeVec.scale(0.5);
-                    const center = boundingInfo.min.add(halfSizeVec);
-                    mesh.position = center.scale(-1);
-
-                    // Set on ground.
-                    mesh.position.y += halfSizeVec.y;
-
-                    // Recompute Info.
-                    mesh.computeWorldMatrix(true);
-                });
-            }
-        }
+        this.models.forEach(model => {
+            model.configuration = modelConfiguration;
+        })
     }
     }
 
 
     public dispose() {
     public dispose() {
+        if (this._isDisposed) {
+            return;
+        }
         window.removeEventListener('resize', this.resize);
         window.removeEventListener('resize', this.resize);
         if (this.sceneOptimizer) {
         if (this.sceneOptimizer) {
             this.sceneOptimizer.stop();
             this.sceneOptimizer.stop();
             this.sceneOptimizer.dispose();
             this.sceneOptimizer.dispose();
         }
         }
 
 
+        if (this.environmentHelper) {
+            this.environmentHelper.dispose();
+        }
+
+        if (this._configurationLoader) {
+            this._configurationLoader.dispose();
+        }
+
+        //observers
+        this.onEngineInitObservable.clear();
+        delete this.onEngineInitObservable;
+        this.onInitDoneObservable.clear();
+        delete this.onInitDoneObservable;
+        this.onLoaderInitObservable.clear();
+        delete this.onLoaderInitObservable;
+        this.onModelLoadedObservable.clear();
+        delete this.onModelLoadedObservable;
+        this.onModelLoadErrorObservable.clear();
+        delete this.onModelLoadErrorObservable;
+        this.onModelLoadProgressObservable.clear();
+        delete this.onModelLoadProgressObservable;
+        this.onSceneInitObservable.clear();
+        delete this.onSceneInitObservable;
+
         if (this.scene.activeCamera) {
         if (this.scene.activeCamera) {
             this.scene.activeCamera.detachControl(this.canvas);
             this.scene.activeCamera.detachControl(this.canvas);
         }
         }
 
 
+        this.modelLoader.dispose();
+
+        this.models.forEach(model => {
+            model.dispose();
+        });
+
+        this.models.length = 0;
+
         this.scene.dispose();
         this.scene.dispose();
         this.engine.dispose();
         this.engine.dispose();
 
 
         this.templateManager.dispose();
         this.templateManager.dispose();
+        viewerManager.removeViewer(this);
+        this._isDisposed = true;
     }
     }
 
 
     protected abstract prepareContainerElement();
     protected abstract prepareContainerElement();
@@ -744,6 +698,43 @@ export abstract class AbstractViewer {
     private isLoading: boolean;
     private isLoading: boolean;
     private nextLoading: Function;
     private nextLoading: Function;
 
 
+    public initModel(modelConfig: any = this.configuration.model, clearScene: boolean = true): ViewerModel {
+        let model = this.modelLoader.load(modelConfig);
+
+        if (clearScene) {
+            this.models.forEach(m => m.dispose());
+            this.models.length = 0;
+        }
+
+        this.models.push(model);
+        this.lastUsedLoader = model.loader;
+        model.onLoadErrorObservable.add((errorObject) => {
+            this.onModelLoadErrorObservable.notifyObserversWithPromise(errorObject);
+        });
+        model.onLoadProgressObservable.add((progressEvent) => {
+            return this.onModelLoadProgressObservable.notifyObserversWithPromise(progressEvent);
+        });
+        this.onLoaderInitObservable.notifyObserversWithPromise(this.lastUsedLoader);
+
+        model.onLoadedObservable.add(() => {
+            this.onModelLoadedObservable.notifyObserversWithPromise(model)
+                .then(() => {
+                    this.configureLights(this.configuration.lights);
+
+                    if (this.configuration.camera) {
+                        this.configureCamera(this.configuration.camera, model);
+                    }
+                    return this.initEnvironment(model);
+                }).then(() => {
+                    this.isLoading = false;
+                    return model;
+                });
+        });
+
+
+        return model;
+    }
+
     public loadModel(modelConfig: any = this.configuration.model, clearScene: boolean = true): Promise<ViewerModel> {
     public loadModel(modelConfig: any = this.configuration.model, clearScene: boolean = true): Promise<ViewerModel> {
         // no model was provided? Do nothing!
         // no model was provided? Do nothing!
         let modelUrl = (typeof modelConfig === 'string') ? modelConfig : modelConfig.url;
         let modelUrl = (typeof modelConfig === 'string') ? modelConfig : modelConfig.url;
@@ -751,12 +742,8 @@ export abstract class AbstractViewer {
             return Promise.reject("no model configuration found");
             return Promise.reject("no model configuration found");
         }
         }
         if (this.isLoading) {
         if (this.isLoading) {
-            //another model is being model. Wait for it to finish, trigger the load afterwards
-            /*this.nextLoading = () => {
-                delete this.nextLoading;
-                return this.loadModel(modelConfig, clearScene);
-            }*/
-            return Promise.reject("sanother model is curently being loaded.");
+            // We can decide here whether or not to cancel the lst load, but the developer can do that.
+            return Promise.reject("another model is curently being loaded.");
         }
         }
         this.isLoading = true;
         this.isLoading = true;
         if ((typeof modelConfig === 'string')) {
         if ((typeof modelConfig === 'string')) {
@@ -773,50 +760,13 @@ export abstract class AbstractViewer {
 
 
         return Promise.resolve(this.scene).then((scene) => {
         return Promise.resolve(this.scene).then((scene) => {
             if (!scene) return this.initScene();
             if (!scene) return this.initScene();
-
-            if (clearScene) {
-                this.models.forEach(m => m.dispose());
-                this.models.length = 0;
-            }
             return scene;
             return scene;
         }).then(() => {
         }).then(() => {
             return new Promise<ViewerModel>((resolve, reject) => {
             return new Promise<ViewerModel>((resolve, reject) => {
                 // at this point, configuration.model is an object, not a string
                 // at this point, configuration.model is an object, not a string
-                let model = new ViewerModel(<IModelConfiguration>this.configuration.model, this.scene);
-                this.models.push(model);
-                this.lastUsedLoader = model.loader;
-                model.onLoadedObservable.add((model) => {
-                    resolve(model);
-                });
-                model.onLoadErrorObservable.add((errorObject) => {
-                    this.onModelLoadErrorObservable.notifyObserversWithPromise(errorObject).then(() => {
-                        reject(errorObject.exception);
-                    });
-                });
-                model.onLoadProgressObservable.add((progressEvent) => {
-                    return this.onModelLoadProgressObservable.notifyObserversWithPromise(progressEvent);
-                });
-                this.onLoaderInitObservable.notifyObserversWithPromise(this.lastUsedLoader);
+                return this.initModel(modelConfig, clearScene);
             });
             });
-        }).then((model: ViewerModel) => {
-            return this.onModelLoadedObservable.notifyObserversWithPromise(model)
-                .then(() => {
-                    // update the models' configuration
-                    this.configureModel(this.configuration.model || modelConfig, model);
-                    this.configureLights(this.configuration.lights);
-
-                    if (this.configuration.camera) {
-                        this.configureCamera(this.configuration.camera, model);
-                    }
-                    return this.initEnvironment(model);
-                }).then(() => {
-                    this.isLoading = false;
-                    /*if (this.nextLoading) {
-                        return this.nextLoading();
-                    }*/
-                    return model;
-                });
-        });
+        })
     }
     }
 
 
     protected initEnvironment(model?: ViewerModel): Promise<Scene> {
     protected initEnvironment(model?: ViewerModel): Promise<Scene> {

+ 14 - 2
Viewer/src/viewer/viewerManager.ts

@@ -1,5 +1,3 @@
-/// <reference path="../../../dist/preview release/babylon.d.ts"/>
-
 import { Observable } from 'babylonjs';
 import { Observable } from 'babylonjs';
 import { AbstractViewer } from './viewer';
 import { AbstractViewer } from './viewer';
 
 
@@ -9,10 +7,12 @@ export class ViewerManager {
 
 
     public onViewerAdded: (viewer: AbstractViewer) => void;
     public onViewerAdded: (viewer: AbstractViewer) => void;
     public onViewerAddedObservable: Observable<AbstractViewer>;
     public onViewerAddedObservable: Observable<AbstractViewer>;
+    public onViewerRemovedObservable: Observable<string>;
 
 
     constructor() {
     constructor() {
         this.viewers = {};
         this.viewers = {};
         this.onViewerAddedObservable = new Observable();
         this.onViewerAddedObservable = new Observable();
+        this.onViewerRemovedObservable = new Observable();
     }
     }
 
 
     public addViewer(viewer: AbstractViewer) {
     public addViewer(viewer: AbstractViewer) {
@@ -20,6 +20,12 @@ export class ViewerManager {
         this._onViewerAdded(viewer);
         this._onViewerAdded(viewer);
     }
     }
 
 
+    public removeViewer(viewer: AbstractViewer) {
+        let id = viewer.getBaseId();
+        delete this.viewers[id];
+        this.onViewerRemovedObservable.notifyObservers(id);
+    }
+
     public getViewerById(id: string): AbstractViewer {
     public getViewerById(id: string): AbstractViewer {
         return this.viewers[id];
         return this.viewers[id];
     }
     }
@@ -52,6 +58,12 @@ export class ViewerManager {
         this.onViewerAdded && this.onViewerAdded(viewer);
         this.onViewerAdded && this.onViewerAdded(viewer);
         this.onViewerAddedObservable.notifyObservers(viewer);
         this.onViewerAddedObservable.notifyObservers(viewer);
     }
     }
+
+    public dispose() {
+        for (let id in this.viewers) {
+            this.viewers[id].dispose();
+        }
+    }
 }
 }
 
 
 export let viewerManager = new ViewerManager();
 export let viewerManager = new ViewerManager();

+ 3 - 1
Viewer/webpack.config.js

@@ -24,7 +24,9 @@ module.exports = {
     },
     },
     externals: {
     externals: {
         // until physics will be integrated in the viewer, ignore cannon
         // until physics will be integrated in the viewer, ignore cannon
-        cannon: 'CANNON'
+        cannon: 'CANNON',
+        oimo: 'OIMO',
+        './Oimo': 'OIMO'
     },
     },
     devtool: 'source-map',
     devtool: 'source-map',
     plugins: [
     plugins: [

+ 1 - 1
dist/preview release/Oimo.js

@@ -1,6 +1,6 @@
 (function (global, factory) {
 (function (global, factory) {
 	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
 	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
-	typeof define === 'function' && define.amd ? define("oimo", ['exports'], factory) :
+	typeof define === 'function' && define.amd ? define(['exports'], factory) :
 	(factory((global.OIMO = global.OIMO || {})));
 	(factory((global.OIMO = global.OIMO || {})));
 }(this, (function (exports) { 'use strict';
 }(this, (function (exports) { 'use strict';
 
 

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


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


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


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


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


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


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


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


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


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

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

+ 4 - 0
dist/preview release/gui/babylon.gui.d.ts

@@ -357,6 +357,10 @@ declare module BABYLON.GUI {
         protected _children: Control[];
         protected _children: Control[];
         protected _measureForChildren: Measure;
         protected _measureForChildren: Measure;
         protected _background: string;
         protected _background: string;
+        protected _adaptWidthToChildren: boolean;
+        protected _adaptHeightToChildren: boolean;
+        adaptHeightToChildren: boolean;
+        adaptWidthToChildren: boolean;
         background: string;
         background: string;
         readonly children: Control[];
         readonly children: Control[];
         constructor(name?: string | undefined);
         constructor(name?: string | undefined);

+ 72 - 26
dist/preview release/gui/babylon.gui.js

@@ -1,33 +1,29 @@
-var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
-var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
-if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
-else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
-return c > 3 && r && Object.defineProperty(target, key, r), r;
-};
-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 __decorate=this&&this.__decorate||function(e,t,r,c){var o,f=arguments.length,n=f<3?t:null===c?c=Object.getOwnPropertyDescriptor(t,r):c;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(e,t,r,c);else for(var l=e.length-1;l>=0;l--)(o=e[l])&&(n=(f<3?o(n):f>3?o(t,r,n):o(t,r))||n);return f>3&&n&&Object.defineProperty(t,r,n),n};
+var __extends=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,o){t.__proto__=o}||function(t,o){for(var n in o)o.hasOwnProperty(n)&&(t[n]=o[n])};return function(o,n){function r(){this.constructor=o}t(o,n),o.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();
+
 
 
 (function universalModuleDefinition(root, factory) {
 (function universalModuleDefinition(root, factory) {
-    if(typeof exports === 'object' && typeof module === 'object')
-        module.exports = factory(require("babylonjs"));
-    else if(typeof define === 'function' && define.amd)
-        define("babylonjs-gui", ["babylonjs"], factory);
-    else if(typeof exports === 'object')
-        exports["babylonjs-gui"] = factory(require("babylonjs"));
-    else {
-        root["BABYLON"]["GUI"] = factory(root["BABYLON"]);
+    var amdDependencies = [];
+    var BABYLON = root.BABYLON;
+    if(typeof exports === 'object' && typeof module === 'object') {
+         BABYLON = BABYLON || require("babylonjs"); 
+
+        module.exports = factory(BABYLON);
+    } else if(typeof define === 'function' && define.amd) {
+         amdDependencies.push("babylonjs");
+
+        define("babylonjs-gui", amdDependencies, factory);
+    } else if(typeof exports === 'object') {
+         BABYLON = BABYLON || require("babylonjs"); 
+
+        exports["babylonjs-gui"] = factory(BABYLON);
+    } else {
+        root["BABYLON"]["GUI"] = factory(BABYLON);
     }
     }
 })(this, function(BABYLON) {
 })(this, function(BABYLON) {
-    "use strict";
+  BABYLON = BABYLON || this.BABYLON;
+
+"use strict";
 /// <reference path="../../dist/preview release/babylon.d.ts"/>
 /// <reference path="../../dist/preview release/babylon.d.ts"/>
 
 
 var BABYLON;
 var BABYLON;
@@ -1994,8 +1990,44 @@ var BABYLON;
                 _this.name = name;
                 _this.name = name;
                 _this._children = new Array();
                 _this._children = new Array();
                 _this._measureForChildren = GUI.Measure.Empty();
                 _this._measureForChildren = GUI.Measure.Empty();
+                _this._adaptWidthToChildren = false;
+                _this._adaptHeightToChildren = false;
                 return _this;
                 return _this;
             }
             }
+            Object.defineProperty(Container.prototype, "adaptHeightToChildren", {
+                get: function () {
+                    return this._adaptHeightToChildren;
+                },
+                set: function (value) {
+                    if (this._adaptHeightToChildren === value) {
+                        return;
+                    }
+                    this._adaptHeightToChildren = value;
+                    if (value) {
+                        this.height = "100%";
+                    }
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Container.prototype, "adaptWidthToChildren", {
+                get: function () {
+                    return this._adaptWidthToChildren;
+                },
+                set: function (value) {
+                    if (this._adaptWidthToChildren === value) {
+                        return;
+                    }
+                    this._adaptWidthToChildren = value;
+                    if (value) {
+                        this.width = "100%";
+                    }
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
             Object.defineProperty(Container.prototype, "background", {
             Object.defineProperty(Container.prototype, "background", {
                 get: function () {
                 get: function () {
                     return this._background;
                     return this._background;
@@ -2119,6 +2151,8 @@ var BABYLON;
                 if (this._processMeasures(parentMeasure, context)) {
                 if (this._processMeasures(parentMeasure, context)) {
                     this._localDraw(context);
                     this._localDraw(context);
                     this._clipForChildren(context);
                     this._clipForChildren(context);
+                    var computedWidth = -1;
+                    var computedHeight = -1;
                     for (var _i = 0, _a = this._children; _i < _a.length; _i++) {
                     for (var _i = 0, _a = this._children; _i < _a.length; _i++) {
                         var child = _a[_i];
                         var child = _a[_i];
                         if (child.isVisible && !child.notRenderable) {
                         if (child.isVisible && !child.notRenderable) {
@@ -2127,8 +2161,20 @@ var BABYLON;
                             if (child.onAfterDrawObservable.hasObservers()) {
                             if (child.onAfterDrawObservable.hasObservers()) {
                                 child.onAfterDrawObservable.notifyObservers(child);
                                 child.onAfterDrawObservable.notifyObservers(child);
                             }
                             }
+                            if (this.adaptWidthToChildren && child._width.isPixel) {
+                                computedWidth = Math.max(computedWidth, child._currentMeasure.width);
+                            }
+                            if (this.adaptHeightToChildren && child._height.isPixel) {
+                                computedHeight = Math.max(computedHeight, child._currentMeasure.height);
+                            }
                         }
                         }
                     }
                     }
+                    if (this.adaptWidthToChildren && computedWidth >= 0) {
+                        this.width = computedWidth + "px";
+                    }
+                    if (this.adaptHeightToChildren && computedHeight >= 0) {
+                        this.height = computedHeight + "px";
+                    }
                 }
                 }
                 context.restore();
                 context.restore();
                 if (this.onAfterDrawObservable.hasObservers()) {
                 if (this.onAfterDrawObservable.hasObservers()) {

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


+ 4 - 0
dist/preview release/gui/babylon.gui.module.d.ts

@@ -363,6 +363,10 @@ declare module BABYLON.GUI {
         protected _children: Control[];
         protected _children: Control[];
         protected _measureForChildren: Measure;
         protected _measureForChildren: Measure;
         protected _background: string;
         protected _background: string;
+        protected _adaptWidthToChildren: boolean;
+        protected _adaptHeightToChildren: boolean;
+        adaptHeightToChildren: boolean;
+        adaptWidthToChildren: boolean;
         background: string;
         background: string;
         readonly children: Control[];
         readonly children: Control[];
         constructor(name?: string | undefined);
         constructor(name?: string | undefined);

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

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

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


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

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

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

@@ -307,6 +307,7 @@ var BABYLON;
             loader.onTextureLoadedObservable.add(function (texture) { return _this.onTextureLoadedObservable.notifyObservers(texture); });
             loader.onTextureLoadedObservable.add(function (texture) { return _this.onTextureLoadedObservable.notifyObservers(texture); });
             loader.onMaterialLoadedObservable.add(function (material) { return _this.onMaterialLoadedObservable.notifyObservers(material); });
             loader.onMaterialLoadedObservable.add(function (material) { return _this.onMaterialLoadedObservable.notifyObservers(material); });
             loader.onExtensionLoadedObservable.add(function (extension) { return _this.onExtensionLoadedObservable.notifyObservers(extension); });
             loader.onExtensionLoadedObservable.add(function (extension) { return _this.onExtensionLoadedObservable.notifyObservers(extension); });
+            loader.onAnimationGroupLoadedObservable.add(function (animationGroup) { return _this.onAnimationGroupLoadedObservable.notifyObservers(animationGroup); });
             loader.onCompleteObservable.add(function () {
             loader.onCompleteObservable.add(function () {
                 _this.onMeshLoadedObservable.clear();
                 _this.onMeshLoadedObservable.clear();
                 _this.onTextureLoadedObservable.clear();
                 _this.onTextureLoadedObservable.clear();

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


+ 5 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -307,6 +307,7 @@ var BABYLON;
             loader.onTextureLoadedObservable.add(function (texture) { return _this.onTextureLoadedObservable.notifyObservers(texture); });
             loader.onTextureLoadedObservable.add(function (texture) { return _this.onTextureLoadedObservable.notifyObservers(texture); });
             loader.onMaterialLoadedObservable.add(function (material) { return _this.onMaterialLoadedObservable.notifyObservers(material); });
             loader.onMaterialLoadedObservable.add(function (material) { return _this.onMaterialLoadedObservable.notifyObservers(material); });
             loader.onExtensionLoadedObservable.add(function (extension) { return _this.onExtensionLoadedObservable.notifyObservers(extension); });
             loader.onExtensionLoadedObservable.add(function (extension) { return _this.onExtensionLoadedObservable.notifyObservers(extension); });
+            loader.onAnimationGroupLoadedObservable.add(function (animationGroup) { return _this.onAnimationGroupLoadedObservable.notifyObservers(animationGroup); });
             loader.onCompleteObservable.add(function () {
             loader.onCompleteObservable.add(function () {
                 _this.onMeshLoadedObservable.clear();
                 _this.onMeshLoadedObservable.clear();
                 _this.onTextureLoadedObservable.clear();
                 _this.onTextureLoadedObservable.clear();
@@ -1792,7 +1793,9 @@ var BABYLON;
                 return (BABYLON.Tools.IsBase64(uri) || uri.indexOf("..") === -1);
                 return (BABYLON.Tools.IsBase64(uri) || uri.indexOf("..") === -1);
             };
             };
             GLTFLoader._GetDrawMode = function (context, mode) {
             GLTFLoader._GetDrawMode = function (context, mode) {
-                mode = mode || 4 /* TRIANGLES */;
+                if (mode == undefined) {
+                    mode = 4 /* TRIANGLES */;
+                }
                 switch (mode) {
                 switch (mode) {
                     case 0 /* POINTS */: return BABYLON.Material.PointListDrawMode;
                     case 0 /* POINTS */: return BABYLON.Material.PointListDrawMode;
                     case 1 /* LINES */: return BABYLON.Material.LineListDrawMode;
                     case 1 /* LINES */: return BABYLON.Material.LineListDrawMode;
@@ -2020,7 +2023,7 @@ var BABYLON;
                                 if (indexLOD !== 0) {
                                 if (indexLOD !== 0) {
                                     var previousNodeLOD = nodeLODs[indexLOD - 1];
                                     var previousNodeLOD = nodeLODs[indexLOD - 1];
                                     if (previousNodeLOD._babylonMesh) {
                                     if (previousNodeLOD._babylonMesh) {
-                                        previousNodeLOD._babylonMesh.dispose();
+                                        previousNodeLOD._babylonMesh.dispose(false, true);
                                         delete previousNodeLOD._babylonMesh;
                                         delete previousNodeLOD._babylonMesh;
                                     }
                                     }
                                 }
                                 }

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


+ 5 - 2
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -307,6 +307,7 @@ var BABYLON;
             loader.onTextureLoadedObservable.add(function (texture) { return _this.onTextureLoadedObservable.notifyObservers(texture); });
             loader.onTextureLoadedObservable.add(function (texture) { return _this.onTextureLoadedObservable.notifyObservers(texture); });
             loader.onMaterialLoadedObservable.add(function (material) { return _this.onMaterialLoadedObservable.notifyObservers(material); });
             loader.onMaterialLoadedObservable.add(function (material) { return _this.onMaterialLoadedObservable.notifyObservers(material); });
             loader.onExtensionLoadedObservable.add(function (extension) { return _this.onExtensionLoadedObservable.notifyObservers(extension); });
             loader.onExtensionLoadedObservable.add(function (extension) { return _this.onExtensionLoadedObservable.notifyObservers(extension); });
+            loader.onAnimationGroupLoadedObservable.add(function (animationGroup) { return _this.onAnimationGroupLoadedObservable.notifyObservers(animationGroup); });
             loader.onCompleteObservable.add(function () {
             loader.onCompleteObservable.add(function () {
                 _this.onMeshLoadedObservable.clear();
                 _this.onMeshLoadedObservable.clear();
                 _this.onTextureLoadedObservable.clear();
                 _this.onTextureLoadedObservable.clear();
@@ -3990,7 +3991,9 @@ var BABYLON;
                 return (BABYLON.Tools.IsBase64(uri) || uri.indexOf("..") === -1);
                 return (BABYLON.Tools.IsBase64(uri) || uri.indexOf("..") === -1);
             };
             };
             GLTFLoader._GetDrawMode = function (context, mode) {
             GLTFLoader._GetDrawMode = function (context, mode) {
-                mode = mode || 4 /* TRIANGLES */;
+                if (mode == undefined) {
+                    mode = 4 /* TRIANGLES */;
+                }
                 switch (mode) {
                 switch (mode) {
                     case 0 /* POINTS */: return BABYLON.Material.PointListDrawMode;
                     case 0 /* POINTS */: return BABYLON.Material.PointListDrawMode;
                     case 1 /* LINES */: return BABYLON.Material.LineListDrawMode;
                     case 1 /* LINES */: return BABYLON.Material.LineListDrawMode;
@@ -4218,7 +4221,7 @@ var BABYLON;
                                 if (indexLOD !== 0) {
                                 if (indexLOD !== 0) {
                                     var previousNodeLOD = nodeLODs[indexLOD - 1];
                                     var previousNodeLOD = nodeLODs[indexLOD - 1];
                                     if (previousNodeLOD._babylonMesh) {
                                     if (previousNodeLOD._babylonMesh) {
-                                        previousNodeLOD._babylonMesh.dispose();
+                                        previousNodeLOD._babylonMesh.dispose(false, true);
                                         delete previousNodeLOD._babylonMesh;
                                         delete previousNodeLOD._babylonMesh;
                                     }
                                     }
                                 }
                                 }

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


+ 27 - 28
dist/preview release/loaders/babylonjs.loaders.js

@@ -1,33 +1,29 @@
-var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
-var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
-if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
-else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
-return c > 3 && r && Object.defineProperty(target, key, r), r;
-};
-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 __decorate=this&&this.__decorate||function(e,t,r,c){var o,f=arguments.length,n=f<3?t:null===c?c=Object.getOwnPropertyDescriptor(t,r):c;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(e,t,r,c);else for(var l=e.length-1;l>=0;l--)(o=e[l])&&(n=(f<3?o(n):f>3?o(t,r,n):o(t,r))||n);return f>3&&n&&Object.defineProperty(t,r,n),n};
+var __extends=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,o){t.__proto__=o}||function(t,o){for(var n in o)o.hasOwnProperty(n)&&(t[n]=o[n])};return function(o,n){function r(){this.constructor=o}t(o,n),o.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();
+
 
 
 (function universalModuleDefinition(root, factory) {
 (function universalModuleDefinition(root, factory) {
-    if(typeof exports === 'object' && typeof module === 'object')
-        module.exports = factory(require("babylonjs"));
-    else if(typeof define === 'function' && define.amd)
-        define("babylonjs-loaders", ["babylonjs"], factory);
-    else if(typeof exports === 'object')
-        exports["babylonjs-loaders"] = factory(require("babylonjs"));
-    else {
-        root["BABYLON"] = factory(root["BABYLON"]);
+    var amdDependencies = [];
+    var BABYLON = root.BABYLON;
+    if(typeof exports === 'object' && typeof module === 'object') {
+         BABYLON = BABYLON || require("babylonjs"); 
+
+        module.exports = factory(BABYLON);
+    } else if(typeof define === 'function' && define.amd) {
+         amdDependencies.push("babylonjs");
+
+        define("babylonjs-loaders", amdDependencies, factory);
+    } else if(typeof exports === 'object') {
+         BABYLON = BABYLON || require("babylonjs"); 
+
+        exports["babylonjs-loaders"] = factory(BABYLON);
+    } else {
+        root["BABYLON"] = factory(BABYLON);
     }
     }
 })(this, function(BABYLON) {
 })(this, function(BABYLON) {
-    "use strict";
+  BABYLON = BABYLON || this.BABYLON;
+
+"use strict";
 
 
 var BABYLON;
 var BABYLON;
 (function (BABYLON) {
 (function (BABYLON) {
@@ -1308,6 +1304,7 @@ var BABYLON;
             loader.onTextureLoadedObservable.add(function (texture) { return _this.onTextureLoadedObservable.notifyObservers(texture); });
             loader.onTextureLoadedObservable.add(function (texture) { return _this.onTextureLoadedObservable.notifyObservers(texture); });
             loader.onMaterialLoadedObservable.add(function (material) { return _this.onMaterialLoadedObservable.notifyObservers(material); });
             loader.onMaterialLoadedObservable.add(function (material) { return _this.onMaterialLoadedObservable.notifyObservers(material); });
             loader.onExtensionLoadedObservable.add(function (extension) { return _this.onExtensionLoadedObservable.notifyObservers(extension); });
             loader.onExtensionLoadedObservable.add(function (extension) { return _this.onExtensionLoadedObservable.notifyObservers(extension); });
+            loader.onAnimationGroupLoadedObservable.add(function (animationGroup) { return _this.onAnimationGroupLoadedObservable.notifyObservers(animationGroup); });
             loader.onCompleteObservable.add(function () {
             loader.onCompleteObservable.add(function () {
                 _this.onMeshLoadedObservable.clear();
                 _this.onMeshLoadedObservable.clear();
                 _this.onTextureLoadedObservable.clear();
                 _this.onTextureLoadedObservable.clear();
@@ -4973,7 +4970,9 @@ var BABYLON;
                 return (BABYLON.Tools.IsBase64(uri) || uri.indexOf("..") === -1);
                 return (BABYLON.Tools.IsBase64(uri) || uri.indexOf("..") === -1);
             };
             };
             GLTFLoader._GetDrawMode = function (context, mode) {
             GLTFLoader._GetDrawMode = function (context, mode) {
-                mode = mode || 4 /* TRIANGLES */;
+                if (mode == undefined) {
+                    mode = 4 /* TRIANGLES */;
+                }
                 switch (mode) {
                 switch (mode) {
                     case 0 /* POINTS */: return BABYLON.Material.PointListDrawMode;
                     case 0 /* POINTS */: return BABYLON.Material.PointListDrawMode;
                     case 1 /* LINES */: return BABYLON.Material.LineListDrawMode;
                     case 1 /* LINES */: return BABYLON.Material.LineListDrawMode;
@@ -5192,7 +5191,7 @@ var BABYLON;
                                 if (indexLOD !== 0) {
                                 if (indexLOD !== 0) {
                                     var previousNodeLOD = nodeLODs[indexLOD - 1];
                                     var previousNodeLOD = nodeLODs[indexLOD - 1];
                                     if (previousNodeLOD._babylonMesh) {
                                     if (previousNodeLOD._babylonMesh) {
-                                        previousNodeLOD._babylonMesh.dispose();
+                                        previousNodeLOD._babylonMesh.dispose(false, true);
                                         delete previousNodeLOD._babylonMesh;
                                         delete previousNodeLOD._babylonMesh;
                                     }
                                     }
                                 }
                                 }

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


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

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-loaders",
     "name": "babylonjs-loaders",
     "description": "The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.",
     "description": "The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.",
-    "version": "3.2.0-alphaC",
+    "version": "3.2.0-beta.1",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     ],
     "license": "Apache-2.0",
     "license": "Apache-2.0",
     "dependencies": {
     "dependencies": {
-        "babylonjs-gltf2interface": "3.2.0-alphaC"
+        "babylonjs-gltf2interface": "3.2.0-beta.1"
     },
     },
     "peerDependencies": {
     "peerDependencies": {
         "babylonjs": ">=3.2.0-alpha"
         "babylonjs": ">=3.2.0-alpha"

+ 22 - 26
dist/preview release/materialsLibrary/babylonjs.materials.js

@@ -1,33 +1,29 @@
-var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
-var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
-if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
-else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
-return c > 3 && r && Object.defineProperty(target, key, r), r;
-};
-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 __decorate=this&&this.__decorate||function(e,t,r,c){var o,f=arguments.length,n=f<3?t:null===c?c=Object.getOwnPropertyDescriptor(t,r):c;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(e,t,r,c);else for(var l=e.length-1;l>=0;l--)(o=e[l])&&(n=(f<3?o(n):f>3?o(t,r,n):o(t,r))||n);return f>3&&n&&Object.defineProperty(t,r,n),n};
+var __extends=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,o){t.__proto__=o}||function(t,o){for(var n in o)o.hasOwnProperty(n)&&(t[n]=o[n])};return function(o,n){function r(){this.constructor=o}t(o,n),o.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();
+
 
 
 (function universalModuleDefinition(root, factory) {
 (function universalModuleDefinition(root, factory) {
-    if(typeof exports === 'object' && typeof module === 'object')
-        module.exports = factory(require("babylonjs"));
-    else if(typeof define === 'function' && define.amd)
-        define("babylonjs-materials", ["babylonjs"], factory);
-    else if(typeof exports === 'object')
-        exports["babylonjs-materials"] = factory(require("babylonjs"));
-    else {
-        root["BABYLON"] = factory(root["BABYLON"]);
+    var amdDependencies = [];
+    var BABYLON = root.BABYLON;
+    if(typeof exports === 'object' && typeof module === 'object') {
+         BABYLON = BABYLON || require("babylonjs"); 
+
+        module.exports = factory(BABYLON);
+    } else if(typeof define === 'function' && define.amd) {
+         amdDependencies.push("babylonjs");
+
+        define("babylonjs-materials", amdDependencies, factory);
+    } else if(typeof exports === 'object') {
+         BABYLON = BABYLON || require("babylonjs"); 
+
+        exports["babylonjs-materials"] = factory(BABYLON);
+    } else {
+        root["BABYLON"] = factory(BABYLON);
     }
     }
 })(this, function(BABYLON) {
 })(this, function(BABYLON) {
-    "use strict";
+  BABYLON = BABYLON || this.BABYLON;
+
+"use strict";
 
 
 
 
 var BABYLON;
 var BABYLON;

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


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

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

+ 22 - 26
dist/preview release/postProcessesLibrary/babylonjs.postProcess.js

@@ -1,33 +1,29 @@
-var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
-var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
-if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
-else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
-return c > 3 && r && Object.defineProperty(target, key, r), r;
-};
-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 __decorate=this&&this.__decorate||function(e,t,r,c){var o,f=arguments.length,n=f<3?t:null===c?c=Object.getOwnPropertyDescriptor(t,r):c;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(e,t,r,c);else for(var l=e.length-1;l>=0;l--)(o=e[l])&&(n=(f<3?o(n):f>3?o(t,r,n):o(t,r))||n);return f>3&&n&&Object.defineProperty(t,r,n),n};
+var __extends=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,o){t.__proto__=o}||function(t,o){for(var n in o)o.hasOwnProperty(n)&&(t[n]=o[n])};return function(o,n){function r(){this.constructor=o}t(o,n),o.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();
+
 
 
 (function universalModuleDefinition(root, factory) {
 (function universalModuleDefinition(root, factory) {
-    if(typeof exports === 'object' && typeof module === 'object')
-        module.exports = factory(require("babylonjs"));
-    else if(typeof define === 'function' && define.amd)
-        define("babylonjs-post-process", ["babylonjs"], factory);
-    else if(typeof exports === 'object')
-        exports["babylonjs-post-process"] = factory(require("babylonjs"));
-    else {
-        root["BABYLON"] = factory(root["BABYLON"]);
+    var amdDependencies = [];
+    var BABYLON = root.BABYLON;
+    if(typeof exports === 'object' && typeof module === 'object') {
+         BABYLON = BABYLON || require("babylonjs"); 
+
+        module.exports = factory(BABYLON);
+    } else if(typeof define === 'function' && define.amd) {
+         amdDependencies.push("babylonjs");
+
+        define("babylonjs-post-process", amdDependencies, factory);
+    } else if(typeof exports === 'object') {
+         BABYLON = BABYLON || require("babylonjs"); 
+
+        exports["babylonjs-post-process"] = factory(BABYLON);
+    } else {
+        root["BABYLON"] = factory(BABYLON);
     }
     }
 })(this, function(BABYLON) {
 })(this, function(BABYLON) {
-    "use strict";
+  BABYLON = BABYLON || this.BABYLON;
+
+"use strict";
 
 
 
 
 
 

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


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

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

+ 22 - 26
dist/preview release/proceduralTexturesLibrary/babylonjs.proceduralTextures.js

@@ -1,33 +1,29 @@
-var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
-var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
-if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
-else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
-return c > 3 && r && Object.defineProperty(target, key, r), r;
-};
-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 __decorate=this&&this.__decorate||function(e,t,r,c){var o,f=arguments.length,n=f<3?t:null===c?c=Object.getOwnPropertyDescriptor(t,r):c;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(e,t,r,c);else for(var l=e.length-1;l>=0;l--)(o=e[l])&&(n=(f<3?o(n):f>3?o(t,r,n):o(t,r))||n);return f>3&&n&&Object.defineProperty(t,r,n),n};
+var __extends=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,o){t.__proto__=o}||function(t,o){for(var n in o)o.hasOwnProperty(n)&&(t[n]=o[n])};return function(o,n){function r(){this.constructor=o}t(o,n),o.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();
+
 
 
 (function universalModuleDefinition(root, factory) {
 (function universalModuleDefinition(root, factory) {
-    if(typeof exports === 'object' && typeof module === 'object')
-        module.exports = factory(require("babylonjs"));
-    else if(typeof define === 'function' && define.amd)
-        define("babylonjs-procedural-textures", ["babylonjs"], factory);
-    else if(typeof exports === 'object')
-        exports["babylonjs-procedural-textures"] = factory(require("babylonjs"));
-    else {
-        root["BABYLON"] = factory(root["BABYLON"]);
+    var amdDependencies = [];
+    var BABYLON = root.BABYLON;
+    if(typeof exports === 'object' && typeof module === 'object') {
+         BABYLON = BABYLON || require("babylonjs"); 
+
+        module.exports = factory(BABYLON);
+    } else if(typeof define === 'function' && define.amd) {
+         amdDependencies.push("babylonjs");
+
+        define("babylonjs-procedural-textures", amdDependencies, factory);
+    } else if(typeof exports === 'object') {
+         BABYLON = BABYLON || require("babylonjs"); 
+
+        exports["babylonjs-procedural-textures"] = factory(BABYLON);
+    } else {
+        root["BABYLON"] = factory(BABYLON);
     }
     }
 })(this, function(BABYLON) {
 })(this, function(BABYLON) {
-    "use strict";
+  BABYLON = BABYLON || this.BABYLON;
+
+"use strict";
 
 
 
 
 var BABYLON;
 var BABYLON;

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


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

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

+ 22 - 26
dist/preview release/serializers/babylonjs.serializers.js

@@ -1,33 +1,29 @@
-var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
-var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
-if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
-else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
-return c > 3 && r && Object.defineProperty(target, key, r), r;
-};
-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 __decorate=this&&this.__decorate||function(e,t,r,c){var o,f=arguments.length,n=f<3?t:null===c?c=Object.getOwnPropertyDescriptor(t,r):c;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(e,t,r,c);else for(var l=e.length-1;l>=0;l--)(o=e[l])&&(n=(f<3?o(n):f>3?o(t,r,n):o(t,r))||n);return f>3&&n&&Object.defineProperty(t,r,n),n};
+var __extends=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,o){t.__proto__=o}||function(t,o){for(var n in o)o.hasOwnProperty(n)&&(t[n]=o[n])};return function(o,n){function r(){this.constructor=o}t(o,n),o.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();
+
 
 
 (function universalModuleDefinition(root, factory) {
 (function universalModuleDefinition(root, factory) {
-    if(typeof exports === 'object' && typeof module === 'object')
-        module.exports = factory(require("babylonjs"));
-    else if(typeof define === 'function' && define.amd)
-        define("babylonjs-serializers", ["babylonjs"], factory);
-    else if(typeof exports === 'object')
-        exports["babylonjs-serializers"] = factory(require("babylonjs"));
-    else {
-        root["BABYLON"] = factory(root["BABYLON"]);
+    var amdDependencies = [];
+    var BABYLON = root.BABYLON;
+    if(typeof exports === 'object' && typeof module === 'object') {
+         BABYLON = BABYLON || require("babylonjs"); 
+
+        module.exports = factory(BABYLON);
+    } else if(typeof define === 'function' && define.amd) {
+         amdDependencies.push("babylonjs");
+
+        define("babylonjs-serializers", amdDependencies, factory);
+    } else if(typeof exports === 'object') {
+         BABYLON = BABYLON || require("babylonjs"); 
+
+        exports["babylonjs-serializers"] = factory(BABYLON);
+    } else {
+        root["BABYLON"] = factory(BABYLON);
     }
     }
 })(this, function(BABYLON) {
 })(this, function(BABYLON) {
-    "use strict";
+  BABYLON = BABYLON || this.BABYLON;
+
+"use strict";
 
 
 var BABYLON;
 var BABYLON;
 (function (BABYLON) {
 (function (BABYLON) {

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


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

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

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

@@ -1,7 +1,7 @@
 {
 {
-  "errors": 7154,
+  "errors": 7152,
   "babylon.typedoc.json": {
   "babylon.typedoc.json": {
-    "errors": 7154,
+    "errors": 7152,
     "AnimationKeyInterpolation": {
     "AnimationKeyInterpolation": {
       "Enumeration": {
       "Enumeration": {
         "Comments": {
         "Comments": {
@@ -3143,11 +3143,6 @@
             "MissingReturn": true
             "MissingReturn": true
           }
           }
         },
         },
-        "start": {
-          "Comments": {
-            "MissingReturn": true
-          }
-        },
         "stop": {
         "stop": {
           "Comments": {
           "Comments": {
             "MissingReturn": true
             "MissingReturn": true
@@ -25731,11 +25726,6 @@
           "Comments": {
           "Comments": {
             "MissingText": true
             "MissingText": true
           }
           }
-        },
-        "currentFrame": {
-          "Comments": {
-            "MissingText": true
-          }
         }
         }
       },
       },
       "Method": {
       "Method": {

+ 30 - 1
dist/preview release/viewer/babylon.viewer.d.ts

@@ -2,6 +2,8 @@ declare module BabylonViewer {
 
 
     export let disableInit: boolean;
     export let disableInit: boolean;
 
 
+    export function disposeAll(): void;
+
     export interface ITemplateConfiguration {
     export interface ITemplateConfiguration {
         location?: string;
         location?: string;
         html?: string;
         html?: string;
@@ -91,7 +93,9 @@ declare module BabylonViewer {
     interface ViewerManager {
     interface ViewerManager {
         onViewerAdded: (viewer: AbstractViewer) => void;
         onViewerAdded: (viewer: AbstractViewer) => void;
         onViewerAddedObservable: BABYLON.Observable<AbstractViewer>;
         onViewerAddedObservable: BABYLON.Observable<AbstractViewer>;
+        onViewerRemovedObservable: BABYLON.Observable<string>;
         addViewer(viewer: AbstractViewer): void;
         addViewer(viewer: AbstractViewer): void;
+        removeViewer(viewer: AbstractViewer): void;
         getViewerById(id: string): AbstractViewer;
         getViewerById(id: string): AbstractViewer;
         getViewerByHTMLElement(element: HTMLElement): AbstractViewer | undefined;
         getViewerByHTMLElement(element: HTMLElement): AbstractViewer | undefined;
         getViewerPromiseById(id: string): Promise<AbstractViewer>;
         getViewerPromiseById(id: string): Promise<AbstractViewer>;
@@ -201,6 +205,7 @@ declare module BabylonViewer {
 
 
     export interface IModelConfiguration {
     export interface IModelConfiguration {
         url?: string;
         url?: string;
+        root?: string;
         loader?: string; // obj, gltf?
         loader?: string; // obj, gltf?
         position?: { x: number, y: number, z: number };
         position?: { x: number, y: number, z: number };
         rotation?: { x: number, y: number, z: number, w?: number };
         rotation?: { x: number, y: number, z: number, w?: number };
@@ -426,9 +431,24 @@ declare module BabylonViewer {
         goToFrame(frameNumber: number): any;
         goToFrame(frameNumber: number): any;
     }
     }
 
 
-    export interface ViewerModel extends BABYLON.IDisposable {
+    export enum ModelState {
+        INIT,
+        LOADING,
+        LOADED,
+        ERROR
+    }
+
+    export class ModelLoader {
+        constructor(viewer: AbstractViewer);
+        load(modelConfiguration: IModelConfiguration): ViewerModel;
+        dispose(): void;
+    }
+
+    export class ViewerModel {
+        constructor(scene: BABYLON.Scene, modelConfiguration: IModelConfiguration, disableAutoLoad: boolean);
         loader: BABYLON.ISceneLoaderPlugin | BABYLON.ISceneLoaderPluginAsync;
         loader: BABYLON.ISceneLoaderPlugin | BABYLON.ISceneLoaderPluginAsync;
         meshes: Array<BABYLON.AbstractMesh>;
         meshes: Array<BABYLON.AbstractMesh>;
+        rootMesh: BABYLON.AbstractMesh;
         particleSystems: Array<BABYLON.ParticleSystem>;
         particleSystems: Array<BABYLON.ParticleSystem>;
         skeletons: Array<BABYLON.Skeleton>;
         skeletons: Array<BABYLON.Skeleton>;
         currentAnimation: IModelAnimation;
         currentAnimation: IModelAnimation;
@@ -438,7 +458,13 @@ declare module BabylonViewer {
             message: string;
             message: string;
             exception: any;
             exception: any;
         }>;
         }>;
+        onAfterConfigure: BABYLON.Observable<ViewerModel>;
+        state: ModelState;
+        loadId: number;
         load(): void;
         load(): void;
+        initAnimations(): void;
+        addAnimationGroup(animationGroup: BABYLON.AnimationGroup): void;
+        getAnimations(): Array<IModelAnimation>;
         getAnimationNames(): string[];
         getAnimationNames(): string[];
         playAnimation(name: string): IModelAnimation;
         playAnimation(name: string): IModelAnimation;
         dispose(): void;
         dispose(): void;
@@ -454,6 +480,7 @@ declare module BabylonViewer {
         sceneOptimizer: BABYLON.SceneOptimizer;
         sceneOptimizer: BABYLON.SceneOptimizer;
         baseId: string;
         baseId: string;
         models: Array<ViewerModel>;
         models: Array<ViewerModel>;
+        modelLoader: ModelLoader;
         lastUsedLoader: BABYLON.ISceneLoaderPlugin | BABYLON.ISceneLoaderPluginAsync;
         lastUsedLoader: BABYLON.ISceneLoaderPlugin | BABYLON.ISceneLoaderPluginAsync;
         protected configuration: ViewerConfiguration;
         protected configuration: ViewerConfiguration;
         environmentHelper: BABYLON.EnvironmentHelper;
         environmentHelper: BABYLON.EnvironmentHelper;
@@ -462,6 +489,7 @@ declare module BabylonViewer {
         protected defaultPipelineTextureType: number;
         protected defaultPipelineTextureType: number;
         protected maxShadows: number;
         protected maxShadows: number;
         readonly isHdrSupported: boolean;
         readonly isHdrSupported: boolean;
+        protected _isDisposed: boolean;
         onSceneInitObservable: BABYLON.Observable<BABYLON.Scene>;
         onSceneInitObservable: BABYLON.Observable<BABYLON.Scene>;
         onEngineInitObservable: BABYLON.Observable<BABYLON.Engine>;
         onEngineInitObservable: BABYLON.Observable<BABYLON.Engine>;
         onModelLoadedObservable: BABYLON.Observable<ViewerModel>;
         onModelLoadedObservable: BABYLON.Observable<ViewerModel>;
@@ -494,6 +522,7 @@ declare module BabylonViewer {
         protected onTemplatesLoaded(): Promise<AbstractViewer>;
         protected onTemplatesLoaded(): Promise<AbstractViewer>;
         protected initEngine(): Promise<BABYLON.Engine>;
         protected initEngine(): Promise<BABYLON.Engine>;
         protected initScene(): Promise<BABYLON.Scene>;
         protected initScene(): Promise<BABYLON.Scene>;
+        initModel(modelConfig?: any, clearScene?: boolean): ViewerModel
         loadModel(modelConfig?: any, clearScene?: boolean): Promise<ViewerModel>;
         loadModel(modelConfig?: any, clearScene?: boolean): Promise<ViewerModel>;
         protected initEnvironment(viewerModel?: ViewerModel): Promise<BABYLON.Scene>;
         protected initEnvironment(viewerModel?: ViewerModel): Promise<BABYLON.Scene>;
         protected handleHardwareLimitations(): void;
         protected handleHardwareLimitations(): void;

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


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


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

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-viewer",
     "name": "babylonjs-viewer",
     "description": "A simple-to-use viewer based on BabylonJS to display 3D elements natively",
     "description": "A simple-to-use viewer based on BabylonJS to display 3D elements natively",
-    "version": "3.2.0-alphaC",
+    "version": "3.2.0-beta.1",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

@@ -14,7 +14,7 @@
 - Added [GlowLayer](https://doc.babylonjs.com/how_to/glow_layer) to easily support glow from emissive materials. Demo [here](http://www.babylonjs.com/demos/GlowLayer/) ([sebavan](https://github.com/sebavan))
 - Added [GlowLayer](https://doc.babylonjs.com/how_to/glow_layer) to easily support glow from emissive materials. Demo [here](http://www.babylonjs.com/demos/GlowLayer/) ([sebavan](https://github.com/sebavan))
 - New [AssetContainer](http://doc.babylonjs.com/how_to/how_to_use_assetcontainer) class and loading methods ([trevordev](https://github.com/trevordev))
 - New [AssetContainer](http://doc.babylonjs.com/how_to/how_to_use_assetcontainer) class and loading methods ([trevordev](https://github.com/trevordev))
 - Added [depth of field](https://www.babylonjs-playground.com/frame.html#8F5HYV#5), sharpening, MSAA, chromatic aberration and grain effect to the default pipeline ([trevordev](https://github.com/trevordev))
 - Added [depth of field](https://www.babylonjs-playground.com/frame.html#8F5HYV#5), sharpening, MSAA, chromatic aberration and grain effect to the default pipeline ([trevordev](https://github.com/trevordev))
-- Added support for [animation weights](http://doc.babylonjs.com/babylon101/animations#animation-weights). Demo [here](https://www.babylonjs-playground.com/#IQN716#3) ([deltakosh](https://github.com/deltakosh))
+- Added support for [animation weights](http://doc.babylonjs.com/babylon101/animations#animation-weights). Demo [here](https://www.babylonjs-playground.com/#IQN716#9) ([deltakosh](https://github.com/deltakosh))
 - Added [sub emitters for particle system](http://doc.babylonjs.com/babylon101/particles#sub-emitters) which will spawn new particle systems when particles dies. Demo [here](https://www.babylonjs-playground.com/frame.html#9NHBCC#1) ([IbraheemOsama](https://github.com/IbraheemOsama))
 - Added [sub emitters for particle system](http://doc.babylonjs.com/babylon101/particles#sub-emitters) which will spawn new particle systems when particles dies. Demo [here](https://www.babylonjs-playground.com/frame.html#9NHBCC#1) ([IbraheemOsama](https://github.com/IbraheemOsama))
 - New [Babylon.js](http://doc.babylonjs.com/resources/maya) and [glTF](http://doc.babylonjs.com/resources/maya_to_gltf) exporter for Autodesk Maya ([Noalak](https://github.com/Noalak))
 - New [Babylon.js](http://doc.babylonjs.com/resources/maya) and [glTF](http://doc.babylonjs.com/resources/maya_to_gltf) exporter for Autodesk Maya ([Noalak](https://github.com/Noalak))
 - New glTF [serializer](https://github.com/BabylonJS/Babylon.js/tree/master/serializers/src/glTF/2.0). You can now export glTF or glb files directly from a Babylon scene ([kcoley](https://github.com/kcoley))
 - New glTF [serializer](https://github.com/BabylonJS/Babylon.js/tree/master/serializers/src/glTF/2.0). You can now export glTF or glb files directly from a Babylon scene ([kcoley](https://github.com/kcoley))
@@ -92,12 +92,13 @@
 - Default fragment shader will clamp negative values to avoid underflow, webVR post processing will render to eye texture size ([trevordev](https://github.com/trevordev))
 - Default fragment shader will clamp negative values to avoid underflow, webVR post processing will render to eye texture size ([trevordev](https://github.com/trevordev))
 - Supports Environment Drag and Drop in Sandbox ([sebavan](https://github.com/sebavan))
 - Supports Environment Drag and Drop in Sandbox ([sebavan](https://github.com/sebavan))
 - EnvironmentHelper has no an onError observable to handle errors when loading the textures ([RaananW](https://github.com/RaananW))
 - EnvironmentHelper has no an onError observable to handle errors when loading the textures ([RaananW](https://github.com/RaananW))
-- (Viewer) Viewer supports model animations ([RaananW](https://github.com/RaananW))
+- (Viewer) Viewer supports model animations and multi-model loading ([RaananW](https://github.com/RaananW))
 - Tests for sharpen, chromatic aberration, default pipeline and enable/disable post processes ([trevordev](https://github.com/trevordev))
 - Tests for sharpen, chromatic aberration, default pipeline and enable/disable post processes ([trevordev](https://github.com/trevordev))
 - onPointer* callbacks have now the event type as a 3rd variable ([RaananW](https://github.com/RaananW))
 - onPointer* callbacks have now the event type as a 3rd variable ([RaananW](https://github.com/RaananW))
 - Lightmap texture in PBR material follow the gammaSpace Flag of the texture ([sebavan](https://github.com/sebavan))
 - Lightmap texture in PBR material follow the gammaSpace Flag of the texture ([sebavan](https://github.com/sebavan))
 - Added setTextureFromPostProcessOutput to bind the output of a postprocess into an effect ([trevordev](https://github.com/trevordev))
 - Added setTextureFromPostProcessOutput to bind the output of a postprocess into an effect ([trevordev](https://github.com/trevordev))
 - Added support for primitive modes to glTF 2.0 loader. ([bghgary](https://github.com/bghgary)]
 - Added support for primitive modes to glTF 2.0 loader. ([bghgary](https://github.com/bghgary)]
+- Cannon and Oimo are optional dependencies ([RaananW](https://github.com/RaananW))
 
 
 ## Bug fixes
 ## Bug fixes
 
 

+ 56 - 0
gui/src/controls/container.ts

@@ -5,6 +5,44 @@ module BABYLON.GUI {
         protected _children = new Array<Control>();
         protected _children = new Array<Control>();
         protected _measureForChildren = Measure.Empty();  
         protected _measureForChildren = Measure.Empty();  
         protected _background: string;   
         protected _background: string;   
+        protected _adaptWidthToChildren = false;
+        protected _adaptHeightToChildren = false;
+
+        public get adaptHeightToChildren(): boolean {
+            return this._adaptHeightToChildren;
+        }
+
+        public set adaptHeightToChildren(value: boolean) {
+            if (this._adaptHeightToChildren === value) {
+                return;
+            }
+
+            this._adaptHeightToChildren = value;
+
+            if (value) {
+                this.height = "100%";
+            }
+
+            this._markAsDirty();
+        }       
+        
+        public get adaptWidthToChildren(): boolean {
+            return this._adaptWidthToChildren;
+        }
+
+        public set adaptWidthToChildren(value: boolean) {
+            if (this._adaptWidthToChildren === value) {
+                return;
+            }
+
+            this._adaptWidthToChildren = value;
+
+            if (value) {
+                this.width = "100%";
+            }
+
+            this._markAsDirty();
+        }           
 
 
         public get background(): string {
         public get background(): string {
             return this._background;
             return this._background;
@@ -159,6 +197,10 @@ module BABYLON.GUI {
                 this._localDraw(context);
                 this._localDraw(context);
 
 
                 this._clipForChildren(context);
                 this._clipForChildren(context);
+
+                let computedWidth = -1;
+                let computedHeight = -1;
+
                 for (var child of this._children) {
                 for (var child of this._children) {
                     if (child.isVisible && !child.notRenderable) {
                     if (child.isVisible && !child.notRenderable) {
                         child._tempParentMeasure.copyFrom(this._measureForChildren);
                         child._tempParentMeasure.copyFrom(this._measureForChildren);
@@ -167,8 +209,22 @@ module BABYLON.GUI {
                         if (child.onAfterDrawObservable.hasObservers()) {
                         if (child.onAfterDrawObservable.hasObservers()) {
                             child.onAfterDrawObservable.notifyObservers(child);
                             child.onAfterDrawObservable.notifyObservers(child);
                         }
                         }
+
+                        if (this.adaptWidthToChildren && child._width.isPixel) {
+                            computedWidth = Math.max(computedWidth, child._currentMeasure.width);
+                        }
+                        if (this.adaptHeightToChildren && child._height.isPixel) {
+                            computedHeight = Math.max(computedHeight, child._currentMeasure.height);
+                        }                        
                     }
                     }
                 }
                 }
+
+                if (this.adaptWidthToChildren && computedWidth >= 0) {
+                    this.width = computedWidth + "px";
+                }
+                if (this.adaptHeightToChildren && computedHeight >= 0) {
+                    this.height = computedHeight + "px";
+                }                
             }
             }
             context.restore();
             context.restore();
 
 

+ 1 - 2
gui/src/tsconfig.json

@@ -7,7 +7,6 @@
     "noImplicitReturns": true,
     "noImplicitReturns": true,
     "noImplicitThis": true,
     "noImplicitThis": true,
     "noUnusedLocals": true,    
     "noUnusedLocals": true,    
-    "strictNullChecks": true,
-    "strict": true
+    "strictNullChecks": true    
   }
   }
 }
 }

+ 1 - 2
inspector/src/tsconfig.json

@@ -7,7 +7,6 @@
         "noImplicitReturns": true,
         "noImplicitReturns": true,
         "noImplicitThis": true,
         "noImplicitThis": true,
         "noUnusedLocals": true,    
         "noUnusedLocals": true,    
-        "strictNullChecks": true,
-        "strict": true
+        "strictNullChecks": true
     }
     }
 }
 }

+ 1 - 1
loaders/src/glTF/2.0/Extensions/MSFT_lod.ts

@@ -43,7 +43,7 @@ module BABYLON.GLTF2.Extensions {
                         if (indexLOD !== 0) {
                         if (indexLOD !== 0) {
                             const previousNodeLOD = nodeLODs[indexLOD - 1];
                             const previousNodeLOD = nodeLODs[indexLOD - 1];
                             if (previousNodeLOD._babylonMesh) {
                             if (previousNodeLOD._babylonMesh) {
-                                previousNodeLOD._babylonMesh.dispose();
+                                previousNodeLOD._babylonMesh.dispose(false, true);
                                 delete previousNodeLOD._babylonMesh;
                                 delete previousNodeLOD._babylonMesh;
                             }
                             }
                         }
                         }

+ 1 - 0
loaders/src/glTF/babylon.glTFFileLoader.ts

@@ -373,6 +373,7 @@ module BABYLON {
             loader.onTextureLoadedObservable.add(texture => this.onTextureLoadedObservable.notifyObservers(texture));
             loader.onTextureLoadedObservable.add(texture => this.onTextureLoadedObservable.notifyObservers(texture));
             loader.onMaterialLoadedObservable.add(material => this.onMaterialLoadedObservable.notifyObservers(material));
             loader.onMaterialLoadedObservable.add(material => this.onMaterialLoadedObservable.notifyObservers(material));
             loader.onExtensionLoadedObservable.add(extension => this.onExtensionLoadedObservable.notifyObservers(extension));
             loader.onExtensionLoadedObservable.add(extension => this.onExtensionLoadedObservable.notifyObservers(extension));
+            loader.onAnimationGroupLoadedObservable.add(animationGroup => this.onAnimationGroupLoadedObservable.notifyObservers(animationGroup));
 
 
             loader.onCompleteObservable.add(() => {
             loader.onCompleteObservable.add(() => {
                 this.onMeshLoadedObservable.clear();
                 this.onMeshLoadedObservable.clear();

+ 1 - 2
loaders/src/tsconfig.json

@@ -10,7 +10,6 @@
     "noImplicitReturns": true,
     "noImplicitReturns": true,
     "noImplicitThis": true,
     "noImplicitThis": true,
     "noUnusedLocals": true,    
     "noUnusedLocals": true,    
-    "strictNullChecks": true,
-    "strict": true
+    "strictNullChecks": true
   }
   }
 }
 }

+ 1 - 2
materialsLibrary/src/tsconfig.json

@@ -7,7 +7,6 @@
     "noImplicitReturns": true,
     "noImplicitReturns": true,
     "noImplicitThis": true,
     "noImplicitThis": true,
     "noUnusedLocals": true,
     "noUnusedLocals": true,
-    "strictNullChecks": true,
-    "strict": true
+    "strictNullChecks": true
   }
   }
 }
 }

+ 1 - 4
package.json

@@ -9,7 +9,7 @@
     ],
     ],
     "name": "babylonjs",
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "3.2.0-alphaC",
+    "version": "3.2.0-beta.1",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -33,9 +33,6 @@
         "webgl"
         "webgl"
     ],
     ],
     "license": "Apache-2.0",
     "license": "Apache-2.0",
-    "dependencies": {
-        "cannon": "0.6.2"
-    },
     "engines": {
     "engines": {
         "node": "*"
         "node": "*"
     },
     },

+ 1 - 2
postProcessLibrary/src/tsconfig.json

@@ -7,7 +7,6 @@
     "noImplicitReturns": true,
     "noImplicitReturns": true,
     "noImplicitThis": true,
     "noImplicitThis": true,
     "noUnusedLocals": true,    
     "noUnusedLocals": true,    
-    "strictNullChecks": true,
-    "strict": true
+    "strictNullChecks": true
   }
   }
 }
 }

+ 1 - 2
proceduralTexturesLibrary/src/tsconfig.json

@@ -7,7 +7,6 @@
     "noImplicitReturns": true,
     "noImplicitReturns": true,
     "noImplicitThis": true,
     "noImplicitThis": true,
     "noUnusedLocals": true,    
     "noUnusedLocals": true,    
-    "strictNullChecks": true,
-    "strict": true
+    "strictNullChecks": true
   }
   }
 }
 }

+ 1 - 11
sandbox/index-local.html

@@ -19,16 +19,7 @@
     <div id="help02" class="help2">
     <div id="help02" class="help2">
         <span class="helpText">Or directly drag'n'drop your files in the browser</span>
         <span class="helpText">Or directly drag'n'drop your files in the browser</span>
     </div>
     </div>
-    <div id="perf" class="perffooter">
-        <div class="footerLeft">
-            <div id="miscCounters"></div>
-        </div>
-        <div class="footerRight">
-            <div id="fps"></div>
-            <img id="btnDownArrow" src="./Assets/FlecheDown.png" />
-        </div>
-    </div>
-    <div class="footer">
+    <div id="footer" class="footer">
         <div class="footerLeft">
         <div class="footerLeft">
             Powered by <a href="http://www.babylonjs.com/" target="_blank">Babylon.js</a><br />
             Powered by <a href="http://www.babylonjs.com/" target="_blank">Babylon.js</a><br />
         </div>
         </div>
@@ -48,7 +39,6 @@
             </ul>
             </ul>
         </div>
         </div>
     </div>
     </div>
-    <div id="loadingText" class="loadingText"></div>
     <div id="errorZone"></div>
     <div id="errorZone"></div>
     <script>
     <script>
         BABYLONDEVTOOLS.Loader.require('index.js')
         BABYLONDEVTOOLS.Loader.require('index.js')

+ 3 - 6
sandbox/index.html

@@ -47,11 +47,9 @@
     <div id="help02" class="help2">
     <div id="help02" class="help2">
         <span class="helpText">Or directly drag'n'drop your files in the browser</span>
         <span class="helpText">Or directly drag'n'drop your files in the browser</span>
     </div>
     </div>
-    <div class="footer">
+    <div id="footer" class="footer">
         <div class="footerLeft">
         <div class="footerLeft">
-            Powered by
-            <a href="http://www.babylonjs.com/" target="_blank">Babylon.js</a>
-            <br />
+            Powered by <a href="http://www.babylonjs.com/" target="_blank">Babylon.js</a><br />
         </div>
         </div>
         <div class="footerRight">
         <div class="footerRight">
             <ul>
             <ul>
@@ -59,7 +57,7 @@
                     <img src="./Assets/BtnFullscreen.png" alt="Switch the scene to full screen" title="Switch the scene to full screen" />
                     <img src="./Assets/BtnFullscreen.png" alt="Switch the scene to full screen" title="Switch the scene to full screen" />
                 </li>
                 </li>
                 <li id="btnPerf">
                 <li id="btnPerf">
-                    <img src="./Assets/BtnPerf.png" alt="Display debug & performance layer" title="Display debug & performance layer" />
+                    <img src="./Assets/BtnPerf.png" alt="Display inspector" title="Display inspector" />
                 </li>
                 </li>
                 <li id="btnFiles">
                 <li id="btnFiles">
                     <div class="custom-upload" title="Open your scene from your hard drive (.babylon, .gltf, .glb, .obj)">
                     <div class="custom-upload" title="Open your scene from your hard drive (.babylon, .gltf, .glb, .obj)">
@@ -69,7 +67,6 @@
             </ul>
             </ul>
         </div>
         </div>
     </div>
     </div>
-    <div id="loadingText" class="loadingText"></div>
     <div id="errorZone"></div>
     <div id="errorZone"></div>
     <script src="index.js"></script>
     <script src="index.js"></script>
 </body>
 </body>

+ 137 - 64
sandbox/index.js

@@ -1,19 +1,42 @@
 /// <reference path="../dist/preview release/babylon.d.ts" />
 /// <reference path="../dist/preview release/babylon.d.ts" />
 /// <reference path="../dist/preview release/loaders/babylon.glTFFileLoader.d.ts" />
 /// <reference path="../dist/preview release/loaders/babylon.glTFFileLoader.d.ts" />
 
 
+var assetUrl;
+var cameraPosition;
+var kiosk;
+
+var indexOf = location.href.indexOf("?");
+if (indexOf !== -1) {
+    var params = location.href.substr(indexOf + 1).split("&");
+    for (var index = 0; index < params.length; index++) {
+        var [name, value] = params[index].split("=");
+        switch (name) {
+            case "assetUrl": {
+                assetUrl = value;
+                break;
+            }
+            case "cameraPosition": {
+                cameraPosition = BABYLON.Vector3.FromArray(value.split(",").map(component => +component));
+                break;
+            }
+            case "kiosk": {
+                kiosk = value === "true" ? true : false;
+                break;
+            }
+        }
+    }
+}
+
 if (BABYLON.Engine.isSupported()) {
 if (BABYLON.Engine.isSupported()) {
     var canvas = document.getElementById("renderCanvas");
     var canvas = document.getElementById("renderCanvas");
     var engine = new BABYLON.Engine(canvas, true);
     var engine = new BABYLON.Engine(canvas, true);
-    var divFps = document.getElementById("fps");
     var htmlInput = document.getElementById("files");
     var htmlInput = document.getElementById("files");
+    var footer = document.getElementById("footer");
     var btnFullScreen = document.getElementById("btnFullscreen");
     var btnFullScreen = document.getElementById("btnFullscreen");
-    var btnDownArrow = document.getElementById("btnDownArrow");
-    var perffooter = document.getElementById("perf");
     var btnPerf = document.getElementById("btnPerf");
     var btnPerf = document.getElementById("btnPerf");
-    var miscCounters = document.getElementById("miscCounters");
     var help01 = document.getElementById("help01");
     var help01 = document.getElementById("help01");
     var help02 = document.getElementById("help02");
     var help02 = document.getElementById("help02");
-    var loadingText = document.getElementById("loadingText");
+    var errorZone = document.getElementById("errorZone");
     var filesInput;
     var filesInput;
     var currentHelpCounter;
     var currentHelpCounter;
     var currentScene;
     var currentScene;
@@ -54,13 +77,13 @@ if (BABYLON.Engine.isSupported()) {
             enableDebugLayer = false;
             enableDebugLayer = false;
             currentScene.debugLayer.hide();
             currentScene.debugLayer.hide();
         };
         };
-
-        if (enableDebugLayer) {
+    
+            if (enableDebugLayer) {
             hideDebugLayerAndLogs();
             hideDebugLayerAndLogs();
         }
         }
 
 
         // Clear the error
         // Clear the error
-        document.getElementById("errorZone").style.display = 'none';
+        errorZone.style.display = 'none';
 
 
         currentScene = babylonScene;
         currentScene = babylonScene;
         document.title = "BabylonJS - " + sceneFile.name;
         document.title = "BabylonJS - " + sceneFile.name;
@@ -75,17 +98,28 @@ if (BABYLON.Engine.isSupported()) {
         // Attach camera to canvas inputs
         // Attach camera to canvas inputs
         if (!currentScene.activeCamera || currentScene.lights.length === 0) {
         if (!currentScene.activeCamera || currentScene.lights.length === 0) {
             currentScene.createDefaultCameraOrLight(true);
             currentScene.createDefaultCameraOrLight(true);
-            // Enable camera's behaviors
-            currentScene.activeCamera.useFramingBehavior = true;
-
-            var framingBehavior = currentScene.activeCamera.getBehaviorByName("Framing");
-            framingBehavior.framingTime = 0;
-            framingBehavior.elevationReturnTime = -1;
 
 
-            if (currentScene.meshes.length) {
-                var worldExtends = currentScene.getWorldExtends();
-                currentScene.activeCamera.lowerRadiusLimit = null;
-                framingBehavior.zoomOnBoundingInfo(worldExtends.min, worldExtends.max);
+            if (cameraPosition) {
+                currentScene.activeCamera.setPosition(cameraPosition);
+            }
+            else {
+                if (currentPluginName === "gltf") {
+                    // glTF assets use a +Z forward convention while the default camera faces +Z. Rotate the camera to look at the front of the asset.
+                    currentScene.activeCamera.alpha += Math.PI;
+                }
+
+                // Enable camera's behaviors
+                currentScene.activeCamera.useFramingBehavior = true;
+
+                var framingBehavior = currentScene.activeCamera.getBehaviorByName("Framing");
+                framingBehavior.framingTime = 0;
+                framingBehavior.elevationReturnTime = -1;
+
+                if (currentScene.meshes.length) {
+                    var worldExtends = currentScene.getWorldExtends();
+                    currentScene.activeCamera.lowerRadiusLimit = null;
+                    framingBehavior.zoomOnBoundingInfo(worldExtends.min, worldExtends.max);
+                }
             }
             }
 
 
             currentScene.activeCamera.pinchPrecision = 200 / currentScene.activeCamera.radius;
             currentScene.activeCamera.pinchPrecision = 200 / currentScene.activeCamera.radius;
@@ -101,9 +135,6 @@ if (BABYLON.Engine.isSupported()) {
         if (currentPluginName === "gltf") {
         if (currentPluginName === "gltf") {
             var hdrTexture = BABYLON.CubeTexture.CreateFromPrefilteredData(skyboxPath, currentScene);
             var hdrTexture = BABYLON.CubeTexture.CreateFromPrefilteredData(skyboxPath, currentScene);
             currentSkybox = currentScene.createDefaultSkybox(hdrTexture, true, (currentScene.activeCamera.maxZ - currentScene.activeCamera.minZ) / 2, 0.3);
             currentSkybox = currentScene.createDefaultSkybox(hdrTexture, true, (currentScene.activeCamera.maxZ - currentScene.activeCamera.minZ) / 2, 0.3);
-
-            // glTF assets use a +Z forward convention while the default camera faces +Z. Rotate the camera to look at the front of the asset.
-            currentScene.activeCamera.alpha += Math.PI;
         }
         }
 
 
         // In case of error during loading, meshes will be empty and clearColor is set to red
         // In case of error during loading, meshes will be empty and clearColor is set to red
@@ -138,47 +169,85 @@ if (BABYLON.Engine.isSupported()) {
 
 
         var errorContent = '<div class="alert alert-error"><button type="button" class="close" data-dismiss="alert">&times;</button>' + message.replace("file:[object File]", "'" + sceneFile.name + "'") + '</div>';
         var errorContent = '<div class="alert alert-error"><button type="button" class="close" data-dismiss="alert">&times;</button>' + message.replace("file:[object File]", "'" + sceneFile.name + "'") + '</div>';
 
 
-        document.getElementById("errorZone").style.display = 'block';
-        document.getElementById("errorZone").innerHTML = errorContent;
+        errorZone.style.display = 'block';
+        errorZone.innerHTML = errorContent;
 
 
         // Close button error
         // Close button error
-        document.getElementById("errorZone").querySelector('.close').addEventListener('click', function () {
-            document.getElementById("errorZone").style.display = 'none';
+        errorZone.querySelector('.close').addEventListener('click', function () {
+            errorZone.style.display = 'none';
         });
         });
     };
     };
 
 
-    filesInput = new BABYLON.FilesInput(engine, null, sceneLoaded, null, null, null, function () { BABYLON.Tools.ClearLogCache() }, null, sceneError);
-    filesInput.onProcessFileCallback = (function (file, name, extension) {
-        if (filesInput._filesToLoad && filesInput._filesToLoad.length === 1 && extension && extension.toLowerCase() === "dds") {
-            BABYLON.FilesInput.FilesToLoad[name] = file;
-            skyboxPath = "file:" + file.correctName;
-            return false;
-        }
-        return true;
-    }).bind(this);
-    filesInput.monitorElementForDragNDrop(canvas);
+    if (assetUrl) {
+        var rootUrl = BABYLON.Tools.GetFolderPath(assetUrl);
+        var fileName = BABYLON.Tools.GetFilename(assetUrl);
+        BABYLON.SceneLoader.LoadAsync(rootUrl, fileName, engine).then(function (scene) {
+            sceneLoaded({ name: fileName }, scene);
+            scene.whenReadyAsync().then(function () {
+                engine.runRenderLoop(function ()  {
+                    scene.render();
+                });
+            });
+        }).catch(function (reason) {
+            sceneError({ name: fileName }, null, reason);
+        });
+    }
+    else {
+        filesInput = new BABYLON.FilesInput(engine, null, sceneLoaded, null, null, null, function () { BABYLON.Tools.ClearLogCache() }, null, sceneError);
+        filesInput.onProcessFileCallback = (function (file, name, extension) {
+            if (filesInput._filesToLoad && filesInput._filesToLoad.length === 1 && extension && extension.toLowerCase() === "dds") {
+                BABYLON.FilesInput.FilesToLoad[name] = file;
+                skyboxPath = "file:" + file.correctName;
+                return false;
+            }
+            return true;
+        }).bind(this);
+        filesInput.monitorElementForDragNDrop(canvas);
+
+        window.addEventListener("keydown", function (evt) {
+            // Press R to reload
+            if (evt.keyCode === 82) {
+                filesInput.reload();
+            }
+        });
 
 
-    window.addEventListener("keydown", function (evt) {
-        // Press R to reload
-        if (evt.keyCode === 82) {
-            filesInput.reload();
-        }
-    });
-    htmlInput.addEventListener('change', function (event) {
-        var filestoLoad;
-        // Handling data transfer via drag'n'drop
-        if (event && event.dataTransfer && event.dataTransfer.files) {
-            filesToLoad = event.dataTransfer.files;
-        }
-        // Handling files from input files
-        if (event && event.target && event.target.files) {
-            filesToLoad = event.target.files;
+        htmlInput.addEventListener('change', function (event) {
+            var filestoLoad;
+            // Handling data transfer via drag'n'drop
+            if (event && event.dataTransfer && event.dataTransfer.files) {
+                filesToLoad = event.dataTransfer.files;
+            }
+            // Handling files from input files
+            if (event && event.target && event.target.files) {
+                filesToLoad = event.target.files;
+            }
+            filesInput.loadFiles(event);
+        }, false);
+    }
+
+    if (kiosk) {
+        footer.style.display = "none";
+    }
+    else {
+        // The help tips will be displayed only 5 times
+        if (currentHelpCounter < 5) {
+            help01.className = "help shown";
+
+            setTimeout(function () {
+                help01.className = "help";
+                help02.className = "help2 shown";
+                setTimeout(function () {
+                    help02.className = "help2";
+                    localStorage.setItem("helpcounter", currentHelpCounter + 1);
+                }, 5000);
+            }, 5000);
         }
         }
-        filesInput.loadFiles(event);
-    }, false);
+    }
+
     btnFullScreen.addEventListener('click', function () {
     btnFullScreen.addEventListener('click', function () {
         engine.switchFullscreen(true);
         engine.switchFullscreen(true);
     }, false);
     }, false);
+
     btnPerf.addEventListener('click', function () {
     btnPerf.addEventListener('click', function () {
         if (currentScene) {
         if (currentScene) {
             if (!enableDebugLayer) {
             if (!enableDebugLayer) {
@@ -191,19 +260,23 @@ if (BABYLON.Engine.isSupported()) {
             }
             }
         }
         }
     }, false);
     }, false);
-    // The help tips will be displayed only 5 times
-    if (currentHelpCounter < 5) {
-        help01.className = "help shown";
 
 
-        setTimeout(function () {
-            help01.className = "help";
-            help02.className = "help2 shown";
-            setTimeout(function () {
-                help02.className = "help2";
-                localStorage.setItem("helpcounter", currentHelpCounter + 1);
-            }, 5000);
-        }, 5000);
-    }
+    window.addEventListener("keydown", function (evt) {
+        // Press Esc to toggle footer
+        if (evt.keyCode === 27) {
+            if (footer.style.display === "none") {
+                footer.style.display = "block";
+            }
+            else {
+                footer.style.display = "none";
+                errorZone.style.display = "none";
+                if (enableDebugLayer) {
+                    currentScene.debugLayer.hide();
+                    enableDebugLayer = false;
+                }
+            }
+        }
+    });
 
 
     sizeScene();
     sizeScene();
 
 

+ 1 - 2
serializers/src/tsconfig.json

@@ -7,7 +7,6 @@
     "noImplicitReturns": true,
     "noImplicitReturns": true,
     "noImplicitThis": true,
     "noImplicitThis": true,
     "noUnusedLocals": true,    
     "noUnusedLocals": true,    
-    "strictNullChecks": true,
-    "strict": true
+    "strictNullChecks": true
   }
   }
 }
 }

+ 42 - 1
src/Animations/babylon.animatable.ts

@@ -7,10 +7,30 @@
         private _scene: Scene;
         private _scene: Scene;
         private _speedRatio = 1;
         private _speedRatio = 1;
         private _weight = -1.0;
         private _weight = -1.0;
+        private _syncRoot: Animatable;
 
 
         public animationStarted = false;
         public animationStarted = false;
 
 
         /**
         /**
+         * Gets the root Animatable used to synchronize and normalize animations
+         */
+        public get syncRoot(): Animatable {
+            return this._syncRoot;
+        }
+
+        /**
+         * Gets the current frame of the first RuntimeAnimation
+         * Used to synchronize Animatables
+         */
+        public get masterFrame(): number {
+            if (this._runtimeAnimations.length === 0) {
+                return 0;
+            }
+
+            return this._runtimeAnimations[0].currentFrame;
+        }
+
+        /**
          * Gets or sets the animatable weight (-1.0 by default meaning not weighted)
          * Gets or sets the animatable weight (-1.0 by default meaning not weighted)
          */
          */
         public get weight(): number {
         public get weight(): number {
@@ -55,6 +75,27 @@
         }
         }
 
 
         // Methods
         // Methods
+        /**
+         * Synchronize and normalize current Animatable with a source Animatable.
+         * This is useful when using animation weights and when animations are not of the same length
+         * @param root defines the root Animatable to synchronize with
+         * @returns the current Animatable
+         */
+        public syncWith(root: Animatable): Animatable {
+            this._syncRoot = root;
+
+            if (root) {
+                // Make sure this animatable will animate after the root
+                let index = this._scene._activeAnimatables.indexOf(this);
+                if (index > -1) {
+                    this._scene._activeAnimatables.splice(index, 1);
+                    this._scene._activeAnimatables.push(this);
+                }
+            }
+
+            return this;
+        }
+
         public getAnimations(): RuntimeAnimation[] {
         public getAnimations(): RuntimeAnimation[] {
             return this._runtimeAnimations;
             return this._runtimeAnimations;
         }
         }
@@ -63,7 +104,7 @@
             for (var index = 0; index < animations.length; index++) {
             for (var index = 0; index < animations.length; index++) {
                 var animation = animations[index];
                 var animation = animations[index];
 
 
-                this._runtimeAnimations.push(new RuntimeAnimation(target, animation, this._scene));
+                this._runtimeAnimations.push(new RuntimeAnimation(target, animation, this._scene, this));
             }
             }
         }
         }
 
 

+ 12 - 2
src/Animations/babylon.animationGroup.ts

@@ -144,15 +144,25 @@ module BABYLON {
          * Start all animations on given targets
          * Start all animations on given targets
          * @param loop defines if animations must loop
          * @param loop defines if animations must loop
          * @param speedRatio defines the ratio to apply to animation speed (1 by default)
          * @param speedRatio defines the ratio to apply to animation speed (1 by default)
+         * @param from defines the from key (optional)
+         * @param to defines the to key (optional)
+         * @returns the current animation group
          */
          */
-        public start(loop = false, speedRatio = 1): AnimationGroup {
+        public start(loop = false, speedRatio = 1, from?: number, to?: number): AnimationGroup {
             if (this._isStarted || this._targetedAnimations.length === 0) {
             if (this._isStarted || this._targetedAnimations.length === 0) {
                 return this;
                 return this;
             }
             }
 
 
             for (var index = 0; index < this._targetedAnimations.length; index++) {
             for (var index = 0; index < this._targetedAnimations.length; index++) {
                 let targetedAnimation = this._targetedAnimations[index];
                 let targetedAnimation = this._targetedAnimations[index];
-                this._animatables.push(this._scene.beginDirectAnimation(targetedAnimation.target, [targetedAnimation.animation], this._from, this._to, loop, speedRatio, () => {
+                if (!targetedAnimation.target.animations) {
+                    targetedAnimation.target.animations = [];
+                }
+                if (targetedAnimation.target.animations.indexOf(targetedAnimation.animation) === -1) {
+                    targetedAnimation.target.animations.push(targetedAnimation.animation);
+                }
+                
+                this._animatables.push(this._scene.beginDirectAnimation(targetedAnimation.target, [targetedAnimation.animation], from !== undefined ? from : this._from, to !== undefined ? to : this._to, loop, speedRatio, () => {
                     this.onAnimationEndObservable.notifyObservers(targetedAnimation);
                     this.onAnimationEndObservable.notifyObservers(targetedAnimation);
                 }));
                 }));
             }
             }

+ 23 - 5
src/Animations/babylon.runtimeAnimation.ts

@@ -1,9 +1,10 @@
 module BABYLON {
 module BABYLON {
 
 
     export class RuntimeAnimation {
     export class RuntimeAnimation {
-        public currentFrame: number = 0;
+        private _currentFrame: number = 0;
         private _animation: Animation;
         private _animation: Animation;
         private _target: any;
         private _target: any;
+        private _host: Animatable;
 
 
         private _originalValue: any;
         private _originalValue: any;
         private _originalBlendValue: any;
         private _originalBlendValue: any;
@@ -16,7 +17,14 @@
         private _currentValue: any;
         private _currentValue: any;
         private _activeTarget: any;
         private _activeTarget: any;
         private _targetPath: string = "";
         private _targetPath: string = "";
-        private _weight = 1.0
+        private _weight = 1.0;
+
+        /**
+         * Gets the current frame
+         */
+        public get currentFrame(): number {
+            return this._currentFrame;
+        }
 
 
         /**
         /**
          * Gets the weight of the runtime animation
          * Gets the weight of the runtime animation
@@ -58,11 +66,13 @@
          * @param target defines the target of the animation
          * @param target defines the target of the animation
          * @param animation defines the source {BABYLON.Animation} object
          * @param animation defines the source {BABYLON.Animation} object
          * @param scene defines the hosting scene
          * @param scene defines the hosting scene
+         * @param host defines the initiating Animatable
          */
          */
-        public constructor(target: any, animation: Animation, scene: Scene) {
+        public constructor(target: any, animation: Animation, scene: Scene, host: Animatable) {
             this._animation = animation;
             this._animation = animation;
             this._target = target;
             this._target = target;
             this._scene = scene;
             this._scene = scene;
+            this._host = host;
 
 
             animation._runtimeAnimations.push(this);
             animation._runtimeAnimations.push(this);
         }
         }
@@ -74,7 +84,7 @@
         public reset(): void {
         public reset(): void {
             this._offsetsCache = {};
             this._offsetsCache = {};
             this._highLimitsCache = {};
             this._highLimitsCache = {};
-            this.currentFrame = 0;
+            this._currentFrame = 0;
             this._blendingFactor = 0;
             this._blendingFactor = 0;
             this._originalValue = null;
             this._originalValue = null;
         }
         }
@@ -104,7 +114,7 @@
                 return highLimitValue.clone ? highLimitValue.clone() : highLimitValue;
                 return highLimitValue.clone ? highLimitValue.clone() : highLimitValue;
             }
             }
 
 
-            this.currentFrame = currentFrame;
+            this._currentFrame = currentFrame;
 
 
             let keys = this._animation.getKeys();
             let keys = this._animation.getKeys();
 
 
@@ -482,6 +492,14 @@
             // Compute value
             // Compute value
             var repeatCount = (ratio / range) >> 0;
             var repeatCount = (ratio / range) >> 0;
             var currentFrame = returnValue ? from + ratio % range : to;
             var currentFrame = returnValue ? from + ratio % range : to;
+
+            // Need to normalize?
+            if (this._host && this._host.syncRoot) {
+                let syncRoot = this._host.syncRoot;
+                let hostNormalizedFrame = (syncRoot.masterFrame - syncRoot.fromFrame) / (syncRoot.toFrame - syncRoot.fromFrame);
+                currentFrame = from + (to - from) * hostNormalizedFrame;
+            }
+
             var currentValue = this._interpolate(currentFrame, repeatCount, this._getCorrectLoopMode(), offsetValue, highLimitValue);
             var currentValue = this._interpolate(currentFrame, repeatCount, this._getCorrectLoopMode(), offsetValue, highLimitValue);
 
 
             // Set value
             // Set value

+ 88 - 73
src/Audio/babylon.sound.ts

@@ -91,89 +91,104 @@ module BABYLON {
                 }
                 }
                 this._scene.mainSoundTrack.AddSound(this);
                 this._scene.mainSoundTrack.AddSound(this);
                 var validParameter = true;
                 var validParameter = true;
+
                 // if no parameter is passed, you need to call setAudioBuffer yourself to prepare the sound
                 // if no parameter is passed, you need to call setAudioBuffer yourself to prepare the sound
                 if (urlOrArrayBuffer) {
                 if (urlOrArrayBuffer) {
-                    if (typeof (urlOrArrayBuffer) === "string") this._urlType = "String";
-                    if (Array.isArray(urlOrArrayBuffer)) this._urlType = "Array";
-                    if (urlOrArrayBuffer instanceof ArrayBuffer) this._urlType = "ArrayBuffer";
-
-                    var urls: string[] = [];
-                    var codecSupportedFound = false;
-
-                    switch (this._urlType) {
-                        case "ArrayBuffer":
-                            if ((<ArrayBuffer>urlOrArrayBuffer).byteLength > 0) {
-                                codecSupportedFound = true;
-                                this._soundLoaded(urlOrArrayBuffer);
-                            }
-                            break;
-                        case "String":
-                            urls.push(urlOrArrayBuffer);
-                        case "Array":
-                            if (urls.length === 0) urls = urlOrArrayBuffer;
-                            // If we found a supported format, we load it immediately and stop the loop
-                            for (var i = 0; i < urls.length; i++) {
-                                var url = urls[i];
-                                if (url.indexOf(".mp3", url.length - 4) !== -1 && Engine.audioEngine.isMP3supported) {
-                                    codecSupportedFound = true;
-                                }
-                                if (url.indexOf(".ogg", url.length - 4) !== -1 && Engine.audioEngine.isOGGsupported) {
-                                    codecSupportedFound = true;
-                                }
-                                if (url.indexOf(".wav", url.length - 4) !== -1) {
-                                    codecSupportedFound = true;
-                                }
-                                if (url.indexOf("blob:") !== -1) {
+                    try {
+                        if (typeof (urlOrArrayBuffer) === "string") this._urlType = "String";
+                        if (Array.isArray(urlOrArrayBuffer)) this._urlType = "Array";
+                        if (urlOrArrayBuffer instanceof ArrayBuffer) this._urlType = "ArrayBuffer";
+
+                        var urls: string[] = [];
+                        var codecSupportedFound = false;
+
+                        switch (this._urlType) {
+                            case "ArrayBuffer":
+                                if ((<ArrayBuffer>urlOrArrayBuffer).byteLength > 0) {
                                     codecSupportedFound = true;
                                     codecSupportedFound = true;
+                                    this._soundLoaded(urlOrArrayBuffer);
                                 }
                                 }
-                                if (codecSupportedFound) {
-                                    // Loading sound using XHR2
-                                    if (!this._streaming) {
-                                        this._scene._loadFile(url, (data) => { this._soundLoaded(data as ArrayBuffer); }, undefined, true, true);
+                                break;
+                            case "String":
+                                urls.push(urlOrArrayBuffer);
+                            case "Array":
+                                if (urls.length === 0) urls = urlOrArrayBuffer;
+                                // If we found a supported format, we load it immediately and stop the loop
+                                for (var i = 0; i < urls.length; i++) {
+                                    var url = urls[i];
+                                    if (url.indexOf(".mp3", url.length - 4) !== -1 && Engine.audioEngine.isMP3supported) {
+                                        codecSupportedFound = true;
+                                    }
+                                    if (url.indexOf(".ogg", url.length - 4) !== -1 && Engine.audioEngine.isOGGsupported) {
+                                        codecSupportedFound = true;
                                     }
                                     }
-                                    // Streaming sound using HTML5 Audio tag
-                                    else {
-                                        this._htmlAudioElement = new Audio(url);
-                                        this._htmlAudioElement.controls = false;
-                                        this._htmlAudioElement.loop = this.loop;
-                                        Tools.SetCorsBehavior(url, this._htmlAudioElement);
-                                        this._htmlAudioElement.preload = "auto";
-                                        this._htmlAudioElement.addEventListener("canplaythrough", () => {
-                                            this._isReadyToPlay = true;
-                                            if (this.autoplay) {
-                                                this.play();
-                                            }
-                                            if (this._readyToPlayCallback) {
-                                                this._readyToPlayCallback();
-                                            }
-                                        });
-                                        document.body.appendChild(this._htmlAudioElement);
+                                    if (url.indexOf(".wav", url.length - 4) !== -1) {
+                                        codecSupportedFound = true;
+                                    }
+                                    if (url.indexOf("blob:") !== -1) {
+                                        codecSupportedFound = true;
+                                    }
+                                    if (codecSupportedFound) {
+                                        // Loading sound using XHR2
+                                        if (!this._streaming) {
+                                            this._scene._loadFile(url, (data) => { 
+                                                this._soundLoaded(data as ArrayBuffer); 
+                                            }, undefined, true, true, (exception) => {
+                                                if (exception) {
+                                                    Tools.Error("XHR " + exception.status + " error on: " + url + ".");
+                                                }
+                                                Tools.Error("Sound creation aborted.");
+                                                this._scene.mainSoundTrack.RemoveSound(this);
+                                            });
+                                        }
+                                        // Streaming sound using HTML5 Audio tag
+                                        else {
+                                            this._htmlAudioElement = new Audio(url);
+                                            this._htmlAudioElement.controls = false;
+                                            this._htmlAudioElement.loop = this.loop;
+                                            Tools.SetCorsBehavior(url, this._htmlAudioElement);
+                                            this._htmlAudioElement.preload = "auto";
+                                            this._htmlAudioElement.addEventListener("canplaythrough", () => {
+                                                this._isReadyToPlay = true;
+                                                if (this.autoplay) {
+                                                    this.play();
+                                                }
+                                                if (this._readyToPlayCallback) {
+                                                    this._readyToPlayCallback();
+                                                }
+                                            });
+                                            document.body.appendChild(this._htmlAudioElement);
+                                        }
+                                        break;
                                     }
                                     }
-                                    break;
                                 }
                                 }
-                            }
-                            break;
-                        default:
-                            validParameter = false;
-                            break;
-                    }
+                                break;
+                            default:
+                                validParameter = false;
+                                break;
+                        }
 
 
-                    if (!validParameter) {
-                        Tools.Error("Parameter must be a URL to the sound, an Array of URLs (.mp3 & .ogg) or an ArrayBuffer of the sound.");
-                    }
-                    else {
-                        if (!codecSupportedFound) {
-                            this._isReadyToPlay = true;
-                            // Simulating a ready to play event to avoid breaking code path
-                            if (this._readyToPlayCallback) {
-                                window.setTimeout(() => {
-                                    if (this._readyToPlayCallback) {
-                                        this._readyToPlayCallback();
-                                    }
-                                }, 1000);
+                        if (!validParameter) {
+                            Tools.Error("Parameter must be a URL to the sound, an Array of URLs (.mp3 & .ogg) or an ArrayBuffer of the sound.");
+                        }
+                        else {
+                            if (!codecSupportedFound) {
+                                this._isReadyToPlay = true;
+                                // Simulating a ready to play event to avoid breaking code path
+                                if (this._readyToPlayCallback) {
+                                    window.setTimeout(() => {
+                                        if (this._readyToPlayCallback) {
+                                            this._readyToPlayCallback();
+                                        }
+                                    }, 1000);
+                                }
                             }
                             }
                         }
                         }
                     }
                     }
+                    catch (ex) {
+                        Tools.Error("Unexpected error. Sound creation aborted.");
+                        this._scene.mainSoundTrack.RemoveSound(this);
+                    }
                 }
                 }
             }
             }
             else {
             else {
@@ -195,7 +210,7 @@ module BABYLON {
         }
         }
 
 
         public dispose() {
         public dispose() {
-            if (Engine.audioEngine.canUseWebAudio && this._isReadyToPlay) {
+            if (Engine.audioEngine.canUseWebAudio) { 
                 if (this.isPlaying) {
                 if (this.isPlaying) {
                     this.stop();
                     this.stop();
                 }
                 }

+ 1 - 0
src/Engine/babylon.engine.ts

@@ -5621,6 +5621,7 @@
 
 
             // Unbind
             // Unbind
             this.unbindAllAttributes();
             this.unbindAllAttributes();
+            this._boundUniforms = [];
 
 
             if (this._dummyFramebuffer) {
             if (this._dummyFramebuffer) {
                 this._gl.deleteFramebuffer(this._dummyFramebuffer);
                 this._gl.deleteFramebuffer(this._dummyFramebuffer);

+ 18 - 2
src/Layer/babylon.effectLayer.ts

@@ -372,6 +372,18 @@
                 defines.push("#define NUM_BONE_INFLUENCERS 0");
                 defines.push("#define NUM_BONE_INFLUENCERS 0");
             }
             }
 
 
+            // Morph targets         
+            var manager = (<Mesh>mesh).morphTargetManager;
+            let morphInfluencers = 0;
+            if (manager) {
+                if (manager.numInfluencers > 0) {
+                    defines.push("#define MORPHTARGETS");
+                    morphInfluencers = manager.numInfluencers;
+                    defines.push("#define NUM_MORPH_INFLUENCERS " + morphInfluencers);
+                    MaterialHelper.PrepareAttributesForMorphTargets(attribs, mesh, {"NUM_MORPH_INFLUENCERS": morphInfluencers });
+                }
+            }            
+
             // Instances
             // Instances
             if (useInstances) {
             if (useInstances) {
                 defines.push("#define INSTANCES");
                 defines.push("#define INSTANCES");
@@ -387,8 +399,9 @@
                 this._cachedDefines = join;
                 this._cachedDefines = join;
                 this._effectLayerMapGenerationEffect = this._scene.getEngine().createEffect("glowMapGeneration",
                 this._effectLayerMapGenerationEffect = this._scene.getEngine().createEffect("glowMapGeneration",
                     attribs,
                     attribs,
-                    ["world", "mBones", "viewProjection", "diffuseMatrix", "color", "emissiveMatrix"],
-                    ["diffuseSampler", "emissiveSampler"], join);
+                    ["world", "mBones", "viewProjection", "diffuseMatrix", "color", "emissiveMatrix", "morphTargetInfluences"],
+                    ["diffuseSampler", "emissiveSampler"], join,
+                    undefined, undefined, undefined, { maxSimultaneousMorphTargets: morphInfluencers });
             }
             }
 
 
             return this._effectLayerMapGenerationEffect.isReady();
             return this._effectLayerMapGenerationEffect.isReady();
@@ -558,6 +571,9 @@
                     this._effectLayerMapGenerationEffect.setMatrices("mBones", mesh.skeleton.getTransformMatrices(mesh));
                     this._effectLayerMapGenerationEffect.setMatrices("mBones", mesh.skeleton.getTransformMatrices(mesh));
                 }
                 }
 
 
+                // Morph targets
+                MaterialHelper.BindMorphTargetParameters(mesh, this._effectLayerMapGenerationEffect);
+
                 // Draw
                 // Draw
                 mesh._processRendering(subMesh, this._effectLayerMapGenerationEffect, Material.TriangleFillMode, batch, hardwareInstancedRendering,
                 mesh._processRendering(subMesh, this._effectLayerMapGenerationEffect, Material.TriangleFillMode, batch, hardwareInstancedRendering,
                     (isInstance, world) => this._effectLayerMapGenerationEffect.setMatrix("world", world));
                     (isInstance, world) => this._effectLayerMapGenerationEffect.setMatrix("world", world));

+ 18 - 2
src/Lights/Shadows/babylon.shadowGenerator.ts

@@ -902,6 +902,9 @@
                     this._effect.setMatrices("mBones", (<Skeleton>mesh.skeleton).getTransformMatrices((mesh)));
                     this._effect.setMatrices("mBones", (<Skeleton>mesh.skeleton).getTransformMatrices((mesh)));
                 }
                 }
 
 
+                // Morph targets
+                MaterialHelper.BindMorphTargetParameters(mesh, this._effect);
+
                 if (this.forceBackFacesOnly) {
                 if (this.forceBackFacesOnly) {
                     engine.setState(true, 0, false, true);
                     engine.setState(true, 0, false, true);
                 }
                 }
@@ -1075,6 +1078,18 @@
                 defines.push("#define NUM_BONE_INFLUENCERS 0");
                 defines.push("#define NUM_BONE_INFLUENCERS 0");
             }
             }
 
 
+            // Morph targets         
+            var manager = (<Mesh>mesh).morphTargetManager;
+            let morphInfluencers = 0;
+            if (manager) {
+                if (manager.numInfluencers > 0) {
+                    defines.push("#define MORPHTARGETS");
+                    morphInfluencers = manager.numInfluencers;
+                    defines.push("#define NUM_MORPH_INFLUENCERS " + morphInfluencers);
+                    MaterialHelper.PrepareAttributesForMorphTargets(attribs, mesh, {"NUM_MORPH_INFLUENCERS": morphInfluencers });
+                }
+            }
+
             // Instances
             // Instances
             if (useInstances) {
             if (useInstances) {
                 defines.push("#define INSTANCES");
                 defines.push("#define INSTANCES");
@@ -1090,8 +1105,9 @@
                 this._cachedDefines = join;
                 this._cachedDefines = join;
                 this._effect = this._scene.getEngine().createEffect("shadowMap",
                 this._effect = this._scene.getEngine().createEffect("shadowMap",
                     attribs,
                     attribs,
-                    ["world", "mBones", "viewProjection", "diffuseMatrix", "lightData", "depthValues", "biasAndScale"],
-                    ["diffuseSampler"], join);
+                    ["world", "mBones", "viewProjection", "diffuseMatrix", "lightData", "depthValues", "biasAndScale", "morphTargetInfluences"],
+                    ["diffuseSampler"], join,
+                    undefined, undefined, undefined, { maxSimultaneousMorphTargets: morphInfluencers });
             }
             }
 
 
             if (!this._effect.isReady()) {
             if (!this._effect.isReady()) {

+ 115 - 168
src/Materials/babylon.effect.ts

@@ -1,6 +1,6 @@
 module BABYLON {
 module BABYLON {
     /**
     /**
-	 * EffectFallbacks can be used to add fallbacks (properties to disable) to certain properties when desired to improve performance.
+     * EffectFallbacks can be used to add fallbacks (properties to disable) to certain properties when desired to improve performance.
      * (Eg. Start at high quality with reflection and fog, if fps is low, remove reflection, if still low remove fog)
      * (Eg. Start at high quality with reflection and fog, if fps is low, remove reflection, if still low remove fog)
      */
      */
     export class EffectFallbacks {
     export class EffectFallbacks {
@@ -116,7 +116,7 @@
     }
     }
 
 
     /**
     /**
-	 * Options to be used when creating an effect.
+     * Options to be used when creating an effect.
      */
      */
     export class EffectCreationOptions {
     export class EffectCreationOptions {
         /**
         /**
@@ -227,7 +227,6 @@
         private _vertexSourceCodeOverride: string;
         private _vertexSourceCodeOverride: string;
         private _fragmentSourceCodeOverride: string;
         private _fragmentSourceCodeOverride: string;
         private _transformFeedbackVaryings: Nullable<string[]>;
         private _transformFeedbackVaryings: Nullable<string[]>;
-
         /**
         /**
          * Compiled shader to webGL program.
          * Compiled shader to webGL program.
          */
          */
@@ -288,11 +287,6 @@
 
 
             this.uniqueId = Effect._uniqueIdSeed++;
             this.uniqueId = Effect._uniqueIdSeed++;
 
 
-            if (this._getFromCache(baseName)) {
-                this._prepareEffect();
-                return;
-            }
-
             var vertexSource: any;
             var vertexSource: any;
             var fragmentSource: any;
             var fragmentSource: any;
 
 
@@ -316,83 +310,31 @@
                 fragmentSource = baseName.fragment || baseName;
                 fragmentSource = baseName.fragment || baseName;
             }
             }
 
 
-            let finalVertexCode: string;
-
-            this._loadVertexShaderAsync(vertexSource)
-            .then((vertexCode) => {
-                return this._processIncludesAsync(vertexCode);
-            })
-            .then((vertexCodeWithIncludes) => {
-                finalVertexCode = this._processShaderConversion(vertexCodeWithIncludes, false);
-                return this._loadFragmentShaderAsync(fragmentSource);
-            })
-            .then((fragmentCode) => {
-                return this._processIncludesAsync(fragmentCode);
-            })
-            .then((fragmentCodeWithIncludes) => {
-                let migratedFragmentCode = this._processShaderConversion(fragmentCodeWithIncludes, true);
-                if (baseName) {
-                    var vertex = baseName.vertexElement || baseName.vertex || baseName;
-                    var fragment = baseName.fragmentElement || baseName.fragment || baseName;
-
-                    this._vertexSourceCode = "#define SHADER_NAME vertex:" + vertex + "\n" + finalVertexCode;
-                    this._fragmentSourceCode = "#define SHADER_NAME fragment:" + fragment + "\n" + migratedFragmentCode;
-                } else {
-                    this._vertexSourceCode = finalVertexCode;
-                    this._fragmentSourceCode = migratedFragmentCode;
-                }
-
-                this._setInCache(baseName);
-                this._prepareEffect(); 
+            this._loadVertexShader(vertexSource, vertexCode => {
+                this._processIncludes(vertexCode, vertexCodeWithIncludes => {
+                    this._processShaderConversion(vertexCodeWithIncludes, false, migratedVertexCode => {
+                        this._loadFragmentShader(fragmentSource, (fragmentCode) => {
+                            this._processIncludes(fragmentCode, fragmentCodeWithIncludes => {
+                                this._processShaderConversion(fragmentCodeWithIncludes, true, migratedFragmentCode => {
+                                    if (baseName) {
+                                        var vertex = baseName.vertexElement || baseName.vertex || baseName;
+                                        var fragment = baseName.fragmentElement || baseName.fragment || baseName;
+
+                                        this._vertexSourceCode = "#define SHADER_NAME vertex:" + vertex + "\n" + migratedVertexCode;
+                                        this._fragmentSourceCode = "#define SHADER_NAME fragment:" + fragment + "\n" + migratedFragmentCode;
+                                    } else {
+                                        this._vertexSourceCode = migratedVertexCode;
+                                        this._fragmentSourceCode = migratedFragmentCode;
+                                    }
+                                    this._prepareEffect();
+                                });
+                            });
+                        });
+                    });
+                });
             });
             });
         }
         }
 
 
-        private static _sourceCache: { [baseName: string]: { vertex: string, fragment: string } } = { };
-
-        private _getSourceCacheKey(baseName: string): string {
-            let cacheKey: string = baseName;
-            if (this._indexParameters) {
-                for (let key in this._indexParameters) {
-                    if (this._indexParameters.hasOwnProperty(key)) {
-                        cacheKey += "|";
-                        cacheKey += key
-                        cacheKey += "_";
-                        cacheKey += this._indexParameters[key];
-                    }
-                }
-            }
-
-            return cacheKey;
-        }
-
-        private _getFromCache(baseName: string): boolean {
-            if (typeof baseName !== "string") {
-                return false;
-            }
-
-            let cacheKey = this._getSourceCacheKey(baseName);
-            let sources = Effect._sourceCache[cacheKey];
-            if (!sources) {
-                return false;
-            }
-
-            this._vertexSourceCode = sources.vertex;
-            this._fragmentSourceCode = sources.fragment;
-            return true;
-        }
-
-        private _setInCache(baseName: string): void {
-            if (typeof baseName !== "string") {
-                return;
-            }
-
-            let cacheKey = this._getSourceCacheKey(baseName);
-            Effect._sourceCache[cacheKey] = {
-                vertex: this._vertexSourceCode,
-                fragment: this._fragmentSourceCode
-            };
-        }
-
         /**
         /**
          * Unique key for this effect
          * Unique key for this effect
          */
          */
@@ -423,6 +365,7 @@
         public getProgram(): WebGLProgram {
         public getProgram(): WebGLProgram {
             return this._program;
             return this._program;
         }
         }
+
         /**
         /**
          * The set of names of attribute variables for the shader.
          * The set of names of attribute variables for the shader.
          * @returns An array of attribute names.
          * @returns An array of attribute names.
@@ -509,24 +452,27 @@
         }
         }
 
 
         /** @ignore */
         /** @ignore */
-        public _loadVertexShaderAsync(vertex: any): Promise<any> {
+        public _loadVertexShader(vertex: any, callback: (data: any) => void): void {
             if (Tools.IsWindowObjectExist()) {
             if (Tools.IsWindowObjectExist()) {
                 // DOM element ?
                 // DOM element ?
                 if (vertex instanceof HTMLElement) {
                 if (vertex instanceof HTMLElement) {
                     var vertexCode = Tools.GetDOMTextContent(vertex);
                     var vertexCode = Tools.GetDOMTextContent(vertex);
-                    return Promise.resolve(vertexCode);
+                    callback(vertexCode);
+                    return;
                 }
                 }
             }
             }
 
 
             // Base64 encoded ?
             // Base64 encoded ?
             if (vertex.substr(0, 7) === "base64:") {
             if (vertex.substr(0, 7) === "base64:") {
                 var vertexBinary = window.atob(vertex.substr(7));
                 var vertexBinary = window.atob(vertex.substr(7));
-                return Promise.resolve(vertexBinary);
+                callback(vertexBinary);
+                return;
             }
             }
 
 
             // Is in local store ?
             // Is in local store ?
             if (Effect.ShadersStore[vertex + "VertexShader"]) {
             if (Effect.ShadersStore[vertex + "VertexShader"]) {
-                return Promise.resolve(Effect.ShadersStore[vertex + "VertexShader"]);
+                callback(Effect.ShadersStore[vertex + "VertexShader"]);
+                return;
             }
             }
 
 
             var vertexShaderUrl;
             var vertexShaderUrl;
@@ -538,32 +484,36 @@
             }
             }
 
 
             // Vertex shader
             // Vertex shader
-            return this._engine._loadFileAsync(vertexShaderUrl + ".vertex.fx");
+            this._engine._loadFile(vertexShaderUrl + ".vertex.fx", callback);
         }
         }
 
 
         /** @ignore */
         /** @ignore */
-        public _loadFragmentShaderAsync(fragment: any): Promise<any>  {
+        public _loadFragmentShader(fragment: any, callback: (data: any) => void): void {
             if (Tools.IsWindowObjectExist()) {
             if (Tools.IsWindowObjectExist()) {
                 // DOM element ?
                 // DOM element ?
                 if (fragment instanceof HTMLElement) {
                 if (fragment instanceof HTMLElement) {
                     var fragmentCode = Tools.GetDOMTextContent(fragment);
                     var fragmentCode = Tools.GetDOMTextContent(fragment);
-                    return Promise.resolve(fragmentCode);
+                    callback(fragmentCode);
+                    return;
                 }
                 }
             }
             }
 
 
             // Base64 encoded ?
             // Base64 encoded ?
             if (fragment.substr(0, 7) === "base64:") {
             if (fragment.substr(0, 7) === "base64:") {
                 var fragmentBinary = window.atob(fragment.substr(7));
                 var fragmentBinary = window.atob(fragment.substr(7));
-                return Promise.resolve(fragmentBinary);
+                callback(fragmentBinary);
+                return;
             }
             }
 
 
             // Is in local store ?
             // Is in local store ?
             if (Effect.ShadersStore[fragment + "PixelShader"]) {
             if (Effect.ShadersStore[fragment + "PixelShader"]) {
-                return Promise.resolve(Effect.ShadersStore[fragment + "PixelShader"]);
+                callback(Effect.ShadersStore[fragment + "PixelShader"]);
+                return;
             }
             }
 
 
             if (Effect.ShadersStore[fragment + "FragmentShader"]) {
             if (Effect.ShadersStore[fragment + "FragmentShader"]) {
-                return Promise.resolve(Effect.ShadersStore[fragment + "FragmentShader"]);
+                callback(Effect.ShadersStore[fragment + "FragmentShader"]);
+                return;
             }
             }
 
 
             var fragmentShaderUrl;
             var fragmentShaderUrl;
@@ -575,7 +525,7 @@
             }
             }
 
 
             // Fragment shader
             // Fragment shader
-            return this._engine._loadFileAsync(fragmentShaderUrl + ".fragment.fx");
+            this._engine._loadFile(fragmentShaderUrl + ".fragment.fx", callback);
         }
         }
 
 
         private _dumpShadersSource(vertexCode: string, fragmentCode: string, defines: string): void {
         private _dumpShadersSource(vertexCode: string, fragmentCode: string, defines: string): void {
@@ -607,16 +557,19 @@
             }
             }
         };
         };
 
 
-        private _processShaderConversion(sourceCode: string, isFragment: boolean): any {
+        private _processShaderConversion(sourceCode: string, isFragment: boolean, callback: (data: any) => void): void {
+
             var preparedSourceCode = this._processPrecision(sourceCode);
             var preparedSourceCode = this._processPrecision(sourceCode);
 
 
             if (this._engine.webGLVersion == 1) {
             if (this._engine.webGLVersion == 1) {
-                return preparedSourceCode;
+                callback(preparedSourceCode);
+                return;
             }
             }
 
 
             // Already converted
             // Already converted
             if (preparedSourceCode.indexOf("#version 3") !== -1) {
             if (preparedSourceCode.indexOf("#version 3") !== -1) {
-                return preparedSourceCode.replace("#version 300 es", "");
+                callback(preparedSourceCode.replace("#version 300 es", ""));
+                return;
             }
             }
 
 
             var hasDrawBuffersExtension = preparedSourceCode.search(/#extension.+GL_EXT_draw_buffers.+require/) !== -1;
             var hasDrawBuffersExtension = preparedSourceCode.search(/#extension.+GL_EXT_draw_buffers.+require/) !== -1;
@@ -645,97 +598,92 @@
                 result = result.replace(/void\s+?main\s*\(/g, (hasDrawBuffersExtension ? "" : "out vec4 glFragColor;\n") + "void main(");
                 result = result.replace(/void\s+?main\s*\(/g, (hasDrawBuffersExtension ? "" : "out vec4 glFragColor;\n") + "void main(");
             }
             }
 
 
-            return result;
+            callback(result);
         }
         }
 
 
-        private _processIncludesAsync(sourceCode: string): Promise<any> {
-            return new Promise((resolve, reject) => {
-                var regex = /#include<(.+)>(\((.*)\))*(\[(.*)\])*/g;
-                var match = regex.exec(sourceCode);
+        private _processIncludes(sourceCode: string, callback: (data: any) => void): void {
+            var regex = /#include<(.+)>(\((.*)\))*(\[(.*)\])*/g;
+            var match = regex.exec(sourceCode);
 
 
-                var returnValue = sourceCode;
+            var returnValue = new String(sourceCode);
 
 
-                while (match != null) {
-                    var includeFile = match[1];
+            while (match != null) {
+                var includeFile = match[1];
 
 
-                    // Uniform declaration
-                    if (includeFile.indexOf("__decl__") !== -1) {
-                        includeFile = includeFile.replace(/__decl__/, "");
-                        if (this._engine.supportsUniformBuffers) {
-                            includeFile = includeFile.replace(/Vertex/, "Ubo");
-                            includeFile = includeFile.replace(/Fragment/, "Ubo");
-                        }
-                        includeFile = includeFile + "Declaration";
+                // Uniform declaration
+                if (includeFile.indexOf("__decl__") !== -1) {
+                    includeFile = includeFile.replace(/__decl__/, "");
+                    if (this._engine.supportsUniformBuffers) {
+                        includeFile = includeFile.replace(/Vertex/, "Ubo");
+                        includeFile = includeFile.replace(/Fragment/, "Ubo");
                     }
                     }
+                    includeFile = includeFile + "Declaration";
+                }
 
 
-                    if (Effect.IncludesShadersStore[includeFile]) {
-                        // Substitution
-                        var includeContent = Effect.IncludesShadersStore[includeFile];
-                        if (match[2]) {
-                            var splits = match[3].split(",");
+                if (Effect.IncludesShadersStore[includeFile]) {
+                    // Substitution
+                    var includeContent = Effect.IncludesShadersStore[includeFile];
+                    if (match[2]) {
+                        var splits = match[3].split(",");
 
 
-                            for (var index = 0; index < splits.length; index += 2) {
-                                var source = new RegExp(splits[index], "g");
-                                var dest = splits[index + 1];
+                        for (var index = 0; index < splits.length; index += 2) {
+                            var source = new RegExp(splits[index], "g");
+                            var dest = splits[index + 1];
 
 
-                                includeContent = includeContent.replace(source, dest);
-                            }
+                            includeContent = includeContent.replace(source, dest);
                         }
                         }
+                    }
 
 
-                        if (match[4]) {
-                            var indexString = match[5];
+                    if (match[4]) {
+                        var indexString = match[5];
 
 
-                            if (indexString.indexOf("..") !== -1) {
-                                var indexSplits = indexString.split("..");
-                                var minIndex = parseInt(indexSplits[0]);
-                                var maxIndex = parseInt(indexSplits[1]);
-                                var sourceIncludeContent = includeContent.slice(0);
-                                includeContent = "";
+                        if (indexString.indexOf("..") !== -1) {
+                            var indexSplits = indexString.split("..");
+                            var minIndex = parseInt(indexSplits[0]);
+                            var maxIndex = parseInt(indexSplits[1]);
+                            var sourceIncludeContent = includeContent.slice(0);
+                            includeContent = "";
 
 
-                                if (isNaN(maxIndex)) {
-                                    maxIndex = this._indexParameters[indexSplits[1]];
-                                }
+                            if (isNaN(maxIndex)) {
+                                maxIndex = this._indexParameters[indexSplits[1]];
+                            }
 
 
-                                for (var i = minIndex; i < maxIndex; i++) {
-                                    if (!this._engine.supportsUniformBuffers) {
-                                        // Ubo replacement
-                                        sourceIncludeContent = sourceIncludeContent.replace(/light\{X\}.(\w*)/g, (str: string, p1: string) => {
-                                            return p1 + "{X}";
-                                        });
-                                    }
-                                    includeContent += sourceIncludeContent.replace(/\{X\}/g, i.toString()) + "\n";
-                                }
-                            } else {
+                            for (var i = minIndex; i < maxIndex; i++) {
                                 if (!this._engine.supportsUniformBuffers) {
                                 if (!this._engine.supportsUniformBuffers) {
                                     // Ubo replacement
                                     // Ubo replacement
-                                    includeContent = includeContent.replace(/light\{X\}.(\w*)/g, (str: string, p1: string) => {
+                                    sourceIncludeContent = sourceIncludeContent.replace(/light\{X\}.(\w*)/g, (str: string, p1: string) => {
                                         return p1 + "{X}";
                                         return p1 + "{X}";
                                     });
                                     });
                                 }
                                 }
-                                includeContent = includeContent.replace(/\{X\}/g, indexString);
+                                includeContent += sourceIncludeContent.replace(/\{X\}/g, i.toString()) + "\n";
                             }
                             }
+                        } else {
+                            if (!this._engine.supportsUniformBuffers) {
+                                // Ubo replacement
+                                includeContent = includeContent.replace(/light\{X\}.(\w*)/g, (str: string, p1: string) => {
+                                    return p1 + "{X}";
+                                });
+                            }
+                            includeContent = includeContent.replace(/\{X\}/g, indexString);
                         }
                         }
-
-                        // Replace
-                        returnValue = returnValue.replace(match[0], includeContent);
-                    } else {
-                        var includeShaderUrl = Engine.ShadersRepository + "ShadersInclude/" + includeFile + ".fx";
-
-                        this._engine._loadFileAsync(includeShaderUrl)
-                            .then((fileContent) => {
-                                Effect.IncludesShadersStore[includeFile] = fileContent as string;
-                                return this._processIncludesAsync(returnValue);
-                            })
-                            .then((returnValue) => {
-                                resolve(returnValue);
-                            });
-                        return;
                     }
                     }
 
 
-                    match = regex.exec(sourceCode);
+                    // Replace
+                    returnValue = returnValue.replace(match[0], includeContent);
+                } else {
+                    var includeShaderUrl = Engine.ShadersRepository + "ShadersInclude/" + includeFile + ".fx";
+
+                    this._engine._loadFile(includeShaderUrl, (fileContent) => {
+                        Effect.IncludesShadersStore[includeFile] = fileContent as string;
+                        this._processIncludes(<string>returnValue, callback);
+                    });
+                    return;
                 }
                 }
-                resolve(returnValue);
-            });            
+
+                match = regex.exec(sourceCode);
+            }
+
+            callback(returnValue);
         }
         }
 
 
         private _processPrecision(source: string): string {
         private _processPrecision(source: string): string {
@@ -947,8 +895,7 @@
         }
         }
 
 
         /**
         /**
-         * (Warning! setTextureFromPostProcessOutput may be desired instead)
-         * Sets the input texture of the passed in post process to be input of this effect. (To use the output of the passed in post process use setTextureFromPostProcessOutput)
+         * Sets a texture to be the input of the specified post process. (To use the output, pass in the next post process in the pipeline)
          * @param channel Name of the sampler variable.
          * @param channel Name of the sampler variable.
          * @param postProcess Post process to get the input texture from.
          * @param postProcess Post process to get the input texture from.
          */
          */
@@ -957,7 +904,8 @@
         }
         }
 
 
         /**
         /**
-         * Sets the output texture of the passed in post process to be input of this effect.
+         * (Warning! setTextureFromPostProcessOutput may be desired instead)
+         * Sets the input texture of the passed in post process to be input of this effect. (To use the output of the passed in post process use setTextureFromPostProcessOutput)
          * @param channel Name of the sampler variable.
          * @param channel Name of the sampler variable.
          * @param postProcess Post process to get the output texture from.
          * @param postProcess Post process to get the output texture from.
          */
          */
@@ -1470,7 +1418,6 @@
             return this;
             return this;
         }
         }
 
 
-        // Statics
         /**
         /**
          * Store of each shader (The can be looked up using effect.key)
          * Store of each shader (The can be looked up using effect.key)
          */
          */
@@ -1487,4 +1434,4 @@
             Effect._baseCache = {};
             Effect._baseCache = {};
         }
         }
     }
     }
-} 
+} 

+ 1 - 1
src/Mesh/Compression/babylon.dracoCompression.ts

@@ -188,7 +188,7 @@ module BABYLON {
         }
         }
 
 
         private static _GetDefaultDecoderUrl(): Nullable<string> {
         private static _GetDefaultDecoderUrl(): Nullable<string> {
-            if (!Tools.IsWindowObjectExist) {
+            if (!Tools.IsWindowObjectExist()) {
                 return null;
                 return null;
             }
             }
 
 

+ 1 - 1
src/Mesh/babylon.mesh.ts

@@ -187,7 +187,7 @@
 
 
                 // Deep copy
                 // Deep copy
                 Tools.DeepCopy(source, this, ["name", "material", "skeleton", "instances", "parent", "uniqueId", 
                 Tools.DeepCopy(source, this, ["name", "material", "skeleton", "instances", "parent", "uniqueId", 
-                                              "source", "metadata", "hasLODLevels", "geometry", "isBlocked"], 
+                                              "source", "metadata", "hasLODLevels", "geometry", "isBlocked", "areNormalsFrozen"], 
                                               ["_poseMatrix", "_source"]);
                                               ["_poseMatrix", "_source"]);
 
 
                 // Metadata
                 // Metadata

+ 1 - 1
src/Mesh/babylon.subMesh.ts

@@ -153,7 +153,7 @@
         }
         }
 
 
         public _checkCollision(collider: Collider): boolean {
         public _checkCollision(collider: Collider): boolean {
-            let boundingInfo = this._renderingMesh.getBoundingInfo();
+            let boundingInfo = this.getBoundingInfo();
 
 
             return boundingInfo._checkCollision(collider);
             return boundingInfo._checkCollision(collider);
         }
         }

+ 1 - 1
src/Particles/EmitterTypes/babylon.coneParticleEmitter.ts

@@ -84,7 +84,7 @@ module BABYLON {
             // Better distribution in a cone at normal angles.
             // Better distribution in a cone at normal angles.
             h = 1 - h * h;
             h = 1 - h * h;
             var radius = Scalar.RandomRange(0, this._radius);
             var radius = Scalar.RandomRange(0, this._radius);
-            radius = radius * h / this._height;
+            radius = radius * h;
 
 
             var randX = radius * Math.sin(s);
             var randX = radius * Math.sin(s);
             var randZ = radius * Math.cos(s);
             var randZ = radius * Math.cos(s);

+ 8 - 2
src/Particles/babylon.gpuParticleSystem.ts

@@ -262,8 +262,14 @@
          * @return true if the system is ready
          * @return true if the system is ready
          */
          */
         public isReady(): boolean {
         public isReady(): boolean {
-            if (!this.emitter || !this._updateEffect || !this._renderEffect || 
-                !this._updateEffect.isReady() || !this._renderEffect.isReady() || !this.particleTexture || !this.particleTexture.isReady()) {
+            if (!this._updateEffect) {
+                this._recreateUpdateEffect();
+                this._recreateRenderEffect();
+                return false;
+            }
+
+
+            if (!this.emitter || !this._updateEffect.isReady() || !this._renderEffect.isReady() || !this.particleTexture || !this.particleTexture.isReady()) {
                 return false;
                 return false;
             }
             }
 
 

+ 1 - 1
src/Particles/babylon.particleSystem.ts

@@ -997,11 +997,11 @@
          */
          */
         public createBoxEmitter(direction1: Vector3, direction2: Vector3, minEmitBox: Vector3, maxEmitBox: Vector3): BoxParticleEmitter {
         public createBoxEmitter(direction1: Vector3, direction2: Vector3, minEmitBox: Vector3, maxEmitBox: Vector3): BoxParticleEmitter {
             var particleEmitter = new BoxParticleEmitter();
             var particleEmitter = new BoxParticleEmitter();
+            this.particleEmitterType = particleEmitter;
             this.direction1 = direction1;
             this.direction1 = direction1;
             this.direction2 = direction2;
             this.direction2 = direction2;
             this.minEmitBox = minEmitBox;
             this.minEmitBox = minEmitBox;
             this.maxEmitBox = maxEmitBox;
             this.maxEmitBox = maxEmitBox;
-            this.particleEmitterType = particleEmitter;
             return particleEmitter;
             return particleEmitter;
         }
         }
 
 

+ 3 - 3
src/Physics/Plugins/babylon.cannonJSPlugin.ts

@@ -1,15 +1,15 @@
 module BABYLON {
 module BABYLON {
-    declare var require: any;
+    //declare var require: any;
     declare var CANNON: any;
     declare var CANNON: any;
 
 
     export class CannonJSPlugin implements IPhysicsEnginePlugin {
     export class CannonJSPlugin implements IPhysicsEnginePlugin {
 
 
-        public world: any; //this.BJSCANNON.World
+        public world: any;
         public name: string = "CannonJSPlugin";
         public name: string = "CannonJSPlugin";
         private _physicsMaterials = new Array();
         private _physicsMaterials = new Array();
         private _fixedTimeStep: number = 1 / 60;
         private _fixedTimeStep: number = 1 / 60;
         //See https://github.com/schteppe/CANNON.js/blob/gh-pages/demos/collisionFilter.html
         //See https://github.com/schteppe/CANNON.js/blob/gh-pages/demos/collisionFilter.html
-        public BJSCANNON = typeof CANNON !== 'undefined' ? CANNON : (typeof require !== 'undefined' ? require('cannon') : undefined);
+        public BJSCANNON = CANNON;
 
 
 
 
 
 

+ 0 - 0
src/Physics/Plugins/babylon.oimoJSPlugin.ts


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