David Catuhe il y a 6 ans
Parent
commit
9d6e96b801
100 fichiers modifiés avec 93552 ajouts et 23690 suppressions
  1. 1854 315
      Playground/babylon.d.txt
  2. 2 1
      Playground/debug.html
  3. 402 405
      Playground/ts.html
  4. 55 2
      Tools/Config/config.json
  5. 4 4
      azure-pipelines.yml
  6. 37 38
      bower.json
  7. 1874 314
      dist/preview release/babylon.d.ts
  8. 2 2
      dist/preview release/babylon.js
  9. 5557 514
      dist/preview release/babylon.max.js
  10. 1 1
      dist/preview release/babylon.max.js.map
  11. 13826 10529
      dist/preview release/babylon.module.d.ts
  12. 1875 315
      dist/preview release/documentation.d.ts
  13. 2 2
      dist/preview release/gui/babylon.gui.js
  14. 1 1
      dist/preview release/gui/babylon.gui.js.map
  15. 1 1
      dist/preview release/gui/babylon.gui.min.js
  16. 6 6
      dist/preview release/inspector/babylon.inspector.bundle.js
  17. 171 106
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  18. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  19. 26 7
      dist/preview release/inspector/babylon.inspector.d.ts
  20. 59 14
      dist/preview release/inspector/babylon.inspector.module.d.ts
  21. 4 2
      dist/preview release/inspector/package.json
  22. 13 9
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  23. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.js.map
  24. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  25. 13 9
      dist/preview release/loaders/babylon.glTFFileLoader.js
  26. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.js.map
  27. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  28. 13 9
      dist/preview release/loaders/babylonjs.loaders.js
  29. 1 1
      dist/preview release/loaders/babylonjs.loaders.js.map
  30. 1 1
      dist/preview release/loaders/babylonjs.loaders.min.js
  31. 609 0
      dist/preview release/nodeEditor/babylon.nodeEditor.d.ts
  32. 41 0
      dist/preview release/nodeEditor/babylon.nodeEditor.js
  33. 49364 0
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js
  34. 1 0
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map
  35. 1325 0
      dist/preview release/nodeEditor/babylon.nodeEditor.module.d.ts
  36. 27 0
      dist/preview release/nodeEditor/package.json
  37. 1 0
      dist/preview release/nodeEditor/readme-es6.md
  38. 1 0
      dist/preview release/nodeEditor/readme.md
  39. 1 1
      dist/preview release/packagesSizeBaseLine.json
  40. 14 19
      dist/preview release/serializers/babylon.glTF2Serializer.js
  41. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.js.map
  42. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  43. 1 1
      dist/preview release/serializers/babylonjs.serializers.d.ts
  44. 14 19
      dist/preview release/serializers/babylonjs.serializers.js
  45. 1 1
      dist/preview release/serializers/babylonjs.serializers.js.map
  46. 1 1
      dist/preview release/serializers/babylonjs.serializers.min.js
  47. 2 5
      dist/preview release/serializers/babylonjs.serializers.module.d.ts
  48. 13826 10529
      dist/preview release/viewer/babylon.module.d.ts
  49. 470 322
      dist/preview release/viewer/babylon.viewer.js
  50. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  51. 11 0
      dist/preview release/what's new.md
  52. 2 2
      gui/src/2D/controls/line.ts
  53. 2 2
      inspector/README.md
  54. 46 33
      inspector/src/components/actionTabs/actionTabsComponent.tsx
  55. 4 4
      inspector/src/components/actionTabs/lineContainerComponent.tsx
  56. 5 2
      inspector/src/components/actionTabs/lines/fileButtonLineComponent.tsx
  57. 5 3
      inspector/src/components/actionTabs/lines/floatLineComponent.tsx
  58. 17 5
      inspector/src/components/actionTabs/lines/textureLineComponent.tsx
  59. 12 0
      inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx
  60. 1 1
      inspector/src/components/actionTabs/tabs/propertyGrids/cameras/freeCameraPropertyGridComponent.tsx
  61. 1 1
      inspector/src/components/actionTabs/tabs/propertyGrids/lights/commonShadowLightPropertyGridComponent.tsx
  62. 42 0
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/nodeMaterialPropertyGridComponent.tsx
  63. 1 0
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrMaterialPropertyGridComponent.tsx
  64. 2 0
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/standardMaterialPropertyGridComponent.tsx
  65. 22 0
      inspector/src/components/actionTabs/tabs/propertyGrids/meshes/meshPropertyGridComponent.tsx
  66. 21 0
      inspector/src/components/sceneExplorer/sceneExplorerComponent.tsx
  67. 0 0
      inspector/src/index.css
  68. 0 2
      inspector/src/index.ts
  69. 25 20
      inspector/src/inspector.ts
  70. BIN
      inspector/test/environment.dds
  71. BIN
      inspector/test/explosion.wav
  72. 0 91
      inspector/test/index.js
  73. BIN
      inspector/test/jump.wav
  74. BIN
      inspector/test/test_1.dds
  75. 13 9
      loaders/src/glTF/2.0/glTFLoader.ts
  76. 1 0
      nodeEditor/README-ES6.md
  77. 18 0
      nodeEditor/README.md
  78. 95 0
      nodeEditor/src/components/diagram/defaultNodeModel.ts
  79. 73 0
      nodeEditor/src/components/diagram/defaultPortModel.ts
  80. 94 0
      nodeEditor/src/components/diagram/diagram.scss
  81. 39 0
      nodeEditor/src/components/diagram/generic/genericNodeFactory.tsx
  82. 58 0
      nodeEditor/src/components/diagram/generic/genericNodeModel.tsx
  83. 98 0
      nodeEditor/src/components/diagram/generic/genericNodeWidget.tsx
  84. 39 0
      nodeEditor/src/components/diagram/input/inputNodeFactory.tsx
  85. 29 0
      nodeEditor/src/components/diagram/input/inputNodeModel.tsx
  86. 130 0
      nodeEditor/src/components/diagram/input/inputNodePropertyComponent.tsx
  87. 104 0
      nodeEditor/src/components/diagram/input/inputNodeWidget.tsx
  88. 39 0
      nodeEditor/src/components/diagram/texture/textureNodeFactory.tsx
  89. 40 0
      nodeEditor/src/components/diagram/texture/textureNodeModel.tsx
  90. 90 0
      nodeEditor/src/components/diagram/texture/textureNodeWidget.tsx
  91. 123 0
      nodeEditor/src/components/nodeList/nodeList.scss
  92. 72 0
      nodeEditor/src/components/nodeList/nodeListComponent.tsx
  93. 59 0
      nodeEditor/src/components/propertyTab/properties/texturePropertyTabComponent.tsx
  94. 19 0
      nodeEditor/src/components/propertyTab/properties/vector2PropertyTabComponent.tsx
  95. 19 0
      nodeEditor/src/components/propertyTab/properties/vector3PropertyTabComponent.tsx
  96. 261 0
      nodeEditor/src/components/propertyTab/propertyTab.scss
  97. 39 0
      nodeEditor/src/components/propertyTab/propertyTabComponent.tsx
  98. 12 0
      nodeEditor/src/globalState.ts
  99. 261 0
      nodeEditor/src/graphEditor.tsx
  100. 0 0
      nodeEditor/src/index.ts

Fichier diff supprimé car celui-ci est trop grand
+ 1854 - 315
Playground/babylon.d.txt


+ 2 - 1
Playground/debug.html

@@ -5,7 +5,8 @@
         <title>Babylon.js Playground</title>
         <meta charset='utf-8' />
         <meta name="viewport" content="width=device-width, user-scalable=no">
-        <link rel="shortcut icon" href="https://www.babylonjs.com/img/favicon/favicon.ico">
+        <link rel="shortcut icon" href="https://www.babylonjs.com/favicon.ico">        
+        <link rel="stylesheet" href="https://use.typekit.net/cta4xsb.css">
         <link rel="apple-touch-icon" sizes="57x57" href="https://www.babylonjs.com/img/favicon/apple-icon-57x57.png">
         <link rel="apple-touch-icon" sizes="60x60" href="https://www.babylonjs.com/img/favicon/apple-icon-60x60.png">
         <link rel="apple-touch-icon" sizes="72x72" href="https://www.babylonjs.com/img/favicon/apple-icon-72x72.png">

+ 402 - 405
Playground/ts.html

@@ -1,495 +1,492 @@
 <!DOCTYPE html>
 <html>
 
-    <head>
-        <title>Babylon.js Playground</title>
-        <meta charset='utf-8' />
-        <meta name="viewport" content="width=device-width, user-scalable=no">
-        <link rel="shortcut icon" href="https://www.babylonjs.com/img/favicon/favicon.ico">
-        <link rel="apple-touch-icon" sizes="57x57" href="https://www.babylonjs.com/img/favicon/apple-icon-57x57.png">
-        <link rel="apple-touch-icon" sizes="60x60" href="https://www.babylonjs.com/img/favicon/apple-icon-60x60.png">
-        <link rel="apple-touch-icon" sizes="72x72" href="https://www.babylonjs.com/img/favicon/apple-icon-72x72.png">
-        <link rel="apple-touch-icon" sizes="76x76" href="https://www.babylonjs.com/img/favicon/apple-icon-76x76.png">
-        <link rel="apple-touch-icon" sizes="114x114" href="https://www.babylonjs.com/img/favicon/apple-icon-114x114.png">
-        <link rel="apple-touch-icon" sizes="120x120" href="https://www.babylonjs.com/img/favicon/apple-icon-120x120.png">
-        <link rel="apple-touch-icon" sizes="144x144" href="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png">
-        <link rel="apple-touch-icon" sizes="152x152" href="https://www.babylonjs.com/img/favicon/apple-icon-152x152.png">
-        <link rel="apple-touch-icon" sizes="180x180" href="https://www.babylonjs.com/img/favicon/apple-icon-180x180.png">
-        <link rel="icon" type="image/png" sizes="192x192" href="https://www.babylonjs.com/img/favicon/android-icon-192x192.png">
-        <link rel="icon" type="image/png" sizes="32x32" href="https://www.babylonjs.com/img/favicon/favicon-32x32.png">
-        <link rel="icon" type="image/png" sizes="96x96" href="https://www.babylonjs.com/img/favicon/favicon-96x96.png">
-        <link rel="icon" type="image/png" sizes="16x16" href="https://www.babylonjs.com/img/favicon/favicon-16x16.png">
-        <link rel="manifest" href="https://www.babylonjs.com/img/favicon/manifest.json">
-        <meta name="msapplication-TileColor" content="#ffffff">
-        <meta name="msapplication-TileImage" content="https://www.babylonjs.com/img/favicon/ms-icon-144x144.png">
-        <meta name="msapplication-config" content="https://www.babylonjs.com/img/favicon/browserconfig.xml">
-        <meta name="theme-color" content="#ffffff">
-
-        <script src="js/libs/pep.min.js"></script>
-        <!--For canvas/code separator-->
-        <script src="js/libs/split.js"></script>
-
-        <script src="js/libs/dat.gui.min.js"></script>
-        <!-- jszip -->
-        <script src="js/libs/jszip.min.js"></script>
-        <script src="js/libs/fileSaver.js"></script>
-        <!-- Dependencies -->
-        <script src="https://preview.babylonjs.com/ammo.js"></script>
-        <script src="https://preview.babylonjs.com/cannon.js"></script>
-        <script src="https://preview.babylonjs.com/Oimo.js"></script>
-        <script src="https://preview.babylonjs.com/earcut.min.js"></script>
-        <!-- Babylon.js -->
-        <script src="https://preview.babylonjs.com/babylon.js"></script>
-        <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
-        <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
-        <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
-        <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
-        <script src="https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
-        <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.js"></script>
-        <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
-
-        <!-- Monaco -->
-        <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
-
-        <!-- Extensions -->
-        <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js" async></script>
-        <script src="https://rawgit.com/BabylonJS/Extensions/master/CompoundShader/src/babylonx.CompoundShader.js" async></script>
-
-        <!-- Scene Manager -->
-        <script src="https://mackeyk24.github.io/toolkit/babylon.manager.js"></script>
-        <script src="https://mackeyk24.github.io/toolkit/babylon.navmesh.js"></script>
-
-        <link href="css/index.css" rel="stylesheet" />
-        <link href="css/color_ts.css" rel="stylesheet" />
-    </head>
-
-    <body>
-        <div class="navbar navBar1600">
-            <div class="title">
-                Babylon.js Playground
-            </div>
-            <div class="version" id="mainTitle">
-            </div>
+<head>
+    <title>Babylon.js Playground</title>
+    <meta charset='utf-8' />
+    <meta name="viewport" content="width=device-width, user-scalable=no">
+    <link rel="shortcut icon" href="https://www.babylonjs.com/favicon.ico">
+
+    <link rel="stylesheet" href="https://use.typekit.net/cta4xsb.css">
+
+    <script src="js/libs/pep.min.js"></script>
+    <!--For canvas/code separator-->
+    <script src="js/libs/split.js"></script>
+
+    <script src="js/libs/dat.gui.min.js"></script>
+    <!-- jszip -->
+    <script src="js/libs/jszip.min.js"></script>
+    <script src="js/libs/fileSaver.js"></script>
+    <!-- Dependencies -->
+    <script src="https://preview.babylonjs.com/ammo.js"></script>
+    <script src="https://preview.babylonjs.com/cannon.js"></script>
+    <script src="https://preview.babylonjs.com/Oimo.js"></script>
+    <script src="https://preview.babylonjs.com/gltf_validator.js"></script>
+    <script src="https://preview.babylonjs.com/earcut.min.js"></script>
+    <!-- Babylon.js -->
+    <script src="https://preview.babylonjs.com/babylon.js"></script>
+    <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
+    <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
+    <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
+    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
+    <script src="https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
+    <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.min.js"></script>
+    <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
+
+    <!-- Monaco -->
+    <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
+
+    <!-- Extensions -->
+    <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js" async></script>
+    <script src="https://rawgit.com/BabylonJS/Extensions/master/CompoundShader/src/babylonx.CompoundShader.js"
+        async></script>
+
+    <!-- Scene Manager -->
+    <script src="https://mackeyk24.github.io/toolkit/babylon.manager.js"></script>
+    <script src="https://mackeyk24.github.io/toolkit/babylon.navmesh.js"></script>
+
+    <link href="css/index.css" rel="stylesheet" />
+    <link href="css/color_ts.css" rel="stylesheet" />
+</head>
+
+<body>
+    <div class="navbar navBar1600">
+        <div class="title">
+            Babylon.js Playground
+        </div>
+        <div class="version" id="mainTitle">
+        </div>
 
-            <div class="category">
-                <div class="button run" id="runButton1600">Run
-                    <i class="fa fa-play" aria-hidden="true"></i>
-                </div>
+        <div class="category">
+            <div class="button run" id="runButton1600">Run
+                <i class="fa fa-play" aria-hidden="true"></i>
             </div>
+        </div>
 
 
-            <div class="category">
-                <div class="button" id="newButton1600">New
-                    <i class="fa fa-file" aria-hidden="true"></i>
-                </div>
-                <div class="button removeOnPhone" id="clearButton1600">Clear
-                    <i class="fa fa-trash" aria-hidden="true"></i>
-                </div>
+        <div class="category">
+            <div class="button" id="newButton1600">New
+                <i class="fa fa-file" aria-hidden="true"></i>
+            </div>
+            <div class="button removeOnPhone" id="clearButton1600">Clear
+                <i class="fa fa-trash" aria-hidden="true"></i>
             </div>
+        </div>
 
-            <div class="category">
-                <div class="button" id="saveButton1600">Save
-                    <i class="fa fa-floppy-o" aria-hidden="true"></i>
-                </div>
-                <div class="button removeOnPhone" id="zipButton1600">Zip
-                    <i class="fa fa-download" aria-hidden="true"></i>
-                </div>
+        <div class="category">
+            <div class="button" id="saveButton1600">Save
+                <i class="fa fa-floppy-o" aria-hidden="true"></i>
+            </div>
+            <div class="button removeOnPhone" id="zipButton1600">Zip
+                <i class="fa fa-download" aria-hidden="true"></i>
             </div>
+        </div>
 
-            <div class="category">
-                <div class="button select">Settings
-                    <div class="toDisplay">
-                        <div class="option subSelect">Theme
-                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                            <div class="toDisplaySub">
-                                <div class="option" id="darkTheme1600">Dark</div>
-                                <div class="option" id="lightTheme1600">Light</div>
-                            </div>
+        <div class="category">
+            <div class="button select">Settings
+                <div class="toDisplay">
+                    <div class="option subSelect">Theme
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" id="darkTheme1600">Dark</div>
+                            <div class="option" id="lightTheme1600">Light</div>
                         </div>
-                        <div class="option subSelect">
-                            <span id="currentFontSize1600">Font: 14</span>
-                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                            <div class="toDisplaySub">
-                                <div class="option" onclick="setFontSize(12);">12</div>
-                                <div class="option" onclick="setFontSize(14);">14</div>
-                                <div class="option" onclick="setFontSize(16);">16</div>
-                                <div class="option" onclick="setFontSize(18);">18</div>
-                                <div class="option" onclick="setFontSize(20);">20</div>
-                                <div class="option" onclick="setFontSize(22);">22</div>
-                            </div>
-                        </div>
-                        <div class="option" id="safemodeToggle1600">Safe mode
-                            <i class="far fa-square" aria-hidden="true"></i>
-                        </div>
-                        <div class="option checked" id="editorButton1600">Editor
-                            <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option subSelect">
+                        <span id="currentFontSize1600">Font: 14</span>
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setFontSize(12);">12</div>
+                            <div class="option" onclick="setFontSize(14);">14</div>
+                            <div class="option" onclick="setFontSize(16);">16</div>
+                            <div class="option" onclick="setFontSize(18);">18</div>
+                            <div class="option" onclick="setFontSize(20);">20</div>
+                            <div class="option" onclick="setFontSize(22);">22</div>
                         </div>
-                        <div class="option" id="fullscreenButton1600">Fullscreen</div>
-                        <div class="option" id="editorFullscreenButton1600">Editor Fullscreen</div>
-                        <div class="option" id="formatButton1600">Format code</div>
-                        <div class="option" id="minimapToggle1600">Minimap
-                            <i class="far fa-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="safemodeToggle1600">Safe mode
+                        <i class="far fa-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option checked" id="editorButton1600">Editor
+                        <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton1600">Fullscreen</div>
+                    <div class="option" id="editorFullscreenButton1600">Editor Fullscreen</div>
+                    <div class="option" id="formatButton1600">Format code</div>
+                    <div class="option" id="minimapToggle1600">Minimap
+                        <i class="far fa-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option subSelect" id="qrCodeHover" onmouseover="showQRCode();">QR Code Link
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" style="height:auto;padding: 20px;background: white;" id="qrCodeImage">QR
+                                Code Image</div>
                         </div>
                     </div>
                 </div>
-
-                <div class="button uncheck" id="debugButton1600">Inspector</div>
-                <div class="button" id="metadataButton1600">Metadata</div>
             </div>
 
+            <div class="button uncheck" id="debugButton1600">Inspector</div>
+            <div class="button" id="metadataButton1600">Metadata</div>
+        </div>
 
 
-            <div class="category right">
-                <div class="button select">
-                    <span id="currentVersion1600">Version: Latest</span>
-                    <div class="toDisplay">
-                        <div class="option" onclick="setVersion('latest');">Latest</div>
-                        <div class="option" onclick="setVersion('stable');">Stable</div>
-                    </div>
-                </div>
-                <div class="button select">
-                    <span class="examplesButton">Examples</span>
+
+        <div class="category right">
+            <div class="button select">
+                <span id="currentVersion1600">Version: Latest</span>
+                <div class="toDisplay">
+                    <div class="option" onclick="setVersion('latest');">Latest</div>
+                    <div class="option" onclick="setVersion('stable');">Stable</div>
                 </div>
             </div>
+            <div class="button select">
+                <span class="examplesButton">Examples</span>
+            </div>
         </div>
+    </div>
 
-        <div class="navbar navBar1475">
-            <div class="title">
-                Babylon.js Playground
-            </div>
-            <div class="version" id="mainTitle">
-            </div>
+    <div class="navbar navBar1475">
+        <div class="title">
+            Babylon.js Playground
+        </div>
+        <div class="version" id="mainTitle">
+        </div>
 
-            <div class="category">
-                <div class="button run" id="runButton1475">Run
-                    <i class="fa fa-play" aria-hidden="true"></i>
-                </div>
+        <div class="category">
+            <div class="button run" id="runButton1475">Run
+                <i class="fa fa-play" aria-hidden="true"></i>
             </div>
+        </div>
 
 
-            <div class="category">
-                <div class="button" id="newButton1475">New
-                    <i class="fa fa-file" aria-hidden="true"></i>
-                </div>
-                <div class="button removeOnPhone" id="clearButton1475">Clear
-                    <i class="fa fa-trash" aria-hidden="true"></i>
-                </div>
+        <div class="category">
+            <div class="button" id="newButton1475">New
+                <i class="fa fa-file" aria-hidden="true"></i>
             </div>
+            <div class="button removeOnPhone" id="clearButton1475">Clear
+                <i class="fa fa-trash" aria-hidden="true"></i>
+            </div>
+        </div>
 
-            <div class="category">
-                <div class="button" id="saveButton1475">Save
-                    <i class="fa fa-floppy-o" aria-hidden="true"></i>
-                </div>
-                <div class="button removeOnPhone" id="zipButton1475">Zip
-                    <i class="fa fa-download" aria-hidden="true"></i>
-                </div>
+        <div class="category">
+            <div class="button" id="saveButton1475">Save
+                <i class="fa fa-floppy-o" aria-hidden="true"></i>
             </div>
+            <div class="button removeOnPhone" id="zipButton1475">Zip
+                <i class="fa fa-download" aria-hidden="true"></i>
+            </div>
+        </div>
 
-            <div class="category">
-                <div class="button select">Settings
-                    <div class="toDisplay">
-                        <div class="option subSelect">Theme
-                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                            <div class="toDisplaySub">
-                                <div class="option" id="darkTheme1475">Dark</div>
-                                <div class="option" id="lightTheme1475">Light</div>
-                            </div>
-                        </div>
-                        <div class="option subSelect">
-                            <span id="currentFontSize1475">Font: 14</span>
-                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                            <div class="toDisplaySub">
-                                <div class="option" onclick="setFontSize(12);">12</div>
-                                <div class="option" onclick="setFontSize(14);">14</div>
-                                <div class="option" onclick="setFontSize(16);">16</div>
-                                <div class="option" onclick="setFontSize(18);">18</div>
-                                <div class="option" onclick="setFontSize(20);">20</div>
-                                <div class="option" onclick="setFontSize(22);">22</div>
-                            </div>
+        <div class="category">
+            <div class="button select">Settings
+                <div class="toDisplay">
+                    <div class="option subSelect">Theme
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" id="darkTheme1475">Dark</div>
+                            <div class="option" id="lightTheme1475">Light</div>
                         </div>
-                        <div class="option" id='safemodeToggle1475'>Safe mode
-                            <i class="far fa-square" aria-hidden="true"></i>
-                        </div>
-                        <div class="option checked" id="editorButton1475">Editor
-                            <i class="fa fa-check-square" aria-hidden="true"></i>
-                        </div>
-                        <div class="option" id="fullscreenButton1475">Fullscreen</div>
-                        <div class="option" id="editorFullscreenButton1475">Editor Fullscreen</div>
-                        <div class="option" id="formatButton1475">Format code</div>
-                        <div class="option" id="minimapToggle1475">Minimap
-                            <i class="far fa-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option subSelect">
+                        <span id="currentFontSize1475">Font: 14</span>
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setFontSize(12);">12</div>
+                            <div class="option" onclick="setFontSize(14);">14</div>
+                            <div class="option" onclick="setFontSize(16);">16</div>
+                            <div class="option" onclick="setFontSize(18);">18</div>
+                            <div class="option" onclick="setFontSize(20);">20</div>
+                            <div class="option" onclick="setFontSize(22);">22</div>
                         </div>
-                        <div class="option" id="debugButton1475">Inspector</div>
-                        <div class="option" id="metadataButton1475">Metadata</div>
-                        <div class="option subSelect">
-                            <span id="currentVersion1475">Vers. : Latest</span>
-                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                            <div class="toDisplaySub">
-                                <div class="option" onclick="setVersion('latest');">Latest</div>
-                                <div class="option" onclick="setVersion('stable');">Stable</div>
-                            </div>
+                    </div>
+                    <div class="option" id='safemodeToggle1475'>Safe mode
+                        <i class="far fa-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option checked" id="editorButton1475">Editor
+                        <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton1475">Fullscreen</div>
+                    <div class="option" id="editorFullscreenButton1475">Editor Fullscreen</div>
+                    <div class="option" id="formatButton1475">Format code</div>
+                    <div class="option" id="minimapToggle1475">Minimap
+                        <i class="far fa-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="debugButton1475">Inspector</div>
+                    <div class="option" id="metadataButton1475">Metadata</div>
+                    <div class="option subSelect">
+                        <span id="currentVersion1475">Vers. : Latest</span>
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setVersion('latest');">Latest</div>
+                            <div class="option" onclick="setVersion('stable');">Stable</div>
                         </div>
                     </div>
                 </div>
             </div>
