Browse Source

Merge branch 'master' into pbr-sheen-bug

David Catuhe 5 years ago
parent
commit
5f724e6666

BIN
Playground/css/img/clear_button.png


File diff suppressed because it is too large
+ 292 - 76
Playground/css/index.css


+ 3 - 4
Playground/debug.html

@@ -34,7 +34,6 @@
         <meta name="msapplication-config" content="https://www.babylonjs.com/img/favicon/browserconfig.xml">
         <meta name="theme-color" content="#ffffff">
 
-        <link rel="stylesheet" href="https://use.typekit.net/cta4xsb.css" />
         <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" />
@@ -132,8 +131,8 @@
             </div>
 
             <div class="category languageJS" id="JStoTSbar">
-                <div class="buttonJStoTS languageTS" id="toTSbutton1280">Typescript</div>
-                <div class="buttonJStoTS languageJS" id="toJSbutton1280">Javascript</div>
+                <div class="buttonJStoTS languageTS" id="toTSbutton1280">TS</div>
+                <div class="buttonJStoTS languageJS" id="toJSbutton1280">JS</div>
                 <div class="buttonPG run removeOnDiff" id="runButton1280"><img src="/css/img/playButton.svg"></div>
                 <div class="buttonPG removeOnDiff" id="saveButton1280"><img src="/css/img/saveButton.svg"></div>
                 <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1280"><img
@@ -409,7 +408,7 @@
             <div class="horizontalSeparator"></div>
             <input id="filterBar" type="text" placeholder="Filter examples...">
             <img id="filterBarClear"
-                src="https://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/clear_button.png">
+                src="/css/img/clear_button.png">
         </div>
 
         <div class="fpsLabel languageJS" id="fpsLabel"></div>

+ 3 - 4
Playground/index-local.html

@@ -9,7 +9,6 @@
         <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://use.typekit.net/cta4xsb.css" />
         <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" />
@@ -48,8 +47,8 @@
             </div>
 
             <div class="category languageJS" id="JStoTSbar">
-                <div class="buttonJStoTS languageTS" id="toTSbutton1280" title="Switch to TypeScript">Typescript</div>
-                <div class="buttonJStoTS languageJS" id="toJSbutton1280" title="Switch to JavaScript">Javascript</div>
+                <div class="buttonJStoTS languageTS" id="toTSbutton1280" title="Switch to TypeScript">TS</div>
+                <div class="buttonJStoTS languageJS" id="toJSbutton1280" title="Switch to JavaScript">JS</div>
                 <div class="buttonPG run removeOnDiff" id="runButton1280" title="Run&#10;(Alt+Enter)"><img
                         src="css/img/playButton.svg"></div>
                 <div class="buttonPG removeOnDiff" id="saveButton1280" title="Save&#10;(Ctrl+S)"><img
@@ -333,7 +332,7 @@
             <div class="horizontalSeparator"></div>
             <input id="filterBar" type="text" placeholder="Filter examples...">
             <img id="filterBarClear"
-                src="https://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/clear_button.png">
+                src="css/img/clear_button.png">
         </div>
 
         <div class="fpsLabel languageJS" id="fpsLabel"></div>

+ 42 - 32
Playground/index.html

@@ -10,8 +10,8 @@
         <meta name="google-site-verification" content="wcRjktXhF6DAjmhneKS7UatweBIkEF6QfqsNhAYbUgg" />
         <link rel="shortcut icon" href="https://www.babylonjs.com/favicon.ico">
 
-        <link rel="stylesheet" href="https://use.typekit.net/cta4xsb.css" />
-        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css" />
+        <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" />
 
@@ -26,8 +26,8 @@
             </div>
 
             <div class="category languageJS" id="JStoTSbar">
-                <div class="buttonJStoTS languageTS" id="toTSbutton1280" title="Switch to TypeScript">Typescript</div>
-                <div class="buttonJStoTS languageJS" id="toJSbutton1280" title="Switch to JavaScript">Javascript</div>
+                <div class="buttonJStoTS languageTS" id="toTSbutton1280">TS</div>
+                <div class="buttonJStoTS languageJS" id="toJSbutton1280">JS</div>
                 <div class="buttonPG run removeOnDiff" id="runButton1280" title="Run&#10;(Alt+Enter)"><img
                         src="/css/img/playButton.svg"></div>
                 <div class="buttonPG removeOnDiff" id="saveButton1280" title="Save&#10;(Ctrl+S)"><img
@@ -107,8 +107,8 @@
             </div>
 
             <div class="category languageJS" id="JStoTSbar">
-                <div class="buttonJStoTS languageTS" id="toTSbutton1024" title="Switch to TypeScript">TS</div>
-                <div class="buttonJStoTS languageJS" id="toJSbutton1024" title="Switch to JavaScript">JS</div>
+                <div class="buttonJStoTS languageTS" id="toTSbutton1024">TS</div>
+                <div class="buttonJStoTS languageJS" id="toJSbutton1024">JS</div>
                 <div class="buttonSpaceKiller"></div>
                 <div class="buttonPG run removeOnDiff" id="runButton1024" title="Run&#10;(Alt+Enter)"><img
                         src="/css/img/playButton.svg"></div>
@@ -309,8 +309,7 @@
             </div>
             <div class="horizontalSeparator"></div>
             <input id="filterBar" type="text" placeholder="Filter examples...">
-            <img id="filterBarClear"
-                src="https://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/clear_button.png">
+            <img id="filterBarClear" src="/css/img/clear_button.png">
         </div>
 
         <div class="fpsLabel languageJS" id="fpsLabel"></div>
@@ -396,13 +395,6 @@
         <script src="/js/libs/jszip.min.js"></script>
         <script src="/js/libs/fileSaver.js"></script>
 
-        <!-- Dependencies -->
-        <script src="https://preview.babylonjs.com/ammo.js"></script>
-        <script src="https://preview.babylonjs.com/recast.js"></script>
-        <script src="https://preview.babylonjs.com/cannon.js"></script>
-        <script src="https://preview.babylonjs.com/Oimo.js"></script>
-        <script src="https://preview.babylonjs.com/libktx.js"></script>
-        <script src="https://preview.babylonjs.com/earcut.min.js"></script>
         <!-- Babylon.js -->
         <script src="https://preview.babylonjs.com/babylon.js"></script>
         <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
@@ -415,23 +407,6 @@
         <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.min.js"></script>
         <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
 
-        <!-- Extensions -->
-        <script
-            src="https://rawcdn.githack.com/BabylonJS/Extensions/f43ab677b4bca0a6ab77132d3f785be300382760/ClonerSystem/src/babylonx.cloner.js"
-            async>
-        </script>
-        <script
-            src="https://rawcdn.githack.com/BabylonJS/Extensions/785013ec55b210d12263c91f3f0a2ae70cf0bc8a/CompoundShader/src/babylonx.CompoundShader.js"
-            async></script>
-
-        <!-- Scene Manager -->
-        <script
-            src="https://rawcdn.githack.com/MackeyK24/MackeyK24.github.io/14fda491c50cfca6d3e2f6cbc5e6afe22cc455d6/toolkit/babylon.manager.js">
-        </script>
-        <script
-            src="https://rawcdn.githack.com/MackeyK24/MackeyK24.github.io/14fda491c50cfca6d3e2f6cbc5e6afe22cc455d6/toolkit/babylon.navmesh.js">
-        </script>
-
         <!-- Monaco -->
         <script src="/node_modules/monaco-editor/dev/vs/loader.js"></script>
 
@@ -450,6 +425,41 @@
         <script src="/js/utils.js"></script>
         <script src="/js/zipTool.js"></script>
         <script src="/js/index.js"></script>
+
+        <script>
+            // when loading the following resources, use the global scope and not AMD
+            window.def = window.define;
+            window.define = undefined;
+        </script>
+
+        <!-- Dependencies -->
+        <script src="https://rawcdn.githack.com/BabylonJS/Babylon.js/991ff1bafc4d8ad6d501e9354d70a5e2b2bd3ea2/dist/preview%20release/ammo.js"></script>
+        <script src="https://rawcdn.githack.com/BabylonJS/Babylon.js/54684912728536933561b5cf61ddb2aa9735d9f2/dist/preview%20release/earcut.min.js"></script>
+        <script src="https://preview.babylonjs.com/recast.js"></script>
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/cannon.js/0.6.2/cannon.min.js"></script>
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/oimo/1.0.9/oimo.min.js"></script>
+        <script src="https://preview.babylonjs.com/libktx.js"></script>
+
+        <!-- Extensions -->
+        <script
+            src="https://rawcdn.githack.com/BabylonJS/Extensions/f43ab677b4bca0a6ab77132d3f785be300382760/ClonerSystem/src/babylonx.cloner.js"
+            async>
+        </script>
+        <script
+            src="https://rawcdn.githack.com/BabylonJS/Extensions/785013ec55b210d12263c91f3f0a2ae70cf0bc8a/CompoundShader/src/babylonx.CompoundShader.js"
+            async></script>
+
+        <!-- Scene Manager -->
+        <script
+            src="https://rawcdn.githack.com/MackeyK24/MackeyK24.github.io/14fda491c50cfca6d3e2f6cbc5e6afe22cc455d6/toolkit/babylon.manager.js">
+        </script>
+        <script
+            src="https://rawcdn.githack.com/MackeyK24/MackeyK24.github.io/14fda491c50cfca6d3e2f6cbc5e6afe22cc455d6/toolkit/babylon.navmesh.js">
+        </script>
+        <script>
+            // bring me back my AMD!
+            window.define = window.def;
+        </script>
     </body>
 
 </html>

+ 1 - 2
Playground/indexStable.html

@@ -7,7 +7,6 @@
         <meta name="viewport" content="width=device-width, user-scalable=no">
         <link rel="shortcut icon" href="https://www.babylonjs.com/img/favicon/favicon.ico">
 
-        <link rel="stylesheet" href="https://use.typekit.net/cta4xsb.css" />
         <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" />
@@ -301,7 +300,7 @@
             <div class="horizontalSeparator"></div>
             <input id="filterBar" type="text" placeholder="Filter examples...">
             <img id="filterBarClear"
-                src="https://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/clear_button.png">
+                src="/css/img/clear_button.png">
         </div>
 
         <div class="fpsLabel languageJS" id="fpsLabel"></div>

+ 1 - 2
Playground/indexWebGPU.html

@@ -7,7 +7,6 @@
         <meta name="viewport" content="width=device-width, user-scalable=no">
         <link rel="shortcut icon" href="https://www.babylonjs.com/favicon.ico">
 
-        <link rel="stylesheet" href="https://use.typekit.net/cta4xsb.css" />
         <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" />
@@ -346,7 +345,7 @@
             <div class="horizontalSeparator"></div>
             <input id="filterBar" type="text" placeholder="Filter examples...">
             <img id="filterBarClear"
-                src="https://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/clear_button.png">
+                src="/css/img/clear_button.png">
         </div>
 
         <div class="fpsLabel languageJS" id="fpsLabel"></div>

+ 81 - 73
Playground/js/main.js

@@ -229,6 +229,17 @@ class Main {
         this.fpsLabel = document.getElementById("fpsLabel");
         this.scripts;
         this.previousHash = "";
+
+        // Restore BJS version if needed
+        var restoreVersionResult = true;
+        if (this.parent.settingsPG.restoreVersion() == false) {
+            // Check if there a hash in the URL
+            this.checkHash();
+            restoreVersionResult = false;
+        }
+
+        // Load scripts list
+        this.loadScriptsList(restoreVersionResult);
     }
 
     /**
@@ -266,17 +277,6 @@ class Main {
             }.bind(this)
         );
 
-        // Restore BJS version if needed
-        var restoreVersionResult = true;
-        if (this.parent.settingsPG.restoreVersion() == false) {
-            // Check if there a hash in the URL
-            this.checkHash();
-            restoreVersionResult = false;
-        }
-
-        // Load scripts list
-        this.loadScriptsList(restoreVersionResult);
-
         // -------------------- UI --------------------
         var handleRun = () => compileAndRun(this.parent, this.fpsLabel);
         var handleSave = () => this.askForSave();
@@ -336,53 +336,56 @@ class Main {
             }
         }
         // Language (JS / TS)
-        this.parent.utils.setToMultipleID("toTSbutton", "click", function () {
-            if (location.hash != null && location.hash != "") {
-                this.parent.settingsPG.ScriptLanguage = "TS";
-                window.location = "./";
-            } else {
-                if (this.parent.settingsPG.ScriptLanguage == "JS") {
-                    //revert in case the reload is cancel due to safe mode
-                    if (document.getElementById("safemodeToggle" + this.parent.utils.getCurrentSize()).classList.contains('checked')) {
-                        // Message before unload
-                        var languageTSswapper = function () {
+        if (this.parent.settingsPG.ScriptLanguage === "JS") {
+            this.parent.utils.setToMultipleID("toTSbutton", "click", function () {
+                if (location.hash != null && location.hash != "") {
+                    this.parent.settingsPG.ScriptLanguage = "TS";
+                    window.location = "./";
+                } else {
+                    if (this.parent.settingsPG.ScriptLanguage == "JS") {
+                        //revert in case the reload is cancel due to safe mode
+                        if (document.getElementById("safemodeToggle" + this.parent.utils.getCurrentSize()).classList.contains('checked')) {
+                            // Message before unload
+                            var languageTSswapper = function () {
+                                this.parent.settingsPG.ScriptLanguage = "TS";
+                                window.removeEventListener('unload', languageTSswapper.bind(this));
+                            };
+                            window.addEventListener('unload', languageTSswapper.bind(this));
+
+                            location.reload();
+                        } else {
                             this.parent.settingsPG.ScriptLanguage = "TS";
-                            window.removeEventListener('unload', languageTSswapper.bind(this));
-                        };
-                        window.addEventListener('unload', languageTSswapper.bind(this));
-
-                        location.reload();
-                    } else {
-                        this.parent.settingsPG.ScriptLanguage = "TS";
-                        location.reload();
+                            location.reload();
+                        }
                     }
                 }
-            }
 
-        }.bind(this));
-        this.parent.utils.setToMultipleID("toJSbutton", "click", function () {
-            if (location.hash != null && location.hash != "") {
-                this.parent.settingsPG.ScriptLanguage = "JS";
-                window.location = "./";
-            } else {
-                if (this.parent.settingsPG.ScriptLanguage == "TS") {
-                    //revert in case the reload is cancel due to safe mode
-                    if (document.getElementById("safemodeToggle" + this.parent.utils.getCurrentSize()).classList.contains('checked')) {
-                        // Message before unload
-                        var LanguageJSswapper = function () {
+            }.bind(this));
+        } else {
+            this.parent.utils.setToMultipleID("toJSbutton", "click", function () {
+                if (location.hash != null && location.hash != "") {
+                    this.parent.settingsPG.ScriptLanguage = "JS";
+                    window.location = "./";
+                } else {
+                    if (this.parent.settingsPG.ScriptLanguage == "TS") {
+                        //revert in case the reload is cancel due to safe mode
+                        if (document.getElementById("safemodeToggle" + this.parent.utils.getCurrentSize()).classList.contains('checked')) {
+                            // Message before unload
+                            var LanguageJSswapper = function () {
+                                this.parent.settingsPG.ScriptLanguage = "JS";
+                                window.removeEventListener('unload', LanguageJSswapper.bind(this));
+                            };
+                            window.addEventListener('unload', LanguageJSswapper.bind(this));
+
+                            location.reload();
+                        } else {
                             this.parent.settingsPG.ScriptLanguage = "JS";
-                            window.removeEventListener('unload', LanguageJSswapper.bind(this));
-                        };
-                        window.addEventListener('unload', LanguageJSswapper.bind(this));
-
-                        location.reload();
-                    } else {
-                        this.parent.settingsPG.ScriptLanguage = "JS";
-                        location.reload();
+                            location.reload();
+                        }
                     }
                 }
-            }
-        }.bind(this));
+            }.bind(this));
+        }
         // Safe mode
         this.parent.utils.setToMultipleID("safemodeToggle", 'click', function () {
             document.getElementById("safemodeToggle1280").classList.toggle('checked');
@@ -497,14 +500,16 @@ class Main {
                     if (!this.checkTypescriptSupport(xhr)) return;
 
                     xhr.onreadystatechange = null;
-                    this.parent.monacoCreator.BlockEditorChange = true;
-                    this.parent.monacoCreator.JsEditor.setValue(xhr.responseText);
-                    this.parent.monacoCreator.JsEditor.setPosition({
-                        lineNumber: 0,
-                        column: 0
-                    });
-                    this.parent.monacoCreator.BlockEditorChange = false;
-                    compileAndRun(this.parent, this.fpsLabel);
+                    this.parent.monacoCreator.addOnMoncaoLoadedCallback(function () {
+                        this.parent.monacoCreator.BlockEditorChange = true;
+                        this.parent.monacoCreator.JsEditor.setValue(xhr.responseText);
+                        this.parent.monacoCreator.JsEditor.setPosition({
+                            lineNumber: 0,
+                            column: 0
+                        });
+                        this.parent.monacoCreator.BlockEditorChange = false;
+                        compileAndRun(this.parent, this.fpsLabel);
+                    }, this);
 
                     this.currentSnippetToken = null;
                 }
@@ -1074,8 +1079,8 @@ class Main {
         }
         if (pgHash) {
             var match = pgHash.match(/^(#[A-Za-z\d]*)(%23)([\d]+)$/);
-            if (match){
-                pgHash = match[1]+'#'+match[3];
+            if (match) {
+                pgHash = match[1] + '#' + match[3];
                 parent.location.hash = pgHash;
             }
             this.previousHash = pgHash;
@@ -1096,9 +1101,6 @@ class Main {
 
                         var snippet = JSON.parse(xmlHttp.responseText);
 
-                        this.parent.monacoCreator.BlockEditorChange = true;
-                        this.parent.monacoCreator.JsEditor.setValue(JSON.parse(snippet.jsonPayload).code.toString());
-
                         // Check if title / descr / tags are already set
                         if (snippet.name != null && snippet.name != "") {
                             this.currentSnippetTitle = snippet.name;
@@ -1127,12 +1129,18 @@ class Main {
 
                         this.updateMetadata();
 
-                        this.parent.monacoCreator.JsEditor.setPosition({
-                            lineNumber: 0,
-                            column: 0
-                        });
-                        this.parent.monacoCreator.BlockEditorChange = false;
-                        compileAndRun(this.parent, this.fpsLabel);
+                        this.parent.monacoCreator.addOnMoncaoLoadedCallback(function () {
+                            this.parent.monacoCreator.BlockEditorChange = true;
+                            this.parent.monacoCreator.JsEditor.setValue(JSON.parse(snippet.jsonPayload).code.toString());
+
+                            this.parent.monacoCreator.JsEditor.setPosition({
+                                lineNumber: 0,
+                                column: 0
+                            });
+                            this.parent.monacoCreator.BlockEditorChange = false;
+                            compileAndRun(this.parent, this.fpsLabel);
+                        }, this);
+
                     }
                 }
             }.bind(this);
@@ -1151,21 +1159,21 @@ class Main {
 
         if (this.currentSnippetTitle) {
             selection = document.querySelector('title');
-            if(selection){
+            if (selection) {
                 selection.innerText = (this.currentSnippetTitle + " | Babylon.js Playground");
             }
         }
 
         if (this.currentSnippetDescription) {
             selection = document.querySelector('meta[name="description"]');
-            if(selection){
+            if (selection) {
                 selection.setAttribute("content", this.currentSnippetDescription + " - Babylon.js Playground");
             }
         }
 
         if (this.currentSnippetTags) {
             selection = document.querySelector('meta[name="keywords"]');
-            if(selection){
+            if (selection) {
                 selection.setAttribute("content", "babylon.js, game engine, webgl, 3d," + this.currentSnippetTags);
             }
         }

+ 83 - 21
Playground/js/monacoCreator.js

@@ -23,6 +23,13 @@ class MonacoCreator {
         this.deprecatedCandidates = [];
 
         this.compilerTriggerTimeoutID = null;
+
+        this.addOnMoncaoLoadedCallback(
+            function () {
+                this.parent.main.run();
+            },
+            this
+        );
     }
 
     // ACCESSORS
@@ -43,8 +50,8 @@ class MonacoCreator {
         return this.monacoMode;
     };
     set MonacoMode(mode) {
-        if (this.monacoMode != "javascript"
-            && this.monacoMode != "typescript")
+        if (this.monacoMode != "javascript" &&
+            this.monacoMode != "typescript")
             console.warn("Error while defining Monaco Mode");
         this.monacoMode = mode;
     };
@@ -81,12 +88,16 @@ class MonacoCreator {
         this.setupDefinitionWorker(libContent);
 
         // WARNING !!! We need the 'dev' version of Monaco, as we use monkey-patching to hook into the suggestion adapter
-        require.config({ paths: { 'vs': '/node_modules/monaco-editor/dev/vs' } });
+        require.config({
+            paths: {
+                'vs': '/node_modules/monaco-editor/dev/vs'
+            }
+        });
 
         require(['vs/editor/editor.main'], () => {
             // 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();
 
@@ -95,10 +106,38 @@ class MonacoCreator {
                 this.hookMonacoCompletionProvider(module.SuggestAdapter);
             });
 
-            this.parent.main.run();
+            this.onMonacoLoaded();
         });
     };
 
+    onMonacoLoaded() {
+        if (this.monacoLoaded) {
+            return;
+        }
+        this.onMonacoLoadedCallbacks.forEach((callbackDef) => {
+            callbackDef.func.call(callbackDef.context, this);
+        });
+        this.monacoLoaded = true;
+    }
+
+    /**
+     * This will register a new callback that will be triggered when the monaco loader is done.
+     * If the loader is already done, the function will be executed right away. 
+     * @param {Function} func the function to call when monaco is available
+     * @param {*} context The context of this function
+     */
+    addOnMoncaoLoadedCallback(func, context) {
+        this.onMonacoLoadedCallbacks = this.onMonacoLoadedCallbacks || [];
+        if (this.monacoLoaded) {
+            func.call(context, this);
+        } else {
+            this.onMonacoLoadedCallbacks.push({
+                func: func,
+                context: context
+            });
+        }
+    }
+
     // > 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
@@ -109,22 +148,26 @@ class MonacoCreator {
     // We will also need this worker in the future to compute Intellicode scores for completion using dedicated attributes.
     setupDefinitionWorker(libContent) {
         this.definitionWorker = new Worker('/js/definitionWorker.js');
-        this.definitionWorker.addEventListener('message', ({ data }) => {
+        this.definitionWorker.addEventListener('message', ({
+            data
+        }) => {
             this.deprecatedCandidates = data.result;
             this.analyzeCode();
         });
-        this.definitionWorker.postMessage({ code: libContent });
+        this.definitionWorker.postMessage({
+            code: libContent
+        });
     }
 
     isDeprecatedEntry(details) {
-        return details
-            && details.tags
-            && details.tags.find(this.isDeprecatedTag);
+        return details &&
+            details.tags &&
+            details.tags.find(this.isDeprecatedTag);
     }
 
     isDeprecatedTag(tag) {
-        return tag
-            && tag.name == "deprecated";
+        return tag &&
+            tag.name == "deprecated";
     }
 
     // This will make sure that all members marked with a deprecated jsdoc attribute will be marked as such in Monaco UI
@@ -156,7 +199,10 @@ class MonacoCreator {
         for (const candidate of this.deprecatedCandidates) {
             const matches = model.findMatches(candidate, null, false, true, null, false);
             for (const match of matches) {
-                const position = { lineNumber: match.range.startLineNumber, column: match.range.startColumn };
+                const position = {
+                    lineNumber: match.range.startLineNumber,
+                    column: match.range.startColumn
+                };
                 const wordInfo = model.getWordAtPosition(position);
                 const offset = model.getOffsetAt(position);
 
@@ -184,7 +230,7 @@ class MonacoCreator {
 
         monaco.editor.setModelMarkers(model, source, markers);
     }
-    
+
     // This is our hook in the Monaco suggest adapter, we are called everytime a completion UI is displayed
     // So we need to be super fast.
     // We need the 'dev' version of Monaco, as we use monkey-patching to hook into this suggestion adapter
@@ -273,7 +319,9 @@ class MonacoCreator {
                     label = `(${converter(color.red)}, ${converter(color.green)}, ${converter(color.blue)}, ${converter(color.alpha)})`;
                 }
 
-                return [{ label: label }];
+                return [{
+                    label: label
+                }];
             },
 
             provideDocumentColors: (model) => {
@@ -378,10 +426,16 @@ class MonacoCreator {
         const main = this.parent.main;
         const monacoCreator = this;
 
-        this.diffEditor.addCommand(monaco.KeyCode.Escape, function () { main.toggleDiffEditor(monacoCreator, menuPG); });
+        this.diffEditor.addCommand(monaco.KeyCode.Escape, function () {
+            main.toggleDiffEditor(monacoCreator, menuPG);
+        });
         // Adding default VSCode bindinds for previous/next difference
-        this.diffEditor.addCommand(monaco.KeyMod.Alt | monaco.KeyCode.F5, function () { main.navigateToNext(); });
-        this.diffEditor.addCommand(monaco.KeyMod.Shift | monaco.KeyMod.Alt | monaco.KeyCode.F5, function () { main.navigateToPrevious(); });
+        this.diffEditor.addCommand(monaco.KeyMod.Alt | monaco.KeyCode.F5, function () {
+            main.navigateToNext();
+        });
+        this.diffEditor.addCommand(monaco.KeyMod.Shift | monaco.KeyMod.Alt | monaco.KeyCode.F5, function () {
+            main.navigateToPrevious();
+        });
 
         this.diffEditor.focus();
     }
@@ -418,10 +472,18 @@ class MonacoCreator {
     toggleMinimap() {
         var minimapToggle = document.getElementById("minimapToggle1280");
         if (minimapToggle.classList.contains('checked')) {
-            this.jsEditor.updateOptions({ minimap: { enabled: false } });
+            this.jsEditor.updateOptions({
+                minimap: {
+                    enabled: false
+                }
+            });
             this.parent.utils.setToMultipleID("minimapToggle", "innerHTML", 'Minimap <i class="fa fa-square" aria-hidden="true"></i>');
         } else {
-            this.jsEditor.updateOptions({ minimap: { enabled: true } });
+            this.jsEditor.updateOptions({
+                minimap: {
+                    enabled: true
+                }
+            });
             this.parent.utils.setToMultipleID("minimapToggle", "innerHTML", 'Minimap <i class="fa fa-check-square" aria-hidden="true"></i>');
         }
         minimapToggle.classList.toggle('checked');
@@ -465,4 +527,4 @@ class MonacoCreator {
             return output + stub;
         }
     };
-};
+};

+ 6 - 0
Playground/js/settingsPG.js

@@ -93,9 +93,15 @@ class SettingsPG {
         }
         if (this.scriptLanguage == "JS") {
             this.parent.utils.setToMultipleID("toJSbutton", "removeClass", "floatLeft");
+            this.parent.utils.setToMultipleID("toJSbutton", "addClass", "selectedLanguage");
+            this.parent.utils.setToMultipleID("toJSbutton", "innerHTML", "Javascript");
+            this.parent.utils.setToMultipleID("toTSbutton", "title", "Switch to TypeScript");
         }
         else if (this.scriptLanguage == "TS") {
             this.parent.utils.setToMultipleID("toJSbutton", "addClass", "floatLeft");
+            this.parent.utils.setToMultipleID("toTSbutton", "addClass", "selectedLanguage");
+            this.parent.utils.setToMultipleID("toTSbutton", "innerHTML", "Typescript");
+            this.parent.utils.setToMultipleID("toJSbutton", "title", "Switch to JavaScript");
         }
     };
 

+ 24 - 26
Playground/js/utils.js

@@ -4,7 +4,7 @@
 class Utils {
     constructor(parent) {
         this.parent = parent;
-        
+
         this.multipleSize = [1280, 1024, 'Mobile'];
     }
 
@@ -14,7 +14,8 @@ class Utils {
     markDirty() {
         if (this.parent.monacoCreator.BlockEditorChange) return;
 
-        this.setToMultipleID("safemodeToggle", "addClass", "checked");!
+        this.setToMultipleID("safemodeToggle", "addClass", "checked");
+        !
         this.setToMultipleID('safemodeToggle', 'innerHTML', 'Safe mode <i class="fa fa-check-square" aria-hidden="true"></i>');
     };
 
@@ -38,7 +39,7 @@ class Utils {
         }
 
         // Not an error with proper location
-        return null;        
+        return null;
     }
 
     /**
@@ -71,8 +72,8 @@ class Utils {
         const jsEditor = this.parent.monacoCreator.jsEditor;
         if (gotoLocation) {
             gotoLocation.addEventListener('click', function () {
-                const position = { 
-                    lineNumber: Number(locationError.lineNumber), 
+                const position = {
+                    lineNumber: Number(locationError.lineNumber),
                     column: Number(locationError.columnNumber)
                 };
 
@@ -89,24 +90,21 @@ class Utils {
         this.multipleSize.forEach(function (size) {
             if (thingToDo == "innerHTML") {
                 document.getElementById(id + size).innerHTML = param
-            }
-            else if (thingToDo == "click") {
+            } else if (thingToDo == "click") {
                 if (param.length > 1) {
                     for (var i = 0; i < param.length; i++) {
                         document.getElementById(id + size).addEventListener("click", param[i]);
                     }
-                }
-                else
+                } else
                     document.getElementById(id + size).addEventListener("click", param);
-            }
-            else if (thingToDo == "addClass") {
+            } else if (thingToDo == "addClass") {
                 document.getElementById(id + size).classList.add(param);
-            }
-            else if (thingToDo == "removeClass") {
+            } else if (thingToDo == "removeClass") {
                 document.getElementById(id + size).classList.remove(param);
-            }
-            else if (thingToDo == "display") {
+            } else if (thingToDo == "display") {
                 document.getElementById(id + size).style.display = param;
+            } else if (thingToDo === "title") {
+                document.getElementById(id + size).setAttribute("title", param);
             }
         });
     };
@@ -115,8 +113,8 @@ class Utils {
      * Function to get the current screen size
      */
     getCurrentSize() {
-        for(var i = 0; i < this.multipleSize.length; i++) {
-            if(document.getElementById("menuButton" + this.multipleSize[i]).offsetHeight > 0) return this.multipleSize[i];
+        for (var i = 0; i < this.multipleSize.length; i++) {
+            if (document.getElementById("menuButton" + this.multipleSize[i]).offsetHeight > 0) return this.multipleSize[i];
         }
     };
 
@@ -134,9 +132,9 @@ class Utils {
             lastCallAt = currentTime
 
             if (isCold && options.leading) {
-                return options.accumulate
-                    ? Promise.resolve(fn.call(this, [args])).then(result => result[0])
-                    : Promise.resolve(fn.call(this, ...args))
+                return options.accumulate ?
+                    Promise.resolve(fn.call(this, [args])).then(result => result[0]) :
+                    Promise.resolve(fn.call(this, ...args))
             }
 
             if (deferred) {
@@ -159,7 +157,7 @@ class Utils {
         function getWait(wait) {
             return (typeof wait === 'function') ? wait() : wait
         }
-    
+
         function defer() {
             const deferred = {}
             deferred.promise = new Promise((resolve, reject) => {
@@ -174,14 +172,14 @@ class Utils {
             clearTimeout(timer)
 
             Promise.resolve(
-                options.accumulate
-                    ? fn.call(this, pendingArgs)
-                    : fn.apply(this, pendingArgs[pendingArgs.length - 1])
-            )
+                    options.accumulate ?
+                    fn.call(this, pendingArgs) :
+                    fn.apply(this, pendingArgs[pendingArgs.length - 1])
+                )
                 .then(thisDeferred.resolve, thisDeferred.reject)
 
             pendingArgs = []
             deferred = null
         }
-    }    
+    }
 }

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

@@ -62,6 +62,7 @@
 - Refactored the shadow generators code ([Popov72](https://github.com/Popov72))
 - Supports clip planes with shadows ([sebavan](http://www.github.com/sebavan))
 - Added Workbench color scheme for VSCode ([drigax](https://github.com/drigax) & [Patrick Ryan](https://github.com/PatrickRyanMS))
+- Playground switch buttons are more intuitive ([#7601](https://github.com/BabylonJS/Babylon.js/issues/7601)) ([RaananW](https://github.com/RaananW/))
 
 ### Engine
 
@@ -345,6 +346,7 @@
 - VideoTexture poster respects invertY ([Sebavan](https://github.com/sebavan/)
 - Fix for bug where round-tripped glTF imported scenes have incorrect light orientation, and duplicated parent nodes ([#7377](https://github.com/BabylonJS/Babylon.js/issues/7377))([drigax](https://github.com/drigax))
 - Fix bug in PBR sheen where the sheen effect could be a little darker than expected when using direct lighting ([Popov72](https://github.com/Popov72)
+- Fix bug in PBR shader when `reflectionTexture.linearSpecularLOD` is `true`  ([Popov72](https://github.com/Popov72))
 
 ## Breaking changes
 

+ 9 - 7
src/Materials/Textures/renderTargetTexture.ts

@@ -68,9 +68,11 @@ export class RenderTargetTexture extends Texture {
      * Return null to render with the curent renderList, else return the list of meshes to use for rendering.
      * For 2DArray RTT, layerOrFace is the index of the layer that is going to be rendered, else it is the faceIndex of
      * the cube (if the RTT is a cube, else layerOrFace=0).
-     * The renderList passed to the function is the current render list (the one that will be used if the function returns null)
+     * The renderList passed to the function is the current render list (the one that will be used if the function returns null).
+     * The length of this list is passed through renderListLength: don't use renderList.length directly because the array can
+     * hold dummy elements!
     */
-    public getCustomRenderList: (layerOrFace: number, renderList: Nullable<Immutable<Array<AbstractMesh>>>) => Nullable<Array<AbstractMesh>>;
+    public getCustomRenderList: (layerOrFace: number, renderList: Nullable<Immutable<Array<AbstractMesh>>>, renderListLength: number) => Nullable<Array<AbstractMesh>>;
 
     private _hookArray(array: AbstractMesh[]): void {
         var oldPush = array.push;
@@ -729,7 +731,7 @@ export class RenderTargetTexture extends Texture {
         return Math.min(Engine.FloorPOT(renderDimension), curved);
     }
 
-    private _prepareRenderingManager(currentRenderList: Array<AbstractMesh>, camera: Nullable<Camera>, checkLayerMask: boolean): void {
+    private _prepareRenderingManager(currentRenderList: Array<AbstractMesh>, currentRenderListLength: number, camera: Nullable<Camera>, checkLayerMask: boolean): void {
         var scene = this.getScene();
 
         if (!scene) {
@@ -738,7 +740,6 @@ export class RenderTargetTexture extends Texture {
 
         this._renderingManager.reset();
 
-        var currentRenderListLength = currentRenderList.length;
         var sceneRenderId = scene.getRenderId();
         for (var meshIndex = 0; meshIndex < currentRenderListLength; meshIndex++) {
             var mesh = currentRenderList[meshIndex];
@@ -847,22 +848,23 @@ export class RenderTargetTexture extends Texture {
         // Get the list of meshes to render
         let currentRenderList: Nullable<Array<AbstractMesh>> = null;
         let defaultRenderList = this.renderList ? this.renderList : scene.getActiveMeshes().data;
+        let defaultRenderListLength = this.renderList ? this.renderList.length : scene.getActiveMeshes().length;
 
         if (this.getCustomRenderList) {
-            currentRenderList = this.getCustomRenderList(this.is2DArray ? layer : faceIndex, defaultRenderList);
+            currentRenderList = this.getCustomRenderList(this.is2DArray ? layer : faceIndex, defaultRenderList, defaultRenderListLength);
         }
 
         if (!currentRenderList) {
             // No custom render list provided, we prepare the rendering for the default list, but check
             // first if we did not already performed the preparation before so as to avoid re-doing it several times
             if (!this._defaultRenderListPrepared) {
-                this._prepareRenderingManager(defaultRenderList, camera, !this.renderList);
+                this._prepareRenderingManager(defaultRenderList, defaultRenderListLength, camera, !this.renderList);
                 this._defaultRenderListPrepared = true;
             }
             currentRenderList = defaultRenderList;
         } else {
             // Prepare the rendering for the custom render list provided
-            this._prepareRenderingManager(currentRenderList, camera, false);
+            this._prepareRenderingManager(currentRenderList, currentRenderList.length, camera, false);
         }
 
         // Clear

+ 1 - 1
src/Shaders/ShadersInclude/pbrBRDFFunctions.fx

@@ -99,7 +99,7 @@ float fresnelSchlickGGX(float VdotH, float reflectance0, float reflectance90)
 
 #ifdef CLEARCOAT
     // Knowing ior clear coat is fix for the material
-    // Solving iorbase = 1 + sqrt(fo) / (1 - sqrt(fo)) and f0base = square((iorbase - iorclearcoat) / (iorbase - iorclearcoat))
+    // Solving iorbase = 1 + sqrt(fo) / (1 - sqrt(fo)) and f0base = square((iorbase - iorclearcoat) / (iorbase + iorclearcoat))
     // provide f0base = square(A + B * sqrt(fo)) / (B + A * sqrt(fo))
     // where A = 1 - iorclearcoat
     // and   B = 1 + iorclearcoat

+ 1 - 1
src/Shaders/pbr.fragment.fx

@@ -436,7 +436,7 @@ void main(void) {
         #if defined(LODINREFLECTIONALPHA) && !defined(REFLECTIONMAP_SKYBOX)
             float reflectionLOD = getLodFromAlphaG(vReflectionMicrosurfaceInfos.x, alphaG, NdotVUnclamped);
         #elif defined(LINEARSPECULARREFLECTION)
-            float refractionLOD = getLinearLodFromRoughness(vReflectionMicrosurfaceInfos.x, roughness);
+            float reflectionLOD = getLinearLodFromRoughness(vReflectionMicrosurfaceInfos.x, roughness);
         #else
             float reflectionLOD = getLodFromAlphaG(vReflectionMicrosurfaceInfos.x, alphaG);
         #endif

+ 11 - 33
src/XR/webXRSessionManager.ts

@@ -11,18 +11,6 @@ interface IRenderTargetProvider {
     getRenderTargetForEye(eye: XREye): RenderTargetTexture;
 }
 
-class RenderTargetProvider implements IRenderTargetProvider {
-    private _texture: RenderTargetTexture;
-
-    public constructor(texture: RenderTargetTexture) {
-        this._texture = texture;
-    }
-
-    public getRenderTargetForEye(eye: XREye): RenderTargetTexture {
-        return this._texture;
-    }
-}
-
 /**
  * Manages an XRSession to work with Babylon's engine
  * @see https://doc.babylonjs.com/how_to/webxr
@@ -241,12 +229,11 @@ export class WebXRSessionManager implements IDisposable {
         };
 
         if (this._xrNavigator.xr.native) {
-            this._rttProvider = this._xrNavigator.xr.getNativeRenderTargetProvider(this.session, (width: number, height: number) => {
-                return engine.createRenderTargetTexture({ width: width, height: height }, false);
-            });
+            this._rttProvider = this._xrNavigator.xr.getNativeRenderTargetProvider(this.session, this._createRenderTargetTexture.bind(this));
         } else {
-            // Create render target texture from WebXR's webgl render target
-            this._rttProvider = new RenderTargetProvider(WebXRSessionManager._CreateRenderTargetTextureFromSession(this.session, this.scene, this.baseLayer!));
+            // Create render target texture from xr's webgl render target
+            const rtt = this._createRenderTargetTexture(this.baseLayer!.framebufferWidth, this.baseLayer!.framebufferHeight, this.baseLayer!.framebuffer);
+            this._rttProvider = { getRenderTargetForEye: () => rtt };
         }
 
         // Stop window's animation frame and trigger sessions animation frame
@@ -321,25 +308,16 @@ export class WebXRSessionManager implements IDisposable {
         }
     }
 
-    /**
-     * @hidden
-     * Converts the render layer of xrSession to a render target
-     * @param session session to create render target for
-     * @param scene scene the new render target should be created for
-     * @param baseLayer the webgl layer to create the render target for
-     */
-    public static _CreateRenderTargetTextureFromSession(_session: XRSession, scene: Scene, baseLayer: XRWebGLLayer) {
-        if (!baseLayer) {
-            throw "no layer";
-        }
+    private _createRenderTargetTexture(width: number, height: number, framebuffer: Nullable<WebGLFramebuffer> = null) {
         // Create internal texture
-        var internalTexture = new InternalTexture(scene.getEngine(), InternalTextureSource.Unknown, true);
-        internalTexture.width = baseLayer.framebufferWidth;
-        internalTexture.height = baseLayer.framebufferHeight;
-        internalTexture._framebuffer = baseLayer.framebuffer;
+        var internalTexture = new InternalTexture(this.scene.getEngine(), InternalTextureSource.Unknown, true);
+        internalTexture.width = width;
+        internalTexture.height = height;
+        internalTexture._framebuffer = framebuffer;
 
         // Create render target texture from the internal texture
-        var renderTargetTexture = new RenderTargetTexture("XR renderTargetTexture", { width: internalTexture.width, height: internalTexture.height }, scene, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, true);
+        var renderTargetTexture = new RenderTargetTexture("XR renderTargetTexture", { width: width, height: height }, this.scene,
+            undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, true);
         renderTargetTexture._texture = internalTexture;
 
         return renderTargetTexture;