Explorar o código

Merge remote-tracking branch 'upstream/master' into glTFFileLoader

Gary Hsu %!s(int64=8) %!d(string=hai) anos
pai
achega
da0915734a
Modificáronse 56 ficheiros con 3710 adicións e 12124 borrados
  1. BIN=BIN
      Exporters/Blender/Blender2Babylon-5.2.zip
  2. 2 2
      Exporters/Blender/src/babylon-js/__init__.py
  3. 4 1
      Exporters/Blender/src/babylon-js/json_exporter.py
  4. 5 2
      Exporters/Blender/src/babylon-js/world.py
  5. 0 1109
      Playground/bootstrap/css/bootstrap-responsive.css
  6. 0 9
      Playground/bootstrap/css/bootstrap-responsive.min.css
  7. 0 6167
      Playground/bootstrap/css/bootstrap.css
  8. 0 9
      Playground/bootstrap/css/bootstrap.min.css
  9. BIN=BIN
      Playground/bootstrap/img/glyphicons-halflings-white.png
  10. BIN=BIN
      Playground/bootstrap/img/glyphicons-halflings.png
  11. 0 2280
      Playground/bootstrap/js/bootstrap.js
  12. 0 6
      Playground/bootstrap/js/bootstrap.min.js
  13. 459 0
      Playground/css/index.css
  14. 127 96
      Playground/debug.html
  15. 8 7
      Playground/frame.html
  16. 0 1
      Playground/hand.minified-1.2.js
  17. 102 70
      Playground/index-local.html
  18. 0 188
      Playground/index.css
  19. 100 79
      Playground/index.html
  20. 106 82
      Playground/index2_5.html
  21. 63 0
      Playground/js/actions.js
  22. 122 38
      Playground/index.js
  23. 0 0
      Playground/js/libs/fileSaver.js
  24. 13 13
      Playground/jszip.min.js
  25. 587 0
      Playground/js/libs/split.js
  26. 5 3
      Playground/package.json
  27. 0 146
      Playground/splitbox.css
  28. 0 116
      Playground/splitbox.js
  29. 55 0
      Playground/test.html
  30. 0 2
      Playground/xtag.min.js
  31. 22 22
      dist/preview release/babylon.core.js
  32. 613 611
      dist/preview release/babylon.d.ts
  33. 37 37
      dist/preview release/babylon.js
  34. 49 40
      dist/preview release/babylon.max.js
  35. 613 611
      dist/preview release/babylon.module.d.ts
  36. 32 32
      dist/preview release/babylon.noworker.js
  37. 5 5
      dist/preview release/loaders/babylon.glTF1FileLoader.d.ts
  38. 5 4
      dist/preview release/loaders/babylon.glTF1FileLoader.js
  39. 1 1
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  40. 20 18
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  41. 220 116
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  42. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  43. 21 19
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  44. 220 117
      dist/preview release/loaders/babylon.glTFFileLoader.js
  45. 2 2
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  46. 5 1
      src/Debug/babylon.debugLayer.ts
  47. 25 6
      src/Materials/babylon.material.ts
  48. 1 1
      src/Mesh/babylon.abstractMesh.ts
  49. 7 0
      src/Mesh/babylon.geometry.ts
  50. 1 1
      src/Mesh/babylon.subMesh.ts
  51. 0 30
      src/Tools/babylon.extendedGamepad.ts
  52. 9 3
      src/babylon.engine.ts
  53. BIN=BIN
      tests/validation/ReferenceImages/fresnel.png
  54. BIN=BIN
      tests/validation/ReferenceImages/softShadows.png
  55. 16 3
      tests/validation/config.json
  56. 27 17
      tests/validation/validation.js

BIN=BIN
Exporters/Blender/Blender2Babylon-5.2.zip


+ 2 - 2
Exporters/Blender/src/babylon-js/__init__.py

@@ -1,7 +1,7 @@
 bl_info = {
     'name': 'Babylon.js',
     'author': 'David Catuhe, Jeff Palmer',
-    'version': (5, 2, 0),
+    'version': (5, 2, 1),
     'blender': (2, 76, 0),
     'location': 'File > Export > Babylon.js (.babylon)',
     'description': 'Export Babylon.js scenes (.babylon)',
@@ -11,7 +11,7 @@ bl_info = {
 
 # allow module to be changed during a session (dev purposes)
 if "bpy" in locals():
-    print('Reloading TOB exporter')
+    print('Reloading .babylon exporter')
     import imp
     imp.reload(animation)
     imp.reload(armature)

+ 4 - 1
Exporters/Blender/src/babylon-js/json_exporter.py

@@ -66,6 +66,7 @@ class JsonExporter:
             self.materials = []
             self.multiMaterials = []
             self.sounds = []
+            self.needPhysics = False
 
             # Scene level sound
             if scene.attachedSound != '':
@@ -102,6 +103,8 @@ class JsonExporter:
                             Logger.log(self.fatalError)
                             return
 
+                        if hasattr(mesh, 'physicsImpostor'): self.needPhysics = True
+                        
                         if hasattr(mesh, 'instances'):
                             self.meshesAndNodes.append(mesh)
                         else:
@@ -161,7 +164,7 @@ class JsonExporter:
         file_handler = open(self.filepathMinusExtension + '.babylon', 'w', encoding='utf8')
         file_handler.write('{')
         file_handler.write('"producer":{"name":"Blender","version":"' + bpy.app.version_string + '","exporter_version":"' + format_exporter_version() + '","file":"' + JsonExporter.nameSpace + '.babylon"},\n')
-        self.world.to_scene_file(file_handler)
+        self.world.to_scene_file(file_handler, self.needPhysics)
 
         # Materials
         file_handler.write(',\n"materials":[')

+ 5 - 2
Exporters/Blender/src/babylon-js/world.py

@@ -31,12 +31,15 @@ class World:
 
         Logger.log('Python World class constructor completed')
 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-    def to_scene_file(self, file_handler):
+    def to_scene_file(self, file_handler, needPhysics):
         write_bool(file_handler, 'autoClear', self.autoClear, True)
         write_color(file_handler, 'clearColor', self.clear_color)
         write_color(file_handler, 'ambientColor', self.ambient_color)
         write_vector(file_handler, 'gravity', self.gravity)
-
+        
+        if needPhysics:
+            write_bool(file_handler, 'physicsEnabled', True)
+            
         if hasattr(self, 'fogMode'):
             write_int(file_handler, 'fogMode', self.fogMode)
             write_color(file_handler, 'fogColor', self.fogColor)

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 1109
Playground/bootstrap/css/bootstrap-responsive.css


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 9
Playground/bootstrap/css/bootstrap-responsive.min.css


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 6167
Playground/bootstrap/css/bootstrap.css


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 9
Playground/bootstrap/css/bootstrap.min.css


BIN=BIN
Playground/bootstrap/img/glyphicons-halflings-white.png


BIN=BIN
Playground/bootstrap/img/glyphicons-halflings.png


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 2280
Playground/bootstrap/js/bootstrap.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 6
Playground/bootstrap/js/bootstrap.min.js


+ 459 - 0
Playground/css/index.css

@@ -0,0 +1,459 @@
+@import url("https://fonts.googleapis.com/css?family=Montserrat:300,400");
+@import url("https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css");
+html,
+body {
+    width: 100%;
+    height: 100%;
+    margin: 0;
+    padding: 0;
+    overflow: hidden;
+    font-family: sans-serif;
+}
+.wrapper {
+    height: calc(100% - 40px - 30px); /* nvabar top and bottom*/
+    width: 100%;
+    display: -ms-flexbox;
+    display: flex;
+    -ms-flex-direction: row;
+    flex-direction: row;
+}
+.wrapper .gutter {
+    background-color: #f7f7f7;
+    background-repeat: no-repeat;
+    background-position: 50%;
+}
+.wrapper .gutter.light {
+    background-color: #f7f7f7;
+}
+.wrapper .gutter.dark {
+    background-color: #333;
+}
+
+.wrapper .gutter:hover {
+    cursor: ew-resize;
+}
+.wrapper .gutter.gutter-vertical {
+    background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAFAQMAAABo7865AAAABlBMVEVHcEzMzMzyAv2sAAAAAXRSTlMAQObYZgAAABBJREFUeF5jOAMEEAIEEFwAn3kMwcB6I2AAAAAASUVORK5CYII=");
+}
+.wrapper .gutter.gutter-horizontal {
+    background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==");
+}
+.wrapper #jsEditor {
+    padding-top:5px;
+    height: 100%;
+}
+
+.wrapper #jsEditor.light {
+    background-color: white;
+}
+.wrapper #jsEditor.dark {
+    background-color: #1e1e1e;
+}
+.wrapper #canvasZone {
+    height: 100%;
+}
+#renderCanvas {
+    width: 100%;
+    height: 100%;
+    touch-action: none;
+}
+#fpsLabel {
+    position: absolute;
+    right: 10px;
+    top: 50px;
+    cursor: default;
+    z-index:10;
+    background-color: #7283a0;
+    color:white;
+    padding:5px;
+    border-radius: 3px;
+    font-family: 'Montserrat'
+}
+.navbar {
+    height: 40px;
+    width: 100%;
+    font-family: "Montserrat";
+    font-weight: 400;
+    -webkit-user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+    position: relative;
+    z-index:5;
+    line-height: 40px;
+}
+.navbar.dark {
+    background-color: #333;
+    box-shadow: 0 3px 10px #000;
+}
+.navbar.light {
+    background-color: #efefef;
+    box-shadow: 0 3px 10px #999;
+}
+.navbar .title {
+    height: 40px;
+    padding-left: 10px;
+    color: #15A4FA;
+    display: inline-block;
+}
+.navbar .version {
+    height: 40px;
+    display: inline-block;
+    color: #7283a0;
+    margin-right: 20px;
+}
+.navbar .category {
+    height: 40px;
+    margin: 0 15px 0 15px;
+    display: inline-block;
+}
+.navbar .category.right {
+    position: absolute;
+    right: 0;
+    top: 0;
+}
+.button {
+    display: inline-block;
+    height: 25px;
+    line-height: 25px;
+    color: white;
+    background-color: #7283a0;
+    margin: 0 2px 0 2px;
+    padding: 0 10px 0 10px;
+    font-size: 0.85em;
+    border-radius: 3px;
+}
+
+.button i {
+    margin-left: 10px;
+}
+.button:hover {
+    cursor: pointer;
+    background-color: #15A4FA;
+}
+.navbar .button.run {
+    height: 30px;
+    line-height: 30px;
+    background-color: #15A4FA;
+    font-size: 1.0em;
+}
+.navbar .select {
+    position: relative;
+}
+.navbar .select:after {
+    font-family: 'FontAwesome', sans-serif;
+    content: "\00a0 \00a0 \00a0 \f078";
+}
+.navbar .select .toDisplay {
+    border: 1px solid #7283a0;
+    position: absolute;
+    z-index: 10;
+    left: 0;
+    top: 25px;
+    min-width: 100%;
+    display: none;
+}
+.navbar .select .toDisplay .option {
+    font-size: 0.9em;
+    height: 35px;
+    line-height: 35px;
+    padding: 0px 5px 0px 5px;
+    text-align: center;
+    border-bottom : 1px solid rgba(0,0,0,0.1);
+}
+
+.navbar .select .toDisplay .option.light:hover {
+    cursor: pointer;
+    background-color: #d9d9d9;
+}
+
+
+.navbar .select .toDisplay .option.dark {
+    background-color: #333;
+    color: white;
+}
+.navbar .select .toDisplay .option.light {
+    background-color: white;
+    color: #7283a0;
+}
+.navbar .select .toDisplay .option.dark:hover {
+    cursor: pointer;
+    background-color: #555;
+}
+
+.navbar .select .toDisplayBig {
+    border: 1px solid #7283a0;
+    border-radius: 5px;
+    position: absolute;
+    z-index: 10;
+    top: 32px;
+    width:550px;
+    max-height:350px;
+    right:0;
+    position:absolute;
+    font-size:0.8em;
+    display: none;
+    
+}
+
+.navbar .select .toDisplayBig.light {
+    background-color: white;    
+    color: #15A4FA;
+}
+
+.navbar .select .toDisplayBig.dark {
+    background-color: #333;    
+    color:white;
+}
+
+.navbar .select .toDisplayBig ul {
+    column-count: 3;        
+    padding:0;
+    margin:0;
+    list-style: none;
+}
+
+.navbar .select .toDisplayBig ul li {
+    padding:0 5px 0 5px;
+}
+
+.navbar .select .toDisplayBig ul li:hover {
+    cursor: pointer;
+}
+.navbar .select .toDisplayBig ul li.light:hover {
+    background-color: #d9d9d9;
+}
+.navbar .select .toDisplayBig ul li.dark:hover {
+    background-color: #555;
+}
+
+
+.navbar .select .toDisplayBig a {
+    text-decoration: none;
+}
+
+.navbar .select .toDisplayBig a.dark {
+    color: white;
+}
+
+.navbar .select .toDisplayBig a.light {
+    color: #7283a0;
+}
+
+
+
+.navbar .check:after {
+    font-family: 'FontAwesome', sans-serif;
+    content: "\00a0 \00a0 \00a0 \f14a";
+}
+.navbar .check.uncheck {
+    background-color: #8290aa;
+}
+.navbar .check.uncheck:after {
+    font-family: 'FontAwesome', sans-serif;
+    content: "\00a0 \00a0 \00a0 \f096";
+}
+#errorZone {
+    display:none;
+    position: absolute;
+    width: 50%;
+    left: 25%;
+    bottom: 40px;
+    background-color: #C73228;
+    padding:20px;
+    border-radius: 5px;
+    color:white;
+    font-family: 'Inconsolata';
+}
+#errorZone button {
+    position:absolute;
+    top : 3px;
+    right: 10px;
+    padding: 0;
+    cursor: pointer;
+    background: transparent;
+    border: 0;
+    -webkit-appearance: none;
+    color: #000;
+    text-shadow: 0 1px 0 #fff;
+    opacity: .4;
+    font-size: 1.8em;
+}
+
+/* Navbar bottom */
+
+.navbarBottom {
+    height:30px;
+    width:100%;
+    line-height:30px;
+    position:relative;
+    font-family: 'Montserrat';
+}
+.navbarBottom.dark {
+    background-color: #333;
+}
+.navbarBottom.light {
+    background-color: #efefef;
+}
+
+.navbarBottom #statusBar {
+    line-height:30px;
+    color: #E74C3C;
+    font-family: 'Inconsolata';
+    padding-left:20px;
+}
+
+
+.navbarBottom .links {
+    position:absolute;
+    right : 0;
+    top:-1px;
+    height:30px;
+    padding-right:20px;
+}
+.navbarBottom .links .link{
+    height:30px;
+    display:inline-block;
+    color:#999;
+    padding: 0 10px 0 10px;
+    margin : 0 5px 0 5px;
+    font-size:0.8em;
+}
+.navbarBottom .links .link.light:hover{
+    color:#999;
+    background-color:#333;
+}
+.navbarBottom .links .link.dark:hover{
+    color:#333;
+    background-color:#eee;
+}
+.navbarBottom .links .link a{
+    text-decoration: none;
+    color:#999;
+    display: inline-block;
+}
+
+/* MONACO */
+
+.monaco-editor .container:before,
+.monaco-editor .row:before {
+    content: "";
+    display: inherit;
+}
+.monaco-editor .container:after,
+.monaco-editor .row:after {
+    clear: inherit;
+}
+.monaco-editor .container {
+    width: auto;
+    margin: inherit;
+    padding: inherit;
+}
+.monaco-editor .close {
+    float: none;
+    font-size: inherit;
+    font-weight: inherit;
+    line-height: inherit;
+    color: inherit;
+    text-shadow: inherit;
+    opacity: inherit;
+    filter: inherit;
+}
+.monaco-editor .row {
+    margin: inherit;
+}
+.monaco-editor .invisible {
+    visibility: visible;
+}
+.monaco-editor .view-lines {
+    font-family: 'Inconsolata' !important;
+}
+/* Save form & co */
+
+.save-message {
+    display: none;
+    position:absolute;
+    top:40px; /* navbar top */
+    width: 100%;
+    z-index:5;
+    text-align: center;
+    font-size: 0.8em;
+    line-height: 2em;
+    cursor:pointer;
+}
+
+.save-message.light {
+    background-color: rgba(239, 239, 239, 0.9);
+    color: #7283a0;
+}
+
+.save-message.dark {
+    background-color: rgba(51, 51, 51, 0.9);
+    color: #eee;
+}
+
+.save-layer {
+    display: none;
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    background-color: rgba(120, 120, 120, .5);
+    text-align: center;
+}
+.save-layer .save-form {
+    position: absolute;
+    top: 150px;
+    left: calc(50% - 205px);
+    width: 410px;
+    height: 370px;
+    padding-top: 15px;
+    -webkit-border-radius: 6px;
+    -moz-border-radius: 6px;
+    border-radius: 6px;
+    background-color: rgba(27, 27, 27, 0.75);
+    border-color: #252525;
+    color: white;
+    font-family: "Montserrat";
+    font-size: 14px;
+}
+.save-layer .save-form .separator {
+    width: 350px;
+    border-bottom: 1px solid #999;
+    margin: auto;
+    margin-bottom: 10px;
+}
+.save-layer .save-form input,
+.save-layer .save-form textarea {
+    display:block;
+    width: 350px;
+    margin:auto;
+    margin-bottom: 20px;
+    font-family: "Montserrat";
+    padding:5px;
+}
+
+/*Media queries*/
+
+@media (max-width: 1600px) {
+    .desktopOnly {
+        display: none !important;
+    }
+}
+@media (max-width: 1375px) {
+    .desktopOnly {
+        display: none !important;
+    }
+    .desktopTabletOnly {
+        display: none !important;
+    }
+}
+@media (max-width: 975px) {
+    .title {
+        display : none !important;
+    }
+    .version {
+        display : none !important;
+    }
+}

+ 127 - 96
Playground/debug.html

@@ -1,132 +1,157 @@
 <!DOCTYPE html>
 <html>
+
 <head>
     <title>Babylon.js Playground</title>
+    <meta charset='utf-8' />
+    <meta name="viewport" content="width=device-width, user-scalable=no">
     <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/poly2tri.js"></script>    
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.js"></script>
-    <!--x-tag-->
-    <script src="xtag.min.js"></script>
-    <script src="splitbox.js"></script>
-    <link href="splitbox.css" rel="stylesheet" />
+    <!--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="jszip.min.js"></script>
-    <script src="fileSaver.js"></script>
-    <!-- Bootstrap -->
-    <link href="bootstrap/css/bootstrap.css" rel="stylesheet">
+    <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://babylonjs.azurewebsites.net/cannon.js"></script>
     <script src="https://babylonjs.azurewebsites.net/Oimo.js"></script>
-    <!--<script src="../babylon.js"></script>-->
     <script src="https://babylonjs.azurewebsites.net/babylon.max.js"></script>
     <script src="https://babylonjs.azurewebsites.net/babylon.canvas2d.js"></script>
-    
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.fireMaterial.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.waterMaterial.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.lavaMaterial.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.normalMaterial.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.skyMaterial.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.triPlanarMaterial.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.terrainMaterial.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.gradientMaterial.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.furMaterial.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.gridMaterial.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.shadowOnlyMaterial.js"></script>    
-
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.brickProceduralTexture.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.cloudProceduralTexture.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.fireProceduralTexture.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.grassProceduralTexture.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.marbleProceduralTexture.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.roadProceduralTexture.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.starfieldProceduralTexture.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.woodProceduralTexture.js"></script>
-
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.asciiArtPostProcess.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.digitalRainPostProcess.js"></script>    
+    <script src="https://babylonjs.azurewebsites.net/babylon.inspector.bundle.js"></script>
+
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.fireMaterial.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.waterMaterial.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.lavaMaterial.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.normalMaterial.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.skyMaterial.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.triPlanarMaterial.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.terrainMaterial.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.gradientMaterial.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.furMaterial.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.gridMaterial.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.shadowOnlyMaterial.min.js"></script>
+
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.brickProceduralTexture.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.cloudProceduralTexture.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.fireProceduralTexture.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.grassProceduralTexture.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.marbleProceduralTexture.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.roadProceduralTexture.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.starfieldProceduralTexture.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.woodProceduralTexture.min.js"></script>
+
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.asciiArtPostProcess.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.digitalRainPostProcess.min.js"></script>
 
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.glTFFileLoader.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.objFileLoader.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.stlFileLoader.js"></script>
 
     <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>
-    <link href="index.css" rel="stylesheet" />
+    <link href="css/index.css" rel="stylesheet" />
 </head>
+
 <body>
-    <div class="navbar navbar-inverse navbar-fixed-top">
-        <div class="navbar-inner" id="topbar">
-            <a class="brand largeOnly" href="#" id="mainTitle">Babylon.js Playground</a>
-            <div class="btn-group">
-                <button class="btn" id="runButton">Run</button>
-                <button class="btn" id="saveButton">Save</button>
-                <button class="btn desktopOnly" id="zipButton">Get .zip</button>
-                <button class="btn desktopOnly" id="newButton">New</button>
-                <button class="btn desktopOnly" id="clearButton">Clear</button>
-            </div>
-            <div class="btn-group desktopOnly">
-                <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
-                    <span id="currentFontSize">Font: 12</span>
-                    <span class="caret"></span>
-                </a>
-                <ul class="dropdown-menu" id="sizeList">
-                    <li><a href="#" onclick="setFontSize(12);">12</a></li>
-                    <li><a href="#" onclick="setFontSize(14);">14</a></li>
-                    <li><a href="#" onclick="setFontSize(16);">16</a></li>
-                    <li><a href="#" onclick="setFontSize(18);">18</a></li>
-                    <li><a href="#" onclick="setFontSize(20);">20</a></li>
-                    <li><a href="#" onclick="setFontSize(22);">22</a></li>
-                </ul>
+    <div class="navbar">
+        <div class="title">
+            Babylon.js Playground
+        </div>
+        <div class="version" id="mainTitle">
+            v3.0-alpha
+        </div>
+
+        <div class="category">
+            <div class="button run" id="runButton">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+        </div>
+
+
+        <div class="category">
+            <div class="button" id="newButton">New<i class="fa fa-file" aria-hidden="true"></i></div>
+            <div class="button" id="clearButton">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
+            <div class="button" id="saveButton">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+            <div class="button" id="zipButton">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+        </div>
+
+
+        <div class="category desktopOnly">
+            <div class="button select"><span id="currentFontSize">Font: 14</span>
+                <div class="toDisplay">
+                    <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="btn-group">
-                <label class="btn btn-sm active">
-                    <input type="checkbox" autocomplete="off" id='safemodeToggle' style="margin-top:-0.1em;margin-right:4px">Safe Mode
-                </label>
-                <button class="btn btn-sm" id="metadataButton">+Meta data</button>
-                <button class="btn btn-sm" id="editorButton">-Editor</button>
-                <button class="btn btn-sm" id="debugButton">+Debug layer</button>
+            <div class="button select">Theme
+                <div class="toDisplay">
+                    <div class="option" id="darkTheme">Dark</div>
+                    <div class="option" id="lightTheme">Light</div>
+                </div>
             </div>
