Преглед на файлове

Merge branch 'master' into MatrixDetAndInvert2

Julien Barrois преди 6 години
родител
ревизия
50df9fbe0a
променени са 43 файла, в които са добавени 43016 реда и са изтрити 42334 реда
  1. 23614 23542
      Playground/babylon.d.txt
  2. 383 383
      Playground/indexStable.html
  3. 14 14
      Playground/js/frame.js
  4. 78 98
      Playground/js/index.js
  5. 17742 17741
      dist/preview release/babylon.d.ts
  6. 1 1
      dist/preview release/babylon.js
  7. 24 10
      dist/preview release/babylon.max.js
  8. 24 10
      dist/preview release/babylon.no-module.max.js
  9. 1 1
      dist/preview release/babylon.worker.js
  10. 24 10
      dist/preview release/es6.js
  11. 117 45
      dist/preview release/gui/babylon.gui.d.ts
  12. 1 1
      dist/preview release/gui/babylon.gui.js
  13. 1 1
      dist/preview release/gui/babylon.gui.min.js
  14. 1 1
      dist/preview release/gui/babylon.gui.min.js.map
  15. 249 96
      dist/preview release/gui/babylon.gui.module.d.ts
  16. 4 0
      dist/preview release/loaders/babylon.glTF1FileLoader.js
  17. 1 1
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  18. 4 0
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  19. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  20. 4 0
      dist/preview release/loaders/babylon.glTFFileLoader.js
  21. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  22. 4 0
      dist/preview release/loaders/babylonjs.loaders.js
  23. 1 1
      dist/preview release/loaders/babylonjs.loaders.min.js
  24. 34 1
      dist/preview release/viewer/babylon.viewer.d.ts
  25. 1 1
      dist/preview release/viewer/babylon.viewer.js
  26. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  27. 38 2
      dist/preview release/viewer/babylon.viewer.module.d.ts
  28. 4 1
      dist/preview release/what's new.md
  29. 283 0
      gui/src/2D/controls/baseSlider.ts
  30. 20 1
      gui/src/2D/controls/image.ts
  31. 145 0
      gui/src/2D/controls/imageBasedSlider.ts
  32. 23 21
      gui/src/2D/controls/index.ts
  33. 77 297
      gui/src/2D/controls/slider.ts
  34. 14 0
      gui/src/2D/measure.ts
  35. 5 0
      loaders/src/glTF/babylon.glTFFileLoader.ts
  36. 1 1
      readme.md
  37. 2 0
      src/Cameras/babylon.arcRotateCamera.ts
  38. 2 2
      src/Layer/babylon.effectLayer.ts
  39. 38 36
      src/Math/babylon.math.ts
  40. 25 9
      src/babylon.scene.ts
  41. BIN
      tests/validation/ReferenceImages/pointers.png
  42. 6 0
      tests/validation/config.json
  43. 2 2
      tests/validation/validation.js

Файловите разлики са ограничени, защото са твърде много
+ 23614 - 23542
Playground/babylon.d.txt


+ 383 - 383
Playground/indexStable.html

@@ -1,475 +1,475 @@
 <!DOCTYPE html>
 <html>
 
-    <head>
-        <title>Babylon.js Playground</title>
-        <meta charset='utf-8' />
-        <meta name="viewport" content="width=device-width, user-scalable=no">
-        <link rel="shortcut icon" href="https://www.babylonjs.com/img/favicon/favicon.ico">
-        <link rel="apple-touch-icon" sizes="57x57" href="https://www.babylonjs.com/img/favicon/apple-icon-57x57.png">
-        <link rel="apple-touch-icon" sizes="60x60" href="https://www.babylonjs.com/img/favicon/apple-icon-60x60.png">
-        <link rel="apple-touch-icon" sizes="72x72" href="https://www.babylonjs.com/img/favicon/apple-icon-72x72.png">
-        <link rel="apple-touch-icon" sizes="76x76" href="https://www.babylonjs.com/img/favicon/apple-icon-76x76.png">
-        <link rel="apple-touch-icon" sizes="114x114" href="https://www.babylonjs.com/img/favicon/apple-icon-114x114.png">
-        <link rel="apple-touch-icon" sizes="120x120" href="https://www.babylonjs.com/img/favicon/apple-icon-120x120.png">
-        <link rel="apple-touch-icon" sizes="144x144" href="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png">
-        <link rel="apple-touch-icon" sizes="152x152" href="https://www.babylonjs.com/img/favicon/apple-icon-152x152.png">
-        <link rel="apple-touch-icon" sizes="180x180" href="https://www.babylonjs.com/img/favicon/apple-icon-180x180.png">
-        <link rel="icon" type="image/png" sizes="192x192" href="https://www.babylonjs.com/img/favicon/android-icon-192x192.png">
-        <link rel="icon" type="image/png" sizes="32x32" href="https://www.babylonjs.com/img/favicon/favicon-32x32.png">
-        <link rel="icon" type="image/png" sizes="96x96" href="https://www.babylonjs.com/img/favicon/favicon-96x96.png">
-        <link rel="icon" type="image/png" sizes="16x16" href="https://www.babylonjs.com/img/favicon/favicon-16x16.png">
-        <link rel="manifest" href="https://www.babylonjs.com/img/favicon/manifest.json">
-        <meta name="msapplication-TileColor" content="#ffffff">
-        <meta name="msapplication-TileImage" content="https://www.babylonjs.com/img/favicon/ms-icon-144x144.png">
-        <meta name="msapplication-config" content="https://www.babylonjs.com/img/favicon/browserconfig.xml">
-        <meta name="theme-color" content="#ffffff">
-
-        <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-        <!--For canvas/code separator-->
-        <script src="js/libs/split.js"></script>
-
-        <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
-        <!-- jszip -->
-        <script src="js/libs/jszip.min.js"></script>
-        <script src="js/libs/fileSaver.js"></script>
-        <!-- Physics -->
-        <script src="https://cdn.babylonjs.com/cannon.js"></script>
-        <script src="https://cdn.babylonjs.com/Oimo.js"></script>
-        <script src="https://cdn.babylonjs.com/gltf_validator.js"></script>
-        <script src="https://cdn.babylonjs.com/earcut.min.js"></script>
-        <!-- Monaco -->
-        <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
-        <!-- Babylon.js -->
-        <script src="https://cdn.babylonjs.com/babylon.max.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>
+    <script src="https://cdn.babylonjs.com/gltf_validator.js"></script>
+    <script src="https://cdn.babylonjs.com/earcut.min.js"></script>
+    <!-- Babylon.js -->
+    <script src="https://cdn.babylonjs.com/babylon.js"></script>
+    <script src="https://cdn.babylonjs.com/gui/babylon.gui.min.js"></script>
+    <script src="https://cdn.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
+    <script src="https://cdn.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
+    <script src="https://cdn.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
+    <script src="https://cdn.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
+    <script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.js"></script>
+    <script src="https://cdn.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
+
+    <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>
+    <!-- Monaco -->
+    <script src="node_modules/monaco-editor/min/vs/loader.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 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 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 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>
+        <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 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="far fa-square" 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="far fa-square" aria-hidden="true"></i>
+                    </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>
-
-                <div class="button uncheck" id="debugButton1600">Inspector</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="option" id="safemodeToggle1600">Safe mode
+                        <i class="far fa-square" 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="far fa-square" aria-hidden="true"></i>
                     </div>
-                </div>
-                <div class="button select">
-                    <span class="examplesButton">Examples</span>
                 </div>
             </div>
+
+            <div class="button uncheck" id="debugButton1600">Inspector</div>
+            <div class="button" id="metadataButton1600">Metadata</div>
         </div>
 
-        <div class="navbar navBar1475">
-            <div class="title">
-                Babylon.js Playground
+        <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="version" id="mainTitle">
+            <div class="button select">
+                <span class="examplesButton">Examples</span>
             </div>
+        </div>
+    </div>
 
-            <div class="category">
-                <div class="button run" id="runButton1475">Run
-                    <i class="fa fa-play" aria-hidden="true"></i>
-                </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" id="newButton1475">New
-                    <i class="fa fa-file" aria-hidden="true"></i>
-                </div>
-                <div class="button removeOnPhone" id="clearButton1475">Clear
-                    <i class="fa fa-trash" aria-hidden="true"></i>
-                </div>
+        <div class="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 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>
-                        </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 class="option" id='safemodeToggle1475'>Safe mode
-                            <i class="far fa-square" aria-hidden="true"></i>
-                        </div>
-                        <div class="option checked" id="editorButton1475">Editor
-                            <i class="fa fa-check-square" aria-hidden="true"></i>
+        <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 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="far fa-square" aria-hidden="true"></i>
+                    </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 class="option" id="debugButton1475">Inspector</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 class="option" id='safemodeToggle1475'>Safe mode
+                        <i class="far fa-square" 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="far fa-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="debugButton1475">Inspector</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 class="category right">
-                <div class="button select">
-                    <span class="examplesButton">Examples</span>
-                </div>
+        <div class="category right">
+            <div class="button select">
+                <span class="examplesButton">Examples</span>
             </div>
         </div>
+    </div>
 
-        <div class="navbar navBar1030">
-            <div class="category">
-                <div class="button run" id="runButton1030">Run
-                    <i class="fa fa-play" aria-hidden="true"></i>
-                </div>
+    <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 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 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>
-                        </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 class="option" id="safemodeToggle1030">Safe mode
-                            <i class="far fa-square" aria-hidden="true"></i>
+        <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 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="far fa-square" aria-hidden="true"></i>
+                    </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 class="option" id="debugButton1030">Inspector</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 class="option" id="safemodeToggle1030">Safe mode
+                        <i class="far fa-square" 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="far fa-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="debugButton1030">Inspector</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 class="category right">
-                <div class="button select">
-                    <span class="examplesButton">Examples</span>
-                </div>
+        <div class="category right">
+            <div class="button select">
+                <span class="examplesButton">Examples</span>
             </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="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 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 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 class="option" id="safemodeToggle750">Safe mode
-                            <i class="far fa-square" 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="far fa-square" aria-hidden="true"></i>
+                    </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 class="option" id="debugButton750">Inspector</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="option" id="safemodeToggle750">Safe mode
+                        <i class="far fa-square" 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="far fa-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="debugButton750">Inspector</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 class="category right">
-                <div class="button select">
-                    <span class="examplesButton">Examples</span>
-                </div>
+        <div class="category right">
+            <div class="button select">
+                <span class="examplesButton">Examples</span>
             </div>
         </div>
+    </div>
 
-        <div class="wrapper">
-            <div id="jsEditor"></div>
-            <div id="canvasZone">
-                <canvas touch-action="none" id="renderCanvas"></canvas>
-            </div>
+    <div class="wrapper">
+        <div id="jsEditor"></div>
+        <div id="canvasZone">
+            <canvas touch-action="none" id="renderCanvas"></canvas>
         </div>
-        <div id="exampleList">
-            <div id="exampleBanner">
-                <h1>Examples</h1>
-            </div>
-            <div class="horizontalSeparator"></div>
-            <input id="filterBar" type="text" placeholder="Filter examples...">
-            <img id="filterBarClear" src="https://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/clear_button.png">
+    </div>
+    <div id="exampleList">
+        <div id="exampleBanner">
+            <h1>Examples</h1>
         </div>
+        <div class="horizontalSeparator"></div>
+        <input id="filterBar" type="text" placeholder="Filter examples...">
+        <img id="filterBarClear" src="https://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/clear_button.png">
+    </div>
 
-        <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 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>
+                <div id="saveFormButtonOk" class="button">OK</div>
+                <div id="saveFormButtonCancel" class="button">Cancel</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>
+    <script src="js/actions.js"></script>
+    <script src="js/pbt.js"></script>
+    <script src="js/index.js"></script>
 
-        <!-- Global site tag (gtag.js) - Google Analytics -->
-        <script async src="https://www.googletagmanager.com/gtag/js?id=UA-41767310-2"></script>
-        <script>
+    <!-- Global site tag (gtag.js) - Google Analytics -->
+    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-41767310-2"></script>
+    <script>
         window.dataLayer = window.dataLayer || [];
-        function gtag(){dataLayer.push(arguments);}
+        function gtag() { dataLayer.push(arguments); }
         gtag('js', new Date());
 
         gtag('config', 'UA-41767310-2');
-        </script>        
-    </body>
+    </script>
+</body>
 
-</html>
+</html>

+ 14 - 14
Playground/js/frame.js

