summaryrefslogtreecommitdiffstats
path: root/platform/javascript
diff options
context:
space:
mode:
Diffstat (limited to 'platform/javascript')
-rw-r--r--platform/javascript/SCsub6
-rw-r--r--platform/javascript/audio_driver_javascript.h2
-rw-r--r--platform/javascript/detect.py15
-rw-r--r--platform/javascript/display_server_javascript.cpp20
-rw-r--r--platform/javascript/display_server_javascript.h4
-rw-r--r--platform/javascript/emscripten_helpers.py6
-rw-r--r--platform/javascript/export/export.cpp1
-rw-r--r--platform/javascript/export/export.h2
-rw-r--r--platform/javascript/export/export_plugin.cpp85
-rw-r--r--platform/javascript/export/export_plugin.h26
-rw-r--r--platform/javascript/export/export_server.h3
-rw-r--r--platform/javascript/godot_audio.h2
-rw-r--r--platform/javascript/godot_js.h5
-rw-r--r--platform/javascript/godot_webgl2.h2
-rw-r--r--platform/javascript/http_client_javascript.h1
-rw-r--r--platform/javascript/javascript_singleton.cpp2
-rw-r--r--platform/javascript/js/engine/config.js1
-rw-r--r--platform/javascript/js/libs/library_godot_display.js75
-rw-r--r--platform/javascript/js/libs/library_godot_input.js9
-rw-r--r--platform/javascript/os_javascript.cpp4
-rw-r--r--platform/javascript/os_javascript.h5
21 files changed, 171 insertions, 105 deletions
diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub
index 8d9ba82fd4..4827dc4627 100644
--- a/platform/javascript/SCsub
+++ b/platform/javascript/SCsub
@@ -37,6 +37,8 @@ for ext in env["JS_EXTERNS"]:
build = []
if env["gdnative_enabled"]:
build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"]
+ if env["threads_enabled"]:
+ build_targets.append("#bin/godot${PROGSUFFIX}.worker.js")
# Reset libraries. The main runtime will only link emscripten libraries, not godot ones.
sys_env["LIBS"] = []
# We use IDBFS. Since Emscripten 1.39.1 it needs to be linked explicitly.
@@ -58,7 +60,7 @@ if env["gdnative_enabled"]:
wasm_env.Append(CCFLAGS=["-s", "SIDE_MODULE=2"])
wasm_env.Append(LINKFLAGS=["-s", "SIDE_MODULE=2"])
wasm = wasm_env.add_program("#bin/godot.side${PROGSUFFIX}.wasm", javascript_files)
- build = [sys[0], sys[1], wasm[0]]
+ build = sys + [wasm[0]]
else:
build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"]
if env["threads_enabled"]:
@@ -87,5 +89,5 @@ wrap_list = [
js_wrapped = env.Textfile("#bin/godot", [env.File(f) for f in wrap_list], TEXTFILESUFFIX="${PROGSUFFIX}.wrapped.js")
# Extra will be the thread worker, or the GDNative side, or None
-extra = build[2] if len(build) > 2 else None
+extra = build[2:] if len(build) > 2 else None
env.CreateTemplateZip(js_wrapped, build[1], extra)
diff --git a/platform/javascript/audio_driver_javascript.h b/platform/javascript/audio_driver_javascript.h
index b7b0b3ac96..807e2f936b 100644
--- a/platform/javascript/audio_driver_javascript.h
+++ b/platform/javascript/audio_driver_javascript.h
@@ -158,4 +158,4 @@ public:
};
#endif
-#endif
+#endif // AUDIO_DRIVER_JAVASCRIPT_H
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index 4a9652fc1c..a769260f01 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -185,10 +185,6 @@ def configure(env):
if env["javascript_eval"]:
env.Append(CPPDEFINES=["JAVASCRIPT_EVAL_ENABLED"])
- if env["threads_enabled"] and env["gdnative_enabled"]:
- print("Threads and GDNative support can't be both enabled due to WebAssembly limitations")
- sys.exit(255)
-
# Thread support (via SharedArrayBuffer).
if env["threads_enabled"]:
env.Append(CPPDEFINES=["PTHREAD_NO_RENAME"])
@@ -201,9 +197,14 @@ def configure(env):
env.Append(CPPDEFINES=["NO_THREADS"])
if env["gdnative_enabled"]:
- major, minor, patch = get_compiler_version(env)
- if major < 2 or (major == 2 and minor == 0 and patch < 10):
- print("GDNative support requires emscripten >= 2.0.10, detected: %s.%s.%s" % (major, minor, patch))
+ cc_version = get_compiler_version(env)
+ cc_semver = (int(cc_version["major"]), int(cc_version["minor"]), int(cc_version["patch"]))
+ if cc_semver < (2, 0, 10):
+ print("GDNative support requires emscripten >= 2.0.10, detected: %s.%s.%s" % cc_semver)
+ sys.exit(255)
+
+ if env["threads_enabled"] and cc_semver < (3, 1, 14):
+ print("Threads and GDNative requires emscripten >= 3.1.14, detected: %s.%s.%s" % cc_semver)
sys.exit(255)
env.Append(CCFLAGS=["-s", "RELOCATABLE=1"])
env.Append(LINKFLAGS=["-s", "RELOCATABLE=1"])
diff --git a/platform/javascript/display_server_javascript.cpp b/platform/javascript/display_server_javascript.cpp
index a96c539a1f..30240ad2db 100644
--- a/platform/javascript/display_server_javascript.cpp
+++ b/platform/javascript/display_server_javascript.cpp
@@ -83,7 +83,7 @@ void DisplayServerJavaScript::drop_files_js_callback(char **p_filev, int p_filec
Variant *vp = &v;
Variant ret;
Callable::CallError ce;
- ds->drop_files_callback.call((const Variant **)&vp, 1, ret, ce);
+ ds->drop_files_callback.callp((const Variant **)&vp, 1, ret, ce);
}
// JavaScript quit request callback.
@@ -94,7 +94,7 @@ void DisplayServerJavaScript::request_quit_callback() {
Variant *eventp = &event;
Variant ret;
Callable::CallError ce;
- ds->window_event_callback.call((const Variant **)&eventp, 1, ret, ce);
+ ds->window_event_callback.callp((const Variant **)&eventp, 1, ret, ce);
}
}
@@ -236,7 +236,7 @@ void DisplayServerJavaScript::mouse_move_callback(double p_x, double p_y, double
const char *DisplayServerJavaScript::godot2dom_cursor(DisplayServer::CursorShape p_shape) {
switch (p_shape) {
case DisplayServer::CURSOR_ARROW:
- return "auto";
+ return "default";
case DisplayServer::CURSOR_IBEAM:
return "text";
case DisplayServer::CURSOR_POINTING_HAND:
@@ -270,7 +270,7 @@ const char *DisplayServerJavaScript::godot2dom_cursor(DisplayServer::CursorShape
case DisplayServer::CURSOR_HELP:
return "help";
default:
- return "auto";
+ return "default";
}
}
@@ -296,7 +296,7 @@ void DisplayServerJavaScript::update_voices_callback(int p_size, const char **p_
}
}
-Array DisplayServerJavaScript::tts_get_voices() const {
+TypedArray<Dictionary> DisplayServerJavaScript::tts_get_voices() const {
godot_js_tts_get_voices(update_voices_callback);
return voices;
}
@@ -586,7 +586,7 @@ void DisplayServerJavaScript::vk_input_text_callback(const char *p_text, int p_c
Variant *eventp = &event;
Variant ret;
Callable::CallError ce;
- ds->input_text_callback.call((const Variant **)&eventp, 1, ret, ce);
+ ds->input_text_callback.callp((const Variant **)&eventp, 1, ret, ce);
// Insert key right to reach position.
Input *input = Input::get_singleton();
Ref<InputEventKey> k;
@@ -604,8 +604,8 @@ void DisplayServerJavaScript::vk_input_text_callback(const char *p_text, int p_c
}
}
-void DisplayServerJavaScript::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
- godot_js_display_vk_show(p_existing_text.utf8().get_data(), p_multiline, p_cursor_start, p_cursor_end);
+void DisplayServerJavaScript::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, VirtualKeyboardType p_type, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
+ godot_js_display_vk_show(p_existing_text.utf8().get_data(), p_type, p_cursor_start, p_cursor_end);
}
void DisplayServerJavaScript::virtual_keyboard_hide() {
@@ -691,7 +691,7 @@ void DisplayServerJavaScript::send_window_event_callback(int p_notification) {
Variant *eventp = &event;
Variant ret;
Callable::CallError ce;
- ds->window_event_callback.call((const Variant **)&eventp, 1, ret, ce);
+ ds->window_event_callback.callp((const Variant **)&eventp, 1, ret, ce);
}
}
@@ -734,7 +734,7 @@ void DisplayServerJavaScript::_dispatch_input_event(const Ref<InputEvent> &p_eve
Variant *evp = &ev;
Variant ret;
Callable::CallError ce;
- cb.call((const Variant **)&evp, 1, ret, ce);
+ cb.callp((const Variant **)&evp, 1, ret, ce);
}
}
diff --git a/platform/javascript/display_server_javascript.h b/platform/javascript/display_server_javascript.h
index 79b0fbb652..cbb91477b7 100644
--- a/platform/javascript/display_server_javascript.h
+++ b/platform/javascript/display_server_javascript.h
@@ -124,7 +124,7 @@ public:
// tts
virtual bool tts_is_speaking() const override;
virtual bool tts_is_paused() const override;
- virtual Array tts_get_voices() const override;
+ virtual TypedArray<Dictionary> tts_get_voices() const override;
virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override;
virtual void tts_pause() override;
@@ -157,7 +157,7 @@ public:
virtual float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
- virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1) override;
+ virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), VirtualKeyboardType p_type = KEYBOARD_TYPE_DEFAULT, int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1) override;
virtual void virtual_keyboard_hide() override;
// windows
diff --git a/platform/javascript/emscripten_helpers.py b/platform/javascript/emscripten_helpers.py
index 4dad2d5204..3cb1d75e52 100644
--- a/platform/javascript/emscripten_helpers.py
+++ b/platform/javascript/emscripten_helpers.py
@@ -52,10 +52,10 @@ def create_template_zip(env, js, wasm, extra):
]
# GDNative/Threads specific
if env["gdnative_enabled"]:
- in_files.append(extra) # Runtime
+ in_files.append(extra.pop()) # Runtime
out_files.append(zip_dir.File(binary_name + ".side.wasm"))
- elif env["threads_enabled"]:
- in_files.append(extra) # Worker
+ if env["threads_enabled"]:
+ in_files.append(extra.pop()) # Worker
out_files.append(zip_dir.File(binary_name + ".worker.js"))
service_worker = "#misc/dist/html/service-worker.js"
diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp
index 825c1b6638..ea236f62f7 100644
--- a/platform/javascript/export/export.cpp
+++ b/platform/javascript/export/export.cpp
@@ -30,6 +30,7 @@
#include "export.h"
+#include "editor/editor_settings.h"
#include "export_plugin.h"
void register_javascript_exporter() {
diff --git a/platform/javascript/export/export.h b/platform/javascript/export/export.h
index 41cc66cfb8..29c335ed0e 100644
--- a/platform/javascript/export/export.h
+++ b/platform/javascript/export/export.h
@@ -33,4 +33,4 @@
void register_javascript_exporter();
-#endif
+#endif // JAVASCRIPT_EXPORT_H
diff --git a/platform/javascript/export/export_plugin.cpp b/platform/javascript/export/export_plugin.cpp
index 3334e7394b..0bdee11018 100644
--- a/platform/javascript/export/export_plugin.cpp
+++ b/platform/javascript/export/export_plugin.cpp
@@ -31,6 +31,7 @@
#include "export_plugin.h"
#include "core/config/project_settings.h"
+#include "editor/editor_settings.h"
Error EditorExportPlatformJavaScript::_extract_template(const String &p_template, const String &p_dir, const String &p_name, bool pwa) {
Ref<FileAccess> io_fa;
@@ -38,12 +39,12 @@ Error EditorExportPlatformJavaScript::_extract_template(const String &p_template
unzFile pkg = unzOpen2(p_template.utf8().get_data(), &io);
if (!pkg) {
- EditorNode::get_singleton()->show_warning(TTR("Could not open template for export:") + "\n" + p_template);
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), vformat(TTR("Could not open template for export: \"%s\"."), p_template));
return ERR_FILE_NOT_FOUND;
}
if (unzGoToFirstFile(pkg) != UNZ_OK) {
- EditorNode::get_singleton()->show_warning(TTR("Invalid export template:") + "\n" + p_template);
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), vformat(TTR("Invalid export template: \"%s\"."), p_template));
unzClose(pkg);
return ERR_FILE_CORRUPT;
}
@@ -56,6 +57,11 @@ Error EditorExportPlatformJavaScript::_extract_template(const String &p_template
String file = String::utf8(fname);
+ // Skip folders.
+ if (file.ends_with("/")) {
+ continue;
+ }
+
// Skip service worker and offline page if not exporting pwa.
if (!pwa && (file == "godot.service.worker.js" || file == "godot.offline.html")) {
continue;
@@ -72,7 +78,7 @@ Error EditorExportPlatformJavaScript::_extract_template(const String &p_template
String dst = p_dir.plus_file(file.replace("godot", p_name));
Ref<FileAccess> f = FileAccess::open(dst, FileAccess::WRITE);
if (f.is_null()) {
- EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + dst);
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), vformat(TTR("Could not write file: \"%s\"."), dst));
unzClose(pkg);
return ERR_FILE_CANT_WRITE;
}
@@ -86,7 +92,7 @@ Error EditorExportPlatformJavaScript::_extract_template(const String &p_template
Error EditorExportPlatformJavaScript::_write_or_error(const uint8_t *p_content, int p_size, String p_path) {
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);
if (f.is_null()) {
- EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + p_path);
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not write file: \"%s\"."), p_path));
return ERR_FILE_CANT_WRITE;
}
f->store_buffer(p_content, p_size);
@@ -163,7 +169,7 @@ Error EditorExportPlatformJavaScript::_add_manifest_icon(const String &p_path, c
icon.instantiate();
const Error err = ImageLoader::load_image(p_icon, icon);
if (err != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Could not read file:") + "\n" + p_icon);
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Icon Creation"), vformat(TTR("Could not read file: \"%s\"."), p_icon));
return err;
}
if (icon->get_width() != p_size || icon->get_height() != p_size) {
@@ -175,7 +181,7 @@ Error EditorExportPlatformJavaScript::_add_manifest_icon(const String &p_path, c
}
const Error err = icon->save_png(icon_dest);
if (err != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + icon_dest);
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Icon Creation"), vformat(TTR("Could not write file: \"%s\"."), icon_dest));
return err;
}
Dictionary icon_dict;
@@ -210,7 +216,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &
cache_files.push_back(name + ".icon.png");
cache_files.push_back(name + ".apple-touch-icon.png");
}
- if (mode == EXPORT_MODE_THREADS) {
+ if (mode & EXPORT_MODE_THREADS) {
cache_files.push_back(name + ".worker.js");
cache_files.push_back(name + ".audio.worklet.js");
}
@@ -220,7 +226,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &
Array opt_cache_files;
opt_cache_files.push_back(name + ".wasm");
opt_cache_files.push_back(name + ".pck");
- if (mode == EXPORT_MODE_GDNATIVE) {
+ if (mode & EXPORT_MODE_GDNATIVE) {
opt_cache_files.push_back(name + ".side.wasm");
for (int i = 0; i < p_shared_objects.size(); i++) {
opt_cache_files.push_back(p_shared_objects[i].path.get_file());
@@ -233,7 +239,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &
{
Ref<FileAccess> f = FileAccess::open(sw_path, FileAccess::READ);
if (f.is_null()) {
- EditorNode::get_singleton()->show_warning(TTR("Could not read file:") + "\n" + sw_path);
+ add_message(EXPORT_MESSAGE_ERROR, TTR("PWA"), vformat(TTR("Could not read file: \"%s\"."), sw_path));
return ERR_FILE_CANT_READ;
}
sw.resize(f->get_length());
@@ -252,7 +258,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &
const String offline_dest = dir.plus_file(name + ".offline.html");
err = da->copy(ProjectSettings::get_singleton()->globalize_path(offline_page), offline_dest);
if (err != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Could not read file:") + "\n" + offline_dest);
+ add_message(EXPORT_MESSAGE_ERROR, TTR("PWA"), vformat(TTR("Could not read file: \"%s\"."), offline_dest));
return err;
}
}
@@ -297,7 +303,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &
return OK;
}
-void EditorExportPlatformJavaScript::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
+void EditorExportPlatformJavaScript::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const {
if (p_preset->get("vram_texture_compression/for_desktop")) {
r_features->push_back("s3tc");
}
@@ -312,9 +318,10 @@ void EditorExportPlatformJavaScript::get_preset_features(const Ref<EditorExportP
}
}
ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
- if (mode == EXPORT_MODE_THREADS) {
+ if (mode & EXPORT_MODE_THREADS) {
r_features->push_back("threads");
- } else if (mode == EXPORT_MODE_GDNATIVE) {
+ }
+ if (mode & EXPORT_MODE_GDNATIVE) {
r_features->push_back("wasm32");
}
}
@@ -355,7 +362,7 @@ Ref<Texture2D> EditorExportPlatformJavaScript::get_logo() const {
return logo;
}
-bool EditorExportPlatformJavaScript::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+bool EditorExportPlatformJavaScript::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
#ifndef DEV_ENABLED
// We don't provide export templates for the HTML5 platform currently as there
// is no suitable renderer to use with them. So we forbid exporting and tell
@@ -389,7 +396,27 @@ bool EditorExportPlatformJavaScript::can_export(const Ref<EditorExportPreset> &p
valid = dvalid || rvalid;
r_missing_templates = !valid;
- // Validate the rest of the configuration.
+ if (!err.is_empty()) {
+ r_error = err;
+ }
+
+ return valid;
+}
+
+bool EditorExportPlatformJavaScript::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const {
+#ifndef DEV_ENABLED
+ // We don't provide export templates for the HTML5 platform currently as there
+ // is no suitable renderer to use with them. So we forbid exporting and tell
+ // users why. This is skipped in DEV_ENABLED so that contributors can still test
+ // the pipeline once we start having WebGL or WebGPU support.
+ r_error = "The HTML5 platform is currently not supported in Godot 4.0, as there is no suitable renderer for it.\n";
+ return false;
+#endif
+
+ String err;
+ bool valid = true;
+
+ // Validate the project configuration.
if (p_preset->get("vram_texture_compression/for_mobile")) {
String etc_error = test_etc2();
@@ -438,7 +465,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
}
if (!template_path.is_empty() && !FileAccess::exists(template_path)) {
- EditorNode::get_singleton()->show_warning(TTR("Template file not found:") + "\n" + template_path);
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), vformat(TTR("Template file not found: \"%s\"."), template_path));
return ERR_FILE_NOT_FOUND;
}
@@ -447,7 +474,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
String pck_path = base_path + ".pck";
Error error = save_pack(p_preset, p_debug, pck_path, &shared_objects);
if (error != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + pck_path);
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not write file: \"%s\"."), pck_path));
return error;
}
@@ -457,7 +484,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
String dst = base_dir.plus_file(shared_objects[i].path.get_file());
error = da->copy(shared_objects[i].path, dst);
if (error != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + shared_objects[i].path.get_file());
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not write file: \"%s\"."), shared_objects[i].path.get_file()));
return error;
}
}
@@ -485,7 +512,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
Vector<uint8_t> html;
f = FileAccess::open(html_path, FileAccess::READ);
if (f.is_null()) {
- EditorNode::get_singleton()->show_warning(TTR("Could not read HTML shell:") + "\n" + html_path);
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not read HTML shell: \"%s\"."), html_path));
return ERR_FILE_CANT_READ;
}
html.resize(f->get_length());
@@ -503,7 +530,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
Ref<Image> splash = _get_project_splash();
const String splash_png_path = base_path + ".png";
if (splash->save_png(splash_png_path) != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + splash_png_path);
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not write file: \"%s\"."), splash_png_path));
return ERR_FILE_CANT_WRITE;
}
@@ -513,13 +540,13 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
Ref<Image> favicon = _get_project_icon();
const String favicon_png_path = base_path + ".icon.png";
if (favicon->save_png(favicon_png_path) != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + favicon_png_path);
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not write file: \"%s\"."), favicon_png_path));
return ERR_FILE_CANT_WRITE;
}
favicon->resize(180, 180);
const String apple_icon_png_path = base_path + ".apple-touch-icon.png";
if (favicon->save_png(apple_icon_png_path) != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + apple_icon_png_path);
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not write file: \"%s\"."), apple_icon_png_path));
return ERR_FILE_CANT_WRITE;
}
}
@@ -579,10 +606,11 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese
if (!da->dir_exists(dest)) {
Error err = da->make_dir_recursive(dest);
if (err != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Could not create HTTP server directory:") + "\n" + dest);
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Run"), vformat(TTR("Could not create HTTP server directory: %s."), dest));
return err;
}
}
+
const String basepath = dest.plus_file("tmp_js_export");
Error err = export_project(p_preset, true, basepath + ".html", p_debug_flags);
if (err != OK) {
@@ -625,7 +653,7 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese
err = server->listen(bind_port, bind_ip, use_ssl, ssl_key, ssl_cert);
}
if (err != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Error starting HTTP server:") + "\n" + itos(err));
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Run"), vformat(TTR("Error starting HTTP server: %d."), err));
return err;
}
@@ -654,13 +682,8 @@ EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() {
server.instantiate();
server_thread.start(_server_thread_poll, this);
- Ref<Image> img = memnew(Image(_javascript_logo));
- logo.instantiate();
- logo->create_from_image(img);
-
- img = Ref<Image>(memnew(Image(_javascript_run_icon)));
- run_icon.instantiate();
- run_icon->create_from_image(img);
+ logo = ImageTexture::create_from_image(memnew(Image(_javascript_logo)));
+ run_icon = ImageTexture::create_from_image(memnew(Image(_javascript_run_icon)));
Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
if (theme.is_valid()) {
diff --git a/platform/javascript/export/export_plugin.h b/platform/javascript/export/export_plugin.h
index 2d6cbfde38..16bab02d54 100644
--- a/platform/javascript/export/export_plugin.h
+++ b/platform/javascript/export/export_plugin.h
@@ -36,8 +36,8 @@
#include "core/io/stream_peer_ssl.h"
#include "core/io/tcp_server.h"
#include "core/io/zip_io.h"
-#include "editor/editor_export.h"
#include "editor/editor_node.h"
+#include "editor/export/editor_export_platform.h"
#include "main/splash.gen.h"
#include "platform/javascript/logo.gen.h"
#include "platform/javascript/run_icon.gen.h"
@@ -61,19 +61,16 @@ class EditorExportPlatformJavaScript : public EditorExportPlatform {
EXPORT_MODE_NORMAL = 0,
EXPORT_MODE_THREADS = 1,
EXPORT_MODE_GDNATIVE = 2,
+ EXPORT_MODE_THREADS_GDNATIVE = 3,
};
String _get_template_name(ExportMode p_mode, bool p_debug) const {
String name = "webassembly";
- switch (p_mode) {
- case EXPORT_MODE_THREADS:
- name += "_threads";
- break;
- case EXPORT_MODE_GDNATIVE:
- name += "_gdnative";
- break;
- default:
- break;
+ if (p_mode & EXPORT_MODE_GDNATIVE) {
+ name += "_gdnative";
+ }
+ if (p_mode & EXPORT_MODE_THREADS) {
+ name += "_threads";
}
if (p_debug) {
name += "_debug.zip";
@@ -113,7 +110,7 @@ class EditorExportPlatformJavaScript : public EditorExportPlatform {
static void _server_thread_poll(void *data);
public:
- virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) override;
+ virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
virtual void get_export_options(List<ExportOption> *r_options) override;
@@ -121,7 +118,8 @@ public:
virtual String get_os_name() const override;
virtual Ref<Texture2D> get_logo() const override;
- virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
@@ -133,7 +131,7 @@ public:
virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_option, int p_debug_flags) override;
virtual Ref<Texture2D> get_run_icon() const override;
- virtual void get_platform_features(List<String> *r_features) override {
+ virtual void get_platform_features(List<String> *r_features) const override {
r_features->push_back("web");
r_features->push_back(get_os_name().to_lower());
}
@@ -147,4 +145,4 @@ public:
~EditorExportPlatformJavaScript();
};
-#endif
+#endif // JAVASCRIPT_EXPORT_PLUGIN_H
diff --git a/platform/javascript/export/export_server.h b/platform/javascript/export/export_server.h
index a831b76076..ddbe3cca30 100644
--- a/platform/javascript/export/export_server.h
+++ b/platform/javascript/export/export_server.h
@@ -35,7 +35,6 @@
#include "core/io/stream_peer_ssl.h"
#include "core/io/tcp_server.h"
#include "core/io/zip_io.h"
-#include "editor/editor_export.h"
#include "editor/editor_paths.h"
class EditorHTTPServer : public RefCounted {
@@ -248,4 +247,4 @@ public:
}
};
-#endif
+#endif // JAVASCRIPT_EXPORT_SERVER_H
diff --git a/platform/javascript/godot_audio.h b/platform/javascript/godot_audio.h
index 012f8daeb7..3855b7301e 100644
--- a/platform/javascript/godot_audio.h
+++ b/platform/javascript/godot_audio.h
@@ -63,4 +63,4 @@ extern void godot_audio_script_start(float *p_in_buf, int p_in_size, float *p_ou
}
#endif
-#endif /* GODOT_AUDIO_H */
+#endif // GODOT_AUDIO_H
diff --git a/platform/javascript/godot_js.h b/platform/javascript/godot_js.h
index 1a383c9799..a323f2d157 100644
--- a/platform/javascript/godot_js.h
+++ b/platform/javascript/godot_js.h
@@ -58,6 +58,7 @@ extern void godot_js_input_mouse_move_cb(void (*p_callback)(double p_x, double p
extern void godot_js_input_mouse_wheel_cb(int (*p_callback)(double p_delta_x, double p_delta_y));
extern void godot_js_input_touch_cb(void (*p_callback)(int p_type, int p_count), uint32_t *r_identifiers, double *r_coords);
extern void godot_js_input_key_cb(void (*p_callback)(int p_type, int p_repeat, int p_modifiers), char r_code[32], char r_key[32]);
+extern void godot_js_input_vibrate_handheld(int p_duration_ms);
// Input gamepad
extern void godot_js_input_gamepad_cb(void (*p_on_change)(int p_index, int p_connected, const char *p_id, const char *p_guid));
@@ -120,11 +121,11 @@ extern void godot_js_display_notification_cb(void (*p_callback)(int p_notificati
extern int godot_js_display_vk_available();
extern int godot_js_display_tts_available();
extern void godot_js_display_vk_cb(void (*p_input)(const char *p_text, int p_cursor));
-extern void godot_js_display_vk_show(const char *p_text, int p_multiline, int p_start, int p_end);
+extern void godot_js_display_vk_show(const char *p_text, int p_type, int p_start, int p_end);
extern void godot_js_display_vk_hide();
#ifdef __cplusplus
}
#endif
-#endif /* GODOT_JS_H */
+#endif // GODOT_JS_H
diff --git a/platform/javascript/godot_webgl2.h b/platform/javascript/godot_webgl2.h
index 7c357ff66d..968b70f84b 100644
--- a/platform/javascript/godot_webgl2.h
+++ b/platform/javascript/godot_webgl2.h
@@ -34,4 +34,4 @@
#include "GLES3/gl3.h"
#include "webgl/webgl2.h"
-#endif
+#endif // GODOT_WEBGL2_H
diff --git a/platform/javascript/http_client_javascript.h b/platform/javascript/http_client_javascript.h
index 096aa6a153..fcd225ffc9 100644
--- a/platform/javascript/http_client_javascript.h
+++ b/platform/javascript/http_client_javascript.h
@@ -105,4 +105,5 @@ public:
HTTPClientJavaScript();
~HTTPClientJavaScript();
};
+
#endif // HTTP_CLIENT_JAVASCRIPT_H
diff --git a/platform/javascript/javascript_singleton.cpp b/platform/javascript/javascript_singleton.cpp
index 8dc7aba5f8..204e92b82b 100644
--- a/platform/javascript/javascript_singleton.cpp
+++ b/platform/javascript/javascript_singleton.cpp
@@ -259,7 +259,7 @@ void JavaScriptObjectImpl::_callback(void *p_ref, int p_args_id, int p_argc) {
const Variant *argv[1] = { &arg };
Callable::CallError err;
Variant ret;
- obj->_callable.call(argv, 1, ret, err);
+ obj->_callable.callp(argv, 1, ret, err);
// Set return value
godot_js_wrapper_ex exchange;
diff --git a/platform/javascript/js/engine/config.js b/platform/javascript/js/engine/config.js
index 2e5e1ed0d1..9c4b6c2012 100644
--- a/platform/javascript/js/engine/config.js
+++ b/platform/javascript/js/engine/config.js
@@ -334,6 +334,7 @@ const InternalConfig = function (initConfig) { // eslint-disable-line no-unused-
locale = navigator.languages ? navigator.languages[0] : navigator.language;
locale = locale.split('.')[0];
}
+ locale = locale.replace('-', '_');
const onExit = this.onExit;
// Godot configuration.
diff --git a/platform/javascript/js/libs/library_godot_display.js b/platform/javascript/js/libs/library_godot_display.js
index 5997631bf8..768eaf9e1d 100644
--- a/platform/javascript/js/libs/library_godot_display.js
+++ b/platform/javascript/js/libs/library_godot_display.js
@@ -73,7 +73,7 @@ const GodotDisplayVK = {
GodotDisplayVK.textarea = create('textarea');
GodotDisplayVK.updateSize();
},
- show: function (text, multiline, start, end) {
+ show: function (text, type, start, end) {
if (!GodotDisplayVK.textinput || !GodotDisplayVK.textarea) {
return;
}
@@ -81,7 +81,46 @@ const GodotDisplayVK = {
GodotDisplayVK.hide();
}
GodotDisplayVK.updateSize();
- const elem = multiline ? GodotDisplayVK.textarea : GodotDisplayVK.textinput;
+
+ let elem = GodotDisplayVK.textinput;
+ switch (type) {
+ case 0: // KEYBOARD_TYPE_DEFAULT
+ elem.type = 'text';
+ elem.inputmode = '';
+ break;
+ case 1: // KEYBOARD_TYPE_MULTILINE
+ elem = GodotDisplayVK.textarea;
+ break;
+ case 2: // KEYBOARD_TYPE_NUMBER
+ elem.type = 'text';
+ elem.inputmode = 'numeric';
+ break;
+ case 3: // KEYBOARD_TYPE_NUMBER_DECIMAL
+ elem.type = 'text';
+ elem.inputmode = 'decimal';
+ break;
+ case 4: // KEYBOARD_TYPE_PHONE
+ elem.type = 'tel';
+ elem.inputmode = '';
+ break;
+ case 5: // KEYBOARD_TYPE_EMAIL_ADDRESS
+ elem.type = 'email';
+ elem.inputmode = '';
+ break;
+ case 6: // KEYBOARD_TYPE_PASSWORD
+ elem.type = 'password';
+ elem.inputmode = '';
+ break;
+ case 7: // KEYBOARD_TYPE_URL
+ elem.type = 'url';
+ elem.inputmode = '';
+ break;
+ default:
+ elem.type = 'text';
+ elem.inputmode = '';
+ break;
+ }
+
elem.readonly = false;
elem.disabled = false;
elem.value = text;
@@ -297,26 +336,12 @@ const GodotDisplay = {
$GodotDisplay__deps: ['$GodotConfig', '$GodotRuntime', '$GodotDisplayCursor', '$GodotEventListeners', '$GodotDisplayScreen', '$GodotDisplayVK'],
$GodotDisplay: {
window_icon: '',
- findDPI: function () {
- function testDPI(dpi) {
- return window.matchMedia(`(max-resolution: ${dpi}dpi)`).matches;
- }
- function bisect(low, high, func) {
- const mid = parseInt(((high - low) / 2) + low, 10);
- if (high - low <= 1) {
- return func(high) ? high : low;
- }
- if (func(mid)) {
- return bisect(low, mid, func);
- }
- return bisect(mid, high, func);
- }
- try {
- const dpi = bisect(0, 800, testDPI);
- return dpi >= 96 ? dpi : 96;
- } catch (e) {
- return 96;
- }
+ getDPI: function () {
+ // devicePixelRatio is given in dppx
+ // https://drafts.csswg.org/css-values/#resolution
+ // > due to the 1:96 fixed ratio of CSS *in* to CSS *px*, 1dppx is equivalent to 96dpi.
+ const dpi = Math.round(window.devicePixelRatio * 96);
+ return dpi >= 96 ? dpi : 96;
},
},
@@ -422,7 +447,7 @@ const GodotDisplay = {
godot_js_display_screen_dpi_get__sig: 'i',
godot_js_display_screen_dpi_get: function () {
- return GodotDisplay.findDPI();
+ return GodotDisplay.getDPI();
},
godot_js_display_pixel_ratio_get__sig: 'f',
@@ -694,11 +719,11 @@ const GodotDisplay = {
* Virtual Keyboard
*/
godot_js_display_vk_show__sig: 'viiii',
- godot_js_display_vk_show: function (p_text, p_multiline, p_start, p_end) {
+ godot_js_display_vk_show: function (p_text, p_type, p_start, p_end) {
const text = GodotRuntime.parseString(p_text);
const start = p_start > 0 ? p_start : 0;
const end = p_end > 0 ? p_end : start;
- GodotDisplayVK.show(text, p_multiline, start, end);
+ GodotDisplayVK.show(text, p_type, start, end);
},
godot_js_display_vk_hide__sig: 'v',
diff --git a/platform/javascript/js/libs/library_godot_input.js b/platform/javascript/js/libs/library_godot_input.js
index 1e64c260f8..51571d64a2 100644
--- a/platform/javascript/js/libs/library_godot_input.js
+++ b/platform/javascript/js/libs/library_godot_input.js
@@ -534,6 +534,15 @@ const GodotInput = {
GodotRuntime.free(ptr);
}, false);
},
+
+ godot_js_input_vibrate_handheld__sig: 'vi',
+ godot_js_input_vibrate_handheld: function (p_duration_ms) {
+ if (typeof navigator.vibrate !== 'function') {
+ GodotRuntime.print('This browser does not support vibration.');
+ } else {
+ navigator.vibrate(p_duration_ms);
+ }
+ },
};
autoAddDeps(GodotInput, '$GodotInput');
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index 1686353229..dc81b8b4b6 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -177,6 +177,10 @@ String OS_JavaScript::get_name() const {
return "HTML5";
}
+void OS_JavaScript::vibrate_handheld(int p_duration_ms) {
+ godot_js_input_vibrate_handheld(p_duration_ms);
+}
+
String OS_JavaScript::get_user_data_dir() const {
return "/userfs";
}
diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h
index 0c672111cc..d932745177 100644
--- a/platform/javascript/os_javascript.h
+++ b/platform/javascript/os_javascript.h
@@ -90,13 +90,14 @@ public:
// Implemented in javascript_main.cpp loop callback instead.
void add_frame_delay(bool p_can_draw) override {}
+ void vibrate_handheld(int p_duration_ms) override;
+
String get_cache_path() const override;
String get_config_path() const override;
String get_data_path() const override;
String get_user_data_dir() const override;
bool is_userfs_persistent() const override;
- bool is_single_window() const override { return true; }
void alert(const String &p_alert, const String &p_title = "ALERT!") override;
@@ -107,4 +108,4 @@ public:
OS_JavaScript();
};
-#endif
+#endif // OS_JAVASCRIPT_H