-            <div class="btn-group pull-right">
-                <button class="btn" id="fullscreenButton">Fullscreen</button>
+        </div>
+        <div class="category desktopTabletOnly">
+            <div class="button select">Settings
+                <div class="toDisplay">
+                    <div class="option" id='safemodeToggle'>Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option checked" id="editorButton">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton">Fullscreen</div>
+                    <div class="option" id="metadataButton">Metadata</div>
+                </div>
             </div>
-            <div class="btn-group pull-right">
-                <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
-                    <span id="currentScript">Predefined scripts</span>
-                    <span class="caret"></span>
-                </a>
-                <ul class="dropdown-menu" id="scriptsList"></ul>
+
+            <div class="button check uncheck" id="debugButton">Debug layer</div>
+        </div>
+
+
+
+        <div class="category right">
+            <div class="button select desktopTabletOnly"><span id="currentVersion">Version: Latest</span>
+                <div class="toDisplay">
+                    <div class="option" onclick="setVersion('latest');">Latest</div>
+                    <div class="option" onclick="setVersion('2.5');">2.5</div>
+                </div>
             </div>
-            <div class="save-message" id="saveMessage">
-                This PG has no metadata. Click save to add them.
+            <div class="button select"> <span id="currentScript">Scenes</span>
+                <div class="toDisplayBig">
+                    <ul id="scriptsList">
+                    </ul>
+                </div>
             </div>
         </div>
+        <div class="save-message" id="saveMessage">
+            This PG has no metadata. Click save to add them.
+        </div>
     </div>
 
-    <x-splitbox>
+    <div class="wrapper">
         <div id="jsEditor"></div>
-        <div splitter></div>
         <div id="canvasZone">
             <canvas touch-action="none" id="renderCanvas"></canvas>
         </div>
-    </x-splitbox>
+    </div>
 
     <span class="label" id="fpsLabel">FPS</span>
 
     <div id="errorZone">
     </div>
 
-    <div class="navbar navbar-inverse navbar-fixed-bottom">
-        <div class="navbar-inner">
-            <ul class="nav pull-left">
-                <li id="statusBar"></li>
-            </ul>
-            <ul class="nav pull-right">
-                <li><a href="http://www.html5gamedevs.com/forum/16-babylonjs/">Forum</a></li>
-                <li><a href="https://babylonjs.azurewebsites.net/sandbox">Sandbox</a></li>
-                <li><a href="https://github.com/BabylonJS/Babylon.js/wiki">Wiki</a></li>
-                <li><a href="https://doc.babylonjs.com">Documentation</a></li>
-                <li><a href="https://doc.babylonjs.com/playground">Playground Search</a></li>
-            </ul>
+    <div class="navbarBottom">
+        <div id="statusBar"></div>
+        <div class="links">
+            <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://babylonjs.azurewebsites.net/sandbox">Sandbox</a></div>
+            <div class='link'><a target='_new' href="https://github.com/BabylonJS/Babylon.js/wiki">Wiki</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">Playground Search</a></div>
         </div>
     </div>
 
@@ -135,21 +160,27 @@
             <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="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">
-                <button class="btn save-form-button" id="saveFormButtonOk">OK</button>
-                <button class="btn save-form-button" id="saveFormButtonCancel">Cancel</button>
+
+                <div id="saveFormButtonOk" class="button">OK</div>
+                <div id="saveFormButtonCancel" class="button">Cancel</div>
             </div>
         </div>
     </div>
 
     <script src="https://code.jquery.com/jquery.js"></script>
-    <script src="bootstrap/js/bootstrap.js"></script>
-    <script src="index.js"></script>
+
+    <script src="js/actions.js"></script>
+    <script src="js/index.js"></script>
 </body>
-</html>
+
+</html>

+ 8 - 7
Playground/frame.html

@@ -1,16 +1,15 @@
 <!DOCTYPE html>
 <html>
+
 <head>
     <title>Babylon.js Playground</title>
-    <script src="hand.minified-1.2.js"></script>
     <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/poly2tri.js"></script>    
-    <!-- Babylon.js -->    
+    <!-- Babylon.js -->
     <script src="https://babylonjs.azurewebsites.net/cannon.js"></script>
     <script src="https://babylonjs.azurewebsites.net/Oimo.js"></script>
     <script src="https://babylonjs.azurewebsites.net/babylon.js"></script>
     <script src="https://babylonjs.azurewebsites.net/babylon.canvas2d.js"></script>
-    
+
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.fireMaterial.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.waterMaterial.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.lavaMaterial.min.js"></script>
@@ -31,17 +30,18 @@
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.roadProceduralTexture.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.starfieldProceduralTexture.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.woodProceduralTexture.min.js"></script>
-    
+
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.asciiArtPostProcess.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.digitalRainPostProcess.min.js"></script>
 
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.glTFFileLoader.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.objFileLoader.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.stlFileLoader.js"></script>
-    
+
     <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>
     <link href="frame.css" rel="stylesheet" />
 </head>
+
 <body>
     <canvas touch-action="none" id="renderCanvas"></canvas>
 
@@ -53,4 +53,5 @@
     <script src="https://code.jquery.com/jquery.js"></script>
     <script src="frame.js"></script>
 </body>
-</html>
+
+</html>

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 1
Playground/hand.minified-1.2.js


+ 102 - 70
Playground/index-local.html

@@ -1,69 +1,99 @@
 <!DOCTYPE html>
 <html>
+
 <head>
     <title>Babylon.js Playground</title>
+    <meta charset='utf-8' />
+    <meta name="viewport" content="width=device-width, user-scalable=no">
     <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-    <script src="http://www.babylonjs.com/poly2tri.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>
-    <!--x-tag-->
-    <script src="xtag.min.js"></script>
-    <script src="splitbox.js"></script>
-    <link href="splitbox.css" rel="stylesheet" />
     <!-- jszip -->
-    <script src="jszip.min.js"></script>
-    <script src="fileSaver.js"></script>
-    <!-- Bootstrap -->
-    <link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
+    <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 -->    
-    
+    <!-- Babylon.js -->
     <script src="https://babylonjs.azurewebsites.net/cannon.js"></script>
     <script src="https://babylonjs.azurewebsites.net/Oimo.js"></script>
-	<script src="../tools/DevLoader/BabylonLoader.js"></script>
-    <link href="index.css" rel="stylesheet" />
+    <script src="../tools/DevLoader/BabylonLoader.js"></script>
+
+    <link href="css/index.css" rel="stylesheet" />
 </head>
+
 <body>
-    <div class="navbar navbar-inverse navbar-fixed-top">
-        <div class="navbar-inner" id="topbar">
-            <a class="brand largeOnly" href="#" id="mainTitle">Babylon.js Playground</a>
-            <div class="btn-group">
-                <button class="btn" id="runButton">Run</button>
-                <button class="btn" id="saveButton">Save</button>
-                <button class="btn desktopOnly" id="zipButton">Get .zip</button>
-                <button class="btn desktopOnly" id="newButton">New</button>
-                <button class="btn desktopOnly" id="clearButton">Clear</button>
+    <div class="navbar">
+        <div class="title">
+            Babylon.js Playground
+        </div>
+        <div class="version" id="mainTitle">
+            v3.0-alpha
+        </div>
+
+        <div class="category">
+            <div class="button run" id="runButton">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+        </div>
+
+
+        <div class="category">
+            <div class="button" id="newButton">New<i class="fa fa-file" aria-hidden="true"></i></div>
+            <div class="button" id="clearButton">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
+            <div class="button" id="saveButton">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+            <div class="button" id="zipButton">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+        </div>
+
+
+        <div class="category desktopOnly">
+            <div class="button select"><span id="currentFontSize">Font: 14</span>
+                <div class="toDisplay">
+                    <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="btn-group desktopOnly">
-                <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
-                    <span id="currentFontSize">Font: 12</span>
-                    <span class="caret"></span>
-                </a>
-                <ul class="dropdown-menu" id="sizeList">
-                    <li><a href="#" onclick="setFontSize(12);">12</a></li>
-                    <li><a href="#" onclick="setFontSize(14);">14</a></li>
-                    <li><a href="#" onclick="setFontSize(16);">16</a></li>
-                    <li><a href="#" onclick="setFontSize(18);">18</a></li>
-                    <li><a href="#" onclick="setFontSize(20);">20</a></li>
-                    <li><a href="#" onclick="setFontSize(22);">22</a></li>
-                </ul>
+            <div class="button select">Theme
+                <div class="toDisplay">
+                    <div class="option" id="darkTheme">Dark</div>
+                    <div class="option" id="lightTheme">Light</div>
+                </div>
             </div>
-            <div class="btn-group">
-                <label class="btn btn-sm active">
-                    <input type="checkbox" autocomplete="off" id='safemodeToggle' style="margin-top:-0.1em;margin-right:4px">Safe Mode
-                </label>
-                <button class="btn btn-sm" id="metadataButton">+Meta data</button>
-                <button class="btn btn-sm" id="editorButton">-Editor</button>
-                <button class="btn btn-sm" id="debugButton">+Debug layer</button>
+        </div>
+        <div class="category desktopTabletOnly">
+            <div class="button select">Settings
+                <div class="toDisplay">
+                    <div class="option" id='safemodeToggle'>Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option checked" id="editorButton">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton">Fullscreen</div>
+                    <div class="option" id="metadataButton">Metadata</div>
+                </div>
             </div>
-            <div class="btn-group pull-right">
-                <button class="btn" id="fullscreenButton">Fullscreen</button>
+
+            <div class="button check uncheck" id="debugButton">Debug layer</div>
+        </div>
+
+
+
+        <div class="category right">
+            <div class="button select desktopTabletOnly"><span id="currentVersion">Version: Latest</span>
+                <div class="toDisplay">
+                    <div class="option" onclick="setVersion('latest');">Latest</div>
+                    <div class="option" onclick="setVersion('2.5');">2.5</div>
+                </div>
             </div>
-            <div class="btn-group pull-right">
-                <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
-                    <span id="currentScript">Predefined scripts</span>
-                    <span class="caret"></span>
-                </a>
-                <ul class="dropdown-menu" id="scriptsList"></ul>
+            <div class="button select"> <span id="currentScript">Scenes</span>
+                <div class="toDisplayBig">
+                    <ul id="scriptsList">
+                    </ul>
+                </div>
             </div>
         </div>
         <div class="save-message" id="saveMessage">
@@ -71,31 +101,26 @@
         </div>
     </div>
 
-    <x-splitbox>
+    <div class="wrapper">
         <div id="jsEditor"></div>
-        <div splitter></div>
         <div id="canvasZone">
             <canvas touch-action="none" id="renderCanvas"></canvas>
         </div>
-    </x-splitbox>
+    </div>
 
     <span class="label" id="fpsLabel">FPS</span>
 
     <div id="errorZone">
     </div>
 
-    <div class="navbar navbar-inverse navbar-fixed-bottom">
-        <div class="navbar-inner">
-            <ul class="nav pull-left">
-                <li id="statusBar"></li>
-            </ul>
-            <ul class="nav pull-right">
-                <li><a href="http://www.html5gamedevs.com/forum/16-babylonjs/">Forum</a></li>
-                <li><a href="http://www.babylonjs.com/sandbox">Sandbox</a></li>
-                <li><a href="https://github.com/BabylonJS/Babylon.js/wiki">Wiki</a></li>
-                <li><a href="https://doc.babylonjs.com">Documentation</a></li>
-                <li><a href="https://doc.babylonjs.com/playground">Playground Search</a></li>
-            </ul>
+    <div class="navbarBottom">
+        <div id="statusBar"></div>
+        <div class="links">
+            <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://github.com/BabylonJS/Babylon.js/wiki">Wiki</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">Playground Search</a></div>
         </div>
     </div>
 
@@ -104,24 +129,31 @@
             <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="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">
-                <button class="btn save-form-button" id="saveFormButtonOk">OK</button>
-                <button class="btn save-form-button" id="saveFormButtonCancel">Cancel</button>
+
+                <div id="saveFormButtonOk" class="button">OK</div>
+                <div id="saveFormButtonCancel" class="button">Cancel</div>
             </div>
         </div>
     </div>
 
-    <script src="http://code.jquery.com/jquery.js"></script>
-    <script src="bootstrap/js/bootstrap.min.js"></script>
+    <script src="https://code.jquery.com/jquery.js"></script>
+
+    <script src="js/actions.js"></script>
+    <script src="js/index.js"></script>
     <script>
         BABYLONDEVTOOLS.Loader.require('index.js')
             .load();
     </script>
 </body>
-</html>
+
+</html>

+ 0 - 188
Playground/index.css

@@ -1,188 +0,0 @@
-html, body {
-    overflow: hidden;
-    width: 100%;
-    height: 100%;
-    background-color: #272822;
-}
-
-x-splitbox {
-    position: absolute;
-    left: 0px;
-    top: 50px;
-    width: 100%;
-    bottom: 40px;
-    height: auto;
-}
-
-    x-splitbox > [splitter]:after {
-        display: none;
-    }
-
-
-#jsEditor {
-    min-width: 250px;
-}
-
-#canvasZone {
-    min-width: 250px;
-    height: 100%;
-}
-
-#renderCanvas {
-    width: 100%;
-    height: 100%;
-    touch-action: none;
-}
-
-ul#scriptsList {
-    overflow-y: auto;
-    height: 600px;
-    -webkit-column-count: 3;
-    -moz-column-count: 3;
-    column-count: 3;
-    padding: 10px
-}
-
-#fpsLabel {
-    position: absolute;
-    right: 10px;
-    top: 70px;
-    cursor: default;
-}
-
-#topbar {
-    padding: 5px;
-}
-
-.navbar .brand {
-    margin-left: 0px;
-}
-
-#errorZone {
-    position: absolute;
-    width: 50%;
-    left: 25%;
-    bottom: 40px;
-}
-
-#statusBar {
-    padding: 10px 15px 10px;
-    color: #999;
-}
-
-@media (max-width: 800px) {
-    .desktopOnly {
-        display: none !important;
-    }
-}
-
-@media (max-width: 1100px) {
-    .largeOnly {
-        display: none !important;
-    }
-}
-
-@media (max-width: 550px) {
-    .btn-group > .btn, .btn-group > .dropdown-menu, .btn-group > .popover {
-        font-size: 12px !important;
-    }
-}
-
-/* MONACO */
-.monaco-editor .container:before, .monaco-editor .row:before {
-    content: "";
-    display: inherit;
-}
-
-.monaco-editor .container:after, .monaco-editor .row:after {
-    clear: inherit;
-}
-
-.monaco-editor .container {
-    width: auto;
-    margin: inherit;
-    padding: inherit;
-}
-
-.monaco-editor .close {
-    float: none;
-    font-size: inherit;
-    font-weight: inherit;
-    line-height: inherit;
-    color: inherit;
-    text-shadow: inherit;
-    opacity: inherit;
-    filter: inherit;
-}
-
-.monaco-editor .row {
-    margin: inherit;
-}
-
-.monaco-editor .invisible {
-    visibility: visible;
-}
-
-
-/* Save form & co */
-
-.save-message {
-    display: none;
-    float: left;
-    width: 100%;
-    background-color: rgba(0,0,0,.5);
-    text-align: center;
-    color: white;
-    font-size: 1.1em;
-    line-height: 2em;
-}
-
-.save-layer {
-    display: none;
-    position: absolute;
-    top: 0;
-    left: 0;
-
-    width: 100%;
-    height: 100%;
-
-    background-color: rgba(120,120,120,.5);
-    text-align: center;
-}
-.save-layer .save-form {
-    position: absolute;
-    top: 150px;
-    left: calc(50% - 205px);
-
-    width: 410px;
-    height: 390px;
-    padding-top: 15px;
-    -webkit-border-radius: 6px;
-    -moz-border-radius: 6px;
-    border-radius: 6px;
-
-    background-color: rgba(27,27,27,0.75);/*#1b1b1b;*/
-    background-image: -moz-linear-gradient(top,rgba(34,34,34,.75),rgba(17,17,17,.75));
-    background-image: -webkit-gradient(linear,0 0,0 100%,from(rgba(34,34,34,.75)),to(rgba(17,17,17,.75)));
-    background-image: -webkit-linear-gradient(top,rgba(34,34,34,.75),rgba(17,17,17,.75));
-    background-image: -o-linear-gradient(top,rgba(34,34,34,.75),rgba(17,17,17,.75));
-    background-image: linear-gradient(to bottom,rgba(34,34,34,.75),rgba(17,17,17,.75));
-    background-repeat: repeat-x;
-    border-color: #252525;
-    color: white;
-    font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
-    font-size: 14px;
-}
-.save-layer .save-form .separator {
-    width: 350px;
-    border-bottom: 1px solid #999;
-    margin: auto;
-    margin-top: -6px;
-    margin-bottom: 10px;
-}
-.save-layer .save-form .save-form-buttons {
-    margin-top: 10px;
-}
-.save-layer .save-form input, .save-layer .save-form textarea {
-    width: 350px;
-}

+ 100 - 79
Playground/index.html

@@ -1,27 +1,27 @@
 <!DOCTYPE html>
 <html>
+
 <head>
     <title>Babylon.js Playground</title>
+    <meta charset='utf-8' />
+    <meta name="viewport" content="width=device-width, user-scalable=no">
     <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
+    <!--For canvas/code separator-->
+    <script src="js/libs/split.js"></script>
+
     <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
-    <!--x-tag-->
-    <script src="xtag.min.js"></script>
-    <script src="splitbox.js"></script>
-    <link href="splitbox.css" rel="stylesheet" />
     <!-- jszip -->
-    <script src="jszip.min.js"></script>
-    <script src="fileSaver.js"></script>
-    <!-- Bootstrap -->
-    <link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
+    <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://babylonjs.azurewebsites.net/cannon.js"></script>
     <script src="https://babylonjs.azurewebsites.net/Oimo.js"></script>
-    <!--<script src="../babylon.js"></script>-->
     <script src="https://babylonjs.azurewebsites.net/babylon.js"></script>
     <script src="https://babylonjs.azurewebsites.net/babylon.canvas2d.js"></script>
     <script src="https://babylonjs.azurewebsites.net/babylon.inspector.bundle.js"></script>
-    
+
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.fireMaterial.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.waterMaterial.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.lavaMaterial.min.js"></script>
@@ -49,62 +49,82 @@
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.glTFFileLoader.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.objFileLoader.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.stlFileLoader.js"></script>
-    
+
     <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>
-    <link href="index.css" rel="stylesheet" />
+    <link href="css/index.css" rel="stylesheet" />
 </head>
+
 <body>
-    <div class="navbar navbar-inverse navbar-fixed-top">
-        <div class="navbar-inner" id="topbar">
-            <a class="brand largeOnly" href="#" id="mainTitle">Babylon.js Playground</a>
-            <div class="btn-group">
-                <button class="btn" id="runButton">Run</button>
-                <button class="btn" id="saveButton">Save</button>
-                <button class="btn desktopOnly" id="zipButton">Get .zip</button>
-                <button class="btn desktopOnly" id="newButton">New</button>
-                <button class="btn desktopOnly" id="clearButton">Clear</button>
+    <div class="navbar">
+        <div class="title">
+            Babylon.js Playground
+        </div>
+        <div class="version" id="mainTitle">
+            v3.0-alpha
+        </div>
+
+        <div class="category">
+            <div class="button run" id="runButton">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+        </div>
+
+
+        <div class="category">
+            <div class="button" id="newButton">New<i class="fa fa-file" aria-hidden="true"></i></div>
+            <div class="button" id="clearButton">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
+            <div class="button" id="saveButton">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+            <div class="button" id="zipButton">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+        </div>
+
+
+        <div class="category desktopOnly">
+            <div class="button select"><span id="currentFontSize">Font: 14</span>
+                <div class="toDisplay">
+                    <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="btn-group desktopOnly">
-                <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
-                    <span id="currentFontSize">Font: 12</span>
-                    <span class="caret"></span>
-                </a>
-                <ul class="dropdown-menu" id="sizeList">
-                    <li><a href="#" onclick="setFontSize(12);">12</a></li>
-                    <li><a href="#" onclick="setFontSize(14);">14</a></li>
-                    <li><a href="#" onclick="setFontSize(16);">16</a></li>
-                    <li><a href="#" onclick="setFontSize(18);">18</a></li>
-                    <li><a href="#" onclick="setFontSize(20);">20</a></li>
-                    <li><a href="#" onclick="setFontSize(22);">22</a></li>
-                </ul>
+            <div class="button select">Theme
+                <div class="toDisplay">
+                    <div class="option" id="darkTheme">Dark</div>
+                    <div class="option" id="lightTheme">Light</div>
+                </div>
             </div>
-            <div class="btn-group desktopOnly">
-                <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
-                    <span id="currentVersion">Version: Latest</span>
-                    <span class="caret"></span>
-                </a>
-                <ul class="dropdown-menu" id="versionList">
-                    <li><a href="#" onclick="setVersion('latest');">Latest</a></li>
-                    <li><a href="#" onclick="setVersion('2.5');">2.5</a></li>
-                </ul>
-            </div>            
-            <div class="btn-group">
-                <label class="btn btn-sm active">
-                    <input type="checkbox" autocomplete="off" id='safemodeToggle' style="margin-top:-0.1em;margin-right:4px">Safe Mode
-                </label>
-                <button class="btn btn-sm" id="metadataButton">+Meta data</button>
-                <button class="btn btn-sm" id="editorButton">-Editor</button>
-                <button class="btn btn-sm" id="debugButton">+Debug layer</button>
+        </div>
+        <div class="category desktopTabletOnly">
+            <div class="button select">Settings
+                <div class="toDisplay">
+                    <div class="option" id='safemodeToggle'>Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option checked" id="editorButton">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton">Fullscreen</div>
+                    <div class="option" id="metadataButton">Metadata</div>
+                </div>
             </div>
-            <div class="btn-group pull-right">
-                <button class="btn" id="fullscreenButton">Fullscreen</button>
+
+            <div class="button check uncheck" id="debugButton">Debug layer</div>
+        </div>
+
+
+
+        <div class="category right">
+            <div class="button select desktopTabletOnly"><span id="currentVersion">Version: Latest</span>
+                <div class="toDisplay">
+                    <div class="option" onclick="setVersion('latest');">Latest</div>
+                    <div class="option" onclick="setVersion('2.5');">2.5</div>
+                </div>
             </div>
-            <div class="btn-group pull-right">
-                <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
-                    <span id="currentScript">Predefined scripts</span>
-                    <span class="caret"></span>
-                </a>
-                <ul class="dropdown-menu" id="scriptsList"></ul>
+            <div class="button select"> <span id="currentScript">Scenes</span>
+                <div class="toDisplayBig">
+                    <ul id="scriptsList">
+                    </ul>
+                </div>
             </div>
         </div>
         <div class="save-message" id="saveMessage">
@@ -112,31 +132,26 @@
         </div>
     </div>
 
-    <x-splitbox>
+    <div class="wrapper">
         <div id="jsEditor"></div>
-        <div splitter></div>
         <div id="canvasZone">
             <canvas touch-action="none" id="renderCanvas"></canvas>
         </div>
-    </x-splitbox>
+    </div>
 
     <span class="label" id="fpsLabel">FPS</span>
 
     <div id="errorZone">
     </div>
 