+        </div>
 
-            <div class="category right">
-                <div class="button select">
-                    <span class="examplesButton">Examples</span>
-                </div>
+        <div class="category right">
+            <div class="button select">
+                <span class="examplesButton">Examples</span>
             </div>
         </div>
+    </div>
 
-        <div class="navbar navBar1030">
-            <div class="category">
-                <div class="button run" id="runButton1030">Run
-                    <i class="fa fa-play" aria-hidden="true"></i>
-                </div>
+    <div class="navbar navBar1030">
+        <div class="category">
+            <div class="button run" id="runButton1030">Run
+                <i class="fa fa-play" aria-hidden="true"></i>
             </div>
+        </div>
 
 
-            <div class="category">
-                <div class="button" id="newButton1030">New
-                    <i class="fa fa-file" aria-hidden="true"></i>
-                </div>
-                <div class="button removeOnPhone" id="clearButton1030">Clear
-                    <i class="fa fa-trash" aria-hidden="true"></i>
-                </div>
+        <div class="category">
+            <div class="button" id="newButton1030">New
+                <i class="fa fa-file" aria-hidden="true"></i>
             </div>
+            <div class="button removeOnPhone" id="clearButton1030">Clear
+                <i class="fa fa-trash" aria-hidden="true"></i>
+            </div>
+        </div>
 
-            <div class="category">
-                <div class="button" id="saveButton1030">Save
-                    <i class="fa fa-floppy-o" aria-hidden="true"></i>
-                </div>
-                <div class="button removeOnPhone" id="zipButton1030">Zip
-                    <i class="fa fa-download" aria-hidden="true"></i>
-                </div>
+        <div class="category">
+            <div class="button" id="saveButton1030">Save
+                <i class="fa fa-floppy-o" aria-hidden="true"></i>
             </div>
+            <div class="button removeOnPhone" id="zipButton1030">Zip
+                <i class="fa fa-download" aria-hidden="true"></i>
+            </div>
+        </div>
 
-            <div class="category">
-                <div class="button select">Settings
-                    <div class="toDisplay">
-                        <div class="option subSelect">Theme
-                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                            <div class="toDisplaySub">
-                                <div class="option" id="darkTheme1030">Dark</div>
-                                <div class="option" id="lightTheme1030">Light</div>
-                            </div>
-                        </div>
-                        <div class="option subSelect">
-                            <span id="currentFontSize1030">Font: 14</span>
-                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                            <div class="toDisplaySub">
-                                <div class="option" onclick="setFontSize(12);">12</div>
-                                <div class="option" onclick="setFontSize(14);">14</div>
-                                <div class="option" onclick="setFontSize(16);">16</div>
-                                <div class="option" onclick="setFontSize(18);">18</div>
-                                <div class="option" onclick="setFontSize(20);">20</div>
-                                <div class="option" onclick="setFontSize(22);">22</div>
-                            </div>
+        <div class="category">
+            <div class="button select">Settings
+                <div class="toDisplay">
+                    <div class="option subSelect">Theme
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" id="darkTheme1030">Dark</div>
+                            <div class="option" id="lightTheme1030">Light</div>
                         </div>
-                        <div class="option" id="safemodeToggle1030">Safe mode
-                            <i class="far fa-square" aria-hidden="true"></i>
-                        </div>
-                        <div class="option checked" id="editorButton1030">Editor
-                            <i class="fa fa-check-square" aria-hidden="true"></i>
-                        </div>
-                        <div class="option" id="fullscreenButton1030">Fullscreen</div>
-                        <div class="option" id="editorFullscreenButton1030">Editor Fullscreen</div>
-                        <div class="option" id="formatButton1030">Format code</div>
-                        <div class="option" id="minimapToggle1030">Minimap
-                            <i class="far fa-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option subSelect">
+                        <span id="currentFontSize1030">Font: 14</span>
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setFontSize(12);">12</div>
+                            <div class="option" onclick="setFontSize(14);">14</div>
+                            <div class="option" onclick="setFontSize(16);">16</div>
+                            <div class="option" onclick="setFontSize(18);">18</div>
+                            <div class="option" onclick="setFontSize(20);">20</div>
+                            <div class="option" onclick="setFontSize(22);">22</div>
                         </div>
-                        <div class="option" id="debugButton1030">Inspector</div>
-                        <div class="option" id="metadataButton1030">Metadata</div>
-                        <div class="option subSelect">
-                            <span id="currentVersion1030">Vers. : Latest</span>
-                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                            <div class="toDisplaySub">
-                                <div class="option" onclick="setVersion('latest');">Latest</div>
-                                <div class="option" onclick="setVersion('stable');">Stable</div>
-                            </div>
+                    </div>
+                    <div class="option" id="safemodeToggle1030">Safe mode
+                        <i class="far fa-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option checked" id="editorButton1030">Editor
+                        <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton1030">Fullscreen</div>
+                    <div class="option" id="editorFullscreenButton1030">Editor Fullscreen</div>
+                    <div class="option" id="formatButton1030">Format code</div>
+                    <div class="option" id="minimapToggle1030">Minimap
+                        <i class="far fa-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="debugButton1030">Inspector</div>
+                    <div class="option" id="metadataButton1030">Metadata</div>
+                    <div class="option subSelect">
+                        <span id="currentVersion1030">Vers. : Latest</span>
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setVersion('latest');">Latest</div>
+                            <div class="option" onclick="setVersion('stable');">Stable</div>
                         </div>
                     </div>
                 </div>
             </div>
+        </div>
 
-            <div class="category right">
-                <div class="button select">
-                    <span class="examplesButton">Examples</span>
-                </div>
+        <div class="category right">
+            <div class="button select">
+                <span class="examplesButton">Examples</span>
             </div>
         </div>
-
-        <div class="navbar navBar750">
-            <div class="category">
-                <div class="button select">File
-                    <div class="toDisplay">
-                        <div class="option" id="runButton750">Run
-                            <i class="fa fa-play" aria-hidden="true"></i>
-                        </div>
-                        <div class="option" id="newButton750">New
-                            <i class="fa fa-file" aria-hidden="true"></i>
-                        </div>
-                        <div class="option" id="clearButton750">Clear
-                            <i class="fa fa-trash" aria-hidden="true"></i>
-                        </div>
-                        <div class="option" id="saveButton750">Save
-                            <i class="fa fa-floppy-o" aria-hidden="true"></i>
-                        </div>
-                        <div class="option" id="zipButton750">Zip
-                            <i class="fa fa-download" aria-hidden="true"></i>
-                        </div>
+    </div>
+
+    <div class="navbar navBar750">
+        <div class="category">
+            <div class="button select">File
+                <div class="toDisplay">
+                    <div class="option" id="runButton750">Run
+                        <i class="fa fa-play" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="newButton750">New
+                        <i class="fa fa-file" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="clearButton750">Clear
+                        <i class="fa fa-trash" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="saveButton750">Save
+                        <i class="fa fa-floppy-o" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="zipButton750">Zip
+                        <i class="fa fa-download" aria-hidden="true"></i>
                     </div>
                 </div>
             </div>
+        </div>
 
-            <div class="category">
-                <div class="button select">Settings
-                    <div class="toDisplay">
-                        <div class="option subSelect">Theme
-                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                            <div class="toDisplaySub">
-                                <div class="option" id="darkTheme750">Dark</div>
-                                <div class="option" id="lightTheme750">Light</div>
-                            </div>
+        <div class="category">
+            <div class="button select">Settings
+                <div class="toDisplay">
+                    <div class="option subSelect">Theme
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" id="darkTheme750">Dark</div>
+                            <div class="option" id="lightTheme750">Light</div>
                         </div>
-                        <div class="option subSelect">
-                            <span id="currentFontSize750">Font: 14</span>
-                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                            <div class="toDisplaySub">
-                                <div class="option" onclick="setFontSize(12);">12</div>
-                                <div class="option" onclick="setFontSize(14);">14</div>
-                                <div class="option" onclick="setFontSize(16);">16</div>
-                                <div class="option" onclick="setFontSize(18);">18</div>
-                                <div class="option" onclick="setFontSize(20);">20</div>
-                                <div class="option" onclick="setFontSize(22);">22</div>
-                            </div>
-                        </div>
-                        <div class="option" id="safemodeToggle750">Safe mode
-                            <i class="far fa-square" aria-hidden="true"></i>
-                        </div>
-                        <div style="display:none;" class="option checked" id="editorButton750">Editor
-                            <i class="fa fa-check-square" aria-hidden="true"></i>
-                        </div>
-                        <div class="option" id="fullscreenButton750">Fullscreen</div>
-                        <div class="option" id="editorFullscreenButton750">Editor Fullscreen</div>
-                        <div class="option" id="formatButton750">Format code</div>
-                        <div class="option" id="minimapToggle750">Minimap
-                            <i class="far fa-square" aria-hidden="true"></i>
-                        </div>
-                        <div class="option" id="debugButton750">Inspector</div>
-                        <div class="option" id="metadataButton750">Metadata</div>
-                        <div class="option subSelect">
-                            <span id="currentVersion750">Vers. : Latest</span>
-                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                            <div class="toDisplaySub">
-                                <div class="option" onclick="setVersion('latest');">Latest</div>
-                                <div class="option" onclick="setVersion('stable');">Stable</div>
-                            </div>
+                    </div>
+                    <div class="option subSelect">
+                        <span id="currentFontSize750">Font: 14</span>
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setFontSize(12);">12</div>
+                            <div class="option" onclick="setFontSize(14);">14</div>
+                            <div class="option" onclick="setFontSize(16);">16</div>
+                            <div class="option" onclick="setFontSize(18);">18</div>
+                            <div class="option" onclick="setFontSize(20);">20</div>
+                            <div class="option" onclick="setFontSize(22);">22</div>
                         </div>
-                        <div class="option subSelect" id="qrCodeHover" onmouseover="showQRCode();">QR Code Link
-                            <i class="fa fa-chevron-right" aria-hidden="true"></i>
-                            <div class="toDisplaySub">
-                                <div class="option" style="height:auto;padding: 20px;background: white;" id="qrCodeImage">QR Code Image</div>
-                            </div>
+                    </div>
+                    <div class="option" id="safemodeToggle750">Safe mode
+                        <i class="far fa-square" aria-hidden="true"></i>
+                    </div>
+                    <div style="display:none;" class="option checked" id="editorButton750">Editor
+                        <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton750">Fullscreen</div>
+                    <div class="option" id="editorFullscreenButton750">Editor Fullscreen</div>
+                    <div class="option" id="formatButton750">Format code</div>
+                    <div class="option" id="minimapToggle750">Minimap
+                        <i class="far fa-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="debugButton750">Inspector</div>
+                    <div class="option" id="metadataButton750">Metadata</div>
+                    <div class="option subSelect">
+                        <span id="currentVersion750">Vers. : Latest</span>
+                        <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setVersion('latest');">Latest</div>
+                            <div class="option" onclick="setVersion('stable');">Stable</div>
                         </div>
                     </div>
                 </div>
             </div>
         </div>
 
-        <div class="wrapper">
-            <div id="jsEditor"></div>
-            <div id="canvasZone">
-                <canvas touch-action="none" id="renderCanvas"></canvas>
-            </div>
-        </div>
-        <div id="exampleList" class = "typescript">
-            <div id="exampleBanner">
-                <h1>Examples</h1>
+        <div class="category right">
+            <div class="button select">
+                <span id="currentScript750">Examples</span>
             </div>
-            <div class="horizontalSeparator"></div>
-            <input id="filterBar" type="text" placeholder="Filter examples...">
-            <img id="filterBarClear" src="https://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/clear_button.png">
         </div>
+    </div>
 
-        <span class="label" id="fpsLabel">FPS</span>
-
-        <div id="errorZone">
+    <div class="wrapper">
+        <div id="jsEditor"></div>
+        <div id="canvasZone">
+            <canvas touch-action="none" id="renderCanvas"></canvas>
         </div>
-
-        <div class="navbarBottom">
-            <div id="statusBar"></div>
-            <div class="links">
-                <div class='link'>
-                    <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
-                </div>
-                <div class='link'>
-                    <a target='_new' href="https://forum.babylonjs.com/">Forum</a>
-                </div>
-                <div class='link'>
-                    <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
-                </div>
-                <div class='link'>
-                    <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
-                </div>
-                <div class='link'>
-                    <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
-                </div>
+    </div>
+    <div id="exampleList" class="typescript">
+        <div id="exampleBanner">
+            <h1>Examples</h1>
+        </div>
+        <div class="horizontalSeparator"></div>
+        <input id="filterBar" type="text" placeholder="Filter examples...">
+        <img id="filterBarClear"
+            src="https://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/clear_button.png">
+    </div>
+
+    <span class="label" id="fpsLabel">FPS</span>
+
+    <div id="errorZone">
+    </div>
+
+    <div class="navbarBottom">
+        <div id="statusBar"></div>
+        <div class="links">
+            <div class='link'>
+                <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
+            </div>
+            <div class='link'>
+                <a target='_new' href="https://forum.babylonjs.com/">Forum</a>
+            </div>
+            <div class='link'>
+                <a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a>
+            </div>
+            <div class='link'>
+                <a target='_new' href="https://doc.babylonjs.com">Documentation</a>
+            </div>
+            <div class='link'>
+                <a target='_new' href="https://doc.babylonjs.com/playground">Search</a>
             </div>
         </div>
+    </div>
 
-        <div id="saveLayer" class="save-layer">
-            <div class="save-form">
-                <label for="saveFormTitle">TITLE</label>
-                <div class="separator"></div>
-                <input type="text" maxlength="120" id="saveFormTitle" class="save-form-title">
+    <div id="saveLayer" class="save-layer">
+        <div class="save-form">
+            <label for="saveFormTitle">TITLE</label>
+            <div class="separator"></div>
+            <input type="text" maxlength="120" id="saveFormTitle" class="save-form-title">
 
-                <label for="saveFormDescription">DESCRIPTION</label>
-                <div class="separator"></div>
-                <textarea id="saveFormDescription" rows="4" cols="10"></textarea>
+            <label for="saveFormDescription">DESCRIPTION</label>
+            <div class="separator"></div>
+            <textarea id="saveFormDescription" rows="4" cols="10"></textarea>
 
-                <label for="saveFormTags">TAGS (separated by comma)</label>
-                <div class="separator"></div>
-                <textarea id="saveFormTags" rows="4" cols="10"></textarea>
+            <label for="saveFormTags">TAGS (separated by comma)</label>
+            <div class="separator"></div>
+            <textarea id="saveFormTags" rows="4" cols="10"></textarea>
 
-                <div class="save-form-buttons" id="saveFormButtons">
+            <div class="save-form-buttons" id="saveFormButtons">
 
-                    <div id="saveFormButtonOk" class="button">OK</div>
-                    <div id="saveFormButtonCancel" class="button">Cancel</div>
-                </div>
+                <div id="saveFormButtonOk" class="button">OK</div>
+                <div id="saveFormButtonCancel" class="button">Cancel</div>
             </div>
         </div>
-
-        <div id="waitDiv">
-            <span id="waitTitle">Babylon.js Playground
-                <BR>
-                <BR>
-                <BR>
-            </span>
-            <img src="waitlogo.png" id="waitLogo" />
+    </div>
+
+    <div id="waitDiv">
+        <span id="waitTitle">Babylon.js Playground
+            <BR>
+            <BR>
+            <BR>
+        </span>
+        <div id="logo-part">
+            <img src="v4.svg" id="waitLogo" />
+            <img src="spinner.svg" id="waitSpinner" />
         </div>
+    </div>
+
+    <script src="js/libs/jquery.min.js"></script>
+    <script src="js/jquery.qrcode.js"></script>
+    <script src="js/qrcode.js"></script>
+
+    <script src="js/actions.js"></script>
+    <script src="js/pbt.js"></script>
+    <script src="js/libs/typescript.js"></script>
+    <script src="js/index.js"></script>
+    <script src="js/ts.js"></script>
 
-        <script src="js/libs/jquery.min.js"></script>
-        <script src="js/jquery.qrcode.js"></script>
-        <script src="js/qrcode.js"></script>
-
-        <script src="js/actions.js"></script>
-        <script src="js/pbt.js"></script>
-        <script src="js/libs/typescript.js"></script>
-        <script src="js/index.js"></script>
-        <script src="js/ts.js"></script>
-        
-        <!-- Global site tag (gtag.js) - Google Analytics -->
-        <script async src="https://www.googletagmanager.com/gtag/js?id=UA-41767310-2"></script>
-        <script>
+    <!-- Global site tag (gtag.js) - Google Analytics -->
+    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-41767310-2"></script>
+    <script>
         window.dataLayer = window.dataLayer || [];
-        function gtag(){dataLayer.push(arguments);}
+        function gtag() { dataLayer.push(arguments); }
         gtag('js', new Date());
 
         gtag('config', 'UA-41767310-2');
-        </script>        
-    </body>
+    </script>
+</body>
 
-</html>
+</html>

+ 55 - 2
Tools/Config/config.json

@@ -46,7 +46,8 @@
         "loaders",
         "serializers",
         "gui",
-        "inspector"
+        "inspector",
+        "nodeEditor"
     ],
     "es6modules": [
         "core",
@@ -57,7 +58,8 @@
         "serializers",
         "gui",
         "inspector",
-        "viewer"
+        "viewer",
+        "nodeEditor"
     ],
     "lintModules": [
         "core",
@@ -581,6 +583,57 @@
             }
         }
     },
