Browse Source

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js

sebavan 5 năm trước cách đây
mục cha
commit
0653bd73a9
70 tập tin đã thay đổi với 31596 bổ sung211 xóa
  1. 1 1
      .vscode/launch.json
  2. 3 0
      Playground/README-ES6.md
  3. 16 0
      Playground/README.md
  4. 69 0
      Playground/public/index-local.html
  5. 3 0
      Playground/public/index.js
  6. 253 0
      Playground/public/libs/fileSaver.js
  7. 14 0
      Playground/public/libs/jszip.min.js
  8. 3 0
      Playground/public/libs/split.js
  9. 110 0
      Playground/public/workers/definitionWorker.js
  10. 262 0
      Playground/src/components/monacoComponent.tsx
  11. 2 0
      Playground/src/globalState.ts
  12. 1 0
      Playground/src/index.ts
  13. 9 0
      Playground/src/legacy/legacy.ts
  14. 35 0
      Playground/src/playground.tsx
  15. 21 0
      Playground/src/scss/main.scss
  16. 6 0
      Playground/src/scss/monaco.scss
  17. 28 0
      Playground/tsconfig.json
  18. 46 0
      Playground/webpack.config.js
  19. 52 2
      Tools/Config/config.json
  20. 4 0
      dist/preview release/babylon.d.ts
  21. 2 2
      dist/preview release/babylon.js
  22. 10 8
      dist/preview release/babylon.max.js
  23. 1 1
      dist/preview release/babylon.max.js.map
  24. 8 0
      dist/preview release/babylon.module.d.ts
  25. 27 0
      dist/preview release/documentation.d.ts
  26. 48 48
      dist/preview release/gui/babylon.gui.js
  27. 1 1
      dist/preview release/gui/babylon.gui.js.map
  28. 6 6
      dist/preview release/inspector/babylon.inspector.bundle.js
  29. 358 106
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  30. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  31. 44 1
      dist/preview release/inspector/babylon.inspector.d.ts
  32. 93 3
      dist/preview release/inspector/babylon.inspector.module.d.ts
  33. 1 1
      dist/preview release/libktx.js
  34. BIN
      dist/preview release/libktx.wasm
  35. 31 0
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  36. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.js.map
  37. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  38. 31 0
      dist/preview release/loaders/babylon.glTFFileLoader.js
  39. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.js.map
  40. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  41. 23 0
      dist/preview release/loaders/babylonjs.loaders.d.ts
  42. 31 0
      dist/preview release/loaders/babylonjs.loaders.js
  43. 1 1
      dist/preview release/loaders/babylonjs.loaders.js.map
  44. 1 1
      dist/preview release/loaders/babylonjs.loaders.min.js
  45. 46 0
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  46. 1 1
      dist/preview release/packagesSizeBaseLine.json
  47. 17 0
      dist/preview release/playground/babylon.playground.d.ts
  48. 45 0
      dist/preview release/playground/babylon.playground.js
  49. 29424 0
      dist/preview release/playground/babylon.playground.max.js
  50. 1 0
      dist/preview release/playground/babylon.playground.max.js.map
  51. 44 0
      dist/preview release/playground/babylon.playground.module.d.ts
  52. 27 0
      dist/preview release/playground/package.json
  53. 3 0
      dist/preview release/playground/readme-es6.md
  54. 16 0
      dist/preview release/playground/readme.md
  55. 8 0
      dist/preview release/viewer/babylon.module.d.ts
  56. 5 5
      dist/preview release/viewer/babylon.viewer.js
  57. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  58. 46 0
      dist/preview release/viewer/babylonjs.loaders.module.d.ts
  59. 1 0
      dist/preview release/what's new.md
  60. 1 1
      inspector/src/components/actionTabs/tabs/propertyGrids/animations/animationPropertyGridComponent.tsx
  61. 1 1
      inspector/src/components/actionTabs/tabs/propertyGrids/animations/targetedAnimationPropertyGridComponent.tsx
  62. 42 5
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/texturePropertyGridComponent.tsx
  63. 156 0
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/textures/textureCanvasManager.ts
  64. 4 0
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/textures/textureEditor.scss
  65. 30 0
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/textures/textureEditorComponent.tsx
  66. 1 1
      inspector/src/components/actionTabs/tabs/propertyGrids/animations/popupComponent.tsx
  67. 3 5
      sandbox/public/index-local.html
  68. 2 2
      src/Misc/khronosTextureContainer2.ts
  69. 4 0
      src/XR/features/WebXRControllerTeleportation.ts
  70. 6 1
      src/XR/webXREnterExitUI.ts

+ 1 - 1
.vscode/launch.json

@@ -86,7 +86,7 @@
             "type": "edge",
             "version": "dev",
             "request": "launch",
-            "url": "http://localhost:1338/Playground/index-local.html",
+            "url": "http://localhost:1338/Playground/public/index-local.html",
             "webRoot": "${workspaceRoot}/",
             "sourceMaps": true,
             "preLaunchTask": "run",

+ 3 - 0
Playground/README-ES6.md

@@ -0,0 +1,3 @@
+# Babylon.js Playground
+
+An extension to easily create a full page playground (ala playground.babylonjs.com)

+ 16 - 0
Playground/README.md

@@ -0,0 +1,16 @@
+# Babylon.js Playground
+
+An extension to easily create a full page playground (ala playground.babylonjs.com)
+
+## Usage
+### Online method
+Call the method `Show` of the `BABYLON.Playground` class: 
+```
+BABYLON.Playground.Show({hostElement: document.getElementById("host")});
+```
+
+### Offline method
+If you don't have access to internet, the node editor should be imported manually in your HTML page :
+```
+<script src="babylon.playground.js" />
+``` 

+ 69 - 0
Playground/public/index-local.html

@@ -0,0 +1,69 @@
+<!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/favicon.ico">
+        <meta name="description" content="Babylon.js playground is a live editor for Babylon.js WebGL 3D scenes">
+        <meta name="keywords" content="Babylon.js,WebGL,3D">
+
+        <link rel="stylesheet"
+            href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css" />
+        <link rel="stylesheet" href="/css/index.css" />
+        <link rel="stylesheet" href="/css/index_mobile.css" />
+
+        <!-- Pep -->
+        <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
+        <!--For canvas/code separator-->
+        <script src="libs/split.js"></script>
+
+        <!-- DatGUI -->
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
+        <!-- jszip -->
+        <script src="libs/jszip.min.js"></script>
+        <script src="libs/fileSaver.js"></script>
+
+        <!-- Dependencies -->
+        <script src="/dist/preview%20release/ammo.js"></script>
+        <script src="/dist/preview%20release/recast.js"></script>
+        <script src="/dist/preview%20release/cannon.js"></script>
+        <script src="/dist/preview%20release/Oimo.js"></script>
+        <script src="/dist/preview%20release/libktx.js"></script>
+        <script src="/dist/preview%20release/earcut.min.js"></script>
+        <!-- Monaco -->
+
+        <!-- Babylon.js -->
+        <script src="/Tools/DevLoader/BabylonLoader.js"></script>
+
+        <style>
+            html,
+            body {
+                width: 100%;
+                height: 100%;
+                padding: 0;
+                margin: 0;
+                overflow: hidden;
+            }
+    
+            #host-element {
+                width: 100%;
+                height: 100%;
+            }
+        </style>        
+    </head>
+
+    <body>        
+        <div id="host-element">
+        </div>
+        <script>
+            // Load the scripts + map file to allow vscode debug.
+            BABYLONDEVTOOLS.Loader            
+                .require("index.js")
+                .load(() => {
+                });
+        </script>
+    </body>
+
+</html>

+ 3 - 0
Playground/public/index.js

@@ -0,0 +1,3 @@
+var hostElement = document.getElementById("host-element");
+
+BABYLON.Playground.Show(hostElement);

+ 253 - 0
Playground/public/libs/fileSaver.js

@@ -0,0 +1,253 @@
+/*! FileSaver.js
+ *  A saveAs() FileSaver implementation.
+ *  2014-01-24
+ *
+ *  By Eli Grey, http://eligrey.com
+ *  License: X11/MIT
+ *    See LICENSE.md
+ */
+
+/*global self */
+/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
+
+/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
+
+var saveAs = saveAs
+  // IE 10+ (native saveAs)
+  || (typeof navigator !== "undefined" &&
+      navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator))
+  // Everyone else
+  || (function (view) {
+      "use strict";
+      // IE <10 is explicitly unsupported
+      if (typeof navigator !== "undefined" &&
+          /MSIE [1-9]\./.test(navigator.userAgent)) {
+          return;
+      }
+      var
+            doc = view.document
+            // only get URL when necessary in case BlobBuilder.js hasn't overridden it yet
+          , get_URL = function () {
+              return view.URL || view.webkitURL || view;
+          }
+          , URL = view.URL || view.webkitURL || view
+          , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
+          , can_use_save_link = !view.externalHost && "download" in save_link
+          , click = function (node) {
+              var event = doc.createEvent("MouseEvents");
+              event.initMouseEvent(
+                  "click", true, false, view, 0, 0, 0, 0, 0
+                  , false, false, false, false, 0, null
+              );
+              node.dispatchEvent(event);
+          }
+          , webkit_req_fs = view.webkitRequestFileSystem
+          , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
+          , throw_outside = function (ex) {
+              (view.setImmediate || view.setTimeout)(function () {
+                  throw ex;
+              }, 0);
+          }
+          , force_saveable_type = "application/octet-stream"
+          , fs_min_size = 0
+          , deletion_queue = []
+          , process_deletion_queue = function () {
+              var i = deletion_queue.length;
+              while (i--) {
+                  var file = deletion_queue[i];
+                  if (typeof file === "string") { // file is an object URL
+                      URL.revokeObjectURL(file);
+                  } else { // file is a File
+                      file.remove();
+                  }
+              }
+              deletion_queue.length = 0; // clear queue
+          }
+          , dispatch = function (filesaver, event_types, event) {
+              event_types = [].concat(event_types);
+              var i = event_types.length;
+              while (i--) {
+                  var listener = filesaver["on" + event_types[i]];
+                  if (typeof listener === "function") {
+                      try {
+                          listener.call(filesaver, event || filesaver);
+                      } catch (ex) {
+                          throw_outside(ex);
+                      }
+                  }
+              }
+          }
+          , FileSaver = function (blob, name) {
+              // First try a.download, then web filesystem, then object URLs
+              var
+                    filesaver = this
+                  , type = blob.type
+                  , blob_changed = false
+                  , object_url
+                  , target_view
+                  , get_object_url = function () {
+                      var object_url = get_URL().createObjectURL(blob);
+                      deletion_queue.push(object_url);
+                      return object_url;
+                  }
+                  , dispatch_all = function () {
+                      dispatch(filesaver, "writestart progress write writeend".split(" "));
+                  }
+                  // on any filesys errors revert to saving with object URLs
+                  , fs_error = function () {
+                      // don't create more object URLs than needed
+                      if (blob_changed || !object_url) {
+                          object_url = get_object_url(blob);
+                      }
+                      if (target_view) {
+                          target_view.location.href = object_url;
+                      } else {
+                          window.open(object_url, "_blank");
+                      }
+                      filesaver.readyState = filesaver.DONE;
+                      dispatch_all();
+                  }
+                  , abortable = function (func) {
+                      return function () {
+                          if (filesaver.readyState !== filesaver.DONE) {
+                              return func.apply(this, arguments);
+                          }
+                      };
+                  }
+                  , create_if_not_found = { create: true, exclusive: false }
+                  , slice
+              ;
+              filesaver.readyState = filesaver.INIT;
+              if (!name) {
+                  name = "download";
+              }
+              if (can_use_save_link) {
+                  object_url = get_object_url(blob);
+                  // FF for Android has a nasty garbage collection mechanism
+                  // that turns all objects that are not pure javascript into 'deadObject'
+                  // this means `doc` and `save_link` are unusable and need to be recreated
+                  // `view` is usable though:
+                  doc = view.document;
+                  save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a");
+                  save_link.href = object_url;
+                  save_link.download = name;
+                  var event = doc.createEvent("MouseEvents");
+                  event.initMouseEvent(
+                      "click", true, false, view, 0, 0, 0, 0, 0
+                      , false, false, false, false, 0, null
+                  );
+                  save_link.dispatchEvent(event);
+                  filesaver.readyState = filesaver.DONE;
+                  dispatch_all();
+                  return;
+              }
+              // Object and web filesystem URLs have a problem saving in Google Chrome when
+              // viewed in a tab, so I force save with application/octet-stream
+              // http://code.google.com/p/chromium/issues/detail?id=91158
+              if (view.chrome && type && type !== force_saveable_type) {
+                  slice = blob.slice || blob.webkitSlice;
+                  blob = slice.call(blob, 0, blob.size, force_saveable_type);
+                  blob_changed = true;
+              }
+              // Since I can't be sure that the guessed media type will trigger a download
+              // in WebKit, I append .download to the filename.
+              // https://bugs.webkit.org/show_bug.cgi?id=65440
+              if (webkit_req_fs && name !== "download") {
+                  name += ".download";
+              }
+              if (type === force_saveable_type || webkit_req_fs) {
+                  target_view = view;
+              }
+              if (!req_fs) {
+                  fs_error();
+                  return;
+              }
+              fs_min_size += blob.size;
+              req_fs(view.TEMPORARY, fs_min_size, abortable(function (fs) {
+                  fs.root.getDirectory("saved", create_if_not_found, abortable(function (dir) {
+                      var save = function () {
+                          dir.getFile(name, create_if_not_found, abortable(function (file) {
+                              file.createWriter(abortable(function (writer) {
+                                  writer.onwriteend = function (event) {
+                                      target_view.location.href = file.toURL();
+                                      deletion_queue.push(file);
+                                      filesaver.readyState = filesaver.DONE;
+                                      dispatch(filesaver, "writeend", event);
+                                  };
+                                  writer.onerror = function () {
+                                      var error = writer.error;
+                                      if (error.code !== error.ABORT_ERR) {
+                                          fs_error();
+                                      }
+                                  };
+                                  "writestart progress write abort".split(" ").forEach(function (event) {
+                                      writer["on" + event] = filesaver["on" + event];
+                                  });
+                                  writer.write(blob);
+                                  filesaver.abort = function () {
+                                      writer.abort();
+                                      filesaver.readyState = filesaver.DONE;
+                                  };
+                                  filesaver.readyState = filesaver.WRITING;
+                              }), fs_error);
+                          }), fs_error);
+                      };
+                      dir.getFile(name, { create: false }, abortable(function (file) {
+                          // delete file if it already exists
+                          file.remove();
+                          save();
+                      }), abortable(function (ex) {
+                          if (ex.code === ex.NOT_FOUND_ERR) {
+                              save();
+                          } else {
+                              fs_error();
+                          }
+                      }));
+                  }), fs_error);
+              }), fs_error);
+          }
+          , FS_proto = FileSaver.prototype
+          , saveAs = function (blob, name) {
+              return new FileSaver(blob, name);
+          }
+      ;
+      FS_proto.abort = function () {
+          var filesaver = this;
+          filesaver.readyState = filesaver.DONE;
+          dispatch(filesaver, "abort");
+      };
+      FS_proto.readyState = FS_proto.INIT = 0;
+      FS_proto.WRITING = 1;
+      FS_proto.DONE = 2;
+
+      FS_proto.error =
+      FS_proto.onwritestart =
+      FS_proto.onprogress =
+      FS_proto.onwrite =
+      FS_proto.onabort =
+      FS_proto.onerror =
+      FS_proto.onwriteend =
+          null;
+
+      view.addEventListener("unload", process_deletion_queue, false);
+      saveAs.unload = function () {
+          process_deletion_queue();
+          view.removeEventListener("unload", process_deletion_queue, false);
+      };
+      return saveAs;
+  }(
+	   typeof self !== "undefined" && self
+	|| typeof window !== "undefined" && window
+	|| this.content
+));
+// `self` is undefined in Firefox for Android content script context
+// while `this` is nsIContentFrameMessageManager
+// with an attribute `content` that corresponds to the window
+
+if (typeof module !== "undefined" && module !== null) {
+    module.exports = saveAs;
+} else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) {
+    define([], function () {
+        return saveAs;
+    });
+}

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 14 - 0
Playground/public/libs/jszip.min.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 3 - 0
Playground/public/libs/split.js


+ 110 - 0
Playground/public/workers/definitionWorker.js

@@ -0,0 +1,110 @@
+// > This worker will analyze the syntaxtree and return an array of deprecated functions (but the goal is to do more in the future!)
+// We need to do this because:
+// - checking extended properties during completion is time consuming, so we need to prefilter potential candidates
+// - we don't want to maintain a static list of deprecated members or to instrument this work on the CI
+// - we have more plans involving syntaxtree analysis
+// > This worker was carefully crafted to work even if the processing is super fast or super long. 
+// In both cases the deprecation filter will start working after the worker is done.
+// We will also need this worker in the future to compute Intellicode scores for completion using dedicated attributes.
+
+// see monacoCreator.js/setupDefinitionWorker
+
+// monaco is using 'define' for module dependencies and service lookup.
+// hopefully typescript is self-contained
+var ts = null;
+var define = (id, dependencies, callback) => ts = callback();
+
+importScripts("../node_modules/monaco-editor/dev/vs/language/typescript/lib/typescriptServices.js");
+
+// store deprecated names
+var deprecatedCandidates = [];
+
+// optimize syntaxtree visitor, we don't care about non documented nodes
+function canHaveJsDoc(node) {
+    const kind = node.kind;
+    switch (kind) {
+        case ts.SyntaxKind.Parameter:
+        case ts.SyntaxKind.CallSignature:
+        case ts.SyntaxKind.ConstructSignature:
+        case ts.SyntaxKind.MethodSignature:
+        case ts.SyntaxKind.PropertySignature:
+        case ts.SyntaxKind.ArrowFunction:
+        case ts.SyntaxKind.ParenthesizedExpression:
+        case ts.SyntaxKind.SpreadAssignment:
+        case ts.SyntaxKind.ShorthandPropertyAssignment:
+        case ts.SyntaxKind.PropertyAssignment:
+        case ts.SyntaxKind.FunctionExpression:
+        case ts.SyntaxKind.FunctionDeclaration:
+        case ts.SyntaxKind.LabeledStatement:
+        case ts.SyntaxKind.ExpressionStatement:
+        case ts.SyntaxKind.VariableStatement:
+        case ts.SyntaxKind.Constructor:
+        case ts.SyntaxKind.MethodDeclaration:
+        case ts.SyntaxKind.PropertyDeclaration:
+        case ts.SyntaxKind.GetAccessor:
+        case ts.SyntaxKind.SetAccessor:
+        case ts.SyntaxKind.ClassDeclaration:
+        case ts.SyntaxKind.ClassExpression:
+        case ts.SyntaxKind.InterfaceDeclaration:
+        case ts.SyntaxKind.TypeAliasDeclaration:
+        case ts.SyntaxKind.EnumMember:
+        case ts.SyntaxKind.EnumDeclaration:
+        case ts.SyntaxKind.ModuleDeclaration:
+        case ts.SyntaxKind.ImportEqualsDeclaration:
+        case ts.SyntaxKind.IndexSignature:
+        case ts.SyntaxKind.FunctionType:
+        case ts.SyntaxKind.ConstructorType:
+        case ts.SyntaxKind.JSDocFunctionType:
+        case ts.SyntaxKind.EndOfFileToken:
+        case ts.SyntaxKind.ExportDeclaration:
+            return true;
+        default:
+            return false;
+    }
+}
+
+function onFindDeprecatedCandidate(node) {
+    const name = relatedName(node);
+    if (name)
+        deprecatedCandidates.push(name);
+}
+
+function relatedName(node) {
+    if (canHaveJsDoc(node) && node.name)
+        return node.name.escapedText;
+
+    if (node.parent)
+        return relatedName(parent);
+
+    return undefined;
+}
+
+function visit(node) {
+
+    if (node.jsDoc) {
+        for (const jsDocEntry of node.jsDoc) {
+            if (jsDocEntry.tags) {
+                for (const tag of jsDocEntry.tags) {
+                    if (tag.tagName && tag.tagName.escapedText == 'deprecated')
+                        onFindDeprecatedCandidate(node);
+                }
+            }
+        }
+    }
+
+    ts.forEachChild(node, visit);
+}
+
+function processDefinition(code) {
+    if (deprecatedCandidates.length == 0) {
+        const sourceFile = ts.createSourceFile('babylon.js', code, ts.ScriptTarget.ESNext, true);
+        ts.forEachChild(sourceFile, visit);
+    }
+
+    self.postMessage({ result: deprecatedCandidates });
+}
+
+self.addEventListener('message', event => {
+    const { code } = event.data;
+    processDefinition(code);
+});

+ 262 - 0
Playground/src/components/monacoComponent.tsx

@@ -0,0 +1,262 @@
+import * as React from "react";
+import * as monaco from "monaco-editor/esm/vs/editor/editor.api";
+
+require("../scss/monaco.scss");
+
+interface IMonacoComponentProps {
+    language: "JS" | "TS";
+}
+
+export class MonacoComponent extends React.Component<IMonacoComponentProps> {
+    private _hostReference: React.RefObject<HTMLDivElement>;
+    private _editor: monaco.editor.IStandaloneCodeEditor;
+    private _definitionWorker: Worker;
+    private _deprecatedCandidates: string[];
+   // private _templates: string[];
+    
+    public constructor(props: IMonacoComponentProps) {
+        super(props);
+
+        this._hostReference = React.createRef();
+    }
+
+    async setupMonaco() {
+        let hostElement = this._hostReference.current!;  
+        var editorOptions: monaco.editor.IEditorConstructionOptions = {
+            value: "",
+            language: this.props.language == "JS" ? "javascript" : "typescript",
+            lineNumbers: "on",
+            roundedSelection: true,
+            automaticLayout: true,
+            scrollBeyondLastLine: false,
+            readOnly: false,
+            theme: "vs",
+            contextmenu: false,
+            folding: true,
+            showFoldingControls: "always",
+            renderIndentGuides: true,
+            minimap: {
+                enabled: true
+            }
+        };      
+
+        this._editor = monaco.editor.create(
+            hostElement,
+            editorOptions
+        );
+
+        let response = await fetch("https://preview.babylonjs.com/babylon.d.ts");
+        if (!response.ok) {
+            return;
+        }
+
+        let libContent = await response.text();
+
+        response = await fetch("https://preview.babylonjs.com/gui/babylon.gui.d.ts");
+        if (!response.ok) {
+            return;
+        }
+
+        libContent += await response.text();
+
+        this.setupDefinitionWorker(libContent);
+
+        // Load code templates
+        response = await fetch("/templates.json");
+        if (response.ok) {
+      //      this._templates = await response.json();
+        }
+
+        // Setup the Monaco compilation pipeline, so we can reuse it directly for our scrpting needs
+        this.setupMonacoCompilationPipeline(libContent);
+
+        // This is used for a vscode-like color preview for ColorX types
+        this.setupMonacoColorProvider();
+    }
+
+      // Provide an adornment for BABYLON.ColorX types: color preview
+      setupMonacoColorProvider() {
+        monaco.languages.registerColorProvider(this.props.language == "JS" ? "javascript" : "typescript", {
+            provideColorPresentations: (model, colorInfo) => {
+                const color = colorInfo.color;
+
+                const precision = 100.0;
+                const converter = (n: number) => Math.round(n * precision) / precision;
+
+                let label;
+                if (color.alpha === undefined || color.alpha === 1.0) {
+                    label = `(${converter(color.red)}, ${converter(color.green)}, ${converter(color.blue)})`;
+                } else {
+                    label = `(${converter(color.red)}, ${converter(color.green)}, ${converter(color.blue)}, ${converter(color.alpha)})`;
+                }
+
+                return [{
+                    label: label
+                }];
+            },
+
+            provideDocumentColors: (model) => {
+                const digitGroup = "\\s*(\\d*(?:\\.\\d+)?)\\s*";
+                // we add \n{0} to workaround a Monaco bug, when setting regex options on their side
+                const regex = `BABYLON\\.Color(?:3|4)\\s*\\(${digitGroup},${digitGroup},${digitGroup}(?:,${digitGroup})?\\)\\n{0}`;
+                const matches = model.findMatches(regex, false, true, true, null, true);
+
+                const converter = (g: string) => g === undefined ? undefined : Number(g);
+
+                return matches.map(match => ({
+                    color: {
+                        red: converter(match.matches![1])!,
+                        green: converter(match.matches![2])!,
+                        blue: converter(match.matches![3])!,
+                        alpha: converter(match.matches![4])!
+                    },
+                    range: {
+                        startLineNumber: match.range.startLineNumber,
+                        startColumn: match.range.startColumn + match.matches![0].indexOf("("),
+                        endLineNumber: match.range.startLineNumber,
+                        endColumn: match.range.endColumn
+                    }
+                }));
+            }
+        });
+    }
+
+    // Setup both JS and TS compilation pipelines to work with our scripts. 
+    setupMonacoCompilationPipeline(libContent: string) {
+        const typescript = monaco.languages.typescript;
+
+        if (this.props.language == "JS") {
+            typescript.javascriptDefaults.setCompilerOptions({
+                noLib: false,
+                allowNonTsExtensions: true // required to prevent Uncaught Error: Could not find file: 'inmemory://model/1'.
+            });
+
+            typescript.javascriptDefaults.addExtraLib(libContent, 'babylon.d.ts');
+        } else {
+            typescript.typescriptDefaults.setCompilerOptions({
+                module: typescript.ModuleKind.AMD,
+                target: typescript.ScriptTarget.ESNext,
+                noLib: false,
+                strict: false,
+                alwaysStrict: false,
+                strictFunctionTypes: false,
+                suppressExcessPropertyErrors: false,
+                suppressImplicitAnyIndexErrors: true,
+                noResolve: true,
+                suppressOutputPathCheck: true,
+
+                allowNonTsExtensions: true // required to prevent Uncaught Error: Could not find file: 'inmemory://model/1'.
+            });
+            typescript.typescriptDefaults.addExtraLib(libContent, 'babylon.d.ts');
+        }
+    }
+
+    setupDefinitionWorker(libContent: string) {
+        this._definitionWorker = new Worker('workers/definitionWorker.js');
+        this._definitionWorker.addEventListener('message', ({
+            data
+        }) => {
+            this._deprecatedCandidates = data.result;
+            this.analyzeCode();
+        });
+        this._definitionWorker.postMessage({
+            code: libContent
+        });
+    }
+
+    // This will make sure that all members marked with a deprecated jsdoc attribute will be marked as such in Monaco UI
+    // We use a prefiltered list of deprecated candidates, because the effective call to getCompletionEntryDetails is slow.
+    // @see setupDefinitionWorker
+    async analyzeCode() {
+        // if the definition worker is very fast, this can be called out of context. @see setupDefinitionWorker
+        if (!this._editor)
+            return;
+
+        const model = this._editor.getModel();
+        if (!model)
+            return;
+
+        const uri = model.uri;
+
+        let worker = null;
+        if (this.props.language == "JS")
+            worker = await monaco.languages.typescript.getJavaScriptWorker();
+        else
+            worker = await monaco.languages.typescript.getTypeScriptWorker();
+
+        const languageService = await worker(uri);
+        const source = '[deprecated members]';
+
+        monaco.editor.setModelMarkers(model, source, []);
+        const markers: {
+            startLineNumber: number,
+            endLineNumber: number,
+            startColumn: number,
+            endColumn: number,
+            message: string,
+            severity: monaco.MarkerSeverity.Warning,
+            source: string,
+        }[] = [];
+
+        for (const candidate of this._deprecatedCandidates) {
+            const matches = model.findMatches(candidate, false, false, true, null, false);
+            for (const match of matches) {
+                const position = {
+                    lineNumber: match.range.startLineNumber,
+                    column: match.range.startColumn
+                };
+                const wordInfo = model.getWordAtPosition(position);
+                const offset = model.getOffsetAt(position);
+
+                if (!wordInfo) {
+                    continue;
+                }
+
+                // continue if we already found an issue here
+                if (markers.find(m => m.startLineNumber == position.lineNumber && m.startColumn == position.column))
+                    continue;
+
+                // the following is time consuming on all suggestions, that's why we precompute deprecated candidate names in the definition worker to filter calls
+                // @see setupDefinitionWorker
+                const details = await languageService.getCompletionEntryDetails(uri.toString(), offset, wordInfo.word);
+                if (this.isDeprecatedEntry(details)) {
+                    const deprecatedInfo = details.tags.find(this.isDeprecatedTag);
+                    markers.push({
+                        startLineNumber: match.range.startLineNumber,
+                        endLineNumber: match.range.endLineNumber,
+                        startColumn: wordInfo.startColumn,
+                        endColumn: wordInfo.endColumn,
+                        message: deprecatedInfo.text,
+                        severity: monaco.MarkerSeverity.Warning,
+                        source: source,
+                    });
+                }
+            }
+        }
+
+        monaco.editor.setModelMarkers(model, source, markers);
+    }
+
+    isDeprecatedEntry(details: any) {
+        return details &&
+            details.tags &&
+            details.tags.find(this.isDeprecatedTag);
+    }
+
+    isDeprecatedTag(tag: any) {
+        return tag &&
+            tag.name == "deprecated";
+    }
+
+    componentDidMount() {
+       this.setupMonaco();
+    }
+
+    public render() {
+
+        return (
+            <div id="monacoHost" ref={this._hostReference}>               
+            </div>   
+        )
+    }
+}

+ 2 - 0
Playground/src/globalState.ts

@@ -0,0 +1,2 @@
+export class GlobalState {
+}

+ 1 - 0
Playground/src/index.ts

@@ -0,0 +1 @@
+export * from "./playground";

+ 9 - 0
Playground/src/legacy/legacy.ts

@@ -0,0 +1,9 @@
+import { Playground } from "../index";
+
+var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : undefined);
+if (typeof globalObject !== "undefined") {
+    (<any>globalObject).BABYLON = (<any>globalObject).BABYLON || {};
+    (<any>globalObject).BABYLON.Playground = Playground;
+}
+
+export * from "../index";

+ 35 - 0
Playground/src/playground.tsx

@@ -0,0 +1,35 @@
+import * as React from "react";
+import * as ReactDOM from "react-dom";
+import { MonacoComponent } from './components/monacoComponent';
+//import { GlobalState } from './globalState';
+
+require("./scss/main.scss");
+
+interface IPlaygroundProps {
+}
+
+export class Playground extends React.Component<IPlaygroundProps, {errorMessage: string}> {
+    //private _globalState: GlobalState;
+    
+    public constructor(props: IPlaygroundProps) {
+        super(props);
+       // this._globalState = new GlobalState();
+
+       this.state = {errorMessage: ""};
+    }
+
+    public render() {
+
+        return (
+            <div id="root">  
+                <MonacoComponent language="JS"/>    
+            </div>   
+        )
+    }
+
+    public static Show(hostElement: HTMLElement) {
+        const playground = React.createElement(Playground, {});
+        
+        ReactDOM.render(playground, hostElement);
+    }
+}

+ 21 - 0
Playground/src/scss/main.scss

@@ -0,0 +1,21 @@
+html {
+    --background: #2A2342;
+    --footer-background: #201936;
+    --footer-height: 70px;
+    --button-hover-color: #BB464B;
+    --button-hover-hover: #e0684b;
+    --button-hover-background:  #162D3A;
+    --font-size: 20px;
+}
+
+html, body, #root {
+    width: 100%;
+    height: 100%;
+    padding: 0;
+    margin: 0;
+    overflow: hidden;
+    font-size: var(--font-size);
+    background: var(--background);
+    font-family: "acumin-pro-condensed";
+    font-weight: normal;    
+}

+ 6 - 0
Playground/src/scss/monaco.scss

@@ -0,0 +1,6 @@
+#monacoHost {
+    width: 100%;
+    height: 100%;
+    padding: 0;
+    margin: 0;
+}

+ 28 - 0
Playground/tsconfig.json

@@ -0,0 +1,28 @@
+{
+    "extends": "../tsconfigRules",
+    "compilerOptions": {
+        "jsx": "react",
+        "baseUrl": "./src/",
+        "rootDir": "./src/",
+        "paths": {
+            "babylonjs-gui/*": [
+                "../../dist/preview release/gui/babylon.gui.module.d.ts"
+            ],
+            "babylonjs-gltf2interface": [
+                "../../dist/preview release/glTF2Interface/babylon.glTF2Interface.d.ts"
+            ],
+            "babylonjs-loaders/*": [
+                "../../dist/preview release/loaders/babylonjs.loaders.module.d.ts"
+            ],
+            "babylonjs-materials/*": [
+                "../../dist/preview release/materialsLibrary/babylonjs.materials.module.d.ts"
+            ],
+            "babylonjs-serializers/*": [
+                "../../dist/preview release/serializers/babylonjs.serializers.module.d.ts"
+            ],
+            "babylonjs/*": [
+                "../../dist/preview release/babylon.module.d.ts"
+            ]
+        }
+    }
+}

+ 46 - 0
Playground/webpack.config.js

@@ -0,0 +1,46 @@
+const path = require("path");
+const MiniCssExtractPlugin = require("mini-css-extract-plugin");
+const babylonWebpackConfig = require('../Tools/WebpackPlugins/babylonWebpackConfig');
+
+var config = babylonWebpackConfig({
+    module: "playground",
+    resolve: {
+        extensions: [".js", '.ts', ".tsx"],
+    },
+    moduleRules: [
+        {
+            test: /\.scss$/,
+            use: [
+                // fallback to style-loader in development
+                process.env.NODE_ENV !== 'production' ? 'style-loader' : MiniCssExtractPlugin.loader,
+                "css-loader",
+                "sass-loader"
+            ]
+        }, 
+        {
+            test: /\.css$/,
+            use: ['style-loader', 'css-loader']
+        },
+        {
+            test: /\.svg$/,
+            use: [
+              {
+                loader: 'svg-url-loader',
+                options: {
+                  limit: 10000,
+                },
+              },
+            ],
+          }
+    ],
+    plugins: [
+        new MiniCssExtractPlugin({
+            // Options similar to the same options in webpackOptions.output
+            // both options are optional
+            filename: "[name].css",
+            chunkFilename: "[id].css"
+        })
+    ]
+});
+
+module.exports = config;

+ 52 - 2
Tools/Config/config.json

@@ -48,7 +48,8 @@
         "gui",
         "inspector",
         "nodeEditor",
-        "sandbox"
+        "sandbox",
+        "playground"
     ],
     "es6modules": [
         "core",
@@ -61,7 +62,8 @@
         "inspector",
         "viewer",
         "nodeEditor",
-        "sandbox"
+        "sandbox",
+        "playground"
     ],
     "lintModules": [
         "core",
@@ -686,6 +688,54 @@
             }
         }
     },