-    <div class="navbar navbar-inverse navbar-fixed-bottom">
-        <div class="navbar-inner">
-            <ul class="nav pull-left">
-                <li id="statusBar"></li>
-            </ul>
-            <ul class="nav pull-right">
-                <li><a href="http://www.html5gamedevs.com/forum/16-babylonjs/">Forum</a></li>
-                <li><a href="https://babylonjs.azurewebsites.net/sandbox">Sandbox</a></li>
-                <li><a href="https://github.com/BabylonJS/Babylon.js/wiki">Wiki</a></li>
-                <li><a href="https://doc.babylonjs.com">Documentation</a></li>
-                <li><a href="https://doc.babylonjs.com/playground">Playground Search</a></li>
-            </ul>
+    <div class="navbarBottom">
+        <div id="statusBar"></div>
+        <div class="links">
+            <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://babylonjs.azurewebsites.net/sandbox">Sandbox</a></div>
+            <div class='link'><a target='_new' href="https://github.com/BabylonJS/Babylon.js/wiki">Wiki</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">Playground Search</a></div>
         </div>
     </div>
 
@@ -145,21 +160,27 @@
             <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="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">
-                <button class="btn save-form-button" id="saveFormButtonOk">OK</button>
-                <button class="btn save-form-button" id="saveFormButtonCancel">Cancel</button>
+
+                <div id="saveFormButtonOk" class="button">OK</div>
+                <div id="saveFormButtonCancel" class="button">Cancel</div>
             </div>
         </div>
     </div>
 
     <script src="https://code.jquery.com/jquery.js"></script>
-    <script src="bootstrap/js/bootstrap.min.js"></script>
-    <script src="index.js"></script>
+
+    <script src="js/actions.js"></script>
+    <script src="js/index.js"></script>
 </body>
-</html>
+
+</html>

+ 106 - 82
Playground/index2_5.html

@@ -1,28 +1,27 @@
 <!DOCTYPE html>
 <html>
+
 <head>
     <title>Babylon.js Playground</title>
+    <meta charset='utf-8' />
+    <meta name="viewport" content="width=device-width, user-scalable=no">
     <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/poly2tri.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>
-    <!--x-tag-->
-    <script src="xtag.min.js"></script>
-    <script src="splitbox.js"></script>
-    <link href="splitbox.css" rel="stylesheet" />
     <!-- jszip -->
-    <script src="jszip.min.js"></script>
-    <script src="fileSaver.js"></script>
-    <!-- Bootstrap -->
-    <link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
+    <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://babylonjs.azurewebsites.net/cannon.js"></script>
     <script src="https://babylonjs.azurewebsites.net/Oimo.js"></script>
-    <!--<script src="../babylon.js"></script>-->
     <script src="https://babylonjs.azurewebsites.net/versions/babylon.2.5.js"></script>
     <script src="https://babylonjs.azurewebsites.net/versions/babylon.2.5.canvas2d.js"></script>
     <script src="https://babylonjs.azurewebsites.net/babylon.inspector.bundle.js"></script>
-    
+
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.fireMaterial.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.waterMaterial.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.lavaMaterial.min.js"></script>
@@ -33,6 +32,7 @@
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.gradientMaterial.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.furMaterial.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.gridMaterial.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.shadowOnlyMaterial.min.js"></script>
 
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.brickProceduralTexture.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.cloudProceduralTexture.min.js"></script>
@@ -49,92 +49,109 @@
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.glTFFileLoader.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.objFileLoader.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.stlFileLoader.js"></script>
-    <link href="index.css" rel="stylesheet" />
+
+    <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>
+    <link href="css/index.css" rel="stylesheet" />
 </head>
+
 <body>
-    <div class="navbar navbar-inverse navbar-fixed-top">
-        <div class="navbar-inner" id="topbar">
-            <a class="brand largeOnly" href="#" id="mainTitle">Babylon.js Playground</a>
-            <div class="btn-group">
-                <button class="btn" id="runButton">Run</button>
-                <button class="btn" id="saveButton">Save</button>
-                <button class="btn desktopOnly" id="zipButton">Get .zip</button>
-                <button class="btn desktopOnly" id="newButton">New</button>
-                <button class="btn desktopOnly" id="clearButton">Clear</button>
-            </div>
-            <div class="btn-group desktopOnly">
-                <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
-                    <span id="currentFontSize">Font: 12</span>
-                    <span class="caret"></span>
-                </a>
-                <ul class="dropdown-menu" id="sizeList">
-                    <li><a href="#" onclick="setFontSize(12);">12</a></li>
-                    <li><a href="#" onclick="setFontSize(14);">14</a></li>
-                    <li><a href="#" onclick="setFontSize(16);">16</a></li>
-                    <li><a href="#" onclick="setFontSize(18);">18</a></li>
-                    <li><a href="#" onclick="setFontSize(20);">20</a></li>
-                    <li><a href="#" onclick="setFontSize(22);">22</a></li>
-                </ul>
+    <div class="navbar">
+        <div class="title">
+            Babylon.js Playground
+        </div>
+        <div class="version" id="mainTitle">
+            v3.0-alpha
+        </div>
+
+        <div class="category">
+            <div class="button run" id="runButton">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+        </div>
+
+
+        <div class="category">
+            <div class="button" id="newButton">New<i class="fa fa-file" aria-hidden="true"></i></div>
+            <div class="button" id="clearButton">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
+            <div class="button" id="saveButton">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+            <div class="button" id="zipButton">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+        </div>
+
+
+        <div class="category desktopOnly">
+            <div class="button select"><span id="currentFontSize">Font: 14</span>
+                <div class="toDisplay">
+                    <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="btn-group desktopOnly">
-                <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
-                    <span id="currentVersion">Version: Latest</span>
-                    <span class="caret"></span>
-                </a>
-                <ul class="dropdown-menu" id="versionList">
-                    <li><a href="#" onclick="setVersion('latest');">Latest</a></li>
-                    <li><a href="#" onclick="setVersion('2.5');">2.5</a></li>
-                </ul>
-            </div>            
-            <div class="btn-group">
-                <label class="btn btn-sm active">
-                    <input type="checkbox" autocomplete="off" id='safemodeToggle' style="margin-top:-0.1em;margin-right:4px">Safe Mode
-                </label>
-                <button class="btn btn-sm" id="metadataButton">+Meta data</button>
-                <button class="btn btn-sm" id="editorButton">-Editor</button>
-                <button class="btn btn-sm" id="debugButton">+Debug layer</button>
+            <div class="button select">Theme
+                <div class="toDisplay">
+                    <div class="option" id="darkTheme">Dark</div>
+                    <div class="option" id="lightTheme">Light</div>
+                </div>
             </div>
-            <div class="btn-group pull-right">
-                <button class="btn" id="fullscreenButton">Fullscreen</button>
+        </div>
+        <div class="category desktopTabletOnly">
+            <div class="button select">Settings
+                <div class="toDisplay">
+                    <div class="option" id='safemodeToggle'>Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option checked" id="editorButton">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton">Fullscreen</div>
+                    <div class="option" id="metadataButton">Metadata</div>
+                </div>
             </div>
-            <div class="btn-group pull-right">
-                <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
-                    <span id="currentScript">Predefined scripts</span>
-                    <span class="caret"></span>
-                </a>
-                <ul class="dropdown-menu" id="scriptsList"></ul>
+
+            <div class="button check uncheck" id="debugButton">Debug layer</div>
+        </div>
+
+
+
+        <div class="category right">
+            <div class="button select desktopTabletOnly"><span id="currentVersion">Version: Latest</span>
+                <div class="toDisplay">
+                    <div class="option" onclick="setVersion('latest');">Latest</div>
+                    <div class="option" onclick="setVersion('2.5');">2.5</div>
+                </div>
             </div>
-            <div class="save-message" id="saveMessage">
-                Be the first to fill this playground metadata!
+            <div class="button select"> <span id="currentScript">Scenes</span>
+                <div class="toDisplayBig">
+                    <ul id="scriptsList">
+                    </ul>
+                </div>
             </div>
         </div>
+        <div class="save-message" id="saveMessage">
+            This PG has no metadata. Click save to add them.
+        </div>
     </div>
 
-    <x-splitbox>
+    <div class="wrapper">
         <div id="jsEditor"></div>
-        <div splitter></div>
         <div id="canvasZone">
             <canvas touch-action="none" id="renderCanvas"></canvas>
         </div>
-    </x-splitbox>
+    </div>
 
     <span class="label" id="fpsLabel">FPS</span>
 
     <div id="errorZone">
     </div>
 
-    <div class="navbar navbar-inverse navbar-fixed-bottom">
-        <div class="navbar-inner">
-            <ul class="nav pull-left">
-                <li id="statusBar"></li>
-            </ul>
-            <ul class="nav pull-right">
-                <li><a href="http://www.html5gamedevs.com/forum/16-babylonjs/">Forum</a></li>
-                <li><a href="https://babylonjs.azurewebsites.net/sandbox">Sandbox</a></li>
-                <li><a href="https://github.com/BabylonJS/Babylon.js/wiki">Wiki</a></li>
-                <li><a href="https://doc.babylonjs.com">Documentation</a></li>
-                <li><a href="https://doc.babylonjs.com/playground">Playground Search</a></li>
-            </ul>
+    <div class="navbarBottom">
+        <div id="statusBar"></div>
+        <div class="links">
+            <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://babylonjs.azurewebsites.net/sandbox">Sandbox</a></div>
+            <div class='link'><a target='_new' href="https://github.com/BabylonJS/Babylon.js/wiki">Wiki</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">Playground Search</a></div>
         </div>
     </div>
 
@@ -150,14 +167,21 @@
             <div class="separator"></div>
             <textarea id="saveFormTags" rows="4" cols="10"></textarea>
             <div class="save-form-buttons" id="saveFormButtons">
-                <button class="btn save-form-button" id="saveFormButtonOk">OK</button>
-                <button class="btn save-form-button" id="saveFormButtonCancel">Cancel</button>
+
+                <div id="saveFormButtonOk" class="button">OK</div>
+                <div id="saveFormButtonCancel" class="button">Cancel</div>
             </div>
         </div>
     </div>
 
     <script src="https://code.jquery.com/jquery.js"></script>
-    <script src="bootstrap/js/bootstrap.min.js"></script>
-    <script src="index.js"></script>
+
+    <script>
+        Split(['#jsEditor', '#canvasZone']);
+    </script>
+
+    <script src="js/actions.js"></script>
+    <script src="js/index.js"></script>
 </body>
-</html>
+
+</html>

+ 63 - 0
Playground/js/actions.js

@@ -0,0 +1,63 @@
+(function () {
+
+    var allSelect = document.querySelectorAll('.select');
+    var allToDisplay = document.querySelectorAll('.toDisplay');
+    var allToDisplayBig = document.querySelectorAll('.toDisplayBig');
+
+    var removeAllOptions = function () {
+        for (var index = 0; index < allToDisplay.length; index++) {
+            var a = allToDisplay[index];
+            if (a.style.display == 'block') {
+                a.style.display = 'none';
+            }
+        }
+        for (var index = 0; index < allToDisplayBig.length; index++) {
+            var b = allToDisplayBig[index];
+            if (b.style.display == 'block') {
+                b.style.display = 'none';
+            }
+        }
+    }
+
+    // Remove displayed options
+    window.addEventListener('click', function () {
+        removeAllOptions();
+    });
+
+    // Handle click on select elements
+    for (var index = 0; index < allSelect.length; index++) {
+        var s = allSelect[index];
+        // Get child called to display
+        s.addEventListener('click', function (e) {
+            var toDisplay = this.querySelector('.toDisplay');
+            if (toDisplay) {
+                if (toDisplay.style.display == 'block') {
+                    toDisplay.style.display = 'none';
+                } else {
+                    removeAllOptions();
+                    toDisplay.style.display = 'block';
+                }
+            }
+            toDisplay = this.querySelector('.toDisplayBig');
+            if (toDisplay) {
+                if (toDisplay.style.display == 'block') {
+                    toDisplay.style.display = 'none';
+                } else {
+                    removeAllOptions();
+                    toDisplay.style.display = 'block';
+                }
+            }
+            e.preventDefault();
+            e.stopPropagation();
+        });
+    }
+
+    document.querySelector('#safemodeToggle').addEventListener('click', function () {
+        this.classList.toggle('checked');
+        if (this.classList.contains('checked')) {
+            this.innerHTML = 'Safe mode <i class="fa fa-check-square" aria-hidden="true"></i>';
+        } else {
+            this.innerHTML = 'Safe mode <i class="fa fa-square-o" aria-hidden="true"></i>';
+        }
+    })
+})();

+ 122 - 38
Playground/index.js

@@ -1,5 +1,20 @@
-(function () {
-    var jsEditor;
+var jsEditor;
+(function () {
+    var fontSize = 14;
+
+    var splitInstance = Split(['#jsEditor', '#canvasZone']);
+
+    var elementToTheme = [
+        '.wrapper .gutter',
+        '.wrapper #jsEditor',
+        '.navbar',
+        '.navbar .select .toDisplay .option',
+        '.navbar .select .toDisplayBig',
+        '.navbar .select .toDisplayBig a',
+        '.navbar .select .toDisplayBig ul li',
+        '.navbarBottom',
+        '.navbarBottom .links .link',
+        '.save-message'];
 
     var run = function () {
         var blockEditorChange = false;
@@ -13,7 +28,7 @@
             }
 
             document.getElementById("currentScript").innerHTML = "Custom";
-            document.getElementById('safemodeToggle').checked = true;
+            document.getElementById('safemodeToggle').classList.add('checked');
         });
 
         var snippetUrl = "https://babylonjs-api2.azurewebsites.net/snippets";
@@ -90,17 +105,15 @@
                         var ul = document.getElementById("scriptsList");
                         var index;
                         for (index = 0; index < scripts.length; index++) {
-                            var li = document.createElement("li");
+                            var option = document.createElement("li");
                             var a = document.createElement("a");
-
-                            li.class = "scriptsListEntry";
                             a.href = "#";
                             a.innerHTML = (index + 1) + " - " + scripts[index];
                             a.scriptLinkIndex = index + 1;
                             a.onclick = onScriptClick;
 
-                            li.appendChild(a);
-                            ul.appendChild(li);
+                            option.appendChild(a);
+                            ul.appendChild(option);
                         }
 
                         if (!location.hash) {
@@ -119,6 +132,23 @@
                                 loadScript("scripts/basic scene.js", "Basic scene");
                             }
                         }
+
+                        // Restore theme
+                        var theme = localStorage.getItem("bjs-playground-theme") || 'light';
+                        toggleTheme(theme);
+
+                        // Remove editor if window size is less than 850px
+                        var removeEditorForSmallScreen = function () {
+                            if (mq.matches) {
+                                splitInstance.collapse(0);
+                            } else {
+                                splitInstance.setSizes([50, 50]);
+                            }
+                        }
+                        var mq = window.matchMedia("(max-width: 850px)");
+                        mq.addListener(removeEditorForSmallScreen);
+
+
                     }
                 }
             };
@@ -149,7 +179,7 @@
 
         var showError = function (errorMessage, errorEvent) {
             var errorContent =
-                '<div class="alert alert-error"><button type="button" class="close" data-dismiss="alert">&times;</button><h4>Compilation error</h4>'
+                '<div class="alert alert-error"><button type="button" class="close" data-dismiss="alert">&times;</button>';
             if (errorEvent) {
                 var regEx = /\(.+:(\d+):(\d+)\)\n/g;
 
@@ -165,10 +195,16 @@
 
             errorContent += errorMessage + '</div>';
 
+            document.getElementById("errorZone").style.display = 'block';
             document.getElementById("errorZone").innerHTML = errorContent;
+
+            // Close button error
+            document.getElementById("errorZone").querySelector('.close').addEventListener('click', function () {
+                document.getElementById("errorZone").style.display = 'none';
+            });
         }
 
-        var showNoMetadata = function() {
+        var showNoMetadata = function () {
             document.getElementById("saveFormTitle").value = '';
             document.getElementById("saveFormTitle").readOnly = false;
             document.getElementById("saveFormDescription").value = '';
@@ -177,17 +213,17 @@
             document.getElementById("saveFormTags").readOnly = false;
             document.getElementById("saveFormButtons").style.display = "block";
             document.getElementById("saveMessage").style.display = "block";
-            document.getElementById("metadataButton").style.display = "none";
+            // document.getElementById("metadataButton").style.display = "none";
         };
         showNoMetadata();
 
-        var hideNoMetadata = function() {
+        var hideNoMetadata = function () {
             document.getElementById("saveFormTitle").readOnly = true;
             document.getElementById("saveFormDescription").readOnly = true;
             document.getElementById("saveFormTags").readOnly = true;
-            document.getElementById("saveFormButtons").style.display = "none";
+            document.getElementById("saveFormButtonOk").style.display = "none";
             document.getElementById("saveMessage").style.display = "none";
-            document.getElementById("metadataButton").style.display = "inline-block";
+            document.getElementById("metadataButton").style.display = "block";
         };
 
         compileAndRun = function () {
@@ -205,6 +241,7 @@
 
                 var canvas = document.getElementById("renderCanvas");
                 engine = new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true });
+                document.getElementById("errorZone").style.display = 'none';
                 document.getElementById("errorZone").innerHTML = "";
                 document.getElementById("statusBar").innerHTML = "Loading assets...Please wait";
 
@@ -458,7 +495,8 @@
 
         // Fonts
         setFontSize = function (size) {
-            document.querySelector(".monaco-editor").style.fontSize = size + "px";
+            fontSize = size;
+            document.querySelector(".view-lines").style.fontSize = size + "px";
             document.getElementById("currentFontSize").innerHTML = "Font: " + size;
         };
 
@@ -473,14 +511,15 @@
             var editorButton = document.getElementById("editorButton");
             var scene = engine.scenes[0];
 
-            if (editorButton.innerHTML === "-Editor") {
-                editorButton.innerHTML = "+Editor";
-                document.getElementById("jsEditor").style.display = "none";
-                document.getElementById("canvasZone").style.flexBasis = "100%";
+            // If the editor is present
+            if (editorButton.classList.contains('checked')) {
+                editorButton.classList.remove('checked');
+                splitInstance.collapse(0);
+                editorButton.innerHTML = 'Editor <i class="fa fa-square-o" aria-hidden="true"></i>';
             } else {
-                editorButton.innerHTML = "-Editor";
-                document.getElementById("jsEditor").style.display = "block";
-                document.getElementById("canvasZone").style.flexBasis = undefined;
+                editorButton.classList.add('checked');
+                splitInstance.setSizes([50, 50]);  // Reset
+                editorButton.innerHTML = 'Editor <i class="fa fa-check-square" aria-hidden="true"></i>';
             }
             engine.resize();
 
@@ -490,30 +529,69 @@
             }
         }
 
+        /**
+         * Toggle the dark theme
+         */
+        var toggleTheme = function (theme) {
+            // Monaco
+            var vsTheme;
+            if (theme == 'dark') {
+                vsTheme = 'vs-dark'
+            } else {
+                vsTheme = 'vs'
+            }
+
+            let oldCode = jsEditor.getValue();
+            jsEditor.dispose();
+            jsEditor = monaco.editor.create(document.getElementById('jsEditor'), {
+                value: "",
+                language: "javascript",
+                lineNumbers: true,
+                tabSize: "auto",
+                insertSpaces: "auto",
+                roundedSelection: true,
+                scrollBeyondLastLine: false,
+                automaticLayout: true,
+                readOnly: false,
+                theme: vsTheme,
+                contextmenu: false
+            });
+            jsEditor.setValue(oldCode);
+            setFontSize(fontSize);
+
+            for (var index = 0; index < elementToTheme.length; index++) {
+                var obj = elementToTheme[index];
+                let domObjArr = document.querySelectorAll(obj);
+                for (var domObjIndex = 0; domObjIndex < domObjArr.length; domObjIndex++) {
+                    var domObj = domObjArr[domObjIndex];
+                    domObj.classList.remove('light');
+                    domObj.classList.remove('dark');
+                    domObj.classList.add(theme);
+                }
+            }
+
+            localStorage.setItem("bjs-playground-theme", theme);
+
+        }
+
         var toggleDebug = function () {
             var debugButton = document.getElementById("debugButton");
             var scene = engine.scenes[0];
 
-            if (debugButton.innerHTML === "+Debug layer") {
-                debugButton.innerHTML = "-Debug layer";
+            if (debugButton.classList.contains('uncheck')) {
+                debugButton.classList.remove('uncheck');
                 scene.debugLayer.show();
             } else {
-                debugButton.innerHTML = "+Debug layer";
+                debugButton.classList.add('uncheck');
                 scene.debugLayer.hide();
             }
         }
 
-        var toggleMetadata = function() {
-            var metadataButton = document.getElementById("metadataButton");
+        var toggleMetadata = function () {
+            // var metadataButton = document.getElementById("metadataButton");
             var scene = engine.scenes[0];
-
-            if (metadataButton.innerHTML === "+Meta data") {
-                metadataButton.innerHTML = "-Meta data";
-                document.getElementById("saveLayer").style.display = "block";
-            } else {
-                metadataButton.innerHTML = "+Meta data";
-                document.getElementById("saveLayer").style.display = "none";
-            }
+            // metadataButton.classList.add('checked');
+            document.getElementById("saveLayer").style.display = "block";
         }
 
         // UI
@@ -525,11 +603,17 @@
         document.getElementById("editorButton").addEventListener("click", toggleEditor);
         document.getElementById("debugButton").addEventListener("click", toggleDebug);
         document.getElementById("metadataButton").addEventListener("click", toggleMetadata);
+        document.getElementById("darkTheme").addEventListener("click", toggleTheme.bind(this, 'dark'));
+        document.getElementById("lightTheme").addEventListener("click", toggleTheme.bind(this, 'light'));
+
+        // Restore theme
+        var theme = localStorage.getItem("bjs-playground-theme") || 'light';
+        toggleTheme(theme);
 
         //Navigation Overwrites
         var exitPrompt = function (e) {
             var safeToggle = document.getElementById("safemodeToggle");
-            if (safeToggle.checked) {
+            if (safeToggle.classList.contains('checked')) {
                 e = e || window.event;
                 var message =
                     'This page is asking you to confirm that you want to leave - data you have entered may not be saved.';
@@ -609,7 +693,7 @@
         document.getElementById("saveMessage").addEventListener("click", function () {
             document.getElementById("saveMessage").style.display = "none";
         });
-        document.getElementById("mainTitle").innerHTML = "Babylon.js v" + BABYLON.Engine.Version + " Playground";
+        document.getElementById("mainTitle").innerHTML = "v" + BABYLON.Engine.Version;
 
         var previousHash = "";
 
@@ -682,7 +766,7 @@
 
                         var hash = location.hash.substr(1);
                         currentSnippetToken = hash.split("#")[0];
-                        if(!hash.split("#")[1]) hash += "#0";
+                        if (!hash.split("#")[1]) hash += "#0";
 
 
                         xmlHttp.open("GET", snippetUrl + "/" + hash.replace("#", "/"));

Playground/fileSaver.js → Playground/js/libs/fileSaver.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 13 - 13
Playground/jszip.min.js


+ 587 - 0
Playground/js/libs/split.js

@@ -0,0 +1,587 @@
+// The programming goals of Split.js are to deliver readable, understandable and
+// maintainable code, while at the same time manually optimizing for tiny minified file size,
+// browser compatibility without additional requirements, graceful fallback (IE8 is supported)
+// and very few assumptions about the user's page layout.
+//
+// Make sure all browsers handle this JS library correctly with ES5.
+// More information here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode
+'use strict';
+
+// A wrapper function that does a couple things:
+//
+// 1. Doesn't pollute the global namespace. This is important for a library.
+// 2. Allows us to mount the library in different module systems, as well as
+//    directly in the browser.
+(function() {
+
+// Save the global `this` for use later. In this case, since the library only
+// runs in the browser, it will refer to `window`. Also, figure out if we're in IE8
+// or not. IE8 will still render correctly, but will be static instead of draggable.
+//
+// Save a couple long function names that are used frequently.
+// This optimization saves around 400 bytes.
+//
+// Set a float fudging global, used when dividing and setting sizes to long floats.
+// There's a chance that sometimes the sum of the floats would end up being slightly
+// larger than 100%, breaking the layout. The float fudging value is subtracted from
+// the percentage size.
+var global = this
+  , isIE8 = global.attachEvent && !global[addEventListener]
+  , document = global.document
+  , addEventListener = 'addEventListener'
+  , removeEventListener = 'removeEventListener'
+  , getBoundingClientRect = 'getBoundingClientRect'
+  , FLOAT_FUDGING = 0.5
+
+  // This library only needs two helper functions:
+  //
+  // The first determines which prefixes of CSS calc we need.
+  // We only need to do this once on startup, when this anonymous function is called.
+  // 
+  // Tests -webkit, -moz and -o prefixes. Modified from StackOverflow:
+  // http://stackoverflow.com/questions/16625140/js-feature-detection-to-detect-the-usage-of-webkit-calc-over-calc/16625167#16625167
+  , calc = (function () {
+        var el
+          , prefixes = ["", "-webkit-", "-moz-", "-o-"]
+
+        for (var i = 0; i < prefixes.length; i++) {
+            el = document.createElement('div')
+            el.style.cssText = "width:" + prefixes[i] + "calc(9px)"
+
+            if (el.style.length) {
+                return prefixes[i] + "calc"
+            }
+        }
+    })()
+
+  // The second helper function allows elements and string selectors to be used
+  // interchangeably. In either case an element is returned. This allows us to
+  // do `Split(elem1, elem2)` as well as `Split('#id1', '#id2')`.
+  , elementOrSelector = function (el) {
+        if (typeof el === 'string' || el instanceof String) {
+            return document.querySelector(el)
+        } else {
+            return el
+        }
+    }
+
+  // The main function to initialize a split. Split.js thinks about each pair
+  // of elements as an independant pair. Dragging the gutter between two elements
+  // only changes the dimensions of elements in that pair. This is key to understanding
+  // how the following functions operate, since each function is bound to a pair.
+  // 
+  // A pair object is shaped like this:
+  // 
+  // {
+  //     a: DOM element,
+  //     b: DOM element,
+  //     aMin: Number,
+  //     bMin: Number,
+  //     dragging: Boolean,
+  //     parent: DOM element,
+  //     isFirst: Boolean,
+  //     isLast: Boolean,
+  //     direction: 'horizontal' | 'vertical'
+  // }
+  //
+  // The basic sequence:
+  // 
+  // 1. Set defaults to something sane. `options` doesn't have to be passed at all.
+  // 2. Initialize a bunch of strings based on the direction we're splitting.
+  //    A lot of the behavior in the rest of the library is paramatized down to
+  //    rely on CSS strings and classes.
+  // 3. Define the dragging helper functions, and a few helpers to go with them.
+  // 4. Loop through the elements while pairing them off. Every pair gets an
+  //    `pair` object, a gutter, and special isFirst/isLast properties.
+  // 5. Actually size the pair elements, insert gutters and attach event listeners.
+  , Split = function (ids, options) {
+    var dimension
+      , i
+      , clientDimension
+      , clientAxis
+      , position
+      , gutterClass
+      , paddingA
+      , paddingB
+      , pairs = []
+
+    // 1. Set defaults to something sane. `options` doesn't have to be passed at all,
+    // so create an options object if none exists. Pixel values 10, 100 and 30 are
+    // arbitrary but feel natural.
+    options = typeof options !== 'undefined' ?  options : {}
+
+    if (typeof options.gutterSize === 'undefined') options.gutterSize = 10
+    if (typeof options.minSize === 'undefined') options.minSize = 100
+    if (typeof options.snapOffset === 'undefined') options.snapOffset = 30
+    if (typeof options.direction === 'undefined') options.direction = 'horizontal'
+    if (typeof options.elementStyle === 'undefined') options.elementStyle = function (dimension, size, gutterSize) {
+        var style = {}
+
+        if (typeof size !== 'string' && !(size instanceof String)) {
+            if (!isIE8) {
+                style[dimension] = calc + '(' + size + '% - ' + gutterSize + 'px)'
+            } else {
+                style[dimension] = size + '%'
+            }
+        } else {
+            style[dimension] = size
+        }
+
+        return style
+    }
+    if (typeof options.gutterStyle === 'undefined') options.gutterStyle = function (dimension, gutterSize) {
+        var style = {}
+
+        style[dimension] = gutterSize + 'px'
+
+        return style
+    }
+
+    // 2. Initialize a bunch of strings based on the direction we're splitting.
+    // A lot of the behavior in the rest of the library is paramatized down to
+    // rely on CSS strings and classes.
+    if (options.direction == 'horizontal') {
+        dimension = 'width'
+        clientDimension = 'clientWidth'
+        clientAxis = 'clientX'
+        position = 'left'
+        gutterClass = 'gutter gutter-horizontal'
+        paddingA = 'paddingLeft'
+        paddingB = 'paddingRight'
+        if (!options.cursor) options.cursor = 'ew-resize'
+    } else if (options.direction == 'vertical') {
+        dimension = 'height'
+        clientDimension = 'clientHeight'
+        clientAxis = 'clientY'
+        position = 'top'
+        gutterClass = 'gutter gutter-vertical'
+        paddingA = 'paddingTop'
+        paddingB = 'paddingBottom'
+        if (!options.cursor) options.cursor = 'ns-resize'
+    }
+
+    // 3. Define the dragging helper functions, and a few helpers to go with them.
+    // Each helper is bound to a pair object that contains it's metadata. This
+    // also makes it easy to store references to listeners that that will be
+    // added and removed.
+    // 
+    // Even though there are no other functions contained in them, aliasing
+    // this to self saves 50 bytes or so since it's used so frequently.
+    //
+    // The pair object saves metadata like dragging state, position and
+    // event listener references.
+    //
+    // startDragging calls `calculateSizes` to store the inital size in the pair object.
+    // It also adds event listeners for mouse/touch events,
+    // and prevents selection while dragging so avoid the selecting text.
+    var startDragging = function (e) {
+            // Alias frequently used variables to save space. 200 bytes.
+            var self = this
+              , a = self.a
+              , b = self.b
+
+            // Call the onDragStart callback.
+            if (!self.dragging && options.onDragStart) {
+                options.onDragStart()
+            }
+
+            // Don't actually drag the element. We emulate that in the drag function.
+            e.preventDefault()
+
+            // Set the dragging property of the pair object.
+            self.dragging = true
+
+            // Create two event listeners bound to the same pair object and store
+            // them in the pair object.
+            self.move = drag.bind(self)
+            self.stop = stopDragging.bind(self)
+
+            // All the binding. `window` gets the stop events in case we drag out of the elements.
+            global[addEventListener]('mouseup', self.stop)
+            global[addEventListener]('touchend', self.stop)
+            global[addEventListener]('touchcancel', self.stop)
+
+            self.parent[addEventListener]('mousemove', self.move)
+            self.parent[addEventListener]('touchmove', self.move)
+
+            // Disable selection. Disable!
+            a[addEventListener]('selectstart', noop)
+            a[addEventListener]('dragstart', noop)
+            b[addEventListener]('selectstart', noop)
+            b[addEventListener]('dragstart', noop)
+
+            a.style.userSelect = 'none'
+            a.style.webkitUserSelect = 'none'
+            a.style.MozUserSelect = 'none'
+            a.style.pointerEvents = 'none'
+
+            b.style.userSelect = 'none'
+            b.style.webkitUserSelect = 'none'
+            b.style.MozUserSelect = 'none'
+            b.style.pointerEvents = 'none'
+
+            // Set the cursor, both on the gutter and the parent element.
+            // Doing only a, b and gutter causes flickering.
+            self.gutter.style.cursor = options.cursor
+            self.parent.style.cursor = options.cursor
+
+            // Cache the initial sizes of the pair.
+            calculateSizes.call(self)
+        }
+
+      // stopDragging is very similar to startDragging in reverse.
+      , stopDragging = function () {
+            var self = this
+              , a = self.a
+              , b = self.b
+
+            if (self.dragging && options.onDragEnd) {
+                options.onDragEnd()
+            }
+
+            self.dragging = false
+
+            // Remove the stored event listeners. This is why we store them.
+            global[removeEventListener]('mouseup', self.stop)
+            global[removeEventListener]('touchend', self.stop)
+            global[removeEventListener]('touchcancel', self.stop)
+
+            self.parent[removeEventListener]('mousemove', self.move)
+            self.parent[removeEventListener]('touchmove', self.move)
+
+            // Delete them once they are removed. I think this makes a difference
+            // in memory usage with a lot of splits on one page. But I don't know for sure.
+            delete self.stop
+            delete self.move
+
+            a[removeEventListener]('selectstart', noop)
+            a[removeEventListener]('dragstart', noop)
+            b[removeEventListener]('selectstart', noop)
+            b[removeEventListener]('dragstart', noop)
+
+            a.style.userSelect = ''
+            a.style.webkitUserSelect = ''
+            a.style.MozUserSelect = ''
+            a.style.pointerEvents = ''
+
+            b.style.userSelect = ''
+            b.style.webkitUserSelect = ''
+            b.style.MozUserSelect = ''
+            b.style.pointerEvents = ''
+
+            self.gutter.style.cursor = ''
+            self.parent.style.cursor = ''
+        }
+
+      // drag, where all the magic happens. The logic is really quite simple:
+      // 
+      // 1. Ignore if the pair is not dragging.
+      // 2. Get the offset of the event.
+      // 3. Snap offset to min if within snappable range (within min + snapOffset).
+      // 4. Actually adjust each element in the pair to offset.
+      // 
+      // ---------------------------------------------------------------------
+      // |    | <- this.aMin               ||              this.bMin -> |    |
+      // |    |  | <- this.snapOffset      ||     this.snapOffset -> |  |    |
+      // |    |  |                         ||                        |  |    |
+      // |    |  |                         ||                        |  |    |
+      // ---------------------------------------------------------------------
+      // | <- this.start                                        this.size -> |
+      , drag = function (e) {
+            var offset
+
+            if (!this.dragging) return
+
+            // Get the offset of the event from the first side of the
+            // pair `this.start`. Supports touch events, but not multitouch, so only the first
+            // finger `touches[0]` is counted.
+            if ('touches' in e) {
+                offset = e.touches[0][clientAxis] - this.start
+            } else {
+                offset = e[clientAxis] - this.start
+            }
+
+            // If within snapOffset of min or max, set offset to min or max.
+            // snapOffset buffers aMin and bMin, so logic is opposite for both.
+            // Include the appropriate gutter sizes to prevent overflows.
+            if (offset <= this.aMin + options.snapOffset + this.aGutterSize) {
+                offset = this.aMin + this.aGutterSize
+            } else if (offset >= this.size - (this.bMin + options.snapOffset + this.bGutterSize)) {
+                offset = this.size - (this.bMin + this.bGutterSize)
+            }
+
+            offset = offset - FLOAT_FUDGING
+
+            // Actually adjust the size.
+            adjust.call(this, offset)
+
+            // Call the drag callback continously. Don't do anything too intensive
+            // in this callback.
+            if (options.onDrag) {
+                options.onDrag()
+            }
+        }
+
+      // Cache some important sizes when drag starts, so we don't have to do that
+      // continously:
+      // 
+      // `size`: The total size of the pair. First element + second element + first gutter + second gutter.
+      // `percentage`: The percentage between 0-100 that the pair occupies in the parent.
+      // `start`: The leading side of the first element.
+      //
+      // ------------------------------------------------ - - - - - - - - - - -
+      // |      aGutterSize -> |||                      |                     |
+      // |                     |||                      |                     |
+      // |                     |||                      |                     |
+      // |                     ||| <- bGutterSize       |                     |
+      // ------------------------------------------------ - - - - - - - - - - -
+      // | <- start                             size -> |       parentSize -> |
+      , calculateSizes = function () {
+            // Figure out the parent size minus padding.
+            var computedStyle = global.getComputedStyle(this.parent)
+              , parentSize = this.parent[clientDimension] - parseFloat(computedStyle[paddingA]) - parseFloat(computedStyle[paddingB])
+
+            this.size = this.a[getBoundingClientRect]()[dimension] + this.b[getBoundingClientRect]()[dimension] + this.aGutterSize + this.bGutterSize
+            this.percentage = Math.min(this.size / parentSize * 100, 100)
+            this.start = this.a[getBoundingClientRect]()[position]
+        }
+
+      // Actually adjust the size of elements `a` and `b` to `offset` while dragging.
+      // calc is used to allow calc(percentage + gutterpx) on the whole split instance,
+      // which allows the viewport to be resized without additional logic.
+      // Element a's size is the same as offset. b's size is total size - a size.
+      // Both sizes are calculated from the initial parent percentage, then the gutter size is subtracted.
+      , adjust = function (offset) {
+            setElementSize(this.a, (offset / this.size * this.percentage), this.aGutterSize)
+            setElementSize(this.b, (this.percentage - (offset / this.size * this.percentage)), this.bGutterSize)
+        }
+      , setElementSize = function (el, size, gutterSize) {
+            // Split.js allows setting sizes via numbers (ideally), or if you must,
+            // by string, like '300px'. This is less than ideal, because it breaks
+            // the fluid layout that `calc(% - px)` provides. You're on your own if you do that,
+            // make sure you calculate the gutter size by hand.
+            var style = options.elementStyle(dimension, size, gutterSize)
+              , props = Object.keys(style)
+
+            for (var i = 0; i < props.length; i++) {
+                el.style[props[i]] = style[props[i]]
+            }
+        }
+      , setGutterSize = function (gutter, gutterSize) {
+            var style = options.gutterStyle(dimension, gutterSize)
+              , props = Object.keys(style)
+
+            for (var i = 0; i < props.length; i++) {
+                gutter.style[props[i]] = style[props[i]]
+            }
+        }
+
+      // No-op function to prevent default. Used to prevent selection.
+      , noop = function () { return false }
+
+      // All DOM elements in the split should have a common parent. We can grab
+      // the first elements parent and hope users read the docs because the
+      // behavior will be whacky otherwise.
+      , parent = elementOrSelector(ids[0]).parentNode
+
+    // Set default options.sizes to equal percentages of the parent element.
+    if (!options.sizes) {
+        var percent = 100 / ids.length
+
+        options.sizes = []
+
+        for (i = 0; i < ids.length; i++) {
+            options.sizes.push(percent)
+        }
+    }
+
+    // Standardize minSize to an array if it isn't already. This allows minSize
+    // to be passed as a number.
+    if (!Array.isArray(options.minSize)) {
+        var minSizes = []
+
+        for (i = 0; i < ids.length; i++) {
+            minSizes.push(options.minSize)
+        }
+
+        options.minSize = minSizes
+    }
+
+    // 5. Loop through the elements while pairing them off. Every pair gets a
+    // `pair` object, a gutter, and isFirst/isLast properties.
+    //
+    // Basic logic:
+    //
+    // - Starting with the second element `i > 0`, create `pair` objects with
+    //   `a = ids[i - 1]` and `b = ids[i]`
+    // - Set gutter sizes based on the _pair_ being first/last. The first and last
+    //   pair have gutterSize / 2, since they only have one half gutter, and not two.
+    // - Create gutter elements and add event listeners.
+    // - Set the size of the elements, minus the gutter sizes.
+    //
+    // -----------------------------------------------------------------------
+    // |     i=0     |         i=1         |        i=2       |      i=3     |
+    // |             |       isFirst       |                  |     isLast   |
+    // |           pair 0                pair 1             pair 2           |
+    // |             |                     |                  |              |
+    // -----------------------------------------------------------------------
+    for (i = 0; i < ids.length; i++) {
+        var el = elementOrSelector(ids[i])
+          , isFirstPair = (i == 1)
+          , isLastPair = (i == ids.length - 1)
+          , size = options.sizes[i]
+          , gutterSize = options.gutterSize
+          , pair
+          , parentFlexDirection = window.getComputedStyle(parent).flexDirection
+          , temp
+
+        if (i > 0) {
+            // Create the pair object with it's metadata.
+            pair = {
+                a: elementOrSelector(ids[i - 1]),
+                b: el,
+                aMin: options.minSize[i - 1],
+                bMin: options.minSize[i],
+                dragging: false,
+                parent: parent,
+                isFirst: isFirstPair,
+                isLast: isLastPair,
+                direction: options.direction
+            }
+
+            // For first and last pairs, first and last gutter width is half.
+            pair.aGutterSize = options.gutterSize
+            pair.bGutterSize = options.gutterSize
+
+            if (isFirstPair) {
+                pair.aGutterSize = options.gutterSize / 2
+            }
+
+            if (isLastPair) {
+                pair.bGutterSize = options.gutterSize / 2
+            }
+
+            // if the parent has a reverse flex-direction, switch the pair elements.
+            if (parentFlexDirection === 'row-reverse' || parentFlexDirection === 'column-reverse') {
+                temp = pair.a;
+                pair.a = pair.b;
+                pair.b = temp;
+            }
+        }
+
+        // Determine the size of the current element. IE8 is supported by
+        // staticly assigning sizes without draggable gutters. Assigns a string
+        // to `size`.
+        // 
+        // IE9 and above
+        if (!isIE8) {
+            // Create gutter elements for each pair.
+            if (i > 0) {
+                var gutter = document.createElement('div')
+
+                gutter.className = gutterClass
+
+                setGutterSize(gutter, gutterSize)
+
+                gutter[addEventListener]('mousedown', startDragging.bind(pair))
+                gutter[addEventListener]('touchstart', startDragging.bind(pair))
+
+                parent.insertBefore(gutter, el)
+
+                pair.gutter = gutter
+            }
+
+            // Half-size gutters for first and last elements.
+            if (i === 0 || i == ids.length - 1) {
+                gutterSize = options.gutterSize / 2
+            }
+        }
+
+        // Set the element size to our determined size.
+        setElementSize(el, size, gutterSize)
+
+        if (i > 0) {
+            var aSize = pair.a[getBoundingClientRect]()[dimension]
+              , bSize = pair.b[getBoundingClientRect]()[dimension]
+
+            if (aSize < pair.aMin) {
+                pair.aMin = aSize
+            }
+
+            if (bSize < pair.bMin) {
+                pair.bMin = bSize
+            }
+        }
+
+        // After the first iteration, and we have a pair object, append it to the
+        // list of pairs.
+        if (i > 0) {
+            pairs.push(pair)
+        }
+    }
+
+    return {
+        setSizes: function (sizes) {
+            for (var i = 0; i < sizes.length; i++) {
+                if (i > 0) {
+                    var pair = pairs[i - 1]
+
+                    setElementSize(pair.a, sizes[i - 1], pair.aGutterSize)
+                    setElementSize(pair.b, sizes[i], pair.bGutterSize)
+                }
+            }
+        },
+        getSizes: function () {
+            var sizes = []
+
+            for (var i = 0; i < pairs.length; i++) {
+                var pair = pairs[i]
+                  , computedStyle = global.getComputedStyle(pair.parent)
+                  , parentSize = pair.parent[clientDimension] - parseFloat(computedStyle[paddingA]) - parseFloat(computedStyle[paddingB])
+
+                sizes.push((pair.a[getBoundingClientRect]()[dimension] + pair.aGutterSize) / parentSize * 100)
+
+                if (i === pairs.length - 1) {
+                    sizes.push((pair.b[getBoundingClientRect]()[dimension] + pair.bGutterSize) / parentSize * 100)
+                }
+            }
+
+            return sizes
+        },
+        collapse: function (i) {
+            var pair
+
+            if (i === pairs.length) {
+                pair = pairs[i - 1]
+
+                calculateSizes.call(pair)
+                adjust.call(pair, pair.size - pair.bGutterSize)
+            } else {
+                pair = pairs[i]
+
+                calculateSizes.call(pair)
+                adjust.call(pair, pair.aGutterSize)
+            }
+        },
+        destroy: function () {
+            for (var i = 0; i < pairs.length; i++) {
+                pairs[i].parent.removeChild(pairs[i].gutter)
+                pairs[i].a.style[dimension] = ''
+                pairs[i].b.style[dimension] = ''
+            }
+        }
+    }
+}
+
+// Play nicely with module systems, and the browser too if you include it raw.
+if (typeof exports !== 'undefined') {
+    if (typeof module !== 'undefined' && module.exports) {
+        exports = module.exports = Split
+    }
+    exports.Split = Split
+} else {
+    global.Split = Split
+}
+
+// Call our wrapper function with the current global. In this case, `window`.
+}).call(window);

+ 5 - 3
Playground/package.json

@@ -1,12 +1,14 @@
 {
   "name": "babylonjsplayground",
-  "version": "2.5.0",
+  "version": "2.6.0",
   "description": "Babylon.js is a 3D engine based on webgl and javascript",
   "main": "",
-  "repository": { "url": "https://github.com/BabylonJS/Babylon.js/" },
+  "repository": {
+    "url": "https://github.com/BabylonJS/Babylon.js/"
+  },
   "readme": "https://github.com/BabylonJS/Babylon.js/blob/master/readme.md",
   "license": "(Apache-2.0)",
   "devDependencies": {
     "monaco-editor": "^0.7.0"
   }
-}
+}

+ 0 - 146
Playground/splitbox.css

@@ -1,146 +0,0 @@
-x-splitbox {
-  position: relative;
-  display: -webkit-box;      /* OLD - iOS 6-, Safari 3.1-6 */
-  display: -moz-box;         /* OLD - Firefox 19- (buggy but mostly works) */
-  display: -ms-flexbox;      /* TWEENER - IE 10 */
-  display: -webkit-flex;     /* NEW - Chrome */
-  display: flex;             /* NEW, Spec - Opera 12.1, Firefox 20+ */
-  height: 100%;
-  overflow: hidden;
-  -webkit-box-sizing: border-box;
-  -moz-box-sizing: border-box;
-  -ms-box-sizing: border-box;
-  box-sizing: border-box;
-  -webkit-box-orient: horizontal;
-  -moz-box-orient: horizontal;
-  -ms-box-orient: horizontal;
-  box-orient: horizontal;
-  -webkit-flex-direction: row;
-  -moz-flex-direction: row;
-  -ms-flex-direction: row;
-  flex-direction: row;
-}
-
-x-splitbox[direction="column"] {
-  -webkit-box-orient: vertical;
-  -moz-box-orient: vertical;
-  -ms-box-orient: vertical;
-  box-orient: vertical;
-  -webkit-flex-direction: column;
-  -moz-flex-direction: column;
-  -ms-flex-direction: column;
-  flex-direction: column;
-}
-
-x-splitbox > *:not([splitter]) {
-  min-width: 0;
-  min-height: 0;
-  -webkit-box-flex: 1;
-  -moz-box-flex: 1;
-  -webkit-flex: 1;
-  flex: 1;
-  -ms-flex: auto;
-  -webkit-box-sizing: border-box;
-  -moz-box-sizing: border-box;
-  -ms-box-sizing: border-box;
-  box-sizing: border-box;
-}
-
-x-splitbox[dragging], x-splitbox > [splitter] {
-  -moz-user-select: -moz-none;
-  -khtml-user-select: none;
-  -webkit-user-select: none;
-  -ms-user-select: none;
-  user-select: none;
-  -webkit-user-drag: none;
-}
-
-x-splitbox > [splitter] {
-  display: block;
-  position: relative;
-  min-width: 0px !important;
-  max-width: 0px !important;
-  cursor: ew-resize;
-  background: #fff;
-  opacity: 0.6;
-}
-
-  x-splitbox > [splitter]:before {
-    content: " ";
-    display: block;
-    position: absolute;
-    width: 0.8em;
-    height: 100%;
-    opacity: 0;
-    background: inherit;
-    -webkit-box-sizing: border-box;
-    -moz-box-sizing: border-box;
-    -ms-box-sizing: border-box;
-    box-sizing: border-box;
-    -webkit-transform: translate(-50%, 0);
-    -ms-transform: translate(-50%, 0);
-    transform: translate(-50%, 0);
-  }
-
-  x-splitbox > [splitter]:after {
-    content: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMWVtIiB3aWR0aD0iMWVtIiB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0Ij48cGF0aCBmaWxsPSJyZ2JhKDAsMCwwLDAuNzUpIiBkPSJNNzU4IDIzNGwyMzIgMjc4LTIzMiAyNzgtNjYtNTQgMTg2LTIyNC0xODYtMjI0ek00NzAgNTU0di04NGg4NHY4NGgtODR6TTcyNiA0NzB2ODRoLTg2di04NGg4NnpNMjk4IDU1NHYtODRoODZ2ODRoLTg2ek0zMzIgMjg4bC0xODYgMjI0IDE4NiAyMjQtNjYgNTQtMjMyLTI3OCAyMzItMjc4eiI+PC9wYXRoPjwvc3ZnPg==');
-    position: absolute;
-    top: 50%;
-    left: 50%;
-    height: 1em;
-    padding: 0.05em;
-    background: inherit;
-    border-radius: 100%;
-    -webkit-box-shadow: 0 1px 1px 0px rgba(0,0,0,0.4);
-    -ms-box-shadow: 0 1px 1px 0px rgba(0,0,0,0.4);
-    box-shadow: 0 1px 1px 0px rgba(0,0,0,0.4);
-    -webkit-transform: translate(-50%, -50%);
-    -ms-transform: translate(-50%, -50%);
-    transform: translate(-50%, -50%);
-  }
-
-  x-splitbox[direction="column"] > [splitter] {
-    cursor: ns-resize;
-    min-width: auto !important;
-    max-width: none !important;
-    min-height: 0px !important;
-    max-height: 0px !important;
-  }
-
-  x-splitbox[direction="column"] > [splitter]:before {
-    width: 100%;
-    height: 0.8em;
-    -webkit-transform: translate(0%, -50%);
-    -ms-transform: translate(0%, -50%);
-    transform: translate(0%, -50%);
-  }
-
-  x-splitbox[direction="column"] > [splitter]:after {
-    -webkit-box-shadow: 1px 0 1px 0px rgba(0,0,0,0.4);
-    -ms-box-shadow: 1px 0 1px 0px rgba(0,0,0,0.4);
-    box-shadow: 1px 0 1px 0px rgba(0,0,0,0.4);
-    -webkit-transform: translate(-50%, -50%) rotate(90deg);
-    -ms-transform: translate(-50%, -50%) rotate(90deg);
-    transform: translate(-50%, -50%) rotate(90deg);
-  }
-
-  x-splitbox > [splitter]:hover, x-splitbox > [splitter][dragging] {
-    opacity: 1;
-    z-index: 2;
-  }
-
-  x-splitbox > [splitter][dragging]:before {
-    opacity: 0.3;
-  }
-
-
-@media screen and (max-device-width: 415px) {
-  x-splitbox > [splitter]:before {
-    display: block;
-  }
-
-    x-splitbox[direction="column"] > [splitter] {
-      display: block;
-    }
-}
-

+ 0 - 116
Playground/splitbox.js

@@ -1,116 +0,0 @@
-(function () {
-
-    function startDrag(node, splitter, event) {
-
-        node.setAttribute('dragging', '');
-        node.xtag.splitter = splitter;
-        splitter.setAttribute('dragging', '');
-        splitter.style.zIndex = node.xtag.splitZ = (node.xtag.splitZ || 0) + 1;
-
-        var props = getProps(node);
-        var lastCoord = event[props.page] - node[props.edge];
-        var next = splitter.nextElementSibling, next = !next.hasAttribute('splitter') && next;
-        var previous = splitter.previousElementSibling, previous = !previous.hasAttribute('splitter') && previous;
-        var startingTotal = next[props.size] + previous[props.size];
-
-        setPercents(node, props);
-
-        node.xtag.drag = xtag.addEvent(node, 'move', function (e) {
-            var delta = e[props.page] - node[props.edge] - lastCoord;
-            var nextSize = next[props.size];
-            var prevSize = previous[props.size];
-            var nextMod = nextSize - delta;
-            var prevMod = prevSize + delta;
-
-            if (delta > 0) {
-                if (nextSize > 0) {
-                    if (nextMod <= 0 || prevMod >= startingTotal || prevMod > startingTotal || nextMod > startingTotal) {
-                        prevMod = startingTotal;
-                        nextMod = 0;
-                    }
-                    setMinMax(next, props, nextMod);
-                    setMinMax(previous, props, prevMod);
-                }
-            }
-
-            else if (delta < 0) {
-                if (prevSize > 0) {
-                    if (prevMod <= 0 || nextMod >= startingTotal || prevMod > startingTotal || nextMod > startingTotal) {
-                        nextMod = startingTotal;
-                        prevMod = 0;
-                    }
-                    setMinMax(next, props, nextMod);
-                    setMinMax(previous, props, prevMod);
-                }
-            }
-
-            lastCoord = e[props.page] - node[props.edge];
-        });
-    }
-
-    function getProps(node) {
-        return node.xtag.props = (node.direction == 'column') ? {
-            page: 'pageY',
-            size: 'clientHeight',
-            edge: 'clientTop',
-            parentSize: node.clientHeight
-        } : {
-            page: 'pageX',
-            size: 'clientWidth',
-            edge: 'clientLeft',
-            parentSize: node.clientWidth
-        };
-    }
-
-    function setPercents(node, props, setup) {
-        node.xtag.panels = xtag.queryChildren(node, '*:not([splitter])').map(function (el) {
-            setMinMax(el, props, el[props.size], setup);
-            return el;
-        });
-    }
-
-    function setMinMax(panel, props, value, setup) {
-        panel.style.flex = panel.style[xtag.prefix.lowercase + 'Flex'] = (setup ? '0 0 ' : '1 1 ') + (value / props.parentSize) * 100 + '%';
-    }
-
-    function stopDrag(node) {
-        if (node.xtag.drag) {
-            xtag.removeEvent(node, node.xtag.drag);
-            node.removeAttribute('dragging');
-            node.xtag.splitter.removeAttribute('dragging');
-            node.xtag.splitter = null;
-            node.xtag.drag = null;
-        }
-    }
-
-    xtag.addEvent(window, 'tapend', function (e) {
-        xtag.query(document, 'x-splitbox[dragging]').forEach(stopDrag);
-    })
-
-    xtag.register('x-splitbox', {
-        events: {
-            'tapstart:delegate(x-splitbox > [splitter])': function (e) {
-                startDrag(e.currentTarget, this, e);
-            },
-            dragstart: function (e) {
-                if (this.hasAttribute('dragging')) {
-                    e.preventDefault();
-                    return false;
-                }
-            },
-            contextmemu: function (e) {
-                e.preventDefault();
-            }
-        },
-        accessors: {
-            direction: {
-                attribute: { def: 'row' },
-                set: function (direction) {
-                    setPercents(this, getProps(this), true);
-                }
-            }
-        }
-    });
-
-})();
-

+ 55 - 0
Playground/test.html

@@ -0,0 +1,55 @@
+<div class="navbar-inner" id="topbar">
+    <a class="brand largeOnly" href="#" id="mainTitle">Babylon.js Playground</a>
+    <div class="btn-group">
+        <button class="btn" id="runButton">Run</button>
+        <button class="btn" id="saveButton">Save</button>
+        <button class="btn desktopOnly" id="zipButton">Get .zip</button>
+        <button class="btn desktopOnly" id="newButton">New</button>
+        <button class="btn desktopOnly" id="clearButton">Clear</button>
+    </div>
+    <div class="btn-group desktopOnly">
+        <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
+            <span id="currentFontSize">Font: 12</span>
+            <span class="caret"></span>
+        </a>
+        <ul class="dropdown-menu" id="sizeList">
+            <li><a href="#" onclick="setFontSize(12);">12</a></li>
+            <li><a href="#" onclick="setFontSize(14);">14</a></li>
+            <li><a href="#" onclick="setFontSize(16);">16</a></li>
+            <li><a href="#" onclick="setFontSize(18);">18</a></li>
+            <li><a href="#" onclick="setFontSize(20);">20</a></li>
+            <li><a href="#" onclick="setFontSize(22);">22</a></li>
+        </ul>
+    </div>
+    <div class="btn-group desktopOnly">
+        <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
+            <span id="currentVersion">Version: Latest</span>
+            <span class="caret"></span>
+        </a>
+        <ul class="dropdown-menu" id="versionList">
+            <li><a href="#" onclick="setVersion('latest');">Latest</a></li>
+            <li><a href="#" onclick="setVersion('2.5');">2.5</a></li>
+        </ul>
+    </div>
+    <div class="btn-group">
+        <label class="btn btn-sm active">
+                    <input type="checkbox" autocomplete="off" id='safemodeToggle' style="margin-top:-0.1em;margin-right:4px">Safe Mode
+                </label>
+        <button class="btn btn-sm" id="metadataButton">+Meta data</button>
+        <button class="btn btn-sm" id="editorButton">-Editor</button>
+        <button class="btn btn-sm" id="debugButton">+Debug layer</button>
+    </div>
+    <div class="btn-group pull-right">
+        <button class="btn" id="fullscreenButton">Fullscreen</button>
+    </div>
+    <div class="btn-group pull-right">
+        <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
+            <span id="currentScript">Predefined scripts</span>
+            <span class="caret"></span>
+        </a>
+        <ul class="dropdown-menu" id="scriptsList"></ul>
+    </div>
+</div>
+<div class="save-message" id="saveMessage">
+    This PG has no metadata. Click save to add them.
+</div>

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 2
Playground/xtag.min.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 22 - 22
dist/preview release/babylon.core.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 613 - 611
dist/preview release/babylon.d.ts


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 37 - 37
dist/preview release/babylon.js


+ 49 - 40
dist/preview release/babylon.max.js

@@ -10757,6 +10757,12 @@ var BABYLON;
                 this._currentBufferPointers[i] = null;
             }
         };
+        Engine.prototype.releaseEffects = function () {
+            for (var name in this._compiledEffects) {
+                this._gl.deleteProgram(this._compiledEffects[name]._program);
+            }
+            this._compiledEffects = {};
+        };
         // Dispose
         Engine.prototype.dispose = function () {
             this.hideLoadingUI();
@@ -10768,9 +10774,7 @@ var BABYLON;
             // Release audio engine
             Engine.audioEngine.dispose();
             // Release effects
-            for (var name in this._compiledEffects) {
-                this._gl.deleteProgram(this._compiledEffects[name]._program);
-            }
+            this.releaseEffects();
             // Unbind
             this.unbindAllAttributes();
             this._gl = null;
@@ -12699,7 +12703,7 @@ var BABYLON;
             if (index === -1) {
                 return;
             }
-            this._lightSources.slice(index, 1);
+            this._lightSources.splice(index, 1);
         };
         AbstractMesh.prototype._markSubMeshesAsDirty = function (func) {
             if (!this.subMeshes) {
@@ -21699,12 +21703,14 @@ var BABYLON;
                 return false;
             }
             var index;
+            // Geometries
             for (index = 0; index < this._geometries.length; index++) {
                 var geometry = this._geometries[index];
                 if (geometry.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADING) {
                     return false;
                 }
             }
+            // Meshes
             for (index = 0; index < this.meshes.length; index++) {
                 var mesh = this.meshes[index];
                 if (!mesh.isEnabled()) {
@@ -31595,17 +31601,37 @@ var BABYLON;
             if (index >= 0) {
                 this._scene.materials.splice(index, 1);
             }
-            // Shader are kept in cache for further use but we can get rid of this by using forceDisposeEffect
-            if (forceDisposeEffect && this._effect) {
-                this._scene.getEngine()._releaseEffect(this._effect);
-                this._effect = null;
-            }
             // Remove from meshes
             for (index = 0; index < this._scene.meshes.length; index++) {
                 var mesh = this._scene.meshes[index];
                 if (mesh.material === this) {
                     mesh.material = null;
                 }
+                if (mesh.geometry) {
+                    var geometry = mesh.geometry;
+                    if (this.storeEffectOnSubMeshes) {
+                        for (var _i = 0, _a = mesh.subMeshes; _i < _a.length; _i++) {
+                            var subMesh = _a[_i];
+                            geometry._releaseVertexArrayObject(subMesh._materialEffect);
+                        }
+                    }
+                    else {
+                        geometry._releaseVertexArrayObject(this._effect);
+                    }
+                }
+            }
+            // Shader are kept in cache for further use but we can get rid of this by using forceDisposeEffect
+            if (forceDisposeEffect && this._effect) {
+                if (this.storeEffectOnSubMeshes) {
+                    for (var _b = 0, _c = mesh.subMeshes; _b < _c.length; _b++) {
+                        var subMesh = _c[_b];
+                        this._scene.getEngine()._releaseEffect(subMesh._materialEffect);
+                    }
+                }
+                else {
+                    this._scene.getEngine()._releaseEffect(this._effect);
+                }
+                this._effect = null;
             }
             // Callback
             this.onDisposeObservable.notifyObservers(this);
@@ -43009,6 +43035,12 @@ var BABYLON;
             }
             return this._indexBuffer;
         };
+        Geometry.prototype._releaseVertexArrayObject = function (effect) {
+            if (this._vertexArrayObjects[effect.key]) {
+                this._engine.releaseVertexArrayObject(this._vertexArrayObjects[effect.key]);
+                delete this._vertexArrayObjects[effect.key];
+            }
+        };
         Geometry.prototype.releaseForMesh = function (mesh, shouldDispose) {
             var meshes = this._meshes;
             var index = meshes.indexOf(mesh);
@@ -53484,12 +53516,6 @@ var BABYLON;
         }
         PoseEnabledController.prototype.update = function () {
             _super.prototype.update.call(this);
-            // update this device's offset position from the attached camera, if provided
-            //if (this._poseControlledCamera && this._poseControlledCamera.deviceScaleFactor) {
-            //this.position.copyFrom(this._poseControlledCamera.position);
-            //this.rotationQuaternion.copyFrom(this._poseControlledCamera.rotationQuaternion);
-            //this.deviceScaleFactor = this._poseControlledCamera.deviceScaleFactor;
-            //}
             var pose = this.vrGamepad.pose;
             this.updateFromDevice(pose);
             if (this._mesh) {
@@ -53507,11 +53533,6 @@ var BABYLON;
                     }
                     this.devicePosition.scaleToRef(this.deviceScaleFactor, this._calculatedPosition);
                     this._calculatedPosition.addInPlace(this.position);
-                    // scale the position using the scale factor, add the device's position
-                    /*if (this._poseControlledCamera) {
-                        // this allows total positioning freedom - the device, the camera and the mesh can be individually controlled.
-                        this._calculatedPosition.addInPlace(this._poseControlledCamera.position);
-                    }*/
                 }
                 if (poseData.orientation) {
                     this.deviceRotationQuaternion.copyFromFloats(this.rawPose.orientation[0], this.rawPose.orientation[1], -this.rawPose.orientation[2], -this.rawPose.orientation[3]);
@@ -53526,23 +53547,6 @@ var BABYLON;
                     }
                     // if the camera is set, rotate to the camera's rotation
                     this.deviceRotationQuaternion.multiplyToRef(this.rotationQuaternion, this._calculatedRotation);
-                    /*if (this._poseControlledCamera) {
-                        Matrix.ScalingToRef(1, 1, 1, Tmp.Matrix[1]);
-                        this._calculatedRotation.toRotationMatrix(Tmp.Matrix[0]);
-                        Matrix.TranslationToRef(this._calculatedPosition.x, this._calculatedPosition.y, this._calculatedPosition.z, Tmp.Matrix[2]);
-
-                        //Matrix.Identity().multiplyToRef(Tmp.Matrix[1], Tmp.Matrix[4]);
-                        Tmp.Matrix[1].multiplyToRef(Tmp.Matrix[0], Tmp.Matrix[5]);
-
-                        this._poseControlledCamera.getWorldMatrix().getTranslationToRef(Tmp.Vector3[0])
-
-                        Matrix.ComposeToRef(new Vector3(this.deviceScaleFactor, this.deviceScaleFactor, this.deviceScaleFactor), this._poseControlledCamera.rotationQuaternion, Tmp.Vector3[0], Tmp.Matrix[4]);
-                        Tmp.Matrix[5].multiplyToRef(Tmp.Matrix[2], Tmp.Matrix[1]);
-
-                        Tmp.Matrix[1].multiplyToRef(Tmp.Matrix[4], Tmp.Matrix[2]);
-                        Tmp.Matrix[2].decompose(Tmp.Vector3[0], this._calculatedRotation, this._calculatedPosition);
-
-                    }*/
                 }
             }
         };
@@ -61042,8 +61046,8 @@ var BABYLON;
                 // Colors
                 this._myScene.ambientColor.multiplyToRef(this.ambientColor, this._globalAmbientColor);
                 if (this._defines.METALLICWORKFLOW) {
-                    PBRMaterial._scaledReflectivity.r = this.metallic === undefined ? 1 : this.metallic;
-                    PBRMaterial._scaledReflectivity.g = this.roughness === undefined ? 1 : this.roughness;
+                    PBRMaterial._scaledReflectivity.r = (this.metallic === undefined || this.metallic === null) ? 1 : this.metallic;
+                    PBRMaterial._scaledReflectivity.g = (this.roughness === undefined || this.roughness === null) ? 1 : this.roughness;
                     this._effect.setColor4("vReflectivityColor", PBRMaterial._scaledReflectivity, 0);
                 }
                 else {
@@ -61456,7 +61460,12 @@ var BABYLON;
         };
         DebugLayer.prototype.hide = function () {
             if (this._inspector) {
-                this._inspector.dispose();
+                try {
+                    this._inspector.dispose();
+                }
+                catch (e) {
+                    // If the inspector has been removed directly from the inspector tool
+                }
                 this._inspector = null;
             }
         };

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 613 - 611
dist/preview release/babylon.module.d.ts


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 32 - 32
dist/preview release/babylon.noworker.js


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

@@ -5,8 +5,8 @@ declare module BABYLON {
         bin: ArrayBufferView;
     }
     interface IGLTFLoader {
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onsuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onerror?: () => void) => boolean;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onsuccess: () => void, onerror: () => void) => boolean;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onsuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onerror: () => void) => void;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onsuccess: () => void, onerror: () => void) => void;
     }
     class GLTFFileLoader implements ISceneLoaderPluginAsync {
         static GLTFLoaderV1: IGLTFLoader;
@@ -14,8 +14,8 @@ declare module BABYLON {
         static HomogeneousCoordinates: boolean;
         static IncrementalLoading: boolean;
         extensions: ISceneLoaderPluginExtensions;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError?: () => void): boolean;
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onError: () => void): boolean;
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError: () => void): void;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onError: () => void): void;
         private static _parse(data);
         private _getLoader(loaderData);
         private static _parseBinary(data);
@@ -370,7 +370,7 @@ declare module BABYLON.GLTF1 {
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError?: () => void, onProgress?: () => void): boolean;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onError: () => void): boolean;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onError: () => void): void;
         private _loadShadersAsync(gltfRuntime, onload);
         private _loadBuffersAsync(gltfRuntime, onload, onProgress?);
         private _createNodes(gltfRuntime);

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

@@ -12,15 +12,17 @@ var BABYLON;
             var loaderData = GLTFFileLoader._parse(data);
             var loader = this._getLoader(loaderData);
             if (!loader) {
-                return false;
+                onError();
+                return;
             }
-            return loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onError);
+            loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onError);
         };
         GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onError) {
             var loaderData = GLTFFileLoader._parse(data);
             var loader = this._getLoader(loaderData);
             if (!loader) {
-                return false;
+                onError();
+                return;
             }
             return loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onError);
         };
@@ -1662,7 +1664,6 @@ var BABYLON;
                         }
                     }, onError);
                 }, onError);
-                return true;
             };
             GLTFLoader.prototype._loadShadersAsync = function (gltfRuntime, onload) {
                 var hasShaders = false;

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 1
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


+ 20 - 18
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -5,8 +5,8 @@ declare module BABYLON {
         bin: ArrayBufferView;
     }
     interface IGLTFLoader {
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onsuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onerror?: () => void) => boolean;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onsuccess: () => void, onerror: () => void) => boolean;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onsuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onerror: () => void) => void;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onsuccess: () => void, onerror: () => void) => void;
     }
     class GLTFFileLoader implements ISceneLoaderPluginAsync {
         static GLTFLoaderV1: IGLTFLoader;
@@ -14,8 +14,8 @@ declare module BABYLON {
         static HomogeneousCoordinates: boolean;
         static IncrementalLoading: boolean;
         extensions: ISceneLoaderPluginExtensions;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError?: () => void): boolean;
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onError: () => void): boolean;
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError: () => void): void;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onError: () => void): void;
         private static _parse(data);
         private _getLoader(loaderData);
         private static _parseBinary(data);