+    "nodeEditor": {
+        "libraries": [
+            {
+                "output": "babylon.nodeEditor.js",
+                "entry": "./legacy/legacy.ts"
+            }
+        ],
+        "build": {
+            "ignoreInTestMode": true,
+            "mainFolder": "./nodeEditor/",
+            "uncheckedLintImports": [
+                "react",
+                "react-dom",
+                "re-resizable",
+                "glTF"
+            ],
+            "umd": {
+                "packageName": "babylonjs-node-editor",
+                "webpackRoot": "NODEEDITOR",
+                "processDeclaration": {
+                    "filename": "babylon.nodeEditor.module.d.ts",
+                    "moduleName": "NODEEDITOR",
+                    "importsToRemove": [],
+                    "classMap": {
+                        "babylonjs": "BABYLON",
+                        "react": "React",
+                        "@babylonjs/core": "BABYLON",
+                        "@fortawesome": false,
+                        "react-contextmenu": false
+                    }
+                }
+            },
+            "es6": {
+                "webpackBuild": true,
+                "buildDependencies": [
+                    "node_modules/re-resizable/lib/index.es5.js",
+                    "Tools/**/*"
+                ],
+                "packageName": "@babylonjs/node-editor",
+                "readme": "dist/preview release/nodeEditor/readme-es6.md",
+                "packagesFiles": [
+                    "babylon.nodeEditor.max.js",
+                    "babylon.nodeEditor.max.js.map",
+                    "babylon.nodeEditor.module.d.ts",
+                    "readme.md"
+                ],
+                "typings": "babylon.nodeEditor.module.d.ts",
+                "index": "babylon.nodeEditor.max.js"
+            }
+        }
+    },
     "viewer": {
         "libraries": [
             {

+ 4 - 4
azure-pipelines.yml

@@ -19,7 +19,7 @@ jobs:
     inputs:
       workingDir: Tools/Gulp
       verbose: false
-  - script: 'gulp tests-whatsnew'
+  - script: 'gulp tests-whatsnew --max-old-space-size=8192'
     workingDirectory: Tools/Gulp
     displayName: 'Whats new'
     env:
@@ -37,7 +37,7 @@ jobs:
     inputs:
       workingDir: Tools/Gulp
       verbose: false
-  - script: 'gulp typedoc-check'
+  - script: 'gulp typedoc-check --max-old-space-size=8192'
     workingDirectory: Tools/Gulp
     displayName: 'Typedoc check'
 
@@ -52,7 +52,7 @@ jobs:
     inputs:
       workingDir: Tools/Gulp
       verbose: false
-  - script: 'gulp fullLint'
+  - script: 'gulp fullLint --max-old-space-size=8192'
     workingDirectory: Tools/Gulp
     displayName: 'Full Lint'
 
@@ -207,4 +207,4 @@ jobs:
     condition: succeededOrFailed()
     inputs:
       testRunner: JUnit
-      testResultsFiles: '.temp/testResults/ViewerValidationTests.xml'
+      testResultsFiles: '.temp/testResults/ViewerValidationTests.xml'

+ 37 - 38
bower.json

@@ -1,39 +1,38 @@
 {
-  "name": "babylonjs",
-  "description": "Babylon.js is a complete JavaScript framework for building 3D games with HTML 5 and WebGL",
-  "main": "./dist/babylon.2.5.js",
-  "homepage": "https://www.babylonjs.com",
-  "repository": {
-    "type": "git",
-    "url": "git://github.com/BabylonJS/Babylon.js.git"
-  },
-  "authors": [
-    "David Catuhe",
-    "David Rousset"
-  ],
-  "keywords": [
-    "3D",
-    "WebGL",
-    "WebAudio",
-    "Shaders",
-    "Realtime"
-  ],
-  "license": "Apache-2.0",
-  "ignore": [
-    "**/.*",
-    "node_modules",
-    "Babylon",
-    "Exporters",
-    "Loaders",
-    "Previous releases",
-    "/Tools",
-    "gulpfile.js",
-    "package.json",
-    "babylon.2.1*.*",
-    "*.md",
-    "*.yml",
-    "cannon.js",
-    "Oimo.js",
-    "poly2tri.js"
-  ]
-}
+    "name": "babylonjs",
+    "description": "Babylon.js is a complete JavaScript framework for building 3D games with HTML 5 and WebGL",
+    "main": "./dist/babylon.js",
+    "homepage": "https://www.babylonjs.com",
+    "repository": {
+        "type": "git",
+        "url": "git://github.com/BabylonJS/Babylon.js.git"
+    },
+    "authors": [
+        "David Catuhe"
+    ],
+    "keywords": [
+        "3D",
+        "WebGL",
+        "WebAudio",
+        "Shaders",
+        "Realtime"
+    ],
+    "license": "Apache-2.0",
+    "ignore": [
+        "**/.*",
+        "node_modules",
+        "Babylon",
+        "Exporters",
+        "Loaders",
+        "Previous releases",
+        "/Tools",
+        "gulpfile.js",
+        "package.json",
+        "babylon.2.1*.*",
+        "*.md",
+        "*.yml",
+        "cannon.js",
+        "Oimo.js",
+        "poly2tri.js"
+    ]
+}

Fichier diff supprimé car celui-ci est trop grand
+ 1874 - 314
dist/preview release/babylon.d.ts


Fichier diff supprimé car celui-ci est trop grand
+ 2 - 2
dist/preview release/babylon.js


Fichier diff supprimé car celui-ci est trop grand
+ 5557 - 514
dist/preview release/babylon.max.js


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/babylon.max.js.map


Fichier diff supprimé car celui-ci est trop grand
+ 13826 - 10529
dist/preview release/babylon.module.d.ts


Fichier diff supprimé car celui-ci est trop grand
+ 1875 - 315
dist/preview release/documentation.d.ts


+ 2 - 2
dist/preview release/gui/babylon.gui.js

@@ -8216,8 +8216,8 @@ var Line = /** @class */ (function (_super) {
         context.lineWidth = this._lineWidth;
         context.setLineDash(this._dash);
         context.beginPath();
-        context.moveTo(this._cachedParentMeasure.left + this._x1.getValue(this._host), this._cachedParentMeasure.left + this._y1.getValue(this._host));
-        context.lineTo(this._cachedParentMeasure.left + this._effectiveX2, this._cachedParentMeasure.left + this._effectiveY2);
+        context.moveTo(this._cachedParentMeasure.left + this._x1.getValue(this._host), this._cachedParentMeasure.top + this._y1.getValue(this._host));
+        context.lineTo(this._cachedParentMeasure.left + this._effectiveX2, this._cachedParentMeasure.top + this._effectiveY2);
         context.stroke();
         context.restore();
     };

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/gui/babylon.gui.js.map


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js


Fichier diff supprimé car celui-ci est trop grand
+ 6 - 6
dist/preview release/inspector/babylon.inspector.bundle.js


Fichier diff supprimé car celui-ci est trop grand
+ 171 - 106
dist/preview release/inspector/babylon.inspector.bundle.max.js


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.max.js.map


+ 26 - 7
dist/preview release/inspector/babylon.inspector.d.ts

@@ -90,7 +90,7 @@ declare module INSPECTOR {
 }
 declare module INSPECTOR {
     interface ILineContainerComponentProps {
-        globalState: GlobalState;
+        globalState?: GlobalState;
         title: string;
         children: any[] | any;
         closed?: boolean;
@@ -406,6 +406,8 @@ declare module INSPECTOR {
         accept: string;
     }
     export class FileButtonLineComponent extends React.Component<IFileButtonLineComponentProps> {
+        private static _IDGenerator;
+        private _id;
         constructor(props: IFileButtonLineComponentProps);
         onChange(evt: any): void;
         render(): JSX.Element;
@@ -453,7 +455,8 @@ declare module INSPECTOR {
         texture: BABYLON.BaseTexture;
         width: number;
         height: number;
-        globalState: GlobalState;
+        globalState?: GlobalState;
+        hideChannelSelect?: boolean;
     }
     export class TextureLineComponent extends React.Component<ITextureLineComponentProps, {
         displayRed: boolean;
@@ -486,6 +489,8 @@ declare module INSPECTOR {
         isInteger?: boolean;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
         additionalClass?: string;
+        step?: string;
+        digits?: number;
     }
     export class FloatLineComponent extends React.Component<IFloatLineComponentProps, {
         value: string;
@@ -1215,6 +1220,20 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
+    interface INodeMaterialPropertyGridComponentProps {
+        globalState: GlobalState;
+        material: BABYLON.NodeMaterial;
+        lockObject: LockObject;
+        onSelectionChangedObservable?: BABYLON.Observable<any>;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class NodeMaterialPropertyGridComponent extends React.Component<INodeMaterialPropertyGridComponentProps> {
+        constructor(props: INodeMaterialPropertyGridComponentProps);
+        edit(): void;
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
     export class PropertyGridTabComponent extends PaneComponent {
         private _timerIntervalId;
         private _lockObject;
@@ -1291,7 +1310,7 @@ declare module INSPECTOR {
 }
 declare module INSPECTOR {
     interface IActionTabsComponentProps {
-        scene: BABYLON.Scene;
+        scene?: BABYLON.Scene;
         noCommands?: boolean;
         noHeader?: boolean;
         noExpand?: boolean;
@@ -1299,7 +1318,7 @@ declare module INSPECTOR {
         popupMode?: boolean;
         onPopup?: () => void;
         onClose?: () => void;
-        globalState: GlobalState;
+        globalState?: GlobalState;
     }
     export class ActionTabsComponent extends React.Component<IActionTabsComponentProps, {
         selectedEntity: any;
@@ -1312,7 +1331,7 @@ declare module INSPECTOR {
         componentWillMount(): void;
         componentWillUnmount(): void;
         changeSelectedTab(index: number): void;
-        renderContent(): JSX.Element;
+        renderContent(): JSX.Element | null;
         onClose(): void;
         onPopup(): void;
         render(): JSX.Element;
@@ -1715,11 +1734,11 @@ declare module INSPECTOR {
         private static _CreateSceneExplorer;
         private static _CreateActionTabs;
         private static _CreateEmbedHost;
-        private static _CreatePopup;
+        static _CreatePopup(title: string, windowVariableName: string, width?: number, height?: number): BABYLON.Nullable<HTMLDivElement>;
         static readonly IsVisible: boolean;
         static EarlyAttachToLoader(): void;
         static Show(scene: BABYLON.Scene, userOptions: Partial<BABYLON.IInspectorOptions>): void;
-        private static _CreateCanvasContainer;
+        static _CreateCanvasContainer(parentControl: HTMLElement): void;
         private static _DestroyCanvasContainer;
         private static _Cleanup;
         private static _RemoveElementFromDOM;

+ 59 - 14
dist/preview release/inspector/babylon.inspector.module.d.ts

@@ -111,7 +111,7 @@ declare module "babylonjs-inspector/components/actionTabs/lineContainerComponent
     import * as React from "react";
     import { GlobalState } from "babylonjs-inspector/components/globalState";
     interface ILineContainerComponentProps {
-        globalState: GlobalState;
+        globalState?: GlobalState;
         title: string;
         children: any[] | any;
         closed?: boolean;
@@ -474,6 +474,8 @@ declare module "babylonjs-inspector/components/actionTabs/lines/fileButtonLineCo
         accept: string;
     }
     export class FileButtonLineComponent extends React.Component<IFileButtonLineComponentProps> {
+        private static _IDGenerator;
+        private _id;
         constructor(props: IFileButtonLineComponentProps);
         onChange(evt: any): void;
         render(): JSX.Element;
@@ -535,7 +537,8 @@ declare module "babylonjs-inspector/components/actionTabs/lines/textureLineCompo
         texture: BaseTexture;
         width: number;
         height: number;
-        globalState: GlobalState;
+        globalState?: GlobalState;
+        hideChannelSelect?: boolean;
     }
     export class TextureLineComponent extends React.Component<ITextureLineComponentProps, {
         displayRed: boolean;
@@ -572,6 +575,8 @@ declare module "babylonjs-inspector/components/actionTabs/lines/floatLineCompone
         isInteger?: boolean;
         onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
         additionalClass?: string;
+        step?: string;
+        digits?: number;
     }
     export class FloatLineComponent extends React.Component<IFloatLineComponentProps, {
         value: string;
@@ -1591,6 +1596,26 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/pos
         render(): JSX.Element;
     }
 }
+declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/materials/nodeMaterialPropertyGridComponent" {
+    import * as React from "react";
+    import { Observable } from "babylonjs/Misc/observable";
+    import { NodeMaterial } from "babylonjs/Materials/Node/nodeMaterial";
+    import { PropertyChangedEvent } from "babylonjs-inspector/components/propertyChangedEvent";
+    import { LockObject } from "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/lockObject";
+    import { GlobalState } from "babylonjs-inspector/components/globalState";
+    interface INodeMaterialPropertyGridComponentProps {
+        globalState: GlobalState;
+        material: NodeMaterial;
+        lockObject: LockObject;
+        onSelectionChangedObservable?: Observable<any>;
+        onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
+    }
+    export class NodeMaterialPropertyGridComponent extends React.Component<INodeMaterialPropertyGridComponentProps> {
+        constructor(props: INodeMaterialPropertyGridComponentProps);
+        edit(): void;
+        render(): JSX.Element;
+    }
+}
 declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGridTabComponent" {
     import { PaneComponent, IPaneComponentProps } from "babylonjs-inspector/components/actionTabs/paneComponent";
     export class PropertyGridTabComponent extends PaneComponent {
@@ -1680,7 +1705,7 @@ declare module "babylonjs-inspector/components/actionTabs/actionTabsComponent" {
     import { Scene } from "babylonjs/scene";
     import { GlobalState } from "babylonjs-inspector/components/globalState";
     interface IActionTabsComponentProps {
-        scene: Scene;
+        scene?: Scene;
         noCommands?: boolean;
         noHeader?: boolean;
         noExpand?: boolean;
@@ -1688,7 +1713,7 @@ declare module "babylonjs-inspector/components/actionTabs/actionTabsComponent" {
         popupMode?: boolean;
         onPopup?: () => void;
         onClose?: () => void;
-        globalState: GlobalState;
+        globalState?: GlobalState;
     }
     export class ActionTabsComponent extends React.Component<IActionTabsComponentProps, {
         selectedEntity: any;
@@ -1701,7 +1726,7 @@ declare module "babylonjs-inspector/components/actionTabs/actionTabsComponent" {
         componentWillMount(): void;
         componentWillUnmount(): void;
         changeSelectedTab(index: number): void;
-        renderContent(): JSX.Element;
+        renderContent(): JSX.Element | null;
         onClose(): void;
         onPopup(): void;
         render(): JSX.Element;
@@ -2154,6 +2179,7 @@ declare module "babylonjs-inspector/components/embedHost/embedHostComponent" {
 }
 declare module "babylonjs-inspector/inspector" {
     import { IInspectorOptions } from "babylonjs/Debug/debugLayer";
+    import { Nullable } from "babylonjs/types";
     import { Observable } from "babylonjs/Misc/observable";
     import { Scene } from "babylonjs/scene";
     import { PropertyChangedEvent } from "babylonjs-inspector/components/propertyChangedEvent";
@@ -2176,11 +2202,11 @@ declare module "babylonjs-inspector/inspector" {
         private static _CreateSceneExplorer;
         private static _CreateActionTabs;
         private static _CreateEmbedHost;
-        private static _CreatePopup;
+        static _CreatePopup(title: string, windowVariableName: string, width?: number, height?: number): Nullable<HTMLDivElement>;
         static readonly IsVisible: boolean;
         static EarlyAttachToLoader(): void;
         static Show(scene: Scene, userOptions: Partial<IInspectorOptions>): void;
-        private static _CreateCanvasContainer;
+        static _CreateCanvasContainer(parentControl: HTMLElement): void;
         private static _DestroyCanvasContainer;
         private static _Cleanup;
         private static _RemoveElementFromDOM;
@@ -2288,7 +2314,7 @@ declare module INSPECTOR {
 }
 declare module INSPECTOR {
     interface ILineContainerComponentProps {
-        globalState: GlobalState;
+        globalState?: GlobalState;
         title: string;
         children: any[] | any;
         closed?: boolean;
@@ -2604,6 +2630,8 @@ declare module INSPECTOR {
         accept: string;
     }
     export class FileButtonLineComponent extends React.Component<IFileButtonLineComponentProps> {
+        private static _IDGenerator;
+        private _id;
         constructor(props: IFileButtonLineComponentProps);
         onChange(evt: any): void;
         render(): JSX.Element;
@@ -2651,7 +2679,8 @@ declare module INSPECTOR {
         texture: BABYLON.BaseTexture;
         width: number;
         height: number;
-        globalState: GlobalState;
+        globalState?: GlobalState;
+        hideChannelSelect?: boolean;
     }
     export class TextureLineComponent extends React.Component<ITextureLineComponentProps, {
         displayRed: boolean;
@@ -2684,6 +2713,8 @@ declare module INSPECTOR {
         isInteger?: boolean;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
         additionalClass?: string;
+        step?: string;
+        digits?: number;
     }
     export class FloatLineComponent extends React.Component<IFloatLineComponentProps, {
         value: string;
@@ -3413,6 +3444,20 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
+    interface INodeMaterialPropertyGridComponentProps {
+        globalState: GlobalState;
+        material: BABYLON.NodeMaterial;
+        lockObject: LockObject;
+        onSelectionChangedObservable?: BABYLON.Observable<any>;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class NodeMaterialPropertyGridComponent extends React.Component<INodeMaterialPropertyGridComponentProps> {
+        constructor(props: INodeMaterialPropertyGridComponentProps);
+        edit(): void;
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
     export class PropertyGridTabComponent extends PaneComponent {
         private _timerIntervalId;
         private _lockObject;
@@ -3489,7 +3534,7 @@ declare module INSPECTOR {
 }
 declare module INSPECTOR {
     interface IActionTabsComponentProps {
-        scene: BABYLON.Scene;
+        scene?: BABYLON.Scene;
         noCommands?: boolean;
         noHeader?: boolean;
         noExpand?: boolean;
@@ -3497,7 +3542,7 @@ declare module INSPECTOR {
         popupMode?: boolean;
         onPopup?: () => void;
         onClose?: () => void;
-        globalState: GlobalState;
+        globalState?: GlobalState;
     }
     export class ActionTabsComponent extends React.Component<IActionTabsComponentProps, {
         selectedEntity: any;
@@ -3510,7 +3555,7 @@ declare module INSPECTOR {
         componentWillMount(): void;
         componentWillUnmount(): void;
         changeSelectedTab(index: number): void;
-        renderContent(): JSX.Element;
+        renderContent(): JSX.Element | null;
         onClose(): void;
         onPopup(): void;
         render(): JSX.Element;
@@ -3913,11 +3958,11 @@ declare module INSPECTOR {
         private static _CreateSceneExplorer;
         private static _CreateActionTabs;
         private static _CreateEmbedHost;
-        private static _CreatePopup;
+        static _CreatePopup(title: string, windowVariableName: string, width?: number, height?: number): BABYLON.Nullable<HTMLDivElement>;
         static readonly IsVisible: boolean;
         static EarlyAttachToLoader(): void;
         static Show(scene: BABYLON.Scene, userOptions: Partial<BABYLON.IInspectorOptions>): void;
-        private static _CreateCanvasContainer;
+        static _CreateCanvasContainer(parentControl: HTMLElement): void;
         private static _DestroyCanvasContainer;
         private static _Cleanup;
         private static _RemoveElementFromDOM;

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

@@ -29,14 +29,16 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "@types/react": "~16.7.3",
-        "@types/react-dom": "~16.0.9",
         "babylonjs": "4.1.0-alpha.1",
         "babylonjs-gui": "4.1.0-alpha.1",
         "babylonjs-loaders": "4.1.0-alpha.1",
         "babylonjs-serializers": "4.1.0-alpha.1",
         "babylonjs-gltf2interface": "4.1.0-alpha.1"
     },
+    "devDependencies": {
+        "@types/react": "~16.7.3",
+        "@types/react-dom": "~16.0.9"
+    },
     "engines": {
         "node": "*"
     }

+ 13 - 9
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -2062,10 +2062,10 @@ var GLTFLoader = /** @class */ (function () {
         else if (primitive.targets.length !== node._numMorphTargets) {
             throw new Error(context + ": Primitives do not have the same number of targets");
         }
-        babylonMesh.morphTargetManager = new babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["MorphTargetManager"]();
+        babylonMesh.morphTargetManager = new babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["MorphTargetManager"](babylonMesh.getScene());
         for (var index = 0; index < primitive.targets.length; index++) {
             var weight = node.weights ? node.weights[index] : mesh.weights ? mesh.weights[index] : 0;
-            babylonMesh.morphTargetManager.addTarget(new babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["MorphTarget"]("morphTarget" + index, weight));
+            babylonMesh.morphTargetManager.addTarget(new babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["MorphTarget"]("morphTarget" + index, weight, babylonMesh.getScene()));
             // TODO: tell the target whether it has positions, normals, tangents
         }
     };
@@ -2098,28 +2098,32 @@ var GLTFLoader = /** @class */ (function () {
             }));
         };
         loadAttribute("POSITION", babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["VertexBuffer"].PositionKind, function (babylonVertexBuffer, data) {
+            var positions = new Float32Array(data.length);
             babylonVertexBuffer.forEach(data.length, function (value, index) {
-                data[index] += value;
+                positions[index] = data[index] + value;
             });
-            babylonMorphTarget.setPositions(data);
+            babylonMorphTarget.setPositions(positions);
         });
         loadAttribute("NORMAL", babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["VertexBuffer"].NormalKind, function (babylonVertexBuffer, data) {
-            babylonVertexBuffer.forEach(data.length, function (value, index) {
-                data[index] += value;
+            var normals = new Float32Array(data.length);
+            babylonVertexBuffer.forEach(normals.length, function (value, index) {
+                normals[index] = data[index] + value;
             });
-            babylonMorphTarget.setNormals(data);
+            babylonMorphTarget.setNormals(normals);
         });
         loadAttribute("TANGENT", babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["VertexBuffer"].TangentKind, function (babylonVertexBuffer, data) {
+            var tangents = new Float32Array(data.length / 3 * 4);
             var dataIndex = 0;
             babylonVertexBuffer.forEach(data.length / 3 * 4, function (value, index) {
                 // Tangent data for morph targets is stored as xyz delta.
                 // The vertexData.tangent is stored as xyzw.
                 // So we need to skip every fourth vertexData.tangent.
                 if (((index + 1) % 4) !== 0) {
-                    data[dataIndex++] += value;
+                    tangents[dataIndex] = data[dataIndex] + value;
+                    dataIndex++;
                 }
             });
-            babylonMorphTarget.setTangents(data);
+            babylonMorphTarget.setTangents(tangents);
         });
         return Promise.all(promises).then(function () { });
     };

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.js.map


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 13 - 9
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -4611,10 +4611,10 @@ var GLTFLoader = /** @class */ (function () {
         else if (primitive.targets.length !== node._numMorphTargets) {
             throw new Error(context + ": Primitives do not have the same number of targets");
         }
-        babylonMesh.morphTargetManager = new babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["MorphTargetManager"]();
+        babylonMesh.morphTargetManager = new babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["MorphTargetManager"](babylonMesh.getScene());
         for (var index = 0; index < primitive.targets.length; index++) {
             var weight = node.weights ? node.weights[index] : mesh.weights ? mesh.weights[index] : 0;
-            babylonMesh.morphTargetManager.addTarget(new babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["MorphTarget"]("morphTarget" + index, weight));
+            babylonMesh.morphTargetManager.addTarget(new babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["MorphTarget"]("morphTarget" + index, weight, babylonMesh.getScene()));
             // TODO: tell the target whether it has positions, normals, tangents
         }
     };
@@ -4647,28 +4647,32 @@ var GLTFLoader = /** @class */ (function () {
             }));
         };
         loadAttribute("POSITION", babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["VertexBuffer"].PositionKind, function (babylonVertexBuffer, data) {
+            var positions = new Float32Array(data.length);
             babylonVertexBuffer.forEach(data.length, function (value, index) {
-                data[index] += value;
+                positions[index] = data[index] + value;
             });
-            babylonMorphTarget.setPositions(data);
+            babylonMorphTarget.setPositions(positions);
         });
         loadAttribute("NORMAL", babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["VertexBuffer"].NormalKind, function (babylonVertexBuffer, data) {
-            babylonVertexBuffer.forEach(data.length, function (value, index) {
-                data[index] += value;
+            var normals = new Float32Array(data.length);
+            babylonVertexBuffer.forEach(normals.length, function (value, index) {
+                normals[index] = data[index] + value;
             });
-            babylonMorphTarget.setNormals(data);
+            babylonMorphTarget.setNormals(normals);
         });
         loadAttribute("TANGENT", babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["VertexBuffer"].TangentKind, function (babylonVertexBuffer, data) {
+            var tangents = new Float32Array(data.length / 3 * 4);
             var dataIndex = 0;
             babylonVertexBuffer.forEach(data.length / 3 * 4, function (value, index) {
                 // Tangent data for morph targets is stored as xyz delta.
                 // The vertexData.tangent is stored as xyzw.
                 // So we need to skip every fourth vertexData.tangent.
                 if (((index + 1) % 4) !== 0) {
-                    data[dataIndex++] += value;
+                    tangents[dataIndex] = data[dataIndex] + value;
+                    dataIndex++;
                 }
             });
-            babylonMorphTarget.setTangents(data);
+            babylonMorphTarget.setTangents(tangents);
         });
         return Promise.all(promises).then(function () { });
     };

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.js.map


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 13 - 9
dist/preview release/loaders/babylonjs.loaders.js

@@ -5953,10 +5953,10 @@ var GLTFLoader = /** @class */ (function () {
         else if (primitive.targets.length !== node._numMorphTargets) {
             throw new Error(context + ": Primitives do not have the same number of targets");
         }
-        babylonMesh.morphTargetManager = new babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["MorphTargetManager"]();
+        babylonMesh.morphTargetManager = new babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["MorphTargetManager"](babylonMesh.getScene());
         for (var index = 0; index < primitive.targets.length; index++) {
             var weight = node.weights ? node.weights[index] : mesh.weights ? mesh.weights[index] : 0;
-            babylonMesh.morphTargetManager.addTarget(new babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["MorphTarget"]("morphTarget" + index, weight));
+            babylonMesh.morphTargetManager.addTarget(new babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["MorphTarget"]("morphTarget" + index, weight, babylonMesh.getScene()));
             // TODO: tell the target whether it has positions, normals, tangents
         }
     };
@@ -5989,28 +5989,32 @@ var GLTFLoader = /** @class */ (function () {
             }));
         };
         loadAttribute("POSITION", babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["VertexBuffer"].PositionKind, function (babylonVertexBuffer, data) {
+            var positions = new Float32Array(data.length);
             babylonVertexBuffer.forEach(data.length, function (value, index) {
-                data[index] += value;
+                positions[index] = data[index] + value;
             });
-            babylonMorphTarget.setPositions(data);
+            babylonMorphTarget.setPositions(positions);
         });
         loadAttribute("NORMAL", babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["VertexBuffer"].NormalKind, function (babylonVertexBuffer, data) {
-            babylonVertexBuffer.forEach(data.length, function (value, index) {
-                data[index] += value;
+            var normals = new Float32Array(data.length);
+            babylonVertexBuffer.forEach(normals.length, function (value, index) {
+                normals[index] = data[index] + value;
             });
-            babylonMorphTarget.setNormals(data);
+            babylonMorphTarget.setNormals(normals);
         });
         loadAttribute("TANGENT", babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["VertexBuffer"].TangentKind, function (babylonVertexBuffer, data) {
+            var tangents = new Float32Array(data.length / 3 * 4);
             var dataIndex = 0;
             babylonVertexBuffer.forEach(data.length / 3 * 4, function (value, index) {
                 // Tangent data for morph targets is stored as xyz delta.
                 // The vertexData.tangent is stored as xyzw.
                 // So we need to skip every fourth vertexData.tangent.
                 if (((index + 1) % 4) !== 0) {
-                    data[dataIndex++] += value;
+                    tangents[dataIndex] = data[dataIndex] + value;
+                    dataIndex++;
                 }
             });
-            babylonMorphTarget.setTangents(data);
+            babylonMorphTarget.setTangents(tangents);
         });
         return Promise.all(promises).then(function () { });
     };

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.js.map


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.min.js


+ 609 - 0
dist/preview release/nodeEditor/babylon.nodeEditor.d.ts

@@ -0,0 +1,609 @@
+/// <reference types="react" />
+declare module NODEEDITOR {
+    /**
+     * Port model
+     */
+    export class DefaultPortModel extends PortModel {
+        /**
+         * If the port is input or output
+         */
+        position: string | "input" | "output";
+        /**
+         * What the port is connected to
+         */
+        connection: BABYLON.Nullable<BABYLON.NodeMaterialConnectionPoint>;
+        static idCounter: number;
+        constructor(name: string, type?: string);
+        syncWithNodeMaterialConnectionPoint(connection: BABYLON.NodeMaterialConnectionPoint): void;
+        getNodeModel(): DefaultNodeModel;
+        link(outPort: DefaultPortModel): LinkModel<import("storm-react-diagrams").LinkModelListener>;
+        getInputFromBlock(): void;
+        createLinkModel(): LinkModel;
+        getValue: Function;
+        static SortInputOutput(a: BABYLON.Nullable<DefaultPortModel>, b: BABYLON.Nullable<DefaultPortModel>): {
+            input: DefaultPortModel;
+            output: DefaultPortModel;
+        } | null;
+    }
+}
+declare module NODEEDITOR {
+    interface ITextLineComponentProps {
+        label: string;
+        value: string;
+        color?: string;
+        underline?: boolean;
+        onLink?: () => void;
+    }
+    export class TextLineComponent extends React.Component<ITextLineComponentProps> {
+        constructor(props: ITextLineComponentProps);
+        onLink(): void;
+        renderContent(): JSX.Element;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    /**
+     * Generic node model which stores information about a node editor block
+     */
+    export class GenericNodeModel extends DefaultNodeModel {
+        /**
+         * Labels for the block
+         */
+        header: string;
+        /**
+         * BABYLON.Vector2 for the node if it exists
+         */
+        vector2: BABYLON.Nullable<BABYLON.Vector2>;
+        /**
+         * BABYLON.Vector3 for the node if it exists
+         */
+        vector3: BABYLON.Nullable<BABYLON.Vector3>;
+        /**
+         * BABYLON.Vector4 for the node if it exists
+         */
+        vector4: BABYLON.Nullable<BABYLON.Vector4>;
+        /**
+         * BABYLON.Matrix for the node if it exists
+         */
+        matrix: BABYLON.Nullable<BABYLON.Matrix>;
+        /**
+         * Constructs the node model
+         */
+        constructor();
+        prepare(options: NodeCreationOptions, nodes: Array<DefaultNodeModel>, model: DiagramModel, graphEditor: GraphEditor, filterInputs: string[]): void;
+        renderProperties(globalState: GlobalState): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    /**
+     * GenericNodeWidgetProps
+     */
+    export interface GenericNodeWidgetProps {
+        node: BABYLON.Nullable<GenericNodeModel>;
+        globalState: GlobalState;
+    }
+    /**
+     * GenericNodeWidgetState
+     */
+    export interface GenericNodeWidgetState {
+    }
+    /**
+     * Used to display a node block for the node editor
+     */
+    export class GenericNodeWidget extends React.Component<GenericNodeWidgetProps, GenericNodeWidgetState> {
+        /**
+         * Creates a GenericNodeWidget
+         * @param props
+         */
+        constructor(props: GenericNodeWidgetProps);
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    /**
+     * Node factory which creates editor nodes
+     */
+    export class GenericNodeFactory extends SRD.AbstractNodeFactory {
+        private _globalState;
+        /**
+         * Constructs a GenericNodeFactory
+         */
+        constructor(globalState: GlobalState);
+        /**
+         * Generates a node widget
+         * @param diagramEngine diagram engine
+         * @param node node to generate
+         * @returns node widget jsx
+         */
+        generateReactWidget(diagramEngine: SRD.DiagramEngine, node: GenericNodeModel): JSX.Element;
+        /**
+         * Gets a new instance of a node model
+         * @returns generic node model
+         */
+        getNewInstance(): GenericNodeModel;
+    }
+}
+declare module NODEEDITOR {
+    interface ILineContainerComponentProps {
+        title: string;
+        children: any[] | any;
+        closed?: boolean;
+    }
+    export class LineContainerComponent extends React.Component<ILineContainerComponentProps, {
+        isExpanded: boolean;
+    }> {
+        private static _InMemoryStorage;
+        constructor(props: ILineContainerComponentProps);
+        switchExpandedState(): void;
+        renderHeader(): JSX.Element;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    export interface IButtonLineComponentProps {
+        label: string;
+        onClick: () => void;
+    }
+    export class ButtonLineComponent extends React.Component<IButtonLineComponentProps> {
+        constructor(props: IButtonLineComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    interface INodeListComponentProps {
+        globalState: GlobalState;
+        onAddValueNode: (b: string) => void;
+        onAddNodeFromClass: (ObjectClass: typeof BABYLON.NodeMaterialBlock) => void;
+    }
+    export class NodeListComponent extends React.Component<INodeListComponentProps> {
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    interface IPropertyTabComponentProps {
+        globalState: GlobalState;
+    }
+    export class PropertyTabComponent extends React.Component<IPropertyTabComponentProps, {
+        currentNode: BABYLON.Nullable<DefaultNodeModel>;
+    }> {
+        constructor(props: IPropertyTabComponentProps);
+        componentWillMount(): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    interface IPortalProps {
+        globalState: GlobalState;
+    }
+    export class Portal extends React.Component<IPortalProps> {
+        render(): React.ReactPortal;
+    }
+}
+declare module NODEEDITOR {
+    interface IFileButtonLineComponentProps {
+        label: string;
+        onClick: (file: File) => void;
+        accept: string;
+    }
+    export class FileButtonLineComponent extends React.Component<IFileButtonLineComponentProps> {
+        constructor(props: IFileButtonLineComponentProps);
+        onChange(evt: any): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    interface ITexturePropertyTabComponentProps {
+        globalState: GlobalState;
+        node: TextureNodeModel;
+    }
+    export class TexturePropertyTabComponent extends React.Component<ITexturePropertyTabComponentProps> {
+        /**
+         * Replaces the texture of the node
+         * @param file the file of the texture to use
+         */
+        replaceTexture(file: File): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    /**
+     * BABYLON.Texture node model which stores information about a node editor block
+     */
+    export class TextureNodeModel extends DefaultNodeModel {
+        /**
+         * BABYLON.Texture for the node if it exists
+         */
+        texture: BABYLON.Nullable<BABYLON.Texture>;
+        /**
+         * Constructs the node model
+         */
+        constructor();
+        renderProperties(globalState: GlobalState): JSX.Element;
+        prepare(options: NodeCreationOptions, nodes: Array<DefaultNodeModel>, model: DiagramModel, graphEditor: GraphEditor, filterInputs: string[]): void;
+    }
+}
+declare module NODEEDITOR {
+    interface ITextureLineComponentProps {
+        texture: BABYLON.BaseTexture;
+        width: number;
+        height: number;
+        globalState?: any;
+        hideChannelSelect?: boolean;
+    }
+    export class TextureLineComponent extends React.Component<ITextureLineComponentProps, {
+        displayRed: boolean;
+        displayGreen: boolean;
+        displayBlue: boolean;
+        displayAlpha: boolean;
+        face: number;
+    }> {
+        constructor(props: ITextureLineComponentProps);
+        shouldComponentUpdate(nextProps: ITextureLineComponentProps, nextState: {
+            displayRed: boolean;
+            displayGreen: boolean;
+            displayBlue: boolean;
+            displayAlpha: boolean;
+            face: number;
+        }): boolean;
+        componentDidMount(): void;
+        componentDidUpdate(): void;
+        updatePreview(): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    /**
+     * GenericNodeWidgetProps
+     */
+    export interface TextureNodeWidgetProps {
+        node: BABYLON.Nullable<TextureNodeModel>;
+        globalState: GlobalState;
+    }
+    /**
+     * Used to display a node block for the node editor
+     */
+    export class TextureNodeWidget extends React.Component<TextureNodeWidgetProps> {
+        /**
+         * Creates a GenericNodeWidget
+         * @param props
+         */
+        constructor(props: TextureNodeWidgetProps);
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    /**
+     * Node factory which creates editor nodes
+     */
+    export class TextureNodeFactory extends SRD.AbstractNodeFactory {
+        private _globalState;
+        /**
+         * Constructs a TextureNodeFactory
+         */
+        constructor(globalState: GlobalState);
+        /**
+         * Generates a node widget
+         * @param diagramEngine diagram engine
+         * @param node node to generate
+         * @returns node widget jsx
+         */
+        generateReactWidget(diagramEngine: SRD.DiagramEngine, node: TextureNodeModel): JSX.Element;
+        /**
+         * Gets a new instance of a node model
+         * @returns texture node model
+         */
+        getNewInstance(): TextureNodeModel;
+    }
+}
+declare module NODEEDITOR {
+    interface INumericInputComponentProps {
+        label: string;
+        value: number;
+        step?: number;
+        onChange: (value: number) => void;
+    }
+    export class NumericInputComponent extends React.Component<INumericInputComponentProps, {
+        value: string;
+    }> {
+        static defaultProps: {
+            step: number;
+        };
+        private _localChange;
+        constructor(props: INumericInputComponentProps);
+        shouldComponentUpdate(nextProps: INumericInputComponentProps, nextState: {
+            value: string;
+        }): boolean;
+        updateValue(evt: any): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    export class PropertyChangedEvent {
+        object: any;
+        property: string;
+        value: any;
+        initialValue: any;
+    }
+}
+declare module NODEEDITOR {
+    interface IVector2LineComponentProps {
+        label: string;
+        target: any;
+        propertyName: string;
+        step?: number;
+        onChange?: (newvalue: BABYLON.Vector2) => void;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class Vector2LineComponent extends React.Component<IVector2LineComponentProps, {
+        isExpanded: boolean;
+        value: BABYLON.Vector2;
+    }> {
+        static defaultProps: {
+            step: number;
+        };
+        private _localChange;
+        constructor(props: IVector2LineComponentProps);
+        shouldComponentUpdate(nextProps: IVector2LineComponentProps, nextState: {
+            isExpanded: boolean;
+            value: BABYLON.Vector2;
+        }): boolean;
+        switchExpandState(): void;
+        raiseOnPropertyChanged(previousValue: BABYLON.Vector2): void;
+        updateStateX(value: number): void;
+        updateStateY(value: number): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    interface IVector2PropertyTabComponentProps {
+        globalState: GlobalState;
+        connection: BABYLON.NodeMaterialConnectionPoint;
+    }
+    export class Vector2PropertyTabComponent extends React.Component<IVector2PropertyTabComponentProps> {
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    interface IVector3LineComponentProps {
+        label: string;
+        target: any;
+        propertyName: string;
+        step?: number;
+        onChange?: (newvalue: BABYLON.Vector3) => void;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class Vector3LineComponent extends React.Component<IVector3LineComponentProps, {
+        isExpanded: boolean;
+        value: BABYLON.Vector3;
+    }> {
+        static defaultProps: {
+            step: number;
+        };
+        private _localChange;
+        constructor(props: IVector3LineComponentProps);
+        shouldComponentUpdate(nextProps: IVector3LineComponentProps, nextState: {
+            isExpanded: boolean;
+            value: BABYLON.Vector3;
+        }): boolean;
+        switchExpandState(): void;
+        raiseOnPropertyChanged(previousValue: BABYLON.Vector3): void;
+        updateVector3(): void;
+        updateStateX(value: number): void;
+        updateStateY(value: number): void;
+        updateStateZ(value: number): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    interface IVector3PropertyTabComponentProps {
+        globalState: GlobalState;
+        connection: BABYLON.NodeMaterialConnectionPoint;
+    }
+    export class Vector3PropertyTabComponent extends React.Component<IVector3PropertyTabComponentProps> {
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    export interface ICheckBoxLineComponentProps {
+        label: string;
+        target?: any;
+        propertyName?: string;
+        isSelected?: () => boolean;
+        onSelect?: (value: boolean) => void;
+        onValueChanged?: () => void;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class CheckBoxLineComponent extends React.Component<ICheckBoxLineComponentProps, {
+        isSelected: boolean;
+    }> {
+        private static _UniqueIdSeed;
+        private _uniqueId;
+        private _localChange;
+        constructor(props: ICheckBoxLineComponentProps);
+        shouldComponentUpdate(nextProps: ICheckBoxLineComponentProps, nextState: {
+            isSelected: boolean;
+        }): boolean;
+        onChange(): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    class ListLineOption {
+        label: string;
+        value: number;
+    }
+    interface IOptionsLineComponentProps {
+        label: string;
+        target: any;
+        propertyName: string;
+        options: ListLineOption[];
+        noDirectUpdate?: boolean;
+        onSelect?: (value: number) => void;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class OptionsLineComponent extends React.Component<IOptionsLineComponentProps, {
+        value: number;
+    }> {
+        private _localChange;
+        constructor(props: IOptionsLineComponentProps);
+        shouldComponentUpdate(nextProps: IOptionsLineComponentProps, nextState: {
+            value: number;
+        }): boolean;
+        raiseOnPropertyChanged(newValue: number, previousValue: number): void;
+        updateValue(valueString: string): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    interface IInputPropertyTabComponentProps {
+        globalState: GlobalState;
+        inputNode: InputNodeModel;
+    }
+    export class InputPropertyTabComponentProps extends React.Component<IInputPropertyTabComponentProps> {
+        constructor(props: IInputPropertyTabComponentProps);
+        renderValue(globalState: GlobalState): JSX.Element | null;
+        setDefaultValue(): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    /**
+     * Generic node model which stores information about a node editor block
+     */
+    export class InputNodeModel extends DefaultNodeModel {
+        connection?: BABYLON.NodeMaterialConnectionPoint;
+        /**
+         * Constructs the node model
+         */
+        constructor();
+        renderProperties(globalState: GlobalState): JSX.Element | null;
+    }
+}
+declare module NODEEDITOR {
+    /**
+     * GenericNodeWidgetProps
+     */
+    export interface InputNodeWidgetProps {
+        node: BABYLON.Nullable<InputNodeModel>;
+        globalState: GlobalState;
+    }
+    /**
+     * Used to display a node block for the node editor
+     */
+    export class InputNodeWidget extends React.Component<InputNodeWidgetProps> {
+        /**
+         * Creates a GenericNodeWidget
+         * @param props
+         */
+        constructor(props: InputNodeWidgetProps);
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    /**
+     * Node factory which creates editor nodes
+     */
+    export class InputNodeFactory extends SRD.AbstractNodeFactory {
+        private _globalState;
+        /**
+         * Constructs a GenericNodeFactory
+         */
+        constructor(globalState: GlobalState);
+        /**
+         * Generates a node widget
+         * @param diagramEngine diagram engine
+         * @param node node to generate
+         * @returns node widget jsx
+         */
+        generateReactWidget(diagramEngine: SRD.DiagramEngine, node: InputNodeModel): JSX.Element;
+        /**
+         * Gets a new instance of a node model
+         * @returns input node model
+         */
+        getNewInstance(): InputNodeModel;
+    }
+}
+declare module NODEEDITOR {
+    interface IGraphEditorProps {
+        globalState: GlobalState;
+    }
+    export class NodeCreationOptions {
+        column: number;
+        nodeMaterialBlock?: BABYLON.NodeMaterialBlock;
+        type?: string;
+        connection?: BABYLON.NodeMaterialConnectionPoint;
+    }
+    export class GraphEditor extends React.Component<IGraphEditorProps> {
+        private _engine;
+        private _model;
+        private _nodes;
+        /**
+         * Current row/column position used when adding new nodes
+         */
+        private _rowPos;
+        /**
+         * Creates a node and recursivly creates its parent nodes from it's input
+         * @param nodeMaterialBlock
+         */
+        createNodeFromObject(options: NodeCreationOptions): DefaultNodeModel;
+        componentDidMount(): void;
+        componentWillUnmount(): void;
+        constructor(props: IGraphEditorProps);
+        addNodeFromClass(ObjectClass: typeof BABYLON.NodeMaterialBlock): DefaultNodeModel;
+        addValueNode(type: string, column?: number, connection?: BABYLON.NodeMaterialConnectionPoint): DefaultNodeModel;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    /**
+     * Generic node model which stores information about a node editor block
+     */
+    export class DefaultNodeModel extends NodeModel {
+        /**
+         * The babylon block this node represents
+         */
+        block: BABYLON.Nullable<BABYLON.NodeMaterialBlock>;
+        ports: {
+            [s: string]: DefaultPortModel;
+        };
+        /**
+         * Constructs the node model
+         */
+        constructor(key: string);
+        prepare(options: NodeCreationOptions, nodes: Array<DefaultNodeModel>, model: DiagramModel, graphEditor: GraphEditor, filterInputs: string[]): void;
+        renderProperties(globalState: GlobalState): JSX.Element | null;
+    }
+}
+declare module NODEEDITOR {
+    export class GlobalState {
+        nodeMaterial?: BABYLON.NodeMaterial;
+        hostElement: HTMLElement;
+        hostDocument: HTMLDocument;
+        onSelectionChangedObservable: BABYLON.Observable<BABYLON.Nullable<DefaultNodeModel>>;
+        onRebuildRequiredObservable: BABYLON.Observable<void>;
+    }
+}
+declare module NODEEDITOR {
+    export class Popup {
+        static CreatePopup(title: string, windowVariableName: string, width?: number, height?: number): HTMLDivElement | null;
+        private static _CopyStyles;
+    }
+}
+declare module NODEEDITOR {
+    /**
+     * Interface used to specify creation options for the node editor
+     */
+    export interface INodeEditorOptions {
+        nodeMaterial: BABYLON.NodeMaterial;
+    }
+    /**
+     * Class used to create a node editor
+     */
+    export class NodeEditor {
+        /**
+         * Show the node editor
+         * @param options defines the options to use to configure the node editor
+         */
+        static Show(options: INodeEditorOptions): void;
+    }
+}

Fichier diff supprimé car celui-ci est trop grand
+ 41 - 0
dist/preview release/nodeEditor/babylon.nodeEditor.js


Fichier diff supprimé car celui-ci est trop grand
+ 49364 - 0
dist/preview release/nodeEditor/babylon.nodeEditor.max.js


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 0
dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map


Fichier diff supprimé car celui-ci est trop grand
+ 1325 - 0
dist/preview release/nodeEditor/babylon.nodeEditor.module.d.ts


+ 27 - 0
dist/preview release/nodeEditor/package.json

@@ -0,0 +1,27 @@
+{
+    "author": {
+        "name": "David CATUHE"
+    },
+    "name": "babylonjs-node-editor",
+    "description": "The Babylon.js node material editor.",
+    "version": "4.1.0-alpha.0",
+    "repository": {
+        "type": "git",
+        "url": "https://github.com/BabylonJS/Babylon.js.git"
+    },
+    "license": "Apache-2.0",
+    "dependencies": {
+        "babylonjs": "4.1.0-alpha.0"
+    },
+    "files": [
+        "babylon.nodeEditor.max.js.map",
+        "babylon.nodeEditor.max.js",
+        "babylon.nodeEditor.js",
+        "babylon.nodeEditor.module.d.ts",
+        "readme.md",
+        "package.json"
+    ],
+    "engines": {
+        "node": "*"
+    }
+}

+ 1 - 0
dist/preview release/nodeEditor/readme-es6.md

@@ -0,0 +1 @@
+Node Editor es6

+ 1 - 0
dist/preview release/nodeEditor/readme.md

@@ -0,0 +1 @@
+Node Editor

+ 1 - 1
dist/preview release/packagesSizeBaseLine.json

@@ -1 +1 @@
-{"engineOnly":290833,"sceneOnly":500617,"minGridMaterial":627677,"minStandardMaterial":752502}
+{"engineOnly":291259,"sceneOnly":501088,"minGridMaterial":628531,"minStandardMaterial":753356}

+ 14 - 19
dist/preview release/serializers/babylon.glTF2Serializer.js

@@ -300,14 +300,13 @@ _glTFExporter__WEBPACK_IMPORTED_MODULE_1__["_Exporter"].RegisterExtension(NAME,
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KHR_texture_transform", function() { return KHR_texture_transform; });
-/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Maths/math");
-/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__);
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _glTFExporter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../glTFExporter */ "./glTF/2.0/glTFExporter.ts");
 /* harmony import */ var _shaders_textureTransform_fragment__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../shaders/textureTransform.fragment */ "./glTF/2.0/shaders/textureTransform.fragment.ts");
 
 
 
-
 var NAME = "KHR_texture_transform";
 
 /**
@@ -329,6 +328,12 @@ var KHR_texture_transform = /** @class */ (function () {
     KHR_texture_transform.prototype.preExportTextureAsync = function (context, babylonTexture, mimeType) {
         var _this = this;
         return new Promise(function (resolve, reject) {
+            var scene = babylonTexture.getScene();
+            if (!scene) {
+                reject(context + ": \"scene\" is not defined for Babylon texture " + babylonTexture.name + "!");
+                return;
+            }
+            // TODO: this doesn't take into account rotation center values
             var texture_transform_extension = {};
             if (babylonTexture.uOffset !== 0 || babylonTexture.vOffset !== 0) {
                 texture_transform_extension.offset = [babylonTexture.uOffset, babylonTexture.vOffset];
@@ -341,19 +346,9 @@ var KHR_texture_transform = /** @class */ (function () {
             }
             if (!Object.keys(texture_transform_extension).length) {
                 resolve(babylonTexture);
+                return;
             }
-            var scale = texture_transform_extension.scale ? new babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__["Vector2"](texture_transform_extension.scale[0], texture_transform_extension.scale[1]) : babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__["Vector2"].One();
-            var rotation = texture_transform_extension.rotation != null ? texture_transform_extension.rotation : 0;
-            var offset = texture_transform_extension.offset ? new babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__["Vector2"](texture_transform_extension.offset[0], texture_transform_extension.offset[1]) : babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__["Vector2"].Zero();
-            var scene = babylonTexture.getScene();
-            if (!scene) {
-                reject(context + ": \"scene\" is not defined for Babylon texture " + babylonTexture.name + "!");
-            }
-            else {
-                _this.textureTransformTextureAsync(babylonTexture, offset, rotation, scale, scene).then(function (texture) {
-                    resolve(texture);
-                });
-            }
+            return _this._textureTransformTextureAsync(babylonTexture, scene);
         });
     };
     /**
@@ -364,11 +359,11 @@ var KHR_texture_transform = /** @class */ (function () {
      * @param scale
      * @param scene
      */
-    KHR_texture_transform.prototype.textureTransformTextureAsync = function (babylonTexture, offset, rotation, scale, scene) {
-        return new Promise(function (resolve, reject) {
-            var proceduralTexture = new babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__["ProceduralTexture"]("" + babylonTexture.name, babylonTexture.getSize(), "textureTransform", scene);
+    KHR_texture_transform.prototype._textureTransformTextureAsync = function (babylonTexture, scene) {
+        return new Promise(function (resolve) {
+            var proceduralTexture = new babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__["ProceduralTexture"]("" + babylonTexture.name, babylonTexture.getSize(), "textureTransform", scene);
             if (!proceduralTexture) {
-                babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__["Tools"].Log("Cannot create procedural texture for " + babylonTexture.name + "!");
+                babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__["Tools"].Log("Cannot create procedural texture for " + babylonTexture.name + "!");
                 resolve(babylonTexture);
             }
             proceduralTexture.setTexture("textureSampler", babylonTexture);

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/serializers/babylon.glTF2Serializer.js.map


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/serializers/babylon.glTF2Serializer.min.js


+ 1 - 1
dist/preview release/serializers/babylonjs.serializers.d.ts

@@ -1023,7 +1023,7 @@ declare module BABYLON.GLTF2.Exporter.Extensions {
          * @param scale
          * @param scene
          */
-        textureTransformTextureAsync(babylonTexture: Texture, offset: Vector2, rotation: number, scale: Vector2, scene: Scene): Promise<BaseTexture>;
+        private _textureTransformTextureAsync;
     }
 }
 declare module BABYLON.GLTF2.Exporter.Extensions {

+ 14 - 19
dist/preview release/serializers/babylonjs.serializers.js

@@ -478,14 +478,13 @@ _glTFExporter__WEBPACK_IMPORTED_MODULE_1__["_Exporter"].RegisterExtension(NAME,
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KHR_texture_transform", function() { return KHR_texture_transform; });
-/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Maths/math");
-/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__);
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _glTFExporter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../glTFExporter */ "./glTF/2.0/glTFExporter.ts");
 /* harmony import */ var _shaders_textureTransform_fragment__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../shaders/textureTransform.fragment */ "./glTF/2.0/shaders/textureTransform.fragment.ts");
 
 
 
-
 var NAME = "KHR_texture_transform";
 
 /**
@@ -507,6 +506,12 @@ var KHR_texture_transform = /** @class */ (function () {
     KHR_texture_transform.prototype.preExportTextureAsync = function (context, babylonTexture, mimeType) {
         var _this = this;
         return new Promise(function (resolve, reject) {
+            var scene = babylonTexture.getScene();
+            if (!scene) {
+                reject(context + ": \"scene\" is not defined for Babylon texture " + babylonTexture.name + "!");
+                return;
+            }
+            // TODO: this doesn't take into account rotation center values
             var texture_transform_extension = {};
             if (babylonTexture.uOffset !== 0 || babylonTexture.vOffset !== 0) {
                 texture_transform_extension.offset = [babylonTexture.uOffset, babylonTexture.vOffset];
@@ -519,19 +524,9 @@ var KHR_texture_transform = /** @class */ (function () {
             }
             if (!Object.keys(texture_transform_extension).length) {
                 resolve(babylonTexture);
+                return;
             }
-            var scale = texture_transform_extension.scale ? new babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__["Vector2"](texture_transform_extension.scale[0], texture_transform_extension.scale[1]) : babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__["Vector2"].One();
-            var rotation = texture_transform_extension.rotation != null ? texture_transform_extension.rotation : 0;
-            var offset = texture_transform_extension.offset ? new babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__["Vector2"](texture_transform_extension.offset[0], texture_transform_extension.offset[1]) : babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__["Vector2"].Zero();
-            var scene = babylonTexture.getScene();
-            if (!scene) {
-                reject(context + ": \"scene\" is not defined for Babylon texture " + babylonTexture.name + "!");
-            }
-            else {
-                _this.textureTransformTextureAsync(babylonTexture, offset, rotation, scale, scene).then(function (texture) {
-                    resolve(texture);
-                });
-            }
+            return _this._textureTransformTextureAsync(babylonTexture, scene);
         });
     };
     /**
@@ -542,11 +537,11 @@ var KHR_texture_transform = /** @class */ (function () {
      * @param scale
      * @param scene
      */
-    KHR_texture_transform.prototype.textureTransformTextureAsync = function (babylonTexture, offset, rotation, scale, scene) {
-        return new Promise(function (resolve, reject) {
-            var proceduralTexture = new babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__["ProceduralTexture"]("" + babylonTexture.name, babylonTexture.getSize(), "textureTransform", scene);
+    KHR_texture_transform.prototype._textureTransformTextureAsync = function (babylonTexture, scene) {
+        return new Promise(function (resolve) {
+            var proceduralTexture = new babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__["ProceduralTexture"]("" + babylonTexture.name, babylonTexture.getSize(), "textureTransform", scene);
             if (!proceduralTexture) {
-                babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__["Tools"].Log("Cannot create procedural texture for " + babylonTexture.name + "!");
+                babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__["Tools"].Log("Cannot create procedural texture for " + babylonTexture.name + "!");
                 resolve(babylonTexture);
             }
             proceduralTexture.setTexture("textureSampler", babylonTexture);

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/serializers/babylonjs.serializers.js.map


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/serializers/babylonjs.serializers.min.js


+ 2 - 5
dist/preview release/serializers/babylonjs.serializers.module.d.ts

@@ -1048,10 +1048,7 @@ declare module "babylonjs-serializers/glTF/2.0/shaders/textureTransform.fragment
 declare module "babylonjs-serializers/glTF/2.0/Extensions/KHR_texture_transform" {
     import { ImageMimeType } from "babylonjs-gltf2interface";
     import { Nullable } from "babylonjs/types";
-    import { Vector2 } from "babylonjs/Maths/math";
-    import { BaseTexture } from "babylonjs/Materials/Textures/baseTexture";
     import { Texture } from "babylonjs/Materials/Textures/texture";
-    import { Scene } from "babylonjs/scene";
     import { IGLTFExporterExtensionV2 } from "babylonjs-serializers/glTF/2.0/glTFExporterExtension";
     import { _Exporter } from "babylonjs-serializers/glTF/2.0/glTFExporter";
     import "babylonjs-serializers/glTF/2.0/shaders/textureTransform.fragment";
@@ -1078,7 +1075,7 @@ declare module "babylonjs-serializers/glTF/2.0/Extensions/KHR_texture_transform"
          * @param scale
          * @param scene
          */
-        textureTransformTextureAsync(babylonTexture: Texture, offset: Vector2, rotation: number, scale: Vector2, scene: Scene): Promise<BaseTexture>;
+        private _textureTransformTextureAsync;
     }
 }
 declare module "babylonjs-serializers/glTF/2.0/Extensions/KHR_lights_punctual" {
@@ -2204,7 +2201,7 @@ declare module BABYLON.GLTF2.Exporter.Extensions {
          * @param scale
          * @param scene
          */
-        textureTransformTextureAsync(babylonTexture: Texture, offset: Vector2, rotation: number, scale: Vector2, scene: Scene): Promise<BaseTexture>;
+        private _textureTransformTextureAsync;
     }
 }
 declare module BABYLON.GLTF2.Exporter.Extensions {

Fichier diff supprimé car celui-ci est trop grand
+ 13826 - 10529
dist/preview release/viewer/babylon.module.d.ts


Fichier diff supprimé car celui-ci est trop grand
+ 470 - 322
dist/preview release/viewer/babylon.viewer.js


Fichier diff supprimé car celui-ci est trop grand
+ 2 - 2
dist/preview release/viewer/babylon.viewer.max.js


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

@@ -5,7 +5,13 @@
 ## Optimizations
 
 ## Updates
+
+### Core Engine
 - Support Vive Focus 3Dof controller ([TrevorDev](https://github.com/TrevorDev))
+- Planar positioning support for GizmoManager ([Balupg](https://github.com/balupg))
+- Individual gizmos can now be enabled/disabled ([Balupg](https://github.com/balupg))
+- Unify preparation of instance attributes. Added `MaterialHelper.PushAttributesForInstances` ([MarkusBillharz](https://github.com/MarkusBillharz))
+- Added support for PBR [irradiance map](https://doc.babylonjs.com/how_to/physically_based_rendering_master#irradiance-map)
 
 ### Engine
 - Added preprocessors for shaders to improve how shaders are compiled for WebGL1/2 or WebGPU ([Deltakosh](https://github.com/deltakosh/))
@@ -13,7 +19,10 @@
 ### Inspector
 - Added support for `ShadowGenerator` ([Deltakosh](https://github.com/deltakosh/))
 - Added support for scene normalization ([Deltakosh](https://github.com/deltakosh/))
+- Added support for morph targets ([Deltakosh](https://github.com/deltakosh/))
+- Added context menu to add `SSAORenderingPipeline` and `SSAO2RenderingPipeline` ([Deltakosh](https://github.com/deltakosh/))
 - Added support for texture creation and assignments per material ([Deltakosh](https://github.com/deltakosh/))
+- Node material editor ([Deltakosh](https://github.com/deltakosh/)/[TrevorDev](https://github.com/TrevorDev))
 
 ### Tools
 - Added `Color3.toHSV()`, `Color3.toHSVToRef()` and `Color3.HSVtoRGBToRef()` ([Deltakosh](https://github.com/deltakosh/))
@@ -25,5 +34,7 @@
 ## Bug fixes
 - Added support for `AnimationGroup` serialization ([Drigax](https://github.com/drigax/))
 - Removing assetContainer from scene will also remove gui layers ([TrevorDev](https://github.com/TrevorDev))
+- A scene's input manager not adding key listeners when the canvas is already focused ([Poolminer](https://github.com/Poolminer))
+- Runtime animation `goToFrame` when going back in time now correctly triggers future events when reached ([zakhenry](https://github.com/zakhenry))
 
 ## Breaking changes

+ 2 - 2
gui/src/2D/controls/line.ts

@@ -180,9 +180,9 @@ export class Line extends Control {
         context.setLineDash(this._dash);
 
         context.beginPath();
-        context.moveTo(this._cachedParentMeasure.left + this._x1.getValue(this._host), this._cachedParentMeasure.left + this._y1.getValue(this._host));
+        context.moveTo(this._cachedParentMeasure.left + this._x1.getValue(this._host), this._cachedParentMeasure.top + this._y1.getValue(this._host));
 
-        context.lineTo(this._cachedParentMeasure.left + this._effectiveX2, this._cachedParentMeasure.left + this._effectiveY2);
+        context.lineTo(this._cachedParentMeasure.left + this._effectiveX2, this._cachedParentMeasure.top + this._effectiveY2);
         context.stroke();
 
         context.restore();

+ 2 - 2
inspector/README.md

@@ -9,13 +9,13 @@ Call the method `show` of the scene debugLayer:
 ```
 scene.debugLayer.show();
 ```
-This method will retrieve dynamically the library `inspector.js`, download it and add
+This method will retrieve dynamically the library `babylon.inspector.bundle.js`, download it and add
 it to the html page.
 
 ### Offline method
 If you don't have access to internet, the inspector should be imported manually in your HTML page :
 ```
-<script src="babylon.inspector.js" />
+<script src="babylon.inspector.bundle.js" />
 ``` 
 Then, call the method `show` of the scene debugLayer: 
 ```

+ 46 - 33
inspector/src/components/actionTabs/actionTabsComponent.tsx

@@ -15,7 +15,7 @@ import { GlobalState } from "../../components/globalState";
 require("./actionTabs.scss");
 
 interface IActionTabsComponentProps {
-    scene: Scene,
+    scene?: Scene,
     noCommands?: boolean,
     noHeader?: boolean,
     noExpand?: boolean,
@@ -23,7 +23,7 @@ interface IActionTabsComponentProps {
     popupMode?: boolean,
     onPopup?: () => void,
     onClose?: () => void,
-    globalState: GlobalState
+    globalState?: GlobalState
 }
 
 export class ActionTabsComponent extends React.Component<IActionTabsComponentProps, { selectedEntity: any, selectedIndex: number }> {
@@ -36,53 +36,66 @@ export class ActionTabsComponent extends React.Component<IActionTabsComponentPro
 
         let initialIndex = 0;
 
-        const validationResutls = this.props.globalState.validationResults;
-        if (validationResutls) {
-            if (validationResutls.issues.numErrors || validationResutls.issues.numWarnings) {
-                initialIndex = 3;
+        if(this.props.globalState){
+            const validationResutls = this.props.globalState.validationResults;
+            if (validationResutls) {
+                if (validationResutls.issues.numErrors || validationResutls.issues.numWarnings) {
+                    initialIndex = 3;
+                }
             }
         }
+        
 
         this.state = { selectedEntity: null, selectedIndex: initialIndex }
     }
 
     componentWillMount() {
-        this._onSelectionChangeObserver = this.props.globalState.onSelectionChangedObservable.add((entity) => {
-            this.setState({ selectedEntity: entity, selectedIndex: 0 });
-        });
-
-        this._onTabChangedObserver = this.props.globalState.onTabChangedObservable.add(index => {
-            this.setState({ selectedIndex: index });
-        });
+        if(this.props.globalState){
+            this._onSelectionChangeObserver = this.props.globalState.onSelectionChangedObservable.add((entity) => {
+                this.setState({ selectedEntity: entity, selectedIndex: 0 });
+            });
+
+            this._onTabChangedObserver = this.props.globalState.onTabChangedObservable.add(index => {
+                this.setState({ selectedIndex: index });
+            });
+        }
     }
 
     componentWillUnmount() {
-        if (this._onSelectionChangeObserver) {
-            this.props.globalState.onSelectionChangedObservable.remove(this._onSelectionChangeObserver);
-        }
+        if(this.props.globalState){
+            if (this._onSelectionChangeObserver) {
+                this.props.globalState.onSelectionChangedObservable.remove(this._onSelectionChangeObserver);
+            }
 
-        if (this._onTabChangedObserver) {
-            this.props.globalState.onTabChangedObservable.remove(this._onTabChangedObserver);
+            if (this._onTabChangedObserver) {
+                this.props.globalState.onTabChangedObservable.remove(this._onTabChangedObserver);
+            }
         }
     }
 
     changeSelectedTab(index: number) {
-        this.props.globalState.onTabChangedObservable.notifyObservers(index);
+        if(this.props.globalState){
+            this.props.globalState.onTabChangedObservable.notifyObservers(index);
+        }
     }
 
     renderContent() {
-        return (
-            <TabsComponent selectedIndex={this.state.selectedIndex} onSelectedIndexChange={(value) => this.changeSelectedTab(value)}>
-                <PropertyGridTabComponent
-                    title="Properties" icon={faFileAlt} scene={this.props.scene} selectedEntity={this.state.selectedEntity}
-                    globalState={this.props.globalState}
-                    onSelectionChangedObservable={this.props.globalState.onSelectionChangedObservable}
-                    onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />
-                <DebugTabComponent title="Debug" icon={faBug} scene={this.props.scene} globalState={this.props.globalState} />
-                <StatisticsTabComponent title="Statistics" icon={faChartBar} scene={this.props.scene} globalState={this.props.globalState} />
-                <ToolsTabComponent title="Tools" icon={faWrench} scene={this.props.scene} globalState={this.props.globalState} />
-            </TabsComponent>
-        )
+        if(this.props.globalState && this.props.scene){
+            return (
+                <TabsComponent selectedIndex={this.state.selectedIndex} onSelectedIndexChange={(value) => this.changeSelectedTab(value)}>
+                    <PropertyGridTabComponent
+                        title="Properties" icon={faFileAlt} scene={this.props.scene} selectedEntity={this.state.selectedEntity}
+                        globalState={this.props.globalState}
+                        onSelectionChangedObservable={this.props.globalState.onSelectionChangedObservable}
+                        onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />
+                    <DebugTabComponent title="Debug" icon={faBug} scene={this.props.scene} globalState={this.props.globalState} />
+                    <StatisticsTabComponent title="Statistics" icon={faChartBar} scene={this.props.scene} globalState={this.props.globalState} />
+                    <ToolsTabComponent title="Tools" icon={faWrench} scene={this.props.scene} globalState={this.props.globalState} />
+                </TabsComponent>
+            )
+        }else{
+            return null;
+        }
     }
 
     onClose() {
@@ -105,7 +118,7 @@ export class ActionTabsComponent extends React.Component<IActionTabsComponentPro
                 <div id="actionTabs">
                     {
                         !this.props.noHeader &&
-                        <HeaderComponent title="INSPECTOR" handleBack={true} noClose={this.props.noClose} noExpand={this.props.noExpand} noCommands={this.props.noCommands} onClose={() => this.onClose()} onPopup={() => this.onPopup()} onSelectionChangedObservable={this.props.globalState.onSelectionChangedObservable} />
+                        <HeaderComponent title="INSPECTOR" handleBack={true} noClose={this.props.noClose} noExpand={this.props.noExpand} noCommands={this.props.noCommands} onClose={() => this.onClose()} onPopup={() => this.onPopup()} onSelectionChangedObservable={this.props.globalState ? this.props.globalState.onSelectionChangedObservable : undefined} />
                     }
                     {this.renderContent()}
                 </div>
@@ -128,7 +141,7 @@ export class ActionTabsComponent extends React.Component<IActionTabsComponentPro
             <Resizable id="actionTabs" minWidth={300} maxWidth={600} size={{ height: "100%" }} minHeight="100%" enable={{ top: false, right: false, bottom: false, left: true, topRight: false, bottomRight: false, bottomLeft: false, topLeft: false }}>
                 {
                     !this.props.noHeader &&
-                    <HeaderComponent title="INSPECTOR" handleBack={true} noClose={this.props.noClose} noExpand={this.props.noExpand} noCommands={this.props.noCommands} onClose={() => this.onClose()} onPopup={() => this.onPopup()} onSelectionChangedObservable={this.props.globalState.onSelectionChangedObservable} />
+                    <HeaderComponent title="INSPECTOR" handleBack={true} noClose={this.props.noClose} noExpand={this.props.noExpand} noCommands={this.props.noCommands} onClose={() => this.onClose()} onPopup={() => this.onPopup()} onSelectionChangedObservable={this.props.globalState ? this.props.globalState.onSelectionChangedObservable : undefined} />
                 }
                 {this.renderContent()}
             </Resizable>

+ 4 - 4
inspector/src/components/actionTabs/lineContainerComponent.tsx

@@ -4,7 +4,7 @@ import { faChevronDown } from '@fortawesome/free-solid-svg-icons';
 import { GlobalState } from '../../components/globalState';
 
 interface ILineContainerComponentProps {
-    globalState: GlobalState;
+    globalState?: GlobalState;
     title: string;
     children: any[] | any;
     closed?: boolean;
@@ -55,13 +55,13 @@ export class LineContainerComponent extends React.Component<ILineContainerCompon
     }
 
     componentDidMount() {
-        if (!this.props.globalState.selectedLineContainerTitle) {
+        if (this.props.globalState && !this.props.globalState.selectedLineContainerTitle) {
             return;
         }
 
-        if (this.props.globalState.selectedLineContainerTitle === this.props.title) {
+        if (this.props.globalState && this.props.globalState.selectedLineContainerTitle === this.props.title) {
             setTimeout(() => {
-                this.props.globalState.selectedLineContainerTitle = "";
+                this.props.globalState!.selectedLineContainerTitle = "";
             });
 
             this.setState({ isExpanded: true, isHighlighted: true });

+ 5 - 2
inspector/src/components/actionTabs/lines/fileButtonLineComponent.tsx

@@ -7,6 +7,9 @@ interface IFileButtonLineComponentProps {
 }
 
 export class FileButtonLineComponent extends React.Component<IFileButtonLineComponentProps> {
+    private static _IDGenerator = 0;
+    private _id = FileButtonLineComponent._IDGenerator++;
+
     constructor(props: IFileButtonLineComponentProps) {
         super(props);
     }
@@ -23,10 +26,10 @@ export class FileButtonLineComponent extends React.Component<IFileButtonLineComp
     render() {
         return (
             <div className="buttonLine">
-                <label htmlFor="file-upload" className="file-upload">
+                <label htmlFor={"file-upload" + this._id} className="file-upload">
                     {this.props.label}
                 </label>
-                <input ref="upload" id="file-upload" type="file" accept={this.props.accept} onChange={evt => this.onChange(evt)} />
+                <input ref="upload" id={"file-upload" + this._id} type="file" accept={this.props.accept} onChange={evt => this.onChange(evt)} />
             </div>
         );
     }

+ 5 - 3
inspector/src/components/actionTabs/lines/floatLineComponent.tsx

@@ -13,6 +13,8 @@ interface IFloatLineComponentProps {
     isInteger?: boolean;
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
     additionalClass?: string;
+    step?: string,
+    digits?: number
 }
 
 export class FloatLineComponent extends React.Component<IFloatLineComponentProps, { value: string }> {
@@ -23,7 +25,7 @@ export class FloatLineComponent extends React.Component<IFloatLineComponentProps
         super(props);
 
         let currentValue = this.props.target[this.props.propertyName];
-        this.state = { value: currentValue ? (this.props.isInteger ? currentValue.toFixed(0) : currentValue.toFixed(3)) : "0" };
+        this.state = { value: currentValue ? (this.props.isInteger ? currentValue.toFixed(0) : currentValue.toFixed(this.props.digits || 3)) : "0" };
         this._store = currentValue;
     }
 
@@ -38,7 +40,7 @@ export class FloatLineComponent extends React.Component<IFloatLineComponentProps
         }
 
         const newValue = nextProps.target[nextProps.propertyName];
-        const newValueString = newValue ? this.props.isInteger ? newValue.toFixed(0) : newValue.toFixed(3) : "0";
+        const newValueString = newValue ? this.props.isInteger ? newValue.toFixed(0) : newValue.toFixed(this.props.digits || 3) : "0";
 
         if (newValueString !== nextState.value) {
             nextState.value = newValueString;
@@ -109,7 +111,7 @@ export class FloatLineComponent extends React.Component<IFloatLineComponentProps
                     {this.props.label}
                 </div>
                 <div className="value">
-                    <input type="number" step="0.01" className="numeric-input" value={this.state.value} onBlur={() => this.unlock()} onFocus={() => this.lock()} onChange={evt => this.updateValue(evt.target.value)} />
+                    <input type="number" step={this.props.step || "0.01"} className="numeric-input" value={this.state.value} onBlur={() => this.unlock()} onFocus={() => this.lock()} onChange={evt => this.updateValue(evt.target.value)} />
                 </div>
             </div>
         );

+ 17 - 5
inspector/src/components/actionTabs/lines/textureLineComponent.tsx

@@ -13,7 +13,8 @@ interface ITextureLineComponentProps {
     texture: BaseTexture;
     width: number;
     height: number;
-    globalState: GlobalState;
+    globalState?: GlobalState;
+    hideChannelSelect?:boolean;
 }
 
 export class TextureLineComponent extends React.Component<ITextureLineComponentProps, { displayRed: boolean, displayGreen: boolean, displayBlue: boolean, displayAlpha: boolean, face: number }> {
@@ -43,6 +44,11 @@ export class TextureLineComponent extends React.Component<ITextureLineComponentP
 
     updatePreview() {
         var texture = this.props.texture;
+        if(!texture.isReady() && texture._texture){
+            texture._texture.onLoadedObservable.addOnce(()=>{
+                this.updatePreview();
+            })
+        }
         var scene = texture.getScene()!;
         var engine = scene.getEngine();
         var size = texture.getSize();
@@ -72,7 +78,10 @@ export class TextureLineComponent extends React.Component<ITextureLineComponentP
 
         const previewCanvas = this.refs.canvas as HTMLCanvasElement;
 
-        this.props.globalState.blockMutationUpdates = true;
+        if(this.props.globalState){
+            this.props.globalState.blockMutationUpdates = true;
+        }
+        
         let rtt = new RenderTargetTexture(
             "temp",
             { width: width, height: height },
@@ -156,7 +165,10 @@ export class TextureLineComponent extends React.Component<ITextureLineComponentP
         passPostProcess.dispose();
 
         previewCanvas.style.height = height + "px";
-        this.props.globalState.blockMutationUpdates = false;
+        if(this.props.globalState){
+            this.props.globalState.blockMutationUpdates = false;
+        }
+        
     }
 
     render() {
@@ -165,7 +177,7 @@ export class TextureLineComponent extends React.Component<ITextureLineComponentP
         return (
             <div className="textureLine">
                 {
-                    texture.isCube &&
+                    !this.props.hideChannelSelect && texture.isCube &&
                     <div className="control3D">
                         <button className={this.state.face === 0 ? "px command selected" : "px command"} onClick={() => this.setState({ face: 0 })}>PX</button>
                         <button className={this.state.face === 1 ? "nx command selected" : "nx command"} onClick={() => this.setState({ face: 1 })}>NX</button>
@@ -176,7 +188,7 @@ export class TextureLineComponent extends React.Component<ITextureLineComponentP
                     </div>
                 }
                 {
-                    !texture.isCube &&
+                    !this.props.hideChannelSelect && !texture.isCube &&
                     <div className="control">
                         <button className={this.state.displayRed && !this.state.displayGreen ? "red command selected" : "red command"} onClick={() => this.setState({ displayRed: true, displayGreen: false, displayBlue: false, displayAlpha: false })}>R</button>
                         <button className={this.state.displayGreen && !this.state.displayBlue ? "green command selected" : "green command"} onClick={() => this.setState({ displayRed: false, displayGreen: true, displayBlue: false, displayAlpha: false })}>G</button>

+ 12 - 0
inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx

@@ -85,6 +85,8 @@ import { SpotLight } from 'babylonjs/Lights/spotLight';
 import { SpotLightPropertyGridComponent } from './propertyGrids/lights/spotLightPropertyGridComponent';
 import { LensRenderingPipeline } from 'babylonjs/PostProcesses/RenderPipeline/Pipelines/lensRenderingPipeline';
 import { LensRenderingPipelinePropertyGridComponent } from './propertyGrids/postProcesses/lensRenderingPipelinePropertyGridComponent';
+import { NodeMaterial } from 'babylonjs/Materials/Node/nodeMaterial';
+import { NodeMaterialPropertyGridComponent } from './propertyGrids/materials/nodeMaterialPropertyGridComponent';
 
 export class PropertyGridTabComponent extends PaneComponent {
     private _timerIntervalId: number;
@@ -213,6 +215,16 @@ export class PropertyGridTabComponent extends PaneComponent {
                     onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
             }
 
+            if (className === "NodeMaterial") {
+                const material = entity as NodeMaterial;
+                return (<NodeMaterialPropertyGridComponent
+                    globalState={this.props.globalState}
+                    material={material}
+                    lockObject={this._lockObject}
+                    onSelectionChangedObservable={this.props.onSelectionChangedObservable}
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
+            }
+
             if (className === "PBRMaterial") {
                 const material = entity as PBRMaterial;
                 return (<PBRMaterialPropertyGridComponent

+ 1 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/cameras/freeCameraPropertyGridComponent.tsx

@@ -37,7 +37,7 @@ export class FreeCameraPropertyGridComponent extends React.Component<IFreeCamera
                 </LineContainerComponent>
                 <LineContainerComponent globalState={this.props.globalState} title="COLLISIONS" closed={true}>
                     <CheckBoxLineComponent label="Check collisions" target={camera} propertyName="checkCollisions" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <CheckBoxLineComponent label="Apply gravity" target={camera} propertyName="applYGravity" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <CheckBoxLineComponent label="Apply gravity" target={camera} propertyName="applyGravity" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <Vector3LineComponent label="Ellipsoid" target={camera} propertyName="ellipsoid" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <Vector3LineComponent label="Ellipsoid offset" target={camera} propertyName="ellipsoidOffset" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>

+ 1 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/lights/commonShadowLightPropertyGridComponent.tsx

@@ -76,7 +76,7 @@ export class CommonShadowLightPropertyGridComponent extends React.Component<ICom
                 {
                     generator !== null &&
                     <LineContainerComponent globalState={this.props.globalState} title="SHADOW GENERATOR">
-                        <FloatLineComponent lockObject={this.props.lockObject} label="Bias" target={generator} propertyName="bias" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                        <FloatLineComponent lockObject={this.props.lockObject} digits={4} step="0.0001" label="Bias" target={generator} propertyName="bias" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         <FloatLineComponent lockObject={this.props.lockObject} label="Normal bias" target={generator} propertyName="normalBias" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         <SliderLineComponent label="Darkness" target={generator} minimum={0} maximum={1} step={0.01} propertyName="darkness" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         <CheckBoxLineComponent label="Allow transparent shadows" target={generator} propertyName="transparencyShadow" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />

+ 42 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/materials/nodeMaterialPropertyGridComponent.tsx

@@ -0,0 +1,42 @@
+import * as React from "react";
+
+import { Observable } from "babylonjs/Misc/observable";
+import { NodeMaterial } from "babylonjs/Materials/Node/nodeMaterial";
+
+import { PropertyChangedEvent } from "../../../../propertyChangedEvent";
+import { LineContainerComponent } from "../../../lineContainerComponent";
+import { CommonMaterialPropertyGridComponent } from "./commonMaterialPropertyGridComponent";
+import { LockObject } from "../lockObject";
+import { GlobalState } from '../../../../globalState';
+import { ButtonLineComponent } from '../../../lines/buttonLineComponent';
+
+interface INodeMaterialPropertyGridComponentProps {
+    globalState: GlobalState;
+    material: NodeMaterial;
+    lockObject: LockObject;
+    onSelectionChangedObservable?: Observable<any>;
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
+}
+
+export class NodeMaterialPropertyGridComponent extends React.Component<INodeMaterialPropertyGridComponentProps> {
+    constructor(props: INodeMaterialPropertyGridComponentProps) {
+        super(props);
+    }
+
+    edit() {
+        this.props.material.edit();
+    }
+
+    render() {
+        const material = this.props.material;
+
+        return (
+            <div className="pane">
+                <CommonMaterialPropertyGridComponent globalState={this.props.globalState} lockObject={this.props.lockObject} material={material} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <LineContainerComponent globalState={this.props.globalState} title="EDITOR">
+                    <ButtonLineComponent label="Edit" onClick={() => this.edit()} />
+                </LineContainerComponent>
+            </div>
+        );
+    }
+}

+ 1 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrMaterialPropertyGridComponent.tsx

@@ -45,6 +45,7 @@ export class PBRMaterialPropertyGridComponent extends React.Component<IPBRMateri
                 <TextureLinkLineComponent label="Opacity" texture={material.opacityTexture} propertyName="opacityTexture" material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
                 <TextureLinkLineComponent label="Ambient" texture={material.ambientTexture} propertyName="ambientTexture" material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
                 <TextureLinkLineComponent label="Lightmap" texture={material.lightmapTexture} propertyName="lightmapTexture" material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
+                <CheckBoxLineComponent label="Use lightmap as shadowmap" target={material} propertyName="useLightmapAsShadowmap " onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
             </LineContainerComponent>
         );
     }

+ 2 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/materials/standardMaterialPropertyGridComponent.tsx

@@ -12,6 +12,7 @@ import { CommonMaterialPropertyGridComponent } from "./commonMaterialPropertyGri
 import { TextureLinkLineComponent } from "../../../lines/textureLinkLineComponent";
 import { LockObject } from "../lockObject";
 import { GlobalState } from '../../../../globalState';
+import { CheckBoxLineComponent } from '../../../lines/checkBoxLineComponent';
 
 interface IStandardMaterialPropertyGridComponentProps {
     globalState: GlobalState;
@@ -44,6 +45,7 @@ export class StandardMaterialPropertyGridComponent extends React.Component<IStan
                 <TextureLinkLineComponent label="Opacity" texture={material.opacityTexture} propertyName="opacityTexture" material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
                 <TextureLinkLineComponent label="Ambient" texture={material.ambientTexture} propertyName="ambientTexture" material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
                 <TextureLinkLineComponent label="Lightmap" texture={material.lightmapTexture} propertyName="lightmapTexture" material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
+                <CheckBoxLineComponent label="Use lightmap as shadowmap" target={material} propertyName="useLightmapAsShadowmap " onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
             </LineContainerComponent>
         );
     }

+ 22 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/meshes/meshPropertyGridComponent.tsx

@@ -22,6 +22,7 @@ import { GlobalState } from '../../../../globalState';
 import { CustomPropertyGridComponent } from '../customPropertyGridComponent';
 import { StandardMaterial } from 'babylonjs/Materials/standardMaterial';
 import { Color3LineComponent } from '../../../lines/color3LineComponent';
+import { MorphTarget } from 'babylonjs/Morph/morphTarget';
 
 interface IMeshPropertyGridComponentProps {
     globalState: GlobalState;
@@ -209,6 +210,14 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
         const renderNormalVectors = (mesh.reservedDataStore && mesh.reservedDataStore.normalLines) ? true : false;
         const renderWireframeOver = (mesh.reservedDataStore && mesh.reservedDataStore.wireframeOver) ? true : false;
 
+        var morphTargets: MorphTarget[] = [];
+
+        if (mesh.morphTargetManager) {
+            for (var index = 0; index < mesh.morphTargetManager.numTargets; index++) {
+                morphTargets.push(mesh.morphTargetManager.getTarget(index));
+            }
+        }
+
         return (
             <div className="pane">
                 <CustomPropertyGridComponent globalState={this.props.globalState} target={mesh}
@@ -264,6 +273,19 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
                         <CheckBoxLineComponent label="Infinite distance" target={mesh} propertyName="infiniteDistance" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     }
                 </LineContainerComponent>
+                {
+                    mesh.morphTargetManager != null &&
+                    <LineContainerComponent globalState={this.props.globalState} title="MORPH TARGETS" closed={true}>
+                        {
+                            morphTargets.map((mt, i) => {
+                                return (
+                                    <SliderLineComponent label={mt.name} target={mt} propertyName="influence" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                                )
+                            })
+                        }
+                    </LineContainerComponent>
+
+                }
                 <LineContainerComponent globalState={this.props.globalState} title="ADVANCED" closed={true}>
                     {
                         mesh.useBones &&

+ 21 - 0
inspector/src/components/sceneExplorer/sceneExplorerComponent.tsx

@@ -17,6 +17,7 @@ import { Vector3 } from 'babylonjs/Maths/math';
 import { PointLight } from 'babylonjs/Lights/pointLight';
 import { FreeCamera } from 'babylonjs/Cameras/freeCamera';
 import { DirectionalLight } from 'babylonjs/Lights/directionalLight';
+import { SSAORenderingPipeline } from 'babylonjs/PostProcesses/RenderPipeline/Pipelines/ssaoRenderingPipeline';
 
 require("./sceneExplorer.scss");
 
@@ -246,6 +247,26 @@ export class SceneExplorerComponent extends React.Component<ISceneExplorerCompon
                     }
                 });
             }
+
+            if (!pipelines.some(p => p.getClassName() === "SSAORenderingPipeline")) {
+                pipelineContextMenus.push({
+                    label: "Add new SSAO Rendering Pipeline",
+                    action: () => {
+                        let newPipeline = new SSAORenderingPipeline("SSAO rendering pipeline", scene, 1, [scene.activeCamera!]);
+                        this.props.globalState.onSelectionChangedObservable.notifyObservers(newPipeline);
+                    }
+                });
+            }
+
+            if (scene.getEngine().webGLVersion > 1 && !pipelines.some(p => p.getClassName() === "SSAORenderingPipeline")) {
+                pipelineContextMenus.push({
+                    label: "Add new SSAO2 Rendering Pipeline",
+                    action: () => {
+                        let newPipeline = new SSAORenderingPipeline("SSAO2 rendering pipeline", scene, 1, [scene.activeCamera!]);
+                        this.props.globalState.onSelectionChangedObservable.notifyObservers(newPipeline);
+                    }
+                });
+            }
         }
 
         let nodeContextMenus: { label: string, action: () => void }[] = [];

+ 0 - 0
inspector/src/index.css


+ 0 - 2
inspector/src/index.ts

@@ -1,3 +1 @@
-require("./index.css");
-
 export * from "./inspector";

+ 25 - 20
inspector/src/inspector.ts

@@ -48,22 +48,27 @@ export class Inspector {
     private static _CopyStyles(sourceDoc: HTMLDocument, targetDoc: HTMLDocument) {
         for (var index = 0; index < sourceDoc.styleSheets.length; index++) {
             var styleSheet: any = sourceDoc.styleSheets[index];
-            if (styleSheet.cssRules) { // for <style> elements
-                const newStyleEl = sourceDoc.createElement('style');
-
-                for (var cssRule of styleSheet.cssRules) {
-                    // write the text of each rule into the body of the style element
-                    newStyleEl.appendChild(sourceDoc.createTextNode(cssRule.cssText));
+            try{
+                if (styleSheet.cssRules) { // for <style> elements
+                    const newStyleEl = sourceDoc.createElement('style');
+    
+                    for (var cssRule of styleSheet.cssRules) {
+                        // write the text of each rule into the body of the style element
+                        newStyleEl.appendChild(sourceDoc.createTextNode(cssRule.cssText));
+                    }
+    
+                    targetDoc.head!.appendChild(newStyleEl);
+                } else if (styleSheet.href) { // for <link> elements loading CSS from a URL
+                    const newLinkEl = sourceDoc.createElement('link');
+    
+                    newLinkEl.rel = 'stylesheet';
+                    newLinkEl.href = styleSheet.href;
+                    targetDoc.head!.appendChild(newLinkEl);
                 }
-
-                targetDoc.head!.appendChild(newStyleEl);
-            } else if (styleSheet.href) { // for <link> elements loading CSS from a URL
-                const newLinkEl = sourceDoc.createElement('link');
-
-                newLinkEl.rel = 'stylesheet';
-                newLinkEl.href = styleSheet.href;
-                targetDoc.head!.appendChild(newLinkEl);
+            }catch(e){
+                console.log(e)
             }
+            
         }
     }
 
@@ -250,12 +255,12 @@ export class Inspector {
             ReactDOM.render(embedHostElement, this._EmbedHost);
         }
     }
-    private static _CreatePopup(title: string, windowVariableName: string) {
+    public static _CreatePopup(title: string, windowVariableName: string, width = 300, height = 800) {
         const windowCreationOptionsList = {
-            width: 300,
-            height: 800,
-            top: (window.innerHeight - 800) / 2 + window.screenY,
-            left: (window.innerWidth - 300) / 2 + window.screenX
+            width: width,
+            height: height,
+            top: (window.innerHeight - width) / 2 + window.screenY,
+            left: (window.innerWidth - height) / 2 + window.screenX
         };
 
         var windowCreationOptions = Object.keys(windowCreationOptionsList)
@@ -410,7 +415,7 @@ export class Inspector {
         }
     }
 
-    private static _CreateCanvasContainer(parentControl: HTMLElement) {
+    public static _CreateCanvasContainer(parentControl: HTMLElement) {
         // Create a container for previous elements
         this._NewCanvasContainer = parentControl.ownerDocument!.createElement("div");
         this._NewCanvasContainer.style.display = parentControl.style.display;

BIN
inspector/test/environment.dds


BIN
inspector/test/explosion.wav


+ 0 - 91
inspector/test/index.js

@@ -1,91 +0,0 @@
-/// <reference path="../../dist/preview release/babylon.d.ts"/>
-
-var Test = (function() {
-    function Test(canvasId) {
-        var _this = this;
-        var canvas = document.getElementById(canvasId);
-        this.engine = new BABYLON.Engine(canvas, true);
-        this.scene = null;
-        window.addEventListener("resize", function() {
-            _this.engine.resize();
-        });
-        this._run();
-    }
-    Test.prototype._run = function() {
-        var _this = this;
-        this._initScene();
-        this.scene.executeWhenReady(function() {
-            _this.engine.runRenderLoop(function() {
-                _this.scene.render();
-            });
-        });
-    };
-    Test.prototype._initScene = function() {
-        var scene = new BABYLON.Scene(this.engine);
-        var canvas = scene.getEngine().getRenderingCanvas();
-
-        var camera = new BABYLON.FreeCamera("Camera", new BABYLON.Vector3(0, 2, -2), scene);
-
-        var camera2 = new BABYLON.ArcRotateCamera("Camera2", 0, 0, 5, new BABYLON.Vector3(0, 0, 0), scene);
-
-        var camera3 = new BABYLON.ArcRotateCamera("Camera3", 0, 0, 10, new BABYLON.Vector3(0, 0, 0), scene);
-
-        var camera4 = new BABYLON.ArcRotateCamera("Camera4", 0, 0, 15, new BABYLON.Vector3(0, 0, 0), scene);
-
-        var camera5 = new BABYLON.ArcRotateCamera("Camera5", 0, 0, 20, new BABYLON.Vector3(0, 0, 0), scene);
-
-        var camera6 = new BABYLON.ArcRotateCamera("Camera6", 0, 0, 25, new BABYLON.Vector3(0, 0, 0), scene);
-
-        scene.activeCamera = camera2;
-
-        camera2.attachControl(canvas);
-
-        var sceneRoot = new BABYLON.TransformNode("abstractmesh");
-
-        var tn = new BABYLON.TransformNode("transform node");
-
-        let DDSTexture = new BABYLON.CubeTexture("test/environment.dds", scene);
-        let DDSTexture2 = new BABYLON.Texture("test/test_1.dds", scene);
-
-        // Our built-in 'ground' shape. Params: name, width, depth, subdivs, scene
-        var ground = BABYLON.Mesh.CreateGround("node_damagedHelmet_-6514", 6, 6, 2, scene);
-        ground.parent = tn;
-
-        let num = 5;
-        let angStep = 6.283185307 / num;
-        let rad = 2;
-        let p = sceneRoot;
-        for (let i = 0; i < num; i++) {
-            // Our built-in 'sphere' shape. Params: name, subdivs, size, scene
-            let sphere = BABYLON.Mesh.CreateSphere('sphere' + i, 16, 2, scene);
-
-            // Move the sphere upward 1/2 its height        
-            sphere.position.y = 0.2;
-            sphere.position.x = Math.sin(i * angStep) * rad;
-            sphere.position.z = Math.cos(i * angStep) * rad;
-            sphere.parent = p;
-            p = sphere;
-        }
-
-        let t = 0;
-        scene.registerBeforeRender(() => {
-            ground.rotation.y += 0.01;
-            ground.position.y = Math.cos(t += 0.01);
-        });
-
-        scene.createDefaultCameraOrLight(true);
-        scene.activeCamera.attachControl(canvas);
-        
-        scene.debugLayer.show({embedMode: true});
-        //scene.debugLayer.show();
-        scene.debugLayer.onPropertyChangedObservable.add((result) => {
-            console.log(result.object);
-            console.log("Property : " + result.property);
-            console.log("New value : " + result.value);
-            console.log("Old value : " + result.initialValue);
-        });
-
-        this.scene = scene;
-    };
-    return Test;
-}());

BIN
inspector/test/jump.wav


BIN
inspector/test/test_1.dds


+ 13 - 9
loaders/src/glTF/2.0/glTFLoader.ts

@@ -852,10 +852,10 @@ export class GLTFLoader implements IGLTFLoader {
             throw new Error(`${context}: Primitives do not have the same number of targets`);
         }
 
-        babylonMesh.morphTargetManager = new MorphTargetManager();
+        babylonMesh.morphTargetManager = new MorphTargetManager(babylonMesh.getScene());
         for (let index = 0; index < primitive.targets.length; index++) {
             const weight = node.weights ? node.weights[index] : mesh.weights ? mesh.weights[index] : 0;
-            babylonMesh.morphTargetManager.addTarget(new MorphTarget(`morphTarget${index}`, weight));
+            babylonMesh.morphTargetManager.addTarget(new MorphTarget(`morphTarget${index}`, weight, babylonMesh.getScene()));
             // TODO: tell the target whether it has positions, normals, tangents
         }
     }
@@ -896,32 +896,36 @@ export class GLTFLoader implements IGLTFLoader {
         };
 
         loadAttribute("POSITION", VertexBuffer.PositionKind, (babylonVertexBuffer, data) => {
+            const positions = new Float32Array(data.length);
             babylonVertexBuffer.forEach(data.length, (value, index) => {
-                data[index] += value;
+                positions[index] = data[index] + value;
             });
 
-            babylonMorphTarget.setPositions(data);
+            babylonMorphTarget.setPositions(positions);
         });
 
         loadAttribute("NORMAL", VertexBuffer.NormalKind, (babylonVertexBuffer, data) => {
-            babylonVertexBuffer.forEach(data.length, (value, index) => {
-                data[index] += value;
+            const normals = new Float32Array(data.length);
+            babylonVertexBuffer.forEach(normals.length, (value, index) => {
+                normals[index] = data[index] + value;
             });
 
-            babylonMorphTarget.setNormals(data);
+            babylonMorphTarget.setNormals(normals);
         });
 
         loadAttribute("TANGENT", VertexBuffer.TangentKind, (babylonVertexBuffer, data) => {
+            const tangents = new Float32Array(data.length / 3 * 4);
             let dataIndex = 0;
             babylonVertexBuffer.forEach(data.length / 3 * 4, (value, index) => {
                 // Tangent data for morph targets is stored as xyz delta.
                 // The vertexData.tangent is stored as xyzw.
                 // So we need to skip every fourth vertexData.tangent.
                 if (((index + 1) % 4) !== 0) {
-                    data[dataIndex++] += value;
+                    tangents[dataIndex] = data[dataIndex] + value;
+                    dataIndex++;
                 }
             });
-            babylonMorphTarget.setTangents(data);
+            babylonMorphTarget.setTangents(tangents);
         });
 
         return Promise.all(promises).then(() => { });

+ 1 - 0
nodeEditor/README-ES6.md

@@ -0,0 +1 @@
+Node Editor

+ 18 - 0
nodeEditor/README.md

@@ -0,0 +1,18 @@
+# Babylon.js Node Editor
+
+An extension to easily create or update any NodeMaterial.
+
+## Usage
+### Online method
+Call the method `Show` of the `BABYLON.NoteMaterial` class: 
+```
+BABYLON.NoteMaterial.Show({hostElement: document.getElementById("host")});
+```
+This method will retrieve dynamically the library `nodeEditor.js`, download it and add
+it to the html page.
+
+### Offline method
+If you don't have access to internet, the node editor should be imported manually in your HTML page :
+```
+<script src="babylon.nodeEditor.js" />
+``` 

+ 95 - 0
nodeEditor/src/components/diagram/defaultNodeModel.ts

@@ -0,0 +1,95 @@
+import { NodeModel, DiagramModel } from "storm-react-diagrams";
+import { Nullable } from 'babylonjs/types';
+import { NodeMaterialBlock } from 'babylonjs/Materials/Node/nodeMaterialBlock';
+import { NodeMaterialBlockConnectionPointTypes } from 'babylonjs/Materials/Node/nodeMaterialBlockConnectionPointTypes';
+import { GraphEditor, NodeCreationOptions } from '../../graphEditor';
+import { GlobalState } from '../../globalState';
+import { DefaultPortModel } from './defaultPortModel';
+
+/**
+ * Generic node model which stores information about a node editor block
+ */
+export class DefaultNodeModel extends NodeModel {
+	/**
+	 * The babylon block this node represents
+	 */
+    public block: Nullable<NodeMaterialBlock> = null;
+
+    public ports: { [s: string]: DefaultPortModel };
+
+	/**
+	 * Constructs the node model
+	 */
+    constructor(key: string) {
+        super(key);
+    }
+
+    prepare(options: NodeCreationOptions, nodes: Array<DefaultNodeModel>, model: DiagramModel, graphEditor: GraphEditor, filterInputs: string[]) {
+        this.block = options.nodeMaterialBlock || null;
+
+        if (!options.nodeMaterialBlock) {
+            return;
+        }
+        // Create output ports
+        options.nodeMaterialBlock._outputs.forEach((connection: any) => {
+            var outputPort = new DefaultPortModel(connection.name, "output");
+            outputPort.syncWithNodeMaterialConnectionPoint(connection);
+            this.addPort(outputPort)
+        })
+
+        // Create input ports and nodes if they exist
+        options.nodeMaterialBlock._inputs.forEach((connection) => {
+            if (filterInputs.length > 0 && filterInputs.indexOf(connection.name) === -1) {
+                return;
+            }
+
+            var inputPort = new DefaultPortModel(connection.name, "input");
+            inputPort.connection = connection;
+            this.addPort(inputPort)
+
+            console.log(connection.name + " for " + options.nodeMaterialBlock!.name)
+
+            if (connection.connectedPoint) {
+                // Block is not a leaf node, create node for the given block type
+                var connectedNode;
+                var existingNodes = nodes.filter((n) => { return n.block === (connection as any)._connectedPoint._ownerBlock });
+                if (existingNodes.length == 0) {
+                    connectedNode = graphEditor.createNodeFromObject({ column: options.column + 1, nodeMaterialBlock: connection.connectedPoint._ownerBlock });
+                } else {
+                    connectedNode = existingNodes[0];
+                }
+
+                let link = connectedNode.ports[connection.connectedPoint.name].link(inputPort);
+                model.addAll(link);
+            } else {
+                // Create value node for the connection
+                var type = ""
+                if (connection.type == NodeMaterialBlockConnectionPointTypes.Texture) {
+                    type = "Texture"
+                } else if (connection.type == NodeMaterialBlockConnectionPointTypes.Matrix) {
+                    type = "Matrix"
+                } else if (connection.type & NodeMaterialBlockConnectionPointTypes.Vector3OrColor3) {
+                    type = "Vector3"
+                } else if (connection.type & NodeMaterialBlockConnectionPointTypes.Vector2) {
+                    type = "Vector2"
+                } else if (connection.type & NodeMaterialBlockConnectionPointTypes.Vector3OrColor3OrVector4OrColor4) {
+                    type = "Vector4"
+                }
+
+                // Create links
+                var localNode = graphEditor.addValueNode(type, options.column + 1, connection);
+                if (localNode) {
+                    var ports = localNode.getPorts()
+                    for (var key in ports) {
+                        let link = (ports[key] as DefaultPortModel).link(inputPort);
+                        model.addAll(link);
+                    }
+                }
+            }
+        });
+    }
+
+    renderProperties(globalState: GlobalState): JSX.Element | null {
+        return null;
+    }
+}

+ 73 - 0
nodeEditor/src/components/diagram/defaultPortModel.ts

@@ -0,0 +1,73 @@
+import { LinkModel, PortModel, DefaultLinkModel } from "storm-react-diagrams";
+import { Nullable } from 'babylonjs/types';
+import { NodeMaterialConnectionPoint } from 'babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint';
+import { DefaultNodeModel } from './defaultNodeModel';
+
+/**
+ * Port model
+ */
+export class DefaultPortModel extends PortModel {
+	/**
+	 * If the port is input or output
+	 */
+    public position: string | "input" | "output";
+	/**
+	 * What the port is connected to
+	 */
+    public connection: Nullable<NodeMaterialConnectionPoint> = null;
+
+
+    static idCounter = 0;
+
+    constructor(name: string, type: string = "input") {
+        super(name, "generic");
+        this.position = type;
+        DefaultPortModel.idCounter++;
+    }
+
+    syncWithNodeMaterialConnectionPoint(connection: NodeMaterialConnectionPoint) {
+        this.connection = connection;
+        this.name = connection.name;
+    }
+
+    getNodeModel() {
+        return this.parent as DefaultNodeModel
+    }
+
+    link(outPort: DefaultPortModel) {
+        var link = this.createLinkModel()
+        link.setSourcePort(this)
+        link.setTargetPort(outPort)
+        return link;
+    }
+
+    getInputFromBlock() {
+
+    }
+
+    createLinkModel(): LinkModel {
+        return new DefaultLinkModel();
+    }
+
+    getValue: Function = () => {
+        return null;
+    }
+
+    static SortInputOutput(a: Nullable<DefaultPortModel>, b: Nullable<DefaultPortModel>) {
+        if (!a || !b) {
+            return null;
+        } else if (a.position == "output" && b.position == "input") {
+            return {
+                input: b,
+                output: a
+            }
+        } else if (b.position == "output" && a.position == "input") {
+            return {
+                input: a,
+                output: b
+            }
+        } else {
+            return null;
+        }
+    }
+}

+ 94 - 0
nodeEditor/src/components/diagram/diagram.scss

@@ -0,0 +1,94 @@
+.diagramBlock {
+    background: white;
+    width: 200px;
+    border: 4px solid black;
+
+    &.input {
+        background: green;
+        color:white;
+    }
+
+    &.attribute {
+        background: orange;
+    }
+
+    &.output {
+        background: blue;
+        color:white;
+
+        .inputs { 
+            color:white;
+        }
+    }
+
+    .header {
+        margin: 10px;
+        font-size: 16px;
+        text-align: center;
+        
+        white-space: nowrap;
+        text-overflow: ellipsis;
+        overflow: hidden;
+    }
+
+    .value {
+        height: 34px;
+        text-align: center;
+        font-size: 20px;
+        font-weight: bold;
+    }
+
+    .inputs {
+        .input-port {
+            display: grid;
+            grid-template-columns: 4px calc(100% - 4px);
+            grid-template-rows: 100%;
+
+            .input-port-plug {
+                grid-column: 1;
+                grid-row: 1;
+                display: grid;
+                align-content: center;
+                margin-left: -11px;
+                
+                .srd-port {
+                    background: grey;
+                }
+            }
+
+            .input-port-label {
+                margin-left: 10px;
+                grid-column: 2;
+                grid-row: 1;         
+                margin-bottom: 2px;       
+            }
+        }
+    }
+
+    .outputs {
+        .output-port {
+            display: grid;
+            grid-template-columns: calc(100% - 4px) 4px;
+            grid-template-rows: 100%;
+
+            .output-port-plug {
+                grid-column: 2;
+                grid-row: 1;
+                display: grid;
+                align-content: center;
+
+                .srd-port {
+                    background: grey;
+                }
+            }
+
+            .output-port-label {
+                text-align: right;
+                margin-right: 10px;
+                grid-column: 1;
+                grid-row: 1;                        
+                margin-bottom: 2px;        
+            }
+        }
+    }
+}

+ 39 - 0
nodeEditor/src/components/diagram/generic/genericNodeFactory.tsx

@@ -0,0 +1,39 @@
+import * as SRD from "storm-react-diagrams";
+import { GenericNodeWidget } from "./genericNodeWidget";
+import { GenericNodeModel } from "./genericNodeModel";
+import * as React from "react";
+import { GlobalState } from '../../../globalState';
+
+/**
+ * Node factory which creates editor nodes
+ */
+export class GenericNodeFactory extends SRD.AbstractNodeFactory {
+    private _globalState: GlobalState;
+
+	/**
+	 * Constructs a GenericNodeFactory
+	 */
+    constructor(globalState: GlobalState) {
+        super("generic");
+
+        this._globalState = globalState;
+    }
+
+	/**
+	 * Generates a node widget
+	 * @param diagramEngine diagram engine
+	 * @param node node to generate
+	 * @returns node widget jsx
+	 */
+    generateReactWidget(diagramEngine: SRD.DiagramEngine, node: GenericNodeModel): JSX.Element {
+        return <GenericNodeWidget node={node} globalState={this._globalState} />;
+    }
+
+	/**
+	 * Gets a new instance of a node model
+	 * @returns generic node model
+	 */
+    getNewInstance() {
+        return new GenericNodeModel();
+    }
+}

+ 58 - 0
nodeEditor/src/components/diagram/generic/genericNodeModel.tsx

@@ -0,0 +1,58 @@
+import * as React from "react";
+import { Nullable } from 'babylonjs/types';
+import { Vector2, Vector3, Vector4, Matrix } from 'babylonjs/Maths/math';
+import { DefaultNodeModel } from '../defaultNodeModel';
+import { DiagramModel } from 'storm-react-diagrams/dist/@types/src/models/DiagramModel';
+import { GraphEditor, NodeCreationOptions } from '../../../graphEditor';
+import { GlobalState } from '../../../globalState';
+import { TextLineComponent } from '../../../sharedComponents/textLineComponent';
+
+/**
+ * Generic node model which stores information about a node editor block
+ */
+export class GenericNodeModel extends DefaultNodeModel {
+	/**
+	 * Labels for the block
+	 */
+    public header = "";
+	/**
+	 * Vector2 for the node if it exists
+	 */
+    public vector2: Nullable<Vector2> = null;
+	/**
+	 * Vector3 for the node if it exists
+	 */
+    public vector3: Nullable<Vector3> = null;
+	/**
+	 * Vector4 for the node if it exists
+	 */
+    public vector4: Nullable<Vector4> = null;
+	/**
+	 * Matrix for the node if it exists
+	 */
+    public matrix: Nullable<Matrix> = null;
+
+	/**
+	 * Constructs the node model
+	 */
+    constructor() {
+        super("generic");
+    }
+
+    prepare(options: NodeCreationOptions, nodes: Array<DefaultNodeModel>, model: DiagramModel, graphEditor: GraphEditor, filterInputs: string[]) {
+        if (options.nodeMaterialBlock) {
+            this.header = options.nodeMaterialBlock.name;
+        }
+
+        super.prepare(options, nodes, model, graphEditor, filterInputs);
+    }
+
+    renderProperties(globalState: GlobalState) {
+
+        return (
+            <div>
+                <TextLineComponent label="Type" value={this.block!.getClassName()} />
+            </div>
+        );
+    }
+}

+ 98 - 0
nodeEditor/src/components/diagram/generic/genericNodeWidget.tsx

@@ -0,0 +1,98 @@
+import * as React from "react";
+import { PortWidget } from "storm-react-diagrams";
+import { DefaultPortModel } from '../defaultPortModel';
+import { Nullable } from 'babylonjs/types';
+import { GlobalState } from '../../../globalState';
+import { GenericNodeModel } from './genericNodeModel';
+
+/**
+ * GenericNodeWidgetProps
+ */
+export interface GenericNodeWidgetProps {
+    node: Nullable<GenericNodeModel>;
+    globalState: GlobalState;
+}
+
+/**
+ * GenericNodeWidgetState
+ */
+export interface GenericNodeWidgetState {
+
+}
+
+/**
+ * Used to display a node block for the node editor
+ */
+export class GenericNodeWidget extends React.Component<GenericNodeWidgetProps, GenericNodeWidgetState> {
+	/**
+	 * Creates a GenericNodeWidget
+	 * @param props 
+	 */
+    constructor(props: GenericNodeWidgetProps) {
+        super(props);
+        this.state = {};
+
+        if (this.props.node) {
+            this.props.node.addListener({
+                selectionChanged: () => {
+                    let selected = (this.props.node as any).selected;
+                    this.props.globalState.onSelectionChangedObservable.notifyObservers(selected ? this.props.node : null);
+                }
+            });
+        }
+    }
+
+    render() {
+        var header = "";
+        var inputPorts = new Array<JSX.Element>()
+        var outputPorts = new Array<JSX.Element>()
+        if (this.props.node) {
+            // Header label
+            if (this.props.node.header) {
+                header = this.props.node.header;
+            }
+
+            // Input/Output ports
+            for (var key in this.props.node.ports) {
+                var port = this.props.node.ports[key] as DefaultPortModel;
+                if (port.position === "input") {
+                    inputPorts.push(
+                        <div key={key} className="input-port">
+                            <div className="input-port-plug">
+                                <PortWidget key={key} name={port.name} node={this.props.node} />
+                            </div>
+                            <div className="input-port-label">
+                                {port.name}
+                            </div>
+                        </div>
+                    )
+                } else {
+                    outputPorts.push(
+                        <div key={key} className="output-port">
+                            <div className="output-port-label">
+                                {port.name}
+                            </div>
+                            <div className="output-port-plug">
+                                <PortWidget key={key} name={port.name} node={this.props.node} />
+                            </div>
+                        </div>
+                    )
+                }
+            }
+        }
+
+        return (
+            <div className={"diagramBlock" + (outputPorts.length === 0 ? " output" : "")}>
+                <div className="header">
+                    {header}
+                </div>
+                <div className="inputs">
+                    {inputPorts}
+                </div>
+                <div className="outputs">
+                    {outputPorts}
+                </div>
+            </div>
+        );
+    }
+}

+ 39 - 0
nodeEditor/src/components/diagram/input/inputNodeFactory.tsx

@@ -0,0 +1,39 @@
+import * as SRD from "storm-react-diagrams";
+import * as React from "react";
+import { GlobalState } from '../../../globalState';
+import { InputNodeModel } from './inputNodeModel';
+import { InputNodeWidget } from './inputNodeWidget';
+
+/**
+ * Node factory which creates editor nodes
+ */
+export class InputNodeFactory extends SRD.AbstractNodeFactory {
+    private _globalState: GlobalState;
+
+	/**
+	 * Constructs a GenericNodeFactory
+	 */
+    constructor(globalState: GlobalState) {
+        super("input");
+
+        this._globalState = globalState;
+    }
+
+	/**
+	 * Generates a node widget
+	 * @param diagramEngine diagram engine
+	 * @param node node to generate
+	 * @returns node widget jsx
+	 */
+    generateReactWidget(diagramEngine: SRD.DiagramEngine, node: InputNodeModel): JSX.Element {
+        return <InputNodeWidget node={node} globalState={this._globalState} />;
+    }
+
+	/**
+	 * Gets a new instance of a node model
+	 * @returns input node model
+	 */
+    getNewInstance() {
+        return new InputNodeModel();
+    }
+}

+ 29 - 0
nodeEditor/src/components/diagram/input/inputNodeModel.tsx

@@ -0,0 +1,29 @@
+import * as React from "react";
+import { DefaultNodeModel } from '../defaultNodeModel';
+import { NodeMaterialConnectionPoint } from 'babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint';
+import { GlobalState } from '../../../globalState';
+import { InputPropertyTabComponentProps } from './inputNodePropertyComponent';
+
+/**
+ * Generic node model which stores information about a node editor block
+ */
+export class InputNodeModel extends DefaultNodeModel {
+    public connection?: NodeMaterialConnectionPoint;
+
+	/**
+	 * Constructs the node model
+	 */
+    constructor() {
+        super("input");
+    }
+
+    renderProperties(globalState: GlobalState) {
+        if (!this.connection) {
+            return null;
+        }
+
+        return (
+            <InputPropertyTabComponentProps globalState={globalState} inputNode={this} />
+        );
+    }
+}

+ 130 - 0
nodeEditor/src/components/diagram/input/inputNodePropertyComponent.tsx

@@ -0,0 +1,130 @@
+
+import * as React from "react";
+import { Vector2PropertyTabComponent } from '../../propertyTab/properties/vector2PropertyTabComponent';
+import { Vector3PropertyTabComponent } from '../../propertyTab/properties/vector3PropertyTabComponent';
+import { CheckBoxLineComponent } from '../../../sharedComponents/checkBoxLineComponent';
+import { GlobalState } from '../../../globalState';
+import { InputNodeModel } from './inputNodeModel';
+import { NodeMaterialBlockConnectionPointTypes } from 'babylonjs/Materials/Node/nodeMaterialBlockConnectionPointTypes';
+import { OptionsLineComponent } from '../../../sharedComponents/optionsLineComponent';
+import { NodeMaterialWellKnownValues } from 'babylonjs/Materials/Node/nodeMaterialWellKnownValues';
+import { Vector2, Vector3, Matrix } from 'babylonjs/Maths/math';
+
+interface IInputPropertyTabComponentProps {
+    globalState: GlobalState;
+    inputNode: InputNodeModel;
+}
+
+export class InputPropertyTabComponentProps extends React.Component<IInputPropertyTabComponentProps> {
+
+    constructor(props: IInputPropertyTabComponentProps) {
+        super(props)
+    }
+
+    renderValue(globalState: GlobalState) {
+        let connection = this.props.inputNode.connection!;
+        switch (connection.type) {
+            case NodeMaterialBlockConnectionPointTypes.Vector2:
+                return (
+                    <Vector2PropertyTabComponent globalState={globalState} connection={connection} />
+                );
+            case NodeMaterialBlockConnectionPointTypes.Vector3:
+            case NodeMaterialBlockConnectionPointTypes.Color3:
+            case NodeMaterialBlockConnectionPointTypes.Vector3OrColor3:
+                return (
+                    <Vector3PropertyTabComponent globalState={globalState} connection={connection} />
+                );
+        }
+        return null;
+    }
+
+    setDefaultValue() {
+        let connection = this.props.inputNode.connection!;
+        switch (connection.type) {
+            case NodeMaterialBlockConnectionPointTypes.Vector2:
+                connection.value = Vector2.Zero();
+                break;
+            case NodeMaterialBlockConnectionPointTypes.Vector3:
+            case NodeMaterialBlockConnectionPointTypes.Color3:
+            case NodeMaterialBlockConnectionPointTypes.Vector3OrColor3:
+                connection.value = Vector3.Zero();
+                break;
+            case NodeMaterialBlockConnectionPointTypes.Matrix:
+                connection.value = Matrix.Identity();
+                break;
+        }
+    }
+
+    render() {
+        let connection = this.props.inputNode.connection!;
+
+        var wellKnownOptions = [
+            { label: "World", value: NodeMaterialWellKnownValues.World },
+            { label: "WorldxView", value: NodeMaterialWellKnownValues.WorldView },
+            { label: "WorldxViewxProjection", value: NodeMaterialWellKnownValues.WorldViewProjection },
+            { label: "View", value: NodeMaterialWellKnownValues.View },
+            { label: "ViewxProjection", value: NodeMaterialWellKnownValues.ViewProjection },
+            { label: "Projection", value: NodeMaterialWellKnownValues.Projection },
+            { label: "Automatic", value: NodeMaterialWellKnownValues.Automatic },
+        ];
+
+        /**
+         * Gets the base math type of node material block connection point.
+         * @param type Type to parse.
+         */
+        function getBaseType(type: NodeMaterialBlockConnectionPointTypes): string {
+            switch (type) {
+                case NodeMaterialBlockConnectionPointTypes.Vector3OrColor3:
+                case NodeMaterialBlockConnectionPointTypes.Color3: {
+                    return NodeMaterialBlockConnectionPointTypes[NodeMaterialBlockConnectionPointTypes.Vector3];
+                }
+                case NodeMaterialBlockConnectionPointTypes.Vector4OrColor4:
+                case NodeMaterialBlockConnectionPointTypes.Vector3OrVector4:
+                case NodeMaterialBlockConnectionPointTypes.Color3OrColor4:
+                case NodeMaterialBlockConnectionPointTypes.Vector3OrColor3OrVector4OrColor4:
+                case NodeMaterialBlockConnectionPointTypes.Color4: {
+                    return NodeMaterialBlockConnectionPointTypes[NodeMaterialBlockConnectionPointTypes.Vector4];
+                }
+                default: {
+                    return NodeMaterialBlockConnectionPointTypes[type];
+                }
+            }
+        }
+
+        return (
+            <div>
+                <h1>{getBaseType(connection.type)}</h1>
+                <CheckBoxLineComponent label="Is mesh attribute" onSelect={value => {
+                    connection!.isAttribute = value;
+                    this.props.globalState.onRebuildRequiredObservable.notifyObservers();
+                    this.forceUpdate();
+                }} isSelected={() => connection!.isAttribute} />
+                {
+                    connection.isUniform &&
+                    <CheckBoxLineComponent label="Is well known value" onSelect={value => {
+                        if (value) {
+                            connection!.setAsWellKnownValue(NodeMaterialWellKnownValues.World);
+                        } else {
+                            connection!.setAsWellKnownValue(null);
+                            this.setDefaultValue();
+                        }
+                        this.props.globalState.onRebuildRequiredObservable.notifyObservers();
+                        this.forceUpdate();
+                    }} isSelected={() => connection!.isWellKnownValue} />
+                }
+                {
+                    connection.isUniform && !connection.isWellKnownValue &&
+                    this.renderValue(this.props.globalState)
+                }
+                {
+                    connection.isUniform && connection.isWellKnownValue &&
+                    <OptionsLineComponent label="Well known value" options={wellKnownOptions} target={connection} propertyName="wellKnownValue" onSelect={(value: any) => {
+                        connection.setAsWellKnownValue(value);
+                        this.forceUpdate();
+                        this.props.globalState.onRebuildRequiredObservable.notifyObservers();
+                    }} />
+                }
+            </div>
+        );
+    }
+}

+ 104 - 0
nodeEditor/src/components/diagram/input/inputNodeWidget.tsx

@@ -0,0 +1,104 @@
+import * as React from "react";
+import { PortWidget } from "storm-react-diagrams";
+import { InputNodeModel } from './inputNodeModel';
+import { Nullable } from 'babylonjs/types';
+import { GlobalState } from '../../../globalState';
+import { DefaultPortModel } from '../defaultPortModel';
+import { NodeMaterialWellKnownValues } from 'babylonjs/Materials/Node/nodeMaterialWellKnownValues';
+
+/**
+ * GenericNodeWidgetProps
+ */
+export interface InputNodeWidgetProps {
+    node: Nullable<InputNodeModel>;
+    globalState: GlobalState;
+}
+
+/**
+ * Used to display a node block for the node editor
+ */
+export class InputNodeWidget extends React.Component<InputNodeWidgetProps> {
+	/**
+	 * Creates a GenericNodeWidget
+	 * @param props 
+	 */
+    constructor(props: InputNodeWidgetProps) {
+        super(props);
+        this.state = {};
+
+        if (this.props.node) {
+            this.props.node.addListener({
+                selectionChanged: () => {
+                    let selected = (this.props.node as any).selected;
+                    this.props.globalState.onSelectionChangedObservable.notifyObservers(selected ? this.props.node : null);
+                }
+            });
+        }
+    }
+
+    render() {
+        var outputPorts = new Array<JSX.Element>()
+        let port: DefaultPortModel;
+        if (this.props.node) {
+            for (var key in this.props.node.ports) {
+                port = this.props.node.ports[key] as DefaultPortModel;
+
+                outputPorts.push(
+                    <div key={key} className="output-port">
+                        <div className="output-port-label">
+                        </div>
+                        <div className="output-port-plug">
+                            <PortWidget key={key} name={port.name} node={this.props.node} />
+                        </div>
+                    </div>
+                );
+                break;
+            }
+        }
+
+        let connection = this.props.node!.connection!;
+        let value = "";
+
+        if (connection.isAttribute) {
+            value = "mesh." + connection.name;
+        } else if (connection.isWellKnownValue) {
+            switch (connection.wellKnownValue) {
+                case NodeMaterialWellKnownValues.World:
+                    value = "World";
+                    break;
+                case NodeMaterialWellKnownValues.WorldView:
+                    value = "World x View";
+                    break;
+                case NodeMaterialWellKnownValues.WorldViewProjection:
+                    value = "World x View x Projection";
+                    break;
+                case NodeMaterialWellKnownValues.View:
+                    value = "View";
+                    break;
+                case NodeMaterialWellKnownValues.ViewProjection:
+                    value = "View x Projection";
+                    break;
+                case NodeMaterialWellKnownValues.Projection:
+                    value = "Projection";
+                    break;
+                case NodeMaterialWellKnownValues.Automatic:
+                    value = "Automatic";
+                    break;
+            }
+        }
+
+        return (
+            <div className={"diagramBlock input" + (connection.isAttribute ? " attribute" : "")}>
+                <div className="header">
+                    {port!.name}
+                </div>
+                <div className="outputs">
+                    {outputPorts}
+                </div>
+                <div className="value">
+                    {value}
+                </div>
+            </div>
+        );
+    }
+}

+ 39 - 0
nodeEditor/src/components/diagram/texture/textureNodeFactory.tsx

@@ -0,0 +1,39 @@
+import * as SRD from "storm-react-diagrams";
+import { TextureNodeWidget } from "./textureNodeWidget";
+import { TextureNodeModel } from "./textureNodeModel";
+import * as React from "react";
+import { GlobalState } from '../../../globalState';
+
+/**
+ * Node factory which creates editor nodes
+ */
+export class TextureNodeFactory extends SRD.AbstractNodeFactory {
+    private _globalState: GlobalState;
+
+	/**
+	 * Constructs a TextureNodeFactory
+	 */
+    constructor(globalState: GlobalState) {
+        super("texture");
+
+        this._globalState = globalState;
+    }
+
+	/**
+	 * Generates a node widget
+	 * @param diagramEngine diagram engine
+	 * @param node node to generate
+	 * @returns node widget jsx
+	 */
+    generateReactWidget(diagramEngine: SRD.DiagramEngine, node: TextureNodeModel): JSX.Element {
+        return <TextureNodeWidget node={node} globalState={this._globalState} />;
+    }
+
+	/**
+	 * Gets a new instance of a node model
+	 * @returns texture node model
+	 */
+    getNewInstance() {
+        return new TextureNodeModel();
+    }
+}

+ 40 - 0
nodeEditor/src/components/diagram/texture/textureNodeModel.tsx

@@ -0,0 +1,40 @@
+import * as React from 'react';
+import { Nullable } from 'babylonjs/types';
+import { Texture } from 'babylonjs/Materials/Textures/texture';
+import { DefaultNodeModel } from '../defaultNodeModel';
+import { GlobalState } from '../../../globalState';
+import { TexturePropertyTabComponent } from '../../../components/propertyTab/properties/texturePropertyTabComponent';
+import { NodeCreationOptions, GraphEditor } from '../../../graphEditor';
+import { DiagramModel } from 'storm-react-diagrams/dist/@types/src/models/DiagramModel';
+import { TextureBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/textureBlock';
+
+/**
+ * Texture node model which stores information about a node editor block
+ */
+export class TextureNodeModel extends DefaultNodeModel {
+	/**
+	 * Texture for the node if it exists
+	 */
+    public texture: Nullable<Texture> = null;
+	/**
+	 * Constructs the node model
+	 */
+    constructor() {
+        super("texture");
+    }
+
+    renderProperties(globalState: GlobalState) {
+        return (
+            <TexturePropertyTabComponent globalState={globalState} node={this} />
+        );
+    }
+
+    prepare(options: NodeCreationOptions, nodes: Array<DefaultNodeModel>, model: DiagramModel, graphEditor: GraphEditor, filterInputs: string[]) {
+        let textureBlock = options.nodeMaterialBlock as TextureBlock;
+
+        this.texture = textureBlock.texture.value;
+
+        super.prepare(options, nodes, model, graphEditor, filterInputs);
+    }
+
+}

+ 90 - 0
nodeEditor/src/components/diagram/texture/textureNodeWidget.tsx

@@ -0,0 +1,90 @@
+import * as React from "react";
+import { PortWidget } from "storm-react-diagrams";
+import { TextureNodeModel } from './textureNodeModel';
+import { TextureLineComponent } from "../../../sharedComponents/textureLineComponent"
+import { Nullable } from 'babylonjs/types';
+import { GlobalState } from '../../../globalState';
+import { DefaultPortModel } from '../defaultPortModel';
+
+/**
+ * GenericNodeWidgetProps
+ */
+export interface TextureNodeWidgetProps {
+    node: Nullable<TextureNodeModel>;
+    globalState: GlobalState;
+}
+
+/**
+ * Used to display a node block for the node editor
+ */
+export class TextureNodeWidget extends React.Component<TextureNodeWidgetProps> {
+	/**
+	 * Creates a GenericNodeWidget
+	 * @param props 
+	 */
+    constructor(props: TextureNodeWidgetProps) {
+        super(props);
+        this.state = {};
+
+        if (this.props.node) {
+            this.props.node.addListener({
+                selectionChanged: () => {
+                    let selected = (this.props.node as any).selected;
+                    this.props.globalState.onSelectionChangedObservable.notifyObservers(selected ? this.props.node : null);
+                }
+            });
+        }
+    }
+
+    render() {
+        var inputPorts = new Array<JSX.Element>();
+        var outputPorts = new Array<JSX.Element>();
+        if (this.props.node) {
+            // Input/Output ports
+            for (var key in this.props.node.ports) {
+                var port = this.props.node.ports[key] as DefaultPortModel;
+                if (port.position === "output") {
+                    outputPorts.push(
+                        <div key={key} className="output-port">
+                            <div className="output-port-label">
+                                {port.name}
+                            </div>
+                            <div className="output-port-plug">
+                                <PortWidget key={key} name={port.name} node={this.props.node} />
+                            </div>
+                        </div>
+                    );
+                } else if (port.name === "uv") {
+                    inputPorts.push(
+                        <div key={key} className="input-port">
+                            <div className="input-port-plug">
+                                <PortWidget key={key} name={port.name} node={this.props.node} />
+                            </div>
+                            <div className="input-port-label">
+                                {port.name}
+                            </div>
+                        </div>
+                    )
+                }
+            }
+        }
+
+        return (
+            <div className={"diagramBlock"}>
+                <div className="header">
+                    {`Texture (${this.props.node && this.props.node.texture ? this.props.node.texture.name : "not set"})`}
+                </div>
+                <div className="inputs">
+                    {inputPorts}
+                </div>
+                <div className="outputs">
+                    {outputPorts}
+                </div>
+                {
+                    this.props.node && this.props.node.texture &&
+                    <TextureLineComponent ref="textureView" width={200} height={180} texture={this.props.node.texture} hideChannelSelect={true} />
+                }
+            </div>
+        );
+    }
+}

+ 123 - 0
nodeEditor/src/components/nodeList/nodeList.scss

@@ -0,0 +1,123 @@
+#nodeList {
+    background: #333333;
+    height: 100%;
+    margin: 0;
+    padding: 0;
+    display: grid;
+    width: 200px; 
+    overflow: hidden;
+
+    .pane {
+        color: white;
+
+        overflow-x: hidden;
+        overflow-y: auto;
+        height: 100%;
+
+        -webkit-user-select: none; 
+        -moz-user-select: none;   
+        -ms-user-select: none;    
+        user-select: none;     
+
+        .underline {
+            border-bottom: 0.5px solid rgba(255, 255, 255, 0.5);
+        }
+    
+        .buttonLine {
+            height: 30px;
+            display: grid;
+            align-items: center;
+            justify-items: stretch;
+
+            button {
+                background: #222222;
+                border: 1px solid rgb(51, 122, 183);
+                margin: 5px 10px 5px 10px;
+                color:white;
+                padding: 4px 5px;
+                opacity: 0.9;
+            }
+
+            button:hover {
+                opacity: 1.0;
+            }
+
+            button:active {
+                background: #282828;
+            }   
+            
+            button:focus {
+                border: 1px solid rgb(51, 122, 183);
+                outline: 0px;
+            }  
+        }
+
+        .paneContainer {
+            margin-top: 3px;
+            display:grid;
+            grid-template-rows: 100%;
+            grid-template-columns: 100%;
+            
+            .paneList {
+                border-left: 3px solid transparent;
+            }
+
+            &:hover {  
+                .paneList {                      
+                    border-left: 3px solid rgba(51, 122, 183, 0.8);
+                }
+
+                .paneContainer-content {
+                    .header {
+                        .title {   
+                            border-left: 3px solid rgb(51, 122, 183);
+                        }
+                    }
+                }
+            }
+
+            .paneContainer-content {
+                grid-row: 1;
+                grid-column: 1;
+
+                .header {
+                    display: grid;
+                    grid-template-columns: 1fr auto;
+                    background: #555555;    
+                    height: 30px;   
+                    padding-right: 5px;                        
+                    cursor: pointer;
+                    
+                    .title {                                
+                        border-left: 3px solid transparent;
+                        padding-left: 5px;
+                        grid-column: 1;
+                        display: flex;
+                        align-items: center;
+                    }
+
+                    .collapse {
+                        grid-column: 2;
+                        display: flex;
+                        align-items: center;  
+                        justify-items: center;
+                        transform-origin: center;
+
+                        &.closed {
+                            transform: rotate(180deg);
+                        }
+                    }                        
+                }
+
+                .paneList > div:not(:last-child) {
+                    border-bottom: 0.5px solid rgba(255, 255, 255, 0.1);
+                }
+
+                .fragment > div:not(:last-child)  {
+                    border-bottom: 0.5px solid rgba(255, 255, 255, 0.1);
+                }
+            }
+        }
+    }    
+}
+

+ 72 - 0
nodeEditor/src/components/nodeList/nodeListComponent.tsx

@@ -0,0 +1,72 @@
+
+import * as React from "react";
+import { GlobalState } from '../../globalState';
+import { LineContainerComponent } from '../../sharedComponents/lineContainerComponent';
+import { ButtonLineComponent } from '../../sharedComponents/buttonLineComponent';
+import { AlphaTestBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/alphaTestBlock';
+import { FragmentOutputBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/fragmentOutputBlock';
+import { ImageProcessingBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/imageProcessingBlock';
+import { RGBAMergerBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/rgbaMergerBlock';
+import { RGBASplitterBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/rgbaSplitterBlock';
+import { TextureBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/textureBlock';
+import { BonesBlock } from 'babylonjs/Materials/Node/Blocks/Vertex/bonesBlock';
+import { InstancesBlock } from 'babylonjs/Materials/Node/Blocks/Vertex/instancesBlock';
+import { MorphTargetsBlock } from 'babylonjs/Materials/Node/Blocks/Vertex/morphTargetsBlock';
+import { VertexOutputBlock } from 'babylonjs/Materials/Node/Blocks/Vertex/vertexOutputBlock';
+import { FogBlock } from 'babylonjs/Materials/Node/Blocks/Dual/fogBlock';
+import { AddBlock } from 'babylonjs/Materials/Node/Blocks/addBlock';
+import { ClampBlock } from 'babylonjs/Materials/Node/Blocks/clampBlock';
+import { MatrixMultiplicationBlock } from 'babylonjs/Materials/Node/Blocks/matrixMultiplicationBlock';
+import { MultiplyBlock } from 'babylonjs/Materials/Node/Blocks/multiplyBlock';
+import { Vector2TransformBlock } from 'babylonjs/Materials/Node/Blocks/vector2TransformBlock';
+import { Vector3TransformBlock } from 'babylonjs/Materials/Node/Blocks/vector3TransformBlock';
+import { Vector4TransformBlock } from 'babylonjs/Materials/Node/Blocks/vector4TransformBlock';
+import { NodeMaterialBlock } from 'babylonjs/Materials/Node/nodeMaterialBlock';
+
+require("./nodeList.scss");
+
+interface INodeListComponentProps {
+    globalState: GlobalState;
+    onAddValueNode: (b: string) => void;
+    onAddNodeFromClass: (ObjectClass: typeof NodeMaterialBlock) => void;
+}
+
+export class NodeListComponent extends React.Component<INodeListComponentProps> {
+    render() {
+        // Block types used to create the menu from
+        const allBlocks = {
+            Vertex: [BonesBlock, InstancesBlock, MorphTargetsBlock],
+            Fragment: [AlphaTestBlock, , ImageProcessingBlock, RGBAMergerBlock, RGBASplitterBlock, TextureBlock],
+            Outputs: [VertexOutputBlock, FragmentOutputBlock],
+            Dual: [FogBlock],
+            Math: [AddBlock, ClampBlock, MatrixMultiplicationBlock, MultiplyBlock, Vector2TransformBlock, Vector3TransformBlock, Vector4TransformBlock],
+            Inputs: ["Texture", "Vector2", "Vector3", "Matrix"],
+        }
+
+        // Create node menu
+        var blockMenu = []
+        for (var key in allBlocks) {
+            var blockList = (allBlocks as any)[key].map((b: any) => {
+                var label = typeof b === "string" ? b : b.prototype.getClassName().replace("Block", "")
+                var onClick = typeof b === "string" ? () => { this.props.onAddValueNode(b) } : () => { this.props.onAddNodeFromClass(b) };
+                return <ButtonLineComponent label={label} onClick={onClick} />
+            })
+            blockMenu.push(
+                <LineContainerComponent title={key + " blocks"} closed={false}>
+                    {blockList}
+                </LineContainerComponent>
+            )
+        }
+
+        return (
+            <div id="nodeList" style={{ borderRightStyle: "solid", borderColor: "grey", borderWidth: "1px" }} >
+                <div className="panes">
+                    <div className="pane">
+                        {blockMenu}
+                    </div>
+                </div>
+            </div>
+        );
+
+    }
+}

+ 59 - 0
nodeEditor/src/components/propertyTab/properties/texturePropertyTabComponent.tsx

@@ -0,0 +1,59 @@
+
+import * as React from "react";
+import { GlobalState } from '../../../globalState';
+import { Texture } from 'babylonjs/Materials/Textures/texture';
+import { FileButtonLineComponent } from '../../../sharedComponents/fileButtonLineComponent';
+import { Tools } from 'babylonjs/Misc/tools';
+import { Engine } from 'babylonjs/Engines/engine';
+import { TextureNodeModel } from '../../../components/diagram/texture/textureNodeModel';
+
+interface ITexturePropertyTabComponentProps {
+    globalState: GlobalState;
+    node: TextureNodeModel;
+}
+
+export class TexturePropertyTabComponent extends React.Component<ITexturePropertyTabComponentProps> {
+
+	/**
+	 * Replaces the texture of the node
+	 * @param file the file of the texture to use
+	 */
+    replaceTexture(file: File) {
+        if (!this.props.node) {
+            return;
+        }
+
+        let texture = this.props.node.texture as Texture;
+        if (!texture) {
+            this.props.node.texture = new Texture(null, Engine.LastCreatedScene)
+            texture = this.props.node.texture;
+        }
+
+        Tools.ReadFile(file, (data) => {
+            var blob = new Blob([data], { type: "octet/stream" });
+            var url = URL.createObjectURL(blob);
+
+            if (texture.isCube) {
+                let extension: string | undefined = undefined;
+                if (file.name.toLowerCase().indexOf(".dds") > 0) {
+                    extension = ".dds";
+                } else if (file.name.toLowerCase().indexOf(".env") > 0) {
+                    extension = ".env";
+                }
+
+                (texture as Texture).updateURL(url, extension, () => this.forceUpdate());
+            } else {
+                (texture as Texture).updateURL(url, null, () => this.forceUpdate());
+            }
+        }, undefined, true);
+    }
+
+    render() {
+        return (
+            <div>
+                <h1>Texture</h1>
+                <FileButtonLineComponent label="Replace texture" onClick={(file) => this.replaceTexture(file)} accept=".jpg, .png, .tga, .dds, .env" />
+            </div>
+        );
+    }
+}

+ 19 - 0
nodeEditor/src/components/propertyTab/properties/vector2PropertyTabComponent.tsx

@@ -0,0 +1,19 @@
+
+import * as React from "react";
+import { GlobalState } from '../../../globalState';
+import { Vector2LineComponent } from '../../../sharedComponents/vector2LineComponent';
+import { NodeMaterialConnectionPoint } from 'babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint';
+
+interface IVector2PropertyTabComponentProps {
+    globalState: GlobalState;
+    connection: NodeMaterialConnectionPoint;
+}
+
+export class Vector2PropertyTabComponent extends React.Component<IVector2PropertyTabComponentProps> {
+
+    render() {
+        return (
+            <Vector2LineComponent label="Value" target={this.props.connection} propertyName="value"></Vector2LineComponent>
+        );
+    }
+}

+ 19 - 0
nodeEditor/src/components/propertyTab/properties/vector3PropertyTabComponent.tsx

@@ -0,0 +1,19 @@
+
+import * as React from "react";
+import { GlobalState } from '../../../globalState';
+import { Vector3LineComponent } from '../../../sharedComponents/vector3LineComponent';
+import { NodeMaterialConnectionPoint } from 'babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint';
+
+interface IVector3PropertyTabComponentProps {
+    globalState: GlobalState;
+    connection: NodeMaterialConnectionPoint;
+}
+
+export class Vector3PropertyTabComponent extends React.Component<IVector3PropertyTabComponentProps> {
+
+    render() {
+        return (
+            <Vector3LineComponent label="Value" target={this.props.connection} propertyName="value"></Vector3LineComponent>
+        );
+    }
+}

+ 261 - 0
nodeEditor/src/components/propertyTab/propertyTab.scss

@@ -0,0 +1,261 @@
+#propertyTab {
+    padding: 5px;
+    $line-padding-left: 2px;
+    color:white;
+
+    .vector3Line {
+        padding-left:$line-padding-left;                    
+        display: grid;
+
+        .firstLine {
+            display: grid;
+            grid-template-columns: 1fr auto 20px;
+            height: 30px;
+
+            .label {
+                grid-column: 1;
+                display: flex;
+                align-items: center;
+            }
+
+            .vector {
+                grid-column: 2;
+                display: flex;
+                align-items: center;
+                text-align: right;
+                opacity: 0.8;
+            }
+
+            .expand {
+                grid-column: 3;
+                display: grid;
+                align-items: center;
+                justify-items: center;
+                cursor: pointer;
+            }
+        }
+
+        .secondLine {
+            display: grid;
+            padding-right: 5px;  
+            border-left: 1px solid rgb(51, 122, 183);
+
+            .numeric {
+                display: grid;
+                grid-template-columns: 1fr auto;
+            }
+
+            .numeric-label {
+                text-align: right;
+                grid-column: 1;
+                display: flex;
+                align-items: center;                            
+                justify-self: right;
+                margin-right: 10px;                          
+            }
+
+            .numeric-value {
+                width: 120px;
+                grid-column: 2;
+                display: flex;
+                align-items: center;  
+                border: 1px solid  rgb(51, 122, 183);
+            }                        
+        }
+    }
+
+    .buttonLine {
+        height: 30px;
+        display: grid;
+        align-items: center;
+        justify-items: stretch;
+
+        input[type="file"] {
+            display: none;
+        }
+
+        .file-upload {            
+            background: #222222;
+            border: 1px solid rgb(51, 122, 183);
+            margin: 5px 10px;
+            color:white;
+            padding: 4px 5px;
+            opacity: 0.9;
+            cursor: pointer;
+            text-align: center;
+        }
+
+        .file-upload:hover {
+            opacity: 1.0;
+        }
+
+        .file-upload:active {
+            transform: scale(0.98);
+            transform-origin: 0.5 0.5;
+        }
+
+        button {
+            background: #222222;
+            border: 1px solid rgb(51, 122, 183);
+            margin: 5px 10px 5px 10px;
+            color:white;
+            padding: 4px 5px;
+            opacity: 0.9;
+        }
+
+        button:hover {
+            opacity: 1.0;
+        }
+
+        button:active {
+            background: #282828;
+        }   
+        
+        button:focus {
+            border: 1px solid rgb(51, 122, 183);
+            outline: 0px;
+        }  
+    }
+
+    
+    .checkBoxLine {
+        padding-left: $line-padding-left;
+        height: 30px;
+        display: grid;
+        grid-template-columns: 1fr auto;
+
+        .label {
+            grid-column: 1;
+            display: flex;
+            align-items: center;
+        }
+
+        .checkBox {
+            grid-column: 2;
+            
+            display: flex;
+            align-items: center;
+
+            .lbl {
+                position: relative;
+                display: block;
+                height: 14px;
+                width: 34px;
+                margin-right: 5px;
+                background: #898989;
+                border-radius: 100px;
+                cursor: pointer;
+                transition: all 0.3s ease;
+            }
+
+            .lbl:after {
+                position: absolute;
+                left: 3px;
+                top: 2px;
+                display: block;
+                width: 10px;
+                height: 10px;
+                border-radius: 100px;
+                background: #fff;
+                box-shadow: 0px 3px 3px rgba(0,0,0,0.05);
+                content: '';
+                transition: all 0.15s ease;
+            }
+
+            .lbl:active:after { 
+                transform: scale(1.15, 0.85); 
+            }
+
+            .cbx:checked ~ label { 
+                background: rgb(51, 122, 183);
+            }
+
+            .cbx:checked ~ label:after {
+                left: 20px;
+                background: rgb(22, 73, 117);
+            }
+
+            .hidden { 
+                display: none; 
+            }               
+        }                    
+    }  
+
+    .listLine {
+        padding-left: $line-padding-left;
+        height: 30px;
+        display: grid;
+        grid-template-columns: 1fr auto;
+
+
+        .label {
+            grid-column: 1;
+            display: flex;
+            align-items: center;
+        }
+
+        .options {
+            grid-column: 2;
+            
+            display: flex;
+            align-items: center;   
+            margin-right: 5px;
+
+            select {
+                width: 115px;
+            }
+        }                    
+    }  
+    
+    .textLine {
+        padding-left: $line-padding-left;
+        height: 30px;
+        display: grid;
+        grid-template-columns: 1fr auto;
+
+        .label {
+            grid-column: 1;
+            display: flex;
+            align-items: center;
+        }
+
+        .link-value {
+            grid-column: 2;
+            white-space: nowrap;
+            text-overflow: ellipsis;
+            overflow: hidden;
+            text-align: end;
+            opacity: 0.8;
+            margin:5px;
+            margin-top: 6px;
+            max-width: 140px;
+            text-decoration: underline;
+            cursor: pointer;
+        }
+
+        .value {
+            grid-column: 2;
+            white-space: nowrap;
+            text-overflow: ellipsis;
+            overflow: hidden;
+            text-align: end;
+            opacity: 0.8;
+            margin:5px;
+            margin-top: 6px;
+            max-width: 200px;
+            -webkit-user-select: text; 
+            -moz-user-select: text;   
+            -ms-user-select: text;    
+            user-select: text;                
+
+            &.check {
+                color: green;
+            }
+
+            &.uncheck {
+                color: red;
+            }  
+        }
+    }    
+
+}

+ 39 - 0
nodeEditor/src/components/propertyTab/propertyTabComponent.tsx

@@ -0,0 +1,39 @@
+
+import * as React from "react";
+import { GlobalState } from '../../globalState';
+import { Nullable } from 'babylonjs/types';
+import { DefaultNodeModel } from '../../components/diagram/defaultNodeModel';
+require("./propertyTab.scss");
+
+interface IPropertyTabComponentProps {
+    globalState: GlobalState;
+}
+
+export class PropertyTabComponent extends React.Component<IPropertyTabComponentProps, { currentNode: Nullable<DefaultNodeModel> }> {
+
+    constructor(props: IPropertyTabComponentProps) {
+        super(props)
+
+        this.state = { currentNode: null };
+    }
+
+    componentWillMount() {
+        this.props.globalState.onSelectionChangedObservable.add(block => {
+            this.setState({ currentNode: block });
+        });
+    }
+
+    render() {
+        if (this.state.currentNode) {
+            return (
+                <div id="propertyTab">
+                    {this.state.currentNode.renderProperties(this.props.globalState)}
+                </div>
+            );
+        }
+
+        return (
+            <div id="propertyTab" />
+        );
+    }
+}

+ 12 - 0
nodeEditor/src/globalState.ts

@@ -0,0 +1,12 @@
+import { NodeMaterial } from "babylonjs/Materials/Node/nodeMaterial"
+import { Nullable } from "babylonjs/types"
+import { Observable } from 'babylonjs/Misc/observable';
+import { DefaultNodeModel } from './components/diagram/defaultNodeModel';
+
+export class GlobalState {
+    nodeMaterial?: NodeMaterial;
+    hostElement: HTMLElement;
+    hostDocument: HTMLDocument;
+    onSelectionChangedObservable = new Observable<Nullable<DefaultNodeModel>>();
+    onRebuildRequiredObservable = new Observable<void>();
+}

+ 261 - 0
nodeEditor/src/graphEditor.tsx

@@ -0,0 +1,261 @@
+import {
+    DiagramEngine,
+    DiagramModel,
+    DiagramWidget,
+    MoveCanvasAction
+} from "storm-react-diagrams";
+
+import * as React from "react";
+import { GlobalState } from './globalState';
+
+import { GenericNodeFactory } from './components/diagram/generic/genericNodeFactory';
+import { GenericNodeModel } from './components/diagram/generic/genericNodeModel';
+import { NodeMaterialBlock } from 'babylonjs/Materials/Node/nodeMaterialBlock';
+import { NodeMaterialConnectionPoint } from 'babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint';
+import { NodeListComponent } from './components/nodeList/nodeListComponent';
+import { PropertyTabComponent } from './components/propertyTab/propertyTabComponent';
+import { Portal } from './portal';
+import { TextureNodeFactory } from './components/diagram/texture/textureNodeFactory';
+import { DefaultNodeModel } from './components/diagram/defaultNodeModel';
+import { TextureNodeModel } from './components/diagram/texture/textureNodeModel';
+import { DefaultPortModel } from './components/diagram/defaultPortModel';
+import { InputNodeFactory } from './components/diagram/input/inputNodeFactory';
+import { InputNodeModel } from './components/diagram/input/inputNodeModel';
+import { TextureBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/textureBlock';
+
+require("storm-react-diagrams/dist/style.min.css");
+require("./main.scss");
+require("./components/diagram/diagram.scss");
+
+/*
+Graph Editor Overview
+
+Storm React setup:
+GenericNodeModel - Represents the nodes in the graph and can be any node type (eg. texture, vector2, etc)
+GenericNodeWidget - Renders the node model in the graph 
+GenericPortModel - Represents the input/output of a node (contained within each GenericNodeModel)
+
+Generating/modifying the graph:
+Generating node graph - the createNodeFromObject method is used to recursively create the graph
+Modifications to the graph - The listener in the constructor of GraphEditor listens for port changes and updates the node material based on changes
+Saving the graph/generating code - Not yet done
+*/
+
+interface IGraphEditorProps {
+    globalState: GlobalState;
+}
+
+export class NodeCreationOptions {
+    column: number;
+    nodeMaterialBlock?: NodeMaterialBlock;
+    type?: string;
+    connection?: NodeMaterialConnectionPoint;
+}
+
+export class GraphEditor extends React.Component<IGraphEditorProps> {
+    private _engine: DiagramEngine;
+    private _model: DiagramModel;
+
+    private _nodes = new Array<DefaultNodeModel>();
+
+    /**
+     * Current row/column position used when adding new nodes
+     */
+    private _rowPos = new Array<number>()
+
+    /**
+     * Creates a node and recursivly creates its parent nodes from it's input
+     * @param nodeMaterialBlock 
+     */
+    public createNodeFromObject(options: NodeCreationOptions) {
+        // Update rows/columns
+        if (this._rowPos[options.column] == undefined) {
+            this._rowPos[options.column] = 0;
+        } else {
+            this._rowPos[options.column]++;
+        }
+
+        // Create new node in the graph
+        var outputNode: DefaultNodeModel;
+        var filterInputs = [];
+
+        if (options.nodeMaterialBlock) {
+            if (options.nodeMaterialBlock instanceof TextureBlock) {
+                outputNode = new TextureNodeModel();
+                filterInputs.push("uv");
+            } else {
+                outputNode = new GenericNodeModel();
+            }
+        } else {
+            outputNode = new InputNodeModel();
+            (outputNode as InputNodeModel).connection = options.connection;
+        }
+        this._nodes.push(outputNode)
+        outputNode.setPosition(1600 - (300 * options.column), 210 * this._rowPos[options.column])
+        this._model.addAll(outputNode);
+
+        if (options.nodeMaterialBlock) {
+            outputNode.prepare(options, this._nodes, this._model, this, filterInputs);
+        }
+
+        return outputNode;
+    }
+
+    componentDidMount() {
+        if (this.props.globalState.hostDocument) {
+            var widget = (this.refs["test"] as DiagramWidget);
+            widget.setState({ document: this.props.globalState.hostDocument })
+            this.props.globalState.hostDocument!.addEventListener("keyup", widget.onKeyUpPointer as any, false);
+        }
+    }
+
+    componentWillUnmount() {
+        if (this.props.globalState.hostDocument) {
+            var widget = (this.refs["test"] as DiagramWidget);
+            this.props.globalState.hostDocument!.removeEventListener("keyup", widget.onKeyUpPointer as any, false);
+        }
+    }
+
+    constructor(props: IGraphEditorProps) {
+        super(props);
+
+        // setup the diagram engine
+        this._engine = new DiagramEngine();
+        this._engine.installDefaultFactories()
+        this._engine.registerNodeFactory(new GenericNodeFactory(this.props.globalState));
+        this._engine.registerNodeFactory(new TextureNodeFactory(this.props.globalState));
+        this._engine.registerNodeFactory(new InputNodeFactory(this.props.globalState));
+
+        // setup the diagram model
+        this._model = new DiagramModel();
+
+        // Listen to events to connect/disconnect blocks or
+        this._model.addListener({
+            linksUpdated: (e) => {
+                if (!e.isCreated) {
+                    // Link is deleted
+                    console.log("link deleted");
+                    var link = DefaultPortModel.SortInputOutput(e.link.sourcePort as DefaultPortModel, e.link.targetPort as DefaultPortModel);
+                    console.log(link)
+                    if (link) {
+                        if (link.output.connection && link.input.connection) {
+                            // Disconnect standard nodes
+                            console.log("disconnected " + link.output.connection.name + " from " + link.input.connection.name)
+                            link.output.connection.disconnectFrom(link.input.connection)
+                            link.input.syncWithNodeMaterialConnectionPoint(link.input.connection)
+                            link.output.syncWithNodeMaterialConnectionPoint(link.output.connection)
+                        } else if (link.input.connection && link.input.connection.value) {
+                            console.log("value link removed");
+                            link.input.connection.value = null;
+                        } else {
+                            console.log("invalid link error");
+                        }
+                    }
+                } else {
+                    console.log("link created")
+                    console.log(e.link.sourcePort)
+                }
+                e.link.addListener({
+                    sourcePortChanged: () => {
+                        console.log("port change")
+                    },
+                    targetPortChanged: () => {
+                        // Link is created with a target port
+                        console.log("Link set to target")
+                        var link = DefaultPortModel.SortInputOutput(e.link.sourcePort as DefaultPortModel, e.link.targetPort as DefaultPortModel);
+
+                        if (link) {
+                            if (link.output.connection && link.input.connection) {
+                                console.log("link standard blocks")
+                                link.output.connection.connectTo(link.input.connection)
+                            } else if (link.input.connection) {
+                                console.log("link value to standard block")
+                                link.input.connection.value = link.output.getValue();
+
+                            }
+                            if (this.props.globalState.nodeMaterial) {
+                                this.props.globalState.nodeMaterial.build()
+                            }
+                        }
+                    }
+
+                })
+
+            },
+            nodesUpdated: (e) => {
+                if (e.isCreated) {
+                    console.log("new node")
+                } else {
+                    console.log("node deleted")
+                }
+            }
+        });
+
+        this.props.globalState.onRebuildRequiredObservable.add(() => {
+            if (this.props.globalState.nodeMaterial) {
+                this.props.globalState.nodeMaterial.build();
+            }
+        });
+
+        // Load graph of nodes from the material
+        if (this.props.globalState.nodeMaterial) {
+            var material: any = this.props.globalState.nodeMaterial;
+            material._vertexOutputNodes.forEach((n: any) => {
+                this.createNodeFromObject({ column: 0, nodeMaterialBlock: n });
+            })
+            material._fragmentOutputNodes.forEach((n: any) => {
+                this.createNodeFromObject({ column: 0, nodeMaterialBlock: n });
+            })
+        }
+
+        // Zoom out a bit at the start
+        this._model.setZoomLevel(80)
+
+        // load model into engine
+        this._engine.setDiagramModel(this._model);
+    }
+
+    addNodeFromClass(ObjectClass: typeof NodeMaterialBlock) {
+        var block = new ObjectClass(ObjectClass.prototype.getClassName() + "sdfsdf")
+        var localNode = this.createNodeFromObject({ column: 0, nodeMaterialBlock: block })
+        var widget = (this.refs["test"] as DiagramWidget);
+
+        this.forceUpdate()
+
+        // This is needed to fix link offsets when created, (eg. create a fog block)
+        // Todo figure out how to correct this without this
+        setTimeout(() => {
+            widget.startFiringAction(new MoveCanvasAction(1, 0, this._model));
+        }, 500);
+
+        return localNode
+    }
+
+    addValueNode(type: string, column = 0, connection?: NodeMaterialConnectionPoint) {
+        var localNode = this.createNodeFromObject({ column: column, type: type, connection: connection })
+        var outPort = new DefaultPortModel(type, "output");
+
+        localNode.addPort(outPort);
+        this.forceUpdate();
+
+        return localNode;
+    }
+
+    render() {
+        return (
+            <Portal globalState={this.props.globalState}>
+                <div id="node-editor-graph-root">
+                    {/* Node creation menu */}
+                    <NodeListComponent globalState={this.props.globalState} onAddValueNode={b => this.addValueNode(b)} onAddNodeFromClass={b => this.addNodeFromClass(b)} />
+
+                    {/* The node graph diagram */}
+                    <DiagramWidget deleteKeys={[46]} ref={"test"} inverseZoom={true} className="diagram-container" diagramEngine={this._engine} maxNumberPointsPerLink={0} />
+
+                    {/* Property tab */}
+                    <PropertyTabComponent globalState={this.props.globalState} />
+                </div>
+            </Portal>
+        );
+
+    }
+}

+ 0 - 0
nodeEditor/src/index.ts


Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff