summaryrefslogtreecommitdiff
path: root/platform/javascript
diff options
context:
space:
mode:
authorRĂ©mi Verschelde <rverschelde@gmail.com>2017-01-15 00:30:52 +0100
committerGitHub <noreply@github.com>2017-01-15 00:30:52 +0100
commit07f65184f3886fc836f6d7f8de5052c64bda50bf (patch)
treec22cfb4b2c1d8c086a934fadd660e81e2917a880 /platform/javascript
parentfe8459ac3badc0d2b2b36bf29670d2639825d644 (diff)
parent1f7d4c4d0ee8eba0a1d8084019269a45dfa76be4 (diff)
Merge pull request #7519 from eska014/web-presentation
Improve Web export presentation
Diffstat (limited to 'platform/javascript')
-rw-r--r--platform/javascript/SCsub1
-rw-r--r--platform/javascript/detect.py1
-rw-r--r--platform/javascript/export/export.cpp2
-rw-r--r--platform/javascript/godot_shell.html381
-rw-r--r--platform/javascript/javascript_main.cpp42
-rw-r--r--platform/javascript/os_javascript.cpp12
6 files changed, 250 insertions, 189 deletions
diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub
index 5d5cd1590a..a20c0f7a70 100644
--- a/platform/javascript/SCsub
+++ b/platform/javascript/SCsub
@@ -22,6 +22,7 @@ env.Append(LINKFLAGS=["-s", "EXPORTED_FUNCTIONS=\"['_main','_audio_server_mix_fu
env.Append(LINKFLAGS=["--shell-file", '"platform/javascript/godot_shell.html"'])
build = env.Program('#bin/godot', javascript_objects, PROGSUFFIX=env["PROGSUFFIX"] + ".html")
+Depends(build, "godot_shell.html")
def make_html_shell(target, source, env):
html_path = target[0].rstr()
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index 2cb6874000..55b05a9123 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -81,7 +81,6 @@ def configure(env):
env.Append(CPPFLAGS=['-DJAVASCRIPT_ENABLED', '-DUNIX_ENABLED', '-DPTHREAD_NO_RENAME', '-DNO_FCNTL', '-DMPC_FIXED_POINT', '-DTYPED_METHOD_BIND', '-DNO_THREADS'])
env.Append(CPPFLAGS=['-DGLES2_ENABLED'])
env.Append(CPPFLAGS=['-DGLES_NO_CLIENT_ARRAYS'])
- env.Append(CPPFLAGS=['-s', 'FULL_ES2=1'])
# env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED','-DMPC_FIXED_POINT'])
if env['wasm'] == 'yes':
diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp
index 33776bc273..e0ff9932cc 100644
--- a/platform/javascript/export/export.cpp
+++ b/platform/javascript/export/export.cpp
@@ -377,7 +377,7 @@ EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() {
logo->create_from_image(img);
max_memory=3;
html_title="";
- html_font_family="arial,sans-serif";
+ html_font_family="'Droid Sans',arial,sans-serif";
html_controls_enabled=true;
pack_mode=PACK_SINGLE_FILE;
}
diff --git a/platform/javascript/godot_shell.html b/platform/javascript/godot_shell.html
index 3170d2bb9e..a8b9594935 100644
--- a/platform/javascript/godot_shell.html
+++ b/platform/javascript/godot_shell.html
@@ -3,14 +3,14 @@
<head>
<meta charset="utf-8" />
<title>$GODOT_HEAD_TITLE</title>
- $GODOT_HEAD_INCLUDE
+$GODOT_HEAD_INCLUDE
<style type="text/css">
body {
margin: 0;
border: 0 none;
padding: 0;
text-align: center;
- background-color: black;
+ background-color: #222226;
font-family: $GODOT_STYLE_FONT_FAMILY;
}
@@ -71,7 +71,7 @@
margin: 0;
border: 0 none;
padding: 0;
- background-color: #111;
+ background-color: #0c0c0c;
}
#canvas {
@@ -81,6 +81,7 @@
* calculate cursor coordinates correctly */
border: 0 none;
padding: 0;
+ color: white;
}
@@ -101,6 +102,8 @@
}
#status {
+ line-height: 1.3;
+ cursor: pointer;
visibility: visible;
padding: 4px 6px;
}
@@ -123,7 +126,7 @@
-ms-user-select: none;
}
- #container:hover > #controls {
+ :hover > #controls {
opacity: 1.0;
transition: opacity 60ms ease-in-out;
}
@@ -135,223 +138,289 @@
margin-right: 2px;
}
+ #controls > label > input {
+ vertical-align: middle;
+ }
+
#controls > label > input[type="checkbox"] {
/* override user agent style */
margin-left: 0;
}
- label > input {
- vertical-align: middle;
- }
-
- #display-output { display: none; }
+ #output-toggle { display: none; }
/* Debug output
* ============ */
- #output {
+ #output-panel {
display: none;
- margin: 6px auto;
- border: 2px groove grey;
- padding: 4px;
- outline: none;
+ max-width: $GODOT_CANVAS_WIDTHpx;
+ font-size: small;
+ margin: 6px auto 0;
+ padding: 0 4px 4px;
text-align: left;
+ line-height: 2.2;
+ }
+
+ #output-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+
+ #output-container {
+ padding: 6px;
+ background-color: #2c2a32;
+ box-shadow: inset 0 0 1px 1px #232127;
+ color: #bbb;
+ }
+
+ #output-scroll {
+ line-height: 1;
+ height: 12em;
+ overflow-y: scroll;
white-space: pre-wrap;
font-size: small;
- color: #eee;
- background-color: black;
font-family: "Lucida Console", Monaco, monospace;
}
- /* Export style include
- * ==================== */
+/* Export style include
+ * ==================== */
+
+$GODOT_STYLE_INCLUDE
- $GODOT_STYLE_INCLUDE
</style>
</head>
<body>
<div id="container">
<canvas id="canvas" width="$GODOT_CANVAS_WIDTH" height="$GODOT_CANVAS_HEIGHT" onclick="canvas.ownerDocument.defaultView.focus();" oncontextmenu="event.preventDefault();">
- HTML5 canvas appears to be unsupported in the current browser.<br />Please try updating or use a different browser.
+ HTML5 canvas appears to be unsupported in the current browser.<br />
+ Please try updating or use a different browser.
</canvas>
<div id="status-container">
- <span id="status" class="godot" onclick="this.style.visibility='hidden';">Loading page...</span>
+ <span id="status" class="godot" onclick="this.style.visibility='hidden';">Downloading page...</span>
</div>
<div id="controls" class="godot">
- <label id="display-output"><input id="output-toggle" type="checkbox" autocomplete="off" onchange="Presentation.setOutputVisible(this.checked);" />display output</label>
+ <label id="output-toggle"><input type="checkbox" checked="checked" autocomplete="off" onchange="Presentation.setOutputVisible(this.checked);" />Display Output</label>
<!-- hidden until implemented
- <label><input id="lock-cursor" type="checkbox" autocomplete="off" />lock cursor</label>
- <label><input id="resize-canvas" type="checkbox" autocomplete="off" />resize canvas</label>
+ <label><input class="postRun-enable" type="checkbox" disabled="disabled" autocomplete="off" />lock cursor</label>
+ <label><input class="postRun-enable" type="checkbox" disabled="disabled" autocomplete="off" onchange="Presentation.setCanvasMaximized(this.checked);" />maximize</label>
-->
- <button id="fullscreen" class="godot" type="button" disabled="disabled" autocomplete="off" onclick="Presentation.goFullscreen();">fullscreen</button>
+ <button id="fullscreen" class="godot postRun-enable" type="button" disabled="disabled" autocomplete="off" onclick="Presentation.requestFullscreen();">Fullscreen</button>
</div>
</div>
- <!-- Firefox adds extra space to textarea, but shouldn't matter too much https://bugzilla.mozilla.org/show_bug.cgi?id=33654 -->
- <textarea id="output" rows="10" cols="100" readonly="readonly" style="resize:none"></textarea>
+ <div id="output-panel" class="godot">
+ <div id="output-header">
+ Output:
+ <button class="godot" type="button" autocomplete="off" onclick="Presentation.clearOutput();">Clear</button>
+ </div>
+ <div id="output-container"><div id="output-scroll"></div></div>
+ </div>
+ <!-- Scripts -->
<script type="text/javascript">//<![CDATA[
var Presentation = (function() {
var statusElement = document.getElementById("status");
- var outputElement = document.getElementById("output");
- var doneLoading = false;
-
- function onLoaded() {
- doneLoading = true;
- var fullscreenButtonElement = document.getElementById("fullscreen");
- fullscreenButtonElement.disabled = false;
- }
+ var canvasElement = document.getElementById("canvas");
var presentation = {
- statusElement: statusElement,
- outputElement: outputElement,
- setOutputVisible: function setOutputVisible(visible) {
- outputElement.style.display = (visible?"block":"none");
+ postRun: [
+ function() {
+ var elements = document.getElementsByClassName("postRun-enable");
+ Array.prototype.slice.call(elements).forEach(function(element) {
+ element.disabled = false;
+ });
+ }
+ ],
+ requestFullscreen: function requestFullscreen() {
+ if (typeof Module !== "undefined" && Module.requestFullscreen) {
+ Module.requestFullscreen(false, false);
+ }
+ },
+ /*
+ requestPointerlock: function requestPointerlock() {
+ if (typeof Module !== "undefined" && Module.requestPointerlock) {
+ Module.requestPointerlock(false, false);
+ }
},
+ setCanvasMaximized: function setCanvasMaximized(enabled) {
+ if (typeof Module !== "undefined" && Module.setCanvasMaximized) {
+ Module.setCanvasMaximized(enabled);
+ }
+ },
+ */
setStatusVisible: function setStatusVisible(visible) {
statusElement.style.visibility = (visible?"visible":"hidden");
},
setStatus: function setStatus(text) {
- if (!text || text.length === 0) {
- Presentation.setStatusVisible(false);
- onLoaded();
- } else {
- Presentation.setStatusVisible(true);
- statusElement.innerHTML = text;
+ if (text.length === 0) {
+ // emscripten sets empty string as status after "Running..."
+ // per timeout, but another status may have been set by then
+ if (Presentation.setStatus.lastText === "Running...")
+ Presentation.setStatusVisible(false);
+ return;
}
+ Presentation.setStatus.lastText = text;
+ while (statusElement.lastChild) {
+ statusElement.removeChild(statusElement.lastChild);
+ }
+ var lines = text.split("\n");
+ lines.forEach(function(line, index) {
+ statusElement.appendChild(document.createTextNode(line));
+ statusElement.appendChild(document.createElement("br"));
+ });
+ var closeNote = document.createElement("span");
+ closeNote.style.fontSize = "small";
+ closeNote.textContent = "click to close";
+ statusElement.appendChild(closeNote);
+ Presentation.setStatusVisible(true);
+ },
+ isWebGLAvailable: function isWebGLAvailable() {
+ var context;
+ try {
+ context = canvasElement.getContext("webgl") || canvasElement.getContext("experimental-webgl");
+ } catch (e) {}
+ return !!context;
},
- goFullscreen: function goFullscreen() {
- if (doneLoading) Module.requestFullScreen(false, false);
- }
};
+ window.onerror = function(event) { presentation.setStatus("Failure during start-up\nSee JavaScript console") };
+
if ($GODOT_CONTROLS_ENABLED) { // controls enabled
- (function() {
- var controlsElement = document.getElementById("controls");
- controlsElement.style.visibility="visible";
- })();
+ document.getElementById("controls").style.visibility="visible";
}
if ($GODOT_DEBUG_ENABLED) { // debugging enabled
- (function() {
- var outputToggleLabel = document.getElementById("display-output");
- var outputToggle = document.getElementById("output-toggle");
-
- outputElement.value = ""; // clear browser cache
- outputElement.style.display = "block";
- outputToggle.checked = true;
- outputToggleLabel.style.display = "inline";
-
- presentation.print = function print(text) {
- if (outputElement.value.length !== 0)
- outputElement.value += "\n";
- outputElement.value += text;
- outputElement.scrollTop = outputElement.scrollHeight; // focus on bottom
- };
- })();
+ var outputRoot = document.getElementById("output-panel");
+ var outputElement = document.getElementById("output-scroll");
+ var outputToggle = document.getElementById("output-toggle");
+ const maxOutputMessages = 400;
+
+ presentation.setOutputVisible = function setOutputVisible(visible) {
+ outputRoot.style.display = (visible?"block":"none");
+ };
+ presentation.clearOutput = function clearOutput() {
+ while (outputElement.firstChild) {
+ outputElement.firstChild.remove();
+ }
+ };
+
+ presentation.setOutputVisible(true);
+ outputToggle.style.display = "inline";
+
+ presentation.print = function print(text) {
+ if (arguments.length > 1) {
+ text = Array.prototype.slice.call(arguments).join(" ");
+ }
+ if (text.length <= 0) return;
+ while (outputElement.childElementCount >= maxOutputMessages) {
+ outputElement.firstChild.remove();
+ }
+ var msg = document.createElement("div");
+ if (text.trim().startsWith("**ERROR**")
+ || text.startsWith("**EXCEPTION**")) {
+ msg.style.color = "#d44";
+ } else if (text.trim().startsWith("**WARNING**")) {
+ msg.style.color = "#ccc000";
+ } else if (text.trim().startsWith("**SCRIPT ERROR**")) {
+ msg.style.color = "#c6d";
+ }
+ msg.textContent = text;
+ var scrollToBottom = outputElement.scrollHeight - (outputElement.clientHeight + outputElement.scrollTop) < 10;
+ outputElement.appendChild(msg);
+ if (scrollToBottom) {
+ outputElement.scrollTop = outputElement.scrollHeight;
+ }
+ };
+
+ presentation.postRun.push(function() {
+ window.onerror = function(event) { presentation.print("**EXCEPTION**:", event) };
+ });
+
+ } else {
+ presentation.postRun.push(function() { window.onerror = null; });
}
return presentation;
})();
// Emscripten interface
- var Module = (function() {
- var print = (function() {
- if (typeof Presentation.print === "function") {
- return function print(text) {
- if (arguments.length > 1)
- text = Array.prototype.slice.call(arguments).join(" ");
- console.log(text);
- Presentation.print(text);
- };
- } else {
- return function print(text) {
- if (arguments.length > 1)
- text = Array.prototype.slice.call(arguments).join(" ");
- console.log(text);
- };
+ var Module = {
+ TOTAL_MEMORY: $GODOT_TMEM,
+ postRun: (function() {
+ if (typeof Presentation !== "undefined" && Presentation.postRun instanceof Array) {
+ return Presentation.postRun;
}
- })();
-
- var canvas = (function() {
- var canvasElement = document.getElementById("canvas");
-
+ })(),
+ print: function print(text) {
+ if (arguments.length > 1) {
+ text = Array.prototype.slice.call(arguments).join(" ");
+ }
+ console.log(text);
+ if (typeof Presentation !== "undefined" && typeof Presentation.print === "function") {
+ Presentation.print(text);
+ }
+ },
+ printErr: function printErr(text) {
+ if (arguments.length > 1) {
+ text = Array.prototype.slice.call(arguments).join(" ");
+ }
+ console.error(text);
+ if (typeof Presentation !== "undefined" && typeof Presentation.print === "function") {
+ Presentation.print("**ERROR**:", text)
+ }
+ },
+ canvas: (function() {
+ var canvas = document.getElementById("canvas");
// As a default initial behavior, pop up an alert when WebGL context is lost. To make your
// application robust, you may want to override this behavior before shipping!
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
- canvasElement.addEventListener("webglcontextlost", function(e) { alert("WebGL context lost. Plase reload the page."); e.preventDefault(); }, false);
-
- return canvasElement;
- })();
-
- var setStatus = (function() {
- if (typeof Presentation.setStatus === "function")
- return function setStatus(text) {
- if (!Module.setStatus.last)
- Module.setStatus.last = { time: Date.now(), text: "" };
- if (text === Module.setStatus.text)
- return;
- var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
- var now = Date.now();
- if (m) {
- if (now - Date.now() < 30) // if this is a progress update, skip it if too soon
- return;
- text = m[1];
- }
- Presentation.setStatus(text);
- };
- else
- return function setStatus(text) {
- if (!Module.setStatus.last)
- Module.setStatus.last = { time: Date.now(), text: "" };
- if (text === Module.setStatus.text)
- return;
- var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
- var now = Date.now();
- if (m) {
- if (now - Date.now() < 30) // if this is a progress update, skip it if too soon
- return;
- text = m[1];
- }
- };
- })();
-
- return {
- TOTAL_MEMORY: 268435456,
- preRun: [],
- postRun: [],
- print: print,
- printErr: function printErr(text) {
- if (arguments.length > 1)
- text = Array.prototype.slice.call(arguments).join(" ");
- if (0) { // XXX disabled for safety `if (typeof dump == "function")`
- dump(text + "\n"); // fast, straight to the real console
- } else {
- console.error(text);
- }
- },
- canvas: canvas,
- setStatus: setStatus,
- totalDependencies: 0,
- monitorRunDependencies: function monitorRunDependencies(left) {
- this.totalDependencies = Math.max(this.totalDependencies, left);
- Module.setStatus(left ? "Preparing... (" + (this.totalDependencies-left) + "/" + this.totalDependencies + ")" : "All downloads complete.");
+ canvas.addEventListener("webglcontextlost", function(e) { alert("WebGL context lost. Plase reload the page."); e.preventDefault(); }, false);
+ return canvas;
+
+ })(),
+ setStatus: function setStatus(text) {
+ var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
+ var now = Date.now();
+ if (m) {
+ if (now - Date.now() < 30) // if this is a progress update, skip it if too soon
+ return;
+ text = m[1];
}
- };
- })();
+ if (typeof Presentation !== "undefined" && typeof Presentation.setStatus == "function") {
+ Presentation.setStatus(text);
+ }
+ }
+ };
- Presentation.setStatus("Downloading...");
+ if (!Presentation.isWebGLAvailable()) {
+ Presentation.setStatus("WebGL appears to be unsupported in the current browser.\nPlease try updating or use a different browser.");
+ Presentation.preventLoading = true;
+ } else {
+ Presentation.setStatus("Downloading...");
+ }
- window.onerror = function(event) {
- // TODO: do not warn on ok events like simulating an infinite loop or exitStatus
- Module.setStatus("Exception thrown, see JavaScript console");
- Module.setStatus = function(text) {
- if (text) Module.printErr("[post-exception status] " + text);
- };
- };
+ if (Presentation.preventLoading) {
+ // prevent *fs.js and Emscripten's SCRIPT placeholder from loading any files
+ Presentation._XHR_send = XMLHttpRequest.prototype.send;
+ XMLHttpRequest.prototype.send = function() {};
+ Presentation._Node_appendChild = Node.prototype.appendChild;
+ Node.prototype.appendChild = function(node) {
+ if (!(node instanceof HTMLScriptElement)) {
+ return Presentation._Node_appendChild.call(this, node);
+ }
+ }
+ }
//]]></script>
<script type="text/javascript" src="$GODOT_BASEfs.js"></script>
- {{{ SCRIPT }}}
+{{{ SCRIPT }}}
+ <script type="text/javascript">
+ if (Presentation.preventLoading) {
+ XMLHttpRequest.prototype.send = Presentation._XHR_send;
+ Node.prototype.appendChild = Presentation._Node_appendChild;
+ }
+ </script>
</body>
</html>
diff --git a/platform/javascript/javascript_main.cpp b/platform/javascript/javascript_main.cpp
index 6ec7f1ec3d..dc4d80df7b 100644
--- a/platform/javascript/javascript_main.cpp
+++ b/platform/javascript/javascript_main.cpp
@@ -140,10 +140,9 @@ static void _godot_draw(void) {
extern "C" {
-void main_after_fs_sync(int value) {
+void main_after_fs_sync() {
start_step=1;
- printf("FS SYNCHED!\n");
}
}
@@ -178,26 +177,25 @@ int main(int argc, char *argv[]) {
glutDisplayFunc(_godot_draw);
//glutSpecialFunc(gears_special);
-
-
- //mount persistent filesystem
- EM_ASM(
- FS.mkdir('/userfs');
- FS.mount(IDBFS, {}, '/userfs');
-
-
-
- // sync from persisted state into memory and then
- // run the 'test' function
- FS.syncfs(true, function (err) {
- assert(!err);
- console.log("done syncinc!");
- _after_sync_cb = Module.cwrap('main_after_fs_sync', 'void',['number']);
- _after_sync_cb(0);
-
- });
-
- );
+ //mount persistent file system
+ EM_ASM(
+ FS.mkdir('/userfs');
+ FS.mount(IDBFS, {}, '/userfs');
+
+ // sync from persistent state into memory and then
+ // run the 'main_after_fs_sync' function
+ FS.syncfs(true, function(err) {
+
+ if (err) {
+ Module.setStatus('Failed to load persistent data\nPlease allow (third-party) cookies');
+ Module.printErr('Failed to populate IDB file system: ' + err.message);
+ Module.exit();
+ } else {
+ Module.print('Successfully populated IDB file system');
+ ccall('main_after_fs_sync', 'void', []);
+ }
+ });
+ );
glutMainLoop();
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index 18bf8f6a86..fed9598096 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -502,18 +502,12 @@ bool OS_JavaScript::main_loop_iterate() {
time_to_save_sync-=elapsed;
- print_line("elapsed "+itos(elapsed)+" tts "+itos(time_to_save_sync));
-
if (time_to_save_sync<0) {
//time to sync, for real
- // run 'success'
- print_line("DOING SYNCH!");
EM_ASM(
- FS.syncfs(function (err) {
- assert(!err);
- console.log("Synched!");
- //ccall('success', 'v');
- });
+ FS.syncfs(function(err) {
+ if (err) { Module.printErr('Failed to save IDB file system: ' + err.message); }
+ });
);
}