@@ -78,11 +78,11 @@ declare module BABYLON.GLTF2 {
     }
     enum ETextureMagFilter {
         NEAREST = 9728,
-        LINEAR = 9728,
+        LINEAR = 9729,
     }
     enum ETextureMinFilter {
         NEAREST = 9728,
-        LINEAR = 9728,
+        LINEAR = 9729,
         NEAREST_MIPMAP_NEAREST = 9984,
         LINEAR_MIPMAP_NEAREST = 9985,
         NEAREST_MIPMAP_LINEAR = 9986,
@@ -276,7 +276,8 @@ declare module BABYLON.GLTF2 {
         source: number;
         target?: ETextureTarget;
         type?: ETextureType;
-        babylonTexture?: Texture;
+        babylonTextures: Texture[];
+        blobURL: string;
     }
     interface IGLTFTextureInfo {
         index: number;
@@ -335,22 +336,23 @@ declare module BABYLON.GLTF2 {
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
         static LoadMaterial(runtime: IGLTFRuntime, index: number): IGLTFMaterial;
-        static LoadMetallicRoughnessMaterialProperties: (runtime: IGLTFRuntime, material: IGLTFMaterial) => void;
-        static LoadCommonMaterialProperties(runtime: IGLTFRuntime, material: IGLTFMaterial): void;
+        static LoadMetallicRoughnessMaterialPropertiesAsync(runtime: IGLTFRuntime, material: IGLTFMaterial, onSuccess: () => void, onError: () => void): void;
+        static LoadCommonMaterialPropertiesAsync(runtime: IGLTFRuntime, material: IGLTFMaterial, onSuccess: () => void, onError: () => void): void;
         static LoadAlphaProperties(runtime: IGLTFRuntime, material: IGLTFMaterial): void;
         static LoadTextureAsync(runtime: IGLTFRuntime, textureInfo: IGLTFTextureInfo, onSuccess: (babylonTexture: Texture) => void, onError: () => void): void;
-        static CreateTextureAsync(runtime: IGLTFRuntime, textureInfo: IGLTFTextureInfo, buffer: ArrayBufferView, mimeType: string, onSuccess: (babylonTexture: Texture) => void, onError: () => void): void;
+        private static _createTextureAsync(runtime, texture, texCoord, url, onSuccess, onError);
         /**
         * Import meshes
         */
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError?: () => void): boolean;
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError?: () => void): void;
         /**
         * Load scene
         */
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onError: () => void): boolean;
-        private _loadBuffersAsync(runtime, onSuccess, onError);
-        private _loadBufferAsync(runtime, index, onSuccess, onError);
-        private _createRuntime(scene, data, rootUrl, importOnlyMeshes);
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onError: () => void): void;
+        private static _loadBuffersAsync(runtime, onSuccess, onError);
+        private static _loadBufferAsync(runtime, index, onSuccess, onError);
+        private static _loadMaterialsAsync(runtime, onSuccess, onError);
+        private static _createRuntime(scene, data, rootUrl, importOnlyMeshes);
     }
 }
 
@@ -412,9 +414,9 @@ declare module BABYLON.GLTF2 {
         constructor(name: string);
         readonly name: string;
         protected postCreateRuntime(runtime: IGLTFRuntime): void;
-        protected loadMaterial(runtime: IGLTFRuntime, index: number): boolean;
+        protected loadMaterialAsync(runtime: IGLTFRuntime, index: number, onSuccess: () => void, onError: () => void): boolean;
         static PostCreateRuntime(runtime: IGLTFRuntime): void;
-        static LoadMaterial(runtime: IGLTFRuntime, index: number): void;
+        static LoadMaterialAsync(runtime: IGLTFRuntime, index: number, onSuccess: () => void, onError: () => void): void;
     }
 }
 
@@ -422,6 +424,6 @@ declare module BABYLON.GLTF2 {
 declare module BABYLON.GLTF2 {
     class GLTFMaterialsPbrSpecularGlossinessExtension extends GLTFLoaderExtension {
         constructor();
-        protected loadMaterial(runtime: IGLTFRuntime, index: number): boolean;
+        protected loadMaterialAsync(runtime: IGLTFRuntime, index: number, onSuccess: () => void, onError: () => void): boolean;
     }
 }

+ 220 - 116
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -12,15 +12,17 @@ var BABYLON;
             var loaderData = GLTFFileLoader._parse(data);
             var loader = this._getLoader(loaderData);
             if (!loader) {
-                return false;
+                onError();
+                return;
             }
-            return loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onError);
+            loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onError);
         };
         GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onError) {
             var loaderData = GLTFFileLoader._parse(data);
             var loader = this._getLoader(loaderData);
             if (!loader) {
-                return false;
+                onError();
+                return;
             }
             return loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onError);
         };
@@ -284,12 +286,12 @@ var BABYLON;
         var ETextureMagFilter;
         (function (ETextureMagFilter) {
             ETextureMagFilter[ETextureMagFilter["NEAREST"] = 9728] = "NEAREST";
-            ETextureMagFilter[ETextureMagFilter["LINEAR"] = 9728] = "LINEAR";
+            ETextureMagFilter[ETextureMagFilter["LINEAR"] = 9729] = "LINEAR";
         })(ETextureMagFilter = GLTF2.ETextureMagFilter || (GLTF2.ETextureMagFilter = {}));
         var ETextureMinFilter;
         (function (ETextureMinFilter) {
             ETextureMinFilter[ETextureMinFilter["NEAREST"] = 9728] = "NEAREST";
-            ETextureMinFilter[ETextureMinFilter["LINEAR"] = 9728] = "LINEAR";
+            ETextureMinFilter[ETextureMinFilter["LINEAR"] = 9729] = "LINEAR";
             ETextureMinFilter[ETextureMinFilter["NEAREST_MIPMAP_NEAREST"] = 9984] = "NEAREST_MIPMAP_NEAREST";
             ETextureMinFilter[ETextureMinFilter["LINEAR_MIPMAP_NEAREST"] = 9985] = "LINEAR_MIPMAP_NEAREST";
             ETextureMinFilter[ETextureMinFilter["NEAREST_MIPMAP_LINEAR"] = 9986] = "NEAREST_MIPMAP_LINEAR";
@@ -983,11 +985,11 @@ var BABYLON;
                 var skeleton = runtime.babylonScene.skeletons[i];
                 runtime.babylonScene.beginAnimation(skeleton, 0, Number.MAX_VALUE, true, 1.0);
             }
-        };
-        var importMaterials = function (runtime) {
-            if (runtime.gltf.materials) {
-                for (var i = 0; i < runtime.gltf.materials.length; i++) {
-                    GLTF2.GLTFLoaderExtension.LoadMaterial(runtime, i);
+            // Revoke object urls created during load
+            for (var i = 0; i < runtime.gltf.textures.length; i++) {
+                var texture = runtime.gltf.textures[i];
+                if (texture.blobURL) {
+                    URL.revokeObjectURL(texture.blobURL);
                 }
             }
         };
@@ -1040,14 +1042,92 @@ var BABYLON;
                 material.babylonMaterial.useScalarInLinearSpace = true;
                 return material;
             };
-            GLTFLoader.LoadCommonMaterialProperties = function (runtime, material) {
+            GLTFLoader.LoadMetallicRoughnessMaterialPropertiesAsync = function (runtime, material, onSuccess, onError) {
+                // Ensure metallic workflow
+                material.babylonMaterial.metallic = 1;
+                material.babylonMaterial.roughness = 1;
+                var properties = material.pbrMetallicRoughness;
+                if (!properties) {
+                    onSuccess();
+                    return;
+                }
+                //
+                // Load Factors
+                //
+                material.babylonMaterial.albedoColor = properties.baseColorFactor ? BABYLON.Color3.FromArray(properties.baseColorFactor) : new BABYLON.Color3(1, 1, 1);
+                material.babylonMaterial.metallic = properties.metallicFactor || 1;
+                material.babylonMaterial.roughness = properties.roughnessFactor || 1;
+                //
+                // Load Textures
+                //
+                if (!properties.baseColorTexture && !properties.metallicRoughnessTexture) {
+                    onSuccess();
+                    return;
+                }
+                var checkSuccess = function () {
+                    if ((!properties.baseColorTexture || material.babylonMaterial.albedoTexture) &&
+                        (!properties.metallicRoughnessTexture || material.babylonMaterial.metallicTexture)) {
+                        onSuccess();
+                    }
+                };
+                if (properties.baseColorTexture) {
+                    GLTFLoader.LoadTextureAsync(runtime, properties.baseColorTexture, function (texture) {
+                        material.babylonMaterial.albedoTexture = texture;
+                        GLTFLoader.LoadAlphaProperties(runtime, material);
+                        checkSuccess();
+                    }, function () {
+                        BABYLON.Tools.Error("Failed to load base color texture");
+                        onError();
+                    });
+                }
+                if (properties.metallicRoughnessTexture) {
+                    GLTFLoader.LoadTextureAsync(runtime, properties.metallicRoughnessTexture, function (texture) {
+                        material.babylonMaterial.metallicTexture = texture;
+                        material.babylonMaterial.useMetallnessFromMetallicTextureBlue = true;
+                        material.babylonMaterial.useRoughnessFromMetallicTextureGreen = true;
+                        material.babylonMaterial.useRoughnessFromMetallicTextureAlpha = false;
+                        checkSuccess();
+                    }, function () {
+                        BABYLON.Tools.Error("Failed to load metallic roughness texture");
+                        onError();
+                    });
+                }
+            };
+            GLTFLoader.LoadCommonMaterialPropertiesAsync = function (runtime, material, onSuccess, onError) {
+                //
+                // Load Factors
+                //
+                material.babylonMaterial.useEmissiveAsIllumination = (material.emissiveFactor || material.emissiveTexture) ? true : false;
+                material.babylonMaterial.emissiveColor = material.emissiveFactor ? BABYLON.Color3.FromArray(material.emissiveFactor) : new BABYLON.Color3(0, 0, 0);
+                if (material.doubleSided) {
+                    material.babylonMaterial.backFaceCulling = false;
+                    material.babylonMaterial.twoSidedLighting = true;
+                }
+                //
+                // Load Textures
+                //
+                if (!material.normalTexture && !material.occlusionTexture && !material.emissiveTexture) {
+                    onSuccess();
+                    return;
+                }
+                var checkSuccess = function () {
+                    if ((!material.normalTexture || material.babylonMaterial.bumpTexture) &&
+                        (!material.occlusionTexture || material.babylonMaterial.ambientTexture) &&
+                        (!material.emissiveTexture || material.babylonMaterial.emissiveTexture)) {
+                        onSuccess();
+                    }
+                };
                 if (material.normalTexture) {
                     GLTFLoader.LoadTextureAsync(runtime, material.normalTexture, function (babylonTexture) {
                         material.babylonMaterial.bumpTexture = babylonTexture;
                         if (material.normalTexture.scale !== undefined) {
                             material.babylonMaterial.bumpTexture.level = material.normalTexture.scale;
                         }
-                    }, function () { return BABYLON.Tools.Warn("Failed to load normal texture"); });
+                        checkSuccess();
+                    }, function () {
+                        BABYLON.Tools.Error("Failed to load normal texture");
+                        onError();
+                    });
                 }
                 if (material.occlusionTexture) {
                     GLTFLoader.LoadTextureAsync(runtime, material.occlusionTexture, function (babylonTexture) {
@@ -1056,18 +1136,20 @@ var BABYLON;
                         if (material.occlusionTexture.strength !== undefined) {
                             material.babylonMaterial.ambientTextureStrength = material.occlusionTexture.strength;
                         }
-                    }, function () { return BABYLON.Tools.Warn("Failed to load occlusion texture"); });
+                        checkSuccess();
+                    }, function () {
+                        BABYLON.Tools.Error("Failed to load occlusion texture");
+                        onError();
+                    });
                 }
-                material.babylonMaterial.useEmissiveAsIllumination = (material.emissiveFactor || material.emissiveTexture) ? true : false;
-                material.babylonMaterial.emissiveColor = material.emissiveFactor ? BABYLON.Color3.FromArray(material.emissiveFactor) : new BABYLON.Color3(0, 0, 0);
                 if (material.emissiveTexture) {
                     GLTFLoader.LoadTextureAsync(runtime, material.emissiveTexture, function (babylonTexture) {
                         material.babylonMaterial.emissiveTexture = babylonTexture;
-                    }, function () { return BABYLON.Tools.Warn("Failed to load emissive texture"); });
-                }
-                if (material.doubleSided) {
-                    material.babylonMaterial.backFaceCulling = false;
-                    material.babylonMaterial.twoSidedLighting = true;
+                        checkSuccess();
+                    }, function () {
+                        BABYLON.Tools.Error("Failed to load emissive texture");
+                        onError();
+                    });
                 }
             };
             GLTFLoader.LoadAlphaProperties = function (runtime, material) {
@@ -1092,64 +1174,69 @@ var BABYLON;
             };
             GLTFLoader.LoadTextureAsync = function (runtime, textureInfo, onSuccess, onError) {
                 var texture = runtime.gltf.textures[textureInfo.index];
+                var texCoord = textureInfo.texCoord || 0;
                 if (!texture || texture.source === undefined) {
                     onError();
                     return;
                 }
-                if (texture.babylonTexture) {
-                    onSuccess(texture.babylonTexture);
+                if (texture.babylonTextures) {
+                    var babylonTexture = texture.babylonTextures[texCoord];
+                    if (!babylonTexture) {
+                        for (var i = 0; i < texture.babylonTextures.length; i++) {
+                            babylonTexture = texture.babylonTextures[i];
+                            if (babylonTexture) {
+                                babylonTexture = babylonTexture.clone();
+                                babylonTexture.coordinatesIndex = texCoord;
+                                break;
+                            }
+                        }
+                    }
+                    onSuccess(babylonTexture);
                     return;
                 }
                 var source = runtime.gltf.images[texture.source];
-                if (source.uri === undefined) {
-                    var bufferView = runtime.gltf.bufferViews[source.bufferView];
-                    var buffer = GLTF2.GLTFUtils.GetBufferFromBufferView(runtime, bufferView, 0, bufferView.byteLength, GLTF2.EComponentType.UNSIGNED_BYTE);
-                    GLTFLoader.CreateTextureAsync(runtime, textureInfo, buffer, source.mimeType, onSuccess, onError);
-                }
-                else if (GLTF2.GLTFUtils.IsBase64(source.uri)) {
-                    GLTFLoader.CreateTextureAsync(runtime, textureInfo, new Uint8Array(GLTF2.GLTFUtils.DecodeBase64(source.uri)), source.mimeType, onSuccess, onError);
+                var sourceURL = runtime.rootUrl + source.uri;
+                if (texture.blobURL) {
+                    sourceURL = texture.blobURL;
                 }
                 else {
-                    BABYLON.Tools.LoadFile(runtime.rootUrl + source.uri, function (data) {
-                        GLTFLoader.CreateTextureAsync(runtime, textureInfo, new Uint8Array(data), source.mimeType, onSuccess, onError);
-                    }, null, null, true, onError);
+                    if (source.uri === undefined) {
+                        var bufferView = runtime.gltf.bufferViews[source.bufferView];
+                        var buffer = GLTF2.GLTFUtils.GetBufferFromBufferView(runtime, bufferView, 0, bufferView.byteLength, GLTF2.EComponentType.UNSIGNED_BYTE);
+                        texture.blobURL = URL.createObjectURL(new Blob([buffer], { type: source.mimeType }));
+                        sourceURL = texture.blobURL;
+                    }
+                    else if (GLTF2.GLTFUtils.IsBase64(source.uri)) {
+                        var decodedBuffer = new Uint8Array(GLTF2.GLTFUtils.DecodeBase64(source.uri));
+                        texture.blobURL = URL.createObjectURL(new Blob([decodedBuffer], { type: source.mimeType }));
+                        sourceURL = texture.blobURL;
+                    }
                 }
+                GLTFLoader._createTextureAsync(runtime, texture, texCoord, sourceURL, onSuccess, onError);
             };
-            GLTFLoader.CreateTextureAsync = function (runtime, textureInfo, buffer, mimeType, onSuccess, onError) {
-                var texture = runtime.gltf.textures[textureInfo.index];
-                if (!texture || texture.source === undefined) {
-                    onError();
-                    return;
-                }
-                if (texture.babylonTexture) {
-                    onSuccess(texture.babylonTexture);
-                    return;
-                }
+            GLTFLoader._createTextureAsync = function (runtime, texture, texCoord, url, onSuccess, onError) {
                 var sampler = texture.sampler ? runtime.gltf.samplers[texture.sampler] : {};
-                var createMipMaps = (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST_MIPMAP_NEAREST) ||
-                    (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST_MIPMAP_LINEAR) ||
-                    (sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR_MIPMAP_NEAREST) ||
-                    (sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR_MIPMAP_LINEAR);
+                var noMipMaps = (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST || sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR);
                 var samplingMode = BABYLON.Texture.BILINEAR_SAMPLINGMODE;
-                var blob = new Blob([buffer], { type: mimeType });
-                var blobURL = URL.createObjectURL(blob);
-                var revokeBlobURL = function () { return URL.revokeObjectURL(blobURL); };
-                texture.babylonTexture = new BABYLON.Texture(blobURL, runtime.babylonScene, !createMipMaps, true, samplingMode, revokeBlobURL, revokeBlobURL);
-                texture.babylonTexture.coordinatesIndex = textureInfo.texCoord === undefined ? 0 : textureInfo.texCoord;
-                texture.babylonTexture.wrapU = GLTF2.GLTFUtils.GetWrapMode(sampler.wrapS);
-                texture.babylonTexture.wrapV = GLTF2.GLTFUtils.GetWrapMode(sampler.wrapT);
-                texture.babylonTexture.name = texture.name;
-                onSuccess(texture.babylonTexture);
+                var babylonTexture = new BABYLON.Texture(url, runtime.babylonScene, noMipMaps, true, samplingMode, function () {
+                    onSuccess(babylonTexture);
+                }, onError);
+                babylonTexture.coordinatesIndex = texCoord;
+                babylonTexture.wrapU = GLTF2.GLTFUtils.GetWrapMode(sampler.wrapS);
+                babylonTexture.wrapV = GLTF2.GLTFUtils.GetWrapMode(sampler.wrapT);
+                babylonTexture.name = texture.name;
+                // Cache the texture
+                texture.babylonTextures = texture.babylonTextures || [];
+                texture.babylonTextures[texCoord] = babylonTexture;
             };
             /**
             * Import meshes
             */
             GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onError) {
                 scene.useRightHandedSystem = true;
-                var runtime = this._createRuntime(scene, data, rootUrl, true);
+                var runtime = GLTFLoader._createRuntime(scene, data, rootUrl, true);
                 if (!runtime) {
-                    if (onError)
-                        onError();
+                    onError();
                     return;
                 }
                 if (meshesNames === "") {
@@ -1183,58 +1270,50 @@ var BABYLON;
                     }
                 }
                 // Load buffers, materials, etc.
-                this._loadBuffersAsync(runtime, function () {
-                    importMaterials(runtime);
-                    postLoad(runtime);
-                    if (!BABYLON.GLTFFileLoader.IncrementalLoading && onSuccess) {
+                GLTFLoader._loadBuffersAsync(runtime, function () {
+                    GLTFLoader._loadMaterialsAsync(runtime, function () {
+                        postLoad(runtime);
                         onSuccess(meshes, null, skeletons);
-                    }
+                    }, onError);
                 }, onError);
                 if (BABYLON.GLTFFileLoader.IncrementalLoading && onSuccess) {
                     onSuccess(meshes, null, skeletons);
                 }
-                return true;
             };
             /**
             * Load scene
             */
             GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onError) {
                 scene.useRightHandedSystem = true;
-                var runtime = this._createRuntime(scene, data, rootUrl, false);
+                var runtime = GLTFLoader._createRuntime(scene, data, rootUrl, false);
                 if (!runtime) {
-                    if (onError)
-                        onError();
-                    return false;
+                    onError();
+                    return;
                 }
                 importScene(runtime);
-                this._loadBuffersAsync(runtime, function () {
-                    importMaterials(runtime);
-                    postLoad(runtime);
-                    if (!BABYLON.GLTFFileLoader.IncrementalLoading) {
+                GLTFLoader._loadBuffersAsync(runtime, function () {
+                    GLTFLoader._loadMaterialsAsync(runtime, function () {
+                        postLoad(runtime);
                         onSuccess();
-                    }
+                    }, onError);
                 }, onError);
-                if (BABYLON.GLTFFileLoader.IncrementalLoading) {
-                    onSuccess();
-                }
-                return true;
             };
-            GLTFLoader.prototype._loadBuffersAsync = function (runtime, onSuccess, onError) {
+            GLTFLoader._loadBuffersAsync = function (runtime, onSuccess, onError) {
                 var _this = this;
                 if (runtime.gltf.buffers.length == 0) {
                     onSuccess();
                     return;
                 }
-                var loadedCount = 0;
+                var successCount = 0;
                 runtime.gltf.buffers.forEach(function (buffer, index) {
                     _this._loadBufferAsync(runtime, index, function () {
-                        if (++loadedCount >= runtime.gltf.buffers.length) {
+                        if (++successCount === runtime.gltf.buffers.length) {
                             onSuccess();
                         }
                     }, onError);
                 });
             };
-            GLTFLoader.prototype._loadBufferAsync = function (runtime, index, onSuccess, onError) {
+            GLTFLoader._loadBufferAsync = function (runtime, index, onSuccess, onError) {
                 var buffer = runtime.gltf.buffers[index];
                 if (buffer.uri === undefined) {
                     // buffer.loadedBufferView should already be set
@@ -1254,7 +1333,22 @@ var BABYLON;
                     }, null, null, true, onError);
                 }
             };
-            GLTFLoader.prototype._createRuntime = function (scene, data, rootUrl, importOnlyMeshes) {
+            GLTFLoader._loadMaterialsAsync = function (runtime, onSuccess, onError) {
+                var materials = runtime.gltf.materials;
+                if (!materials) {
+                    onSuccess();
+                    return;
+                }
+                var successCount = 0;
+                for (var i = 0; i < materials.length; i++) {
+                    GLTF2.GLTFLoaderExtension.LoadMaterialAsync(runtime, i, function () {
+                        if (++successCount === materials.length) {
+                            onSuccess();
+                        }
+                    }, onError);
+                }
+            };
+            GLTFLoader._createRuntime = function (scene, data, rootUrl, importOnlyMeshes) {
                 var runtime = {
                     gltf: data.json,
                     babylonScene: scene,
@@ -1283,32 +1377,6 @@ var BABYLON;
             return GLTFLoader;
         }());
         GLTFLoader.Extensions = {};
-        GLTFLoader.LoadMetallicRoughnessMaterialProperties = function (runtime, material) {
-            var properties = material.pbrMetallicRoughness;
-            if (!properties)
-                return;
-            material.babylonMaterial.albedoColor = properties.baseColorFactor ? BABYLON.Color3.FromArray(properties.baseColorFactor) : new BABYLON.Color3(1, 1, 1);
-            material.babylonMaterial.metallic = properties.metallicFactor === undefined ? 1 : properties.metallicFactor;
-            material.babylonMaterial.roughness = properties.roughnessFactor === undefined ? 1 : properties.roughnessFactor;
-            if (properties.baseColorTexture) {
-                GLTFLoader.LoadTextureAsync(runtime, properties.baseColorTexture, function (texture) {
-                    material.babylonMaterial.albedoTexture = texture;
-                    GLTFLoader.LoadAlphaProperties(runtime, material);
-                }, function () {
-                    BABYLON.Tools.Warn("Failed to load base color texture");
-                });
-            }
-            if (properties.metallicRoughnessTexture) {
-                GLTFLoader.LoadTextureAsync(runtime, properties.metallicRoughnessTexture, function (texture) {
-                    material.babylonMaterial.metallicTexture = texture;
-                    material.babylonMaterial.useMetallnessFromMetallicTextureBlue = true;
-                    material.babylonMaterial.useRoughnessFromMetallicTextureGreen = true;
-                    material.babylonMaterial.useRoughnessFromMetallicTextureAlpha = false;
-                }, function () {
-                    BABYLON.Tools.Warn("Failed to load metallic roughness texture");
-                });
-            }
-        };
         GLTF2.GLTFLoader = GLTFLoader;
         BABYLON.GLTFFileLoader.GLTFLoaderV2 = new GLTFLoader();
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
@@ -1469,7 +1537,7 @@ var BABYLON;
             });
             GLTFLoaderExtension.prototype.postCreateRuntime = function (runtime) { };
             // Return true to stop other extensions from loading materials.
-            GLTFLoaderExtension.prototype.loadMaterial = function (runtime, index) { return false; };
+            GLTFLoaderExtension.prototype.loadMaterialAsync = function (runtime, index, onSuccess, onError) { return false; };
             // ---------
             // Utilities
             // ---------
@@ -1479,18 +1547,33 @@ var BABYLON;
                     extension.postCreateRuntime(runtime);
                 }
             };
-            GLTFLoaderExtension.LoadMaterial = function (runtime, index) {
+            GLTFLoaderExtension.LoadMaterialAsync = function (runtime, index, onSuccess, onError) {
                 for (var extensionName in GLTF2.GLTFLoader.Extensions) {
                     var extension = GLTF2.GLTFLoader.Extensions[extensionName];
-                    if (extension.loadMaterial(runtime, index)) {
+                    if (extension.loadMaterialAsync(runtime, index, onSuccess, onError)) {
                         return;
                     }
                 }
                 var material = GLTF2.GLTFLoader.LoadMaterial(runtime, index);
-                if (material) {
-                    GLTF2.GLTFLoader.LoadMetallicRoughnessMaterialProperties(runtime, material);
-                    GLTF2.GLTFLoader.LoadCommonMaterialProperties(runtime, material);
+                if (!material) {
+                    onSuccess();
+                    return;
                 }
+                var metallicRoughnessPropertiesSuccess = false;
+                var commonPropertiesSuccess = false;
+                var checkSuccess = function () {
+                    if (metallicRoughnessPropertiesSuccess && commonPropertiesSuccess) {
+                        onSuccess();
+                    }
+                };
+                GLTF2.GLTFLoader.LoadMetallicRoughnessMaterialPropertiesAsync(runtime, material, function () {
+                    metallicRoughnessPropertiesSuccess = true;
+                    checkSuccess();
+                }, onError);
+                GLTF2.GLTFLoader.LoadCommonMaterialPropertiesAsync(runtime, material, function () {
+                    commonPropertiesSuccess = true;
+                    checkSuccess();
+                }, onError);
             };
             return GLTFLoaderExtension;
         }());
@@ -1520,33 +1603,54 @@ var BABYLON;
             function GLTFMaterialsPbrSpecularGlossinessExtension() {
                 return _super.call(this, "KHR_materials_pbrSpecularGlossiness") || this;
             }
-            GLTFMaterialsPbrSpecularGlossinessExtension.prototype.loadMaterial = function (runtime, index) {
+            GLTFMaterialsPbrSpecularGlossinessExtension.prototype.loadMaterialAsync = function (runtime, index, onSuccess, onError) {
                 var material = GLTF2.GLTFLoader.LoadMaterial(runtime, index);
                 if (!material || !material.extensions)
                     return false;
                 var properties = material.extensions[this.name];
                 if (!properties)
                     return false;
+                //
+                // Load Factors
+                //
                 material.babylonMaterial.albedoColor = properties.diffuseFactor ? BABYLON.Color3.FromArray(properties.diffuseFactor) : new BABYLON.Color3(1, 1, 1);
                 material.babylonMaterial.reflectivityColor = properties.specularFactor ? BABYLON.Color3.FromArray(properties.specularFactor) : new BABYLON.Color3(1, 1, 1);
                 material.babylonMaterial.microSurface = properties.glossinessFactor === undefined ? 1 : properties.glossinessFactor;
+                //
+                // Load Textures
+                //
+                var commonMaterialPropertiesSuccess = false;
+                var checkSuccess = function () {
+                    if ((!properties.diffuseTexture || material.babylonMaterial.albedoTexture) &&
+                        (!properties.specularGlossinessTexture || material.babylonMaterial.reflectivityTexture) &&
+                        commonMaterialPropertiesSuccess) {
+                        onSuccess();
+                    }
+                };
                 if (properties.diffuseTexture) {
                     GLTF2.GLTFLoader.LoadTextureAsync(runtime, properties.diffuseTexture, function (texture) {
                         material.babylonMaterial.albedoTexture = texture;
                         GLTF2.GLTFLoader.LoadAlphaProperties(runtime, material);
+                        checkSuccess();
                     }, function () {
                         BABYLON.Tools.Warn("Failed to load diffuse texture");
+                        onError();
                     });
                 }
                 if (properties.specularGlossinessTexture) {
                     GLTF2.GLTFLoader.LoadTextureAsync(runtime, properties.specularGlossinessTexture, function (texture) {
                         material.babylonMaterial.reflectivityTexture = texture;
                         material.babylonMaterial.useMicroSurfaceFromReflectivityMapAlpha = true;
+                        checkSuccess();
                     }, function () {
                         BABYLON.Tools.Warn("Failed to load metallic roughness texture");
+                        onError();
                     });
                 }
-                GLTF2.GLTFLoader.LoadCommonMaterialProperties(runtime, material);
+                GLTF2.GLTFLoader.LoadCommonMaterialPropertiesAsync(runtime, material, function () {
+                    commonMaterialPropertiesSuccess = true;
+                    checkSuccess();
+                }, onError);
                 return true;
             };
             return GLTFMaterialsPbrSpecularGlossinessExtension;

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 21 - 19
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -5,8 +5,8 @@ declare module BABYLON {
         bin: ArrayBufferView;
     }
     interface IGLTFLoader {
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onsuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onerror?: () => void) => boolean;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onsuccess: () => void, onerror: () => void) => boolean;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onsuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onerror: () => void) => void;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onsuccess: () => void, onerror: () => void) => void;
     }
     class GLTFFileLoader implements ISceneLoaderPluginAsync {
         static GLTFLoaderV1: IGLTFLoader;
@@ -14,8 +14,8 @@ declare module BABYLON {
         static HomogeneousCoordinates: boolean;
         static IncrementalLoading: boolean;
         extensions: ISceneLoaderPluginExtensions;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError?: () => void): boolean;
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onError: () => void): boolean;
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError: () => void): void;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onError: () => void): void;
         private static _parse(data);
         private _getLoader(loaderData);
         private static _parseBinary(data);
@@ -370,7 +370,7 @@ declare module BABYLON.GLTF1 {
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError?: () => void, onProgress?: () => void): boolean;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onError: () => void): boolean;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onError: () => void): void;
         private _loadShadersAsync(gltfRuntime, onload);
         private _loadBuffersAsync(gltfRuntime, onload, onProgress?);
         private _createNodes(gltfRuntime);
@@ -573,11 +573,11 @@ declare module BABYLON.GLTF2 {
     }
     enum ETextureMagFilter {
         NEAREST = 9728,
-        LINEAR = 9728,
+        LINEAR = 9729,
     }
     enum ETextureMinFilter {
         NEAREST = 9728,
-        LINEAR = 9728,
+        LINEAR = 9729,
         NEAREST_MIPMAP_NEAREST = 9984,
         LINEAR_MIPMAP_NEAREST = 9985,
         NEAREST_MIPMAP_LINEAR = 9986,
@@ -771,7 +771,8 @@ declare module BABYLON.GLTF2 {
         source: number;
         target?: ETextureTarget;
         type?: ETextureType;
-        babylonTexture?: Texture;
+        babylonTextures: Texture[];
+        blobURL: string;
     }
     interface IGLTFTextureInfo {
         index: number;
@@ -830,22 +831,23 @@ declare module BABYLON.GLTF2 {
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
         static LoadMaterial(runtime: IGLTFRuntime, index: number): IGLTFMaterial;
-        static LoadMetallicRoughnessMaterialProperties: (runtime: IGLTFRuntime, material: IGLTFMaterial) => void;
-        static LoadCommonMaterialProperties(runtime: IGLTFRuntime, material: IGLTFMaterial): void;
+        static LoadMetallicRoughnessMaterialPropertiesAsync(runtime: IGLTFRuntime, material: IGLTFMaterial, onSuccess: () => void, onError: () => void): void;
+        static LoadCommonMaterialPropertiesAsync(runtime: IGLTFRuntime, material: IGLTFMaterial, onSuccess: () => void, onError: () => void): void;
         static LoadAlphaProperties(runtime: IGLTFRuntime, material: IGLTFMaterial): void;
         static LoadTextureAsync(runtime: IGLTFRuntime, textureInfo: IGLTFTextureInfo, onSuccess: (babylonTexture: Texture) => void, onError: () => void): void;
-        static CreateTextureAsync(runtime: IGLTFRuntime, textureInfo: IGLTFTextureInfo, buffer: ArrayBufferView, mimeType: string, onSuccess: (babylonTexture: Texture) => void, onError: () => void): void;
+        private static _createTextureAsync(runtime, texture, texCoord, url, onSuccess, onError);
         /**
         * Import meshes
         */
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError?: () => void): boolean;
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError?: () => void): void;
         /**
         * Load scene
         */
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onError: () => void): boolean;
-        private _loadBuffersAsync(runtime, onSuccess, onError);
-        private _loadBufferAsync(runtime, index, onSuccess, onError);
-        private _createRuntime(scene, data, rootUrl, importOnlyMeshes);
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onError: () => void): void;
+        private static _loadBuffersAsync(runtime, onSuccess, onError);
+        private static _loadBufferAsync(runtime, index, onSuccess, onError);
+        private static _loadMaterialsAsync(runtime, onSuccess, onError);
+        private static _createRuntime(scene, data, rootUrl, importOnlyMeshes);
     }
 }
 
@@ -907,9 +909,9 @@ declare module BABYLON.GLTF2 {
         constructor(name: string);
         readonly name: string;
         protected postCreateRuntime(runtime: IGLTFRuntime): void;
-        protected loadMaterial(runtime: IGLTFRuntime, index: number): boolean;
+        protected loadMaterialAsync(runtime: IGLTFRuntime, index: number, onSuccess: () => void, onError: () => void): boolean;
         static PostCreateRuntime(runtime: IGLTFRuntime): void;
-        static LoadMaterial(runtime: IGLTFRuntime, index: number): void;
+        static LoadMaterialAsync(runtime: IGLTFRuntime, index: number, onSuccess: () => void, onError: () => void): void;
     }
 }
 
@@ -917,6 +919,6 @@ declare module BABYLON.GLTF2 {
 declare module BABYLON.GLTF2 {
     class GLTFMaterialsPbrSpecularGlossinessExtension extends GLTFLoaderExtension {
         constructor();
-        protected loadMaterial(runtime: IGLTFRuntime, index: number): boolean;
+        protected loadMaterialAsync(runtime: IGLTFRuntime, index: number, onSuccess: () => void, onError: () => void): boolean;
     }
 }

+ 220 - 117
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -12,15 +12,17 @@ var BABYLON;
             var loaderData = GLTFFileLoader._parse(data);
             var loader = this._getLoader(loaderData);
             if (!loader) {
-                return false;
+                onError();
+                return;
             }
-            return loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onError);
+            loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onError);
         };
         GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onError) {
             var loaderData = GLTFFileLoader._parse(data);
             var loader = this._getLoader(loaderData);
             if (!loader) {
-                return false;
+                onError();
+                return;
             }
             return loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onError);
         };
@@ -1662,7 +1664,6 @@ var BABYLON;
                         }
                     }, onError);
                 }, onError);
-                return true;
             };
             GLTFLoader.prototype._loadShadersAsync = function (gltfRuntime, onload) {
                 var hasShaders = false;
@@ -2435,12 +2436,12 @@ var BABYLON;
         var ETextureMagFilter;
         (function (ETextureMagFilter) {
             ETextureMagFilter[ETextureMagFilter["NEAREST"] = 9728] = "NEAREST";
-            ETextureMagFilter[ETextureMagFilter["LINEAR"] = 9728] = "LINEAR";
+            ETextureMagFilter[ETextureMagFilter["LINEAR"] = 9729] = "LINEAR";
         })(ETextureMagFilter = GLTF2.ETextureMagFilter || (GLTF2.ETextureMagFilter = {}));
         var ETextureMinFilter;
         (function (ETextureMinFilter) {
             ETextureMinFilter[ETextureMinFilter["NEAREST"] = 9728] = "NEAREST";
-            ETextureMinFilter[ETextureMinFilter["LINEAR"] = 9728] = "LINEAR";
+            ETextureMinFilter[ETextureMinFilter["LINEAR"] = 9729] = "LINEAR";
             ETextureMinFilter[ETextureMinFilter["NEAREST_MIPMAP_NEAREST"] = 9984] = "NEAREST_MIPMAP_NEAREST";
             ETextureMinFilter[ETextureMinFilter["LINEAR_MIPMAP_NEAREST"] = 9985] = "LINEAR_MIPMAP_NEAREST";
             ETextureMinFilter[ETextureMinFilter["NEAREST_MIPMAP_LINEAR"] = 9986] = "NEAREST_MIPMAP_LINEAR";
@@ -3134,11 +3135,11 @@ var BABYLON;
                 var skeleton = runtime.babylonScene.skeletons[i];
                 runtime.babylonScene.beginAnimation(skeleton, 0, Number.MAX_VALUE, true, 1.0);
             }
-        };
-        var importMaterials = function (runtime) {
-            if (runtime.gltf.materials) {
-                for (var i = 0; i < runtime.gltf.materials.length; i++) {
-                    GLTF2.GLTFLoaderExtension.LoadMaterial(runtime, i);
+            // Revoke object urls created during load
+            for (var i = 0; i < runtime.gltf.textures.length; i++) {
+                var texture = runtime.gltf.textures[i];
+                if (texture.blobURL) {
+                    URL.revokeObjectURL(texture.blobURL);
                 }
             }
         };
@@ -3191,14 +3192,92 @@ var BABYLON;
                 material.babylonMaterial.useScalarInLinearSpace = true;
                 return material;
             };
-            GLTFLoader.LoadCommonMaterialProperties = function (runtime, material) {
+            GLTFLoader.LoadMetallicRoughnessMaterialPropertiesAsync = function (runtime, material, onSuccess, onError) {
+                // Ensure metallic workflow
+                material.babylonMaterial.metallic = 1;
+                material.babylonMaterial.roughness = 1;
+                var properties = material.pbrMetallicRoughness;
+                if (!properties) {
+                    onSuccess();
+                    return;
+                }
+                //
+                // Load Factors
+                //
+                material.babylonMaterial.albedoColor = properties.baseColorFactor ? BABYLON.Color3.FromArray(properties.baseColorFactor) : new BABYLON.Color3(1, 1, 1);
+                material.babylonMaterial.metallic = properties.metallicFactor || 1;
+                material.babylonMaterial.roughness = properties.roughnessFactor || 1;
+                //
+                // Load Textures
+                //
+                if (!properties.baseColorTexture && !properties.metallicRoughnessTexture) {
+                    onSuccess();
+                    return;
+                }
+                var checkSuccess = function () {
+                    if ((!properties.baseColorTexture || material.babylonMaterial.albedoTexture) &&
+                        (!properties.metallicRoughnessTexture || material.babylonMaterial.metallicTexture)) {
+                        onSuccess();
+                    }
+                };
+                if (properties.baseColorTexture) {
+                    GLTFLoader.LoadTextureAsync(runtime, properties.baseColorTexture, function (texture) {
+                        material.babylonMaterial.albedoTexture = texture;
+                        GLTFLoader.LoadAlphaProperties(runtime, material);
+                        checkSuccess();
+                    }, function () {
+                        BABYLON.Tools.Error("Failed to load base color texture");
+                        onError();
+                    });
+                }
+                if (properties.metallicRoughnessTexture) {
+                    GLTFLoader.LoadTextureAsync(runtime, properties.metallicRoughnessTexture, function (texture) {
+                        material.babylonMaterial.metallicTexture = texture;
+                        material.babylonMaterial.useMetallnessFromMetallicTextureBlue = true;
+                        material.babylonMaterial.useRoughnessFromMetallicTextureGreen = true;
+                        material.babylonMaterial.useRoughnessFromMetallicTextureAlpha = false;
+                        checkSuccess();
+                    }, function () {
+                        BABYLON.Tools.Error("Failed to load metallic roughness texture");
+                        onError();
+                    });
+                }
+            };
+            GLTFLoader.LoadCommonMaterialPropertiesAsync = function (runtime, material, onSuccess, onError) {
+                //
+                // Load Factors
+                //
+                material.babylonMaterial.useEmissiveAsIllumination = (material.emissiveFactor || material.emissiveTexture) ? true : false;
+                material.babylonMaterial.emissiveColor = material.emissiveFactor ? BABYLON.Color3.FromArray(material.emissiveFactor) : new BABYLON.Color3(0, 0, 0);
+                if (material.doubleSided) {
+                    material.babylonMaterial.backFaceCulling = false;
+                    material.babylonMaterial.twoSidedLighting = true;
+                }
+                //
+                // Load Textures
+                //
+                if (!material.normalTexture && !material.occlusionTexture && !material.emissiveTexture) {
+                    onSuccess();
+                    return;
+                }
+                var checkSuccess = function () {
+                    if ((!material.normalTexture || material.babylonMaterial.bumpTexture) &&
+                        (!material.occlusionTexture || material.babylonMaterial.ambientTexture) &&
+                        (!material.emissiveTexture || material.babylonMaterial.emissiveTexture)) {
+                        onSuccess();
+                    }
+                };
                 if (material.normalTexture) {
                     GLTFLoader.LoadTextureAsync(runtime, material.normalTexture, function (babylonTexture) {
                         material.babylonMaterial.bumpTexture = babylonTexture;
                         if (material.normalTexture.scale !== undefined) {
                             material.babylonMaterial.bumpTexture.level = material.normalTexture.scale;
                         }
-                    }, function () { return BABYLON.Tools.Warn("Failed to load normal texture"); });
+                        checkSuccess();
+                    }, function () {
+                        BABYLON.Tools.Error("Failed to load normal texture");
+                        onError();
+                    });
                 }
                 if (material.occlusionTexture) {
                     GLTFLoader.LoadTextureAsync(runtime, material.occlusionTexture, function (babylonTexture) {
@@ -3207,18 +3286,20 @@ var BABYLON;
                         if (material.occlusionTexture.strength !== undefined) {
                             material.babylonMaterial.ambientTextureStrength = material.occlusionTexture.strength;
                         }
-                    }, function () { return BABYLON.Tools.Warn("Failed to load occlusion texture"); });
+                        checkSuccess();
+                    }, function () {
+                        BABYLON.Tools.Error("Failed to load occlusion texture");
+                        onError();
+                    });
                 }