+    "playground": {
+        "libraries": [
+            {
+                "output": "babylon.playground.js",
+                "entry": "./legacy/legacy.ts"
+            }
+        ],
+        "build": {            
+            "ignoreInWorkerMode": true,
+            "ignoreInTestMode": true,
+            "mainFolder": "./playground/",
+            "uncheckedLintImports": [
+                "react",
+                "react-dom"
+            ],
+            "umd": {
+                "packageName": "babylonjs-playground",
+                "webpackRoot": "PLAYGROUND",
+                "processDeclaration": {
+                    "filename": "babylon.playground.module.d.ts",
+                    "moduleName": "PLAYGROUND",
+                    "importsToRemove": [],
+                    "classMap": {
+                        "babylonjs": "BABYLON",
+                        "react": "React",
+                        "@babylonjs/core": "BABYLON",
+                        "@fortawesome": false
+                    }
+                }
+            },
+            "es6": {
+                "webpackBuild": true,
+                "buildDependencies": [
+                    "Tools/**/*"
+                ],
+                "packageName": "@babylonjs/playground",
+                "readme": "dist/preview release/playground/readme-es6.md",
+                "packagesFiles": [
+                    "babylon.playground.max.js",
+                    "babylon.playground.max.js.map",
+                    "babylon.playground.module.d.ts",
+                    "readme.md"
+                ],
+                "typings": "babylon.playground.module.d.ts",
+                "index": "babylon.playground.max.js"
+            }
+        }
+    },
     "viewer": {
         "libraries": [
             {

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

@@ -48149,6 +48149,10 @@ declare module BABYLON {
          * A list of optional features to init the session with
          */
         optionalFeatures?: string[];
+        /**
+         * A list of optional features to init the session with
+         */
+        requiredFeatures?: string[];
     }
     /**
      * UI to allow the user to enter/exit XR mode

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 2 - 2
dist/preview release/babylon.js


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

@@ -125143,7 +125143,7 @@ var Mesh = /** @class */ (function (_super) {
             var colors = new Array();
             var pstring = new Array(); //lists facet vertex positions (a,b,c) as string "a|b|c"
             var indexPtr = 0; // pointer to next available index value
-            var uniquePositions = new Array(); // unique vertex positions
+            var uniquePositions = {}; // unique vertex positions
             var ptr; // pointer to element in uniquePositions
             var facet;
             for (var i = 0; i < currentIndices.length; i += 3) {
@@ -125158,7 +125158,6 @@ var Mesh = /** @class */ (function (_super) {
                         }
                         pstring[j] += currentPositions[3 * facet[j] + k] + "|";
                     }
-                    pstring[j] = pstring[j].slice(0, -1);
                 }
                 //check facet vertices to see that none are repeated
                 // do not process any facet that has a repeated vertex, ie is a line
@@ -125167,9 +125166,9 @@ var Mesh = /** @class */ (function (_super) {
                     // if not listed add to uniquePositions and set index pointer
                     // if listed use its index in uniquePositions and new index pointer
                     for (var j = 0; j < 3; j++) {
-                        ptr = uniquePositions.indexOf(pstring[j]);
-                        if (ptr < 0) {
-                            uniquePositions.push(pstring[j]);
+                        ptr = uniquePositions[pstring[j]];
+                        if (ptr === undefined) {
+                            uniquePositions[pstring[j]] = indexPtr;
                             ptr = indexPtr++;
                             //not listed so add individual x, y, z coordinates to positions
                             for (var k = 0; k < 3; k++) {
@@ -137865,7 +137864,7 @@ var KhronosTextureContainer2 = /** @class */ (function () {
         var _this = this;
         if (!KhronosTextureContainer2._ModulePromise) {
             KhronosTextureContainer2._ModulePromise = new Promise(function (resolve) {
-                LIBKTX().then(function (module) {
+                LIBKTX({ preinitializedWebGLContext: engine._gl }).then(function (module) {
                     module.GL.makeContextCurrent(module.GL.registerContext(engine._gl, { majorVersion: engine._webGLVersion }));
                     KhronosTextureContainer2._TranscodeFormat = _this._determineTranscodeFormat(module.TranscodeTarget, engine.getCaps());
                     resolve({ module: module });
@@ -137878,7 +137877,7 @@ var KhronosTextureContainer2 = /** @class */ (function () {
             var module = moduleWrapper.module;
             var ktxTexture = new module.ktxTexture(data);
             try {
-                if (ktxTexture.isBasisSupercompressed) {
+                if (ktxTexture.needsTranscoding) {
                     ktxTexture.transcodeBasis(KhronosTextureContainer2._TranscodeFormat, 0);
                 }
                 internalTexture.width = internalTexture.baseWidth = ktxTexture.baseWidth;
@@ -182654,6 +182653,8 @@ var WebXRMotionControllerTeleportation = /** @class */ (function (_super) {
         if (!_super.prototype.attach.call(this)) {
             return false;
         }
+        // Safety reset
+        this._currentTeleportationControllerId = '';
         this._options.xrInput.controllers.forEach(this._attachController);
         this._addNewAttachObserver(this._options.xrInput.onControllerAddedObservable, this._attachController);
         this._addNewAttachObserver(this._options.xrInput.onControllerRemovedObservable, function (controller) {
@@ -182671,6 +182672,7 @@ var WebXRMotionControllerTeleportation = /** @class */ (function (_super) {
             _this._detachController(controllerId);
         });
         this._setTargetMeshVisibility(false);
+        this._currentTeleportationControllerId = '';
         return true;
     };
     WebXRMotionControllerTeleportation.prototype.dispose = function () {
@@ -186504,7 +186506,7 @@ var WebXREnterExitUI = /** @class */ (function () {
                                     _a.label = 3;
                                 case 3:
                                     _a.trys.push([3, 5, , 6]);
-                                    return [4 /*yield*/, helper.enterXRAsync(ui._buttons[i].sessionMode, ui._buttons[i].referenceSpaceType, options.renderTarget, { optionalFeatures: options.optionalFeatures })];
+                                    return [4 /*yield*/, helper.enterXRAsync(ui._buttons[i].sessionMode, ui._buttons[i].referenceSpaceType, options.renderTarget, { optionalFeatures: options.optionalFeatures, requiredFeatures: options.requiredFeatures })];
                                 case 4:
                                     _a.sent();
                                     ui._updateButtons(ui._buttons[i]);

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/babylon.max.js.map


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

@@ -49940,6 +49940,10 @@ declare module "babylonjs/XR/webXREnterExitUI" {
          * A list of optional features to init the session with
          */
         optionalFeatures?: string[];
+        /**
+         * A list of optional features to init the session with
+         */
+        requiredFeatures?: string[];
     }
     /**
      * UI to allow the user to enter/exit XR mode
@@ -126383,6 +126387,10 @@ declare module BABYLON {
          * A list of optional features to init the session with
          */
         optionalFeatures?: string[];
+        /**
+         * A list of optional features to init the session with
+         */
+        requiredFeatures?: string[];
     }
     /**
      * UI to allow the user to enter/exit XR mode

+ 27 - 0
dist/preview release/documentation.d.ts

@@ -48149,6 +48149,10 @@ declare module BABYLON {
          * A list of optional features to init the session with
          */
         optionalFeatures?: string[];
+        /**
+         * A list of optional features to init the session with
+         */
+        requiredFeatures?: string[];
     }
     /**
      * UI to allow the user to enter/exit XR mode
@@ -80808,22 +80812,45 @@ declare module BABYLON.GLTF2.Loader.Extensions {
          */
         static GetAvailableVariants(rootMesh: Mesh): string[];
         /**
+         * Gets the list of available variant tag names for this asset.
+         * @param rootMesh The glTF root mesh
+         * @returns the list of all the variant names for this model
+         */
+        getAvailableVariants(rootMesh: Mesh): string[];
+        /**
          * Select a variant given a variant tag name or a list of variant tag names.
          * @param rootMesh The glTF root mesh
          * @param variantName The variant name(s) to select.
          */
         static SelectVariant(rootMesh: Mesh, variantName: string | string[]): void;
         /**
+         * Select a variant given a variant tag name or a list of variant tag names.
+         * @param rootMesh The glTF root mesh
+         * @param variantName The variant name(s) to select.
+         */
+        selectVariant(rootMesh: Mesh, variantName: string | string[]): void;
+        /**
          * Reset back to the original before selecting a variant.
          * @param rootMesh The glTF root mesh
          */
         static Reset(rootMesh: Mesh): void;
         /**
+         * Reset back to the original before selecting a variant.
+         * @param rootMesh The glTF root mesh
+         */
+        reset(rootMesh: Mesh): void;
+        /**
          * Gets the last selected variant tag name(s) or null if original.
          * @param rootMesh The glTF root mesh
          * @returns The selected variant tag name(s).
          */
         static GetLastSelectedVariant(rootMesh: Mesh): Nullable<string | string[]>;
+        /**
+         * Gets the last selected variant tag name(s) or null if original.
+         * @param rootMesh The glTF root mesh
+         * @returns The selected variant tag name(s).
+         */
+        getLastSelectedVariant(rootMesh: Mesh): Nullable<string | string[]>;
         private static _GetExtensionMetadata;
         /** @hidden */
         _loadMeshPrimitiveAsync(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Nullable<Promise<AbstractMesh>>;

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

@@ -7,7 +7,7 @@
 		exports["babylonjs-gui"] = factory(require("babylonjs"));
 	else
 		root["BABYLON"] = root["BABYLON"] || {}, root["BABYLON"]["GUI"] = factory(root["BABYLON"]);
-})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_Maths_math_vector__) {
+})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_observable__) {
 return /******/ (function(modules) { // webpackBootstrap
 /******/ 	// The module cache
 /******/ 	var installedModules = {};
@@ -400,7 +400,7 @@ module.exports = g;
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AdvancedDynamicTextureInstrumentation", function() { return AdvancedDynamicTextureInstrumentation; });
-/* harmony import */ var babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/perfCounter */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/perfCounter */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0__);
 
 /**
@@ -543,7 +543,7 @@ var AdvancedDynamicTextureInstrumentation = /** @class */ (function () {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AdvancedDynamicTexture", function() { return AdvancedDynamicTexture; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _controls_container__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./controls/container */ "./2D/controls/container.ts");
 /* harmony import */ var _style__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./style */ "./2D/style.ts");
@@ -1515,7 +1515,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _textBlock__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./textBlock */ "./2D/controls/textBlock.ts");
 /* harmony import */ var _image__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./image */ "./2D/controls/image.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5__);
 
 
@@ -1747,7 +1747,7 @@ babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5__["_TypeStore"].RegisteredTy
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Checkbox", function() { return Checkbox; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
@@ -1930,7 +1930,7 @@ babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].RegisteredT
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ColorPicker", function() { return ColorPicker; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _inputText__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./inputText */ "./2D/controls/inputText.ts");
@@ -3319,7 +3319,7 @@ babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].RegisteredT
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Container", function() { return Container; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/logger */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/logger */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../measure */ "./2D/measure.ts");
@@ -3734,7 +3734,7 @@ babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].RegisteredTypes
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Control", function() { return Control; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../measure */ "./2D/measure.ts");
@@ -5660,7 +5660,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DisplayGrid", function() { return DisplayGrid; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
@@ -5893,7 +5893,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__);
 
 
@@ -5990,7 +5990,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4__);
 
 
@@ -6448,7 +6448,7 @@ babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4__["_TypeStore"].RegisteredTypes[
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Image", function() { return Image; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 
@@ -7375,7 +7375,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InputPassword", function() { return InputPassword; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _inputText__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./inputText */ "./2D/controls/inputText.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
@@ -7414,7 +7414,7 @@ babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__["_TypeStore"].RegisteredTy
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InputText", function() { return InputText; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
@@ -8427,7 +8427,7 @@ babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].RegisteredT
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Line", function() { return Line; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
@@ -8698,7 +8698,7 @@ babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].Registere
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiLine", function() { return MultiLine; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/abstractMesh */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/abstractMesh */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _multiLinePoint__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../multiLinePoint */ "./2D/multiLinePoint.ts");
@@ -8968,7 +8968,7 @@ babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].Registe
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RadioButton", function() { return RadioButton; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
@@ -9175,7 +9175,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Rectangle", function() { return Rectangle; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
@@ -9325,7 +9325,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _scrollViewerWindow__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./scrollViewerWindow */ "./2D/controls/scrollViewers/scrollViewerWindow.ts");
 /* harmony import */ var _sliders_scrollBar__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../sliders/scrollBar */ "./2D/controls/sliders/scrollBar.ts");
 /* harmony import */ var _sliders_imageScrollBar__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../sliders/imageScrollBar */ "./2D/controls/sliders/imageScrollBar.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7__);
 
 
@@ -10948,7 +10948,7 @@ var SelectionPanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BaseSlider", function() { return BaseSlider; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../control */ "./2D/controls/control.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../valueAndUnit */ "./2D/valueAndUnit.ts");
@@ -11278,7 +11278,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _baseSlider__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./baseSlider */ "./2D/controls/sliders/baseSlider.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../measure */ "./2D/measure.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__);
 
 
@@ -11871,7 +11871,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Slider", function() { return Slider; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _baseSlider__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./baseSlider */ "./2D/controls/sliders/baseSlider.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
@@ -12126,7 +12126,7 @@ babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__["_TypeStore"].RegisteredTy
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StackPanel", function() { return StackPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
@@ -12394,7 +12394,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextWrapping", function() { return TextWrapping; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextBlock", function() { return TextBlock; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
@@ -12857,7 +12857,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KeyPropertySet", function() { return KeyPropertySet; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VirtualKeyboard", function() { return VirtualKeyboard; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
 /* harmony import */ var _button__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./button */ "./2D/controls/button.ts");
@@ -13246,7 +13246,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector2WithInfo", function() { return Vector2WithInfo; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Matrix2D", function() { return Matrix2D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 
 
@@ -13471,7 +13471,7 @@ var Matrix2D = /** @class */ (function () {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Measure", function() { return Measure; });
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 
 var tmpRect = [
@@ -13620,7 +13620,7 @@ var Measure = /** @class */ (function () {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiLinePoint", function() { return MultiLinePoint; });
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./valueAndUnit */ "./2D/valueAndUnit.ts");
 
@@ -13763,7 +13763,7 @@ var MultiLinePoint = /** @class */ (function () {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Style", function() { return Style; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./valueAndUnit */ "./2D/valueAndUnit.ts");
 
@@ -14069,7 +14069,7 @@ var ValueAndUnit = /** @class */ (function () {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "XmlLoader", function() { return XmlLoader; });
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0__);
 
 /**
@@ -14388,7 +14388,7 @@ var XmlLoader = /** @class */ (function () {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AbstractButton3D", function() { return AbstractButton3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control3D */ "./3D/controls/control3D.ts");
 
@@ -14431,7 +14431,7 @@ var AbstractButton3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Button3D", function() { return Button3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _abstractButton3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./abstractButton3D */ "./3D/controls/abstractButton3D.ts");
 /* harmony import */ var _2D_advancedDynamicTexture__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../2D/advancedDynamicTexture */ "./2D/advancedDynamicTexture.ts");
@@ -14612,7 +14612,7 @@ var Button3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Container3D", function() { return Container3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control3D */ "./3D/controls/control3D.ts");
 
@@ -14769,7 +14769,7 @@ var Container3D = /** @class */ (function (_super) {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Control3D", function() { return Control3D; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _vector3WithInfo__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../vector3WithInfo */ "./3D/vector3WithInfo.ts");
 
@@ -15175,7 +15175,7 @@ var Control3D = /** @class */ (function () {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CylinderPanel", function() { return CylinderPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
@@ -15261,7 +15261,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HolographicButton", function() { return HolographicButton; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _button3D__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./button3D */ "./3D/controls/button3D.ts");
-/* harmony import */ var babylonjs_Materials_standardMaterial__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Materials/standardMaterial */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Materials_standardMaterial__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Materials/standardMaterial */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Materials_standardMaterial__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_standardMaterial__WEBPACK_IMPORTED_MODULE_2__);
 /* harmony import */ var _materials_fluentMaterial__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../materials/fluentMaterial */ "./3D/materials/fluentMaterial.ts");
 /* harmony import */ var _2D_controls_stackPanel__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../2D/controls/stackPanel */ "./2D/controls/stackPanel.ts");
@@ -15755,7 +15755,7 @@ var MeshButton3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PlanePanel", function() { return PlanePanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
@@ -15810,7 +15810,7 @@ var PlanePanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ScatterPanel", function() { return ScatterPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
@@ -15937,7 +15937,7 @@ var ScatterPanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpherePanel", function() { return SpherePanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
@@ -16023,7 +16023,7 @@ var SpherePanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StackPanel3D", function() { return StackPanel3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 
@@ -16148,7 +16148,7 @@ var StackPanel3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VolumeBasedPanel", function() { return VolumeBasedPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 
@@ -16339,7 +16339,7 @@ var VolumeBasedPanel = /** @class */ (function (_super) {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GUI3DManager", function() { return GUI3DManager; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _controls_container3D__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./controls/container3D */ "./3D/controls/container3D.ts");
 
@@ -16606,7 +16606,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FluentMaterialDefines", function() { return FluentMaterialDefines; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FluentMaterial", function() { return FluentMaterial; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/decorators */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/decorators */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _shaders_fluent_vertex__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./shaders/fluent.vertex */ "./3D/materials/shaders/fluent.vertex.ts");
 /* harmony import */ var _shaders_fluent_fragment__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./shaders/fluent.fragment */ "./3D/materials/shaders/fluent.fragment.ts");
@@ -16929,7 +16929,7 @@ __webpack_require__.r(__webpack_exports__);
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fluentPixelShader", function() { return fluentPixelShader; });
-/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__);
 
 var name = 'fluentPixelShader';
@@ -16951,7 +16951,7 @@ var fluentPixelShader = { name: name, shader: shader };
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fluentVertexShader", function() { return fluentVertexShader; });
-/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__);
 
 var name = 'fluentVertexShader';
@@ -16974,7 +16974,7 @@ var fluentVertexShader = { name: name, shader: shader };
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector3WithInfo", function() { return Vector3WithInfo; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/observable");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 
 
@@ -17276,14 +17276,14 @@ if (typeof globalObject !== "undefined") {
 
 /***/ }),
 
-/***/ "babylonjs/Maths/math.vector":
+/***/ "babylonjs/Misc/observable":
 /*!****************************************************************************************************!*\
   !*** external {"root":"BABYLON","commonjs":"babylonjs","commonjs2":"babylonjs","amd":"babylonjs"} ***!
   \****************************************************************************************************/
 /*! no static exports found */
 /***/ (function(module, exports) {
 
-module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_Maths_math_vector__;
+module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_observable__;
 
 /***/ })
 

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/gui/babylon.gui.js.map


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 6 - 6
dist/preview release/inspector/babylon.inspector.bundle.js


+ 358 - 106
dist/preview release/inspector/babylon.inspector.bundle.max.js

@@ -1,13 +1,13 @@
 (function webpackUniversalModuleDefinition(root, factory) {
 	if(typeof exports === 'object' && typeof module === 'object')
-		module.exports = factory(require("babylonjs-gui"), require("babylonjs-loaders"), require("babylonjs-loaders"), require("babylonjs-materials"), require("babylonjs-serializers"), require("babylonjs"));
+		module.exports = factory(require("babylonjs-gui"), require("babylonjs-loaders"), require("babylonjs-materials"), require("babylonjs-serializers"), require("babylonjs"));
 	else if(typeof define === 'function' && define.amd)
-		define("babylonjs-inspector", ["babylonjs-gui", "babylonjs-loaders", "babylonjs-loaders", "babylonjs-materials", "babylonjs-serializers", "babylonjs"], factory);
+		define("babylonjs-inspector", ["babylonjs-gui", "babylonjs-loaders", "babylonjs-materials", "babylonjs-serializers", "babylonjs"], factory);
 	else if(typeof exports === 'object')
-		exports["babylonjs-inspector"] = factory(require("babylonjs-gui"), require("babylonjs-loaders"), require("babylonjs-loaders"), require("babylonjs-materials"), require("babylonjs-serializers"), require("babylonjs"));
+		exports["babylonjs-inspector"] = factory(require("babylonjs-gui"), require("babylonjs-loaders"), require("babylonjs-materials"), require("babylonjs-serializers"), require("babylonjs"));
 	else
-		root["INSPECTOR"] = factory(root["BABYLON"]["GUI"], root["BABYLON"]["GLTF2"]["Loader"]["Extensions"], root["BABYLON"], root["BABYLON"], root["BABYLON"], root["BABYLON"]);
-})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_gui_2D_controls_image__, __WEBPACK_EXTERNAL_MODULE_babylonjs_loaders_glTF_2_0_Extensions_KHR_materials_variants__, __WEBPACK_EXTERNAL_MODULE_babylonjs_loaders_glTF_index__, __WEBPACK_EXTERNAL_MODULE_babylonjs_materials_grid_gridMaterial__, __WEBPACK_EXTERNAL_MODULE_babylonjs_serializers_glTF_2_0_index__, __WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_observable__) {
+		root["INSPECTOR"] = factory(root["BABYLON"]["GUI"], root["BABYLON"], root["BABYLON"], root["BABYLON"], root["BABYLON"]);
+})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_gui_2D_controls_image__, __WEBPACK_EXTERNAL_MODULE_babylonjs_loaders_glTF_index__, __WEBPACK_EXTERNAL_MODULE_babylonjs_materials_grid_gridMaterial__, __WEBPACK_EXTERNAL_MODULE_babylonjs_serializers_glTF_2_0_index__, __WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_observable__) {
 return /******/ (function(modules) { // webpackBootstrap
 /******/ 	// The module cache
 /******/ 	var installedModules = {};
@@ -11322,6 +11322,24 @@ module.exports = exports;
 
 /***/ }),
 
+/***/ "../../node_modules/css-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js!./components/actionTabs/tabs/propertyGrids/materials/textures/textureEditor.scss":
+/*!*********************************************************************************************************************************************************************************************************!*\
+  !*** D:/Repos/Babylon.js/node_modules/css-loader/dist/cjs.js!D:/Repos/Babylon.js/node_modules/sass-loader/dist/cjs.js!./components/actionTabs/tabs/propertyGrids/materials/textures/textureEditor.scss ***!
+  \*********************************************************************************************************************************************************************************************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+// Imports
+var ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../../../../../../node_modules/css-loader/dist/runtime/api.js */ "../../node_modules/css-loader/dist/runtime/api.js");
+exports = ___CSS_LOADER_API_IMPORT___(false);
+// Module
+exports.push([module.i, "#texture-canvas {\n  width: 100%;\n  height: 100%; }\n", ""]);
+// Exports
+module.exports = exports;
+
+
+/***/ }),
+
 /***/ "../../node_modules/css-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js!./components/embedHost/embedHost.scss":
 /*!**************************************************************************************************************************************************************!*\
   !*** D:/Repos/Babylon.js/node_modules/css-loader/dist/cjs.js!D:/Repos/Babylon.js/node_modules/sass-loader/dist/cjs.js!./components/embedHost/embedHost.scss ***!
@@ -64893,7 +64911,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../../../lines/floatLineComponent */ "./components/actionTabs/lines/floatLineComponent.tsx");
 /* harmony import */ var _lines_textLineComponent__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../../../lines/textLineComponent */ "./components/actionTabs/lines/textLineComponent.tsx");
 /* harmony import */ var _animations_animationCurveEditorComponent__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../animations/animationCurveEditorComponent */ "./components/actionTabs/tabs/propertyGrids/animations/animationCurveEditorComponent.tsx");
-/* harmony import */ var _animations_popupComponent__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../animations/popupComponent */ "./components/actionTabs/tabs/propertyGrids/animations/popupComponent.tsx");
+/* harmony import */ var _popupComponent__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../../../../popupComponent */ "./components/popupComponent.tsx");
 
 
 
@@ -65033,7 +65051,7 @@ var AnimationGridComponent = /** @class */ (function (_super) {
                     animations.map(function (anim, i) {
                         return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_8__["TextLineComponent"], { key: anim.targetProperty + i, label: '#' + i + ' >', value: anim.targetProperty }));
                     }),
-                    this._isCurveEditorOpen && (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_animations_popupComponent__WEBPACK_IMPORTED_MODULE_10__["PopupComponent"], { id: 'curve-editor', title: 'Curve Animation Editor', size: { width: 1024, height: 490 }, onOpen: function (window) { }, onClose: function (window) {
+                    this._isCurveEditorOpen && (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_popupComponent__WEBPACK_IMPORTED_MODULE_10__["PopupComponent"], { id: 'curve-editor', title: 'Curve Animation Editor', size: { width: 1024, height: 490 }, onOpen: function (window) { }, onClose: function (window) {
                             return _this.onCloseAnimationCurveEditor(window);
                         } },
                         react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_animations_animationCurveEditorComponent__WEBPACK_IMPORTED_MODULE_9__["AnimationCurveEditorComponent"], { scene: this.props.scene, entity: animatableAsAny, close: function (event) {
@@ -66043,81 +66061,6 @@ var Notification = /** @class */ (function (_super) {
 
 /***/ }),
 
-/***/ "./components/actionTabs/tabs/propertyGrids/animations/popupComponent.tsx":
-/*!********************************************************************************!*\
-  !*** ./components/actionTabs/tabs/propertyGrids/animations/popupComponent.tsx ***!
-  \********************************************************************************/
-/*! exports provided: PopupComponent */
-/***/ (function(module, __webpack_exports__, __webpack_require__) {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PopupComponent", function() { return PopupComponent; });
-/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react */ "../../node_modules/react/index.js");
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
-/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react-dom */ "../../node_modules/react-dom/index.js");
-/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_2__);
-/* harmony import */ var _inspector__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../../../../inspector */ "./inspector.ts");
-
-
-
-
-var PopupComponent = /** @class */ (function (_super) {
-    Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(PopupComponent, _super);
-    function PopupComponent(props) {
-        var _this = _super.call(this, props) || this;
-        _this._container = document.createElement('div');
-        _this._container.id = _this.props.id;
-        _this._window;
-        _this.state = {
-            isComponentMounted: false,
-            blockedByBrowser: false,
-        };
-        return _this;
-    }
-    PopupComponent.prototype.componentDidMount = function () {
-        this.openPopup();
-        this.setState({ isComponentMounted: true });
-    };
-    PopupComponent.prototype.openPopup = function () {
-        var _this = this;
-        var _a = this.props, title = _a.title, size = _a.size, onClose = _a.onClose, onOpen = _a.onOpen;
-        var windowVariableName = "window_" + title;
-        this._container = _inspector__WEBPACK_IMPORTED_MODULE_3__["Inspector"]._CreatePopup(title, windowVariableName, size.width, size.height);
-        this._window = _inspector__WEBPACK_IMPORTED_MODULE_3__["Inspector"][windowVariableName];
-        if (this._window) {
-            onOpen(this._window);
-            this._window.addEventListener('beforeunload', function () { return _this._window && onClose(_this._window); });
-        }
-        else {
-            if (!this._window) {
-                this.setState({ blockedByBrowser: true }, function () {
-                    if (_this.state.blockedByBrowser) {
-                        alert("You might have blocked popups in your browser");
-                        console.warn("Popup window couldn't be created");
-                    }
-                });
-            }
-        }
-    };
-    PopupComponent.prototype.componentWillUnmount = function () {
-        if (this._window) {
-            this._window.close();
-        }
-    };
-    PopupComponent.prototype.render = function () {
-        if (!this.state.isComponentMounted || this._container === null)
-            return null;
-        return react_dom__WEBPACK_IMPORTED_MODULE_2__["createPortal"](this.props.children, this._container);
-    };
-    return PopupComponent;
-}(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));
-
-
-
-/***/ }),
-
 /***/ "./components/actionTabs/tabs/propertyGrids/animations/saveSnippet.tsx":
 /*!*****************************************************************************!*\
   !*** ./components/actionTabs/tabs/propertyGrids/animations/saveSnippet.tsx ***!
@@ -66517,7 +66460,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _lineContainerComponent__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../../lineContainerComponent */ "./components/actionTabs/lineContainerComponent.tsx");
 /* harmony import */ var _lines_textLineComponent__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../../lines/textLineComponent */ "./components/actionTabs/lines/textLineComponent.tsx");
 /* harmony import */ var _lines_textInputLineComponent__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../../lines/textInputLineComponent */ "./components/actionTabs/lines/textInputLineComponent.tsx");
-/* harmony import */ var _animations_popupComponent__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../animations/popupComponent */ "./components/actionTabs/tabs/propertyGrids/animations/popupComponent.tsx");
+/* harmony import */ var _popupComponent__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../../../popupComponent */ "./components/popupComponent.tsx");
 /* harmony import */ var _animations_animationCurveEditorComponent__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../animations/animationCurveEditorComponent */ "./components/actionTabs/tabs/propertyGrids/animations/animationCurveEditorComponent.tsx");
 
 
@@ -66582,7 +66525,7 @@ var TargetedAnimationGridComponent = /** @class */ (function (_super) {
                         return _this.props.globalState.onSelectionChangedObservable.notifyObservers(targetedAnimation);
                     } })),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_buttonLineComponent__WEBPACK_IMPORTED_MODULE_2__["ButtonLineComponent"], { label: 'Edit animation', onClick: function () { return _this.onOpenAnimationCurveEditor(); } }),
-                this._isCurveEditorOpen && (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_animations_popupComponent__WEBPACK_IMPORTED_MODULE_6__["PopupComponent"], { id: 'curve-editor', title: 'Curve Animation Editor', size: { width: 1024, height: 512 }, onOpen: function (window) { }, onClose: function (window) {
+                this._isCurveEditorOpen && (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_popupComponent__WEBPACK_IMPORTED_MODULE_6__["PopupComponent"], { id: 'curve-editor', title: 'Curve Animation Editor', size: { width: 1024, height: 512 }, onOpen: function (window) { }, onClose: function (window) {
                         return _this.onCloseAnimationCurveEditor(window);
                     } },
                     react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_animations_animationCurveEditorComponent__WEBPACK_IMPORTED_MODULE_7__["AnimationCurveEditorComponent"], { scene: this.props.scene, entity: targetedAnimation, playOrPause: function () { return _this.playOrPause(); }, lockObject: this.props.lockObject, globalState: this.props.globalState, close: function (event) { return _this.onCloseAnimationCurveEditor(event.view); } }))),
@@ -69705,6 +69648,11 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _lines_buttonLineComponent__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../../../lines/buttonLineComponent */ "./components/actionTabs/lines/buttonLineComponent.tsx");
 /* harmony import */ var _lines_textInputLineComponent__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../../../lines/textInputLineComponent */ "./components/actionTabs/lines/textInputLineComponent.tsx");
 /* harmony import */ var _animations_animationPropertyGridComponent__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../animations/animationPropertyGridComponent */ "./components/actionTabs/tabs/propertyGrids/animations/animationPropertyGridComponent.tsx");
+/* harmony import */ var _popupComponent__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../../../../popupComponent */ "./components/popupComponent.tsx");
+/* harmony import */ var _textures_textureEditorComponent__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./textures/textureEditorComponent */ "./components/actionTabs/tabs/propertyGrids/materials/textures/textureEditorComponent.tsx");
+
+
+
 
 
 
@@ -69727,6 +69675,7 @@ var TexturePropertyGridComponent = /** @class */ (function (_super) {
     Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(TexturePropertyGridComponent, _super);
     function TexturePropertyGridComponent(props) {
         var _this = _super.call(this, props) || this;
+        _this._isTextureEditorOpen = false;
         var texture = _this.props.texture;
         _this.textureLineRef = react__WEBPACK_IMPORTED_MODULE_1__["createRef"]();
         if (!texture || !texture.rootContainer) {
@@ -69761,15 +69710,24 @@ var TexturePropertyGridComponent = /** @class */ (function (_super) {
                     else if (file.name.toLowerCase().indexOf(".env") > 0) {
                         extension = ".env";
                     }
-                    texture.updateURL(base64data, extension, function () { return _this.foreceRefresh(); });
+                    texture.updateURL(base64data, extension, function () { return _this.forceRefresh(); });
                 }
                 else {
-                    texture.updateURL(base64data, null, function () { return _this.foreceRefresh(); });
+                    texture.updateURL(base64data, null, function () { return _this.forceRefresh(); });
                 }
             };
         }, undefined, true);
     };
-    TexturePropertyGridComponent.prototype.foreceRefresh = function () {
+    TexturePropertyGridComponent.prototype.onOpenTextureEditor = function () {
+        this._isTextureEditorOpen = true;
+    };
+    TexturePropertyGridComponent.prototype.onCloseTextureEditor = function (window) {
+        this._isTextureEditorOpen = false;
+        if (window !== null) {
+            window.close();
+        }
+    };
+    TexturePropertyGridComponent.prototype.forceRefresh = function () {
         this.forceUpdate();
         this.textureLineRef.current.updatePreview();
     };
@@ -69804,14 +69762,21 @@ var TexturePropertyGridComponent = /** @class */ (function (_super) {
                 extension = textureUrl[index] + extension;
             }
         }
+        var editable = texture.textureType != babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_2__["Engine"].TEXTURETYPE_FLOAT && texture.textureType != babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_2__["Engine"].TEXTURETYPE_FLOAT_32_UNSIGNED_INT_24_8_REV && texture.textureType !== babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_2__["Engine"].TEXTURETYPE_HALF_FLOAT;
         return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", { className: "pane" },
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_3__["LineContainerComponent"], { globalState: this.props.globalState, title: "PREVIEW" },
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLineComponent__WEBPACK_IMPORTED_MODULE_7__["TextureLineComponent"], { ref: this.textureLineRef, texture: texture, width: 256, height: 256, globalState: this.props.globalState }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_fileButtonLineComponent__WEBPACK_IMPORTED_MODULE_10__["FileButtonLineComponent"], { label: "Load texture from file", onClick: function (file) { return _this.updateTexture(file); }, accept: ".jpg, .png, .tga, .dds, .env" }),
+                editable &&
+                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_buttonLineComponent__WEBPACK_IMPORTED_MODULE_14__["ButtonLineComponent"], { label: "View", onClick: function () { return _this.onOpenTextureEditor(); } }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textInputLineComponent__WEBPACK_IMPORTED_MODULE_15__["TextInputLineComponent"], { label: "URL", value: textureUrl, lockObject: this.props.lockObject, onChange: function (url) {
                         texture.updateURL(url);
-                        _this.foreceRefresh();
+                        _this.forceRefresh();
                     } })),
