summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/bullet/bullet_physics_server.cpp8
-rw-r--r--modules/bullet/bullet_physics_server.h4
-rw-r--r--modules/bullet/rigid_body_bullet.cpp34
-rw-r--r--modules/bullet/rigid_body_bullet.h8
-rw-r--r--modules/gdnative/gdnative.cpp20
-rw-r--r--modules/gdnative/gdnative_library_editor_plugin.cpp16
-rw-r--r--modules/gdnative/register_types.cpp108
-rw-r--r--modules/gdscript/editor/gdscript_translation_parser_plugin.cpp178
-rw-r--r--modules/gdscript/editor/gdscript_translation_parser_plugin.h57
-rw-r--r--modules/gdscript/register_types.cpp6
-rw-r--r--modules/gridmap/grid_map_editor_plugin.h1
-rw-r--r--modules/opensimplex/open_simplex_noise.cpp2
12 files changed, 375 insertions, 67 deletions
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
index 55686543f3..f397c53344 100644
--- a/modules/bullet/bullet_physics_server.cpp
+++ b/modules/bullet/bullet_physics_server.cpp
@@ -707,11 +707,11 @@ void BulletPhysicsServer3D::body_add_central_force(RID p_body, const Vector3 &p_
body->apply_central_force(p_force);
}
-void BulletPhysicsServer3D::body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_pos) {
+void BulletPhysicsServer3D::body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_position) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
- body->apply_force(p_force, p_pos);
+ body->apply_force(p_force, p_position);
}
void BulletPhysicsServer3D::body_add_torque(RID p_body, const Vector3 &p_torque) {
@@ -728,11 +728,11 @@ void BulletPhysicsServer3D::body_apply_central_impulse(RID p_body, const Vector3
body->apply_central_impulse(p_impulse);
}
-void BulletPhysicsServer3D::body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse) {
+void BulletPhysicsServer3D::body_apply_impulse(RID p_body, const Vector3 &p_impulse, const Vector3 &p_position) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
- body->apply_impulse(p_pos, p_impulse);
+ body->apply_impulse(p_impulse, p_position);
}
void BulletPhysicsServer3D::body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse) {
diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h
index 558d1ce5f7..8e8b33a4b8 100644
--- a/modules/bullet/bullet_physics_server.h
+++ b/modules/bullet/bullet_physics_server.h
@@ -223,11 +223,11 @@ public:
virtual Vector3 body_get_applied_torque(RID p_body) const;
virtual void body_add_central_force(RID p_body, const Vector3 &p_force);
- virtual void body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_pos);
+ virtual void body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_position = Vector3());
virtual void body_add_torque(RID p_body, const Vector3 &p_torque);
virtual void body_apply_central_impulse(RID p_body, const Vector3 &p_impulse);
- virtual void body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse);
+ virtual void body_apply_impulse(RID p_body, const Vector3 &p_impulse, const Vector3 &p_position = Vector3());
virtual void body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse);
virtual void body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity);
diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
index 9aac7ba9e4..6cfbe18a64 100644
--- a/modules/bullet/rigid_body_bullet.cpp
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -118,8 +118,8 @@ void BulletPhysicsDirectBodyState3D::add_central_force(const Vector3 &p_force) {
body->apply_central_force(p_force);
}
-void BulletPhysicsDirectBodyState3D::add_force(const Vector3 &p_force, const Vector3 &p_pos) {
- body->apply_force(p_force, p_pos);
+void BulletPhysicsDirectBodyState3D::add_force(const Vector3 &p_force, const Vector3 &p_position) {
+ body->apply_force(p_force, p_position);
}
void BulletPhysicsDirectBodyState3D::add_torque(const Vector3 &p_torque) {
@@ -130,8 +130,8 @@ void BulletPhysicsDirectBodyState3D::apply_central_impulse(const Vector3 &p_impu
body->apply_central_impulse(p_impulse);
}
-void BulletPhysicsDirectBodyState3D::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse) {
- body->apply_impulse(p_pos, p_impulse);
+void BulletPhysicsDirectBodyState3D::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) {
+ body->apply_impulse(p_impulse, p_position);
}
void BulletPhysicsDirectBodyState3D::apply_torque_impulse(const Vector3 &p_impulse) {
@@ -604,23 +604,23 @@ Variant RigidBodyBullet::get_state(PhysicsServer3D::BodyState p_state) const {
}
void RigidBodyBullet::apply_central_impulse(const Vector3 &p_impulse) {
- btVector3 btImpu;
- G_TO_B(p_impulse, btImpu);
+ btVector3 btImpulse;
+ G_TO_B(p_impulse, btImpulse);
if (Vector3() != p_impulse) {
btBody->activate();
}
- btBody->applyCentralImpulse(btImpu);
+ btBody->applyCentralImpulse(btImpulse);
}
-void RigidBodyBullet::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse) {
- btVector3 btImpu;
- btVector3 btPos;
- G_TO_B(p_impulse, btImpu);
- G_TO_B(p_pos, btPos);
+void RigidBodyBullet::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) {
+ btVector3 btImpulse;
+ btVector3 btPosition;
+ G_TO_B(p_impulse, btImpulse);
+ G_TO_B(p_position, btPosition);
if (Vector3() != p_impulse) {
btBody->activate();
}
- btBody->applyImpulse(btImpu, btPos);
+ btBody->applyImpulse(btImpulse, btPosition);
}
void RigidBodyBullet::apply_torque_impulse(const Vector3 &p_impulse) {
@@ -632,15 +632,15 @@ void RigidBodyBullet::apply_torque_impulse(const Vector3 &p_impulse) {
btBody->applyTorqueImpulse(btImp);
}
-void RigidBodyBullet::apply_force(const Vector3 &p_force, const Vector3 &p_pos) {
+void RigidBodyBullet::apply_force(const Vector3 &p_force, const Vector3 &p_position) {
btVector3 btForce;
- btVector3 btPos;
+ btVector3 btPosition;
G_TO_B(p_force, btForce);
- G_TO_B(p_pos, btPos);
+ G_TO_B(p_position, btPosition);
if (Vector3() != p_force) {
btBody->activate();
}
- btBody->applyForce(btForce, btPos);
+ btBody->applyForce(btForce, btPosition);
}
void RigidBodyBullet::apply_central_force(const Vector3 &p_force) {
diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h
index 6d159504b8..ddc9d2916a 100644
--- a/modules/bullet/rigid_body_bullet.h
+++ b/modules/bullet/rigid_body_bullet.h
@@ -111,10 +111,10 @@ public:
virtual Transform get_transform() const;
virtual void add_central_force(const Vector3 &p_force);
- virtual void add_force(const Vector3 &p_force, const Vector3 &p_pos);
+ virtual void add_force(const Vector3 &p_force, const Vector3 &p_position = Vector3());
virtual void add_torque(const Vector3 &p_torque);
virtual void apply_central_impulse(const Vector3 &p_impulse);
- virtual void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse);
+ virtual void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3());
virtual void apply_torque_impulse(const Vector3 &p_impulse);
virtual void set_sleep_state(bool p_sleep);
@@ -284,12 +284,12 @@ public:
void set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant);
Variant get_state(PhysicsServer3D::BodyState p_state) const;
- void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse);
void apply_central_impulse(const Vector3 &p_impulse);
+ void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3());
void apply_torque_impulse(const Vector3 &p_impulse);
- void apply_force(const Vector3 &p_force, const Vector3 &p_pos);
void apply_central_force(const Vector3 &p_force);
+ void apply_force(const Vector3 &p_force, const Vector3 &p_position = Vector3());
void apply_torque(const Vector3 &p_torque);
void set_applied_force(const Vector3 &p_force);
diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp
index 3d747ba41e..bb2da70c3a 100644
--- a/modules/gdnative/gdnative.cpp
+++ b/modules/gdnative/gdnative.cpp
@@ -291,8 +291,26 @@ bool GDNative::initialize() {
return false;
}
#ifdef IPHONE_ENABLED
- // on iOS we use static linking
+ // On iOS we use static linking by default.
String path = "";
+
+ // On iOS dylibs is not allowed, but can be replaced with .framework or .xcframework.
+ // If they are used, we can run dlopen on them.
+ // They should be located under Frameworks directory, so we need to replace library path.
+ if (!lib_path.ends_with(".a")) {
+ path = ProjectSettings::get_singleton()->globalize_path(lib_path);
+
+ if (!FileAccess::exists(path)) {
+ String lib_name = lib_path.get_basename().get_file();
+ String framework_path_format = "Frameworks/$name.framework/$name";
+
+ Dictionary format_dict;
+ format_dict["name"] = lib_name;
+ String framework_path = framework_path_format.format(format_dict, "$_");
+
+ path = OS::get_singleton()->get_executable_path().get_base_dir().plus_file(framework_path);
+ }
+ }
#elif defined(ANDROID_ENABLED)
// On Android dynamic libraries are located separately from resource assets,
// we should pass library name to dlopen(). The library name is flattened
diff --git a/modules/gdnative/gdnative_library_editor_plugin.cpp b/modules/gdnative/gdnative_library_editor_plugin.cpp
index 5896da4640..1d4d188f23 100644
--- a/modules/gdnative/gdnative_library_editor_plugin.cpp
+++ b/modules/gdnative/gdnative_library_editor_plugin.cpp
@@ -127,15 +127,24 @@ void GDNativeLibraryEditor::_on_item_button(Object *item, int column, int id) {
String section = (id == BUTTON_SELECT_DEPENDENCES || id == BUTTON_CLEAR_DEPENDENCES) ? "dependencies" : "entry";
if (id == BUTTON_SELECT_LIBRARY || id == BUTTON_SELECT_DEPENDENCES) {
+ TreeItem *treeItem = Object::cast_to<TreeItem>(item)->get_parent();
EditorFileDialog::FileMode mode = EditorFileDialog::FILE_MODE_OPEN_FILE;
if (id == BUTTON_SELECT_DEPENDENCES) {
mode = EditorFileDialog::FILE_MODE_OPEN_FILES;
+ } else if (treeItem->get_text(0) == "iOS") {
+ mode = EditorFileDialog::FILE_MODE_OPEN_ANY;
}
file_dialog->set_meta("target", target);
file_dialog->set_meta("section", section);
file_dialog->clear_filters();
- file_dialog->add_filter(Object::cast_to<TreeItem>(item)->get_parent()->get_metadata(0));
+
+ String filter_string = treeItem->get_metadata(0);
+ Vector<String> filters = filter_string.split(",", false, 0);
+ for (int i = 0; i < filters.size(); i++) {
+ file_dialog->add_filter(filters[i]);
+ }
+
file_dialog->set_file_mode(mode);
file_dialog->popup_centered_ratio();
@@ -309,7 +318,9 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() {
platform_ios.name = "iOS";
platform_ios.entries.push_back("armv7");
platform_ios.entries.push_back("arm64");
- platform_ios.library_extension = "*.dylib";
+ // iOS can use both Static and Dynamic libraries.
+ // Frameworks is actually a folder with files.
+ platform_ios.library_extension = "*.framework; Framework, *.xcframework; Binary Framework, *.a; Static Library, *.dylib; Dynamic Library";
platforms["iOS"] = platform_ios;
}
@@ -360,6 +371,7 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() {
//file_dialog->set_resizable(true);
add_child(file_dialog);
file_dialog->connect("file_selected", callable_mp(this, &GDNativeLibraryEditor::_on_library_selected));
+ file_dialog->connect("dir_selected", callable_mp(this, &GDNativeLibraryEditor::_on_library_selected));
file_dialog->connect("files_selected", callable_mp(this, &GDNativeLibraryEditor::_on_dependencies_selected));
new_architecture_dialog = memnew(ConfirmationDialog);
diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp
index 136af5bd1e..d1b1513ac3 100644
--- a/modules/gdnative/register_types.cpp
+++ b/modules/gdnative/register_types.cpp
@@ -142,47 +142,85 @@ void GDNativeExportPlugin::_export_file(const String &p_path, const String &p_ty
}
}
+ // Add symbols for staticaly linked libraries on iOS
if (p_features.has("iOS")) {
- // Register symbols in the "fake" dynamic lookup table, because dlsym does not work well on iOS.
- LibrarySymbol expected_symbols[] = {
- { "gdnative_init", true },
- { "gdnative_terminate", false },
- { "nativescript_init", false },
- { "nativescript_frame", false },
- { "nativescript_thread_enter", false },
- { "nativescript_thread_exit", false },
- { "gdnative_singleton", false }
- };
- String declare_pattern = "extern \"C\" void $name(void)$weak;\n";
- String additional_code = "extern void register_dynamic_symbol(char *name, void *address);\n"
- "extern void add_ios_init_callback(void (*cb)());\n";
- String linker_flags = "";
- for (unsigned long i = 0; i < sizeof(expected_symbols) / sizeof(expected_symbols[0]); ++i) {
- String full_name = lib->get_symbol_prefix() + expected_symbols[i].name;
- String code = declare_pattern.replace("$name", full_name);
- code = code.replace("$weak", expected_symbols[i].is_required ? "" : " __attribute__((weak))");
- additional_code += code;
-
- if (!expected_symbols[i].is_required) {
- if (linker_flags.length() > 0) {
- linker_flags += " ";
+ bool should_fake_dynamic = false;
+
+ List<String> entry_keys;
+ config->get_section_keys("entry", &entry_keys);
+
+ for (List<String>::Element *E = entry_keys.front(); E; E = E->next()) {
+ String key = E->get();
+
+ Vector<String> tags = key.split(".");
+
+ bool skip = false;
+ for (int i = 0; i < tags.size(); i++) {
+ bool has_feature = p_features.has(tags[i]);
+
+ if (!has_feature) {
+ skip = true;
+ break;
}
- linker_flags += "-Wl,-U,_" + full_name;
}
- }
- additional_code += String("void $prefixinit() {\n").replace("$prefix", lib->get_symbol_prefix());
- String register_pattern = " if (&$name) register_dynamic_symbol((char *)\"$name\", (void *)$name);\n";
- for (unsigned long i = 0; i < sizeof(expected_symbols) / sizeof(expected_symbols[0]); ++i) {
- String full_name = lib->get_symbol_prefix() + expected_symbols[i].name;
- additional_code += register_pattern.replace("$name", full_name);
+ if (skip) {
+ continue;
+ }
+
+ String entry_lib_path = config->get_value("entry", key);
+ if (entry_lib_path.begins_with("res://") && entry_lib_path.ends_with(".a")) {
+ // If we find static library that was used for export
+ // we should add a fake loopup table.
+ // In case of dynamic library being used,
+ // this symbols will not cause any issues with library loading.
+ should_fake_dynamic = true;
+ break;
+ }
}
- additional_code += "}\n";
- additional_code += String("struct $prefixstruct {$prefixstruct() {add_ios_init_callback($prefixinit);}};\n").replace("$prefix", lib->get_symbol_prefix());
- additional_code += String("$prefixstruct $prefixstruct_instance;\n").replace("$prefix", lib->get_symbol_prefix());
- add_ios_cpp_code(additional_code);
- add_ios_linker_flags(linker_flags);
+ if (should_fake_dynamic) {
+ // Register symbols in the "fake" dynamic lookup table, because dlsym does not work well on iOS.
+ LibrarySymbol expected_symbols[] = {
+ { "gdnative_init", true },
+ { "gdnative_terminate", false },
+ { "nativescript_init", false },
+ { "nativescript_frame", false },
+ { "nativescript_thread_enter", false },
+ { "nativescript_thread_exit", false },
+ { "gdnative_singleton", false }
+ };
+ String declare_pattern = "extern \"C\" void $name(void)$weak;\n";
+ String additional_code = "extern void register_dynamic_symbol(char *name, void *address);\n"
+ "extern void add_ios_init_callback(void (*cb)());\n";
+ String linker_flags = "";
+ for (unsigned long i = 0; i < sizeof(expected_symbols) / sizeof(expected_symbols[0]); ++i) {
+ String full_name = lib->get_symbol_prefix() + expected_symbols[i].name;
+ String code = declare_pattern.replace("$name", full_name);
+ code = code.replace("$weak", expected_symbols[i].is_required ? "" : " __attribute__((weak))");
+ additional_code += code;
+
+ if (!expected_symbols[i].is_required) {
+ if (linker_flags.length() > 0) {
+ linker_flags += " ";
+ }
+ linker_flags += "-Wl,-U,_" + full_name;
+ }
+ }
+
+ additional_code += String("void $prefixinit() {\n").replace("$prefix", lib->get_symbol_prefix());
+ String register_pattern = " if (&$name) register_dynamic_symbol((char *)\"$name\", (void *)$name);\n";
+ for (unsigned long i = 0; i < sizeof(expected_symbols) / sizeof(expected_symbols[0]); ++i) {
+ String full_name = lib->get_symbol_prefix() + expected_symbols[i].name;
+ additional_code += register_pattern.replace("$name", full_name);
+ }
+ additional_code += "}\n";
+ additional_code += String("struct $prefixstruct {$prefixstruct() {add_ios_init_callback($prefixinit);}};\n").replace("$prefix", lib->get_symbol_prefix());
+ additional_code += String("$prefixstruct $prefixstruct_instance;\n").replace("$prefix", lib->get_symbol_prefix());
+
+ add_ios_cpp_code(additional_code);
+ add_ios_linker_flags(linker_flags);
+ }
}
}
diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
new file mode 100644
index 0000000000..a1b18978fc
--- /dev/null
+++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
@@ -0,0 +1,178 @@
+/*************************************************************************/
+/* gdscript_translation_parser_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gdscript_translation_parser_plugin.h"
+
+#include "core/io/resource_loader.h"
+#include "modules/gdscript/gdscript.h"
+
+void GDScriptEditorTranslationParserPlugin::get_recognized_extensions(List<String> *r_extensions) const {
+ GDScriptLanguage::get_singleton()->get_recognized_extensions(r_extensions);
+}
+
+Error GDScriptEditorTranslationParserPlugin::parse_file(const String &p_path, Vector<String> *r_extracted_strings) {
+ List<String> extensions;
+ get_recognized_extensions(&extensions);
+ bool extension_valid = false;
+ for (auto E = extensions.front(); E; E = E->next()) {
+ if (p_path.get_extension() == E->get()) {
+ extension_valid = true;
+ break;
+ }
+ }
+
+ if (!extension_valid) {
+ Vector<String> temp;
+ for (auto E = extensions.front(); E; E = E->next()) {
+ temp.push_back(E->get());
+ }
+ String valid_extensions = String(", ").join(temp);
+ ERR_PRINT("Argument p_path \"" + p_path + "\" has wrong extension. List of valid extensions: " + valid_extensions);
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Error err;
+ RES loaded_res = ResourceLoader::load(p_path, "", false, &err);
+ if (err) {
+ ERR_PRINT("Failed to load " + p_path);
+ return err;
+ }
+
+ Ref<GDScript> gdscript = loaded_res;
+ parse_text(gdscript->get_source_code(), r_extracted_strings);
+
+ return OK;
+}
+
+void GDScriptEditorTranslationParserPlugin::parse_text(const String &p_text, Vector<String> *r_extracted_strings) {
+ // Parse and match all GDScript function API that involves translation string.
+ // E.g get_node("Label").text = "something", var test = tr("something"), "something" will be matched and collected.
+
+ Vector<String> parsed_strings;
+
+ // Search translation strings with RegEx.
+ regex.clear();
+ regex.compile(String("|").join(patterns));
+ Array results = regex.search_all(p_text);
+ _get_captured_strings(results, &parsed_strings);
+
+ // Special handling for FileDialog.
+ Vector<String> temp;
+ _parse_file_dialog(p_text, &temp);
+ parsed_strings.append_array(temp);
+
+ // Filter out / and +
+ String filter = "(?:\\\\\\n|\"[\\s\\\\]*\\+\\s*\")";
+ regex.clear();
+ regex.compile(filter);
+ for (int i = 0; i < parsed_strings.size(); i++) {
+ parsed_strings.set(i, regex.sub(parsed_strings[i], "", true));
+ }
+
+ r_extracted_strings->append_array(parsed_strings);
+}
+
+void GDScriptEditorTranslationParserPlugin::_parse_file_dialog(const String &p_source_code, Vector<String> *r_output) {
+ // FileDialog API has the form .filters = PackedStringArray(["*.png ; PNG Images","*.gd ; GDScript Files"]).
+ // First filter: Get "*.png ; PNG Images", "*.gd ; GDScript Files" from PackedStringArray.
+ regex.clear();
+ regex.compile(String("|").join(file_dialog_patterns));
+ Array results = regex.search_all(p_source_code);
+
+ Vector<String> temp;
+ _get_captured_strings(results, &temp);
+ String captured_strings = String(",").join(temp);
+
+ // Second filter: Get the texts after semicolon from "*.png ; PNG Images","*.gd ; GDScript Files".
+ String second_filter = "\"[^;]+;" + text + "\"";
+ regex.clear();
+ regex.compile(second_filter);
+ results = regex.search_all(captured_strings);
+ _get_captured_strings(results, r_output);
+ for (int i = 0; i < r_output->size(); i++) {
+ r_output->set(i, r_output->get(i).strip_edges());
+ }
+}
+
+void GDScriptEditorTranslationParserPlugin::_get_captured_strings(const Array &p_results, Vector<String> *r_output) {
+ Ref<RegExMatch> result;
+ for (int i = 0; i < p_results.size(); i++) {
+ result = p_results[i];
+ for (int j = 0; j < result->get_group_count(); j++) {
+ String s = result->get_string(j + 1);
+ // Prevent reading text with only spaces.
+ if (!s.strip_edges().empty()) {
+ r_output->push_back(s);
+ }
+ }
+ }
+}
+
+GDScriptEditorTranslationParserPlugin::GDScriptEditorTranslationParserPlugin() {
+ // Regex search pattern templates.
+ // The extra complication in the regex pattern is to ensure that the matching works when users write over multiple lines, use tabs etc.
+ const String dot = "\\.[\\s\\\\]*";
+ const String str_assign_template = "[\\s\\\\]*=[\\s\\\\]*\"" + text + "\"";
+ const String first_arg_template = "[\\s\\\\]*\\([\\s\\\\]*\"" + text + "\"[\\s\\S]*?\\)";
+ const String second_arg_template = "[\\s\\\\]*\\([\\s\\S]+?,[\\s\\\\]*\"" + text + "\"[\\s\\S]*?\\)";
+
+ // Common patterns.
+ patterns.push_back("tr" + first_arg_template);
+ patterns.push_back(dot + "text" + str_assign_template);
+ patterns.push_back(dot + "placeholder_text" + str_assign_template);
+ patterns.push_back(dot + "hint_tooltip" + str_assign_template);
+ patterns.push_back(dot + "set_text" + first_arg_template);
+ patterns.push_back(dot + "set_tooltip" + first_arg_template);
+ patterns.push_back(dot + "set_placeholder" + first_arg_template);
+
+ // Tabs and TabContainer API.
+ patterns.push_back(dot + "set_tab_title" + second_arg_template);
+ patterns.push_back(dot + "add_tab" + first_arg_template);
+
+ // PopupMenu API.
+ patterns.push_back(dot + "add_check_item" + first_arg_template);
+ patterns.push_back(dot + "add_icon_check_item" + second_arg_template);
+ patterns.push_back(dot + "add_icon_item" + second_arg_template);
+ patterns.push_back(dot + "add_icon_radio_check_item" + second_arg_template);
+ patterns.push_back(dot + "add_item" + first_arg_template);
+ patterns.push_back(dot + "add_multistate_item" + first_arg_template);
+ patterns.push_back(dot + "add_radio_check_item" + first_arg_template);
+ patterns.push_back(dot + "add_separator" + first_arg_template);
+ patterns.push_back(dot + "add_submenu_item" + first_arg_template);
+ patterns.push_back(dot + "set_item_text" + second_arg_template);
+ //patterns.push_back(dot + "set_item_tooltip" + second_arg_template); //no tr() behind this function. might be bug.
+
+ // FileDialog API - special case.
+ const String fd_text = "((?:[\\s\\\\]*\"(?:[^\"\\\\]|\\\\[\\s\\S])*(?:\"[\\s\\\\]*\\+[\\s\\\\]*\"(?:[^\"\\\\]|\\\\[\\s\\S])*)*\"[\\s\\\\]*,?)*)";
+ const String packed_string_array = "[\\s\\\\]*PackedStringArray[\\s\\\\]*\\([\\s\\\\]*\\[" + fd_text + "\\][\\s\\\\]*\\)";
+ file_dialog_patterns.push_back(dot + "add_filter[\\s\\\\]*\\(" + fd_text + "[\\s\\\\]*\\)");
+ file_dialog_patterns.push_back(dot + "filters[\\s\\\\]*=" + packed_string_array);
+ file_dialog_patterns.push_back(dot + "set_filters[\\s\\\\]*\\(" + packed_string_array + "[\\s\\\\]*\\)");
+}
diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.h b/modules/gdscript/editor/gdscript_translation_parser_plugin.h
new file mode 100644
index 0000000000..ef967845b9
--- /dev/null
+++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.h
@@ -0,0 +1,57 @@
+/*************************************************************************/
+/* gdscript_translation_parser_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* 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 */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GDSCRIPT_TRANSLATION_PARSER_PLUGIN_H
+#define GDSCRIPT_TRANSLATION_PARSER_PLUGIN_H
+
+#include "editor/editor_translation_parser.h"
+#include "modules/regex/regex.h"
+
+class GDScriptEditorTranslationParserPlugin : public EditorTranslationParserPlugin {
+ GDCLASS(GDScriptEditorTranslationParserPlugin, EditorTranslationParserPlugin);
+
+ // Regex and search patterns that are used to match translation strings.
+ const String text = "((?:[^\"\\\\]|\\\\[\\s\\S])*(?:\"[\\s\\\\]*\\+[\\s\\\\]*\"(?:[^\"\\\\]|\\\\[\\s\\S])*)*)";
+ RegEx regex;
+ Vector<String> patterns;
+ Vector<String> file_dialog_patterns;
+
+ void _parse_file_dialog(const String &p_source_code, Vector<String> *r_output);
+ void _get_captured_strings(const Array &p_results, Vector<String> *r_output);
+
+public:
+ virtual Error parse_file(const String &p_path, Vector<String> *r_extracted_strings);
+ virtual void parse_text(const String &p_text, Vector<String> *r_extracted_strings);
+ virtual void get_recognized_extensions(List<String> *r_extensions) const;
+
+ GDScriptEditorTranslationParserPlugin();
+};
+
+#endif // GDSCRIPT_TRANSLATION_PARSER_PLUGIN_H
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index 0625123530..53e760ffa7 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -46,7 +46,9 @@ Ref<ResourceFormatSaverGDScript> resource_saver_gd;
#include "editor/editor_export.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_translation_parser.h"
#include "editor/gdscript_highlighter.h"
+#include "editor/gdscript_translation_parser_plugin.h"
#ifndef GDSCRIPT_NO_LSP
#include "core/engine.h"
@@ -164,6 +166,10 @@ void register_gdscript_types() {
#ifdef TOOLS_ENABLED
ScriptEditor::register_create_syntax_highlighter_function(GDScriptSyntaxHighlighter::create);
EditorNode::add_init_callback(_editor_init);
+
+ Ref<GDScriptEditorTranslationParserPlugin> gdscript_translation_parser_plugin;
+ gdscript_translation_parser_plugin.instance();
+ EditorTranslationParser::get_singleton()->add_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD);
#endif // TOOLS_ENABLED
}
diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h
index 0ae9b27833..31a01cdc91 100644
--- a/modules/gridmap/grid_map_editor_plugin.h
+++ b/modules/gridmap/grid_map_editor_plugin.h
@@ -33,7 +33,6 @@
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
-#include "editor/pane_drag.h"
#include "grid_map.h"
class Node3DEditorPlugin;
diff --git a/modules/opensimplex/open_simplex_noise.cpp b/modules/opensimplex/open_simplex_noise.cpp
index 00b3d47db9..b08219d258 100644
--- a/modules/opensimplex/open_simplex_noise.cpp
+++ b/modules/opensimplex/open_simplex_noise.cpp
@@ -110,7 +110,7 @@ Ref<Image> OpenSimplexNoise::get_image(int p_width, int p_height) {
for (int i = 0; i < p_height; i++) {
for (int j = 0; j < p_width; j++) {
- float v = get_noise_2d(i, j);
+ float v = get_noise_2d(j, i);
v = v * 0.5 + 0.5; // Normalize [0..1]
uint8_t value = uint8_t(CLAMP(v * 255.0, 0, 255));
wd8[(i * p_width + j) * 4 + 0] = value;