-                material.babylonMaterial.useEmissiveAsIllumination = (material.emissiveFactor || material.emissiveTexture) ? true : false;
-                material.babylonMaterial.emissiveColor = material.emissiveFactor ? BABYLON.Color3.FromArray(material.emissiveFactor) : new BABYLON.Color3(0, 0, 0);
                 if (material.emissiveTexture) {
                     GLTFLoader.LoadTextureAsync(runtime, material.emissiveTexture, function (babylonTexture) {
                         material.babylonMaterial.emissiveTexture = babylonTexture;
-                    }, function () { return BABYLON.Tools.Warn("Failed to load emissive texture"); });
-                }
-                if (material.doubleSided) {
-                    material.babylonMaterial.backFaceCulling = false;
-                    material.babylonMaterial.twoSidedLighting = true;
+                        checkSuccess();
+                    }, function () {
+                        BABYLON.Tools.Error("Failed to load emissive texture");
+                        onError();
+                    });
                 }
             };
             GLTFLoader.LoadAlphaProperties = function (runtime, material) {
@@ -3243,64 +3324,69 @@ var BABYLON;
             };
             GLTFLoader.LoadTextureAsync = function (runtime, textureInfo, onSuccess, onError) {
                 var texture = runtime.gltf.textures[textureInfo.index];
+                var texCoord = textureInfo.texCoord || 0;
                 if (!texture || texture.source === undefined) {
                     onError();
                     return;
                 }
-                if (texture.babylonTexture) {
-                    onSuccess(texture.babylonTexture);
+                if (texture.babylonTextures) {
+                    var babylonTexture = texture.babylonTextures[texCoord];
+                    if (!babylonTexture) {
+                        for (var i = 0; i < texture.babylonTextures.length; i++) {
+                            babylonTexture = texture.babylonTextures[i];
+                            if (babylonTexture) {
+                                babylonTexture = babylonTexture.clone();
+                                babylonTexture.coordinatesIndex = texCoord;
+                                break;
+                            }
+                        }
+                    }
+                    onSuccess(babylonTexture);
                     return;
                 }
                 var source = runtime.gltf.images[texture.source];
-                if (source.uri === undefined) {
-                    var bufferView = runtime.gltf.bufferViews[source.bufferView];
-                    var buffer = GLTF2.GLTFUtils.GetBufferFromBufferView(runtime, bufferView, 0, bufferView.byteLength, GLTF2.EComponentType.UNSIGNED_BYTE);
-                    GLTFLoader.CreateTextureAsync(runtime, textureInfo, buffer, source.mimeType, onSuccess, onError);
-                }
-                else if (GLTF2.GLTFUtils.IsBase64(source.uri)) {
-                    GLTFLoader.CreateTextureAsync(runtime, textureInfo, new Uint8Array(GLTF2.GLTFUtils.DecodeBase64(source.uri)), source.mimeType, onSuccess, onError);
+                var sourceURL = runtime.rootUrl + source.uri;
+                if (texture.blobURL) {
+                    sourceURL = texture.blobURL;
                 }
                 else {
-                    BABYLON.Tools.LoadFile(runtime.rootUrl + source.uri, function (data) {
-                        GLTFLoader.CreateTextureAsync(runtime, textureInfo, new Uint8Array(data), source.mimeType, onSuccess, onError);
-                    }, null, null, true, onError);
+                    if (source.uri === undefined) {
+                        var bufferView = runtime.gltf.bufferViews[source.bufferView];
+                        var buffer = GLTF2.GLTFUtils.GetBufferFromBufferView(runtime, bufferView, 0, bufferView.byteLength, GLTF2.EComponentType.UNSIGNED_BYTE);
+                        texture.blobURL = URL.createObjectURL(new Blob([buffer], { type: source.mimeType }));
+                        sourceURL = texture.blobURL;
+                    }
+                    else if (GLTF2.GLTFUtils.IsBase64(source.uri)) {
+                        var decodedBuffer = new Uint8Array(GLTF2.GLTFUtils.DecodeBase64(source.uri));
+                        texture.blobURL = URL.createObjectURL(new Blob([decodedBuffer], { type: source.mimeType }));
+                        sourceURL = texture.blobURL;
+                    }
                 }
+                GLTFLoader._createTextureAsync(runtime, texture, texCoord, sourceURL, onSuccess, onError);
             };
-            GLTFLoader.CreateTextureAsync = function (runtime, textureInfo, buffer, mimeType, onSuccess, onError) {
-                var texture = runtime.gltf.textures[textureInfo.index];
-                if (!texture || texture.source === undefined) {
-                    onError();
-                    return;
-                }
-                if (texture.babylonTexture) {
-                    onSuccess(texture.babylonTexture);
-                    return;
-                }
+            GLTFLoader._createTextureAsync = function (runtime, texture, texCoord, url, onSuccess, onError) {
                 var sampler = texture.sampler ? runtime.gltf.samplers[texture.sampler] : {};
-                var createMipMaps = (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST_MIPMAP_NEAREST) ||
-                    (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST_MIPMAP_LINEAR) ||
-                    (sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR_MIPMAP_NEAREST) ||
-                    (sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR_MIPMAP_LINEAR);
+                var noMipMaps = (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST || sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR);
                 var samplingMode = BABYLON.Texture.BILINEAR_SAMPLINGMODE;
-                var blob = new Blob([buffer], { type: mimeType });
-                var blobURL = URL.createObjectURL(blob);
-                var revokeBlobURL = function () { return URL.revokeObjectURL(blobURL); };
-                texture.babylonTexture = new BABYLON.Texture(blobURL, runtime.babylonScene, !createMipMaps, true, samplingMode, revokeBlobURL, revokeBlobURL);
-                texture.babylonTexture.coordinatesIndex = textureInfo.texCoord === undefined ? 0 : textureInfo.texCoord;
-                texture.babylonTexture.wrapU = GLTF2.GLTFUtils.GetWrapMode(sampler.wrapS);
-                texture.babylonTexture.wrapV = GLTF2.GLTFUtils.GetWrapMode(sampler.wrapT);
-                texture.babylonTexture.name = texture.name;
-                onSuccess(texture.babylonTexture);
+                var babylonTexture = new BABYLON.Texture(url, runtime.babylonScene, noMipMaps, true, samplingMode, function () {
+                    onSuccess(babylonTexture);
+                }, onError);
+                babylonTexture.coordinatesIndex = texCoord;
+                babylonTexture.wrapU = GLTF2.GLTFUtils.GetWrapMode(sampler.wrapS);
+                babylonTexture.wrapV = GLTF2.GLTFUtils.GetWrapMode(sampler.wrapT);
+                babylonTexture.name = texture.name;
+                // Cache the texture
+                texture.babylonTextures = texture.babylonTextures || [];
+                texture.babylonTextures[texCoord] = babylonTexture;
             };
             /**
             * Import meshes
             */
             GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onError) {
                 scene.useRightHandedSystem = true;
-                var runtime = this._createRuntime(scene, data, rootUrl, true);
+                var runtime = GLTFLoader._createRuntime(scene, data, rootUrl, true);
                 if (!runtime) {
-                    if (onError)
-                        onError();
+                    onError();
                     return;
                 }
                 if (meshesNames === "") {
@@ -3334,58 +3420,50 @@ var BABYLON;
                     }
                 }
                 // Load buffers, materials, etc.
-                this._loadBuffersAsync(runtime, function () {
-                    importMaterials(runtime);
-                    postLoad(runtime);
-                    if (!BABYLON.GLTFFileLoader.IncrementalLoading && onSuccess) {
+                GLTFLoader._loadBuffersAsync(runtime, function () {
+                    GLTFLoader._loadMaterialsAsync(runtime, function () {
+                        postLoad(runtime);
                         onSuccess(meshes, null, skeletons);
-                    }
+                    }, onError);
                 }, onError);
                 if (BABYLON.GLTFFileLoader.IncrementalLoading && onSuccess) {
                     onSuccess(meshes, null, skeletons);
                 }
-                return true;
             };
             /**
             * Load scene
             */
             GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onError) {
                 scene.useRightHandedSystem = true;
-                var runtime = this._createRuntime(scene, data, rootUrl, false);
+                var runtime = GLTFLoader._createRuntime(scene, data, rootUrl, false);
                 if (!runtime) {
-                    if (onError)
-                        onError();
-                    return false;
+                    onError();
+                    return;
                 }
                 importScene(runtime);
-                this._loadBuffersAsync(runtime, function () {
-                    importMaterials(runtime);
-                    postLoad(runtime);
-                    if (!BABYLON.GLTFFileLoader.IncrementalLoading) {
+                GLTFLoader._loadBuffersAsync(runtime, function () {
+                    GLTFLoader._loadMaterialsAsync(runtime, function () {
+                        postLoad(runtime);
                         onSuccess();
-                    }
+                    }, onError);
                 }, onError);
-                if (BABYLON.GLTFFileLoader.IncrementalLoading) {
-                    onSuccess();
-                }
-                return true;
             };
-            GLTFLoader.prototype._loadBuffersAsync = function (runtime, onSuccess, onError) {
+            GLTFLoader._loadBuffersAsync = function (runtime, onSuccess, onError) {
                 var _this = this;
                 if (runtime.gltf.buffers.length == 0) {
                     onSuccess();
                     return;
                 }
-                var loadedCount = 0;
+                var successCount = 0;
                 runtime.gltf.buffers.forEach(function (buffer, index) {
                     _this._loadBufferAsync(runtime, index, function () {
-                        if (++loadedCount >= runtime.gltf.buffers.length) {
+                        if (++successCount === runtime.gltf.buffers.length) {
                             onSuccess();
                         }
                     }, onError);
                 });
             };
-            GLTFLoader.prototype._loadBufferAsync = function (runtime, index, onSuccess, onError) {
+            GLTFLoader._loadBufferAsync = function (runtime, index, onSuccess, onError) {
                 var buffer = runtime.gltf.buffers[index];
                 if (buffer.uri === undefined) {
                     // buffer.loadedBufferView should already be set
@@ -3405,7 +3483,22 @@ var BABYLON;
                     }, null, null, true, onError);
                 }
             };
-            GLTFLoader.prototype._createRuntime = function (scene, data, rootUrl, importOnlyMeshes) {
+            GLTFLoader._loadMaterialsAsync = function (runtime, onSuccess, onError) {
+                var materials = runtime.gltf.materials;
+                if (!materials) {
+                    onSuccess();
+                    return;
+                }
+                var successCount = 0;
+                for (var i = 0; i < materials.length; i++) {
+                    GLTF2.GLTFLoaderExtension.LoadMaterialAsync(runtime, i, function () {
+                        if (++successCount === materials.length) {
+                            onSuccess();
+                        }
+                    }, onError);
+                }
+            };
+            GLTFLoader._createRuntime = function (scene, data, rootUrl, importOnlyMeshes) {
                 var runtime = {
                     gltf: data.json,
                     babylonScene: scene,
@@ -3434,32 +3527,6 @@ var BABYLON;
             return GLTFLoader;
         }());
         GLTFLoader.Extensions = {};
-        GLTFLoader.LoadMetallicRoughnessMaterialProperties = function (runtime, material) {
-            var properties = material.pbrMetallicRoughness;
-            if (!properties)
-                return;
-            material.babylonMaterial.albedoColor = properties.baseColorFactor ? BABYLON.Color3.FromArray(properties.baseColorFactor) : new BABYLON.Color3(1, 1, 1);
-            material.babylonMaterial.metallic = properties.metallicFactor === undefined ? 1 : properties.metallicFactor;
-            material.babylonMaterial.roughness = properties.roughnessFactor === undefined ? 1 : properties.roughnessFactor;
-            if (properties.baseColorTexture) {
-                GLTFLoader.LoadTextureAsync(runtime, properties.baseColorTexture, function (texture) {
-                    material.babylonMaterial.albedoTexture = texture;
-                    GLTFLoader.LoadAlphaProperties(runtime, material);
-                }, function () {
-                    BABYLON.Tools.Warn("Failed to load base color texture");
-                });
-            }
-            if (properties.metallicRoughnessTexture) {
-                GLTFLoader.LoadTextureAsync(runtime, properties.metallicRoughnessTexture, function (texture) {
-                    material.babylonMaterial.metallicTexture = texture;
-                    material.babylonMaterial.useMetallnessFromMetallicTextureBlue = true;
-                    material.babylonMaterial.useRoughnessFromMetallicTextureGreen = true;
-                    material.babylonMaterial.useRoughnessFromMetallicTextureAlpha = false;
-                }, function () {
-                    BABYLON.Tools.Warn("Failed to load metallic roughness texture");
-                });
-            }
-        };
         GLTF2.GLTFLoader = GLTFLoader;
         BABYLON.GLTFFileLoader.GLTFLoaderV2 = new GLTFLoader();
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
@@ -3620,7 +3687,7 @@ var BABYLON;
             });
             GLTFLoaderExtension.prototype.postCreateRuntime = function (runtime) { };
             // Return true to stop other extensions from loading materials.
-            GLTFLoaderExtension.prototype.loadMaterial = function (runtime, index) { return false; };
+            GLTFLoaderExtension.prototype.loadMaterialAsync = function (runtime, index, onSuccess, onError) { return false; };
             // ---------
             // Utilities
             // ---------
@@ -3630,18 +3697,33 @@ var BABYLON;
                     extension.postCreateRuntime(runtime);
                 }
             };
-            GLTFLoaderExtension.LoadMaterial = function (runtime, index) {
+            GLTFLoaderExtension.LoadMaterialAsync = function (runtime, index, onSuccess, onError) {
                 for (var extensionName in GLTF2.GLTFLoader.Extensions) {
                     var extension = GLTF2.GLTFLoader.Extensions[extensionName];
-                    if (extension.loadMaterial(runtime, index)) {
+                    if (extension.loadMaterialAsync(runtime, index, onSuccess, onError)) {
                         return;
                     }
                 }
                 var material = GLTF2.GLTFLoader.LoadMaterial(runtime, index);
-                if (material) {
-                    GLTF2.GLTFLoader.LoadMetallicRoughnessMaterialProperties(runtime, material);
-                    GLTF2.GLTFLoader.LoadCommonMaterialProperties(runtime, material);
+                if (!material) {
+                    onSuccess();
+                    return;
                 }
+                var metallicRoughnessPropertiesSuccess = false;
+                var commonPropertiesSuccess = false;
+                var checkSuccess = function () {
+                    if (metallicRoughnessPropertiesSuccess && commonPropertiesSuccess) {
+                        onSuccess();
+                    }
+                };
+                GLTF2.GLTFLoader.LoadMetallicRoughnessMaterialPropertiesAsync(runtime, material, function () {
+                    metallicRoughnessPropertiesSuccess = true;
+                    checkSuccess();
+                }, onError);
+                GLTF2.GLTFLoader.LoadCommonMaterialPropertiesAsync(runtime, material, function () {
+                    commonPropertiesSuccess = true;
+                    checkSuccess();
+                }, onError);
             };
             return GLTFLoaderExtension;
         }());
@@ -3671,33 +3753,54 @@ var BABYLON;
             function GLTFMaterialsPbrSpecularGlossinessExtension() {
                 return _super.call(this, "KHR_materials_pbrSpecularGlossiness") || this;
             }
-            GLTFMaterialsPbrSpecularGlossinessExtension.prototype.loadMaterial = function (runtime, index) {
+            GLTFMaterialsPbrSpecularGlossinessExtension.prototype.loadMaterialAsync = function (runtime, index, onSuccess, onError) {
                 var material = GLTF2.GLTFLoader.LoadMaterial(runtime, index);
                 if (!material || !material.extensions)
                     return false;
                 var properties = material.extensions[this.name];
                 if (!properties)
                     return false;
+                //
+                // Load Factors
+                //
                 material.babylonMaterial.albedoColor = properties.diffuseFactor ? BABYLON.Color3.FromArray(properties.diffuseFactor) : new BABYLON.Color3(1, 1, 1);
                 material.babylonMaterial.reflectivityColor = properties.specularFactor ? BABYLON.Color3.FromArray(properties.specularFactor) : new BABYLON.Color3(1, 1, 1);
                 material.babylonMaterial.microSurface = properties.glossinessFactor === undefined ? 1 : properties.glossinessFactor;
+                //
+                // Load Textures
+                //
+                var commonMaterialPropertiesSuccess = false;
+                var checkSuccess = function () {
+                    if ((!properties.diffuseTexture || material.babylonMaterial.albedoTexture) &&
+                        (!properties.specularGlossinessTexture || material.babylonMaterial.reflectivityTexture) &&
+                        commonMaterialPropertiesSuccess) {
+                        onSuccess();
+                    }
+                };
                 if (properties.diffuseTexture) {
                     GLTF2.GLTFLoader.LoadTextureAsync(runtime, properties.diffuseTexture, function (texture) {
                         material.babylonMaterial.albedoTexture = texture;
                         GLTF2.GLTFLoader.LoadAlphaProperties(runtime, material);
+                        checkSuccess();
                     }, function () {
                         BABYLON.Tools.Warn("Failed to load diffuse texture");
+                        onError();
                     });
                 }
                 if (properties.specularGlossinessTexture) {
                     GLTF2.GLTFLoader.LoadTextureAsync(runtime, properties.specularGlossinessTexture, function (texture) {
                         material.babylonMaterial.reflectivityTexture = texture;
                         material.babylonMaterial.useMicroSurfaceFromReflectivityMapAlpha = true;
+                        checkSuccess();
                     }, function () {
                         BABYLON.Tools.Warn("Failed to load metallic roughness texture");
+                        onError();
                     });
                 }
-                GLTF2.GLTFLoader.LoadCommonMaterialProperties(runtime, material);
+                GLTF2.GLTFLoader.LoadCommonMaterialPropertiesAsync(runtime, material, function () {
+                    commonMaterialPropertiesSuccess = true;
+                    checkSuccess();
+                }, onError);
                 return true;
             };
             return GLTFMaterialsPbrSpecularGlossinessExtension;

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 2 - 2
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 5 - 1
src/Debug/babylon.debugLayer.ts

@@ -46,7 +46,11 @@ module BABYLON {
 
         public hide() {
             if (this._inspector) {
-                this._inspector.dispose();
+                try {
+                    this._inspector.dispose();
+                } catch (e) {
+                    // If the inspector has been removed directly from the inspector tool
+                }
                 this._inspector = null;
             }
         }

+ 25 - 6
src/Materials/babylon.material.ts

@@ -488,12 +488,6 @@
                 this._scene.materials.splice(index, 1);
             }
 
-            // Shader are kept in cache for further use but we can get rid of this by using forceDisposeEffect
-            if (forceDisposeEffect && this._effect) {
-                this._scene.getEngine()._releaseEffect(this._effect);
-                this._effect = null;
-            }
-
             // Remove from meshes
             for (index = 0; index < this._scene.meshes.length; index++) {
                 var mesh = this._scene.meshes[index];
@@ -501,8 +495,33 @@
                 if (mesh.material === this) {
                     mesh.material = null;
                 }
+
+                if ((<Mesh>mesh).geometry) {
+                    var geometry = (<Mesh>mesh).geometry;
+
+                    if (this.storeEffectOnSubMeshes) {
+                        for (var subMesh of mesh.subMeshes) {
+                            geometry._releaseVertexArrayObject(subMesh._materialEffect);
+                        }
+                    } else {
+                        geometry._releaseVertexArrayObject(this._effect)
+                    }
+                }
             }
 
+            // Shader are kept in cache for further use but we can get rid of this by using forceDisposeEffect
+            if (forceDisposeEffect && this._effect) {
+                    if (this.storeEffectOnSubMeshes) {
+                        for (var subMesh of mesh.subMeshes) {
+                            this._scene.getEngine()._releaseEffect(subMesh._materialEffect); 
+                        }
+                    } else {
+                        this._scene.getEngine()._releaseEffect(this._effect);                    
+                    }
+
+                this._effect = null;
+            }
+            
             // Callback
             this.onDisposeObservable.notifyObservers(this);
 

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

@@ -419,7 +419,7 @@
             if (index === -1) {
                 return;
             }
-            this._lightSources.slice(index, 1);       
+            this._lightSources.splice(index, 1);       
         }
 
         private _markSubMeshesAsDirty(func: (defines: MaterialDefines) => void) {

+ 7 - 0
src/Mesh/babylon.geometry.ts

@@ -348,6 +348,13 @@
             return this._indexBuffer;
         }
 
+        public _releaseVertexArrayObject(effect: Effect) {
+            if (this._vertexArrayObjects[effect.key]) {
+                this._engine.releaseVertexArrayObject(this._vertexArrayObjects[effect.key]);
+                delete this._vertexArrayObjects[effect.key];
+            }
+        }
+
         public releaseForMesh(mesh: Mesh, shouldDispose?: boolean): void {
             var meshes = this._meshes;
             var index = meshes.indexOf(mesh);

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

@@ -16,7 +16,7 @@
         public _id: number;
 
         public _materialDefines: MaterialDefines;
-        private _materialEffect: Effect;
+        public _materialEffect: Effect;
         private _currentMaterial: Material;
 
         public get effect(): Effect {

+ 0 - 30
src/Tools/babylon.extendedGamepad.ts

@@ -59,12 +59,6 @@ module BABYLON {
 
         public update() {
             super.update();
-            // update this device's offset position from the attached camera, if provided
-            //if (this._poseControlledCamera && this._poseControlledCamera.deviceScaleFactor) {
-            //this.position.copyFrom(this._poseControlledCamera.position);
-            //this.rotationQuaternion.copyFrom(this._poseControlledCamera.rotationQuaternion);
-            //this.deviceScaleFactor = this._poseControlledCamera.deviceScaleFactor;
-            //}
             var pose: GamepadPose = this.vrGamepad.pose;
             this.updateFromDevice(pose);
 
@@ -85,12 +79,6 @@ module BABYLON {
 
                     this.devicePosition.scaleToRef(this.deviceScaleFactor, this._calculatedPosition);
                     this._calculatedPosition.addInPlace(this.position);
-
-                    // scale the position using the scale factor, add the device's position
-                    /*if (this._poseControlledCamera) {
-                        // this allows total positioning freedom - the device, the camera and the mesh can be individually controlled.
-                        this._calculatedPosition.addInPlace(this._poseControlledCamera.position);
-                    }*/
                 }
                 if (poseData.orientation) {
                     this.deviceRotationQuaternion.copyFromFloats(this.rawPose.orientation[0], this.rawPose.orientation[1], -this.rawPose.orientation[2], -this.rawPose.orientation[3]);
@@ -105,24 +93,6 @@ module BABYLON {
 
                     // if the camera is set, rotate to the camera's rotation
                     this.deviceRotationQuaternion.multiplyToRef(this.rotationQuaternion, this._calculatedRotation);
-
-                    /*if (this._poseControlledCamera) {
-                        Matrix.ScalingToRef(1, 1, 1, Tmp.Matrix[1]);
-                        this._calculatedRotation.toRotationMatrix(Tmp.Matrix[0]);
-                        Matrix.TranslationToRef(this._calculatedPosition.x, this._calculatedPosition.y, this._calculatedPosition.z, Tmp.Matrix[2]);
-
-                        //Matrix.Identity().multiplyToRef(Tmp.Matrix[1], Tmp.Matrix[4]);
-                        Tmp.Matrix[1].multiplyToRef(Tmp.Matrix[0], Tmp.Matrix[5]);
-
-                        this._poseControlledCamera.getWorldMatrix().getTranslationToRef(Tmp.Vector3[0])
-
-                        Matrix.ComposeToRef(new Vector3(this.deviceScaleFactor, this.deviceScaleFactor, this.deviceScaleFactor), this._poseControlledCamera.rotationQuaternion, Tmp.Vector3[0], Tmp.Matrix[4]);
-                        Tmp.Matrix[5].multiplyToRef(Tmp.Matrix[2], Tmp.Matrix[1]);
-
-                        Tmp.Matrix[1].multiplyToRef(Tmp.Matrix[4], Tmp.Matrix[2]);
-                        Tmp.Matrix[2].decompose(Tmp.Vector3[0], this._calculatedRotation, this._calculatedPosition);
-
-                    }*/
                 }
             }
         }

+ 9 - 3
src/babylon.engine.ts

@@ -3311,6 +3311,14 @@
             }
         }
 
+        public releaseEffects() {
+            for (var name in this._compiledEffects) {
+                this._gl.deleteProgram(this._compiledEffects[name]._program);
+            }
+
+            this._compiledEffects = {};
+        }
+
         // Dispose
         public dispose(): void {
             this.hideLoadingUI();
@@ -3326,9 +3334,7 @@
             Engine.audioEngine.dispose();
 
             // Release effects
-            for (var name in this._compiledEffects) {
-                this._gl.deleteProgram(this._compiledEffects[name]._program);
-            }
+            this.releaseEffects();
 
             // Unbind
             this.unbindAllAttributes();

BIN=BIN
tests/validation/ReferenceImages/fresnel.png


BIN=BIN
tests/validation/ReferenceImages/softShadows.png


+ 16 - 3
tests/validation/config.json

@@ -1,7 +1,7 @@
 {
   "root": "https://cdn.rawgit.com/BabylonJS/Website/06ecbea7",
-  "tests": [  
-   {
+  "tests": [   
+ {
       "title": "Sponza",
       "sceneFolder": "/Scenes/Sponza/",
       "sceneFilename": "Sponza.babylon",
@@ -90,7 +90,20 @@
       "scriptToRun": "/Demos/Polygon/polygon.js",
       "functionToCall": "CreatePolygonScene",
       "referenceImage": "polygon.png"
-    },      
+    },        
+    {
+      "title": "Soft Shadows",
+      "renderCount": 5,
+      "scriptToRun": "/Demos/SoftShadows/softShadows.js",
+      "functionToCall": "CreateSoftShadowsTestScene",
+      "referenceImage": "softShadows.png"
+    },
+    {
+      "title": "Fresnel",
+      "scriptToRun": "/Demos/Fresnel/fresnel.js",
+      "functionToCall": "CreateFresnelTestScene",
+      "referenceImage": "fresnel.png"
+    },
     {
       "title": "Lines",
       "scriptToRun": "/Demos/Lines/lines.js",

+ 27 - 17
tests/validation/validation.js

@@ -97,11 +97,16 @@ function processCurrentScene(test, resultCanvas, result, renderImage, index, wai
     currentScene.executeWhenReady(function () {
         var renderCount = test.renderCount || 1;
 
-        for (var renderIndex = 0; renderIndex < renderCount; renderIndex++) {
+        engine.runRenderLoop(function() {
             currentScene.render();
-        }
+            renderCount--;
+
+            if (renderCount === 0) {
+                engine.stopRenderLoop();
+                evaluate(resultCanvas, result, renderImage, index, waitRing);
+            }
+        });
 
-        evaluate(resultCanvas, result, renderImage, index, waitRing);
     });
 }
 
@@ -163,24 +168,29 @@ function runTest(index) {
             processCurrentScene(test, resultCanvas, result, renderImage, index, waitRing);
         });
     } else {
-        var script = document.createElement("script");
-        script.setAttribute("type", "text/javascript")
-
-        var runScript = function () {
-            currentScene = eval(test.functionToCall + "(engine)");
-            processCurrentScene(test, resultCanvas, result, renderImage, index, waitRing);
+        // Fix references
+        if (test.specificRoot) {
+            BABYLON.Tools.BaseUrl = config.root + test.specificRoot;
         }
 
-        script.onreadystatechange = function () {
-            if (this.readyState == 'complete') {
-                runScript();
-            }
-        }
+        var request = new XMLHttpRequest();
+        request.open('GET', config.root + test.scriptToRun, true);
+
+        request.onreadystatechange = () => {
+            if (request.readyState === 4) {
+                request.onreadystatechange = null; 
 
-        script.onload = runScript;
-        script.setAttribute("src", config.root + test.scriptToRun);
+                var scriptToRun = request.responseText.replace(/..\/..\/assets\//g, config.root + "/Assets/");
+
+                console.log(scriptToRun);
+
+                currentScene = eval(scriptToRun + test.functionToCall + "(engine)");
+                processCurrentScene(test, resultCanvas, result, renderImage, index, waitRing);
+            }
+        };
 
-        document.getElementsByTagName("head")[0].appendChild(script);
+        request.send(null);
+        
     }
 }