summaryrefslogtreecommitdiff
path: root/platform/javascript
diff options
context:
space:
mode:
Diffstat (limited to 'platform/javascript')
-rw-r--r--platform/javascript/audio_driver_javascript.cpp6
-rw-r--r--platform/javascript/detect.py5
-rw-r--r--platform/javascript/export/export.cpp55
-rw-r--r--platform/javascript/http_request.js3
-rw-r--r--platform/javascript/id_handler.js5
-rw-r--r--platform/javascript/os_javascript.cpp70
-rw-r--r--platform/javascript/os_javascript.h2
7 files changed, 93 insertions, 53 deletions
diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/javascript/audio_driver_javascript.cpp
index 4144eb3499..f1bc7c4382 100644
--- a/platform/javascript/audio_driver_javascript.cpp
+++ b/platform/javascript/audio_driver_javascript.cpp
@@ -63,7 +63,7 @@ void AudioDriverJavaScript::mix_to_js() {
void AudioDriverJavaScript::process_capture(float sample) {
int32_t sample32 = int32_t(sample * 32768.f) * (1U << 16);
- capture_buffer_write(sample32);
+ input_buffer_write(sample32);
}
Error AudioDriverJavaScript::init() {
@@ -198,7 +198,7 @@ void AudioDriverJavaScript::finish() {
Error AudioDriverJavaScript::capture_start() {
- capture_buffer_init(buffer_length);
+ input_buffer_init(buffer_length);
/* clang-format off */
EM_ASM({
@@ -245,6 +245,8 @@ Error AudioDriverJavaScript::capture_stop() {
});
/* clang-format on */
+ input_buffer.clear();
+
return OK;
}
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index 7bf3e1bc1d..1766833364 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -131,6 +131,11 @@ def configure(env):
env.Append(LINKFLAGS=['-s', 'BINARYEN=1'])
+ # Only include the JavaScript support code for the web environment
+ # (i.e. exclude Node.js and other unused environments).
+ # This makes the JavaScript support code about 4 KB smaller.
+ env.Append(LINKFLAGS=['-s', 'ENVIRONMENT=web'])
+
# This needs to be defined for Emscripten using 'fastcomp' (default pre-1.39.0)
# and undefined if using 'upstream'. And to make things simple, earlier
# Emscripten versions didn't include 'fastcomp' in their path, so we check
diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp
index 9b93d4f140..c1cb8bcb58 100644
--- a/platform/javascript/export/export.cpp
+++ b/platform/javascript/export/export.cpp
@@ -86,7 +86,7 @@ public:
ERR_FAIL_COND_MSG(req[0] != "GET" || req[2] != "HTTP/1.1", "Invalid method or HTTP version.");
String filepath = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_js_export");
- String basereq = "/tmp_js_export";
+ const String basereq = "/tmp_js_export";
String ctype = "";
if (req[1] == basereq + ".html") {
filepath += ".html";
@@ -97,8 +97,13 @@ public:
} else if (req[1] == basereq + ".pck") {
filepath += ".pck";
ctype = "application/octet-stream";
- } else if (req[1] == basereq + ".png") {
- filepath += ".png";
+ } else if (req[1] == basereq + ".png" || req[1] == "/favicon.png") {
+ // Also allow serving the generated favicon for a smoother loading experience.
+ if (req[1] == "/favicon.png") {
+ filepath = EditorSettings::get_singleton()->get_cache_dir().plus_file("favicon.png");
+ } else {
+ filepath += ".png";
+ }
ctype = "image/png";
} else if (req[1] == basereq + ".wasm") {
filepath += ".wasm";
@@ -470,11 +475,10 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
}
Ref<Image> splash;
- String splash_path = GLOBAL_GET("application/boot_splash/image");
- splash_path = splash_path.strip_edges();
+ const String splash_path = String(GLOBAL_GET("application/boot_splash/image")).strip_edges();
if (!splash_path.empty()) {
splash.instance();
- Error err = splash->load(splash_path);
+ const Error err = splash->load(splash_path);
if (err) {
EditorNode::get_singleton()->show_warning(TTR("Could not read boot splash image file:") + "\n" + splash_path + "\n" + TTR("Using default boot splash image."));
splash.unref();
@@ -483,11 +487,32 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
if (splash.is_null()) {
splash = Ref<Image>(memnew(Image(boot_splash_png)));
}
- String png_path = p_path.get_base_dir().plus_file(p_path.get_file().get_basename() + ".png");
- if (splash->save_png(png_path) != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + png_path);
+ const String splash_png_path = p_path.get_base_dir().plus_file(p_path.get_file().get_basename() + ".png");
+ if (splash->save_png(splash_png_path) != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + splash_png_path);
return ERR_FILE_CANT_WRITE;
}
+
+ // Save a favicon that can be accessed without waiting for the project to finish loading.
+ // This way, the favicon can be displayed immediately when loading the page.
+ Ref<Image> favicon;
+ const String favicon_path = String(GLOBAL_GET("application/config/icon")).strip_edges();
+ if (!favicon_path.empty()) {
+ favicon.instance();
+ const Error err = favicon->load(favicon_path);
+ if (err) {
+ favicon.unref();
+ }
+ }
+
+ if (favicon.is_valid()) {
+ const String favicon_png_path = p_path.get_base_dir().plus_file("favicon.png");
+ if (favicon->save_png(favicon_png_path) != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + favicon_png_path);
+ return ERR_FILE_CANT_WRITE;
+ }
+ }
+
return OK;
}
@@ -536,9 +561,8 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese
return OK;
}
- String basepath = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_js_export");
- String path = basepath + ".html";
- Error err = export_project(p_preset, true, path, p_debug_flags);
+ const String basepath = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_js_export");
+ Error err = export_project(p_preset, true, basepath + ".html", p_debug_flags);
if (err != OK) {
// Export generates several files, clean them up on failure.
DirAccess::remove_file_or_error(basepath + ".html");
@@ -546,13 +570,14 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese
DirAccess::remove_file_or_error(basepath + ".pck");
DirAccess::remove_file_or_error(basepath + ".png");
DirAccess::remove_file_or_error(basepath + ".wasm");
+ DirAccess::remove_file_or_error(EditorSettings::get_singleton()->get_cache_dir().plus_file("favicon.png"));
return err;
}
- IP_Address bind_ip;
- uint16_t bind_port = EDITOR_GET("export/web/http_port");
+ const uint16_t bind_port = EDITOR_GET("export/web/http_port");
// Resolve host if needed.
- String bind_host = EDITOR_GET("export/web/http_host");
+ const String bind_host = EDITOR_GET("export/web/http_host");
+ IP_Address bind_ip;
if (bind_host.is_valid_ip_address()) {
bind_ip = bind_host;
} else {
diff --git a/platform/javascript/http_request.js b/platform/javascript/http_request.js
index c112039d0b..f621689f9d 100644
--- a/platform/javascript/http_request.js
+++ b/platform/javascript/http_request.js
@@ -3,9 +3,10 @@
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
-/* http://www.godotengine.org */
+/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/javascript/id_handler.js b/platform/javascript/id_handler.js
index 36ef5aa8ef..3851123ed1 100644
--- a/platform/javascript/id_handler.js
+++ b/platform/javascript/id_handler.js
@@ -3,9 +3,10 @@
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
-/* http://www.godotengine.org */
+/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index 592def8011..34dce90b6b 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -49,6 +49,7 @@
#define DOM_BUTTON_RIGHT 2
#define DOM_BUTTON_XBUTTON1 3
#define DOM_BUTTON_XBUTTON2 4
+#define GODOT_CANVAS_SELECTOR "#canvas"
// Window (canvas)
@@ -70,18 +71,23 @@ static bool is_canvas_focused() {
/* clang-format on */
}
-static Point2 correct_canvas_position(int x, int y) {
+static Point2 compute_position_in_canvas(int x, int y) {
+ int canvas_x = EM_ASM_INT({
+ return document.getElementById('canvas').getBoundingClientRect().x;
+ });
+ int canvas_y = EM_ASM_INT({
+ return document.getElementById('canvas').getBoundingClientRect().y;
+ });
int canvas_width;
int canvas_height;
- emscripten_get_canvas_element_size(NULL, &canvas_width, &canvas_height);
+ emscripten_get_canvas_element_size(GODOT_CANVAS_SELECTOR, &canvas_width, &canvas_height);
double element_width;
double element_height;
- emscripten_get_element_css_size(NULL, &element_width, &element_height);
+ emscripten_get_element_css_size(GODOT_CANVAS_SELECTOR, &element_width, &element_height);
- x = (int)(canvas_width / element_width * x);
- y = (int)(canvas_height / element_height * y);
- return Point2(x, y);
+ return Point2((int)(canvas_width / element_width * (x - canvas_x)),
+ (int)(canvas_height / element_height * (y - canvas_y)));
}
static bool cursor_inside_canvas = true;
@@ -135,14 +141,14 @@ void OS_JavaScript::set_window_size(const Size2 p_size) {
emscripten_exit_soft_fullscreen();
window_maximized = false;
}
- emscripten_set_canvas_element_size(NULL, p_size.x, p_size.y);
+ emscripten_set_canvas_element_size(GODOT_CANVAS_SELECTOR, p_size.x, p_size.y);
}
}
Size2 OS_JavaScript::get_window_size() const {
int canvas[2];
- emscripten_get_canvas_element_size(NULL, canvas, canvas + 1);
+ emscripten_get_canvas_element_size(GODOT_CANVAS_SELECTOR, canvas, canvas + 1);
return Size2(canvas[0], canvas[1]);
}
@@ -162,7 +168,7 @@ void OS_JavaScript::set_window_maximized(bool p_enabled) {
strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF;
strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT;
strategy.canvasResizedCallback = NULL;
- emscripten_enter_soft_fullscreen(NULL, &strategy);
+ emscripten_enter_soft_fullscreen(GODOT_CANVAS_SELECTOR, &strategy);
window_maximized = p_enabled;
}
}
@@ -191,7 +197,7 @@ void OS_JavaScript::set_window_fullscreen(bool p_enabled) {
strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF;
strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT;
strategy.canvasResizedCallback = NULL;
- EMSCRIPTEN_RESULT result = emscripten_request_fullscreen_strategy(NULL, false, &strategy);
+ EMSCRIPTEN_RESULT result = emscripten_request_fullscreen_strategy(GODOT_CANVAS_SELECTOR, false, &strategy);
ERR_FAIL_COND_MSG(result == EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED, "Enabling fullscreen is only possible from an input callback for the HTML5 platform.");
ERR_FAIL_COND_MSG(result != EMSCRIPTEN_RESULT_SUCCESS, "Enabling fullscreen is only possible from an input callback for the HTML5 platform.");
// Not fullscreen yet, so prevent "windowed" canvas dimensions from
@@ -298,7 +304,7 @@ EM_BOOL OS_JavaScript::mouse_button_callback(int p_event_type, const EmscriptenM
Ref<InputEventMouseButton> ev;
ev.instance();
ev->set_pressed(p_event_type == EMSCRIPTEN_EVENT_MOUSEDOWN);
- ev->set_position(correct_canvas_position(p_event->canvasX, p_event->canvasY));
+ ev->set_position(compute_position_in_canvas(p_event->clientX, p_event->clientY));
ev->set_global_position(ev->get_position());
dom2godot_mod(p_event, ev);
@@ -363,7 +369,7 @@ EM_BOOL OS_JavaScript::mousemove_callback(int p_event_type, const EmscriptenMous
OS_JavaScript *os = get_singleton();
int input_mask = os->input->get_mouse_button_mask();
- Point2 pos = correct_canvas_position(p_event->canvasX, p_event->canvasY);
+ Point2 pos = compute_position_in_canvas(p_event->clientX, p_event->clientY);
// For motion outside the canvas, only read mouse movement if dragging
// started inside the canvas; imitating desktop app behaviour.
if (!cursor_inside_canvas && !input_mask)
@@ -697,7 +703,7 @@ EM_BOOL OS_JavaScript::touch_press_callback(int p_event_type, const EmscriptenTo
if (!touch.isChanged)
continue;
ev->set_index(touch.identifier);
- ev->set_position(correct_canvas_position(touch.canvasX, touch.canvasY));
+ ev->set_position(compute_position_in_canvas(touch.clientX, touch.clientY));
os->touches[i] = ev->get_position();
ev->set_pressed(p_event_type == EMSCRIPTEN_EVENT_TOUCHSTART);
@@ -722,7 +728,7 @@ EM_BOOL OS_JavaScript::touchmove_callback(int p_event_type, const EmscriptenTouc
if (!touch.isChanged)
continue;
ev->set_index(touch.identifier);
- ev->set_position(correct_canvas_position(touch.canvasX, touch.canvasY));
+ ev->set_position(compute_position_in_canvas(touch.clientX, touch.clientY));
Point2 &prev = os->touches[i];
ev->set_relative(ev->get_position() - prev);
prev = ev->get_position();
@@ -921,7 +927,7 @@ Error OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver,
}
}
- EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context(NULL, &attributes);
+ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context(GODOT_CANVAS_SELECTOR, &attributes);
if (emscripten_webgl_make_context_current(ctx) != EMSCRIPTEN_RESULT_SUCCESS) {
gl_initialization_error = true;
}
@@ -974,7 +980,7 @@ Error OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver,
EMSCRIPTEN_RESULT result;
#define EM_CHECK(ev) \
if (result != EMSCRIPTEN_RESULT_SUCCESS) \
- ERR_PRINTS("Error while setting " #ev " callback: Code " + itos(result))
+ ERR_PRINT("Error while setting " #ev " callback: Code " + itos(result));
#define SET_EM_CALLBACK(target, ev, cb) \
result = emscripten_set_##ev##_callback(target, NULL, true, &cb); \
EM_CHECK(ev)
@@ -984,21 +990,21 @@ Error OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver,
// These callbacks from Emscripten's html5.h suffice to access most
// JavaScript APIs. For APIs that are not (sufficiently) exposed, EM_ASM
// is used below.
- SET_EM_CALLBACK("#window", mousemove, mousemove_callback)
- SET_EM_CALLBACK("#canvas", mousedown, mouse_button_callback)
- SET_EM_CALLBACK("#window", mouseup, mouse_button_callback)
- SET_EM_CALLBACK("#window", wheel, wheel_callback)
- SET_EM_CALLBACK("#window", touchstart, touch_press_callback)
- SET_EM_CALLBACK("#window", touchmove, touchmove_callback)
- SET_EM_CALLBACK("#window", touchend, touch_press_callback)
- SET_EM_CALLBACK("#window", touchcancel, touch_press_callback)
- SET_EM_CALLBACK("#canvas", keydown, keydown_callback)
- SET_EM_CALLBACK("#canvas", keypress, keypress_callback)
- SET_EM_CALLBACK("#canvas", keyup, keyup_callback)
- SET_EM_CALLBACK(NULL, fullscreenchange, fullscreen_change_callback)
+ SET_EM_CALLBACK(EMSCRIPTEN_EVENT_TARGET_WINDOW, mousemove, mousemove_callback)
+ SET_EM_CALLBACK(GODOT_CANVAS_SELECTOR, mousedown, mouse_button_callback)
+ SET_EM_CALLBACK(EMSCRIPTEN_EVENT_TARGET_WINDOW, mouseup, mouse_button_callback)
+ SET_EM_CALLBACK(EMSCRIPTEN_EVENT_TARGET_WINDOW, wheel, wheel_callback)
+ SET_EM_CALLBACK(EMSCRIPTEN_EVENT_TARGET_WINDOW, touchstart, touch_press_callback)
+ SET_EM_CALLBACK(EMSCRIPTEN_EVENT_TARGET_WINDOW, touchmove, touchmove_callback)
+ SET_EM_CALLBACK(EMSCRIPTEN_EVENT_TARGET_WINDOW, touchend, touch_press_callback)
+ SET_EM_CALLBACK(EMSCRIPTEN_EVENT_TARGET_WINDOW, touchcancel, touch_press_callback)
+ SET_EM_CALLBACK(GODOT_CANVAS_SELECTOR, keydown, keydown_callback)
+ SET_EM_CALLBACK(GODOT_CANVAS_SELECTOR, keypress, keypress_callback)
+ SET_EM_CALLBACK(GODOT_CANVAS_SELECTOR, keyup, keyup_callback)
+ SET_EM_CALLBACK(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, fullscreenchange, fullscreen_change_callback)
SET_EM_CALLBACK_NOTARGET(gamepadconnected, gamepad_change_callback)
SET_EM_CALLBACK_NOTARGET(gamepaddisconnected, gamepad_change_callback)
-#undef SET_EM_CALLBACK_NODATA
+#undef SET_EM_CALLBACK_NOTARGET
#undef SET_EM_CALLBACK
#undef EM_CHECK
@@ -1079,15 +1085,15 @@ bool OS_JavaScript::main_loop_iterate() {
strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF;
strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT;
strategy.canvasResizedCallback = NULL;
- emscripten_enter_soft_fullscreen(NULL, &strategy);
+ emscripten_enter_soft_fullscreen(GODOT_CANVAS_SELECTOR, &strategy);
} else {
- emscripten_set_canvas_element_size(NULL, windowed_size.width, windowed_size.height);
+ emscripten_set_canvas_element_size(GODOT_CANVAS_SELECTOR, windowed_size.width, windowed_size.height);
}
just_exited_fullscreen = false;
}
int canvas[2];
- emscripten_get_canvas_element_size(NULL, canvas, canvas + 1);
+ emscripten_get_canvas_element_size(GODOT_CANVAS_SELECTOR, canvas, canvas + 1);
video_mode.width = canvas[0];
video_mode.height = canvas[1];
if (!window_maximized && !video_mode.fullscreen && !just_exited_fullscreen && !entering_fullscreen) {
diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h
index 2d1c765e76..5c02a292ee 100644
--- a/platform/javascript/os_javascript.h
+++ b/platform/javascript/os_javascript.h
@@ -141,7 +141,7 @@ public:
void run_async();
bool main_loop_iterate();
- virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL);
+ virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL);
virtual Error kill(const ProcessID &p_pid);
virtual int get_process_id() const;