@@ -1,5 +1,5 @@
-(function () {
-    var snippetUrl = "//babylonjs-api2.azurewebsites.net/snippets";
+(function() {
+    var snippetUrl = "https://snippet.babylonjs.com";
     var currentSnippetToken;
     var engine;
     var fpsLabel = document.getElementById("fpsLabel");
@@ -18,12 +18,12 @@
     }
 
     BABYLON.Engine.ShadersRepository = "/src/Shaders/";
-    var loadScript = function (scriptURL, title) {
+    var loadScript = function(scriptURL, title) {
         var xhr = new XMLHttpRequest();
 
         xhr.open('GET', scriptURL, true);
 
-        xhr.onreadystatechange = function () {
+        xhr.onreadystatechange = function() {
             if (xhr.readyState === 4) {
                 if (xhr.status === 200) {
                     blockEditorChange = true;
@@ -43,11 +43,11 @@
         xhr.send(null);
     };
 
-    var showError = function (error) {
+    var showError = function(error) {
         console.warn(error);
     };
 
-    compileAndRun = function (code) {
+    compileAndRun = function(code) {
         try {
 
             if (!BABYLON.Engine.isSupported()) {
@@ -67,7 +67,7 @@
             var createEngineFunction = "createDefaultEngine";
             var createSceneFunction;
 
-            var createDefaultEngine = function () {
+            var createDefaultEngine = function() {
                 return new BABYLON.Engine(canvas, true, { stencil: true });
             }
 
@@ -119,7 +119,7 @@
             }
 
             BABYLON.Camera.ForceAttachControlToAlwaysPreventDefault = true;
-            engine.runRenderLoop(function () {
+            engine.runRenderLoop(function() {
                 if (engine.scenes.length === 0) {
                     return;
                 }
@@ -143,14 +143,14 @@
             // showError(e.message);
         }
     };
-    window.addEventListener("resize", function () {
+    window.addEventListener("resize", function() {
         if (engine) {
             engine.resize();
         }
     });
 
     // UI
-    var cleanHash = function () {
+    var cleanHash = function() {
         var splits = decodeURIComponent(location.hash.substr(1)).split("#");
 
         if (splits.length > 2) {
@@ -160,22 +160,22 @@
         location.hash = splits.join("#");
     };
 
-    var checkHash = function () {
+    var checkHash = function() {
         if (location.hash) {
             cleanHash();
 
             try {
                 var xmlHttp = new XMLHttpRequest();
-                xmlHttp.onreadystatechange = function () {
+                xmlHttp.onreadystatechange = function() {
                     if (xmlHttp.readyState === 4) {
                         if (xmlHttp.status === 200) {
-                            var snippetCode = JSON.parse(JSON.parse(xmlHttp.responseText)[0].jsonPayload).code;
+                            var snippetCode = JSON.parse(JSON.parse(xmlHttp.responseText).jsonPayload).code;
                             compileAndRun(snippetCode);
 
                             var refresh = document.getElementById("refresh");
 
                             if (refresh) {
-                                refresh.addEventListener("click", function () {
+                                refresh.addEventListener("click", function() {
                                     compileAndRun(snippetCode);
                                 });
                             }

+ 78 - 98
Playground/js/index.js

@@ -30,16 +30,16 @@ function showError(errorMessage, errorEvent) {
     document.getElementById("errorZone").innerHTML = errorContent;
 
     // Close button error
-    document.getElementById("errorZone").querySelector('.close').addEventListener('click', function () {
+    document.getElementById("errorZone").querySelector('.close').addEventListener('click', function() {
         document.getElementById("errorZone").style.display = 'none';
     });
 }
 
-(function () {
+(function() {
 
     var multipleSize = [1600, 1475, 1030, 750];
-    var setToMultipleID = function (id, thingToDo, param) {
-        multipleSize.forEach(function (size) {
+    var setToMultipleID = function(id, thingToDo, param) {
+        multipleSize.forEach(function(size) {
 
             if (thingToDo == "innerHTML") {
                 document.getElementById(id + size).innerHTML = param
@@ -76,7 +76,7 @@ function showError(errorMessage, errorEvent) {
         '.navbarBottom',
         '.navbarBottom .links .link'];
 
-    var run = function () {
+    var run = function() {
 
         // #region - Examples playgrounds
         var examplesButton = document.getElementsByClassName("examplesButton");
@@ -84,7 +84,7 @@ function showError(errorMessage, errorEvent) {
         if (examplesButton && examplesButton.length > 0) {
             var isExamplesDisplayed = false;
             for (var i = 0; i < examplesButton.length; i++) {
-                examplesButton[i].parentElement.onclick = function () {
+                examplesButton[i].parentElement.onclick = function() {
                     isExamplesDisplayed = !isExamplesDisplayed;
                     if (isExamplesDisplayed) {
                         document.getElementById("exampleList").style.display = "block";
@@ -102,7 +102,7 @@ function showError(errorMessage, errorEvent) {
         var filterBar = document.getElementById("filterBar");
         if (filterBar) {
             var filterBarClear = document.getElementById("filterBarClear");
-            var filter = function () {
+            var filter = function() {
                 var filterText = filterBar.value.toLowerCase();
                 if (filterText == "") filterBarClear.style.display = "none";
                 else filterBarClear.style.display = "inline-block";
@@ -132,10 +132,10 @@ function showError(errorMessage, errorEvent) {
                 if (displayCount == 0) document.getElementById("noResultsContainer").style.display = "block";
                 else document.getElementById("noResultsContainer").style.display = "none";
             }
-            filterBar.oninput = function () {
+            filterBar.oninput = function() {
                 filter();
             }
-            filterBarClear.onclick = function () {
+            filterBarClear.onclick = function() {
                 filterBar.value = "";
                 filter();
             }
@@ -144,7 +144,7 @@ function showError(errorMessage, errorEvent) {
 
         var blockEditorChange = false;
 
-        var markDirty = function () {
+        var markDirty = function() {
             if (blockEditorChange) {
                 return;
             }
@@ -155,11 +155,11 @@ function showError(errorMessage, errorEvent) {
             setToMultipleID('safemodeToggle', 'innerHTML', 'Safe mode <i class="fa fa-check-square" aria-hidden="true"></i>');
         }
 
-        jsEditor.onKeyUp(function (evt) {
+        jsEditor.onKeyUp(function(evt) {
             markDirty();
         });
 
-        var snippetUrl = "//babylonjs-api2.azurewebsites.net/snippets";
+        var snippetV3Url = "https://snippet.babylonjs.com"
         var currentSnippetToken;
         var currentSnippetTitle = null;
         var currentSnippetDescription = null;
@@ -176,7 +176,7 @@ function showError(errorMessage, errorEvent) {
             setToMultipleID("currentVersion", "innerHTML", "Version: Latest");
         }
 
-        var checkTypescriptSupport = function (xhr) {
+        var checkTypescriptSupport = function(xhr) {
             var filename = location.pathname.substring(location.pathname.lastIndexOf('/') + 1);
             if (xhr.responseText.indexOf("class Playground") !== -1) {// Typescript content
                 if (!filename) {
@@ -197,12 +197,12 @@ function showError(errorMessage, errorEvent) {
             return true;
         }
 
-        var loadScript = function (scriptURL, title) {
+        var loadScript = function(scriptURL, title) {
             var xhr = new XMLHttpRequest();
 
             xhr.open('GET', scriptURL, true);
 
-            xhr.onreadystatechange = function () {
+            xhr.onreadystatechange = function() {
                 if (xhr.readyState === 4) {
                     if (xhr.status === 200) {
 
@@ -227,20 +227,7 @@ function showError(errorMessage, errorEvent) {
             xhr.send(null);
         };
 
-        var loadScriptFromIndex = function (index) {
-            if (index === 0) {
-                index = 1;
-            }
-
-            var script = scripts[index - 1].trim();
-            loadScript("scripts/" + script + ".js", script);
-        }
-
-        var onScriptClick = function (evt) {
-            loadScriptFromIndex(evt.target.scriptLinkIndex);
-        };
-
-        var loadScriptsList = function () {
+        var loadScriptsList = function() {
 
             var exampleList = document.getElementById("exampleList");
 
@@ -253,7 +240,7 @@ function showError(errorMessage, errorEvent) {
                 xhr.open('GET', 'https://raw.githubusercontent.com/BabylonJS/Documentation/master/examples/list_ts.json', true);
             }
 
-            xhr.onreadystatechange = function () {
+            xhr.onreadystatechange = function() {
                 if (xhr.readyState === 4) {
                     if (xhr.status === 200) {
                         scripts = JSON.parse(xhr.response)["examples"];
@@ -344,8 +331,6 @@ function showError(errorMessage, errorEvent) {
                                 var query = queryString.replace("?", "");
                                 index = parseInt(query);
                                 if (!isNaN(index)) {
-                                    // Old examples
-                                    //loadScriptFromIndex(index);
                                     var newPG = "";
                                     switch (index) {
                                         case 1: newPG = "#TAZ2CB#0"; break; // Basic scene
@@ -400,7 +385,7 @@ function showError(errorMessage, errorEvent) {
                         toggleTheme(theme);
 
                         // Remove editor if window size is less than 850px
-                        var removeEditorForSmallScreen = function () {
+                        var removeEditorForSmallScreen = function() {
                             if (mq.matches) {
                                 splitInstance.collapse(0);
                             } else {
@@ -416,7 +401,7 @@ function showError(errorMessage, errorEvent) {
             xhr.send(null);
         }
 
-        var createNewScript = function () {
+        var createNewScript = function() {
             // check if checked is on
             let iCanClear = checkSafeMode("Are you sure you want to create a new playground?");
             if (!iCanClear) return;
@@ -436,7 +421,7 @@ function showError(errorMessage, errorEvent) {
             compileAndRun();
         }
 
-        var clear = function () {
+        var clear = function() {
             // check if checked is on
             let iCanClear = checkSafeMode("Are you sure you want to clear the playground?");
             if (!iCanClear) return;
@@ -447,7 +432,7 @@ function showError(errorMessage, errorEvent) {
             jsEditor.focus();
         }
 
-        var checkSafeMode = function (message) {
+        var checkSafeMode = function(message) {
             var safeToggle = document.getElementById("safemodeToggle1600");
             if (safeToggle.classList.contains('checked')) {
                 let confirm = window.confirm(message);
@@ -462,7 +447,7 @@ function showError(errorMessage, errorEvent) {
             }
         }
 
-        var showNoMetadata = function () {
+        var showNoMetadata = function() {
             if (currentSnippetTitle) {
                 document.getElementById("saveFormTitle").value = currentSnippetTitle;
                 document.getElementById("saveFormTitle").readOnly = true;
@@ -492,7 +477,7 @@ function showError(errorMessage, errorEvent) {
         };
         showNoMetadata();
 
-        var hideNoMetadata = function () {
+        var hideNoMetadata = function() {
             document.getElementById("saveFormTitle").readOnly = true;
             document.getElementById("saveFormDescription").readOnly = true;
             document.getElementById("saveFormTags").readOnly = true;
@@ -500,7 +485,7 @@ function showError(errorMessage, errorEvent) {
             setToMultipleID("metadataButton", "display", "inline-block");
         };
 
-        compileAndRun = function () {
+        compileAndRun = function() {
             try {
                 var waitRing = document.getElementById("waitDiv");
                 if (waitRing) {
@@ -553,8 +538,8 @@ function showError(errorMessage, errorEvent) {
                 var createEngineFunction = "createDefaultEngine";
                 var createSceneFunction;
 
-                getRunCode(jsEditor, function (code) {
-                    var createDefaultEngine = function () {
+                getRunCode(jsEditor, function(code) {
+                    var createDefaultEngine = function() {
                         return new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true });
                     }
 
@@ -598,7 +583,7 @@ function showError(errorMessage, errorEvent) {
                         eval("scene = " + createSceneFunction + "()");
 
                         // if scene returns a promise avoid checks
-                        if(scene.then){
+                        if (scene.then) {
                             checkCamera = false
                             checkSceneCount = false
                         }
@@ -619,7 +604,7 @@ function showError(errorMessage, errorEvent) {
 
                     }
 
-                    engine.runRenderLoop(function () {
+                    engine.runRenderLoop(function() {
                         if (engine.scenes.length === 0) {
                             return;
                         }
@@ -637,7 +622,7 @@ function showError(errorMessage, errorEvent) {
                         fpsLabel.style.right = document.body.clientWidth - (jsEditor.domElement.clientWidth + canvas.clientWidth) + "px";
                         fpsLabel.innerHTML = engine.getFps().toFixed() + " fps";
                     });
-    
+
                     if (checkSceneCount && engine.scenes.length === 0) {
 
                         showError("You must at least create a scene.", null);
@@ -647,20 +632,20 @@ function showError(errorMessage, errorEvent) {
                     if (checkCamera && engine.scenes[0].activeCamera == null) {
                         showError("You must at least create a camera.", null);
                         return;
-                    }else if(scene.then){
-                        scene.then(function (){
+                    } else if (scene.then) {
+                        scene.then(function() {
                             document.getElementById("statusBar").innerHTML = "";
                         });
-                    }else{
-                        engine.scenes[0].executeWhenReady(function () {
+                    } else {
+                        engine.scenes[0].executeWhenReady(function() {
                             document.getElementById("statusBar").innerHTML = "";
                         });
-                    }           
+                    }
 
                     if (scene) {
                         if (showInspector) {
                             scene.debugLayer.show({ initialTab: initialTabIndex });
-                            scene.executeWhenReady(function () {
+                            scene.executeWhenReady(function() {
                                 scene.debugLayer._inspector.refresh();
                             })
                         } else if (showDebugLayer) {
@@ -676,7 +661,7 @@ function showError(errorMessage, errorEvent) {
             }
         };
         window.addEventListener("resize",
-            function () {
+            function() {
                 if (engine) {
                     engine.resize();
                 }
@@ -686,7 +671,7 @@ function showError(errorMessage, errorEvent) {
         loadScriptsList();
 
         // Zip
-        var addContentToZip = function (zip, name, url, replace, buffer, then) {
+        var addContentToZip = function(zip, name, url, replace, buffer, then) {
             if (url.substring(0, 5) == "http:" || url.substring(0, 5) == "blob:" || url.substring(0, 6) == "https:") {
                 then();
                 return;
@@ -700,7 +685,7 @@ function showError(errorMessage, errorEvent) {
                 xhr.responseType = "arraybuffer";
             }
 
-            xhr.onreadystatechange = function () {
+            xhr.onreadystatechange = function() {
                 if (xhr.readyState === 4) {
                     if (xhr.status === 200) {
                         var text;
@@ -728,7 +713,7 @@ function showError(errorMessage, errorEvent) {
             xhr.send(null);
         }
 
-        var addTexturesToZip = function (zip, index, textures, folder, then) {
+        var addTexturesToZip = function(zip, index, textures, folder, then) {
 
             if (index === textures.length) {
                 then();
@@ -775,7 +760,7 @@ function showError(errorMessage, errorEvent) {
                     url,
                     null,
                     true,
-                    function () {
+                    function() {
                         addTexturesToZip(zip, index + 1, textures, folder, then);
                     });
             }
@@ -784,7 +769,7 @@ function showError(errorMessage, errorEvent) {
             }
         }
 
-        var addImportedFilesToZip = function (zip, index, importedFiles, folder, then) {
+        var addImportedFilesToZip = function(zip, index, importedFiles, folder, then) {
             if (index === importedFiles.length) {
                 then();
                 return;
@@ -802,12 +787,12 @@ function showError(errorMessage, errorEvent) {
                 url,
                 null,
                 true,
-                function () {
+                function() {
                     addImportedFilesToZip(zip, index + 1, importedFiles, folder, then);
                 });
         }
 
-        var getZip = function () {
+        var getZip = function() {
             if (engine.scenes.length === 0) {
                 return;
             }
@@ -831,17 +816,17 @@ function showError(errorMessage, errorEvent) {
                 "zipContent/index.html",
                 zipCode,
                 false,
-                function () {
+                function() {
                     addTexturesToZip(zip,
                         0,
                         textures,
                         null,
-                        function () {
+                        function() {
                             addImportedFilesToZip(zip,
                                 0,
                                 importedFiles,
                                 null,
-                                function () {
+                                function() {
                                     var blob = zip.generate({ type: "blob" });
                                     saveAs(blob, "sample.zip");
                                     document.getElementById("statusBar").innerHTML = "";
@@ -851,7 +836,7 @@ function showError(errorMessage, errorEvent) {
         }
 
         // Versions
-        setVersion = function (version) {
+        setVersion = function(version) {
             switch (version) {
                 case "stable":
                     location.href = "indexStable.html" + location.hash;
@@ -863,35 +848,35 @@ function showError(errorMessage, errorEvent) {
         }
 
         // Fonts
-        setFontSize = function (size) {
+        setFontSize = function(size) {
             fontSize = size;
             jsEditor.updateOptions({ fontSize: size });
             setToMultipleID("currentFontSize", "innerHTML", "Font: " + size);
         };
 
         // Fullscreen
-        document.getElementById("renderCanvas").addEventListener("webkitfullscreenchange", function () {
+        document.getElementById("renderCanvas").addEventListener("webkitfullscreenchange", function() {
             if (document.webkitIsFullScreen) goFullPage();
             else exitFullPage();
         }, false);
 
-        var goFullPage = function () {
+        var goFullPage = function() {
             var canvasElement = document.getElementById("renderCanvas");
             canvasElement.style.position = "absolute";
             canvasElement.style.top = 0;
             canvasElement.style.left = 0;
             canvasElement.style.zIndex = 100;
         }
-        var exitFullPage = function () {
+        var exitFullPage = function() {
             document.getElementById("renderCanvas").style.position = "relative";
             document.getElementById("renderCanvas").style.zIndex = 0;
         }
-        var goFullscreen = function () {
+        var goFullscreen = function() {
             if (engine) {
                 engine.switchFullscreen(true);
             }
         }
-        var editorGoFullscreen = function () {
+        var editorGoFullscreen = function() {
             var editorDiv = document.getElementById("jsEditor");
             if (editorDiv.requestFullscreen) {
                 editorDiv.requestFullscreen();
@@ -903,7 +888,7 @@ function showError(errorMessage, errorEvent) {
 
         }
 
-        var toggleEditor = function () {
+        var toggleEditor = function() {
             var editorButton = document.getElementById("editorButton1600");
             var scene = engine.scenes[0];
 
@@ -928,7 +913,7 @@ function showError(errorMessage, errorEvent) {
         /**
          * Toggle the dark theme
          */
-        var toggleTheme = function (theme) {
+        var toggleTheme = function(theme) {
             // Monaco
             var vsTheme;
             if (theme == 'dark') {
@@ -963,7 +948,7 @@ function showError(errorMessage, errorEvent) {
             jsEditor.setValue(oldCode);
             setFontSize(fontSize);
 
-            jsEditor.onKeyUp(function (evt) {
+            jsEditor.onKeyUp(function(evt) {
                 markDirty();
             });
 
@@ -981,7 +966,7 @@ function showError(errorMessage, errorEvent) {
             localStorage.setItem("bjs-playground-theme", theme);
         }
 
-        var toggleDebug = function () {
+        var toggleDebug = function() {
             // Always showing the debug layer, because you can close it by itself
             var scene = engine.scenes[0];
             if (document.getElementsByClassName("insp-right-panel")[0]) {
@@ -993,16 +978,16 @@ function showError(errorMessage, errorEvent) {
             }
         }
 
-        var toggleMetadata = function () {
+        var toggleMetadata = function() {
             var scene = engine.scenes[0];
             document.getElementById("saveLayer").style.display = "block";
         }
 
-        var formatCode = function () {
+        var formatCode = function() {
             jsEditor.getAction('editor.action.format').run();
         }
 
-        var toggleMinimap = function () {
+        var toggleMinimap = function() {
             var minimapToggle = document.getElementById("minimapToggle1600");
             if (minimapToggle.classList.contains('checked')) {
                 jsEditor.updateOptions({ minimap: { enabled: false } });
@@ -1016,7 +1001,7 @@ function showError(errorMessage, errorEvent) {
 
 
         //Navigation Overwrites
-        var exitPrompt = function (e) {
+        var exitPrompt = function(e) {
             var safeToggle = document.getElementById("safemodeToggle1600");
             if (safeToggle.classList.contains('checked')) {
                 e = e || window.event;
@@ -1032,7 +1017,7 @@ function showError(errorMessage, errorEvent) {
         window.onbeforeunload = exitPrompt;
 
         // Snippet
-        var save = function () {
+        var save = function() {
 
             // Retrieve title if necessary
             if (document.getElementById("saveLayer")) {
@@ -1042,9 +1027,9 @@ function showError(errorMessage, errorEvent) {
             }
 
             var xmlHttp = new XMLHttpRequest();
-            xmlHttp.onreadystatechange = function () {
+            xmlHttp.onreadystatechange = function() {
                 if (xmlHttp.readyState === 4) {
-                    if (xmlHttp.status === 201) {
+                    if (xmlHttp.status === 200) {
                         var baseUrl = location.href.replace(location.hash, "").replace(location.search, "");
                         var snippet = JSON.parse(xmlHttp.responseText);
                         var newUrl = baseUrl + "#" + snippet.id;
@@ -1062,13 +1047,13 @@ function showError(errorMessage, errorEvent) {
                 }
             }
 
-            xmlHttp.open("POST", snippetUrl + (currentSnippetToken ? "/" + currentSnippetToken : ""), true);
+            xmlHttp.open("POST", snippetV3Url + (currentSnippetToken ? "/" + currentSnippetToken : ""), true);
             xmlHttp.setRequestHeader("Content-Type", "application/json");
 
             var dataToSend = {
-                payload: {
+                payload: JSON.stringify({
                     code: jsEditor.getValue()
-                },
+                }),
                 name: currentSnippetTitle,
                 description: currentSnippetDescription,
                 tags: currentSnippetTags
@@ -1077,7 +1062,7 @@ function showError(errorMessage, errorEvent) {
             xmlHttp.send(JSON.stringify(dataToSend));
         }
 
-        var askForSave = function () {
+        var askForSave = function() {
             if (currentSnippetTitle == null
                 || currentSnippetDescription == null
                 || currentSnippetTags == null) {
@@ -1088,18 +1073,18 @@ function showError(errorMessage, errorEvent) {
                 save();
             }
         };
-        document.getElementById("saveFormButtonOk").addEventListener("click", function () {
+        document.getElementById("saveFormButtonOk").addEventListener("click", function() {
             document.getElementById("saveLayer").style.display = "none";
             save();
         });
-        document.getElementById("saveFormButtonCancel").addEventListener("click", function () {
+        document.getElementById("saveFormButtonCancel").addEventListener("click", function() {
             document.getElementById("saveLayer").style.display = "none";
         });
         document.getElementById("mainTitle").innerHTML = "v" + BABYLON.Engine.Version;
 
         var previousHash = "";
 
-        var cleanHash = function () {
+        var cleanHash = function() {
             var splits = decodeURIComponent(location.hash.substr(1)).split("#");
 
             if (splits.length > 2) {
@@ -1109,7 +1094,7 @@ function showError(errorMessage, errorEvent) {
             location.hash = splits.join("#");
         }
 
-        var checkHash = function (firstTime) {
+        var checkHash = function(firstTime) {
             if (location.hash) {
                 if (previousHash !== location.hash) {
                     cleanHash();
@@ -1118,7 +1103,7 @@ function showError(errorMessage, errorEvent) {
 
                     try {
                         var xmlHttp = new XMLHttpRequest();
-                        xmlHttp.onreadystatechange = function () {
+                        xmlHttp.onreadystatechange = function() {
                             if (xmlHttp.readyState === 4) {
                                 if (xmlHttp.status === 200) {
 
@@ -1126,7 +1111,7 @@ function showError(errorMessage, errorEvent) {
                                         return;
                                     }
 
-                                    var snippet = JSON.parse(xmlHttp.responseText)[0];
+                                    var snippet = JSON.parse(xmlHttp.responseText);
 
                                     blockEditorChange = true;
                                     jsEditor.setValue(JSON.parse(snippet.jsonPayload).code.toString());
@@ -1166,11 +1151,6 @@ function showError(errorMessage, errorEvent) {
                                     compileAndRun();
 
                                     // setToMultipleID("currentScript", "innerHTML", "Custom");
-                                } else if (firstTime) {
-                                    location.href = location.href.replace(location.hash, "");
-                                    if (scripts) {
-                                        loadScriptFromIndex(0);
-                                    }
                                 }
                             }
                         };
@@ -1180,7 +1160,7 @@ function showError(errorMessage, errorEvent) {
                         if (!hash.split("#")[1]) hash += "#0";
 
 
-                        xmlHttp.open("GET", snippetUrl + "/" + hash.replace("#", "/"));
+                        xmlHttp.open("GET", snippetV3Url + "/" + hash.replace("#", "/"));
                         xmlHttp.send();
                     } catch (e) {
 
@@ -1209,7 +1189,7 @@ function showError(errorMessage, errorEvent) {
         setToMultipleID("darkTheme", "click", toggleTheme.bind(this, 'dark'));
         setToMultipleID("lightTheme", "click", toggleTheme.bind(this, 'light'));
         // Safe mode
-        setToMultipleID("safemodeToggle", 'click', function () {
+        setToMultipleID("safemodeToggle", 'click', function() {
             document.getElementById("safemodeToggle1600").classList.toggle('checked');
             if (document.getElementById("safemodeToggle1600").classList.contains('checked')) {
                 setToMultipleID("safemodeToggle", "innerHTML", 'Safe mode <i class="fa fa-check-square" aria-hidden="true"></i>');
@@ -1245,11 +1225,11 @@ function showError(errorMessage, errorEvent) {
 
     xhr.open('GET', "babylon.d.txt", true);
 
-    xhr.onreadystatechange = function () {
+    xhr.onreadystatechange = function() {
         if (xhr.readyState === 4) {
             if (xhr.status === 200) {
                 require.config({ paths: { 'vs': 'node_modules/monaco-editor/min/vs' } });
-                require(['vs/editor/editor.main'], function () {
+                require(['vs/editor/editor.main'], function() {
                     if (monacoMode === "javascript") {
                         monaco.languages.typescript.javascriptDefaults.addExtraLib(xhr.responseText, 'babylon.d.ts');
                     } else {

Файловите разлики са ограничени, защото са твърде много
+ 17742 - 17741
dist/preview release/babylon.d.ts


Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
dist/preview release/babylon.js


+ 24 - 10
dist/preview release/babylon.max.js

@@ -26890,11 +26890,18 @@ var BABYLON;
          * The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
          * @param pickResult pickingInfo of the object wished to simulate pointer event on
          * @param pointerEventInit pointer event state to be used when simulating the pointer event (eg. pointer id for multitouch)
+         * @param doubleTap indicates that the pointer up event should be considered as part of a double click (false by default)
          * @returns the current scene
          */
-        Scene.prototype.simulatePointerUp = function (pickResult, pointerEventInit) {
+        Scene.prototype.simulatePointerUp = function (pickResult, pointerEventInit, doubleTap) {
             var evt = new PointerEvent("pointerup", pointerEventInit);
             var clickInfo = new ClickInfo();
+            if (doubleTap) {
+                clickInfo.doubleClick = true;
+            }
+            else {
+                clickInfo.singleClick = true;
+            }
             if (this._checkPrePointerObservable(pickResult, evt, BABYLON.PointerEventTypes.POINTERUP)) {
                 return this;
             }
@@ -26940,7 +26947,7 @@ var BABYLON;
                 this._pickedDownMesh !== this._pickedUpMesh) {
                 this._pickedDownMesh.actionManager.processTrigger(BABYLON.ActionManager.OnPickOutTrigger, BABYLON.ActionEvent.CreateNew(this._pickedDownMesh, evt));
             }
-            var type = BABYLON.PointerEventTypes.POINTERUP;
+            var type = 0;
             if (this.onPointerObservable.hasObservers()) {
                 if (!clickInfo.ignore && !clickInfo.hasSwiped) {
                     if (clickInfo.singleClick && this.onPointerObservable.hasSpecificMask(BABYLON.PointerEventTypes.POINTERTAP)) {
@@ -26949,10 +26956,18 @@ var BABYLON;
                     else if (clickInfo.doubleClick && this.onPointerObservable.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP)) {
                         type = BABYLON.PointerEventTypes.POINTERDOUBLETAP;
                     }
+                    if (type) {
+                        var pi = new BABYLON.PointerInfo(type, evt, pickResult);
+                        this._setRayOnPointerInfo(pi);
+                        this.onPointerObservable.notifyObservers(pi, type);
+                    }
+                }
+                if (!clickInfo.ignore) {
+                    type = BABYLON.PointerEventTypes.POINTERUP;
+                    var pi = new BABYLON.PointerInfo(type, evt, pickResult);
+                    this._setRayOnPointerInfo(pi);
+                    this.onPointerObservable.notifyObservers(pi, type);
                 }
-                var pi = new BABYLON.PointerInfo(type, evt, pickResult);
-                this._setRayOnPointerInfo(pi);
-                this.onPointerObservable.notifyObservers(pi, type);
             }
             if (this.onPointerUp && !clickInfo.ignore) {
                 this.onPointerUp(evt, pickResult, type);
@@ -27106,8 +27121,9 @@ var BABYLON;
                         }
                     }
                 }
-                clickInfo.ignore = needToIgnoreNext;
-                cb(clickInfo, _this._currentPickResult);
+                if (!needToIgnoreNext) {
+                    cb(clickInfo, _this._currentPickResult);
+                }
             };
             this._onPointerMove = function (evt) {
                 _this._updatePointerPosition(evt);
@@ -27183,8 +27199,6 @@ var BABYLON;
                                     }
                                 }
                             }
-                        }
-                        else {
                             if (_this._checkPrePointerObservable(null, evt, BABYLON.PointerEventTypes.POINTERUP)) {
                                 return;
                             }
@@ -112045,7 +112059,7 @@ var BABYLON;
             if (!material) {
                 return false;
             }
-            if (!material.isReady(subMesh.getMesh(), useInstances)) {
+            if (!material.isReadyForSubMesh(subMesh.getMesh(), subMesh, useInstances)) {
                 return false;
             }
             var defines = [];

+ 24 - 10
dist/preview release/babylon.no-module.max.js

@@ -26857,11 +26857,18 @@ var BABYLON;
          * The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
          * @param pickResult pickingInfo of the object wished to simulate pointer event on
          * @param pointerEventInit pointer event state to be used when simulating the pointer event (eg. pointer id for multitouch)
+         * @param doubleTap indicates that the pointer up event should be considered as part of a double click (false by default)
          * @returns the current scene
          */
-        Scene.prototype.simulatePointerUp = function (pickResult, pointerEventInit) {
+        Scene.prototype.simulatePointerUp = function (pickResult, pointerEventInit, doubleTap) {
             var evt = new PointerEvent("pointerup", pointerEventInit);
             var clickInfo = new ClickInfo();
+            if (doubleTap) {
+                clickInfo.doubleClick = true;
+            }
+            else {
+                clickInfo.singleClick = true;
+            }
             if (this._checkPrePointerObservable(pickResult, evt, BABYLON.PointerEventTypes.POINTERUP)) {
                 return this;
             }
@@ -26907,7 +26914,7 @@ var BABYLON;
                 this._pickedDownMesh !== this._pickedUpMesh) {
                 this._pickedDownMesh.actionManager.processTrigger(BABYLON.ActionManager.OnPickOutTrigger, BABYLON.ActionEvent.CreateNew(this._pickedDownMesh, evt));
             }
-            var type = BABYLON.PointerEventTypes.POINTERUP;
+            var type = 0;
             if (this.onPointerObservable.hasObservers()) {
                 if (!clickInfo.ignore && !clickInfo.hasSwiped) {
                     if (clickInfo.singleClick && this.onPointerObservable.hasSpecificMask(BABYLON.PointerEventTypes.POINTERTAP)) {
@@ -26916,10 +26923,18 @@ var BABYLON;
                     else if (clickInfo.doubleClick && this.onPointerObservable.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP)) {
                         type = BABYLON.PointerEventTypes.POINTERDOUBLETAP;
                     }
+                    if (type) {
+                        var pi = new BABYLON.PointerInfo(type, evt, pickResult);
+                        this._setRayOnPointerInfo(pi);
+                        this.onPointerObservable.notifyObservers(pi, type);
+                    }
+                }
+                if (!clickInfo.ignore) {
+                    type = BABYLON.PointerEventTypes.POINTERUP;
+                    var pi = new BABYLON.PointerInfo(type, evt, pickResult);
+                    this._setRayOnPointerInfo(pi);
+                    this.onPointerObservable.notifyObservers(pi, type);
                 }
-                var pi = new BABYLON.PointerInfo(type, evt, pickResult);
-                this._setRayOnPointerInfo(pi);
-                this.onPointerObservable.notifyObservers(pi, type);
             }
             if (this.onPointerUp && !clickInfo.ignore) {
                 this.onPointerUp(evt, pickResult, type);
@@ -27073,8 +27088,9 @@ var BABYLON;
                         }
                     }
                 }
-                clickInfo.ignore = needToIgnoreNext;
-                cb(clickInfo, _this._currentPickResult);
+                if (!needToIgnoreNext) {
+                    cb(clickInfo, _this._currentPickResult);
+                }
             };
             this._onPointerMove = function (evt) {
                 _this._updatePointerPosition(evt);
@@ -27150,8 +27166,6 @@ var BABYLON;
                                     }
                                 }
                             }
-                        }
-                        else {
                             if (_this._checkPrePointerObservable(null, evt, BABYLON.PointerEventTypes.POINTERUP)) {
                                 return;
                             }
@@ -112012,7 +112026,7 @@ var BABYLON;
             if (!material) {
                 return false;
             }
-            if (!material.isReady(subMesh.getMesh(), useInstances)) {
+            if (!material.isReadyForSubMesh(subMesh.getMesh(), subMesh, useInstances)) {
                 return false;
             }
             var defines = [];

Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
dist/preview release/babylon.worker.js


+ 24 - 10
dist/preview release/es6.js

@@ -26857,11 +26857,18 @@ var BABYLON;
          * The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
          * @param pickResult pickingInfo of the object wished to simulate pointer event on
          * @param pointerEventInit pointer event state to be used when simulating the pointer event (eg. pointer id for multitouch)
+         * @param doubleTap indicates that the pointer up event should be considered as part of a double click (false by default)
          * @returns the current scene
          */
-        Scene.prototype.simulatePointerUp = function (pickResult, pointerEventInit) {
+        Scene.prototype.simulatePointerUp = function (pickResult, pointerEventInit, doubleTap) {
             var evt = new PointerEvent("pointerup", pointerEventInit);
             var clickInfo = new ClickInfo();
+            if (doubleTap) {
+                clickInfo.doubleClick = true;
+            }
+            else {
+                clickInfo.singleClick = true;
+            }
             if (this._checkPrePointerObservable(pickResult, evt, BABYLON.PointerEventTypes.POINTERUP)) {
                 return this;
             }
@@ -26907,7 +26914,7 @@ var BABYLON;
                 this._pickedDownMesh !== this._pickedUpMesh) {
                 this._pickedDownMesh.actionManager.processTrigger(BABYLON.ActionManager.OnPickOutTrigger, BABYLON.ActionEvent.CreateNew(this._pickedDownMesh, evt));
             }
-            var type = BABYLON.PointerEventTypes.POINTERUP;
+            var type = 0;
             if (this.onPointerObservable.hasObservers()) {
                 if (!clickInfo.ignore && !clickInfo.hasSwiped) {
                     if (clickInfo.singleClick && this.onPointerObservable.hasSpecificMask(BABYLON.PointerEventTypes.POINTERTAP)) {
@@ -26916,10 +26923,18 @@ var BABYLON;
                     else if (clickInfo.doubleClick && this.onPointerObservable.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP)) {
                         type = BABYLON.PointerEventTypes.POINTERDOUBLETAP;
                     }
+                    if (type) {
+                        var pi = new BABYLON.PointerInfo(type, evt, pickResult);
+                        this._setRayOnPointerInfo(pi);
+                        this.onPointerObservable.notifyObservers(pi, type);
+                    }
+                }
+                if (!clickInfo.ignore) {
+                    type = BABYLON.PointerEventTypes.POINTERUP;
+                    var pi = new BABYLON.PointerInfo(type, evt, pickResult);
+                    this._setRayOnPointerInfo(pi);
+                    this.onPointerObservable.notifyObservers(pi, type);
                 }
-                var pi = new BABYLON.PointerInfo(type, evt, pickResult);
-                this._setRayOnPointerInfo(pi);
-                this.onPointerObservable.notifyObservers(pi, type);
             }
             if (this.onPointerUp && !clickInfo.ignore) {
                 this.onPointerUp(evt, pickResult, type);
@@ -27073,8 +27088,9 @@ var BABYLON;
                         }
                     }
                 }
-                clickInfo.ignore = needToIgnoreNext;
-                cb(clickInfo, _this._currentPickResult);
+                if (!needToIgnoreNext) {
+                    cb(clickInfo, _this._currentPickResult);
+                }
             };
             this._onPointerMove = function (evt) {
                 _this._updatePointerPosition(evt);
@@ -27150,8 +27166,6 @@ var BABYLON;
                                     }
                                 }
                             }
-                        }
-                        else {
                             if (_this._checkPrePointerObservable(null, evt, BABYLON.PointerEventTypes.POINTERUP)) {
                                 return;
                             }
@@ -112012,7 +112026,7 @@ var BABYLON;
             if (!material) {
                 return false;
             }
-            if (!material.isReady(subMesh.getMesh(), useInstances)) {
+            if (!material.isReadyForSubMesh(subMesh.getMesh(), subMesh, useInstances)) {
                 return false;
             }
             var defines = [];

+ 117 - 45
dist/preview release/gui/babylon.gui.d.ts

@@ -346,6 +346,14 @@ declare module BABYLON.GUI {
                 */
             copyFrom(other: Measure): void;
             /**
+                * Copy from a group of 4 floats
+                * @param left defines left coordinate
+                * @param top defines top coordinate
+                * @param width defines width dimension
+                * @param height defines height dimension
+                */
+            copyFromFloats(left: number, top: number, width: number, height: number): void;
+            /**
                 * Check equality between this measure and another one
                 * @param other defines the other measures
                 * @returns true if both measures are equals
@@ -1322,6 +1330,14 @@ declare module BABYLON.GUI {
     export class Image extends Control {
             name?: string | undefined;
             /**
+                * BABYLON.Observable notified when the content is loaded
+                */
+            onImageLoadedObservable: BABYLON.Observable<Image>;
+            /**
+                * Gets a boolean indicating that the content is loaded
+                */
+            readonly isLoaded: boolean;
+            /**
                 * Gets or sets the left coordinate in the source image
                 */
             sourceLeft: number;
@@ -1377,6 +1393,7 @@ declare module BABYLON.GUI {
             /** Force the control to synchronize with its content */
             synchronizeSizeWithContent(): void;
             _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+            dispose(): void;
             /** STRETCH_NONE */
             static readonly STRETCH_NONE: number;
             /** STRETCH_FILL */
@@ -2006,51 +2023,6 @@ declare module BABYLON.GUI {
     }
 }
 declare module BABYLON.GUI {
-    /**
-        * Class used to create slider controls
-        */
-    export class Slider extends Control {
-            name?: string | undefined;
-            /** BABYLON.Observable raised when the sldier value changes */
-            onValueChangedObservable: BABYLON.Observable<number>;
-            /** Gets or sets border color */
-            borderColor: string;
-            /** Gets or sets background color */
-            background: string;
-            /** Gets or sets main bar offset */
-            barOffset: string | number;
-            /** Gets main bar offset in pixels*/
-            readonly barOffsetInPixels: number;
-            /** Gets or sets thumb width */
-            thumbWidth: string | number;
-            /** Gets thumb width in pixels */
-            readonly thumbWidthInPixels: number;
-            /** Gets or sets minimum value */
-            minimum: number;
-            /** Gets or sets maximum value */
-            maximum: number;
-            /** Gets or sets current value */
-            value: number;
-            /**Gets or sets a boolean indicating if the slider should be vertical or horizontal */
-            isVertical: boolean;
-            /** Gets or sets a boolean indicating if the thumb should be round or square */
-            isThumbCircle: boolean;
-            /** Gets or sets a value indicating if the thumb can go over main bar extends */
-            isThumbClamped: boolean;
-            /**
-                * Creates a new Slider
-                * @param name defines the control name
-                */
-            constructor(name?: string | undefined);
-            protected _getTypeName(): string;
-            protected _getThumbThickness(type: string, backgroundLength: number): number;
-            _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-            _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
-            _onPointerMove(target: Control, coordinates: BABYLON.Vector2): void;
-            _onPointerUp(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
-    }
-}
-declare module BABYLON.GUI {
     /** Class used to create rectangle container */
     export class Rectangle extends Container {
             name?: string | undefined;
@@ -2104,6 +2076,106 @@ declare module BABYLON.GUI {
 }
 declare module BABYLON.GUI {
     /**
+        * Class used to create slider controls
+        */
+    export class BaseSlider extends Control {
+            name?: string | undefined;
+            protected _thumbWidth: ValueAndUnit;
+            protected _barOffset: ValueAndUnit;
+            protected _effectiveBarOffset: number;
+            protected _renderLeft: number;
+            protected _renderTop: number;
+            protected _renderWidth: number;
+            protected _renderHeight: number;
+            protected _backgroundBoxLength: number;
+            protected _backgroundBoxThickness: number;
+            protected _effectiveThumbThickness: number;
+            /** BABYLON.Observable raised when the sldier value changes */
+            onValueChangedObservable: BABYLON.Observable<number>;
+            /** Gets or sets main bar offset (ie. the margin applied to the value bar) */
+            barOffset: string | number;
+            /** Gets main bar offset in pixels*/
+            readonly barOffsetInPixels: number;
+            /** Gets or sets thumb width */
+            thumbWidth: string | number;
+            /** Gets thumb width in pixels */
+            readonly thumbWidthInPixels: number;
+            /** Gets or sets minimum value */
+            minimum: number;
+            /** Gets or sets maximum value */
+            maximum: number;
+            /** Gets or sets current value */
+            value: number;
+            /**Gets or sets a boolean indicating if the slider should be vertical or horizontal */
+            isVertical: boolean;
+            /** Gets or sets a value indicating if the thumb can go over main bar extends */
+            isThumbClamped: boolean;
+            /**
+                * Creates a new BaseSlider
+                * @param name defines the control name
+                */
+            constructor(name?: string | undefined);
+            protected _getTypeName(): string;
+            protected _getThumbPosition(): number;
+            protected _getThumbThickness(type: string): number;
+            protected _prepareRenderingData(type: string): void;
+            _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
+            _onPointerMove(target: Control, coordinates: BABYLON.Vector2): void;
+            _onPointerUp(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
+    }
+}
+declare module BABYLON.GUI {
+    /**
+        * Class used to create slider controls
+        */
+    export class Slider extends BaseSlider {
+            name?: string | undefined;
+            /** Gets or sets a boolean indicating if the thumb must be rendered */
+            displayThumb: boolean;
+            /** Gets or sets border color */
+            borderColor: string;
+            /** Gets or sets background color */
+            background: string;
+            /** Gets or sets a boolean indicating if the thumb should be round or square */
+            isThumbCircle: boolean;
+            /**
+                * Creates a new Slider
+                * @param name defines the control name
+                */
+            constructor(name?: string | undefined);
+            protected _getTypeName(): string;
+            _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+    }
+}
+declare module BABYLON.GUI {
+    /**
+        * Class used to create slider controls based on images
+        */
+    export class ImageBasedSlider extends BaseSlider {
+            name?: string | undefined;
+            /**
+                * Gets or sets the image used to render the background
+                */
+            backgroundImage: Image;
+            /**
+                * Gets or sets the image used to render the value bar
+                */
+            valueBarImage: Image;
+            /**
+                * Gets or sets the image used to render the thumb
+                */
+            thumbImage: Image;
+            /**
+                * Creates a new ImageBasedSlider
+                * @param name defines the control name
+                */
+            constructor(name?: string | undefined);
+            protected _getTypeName(): string;
+            _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+    }
+}
+declare module BABYLON.GUI {
+    /**
       * Forcing an export so that this code will execute
       * @hidden
       */

Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
dist/preview release/gui/babylon.gui.js


Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js


Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js.map


+ 249 - 96
dist/preview release/gui/babylon.gui.module.d.ts

@@ -42,9 +42,11 @@ declare module 'babylonjs-gui/2D/controls' {
     export * from "babylonjs-gui/2D/controls/selector";
     export * from "babylonjs-gui/2D/controls/textBlock";
     export * from "babylonjs-gui/2D/controls/virtualKeyboard";
-    export * from "babylonjs-gui/2D/controls/slider";
     export * from "babylonjs-gui/2D/controls/rectangle";
     export * from "babylonjs-gui/2D/controls/displayGrid";
+    export * from "babylonjs-gui/2D/controls/baseSlider";
+    export * from "babylonjs-gui/2D/controls/slider";
+    export * from "babylonjs-gui/2D/controls/imageBasedSlider";
     export * from "babylonjs-gui/2D/controls/statics";
 }
 
@@ -392,6 +394,14 @@ declare module 'babylonjs-gui/2D/measure' {
                 */
             copyFrom(other: Measure): void;
             /**
+                * Copy from a group of 4 floats
+                * @param left defines left coordinate
+                * @param top defines top coordinate
+                * @param width defines width dimension
+                * @param height defines height dimension
+                */
+            copyFromFloats(left: number, top: number, width: number, height: number): void;
+            /**
                 * Check equality between this measure and another one
                 * @param other defines the other measures
                 * @returns true if both measures are equals
@@ -1430,7 +1440,7 @@ declare module 'babylonjs-gui/2D/controls/grid' {
 
 declare module 'babylonjs-gui/2D/controls/image' {
     import { Control } from "babylonjs-gui/2D/controls/control";
-    import { Nullable } from "babylonjs";
+    import { Nullable, Observable } from "babylonjs";
     import { Measure } from "babylonjs-gui/2D/measure";
     /**
         * Class used to create 2D images
@@ -1438,6 +1448,14 @@ declare module 'babylonjs-gui/2D/controls/image' {
     export class Image extends Control {
             name?: string | undefined;
             /**
+                * Observable notified when the content is loaded
+                */
+            onImageLoadedObservable: Observable<Image>;
+            /**
+                * Gets a boolean indicating that the content is loaded
+                */
+            readonly isLoaded: boolean;
+            /**
                 * Gets or sets the left coordinate in the source image
                 */
             sourceLeft: number;
@@ -1493,6 +1511,7 @@ declare module 'babylonjs-gui/2D/controls/image' {
             /** Force the control to synchronize with its content */
             synchronizeSizeWithContent(): void;
             _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+            dispose(): void;
             /** STRETCH_NONE */
             static readonly STRETCH_NONE: number;
             /** STRETCH_FILL */
@@ -2158,55 +2177,6 @@ declare module 'babylonjs-gui/2D/controls/virtualKeyboard' {
     }
 }
 
-declare module 'babylonjs-gui/2D/controls/slider' {
-    import { Control } from "babylonjs-gui/2D/controls/control";
-    import { Observable, Vector2 } from "babylonjs";
-    import { Measure } from "babylonjs-gui/2D/measure";
-    /**
-        * Class used to create slider controls
-        */
-    export class Slider extends Control {
-            name?: string | undefined;
-            /** Observable raised when the sldier value changes */
-            onValueChangedObservable: Observable<number>;
-            /** Gets or sets border color */
-            borderColor: string;
-            /** Gets or sets background color */
-            background: string;
-            /** Gets or sets main bar offset */
-            barOffset: string | number;
-            /** Gets main bar offset in pixels*/
-            readonly barOffsetInPixels: number;
-            /** Gets or sets thumb width */
-            thumbWidth: string | number;
-            /** Gets thumb width in pixels */
-            readonly thumbWidthInPixels: number;
-            /** Gets or sets minimum value */
-            minimum: number;
-            /** Gets or sets maximum value */
-            maximum: number;
-            /** Gets or sets current value */
-            value: number;
-            /**Gets or sets a boolean indicating if the slider should be vertical or horizontal */
-            isVertical: boolean;
-            /** Gets or sets a boolean indicating if the thumb should be round or square */
-            isThumbCircle: boolean;
-            /** Gets or sets a value indicating if the thumb can go over main bar extends */
-            isThumbClamped: boolean;
-            /**
-                * Creates a new Slider
-                * @param name defines the control name
-                */
-            constructor(name?: string | undefined);
-            protected _getTypeName(): string;
-            protected _getThumbThickness(type: string, backgroundLength: number): number;
-            _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-            _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
-            _onPointerMove(target: Control, coordinates: Vector2): void;
-            _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
-    }
-}
-
 declare module 'babylonjs-gui/2D/controls/rectangle' {
     import { Container } from "babylonjs-gui/2D/controls/container";
     import { Measure } from "babylonjs-gui/2D/measure";
@@ -2265,6 +2235,117 @@ declare module 'babylonjs-gui/2D/controls/displayGrid' {
     }
 }
 
+declare module 'babylonjs-gui/2D/controls/baseSlider' {
+    import { Control } from "babylonjs-gui/2D/controls/control";
+    import { ValueAndUnit } from "babylonjs-gui/2D/valueAndUnit";
+    import { Observable, Vector2 } from "babylonjs";
+    /**
+        * Class used to create slider controls
+        */
+    export class BaseSlider extends Control {
+            name?: string | undefined;
+            protected _thumbWidth: ValueAndUnit;
+            protected _barOffset: ValueAndUnit;
+            protected _effectiveBarOffset: number;
+            protected _renderLeft: number;
+            protected _renderTop: number;
+            protected _renderWidth: number;
+            protected _renderHeight: number;
+            protected _backgroundBoxLength: number;
+            protected _backgroundBoxThickness: number;
+            protected _effectiveThumbThickness: number;
+            /** Observable raised when the sldier value changes */
+            onValueChangedObservable: Observable<number>;
+            /** Gets or sets main bar offset (ie. the margin applied to the value bar) */
+            barOffset: string | number;
+            /** Gets main bar offset in pixels*/
+            readonly barOffsetInPixels: number;
+            /** Gets or sets thumb width */
+            thumbWidth: string | number;
+            /** Gets thumb width in pixels */
+            readonly thumbWidthInPixels: number;
+            /** Gets or sets minimum value */
+            minimum: number;
+            /** Gets or sets maximum value */
+            maximum: number;
+            /** Gets or sets current value */
+            value: number;
+            /**Gets or sets a boolean indicating if the slider should be vertical or horizontal */
+            isVertical: boolean;
+            /** Gets or sets a value indicating if the thumb can go over main bar extends */
+            isThumbClamped: boolean;
+            /**
+                * Creates a new BaseSlider
+                * @param name defines the control name
+                */
+            constructor(name?: string | undefined);
+            protected _getTypeName(): string;
+            protected _getThumbPosition(): number;
+            protected _getThumbThickness(type: string): number;
+            protected _prepareRenderingData(type: string): void;
+            _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
+            _onPointerMove(target: Control, coordinates: Vector2): void;
+            _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
+    }
+}
+
+declare module 'babylonjs-gui/2D/controls/slider' {
+    import { Measure } from "babylonjs-gui/2D/measure";
+    import { BaseSlider } from "babylonjs-gui/2D/controls/baseSlider";
+    /**
+        * Class used to create slider controls
+        */
+    export class Slider extends BaseSlider {
+            name?: string | undefined;
+            /** Gets or sets a boolean indicating if the thumb must be rendered */
+            displayThumb: boolean;
+            /** Gets or sets border color */
+            borderColor: string;
+            /** Gets or sets background color */
+            background: string;
+            /** Gets or sets a boolean indicating if the thumb should be round or square */
+            isThumbCircle: boolean;
+            /**
+                * Creates a new Slider
+                * @param name defines the control name
+                */
+            constructor(name?: string | undefined);
+            protected _getTypeName(): string;
+            _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+    }
+}
+
+declare module 'babylonjs-gui/2D/controls/imageBasedSlider' {
+    import { BaseSlider } from "babylonjs-gui/2D/controls/baseSlider";
+    import { Measure } from "babylonjs-gui/2D/measure";
+    import { Image } from "babylonjs-gui/2D/controls/image";
+    /**
+        * Class used to create slider controls based on images
+        */
+    export class ImageBasedSlider extends BaseSlider {
+            name?: string | undefined;
+            /**
+                * Gets or sets the image used to render the background
+                */
+            backgroundImage: Image;
+            /**
+                * Gets or sets the image used to render the value bar
+                */
+            valueBarImage: Image;
+            /**
+                * Gets or sets the image used to render the thumb
+                */
+            thumbImage: Image;
+            /**
+                * Creates a new ImageBasedSlider
+                * @param name defines the control name
+                */
+            constructor(name?: string | undefined);
+            protected _getTypeName(): string;
+            _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+    }
+}
+
 declare module 'babylonjs-gui/2D/controls/statics' {
     /**
       * Forcing an export so that this code will execute
@@ -3191,6 +3272,14 @@ declare module BABYLON.GUI {
                 */
             copyFrom(other: Measure): void;
             /**
+                * Copy from a group of 4 floats
+                * @param left defines left coordinate
+                * @param top defines top coordinate
+                * @param width defines width dimension
+                * @param height defines height dimension
+                */
+            copyFromFloats(left: number, top: number, width: number, height: number): void;
+            /**
                 * Check equality between this measure and another one
                 * @param other defines the other measures
                 * @returns true if both measures are equals
@@ -4167,6 +4256,14 @@ declare module BABYLON.GUI {
     export class Image extends Control {
             name?: string | undefined;
             /**
+                * BABYLON.Observable notified when the content is loaded
+                */
+            onImageLoadedObservable: BABYLON.Observable<Image>;
+            /**
+                * Gets a boolean indicating that the content is loaded
+                */
+            readonly isLoaded: boolean;
+            /**
                 * Gets or sets the left coordinate in the source image
                 */
             sourceLeft: number;
@@ -4222,6 +4319,7 @@ declare module BABYLON.GUI {
             /** Force the control to synchronize with its content */
             synchronizeSizeWithContent(): void;
             _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+            dispose(): void;
             /** STRETCH_NONE */
             static readonly STRETCH_NONE: number;
             /** STRETCH_FILL */
@@ -4851,51 +4949,6 @@ declare module BABYLON.GUI {
     }
 }
 declare module BABYLON.GUI {
-    /**
-        * Class used to create slider controls
-        */
-    export class Slider extends Control {
-            name?: string | undefined;
-            /** BABYLON.Observable raised when the sldier value changes */
-            onValueChangedObservable: BABYLON.Observable<number>;
-            /** Gets or sets border color */
-            borderColor: string;
-            /** Gets or sets background color */
-            background: string;
-            /** Gets or sets main bar offset */
-            barOffset: string | number;
-            /** Gets main bar offset in pixels*/
-            readonly barOffsetInPixels: number;
-            /** Gets or sets thumb width */
-            thumbWidth: string | number;
-            /** Gets thumb width in pixels */
-            readonly thumbWidthInPixels: number;
-            /** Gets or sets minimum value */
-            minimum: number;
-            /** Gets or sets maximum value */
-            maximum: number;
-            /** Gets or sets current value */
-            value: number;
-            /**Gets or sets a boolean indicating if the slider should be vertical or horizontal */
-            isVertical: boolean;
-            /** Gets or sets a boolean indicating if the thumb should be round or square */
-            isThumbCircle: boolean;
-            /** Gets or sets a value indicating if the thumb can go over main bar extends */
-            isThumbClamped: boolean;
-            /**
-                * Creates a new Slider
-                * @param name defines the control name
-                */
-            constructor(name?: string | undefined);
-            protected _getTypeName(): string;
-            protected _getThumbThickness(type: string, backgroundLength: number): number;
-            _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-            _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
-            _onPointerMove(target: Control, coordinates: BABYLON.Vector2): void;
-            _onPointerUp(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
-    }
-}
-declare module BABYLON.GUI {
     /** Class used to create rectangle container */
     export class Rectangle extends Container {
             name?: string | undefined;
@@ -4949,6 +5002,106 @@ declare module BABYLON.GUI {
 }
 declare module BABYLON.GUI {
     /**
+        * Class used to create slider controls
+        */
+    export class BaseSlider extends Control {
+            name?: string | undefined;
+            protected _thumbWidth: ValueAndUnit;
+            protected _barOffset: ValueAndUnit;
+            protected _effectiveBarOffset: number;
+            protected _renderLeft: number;
+            protected _renderTop: number;
+            protected _renderWidth: number;
+            protected _renderHeight: number;
+            protected _backgroundBoxLength: number;
+            protected _backgroundBoxThickness: number;
+            protected _effectiveThumbThickness: number;
+            /** BABYLON.Observable raised when the sldier value changes */
+            onValueChangedObservable: BABYLON.Observable<number>;
+            /** Gets or sets main bar offset (ie. the margin applied to the value bar) */
+            barOffset: string | number;
+            /** Gets main bar offset in pixels*/
+            readonly barOffsetInPixels: number;
+            /** Gets or sets thumb width */
+            thumbWidth: string | number;
+            /** Gets thumb width in pixels */
+            readonly thumbWidthInPixels: number;
+            /** Gets or sets minimum value */
+            minimum: number;
+            /** Gets or sets maximum value */
+            maximum: number;
+            /** Gets or sets current value */
+            value: number;
+            /**Gets or sets a boolean indicating if the slider should be vertical or horizontal */
+            isVertical: boolean;
+            /** Gets or sets a value indicating if the thumb can go over main bar extends */
+            isThumbClamped: boolean;
+            /**
+                * Creates a new BaseSlider
+                * @param name defines the control name
+                */
+            constructor(name?: string | undefined);
+            protected _getTypeName(): string;
+            protected _getThumbPosition(): number;
+            protected _getThumbThickness(type: string): number;
+            protected _prepareRenderingData(type: string): void;
+            _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
+            _onPointerMove(target: Control, coordinates: BABYLON.Vector2): void;
+            _onPointerUp(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
+    }
+}
+declare module BABYLON.GUI {
+    /**
+        * Class used to create slider controls
+        */
+    export class Slider extends BaseSlider {
+            name?: string | undefined;
+            /** Gets or sets a boolean indicating if the thumb must be rendered */
+            displayThumb: boolean;
+            /** Gets or sets border color */
+            borderColor: string;
+            /** Gets or sets background color */
+            background: string;
+            /** Gets or sets a boolean indicating if the thumb should be round or square */
+            isThumbCircle: boolean;
+            /**
+                * Creates a new Slider
+                * @param name defines the control name
+                */
+            constructor(name?: string | undefined);
+            protected _getTypeName(): string;
+            _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+    }
+}
+declare module BABYLON.GUI {
+    /**
+        * Class used to create slider controls based on images
+        */
+    export class ImageBasedSlider extends BaseSlider {
+            name?: string | undefined;
+            /**
+                * Gets or sets the image used to render the background
+                */
+            backgroundImage: Image;
+            /**
+                * Gets or sets the image used to render the value bar
+                */
+            valueBarImage: Image;
+            /**
+                * Gets or sets the image used to render the thumb
+                */
+            thumbImage: Image;
+            /**
+                * Creates a new ImageBasedSlider
+                * @param name defines the control name
+                */
+            constructor(name?: string | undefined);
+            protected _getTypeName(): string;
+            _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+    }
+}
+declare module BABYLON.GUI {
+    /**
       * Forcing an export so that this code will execute
       * @hidden
       */

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

@@ -500,6 +500,10 @@ var BABYLON;
                 _this._endPerformanceCounter("Validate JSON");
                 _this.onValidatedObservable.notifyObservers(result);
                 _this.onValidatedObservable.clear();
+            }, function (reason) {
+                _this._endPerformanceCounter("Validate JSON");
+                BABYLON.Tools.Warn("Failed to validate: " + reason);
+                _this.onValidatedObservable.clear();
             });
         };
         GLTFFileLoader.prototype._getLoader = function (loaderData) {

Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


+ 4 - 0
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -500,6 +500,10 @@ var BABYLON;
                 _this._endPerformanceCounter("Validate JSON");
                 _this.onValidatedObservable.notifyObservers(result);
                 _this.onValidatedObservable.clear();
+            }, function (reason) {
+                _this._endPerformanceCounter("Validate JSON");
+                BABYLON.Tools.Warn("Failed to validate: " + reason);
+                _this.onValidatedObservable.clear();
             });
         };
         GLTFFileLoader.prototype._getLoader = function (loaderData) {

Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 4 - 0
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -500,6 +500,10 @@ var BABYLON;
                 _this._endPerformanceCounter("Validate JSON");
                 _this.onValidatedObservable.notifyObservers(result);
                 _this.onValidatedObservable.clear();
+            }, function (reason) {
+                _this._endPerformanceCounter("Validate JSON");
+                BABYLON.Tools.Warn("Failed to validate: " + reason);
+                _this.onValidatedObservable.clear();
             });
         };
         GLTFFileLoader.prototype._getLoader = function (loaderData) {

Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 4 - 0
dist/preview release/loaders/babylonjs.loaders.js

@@ -1586,6 +1586,10 @@ var BABYLON;
                 _this._endPerformanceCounter("Validate JSON");
                 _this.onValidatedObservable.notifyObservers(result);
                 _this.onValidatedObservable.clear();
+            }, function (reason) {
+                _this._endPerformanceCounter("Validate JSON");
+                BABYLON.Tools.Warn("Failed to validate: " + reason);
+                _this.onValidatedObservable.clear();
             });
         };
         GLTFFileLoader.prototype._getLoader = function (loaderData) {

Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.min.js


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

@@ -924,7 +924,7 @@ declare module BabylonViewer {
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 declare module BabylonViewer {
@@ -1558,6 +1558,20 @@ declare module BabylonViewer {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 declare module BabylonViewer {
+    /**
+        * A custom upgrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedUpgrade(sceneManager: SceneManager): boolean;
+    /**
+        * A custom degrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedDegrade(sceneManager: SceneManager): boolean;
+}
+declare module BabylonViewer {
 }
 declare module BabylonViewer {
     export interface IEnvironmentMapConfiguration {
@@ -1844,6 +1858,25 @@ declare module BabylonViewer {
     }
 }
 declare module BabylonViewer {
+    export interface IDefaultRenderingPipelineConfiguration {
+        sharpenEnabled?: boolean;
+        bloomEnabled?: boolean;
+        bloomThreshold?: number;
+        depthOfFieldEnabled?: boolean;
+        depthOfFieldBlurLevel?: BABYLON.DepthOfFieldEffectBlurLevel;
+        fxaaEnabled?: boolean;
+        imageProcessingEnabled?: boolean;
+        defaultPipelineTextureType?: number;
+        bloomScale?: number;
+        chromaticAberrationEnabled?: boolean;
+        grainEnabled?: boolean;
+        bloomKernel?: number;
+        hardwareScaleLevel?: number;
+        bloomWeight?: number;
+        hdr?: boolean;
+        samples?: number;
+        glowLayerEnabled?: boolean;
+    }
 }
 declare module BabylonViewer {
     export interface IGroundConfiguration {

Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
dist/preview release/viewer/babylon.viewer.js


Файловите разлики са ограничени, защото са твърде много
+ 2 - 2
dist/preview release/viewer/babylon.viewer.max.js


+ 38 - 2
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -985,13 +985,14 @@ declare module 'babylonjs-viewer/templating/viewerTemplatePlugin' {
 }
 
 declare module 'babylonjs-viewer/optimizer/custom' {
+    import { extendedUpgrade } from "babylonjs-viewer/optimizer/custom/extended";
     import { SceneManager } from "babylonjs-viewer/managers/sceneManager";
     /**
       *
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 
@@ -1662,6 +1663,22 @@ declare module 'babylonjs-viewer/loader/plugins' {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 
+declare module 'babylonjs-viewer/optimizer/custom/extended' {
+    import { SceneManager } from 'babylonjs-viewer/managers/sceneManager';
+    /**
+        * A custom upgrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedUpgrade(sceneManager: SceneManager): boolean;
+    /**
+        * A custom degrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedDegrade(sceneManager: SceneManager): boolean;
+}
+
 declare module 'babylonjs-viewer/configuration/interfaces' {
     export * from 'babylonjs-viewer/configuration/interfaces/cameraConfiguration';
     export * from 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration';
@@ -1990,7 +2007,26 @@ declare module 'babylonjs-viewer/configuration/interfaces/colorGradingConfigurat
 }
 
 declare module 'babylonjs-viewer/configuration/interfaces/defaultRenderingPipelineConfiguration' {
-    
+    import { DepthOfFieldEffectBlurLevel } from 'babylonjs';
+    export interface IDefaultRenderingPipelineConfiguration {
+        sharpenEnabled?: boolean;
+        bloomEnabled?: boolean;
+        bloomThreshold?: number;
+        depthOfFieldEnabled?: boolean;
+        depthOfFieldBlurLevel?: DepthOfFieldEffectBlurLevel;
+        fxaaEnabled?: boolean;
+        imageProcessingEnabled?: boolean;
+        defaultPipelineTextureType?: number;
+        bloomScale?: number;
+        chromaticAberrationEnabled?: boolean;
+        grainEnabled?: boolean;
+        bloomKernel?: number;
+        hardwareScaleLevel?: number;
+        bloomWeight?: number;
+        hdr?: boolean;
+        samples?: number;
+        glowLayerEnabled?: boolean;
+    }
 }
 
 declare module 'babylonjs-viewer/configuration/interfaces/groundConfiguration' {

+ 4 - 1
dist/preview release/what's new.md

@@ -17,6 +17,7 @@
 ### GUI
 
 - Added `button.image` and `button.textBlock` to simplify access to button internal parts ([Deltakosh](https://github.com/deltakosh))
+- Added `sldier.displayThumb` to show/hide slider's thumb ([Deltakosh](https://github.com/deltakosh))
 
 ### Core Engine
 
@@ -46,7 +47,6 @@
 ### Materials Library
 
 ## Bug fixes
-- Add missing effect layer to asset container ([TrevorDev](https://github.com/TrevorDev))
 
 ### Core Engine
 - Fixed a bug with `mesh.alwaysSelectAsActiveMesh` preventing layerMask to be taken in account ([Deltakosh](https://github.com/deltakosh))
@@ -55,6 +55,9 @@
 - Handle properly the `LinesMesh` `intersectionThreshold` by using its value directly when the intersection against a `Ray` is checked, instead of extending the `BoundingInfo` accordingly ([barroij](https://github.com/barroij))
 - Fixed the `LineEdgesRenderer` used for edge rendering of `LinesMesh` handle properly LinesMesh made of disconnected lines + Make it work for instance of `LinesMesh` ([barroij](https://github.com/barroij))
 - Fixed `Matrix.toNormalMatrix`function ([barroij](https://github.com/barroij))
+- Add missing effect layer to asset container ([TrevorDev](https://github.com/TrevorDev))
+- Fixed effect layer compatibility with multi materials ([Sebavan](https://github.com/Sebavan))
+
 ### Viewer
 
 ### Loaders

+ 283 - 0
gui/src/2D/controls/baseSlider.ts

@@ -0,0 +1,283 @@
+import { Control } from "./control";
+import { ValueAndUnit } from "../valueAndUnit";
+import { Observable, Vector2 } from "babylonjs";
+
+/**
+ * Class used to create slider controls
+ */
+export class BaseSlider extends Control {
+    protected _thumbWidth = new ValueAndUnit(20, ValueAndUnit.UNITMODE_PIXEL, false);
+    private _minimum = 0;
+    private _maximum = 100;
+    private _value = 50;
+    private _isVertical = false;
+    protected _barOffset = new ValueAndUnit(5, ValueAndUnit.UNITMODE_PIXEL, false);
+    private _isThumbClamped = false;
+
+    // Shared rendering info
+    protected _effectiveBarOffset = 0;
+    protected _renderLeft: number;
+    protected _renderTop: number;
+    protected _renderWidth: number;
+    protected _renderHeight: number;
+    protected _backgroundBoxLength: number;
+    protected _backgroundBoxThickness: number;
+    protected _effectiveThumbThickness: number;
+
+    /** Observable raised when the sldier value changes */
+    public onValueChangedObservable = new Observable<number>();
+
+    /** Gets or sets main bar offset (ie. the margin applied to the value bar) */
+    public get barOffset(): string | number {
+        return this._barOffset.toString(this._host);
+    }
+
+    /** Gets main bar offset in pixels*/
+    public get barOffsetInPixels(): number {
+        return this._barOffset.getValueInPixel(this._host, this._cachedParentMeasure.width);
+    }
+
+    public set barOffset(value: string | number) {
+        if (this._barOffset.toString(this._host) === value) {
+            return;
+        }
+
+        if (this._barOffset.fromString(value)) {
+            this._markAsDirty();
+        }
+    }
+
+    /** Gets or sets thumb width */
+    public get thumbWidth(): string | number {
+        return this._thumbWidth.toString(this._host);
+    }
+
+    /** Gets thumb width in pixels */
+    public get thumbWidthInPixels(): number {
+        return this._thumbWidth.getValueInPixel(this._host, this._cachedParentMeasure.width);
+    }
+
+    public set thumbWidth(value: string | number) {
+        if (this._thumbWidth.toString(this._host) === value) {
+            return;
+        }
+
+        if (this._thumbWidth.fromString(value)) {
+            this._markAsDirty();
+        }
+    }
+
+    /** Gets or sets minimum value */
+    public get minimum(): number {
+        return this._minimum;
+    }
+
+    public set minimum(value: number) {
+        if (this._minimum === value) {
+            return;
+        }
+
+        this._minimum = value;
+        this._markAsDirty();
+
+        this.value = Math.max(Math.min(this.value, this._maximum), this._minimum);
+    }
+
+    /** Gets or sets maximum value */
+    public get maximum(): number {
+        return this._maximum;
+    }
+
+    public set maximum(value: number) {
+        if (this._maximum === value) {
+            return;
+        }
+
+        this._maximum = value;
+        this._markAsDirty();
+
+        this.value = Math.max(Math.min(this.value, this._maximum), this._minimum);
+    }
+
+    /** Gets or sets current value */
+    public get value(): number {
+        return this._value;
+    }
+
+    public set value(value: number) {
+        value = Math.max(Math.min(value, this._maximum), this._minimum);
+
+        if (this._value === value) {
+            return;
+        }
+
+        this._value = value;
+        this._markAsDirty();
+        this.onValueChangedObservable.notifyObservers(this._value);
+    }
+
+    /**Gets or sets a boolean indicating if the slider should be vertical or horizontal */
+    public get isVertical(): boolean {
+        return this._isVertical;
+    }
+
+    public set isVertical(value: boolean) {
+        if (this._isVertical === value) {
+            return;
+        }
+
+        this._isVertical = value;
+        this._markAsDirty();
+    }
+
+    /** Gets or sets a value indicating if the thumb can go over main bar extends */
+    public get isThumbClamped(): boolean {
+        return this._isThumbClamped;
+    }
+
+    public set isThumbClamped(value: boolean) {
+        if (this._isThumbClamped === value) {
+            return;
+        }
+
+        this._isThumbClamped = value;
+        this._markAsDirty();
+    }
+
+    /**
+     * Creates a new BaseSlider
+     * @param name defines the control name
+     */
+    constructor(public name?: string) {
+        super(name);
+
+        this.isPointerBlocker = true;
+    }
+
+    protected _getTypeName(): string {
+        return "BaseSlider";
+    }
+
+    protected _getThumbPosition() {
+        if (this.isVertical) {
+            return ((this.maximum - this.value) / (this.maximum - this.minimum)) * this._backgroundBoxLength;
+        }
+
+        return ((this.value - this.minimum) / (this.maximum - this.minimum)) * this._backgroundBoxLength;
+    }
+
+    protected _getThumbThickness(type: string): number {
+        var thumbThickness = 0;
+        switch (type) {
+            case "circle":
+                if (this._thumbWidth.isPixel) {
+                    thumbThickness = Math.max(this._thumbWidth.getValue(this._host), this._backgroundBoxThickness);
+                }
+                else {
+                    thumbThickness = this._backgroundBoxThickness * this._thumbWidth.getValue(this._host);
+                }
+                break;
+            case "rectangle":
+                if (this._thumbWidth.isPixel) {
+                    thumbThickness = Math.min(this._thumbWidth.getValue(this._host), this._backgroundBoxThickness);
+                }
+                else {
+                    thumbThickness = this._backgroundBoxThickness * this._thumbWidth.getValue(this._host);
+                }
+        }
+        return thumbThickness;
+    }
+
+    protected _prepareRenderingData(type: string) {
+        // Main bar
+        this._effectiveBarOffset = 0;
+        this._renderLeft = this._currentMeasure.left;
+        this._renderTop = this._currentMeasure.top;
+        this._renderWidth = this._currentMeasure.width;
+        this._renderHeight = this._currentMeasure.height;
+
+        this._backgroundBoxLength = Math.max(this._currentMeasure.width, this._currentMeasure.height);
+        this._backgroundBoxThickness = Math.min(this._currentMeasure.width, this._currentMeasure.height);
+        this._effectiveThumbThickness = this._getThumbThickness(type);
+
+        this._backgroundBoxLength -= this._effectiveThumbThickness;
+        //throw error when height is less than width for vertical slider
+        if ((this.isVertical && this._currentMeasure.height < this._currentMeasure.width)) {
+            console.error("Height should be greater than width");
+            return;
+        }
+        if (this._barOffset.isPixel) {
+            this._effectiveBarOffset = Math.min(this._barOffset.getValue(this._host), this._backgroundBoxThickness);
+        }
+        else {
+            this._effectiveBarOffset = this._backgroundBoxThickness * this._barOffset.getValue(this._host);
+        }
+
+        this._backgroundBoxThickness -= (this._effectiveBarOffset * 2);
+
+        if (this.isVertical) {
+            this._renderLeft += this._effectiveBarOffset;
+            if (!this.isThumbClamped) {
+                this._renderTop += (this._effectiveThumbThickness / 2);
+            }
+
+            this._renderHeight = this._backgroundBoxLength;
+            this._renderWidth = this._backgroundBoxThickness;
+
+        }
+        else {
+            this._renderTop += this._effectiveBarOffset;
+            if (!this.isThumbClamped) {
+                this._renderLeft += (this._effectiveThumbThickness / 2);
+            }
+            this._renderHeight = this._backgroundBoxThickness;
+            this._renderWidth = this._backgroundBoxLength;
+        }
+    }
+
+    // Events
+    private _pointerIsDown = false;
+
+    private _updateValueFromPointer(x: number, y: number): void {
+        if (this.rotation != 0) {
+            this._invertTransformMatrix.transformCoordinates(x, y, this._transformedPosition);
+            x = this._transformedPosition.x;
+            y = this._transformedPosition.y;
+        }
+
+        if (this._isVertical) {
+            this.value = this._minimum + (1 - ((y - this._currentMeasure.top) / this._currentMeasure.height)) * (this._maximum - this._minimum);
+        }
+        else {
+            this.value = this._minimum + ((x - this._currentMeasure.left) / this._currentMeasure.width) * (this._maximum - this._minimum);
+        }
+    }
+
+    public _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean {
+        if (!super._onPointerDown(target, coordinates, pointerId, buttonIndex)) {
+            return false;
+        }
+
+        this._pointerIsDown = true;
+
+        this._updateValueFromPointer(coordinates.x, coordinates.y);
+        this._host._capturingControl[pointerId] = this;
+
+        return true;
+    }
+
+    public _onPointerMove(target: Control, coordinates: Vector2): void {
+        if (this._pointerIsDown) {
+            this._updateValueFromPointer(coordinates.x, coordinates.y);
+        }
+
+        super._onPointerMove(target, coordinates);
+    }
+
+    public _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void {
+        this._pointerIsDown = false;
+
+        delete this._host._capturingControl[pointerId];
+        super._onPointerUp(target, coordinates, pointerId, buttonIndex, notifyClick);
+    }
+}

+ 20 - 1
gui/src/2D/controls/image.ts

@@ -1,5 +1,5 @@
 import { Control } from "./control";
-import { Nullable, Tools } from "babylonjs";
+import { Nullable, Tools, Observable } from "babylonjs";
 import { Measure } from "../measure";
 
 /**
@@ -24,6 +24,18 @@ export class Image extends Control {
     private _cellId: number = -1;
 
     /**
+     * Observable notified when the content is loaded
+     */
+    public onImageLoadedObservable = new Observable<Image>();
+
+    /**
+     * Gets a boolean indicating that the content is loaded
+     */
+    public get isLoaded(): boolean {
+        return this._loaded;
+    }
+
+    /**
      * Gets or sets the left coordinate in the source image
      */
     public get sourceLeft(): number {
@@ -155,6 +167,8 @@ export class Image extends Control {
             this.synchronizeSizeWithContent();
         }
 
+        this.onImageLoadedObservable.notifyObservers(this);
+
         this._markAsDirty();
     }
 
@@ -321,6 +335,11 @@ export class Image extends Control {
         context.restore();
     }
 
+    public dispose() {
+        super.dispose();
+        this.onImageLoadedObservable.clear();
+    }
+
     // Static
     /** STRETCH_NONE */
     public static readonly STRETCH_NONE = 0;

+ 145 - 0
gui/src/2D/controls/imageBasedSlider.ts

@@ -0,0 +1,145 @@
+import { BaseSlider } from "./baseSlider";
+import { Measure } from "../measure";
+import { Image } from "./image";
+
+/**
+ * Class used to create slider controls based on images
+ */
+export class ImageBasedSlider extends BaseSlider {
+    private _backgroundImage: Image;
+    private _thumbImage: Image;
+    private _valueBarImage: Image;
+
+    private _tempMeasure = new Measure(0, 0, 0, 0);
+
+    /**
+     * Gets or sets the image used to render the background
+     */
+    public get backgroundImage(): Image {
+        return this._backgroundImage;
+    }
+
+    public set backgroundImage(value: Image) {
+        if (this._backgroundImage === value) {
+            return;
+        }
+
+        this._backgroundImage = value;
+
+        if (value && !value.isLoaded) {
+            value.onImageLoadedObservable.addOnce(() => this._markAsDirty());
+        }
+
+        this._markAsDirty();
+    }
+
+    /**
+     * Gets or sets the image used to render the value bar
+     */
+    public get valueBarImage(): Image {
+        return this._valueBarImage;
+    }
+
+    public set valueBarImage(value: Image) {
+        if (this._valueBarImage === value) {
+            return;
+        }
+
+        this._valueBarImage = value;
+
+        if (value && !value.isLoaded) {
+            value.onImageLoadedObservable.addOnce(() => this._markAsDirty());
+        }
+
+        this._markAsDirty();
+    }
+
+    /**
+     * Gets or sets the image used to render the thumb
+     */
+    public get thumbImage(): Image {
+        return this._thumbImage;
+    }
+
+    public set thumbImage(value: Image) {
+        if (this._thumbImage === value) {
+            return;
+        }
+
+        this._thumbImage = value;
+
+        if (value && !value.isLoaded) {
+            value.onImageLoadedObservable.addOnce(() => this._markAsDirty());
+        }
+
+        this._markAsDirty();
+    }
+
+    /**
+     * Creates a new ImageBasedSlider
+     * @param name defines the control name
+     */
+    constructor(public name?: string) {
+        super(name);
+    }
+
+    protected _getTypeName(): string {
+        return "ImageBasedSlider";
+    }
+
+    public _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
+        context.save();
+
+        this._applyStates(context);
+        if (this._processMeasures(parentMeasure, context)) {
+
+            this._prepareRenderingData("rectangle");
+            const thumbPosition = this._getThumbPosition();
+            var left = this._renderLeft;
+            var top = this._renderTop;
+            var width = this._renderWidth;
+            var height = this._renderHeight;
+
+            // Background
+            if (this._backgroundImage) {
+                this._tempMeasure.copyFromFloats(left, top, width, height);
+                if (this.isThumbClamped) {
+                    if (this.isVertical) {
+                        this._tempMeasure.height += this._effectiveThumbThickness;
+                    } else {
+                        this._tempMeasure.width += this._effectiveThumbThickness;
+                    }
+
+                }
+                this._backgroundImage._draw(this._tempMeasure, context);
+            }
+
+            // Bar
+            if (this._valueBarImage) {
+                if (this.isVertical) {
+                    this._tempMeasure.copyFromFloats(left, top + thumbPosition, width, height - thumbPosition);
+                    if (this.isThumbClamped) {
+                        this._tempMeasure.copyFromFloats(left, top + thumbPosition, width, this._currentMeasure.height - thumbPosition);
+                    } else {
+                        this._tempMeasure.copyFromFloats(left, top + thumbPosition, width, height - thumbPosition);
+                    }
+                } else {
+                    this._tempMeasure.copyFromFloats(left, top, thumbPosition, height);
+                }
+                this._valueBarImage._draw(this._tempMeasure, context);
+            }
+
+            // Thumb
+            if (this._thumbImage) {
+                if (this.isVertical) {
+                    this._tempMeasure.copyFromFloats(left - this._effectiveBarOffset, this._currentMeasure.top + thumbPosition, this._currentMeasure.width, this._effectiveThumbThickness);
+                } else {
+                    this._tempMeasure.copyFromFloats(this._currentMeasure.left + thumbPosition, this._currentMeasure.top, this._effectiveThumbThickness, this._currentMeasure.height);
+                }
+                this._thumbImage._draw(this._tempMeasure, context);
+            }
+        }
+
+        context.restore();
+    }
+}

+ 23 - 21
gui/src/2D/controls/index.ts

@@ -1,22 +1,24 @@
-export * from "./button";
-export * from "./checkbox";
-export * from "./colorpicker";
-export * from "./container";
-export * from "./control";
-export * from "./ellipse";
-export * from "./grid";
-export * from "./image";
-export * from "./inputText";
-export * from "./inputPassword";
-export * from "./line";
-export * from "./multiLine";
-export * from "./radioButton";
-export * from "./stackPanel";
-export * from "./selector";
-export * from "./textBlock";
-export * from "./virtualKeyboard";
-export * from "./slider";
-export * from "./rectangle";
-export * from "./displayGrid";
-
+export * from "./button";
+export * from "./checkbox";
+export * from "./colorpicker";
+export * from "./container";
+export * from "./control";
+export * from "./ellipse";
+export * from "./grid";
+export * from "./image";
+export * from "./inputText";
+export * from "./inputPassword";
+export * from "./line";
+export * from "./multiLine";
+export * from "./radioButton";
+export * from "./stackPanel";
+export * from "./selector";
+export * from "./textBlock";
+export * from "./virtualKeyboard";
+export * from "./rectangle";
+export * from "./displayGrid";
+export * from "./baseSlider";
+export * from "./slider";
+export * from "./imageBasedSlider";
+
 export * from "./statics";

+ 77 - 297
gui/src/2D/controls/slider.ts

@@ -1,25 +1,28 @@
-import { Control } from "./control";
-import { ValueAndUnit } from "../valueAndUnit";
-import { Observable, Vector2 } from "babylonjs";
 import { Measure } from "../measure";
+import { BaseSlider } from "./baseSlider";
 
 /**
  * Class used to create slider controls
  */
-export class Slider extends Control {
-    private _thumbWidth = new ValueAndUnit(20, ValueAndUnit.UNITMODE_PIXEL, false);
-    private _minimum = 0;
-    private _maximum = 100;
-    private _value = 50;
-    private _isVertical = false;
+export class Slider extends BaseSlider {
     private _background = "black";
     private _borderColor = "white";
-    private _barOffset = new ValueAndUnit(5, ValueAndUnit.UNITMODE_PIXEL, false);
     private _isThumbCircle = false;
-    private _isThumbClamped = false;
+    private _displayThumb = true;
 
-    /** Observable raised when the sldier value changes */
-    public onValueChangedObservable = new Observable<number>();
+    /** Gets or sets a boolean indicating if the thumb must be rendered */
+    public get displayThumb(): boolean {
+        return this._displayThumb;
+    }
+
+    public set displayThumb(value: boolean) {
+        if (this._displayThumb === value) {
+            return;
+        }
+
+        this._displayThumb = value;
+        this._markAsDirty();
+    }
 
     /** Gets or sets border color */
     public get borderColor(): string {
@@ -49,109 +52,6 @@ export class Slider extends Control {
         this._markAsDirty();
     }
 
-    /** Gets or sets main bar offset */
-    public get barOffset(): string | number {
-        return this._barOffset.toString(this._host);
-    }
-
-    /** Gets main bar offset in pixels*/
-    public get barOffsetInPixels(): number {
-        return this._barOffset.getValueInPixel(this._host, this._cachedParentMeasure.width);
-    }
-
-    public set barOffset(value: string | number) {
-        if (this._barOffset.toString(this._host) === value) {
-            return;
-        }
-
-        if (this._barOffset.fromString(value)) {
-            this._markAsDirty();
-        }
-    }
-
-    /** Gets or sets thumb width */
-    public get thumbWidth(): string | number {
-        return this._thumbWidth.toString(this._host);
-    }
-
-    /** Gets thumb width in pixels */
-    public get thumbWidthInPixels(): number {
-        return this._thumbWidth.getValueInPixel(this._host, this._cachedParentMeasure.width);
-    }
-
-    public set thumbWidth(value: string | number) {
-        if (this._thumbWidth.toString(this._host) === value) {
-            return;
-        }
-
-        if (this._thumbWidth.fromString(value)) {
-            this._markAsDirty();
-        }
-    }
-
-    /** Gets or sets minimum value */
-    public get minimum(): number {
-        return this._minimum;
-    }
-
-    public set minimum(value: number) {
-        if (this._minimum === value) {
-            return;
-        }
-
-        this._minimum = value;
-        this._markAsDirty();
-
-        this.value = Math.max(Math.min(this.value, this._maximum), this._minimum);
-    }
-
-    /** Gets or sets maximum value */
-    public get maximum(): number {
-        return this._maximum;
-    }
-
-    public set maximum(value: number) {
-        if (this._maximum === value) {
-            return;
-        }
-
-        this._maximum = value;
-        this._markAsDirty();
-
-        this.value = Math.max(Math.min(this.value, this._maximum), this._minimum);
-    }
-
-    /** Gets or sets current value */
-    public get value(): number {
-        return this._value;
-    }
-
-    public set value(value: number) {
-        value = Math.max(Math.min(value, this._maximum), this._minimum);
-
-        if (this._value === value) {
-            return;
-        }
-
-        this._value = value;
-        this._markAsDirty();
-        this.onValueChangedObservable.notifyObservers(this._value);
-    }
-
-    /**Gets or sets a boolean indicating if the slider should be vertical or horizontal */
-    public get isVertical(): boolean {
-        return this._isVertical;
-    }
-
-    public set isVertical(value: boolean) {
-        if (this._isVertical === value) {
-            return;
-        }
-
-        this._isVertical = value;
-        this._markAsDirty();
-    }
-
     /** Gets or sets a boolean indicating if the thumb should be round or square */
     public get isThumbCircle(): boolean {
         return this._isThumbCircle;
@@ -166,122 +66,44 @@ export class Slider extends Control {
         this._markAsDirty();
     }
 
-    /** Gets or sets a value indicating if the thumb can go over main bar extends */
-    public get isThumbClamped(): boolean {
-        return this._isThumbClamped;
-    }
-
-    public set isThumbClamped(value: boolean) {
-        if (this._isThumbClamped === value) {
-            return;
-        }
-
-        this._isThumbClamped = value;
-        this._markAsDirty();
-    }
-
     /**
      * Creates a new Slider
      * @param name defines the control name
      */
     constructor(public name?: string) {
         super(name);
-
-        this.isPointerBlocker = true;
     }
 
     protected _getTypeName(): string {
         return "Slider";
     }
 
-    protected _getThumbThickness(type: string, backgroundLength: number): number {
-        var thumbThickness = 0;
-        switch (type) {
-            case "circle":
-                if (this._thumbWidth.isPixel) {
-                    thumbThickness = Math.max(this._thumbWidth.getValue(this._host), backgroundLength);
-                }
-                else {
-                    thumbThickness = backgroundLength * this._thumbWidth.getValue(this._host);
-                }
-                break;
-            case "rectangle":
-                if (this._thumbWidth.isPixel) {
-                    thumbThickness = Math.min(this._thumbWidth.getValue(this._host), backgroundLength);
-                }
-                else {
-                    thumbThickness = backgroundLength * this._thumbWidth.getValue(this._host);
-                }
-        }
-        return thumbThickness;
-    }
-
     public _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
         context.save();
 
         this._applyStates(context);
         if (this._processMeasures(parentMeasure, context)) {
-            // Main bar
-            var effectiveBarOffset = 0;
-            var type = this.isThumbCircle ? "circle" : "rectangle";
-            var left = this._currentMeasure.left;
-            var top = this._currentMeasure.top;
-            var width = this._currentMeasure.width;
-            var height = this._currentMeasure.height;
-
-            var backgroundBoxLength = Math.max(this._currentMeasure.width, this._currentMeasure.height);
-            var backgroundBoxThickness = Math.min(this._currentMeasure.width, this._currentMeasure.height);
 
-            var effectiveThumbThickness = this._getThumbThickness(type, backgroundBoxThickness);
-            backgroundBoxLength -= effectiveThumbThickness;
+            this._prepareRenderingData(this.isThumbCircle ? "circle" : "rectangle");
+            var left = this._renderLeft;
+            var top = this._renderTop;
+            var width = this._renderWidth;
+            var height = this._renderHeight;
 
             var radius = 0;
 
-            //throw error when height is less than width for vertical slider
-            if ((this._isVertical && this._currentMeasure.height < this._currentMeasure.width)) {
-                console.error("Height should be greater than width");
-                return;
-            }
-            if (this._barOffset.isPixel) {
-                effectiveBarOffset = Math.min(this._barOffset.getValue(this._host), backgroundBoxThickness);
-            }
-            else {
-                effectiveBarOffset = backgroundBoxThickness * this._barOffset.getValue(this._host);
-            }
-
-            backgroundBoxThickness -= (effectiveBarOffset * 2);
-
-            if (this._isVertical) {
-                left += effectiveBarOffset;
-                if (!this.isThumbClamped) {
-                    top += (effectiveThumbThickness / 2);
-                }
-
-                height = backgroundBoxLength;
-                width = backgroundBoxThickness;
-
-            }
-            else {
-                top += effectiveBarOffset;
-                if (!this.isThumbClamped) {
-                    left += (effectiveThumbThickness / 2);
-                }
-                height = backgroundBoxThickness;
-                width = backgroundBoxLength;
-            }
-
             if (this.isThumbClamped && this.isThumbCircle) {
-                if (this._isVertical) {
-                    top += (effectiveThumbThickness / 2);
+                if (this.isVertical) {
+                    top += (this._effectiveThumbThickness / 2);
                 }
                 else {
-                    left += (effectiveThumbThickness / 2);
+                    left += (this._effectiveThumbThickness / 2);
                 }
 
-                radius = backgroundBoxThickness / 2;
+                radius = this._backgroundBoxThickness / 2;
             }
             else {
-                radius = (effectiveThumbThickness - effectiveBarOffset) / 2;
+                radius = (this._effectiveThumbThickness - this._effectiveBarOffset) / 2;
             }
 
             if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
@@ -291,19 +113,19 @@ export class Slider extends Control {
                 context.shadowOffsetY = this.shadowOffsetY;
             }
 
-            var thumbPosition = (this._isVertical) ? ((this._maximum - this._value) / (this._maximum - this._minimum)) * backgroundBoxLength : ((this._value - this._minimum) / (this._maximum - this._minimum)) * backgroundBoxLength;
+            const thumbPosition = this._getThumbPosition();
             context.fillStyle = this._background;
 
-            if (this._isVertical) {
+            if (this.isVertical) {
                 if (this.isThumbClamped) {
                     if (this.isThumbCircle) {
                         context.beginPath();
-                        context.arc(left + backgroundBoxThickness / 2, top, radius, Math.PI, 2 * Math.PI);
+                        context.arc(left + this._backgroundBoxThickness / 2, top, radius, Math.PI, 2 * Math.PI);
                         context.fill();
                         context.fillRect(left, top, width, height);
                     }
                     else {
-                        context.fillRect(left, top, width, height + effectiveThumbThickness);
+                        context.fillRect(left, top, width, height + this._effectiveThumbThickness);
                     }
                 }
                 else {
@@ -314,12 +136,12 @@ export class Slider extends Control {
                 if (this.isThumbClamped) {
                     if (this.isThumbCircle) {
                         context.beginPath();
-                        context.arc(left + backgroundBoxLength, top + (backgroundBoxThickness / 2), radius, 0, 2 * Math.PI);
+                        context.arc(left + this._backgroundBoxLength, top + (this._backgroundBoxThickness / 2), radius, 0, 2 * Math.PI);
                         context.fill();
                         context.fillRect(left, top, width, height);
                     }
                     else {
-                        context.fillRect(left, top, width + effectiveThumbThickness, height);
+                        context.fillRect(left, top, width + this._effectiveThumbThickness, height);
                     }
                 }
                 else {
@@ -333,12 +155,13 @@ export class Slider extends Control {
                 context.shadowOffsetY = 0;
             }
 
+            // Value bar
             context.fillStyle = this.color;
-            if (this._isVertical) {
+            if (this.isVertical) {
                 if (this.isThumbClamped) {
                     if (this.isThumbCircle) {
                         context.beginPath();
-                        context.arc(left + backgroundBoxThickness / 2, top + backgroundBoxLength, radius, 0, 2 * Math.PI);
+                        context.arc(left + this._backgroundBoxThickness / 2, top + this._backgroundBoxLength, radius, 0, 2 * Math.PI);
                         context.fill();
                         context.fillRect(left, top + thumbPosition, width, height - thumbPosition);
                     }
@@ -354,7 +177,7 @@ export class Slider extends Control {
                 if (this.isThumbClamped) {
                     if (this.isThumbCircle) {
                         context.beginPath();
-                        context.arc(left, top + backgroundBoxThickness / 2, radius, 0, 2 * Math.PI);
+                        context.arc(left, top + this._backgroundBoxThickness / 2, radius, 0, 2 * Math.PI);
                         context.fill();
                         context.fillRect(left, top, thumbPosition, height);
                     }
@@ -367,96 +190,53 @@ export class Slider extends Control {
                 }
             }
 
-            if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
-                context.shadowColor = this.shadowColor;
-                context.shadowBlur = this.shadowBlur;
-                context.shadowOffsetX = this.shadowOffsetX;
-                context.shadowOffsetY = this.shadowOffsetY;
-            }
-            if (this._isThumbCircle) {
-                context.beginPath();
-                if (this._isVertical) {
-                    context.arc(left + backgroundBoxThickness / 2, top + thumbPosition, radius, 0, 2 * Math.PI);
-                }
-                else {
-                    context.arc(left + thumbPosition, top + (backgroundBoxThickness / 2), radius, 0, 2 * Math.PI);
-                }
-                context.fill();
+            // Thumb
+            if (this.displayThumb) {
                 if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
-                    context.shadowBlur = 0;
-                    context.shadowOffsetX = 0;
-                    context.shadowOffsetY = 0;
-                }
-                context.strokeStyle = this._borderColor;
-                context.stroke();
-            }
-            else {
-                if (this._isVertical) {
-                    context.fillRect(left - effectiveBarOffset, this._currentMeasure.top + thumbPosition, this._currentMeasure.width, effectiveThumbThickness);
-                }
-                else {
-                    context.fillRect(this._currentMeasure.left + thumbPosition, this._currentMeasure.top, effectiveThumbThickness, this._currentMeasure.height);
-                }
-                if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
-                    context.shadowBlur = 0;
-                    context.shadowOffsetX = 0;
-                    context.shadowOffsetY = 0;
-                }
-                context.strokeStyle = this._borderColor;
-                if (this._isVertical) {
-                    context.strokeRect(left - effectiveBarOffset, this._currentMeasure.top + thumbPosition, this._currentMeasure.width, effectiveThumbThickness);
+                    context.shadowColor = this.shadowColor;
+                    context.shadowBlur = this.shadowBlur;
+                    context.shadowOffsetX = this.shadowOffsetX;
+                    context.shadowOffsetY = this.shadowOffsetY;
+                }
+                if (this._isThumbCircle) {
+                    context.beginPath();
+                    if (this.isVertical) {
+                        context.arc(left + this._backgroundBoxThickness / 2, top + thumbPosition, radius, 0, 2 * Math.PI);
+                    }
+                    else {
+                        context.arc(left + thumbPosition, top + (this._backgroundBoxThickness / 2), radius, 0, 2 * Math.PI);
+                    }
+                    context.fill();
+                    if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
+                        context.shadowBlur = 0;
+                        context.shadowOffsetX = 0;
+                        context.shadowOffsetY = 0;
+                    }
+                    context.strokeStyle = this._borderColor;
+                    context.stroke();
                 }
                 else {
-                    context.strokeRect(this._currentMeasure.left + thumbPosition, this._currentMeasure.top, effectiveThumbThickness, this._currentMeasure.height);
+                    if (this.isVertical) {
+                        context.fillRect(left - this._effectiveBarOffset, this._currentMeasure.top + thumbPosition, this._currentMeasure.width, this._effectiveThumbThickness);
+                    }
+                    else {
+                        context.fillRect(this._currentMeasure.left + thumbPosition, this._currentMeasure.top, this._effectiveThumbThickness, this._currentMeasure.height);
+                    }
+                    if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
+                        context.shadowBlur = 0;
+                        context.shadowOffsetX = 0;
+                        context.shadowOffsetY = 0;
+                    }
+                    context.strokeStyle = this._borderColor;
+                    if (this.isVertical) {
+                        context.strokeRect(left - this._effectiveBarOffset, this._currentMeasure.top + thumbPosition, this._currentMeasure.width, this._effectiveThumbThickness);
+                    }
+                    else {
+                        context.strokeRect(this._currentMeasure.left + thumbPosition, this._currentMeasure.top, this._effectiveThumbThickness, this._currentMeasure.height);
+                    }
                 }
             }
         }
         context.restore();
     }
-
-    // Events
-    private _pointerIsDown = false;
-
-    private _updateValueFromPointer(x: number, y: number): void {
-        if (this.rotation != 0) {
-            this._invertTransformMatrix.transformCoordinates(x, y, this._transformedPosition);
-            x = this._transformedPosition.x;
-            y = this._transformedPosition.y;
-        }
-
-        if (this._isVertical) {
-            this.value = this._minimum + (1 - ((y - this._currentMeasure.top) / this._currentMeasure.height)) * (this._maximum - this._minimum);
-        }
-        else {
-            this.value = this._minimum + ((x - this._currentMeasure.left) / this._currentMeasure.width) * (this._maximum - this._minimum);
-        }
-    }
-
-    public _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean {
-        if (!super._onPointerDown(target, coordinates, pointerId, buttonIndex)) {
-            return false;
-        }
-
-        this._pointerIsDown = true;
-
-        this._updateValueFromPointer(coordinates.x, coordinates.y);
-        this._host._capturingControl[pointerId] = this;
-
-        return true;
-    }
-
-    public _onPointerMove(target: Control, coordinates: Vector2): void {
-        if (this._pointerIsDown) {
-            this._updateValueFromPointer(coordinates.x, coordinates.y);
-        }
-
-        super._onPointerMove(target, coordinates);
-    }
-
-    public _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void {
-        this._pointerIsDown = false;
-
-        delete this._host._capturingControl[pointerId];
-        super._onPointerUp(target, coordinates, pointerId, buttonIndex, notifyClick);
-    }
 }

+ 14 - 0
gui/src/2D/measure.ts

@@ -34,6 +34,20 @@ export class Measure {
     }
 
     /**
+     * Copy from a group of 4 floats
+     * @param left defines left coordinate
+     * @param top defines top coordinate
+     * @param width defines width dimension
+     * @param height defines height dimension
+     */
+    public copyFromFloats(left: number, top: number, width: number, height: number): void {
+        this.left = left;
+        this.top = top;
+        this.width = width;
+        this.height = height;
+    }
+
+    /**
      * Check equality between this measure and another one
      * @param other defines the other measures
      * @returns true if both measures are equals

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

@@ -587,6 +587,11 @@ module BABYLON {
 
                 this.onValidatedObservable.notifyObservers(result);
                 this.onValidatedObservable.clear();
+            }, (reason) => {
+                this._endPerformanceCounter("Validate JSON");
+
+                Tools.Warn(`Failed to validate: ${reason}`);
+                this.onValidatedObservable.clear();
             });
         }
 

+ 1 - 1
readme.md

@@ -118,7 +118,7 @@ If you want to contribute, please read our [contribution guidelines](https://git
 - 3DS Max [exporter](https://github.com/BabylonJS/Exporters/tree/master/3ds%20Max) can be used to generate a .babylon file from 3DS Max
 - Maya [exporter](https://github.com/BabylonJS/Exporters/tree/master/Maya) can be used to generate a .babylon file from 3DS Max
 - Blender [exporter](https://github.com/BabylonJS/Exporters/tree/master/Blender) can be used to generate a .babylon file from Blender 3d
-- Unity 5 [exporter](https://github.com/BabylonJS/Exporters/tree/master/Unity%205) can be used to export your geometries from Unity 5 scene editor(animations are supported)
+- Unity 5[ (deprecated) exporter](https://github.com/BabylonJS/Exporters/tree/master/Unity) can be used to export your geometries from Unity 5 scene editor(animations are supported)
 - [glTF Tools](https://github.com/KhronosGroup/glTF#gltf-tools) by KhronosGroup
 
 ## Features

+ 2 - 0
src/Cameras/babylon.arcRotateCamera.ts

@@ -814,9 +814,11 @@ module BABYLON {
 
             if (this.lowerRadiusLimit !== null && this.radius < this.lowerRadiusLimit) {
                 this.radius = this.lowerRadiusLimit;
+                this.inertialRadiusOffset = 0;
             }
             if (this.upperRadiusLimit !== null && this.radius > this.upperRadiusLimit) {
                 this.radius = this.upperRadiusLimit;
+                this.inertialRadiusOffset = 0;
             }
         }
 

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

@@ -343,7 +343,7 @@ module BABYLON {
                 return false;
             }
 
-            if (!material.isReady(subMesh.getMesh(), useInstances)) {
+            if (!material.isReadyForSubMesh(subMesh.getMesh(), subMesh, useInstances)) {
                 return false;
             }
 
@@ -452,7 +452,7 @@ module BABYLON {
 
             // Check
             if (!currentEffect.isReady()) {
-                return;
+                return;
             }
 
             for (var i = 0; i < this._postProcesses.length; i++) {

+ 38 - 36
src/Math/babylon.math.ts

@@ -4613,6 +4613,15 @@ module BABYLON {
          * @returns the current matrix
          */
         public multiplyToRef(other: Readonly<Matrix>, result: Matrix): Matrix {
+            if (this._isIdentity) {
+                result.copyFrom(other);
+                return this;
+            }
+            if ((other as Matrix)._isIdentity) {
+                result.copyFrom(this);
+                return this;
+            }
+
             this.multiplyToArray(other, result._m, 0);
             result._markAsUpdated();
             return this;
@@ -4626,15 +4635,6 @@ module BABYLON {
          * @returns the current matrix
          */
         public multiplyToArray(other: Readonly<Matrix>, result: Float32Array, offset: number): Matrix {
-            if (this._isIdentity) {
-                other.copyToArray(result, offset);
-                return this;
-            }
-            if ((other as Matrix)._isIdentity) {
-                this.copyToArray(result, offset);
-                return this;
-            }
-
             const m = this._m;
             const otherM = other.m;
             var tm0 = m[0], tm1 = m[1], tm2 = m[2], tm3 = m[3];
@@ -4822,7 +4822,6 @@ module BABYLON {
          */
         public transposeToRef(result: Matrix): Matrix {
             Matrix.TransposeToRef(this, result);
-
             return this;
         }
 
@@ -4911,7 +4910,7 @@ module BABYLON {
          * @returns a new matrix sets to the extracted rotation matrix from the current one
          */
         public getRotationMatrix(): Matrix {
-            var result = Matrix.Identity();
+            var result = new Matrix();
             this.getRotationMatrixToRef(result);
             return result;
         }
@@ -4977,6 +4976,7 @@ module BABYLON {
             Matrix.FromArrayToRef(array, offset, result);
             return result;
         }
+
         /**
          * Copy the content of an array into a given matrix
          * @param array defines the source array
@@ -5001,7 +5001,6 @@ module BABYLON {
             for (var index = 0; index < 16; index++) {
                 result._m[index] = array[index + offset] * scale;
             }
-
             result._markAsUpdated();
         }
 
@@ -5077,7 +5076,7 @@ module BABYLON {
             m[4] = initialM21; m[5] = initialM22; m[6] = initialM23; m[7] = initialM24;
             m[8] = initialM31; m[9] = initialM32; m[10] = initialM33; m[11] = initialM34;
             m[12] = initialM41; m[13] = initialM42; m[14] = initialM43; m[15] = initialM44;
-
+            result._markAsUpdated();
             return result;
         }
 
@@ -5089,7 +5088,7 @@ module BABYLON {
          * @returns a new matrix
          */
         public static Compose(scale: Vector3, rotation: Quaternion, translation: Vector3): Matrix {
-            var result = Matrix.Identity();
+            var result = new Matrix();
             Matrix.ComposeToRef(scale, rotation, translation, result);
             return result;
         }
@@ -5363,7 +5362,7 @@ module BABYLON {
          * @returns the new matrix
          */
         public static Translation(x: number, y: number, z: number): Matrix {
-            var result = Matrix.Identity();
+            var result = new Matrix();
             Matrix.TranslationToRef(x, y, z, result);
             return result;
         }
@@ -5633,9 +5632,7 @@ module BABYLON {
          */
         public static OrthoOffCenterLH(left: number, right: number, bottom: number, top: number, znear: number, zfar: number): Matrix {
             var matrix = new Matrix();
-
             Matrix.OrthoOffCenterLHToRef(left, right, bottom, top, znear, zfar, matrix);
-
             return matrix;
         }
 
@@ -5668,7 +5665,7 @@ module BABYLON {
                 result
             );
 
-            result._updateIdentityStatus(a === 1 && b === 1 && c === 1 && d === 0 && i0 === 0 && i1 === 0);
+            result._markAsUpdated();
         }
 
         /**
@@ -5699,7 +5696,7 @@ module BABYLON {
          */
         public static OrthoOffCenterRHToRef(left: number, right: number, bottom: number, top: number, znear: number, zfar: number, result: Matrix): void {
             Matrix.OrthoOffCenterLHToRef(left, right, bottom, top, znear, zfar, result);
-            result._m[10] *= -1.0;
+            result._m[10] *= -1; // No need to call _markAsUpdated as previous function already called it and let _isIdentityDirty to true
         }
 
         /**
@@ -5843,16 +5840,17 @@ module BABYLON {
             var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0);
             var xScale = 2.0 / (leftTan + rightTan);
             var yScale = 2.0 / (upTan + downTan);
-            result._m[0] = xScale;
-            result._m[1] = result._m[2] = result._m[3] = result._m[4] = 0.0;
-            result._m[5] = yScale;
-            result._m[6] = result._m[7] = 0.0;
-            result._m[8] = ((leftTan - rightTan) * xScale * 0.5);
-            result._m[9] = -((upTan - downTan) * yScale * 0.5);
-            result._m[10] = -zfar / (znear - zfar);
-            result._m[11] = 1.0 * rightHandedFactor;
-            result._m[12] = result._m[13] = result._m[15] = 0.0;
-            result._m[14] = -(2.0 * zfar * znear) / (zfar - znear);
+            const m = result._m;
+            m[0] = xScale;
+            m[1] = m[2] = m[3] = m[4] = 0.0;
+            m[5] = yScale;
+            m[6] = m[7] = 0.0;
+            m[8] = ((leftTan - rightTan) * xScale * 0.5);
+            m[9] = -((upTan - downTan) * yScale * 0.5);
+            m[10] = -zfar / (znear - zfar);
+            m[11] = 1.0 * rightHandedFactor;
+            m[12] = m[13] = m[15] = 0.0;
+            m[14] = -(2.0 * zfar * znear) / (zfar - znear);
 
             result._markAsUpdated();
         }
@@ -5873,12 +5871,16 @@ module BABYLON {
             var cx = viewport.x;
             var cy = viewport.y;
 
-            var viewportMatrix = Matrix.FromValues(cw / 2.0, 0.0, 0.0, 0.0,
-                0.0, -ch / 2.0, 0.0, 0.0,
-                0.0, 0.0, zmax - zmin, 0.0,
-                cx + cw / 2.0, ch / 2.0 + cy, zmin, 1);
+            var viewportMatrix = Matrix.FromValues(
+                     cw / 2.0,           0.0,         0.0, 0.0,
+                          0.0,     -ch / 2.0,         0.0, 0.0,
+                          0.0,           0.0, zmax - zmin, 0.0,
+                cx + cw / 2.0, ch / 2.0 + cy,        zmin, 1.0);
 
-            return world.multiply(view).multiply(projection).multiply(viewportMatrix);
+            var matrix = MathTmp.Matrix[0];
+            world.multiplyToRef(view, matrix);
+            matrix.multiplyToRef(projection, matrix);
+            return matrix.multiply(viewportMatrix);
         }
 
         /**
@@ -5912,9 +5914,7 @@ module BABYLON {
          */
         public static Transpose(matrix: Matrix): Matrix {
             var result = new Matrix();
-
             Matrix.TransposeToRef(matrix, result);
-
             return result;
         }
 
@@ -5945,6 +5945,8 @@ module BABYLON {
             rm[13] = mm[7];
             rm[14] = mm[11];
             rm[15] = mm[15];
+            // identity-ness does not change when transposing
+            result._updateIdentityStatus(matrix._isIdentity, matrix._isIdentityDirty);
         }
 
         /**

+ 25 - 9
src/babylon.scene.ts

@@ -1748,12 +1748,19 @@ module BABYLON {
          * The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
          * @param pickResult pickingInfo of the object wished to simulate pointer event on
          * @param pointerEventInit pointer event state to be used when simulating the pointer event (eg. pointer id for multitouch)
+         * @param doubleTap indicates that the pointer up event should be considered as part of a double click (false by default)
          * @returns the current scene
          */
-        public simulatePointerUp(pickResult: PickingInfo, pointerEventInit?: PointerEventInit): Scene {
+        public simulatePointerUp(pickResult: PickingInfo, pointerEventInit?: PointerEventInit, doubleTap?: boolean): Scene {
             let evt = new PointerEvent("pointerup", pointerEventInit);
             let clickInfo = new ClickInfo();
 
+            if (doubleTap) {
+                clickInfo.doubleClick = true;
+            } else {
+                clickInfo.singleClick = true;
+            }
+
             if (this._checkPrePointerObservable(pickResult, evt, PointerEventTypes.POINTERUP)) {
                 return this;
             }
@@ -1802,7 +1809,7 @@ module BABYLON {
                 this._pickedDownMesh.actionManager.processTrigger(ActionManager.OnPickOutTrigger, ActionEvent.CreateNew(this._pickedDownMesh, evt));
             }
 
-            let type = PointerEventTypes.POINTERUP;
+            let type = 0;
             if (this.onPointerObservable.hasObservers()) {
                 if (!clickInfo.ignore && !clickInfo.hasSwiped) {
                     if (clickInfo.singleClick && this.onPointerObservable.hasSpecificMask(PointerEventTypes.POINTERTAP)) {
@@ -1811,10 +1818,20 @@ module BABYLON {
                     else if (clickInfo.doubleClick && this.onPointerObservable.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP)) {
                         type = PointerEventTypes.POINTERDOUBLETAP;
                     }
+                    if (type) {
+                        let pi = new PointerInfo(type, evt, pickResult);
+                        this._setRayOnPointerInfo(pi);
+                        this.onPointerObservable.notifyObservers(pi, type);
+                    }
+                }
+
+                if (!clickInfo.ignore) {
+                    type = PointerEventTypes.POINTERUP;
+
+                    let pi = new PointerInfo(type, evt, pickResult);
+                    this._setRayOnPointerInfo(pi);
+                    this.onPointerObservable.notifyObservers(pi, type);
                 }
-                let pi = new PointerInfo(type, evt, pickResult);
-                this._setRayOnPointerInfo(pi);
-                this.onPointerObservable.notifyObservers(pi, type);
             }
 
             if (this.onPointerUp && !clickInfo.ignore) {
@@ -1981,8 +1998,9 @@ module BABYLON {
                     }
                 }
 
-                clickInfo.ignore = needToIgnoreNext;
-                cb(clickInfo, this._currentPickResult);
+                if (!needToIgnoreNext) {
+                    cb(clickInfo, this._currentPickResult);
+                }
             };
 
             this._onPointerMove = (evt: PointerEvent) => {
@@ -2080,8 +2098,6 @@ module BABYLON {
                                     }
                                 }
                             }
-                        }
-                        else {
                             if (this._checkPrePointerObservable(null, evt, PointerEventTypes.POINTERUP)) {
                                 return;
                             }

BIN
tests/validation/ReferenceImages/pointers.png


+ 6 - 0
tests/validation/config.json

@@ -2,6 +2,12 @@
   "root": "https://rawgit.com/BabylonJS/Website/master",
   "tests": [
     {
+      "title": "Pointers",
+      "playgroundId": "#1GLEJK#5",
+      "referenceImage": "pointers.png",
+      "excludeFromAutomaticTesting": true
+    },
+    {
       "title": "LineEdgesRenderer",
       "playgroundId": "#T90MQ4#1",
       "renderCount": 50,

+ 2 - 2
tests/validation/validation.js

@@ -232,7 +232,7 @@ function runTest(index, done) {
             return;
         }
 
-        var snippetUrl = "//babylonjs-api2.azurewebsites.net/snippets";
+        var snippetUrl = "https://snippet.babylonjs.com";
         var pgRoot = "/Playground"
 
         var retryTime = 500;
@@ -258,7 +258,7 @@ function runTest(index, done) {
                 if (xmlHttp.readyState === 4) {
                     try {
                         xmlHttp.onreadystatechange = null;
-                        var snippet = JSON.parse(xmlHttp.responseText)[0];
+                        var snippet = JSON.parse(xmlHttp.responseText);
                         var code = JSON.parse(snippet.jsonPayload).code.toString();
                         code = code.replace(/\/textures\//g, pgRoot + "/textures/");
                         code = code.replace(/"textures\//g, "\"" + pgRoot + "/textures/");