+            this._isTextureEditorOpen && (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_popupComponent__WEBPACK_IMPORTED_MODULE_17__["PopupComponent"], { id: 'texture-editor', title: 'Texture Editor', size: { width: 1024, height: 490 }, onOpen: function (window) { }, onClose: function (window) {
+                    return _this.onCloseTextureEditor(window);
+                } },
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_textures_textureEditorComponent__WEBPACK_IMPORTED_MODULE_18__["TextureEditorComponent"], { globalState: this.props.globalState, texture: this.props.texture }))),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_customPropertyGridComponent__WEBPACK_IMPORTED_MODULE_13__["CustomPropertyGridComponent"], { globalState: this.props.globalState, target: texture, lockObject: this.props.lockObject, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_3__["LineContainerComponent"], { globalState: this.props.globalState, title: "GENERAL" },
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_5__["TextLineComponent"], { label: "Width", value: texture.getSize().width.toString() }),
@@ -69885,6 +69850,221 @@ var TexturePropertyGridComponent = /** @class */ (function (_super) {
 
 /***/ }),
 
+/***/ "./components/actionTabs/tabs/propertyGrids/materials/textures/textureCanvasManager.ts":
+/*!*********************************************************************************************!*\
+  !*** ./components/actionTabs/tabs/propertyGrids/materials/textures/textureCanvasManager.ts ***!
+  \*********************************************************************************************/
+/*! exports provided: TextureCanvasManager */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextureCanvasManager", function() { return TextureCanvasManager; });
+/* harmony import */ var babylonjs_Engines_engine__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Engines/engine */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Engines_engine__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Engines_engine__WEBPACK_IMPORTED_MODULE_0__);
+
+
+
+
+
+
+
+
+
+
+
+var TextureCanvasManager = /** @class */ (function () {
+    function TextureCanvasManager(targetCanvas, texture) {
+        var _this = this;
+        this._canvas = targetCanvas;
+        this._engine = new babylonjs_Engines_engine__WEBPACK_IMPORTED_MODULE_0__["Engine"](targetCanvas, true);
+        this._scene = new babylonjs_Engines_engine__WEBPACK_IMPORTED_MODULE_0__["Scene"](this._engine);
+        this._scene.clearColor = new babylonjs_Engines_engine__WEBPACK_IMPORTED_MODULE_0__["Color4"](0.2, 0.2, 0.2, 1.0);
+        this._camera = new babylonjs_Engines_engine__WEBPACK_IMPORTED_MODULE_0__["FreeCamera"]("Camera", new babylonjs_Engines_engine__WEBPACK_IMPORTED_MODULE_0__["Vector3"](0, 0, -1), this._scene);
+        this._camera.mode = babylonjs_Engines_engine__WEBPACK_IMPORTED_MODULE_0__["Camera"].ORTHOGRAPHIC_CAMERA;
+        if (texture) {
+            /* Grab image data from original texture and paint it onto the context of a DynamicTexture */
+            var pixelData = texture.readPixels();
+            var arr = new Uint8ClampedArray(pixelData.buffer);
+            var imgData = new ImageData(arr, texture.getSize().width, texture.getSize().height);
+            this._texture = new babylonjs_Engines_engine__WEBPACK_IMPORTED_MODULE_0__["DynamicTexture"]("texture", texture.getSize(), this._scene, false);
+            var ctx = this._texture.getContext();
+            ctx.putImageData(imgData, 0, 0);
+            this._texture.update();
+            this._texture.hasAlpha = texture.hasAlpha;
+        }
+        else {
+            /* If we don't have a texture to start with, just generate a white rectangle */
+            this._texture = new babylonjs_Engines_engine__WEBPACK_IMPORTED_MODULE_0__["DynamicTexture"]("texture", 256, this._scene, false);
+            var ctx = this._texture.getContext();
+            ctx.fillStyle = 'white';
+            ctx.fillRect(0, 0, 256, 256);
+            this._texture.update();
+        }
+        this._texture.updateSamplingMode(babylonjs_Engines_engine__WEBPACK_IMPORTED_MODULE_0__["Engine"].TEXTURE_NEAREST_LINEAR);
+        var textureRatio = this._texture.getSize().width / this._texture.getSize().height;
+        this._plane = babylonjs_Engines_engine__WEBPACK_IMPORTED_MODULE_0__["PlaneBuilder"].CreatePlane("plane", { width: textureRatio, height: 1 }, this._scene);
+        babylonjs_Engines_engine__WEBPACK_IMPORTED_MODULE_0__["NodeMaterial"].ParseFromSnippetAsync("#TPSEV2#3", this._scene)
+            .then(function (material) {
+            _this._planeMaterial = material;
+            _this._planeMaterial.getTextureBlocks()[0].texture = _this._texture;
+            _this._plane.material = _this._planeMaterial;
+            _this._canvas.focus();
+        });
+        this._plane.enableEdgesRendering();
+        this._plane.edgesWidth = 4.0;
+        this._plane.edgesColor = new babylonjs_Engines_engine__WEBPACK_IMPORTED_MODULE_0__["Color4"](1, 1, 1, 1);
+        this._engine.runRenderLoop(function () {
+            _this._engine.resize();
+            _this._scene.render();
+        });
+        this._scale = 1;
+        this._isPanning = false;
+        this._scene.onBeforeRenderObservable.add(function () {
+            var _a, _b;
+            var ratio = ((_a = _this._canvas) === null || _a === void 0 ? void 0 : _a.width) / ((_b = _this._canvas) === null || _b === void 0 ? void 0 : _b.height);
+            _this._camera.orthoBottom = -_this._scale;
+            _this._camera.orthoTop = _this._scale;
+            _this._camera.orthoLeft = -_this._scale * ratio;
+            _this._camera.orthoRight = _this._scale * ratio;
+        });
+        this._scene.onPointerObservable.add(function (pointerInfo) {
+            switch (pointerInfo.type) {
+                case babylonjs_Engines_engine__WEBPACK_IMPORTED_MODULE_0__["PointerEventTypes"].POINTERWHEEL:
+                    var event_1 = pointerInfo.event;
+                    _this._scale += (event_1.deltaY * TextureCanvasManager.ZOOM_MOUSE_SPEED * _this._scale);
+                    _this._scale = Math.min(Math.max(_this._scale, TextureCanvasManager.MIN_SCALE), TextureCanvasManager.MAX_SCALE);
+                    break;
+                case babylonjs_Engines_engine__WEBPACK_IMPORTED_MODULE_0__["PointerEventTypes"].POINTERDOWN:
+                    if (pointerInfo.event.button === TextureCanvasManager.PAN_BUTTON) {
+                        _this._isPanning = true;
+                        _this._mouseX = pointerInfo.event.x;
+                        _this._mouseY = pointerInfo.event.y;
+                    }
+                    break;
+                case babylonjs_Engines_engine__WEBPACK_IMPORTED_MODULE_0__["PointerEventTypes"].POINTERUP:
+                    if (pointerInfo.event.button === TextureCanvasManager.PAN_BUTTON) {
+                        _this._isPanning = false;
+                    }
+                    break;
+                case babylonjs_Engines_engine__WEBPACK_IMPORTED_MODULE_0__["PointerEventTypes"].POINTERMOVE:
+                    if (_this._isPanning) {
+                        _this._camera.position.x -= (pointerInfo.event.x - _this._mouseX) * _this._scale * TextureCanvasManager.PAN_SPEED;
+                        _this._camera.position.y += (pointerInfo.event.y - _this._mouseY) * _this._scale * TextureCanvasManager.PAN_SPEED;
+                        _this._mouseX = pointerInfo.event.x;
+                        _this._mouseY = pointerInfo.event.y;
+                    }
+                    break;
+            }
+        });
+        this._scene.onKeyboardObservable.add(function (kbInfo) {
+            switch (kbInfo.type) {
+                case babylonjs_Engines_engine__WEBPACK_IMPORTED_MODULE_0__["KeyboardEventTypes"].KEYDOWN:
+                    if (kbInfo.event.key == "+") {
+                        _this._scale -= TextureCanvasManager.ZOOM_KEYBOARD_SPEED * _this._scale;
+                    }
+                    if (kbInfo.event.key == "-") {
+                        _this._scale += TextureCanvasManager.ZOOM_KEYBOARD_SPEED * _this._scale;
+                    }
+                    _this._scale = Math.min(Math.max(_this._scale, TextureCanvasManager.MIN_SCALE), TextureCanvasManager.MAX_SCALE);
+                    break;
+            }
+        });
+    }
+    TextureCanvasManager.prototype.dispose = function () {
+        if (this._planeMaterial) {
+            this._planeMaterial.dispose();
+        }
+        this._texture.dispose();
+        this._plane.dispose();
+        this._camera.dispose();
+        this._scene.dispose();
+        this._engine.dispose();
+    };
+    TextureCanvasManager.ZOOM_MOUSE_SPEED = 0.0005;
+    TextureCanvasManager.ZOOM_KEYBOARD_SPEED = 0.2;
+    TextureCanvasManager.PAN_SPEED = 0.002;
+    TextureCanvasManager.PAN_BUTTON = 0; // left mouse button
+    TextureCanvasManager.MIN_SCALE = 0.01;
+    TextureCanvasManager.MAX_SCALE = 10;
+    return TextureCanvasManager;
+}());
+
+
+
+/***/ }),
+
+/***/ "./components/actionTabs/tabs/propertyGrids/materials/textures/textureEditor.scss":
+/*!****************************************************************************************!*\
+  !*** ./components/actionTabs/tabs/propertyGrids/materials/textures/textureEditor.scss ***!
+  \****************************************************************************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+var api = __webpack_require__(/*! ../../../../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js */ "../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js");
+            var content = __webpack_require__(/*! !../../../../../../../../node_modules/css-loader/dist/cjs.js!../../../../../../../../node_modules/sass-loader/dist/cjs.js!./textureEditor.scss */ "../../node_modules/css-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js!./components/actionTabs/tabs/propertyGrids/materials/textures/textureEditor.scss");
+
+            content = content.__esModule ? content.default : content;
+
+            if (typeof content === 'string') {
+              content = [[module.i, content, '']];
+            }
+
+var options = {};
+
+options.insert = "head";
+options.singleton = false;
+
+var update = api(content, options);
+
+
+
+module.exports = content.locals || {};
+
+/***/ }),
+
+/***/ "./components/actionTabs/tabs/propertyGrids/materials/textures/textureEditorComponent.tsx":
+/*!************************************************************************************************!*\
+  !*** ./components/actionTabs/tabs/propertyGrids/materials/textures/textureEditorComponent.tsx ***!
+  \************************************************************************************************/
+/*! exports provided: TextureEditorComponent */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextureEditorComponent", function() { return TextureEditorComponent; });
+/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react */ "../../node_modules/react/index.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _textureCanvasManager__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./textureCanvasManager */ "./components/actionTabs/tabs/propertyGrids/materials/textures/textureCanvasManager.ts");
+
+
+
+__webpack_require__(/*! ./textureEditor.scss */ "./components/actionTabs/tabs/propertyGrids/materials/textures/textureEditor.scss");
+var TextureEditorComponent = /** @class */ (function (_super) {
+    Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(TextureEditorComponent, _super);
+    function TextureEditorComponent() {
+        var _this = _super !== null && _super.apply(this, arguments) || this;
+        _this.reactCanvas = react__WEBPACK_IMPORTED_MODULE_1__["createRef"]();
+        return _this;
+    }
+    TextureEditorComponent.prototype.componentDidMount = function () {
+        this._textureCanvasManager = new _textureCanvasManager__WEBPACK_IMPORTED_MODULE_2__["TextureCanvasManager"](this.reactCanvas.current, this.props.texture);
+    };
+    TextureEditorComponent.prototype.componentWillUnmount = function () {
+        this._textureCanvasManager.dispose();
+    };
+    TextureEditorComponent.prototype.render = function () {
+        return react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", { id: 'texture-editor' },
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("canvas", { id: "texture-canvas", ref: this.reactCanvas, tabIndex: 1 }));
+    };
+    return TextureEditorComponent;
+}(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));
+
+
+
+/***/ }),
+
 /***/ "./components/actionTabs/tabs/propertyGrids/meshes/bonePropertyGridComponent.tsx":
 /*!***************************************************************************************!*\
   !*** ./components/actionTabs/tabs/propertyGrids/meshes/bonePropertyGridComponent.tsx ***!
@@ -72790,15 +72970,12 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _lineContainerComponent__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../lineContainerComponent */ "./components/actionTabs/lineContainerComponent.tsx");
 /* harmony import */ var _lines_buttonLineComponent__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../lines/buttonLineComponent */ "./components/actionTabs/lines/buttonLineComponent.tsx");
 /* harmony import */ var _lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../lines/checkBoxLineComponent */ "./components/actionTabs/lines/checkBoxLineComponent.tsx");
-/* harmony import */ var babylonjs_loaders_glTF_2_0_Extensions_KHR_materials_variants__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! babylonjs-loaders/glTF/2.0/Extensions/KHR_materials_variants */ "babylonjs-loaders/glTF/2.0/Extensions/KHR_materials_variants");
-/* harmony import */ var babylonjs_loaders_glTF_2_0_Extensions_KHR_materials_variants__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(babylonjs_loaders_glTF_2_0_Extensions_KHR_materials_variants__WEBPACK_IMPORTED_MODULE_5__);
 
 
 
 // import { OptionsLineComponent } from '../../lines/optionsLineComponent';
 
 
-
 var VariantsPropertyGridComponent = /** @class */ (function (_super) {
     Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(VariantsPropertyGridComponent, _super);
     function VariantsPropertyGridComponent(props) {
@@ -72807,13 +72984,21 @@ var VariantsPropertyGridComponent = /** @class */ (function (_super) {
         _this._selectedTags = [];
         return _this;
     }
+    VariantsPropertyGridComponent.prototype._getVariantsExtension = function () {
+        var _a;
+        return (_a = this.props.globalState) === null || _a === void 0 ? void 0 : _a.glTFLoaderExtenstions["KHR_materials_variants"];
+    };
     VariantsPropertyGridComponent.prototype.render = function () {
         var _this = this;
-        var variants = babylonjs_loaders_glTF_2_0_Extensions_KHR_materials_variants__WEBPACK_IMPORTED_MODULE_5__["KHR_materials_variants"].GetAvailableVariants(this.props.host);
+        var extension = this._getVariantsExtension();
+        if (!extension) {
+            return null;
+        }
+        var variants = extension.getAvailableVariants(this.props.host);
         if (!variants || variants.length === 0) {
             return null;
         }
-        var lastPickedVariants = babylonjs_loaders_glTF_2_0_Extensions_KHR_materials_variants__WEBPACK_IMPORTED_MODULE_5__["KHR_materials_variants"].GetLastSelectedVariant(this.props.host);
+        var lastPickedVariants = extension.getLastSelectedVariant(this.props.host);
         variants.sort(function (a, b) {
             var aIsActive = lastPickedVariants && lastPickedVariants.indexOf ? lastPickedVariants.indexOf(a) > -1 : lastPickedVariants === a;
             var bIsActive = lastPickedVariants && lastPickedVariants.indexOf ? lastPickedVariants.indexOf(b) > -1 : lastPickedVariants === b;
@@ -72859,7 +73044,7 @@ var VariantsPropertyGridComponent = /** @class */ (function (_super) {
                         }, onSelect: function (value) {
                             if (value) {
                                 _this._selectedTags.push(v);
-                                babylonjs_loaders_glTF_2_0_Extensions_KHR_materials_variants__WEBPACK_IMPORTED_MODULE_5__["KHR_materials_variants"].SelectVariant(_this.props.host, v);
+                                extension.selectVariant(_this.props.host, v);
                             }
                             else {
                                 // Do something on extension?
@@ -72871,7 +73056,7 @@ var VariantsPropertyGridComponent = /** @class */ (function (_super) {
                         } }));
                 }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_buttonLineComponent__WEBPACK_IMPORTED_MODULE_3__["ButtonLineComponent"], { label: "Reset", onClick: function () {
-                        babylonjs_loaders_glTF_2_0_Extensions_KHR_materials_variants__WEBPACK_IMPORTED_MODULE_5__["KHR_materials_variants"].Reset(_this.props.host);
+                        extension.reset(_this.props.host);
                         _this._selectedTags = [];
                         _this.forceUpdate();
                     } }))));
@@ -73746,6 +73931,7 @@ var GlobalState = /** @class */ (function () {
         this.onValidationResultsUpdatedObservable = new babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__["Observable"]();
         this.glTFLoaderExtensionDefaults = {};
         this.glTFLoaderDefaults = { "validate": true };
+        this.glTFLoaderExtenstions = {};
         this.blockMutationUpdates = false;
         this.selectedLineContainerTitles = [];
         this.selectedLineContainerTitlesNoFocus = [];
@@ -73798,6 +73984,7 @@ var GlobalState = /** @class */ (function () {
     };
     GlobalState.prototype.prepareGLTFPlugin = function (loader) {
         var _this = this;
+        this.glTFLoaderExtenstions = {};
         var loaderState = this.glTFLoaderDefaults;
         if (loaderState !== undefined) {
             for (var key in loaderState) {
@@ -73811,6 +73998,7 @@ var GlobalState = /** @class */ (function () {
                     extension[key] = extensionState[key];
                 }
             }
+            _this.glTFLoaderExtenstions[extension.name] = extension;
         });
         if (this.validationResults) {
             this.validationResults = null;
@@ -73937,6 +74125,81 @@ var HeaderComponent = /** @class */ (function (_super) {
 
 /***/ }),
 
+/***/ "./components/popupComponent.tsx":
+/*!***************************************!*\
+  !*** ./components/popupComponent.tsx ***!
+  \***************************************/
+/*! exports provided: PopupComponent */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PopupComponent", function() { return PopupComponent; });
+/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react */ "../../node_modules/react/index.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react-dom */ "../../node_modules/react-dom/index.js");
+/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_2__);
+/* harmony import */ var _inspector__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../inspector */ "./inspector.ts");
+
+
+
+
+var PopupComponent = /** @class */ (function (_super) {
+    Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(PopupComponent, _super);
+    function PopupComponent(props) {
+        var _this = _super.call(this, props) || this;
+        _this._container = document.createElement('div');
+        _this._container.id = _this.props.id;
+        _this._window;
+        _this.state = {
+            isComponentMounted: false,
+            blockedByBrowser: false,
+        };
+        return _this;
+    }
+    PopupComponent.prototype.componentDidMount = function () {
+        this.openPopup();
+        this.setState({ isComponentMounted: true });
+    };
+    PopupComponent.prototype.openPopup = function () {
+        var _this = this;
+        var _a = this.props, title = _a.title, size = _a.size, onClose = _a.onClose, onOpen = _a.onOpen;
+        var windowVariableName = "window_" + title;
+        this._container = _inspector__WEBPACK_IMPORTED_MODULE_3__["Inspector"]._CreatePopup(title, windowVariableName, size.width, size.height);
+        this._window = _inspector__WEBPACK_IMPORTED_MODULE_3__["Inspector"][windowVariableName];
+        if (this._window) {
+            onOpen(this._window);
+            this._window.addEventListener('beforeunload', function () { return _this._window && onClose(_this._window); });
+        }
+        else {
+            if (!this._window) {
+                this.setState({ blockedByBrowser: true }, function () {
+                    if (_this.state.blockedByBrowser) {
+                        alert("You might have blocked popups in your browser");
+                        console.warn("Popup window couldn't be created");
+                    }
+                });
+            }
+        }
+    };
+    PopupComponent.prototype.componentWillUnmount = function () {
+        if (this._window) {
+            this._window.close();
+        }
+    };
+    PopupComponent.prototype.render = function () {
+        if (!this.state.isComponentMounted || this._container === null)
+            return null;
+        return react_dom__WEBPACK_IMPORTED_MODULE_2__["createPortal"](this.props.children, this._container);
+    };
+    return PopupComponent;
+}(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));
+
+
+
+/***/ }),
+
 /***/ "./components/propertyChangedEvent.ts":
 /*!********************************************!*\
   !*** ./components/propertyChangedEvent.ts ***!
@@ -76891,17 +77154,6 @@ module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_gui_2D_controls_image__;
 
 /***/ }),
 
-/***/ "babylonjs-loaders/glTF/2.0/Extensions/KHR_materials_variants":
-/*!************************************************************************************************************************************************************!*\
-  !*** external {"root":["BABYLON","GLTF2","Loader","Extensions"],"commonjs":"babylonjs-loaders","commonjs2":"babylonjs-loaders","amd":"babylonjs-loaders"} ***!
-  \************************************************************************************************************************************************************/
-/*! no static exports found */
-/***/ (function(module, exports) {
-
-module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_loaders_glTF_2_0_Extensions_KHR_materials_variants__;
-
-/***/ }),
-
 /***/ "babylonjs-loaders/glTF/index":
 /*!****************************************************************************************************************************!*\
   !*** external {"root":"BABYLON","commonjs":"babylonjs-loaders","commonjs2":"babylonjs-loaders","amd":"babylonjs-loaders"} ***!

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.max.js.map


+ 44 - 1
dist/preview release/inspector/babylon.inspector.d.ts

@@ -50,6 +50,9 @@ declare module INSPECTOR {
         glTFLoaderDefaults: {
             [key: string]: any;
         };
+        glTFLoaderExtenstions: {
+            [key: string]: BABYLON.IGLTFLoaderExtension;
+        };
         blockMutationUpdates: boolean;
         selectedLineContainerTitles: Array<string>;
         selectedLineContainerTitlesNoFocus: Array<string>;
@@ -1264,6 +1267,42 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
+    export class TextureCanvasManager {
+        private _engine;
+        private _scene;
+        private _texture;
+        private _camera;
+        private _canvas;
+        private _scale;
+        private _isPanning;
+        private _mouseX;
+        private _mouseY;
+        private _plane;
+        private _planeMaterial;
+        private static ZOOM_MOUSE_SPEED;
+        private static ZOOM_KEYBOARD_SPEED;
+        private static PAN_SPEED;
+        private static PAN_BUTTON;
+        private static MIN_SCALE;
+        private static MAX_SCALE;
+        constructor(targetCanvas: HTMLCanvasElement, texture: BABYLON.BaseTexture);
+        dispose(): void;
+    }
+}
+declare module INSPECTOR {
+    interface TextureEditorComponentProps {
+        globalState: GlobalState;
+        texture: BABYLON.BaseTexture;
+    }
+    export class TextureEditorComponent extends React.Component<TextureEditorComponentProps> {
+        private _textureCanvasManager;
+        private reactCanvas;
+        componentDidMount(): void;
+        componentWillUnmount(): void;
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
     interface ITexturePropertyGridComponentProps {
         texture: BABYLON.BaseTexture;
         lockObject: LockObject;
@@ -1273,10 +1312,13 @@ declare module INSPECTOR {
     export class TexturePropertyGridComponent extends React.Component<ITexturePropertyGridComponentProps> {
         private _adtInstrumentation;
         private textureLineRef;
+        private _isTextureEditorOpen;
         constructor(props: ITexturePropertyGridComponentProps);
         componentWillUnmount(): void;
         updateTexture(file: File): void;
-        foreceRefresh(): void;
+        onOpenTextureEditor(): void;
+        onCloseTextureEditor(window: Window | null): void;
+        forceRefresh(): void;
         render(): JSX.Element;
     }
 }
@@ -1510,6 +1552,7 @@ declare module INSPECTOR {
     export class VariantsPropertyGridComponent extends React.Component<IVariantsPropertyGridComponentProps> {
         private _selectedTags;
         constructor(props: IVariantsPropertyGridComponentProps);
+        private _getVariantsExtension;
         render(): JSX.Element | null;
     }
 }

+ 93 - 3
dist/preview release/inspector/babylon.inspector.module.d.ts

@@ -63,6 +63,9 @@ declare module "babylonjs-inspector/components/globalState" {
         glTFLoaderDefaults: {
             [key: string]: any;
         };
+        glTFLoaderExtenstions: {
+            [key: string]: IGLTFLoaderExtension;
+        };
         blockMutationUpdates: boolean;
         selectedLineContainerTitles: Array<string>;
         selectedLineContainerTitlesNoFocus: Array<string>;
@@ -1240,7 +1243,7 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/ani
         render(): JSX.Element;
     }
 }
-declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/animations/popupComponent" {
+declare module "babylonjs-inspector/components/popupComponent" {
     import * as React from "react";
     interface IPopupComponentProps {
         id: string;
@@ -1433,6 +1436,46 @@ declare module "babylonjs-inspector/components/actionTabs/lines/textureLineCompo
         render(): JSX.Element;
     }
 }
+declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/materials/textures/textureCanvasManager" {
+    import { BaseTexture } from 'babylonjs/Materials/Textures/baseTexture';
+    export class TextureCanvasManager {
+        private _engine;
+        private _scene;
+        private _texture;
+        private _camera;
+        private _canvas;
+        private _scale;
+        private _isPanning;
+        private _mouseX;
+        private _mouseY;
+        private _plane;
+        private _planeMaterial;
+        private static ZOOM_MOUSE_SPEED;
+        private static ZOOM_KEYBOARD_SPEED;
+        private static PAN_SPEED;
+        private static PAN_BUTTON;
+        private static MIN_SCALE;
+        private static MAX_SCALE;
+        constructor(targetCanvas: HTMLCanvasElement, texture: BaseTexture);
+        dispose(): void;
+    }
+}
+declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/materials/textures/textureEditorComponent" {
+    import * as React from 'react';
+    import { GlobalState } from "babylonjs-inspector/components/globalState";
+    import { BaseTexture } from 'babylonjs/Materials/Textures/baseTexture';
+    interface TextureEditorComponentProps {
+        globalState: GlobalState;
+        texture: BaseTexture;
+    }
+    export class TextureEditorComponent extends React.Component<TextureEditorComponentProps> {
+        private _textureCanvasManager;
+        private reactCanvas;
+        componentDidMount(): void;
+        componentWillUnmount(): void;
+        render(): JSX.Element;
+    }
+}
 declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/materials/texturePropertyGridComponent" {
     import * as React from "react";
     import { Observable } from "babylonjs/Misc/observable";
@@ -1449,10 +1492,13 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/mat
     export class TexturePropertyGridComponent extends React.Component<ITexturePropertyGridComponentProps> {
         private _adtInstrumentation;
         private textureLineRef;
+        private _isTextureEditorOpen;
         constructor(props: ITexturePropertyGridComponentProps);
         componentWillUnmount(): void;
         updateTexture(file: File): void;
-        foreceRefresh(): void;
+        onOpenTextureEditor(): void;
+        onCloseTextureEditor(window: Window | null): void;
+        forceRefresh(): void;
         render(): JSX.Element;
     }
 }
@@ -1765,6 +1811,7 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/var
     export class VariantsPropertyGridComponent extends React.Component<IVariantsPropertyGridComponentProps> {
         private _selectedTags;
         constructor(props: IVariantsPropertyGridComponentProps);
+        private _getVariantsExtension;
         render(): JSX.Element | null;
     }
 }
@@ -3714,6 +3761,9 @@ declare module INSPECTOR {
         glTFLoaderDefaults: {
             [key: string]: any;
         };
+        glTFLoaderExtenstions: {
+            [key: string]: BABYLON.IGLTFLoaderExtension;
+        };
         blockMutationUpdates: boolean;
         selectedLineContainerTitles: Array<string>;
         selectedLineContainerTitlesNoFocus: Array<string>;
@@ -4928,6 +4978,42 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
+    export class TextureCanvasManager {
+        private _engine;
+        private _scene;
+        private _texture;
+        private _camera;
+        private _canvas;
+        private _scale;
+        private _isPanning;
+        private _mouseX;
+        private _mouseY;
+        private _plane;
+        private _planeMaterial;
+        private static ZOOM_MOUSE_SPEED;
+        private static ZOOM_KEYBOARD_SPEED;
+        private static PAN_SPEED;
+        private static PAN_BUTTON;
+        private static MIN_SCALE;
+        private static MAX_SCALE;
+        constructor(targetCanvas: HTMLCanvasElement, texture: BABYLON.BaseTexture);
+        dispose(): void;
+    }
+}
+declare module INSPECTOR {
+    interface TextureEditorComponentProps {
+        globalState: GlobalState;
+        texture: BABYLON.BaseTexture;
+    }
+    export class TextureEditorComponent extends React.Component<TextureEditorComponentProps> {
+        private _textureCanvasManager;
+        private reactCanvas;
+        componentDidMount(): void;
+        componentWillUnmount(): void;
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
     interface ITexturePropertyGridComponentProps {
         texture: BABYLON.BaseTexture;
         lockObject: LockObject;
@@ -4937,10 +5023,13 @@ declare module INSPECTOR {
     export class TexturePropertyGridComponent extends React.Component<ITexturePropertyGridComponentProps> {
         private _adtInstrumentation;
         private textureLineRef;
+        private _isTextureEditorOpen;
         constructor(props: ITexturePropertyGridComponentProps);
         componentWillUnmount(): void;
         updateTexture(file: File): void;
-        foreceRefresh(): void;
+        onOpenTextureEditor(): void;
+        onCloseTextureEditor(window: Window | null): void;
+        forceRefresh(): void;
         render(): JSX.Element;
     }
 }
@@ -5174,6 +5263,7 @@ declare module INSPECTOR {
     export class VariantsPropertyGridComponent extends React.Component<IVariantsPropertyGridComponentProps> {
         private _selectedTags;
         constructor(props: IVariantsPropertyGridComponentProps);
+        private _getVariantsExtension;
         render(): JSX.Element | null;
     }
 }

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/libktx.js


BIN
dist/preview release/libktx.wasm


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

@@ -1251,6 +1251,14 @@ var KHR_materials_variants = /** @class */ (function () {
         return Object.keys(extensionMetadata.variants);
     };
     /**
+     * Gets the list of available variant tag names for this asset.
+     * @param rootMesh The glTF root mesh
+     * @returns the list of all the variant names for this model
+     */
+    KHR_materials_variants.prototype.getAvailableVariants = function (rootMesh) {
+        return KHR_materials_variants.GetAvailableVariants(rootMesh);
+    };
+    /**
      * Select a variant given a variant tag name or a list of variant tag names.
      * @param rootMesh The glTF root mesh
      * @param variantName The variant name(s) to select.
@@ -1281,6 +1289,14 @@ var KHR_materials_variants = /** @class */ (function () {
         extensionMetadata.lastSelected = variantName;
     };
     /**
+     * Select a variant given a variant tag name or a list of variant tag names.
+     * @param rootMesh The glTF root mesh
+     * @param variantName The variant name(s) to select.
+     */
+    KHR_materials_variants.prototype.selectVariant = function (rootMesh, variantName) {
+        return KHR_materials_variants.SelectVariant(rootMesh, variantName);
+    };
+    /**
      * Reset back to the original before selecting a variant.
      * @param rootMesh The glTF root mesh
      */
@@ -1296,6 +1312,13 @@ var KHR_materials_variants = /** @class */ (function () {
         extensionMetadata.lastSelected = null;
     };
     /**
+     * Reset back to the original before selecting a variant.
+     * @param rootMesh The glTF root mesh
+     */
+    KHR_materials_variants.prototype.reset = function (rootMesh) {
+        return KHR_materials_variants.Reset(rootMesh);
+    };
+    /**
      * Gets the last selected variant tag name(s) or null if original.
      * @param rootMesh The glTF root mesh
      * @returns The selected variant tag name(s).
@@ -1307,6 +1330,14 @@ var KHR_materials_variants = /** @class */ (function () {
         }
         return extensionMetadata.lastSelected;
     };
+    /**
+     * Gets the last selected variant tag name(s) or null if original.
+     * @param rootMesh The glTF root mesh
+     * @returns The selected variant tag name(s).
+     */
+    KHR_materials_variants.prototype.getLastSelectedVariant = function (rootMesh) {
+        return KHR_materials_variants.GetLastSelectedVariant(rootMesh);
+    };
     KHR_materials_variants._GetExtensionMetadata = function (rootMesh) {
         var _a, _b;
         return ((_b = (_a = rootMesh === null || rootMesh === void 0 ? void 0 : rootMesh.metadata) === null || _a === void 0 ? void 0 : _a.gltf) === null || _b === void 0 ? void 0 : _b[NAME]) || null;

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.js.map


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


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

@@ -3865,6 +3865,14 @@ var KHR_materials_variants = /** @class */ (function () {
         return Object.keys(extensionMetadata.variants);
     };
     /**
+     * Gets the list of available variant tag names for this asset.
+     * @param rootMesh The glTF root mesh
+     * @returns the list of all the variant names for this model
+     */
+    KHR_materials_variants.prototype.getAvailableVariants = function (rootMesh) {
+        return KHR_materials_variants.GetAvailableVariants(rootMesh);
+    };
+    /**
      * Select a variant given a variant tag name or a list of variant tag names.
      * @param rootMesh The glTF root mesh
      * @param variantName The variant name(s) to select.
@@ -3895,6 +3903,14 @@ var KHR_materials_variants = /** @class */ (function () {
         extensionMetadata.lastSelected = variantName;
     };
     /**
+     * Select a variant given a variant tag name or a list of variant tag names.
+     * @param rootMesh The glTF root mesh
+     * @param variantName The variant name(s) to select.
+     */
+    KHR_materials_variants.prototype.selectVariant = function (rootMesh, variantName) {
+        return KHR_materials_variants.SelectVariant(rootMesh, variantName);
+    };
+    /**
      * Reset back to the original before selecting a variant.
      * @param rootMesh The glTF root mesh
      */
@@ -3910,6 +3926,13 @@ var KHR_materials_variants = /** @class */ (function () {
         extensionMetadata.lastSelected = null;
     };
     /**
+     * Reset back to the original before selecting a variant.
+     * @param rootMesh The glTF root mesh
+     */
+    KHR_materials_variants.prototype.reset = function (rootMesh) {
+        return KHR_materials_variants.Reset(rootMesh);
+    };
+    /**
      * Gets the last selected variant tag name(s) or null if original.
      * @param rootMesh The glTF root mesh
      * @returns The selected variant tag name(s).
@@ -3921,6 +3944,14 @@ var KHR_materials_variants = /** @class */ (function () {
         }
         return extensionMetadata.lastSelected;
     };
+    /**
+     * Gets the last selected variant tag name(s) or null if original.
+     * @param rootMesh The glTF root mesh
+     * @returns The selected variant tag name(s).
+     */
+    KHR_materials_variants.prototype.getLastSelectedVariant = function (rootMesh) {
+        return KHR_materials_variants.GetLastSelectedVariant(rootMesh);
+    };
     KHR_materials_variants._GetExtensionMetadata = function (rootMesh) {
         var _a, _b;
         return ((_b = (_a = rootMesh === null || rootMesh === void 0 ? void 0 : rootMesh.metadata) === null || _a === void 0 ? void 0 : _a.gltf) === null || _b === void 0 ? void 0 : _b[NAME]) || null;

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.js.map


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.min.js


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

@@ -1949,22 +1949,45 @@ declare module BABYLON.GLTF2.Loader.Extensions {
          */
         static GetAvailableVariants(rootMesh: Mesh): string[];
         /**
+         * Gets the list of available variant tag names for this asset.
+         * @param rootMesh The glTF root mesh
+         * @returns the list of all the variant names for this model
+         */
+        getAvailableVariants(rootMesh: Mesh): string[];
+        /**
          * Select a variant given a variant tag name or a list of variant tag names.
          * @param rootMesh The glTF root mesh
          * @param variantName The variant name(s) to select.
          */
         static SelectVariant(rootMesh: Mesh, variantName: string | string[]): void;
         /**
+         * Select a variant given a variant tag name or a list of variant tag names.
+         * @param rootMesh The glTF root mesh
+         * @param variantName The variant name(s) to select.
+         */
+        selectVariant(rootMesh: Mesh, variantName: string | string[]): void;
+        /**
          * Reset back to the original before selecting a variant.
          * @param rootMesh The glTF root mesh
          */
         static Reset(rootMesh: Mesh): void;
         /**
+         * Reset back to the original before selecting a variant.
+         * @param rootMesh The glTF root mesh
+         */
+        reset(rootMesh: Mesh): void;
+        /**
          * Gets the last selected variant tag name(s) or null if original.
          * @param rootMesh The glTF root mesh
          * @returns The selected variant tag name(s).
          */
         static GetLastSelectedVariant(rootMesh: Mesh): Nullable<string | string[]>;
+        /**
+         * Gets the last selected variant tag name(s) or null if original.
+         * @param rootMesh The glTF root mesh
+         * @returns The selected variant tag name(s).
+         */
+        getLastSelectedVariant(rootMesh: Mesh): Nullable<string | string[]>;
         private static _GetExtensionMetadata;
         /** @hidden */
         _loadMeshPrimitiveAsync(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Nullable<Promise<AbstractMesh>>;

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

@@ -5245,6 +5245,14 @@ var KHR_materials_variants = /** @class */ (function () {
         return Object.keys(extensionMetadata.variants);
     };
     /**
+     * Gets the list of available variant tag names for this asset.
+     * @param rootMesh The glTF root mesh
+     * @returns the list of all the variant names for this model
+     */
+    KHR_materials_variants.prototype.getAvailableVariants = function (rootMesh) {
+        return KHR_materials_variants.GetAvailableVariants(rootMesh);
+    };
+    /**
      * Select a variant given a variant tag name or a list of variant tag names.
      * @param rootMesh The glTF root mesh
      * @param variantName The variant name(s) to select.
@@ -5275,6 +5283,14 @@ var KHR_materials_variants = /** @class */ (function () {
         extensionMetadata.lastSelected = variantName;
     };
     /**
+     * Select a variant given a variant tag name or a list of variant tag names.
+     * @param rootMesh The glTF root mesh
+     * @param variantName The variant name(s) to select.
+     */
+    KHR_materials_variants.prototype.selectVariant = function (rootMesh, variantName) {
+        return KHR_materials_variants.SelectVariant(rootMesh, variantName);
+    };
+    /**
      * Reset back to the original before selecting a variant.
      * @param rootMesh The glTF root mesh
      */
@@ -5290,6 +5306,13 @@ var KHR_materials_variants = /** @class */ (function () {
         extensionMetadata.lastSelected = null;
     };
     /**
+     * Reset back to the original before selecting a variant.
+     * @param rootMesh The glTF root mesh
+     */
+    KHR_materials_variants.prototype.reset = function (rootMesh) {
+        return KHR_materials_variants.Reset(rootMesh);
+    };
+    /**
      * Gets the last selected variant tag name(s) or null if original.
      * @param rootMesh The glTF root mesh
      * @returns The selected variant tag name(s).
@@ -5301,6 +5324,14 @@ var KHR_materials_variants = /** @class */ (function () {
         }
         return extensionMetadata.lastSelected;
     };
+    /**
+     * Gets the last selected variant tag name(s) or null if original.
+     * @param rootMesh The glTF root mesh
+     * @returns The selected variant tag name(s).
+     */
+    KHR_materials_variants.prototype.getLastSelectedVariant = function (rootMesh) {
+        return KHR_materials_variants.GetLastSelectedVariant(rootMesh);
+    };
     KHR_materials_variants._GetExtensionMetadata = function (rootMesh) {
         var _a, _b;
         return ((_b = (_a = rootMesh === null || rootMesh === void 0 ? void 0 : rootMesh.metadata) === null || _a === void 0 ? void 0 : _a.gltf) === null || _b === void 0 ? void 0 : _b[NAME]) || null;

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.js.map


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.min.js


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

@@ -2099,22 +2099,45 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_materials_variants" {
          */
         static GetAvailableVariants(rootMesh: Mesh): string[];
         /**
+         * Gets the list of available variant tag names for this asset.
+         * @param rootMesh The glTF root mesh
+         * @returns the list of all the variant names for this model
+         */
+        getAvailableVariants(rootMesh: Mesh): string[];
+        /**
          * Select a variant given a variant tag name or a list of variant tag names.
          * @param rootMesh The glTF root mesh
          * @param variantName The variant name(s) to select.
          */
         static SelectVariant(rootMesh: Mesh, variantName: string | string[]): void;
         /**
+         * Select a variant given a variant tag name or a list of variant tag names.
+         * @param rootMesh The glTF root mesh
+         * @param variantName The variant name(s) to select.
+         */
+        selectVariant(rootMesh: Mesh, variantName: string | string[]): void;
+        /**
          * Reset back to the original before selecting a variant.
          * @param rootMesh The glTF root mesh
          */
         static Reset(rootMesh: Mesh): void;
         /**
+         * Reset back to the original before selecting a variant.
+         * @param rootMesh The glTF root mesh
+         */
+        reset(rootMesh: Mesh): void;
+        /**
          * Gets the last selected variant tag name(s) or null if original.
          * @param rootMesh The glTF root mesh
          * @returns The selected variant tag name(s).
          */
         static GetLastSelectedVariant(rootMesh: Mesh): Nullable<string | string[]>;
+        /**
+         * Gets the last selected variant tag name(s) or null if original.
+         * @param rootMesh The glTF root mesh
+         * @returns The selected variant tag name(s).
+         */
+        getLastSelectedVariant(rootMesh: Mesh): Nullable<string | string[]>;
         private static _GetExtensionMetadata;
         /** @hidden */
         _loadMeshPrimitiveAsync(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Nullable<Promise<AbstractMesh>>;
@@ -4791,22 +4814,45 @@ declare module BABYLON.GLTF2.Loader.Extensions {
          */
         static GetAvailableVariants(rootMesh: Mesh): string[];
         /**
+         * Gets the list of available variant tag names for this asset.
+         * @param rootMesh The glTF root mesh
+         * @returns the list of all the variant names for this model
+         */
+        getAvailableVariants(rootMesh: Mesh): string[];
+        /**
          * Select a variant given a variant tag name or a list of variant tag names.
          * @param rootMesh The glTF root mesh
          * @param variantName The variant name(s) to select.
          */
         static SelectVariant(rootMesh: Mesh, variantName: string | string[]): void;
         /**
+         * Select a variant given a variant tag name or a list of variant tag names.
+         * @param rootMesh The glTF root mesh
+         * @param variantName The variant name(s) to select.
+         */
+        selectVariant(rootMesh: Mesh, variantName: string | string[]): void;
+        /**
          * Reset back to the original before selecting a variant.
          * @param rootMesh The glTF root mesh
          */
         static Reset(rootMesh: Mesh): void;
         /**
+         * Reset back to the original before selecting a variant.
+         * @param rootMesh The glTF root mesh
+         */
+        reset(rootMesh: Mesh): void;
+        /**
          * Gets the last selected variant tag name(s) or null if original.
          * @param rootMesh The glTF root mesh
          * @returns The selected variant tag name(s).
          */
         static GetLastSelectedVariant(rootMesh: Mesh): Nullable<string | string[]>;
+        /**
+         * Gets the last selected variant tag name(s) or null if original.
+         * @param rootMesh The glTF root mesh
+         * @returns The selected variant tag name(s).
+         */
+        getLastSelectedVariant(rootMesh: Mesh): Nullable<string | string[]>;
         private static _GetExtensionMetadata;
         /** @hidden */
         _loadMeshPrimitiveAsync(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Nullable<Promise<AbstractMesh>>;

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

@@ -1 +1 @@
-{"thinEngineOnly":116308,"engineOnly":152744,"sceneOnly":515374,"minGridMaterial":652717,"minStandardMaterial":801365}
+{"thinEngineOnly":116308,"engineOnly":152744,"sceneOnly":515374,"minGridMaterial":652684,"minStandardMaterial":801332}

+ 17 - 0
dist/preview release/playground/babylon.playground.d.ts

@@ -0,0 +1,17 @@
+/// <reference types="react" />
+declare module PLAYGROUND {
+    export class GlobalState {
+    }
+}
+declare module PLAYGROUND {
+    interface IPlaygroundProps {
+    }
+    export class Playground extends React.Component<IPlaygroundProps, {
+        isFooterVisible: boolean;
+        errorMessage: string;
+    }> {
+        constructor(props: IPlaygroundProps);
+        render(): JSX.Element;
+        static Show(hostElement: HTMLElement): void;
+    }
+}

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 45 - 0
dist/preview release/playground/babylon.playground.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 29424 - 0
dist/preview release/playground/babylon.playground.max.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
dist/preview release/playground/babylon.playground.max.js.map


+ 44 - 0
dist/preview release/playground/babylon.playground.module.d.ts

@@ -0,0 +1,44 @@
+/// <reference types="react" />
+declare module "babylonjs-playground/globalState" {
+    export class GlobalState {
+    }
+}
+declare module "babylonjs-playground/playground" {
+    import * as React from "react";
+    interface IPlaygroundProps {
+    }
+    export class Playground extends React.Component<IPlaygroundProps, {
+        isFooterVisible: boolean;
+        errorMessage: string;
+    }> {
+        constructor(props: IPlaygroundProps);
+        render(): JSX.Element;
+        static Show(hostElement: HTMLElement): void;
+    }
+}
+declare module "babylonjs-playground/index" {
+    export * from "babylonjs-playground/playground";
+}
+declare module "babylonjs-playground/legacy/legacy" {
+    export * from "babylonjs-playground/index";
+}
+declare module "babylonjs-playground" {
+    export * from "babylonjs-playground/legacy/legacy";
+}
+/// <reference types="react" />
+declare module PLAYGROUND {
+    export class GlobalState {
+    }
+}
+declare module PLAYGROUND {
+    interface IPlaygroundProps {
+    }
+    export class Playground extends React.Component<IPlaygroundProps, {
+        isFooterVisible: boolean;
+        errorMessage: string;
+    }> {
+        constructor(props: IPlaygroundProps);
+        render(): JSX.Element;
+        static Show(hostElement: HTMLElement): void;
+    }
+}

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

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

+ 3 - 0
dist/preview release/playground/readme-es6.md

@@ -0,0 +1,3 @@
+# Babylon.js Playground
+
+An extension to easily create a full page playground (ala playground.babylonjs.com)

+ 16 - 0
dist/preview release/playground/readme.md

@@ -0,0 +1,16 @@
+# Babylon.js Playground
+
+An extension to easily create a full page playground (ala playground.babylonjs.com)
+
+## Usage
+### Online method
+Call the method `Show` of the `BABYLON.Playground` class: 
+```
+BABYLON.Playground.Show({hostElement: document.getElementById("host")});
+```
+
+### Offline method
+If you don't have access to internet, the node editor should be imported manually in your HTML page :
+```
+<script src="babylon.playground.js" />
+``` 

+ 8 - 0
dist/preview release/viewer/babylon.module.d.ts

@@ -49940,6 +49940,10 @@ declare module "babylonjs/XR/webXREnterExitUI" {
          * A list of optional features to init the session with
          */
         optionalFeatures?: string[];
+        /**
+         * A list of optional features to init the session with
+         */
+        requiredFeatures?: string[];
     }
     /**
      * UI to allow the user to enter/exit XR mode
@@ -126383,6 +126387,10 @@ declare module BABYLON {
          * A list of optional features to init the session with
          */
         optionalFeatures?: string[];
+        /**
+         * A list of optional features to init the session with
+         */
+        requiredFeatures?: string[];
     }
     /**
      * UI to allow the user to enter/exit XR mode

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 5 - 5
dist/preview release/viewer/babylon.viewer.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 2 - 2
dist/preview release/viewer/babylon.viewer.max.js


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

@@ -2099,22 +2099,45 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_materials_variants" {
          */
         static GetAvailableVariants(rootMesh: Mesh): string[];
         /**
+         * Gets the list of available variant tag names for this asset.
+         * @param rootMesh The glTF root mesh
+         * @returns the list of all the variant names for this model
+         */
+        getAvailableVariants(rootMesh: Mesh): string[];
+        /**
          * Select a variant given a variant tag name or a list of variant tag names.
          * @param rootMesh The glTF root mesh
          * @param variantName The variant name(s) to select.
          */
         static SelectVariant(rootMesh: Mesh, variantName: string | string[]): void;
         /**
+         * Select a variant given a variant tag name or a list of variant tag names.
+         * @param rootMesh The glTF root mesh
+         * @param variantName The variant name(s) to select.
+         */
+        selectVariant(rootMesh: Mesh, variantName: string | string[]): void;
+        /**
          * Reset back to the original before selecting a variant.
          * @param rootMesh The glTF root mesh
          */
         static Reset(rootMesh: Mesh): void;
         /**
+         * Reset back to the original before selecting a variant.
+         * @param rootMesh The glTF root mesh
+         */
+        reset(rootMesh: Mesh): void;
+        /**
          * Gets the last selected variant tag name(s) or null if original.
          * @param rootMesh The glTF root mesh
          * @returns The selected variant tag name(s).
          */
         static GetLastSelectedVariant(rootMesh: Mesh): Nullable<string | string[]>;
+        /**
+         * Gets the last selected variant tag name(s) or null if original.
+         * @param rootMesh The glTF root mesh
+         * @returns The selected variant tag name(s).
+         */
+        getLastSelectedVariant(rootMesh: Mesh): Nullable<string | string[]>;
         private static _GetExtensionMetadata;
         /** @hidden */
         _loadMeshPrimitiveAsync(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Nullable<Promise<AbstractMesh>>;
@@ -4791,22 +4814,45 @@ declare module BABYLON.GLTF2.Loader.Extensions {
          */
         static GetAvailableVariants(rootMesh: Mesh): string[];
         /**
+         * Gets the list of available variant tag names for this asset.
+         * @param rootMesh The glTF root mesh
+         * @returns the list of all the variant names for this model
+         */
+        getAvailableVariants(rootMesh: Mesh): string[];
+        /**
          * Select a variant given a variant tag name or a list of variant tag names.
          * @param rootMesh The glTF root mesh
          * @param variantName The variant name(s) to select.
          */
         static SelectVariant(rootMesh: Mesh, variantName: string | string[]): void;
         /**
+         * Select a variant given a variant tag name or a list of variant tag names.
+         * @param rootMesh The glTF root mesh
+         * @param variantName The variant name(s) to select.
+         */
+        selectVariant(rootMesh: Mesh, variantName: string | string[]): void;
+        /**
          * Reset back to the original before selecting a variant.
          * @param rootMesh The glTF root mesh
          */
         static Reset(rootMesh: Mesh): void;
         /**
+         * Reset back to the original before selecting a variant.
+         * @param rootMesh The glTF root mesh
+         */
+        reset(rootMesh: Mesh): void;
+        /**
          * Gets the last selected variant tag name(s) or null if original.
          * @param rootMesh The glTF root mesh
          * @returns The selected variant tag name(s).
          */
         static GetLastSelectedVariant(rootMesh: Mesh): Nullable<string | string[]>;
+        /**
+         * Gets the last selected variant tag name(s) or null if original.
+         * @param rootMesh The glTF root mesh
+         * @returns The selected variant tag name(s).
+         */
+        getLastSelectedVariant(rootMesh: Mesh): Nullable<string | string[]>;
         private static _GetExtensionMetadata;
         /** @hidden */
         _loadMeshPrimitiveAsync(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Nullable<Promise<AbstractMesh>>;

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

@@ -67,6 +67,7 @@
 - Added support for recording GIF ([Deltakosh](https://github.com/deltakosh))
 - Popup Window available (To be used in Curve Editor) ([pixelspace](https://github.com/devpixelspace))
 - Add support to update inspector when switching to a new scene ([belfortk](https://github.com/belfortk))
+- View textures in pop out window with zoom & pan ([DarraghBurkeMS](https://github.com/DarraghBurkeMS))
 
 ### Cameras
 

+ 1 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/animations/animationPropertyGridComponent.tsx

@@ -19,7 +19,7 @@ import { FloatLineComponent } from '../../../lines/floatLineComponent';
 import { TextLineComponent } from '../../../lines/textLineComponent';
 import { IAnimatable } from 'babylonjs/Animations/animatable.interface';
 import { AnimationCurveEditorComponent } from '../animations/animationCurveEditorComponent';
-import { PopupComponent } from '../animations/popupComponent';
+import { PopupComponent } from '../../../../popupComponent';
 
 interface IAnimationGridComponentProps {
   globalState: GlobalState;

+ 1 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/animations/targetedAnimationPropertyGridComponent.tsx

@@ -11,7 +11,7 @@ import { TextLineComponent } from '../../../lines/textLineComponent';
 import { LockObject } from '../lockObject';
 import { GlobalState } from '../../../../globalState';
 import { TextInputLineComponent } from '../../../lines/textInputLineComponent';
-import { PopupComponent } from '../animations/popupComponent';
+import { PopupComponent } from '../../../../popupComponent';
 import { AnimationCurveEditorComponent } from '../animations/animationCurveEditorComponent';
 import { AnimationGroup } from 'babylonjs/Animations/animationGroup';
 

+ 42 - 5
inspector/src/components/actionTabs/tabs/propertyGrids/materials/texturePropertyGridComponent.tsx

@@ -27,6 +27,10 @@ import { ButtonLineComponent } from '../../../lines/buttonLineComponent';
 import { TextInputLineComponent } from '../../../lines/textInputLineComponent';
 import { AnimationGridComponent } from '../animations/animationPropertyGridComponent';
 
+import { Engine } from 'babylonjs/Engines/engine';
+import { PopupComponent } from '../../../../popupComponent';
+import { TextureEditorComponent } from './textures/textureEditorComponent';
+
 interface ITexturePropertyGridComponentProps {
     texture: BaseTexture,
     lockObject: LockObject,
@@ -38,6 +42,8 @@ export class TexturePropertyGridComponent extends React.Component<ITextureProper
 
     private _adtInstrumentation: Nullable<AdvancedDynamicTextureInstrumentation>;
     private textureLineRef: React.RefObject<TextureLineComponent>;
+
+    private _isTextureEditorOpen = false;
     
 
     constructor(props: ITexturePropertyGridComponentProps) {
@@ -83,16 +89,27 @@ export class TexturePropertyGridComponent extends React.Component<ITextureProper
                         extension = ".env";
                     }
 
-                    (texture as CubeTexture).updateURL(base64data, extension, () => this.foreceRefresh());
+                    (texture as CubeTexture).updateURL(base64data, extension, () => this.forceRefresh());
                 } else {
-                    (texture as Texture).updateURL(base64data, null, () => this.foreceRefresh());
+                    (texture as Texture).updateURL(base64data, null, () => this.forceRefresh());
                 }
             };
 
         }, undefined, true);
-    }    
+    }
+
+    onOpenTextureEditor() {
+        this._isTextureEditorOpen = true;
+    }
+    
+    onCloseTextureEditor(window: Window | null) {
+        this._isTextureEditorOpen = false;
+        if (window !== null) {
+            window.close();
+        }
+    }
 
-    foreceRefresh() {
+    forceRefresh() {
         this.forceUpdate();
         (this.textureLineRef.current as TextureLineComponent).updatePreview();
     }
@@ -132,16 +149,36 @@ export class TexturePropertyGridComponent extends React.Component<ITextureProper
             }
         }
 
+        const editable = texture.textureType != Engine.TEXTURETYPE_FLOAT && texture.textureType != Engine.TEXTURETYPE_FLOAT_32_UNSIGNED_INT_24_8_REV && texture.textureType !== Engine.TEXTURETYPE_HALF_FLOAT;
+
         return (
             <div className="pane">
                 <LineContainerComponent globalState={this.props.globalState} title="PREVIEW">
                     <TextureLineComponent ref={this.textureLineRef} texture={texture} width={256} height={256} globalState={this.props.globalState} />
                     <FileButtonLineComponent label="Load texture from file" onClick={(file) => this.updateTexture(file)} accept=".jpg, .png, .tga, .dds, .env" />
+                    {editable &&
+                        <ButtonLineComponent label="View" onClick={() => this.onOpenTextureEditor()} />
+                    }
                     <TextInputLineComponent label="URL" value={textureUrl} lockObject={this.props.lockObject} onChange={url => {
                         (texture as Texture).updateURL(url);
-                        this.foreceRefresh();
+                        this.forceRefresh();
                     }} />
                 </LineContainerComponent>
+                {this._isTextureEditorOpen && (
+                <PopupComponent
+                  id='texture-editor'
+                  title='Texture Editor'
+                  size={{ width: 1024, height: 490 }}
+                  onOpen={(window: Window) => {}}
+                  onClose={(window: Window) =>
+                    this.onCloseTextureEditor(window)
+                  }
+                >
+                    <TextureEditorComponent
+                        globalState={this.props.globalState}
+                        texture={this.props.texture}
+                    />
+                </PopupComponent>)}
                 <CustomPropertyGridComponent globalState={this.props.globalState} target={texture}
                     lockObject={this.props.lockObject}
                     onPropertyChangedObservable={this.props.onPropertyChangedObservable} />

+ 156 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/materials/textures/textureCanvasManager.ts

@@ -0,0 +1,156 @@
+import { Engine } from 'babylonjs/Engines/engine';
+import { Scene } from 'babylonjs/scene';
+import { Vector3 } from 'babylonjs/Maths/math.vector';
+import { Color4 } from 'babylonjs/Maths/math.color';
+import { FreeCamera } from 'babylonjs/Cameras/freeCamera';
+
+import { PlaneBuilder } from 'babylonjs/Meshes/Builders/planeBuilder';
+import { Mesh } from 'babylonjs/Meshes/mesh';
+import { Camera } from 'babylonjs/Cameras/camera';
+import { DynamicTexture } from 'babylonjs/Materials/Textures/dynamicTexture';
+import { BaseTexture } from 'babylonjs/Materials/Textures/baseTexture';
+import { NodeMaterial } from 'babylonjs/Materials/Node/nodeMaterial';
+
+import { PointerEventTypes } from 'babylonjs/Events/pointerEvents';
+import { KeyboardEventTypes } from 'babylonjs/Events/keyboardEvents';
+
+export class TextureCanvasManager {
+    private _engine: Engine;
+    private _scene: Scene;
+    private _texture: DynamicTexture;
+    private _camera: FreeCamera;
+    private _canvas : HTMLCanvasElement;
+
+    private _scale : number;
+    private _isPanning : boolean;
+    private _mouseX : number;
+    private _mouseY : number;
+
+    private _plane : Mesh;
+    private _planeMaterial : NodeMaterial;
+
+    private static ZOOM_MOUSE_SPEED : number = 0.0005;
+    private static ZOOM_KEYBOARD_SPEED : number = 0.2;
+    private static PAN_SPEED : number = 0.002;
+    private static PAN_BUTTON : number = 0; // left mouse button
+    private static MIN_SCALE : number = 0.01;
+    private static MAX_SCALE : number = 10;
+
+    public constructor(targetCanvas: HTMLCanvasElement, texture: BaseTexture) {
+        this._canvas = targetCanvas;
+
+        this._engine = new Engine(targetCanvas, true);
+        this._scene = new Scene(this._engine);
+        this._scene.clearColor = new Color4(0.2, 0.2, 0.2, 1.0);
+
+        this._camera = new FreeCamera("Camera", new Vector3(0, 0, -1), this._scene);
+        this._camera.mode = Camera.ORTHOGRAPHIC_CAMERA;
+
+        if (texture) {
+            /* Grab image data from original texture and paint it onto the context of a DynamicTexture */
+            const pixelData = texture.readPixels()!;
+            const arr = new Uint8ClampedArray(pixelData.buffer);
+            let imgData = new ImageData(arr, texture.getSize().width, texture.getSize().height);
+            this._texture = new DynamicTexture("texture", texture.getSize(), this._scene, false);
+            const ctx = this._texture.getContext();
+            ctx.putImageData(imgData, 0, 0);
+            this._texture.update();
+            this._texture.hasAlpha = texture.hasAlpha;
+        } else {
+            /* If we don't have a texture to start with, just generate a white rectangle */
+            this._texture = new DynamicTexture("texture",  256, this._scene, false);
+            const ctx = this._texture.getContext();
+            ctx.fillStyle = 'white';
+            ctx.fillRect(0, 0, 256, 256);
+            this._texture.update();
+        }
+
+        this._texture.updateSamplingMode(Engine.TEXTURE_NEAREST_LINEAR);
+        const textureRatio = this._texture.getSize().width / this._texture.getSize().height;
+
+        this._plane = PlaneBuilder.CreatePlane("plane", {width: textureRatio, height: 1}, this._scene);
+        NodeMaterial.ParseFromSnippetAsync("#TPSEV2#3", this._scene)
+            .then((material) => {
+                this._planeMaterial = material;
+                this._planeMaterial.getTextureBlocks()[0].texture = this._texture;
+                this._plane.material = this._planeMaterial;
+                this._canvas.focus();
+            });
+        this._plane.enableEdgesRendering();
+        this._plane.edgesWidth = 4.0;
+        this._plane.edgesColor = new Color4(1,1,1,1);
+
+        this._engine.runRenderLoop(() => {
+            this._engine.resize();
+            this._scene.render();
+
+        });
+
+        this._scale = 1;
+        this._isPanning = false;
+
+        this._scene.onBeforeRenderObservable.add(() => {
+            let ratio = this._canvas?.width / this._canvas?.height;
+            this._camera.orthoBottom = -this._scale;
+            this._camera.orthoTop = this._scale;
+            this._camera.orthoLeft = -this._scale * ratio;
+            this._camera.orthoRight = this._scale * ratio;
+        })
+
+        this._scene.onPointerObservable.add((pointerInfo) => {
+            switch (pointerInfo.type) {
+                case PointerEventTypes.POINTERWHEEL:
+                    const event = pointerInfo.event as MouseWheelEvent;
+                    this._scale += (event.deltaY * TextureCanvasManager.ZOOM_MOUSE_SPEED * this._scale);
+                    this._scale = Math.min(Math.max(this._scale, TextureCanvasManager.MIN_SCALE), TextureCanvasManager.MAX_SCALE);
+                    break;
+                case PointerEventTypes.POINTERDOWN:
+                    if (pointerInfo.event.button === TextureCanvasManager.PAN_BUTTON) {
+                        this._isPanning = true;
+                        this._mouseX = pointerInfo.event.x;
+                        this._mouseY = pointerInfo.event.y;
+                    }
+                    break;
+                case PointerEventTypes.POINTERUP:
+                    if (pointerInfo.event.button === TextureCanvasManager.PAN_BUTTON) {
+                        this._isPanning = false;
+                    }
+                    break;
+                case PointerEventTypes.POINTERMOVE:
+                    if (this._isPanning) {
+                        this._camera.position.x -= (pointerInfo.event.x - this._mouseX) * this._scale * TextureCanvasManager.PAN_SPEED;
+                        this._camera.position.y += (pointerInfo.event.y - this._mouseY) * this._scale * TextureCanvasManager.PAN_SPEED;
+                        this._mouseX = pointerInfo.event.x;
+                        this._mouseY = pointerInfo.event.y;
+                    }
+                    break;
+            }
+        })
+
+        this._scene.onKeyboardObservable.add((kbInfo) => {
+            switch(kbInfo.type) {
+                case KeyboardEventTypes.KEYDOWN:
+                    if (kbInfo.event.key == "+") {
+                        this._scale -= TextureCanvasManager.ZOOM_KEYBOARD_SPEED * this._scale;
+                    }
+                    if (kbInfo.event.key == "-") {
+                        this._scale += TextureCanvasManager.ZOOM_KEYBOARD_SPEED * this._scale;
+                    }
+                    this._scale = Math.min(Math.max(this._scale, TextureCanvasManager.MIN_SCALE), TextureCanvasManager.MAX_SCALE);
+                    break;
+            }
+        })
+
+    }
+
+    public dispose() {
+        if (this._planeMaterial) {
+            this._planeMaterial.dispose();
+        }
+        this._texture.dispose();
+        this._plane.dispose();
+        this._camera.dispose();
+        this._scene.dispose();
+        this._engine.dispose();
+    }
+} 

+ 4 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/materials/textures/textureEditor.scss

@@ -0,0 +1,4 @@
+#texture-canvas {
+    width: 100%;
+    height: 100%;
+}

+ 30 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/materials/textures/textureEditorComponent.tsx

@@ -0,0 +1,30 @@
+import * as React from 'react';
+import { GlobalState } from '../../../../../globalState';
+import { BaseTexture } from 'babylonjs/Materials/Textures/baseTexture';
+import { TextureCanvasManager } from './textureCanvasManager';
+
+require('./textureEditor.scss');
+
+interface TextureEditorComponentProps {
+    globalState: GlobalState;
+    texture: BaseTexture;
+}
+
+export class TextureEditorComponent extends React.Component<TextureEditorComponentProps> {
+    private _textureCanvasManager: TextureCanvasManager;
+    private reactCanvas = React.createRef<HTMLCanvasElement>();
+
+    componentDidMount() {
+        this._textureCanvasManager = new TextureCanvasManager(this.reactCanvas.current!, this.props.texture);
+    }
+
+    componentWillUnmount() {
+        this._textureCanvasManager.dispose();
+    }
+
+    render() {
+        return <div id='texture-editor'>
+            <canvas id="texture-canvas" ref={this.reactCanvas} tabIndex={1}></canvas>
+        </div>
+    }
+}

+ 1 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/animations/popupComponent.tsx

@@ -1,6 +1,6 @@
 import * as React from "react";
 import * as ReactDOM from 'react-dom';
-import { Inspector } from '../../../../../inspector';
+import { Inspector } from '../inspector';
 
 interface IPopupComponentProps {
     id: string,

+ 3 - 5
sandbox/public/index-local.html

@@ -4,15 +4,13 @@
 <head>
     <title>Babylon.js Sandbox - View glTF, glb, obj and babylon files</title>
     <meta name="description" content="Viewer for glTF, glb, obj and babylon files powered by Babylon.js" />
-    <meta name="keywords"
-        content="Babylon.js, Babylon, BabylonJS, glTF, glb, obj, viewer, online viewer, 3D model viewer, 3D, webgl" />
+    <meta name="keywords" content="Babylon.js, Babylon, BabylonJS, glTF, glb, obj, viewer, online viewer, 3D model viewer, 3D, webgl" />
     <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
     <link rel="stylesheet" href="https://use.typekit.net/cta4xsb.css">
     <link rel="shortcut icon" href="https://www.babylonjs.com/favicon.ico">
     <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-
+    <script src="../../dist/preview%20release/libktx.js"></script>
     <script src="../../Tools/DevLoader/BabylonLoader.js"></script>
-    
     <style>
         html,
         body {
@@ -25,7 +23,7 @@
 
         #host-element {
             width: 100%;
-            height: 100%;            
+            height: 100%;
         }
     </style>
 </head>

+ 2 - 2
src/Misc/khronosTextureContainer2.ts

@@ -16,7 +16,7 @@ export class KhronosTextureContainer2 {
     public constructor(engine: ThinEngine) {
         if (!KhronosTextureContainer2._ModulePromise) {
             KhronosTextureContainer2._ModulePromise = new Promise((resolve) => {
-                LIBKTX().then((module: any) => {
+                LIBKTX({preinitializedWebGLContext: engine._gl}).then((module: any) => {
                     module.GL.makeContextCurrent(module.GL.registerContext(engine._gl, { majorVersion: engine._webGLVersion }));
                     KhronosTextureContainer2._TranscodeFormat = this._determineTranscodeFormat(module.TranscodeTarget, engine.getCaps());
                     resolve({ module: module });
@@ -31,7 +31,7 @@ export class KhronosTextureContainer2 {
 
             const ktxTexture = new module.ktxTexture(data);
             try {
-                if (ktxTexture.isBasisSupercompressed) {
+                if (ktxTexture.needsTranscoding) {
                     ktxTexture.transcodeBasis(KhronosTextureContainer2._TranscodeFormat, 0);
                 }
 

+ 4 - 0
src/XR/features/WebXRControllerTeleportation.ts

@@ -237,6 +237,9 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
             return false;
         }
 
+        // Safety reset
+        this._currentTeleportationControllerId = '';
+
         this._options.xrInput.controllers.forEach(this._attachController);
         this._addNewAttachObserver(this._options.xrInput.onControllerAddedObservable, this._attachController);
         this._addNewAttachObserver(this._options.xrInput.onControllerRemovedObservable, (controller) => {
@@ -257,6 +260,7 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
         });
 
         this._setTargetMeshVisibility(false);
+        this._currentTeleportationControllerId = '';
 
         return true;
     }

+ 6 - 1
src/XR/webXREnterExitUI.ts

@@ -58,6 +58,11 @@ export class WebXREnterExitUIOptions {
      * A list of optional features to init the session with
      */
     optionalFeatures?: string[];
+
+    /**
+     * A list of optional features to init the session with
+     */
+    requiredFeatures?: string[];
 }
 /**
  * UI to allow the user to enter/exit XR mode
@@ -157,7 +162,7 @@ export class WebXREnterExitUI implements IDisposable {
                         } else if (helper.state == WebXRState.NOT_IN_XR) {
                             if (options.renderTarget) {
                                 try {
-                                    await helper.enterXRAsync(ui._buttons[i].sessionMode, ui._buttons[i].referenceSpaceType, options.renderTarget, {optionalFeatures: options.optionalFeatures});
+                                    await helper.enterXRAsync(ui._buttons[i].sessionMode, ui._buttons[i].referenceSpaceType, options.renderTarget, {optionalFeatures: options.optionalFeatures, requiredFeatures: options.requiredFeatures});
                                     ui._updateButtons(ui._buttons[i]);
                                 } catch (e) {
                                     // make sure button is visible