Prechádzať zdrojové kódy

Merge remote-tracking branch 'BabylonJS/master'

MackeyK24 7 rokov pred
rodič
commit
34eb85df3e
73 zmenil súbory, kde vykonal 43636 pridanie a 58958 odobranie
  1. BIN
      Playground/LogoPBT.png
  2. 21097 15435
      Playground/babylon.d.txt
  3. 27 0
      Playground/css/index.css
  4. 1 0
      Playground/debug.html
  5. 50 72
      Playground/full.html
  6. 1 0
      Playground/index-local.html
  7. 406 330
      Playground/index.html
  8. 1 0
      Playground/indexStable.html
  9. 2 0
      Playground/js/index.js
  10. 432 0
      Playground/js/pbt.js
  11. 14 0
      Playground/package-lock.json
  12. 6 0
      Tools/Gulp/config.json
  13. 14 4
      Tools/Gulp/gulpfile.js
  14. BIN
      Viewer/assets/img/close.png
  15. BIN
      Viewer/assets/img/fullscreen.png
  16. BIN
      Viewer/assets/img/help-circle.png
  17. BIN
      Viewer/assets/img/loading.png
  18. 210 0
      Viewer/assets/pep.min.js
  19. 2 2
      Viewer/assets/templates/default/navbar.html
  20. 2 4
      Viewer/dist/domExample.html
  21. 5622 7086
      Viewer/dist/viewer.js
  22. 38 0
      Viewer/dist/viewer.min.js
  23. 9 11
      Viewer/package.json
  24. 3 5
      Viewer/src/configuration/configuration.ts
  25. 4 4
      Viewer/src/configuration/loader.ts
  26. 0 2
      Viewer/src/configuration/mappers.ts
  27. 8 12
      Viewer/src/configuration/types/default.ts
  28. 3 1
      Viewer/src/index.ts
  29. 15 1
      Viewer/src/templateManager.ts
  30. 6 4
      Viewer/src/viewer/defaultViewer.ts
  31. 4 0
      Viewer/src/viewer/viewerManager.ts
  32. 9 15
      Viewer/webpack.config.js
  33. 2892 2870
      dist/preview release/babylon.d.ts
  34. 10 10
      dist/preview release/babylon.js
  35. 43 11
      dist/preview release/babylon.max.js
  36. 0 20595
      dist/preview release/babylon.module.d.ts
  37. 11 11
      dist/preview release/babylon.worker.js
  38. 8192 8188
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  39. 8 8
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  40. 24 11
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  41. 4068 4069
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts
  42. 4 1
      dist/preview release/gui/babylon.gui.js
  43. 3 3
      dist/preview release/gui/babylon.gui.min.js
  44. 14 14
      dist/preview release/inspector/babylon.inspector.bundle.js
  45. 3 0
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  46. 17 1
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  47. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  48. 3 0
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  49. 17 1
      dist/preview release/loaders/babylon.glTFFileLoader.js
  50. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  51. 1 1
      dist/preview release/loaders/babylon.objFileLoader.min.js
  52. 17 1
      dist/preview release/loaders/babylonjs.loaders.js
  53. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  54. 3 0
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  55. 3 0
      dist/preview release/what's new.md
  56. 4 0
      gui/src/advancedDynamicTexture.ts
  57. 28 1
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  58. 1 2
      package.json
  59. 2 2
      src/Helpers/babylon.environmentHelper.ts
  60. 6 6
      src/Loading/babylon.sceneLoader.ts
  61. 3 3
      src/Math/babylon.math.ts
  62. 10 3
      src/Mesh/babylon.linesMesh.ts
  63. 10 2
      src/Mesh/babylon.mesh.vertexData.ts
  64. 38 15
      src/Mesh/babylon.meshBuilder.ts
  65. 60 31
      src/Tools/babylon.tools.ts
  66. 105 102
      src/babylon.scene.ts
  67. BIN
      tests/validation/ReferenceImages/gltfMaterial.png
  68. BIN
      tests/validation/ReferenceImages/gltfMaterialAlpha.png
  69. BIN
      tests/validation/ReferenceImages/gltfMaterialMetallicRoughness.png
  70. BIN
      tests/validation/ReferenceImages/gltfMaterialSpecularGlossiness.png
  71. BIN
      tests/validation/ReferenceImages/gltfPrimitiveAttribute.png
  72. BIN
      tests/validation/ReferenceImages/gltfTextureSampler.png
  73. 42 0
      tests/validation/config.json

BIN
Playground/LogoPBT.png


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 21097 - 15435
Playground/babylon.d.txt


+ 27 - 0
Playground/css/index.css

@@ -91,6 +91,33 @@ body {
 .wrapper .gutter.gutter-horizontal {
     background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==");
 }
+
+.pbt-fade {
+    opacity:0.5
+}
+
+.pbt-darken {
+    opacity:1
+}
+
+.pbt-back-highlight {
+    background-color:#CDC8F9;
+}
+
+.pbt-back-white{ 
+    background-color: white
+}
+
+.pbt-margin-decor-on {
+    background-color: #364249; 
+    width:5px;
+}
+
+.pbt-margin-decor-off {
+    background-color: #FF0000;
+    width:5px;
+}     
+
 .wrapper #jsEditor {
     padding-top:5px;
     height: calc(100% - 10px);

+ 1 - 0
Playground/debug.html

@@ -407,6 +407,7 @@
     <script src="https://code.jquery.com/jquery.js"></script>
 
     <script src="js/actions.js"></script>
+    <script src="js/pbt.js"></script>
     <script src="js/index.js"></script>
 </body>
 

+ 50 - 72
Playground/full.html

@@ -1,77 +1,55 @@
 <!DOCTYPE html>
 <html>
 
-<head>
-    <title>Babylon.js Playground</title>
-    <link rel="shortcut icon" href="https://www.babylonjs.com/img/favicon/favicon.ico">
-	<link rel="apple-touch-icon" sizes="57x57" href="https://www.babylonjs.com/img/favicon/apple-icon-57x57.png">
-	<link rel="apple-touch-icon" sizes="60x60" href="https://www.babylonjs.com/img/favicon/apple-icon-60x60.png">
-	<link rel="apple-touch-icon" sizes="72x72" href="https://www.babylonjs.com/img/favicon/apple-icon-72x72.png">
-	<link rel="apple-touch-icon" sizes="76x76" href="https://www.babylonjs.com/img/favicon/apple-icon-76x76.png">
-	<link rel="apple-touch-icon" sizes="114x114" href="https://www.babylonjs.com/img/favicon/apple-icon-114x114.png">
-	<link rel="apple-touch-icon" sizes="120x120" href="https://www.babylonjs.com/img/favicon/apple-icon-120x120.png">
-	<link rel="apple-touch-icon" sizes="144x144" href="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png">
-	<link rel="apple-touch-icon" sizes="152x152" href="https://www.babylonjs.com/img/favicon/apple-icon-152x152.png">
-	<link rel="apple-touch-icon" sizes="180x180" href="https://www.babylonjs.com/img/favicon/apple-icon-180x180.png">
-	<link rel="icon" type="image/png" sizes="192x192"  href="https://www.babylonjs.com/img/favicon/android-icon-192x192.png">
-	<link rel="icon" type="image/png" sizes="32x32" href="https://www.babylonjs.com/img/favicon/favicon-32x32.png">
-	<link rel="icon" type="image/png" sizes="96x96" href="https://www.babylonjs.com/img/favicon/favicon-96x96.png">
-	<link rel="icon" type="image/png" sizes="16x16" href="https://www.babylonjs.com/img/favicon/favicon-16x16.png">
-	<link rel="manifest" href="https://www.babylonjs.com/img/favicon/manifest.json">
-	<meta name="msapplication-TileColor" content="#ffffff">
-	<meta name="msapplication-TileImage" content="https://www.babylonjs.com/img/favicon/ms-icon-144x144.png">
-	<meta name="msapplication-config" content="https://www.babylonjs.com/img/favicon/browserconfig.xml">
-	<meta name="theme-color" content="#ffffff">
-
-    <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-    <!-- Babylon.js -->
-    <script src="https://preview.babylonjs.com/cannon.js"></script>
-    <script src="https://preview.babylonjs.com/Oimo.js"></script>
-    <script src="https://preview.babylonjs.com/babylon.js"></script>    
-    <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
-
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.fireMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.waterMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.lavaMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.normalMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.skyMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.triPlanarMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.terrainMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gradientMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.furMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gridMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.shadowOnlyMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.customMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.cellMaterial.min.js"></script>
-
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.brickProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.cloudProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.fireProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.grassProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.marbleProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.roadProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.starfieldProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.woodProceduralTexture.min.js"></script>
-
-    <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.asciiArtPostProcess.min.js"></script>
-    <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.digitalRainPostProcess.min.js"></script>
-
-    <script src="https://preview.babylonjs.com/loaders/babylon.glTFFileLoader.js"></script>
-    <script src="https://preview.babylonjs.com/loaders/babylon.objFileLoader.js"></script>
-    <script src="https://preview.babylonjs.com/loaders/babylon.stlFileLoader.js"></script>
-
-    <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
-    
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>    
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/canvas2D/dist/preview%20release/babylon.canvas2d.min.js"></script>
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/CompoundShader/src/babylonx.CompoundShader.js"></script>
-    <link href="frame.css" rel="stylesheet" />
-</head>
-
-<body>
-    <canvas touch-action="none" id="renderCanvas" tabindex="1"></canvas>
-    <script src="https://code.jquery.com/jquery.js"></script>
-    <script src="js/frame.js"></script>
-</body>
+    <head>
+        <title>Babylon.js Playground</title>
+        <link rel="shortcut icon" href="https://www.babylonjs.com/img/favicon/favicon.ico">
+        <link rel="apple-touch-icon" sizes="57x57" href="https://www.babylonjs.com/img/favicon/apple-icon-57x57.png">
+        <link rel="apple-touch-icon" sizes="60x60" href="https://www.babylonjs.com/img/favicon/apple-icon-60x60.png">
+        <link rel="apple-touch-icon" sizes="72x72" href="https://www.babylonjs.com/img/favicon/apple-icon-72x72.png">
+        <link rel="apple-touch-icon" sizes="76x76" href="https://www.babylonjs.com/img/favicon/apple-icon-76x76.png">
+        <link rel="apple-touch-icon" sizes="114x114" href="https://www.babylonjs.com/img/favicon/apple-icon-114x114.png">
+        <link rel="apple-touch-icon" sizes="120x120" href="https://www.babylonjs.com/img/favicon/apple-icon-120x120.png">
+        <link rel="apple-touch-icon" sizes="144x144" href="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png">
+        <link rel="apple-touch-icon" sizes="152x152" href="https://www.babylonjs.com/img/favicon/apple-icon-152x152.png">
+        <link rel="apple-touch-icon" sizes="180x180" href="https://www.babylonjs.com/img/favicon/apple-icon-180x180.png">
+        <link rel="icon" type="image/png" sizes="192x192" href="https://www.babylonjs.com/img/favicon/android-icon-192x192.png">
+        <link rel="icon" type="image/png" sizes="32x32" href="https://www.babylonjs.com/img/favicon/favicon-32x32.png">
+        <link rel="icon" type="image/png" sizes="96x96" href="https://www.babylonjs.com/img/favicon/favicon-96x96.png">
+        <link rel="icon" type="image/png" sizes="16x16" href="https://www.babylonjs.com/img/favicon/favicon-16x16.png">
+        <link rel="manifest" href="https://www.babylonjs.com/img/favicon/manifest.json">
+        <meta name="msapplication-TileColor" content="#ffffff">
+        <meta name="msapplication-TileImage" content="https://www.babylonjs.com/img/favicon/ms-icon-144x144.png">
+        <meta name="msapplication-config" content="https://www.babylonjs.com/img/favicon/browserconfig.xml">
+        <meta name="theme-color" content="#ffffff">
+
+        <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
+        <!-- Babylon.js -->
+        <script src="https://preview.babylonjs.com/cannon.js"></script>
+        <script src="https://preview.babylonjs.com/Oimo.js"></script>
+        <script src="https://preview.babylonjs.com/babylon.js"></script>
+        <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
+
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
+
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
+
+        <script src="https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
+
+        <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.js"></script>
+
+        <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
+
+        <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>
+        <script src="https://rawgit.com/BabylonJS/Extensions/master/canvas2D/dist/preview%20release/babylon.canvas2d.min.js"></script>
+        <script src="https://rawgit.com/BabylonJS/Extensions/master/CompoundShader/src/babylonx.CompoundShader.js"></script>
+        <link href="frame.css" rel="stylesheet" />
+    </head>
+
+    <body>
+        <canvas touch-action="none" id="renderCanvas" tabindex="1"></canvas>
+        <script src="https://code.jquery.com/jquery.js"></script>
+        <script src="js/frame.js"></script>
+    </body>
 
 </html>

+ 1 - 0
Playground/index-local.html

@@ -353,6 +353,7 @@
     <script src="https://code.jquery.com/jquery.js"></script>
 
     <script src="js/actions.js"></script>
+    <script src="js/pbt.js"></script>
     <script>
         BABYLONDEVTOOLS.Loader.require('js/index.js')
             .load();

+ 406 - 330
Playground/index.html

@@ -1,414 +1,490 @@
 <!DOCTYPE html>
 <html>
 
-<head>
-    <title>Babylon.js Playground</title>
-    <meta charset='utf-8' />
-    <meta name="viewport" content="width=device-width, user-scalable=no">
-    <link rel="shortcut icon" href="https://www.babylonjs.com/img/favicon/favicon.ico">
-	<link rel="apple-touch-icon" sizes="57x57" href="https://www.babylonjs.com/img/favicon/apple-icon-57x57.png">
-	<link rel="apple-touch-icon" sizes="60x60" href="https://www.babylonjs.com/img/favicon/apple-icon-60x60.png">
-	<link rel="apple-touch-icon" sizes="72x72" href="https://www.babylonjs.com/img/favicon/apple-icon-72x72.png">
-	<link rel="apple-touch-icon" sizes="76x76" href="https://www.babylonjs.com/img/favicon/apple-icon-76x76.png">
-	<link rel="apple-touch-icon" sizes="114x114" href="https://www.babylonjs.com/img/favicon/apple-icon-114x114.png">
-	<link rel="apple-touch-icon" sizes="120x120" href="https://www.babylonjs.com/img/favicon/apple-icon-120x120.png">
-	<link rel="apple-touch-icon" sizes="144x144" href="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png">
-	<link rel="apple-touch-icon" sizes="152x152" href="https://www.babylonjs.com/img/favicon/apple-icon-152x152.png">
-	<link rel="apple-touch-icon" sizes="180x180" href="https://www.babylonjs.com/img/favicon/apple-icon-180x180.png">
-	<link rel="icon" type="image/png" sizes="192x192"  href="https://www.babylonjs.com/img/favicon/android-icon-192x192.png">
-	<link rel="icon" type="image/png" sizes="32x32" href="https://www.babylonjs.com/img/favicon/favicon-32x32.png">
-	<link rel="icon" type="image/png" sizes="96x96" href="https://www.babylonjs.com/img/favicon/favicon-96x96.png">
-	<link rel="icon" type="image/png" sizes="16x16" href="https://www.babylonjs.com/img/favicon/favicon-16x16.png">
-	<link rel="manifest" href="https://www.babylonjs.com/img/favicon/manifest.json">
-	<meta name="msapplication-TileColor" content="#ffffff">
-	<meta name="msapplication-TileImage" content="https://www.babylonjs.com/img/favicon/ms-icon-144x144.png">
-	<meta name="msapplication-config" content="https://www.babylonjs.com/img/favicon/browserconfig.xml">
-	<meta name="theme-color" content="#ffffff">
-    
-    <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-    <!--For canvas/code separator-->
-    <script src="js/libs/split.js"></script>
-
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
-    <!-- jszip -->
-    <script src="js/libs/jszip.min.js"></script>
-    <script src="js/libs/fileSaver.js"></script>
-    <!--Monaco-->
-    <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
-    <!-- Babylon.js -->
-    <script src="https://preview.babylonjs.com/cannon.js"></script>
-    <script src="https://preview.babylonjs.com/Oimo.js"></script>
-    <script src="https://preview.babylonjs.com/babylon.js"></script>    
-    <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
-
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.fireMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.waterMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.lavaMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.normalMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.skyMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.triPlanarMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.terrainMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gradientMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.furMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gridMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.shadowOnlyMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.customMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.cellMaterial.min.js"></script>
-
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.brickProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.cloudProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.fireProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.grassProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.marbleProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.roadProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.starfieldProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.woodProceduralTexture.min.js"></script>
-
-    <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.asciiArtPostProcess.min.js"></script>
-    <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.digitalRainPostProcess.min.js"></script>
-
-    <script src="https://preview.babylonjs.com/loaders/babylon.glTFFileLoader.js"></script>
-    <script src="https://preview.babylonjs.com/loaders/babylon.objFileLoader.js"></script>
-    <script src="https://preview.babylonjs.com/loaders/babylon.stlFileLoader.js"></script>
-
-    <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
-
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/canvas2D/dist/preview%20release/babylon.canvas2d.min.js"></script>
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/CompoundShader/src/babylonx.CompoundShader.js"></script>
-    <link href="css/index.css" rel="stylesheet" />
-</head>
-
-<body>
-    <div class="navbar navBar1600">
-        <div class="title">
-            Babylon.js Playground
-        </div>
-        <div class="version" id="mainTitle">
-        </div>
+    <head>
+        <title>Babylon.js Playground</title>
+        <meta charset='utf-8' />
+        <meta name="viewport" content="width=device-width, user-scalable=no">
+        <link rel="shortcut icon" href="https://www.babylonjs.com/img/favicon/favicon.ico">
+        <link rel="apple-touch-icon" sizes="57x57" href="https://www.babylonjs.com/img/favicon/apple-icon-57x57.png">
+        <link rel="apple-touch-icon" sizes="60x60" href="https://www.babylonjs.com/img/favicon/apple-icon-60x60.png">
+        <link rel="apple-touch-icon" sizes="72x72" href="https://www.babylonjs.com/img/favicon/apple-icon-72x72.png">
+        <link rel="apple-touch-icon" sizes="76x76" href="https://www.babylonjs.com/img/favicon/apple-icon-76x76.png">
+        <link rel="apple-touch-icon" sizes="114x114" href="https://www.babylonjs.com/img/favicon/apple-icon-114x114.png">
+        <link rel="apple-touch-icon" sizes="120x120" href="https://www.babylonjs.com/img/favicon/apple-icon-120x120.png">
+        <link rel="apple-touch-icon" sizes="144x144" href="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png">
+        <link rel="apple-touch-icon" sizes="152x152" href="https://www.babylonjs.com/img/favicon/apple-icon-152x152.png">
+        <link rel="apple-touch-icon" sizes="180x180" href="https://www.babylonjs.com/img/favicon/apple-icon-180x180.png">
+        <link rel="icon" type="image/png" sizes="192x192" href="https://www.babylonjs.com/img/favicon/android-icon-192x192.png">
+        <link rel="icon" type="image/png" sizes="32x32" href="https://www.babylonjs.com/img/favicon/favicon-32x32.png">
+        <link rel="icon" type="image/png" sizes="96x96" href="https://www.babylonjs.com/img/favicon/favicon-96x96.png">
+        <link rel="icon" type="image/png" sizes="16x16" href="https://www.babylonjs.com/img/favicon/favicon-16x16.png">
+        <link rel="manifest" href="https://www.babylonjs.com/img/favicon/manifest.json">
+        <meta name="msapplication-TileColor" content="#ffffff">
+        <meta name="msapplication-TileImage" content="https://www.babylonjs.com/img/favicon/ms-icon-144x144.png">
+        <meta name="msapplication-config" content="https://www.babylonjs.com/img/favicon/browserconfig.xml">
+        <meta name="theme-color" content="#ffffff">
+
+        <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
+        <!--For canvas/code separator-->
+        <script src="js/libs/split.js"></script>
+
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
+        <!-- jszip -->
+        <script src="js/libs/jszip.min.js"></script>
+        <script src="js/libs/fileSaver.js"></script>
+        <!--Monaco-->
+        <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
+        <!-- Babylon.js -->
+        <script src="https://preview.babylonjs.com/cannon.js"></script>
+        <script src="https://preview.babylonjs.com/Oimo.js"></script>
+        <script src="https://preview.babylonjs.com/babylon.js"></script>
+        <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
+
+        <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
+
+        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
+
+        <script src="https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
+
+        <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.js"></script>
+
+        <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
+
+        <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>
+        <script src="https://rawgit.com/BabylonJS/Extensions/master/canvas2D/dist/preview%20release/babylon.canvas2d.min.js"></script>
+        <script src="https://rawgit.com/BabylonJS/Extensions/master/CompoundShader/src/babylonx.CompoundShader.js"></script>
+        <link href="css/index.css" rel="stylesheet" />
+    </head>
+
+    <body>
+        <div class="navbar navBar1600">
+            <div class="title">
+                Babylon.js Playground
+            </div>
+            <div class="version" id="mainTitle">
+            </div>
 
-        <div class="category">
-            <div class="button run" id="runButton1600">Run <i class="fa fa-play" aria-hidden="true"></i></div>
-        </div>
+            <div class="category">
+                <div class="button run" id="runButton1600">Run
+                    <i class="fa fa-play" aria-hidden="true"></i>
+                </div>
+            </div>
 
 
-        <div class="category">
-            <div class="button" id="newButton1600">New<i class="fa fa-file" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="clearButton1600">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
-        </div>
+            <div class="category">
+                <div class="button" id="newButton1600">New
+                    <i class="fa fa-file" aria-hidden="true"></i>
+                </div>
+                <div class="button removeOnPhone" id="clearButton1600">Clear
+                    <i class="fa fa-trash" aria-hidden="true"></i>
+                </div>
+            </div>
 
-        <div class="category">
-            <div class="button" id="saveButton1600">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="zipButton1600">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
-        </div>
+            <div class="category">
+                <div class="button" id="saveButton1600">Save
+                    <i class="fa fa-floppy-o" aria-hidden="true"></i>
+                </div>
+                <div class="button removeOnPhone" id="zipButton1600">Zip
+                    <i class="fa fa-download" aria-hidden="true"></i>
+                </div>
+            </div>
 
-        <div class="category">
-            <div class="button select">Settings
-                <div class="toDisplay">
-                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub">
-                            <div class="option" id="darkTheme1600">Dark</div>
-                            <div class="option" id="lightTheme1600">Light</div>
+            <div class="category">
+                <div class="button select">Settings
+                    <div class="toDisplay">
+                        <div class="option subSelect">Theme
+                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub">
+                                <div class="option" id="darkTheme1600">Dark</div>
+                                <div class="option" id="lightTheme1600">Light</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option subSelect"><span id="currentFontSize1600">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub">
-                            <div class="option" onclick="setFontSize(12);">12</div>
-                            <div class="option" onclick="setFontSize(14);">14</div>
-                            <div class="option" onclick="setFontSize(16);">16</div>
-                            <div class="option" onclick="setFontSize(18);">18</div>
-                            <div class="option" onclick="setFontSize(20);">20</div>
-                            <div class="option" onclick="setFontSize(22);">22</div>
+                        <div class="option subSelect">
+                            <span id="currentFontSize1600">Font: 14</span>
+                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub">
+                                <div class="option" onclick="setFontSize(12);">12</div>
+                                <div class="option" onclick="setFontSize(14);">14</div>
+                                <div class="option" onclick="setFontSize(16);">16</div>
+                                <div class="option" onclick="setFontSize(18);">18</div>
+                                <div class="option" onclick="setFontSize(20);">20</div>
+                                <div class="option" onclick="setFontSize(22);">22</div>
+                            </div>
                         </div>
+                        <div class="option" id="safemodeToggle1600">Safe mode
+                            <i class="fa fa-square-o" aria-hidden="true"></i>
+                        </div>
+                        <div class="option checked" id="editorButton1600">Editor
+                            <i class="fa fa-check-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option" id="fullscreenButton1600">Fullscreen</div>
+                        <div class="option" id="editorFullscreenButton1600">Editor Fullscreen</div>
+                        <div class="option" id="formatButton1600">Format code</div>
                     </div>
-                    <div class="option" id="safemodeToggle1600">Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
-                    <div class="option checked" id="editorButton1600">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option" id="fullscreenButton1600">Fullscreen</div>
-                    <div class="option" id="editorFullscreenButton1600">Editor Fullscreen</div>
-                    <div class="option" id="formatButton1600">Format code</div>
                 </div>
-            </div>
 
-            <div class="button uncheck" id="debugButton1600">Debug layer <i class="fa fa-square-o" aria-hidden="true"></i></div>
-            <div class="button" id="metadataButton1600">Metadata</div>
-        </div>
+                <div class="button uncheck" id="debugButton1600">Debug layer
+                    <i class="fa fa-square-o" aria-hidden="true"></i>
+                </div>
+                <div class="button" id="metadataButton1600">Metadata</div>
+            </div>
 
 
 
-        <div class="category right">
-            <div class="button select"><span id="currentVersion1600">Version: Latest</span>
-                <div class="toDisplay">
-                    <div class="option" onclick="setVersion('latest');">Latest</div>
-                    <div class="option" onclick="setVersion('stable');">Stable</div>
+            <div class="category right">
+                <div class="button select">
+                    <span id="currentVersion1600">Version: Latest</span>
+                    <div class="toDisplay">
+                        <div class="option" onclick="setVersion('latest');">Latest</div>
+                        <div class="option" onclick="setVersion('stable');">Stable</div>
+                    </div>
                 </div>
-            </div>
-            <div class="button select"> <span id="currentScript1600">Scenes</span>
-                <div class="toDisplayBig">
-                    <ul id="scriptsList1600">
-                    </ul>
+                <div class="button select">
+                    <span id="currentScript1600">Scenes</span>
+                    <div class="toDisplayBig">
+                        <ul id="scriptsList1600">
+                        </ul>
+                    </div>
                 </div>
             </div>
+            <div class="save-message" id="saveMessage">
+                This PG has missing metadata. Click save to add them.
+            </div>
         </div>
-        <div class="save-message" id="saveMessage">
-            This PG has missing metadata. Click save to add them.
-        </div>
-    </div>
 
-    <div class="navbar navBar1475">
-        <div class="title">
-            Babylon.js Playground
-        </div>
-        <div class="version" id="mainTitle">
-        </div>
+        <div class="navbar navBar1475">
+            <div class="title">
+                Babylon.js Playground
+            </div>
+            <div class="version" id="mainTitle">
+            </div>
 
-        <div class="category">
-            <div class="button run" id="runButton1475">Run <i class="fa fa-play" aria-hidden="true"></i></div>
-        </div>
+            <div class="category">
+                <div class="button run" id="runButton1475">Run
+                    <i class="fa fa-play" aria-hidden="true"></i>
+                </div>
+            </div>
 
 
-        <div class="category">
-            <div class="button" id="newButton1475">New<i class="fa fa-file" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="clearButton1475">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
-        </div>
+            <div class="category">
+                <div class="button" id="newButton1475">New
+                    <i class="fa fa-file" aria-hidden="true"></i>
+                </div>
+                <div class="button removeOnPhone" id="clearButton1475">Clear
+                    <i class="fa fa-trash" aria-hidden="true"></i>
+                </div>
+            </div>
 
-        <div class="category">
-            <div class="button" id="saveButton1475">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="zipButton1475">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
-        </div>
+            <div class="category">
+                <div class="button" id="saveButton1475">Save
+                    <i class="fa fa-floppy-o" aria-hidden="true"></i>
+                </div>
+                <div class="button removeOnPhone" id="zipButton1475">Zip
+                    <i class="fa fa-download" aria-hidden="true"></i>
+                </div>
+            </div>
 
-        <div class="category">
-            <div class="button select">Settings
-                <div class="toDisplay">
-                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub">
-                            <div class="option" id="darkTheme1475">Dark</div>
-                            <div class="option" id="lightTheme1475">Light</div>
+            <div class="category">
+                <div class="button select">Settings
+                    <div class="toDisplay">
+                        <div class="option subSelect">Theme
+                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub">
+                                <div class="option" id="darkTheme1475">Dark</div>
+                                <div class="option" id="lightTheme1475">Light</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option subSelect"><span id="currentFontSize1475">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub">
-                            <div class="option" onclick="setFontSize(12);">12</div>
-                            <div class="option" onclick="setFontSize(14);">14</div>
-                            <div class="option" onclick="setFontSize(16);">16</div>
-                            <div class="option" onclick="setFontSize(18);">18</div>
-                            <div class="option" onclick="setFontSize(20);">20</div>
-                            <div class="option" onclick="setFontSize(22);">22</div>
+                        <div class="option subSelect">
+                            <span id="currentFontSize1475">Font: 14</span>
+                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub">
+                                <div class="option" onclick="setFontSize(12);">12</div>
+                                <div class="option" onclick="setFontSize(14);">14</div>
+                                <div class="option" onclick="setFontSize(16);">16</div>
+                                <div class="option" onclick="setFontSize(18);">18</div>
+                                <div class="option" onclick="setFontSize(20);">20</div>
+                                <div class="option" onclick="setFontSize(22);">22</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option" id='safemodeToggle1475'>Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
-                    <div class="option checked" id="editorButton1475">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option" id="fullscreenButton1475">Fullscreen</div>
-                    <div class="option" id="editorFullscreenButton1475">Editor Fullscreen</div>
-                    <div class="option" id="formatButton1475">Format code</div>
-                    <div class="option" id="debugButton1475">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
-                    <div class="option" id="metadataButton1475">Metadata</div>
-                    <div class="option subSelect"><span id="currentVersion1475">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub">
-                            <div class="option" onclick="setVersion('latest');">Latest</div>
-                            <div class="option" onclick="setVersion('stable');">Stable</div>
+                        <div class="option" id='safemodeToggle1475'>Safe mode
+                            <i class="fa fa-square-o" aria-hidden="true"></i>
+                        </div>
+                        <div class="option checked" id="editorButton1475">Editor
+                            <i class="fa fa-check-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option" id="fullscreenButton1475">Fullscreen</div>
+                        <div class="option" id="editorFullscreenButton1475">Editor Fullscreen</div>
+                        <div class="option" id="formatButton1475">Format code</div>
+                        <div class="option" id="debugButton1475">Debug layer
+                            <i class="fa fa-square-o" aria-hidden="true"></i>
+                        </div>
+                        <div class="option" id="metadataButton1475">Metadata</div>
+                        <div class="option subSelect">
+                            <span id="currentVersion1475">Vers. : Latest</span>
+                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub">
+                                <div class="option" onclick="setVersion('latest');">Latest</div>
+                                <div class="option" onclick="setVersion('stable');">Stable</div>
+                            </div>
                         </div>
                     </div>
                 </div>
             </div>
-        </div>
 
-        <div class="category right">
-            <div class="button select"> <span id="currentScript1475">Scenes</span>
-                <div class="toDisplayBig">
-                    <ul id="scriptsList1475">
-                    </ul>
+            <div class="category right">
+                <div class="button select">
+                    <span id="currentScript1475">Scenes</span>
+                    <div class="toDisplayBig">
+                        <ul id="scriptsList1475">
+                        </ul>
+                    </div>
                 </div>
             </div>
+            <div class="save-message" id="saveMessage">
+                This PG has missing metadata. Click save to add them.
+            </div>
         </div>
-        <div class="save-message" id="saveMessage">
-            This PG has missing metadata. Click save to add them.
-        </div>
-    </div>
 
-    <div class="navbar navBar1030">
-        <div class="category">
-            <div class="button run" id="runButton1030">Run <i class="fa fa-play" aria-hidden="true"></i></div>
-        </div>
+        <div class="navbar navBar1030">
+            <div class="category">
+                <div class="button run" id="runButton1030">Run
+                    <i class="fa fa-play" aria-hidden="true"></i>
+                </div>
+            </div>
 
 
-        <div class="category">
-            <div class="button" id="newButton1030">New<i class="fa fa-file" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="clearButton1030">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
-        </div>
+            <div class="category">
+                <div class="button" id="newButton1030">New
+                    <i class="fa fa-file" aria-hidden="true"></i>
+                </div>
+                <div class="button removeOnPhone" id="clearButton1030">Clear
+                    <i class="fa fa-trash" aria-hidden="true"></i>
+                </div>
+            </div>
 
-        <div class="category">
-            <div class="button" id="saveButton1030">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="zipButton1030">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
-        </div>
+            <div class="category">
+                <div class="button" id="saveButton1030">Save
+                    <i class="fa fa-floppy-o" aria-hidden="true"></i>
+                </div>
+                <div class="button removeOnPhone" id="zipButton1030">Zip
+                    <i class="fa fa-download" aria-hidden="true"></i>
+                </div>
+            </div>
 
-        <div class="category">
-            <div class="button select">Settings
-                <div class="toDisplay">
-                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub">
-                            <div class="option" id="darkTheme1030">Dark</div>
-                            <div class="option" id="lightTheme1030">Light</div>
+            <div class="category">
+                <div class="button select">Settings
+                    <div class="toDisplay">
+                        <div class="option subSelect">Theme
+                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub">
+                                <div class="option" id="darkTheme1030">Dark</div>
+                                <div class="option" id="lightTheme1030">Light</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option subSelect"><span id="currentFontSize1030">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub">
-                            <div class="option" onclick="setFontSize(12);">12</div>
-                            <div class="option" onclick="setFontSize(14);">14</div>
-                            <div class="option" onclick="setFontSize(16);">16</div>
-                            <div class="option" onclick="setFontSize(18);">18</div>
-                            <div class="option" onclick="setFontSize(20);">20</div>
-                            <div class="option" onclick="setFontSize(22);">22</div>
+                        <div class="option subSelect">
+                            <span id="currentFontSize1030">Font: 14</span>
+                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub">
+                                <div class="option" onclick="setFontSize(12);">12</div>
+                                <div class="option" onclick="setFontSize(14);">14</div>
+                                <div class="option" onclick="setFontSize(16);">16</div>
+                                <div class="option" onclick="setFontSize(18);">18</div>
+                                <div class="option" onclick="setFontSize(20);">20</div>
+                                <div class="option" onclick="setFontSize(22);">22</div>
+                            </div>
                         </div>
-                    </div>
-                    <div class="option" id="safemodeToggle1030">Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
-                    <div class="option checked" id="editorButton1030">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option" id="fullscreenButton1030">Fullscreen</div>
-                    <div class="option" id="editorFullscreenButton1030">Editor Fullscreen</div>
-                    <div class="option" id="formatButton1030">Format code</div>
-                    <div class="option" id="debugButton1030">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
-                    <div class="option" id="metadataButton1030">Metadata</div>
-                    <div class="option subSelect"><span id="currentVersion1030">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub">
-                            <div class="option" onclick="setVersion('latest');">Latest</div>
-                            <div class="option" onclick="setVersion('stable');">Stable</div>
+                        <div class="option" id="safemodeToggle1030">Safe mode
+                            <i class="fa fa-square-o" aria-hidden="true"></i>
+                        </div>
+                        <div class="option checked" id="editorButton1030">Editor
+                            <i class="fa fa-check-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option" id="fullscreenButton1030">Fullscreen</div>
+                        <div class="option" id="editorFullscreenButton1030">Editor Fullscreen</div>
+                        <div class="option" id="formatButton1030">Format code</div>
+                        <div class="option" id="debugButton1030">Debug layer
+                            <i class="fa fa-square-o" aria-hidden="true"></i>
+                        </div>
+                        <div class="option" id="metadataButton1030">Metadata</div>
+                        <div class="option subSelect">
+                            <span id="currentVersion1030">Vers. : Latest</span>
+                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub">
+                                <div class="option" onclick="setVersion('latest');">Latest</div>
+                                <div class="option" onclick="setVersion('stable');">Stable</div>
+                            </div>
                         </div>
                     </div>
                 </div>
             </div>
-        </div>
 
-        <div class="category right">
-            <div class="button select"> <span id="currentScript1030">Scenes</span>
-                <div class="toDisplayBig">
-                    <ul id="scriptsList1030">
-                    </ul>
+            <div class="category right">
+                <div class="button select">
+                    <span id="currentScript1030">Scenes</span>
+                    <div class="toDisplayBig">
+                        <ul id="scriptsList1030">
+                        </ul>
+                    </div>
                 </div>
             </div>
-        </div>
-        <div class="save-message" id="saveMessage">
-            This PG has missing metadata. Click save to add them.
-        </div>
-    </div>
-
-    <div class="navbar navBar750">
-        <div class="category">
-            <div class="button select">File
-                <div class="toDisplay">
-                    <div class="option" id="runButton750">Run <i class="fa fa-play" aria-hidden="true"></i></div>
-                    <div class="option" id="newButton750">New <i class="fa fa-file" aria-hidden="true"></i></div>
-                    <div class="option" id="clearButton750">Clear <i class="fa fa-trash" aria-hidden="true"></i></div>
-                    <div class="option" id="saveButton750">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
-                    <div class="option" id="zipButton750">Zip <i class="fa fa-download" aria-hidden="true"></i></div>
-                </div>
+            <div class="save-message" id="saveMessage">
+                This PG has missing metadata. Click save to add them.
             </div>
         </div>
 
-        <div class="category">
-            <div class="button select">Settings
-                <div class="toDisplay">
-                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub">
-                            <div class="option" id="darkTheme750">Dark</div>
-                            <div class="option" id="lightTheme750">Light</div>
+        <div class="navbar navBar750">
+            <div class="category">
+                <div class="button select">File
+                    <div class="toDisplay">
+                        <div class="option" id="runButton750">Run
+                            <i class="fa fa-play" aria-hidden="true"></i>
                         </div>
-                    </div>
-                    <div class="option subSelect"><span id="currentFontSize750">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub">
-                            <div class="option" onclick="setFontSize(12);">12</div>
-                            <div class="option" onclick="setFontSize(14);">14</div>
-                            <div class="option" onclick="setFontSize(16);">16</div>
-                            <div class="option" onclick="setFontSize(18);">18</div>
-                            <div class="option" onclick="setFontSize(20);">20</div>
-                            <div class="option" onclick="setFontSize(22);">22</div>
+                        <div class="option" id="newButton750">New
+                            <i class="fa fa-file" aria-hidden="true"></i>
+                        </div>
+                        <div class="option" id="clearButton750">Clear
+                            <i class="fa fa-trash" aria-hidden="true"></i>
+                        </div>
+                        <div class="option" id="saveButton750">Save
+                            <i class="fa fa-floppy-o" aria-hidden="true"></i>
+                        </div>
+                        <div class="option" id="zipButton750">Zip
+                            <i class="fa fa-download" aria-hidden="true"></i>
                         </div>
                     </div>
-                    <div class="option" id="safemodeToggle750">Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
-                    <div style="display:none;" class="option checked" id="editorButton750">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
-                    </div>
-                    <div class="option" id="fullscreenButton750">Fullscreen</div>
-                    <div class="option" id="editorFullscreenButton750">Editor Fullscreen</div>
-                    <div class="option" id="formatButton750">Format code</div>
-                    <div class="option" id="debugButton750">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
-                    <div class="option" id="metadataButton750">Metadata</div>
-                    <div class="option subSelect"><span id="currentVersion750">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
-                        <div class="toDisplaySub">
-                            <div class="option" onclick="setVersion('latest');">Latest</div>
-                            <div class="option" onclick="setVersion('stable');">Stable</div>
+                </div>
+            </div>
+
+            <div class="category">
+                <div class="button select">Settings
+                    <div class="toDisplay">
+                        <div class="option subSelect">Theme
+                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub">
+                                <div class="option" id="darkTheme750">Dark</div>
+                                <div class="option" id="lightTheme750">Light</div>
+                            </div>
+                        </div>
+                        <div class="option subSelect">
+                            <span id="currentFontSize750">Font: 14</span>
+                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub">
+                                <div class="option" onclick="setFontSize(12);">12</div>
+                                <div class="option" onclick="setFontSize(14);">14</div>
+                                <div class="option" onclick="setFontSize(16);">16</div>
+                                <div class="option" onclick="setFontSize(18);">18</div>
+                                <div class="option" onclick="setFontSize(20);">20</div>
+                                <div class="option" onclick="setFontSize(22);">22</div>
+                            </div>
+                        </div>
+                        <div class="option" id="safemodeToggle750">Safe mode
+                            <i class="fa fa-square-o" aria-hidden="true"></i>
+                        </div>
+                        <div style="display:none;" class="option checked" id="editorButton750">Editor
+                            <i class="fa fa-check-square" aria-hidden="true"></i>
+                        </div>
+                        <div class="option" id="fullscreenButton750">Fullscreen</div>
+                        <div class="option" id="editorFullscreenButton750">Editor Fullscreen</div>
+                        <div class="option" id="formatButton750">Format code</div>
+                        <div class="option" id="debugButton750">Debug layer
+                            <i class="fa fa-square-o" aria-hidden="true"></i>
+                        </div>
+                        <div class="option" id="metadataButton750">Metadata</div>
+                        <div class="option subSelect">
+                            <span id="currentVersion750">Vers. : Latest</span>
+                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                            <div class="toDisplaySub">
+                                <div class="option" onclick="setVersion('latest');">Latest</div>
+                                <div class="option" onclick="setVersion('stable');">Stable</div>
+                            </div>
                         </div>
                     </div>
                 </div>
             </div>
-        </div>
 
-        <div class="category right">
-            <div class="button select"> <span id="currentScript750">Scenes</span>
-                <div class="toDisplayBig">
-                    <ul id="scriptsList750">
-                    </ul>
+            <div class="category right">
+                <div class="button select">
+                    <span id="currentScript750">Scenes</span>
+                    <div class="toDisplayBig">
+                        <ul id="scriptsList750">
+                        </ul>
+                    </div>
                 </div>
             </div>
+            <div class="save-message" id="saveMessage">
+                This PG has missing metadata. Click save to add them.
+            </div>
         </div>
-        <div class="save-message" id="saveMessage">
-            This PG has missing metadata. Click save to add them.
-        </div>
-    </div>
 
-    <div class="wrapper">
-        <div id="jsEditor"></div>
-        <div id="canvasZone">
-            <canvas touch-action="none" id="renderCanvas"></canvas>
+        <div class="wrapper">
+            <div id="jsEditor"></div>
+            <div id="canvasZone">
+                <canvas touch-action="none" id="renderCanvas"></canvas>
+            </div>
         </div>
-    </div>
 
-    <span class="label" id="fpsLabel">FPS</span>
+        <span class="label" id="fpsLabel">FPS</span>
 
-    <div id="errorZone">
-    </div>
+        <div id="errorZone">
+        </div>
 
-    <div class="navbarBottom">
-        <div id="statusBar"></div>
-        <div class="links">
-            <div class='link'><a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a></div>
-            <div class='link'> <a target='_new' href="http://www.html5gamedevs.com/forum/16-babylonjs/">Forum</a></div>
-            <div class='link'><a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a></div>
-            <div class='link'><a target='_new' href="https://doc.babylonjs.com">Documentation</a></div>
-            <div class='link'><a target='_new' href="https://doc.babylonjs.com/playground">Search</a></div>
+        <div class="navbarBottom">
+            <div id="statusBar"></div>
+            <div class="links">
+                <div class='link'>
+                    <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
+                </div>
+                <div class='link'>
+                    <a target='_new' href="http://www.html5gamedevs.com/forum/16-babylonjs/">Forum</a>
+                </div>
+                <div class='link'>
+                    <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
+                </div>
+                <div class='link'>
+                    <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
+                </div>
+                <div class='link'>
+                    <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
+                </div>
+            </div>
         </div>
-    </div>
 
-    <div id="saveLayer" class="save-layer">
-        <div class="save-form">
-            <label for="saveFormTitle">TITLE</label>
-            <div class="separator"></div>
-            <input type="text" maxlength="120" id="saveFormTitle" class="save-form-title">
+        <div id="saveLayer" class="save-layer">
+            <div class="save-form">
+                <label for="saveFormTitle">TITLE</label>
+                <div class="separator"></div>
+                <input type="text" maxlength="120" id="saveFormTitle" class="save-form-title">
 
-            <label for="saveFormDescription">DESCRIPTION</label>
-            <div class="separator"></div>
-            <textarea id="saveFormDescription" rows="4" cols="10"></textarea>
+                <label for="saveFormDescription">DESCRIPTION</label>
+                <div class="separator"></div>
+                <textarea id="saveFormDescription" rows="4" cols="10"></textarea>
 
-            <label for="saveFormTags">TAGS (separated by comma)</label>
-            <div class="separator"></div>
-            <textarea id="saveFormTags" rows="4" cols="10"></textarea>
+                <label for="saveFormTags">TAGS (separated by comma)</label>
+                <div class="separator"></div>
+                <textarea id="saveFormTags" rows="4" cols="10"></textarea>
 
-            <div class="save-form-buttons" id="saveFormButtons">
+                <div class="save-form-buttons" id="saveFormButtons">
 
-                <div id="saveFormButtonOk" class="button">OK</div>
-                <div id="saveFormButtonCancel" class="button">Cancel</div>
+                    <div id="saveFormButtonOk" class="button">OK</div>
+                    <div id="saveFormButtonCancel" class="button">Cancel</div>
+                </div>
             </div>
         </div>
-    </div>
 
-    <div id="waitDiv">
-        <span id="waitTitle">Babylon.js Playground<BR><BR><BR></span>
-        <img src="waitlogo.png" id="waitLogo"/>
-    </div>   
+        <div id="waitDiv">
+            <span id="waitTitle">Babylon.js Playground
+                <BR>
+                <BR>
+                <BR>
+            </span>
+            <img src="waitlogo.png" id="waitLogo" />
+        </div>
 
-    <script src="https://code.jquery.com/jquery.js"></script>
+        <script src="https://code.jquery.com/jquery.js"></script>
 
     <script src="js/actions.js"></script>
+    <script src="js/pbt.js"></script>
     <script src="js/index.js"></script>
 </body>
 

+ 1 - 0
Playground/indexStable.html

@@ -378,6 +378,7 @@
     </script>
 
     <script src="js/actions.js"></script>
+    <script src="js/pbt.js"></script>
     <script src="js/index.js"></script>
 </body>
 

+ 2 - 0
Playground/js/index.js

@@ -325,6 +325,8 @@
                 var showInspector = false;
                 var showDebugLayer = false;
                 var initialTabIndex = 0;
+                showBJSPGMenu();
+                jsEditor.updateOptions({readOnly: false});
 
                 if (document.getElementsByClassName('insp-wrapper').length > 0) {
                     for (var i = 0; i < engine.scenes.length; i++) {

+ 432 - 0
Playground/js/pbt.js

@@ -0,0 +1,432 @@
+// jsEditor Manipulation
+var PBT = function() {
+    this.decorationStyles = new Array();
+    this.decorations = new Array();
+    var advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("UI");
+    
+    this.clearDecorLines = function() {
+        this.decorations = jsEditor.deltaDecorations(this.decorations, []);
+    }
+
+    this.setDecorLines = function (lineRanges) {    
+        this.decorationStyles = [];
+
+    var endLineNm = jsEditor.getModel()._lines.length;
+        this.decorationStyles.push({ range: new monaco.Range(1,1,endLineNm,1), options: { isWholeLine: true, inlineClassName: 'pbt-fade' }});
+        
+        for(var i = 0; i < lineRanges.length; i +=2) {          
+            this.decorationStyles.push({ range: new monaco.Range(lineRanges[i],1,lineRanges[i + 1],1), options: { isWholeLine: true, linesDecorationsClassName: 'pbt-margin-decor-on' }});
+            this.decorationStyles.push({ range: new monaco.Range(lineRanges[i],1,lineRanges[i + 1],1), options: { isWholeLine: true, className: 'pbt-back-highlight' }});
+            this.decorationStyles.push({ range: new monaco.Range(lineRanges[i],1,lineRanges[i + 1],1), options: { isWholeLine: true, inlineClassName: 'pbt-darken' }});
+        }
+
+    this.decorations = jsEditor.deltaDecorations([this.decorations], this.decorationStyles);  
+    }
+
+    this.replaceLines = function(lineRange, text) {   
+        jsEditor.executeEdits("", [
+            { range: new monaco.Range(lineRange[0], 1, lineRange[1], 100000), text: text}
+       ]);
+    }
+
+    this.replaceText = function(line, start, end, text) {   
+        jsEditor.executeEdits("", [
+            { range: new monaco.Range(line, start, line, end), text: text}
+       ]);
+    }
+
+    this.getLineText = function(lineNm) {
+        return jsEditor.getModel().getLineContent(lineNm);
+    }
+
+    this.hideLines = function(lineRanges) {
+        var ranges = [];
+        for(var i = 0; i < lineRanges.length; i +=2) {
+            ranges.push(new monaco.Range(lineRanges[i], 1, lineRanges[i + 1], 100000));                
+        }
+        jsEditor.setHiddenAreas(ranges);
+    }
+
+    this.editOn = function() {
+        jsEditor.updateOptions({readOnly: false});
+    }
+
+    this.editOff = function() {
+        jsEditor.updateOptions({readOnly: true});
+    }
+
+    //hide menu items
+    this.hideMenu = function() {
+        var headings = document.getElementsByClassName('category');
+        
+        for (var i = 0; i < headings.length; i ++) {
+            headings[i].style.visibility = 'hidden';
+        }
+    
+        headings = document.getElementsByClassName('category right');
+        
+        for (var i = 0; i < headings.length; i ++) {
+            headings[i].style.visibility = 'visible';
+        }
+    }
+
+    //Standard GUI Dialogues
+    this.StandardDialog = function(options) {   
+        options = options||{};
+        var width = options.width||0.5;
+        var height = options.height||0.25;
+        var top = options.top||0;
+        var left = options.left||0;
+        var verticalAlignment = options.verticalAlignment||BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
+        var horizontalAlignment = options.horizontalAlignment||BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
+        var text = options.text||"Playground Based Tutorial";   
+        if(options.useImage === undefined) {
+            var useImage = true;
+        }
+        else {
+            var useImage = false;
+        }
+        var imageURL = options.imageURL||"LogoPBT.png";
+        var textBlockWidth = 0.95;
+        var textBlockLeft = "2%";
+        this.container = new BABYLON.GUI.Rectangle();
+        this.container.verticalAlignment = verticalAlignment;
+        this.container.horizontalAlignment = horizontalAlignment;
+        this.container.width = width;
+        this.container.height = height;
+        this.container.cornerRadius = 10;
+        this.container.color = "#364249";
+        this.container.thickness = 4;
+        this.container.background = "#CDC8F9";
+        this.container.top = top;
+        this.container.left = left;   
+        advancedTexture.addControl(this.container); 
+        if(useImage) {
+            this.logoPBT = BABYLON.GUI.Button.CreateImageOnlyButton("but", imageURL);
+            this.logoPBT.width = "100px";
+            this.logoPBT.height = "100px";
+            this.logoPBT.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
+            this.logoPBT.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
+            this.logoPBT.top = 2;
+            this.logoPBT.left=2;
+            this.logoPBT.color = "#CDC8F9";
+            this.container.addControl(this.logoPBT);
+            textBlockWidth = 0.6;
+            textBlockLeft = "35%";
+        }
+        this.textBlock = new BABYLON.GUI.TextBlock("text", text);
+        this.textBlock.width = textBlockWidth;
+        this.textBlock.height = 0.7
+        this.textBlock.textWrapping = true;
+        this.textBlock.textHorizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
+        this.textBlock.color = "#364249";
+        this.textBlock.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
+        this.textBlock.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
+        this.textBlock.left = textBlockLeft;
+        this.textBlock.top = 2;
+        this.container.addControl(this.textBlock);
+
+        this.nextButton = BABYLON.GUI.Button.CreateSimpleButton("nextbut", "Next >");
+        this.nextButton.width = 0.2
+        this.nextButton.height = 0.15;
+        this.nextButton.color = "white";
+        this.nextButton.cornerRadius = 5;
+        this.nextButton.background = "#364249";
+        this.nextButton.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
+        this.nextButton.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
+        this.nextButton.left = "78%";
+        this.nextButton.top = "80%";
+        this.container.addControl(this.nextButton);
+
+        this.prevButton = BABYLON.GUI.Button.CreateSimpleButton("prevbut", "< Prev");
+        this.prevButton.width = 0.2
+        this.prevButton.height = 0.15;
+        this.prevButton.color = "white";
+        this.prevButton.cornerRadius = 5;
+        this.prevButton.background = "#364249";
+        this.prevButton.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
+        this.prevButton.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
+        this.prevButton.left = "2%";
+        this.prevButton.top = "80%";
+        this.container.addControl(this.prevButton); 
+
+        this.showNext = function() {
+            this.nextButton.isVisible = true;
+        }
+
+        this.hideNext = function() {
+            this.nextButton.isVisible = false;
+        }
+
+        this.getNextButton = function() {
+            return this.nextButton;
+        }
+
+        this.getPrevButton = function() {
+            return this.prevButton;
+        }
+
+        this.showPrev = function() {
+            this.prevButton.isVisible = true;
+        }
+
+        this.hidePrev = function() {
+            this.prevButton.isVisible = false;
+        }
+
+        this.setWidth = function(width) {
+            this.container.width = width;
+        }
+
+        this.setHeight = function(height) {
+            this.container.height = height;
+        }
+
+        this.setTop = function(top) {
+            this.container.top = top;
+        }
+
+        this.setLeft = function(left) {
+            this.container.left = left;
+        }
+
+        this.getWidth = function() {
+            return this.container.width;
+        }
+
+        this.getHeight = function() {
+            return this.container.height;
+        }
+
+        this.getTop = function() {
+            return this.container.top;
+        }
+
+        this.getLeft = function() {
+            return this.container.left;
+        }
+
+        this.setHorizontalAlignment = function(hrzAlgn) {
+            this.container.horizontalAlignment = hrzAlgn;
+        }
+
+        this.setVerticalAlignment = function(vrtAlign) {
+            this.container.VerticalAlignmenv = vrtAlign;
+        }
+
+        this.setText = function(text) {
+            this.textBlock.text = text;
+        }
+
+        this.show = function() {
+            this.container.isVisible = true;
+        }
+
+        this.hide = function() {
+            this.container.isVisible = false;
+        }
+
+        return this;
+    }
+
+//Radio and Checkbox Button GUI
+    this.ButtonGroup = function(name, type) {
+        this.name = name;
+        var type = type||"C"; 
+        type = type.substr(0,1).toUpperCase();
+        if(type !="R") {
+            if(type != "C") {
+                type = "C";
+            }
+        }
+        this.type = type;   
+        this.buttons = new Array();
+        
+        this.addButton = function(text, func, checked) {
+            this.buttons.push({
+                text: text||"", 
+                func: func||null, 
+                checked: checked||false
+        });
+        }
+        return this;
+    }
+
+    this.SelectionDialog = function(options) {
+        options = options||{};
+        var justStarted = true;
+        var width = options.width||0.15;
+        var top = options.top||0;
+        var left = options.left||0;  
+        var verticalAlignment = options.verticalAlignment||BABYLON.GUI.Control.VERTICAL_ALIGNMENT_BOTTOM;
+        var horizontalAlignment = options.horizontalAlignment||BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;    
+        var groups = options.groups; 
+        this.container = new BABYLON.GUI.Rectangle();
+        this.container.verticalAlignment = verticalAlignment;
+        this.container.horizontalAlignment = horizontalAlignment;   
+        this.container.width = 0.25;
+        var height = 36 * groups.length;
+        for(var i = 0; i < groups.length; i++) {
+            height += 32 * groups[i].buttons.length;
+        }
+        this.container.height = height + "px";
+        this.container.cornerRadius = 10;
+        this.container.color = "#364249";
+        this.container.thickness = 4;
+        this.container.background = "#CDC8F9";
+        this.container.top = top;
+        this.container.left = left;
+        advancedTexture.addControl(this.container);
+        
+        var panel = new BABYLON.GUI.StackPanel(); 
+        panel.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
+        panel.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
+        panel.top = 5;
+        panel.left = 5;
+        this.container.addControl(panel);
+
+    var addRadio = function(text, parent, group, func, checked) {
+            checked = checked || false;
+            var button = new BABYLON.GUI.RadioButton();
+            button.width = "20px";
+            button.height = "20px";
+            button.color = "#364249";
+            button.background = "white"; 
+            button.group = group;
+            button.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
+            button.justStarted = true;
+            button.func = func;
+
+        button.onIsCheckedChangedObservable.add(function(state) {                       		
+                if (state && !justStarted) {                  
+                    func();
+                }
+            }); 
+
+        var header = BABYLON.GUI.Control.AddHeader(button, text, "200px", { isHorizontal: true, controlFirst: true });
+            header.height = "30px";
+
+        parent.addControl(header);    
+            button.isChecked = checked; 
+        }
+
+        var addCheckbox = function(text, parent, func, checked) {
+            checked = checked || false;
+            var button = new BABYLON.GUI.Checkbox();
+            button.width = "20px";
+            button.height = "20px";
+            button.color = "#364249";
+            button.background = "white"; 
+            button.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
+            
+            button.onIsCheckedChangedObservable.add(function(state) {	
+                func();	
+            }); 
+            
+            var header = BABYLON.GUI.Control.AddHeader(button, text, "200px", { isHorizontal: true, controlFirst: true });
+            header.height = "30px";
+            
+            parent.addControl(header);    
+            button.isChecked = checked;
+        }
+
+        var groupHeader = function(name) {
+            var groupHeading = new BABYLON.GUI.TextBlock("groupHead", name);
+            groupHeading.width = 0.9;
+            groupHeading.height = "30px";
+            groupHeading.textWrapping = true;
+            groupHeading.color = "black";
+            groupHeading.textHorizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
+            groupHeading.left = "-2px";
+            panel.addControl(groupHeading);
+        }
+
+        var addSpacer = function(name) {
+            var separator = new BABYLON.GUI.Rectangle();
+            separator.width = 1;
+            separator.height = "2px";
+            separator.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
+            separator.background = "#364249";
+            separator.color = "#364249";
+            panel.addControl(separator);
+            
+            groupHeader(name);
+        }
+
+        this.addGroup = function(group) {
+            if(group.type == "R") {
+                for(var i = 0; i < group.buttons.length; i++) {
+                    addRadio(group.buttons[i].text, panel, group.name, group.buttons[i].func, group.buttons[i].checked);
+                }
+            }
+            else {
+                for(var i = 0; i < group.buttons.length; i++) {
+                    addCheckbox(group.buttons[i].text, panel, group.buttons[i].func, group.buttons[i].checked);
+                }
+            }
+            
+            
+        }
+        
+        groupHeader(groups[0].name);
+        this.addGroup(groups[0]);
+        for(var i = 1; i < groups.length; i++) {
+            addSpacer(groups[i].name);
+            this.addGroup(groups[i]);
+        }
+
+        justStarted = false;
+
+        this.setWidth = function(width) {
+            this.container.width = width;
+        }
+
+        this.setTop = function(top) {
+            this.container.top = top;
+        }
+
+        this.setLeft = function(left) {
+            this.container.left = left;
+        }
+
+        this.getWidth = function() {
+            return this.container.width;
+        }
+
+        this.getTop = function() {
+            return this.container.top;
+        }
+
+        this.getLeft = function() {
+            return this.container.left;
+        }
+
+        this.setHorizontalAlignment = function(hrzAlgn) {
+            this.container.horizontalAlignment = hrzAlgn;
+        }
+
+        this.setVerticalAlignment = function(vrtAlign) {
+            this.container.VerticalAlignmenv = vrtAlign;
+        }
+
+        this.show = function() {
+            this.container.isVisible = true;
+        }
+
+        this.hide = function() {
+            this.container.isVisible = false;
+        }
+
+    return this;
+
+    }
+}
+
+showBJSPGMenu = function() {
+    var headings = document.getElementsByClassName('category');
+    
+    for (var i = 0; i < headings.length; i ++) {
+        headings[i].style.visibility = 'visible';
+    }
+}
+    

+ 14 - 0
Playground/package-lock.json

@@ -0,0 +1,14 @@
+{
+  "name": "babylonjsplayground",
+  "version": "3.0.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "monaco-editor": {
+      "version": "0.10.1",
+      "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.10.1.tgz",
+      "integrity": "sha1-jJbE8VtrUli/ksvek8rYp+MAfhQ=",
+      "dev": true
+    }
+  }
+}

+ 6 - 0
Tools/Gulp/config.json

@@ -6,6 +6,12 @@
         "declarationFilename": "babylon.d.ts",
         "declarationModuleFilename": "babylon.module.d.ts",
         "outputDirectory": "../../dist/preview release",
+        "playgroundDirectory": "../../Playground/",
+        "intellisenseFile": "babylon.d.txt",
+        "intellisenseSources": [
+            "../../dist/preview release/babylon.d.ts",
+            "../../dist/preview release/gui/babylon.gui.d.ts"
+        ],
         "outputCustomConfigurationsDirectory": "../../dist/preview release/customConfigurations",
         "srcOutputDirectory": "../../src/",
         "currentConfig": "all"

+ 14 - 4
Tools/Gulp/gulpfile.js

@@ -244,9 +244,6 @@ gulp.task("typescript-compile", function () {
     return merge2([
         tsResult.dts
             .pipe(concat(config.build.declarationFilename))
-            .pipe(gulp.dest(config.build.outputDirectory)),
-        tsResult.dts
-            .pipe(concat(config.build.declarationModuleFilename))
             .pipe(addDtsExport("BABYLON", "babylonjs"))
             .pipe(gulp.dest(config.build.outputDirectory)),
         tsResult.js
@@ -415,7 +412,8 @@ var buildExternalLibrary = function (library, settings, watch) {
 /**
  * The default task, concat and min the main BJS files.
  */
-gulp.task("default", ["typescript-all"], function () {
+gulp.task("default", function (cb) {
+    runSequence("typescript-all", "intellisense", cb);
 });
 
 gulp.task("mainBuild", function (cb) {
@@ -500,6 +498,18 @@ gulp.task("watch", [], function () {
     return tasks;
 });
 
+gulp.task("intellisense", function () {
+    gulp.src(config.build.intellisenseSources)
+        .pipe(concat(config.build.intellisenseFile))
+        .pipe(replace(/^\s*_.*?$/gm, ""))
+        .pipe(replace(/^\s*private .*?$/gm, ""))
+        .pipe(replace(/^\s*public _.*?$/gm, ""))
+        .pipe(replace(/^\s*protected .*?$/gm, ""))
+        .pipe(replace(/^\s*public static _.*?$/gm, ""))
+        .pipe(replace(/^\s*static _.*?$/gm, ""))
+        .pipe(gulp.dest(config.build.playgroundDirectory));
+});
+
 /**
  * Embedded local dev env management.
  */

BIN
Viewer/assets/img/close.png


BIN
Viewer/assets/img/fullscreen.png


BIN
Viewer/assets/img/help-circle.png


BIN
Viewer/assets/img/loading.png


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 210 - 0
Viewer/assets/pep.min.js


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

@@ -102,11 +102,11 @@
 </div>
 <div class="button-container flex-container">
     <!-- holding the buttons -->
-    {{#each buttons}}
+    {{#eachInMap buttons}}
     <div id="{{id}}" class="button">
         {{#if text}}
         <span>{{text}}</span>> {{/if}} {{#if image}}
         <img src="{{image}}" alt="{{altText}}"> {{/if}}
     </div>
-    {{/each}}
+    {{/eachInMap}}
 </div>

+ 2 - 4
Viewer/dist/domExample.html

@@ -15,9 +15,8 @@
     </head>
 
     <body>
-        <babylon extends="minimal">
-            <model url="https://ugcorigin.s-microsoft.com/12/2e77b8e3-0000-0000-7a48-6505db2f0ef9/952/1508427934473.gltf" title="The Bus!"
-                subtitle="Remix3D" thumbnail="http://d33wubrfki0l68.cloudfront.net/7e08139ddee0ec38005f4232346c7f7386831300/fd934/githubuniverse/remix3d.png">
+        <babylon extends="minimal" scene.default-camera="false">
+            <model url="https://playground.babylonjs.com/scenes/BoomBox.glb" title="GLB Model" subtitle="BabylonJS">
             </model>
             <camera>
                 <behaviors>
@@ -27,7 +26,6 @@
             <lights>
                 <light1 type="1" shadow-enabled="true" position.y="0.5" direction.y="-1" intensity="4.5">
                     <shadow-config use-blur-exponential-shadow-map="true" use-kernel-blur="true" blur-kernel="64" blur-scale="4">
-
                     </shadow-config>
                 </light1>
             </lights>

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 5622 - 7086
Viewer/dist/viewer.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 38 - 0
Viewer/dist/viewer.min.js


+ 9 - 11
Viewer/package.json

@@ -23,7 +23,7 @@
     },
     "homepage": "https://github.com/BabylonJS/Babylon.js#readme",
     "devDependencies": {
-        "@types/node": "^8.0.51",
+        "@types/node": "^8.0.52",
         "base64-image-loader": "^1.2.0",
         "html-loader": "^0.5.1",
         "json-loader": "^0.5.7",
@@ -34,15 +34,13 @@
         "webpack-dev-server": "^2.9.4"
     },
     "dependencies": {
-        "babylonjs": "^3.1.0-beta1.1.1",
-        "babylonjs-loaders": "^3.1.0-beta1.1",
-        "babylonjs-materials": "^3.1.0-beta1.1",
-        "babylonjs-post-process": "^3.1.0-beta1.1",
-        "babylonjs-procedural-textures": "^3.1.0-beta1.1",
+        "babylonjs": "^3.1.0-beta3",
+        "babylonjs-loaders": "^3.1.0-beta3",
+        "babylonjs-materials": "^3.1.0-beta3",
+        "babylonjs-post-process": "^3.1.0-beta3",
+        "babylonjs-procedural-textures": "^3.1.0-beta3",
+        "deepmerge": "^2.0.1",
         "es6-promise": "^4.1.1",
-        "handlebars": "^4.0.11",
-        "lodash": "^4.17.4",
-        "lodash.merge": "^4.6.0",
-        "promise-polyfill": "^6.0.2"
+        "handlebars": "^4.0.11"
     }
-}
+}

+ 3 - 5
Viewer/src/configuration/configuration.ts

@@ -44,14 +44,12 @@ export interface ViewerConfiguration {
         scaling?: { x: number, y: number, z: number };
         parentObjectIndex?: number; // the index of the parent object of the model in the loaded meshes array.
 
-        [propName: string]: any; // further configuration, like title and creator
-    } | string,
-
-    description?: string | {
         title: string;
         subtitle?: string;
         thumbnail?: string; // URL or data-url
-    };
+
+        [propName: string]: any; // further configuration, like title and creator
+    } | string;
 
     scene?: {
         debug?: boolean;

+ 4 - 4
Viewer/src/configuration/loader.ts

@@ -2,7 +2,7 @@ import { mapperManager } from './mappers';
 import { ViewerConfiguration } from './configuration';
 import { getConfigurationType } from './types';
 
-import * as merge from 'lodash.merge';
+import deepmerge from 'deepmerge';
 
 export class ConfigurationLoader {
 
@@ -10,11 +10,11 @@ export class ConfigurationLoader {
 
     public loadConfiguration(initConfig: ViewerConfiguration = {}): Promise<ViewerConfiguration> {
 
-        let loadedConfig = merge({}, initConfig);
+        let loadedConfig = deepmerge({}, initConfig);
 
         let extendedConfiguration = getConfigurationType(loadedConfig && loadedConfig.extends);
 
-        loadedConfig = merge(extendedConfiguration, loadedConfig);
+        loadedConfig = deepmerge(extendedConfiguration, loadedConfig);
 
         if (loadedConfig.configuration) {
 
@@ -34,7 +34,7 @@ export class ConfigurationLoader {
             let mapper = mapperManager.getMapper(mapperType);
             return this.loadFile(url).then((data: any) => {
                 let parsed = mapper.map(data);
-                return merge(loadedConfig, parsed);
+                return deepmerge(loadedConfig, parsed);
             });
         } else {
             return Promise.resolve(loadedConfig);

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

@@ -3,8 +3,6 @@ import { ViewerConfiguration } from './configuration';
 
 import { kebabToCamel } from '../helper';
 
-import * as merge from 'lodash.merge';
-
 export interface IMapper {
     map(rawSource: any): ViewerConfiguration;
 }

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 8 - 12
Viewer/src/configuration/types/default.ts


+ 3 - 1
Viewer/src/index.ts

@@ -1,3 +1,4 @@
+import { mapperManager } from './configuration/mappers';
 import { viewerManager } from './viewer/viewerManager';
 import { DefaultViewer } from './viewer/defaultViewer';
 import { AbstractViewer } from './viewer/viewer';
@@ -13,6 +14,7 @@ import { AbstractViewer } from './viewer/viewer';
 import 'babylonjs';
 import 'babylonjs-loaders';
 import 'babylonjs-materials';
+import '../assets/pep.min';
 
 import { InitTags } from './initializer';
 
@@ -27,4 +29,4 @@ setTimeout(() => {
 });
 
 // public API for initialization
-export { InitTags, DefaultViewer, AbstractViewer, viewerManager };
+export { InitTags, DefaultViewer, AbstractViewer, viewerManager, mapperManager };

+ 15 - 1
Viewer/src/templateManager.ts

@@ -144,6 +144,20 @@ export class TemplateManager {
 
 
 import * as Handlebars from 'handlebars/dist/handlebars.min.js';
+// register a new helper. modified https://stackoverflow.com/questions/9838925/is-there-any-method-to-iterate-a-map-with-handlebars-js
+Handlebars.registerHelper('eachInMap', function (map, block) {
+    var out = '';
+    Object.keys(map).map(function (prop) {
+        let data = map[prop];
+        if (typeof data === 'object') {
+            data.id = data.id || prop;
+            out += block.fn(data);
+        } else {
+            out += block.fn({ id: prop, value: data });
+        }
+    });
+    return out;
+});
 
 export class Template {
 
@@ -297,7 +311,7 @@ export function getTemplateAsHtml(templateConfig: ITemplateConfiguration): Promi
             return loadFile(location);
         } else {
             location = location.replace('#', '');
-            let element = document.getElementById('#' + location);
+            let element = document.getElementById(location);
             if (element) {
                 return Promise.resolve(element.innerHTML);
             } else {

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

@@ -107,7 +107,7 @@ export class DefaultViewer extends AbstractViewer {
                                     let requestFullScreen = viewerElement.requestFullscreen || viewerElement.webkitRequestFullscreen || (<any>viewerElement).msRequestFullscreen || (<any>viewerElement).mozRequestFullScreen;
                                     requestFullScreen.call(viewerElement);
                                 } else {
-                                    let exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen
+                                    let exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen || (<any>document).msExitFullscreen || document.mozCancelFullScreen
                                     exitFullscreen.call(document);
                                 }
 
@@ -371,14 +371,16 @@ export class DefaultViewer extends AbstractViewer {
 
     private setupCamera(focusMeshes: Array<AbstractMesh> = []) {
 
+        let cameraConfig = this.configuration.camera || {};
         let sceneConfig = this.configuration.scene || { autoRotate: false, defaultCamera: true };
 
-        if (sceneConfig.defaultCamera) {
+        if (!this.configuration.camera && sceneConfig.defaultCamera) {
+            if (sceneConfig.autoRotate) {
+                this.camera.useAutoRotationBehavior = true;
+            }
             return;
         }
 
-        let cameraConfig = this.configuration.camera || {};
-
         if (cameraConfig.position) {
             this.camera.position.copyFromFloats(cameraConfig.position.x || 0, cameraConfig.position.y || 0, cameraConfig.position.z || 0);
         }

+ 4 - 0
Viewer/src/viewer/viewerManager.ts

@@ -32,6 +32,10 @@ class ViewerManager {
 
     public getViewerPromiseById(id: string): Promise<AbstractViewer> {
         return new Promise((resolve, reject) => {
+            let localViewer = this.getViewerById(id)
+            if (localViewer) {
+                return resolve(localViewer);
+            }
             let viewerFunction = (viewer: AbstractViewer) => {
                 if (viewer.getBaseId() === id) {
                     resolve(viewer);

+ 9 - 15
Viewer/webpack.config.js

@@ -5,7 +5,7 @@ const webpack = require('webpack');
 module.exports = {
     entry: {
         'viewer': './src/index.ts',
-        //'viewer.min': './src/index.ts',
+        'viewer.min': './src/index.ts',
     },
     output: {
         path: path.resolve(__dirname, 'dist'),
@@ -23,19 +23,10 @@ module.exports = {
         new webpack.WatchIgnorePlugin([
             /\.d\.ts$/
         ]),
-        /*new UglifyJSPlugin({
-
-            uglifyOptions: {
-                compress: {
-                    warnings: false,
-                },
-                output: {
-                    comments: false
-                }
-            },
-            sourceMap: true,
-            include: /\.min/,
-        })*/
+        new UglifyJSPlugin({
+            parallel: true,
+            test: /\.min\.js$/i,
+        })
     ],
     module: {
         loaders: [{
@@ -46,7 +37,10 @@ module.exports = {
         {
             test: /\.(html)$/,
             use: {
-                loader: 'html-loader'
+                loader: 'html-loader',
+                options: {
+                    minimize: true
+                }
             }
         },
         {

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 2892 - 2870
dist/preview release/babylon.d.ts


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 10 - 10
dist/preview release/babylon.js


+ 43 - 11
dist/preview release/babylon.max.js

@@ -1781,7 +1781,7 @@ var BABYLON;
             matrix.invert();
             var screenSource = MathTmp.Vector3[0];
             screenSource.x = sourceX / viewportWidth * 2 - 1;
-            screenSource.y = sourceY / viewportHeight * 2 - 1;
+            screenSource.y = -(sourceY / viewportHeight * 2 - 1);
             screenSource.z = 2 * sourceZ - 1.0;
             Vector3.TransformCoordinatesToRef(screenSource, matrix, result);
             var num = screenSource.x * matrix.m[3] + screenSource.y * matrix.m[7] + screenSource.z * matrix.m[11] + matrix.m[15];
@@ -4453,7 +4453,7 @@ var BABYLON;
          * Returns the updated Path2.
          */
         Path2.prototype.addLineTo = function (x, y) {
-            if (closed) {
+            if (this.closed) {
                 //Tools.Error("cannot add lines to closed paths");
                 return this;
             }
@@ -4469,7 +4469,7 @@ var BABYLON;
          */
         Path2.prototype.addArcTo = function (midX, midY, endX, endY, numberOfSegments) {
             if (numberOfSegments === void 0) { numberOfSegments = 36; }
-            if (closed) {
+            if (this.closed) {
                 //Tools.Error("cannot add arcs to closed paths");
                 return this;
             }
@@ -8522,7 +8522,7 @@ var BABYLON;
         });
         Object.defineProperty(Engine, "Version", {
             get: function () {
-                return "3.1-beta-3";
+                return "3.1-beta-4";
             },
             enumerable: true,
             configurable: true
@@ -17909,7 +17909,6 @@ var BABYLON;
              */
             this.onPointerObservable = new BABYLON.Observable();
             this._meshPickProceed = false;
-            this._previousHasSwiped = false;
             this._currentPickResult = null;
             this._previousPickResult = null;
             this._totalPointersPressed = 0;
@@ -18933,7 +18932,6 @@ var BABYLON;
                                     _this._previousStartingPointerPosition.x = _this._startingPointerPosition.x;
                                     _this._previousStartingPointerPosition.y = _this._startingPointerPosition.y;
                                     _this._previousButtonPressed = btn;
-                                    _this._previousHasSwiped = clickInfo.hasSwiped;
                                     if (Scene.ExclusiveDoubleClickMode) {
                                         if (_this._previousDelayedSimpleClickTimeout) {
                                             clearTimeout(_this._previousDelayedSimpleClickTimeout);
@@ -18952,7 +18950,6 @@ var BABYLON;
                                 _this._previousStartingPointerPosition.x = _this._startingPointerPosition.x;
                                 _this._previousStartingPointerPosition.y = _this._startingPointerPosition.y;
                                 _this._previousButtonPressed = btn;
-                                _this._previousHasSwiped = clickInfo.hasSwiped;
                             }
                         }
                     }
@@ -52991,12 +52988,12 @@ var BABYLON;
             if (sceneFilename.name) {
                 sceneFilename = sceneFilename.name;
             }
-            var dotPosition = sceneFilename.lastIndexOf(".");
             var queryStringPosition = sceneFilename.indexOf("?");
-            if (queryStringPosition === -1) {
-                queryStringPosition = sceneFilename.length;
+            if (queryStringPosition !== -1) {
+                sceneFilename = sceneFilename.substring(0, queryStringPosition);
             }
-            var extension = sceneFilename.substring(dotPosition, queryStringPosition).toLowerCase();
+            var dotPosition = sceneFilename.lastIndexOf(".");
+            var extension = sceneFilename.substring(dotPosition, sceneFilename.length).toLowerCase();
             return SceneLoader._getPluginForExtension(extension);
         };
         // use babylon file loader directly if sceneFilename is prefixed with "data:"
@@ -75197,6 +75194,41 @@ var BABYLON;
             this.zoomOnBoundingInfo(boundingBox.minimumWorld, boundingBox.maximumWorld, focusOnOriginXZ, onAnimationEnd);
         };
         /**
+         * Targets the given mesh with its children and updates zoom level accordingly.
+         * @param mesh  The mesh to target.
+         * @param radius Optional. If a cached radius position already exists, overrides default.
+         * @param framingPositionY Position on mesh to center camera focus where 0 corresponds bottom of its bounding box and 1, the top
+         * @param focusOnOriginXZ Determines if the camera should focus on 0 in the X and Z axis instead of the mesh
+         * @param onAnimationEnd Callback triggered at the end of the framing animation
+         */
+        FramingBehavior.prototype.zoomOnMeshHierarchy = function (mesh, focusOnOriginXZ, onAnimationEnd) {
+            if (focusOnOriginXZ === void 0) { focusOnOriginXZ = false; }
+            if (onAnimationEnd === void 0) { onAnimationEnd = null; }
+            mesh.computeWorldMatrix(true);
+            var boundingBox = mesh.getHierarchyBoundingVectors(true);
+            this.zoomOnBoundingInfo(boundingBox.min, boundingBox.max, focusOnOriginXZ, onAnimationEnd);
+        };
+        /**
+         * Targets the given meshes with their children and updates zoom level accordingly.
+         * @param meshes  The mesh to target.
+         * @param radius Optional. If a cached radius position already exists, overrides default.
+         * @param framingPositionY Position on mesh to center camera focus where 0 corresponds bottom of its bounding box and 1, the top
+         * @param focusOnOriginXZ Determines if the camera should focus on 0 in the X and Z axis instead of the mesh
+         * @param onAnimationEnd Callback triggered at the end of the framing animation
+         */
+        FramingBehavior.prototype.zoomOnMeshesHierarchy = function (meshes, focusOnOriginXZ, onAnimationEnd) {
+            if (focusOnOriginXZ === void 0) { focusOnOriginXZ = false; }
+            if (onAnimationEnd === void 0) { onAnimationEnd = null; }
+            var min = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+            var max = new BABYLON.Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
+            for (var i = 0; i < meshes.length; i++) {
+                var boundingInfo = meshes[i].getHierarchyBoundingVectors(true);
+                BABYLON.Tools.CheckExtends(boundingInfo.min, min, max);
+                BABYLON.Tools.CheckExtends(boundingInfo.max, min, max);
+            }
+            this.zoomOnBoundingInfo(min, max, focusOnOriginXZ, onAnimationEnd);
+        };
+        /**
          * Targets the given mesh and updates zoom level accordingly.
          * @param mesh  The mesh to target.
          * @param radius Optional. If a cached radius position already exists, overrides default.

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 20595
dist/preview release/babylon.module.d.ts


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 11 - 11
dist/preview release/babylon.worker.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 8192 - 8188
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 8 - 8
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


+ 24 - 11
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js

@@ -1781,7 +1781,7 @@ var BABYLON;
             matrix.invert();
             var screenSource = MathTmp.Vector3[0];
             screenSource.x = sourceX / viewportWidth * 2 - 1;
-            screenSource.y = sourceY / viewportHeight * 2 - 1;
+            screenSource.y = -(sourceY / viewportHeight * 2 - 1);
             screenSource.z = 2 * sourceZ - 1.0;
             Vector3.TransformCoordinatesToRef(screenSource, matrix, result);
             var num = screenSource.x * matrix.m[3] + screenSource.y * matrix.m[7] + screenSource.z * matrix.m[11] + matrix.m[15];
@@ -4453,7 +4453,7 @@ var BABYLON;
          * Returns the updated Path2.
          */
         Path2.prototype.addLineTo = function (x, y) {
-            if (closed) {
+            if (this.closed) {
                 //Tools.Error("cannot add lines to closed paths");
                 return this;
             }
@@ -4469,7 +4469,7 @@ var BABYLON;
          */
         Path2.prototype.addArcTo = function (midX, midY, endX, endY, numberOfSegments) {
             if (numberOfSegments === void 0) { numberOfSegments = 36; }
-            if (closed) {
+            if (this.closed) {
                 //Tools.Error("cannot add arcs to closed paths");
                 return this;
             }
@@ -17909,7 +17909,6 @@ var BABYLON;
              */
             this.onPointerObservable = new BABYLON.Observable();
             this._meshPickProceed = false;
-            this._previousHasSwiped = false;
             this._currentPickResult = null;
             this._previousPickResult = null;
             this._totalPointersPressed = 0;
@@ -18933,7 +18932,6 @@ var BABYLON;
                                     _this._previousStartingPointerPosition.x = _this._startingPointerPosition.x;
                                     _this._previousStartingPointerPosition.y = _this._startingPointerPosition.y;
                                     _this._previousButtonPressed = btn;
-                                    _this._previousHasSwiped = clickInfo.hasSwiped;
                                     if (Scene.ExclusiveDoubleClickMode) {
                                         if (_this._previousDelayedSimpleClickTimeout) {
                                             clearTimeout(_this._previousDelayedSimpleClickTimeout);
@@ -18952,7 +18950,6 @@ var BABYLON;
                                 _this._previousStartingPointerPosition.x = _this._startingPointerPosition.x;
                                 _this._previousStartingPointerPosition.y = _this._startingPointerPosition.y;
                                 _this._previousButtonPressed = btn;
-                                _this._previousHasSwiped = clickInfo.hasSwiped;
                             }
                         }
                     }
@@ -52837,12 +52834,12 @@ var BABYLON;
             if (sceneFilename.name) {
                 sceneFilename = sceneFilename.name;
             }
-            var dotPosition = sceneFilename.lastIndexOf(".");
             var queryStringPosition = sceneFilename.indexOf("?");
-            if (queryStringPosition === -1) {
-                queryStringPosition = sceneFilename.length;
+            if (queryStringPosition !== -1) {
+                sceneFilename = sceneFilename.substring(0, queryStringPosition);
             }
-            var extension = sceneFilename.substring(dotPosition, queryStringPosition).toLowerCase();
+            var dotPosition = sceneFilename.lastIndexOf(".");
+            var extension = sceneFilename.substring(dotPosition, sceneFilename.length).toLowerCase();
             return SceneLoader._getPluginForExtension(extension);
         };
         // use babylon file loader directly if sceneFilename is prefixed with "data:"
@@ -80389,6 +80386,14 @@ var BABYLON;
                 this._loaderPendingCount = 0;
                 this._loaderTrackers = new Array();
                 this._parent = parent;
+                if (!GLTFLoader._progressEventFactory) {
+                    if (typeof window["ProgressEvent"] === "function") {
+                        GLTFLoader._progressEventFactory = GLTFLoader._createProgressEventByConstructor;
+                    }
+                    else {
+                        GLTFLoader._progressEventFactory = GLTFLoader._createProgressEventByDocument;
+                    }
+                }
             }
             GLTFLoader.RegisterExtension = function (extension) {
                 if (GLTFLoader.Extensions[extension.name]) {
@@ -80399,6 +80404,14 @@ var BABYLON;
                 // Keep the order of registration so that extensions registered first are called first.
                 GLTF2.GLTFLoaderExtension._Extensions.push(extension);
             };
+            GLTFLoader._createProgressEventByConstructor = function (name, data) {
+                return new ProgressEvent(name, data);
+            };
+            GLTFLoader._createProgressEventByDocument = function (name, data) {
+                var event = document.createEvent("ProgressEvent");
+                event.initProgressEvent(name, false, false, data.lengthComputable, data.loaded, data.total);
+                return event;
+            };
             GLTFLoader.prototype.dispose = function () {
                 if (this._disposed) {
                     return;
@@ -80459,7 +80472,7 @@ var BABYLON;
                     loaded += request._loaded;
                     total += request._total;
                 }
-                this._progressCallback(new ProgressEvent("GLTFLoaderProgress", {
+                this._progressCallback(GLTFLoader._progressEventFactory("GLTFLoaderProgress", {
                     lengthComputable: true,
                     loaded: loaded,
                     total: total

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 4068 - 4069
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts


+ 4 - 1
dist/preview release/gui/babylon.gui.js

@@ -212,6 +212,9 @@ var BABYLON;
                 if (this._pointerObserver) {
                     scene.onPointerObservable.remove(this._pointerObserver);
                 }
+                if (this._preKeyboardObserver) {
+                    scene.onPreKeyboardObservable.remove(this._preKeyboardObserver);
+                }
                 if (this._canvasPointerOutObserver) {
                     scene.getEngine().onCanvasPointerOutObservable.remove(this._canvasPointerOutObserver);
                 }
@@ -459,7 +462,7 @@ var BABYLON;
             AdvancedDynamicTexture.CreateFullscreenUI = function (name, foreground, scene) {
                 if (foreground === void 0) { foreground = true; }
                 if (scene === void 0) { scene = null; }
-                var result = new AdvancedDynamicTexture(name, 0, 0, scene);
+                var result = new AdvancedDynamicTexture(name, 0, 0, scene, false, BABYLON.Texture.BILINEAR_SAMPLINGMODE);
                 // Display
                 var layer = new BABYLON.Layer(name + "_layer", null, scene, !foreground);
                 layer.texture = result;

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 3 - 3
dist/preview release/gui/babylon.gui.min.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 14 - 14
dist/preview release/inspector/babylon.inspector.bundle.js


+ 3 - 0
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -324,6 +324,9 @@ declare module BABYLON.GLTF2 {
             [name: string]: GLTFLoaderExtension;
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
+        private static _progressEventFactory;
+        private static _createProgressEventByConstructor(name, data);
+        private static _createProgressEventByDocument(name, data);
         constructor(parent: GLTFFileLoader);
         dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;

+ 17 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -333,6 +333,14 @@ var BABYLON;
                 this._loaderPendingCount = 0;
                 this._loaderTrackers = new Array();
                 this._parent = parent;
+                if (!GLTFLoader._progressEventFactory) {
+                    if (typeof window["ProgressEvent"] === "function") {
+                        GLTFLoader._progressEventFactory = GLTFLoader._createProgressEventByConstructor;
+                    }
+                    else {
+                        GLTFLoader._progressEventFactory = GLTFLoader._createProgressEventByDocument;
+                    }
+                }
             }
             GLTFLoader.RegisterExtension = function (extension) {
                 if (GLTFLoader.Extensions[extension.name]) {
@@ -343,6 +351,14 @@ var BABYLON;
                 // Keep the order of registration so that extensions registered first are called first.
                 GLTF2.GLTFLoaderExtension._Extensions.push(extension);
             };
+            GLTFLoader._createProgressEventByConstructor = function (name, data) {
+                return new ProgressEvent(name, data);
+            };
+            GLTFLoader._createProgressEventByDocument = function (name, data) {
+                var event = document.createEvent("ProgressEvent");
+                event.initProgressEvent(name, false, false, data.lengthComputable, data.loaded, data.total);
+                return event;
+            };
             GLTFLoader.prototype.dispose = function () {
                 if (this._disposed) {
                     return;
@@ -403,7 +419,7 @@ var BABYLON;
                     loaded += request._loaded;
                     total += request._total;
                 }
-                this._progressCallback(new ProgressEvent("GLTFLoaderProgress", {
+                this._progressCallback(GLTFLoader._progressEventFactory("GLTFLoaderProgress", {
                     lengthComputable: true,
                     loaded: loaded,
                     total: total

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 3 - 0
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -871,6 +871,9 @@ declare module BABYLON.GLTF2 {
             [name: string]: GLTFLoaderExtension;
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
+        private static _progressEventFactory;
+        private static _createProgressEventByConstructor(name, data);
+        private static _createProgressEventByDocument(name, data);
         constructor(parent: GLTFFileLoader);
         dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;

+ 17 - 1
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -2478,6 +2478,14 @@ var BABYLON;
                 this._loaderPendingCount = 0;
                 this._loaderTrackers = new Array();
                 this._parent = parent;
+                if (!GLTFLoader._progressEventFactory) {
+                    if (typeof window["ProgressEvent"] === "function") {
+                        GLTFLoader._progressEventFactory = GLTFLoader._createProgressEventByConstructor;
+                    }
+                    else {
+                        GLTFLoader._progressEventFactory = GLTFLoader._createProgressEventByDocument;
+                    }
+                }
             }
             GLTFLoader.RegisterExtension = function (extension) {
                 if (GLTFLoader.Extensions[extension.name]) {
@@ -2488,6 +2496,14 @@ var BABYLON;
                 // Keep the order of registration so that extensions registered first are called first.
                 GLTF2.GLTFLoaderExtension._Extensions.push(extension);
             };
+            GLTFLoader._createProgressEventByConstructor = function (name, data) {
+                return new ProgressEvent(name, data);
+            };
+            GLTFLoader._createProgressEventByDocument = function (name, data) {
+                var event = document.createEvent("ProgressEvent");
+                event.initProgressEvent(name, false, false, data.lengthComputable, data.loaded, data.total);
+                return event;
+            };
             GLTFLoader.prototype.dispose = function () {
                 if (this._disposed) {
                     return;
@@ -2548,7 +2564,7 @@ var BABYLON;
                     loaded += request._loaded;
                     total += request._total;
                 }
-                this._progressCallback(new ProgressEvent("GLTFLoaderProgress", {
+                this._progressCallback(GLTFLoader._progressEventFactory("GLTFLoaderProgress", {
                     lengthComputable: true,
                     loaded: loaded,
                     total: total

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 3 - 3
dist/preview release/loaders/babylon.glTFFileLoader.min.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 1
dist/preview release/loaders/babylon.objFileLoader.min.js


+ 17 - 1
dist/preview release/loaders/babylonjs.loaders.js

@@ -3434,6 +3434,14 @@ var BABYLON;
                 this._loaderPendingCount = 0;
                 this._loaderTrackers = new Array();
                 this._parent = parent;
+                if (!GLTFLoader._progressEventFactory) {
+                    if (typeof window["ProgressEvent"] === "function") {
+                        GLTFLoader._progressEventFactory = GLTFLoader._createProgressEventByConstructor;
+                    }
+                    else {
+                        GLTFLoader._progressEventFactory = GLTFLoader._createProgressEventByDocument;
+                    }
+                }
             }
             GLTFLoader.RegisterExtension = function (extension) {
                 if (GLTFLoader.Extensions[extension.name]) {
@@ -3444,6 +3452,14 @@ var BABYLON;
                 // Keep the order of registration so that extensions registered first are called first.
                 GLTF2.GLTFLoaderExtension._Extensions.push(extension);
             };
+            GLTFLoader._createProgressEventByConstructor = function (name, data) {
+                return new ProgressEvent(name, data);
+            };
+            GLTFLoader._createProgressEventByDocument = function (name, data) {
+                var event = document.createEvent("ProgressEvent");
+                event.initProgressEvent(name, false, false, data.lengthComputable, data.loaded, data.total);
+                return event;
+            };
             GLTFLoader.prototype.dispose = function () {
                 if (this._disposed) {
                     return;
@@ -3504,7 +3520,7 @@ var BABYLON;
                     loaded += request._loaded;
                     total += request._total;
                 }
-                this._progressCallback(new ProgressEvent("GLTFLoaderProgress", {
+                this._progressCallback(GLTFLoader._progressEventFactory("GLTFLoaderProgress", {
                     lengthComputable: true,
                     loaded: loaded,
                     total: total

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 3 - 3
dist/preview release/loaders/babylonjs.loaders.min.js


+ 3 - 0
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -969,6 +969,9 @@ declare module BABYLON.GLTF2 {
             [name: string]: GLTFLoaderExtension;
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
+        private static _progressEventFactory;
+        private static _createProgressEventByConstructor(name, data);
+        private static _createProgressEventByDocument(name, data);
         constructor(parent: GLTFFileLoader);
         dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;

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

@@ -1,6 +1,8 @@
 # 3.1.0:
 
 ## Major updates
+- Viewer (TODO)
+- EnvironmentHelper + BackgroundMaterial (TODO)
 - Added support for webgl context lost and restored events. [Doc here](http://doc.babylonjs.com/tutorials/optimizing_your_scene#handling-webgl-context-lost) ([deltakosh](https://github.com/deltakosh))
 - Added support for non-pow2 textures when in WebGL2 mode ([deltakosh](https://github.com/deltakosh))
 - Engine can now be initialized with an existing webgl context ([deltakosh](https://github.com/deltakosh))
@@ -47,6 +49,7 @@
 - Added `enableDepthSort` parameter to the SPS in order to sort the particles from the camera position ([jerome](https://github.com/jbousquie)) 
 - Added `pivot` property to the SPS solid particles ([jerome](https://github.com/jbousquie)) 
 - Added the mesh facet depth sort to FacetData  ([jerome](https://github.com/jbousquie)) 
+- Added `LineSystem` and `LineMesh` per point colors ([jerome](https://github.com/jbousquie))  
 
 ## Bug fixes
 - Fixed a bug with PBR on iOS ([sebavan](https://github.com/sebavan))

+ 4 - 0
gui/src/advancedDynamicTexture.ts

@@ -215,6 +215,10 @@ module BABYLON.GUI {
                 scene.onPointerObservable.remove(this._pointerObserver);
             }
 
+            if (this._preKeyboardObserver) {
+                scene.onPreKeyboardObservable.remove(this._preKeyboardObserver);
+            }
+
             if (this._canvasPointerOutObserver) {
                 scene.getEngine().onCanvasPointerOutObservable.remove(this._canvasPointerOutObserver);
             }

+ 28 - 1
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -38,6 +38,12 @@ module BABYLON.GLTF2 {
         _total: Nullable<number>;
     }
 
+    interface IProgressEventData {
+        lengthComputable: boolean;
+        loaded: number;
+        total: number;
+    }
+
     export class GLTFLoader implements IGLTFLoader {
         public _gltf: IGLTF;
         public _babylonScene: Scene;
@@ -77,8 +83,29 @@ module BABYLON.GLTF2 {
             GLTFLoaderExtension._Extensions.push(extension);
         }
 
+        // IE 11 Compatibility.
+        private static _progressEventFactory: (name: string, data: IProgressEventData) => ProgressEvent;
+        
+        private static _createProgressEventByConstructor(name: string, data: IProgressEventData): ProgressEvent {
+            return new ProgressEvent(name, data);
+        }
+
+        private static _createProgressEventByDocument(name: string, data: IProgressEventData): ProgressEvent {
+            const event = document.createEvent("ProgressEvent");
+            event.initProgressEvent(name, false, false, data.lengthComputable, data.loaded, data.total);
+            return event;
+        }
+
         public constructor(parent: GLTFFileLoader) {
             this._parent = parent;
+            if (!GLTFLoader._progressEventFactory) {
+                if (typeof (<any>window)["ProgressEvent"] === "function") {
+                    GLTFLoader._progressEventFactory = GLTFLoader._createProgressEventByConstructor;
+                }
+                else {
+                    GLTFLoader._progressEventFactory = GLTFLoader._createProgressEventByDocument;
+                }
+            }
         }
 
         public dispose(): void {
@@ -148,7 +175,7 @@ module BABYLON.GLTF2 {
                 total += request._total;
             }
 
-            this._progressCallback(new ProgressEvent("GLTFLoaderProgress", {
+            this._progressCallback(GLTFLoader._progressEventFactory("GLTFLoaderProgress", {
                 lengthComputable: true,
                 loaded: loaded,
                 total: total

+ 1 - 2
package.json

@@ -16,7 +16,6 @@
     "main": "dist/preview release/babylon.max.js",
     "files": [
         "dist/preview release/babylon.d.ts",
-        "dist/preview release/babylon.module.d.ts",
         "dist/preview release/babylon.js",
         "dist/preview release/babylon.max.js",
         "dist/preview release/babylon.worker.js",
@@ -50,7 +49,7 @@
         "dist/preview release/Oimo.js",
         "package.json"
     ],
-    "typings": "dist/preview release/babylon.module.d.ts",
+    "typings": "dist/preview release/babylon.d.ts",
     "keywords": [
         "3D",
         "javascript",

+ 2 - 2
src/Helpers/babylon.environmentHelper.ts

@@ -100,7 +100,7 @@ namespace BABYLON {
          */
         skyboxTexture: string | BaseTexture;
         /**
-         * The color mixed in the ground texture by default.
+         * The color mixed in the skybox texture by default.
          * BabylonJS clearColor by default.
          */
         skyboxColor: Color3;
@@ -123,7 +123,7 @@ namespace BABYLON {
         rootPosition: Vector3;
 
         /**
-         * Sets up the inmage processing in the scene.
+         * Sets up the image processing in the scene.
          * true by default.
          */
         setupImageProcessing: boolean;

+ 6 - 6
src/Loading/babylon.sceneLoader.ts

@@ -125,15 +125,15 @@
                 sceneFilename = sceneFilename.name;
             }
 
-            var dotPosition = sceneFilename.lastIndexOf(".");
-
             var queryStringPosition = sceneFilename.indexOf("?");
-
-            if (queryStringPosition === -1) {
-                queryStringPosition = sceneFilename.length;
+            
+            if (queryStringPosition !== -1) {
+                sceneFilename = sceneFilename.substring(0, queryStringPosition);
             }
 
-            var extension = sceneFilename.substring(dotPosition, queryStringPosition).toLowerCase();
+            var dotPosition = sceneFilename.lastIndexOf(".");
+
+            var extension = sceneFilename.substring(dotPosition, sceneFilename.length).toLowerCase();
             return SceneLoader._getPluginForExtension(extension);
         }
 

+ 3 - 3
src/Math/babylon.math.ts

@@ -1749,7 +1749,7 @@
             matrix.invert();
             var screenSource = MathTmp.Vector3[0];
             screenSource.x = sourceX / viewportWidth * 2 - 1;
-            screenSource.y = sourceY/ viewportHeight * 2 - 1;
+            screenSource.y = -(sourceY/ viewportHeight * 2 - 1);
             screenSource.z = 2 * sourceZ - 1.0;
             Vector3.TransformCoordinatesToRef(screenSource, matrix, result);
             var num = screenSource.x * matrix.m[3] + screenSource.y * matrix.m[7] + screenSource.z * matrix.m[11] + matrix.m[15];
@@ -4703,7 +4703,7 @@
          * Returns the updated Path2.   
          */
         public addLineTo(x: number, y: number): Path2 {
-            if (closed) {
+            if (this.closed) {
                 //Tools.Error("cannot add lines to closed paths");
                 return this;
             }
@@ -4719,7 +4719,7 @@
          * Returns the updated Path2.  
          */
         public addArcTo(midX: number, midY: number, endX: number, endY: number, numberOfSegments = 36): Path2 {
-            if (closed) {
+            if (this.closed) {
                 //Tools.Error("cannot add arcs to closed paths");
                 return this;
             }

+ 10 - 3
src/Mesh/babylon.linesMesh.ts

@@ -32,26 +32,33 @@
         private _intersectionThreshold: number;
         private _colorShader: ShaderMaterial;
 
-        constructor(name: string, scene: Nullable<Scene> = null, parent: Nullable<Node> = null, source?: LinesMesh, doNotCloneChildren?: boolean, public useVertexColor?: boolean) {
+        constructor(name: string, scene: Nullable<Scene> = null, parent: Nullable<Node> = null, source?: LinesMesh, doNotCloneChildren?: boolean, public useVertexColor?: boolean, public useVertexAlpha?: boolean) {
             super(name, scene, parent, source, doNotCloneChildren);
 
             if (source) {
                 this.color = source.color.clone();
                 this.alpha = source.alpha;
                 this.useVertexColor = source.useVertexColor;
+                this.useVertexAlpha = source.useVertexAlpha;
             }
 
             this._intersectionThreshold = 0.1;
 
+            var defines: String[] = []; 
             var options = {
                 attributes: [VertexBuffer.PositionKind],
                 uniforms: ["world", "viewProjection"],
                 needAlphaBlending: false,
+                defines: defines
             };
-
+            
             if (!useVertexColor) {
                 options.uniforms.push("color");
-                options.needAlphaBlending = true;
+            }
+            else {
+                options.needAlphaBlending = (useVertexAlpha) ? true : false;
+                options.defines.push("#define VERTEXCOLOR");
+                options.attributes.push(VertexBuffer.ColorKind);
             }
 
             this._colorShader = new ShaderMaterial("colorShader", this.getScene(), "color", options);

+ 10 - 2
src/Mesh/babylon.mesh.vertexData.ts

@@ -1265,17 +1265,22 @@
         /**
          * Creates the VertexData of the LineSystem.  
          */
-        public static CreateLineSystem(options: { lines: Vector3[][] }): VertexData {
+        public static CreateLineSystem(options: { lines: Vector3[][], colors?: Nullable<Color4[][]> }): VertexData {
             var indices = [];
             var positions = [];
             var lines = options.lines;
+            var colors = options.colors;
+            var vertexColors = [];
             var idx = 0;
 
             for (var l = 0; l < lines.length; l++) {
                 var points = lines[l];
                 for (var index = 0; index < points.length; index++) {
                     positions.push(points[index].x, points[index].y, points[index].z);
-
+                    if (colors) {
+                        var color = colors[l];
+                        vertexColors.push(color[index].r, color[index].g, color[index].b, color[index].a);
+                    }
                     if (index > 0) {
                         indices.push(idx - 1);
                         indices.push(idx);
@@ -1286,6 +1291,9 @@
             var vertexData = new VertexData();
             vertexData.indices = indices;
             vertexData.positions = positions;
+            if (colors) {
+                vertexData.colors = vertexColors;
+            }
             return vertexData;
         }
 

+ 38 - 15
src/Mesh/babylon.meshBuilder.ts

@@ -358,33 +358,53 @@
          * Like every other parametric shape, it is dynamically updatable by passing an existing instance of LineSystem to this static function.  
          * The parameter `lines` is an array of lines, each line being an array of successive Vector3.   
          * The optional parameter `instance` is an instance of an existing LineSystem object to be updated with the passed `lines` parameter. The way to update it is the same than for 
+         * The optional parameter `colors` is an array of line colors, each line colors being an array of successive Color4, one per line point.  
+         * The optional parameter `useVertexAlpha' is to be set to `true` (default `false`) when the alpha value from the former `Color4` array must be used.  
          * updating a simple Line mesh, you just need to update every line in the `lines` array : http://doc.babylonjs.com/tutorials/How_to_dynamically_morph_a_mesh#lines-and-dashedlines   
          * When updating an instance, remember that only line point positions can change, not the number of points, neither the number of lines.      
          * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.  
          */
-        public static CreateLineSystem(name: string, options: { lines: Vector3[][], updatable: boolean, instance: Nullable<LinesMesh> }, scene: Nullable<Scene>): LinesMesh {
+        public static CreateLineSystem(name: string, options: { lines: Vector3[][], updatable: boolean, instance: Nullable<LinesMesh>, colors?: Nullable<Color4[][]>, useVertexAlpha?: boolean }, scene: Nullable<Scene>): LinesMesh {
             var instance = options.instance;
             var lines = options.lines;
+            var colors = options.colors;
 
             if (instance) { // lines update
-                var positionFunction = (positions: FloatArray) => {
-                    var i = 0;
-                    for (var l = 0; l < lines.length; l++) {
-                        var points = lines[l];
-                        for (var p = 0; p < points.length; p++) {
-                            positions[i] = points[p].x;
-                            positions[i + 1] = points[p].y;
-                            positions[i + 2] = points[p].z;
-                            i += 3;
+                var positions = instance.getVerticesData(VertexBuffer.PositionKind)!;
+                var vertexColor;
+                var lineColors;
+                if (colors) {
+                    vertexColor = instance.getVerticesData(VertexBuffer.ColorKind)!;
+                }
+                var i = 0;
+                var c = 0;
+                for (var l = 0; l < lines.length; l++) {
+                    var points = lines[l];
+                    for (var p = 0; p < points.length; p++) {
+                        positions[i] = points[p].x;
+                        positions[i + 1] = points[p].y;
+                        positions[i + 2] = points[p].z;
+                        if (colors && vertexColor) {
+                            lineColors = colors[l];
+                            vertexColor[c] = lineColors[p].r;
+                            vertexColor[c + 1] = lineColors[p].g;
+                            vertexColor[c + 2] = lineColors[p].b;
+                            vertexColor[c + 3] = lineColors[p].a;
+                            c += 4;
                         }
+                        i += 3;
                     }
-                };
-                instance.updateMeshPositions(positionFunction, false);
+                }
+                instance.updateVerticesData(VertexBuffer.PositionKind, positions, false, false);
+                if (colors && vertexColor) {
+                    instance.updateVerticesData(VertexBuffer.ColorKind, vertexColor, false, false)
+                }
                 return instance;
             }
 
             // line system creation
-            var lineSystem = new LinesMesh(name, scene);
+            var useVertexColor = (colors) ? true : false;
+            var lineSystem = new LinesMesh(name, scene, null, undefined, undefined, useVertexColor, options.useVertexAlpha);
             var vertexData = VertexData.CreateLineSystem(options);
             vertexData.applyToMesh(lineSystem, options.updatable);
             return lineSystem;
@@ -397,11 +417,14 @@
          * Like every other parametric shape, it is dynamically updatable by passing an existing instance of LineMesh to this static function.  
          * The parameter `points` is an array successive Vector3.   
          * The optional parameter `instance` is an instance of an existing LineMesh object to be updated with the passed `points` parameter : http://doc.babylonjs.com/tutorials/How_to_dynamically_morph_a_mesh#lines-and-dashedlines    
+         * The optional parameter `colors` is an array of successive Color4, one per line point.  
+         * The optional parameter `useVertexAlpha' is to be set to `true` (default `false`) when the alpha value from the former `Color4` array must be used.  
          * When updating an instance, remember that only point positions can change, not the number of points.      
          * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.  
          */
-        public static CreateLines(name: string, options: { points: Vector3[], updatable: boolean, instance: Nullable<LinesMesh> }, scene: Nullable<Scene> = null): LinesMesh {
-            var lines = MeshBuilder.CreateLineSystem(name, { lines: [options.points], updatable: options.updatable, instance: options.instance }, scene);
+        public static CreateLines(name: string, options: { points: Vector3[], updatable: boolean, instance: Nullable<LinesMesh>, colors?: Color4[], useVertexAlpha?: boolean }, scene: Nullable<Scene> = null): LinesMesh {
+            var colors = (options.colors) ? [options.colors] : null;
+            var lines = MeshBuilder.CreateLineSystem(name, { lines: [options.points], updatable: options.updatable, instance: options.instance, colors: colors, useVertexAlpha: options.useVertexAlpha }, scene);
             return lines;
         }
 

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 60 - 31
src/Tools/babylon.tools.ts


+ 105 - 102
src/babylon.scene.ts

@@ -96,7 +96,7 @@
         private static _FOGMODE_EXP2 = 2;
         private static _FOGMODE_LINEAR = 3;
 
-        private static _uniqueIdCounter = 0;        
+        private static _uniqueIdCounter = 0;
 
         public static MinDeltaTime = 1.0;
         public static MaxDeltaTime = 1000.0;
@@ -147,7 +147,7 @@
             if (this._environmentTexture === value) {
                 return;
             }
-            
+
             this._environmentTexture = value;
             this.markAllMaterialsAsDirty(Material.TextureDirtyFlag);
         }
@@ -253,37 +253,37 @@
         * An event triggered before animating the scene
         * @type {BABYLON.Observable}
         */
-        public onBeforeAnimationsObservable = new Observable<Scene>();       
-        
+        public onBeforeAnimationsObservable = new Observable<Scene>();
+
         /**
         * An event triggered after animations processing
         * @type {BABYLON.Observable}
         */
-        public onAfterAnimationsObservable = new Observable<Scene>();               
+        public onAfterAnimationsObservable = new Observable<Scene>();
 
         /**
         * An event triggered before draw calls are ready to be sent
         * @type {BABYLON.Observable}
         */
-        public onBeforeDrawPhaseObservable = new Observable<Scene>();          
+        public onBeforeDrawPhaseObservable = new Observable<Scene>();
 
         /**
         * An event triggered after draw calls have been sent
         * @type {BABYLON.Observable}
         */
-        public onAfterDrawPhaseObservable = new Observable<Scene>();         
-        
+        public onAfterDrawPhaseObservable = new Observable<Scene>();
+
         /**
         * An event triggered when physic simulation is about to be run
         * @type {BABYLON.Observable}
         */
-        public onBeforePhysicsObservable = new Observable<Scene>();          
-        
+        public onBeforePhysicsObservable = new Observable<Scene>();
+
         /**
         * An event triggered when physic simulation has been done
         * @type {BABYLON.Observable}
         */
-        public onAfterPhysicsObservable = new Observable<Scene>();           
+        public onAfterPhysicsObservable = new Observable<Scene>();
 
         /**
         * An event triggered when the scene is ready
@@ -324,47 +324,47 @@
         * An event triggered when active meshes evaluation is about to start
         * @type {BABYLON.Observable}
         */
-        public onBeforeActiveMeshesEvaluationObservable = new Observable<Scene>();        
+        public onBeforeActiveMeshesEvaluationObservable = new Observable<Scene>();
 
         /**
         * An event triggered when active meshes evaluation is done
         * @type {BABYLON.Observable}
         */
-        public onAfterActiveMeshesEvaluationObservable = new Observable<Scene>();           
+        public onAfterActiveMeshesEvaluationObservable = new Observable<Scene>();
 
         /**
         * An event triggered when particles rendering is about to start
         * Note: This event can be trigger more than once per frame (because particles can be rendered by render target textures as well)
         * @type {BABYLON.Observable}
         */
-        public onBeforeParticlesRenderingObservable = new Observable<Scene>();        
-        
+        public onBeforeParticlesRenderingObservable = new Observable<Scene>();
+
         /**
         * An event triggered when particles rendering is done
         * Note: This event can be trigger more than once per frame (because particles can be rendered by render target textures as well)
         * @type {BABYLON.Observable}
         */
-        public onAfterParticlesRenderingObservable = new Observable<Scene>();  
+        public onAfterParticlesRenderingObservable = new Observable<Scene>();
 
         /**
         * An event triggered when sprites rendering is about to start
         * Note: This event can be trigger more than once per frame (because sprites can be rendered by render target textures as well)
         * @type {BABYLON.Observable}
         */
-        public onBeforeSpritesRenderingObservable = new Observable<Scene>();        
-        
+        public onBeforeSpritesRenderingObservable = new Observable<Scene>();
+
         /**
         * An event triggered when sprites rendering is done
         * Note: This event can be trigger more than once per frame (because sprites can be rendered by render target textures as well)
         * @type {BABYLON.Observable}
         */
-        public onAfterSpritesRenderingObservable = new Observable<Scene>();          
+        public onAfterSpritesRenderingObservable = new Observable<Scene>();
 
         /**
         * An event triggered when SceneLoader.Append or SceneLoader.Load or SceneLoader.ImportMesh were successfully executed
         * @type {BABYLON.Observable}
         */
-        public onDataLoadedObservable = new Observable<Scene>();            
+        public onDataLoadedObservable = new Observable<Scene>();
 
         /**
         * An event triggered when a camera is created
@@ -407,12 +407,12 @@
         * @type {BABYLON.Observable}
         */
         public onNewTransformNodeAddedObservable = new Observable<TransformNode>();
-        
+
         /**
         * An event triggered when a transform node is removed
         * @type {BABYLON.Observable}
         */
-        public onTransformNodeRemovedObservable = new Observable<TransformNode>();        
+        public onTransformNodeRemovedObservable = new Observable<TransformNode>();
 
         /**
         * An event triggered when a mesh is created
@@ -432,13 +432,13 @@
         * @type {BABYLON.Observable}
         */
         public OnBeforeRenderTargetsRenderObservable = new Observable<Scene>();
-        
+
         /**
         * An event triggered when render targets were rendered.
         * Can happen multiple times per frame.
         * @type {BABYLON.Observable}
         */
-        public OnAfterRenderTargetsRenderObservable = new Observable<Scene>();      
+        public OnAfterRenderTargetsRenderObservable = new Observable<Scene>();
 
         /**
         * An event triggered before calculating deterministic simulation step
@@ -522,7 +522,6 @@
         private _meshPickProceed = false;
 
         private _previousButtonPressed: number;
-        private _previousHasSwiped = false;
         private _currentPickResult: Nullable<PickingInfo> = null;
         private _previousPickResult: Nullable<PickingInfo> = null;
         private _totalPointersPressed = 0;
@@ -554,7 +553,7 @@
          * You have the possibility to skip the process and the call to onKeyboardObservable by setting KeyboardInfoPre.skipOnPointerObservable to true
          */
         public onPreKeyboardObservable = new Observable<KeyboardInfoPre>();
-        
+
         /**
          * Observable event triggered each time an keyboard event is received from the hosting window
          */
@@ -1117,7 +1116,7 @@
 
         public getRenderTargetsDuration(): number {
             Tools.Warn("getRenderTargetsDuration is deprecated. Please use SceneInstrumentation class");
-            return 0;            
+            return 0;
         }
 
         public getRenderDuration(): number {
@@ -1201,7 +1200,7 @@
         }
 
         private _processPointerMove(pickResult: Nullable<PickingInfo>, evt: PointerEvent): Scene {
-            
+
             var canvas = this._engine.getRenderingCanvas();
 
             if (!canvas) {
@@ -1253,7 +1252,7 @@
                 }
             }
 
-            return this;            
+            return this;
         }
 
         /**
@@ -1264,7 +1263,7 @@
             let evt = new PointerEvent("pointerdown");
 
             return this._processPointerDown(pickResult, evt);
-        }        
+        }
 
         private _processPointerDown(pickResult: Nullable<PickingInfo>, evt: PointerEvent): Scene {
             if (pickResult && pickResult.hit && pickResult.pickedMesh) {
@@ -1331,9 +1330,9 @@
             clickInfo.singleClick = true;
 
             return this._processPointerUp(pickResult, evt, clickInfo);
-        }    
+        }
 
-        private _processPointerUp(pickResult: Nullable<PickingInfo>, evt: PointerEvent, clickInfo: ClickInfo): Scene {            
+        private _processPointerUp(pickResult: Nullable<PickingInfo>, evt: PointerEvent, clickInfo: ClickInfo): Scene {
             if (pickResult && pickResult && pickResult.pickedMesh) {
                 this._pickedUpMesh = pickResult.pickedMesh;
                 if (this._pickedDownMesh === this._pickedUpMesh) {
@@ -1506,7 +1505,6 @@
                                     this._previousStartingPointerPosition.x = this._startingPointerPosition.x;
                                     this._previousStartingPointerPosition.y = this._startingPointerPosition.y;
                                     this._previousButtonPressed = btn;
-                                    this._previousHasSwiped = clickInfo.hasSwiped;
                                     if (Scene.ExclusiveDoubleClickMode) {
                                         if (this._previousDelayedSimpleClickTimeout) {
                                             clearTimeout(this._previousDelayedSimpleClickTimeout);
@@ -1527,7 +1525,6 @@
                                 this._previousStartingPointerPosition.x = this._startingPointerPosition.x;
                                 this._previousStartingPointerPosition.y = this._startingPointerPosition.y;
                                 this._previousButtonPressed = btn;
-                                this._previousHasSwiped = clickInfo.hasSwiped;
                             }
                         }
                     }
@@ -1563,7 +1560,7 @@
                 }
 
                 // Meshes
-                var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, this.pointerMovePredicate, false, this.cameraToUseForPointers);             
+                var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, this.pointerMovePredicate, false, this.cameraToUseForPointers);
 
                 this._processPointerMove(pickResult, evt);
             };
@@ -1646,7 +1643,7 @@
                 this._pickedUpMesh = null;
                 this._meshPickProceed = false;
 
-                this._updatePointerPosition(evt);      
+                this._updatePointerPosition(evt);
                 this._initClickEvent(this.onPrePointerObservable, this.onPointerObservable, evt, (clickInfo: ClickInfo, pickResult: Nullable<PickingInfo>) => {
                     // PreObservable support
                     if (this.onPrePointerObservable.hasObservers()) {
@@ -1765,18 +1762,18 @@
             };
 
             let engine = this.getEngine();
-            this._onCanvasFocusObserver = engine.onCanvasFocusObservable.add(()=>{
+            this._onCanvasFocusObserver = engine.onCanvasFocusObservable.add(() => {
                 if (!canvas) {
                     return;
                 }
                 canvas.addEventListener("keydown", this._onKeyDown, false);
-                canvas.addEventListener("keyup", this._onKeyUp, false);   
+                canvas.addEventListener("keyup", this._onKeyUp, false);
             });
 
-            this._onCanvasBlurObserver = engine.onCanvasBlurObservable.add(()=>{       
+            this._onCanvasBlurObserver = engine.onCanvasBlurObservable.add(() => {
                 if (!canvas) {
                     return;
-                }                         
+                }
                 canvas.removeEventListener("keydown", this._onKeyDown);
                 canvas.removeEventListener("keyup", this._onKeyUp);
             });
@@ -1839,7 +1836,7 @@
             this.onKeyboardObservable.clear();
             this.onPreKeyboardObservable.clear();
             this.onPointerObservable.clear();
-            this.onPrePointerObservable.clear();     
+            this.onPrePointerObservable.clear();
         }
 
         // Ready
@@ -2085,7 +2082,7 @@
             this._useAlternateCameraConfiguration = active;
         }
 
-        public getViewMatrix(): Matrix {            
+        public getViewMatrix(): Matrix {
             return this._useAlternateCameraConfiguration ? this._alternateViewMatrix : this._viewMatrix;
         }
 
@@ -2148,7 +2145,7 @@
             if (!this._alternateSceneUbo) {
                 this._createAlternateUbo();
             }
-            
+
             if (this._alternateSceneUbo.useUbo) {
                 this._alternateSceneUbo.updateMatrix("viewProjection", this._alternateTransformMatrix);
                 this._alternateSceneUbo.updateMatrix("view", this._alternateViewMatrix);
@@ -2189,13 +2186,13 @@
             this.onMeshRemovedObservable.notifyObservers(toRemove);
 
             return index;
-        }        
+        }
 
         public addTransformNode(newTransformNode: TransformNode) {
             this.transformNodes.push(newTransformNode);
 
             this.onNewTransformNodeAddedObservable.notifyObservers(newTransformNode);
-        }        
+        }
 
         public removeTransformNode(toRemove: TransformNode): number {
             var index = this.transformNodes.indexOf(toRemove);
@@ -2623,7 +2620,7 @@
             return this.transformNodes.filter(function (m) {
                 return m.id === id;
             })
-        }        
+        }
 
         /**
          * Get a mesh with its auto-generated unique id
@@ -2672,7 +2669,7 @@
                 if (this.transformNodes[index].id === id) {
                     return this.transformNodes[index];
                 }
-            }            
+            }
 
             for (index = this.cameras.length - 1; index >= 0; index--) {
                 if (this.cameras[index].id === id) {
@@ -2755,7 +2752,7 @@
             }
 
             return null;
-        }        
+        }
 
         public getSoundByName(name: string): Nullable<Sound> {
             var index: number;
@@ -2926,7 +2923,7 @@
         public _isInIntermediateRendering(): boolean {
             return this._intermediateRendering
         }
-        
+
         private _activeMeshesFrozen = false;
 
         /**
@@ -2937,7 +2934,7 @@
             this._activeMeshesFrozen = true;
             return this;
         }
-        
+
         /**
          * Use this function to restart evaluating active meshes on every frame
          */
@@ -3013,7 +3010,7 @@
                 if (mesh.alwaysSelectAsActiveMesh || mesh.isVisible && mesh.visibility > 0 && ((mesh.layerMask & this.activeCamera.layerMask) !== 0) && mesh.isInFrustum(this._frustumPlanes)) {
                     this._activeMeshes.push(mesh);
                     this.activeCamera._activeMeshes.push(mesh);
-                        
+
                     mesh._activate(this._renderId);
                     if (meshLOD !== mesh) {
                         meshLOD._activate(this._renderId);
@@ -3060,7 +3057,7 @@
             if (sourceMesh.showBoundingBox || this.forceShowBoundingBoxes) {
                 let boundingInfo = sourceMesh.getBoundingInfo();
 
-                this.getBoundingBoxRenderer().renderList.push(boundingInfo.boundingBox);    
+                this.getBoundingBoxRenderer().renderList.push(boundingInfo.boundingBox);
             }
 
             if (mesh && mesh.subMeshes) {
@@ -3110,7 +3107,7 @@
                 throw new Error("Active camera not set");
 
             Tools.StartPerformanceCounter("Rendering camera " + this.activeCamera.name);
-           
+
             // Viewport
             engine.setViewport(this.activeCamera.viewport);
 
@@ -3214,7 +3211,7 @@
                 }
                 engine.setDepthBuffer(true);
             }
-        
+
             // Activate HighlightLayer stencil
             if (renderhighlights) {
                 this._engine.setStencilBuffer(true);
@@ -3273,7 +3270,7 @@
 
             // Finalize frame
             this.postProcessManager._finalizeFrame(camera.isIntermediate);
-           
+
             // Reset some special arrays
             this._renderTargets.reset();
 
@@ -3294,7 +3291,7 @@
             if (this.activeCamera) {
                 this.activeCamera.update();
             }
-            
+
             // rig cameras
             for (var index = 0; index < camera._rigCameras.length; index++) {
                 this._renderForCamera(camera._rigCameras[index]);
@@ -3371,60 +3368,66 @@
                 this.simplificationQueue.executeNext();
             }
 
-            if(this._engine.isDeterministicLockStep()){
-              var deltaTime = Math.max(Scene.MinDeltaTime, Math.min(this._engine.getDeltaTime(), Scene.MaxDeltaTime)) / 1000;
+            if (this._engine.isDeterministicLockStep()) {
+                var deltaTime = Math.max(Scene.MinDeltaTime, Math.min(this._engine.getDeltaTime(), Scene.MaxDeltaTime)) + this._timeAccumulator;
+
+                var defaultFPS = (60.0 / 1000.0);
+
+                let defaultFrameTime = 1000 / 60; // frame time in MS
+
+                if (this._physicsEngine) {
+                    defaultFrameTime = this._physicsEngine.getTimeStep() / 1000; //timestep in physics engine is in seconds
+                }
+                let stepsTaken = 0;
+
+                var maxSubSteps = this._engine.getLockstepMaxSteps();
+
+                var internalSteps = Math.floor(deltaTime / (1000 * defaultFPS));
+                internalSteps = Math.min(internalSteps, maxSubSteps);
 
-              var defaultTimeStep = (60.0 / 1000.0);
-              if (this._physicsEngine) {
-                defaultTimeStep = this._physicsEngine.getTimeStep();
-              }
+                do {
+                    this.onBeforeStepObservable.notifyObservers(this);
 
-              var maxSubSteps = this._engine.getLockstepMaxSteps();
+                    // Animations
+                    this._animationRatio = defaultFrameTime * defaultFPS;
+                    this._animate();
+                    this.onAfterAnimationsObservable.notifyObservers(this);
 
-              this._timeAccumulator += deltaTime;
+                    // Physics
+                    if (this._physicsEngine) {
+                        this.onBeforePhysicsObservable.notifyObservers(this);
+                        this._physicsEngine._step(defaultFPS);
+                        this.onAfterPhysicsObservable.notifyObservers(this);
+                    }
 
-              // compute the amount of fixed steps we should have taken since the last step
-              var internalSteps = Math.floor(this._timeAccumulator / defaultTimeStep);
-              internalSteps = Math.min(internalSteps, maxSubSteps);
+                    this.onAfterStepObservable.notifyObservers(this);
+                    this._currentStepId++;
 
-              for(this._currentInternalStep = 0; this._currentInternalStep < internalSteps; this._currentInternalStep++){
+                    if ((internalSteps > 1) && (stepsTaken != internalSteps - 1)) {
+                        this._evaluateActiveMeshes();
+                    }
 
-                this.onBeforeStepObservable.notifyObservers(this);
+                    stepsTaken++;
+                    deltaTime -= defaultFrameTime;
 
+                } while (deltaTime > 0 && stepsTaken > maxSubSteps);
+
+                this._timeAccumulator = deltaTime;
+
+            }
+            else {
                 // Animations
-                this._animationRatio = defaultTimeStep * (60.0 / 1000.0);
+                var deltaTime = Math.max(Scene.MinDeltaTime, Math.min(this._engine.getDeltaTime(), Scene.MaxDeltaTime));
+                this._animationRatio = deltaTime * (60.0 / 1000.0);
                 this._animate();
                 this.onAfterAnimationsObservable.notifyObservers(this);
 
                 // Physics
                 if (this._physicsEngine) {
-                   this.onBeforePhysicsObservable.notifyObservers(this);
-                   this._physicsEngine._step(defaultTimeStep);
-                   this.onAfterPhysicsObservable.notifyObservers(this);
-                }
-                this._timeAccumulator -= defaultTimeStep;
-
-                this.onAfterStepObservable.notifyObservers(this);
-                this._currentStepId++;
-
-                if((internalSteps > 1) && (this._currentInternalStep != internalSteps - 1)) {
-                    this._evaluateActiveMeshes();
+                    this.onBeforePhysicsObservable.notifyObservers(this);
+                    this._physicsEngine._step(deltaTime / 1000.0);
+                    this.onAfterPhysicsObservable.notifyObservers(this);
                 }
-              }
-            }
-            else {
-              // Animations
-              var deltaTime = Math.max(Scene.MinDeltaTime, Math.min(this._engine.getDeltaTime(), Scene.MaxDeltaTime));
-              this._animationRatio = deltaTime * (60.0 / 1000.0);
-              this._animate();
-              this.onAfterAnimationsObservable.notifyObservers(this);
-
-              // Physics
-              if (this._physicsEngine) {
-                this.onBeforePhysicsObservable.notifyObservers(this);
-                this._physicsEngine._step(deltaTime / 1000.0);
-                this.onAfterPhysicsObservable.notifyObservers(this);
-              }
             }
 
             // Before render
@@ -4004,7 +4007,7 @@
             // Moving coordinates to local viewport world
             x = x / this._engine.getHardwareScalingLevel() - viewport.x;
             y = y / this._engine.getHardwareScalingLevel() - (this._engine.getRenderHeight() - viewport.y - viewport.height);
-            
+
             result.update(x, y, viewport.width, viewport.height, world ? world : Matrix.Identity(), cameraViewSpace ? Matrix.Identity() : camera.getViewMatrix(), camera.getProjectionMatrix());
             return this;
         }
@@ -4181,7 +4184,7 @@
         public pickSprite(x: number, y: number, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean, camera?: Camera): Nullable<PickingInfo> {
             if (!this._tempPickingRay) {
                 this._tempPickingRay = Ray.Zero();
-            }            
+            }
             this.createPickingRayInCameraSpaceToRef(x, y, this._tempPickingRay, camera);
 
             return this._internalPickSprites(this._tempPickingRay, predicate, fastCheck, camera);
@@ -4204,7 +4207,7 @@
                 if (!this._cachedRayForTransform) {
                     this._cachedRayForTransform = Ray.Zero();
                 }
-                
+
                 Ray.TransformToRef(ray, this._pickWithRayInverseMatrix, this._cachedRayForTransform);
                 return this._cachedRayForTransform;
             }, predicate, fastCheck);
@@ -4236,7 +4239,7 @@
                 if (!this._cachedRayForTransform) {
                     this._cachedRayForTransform = Ray.Zero();
                 }
-                
+
                 Ray.TransformToRef(ray, this._pickWithRayInverseMatrix, this._cachedRayForTransform);
                 return this._cachedRayForTransform;
             }, predicate);
@@ -4340,7 +4343,7 @@
 
             if (this.postProcessManager) {
                 this.postProcessManager._rebuild();
-            }         
+            }
 
             for (var layer of this.layers) {
                 layer._rebuild();
@@ -4360,7 +4363,7 @@
 
             if (this._postProcessRenderPipelineManager) {
                 this._postProcessRenderPipelineManager._rebuild();
-            }            
+            }
         }
 
         public _rebuildTextures(): void {

BIN
tests/validation/ReferenceImages/gltfMaterial.png


BIN
tests/validation/ReferenceImages/gltfMaterialAlpha.png


BIN
tests/validation/ReferenceImages/gltfMaterialMetallicRoughness.png


BIN
tests/validation/ReferenceImages/gltfMaterialSpecularGlossiness.png


BIN
tests/validation/ReferenceImages/gltfPrimitiveAttribute.png


BIN
tests/validation/ReferenceImages/gltfTextureSampler.png


+ 42 - 0
tests/validation/config.json

@@ -188,6 +188,48 @@
       "referenceImage": "gltfnormals.png"
     },
     {
+      "title": "GLTF Material",
+      "renderCount": 20,
+      "scriptToRun": "/Demos/GLTFTests/index.js",
+      "functionToCall": "createMaterialScene",
+      "referenceImage": "gltfMaterial.png"
+    },
+    {
+      "title": "GLTF Material Alpha",
+      "renderCount": 20,
+      "scriptToRun": "/Demos/GLTFTests/index.js",
+      "functionToCall": "createMaterialAlphaScene",
+      "referenceImage": "gltfMaterialAlpha.png"
+    },
+    {
+      "title": "GLTF Primitive Attribute",
+      "renderCount": 20,
+      "scriptToRun": "/Demos/GLTFTests/index.js",
+      "functionToCall": "createPrimitiveAttributeScene",
+      "referenceImage": "gltfPrimitiveAttribute.png"
+    },
+    {
+      "title": "GLTF Metallic Roughness",
+      "renderCount": 20,
+      "scriptToRun": "/Demos/GLTFTests/index.js",
+      "functionToCall": "createMaterialMetallicRoughnessScene",
+      "referenceImage": "gltfMaterialMetallicRoughness.png"
+    },
+    {
+      "title": "GLTF Specular Glossiness",
+      "renderCount": 20,
+      "scriptToRun": "/Demos/GLTFTests/index.js",
+      "functionToCall": "createMaterialSpecularGlossinessScene",
+      "referenceImage": "gltfMaterialSpecularGlossiness.png"
+    },
+    {
+      "title": "GLTF Texture Sampler",
+      "renderCount": 20,
+      "scriptToRun": "/Demos/GLTFTests/index.js",
+      "functionToCall": "createTextureSamplerScene",
+      "referenceImage": "gltfTextureSampler.png"
+    },
+    {
       "title": "PBR glossy",
       "renderCount": 20,
       "replace": "engine.setHardwareScalingLevel, //engine.setHardwareScalingLevel",