summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/class_db.cpp2
-rw-r--r--core/io/image_loader.cpp2
-rw-r--r--core/io/resource_saver.cpp2
-rw-r--r--core/math/quick_hull.cpp2
-rw-r--r--core/os/input.h3
-rw-r--r--core/os/os.cpp2
-rw-r--r--core/ustring.cpp6
-rw-r--r--core/variant.cpp6
-rw-r--r--editor/dependency_editor.cpp63
-rw-r--r--editor/dependency_editor.h3
-rw-r--r--editor/editor_data.cpp2
-rw-r--r--editor/editor_file_dialog.cpp1
-rw-r--r--editor/editor_node.cpp12
-rw-r--r--editor/find_in_files.cpp11
-rw-r--r--editor/icons/icon_paint_vertex.svg58
-rw-r--r--editor/icons/icon_unpaint_vertex.svg58
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp14
-rw-r--r--editor/plugins/asset_library_editor_plugin.h1
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp108
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h4
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp296
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.h23
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp26
-rw-r--r--editor/plugins/tile_map_editor_plugin.h19
-rw-r--r--editor/plugins/tile_set_editor_plugin.cpp6
-rw-r--r--editor/scene_tree_editor.cpp7
-rw-r--r--editor/script_editor_debugger.cpp23
-rw-r--r--main/input_default.cpp122
-rw-r--r--main/input_default.h17
-rw-r--r--main/main.cpp15
-rw-r--r--modules/gdscript/gdscript_editor.cpp24
-rw-r--r--modules/gdscript/gdscript_function.cpp2
-rw-r--r--modules/mono/config.py4
-rw-r--r--modules/mono/utils/mono_reg_utils.cpp2
-rw-r--r--modules/pvr/texture_loader_pvr.cpp4
-rw-r--r--modules/visual_script/visual_script.cpp1
-rw-r--r--modules/visual_script/visual_script.h2
-rw-r--r--platform/android/os_android.cpp49
-rw-r--r--platform/android/os_android.h1
-rw-r--r--platform/iphone/gl_view.mm9
-rw-r--r--platform/iphone/os_iphone.cpp45
-rw-r--r--platform/iphone/os_iphone.h6
-rw-r--r--platform/javascript/os_javascript.cpp35
-rw-r--r--platform/uwp/app.cpp83
-rw-r--r--platform/uwp/app.h1
-rw-r--r--platform/uwp/export/export.cpp8
-rw-r--r--platform/windows/os_windows.cpp39
-rw-r--r--platform/x11/os_x11.cpp17
-rw-r--r--platform/x11/os_x11.h1
-rw-r--r--scene/2d/polygon_2d.cpp84
-rw-r--r--scene/2d/polygon_2d.h24
-rw-r--r--scene/2d/skeleton_2d.cpp2
-rw-r--r--scene/animation/animation_tree_player.cpp4
-rw-r--r--scene/animation/animation_tree_player.h2
-rw-r--r--scene/main/node.cpp16
-rw-r--r--scene/main/node.h6
-rw-r--r--scene/main/scene_tree.cpp8
-rw-r--r--scene/register_scene_types.cpp3
-rw-r--r--servers/physics/body_pair_sw.cpp1
-rw-r--r--servers/physics_2d/body_pair_2d_sw.cpp1
-rw-r--r--servers/visual/shader_language.h1
61 files changed, 999 insertions, 400 deletions
diff --git a/core/class_db.cpp b/core/class_db.cpp
index 92aa131e2d..08c1ade679 100644
--- a/core/class_db.cpp
+++ b/core/class_db.cpp
@@ -254,11 +254,13 @@ HashMap<StringName, StringName, StringNameHasher> ClassDB::compat_classes;
ClassDB::ClassInfo::ClassInfo() {
+ api = API_NONE;
creation_func = NULL;
inherits_ptr = NULL;
disabled = false;
exposed = false;
}
+
ClassDB::ClassInfo::~ClassInfo() {
}
diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp
index 999c9a8ca2..8ebd9d6cd9 100644
--- a/core/io/image_loader.cpp
+++ b/core/io/image_loader.cpp
@@ -37,7 +37,7 @@ bool ImageFormatLoader::recognize(const String &p_extension) const {
get_recognized_extensions(&extensions);
for (List<String>::Element *E = extensions.front(); E; E = E->next()) {
- if (E->get().nocasecmp_to(p_extension.get_extension()) == 0)
+ if (E->get().nocasecmp_to(p_extension) == 0)
return true;
}
diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp
index 609dd7e93c..3dcd94880a 100644
--- a/core/io/resource_saver.cpp
+++ b/core/io/resource_saver.cpp
@@ -56,7 +56,7 @@ Error ResourceSaver::save(const String &p_path, const RES &p_resource, uint32_t
for (List<String>::Element *E = extensions.front(); E; E = E->next()) {
- if (E->get().nocasecmp_to(extension.get_extension()) == 0)
+ if (E->get().nocasecmp_to(extension) == 0)
recognized = true;
}
diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp
index 102e454e02..fc90417413 100644
--- a/core/math/quick_hull.cpp
+++ b/core/math/quick_hull.cpp
@@ -74,7 +74,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_me
int longest_axis = aabb.get_longest_axis_index();
//first two vertices are the most distant
- int simplex[4];
+ int simplex[4] = { 0 };
{
real_t max = 0, min = 0;
diff --git a/core/os/input.h b/core/os/input.h
index 027147b987..001871c5dc 100644
--- a/core/os/input.h
+++ b/core/os/input.h
@@ -118,7 +118,8 @@ public:
void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
- virtual bool is_emulating_touchscreen() const = 0;
+ virtual bool is_emulating_touch_from_mouse() const = 0;
+ virtual bool is_emulating_mouse_from_touch() const = 0;
virtual CursorShape get_default_cursor_shape() = 0;
virtual void set_default_cursor_shape(CursorShape p_shape) = 0;
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 618a4bbac3..854d554b10 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -411,7 +411,7 @@ Error OS::set_cwd(const String &p_cwd) {
bool OS::has_touchscreen_ui_hint() const {
//return false;
- return Input::get_singleton() && Input::get_singleton()->is_emulating_touchscreen();
+ return Input::get_singleton() && Input::get_singleton()->is_emulating_touch_from_mouse();
}
int OS::get_free_static_memory() const {
diff --git a/core/ustring.cpp b/core/ustring.cpp
index b98e202175..921d20a6fd 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -3755,8 +3755,8 @@ String String::get_file() const {
String String::get_extension() const {
int pos = find_last(".");
- if (pos < 0)
- return *this;
+ if (pos < 0 || pos < MAX(find_last("/"), find_last("\\")))
+ return "";
return substr(pos + 1, length());
}
@@ -3834,7 +3834,7 @@ String String::percent_decode() const {
String String::get_basename() const {
int pos = find_last(".");
- if (pos < 0)
+ if (pos < 0 || pos < MAX(find_last("/"), find_last("\\")))
return *this;
return substr(0, pos);
diff --git a/core/variant.cpp b/core/variant.cpp
index 5d48c8785e..a6df95e310 100644
--- a/core/variant.cpp
+++ b/core/variant.cpp
@@ -3167,7 +3167,11 @@ String Variant::get_call_error_text(Object *p_base, const StringName &p_method,
if (ce.error == Variant::CallError::CALL_ERROR_INVALID_ARGUMENT) {
int errorarg = ce.argument;
- err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(ce.expected) + ".";
+ if (p_argptrs) {
+ err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(ce.expected) + ".";
+ } else {
+ err_text = "Cannot convert argument " + itos(errorarg + 1) + " from [missing argptr, type unknown] to " + Variant::get_type_name(ce.expected) + ".";
+ }
} else if (ce.error == Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) {
err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + ".";
} else if (ce.error == Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp
index 19fd297f69..953d787322 100644
--- a/editor/dependency_editor.cpp
+++ b/editor/dependency_editor.cpp
@@ -472,17 +472,18 @@ void DependencyRemoveDialog::_build_removed_dependency_tree(const Vector<Removed
void DependencyRemoveDialog::show(const Vector<String> &p_folders, const Vector<String> &p_files) {
all_remove_files.clear();
- to_delete.clear();
+ dirs_to_delete.clear();
+ files_to_delete.clear();
owners->clear();
for (int i = 0; i < p_folders.size(); ++i) {
String folder = p_folders[i].ends_with("/") ? p_folders[i] : (p_folders[i] + "/");
_find_files_in_removed_folder(EditorFileSystem::get_singleton()->get_filesystem_path(folder), folder);
- to_delete.push_back(folder);
+ dirs_to_delete.push_back(folder);
}
for (int i = 0; i < p_files.size(); ++i) {
all_remove_files[p_files[i]] = String();
- to_delete.push_back(p_files[i]);
+ files_to_delete.push_back(p_files[i]);
}
Vector<RemovedDependency> removed_deps;
@@ -502,29 +503,49 @@ void DependencyRemoveDialog::show(const Vector<String> &p_folders, const Vector<
}
void DependencyRemoveDialog::ok_pressed() {
- bool files_only = true;
- for (int i = 0; i < to_delete.size(); ++i) {
- if (to_delete[i].ends_with("/")) {
- files_only = false;
- } else if (ResourceCache::has(to_delete[i])) {
- Resource *res = ResourceCache::get(to_delete[i]);
- res->set_path(""); //clear reference to path
+
+ if (dirs_to_delete.size() == 0) {
+ //If we only deleted files we should only need to tell the file system about the files we touched.
+ for (int i = 0; i < files_to_delete.size(); ++i)
+ EditorFileSystem::get_singleton()->update_file(files_to_delete[i]);
+ } else {
+
+ for (int i = 0; i < files_to_delete.size(); ++i) {
+ if (ResourceCache::has(files_to_delete[i])) {
+ Resource *res = ResourceCache::get(files_to_delete[i]);
+ res->set_path("");
+ }
+ String path = OS::get_singleton()->get_resource_dir() + files_to_delete[i].replace_first("res://", "/");
+ print_line("Moving to trash: " + path);
+ Error err = OS::get_singleton()->move_to_trash(path);
+ if (err != OK) {
+ EditorNode::get_singleton()->add_io_error(TTR("Cannot remove:") + "\n" + files_to_delete[i] + "\n");
+ }
}
- String path = OS::get_singleton()->get_resource_dir() + to_delete[i].replace_first("res://", "/");
- print_line("Moving to trash: " + path);
- Error err = OS::get_singleton()->move_to_trash(path);
- if (err != OK) {
- EditorNode::get_singleton()->add_io_error(TTR("Cannot remove:") + "\n" + to_delete[i] + "\n");
+ for (int i = 0; i < dirs_to_delete.size(); ++i) {
+ String path = OS::get_singleton()->get_resource_dir() + dirs_to_delete[i].replace_first("res://", "/");
+ print_line("Moving to trash: " + path);
+ Error err = OS::get_singleton()->move_to_trash(path);
+ if (err != OK) {
+ EditorNode::get_singleton()->add_io_error(TTR("Cannot remove:") + "\n" + dirs_to_delete[i] + "\n");
+ }
}
- }
- if (files_only) {
- //If we only deleted files we should only need to tell the file system about the files we touched.
- for (int i = 0; i < to_delete.size(); ++i) {
- EditorFileSystem::get_singleton()->update_file(to_delete[i]);
+ // if some dirs would be deleted, favorite dirs need to be updated
+ Vector<String> previous_favorite_dirs = EditorSettings::get_singleton()->get_favorite_dirs();
+ Vector<String> new_favorite_dirs;
+
+ for (int i = 0; i < previous_favorite_dirs.size(); ++i) {
+ if (dirs_to_delete.find(previous_favorite_dirs[i] + "/") < 0) {
+ new_favorite_dirs.push_back(previous_favorite_dirs[i]);
+ }
}
- } else {
+
+ if (new_favorite_dirs.size() < previous_favorite_dirs.size()) {
+ EditorSettings::get_singleton()->set_favorite_dirs(new_favorite_dirs);
+ }
+
EditorFileSystem::get_singleton()->scan_changes();
}
}
diff --git a/editor/dependency_editor.h b/editor/dependency_editor.h
index 16135c352b..4f268de748 100644
--- a/editor/dependency_editor.h
+++ b/editor/dependency_editor.h
@@ -102,7 +102,8 @@ class DependencyRemoveDialog : public ConfirmationDialog {
Tree *owners;
Map<String, String> all_remove_files;
- Vector<String> to_delete;
+ Vector<String> dirs_to_delete;
+ Vector<String> files_to_delete;
struct RemovedDependency {
String file;
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index 660eaafe8e..37a35b6ebf 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -588,8 +588,6 @@ bool EditorData::check_and_update_scene(int p_idx) {
bool must_reload = _find_updated_instances(edited_scene[p_idx].root, edited_scene[p_idx].root, checked_scenes);
- print_line("MUST RELOAD? " + itos(must_reload));
-
if (must_reload) {
Ref<PackedScene> pscene;
pscene.instance();
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index 4ae6e9a4f4..8a8a21543b 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -1027,6 +1027,7 @@ void EditorFileDialog::invalidate() {
if (is_visible_in_tree()) {
update_file_list();
+ _update_favorites();
invalidated = false;
} else {
invalidated = true;
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 2efc53781a..d8c85df83d 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -469,18 +469,18 @@ void EditorNode::_fs_changed() {
preset.unref();
}
if (preset.is_null()) {
- String err = "Unknown export preset: " + export_defer.preset;
- ERR_PRINTS(err);
+ String errstr = "Unknown export preset: " + export_defer.preset;
+ ERR_PRINTS(errstr);
} else {
Ref<EditorExportPlatform> platform = preset->get_platform();
if (platform.is_null()) {
- String err = "Preset \"" + export_defer.preset + "\" doesn't have a platform.";
- ERR_PRINTS(err);
+ String errstr = "Preset \"" + export_defer.preset + "\" doesn't have a platform.";
+ ERR_PRINTS(errstr);
} else {
// ensures export_project does not loop infinitely, because notifications may
// come during the export
export_defer.preset = "";
- Error err;
+ Error err = OK;
if (!preset->is_runnable() && (export_defer.path.ends_with(".pck") || export_defer.path.ends_with(".zip"))) {
if (export_defer.path.ends_with(".zip")) {
err = platform->export_zip(preset, export_defer.debug, export_defer.path);
@@ -4886,7 +4886,7 @@ EditorNode::EditorNode() {
if (!OS::get_singleton()->has_touchscreen_ui_hint() && Input::get_singleton()) {
//only if no touchscreen ui hint, set emulation
- id->set_emulate_touch(false); //just disable just in case
+ id->set_emulate_touch_from_mouse(false); //just disable just in case
}
id->set_custom_mouse_cursor(RES());
}
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index 9442bbc0e8..74ea46838b 100644
--- a/editor/find_in_files.cpp
+++ b/editor/find_in_files.cpp
@@ -154,9 +154,7 @@ void FindInFiles::_iterate() {
PoolStringArray sub_dirs;
_scan_dir(_root_prefix + _current_dir, sub_dirs);
- if (sub_dirs.size() != 0) {
- _folders_stack.push_back(sub_dirs);
- }
+ _folders_stack.push_back(sub_dirs);
} else {
// Go back one level
@@ -176,7 +174,7 @@ void FindInFiles::_iterate() {
String fpath = _files_to_scan[_files_to_scan.size() - 1];
pop_back(_files_to_scan);
- _scan_file(_root_prefix + fpath);
+ _scan_file(fpath);
} else {
print_line("Search complete");
@@ -202,8 +200,6 @@ void FindInFiles::_scan_dir(String path, PoolStringArray &out_folders) {
return;
}
- //print_line(String("Scanning ") + path);
-
dir->list_dir_begin();
for (int i = 0; i < 1000; ++i) {
@@ -222,7 +218,7 @@ void FindInFiles::_scan_dir(String path, PoolStringArray &out_folders) {
else {
String file_ext = file.get_extension();
if (_extension_filter.has(file_ext)) {
- _files_to_scan.push_back(file);
+ _files_to_scan.push_back(path.plus_file(file));
}
}
}
@@ -232,7 +228,6 @@ void FindInFiles::_scan_file(String fpath) {
FileAccess *f = FileAccess::open(fpath, FileAccess::READ);
if (f == NULL) {
- f->close();
print_line(String("Cannot open file ") + fpath);
return;
}
diff --git a/editor/icons/icon_paint_vertex.svg b/editor/icons/icon_paint_vertex.svg
new file mode 100644
index 0000000000..b53e005dae
--- /dev/null
+++ b/editor/icons/icon_paint_vertex.svg
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ version="1.1"
+ viewBox="0 0 16 16"
+ id="svg4"
+ sodipodi:docname="icon_paint_vertex.svg"
+ inkscape:version="0.92.2 (5c3e80d, 2017-08-06)">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="3066"
+ inkscape:window-height="1689"
+ id="namedview6"
+ showgrid="false"
+ inkscape:zoom="14.75"
+ inkscape:cx="8"
+ inkscape:cy="8"
+ inkscape:window-x="134"
+ inkscape:window-y="55"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg4" />
+ <ellipse
+ style="fill:#ffffff"
+ id="path12"
+ cx="8.3728809"
+ cy="8.1694918"
+ rx="6.6779661"
+ ry="6.0677967" />
+</svg>
diff --git a/editor/icons/icon_unpaint_vertex.svg b/editor/icons/icon_unpaint_vertex.svg
new file mode 100644
index 0000000000..a4633ee80b
--- /dev/null
+++ b/editor/icons/icon_unpaint_vertex.svg
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ version="1.1"
+ viewBox="0 0 16 16"
+ id="svg4"
+ sodipodi:docname="icon_unpaint_vertex.svg"
+ inkscape:version="0.92.2 (5c3e80d, 2017-08-06)">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="3066"
+ inkscape:window-height="1689"
+ id="namedview6"
+ showgrid="false"
+ inkscape:zoom="14.75"
+ inkscape:cx="8"
+ inkscape:cy="8"
+ inkscape:window-x="134"
+ inkscape:window-y="55"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg4" />
+ <ellipse
+ style="fill:#000000"
+ id="path12"
+ cx="8.3728809"
+ cy="8.1694918"
+ rx="6.6779661"
+ ry="6.0677967" />
+</svg>
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index 23cdde299c..05833704d1 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -639,7 +639,7 @@ const char *EditorAssetLibrary::support_key[SUPPORT_MAX] = {
void EditorAssetLibrary::_select_author(int p_id) {
- //opemn author window
+ // Open author window
}
void EditorAssetLibrary::_select_category(int p_id) {
@@ -659,16 +659,6 @@ void EditorAssetLibrary::_select_category(int p_id) {
void EditorAssetLibrary::_select_asset(int p_id) {
_api_request("asset/" + itos(p_id), REQUESTING_ASSET);
-
- /*
- if (description) {
- memdelete(description);
- }
-
-
- description = memnew( EditorAssetLibraryItemDescription );
- add_child(description);
- description->popup_centered_minsize();*/
}
void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PoolByteArray &p_data, int p_queue_id) {
@@ -774,7 +764,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons
_image_update(p_code == HTTPClient::RESPONSE_NOT_MODIFIED, true, p_data, p_queue_id);
} else {
- WARN_PRINTS("Error getting PNG file for asset id " + itos(image_queue[p_queue_id].asset_id));
+ WARN_PRINTS("Error getting PNG file from URL: " + image_queue[p_queue_id].image_url);
Object *obj = ObjectDB::get_instance(image_queue[p_queue_id].target);
if (obj) {
obj->call("set_image", image_queue[p_queue_id].image_type, image_queue[p_queue_id].image_index, get_icon("ErrorSign", "EditorIcons"));
diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h
index 89b79d7cfb..69a65dd3dc 100644
--- a/editor/plugins/asset_library_editor_plugin.h
+++ b/editor/plugins/asset_library_editor_plugin.h
@@ -241,7 +241,6 @@ class EditorAssetLibrary : public PanelContainer {
bool active;
int queue_id;
- int asset_id;
ImageType image_type;
int image_index;
String image_url;
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 027d4975c0..ff38e12250 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -457,7 +457,7 @@ Rect2 CanvasItemEditor::_get_encompassing_rect(const Node *p_node) {
return rect;
}
-void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, int limit, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
+void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, int p_limit, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
if (!p_node)
return;
if (Object::cast_to<Viewport>(p_node))
@@ -466,37 +466,73 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no
const real_t grab_distance = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8);
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
- Node *scene = editor->get_edited_scene();
- if (!(p_node != scene && p_node->get_owner() != scene && (!scene->is_editable_instance(p_node) || p_node->has_meta("_edit_lock_")))) {
+ bool locked = p_node->has_meta("_edit_lock_") && p_node->get_meta("_edit_lock_");
+
+ if (!locked) {
for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
if (canvas_item && !canvas_item->is_set_as_toplevel()) {
- _find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, limit, p_parent_xform * canvas_item->get_transform(), p_canvas_xform);
+ _find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, p_limit, p_parent_xform * canvas_item->get_transform(), p_canvas_xform);
} else {
CanvasLayer *cl = Object::cast_to<CanvasLayer>(p_node);
- _find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, limit, Transform2D(), cl ? cl->get_transform() : p_canvas_xform);
+ _find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, p_limit, Transform2D(), cl ? cl->get_transform() : p_canvas_xform);
}
- if (limit != 0 && r_items.size() >= limit)
+ if (p_limit != 0 && r_items.size() >= p_limit)
return;
}
- }
- if (canvas_item && canvas_item->is_visible_in_tree() && (canvas_item->get_owner() != editor->get_edited_scene() || !canvas_item->has_meta("_edit_lock_"))) {
- Transform2D xform = (p_parent_xform * p_canvas_xform * canvas_item->get_transform()).affine_inverse();
- const real_t local_grab_distance = xform.basis_xform(Vector2(grab_distance, 0)).length() / zoom;
- if (canvas_item->_edit_is_selected_on_click(xform.xform(p_pos), local_grab_distance)) {
- Node2D *node = Object::cast_to<Node2D>(canvas_item);
-
- _SelectResult res;
- res.item = canvas_item;
- res.z_index = node ? node->get_z_index() : 0;
- res.has_z = node;
- r_items.push_back(res);
+ if (canvas_item && canvas_item->is_visible_in_tree()) {
+ Transform2D xform = (p_parent_xform * p_canvas_xform * canvas_item->get_transform()).affine_inverse();
+ const real_t local_grab_distance = xform.basis_xform(Vector2(grab_distance, 0)).length();
+ if (canvas_item->_edit_is_selected_on_click(xform.xform(p_pos), local_grab_distance)) {
+ Node2D *node = Object::cast_to<Node2D>(canvas_item);
+
+ _SelectResult res;
+ res.item = canvas_item;
+ res.z_index = node ? node->get_z_index() : 0;
+ res.has_z = node;
+ r_items.push_back(res);
+ }
}
}
return;
}
+void CanvasItemEditor::_get_canvas_items_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items, int p_limit) {
+
+ Node *scene = editor->get_edited_scene();
+
+ _find_canvas_items_at_pos(p_pos, scene, r_items, p_limit);
+
+ //Remove invalid results
+ for (int i = 0; i < r_items.size(); i++) {
+ Node *node = r_items[i].item;
+
+ // Make sure the selected node is in the current scene
+ while (node && node != scene && node->get_owner() != scene) {
+ node = node->get_parent();
+ };
+
+ // Replace the node by the group if grouped
+ CanvasItem *canvas_item = Object::cast_to<CanvasItem>(node);
+ while (node && node != scene) {
+ CanvasItem *canvas_item_tmp = Object::cast_to<CanvasItem>(node);
+ if (canvas_item_tmp && node->has_meta("_edit_group_")) {
+ canvas_item = canvas_item_tmp;
+ }
+ node = node->get_parent();
+ }
+
+ //Remove the item if invalid
+ if (!canvas_item || (canvas_item != scene && canvas_item->get_owner() != scene && !scene->is_editable_instance(canvas_item->get_owner()))) {
+ r_items.remove(i);
+ i--;
+ } else {
+ r_items[i].item = canvas_item;
+ }
+ }
+}
+
void CanvasItemEditor::_find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_node, List<CanvasItem *> *r_items, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
if (!p_node)
return;
@@ -628,7 +664,7 @@ void CanvasItemEditor::_save_canvas_item_state(List<CanvasItem *> p_canvas_items
if (bone && bone->has_meta("_edit_bone_")) {
// Check if we have an IK chain
List<Node2D *> bone_ik_list;
- bool ik_found;
+ bool ik_found = false;
bone = Object::cast_to<Node2D>(bone->get_parent());
while (bone) {
bone_ik_list.push_back(bone);
@@ -1704,17 +1740,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
// Popup the selection menu list
Point2 click = transform.affine_inverse().xform(b->get_position());
- Node *scene = editor->get_edited_scene();
-
- _find_canvas_items_at_pos(click, scene, selection_results);
- for (int i = 0; i < selection_results.size(); i++) {
- CanvasItem *item = selection_results[i].item;
- if (item != scene && item->get_owner() != scene && !scene->is_editable_instance(item->get_owner())) {
- //invalid result
- selection_results.remove(i);
- i--;
- }
- }
+ _get_canvas_items_at_pos(click, selection_results);
if (selection_results.size() == 1) {
CanvasItem *item = selection_results[0].item;
@@ -1764,7 +1790,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
// Find the item to select
CanvasItem *canvas_item = NULL;
Vector<_SelectResult> selection;
- _find_canvas_items_at_pos(click, scene, selection, editor_selection->get_selection().empty() ? 1 : 0);
+ _get_canvas_items_at_pos(click, selection, editor_selection->get_selection().empty() ? 1 : 0);
for (int i = 0; i < selection.size(); i++) {
if (editor_selection->is_selected(selection[i].item)) {
@@ -1783,23 +1809,6 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
if (!selection.empty())
canvas_item = selection[0].item;
- // Check if the canvas item is in a group, and select the group instead if it is the case
- Node *node = canvas_item;
- while (node && node != scene) {
- CanvasItem *canvas_item_tmp = Object::cast_to<CanvasItem>(node);
- if (canvas_item_tmp && node->has_meta("_edit_group_")) {
- canvas_item = canvas_item_tmp;
- }
- node = node->get_parent();
- }
-
- // Make sure the selected node is in the current scene
- node = canvas_item;
- while (node && ((node != scene && node->get_owner() != scene) || !node->is_class("CanvasItem"))) {
- node = node->get_parent();
- };
- canvas_item = Object::cast_to<CanvasItem>(node);
-
if (!canvas_item) {
// Start a box selection
if (!b->get_shift()) {
@@ -1884,11 +1893,10 @@ bool CanvasItemEditor::_gui_input_hover(const Ref<InputEvent> &p_event) {
if (m.is_valid()) {
if (drag_type == DRAG_NONE && tool == TOOL_SELECT) {
Point2 click = transform.affine_inverse().xform(m->get_position());
- Node *scene = editor->get_edited_scene();
//Checks if the hovered items changed, update the viewport if so
Vector<_SelectResult> hovering_results_tmp;
- _find_canvas_items_at_pos(click, scene, hovering_results_tmp);
+ _get_canvas_items_at_pos(click, hovering_results_tmp);
hovering_results_tmp.sort();
bool changed = false;
if (hovering_results.size() == hovering_results_tmp.size()) {
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 6a1d313a7e..373a4b799e 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -337,7 +337,9 @@ class CanvasItemEditor : public VBoxContainer {
Ref<ShortCut> multiply_grid_step_shortcut;
Ref<ShortCut> divide_grid_step_shortcut;
- void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, int limit = 0, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
+ void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, int p_limit = 0, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
+ void _get_canvas_items_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items, int p_limit = 0);
+
void _find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_node, List<CanvasItem *> *r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
bool _select_click_on_item(CanvasItem *item, Point2 p_click_pos, bool p_append);
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 3a169bd780..2815fa6406 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -35,7 +35,7 @@
#include "os/file_access.h"
#include "os/input.h"
#include "os/keyboard.h"
-
+#include "scene/2d/skeleton_2d.h"
Node2D *Polygon2DEditor::_get_node() const {
return node;
@@ -66,6 +66,8 @@ void Polygon2DEditor::_notification(int p_what) {
uv_button[UV_MODE_SCALE]->set_icon(get_icon("ToolScale", "EditorIcons"));
uv_button[UV_MODE_ADD_SPLIT]->set_icon(get_icon("AddSplit", "EditorIcons"));
uv_button[UV_MODE_REMOVE_SPLIT]->set_icon(get_icon("DeleteSplit", "EditorIcons"));
+ uv_button[UV_MODE_PAINT_WEIGHT]->set_icon(get_icon("PaintVertex", "EditorIcons"));
+ uv_button[UV_MODE_CLEAR_WEIGHT]->set_icon(get_icon("UnpaintVertex", "EditorIcons"));
b_snap_grid->set_icon(get_icon("Grid", "EditorIcons"));
b_snap_enable->set_icon(get_icon("SnapGrid", "EditorIcons"));
@@ -78,31 +80,167 @@ void Polygon2DEditor::_notification(int p_what) {
}
}
+void Polygon2DEditor::_sync_bones() {
+
+ print_line("syncinc");
+ if (!node->has_node(node->get_skeleton())) {
+ error->set_text(TTR("The skeleton property of the Polygon2D does not point to a Skeleton2D node"));
+ error->popup_centered_minsize();
+ return;
+ }
+
+ Node *sn = node->get_node(node->get_skeleton());
+ Skeleton2D *skeleton = Object::cast_to<Skeleton2D>(sn);
+
+ if (!skeleton) {
+ error->set_text(TTR("The skeleton property of the Polygon2D does not point to a Skeleton2D node"));
+ error->popup_centered_minsize();
+ return;
+ }
+
+ Array prev_bones = node->call("_get_bones");
+ node->clear_bones();
+
+ print_line("bones in skeleton: " + itos(skeleton->get_bone_count()));
+
+ for (int i = 0; i < skeleton->get_bone_count(); i++) {
+ NodePath path = skeleton->get_path_to(skeleton->get_bone(i));
+ PoolVector<float> weights;
+ int wc = node->get_polygon().size();
+
+ for (int j = 0; j < prev_bones.size(); j += 2) {
+ NodePath pvp = prev_bones[j];
+ PoolVector<float> pv = prev_bones[j + 1];
+ if (pvp == path && pv.size() == wc) {
+ weights = pv;
+ }
+ }
+
+ if (weights.size() == 0) { //create them
+ weights.resize(node->get_polygon().size());
+ PoolVector<float>::Write w = weights.write();
+ for (int j = 0; j < wc; j++) {
+ w[j] = 0.0;
+ }
+ }
+
+ node->add_bone(path, weights);
+ }
+ Array new_bones = node->call("_get_bones");
+
+ undo_redo->create_action(TTR("Sync bones"));
+ undo_redo->add_do_method(node, "_set_bones", new_bones);
+ undo_redo->add_undo_method(node, "_set_bones", prev_bones);
+ undo_redo->add_do_method(uv_edit_draw, "update");
+ undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(this, "_update_bone_list");
+ undo_redo->add_undo_method(this, "_update_bone_list");
+ undo_redo->commit_action();
+}
+
+void Polygon2DEditor::_update_bone_list() {
+
+ NodePath selected;
+ while (bone_scroll_vb->get_child_count()) {
+ CheckBox *cb = Object::cast_to<CheckBox>(bone_scroll_vb->get_child(0));
+ if (cb && cb->is_pressed()) {
+ selected = cb->get_meta("bone_path");
+ }
+ memdelete(bone_scroll_vb->get_child(0));
+ }
+
+ Ref<ButtonGroup> bg;
+ bg.instance();
+ for (int i = 0; i < node->get_bone_count(); i++) {
+ CheckBox *cb = memnew(CheckBox);
+ NodePath np = node->get_bone_path(i);
+ String name;
+ if (np.get_name_count()) {
+ name = np.get_name(np.get_name_count() - 1);
+ }
+ if (name == String()) {
+ name = "Bone " + itos(i);
+ }
+ cb->set_text(name);
+ cb->set_button_group(bg);
+ cb->set_meta("bone_path", np);
+ bone_scroll_vb->add_child(cb);
+
+ if (np == selected)
+ cb->set_pressed(true);
+
+ cb->connect("pressed", this, "_bone_paint_selected", varray(i));
+ }
+
+ uv_edit_draw->update();
+}
+
+void Polygon2DEditor::_bone_paint_selected(int p_index) {
+ uv_edit_draw->update();
+}
+
void Polygon2DEditor::_uv_edit_mode_select(int p_mode) {
- if (p_mode == 0) {
+ if (p_mode == 0) { //uv
uv_button[UV_MODE_CREATE]->hide();
for (int i = UV_MODE_MOVE; i <= UV_MODE_SCALE; i++) {
uv_button[i]->show();
}
uv_button[UV_MODE_ADD_SPLIT]->hide();
uv_button[UV_MODE_REMOVE_SPLIT]->hide();
+ uv_button[UV_MODE_PAINT_WEIGHT]->hide();
+ uv_button[UV_MODE_CLEAR_WEIGHT]->hide();
_uv_mode(UV_MODE_EDIT_POINT);
- } else if (p_mode == 1) {
+ bone_scroll_main_vb->hide();
+ bone_paint_strength->hide();
+ bone_paint_radius->hide();
+ bone_paint_radius_label->hide();
+
+ } else if (p_mode == 1) { //poly
for (int i = 0; i <= UV_MODE_SCALE; i++) {
uv_button[i]->show();
}
uv_button[UV_MODE_ADD_SPLIT]->hide();
uv_button[UV_MODE_REMOVE_SPLIT]->hide();
+ uv_button[UV_MODE_PAINT_WEIGHT]->hide();
+ uv_button[UV_MODE_CLEAR_WEIGHT]->hide();
_uv_mode(UV_MODE_EDIT_POINT);
- } else {
+
+ bone_scroll_main_vb->hide();
+ bone_paint_strength->hide();
+ bone_paint_radius->hide();
+ bone_paint_radius_label->hide();
+
+ } else if (p_mode == 2) { //splits
for (int i = 0; i <= UV_MODE_SCALE; i++) {
uv_button[i]->hide();
}
uv_button[UV_MODE_ADD_SPLIT]->show();
uv_button[UV_MODE_REMOVE_SPLIT]->show();
+ uv_button[UV_MODE_PAINT_WEIGHT]->hide();
+ uv_button[UV_MODE_CLEAR_WEIGHT]->hide();
_uv_mode(UV_MODE_ADD_SPLIT);
+
+ bone_scroll_main_vb->hide();
+ bone_paint_strength->hide();
+ bone_paint_radius->hide();
+ bone_paint_radius_label->hide();
+
+ } else if (p_mode == 3) { //bones´
+ for (int i = 0; i <= UV_MODE_REMOVE_SPLIT; i++) {
+ uv_button[i]->hide();
+ }
+ uv_button[UV_MODE_PAINT_WEIGHT]->show();
+ uv_button[UV_MODE_CLEAR_WEIGHT]->show();
+ _uv_mode(UV_MODE_PAINT_WEIGHT);
+
+ bone_scroll_main_vb->show();
+ bone_paint_strength->show();
+ bone_paint_radius->show();
+ bone_paint_radius_label->show();
+ _update_bone_list();
+ bone_paint_pos = Vector2(-100000, -100000); //send brush away when switching
}
uv_edit_draw->update();
@@ -261,6 +399,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
uv_create = true;
uv_create_uv_prev = node->get_uv();
uv_create_poly_prev = node->get_polygon();
+ uv_create_bones_prev = node->call("_get_bones");
splits_prev = node->get_splits();
node->set_polygon(uv_prev);
node->set_uv(uv_prev);
@@ -274,6 +413,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
undo_redo->add_undo_method(node, "set_uv", uv_prev);
undo_redo->add_do_method(node, "set_polygon", node->get_polygon());
undo_redo->add_undo_method(node, "set_polygon", uv_prev);
+ undo_redo->add_do_method(node, "clear_bones");
+ undo_redo->add_undo_method(node, "_set_bones", node->call("_get_bones"));
undo_redo->add_do_method(uv_edit_draw, "update");
undo_redo->add_undo_method(uv_edit_draw, "update");
undo_redo->commit_action();
@@ -419,6 +560,25 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
}
}
+ if (uv_move_current == UV_MODE_PAINT_WEIGHT || uv_move_current == UV_MODE_CLEAR_WEIGHT) {
+
+ int bone_selected = -1;
+ for (int i = 0; i < bone_scroll_vb->get_child_count(); i++) {
+ CheckBox *c = Object::cast_to<CheckBox>(bone_scroll_vb->get_child(i));
+ if (c && c->is_pressed()) {
+ bone_selected = i;
+ break;
+ }
+ }
+
+ if (bone_selected != -1 && node->get_bone_weights(bone_selected).size() == uv_prev.size()) {
+
+ prev_weights = node->get_bone_weights(bone_selected);
+ bone_painting = true;
+ bone_painting_bone = bone_selected;
+ }
+ }
+
} else if (uv_drag && !uv_create) {
undo_redo->create_action(TTR("Transform UV Map"));
@@ -435,6 +595,15 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
undo_redo->commit_action();
uv_drag = false;
+ } else if (bone_painting) {
+
+ undo_redo->create_action(TTR("Paint bone weights"));
+ undo_redo->add_do_method(node, "set_bone_weights", bone_painting_bone, node->get_bone_weights(bone_painting_bone));
+ undo_redo->add_undo_method(node, "set_bone_weights", bone_painting_bone, prev_weights);
+ undo_redo->add_do_method(uv_edit_draw, "update");
+ undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->commit_action();
+ bone_painting = false;
}
} else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) {
@@ -445,6 +614,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
uv_create = false;
node->set_uv(uv_create_uv_prev);
node->set_polygon(uv_create_poly_prev);
+ node->call("_set_bones", uv_create_bones_prev);
node->set_splits(splits_prev);
uv_edit_draw->update();
} else if (uv_drag) {
@@ -459,6 +629,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
} else if (split_create) {
split_create = false;
uv_edit_draw->update();
+ } else if (bone_painting) {
+ node->set_bone_weights(bone_painting_bone, prev_weights);
}
} else if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed()) {
@@ -569,10 +741,40 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
}
} break;
}
+
+ if (bone_painting) {
+ bone_paint_pos = Vector2(mm->get_position().x, mm->get_position().y);
+ PoolVector<float> painted_weights = node->get_bone_weights(bone_painting_bone);
+
+ {
+ int pc = painted_weights.size();
+ float amount = bone_paint_strength->get_value();
+ float radius = bone_paint_radius->get_value() * EDSCALE;
+
+ if (uv_mode == UV_MODE_CLEAR_WEIGHT) {
+ amount = -amount;
+ }
+
+ PoolVector<float>::Write w = painted_weights.write();
+ PoolVector<float>::Read r = prev_weights.read();
+ PoolVector<Vector2>::Read rv = uv_prev.read();
+
+ for (int i = 0; i < pc; i++) {
+ if (mtx.xform(rv[i]).distance_to(bone_paint_pos) < radius) {
+ w[i] = CLAMP(r[i] + amount, 0, 1);
+ }
+ }
+ }
+
+ node->set_bone_weights(bone_painting_bone, painted_weights);
+ }
uv_edit_draw->update();
} else if (split_create) {
uv_create_to = mtx.affine_inverse().xform(Vector2(mm->get_position().x, mm->get_position().y));
uv_edit_draw->update();
+ } else if (uv_mode == UV_MODE_PAINT_WEIGHT || uv_mode == UV_MODE_CLEAR_WEIGHT) {
+ bone_paint_pos = Vector2(mm->get_position().x, mm->get_position().y);
+ uv_edit_draw->update();
}
}
@@ -649,6 +851,24 @@ void Polygon2DEditor::_uv_draw() {
uvs = node->get_polygon();
}
+ PoolVector<float>::Read weight_r;
+
+ if (uv_edit_mode[3]->is_pressed()) {
+ int bone_selected = -1;
+ for (int i = 0; i < bone_scroll_vb->get_child_count(); i++) {
+ CheckBox *c = Object::cast_to<CheckBox>(bone_scroll_vb->get_child(i));
+ if (c && c->is_pressed()) {
+ bone_selected = i;
+ break;
+ }
+ }
+
+ if (bone_selected != -1 && node->get_bone_weights(bone_selected).size() == uvs.size()) {
+
+ weight_r = node->get_bone_weights(bone_selected).read();
+ }
+ }
+
Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons");
Rect2 rect(Point2(), mtx.basis_xform(base_tex->get_size()));
@@ -662,7 +882,14 @@ void Polygon2DEditor::_uv_draw() {
next_point = uv_create_to;
}
uv_edit_draw->draw_line(mtx.xform(uvs[i]), mtx.xform(next_point), Color(0.9, 0.5, 0.5), 2);
- uv_edit_draw->draw_texture(handle, mtx.xform(uvs[i]) - handle->get_size() * 0.5);
+ if (weight_r.ptr()) {
+
+ Vector2 draw_pos = mtx.xform(uvs[i]);
+ float weight = weight_r[i];
+ uv_edit_draw->draw_rect(Rect2(draw_pos - Vector2(2, 2) * EDSCALE, Vector2(5, 5) * EDSCALE), Color(weight, weight, weight, 1.0));
+ } else {
+ uv_edit_draw->draw_texture(handle, mtx.xform(uvs[i]) - handle->get_size() * 0.5);
+ }
rect.expand_to(mtx.basis_xform(uvs[i]));
}
@@ -682,6 +909,11 @@ void Polygon2DEditor::_uv_draw() {
uv_edit_draw->draw_line(mtx.xform(uvs[idx_from]), mtx.xform(uvs[idx_to]), Color(0.9, 0.5, 0.5), 2);
}
+ if (uv_mode == UV_MODE_PAINT_WEIGHT || uv_mode == UV_MODE_CLEAR_WEIGHT) {
+
+ uv_edit_draw->draw_circle(bone_paint_pos, bone_paint_radius->get_value() * EDSCALE, Color(1, 1, 1, 0.1));
+ }
+
rect = rect.grow(200);
updating_uv_scroll = true;
uv_hscroll->set_min(rect.position.x);
@@ -711,6 +943,10 @@ void Polygon2DEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_snap_step_x"), &Polygon2DEditor::_set_snap_step_x);
ClassDB::bind_method(D_METHOD("_set_snap_step_y"), &Polygon2DEditor::_set_snap_step_y);
ClassDB::bind_method(D_METHOD("_uv_edit_mode_select"), &Polygon2DEditor::_uv_edit_mode_select);
+ ClassDB::bind_method(D_METHOD("_sync_bones"), &Polygon2DEditor::_sync_bones);
+ ClassDB::bind_method(D_METHOD("_update_bone_list"), &Polygon2DEditor::_update_bone_list);
+
+ ClassDB::bind_method(D_METHOD("_bone_paint_selected"), &Polygon2DEditor::_bone_paint_selected);
}
Vector2 Polygon2DEditor::snap_point(Vector2 p_target) const {
@@ -755,19 +991,25 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) :
uv_edit_mode[2] = memnew(ToolButton);
uv_mode_hb->add_child(uv_edit_mode[2]);
uv_edit_mode[2]->set_toggle_mode(true);
+ uv_edit_mode[3] = memnew(ToolButton);
+ uv_mode_hb->add_child(uv_edit_mode[3]);
+ uv_edit_mode[3]->set_toggle_mode(true);
uv_edit_mode[0]->set_text(TTR("UV"));
uv_edit_mode[0]->set_pressed(true);
uv_edit_mode[1]->set_text(TTR("Poly"));
uv_edit_mode[2]->set_text(TTR("Splits"));
+ uv_edit_mode[3]->set_text(TTR("Bones"));
uv_edit_mode[0]->set_button_group(uv_edit_group);
uv_edit_mode[1]->set_button_group(uv_edit_group);
uv_edit_mode[2]->set_button_group(uv_edit_group);
+ uv_edit_mode[3]->set_button_group(uv_edit_group);
uv_edit_mode[0]->connect("pressed", this, "_uv_edit_mode_select", varray(0));
uv_edit_mode[1]->connect("pressed", this, "_uv_edit_mode_select", varray(1));
uv_edit_mode[2]->connect("pressed", this, "_uv_edit_mode_select", varray(2));
+ uv_edit_mode[3]->connect("pressed", this, "_uv_edit_mode_select", varray(3));
uv_mode_hb->add_child(memnew(VSeparator));
@@ -788,11 +1030,38 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) :
uv_button[4]->set_tooltip(TTR("Scale Polygon"));
uv_button[5]->set_tooltip(TTR("Connect two points to make a split"));
uv_button[6]->set_tooltip(TTR("Select a split to erase it"));
+ uv_button[7]->set_tooltip(TTR("Paint weights with specified intensity"));
+ uv_button[8]->set_tooltip(TTR("UnPaint weights with specified intensity"));
uv_button[0]->hide();
uv_button[5]->hide();
uv_button[6]->hide();
+ uv_button[7]->hide();
+ uv_button[8]->hide();
uv_button[1]->set_pressed(true);
+
+ bone_paint_strength = memnew(HSlider);
+ uv_mode_hb->add_child(bone_paint_strength);
+ bone_paint_strength->set_custom_minimum_size(Size2(75 * EDSCALE, 0));
+ bone_paint_strength->set_v_size_flags(SIZE_SHRINK_CENTER);
+ bone_paint_strength->set_min(0);
+ bone_paint_strength->set_max(1);
+ bone_paint_strength->set_step(0.01);
+ bone_paint_strength->set_value(0.5);
+
+ bone_paint_radius_label = memnew(Label(" " + TTR("Radius:") + " "));
+ uv_mode_hb->add_child(bone_paint_radius_label);
+ bone_paint_radius = memnew(SpinBox);
+ uv_mode_hb->add_child(bone_paint_radius);
+
+ bone_paint_strength->hide();
+ bone_paint_radius->hide();
+ bone_paint_radius_label->hide();
+ bone_paint_radius->set_min(1);
+ bone_paint_radius->set_max(100);
+ bone_paint_radius->set_step(1);
+ bone_paint_radius->set_value(32);
+
HBoxContainer *uv_main_hb = memnew(HBoxContainer);
uv_main_vb->add_child(uv_main_hb);
uv_edit_draw = memnew(Control);
@@ -878,6 +1147,8 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) :
uv_zoom->set_max(4);
uv_zoom->set_value(1);
uv_zoom->set_step(0.01);
+ uv_zoom->set_v_size_flags(SIZE_SHRINK_CENTER);
+
uv_mode_hb->add_child(uv_zoom);
uv_zoom->set_custom_minimum_size(Size2(200, 0));
uv_zoom_value = memnew(SpinBox);
@@ -893,6 +1164,20 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) :
uv_main_vb->add_child(uv_hscroll);
uv_hscroll->connect("value_changed", this, "_uv_scroll_changed");
+ bone_scroll_main_vb = memnew(VBoxContainer);
+ bone_scroll_main_vb->hide();
+ sync_bones = memnew(Button(TTR("Sync Bones")));
+ bone_scroll_main_vb->add_child(sync_bones);
+ uv_main_hb->add_child(bone_scroll_main_vb);
+ bone_scroll = memnew(ScrollContainer);
+ bone_scroll->set_v_scroll(true);
+ bone_scroll->set_h_scroll(false);
+ bone_scroll_main_vb->add_child(bone_scroll);
+ bone_scroll->set_v_size_flags(SIZE_EXPAND_FILL);
+ bone_scroll_vb = memnew(VBoxContainer);
+ bone_scroll->add_child(bone_scroll_vb);
+ sync_bones->connect("pressed", this, "_sync_bones");
+
uv_edit_draw->connect("draw", this, "_uv_draw");
uv_edit_draw->connect("gui_input", this, "_uv_input");
uv_draw_zoom = 1.0;
@@ -901,6 +1186,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) :
uv_create = false;
updating_uv_scroll = false;
split_create = false;
+ bone_painting = false;
error = memnew(AcceptDialog);
add_child(error);
diff --git a/editor/plugins/polygon_2d_editor_plugin.h b/editor/plugins/polygon_2d_editor_plugin.h
index 8631ffb9a7..b18ead4d98 100644
--- a/editor/plugins/polygon_2d_editor_plugin.h
+++ b/editor/plugins/polygon_2d_editor_plugin.h
@@ -32,7 +32,7 @@
#define POLYGON_2D_EDITOR_PLUGIN_H
#include "editor/plugins/abstract_polygon_2d_editor.h"
-
+#include "scene/gui/scroll_container.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
@@ -57,10 +57,12 @@ class Polygon2DEditor : public AbstractPolygon2DEditor {
UV_MODE_SCALE,
UV_MODE_ADD_SPLIT,
UV_MODE_REMOVE_SPLIT,
+ UV_MODE_PAINT_WEIGHT,
+ UV_MODE_CLEAR_WEIGHT,
UV_MODE_MAX
};
- ToolButton *uv_edit_mode[3];
+ ToolButton *uv_edit_mode[4];
Ref<ButtonGroup> uv_edit_group;
Polygon2D *node;
@@ -78,11 +80,27 @@ class Polygon2DEditor : public AbstractPolygon2DEditor {
MenuButton *uv_menu;
TextureRect *uv_icon_zoom;
+ VBoxContainer *bone_scroll_main_vb;
+ ScrollContainer *bone_scroll;
+ VBoxContainer *bone_scroll_vb;
+ Button *sync_bones;
+ HSlider *bone_paint_strength;
+ SpinBox *bone_paint_radius;
+ Label *bone_paint_radius_label;
+ bool bone_painting;
+ int bone_painting_bone;
+ PoolVector<float> prev_weights;
+ Vector2 bone_paint_pos;
+
+ void _sync_bones();
+ void _update_bone_list();
+
Vector2 uv_draw_ofs;
float uv_draw_zoom;
PoolVector<Vector2> uv_prev;
PoolVector<Vector2> uv_create_uv_prev;
PoolVector<Vector2> uv_create_poly_prev;
+ Array uv_create_bones_prev;
PoolVector<int> splits_prev;
Vector2 uv_create_to;
@@ -118,6 +136,7 @@ class Polygon2DEditor : public AbstractPolygon2DEditor {
void _set_snap_step_y(float p_val);
void _uv_edit_mode_select(int p_mode);
+ void _bone_paint_selected(int p_index);
protected:
virtual Node2D *_get_node() const;
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 71a3c90795..a9afc7a670 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -45,6 +45,12 @@ void SpriteFramesEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
load->set_icon(get_icon("Load", "EditorIcons"));
+ copy->set_icon(get_icon("ActionCopy", "EditorIcons"));
+ paste->set_icon(get_icon("ActionPaste", "EditorIcons"));
+ empty->set_icon(get_icon("InsertBefore", "EditorIcons"));
+ empty2->set_icon(get_icon("InsertAfter", "EditorIcons"));
+ move_up->set_icon(get_icon("MoveLeft", "EditorIcons"));
+ move_down->set_icon(get_icon("MoveRight", "EditorIcons"));
_delete->set_icon(get_icon("Remove", "EditorIcons"));
new_anim->set_icon(get_icon("New", "EditorIcons"));
remove_anim->set_icon(get_icon("Remove", "EditorIcons"));
@@ -736,27 +742,35 @@ SpriteFramesEditor::SpriteFramesEditor() {
hbc->add_child(load);
copy = memnew(Button);
- copy->set_text(TTR("Copy"));
+ copy->set_flat(true);
+ copy->set_tooltip(TTR("Copy"));
hbc->add_child(copy);
paste = memnew(Button);
- paste->set_text(TTR("Paste"));
+ paste->set_flat(true);
+ paste->set_tooltip(TTR("Paste"));
hbc->add_child(paste);
empty = memnew(Button);
- empty->set_text(TTR("Insert Empty (Before)"));
+ empty->set_flat(true);
+ empty->set_tooltip(TTR("Insert Empty (Before)"));
hbc->add_child(empty);
empty2 = memnew(Button);
- empty2->set_text(TTR("Insert Empty (After)"));
+ empty2->set_flat(true);
+ empty2->set_tooltip(TTR("Insert Empty (After)"));
hbc->add_child(empty2);
+ hbc->add_spacer(false);
+
move_up = memnew(Button);
- move_up->set_text(TTR("Move (Before)"));
+ move_up->set_flat(true);
+ move_up->set_tooltip(TTR("Move (Before)"));
hbc->add_child(move_up);
move_down = memnew(Button);
- move_down->set_text(TTR("Move (After)"));
+ move_down->set_flat(true);
+ move_down->set_tooltip(TTR("Move (After)"));
hbc->add_child(move_down);
_delete = memnew(Button);
diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h
index 3257901c88..642870aec0 100644
--- a/editor/plugins/tile_map_editor_plugin.h
+++ b/editor/plugins/tile_map_editor_plugin.h
@@ -125,12 +125,11 @@ class TileMapEditor : public VBoxContainer {
bool yf;
bool tr;
- CellOp() {
- idx = -1;
- xf = false;
- yf = false;
- tr = false;
- }
+ CellOp() :
+ idx(TileMap::INVALID_CELL),
+ xf(false),
+ yf(false),
+ tr(false) {}
};
Map<Point2i, CellOp> paint_undo;
@@ -141,8 +140,12 @@ class TileMapEditor : public VBoxContainer {
bool flip_h;
bool flip_v;
bool transpose;
- int auto_x;
- int auto_y;
+
+ TileData() :
+ cell(TileMap::INVALID_CELL),
+ flip_h(false),
+ flip_v(false),
+ transpose(false) {}
};
List<TileData> copydata;
diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp
index 7c40eb5c45..385fa24ad8 100644
--- a/editor/plugins/tile_set_editor_plugin.cpp
+++ b/editor/plugins/tile_set_editor_plugin.cpp
@@ -806,7 +806,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
Vector2 coord((int)(mb->get_position().x / (spacing + size.x)), (int)(mb->get_position().y / (spacing + size.y)));
Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y));
pos = mb->get_position() - pos;
- uint16_t bit;
+ uint16_t bit = 0;
if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) {
if (pos.x < size.x / 2) {
if (pos.y < size.y / 2) {
@@ -869,7 +869,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
Vector2 coord((int)(mm->get_position().x / (spacing + size.x)), (int)(mm->get_position().y / (spacing + size.y)));
Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y));
pos = mm->get_position() - pos;
- uint16_t bit;
+ uint16_t bit = 0;
if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) {
if (pos.x < size.x / 2) {
if (pos.y < size.y / 2) {
@@ -1147,7 +1147,7 @@ void TileSetEditor::_on_tool_clicked(int p_tool) {
case EDITMODE_COLLISION: {
if (!edited_collision_shape.is_null()) {
Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(get_current_tile());
- int index;
+ int index = -1;
for (int i = 0; i < sd.size(); i++) {
if (sd[i].shape == edited_collision_shape) {
index = i;
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index e38347a653..64d278c0c5 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -644,11 +644,12 @@ void SceneTreeEditor::_renamed() {
ERR_FAIL_COND(!n);
String new_name = which->get_text(0);
- if (new_name.find(".") != -1 || new_name.find("/") != -1) {
+ if (!Node::_validate_node_name(new_name)) {
- error->set_text(TTR("Invalid node name, the following characters are not allowed:") + "\n \".\", \"/\"");
+ error->set_text(TTR("Invalid node name, the following characters are not allowed:") + "\n" + Node::invalid_character);
error->popup_centered_minsize();
- new_name = n->get_name();
+
+ which->set_text(0, new_name);
}
if (new_name == n->get_name())
diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp
index e9529eb1c0..50519e2c6e 100644
--- a/editor/script_editor_debugger.cpp
+++ b/editor/script_editor_debugger.cpp
@@ -710,25 +710,6 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
error_list->set_item_metadata(error_list->get_item_count() - 1, stack);
error_count++;
- /*
- int count = p_data[1];
-
- Array cstack;
-
- OutputError oe = errors.front()->get();
-
- packet_peer_stream->put_var(oe.hr);
- packet_peer_stream->put_var(oe.min);
- packet_peer_stream->put_var(oe.sec);
- packet_peer_stream->put_var(oe.msec);
- packet_peer_stream->put_var(oe.source_func);
- packet_peer_stream->put_var(oe.source_file);
- packet_peer_stream->put_var(oe.source_line);
- packet_peer_stream->put_var(oe.error);
- packet_peer_stream->put_var(oe.error_descr);
- packet_peer_stream->put_var(oe.warning);
- packet_peer_stream->put_var(oe.callstack);
- */
} else if (p_msg == "profile_sig") {
//cache a signature
@@ -755,6 +736,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
EditorProfiler::Metric::Category::Item item;
item.calls = 1;
item.line = 0;
+
item.name = "Physics Time";
item.total = metric.physics_time;
item.self = item.total;
@@ -792,8 +774,9 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
for (int i = 0; i < values.size(); i += 2) {
EditorProfiler::Metric::Category::Item item;
- item.name = values[i];
item.calls = 1;
+ item.line = 0;
+ item.name = values[i];
item.self = values[i + 1];
item.total = item.self;
item.signature = "categ::" + name + "::" + item.name;
diff --git a/main/input_default.cpp b/main/input_default.cpp
index 3c40be5082..29d30110e3 100644
--- a/main/input_default.cpp
+++ b/main/input_default.cpp
@@ -194,8 +194,6 @@ void InputDefault::joy_connection_changed(int p_idx, bool p_connected, String p_
Joypad js;
js.name = p_connected ? p_name : "";
js.uid = p_connected ? p_guid : "";
- js.mapping = -1;
- js.hat_current = 0;
if (p_connected) {
@@ -258,6 +256,11 @@ Vector3 InputDefault::get_gyroscope() const {
void InputDefault::parse_input_event(const Ref<InputEvent> &p_event) {
+ _parse_input_event_impl(p_event, false);
+}
+
+void InputDefault::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated) {
+
_THREAD_SAFE_METHOD_
Ref<InputEventKey> k = p_event;
@@ -281,25 +284,30 @@ void InputDefault::parse_input_event(const Ref<InputEvent> &p_event) {
mouse_button_mask &= ~(1 << (mb->get_button_index() - 1));
}
- if (main_loop && emulate_touch && mb->get_button_index() == 1) {
+ Point2 pos = mb->get_global_position();
+ if (mouse_pos != pos) {
+ set_mouse_position(pos);
+ }
+
+ if (main_loop && emulate_touch_from_mouse && !p_is_emulated && mb->get_button_index() == 1) {
Ref<InputEventScreenTouch> touch_event;
touch_event.instance();
touch_event->set_pressed(mb->is_pressed());
touch_event->set_position(mb->get_position());
main_loop->input_event(touch_event);
}
-
- Point2 pos = mb->get_global_position();
- if (mouse_pos != pos) {
- set_mouse_position(pos);
- }
}
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
- if (main_loop && emulate_touch && mm->get_button_mask() & 1) {
+ Point2 pos = mm->get_global_position();
+ if (mouse_pos != pos) {
+ set_mouse_position(pos);
+ }
+
+ if (main_loop && emulate_touch_from_mouse && !p_is_emulated && mm->get_button_mask() & 1) {
Ref<InputEventScreenDrag> drag_event;
drag_event.instance();
@@ -311,6 +319,58 @@ void InputDefault::parse_input_event(const Ref<InputEvent> &p_event) {
}
}
+ if (emulate_mouse_from_touch) {
+
+ Ref<InputEventScreenTouch> st = p_event;
+
+ if (st.is_valid()) {
+ bool translate = false;
+ if (st->is_pressed()) {
+ if (mouse_from_touch_index == -1) {
+ translate = true;
+ mouse_from_touch_index = st->get_index();
+ }
+ } else {
+ if (st->get_index() == mouse_from_touch_index) {
+ translate = true;
+ mouse_from_touch_index = -1;
+ }
+ }
+
+ if (translate) {
+ Ref<InputEventMouseButton> button_event;
+ button_event.instance();
+
+ button_event->set_position(st->get_position());
+ button_event->set_global_position(st->get_position());
+ button_event->set_pressed(st->is_pressed());
+ button_event->set_button_index(BUTTON_LEFT);
+ if (st->is_pressed()) {
+ button_event->set_button_mask(mouse_button_mask | (1 << BUTTON_LEFT - 1));
+ } else {
+ button_event->set_button_mask(mouse_button_mask & ~(1 << BUTTON_LEFT - 1));
+ }
+
+ _parse_input_event_impl(button_event, true);
+ }
+ }
+
+ Ref<InputEventScreenDrag> sd = p_event;
+
+ if (sd.is_valid() && sd->get_index() == mouse_from_touch_index) {
+ Ref<InputEventMouseMotion> motion_event;
+ motion_event.instance();
+
+ motion_event->set_position(sd->get_position());
+ motion_event->set_global_position(sd->get_position());
+ motion_event->set_relative(sd->get_relative());
+ motion_event->set_speed(sd->get_speed());
+ motion_event->set_button_mask(mouse_button_mask);
+
+ _parse_input_event_impl(motion_event, true);
+ }
+ }
+
Ref<InputEventJoypadButton> jb = p_event;
if (jb.is_valid()) {
@@ -495,14 +555,44 @@ void InputDefault::action_release(const StringName &p_action) {
action_state[p_action] = action;
}
-void InputDefault::set_emulate_touch(bool p_emulate) {
+void InputDefault::set_emulate_touch_from_mouse(bool p_emulate) {
+
+ emulate_touch_from_mouse = p_emulate;
+}
+
+bool InputDefault::is_emulating_touch_from_mouse() const {
+
+ return emulate_touch_from_mouse;
+}
+
+// Calling this whenever the game window is focused helps unstucking the "touch mouse"
+// if the OS or its abstraction class hasn't properly reported that touch pointers raised
+void InputDefault::ensure_touch_mouse_raised() {
+
+ if (mouse_from_touch_index != -1) {
+ mouse_from_touch_index = -1;
+
+ Ref<InputEventMouseButton> button_event;
+ button_event.instance();
+
+ button_event->set_position(mouse_pos);
+ button_event->set_global_position(mouse_pos);
+ button_event->set_pressed(false);
+ button_event->set_button_index(BUTTON_LEFT);
+ button_event->set_button_mask(mouse_button_mask & ~(1 << BUTTON_LEFT - 1));
+
+ _parse_input_event_impl(button_event, true);
+ }
+}
+
+void InputDefault::set_emulate_mouse_from_touch(bool p_emulate) {
- emulate_touch = p_emulate;
+ emulate_mouse_from_touch = p_emulate;
}
-bool InputDefault::is_emulating_touchscreen() const {
+bool InputDefault::is_emulating_mouse_from_touch() const {
- return emulate_touch;
+ return emulate_mouse_from_touch;
}
Input::CursorShape InputDefault::get_default_cursor_shape() {
@@ -539,7 +629,9 @@ void InputDefault::set_mouse_in_window(bool p_in_window) {
InputDefault::InputDefault() {
mouse_button_mask = 0;
- emulate_touch = false;
+ emulate_touch_from_mouse = false;
+ emulate_mouse_from_touch = false;
+ mouse_from_touch_index = -1;
main_loop = NULL;
hat_map_default[HAT_UP].type = TYPE_BUTTON;
@@ -797,12 +889,12 @@ InputDefault::JoyEvent InputDefault::_find_to_event(String p_to) {
JoyEvent ret;
ret.type = -1;
+ ret.index = 0;
int i = 0;
while (buttons[i]) {
if (p_to == buttons[i]) {
- //printf("mapping button %s\n", buttons[i]);
ret.type = TYPE_BUTTON;
ret.index = i;
ret.value = 0;
diff --git a/main/input_default.h b/main/input_default.h
index 6dd88cd31e..2e3cae8520 100644
--- a/main/input_default.h
+++ b/main/input_default.h
@@ -60,7 +60,10 @@ class InputDefault : public Input {
Map<StringName, Action> action_state;
- bool emulate_touch;
+ bool emulate_touch_from_mouse;
+ bool emulate_mouse_from_touch;
+
+ int mouse_from_touch_index;
struct VibrationInfo {
float weak_magnitude;
@@ -97,7 +100,6 @@ class InputDefault : public Input {
int hat_current;
Joypad() {
-
for (int i = 0; i < JOY_AXIS_MAX; i++) {
last_axis[i] = 0.0f;
@@ -110,6 +112,7 @@ class InputDefault : public Input {
last_hat = HAT_MASK_CENTER;
filter = 0.01f;
mapping = -1;
+ hat_current = 0;
}
};
@@ -176,6 +179,8 @@ private:
void _axis_event(int p_device, int p_axis, float p_value);
float _handle_deadzone(int p_device, int p_axis, float p_value);
+ void _parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated);
+
public:
virtual bool is_key_pressed(int p_scancode) const;
virtual bool is_mouse_button_pressed(int p_button) const;
@@ -225,8 +230,12 @@ public:
void iteration(float p_step);
- void set_emulate_touch(bool p_emulate);
- virtual bool is_emulating_touchscreen() const;
+ void set_emulate_touch_from_mouse(bool p_emulate);
+ virtual bool is_emulating_touch_from_mouse() const;
+ void ensure_touch_mouse_raised();
+
+ void set_emulate_mouse_from_touch(bool p_emulate);
+ virtual bool is_emulating_mouse_from_touch() const;
virtual CursorShape get_default_cursor_shape();
virtual void set_default_cursor_shape(CursorShape p_shape);
diff --git a/main/main.cpp b/main/main.cpp
index 3542133719..ffc02d8823 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1141,13 +1141,16 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
GLOBAL_DEF("application/config/icon", String());
ProjectSettings::get_singleton()->set_custom_property_info("application/config/icon", PropertyInfo(Variant::STRING, "application/config/icon", PROPERTY_HINT_FILE, "*.png,*.webp"));
- if (bool(GLOBAL_DEF("display/window/handheld/emulate_touchscreen", false))) {
- if (!OS::get_singleton()->has_touchscreen_ui_hint() && Input::get_singleton() && !(editor || project_manager)) {
- //only if no touchscreen ui hint, set emulation
- InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
- if (id)
- id->set_emulate_touch(true);
+ InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
+ if (id) {
+ if (bool(GLOBAL_DEF("input/pointing_devices/emulate_touch_from_mouse", false)) && !(editor || project_manager)) {
+ if (!OS::get_singleton()->has_touchscreen_ui_hint()) {
+ //only if no touchscreen ui hint, set emulation
+ id->set_emulate_touch_from_mouse(true);
+ }
}
+
+ id->set_emulate_mouse_from_touch(bool(GLOBAL_DEF("input/pointing_devices/emulate_mouse_from_touch", true)));
}
MAIN_PRINT("Main: Load Remaps");
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 0d52f0a995..b38b30d4b8 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -430,6 +430,9 @@ struct GDScriptCompletionIdentifier {
Ref<GDScript> script;
Variant::Type type;
Variant value; //im case there is a value, also return it
+
+ GDScriptCompletionIdentifier() :
+ type(Variant::NIL) {}
};
static GDScriptCompletionIdentifier _get_type_from_variant(const Variant &p_variant, bool p_allow_gdnative_class = false) {
@@ -551,9 +554,7 @@ static Ref<Reference> _get_parent_class(GDScriptCompletionContext &context) {
static GDScriptCompletionIdentifier _get_native_class(GDScriptCompletionContext &context) {
- //eeh...
GDScriptCompletionIdentifier id;
- id.type = Variant::NIL;
REF pc = _get_parent_class(context);
if (!pc.is_valid()) {
@@ -1521,6 +1522,13 @@ static void _find_identifiers(GDScriptCompletionContext &context, int p_line, bo
result.insert(_type_names[i]);
}
+ List<String> reserved_words;
+ GDScriptLanguage::get_singleton()->get_reserved_words(&reserved_words);
+
+ for (List<String>::Element *E = reserved_words.front(); E; E = E->next()) {
+ result.insert(E->get());
+ }
+
//autoload singletons
List<PropertyInfo> props;
ProjectSettings::get_singleton()->get_property_list(&props);
@@ -2641,6 +2649,18 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol
context.function = p.get_completion_function();
context.base = p_owner;
context.base_path = p_base_path;
+
+ if (context._class && context._class->extends_class.size() > 0) {
+ bool success = false;
+ ClassDB::get_integer_constant(context._class->extends_class[0], p_symbol, &success);
+ if (success) {
+ r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
+ r_result.class_name = context._class->extends_class[0];
+ r_result.class_member = p_symbol;
+ return OK;
+ }
+ }
+
bool isfunction = false;
switch (p.get_completion_type()) {
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index d32ce25d3c..1c5b8187ca 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -1311,9 +1311,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GDScriptLanguage::get_singleton()->script_frame_time += time_taken - function_call_time;
}
-#endif
if (ScriptDebugger::get_singleton())
GDScriptLanguage::get_singleton()->exit_function();
+#endif
if (_stack_size) {
//free stack
diff --git a/modules/mono/config.py b/modules/mono/config.py
index 18da468bba..18d9c67795 100644
--- a/modules/mono/config.py
+++ b/modules/mono/config.py
@@ -85,7 +85,7 @@ def configure(env):
if not os.path.isfile(os.path.join(mono_lib_path, mono_static_lib_name + lib_suffix)):
raise RuntimeError('Could not find static mono library in: ' + mono_lib_path)
- if os.getenv('VCINSTALLDIR'):
+ if env.msvc:
env.Append(LINKFLAGS=mono_static_lib_name + lib_suffix)
env.Append(LINKFLAGS='Mincore' + lib_suffix)
@@ -100,7 +100,7 @@ def configure(env):
if not mono_lib_name:
raise RuntimeError('Could not find mono library in: ' + mono_lib_path)
- if os.getenv('VCINSTALLDIR'):
+ if env.msvc:
env.Append(LINKFLAGS=mono_lib_name + Environment()['LIBSUFFIX'])
else:
env.Append(LIBS=mono_lib_name)
diff --git a/modules/mono/utils/mono_reg_utils.cpp b/modules/mono/utils/mono_reg_utils.cpp
index 9bb8da8ac0..7b23cd7579 100644
--- a/modules/mono/utils/mono_reg_utils.cpp
+++ b/modules/mono/utils/mono_reg_utils.cpp
@@ -174,6 +174,8 @@ String find_msbuild_tools_path() {
List<String> vswhere_args;
vswhere_args.push_back("-latest");
+ vswhere_args.push_back("-products");
+ vswhere_args.push_back("*");
vswhere_args.push_back("-requires");
vswhere_args.push_back("Microsoft.Component.MSBuild");
diff --git a/modules/pvr/texture_loader_pvr.cpp b/modules/pvr/texture_loader_pvr.cpp
index 76c0b969d8..8174bccdb7 100644
--- a/modules/pvr/texture_loader_pvr.cpp
+++ b/modules/pvr/texture_loader_pvr.cpp
@@ -536,8 +536,8 @@ static void decompress_pvrtc(PVRTCBlock *p_comp_img, const int p_2bit, const int
int p_x, p_y;
- int p_modulation[8][16];
- int p_modulation_modes[8][16];
+ int p_modulation[8][16] = { { 0 } };
+ int p_modulation_modes[8][16] = { { 0 } };
int Mod, DoPT;
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index ef680547ca..03bc4c114a 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -2028,6 +2028,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
function.flow_stack_size = 0;
function.pass_stack_size = 0;
function.node_count = 0;
+
Map<StringName, int> local_var_indices;
if (function.node < 0) {
diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h
index 69bb522173..dad9c68312 100644
--- a/modules/visual_script/visual_script.h
+++ b/modules/visual_script/visual_script.h
@@ -374,12 +374,10 @@ class VisualScriptInstance : public ScriptInstance {
int node;
int max_stack;
int trash_pos;
- int return_pos;
int flow_stack_size;
int pass_stack_size;
int node_count;
int argument_count;
- bool valid;
};
Map<StringName, Function> functions;
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 5557c1de44..fc41adeb76 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -330,17 +330,6 @@ void OS_Android::process_touch(int p_what, int p_pointer, const Vector<TouchPos>
if (touch.size()) {
//end all if exist
- {
- Ref<InputEventMouseButton> ev;
- ev.instance();
- ev->set_button_index(BUTTON_LEFT);
- ev->set_button_mask(BUTTON_MASK_LEFT);
- ev->set_pressed(false);
- ev->set_position(touch[0].pos);
- ev->set_global_position(touch[0].pos);
- input->parse_input_event(ev);
- }
-
for (int i = 0; i < touch.size(); i++) {
Ref<InputEventScreenTouch> ev;
@@ -358,21 +347,6 @@ void OS_Android::process_touch(int p_what, int p_pointer, const Vector<TouchPos>
touch[i].pos = p_points[i].pos;
}
- {
- //send mouse
- Ref<InputEventMouseButton> ev;
- ev.instance();
- // ev.type = Ref<InputEvent>::MOUSE_BUTTON;
- ev->set_button_index(BUTTON_LEFT);
- ev->set_button_mask(BUTTON_MASK_LEFT);
- ev->set_pressed(true);
- ev->set_position(touch[0].pos);
- ev->set_global_position(touch[0].pos);
- input->set_mouse_position(Point2(touch[0].pos.x, touch[0].pos.y));
- last_mouse = touch[0].pos;
- input->parse_input_event(ev);
- }
-
//send touch
for (int i = 0; i < touch.size(); i++) {
@@ -387,19 +361,6 @@ void OS_Android::process_touch(int p_what, int p_pointer, const Vector<TouchPos>
} break;
case 1: { //motion
- if (p_points.size()) {
- //send mouse, should look for point 0?
- Ref<InputEventMouseMotion> ev;
- ev.instance();
- ev->set_button_mask(BUTTON_MASK_LEFT);
- ev->set_position(p_points[0].pos);
- input->set_mouse_position(Point2(ev->get_position().x, ev->get_position().y));
- ev->set_speed(input->get_last_mouse_speed());
- ev->set_relative(p_points[0].pos - last_mouse);
- last_mouse = p_points[0].pos;
- input->parse_input_event(ev);
- }
-
ERR_FAIL_COND(touch.size() != p_points.size());
for (int i = 0; i < touch.size(); i++) {
@@ -432,16 +393,6 @@ void OS_Android::process_touch(int p_what, int p_pointer, const Vector<TouchPos>
if (touch.size()) {
//end all if exist
- Ref<InputEventMouseButton> ev;
- ev.instance();
- ev->set_button_index(BUTTON_LEFT);
- ev->set_button_mask(BUTTON_MASK_LEFT);
- ev->set_pressed(false);
- ev->set_position(touch[0].pos);
- ev->set_global_position(touch[0].pos);
- input->set_mouse_position(Point2(touch[0].pos.x, touch[0].pos.y));
- input->parse_input_event(ev);
-
for (int i = 0; i < touch.size(); i++) {
Ref<InputEventScreenTouch> ev;
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index 12181b3688..d2457e538d 100644
--- a/platform/android/os_android.h
+++ b/platform/android/os_android.h
@@ -93,7 +93,6 @@ public:
private:
Vector<TouchPos> touch;
- Point2 last_mouse;
GFXInitFunc gfx_init_func;
void *gfx_init_ud;
diff --git a/platform/iphone/gl_view.mm b/platform/iphone/gl_view.mm
index ff95cf6e5f..478a3125af 100644
--- a/platform/iphone/gl_view.mm
+++ b/platform/iphone/gl_view.mm
@@ -497,7 +497,7 @@ static void clear_touches() {
int tid = get_touch_id(touch);
ERR_FAIL_COND(tid == -1);
CGPoint touchPoint = [touch locationInView:self];
- OSIPhone::get_singleton()->mouse_button(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, true, touch.tapCount > 1, tid == 0);
+ OSIPhone::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, true, touch.tapCount > 1);
};
};
}
@@ -514,10 +514,9 @@ static void clear_touches() {
continue;
int tid = get_touch_id(touch);
ERR_FAIL_COND(tid == -1);
- int first = get_first_id(touch);
CGPoint touchPoint = [touch locationInView:self];
CGPoint prev_point = [touch previousLocationInView:self];
- OSIPhone::get_singleton()->mouse_move(tid, prev_point.x * self.contentScaleFactor, prev_point.y * self.contentScaleFactor, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, first == tid);
+ OSIPhone::get_singleton()->touch_drag(tid, prev_point.x * self.contentScaleFactor, prev_point.y * self.contentScaleFactor, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor);
};
};
}
@@ -533,9 +532,9 @@ static void clear_touches() {
continue;
int tid = get_touch_id(touch);
ERR_FAIL_COND(tid == -1);
- int rem = remove_touch(touch);
+ remove_touch(touch);
CGPoint touchPoint = [touch locationInView:self];
- OSIPhone::get_singleton()->mouse_button(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, false, false, rem == 0);
+ OSIPhone::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, false, false);
};
};
}
diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp
index 97ebc19335..f618c80a77 100644
--- a/platform/iphone/os_iphone.cpp
+++ b/platform/iphone/os_iphone.cpp
@@ -190,7 +190,7 @@ void OSIPhone::key(uint32_t p_key, bool p_pressed) {
queue_event(ev);
};
-void OSIPhone::mouse_button(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick, bool p_use_as_mouse) {
+void OSIPhone::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick) {
if (!GLOBAL_DEF("debug/disable_touch", false)) {
Ref<InputEventScreenTouch> ev;
@@ -202,28 +202,10 @@ void OSIPhone::mouse_button(int p_idx, int p_x, int p_y, bool p_pressed, bool p_
queue_event(ev);
};
- mouse_list.pressed[p_idx] = p_pressed;
-
- if (p_use_as_mouse) {
-
- Ref<InputEventMouseButton> ev;
- ev.instance();
-
- ev->set_position(Vector2(p_x, p_y));
- ev->set_global_position(Vector2(p_x, p_y));
-
- //mouse_list.pressed[p_idx] = p_pressed;
-
- input->set_mouse_position(ev->get_position());
- ev->set_button_index(BUTTON_LEFT);
- ev->set_doubleclick(p_doubleclick);
- ev->set_pressed(p_pressed);
-
- queue_event(ev);
- };
+ touch_list.pressed[p_idx] = p_pressed;
};
-void OSIPhone::mouse_move(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, bool p_use_as_mouse) {
+void OSIPhone::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y) {
if (!GLOBAL_DEF("debug/disable_touch", false)) {
@@ -234,21 +216,6 @@ void OSIPhone::mouse_move(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_
ev->set_relative(Vector2(p_x - p_prev_x, p_y - p_prev_y));
queue_event(ev);
};
-
- if (p_use_as_mouse) {
- Ref<InputEventMouseMotion> ev;
- ev.instance();
-
- ev->set_position(Vector2(p_x, p_y));
- ev->set_global_position(Vector2(p_x, p_y));
- ev->set_relative(Vector2(p_x - p_prev_x, p_y - p_prev_y));
-
- input->set_mouse_position(ev->get_position());
- ev->set_speed(input->get_last_mouse_speed());
- ev->set_button_mask(BUTTON_LEFT); // pressed
-
- queue_event(ev);
- };
};
void OSIPhone::queue_event(const Ref<InputEvent> &p_event) {
@@ -262,10 +229,10 @@ void OSIPhone::touches_cancelled() {
for (int i = 0; i < MAX_MOUSE_COUNT; i++) {
- if (mouse_list.pressed[i]) {
+ if (touch_list.pressed[i]) {
// send a mouse_up outside the screen
- mouse_button(i, -1, -1, false, false, false);
+ touch_press(i, -1, -1, false, false);
};
};
};
@@ -376,7 +343,7 @@ Point2 OSIPhone::get_mouse_position() const {
int OSIPhone::get_mouse_button_state() const {
- return mouse_list.pressed[0];
+ return 0;
};
void OSIPhone::set_window_title(const String &p_title){};
diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h
index 00d9efb01a..7d73a6fe5c 100644
--- a/platform/iphone/os_iphone.h
+++ b/platform/iphone/os_iphone.h
@@ -106,7 +106,7 @@ private:
};
};
- MouseList mouse_list;
+ MouseList touch_list;
Vector3 last_accel;
@@ -127,8 +127,8 @@ public:
uint8_t get_orientations() const;
- void mouse_button(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick, bool p_use_as_mouse);
- void mouse_move(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, bool p_use_as_mouse);
+ void touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick);
+ void touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y);
void touches_cancelled();
void key(uint32_t p_key, bool p_pressed);
void set_virtual_keyboard_height(int p_height);
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index a275fb7929..1b5463e40d 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -285,23 +285,6 @@ static EM_BOOL _touchpress_callback(int event_type, const EmscriptenTouchEvent *
_input->parse_input_event(ev);
}
-
- if (touch_event->touches[lowest_id_index].isChanged) {
-
- Ref<InputEventMouseButton> ev_mouse;
- ev_mouse.instance();
- ev_mouse->set_button_mask(_input->get_mouse_button_mask());
- dom2godot_mod(touch_event, ev_mouse);
-
- const EmscriptenTouchPoint &first_touch = touch_event->touches[lowest_id_index];
- ev_mouse->set_position(Point2(first_touch.canvasX, first_touch.canvasY));
- ev_mouse->set_global_position(ev_mouse->get_position());
-
- ev_mouse->set_button_index(BUTTON_LEFT);
- ev_mouse->set_pressed(event_type == EMSCRIPTEN_EVENT_TOUCHSTART);
-
- _input->parse_input_event(ev_mouse);
- }
return true;
}
@@ -327,24 +310,6 @@ static EM_BOOL _touchmove_callback(int event_type, const EmscriptenTouchEvent *t
_input->parse_input_event(ev);
}
-
- if (touch_event->touches[lowest_id_index].isChanged) {
-
- Ref<InputEventMouseMotion> ev_mouse;
- ev_mouse.instance();
- dom2godot_mod(touch_event, ev_mouse);
- ev_mouse->set_button_mask(_input->get_mouse_button_mask());
-
- const EmscriptenTouchPoint &first_touch = touch_event->touches[lowest_id_index];
- ev_mouse->set_position(Point2(first_touch.canvasX, first_touch.canvasY));
- ev_mouse->set_global_position(ev_mouse->get_position());
-
- ev_mouse->set_relative(ev_mouse->get_position() - _input->get_mouse_position());
- _input->set_mouse_position(ev_mouse->get_position());
- ev_mouse->set_speed(_input->get_last_mouse_speed());
-
- _input->parse_input_event(ev_mouse);
- }
return true;
}
diff --git a/platform/uwp/app.cpp b/platform/uwp/app.cpp
index 5ff62b38f9..c18aa36402 100644
--- a/platform/uwp/app.cpp
+++ b/platform/uwp/app.cpp
@@ -85,8 +85,7 @@ App::App() :
mWindowHeight(0),
mEglDisplay(EGL_NO_DISPLAY),
mEglContext(EGL_NO_CONTEXT),
- mEglSurface(EGL_NO_SURFACE),
- number_of_contacts(0) {
+ mEglSurface(EGL_NO_SURFACE) {
}
// The first method called when the IFrameworkView is being created.
@@ -271,48 +270,44 @@ void App::pointer_event(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Cor
last_touch_y[screen_touch->get_index()] = pos.Y;
os->input_event(screen_touch);
- if (number_of_contacts > 1)
- return;
+ } else {
- }; // fallthrought of sorts
-
- Ref<InputEventMouseButton> mouse_button;
- mouse_button.instance();
- mouse_button->set_device(0);
- mouse_button->set_pressed(p_pressed);
- mouse_button->set_button_index(but);
- mouse_button->set_position(Vector2(pos.X, pos.Y));
- mouse_button->set_global_position(Vector2(pos.X, pos.Y));
-
- if (p_is_wheel) {
- if (point->Properties->MouseWheelDelta > 0) {
- mouse_button->set_button_index(point->Properties->IsHorizontalMouseWheel ? BUTTON_WHEEL_RIGHT : BUTTON_WHEEL_UP);
- } else if (point->Properties->MouseWheelDelta < 0) {
- mouse_button->set_button_index(point->Properties->IsHorizontalMouseWheel ? BUTTON_WHEEL_LEFT : BUTTON_WHEEL_DOWN);
+ Ref<InputEventMouseButton> mouse_button;
+ mouse_button.instance();
+ mouse_button->set_device(0);
+ mouse_button->set_pressed(p_pressed);
+ mouse_button->set_button_index(but);
+ mouse_button->set_position(Vector2(pos.X, pos.Y));
+ mouse_button->set_global_position(Vector2(pos.X, pos.Y));
+
+ if (p_is_wheel) {
+ if (point->Properties->MouseWheelDelta > 0) {
+ mouse_button->set_button_index(point->Properties->IsHorizontalMouseWheel ? BUTTON_WHEEL_RIGHT : BUTTON_WHEEL_UP);
+ } else if (point->Properties->MouseWheelDelta < 0) {
+ mouse_button->set_button_index(point->Properties->IsHorizontalMouseWheel ? BUTTON_WHEEL_LEFT : BUTTON_WHEEL_DOWN);
+ }
}
- }
- last_touch_x[31] = pos.X;
- last_touch_y[31] = pos.Y;
+ last_touch_x[31] = pos.X;
+ last_touch_y[31] = pos.Y;
- os->input_event(mouse_button);
-
- if (p_is_wheel) {
- // Send release for mouse wheel
- mouse_button->set_pressed(false);
os->input_event(mouse_button);
+
+ if (p_is_wheel) {
+ // Send release for mouse wheel
+ mouse_button->set_pressed(false);
+ os->input_event(mouse_button);
+ }
}
};
void App::OnPointerPressed(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::PointerEventArgs ^ args) {
- number_of_contacts++;
pointer_event(sender, args, true);
};
void App::OnPointerReleased(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::PointerEventArgs ^ args) {
- number_of_contacts--;
pointer_event(sender, args, false);
};
@@ -351,7 +346,7 @@ void App::OnPointerMoved(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Co
Windows::UI::Input::PointerPoint ^ point = args->CurrentPoint;
Windows::Foundation::Point pos = _get_pixel_position(window, point->Position, os);
- if (point->IsInContact && _is_touch(point)) {
+ if (_is_touch(point)) {
Ref<InputEventScreenDrag> screen_drag;
screen_drag.instance();
@@ -361,25 +356,23 @@ void App::OnPointerMoved(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Co
screen_drag->set_relative(Vector2(screen_drag->get_position().x - last_touch_x[screen_drag->get_index()], screen_drag->get_position().y - last_touch_y[screen_drag->get_index()]));
os->input_event(screen_drag);
- if (number_of_contacts > 1)
- return;
-
- }; // fallthrought of sorts
+ } else {
- // In case the mouse grabbed, MouseMoved will handle this
- if (os->get_mouse_mode() == OS::MouseMode::MOUSE_MODE_CAPTURED)
- return;
+ // In case the mouse grabbed, MouseMoved will handle this
+ if (os->get_mouse_mode() == OS::MouseMode::MOUSE_MODE_CAPTURED)
+ return;
- Ref<InputEventMouseMotion> mouse_motion;
- mouse_motion.instance();
- mouse_motion->set_device(0);
- mouse_motion->set_position(Vector2(pos.X, pos.Y));
- mouse_motion->set_global_position(Vector2(pos.X, pos.Y));
- mouse_motion->set_relative(Vector2(pos.X - last_touch_x[31], pos.Y - last_touch_y[31]));
+ Ref<InputEventMouseMotion> mouse_motion;
+ mouse_motion.instance();
+ mouse_motion->set_device(0);
+ mouse_motion->set_position(Vector2(pos.X, pos.Y));
+ mouse_motion->set_global_position(Vector2(pos.X, pos.Y));
+ mouse_motion->set_relative(Vector2(pos.X - last_touch_x[31], pos.Y - last_touch_y[31]));
- last_mouse_pos = pos;
+ last_mouse_pos = pos;
- os->input_event(mouse_motion);
+ os->input_event(mouse_motion);
+ }
}
void App::OnMouseMoved(MouseDevice ^ mouse_device, MouseEventArgs ^ args) {
diff --git a/platform/uwp/app.h b/platform/uwp/app.h
index c23270b8ba..5f69f2cb0e 100644
--- a/platform/uwp/app.h
+++ b/platform/uwp/app.h
@@ -107,7 +107,6 @@ namespace GodotUWP
int last_touch_x[32]; // 20 fingers, index 31 reserved for the mouse
int last_touch_y[32];
- int number_of_contacts;
Windows::Foundation::Point last_mouse_pos;
};
}
diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp
index 7d7bee9227..3c537b3b58 100644
--- a/platform/uwp/export/export.cpp
+++ b/platform/uwp/export/export.cpp
@@ -122,6 +122,14 @@ class AppxPackager {
Vector<BlockHash> hashes;
uLong file_crc32;
ZPOS64_T zip_offset;
+
+ FileMeta() :
+ lfh_size(0),
+ compressed(false),
+ compressed_size(0),
+ uncompressed_size(0),
+ file_crc32(0),
+ zip_offset(0) {}
};
String progress_task;
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 9c37b65d77..363f54fc7b 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -342,6 +342,14 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
} break;
case WM_MOUSEMOVE: {
+ if (input->is_emulating_mouse_from_touch()) {
+ // Universal translation enabled; ignore OS translation
+ LPARAM extra = GetMessageExtraInfo();
+ if (IsPenEvent(extra)) {
+ break;
+ }
+ }
+
if (outside) {
//mouse enter
@@ -367,18 +375,6 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
// Don't calculate relative mouse movement if we don't have focus in CAPTURED mode.
if (!window_has_focus && mouse_mode == MOUSE_MODE_CAPTURED)
break;
- /*
- LPARAM extra = GetMessageExtraInfo();
- if (IsPenEvent(extra)) {
-
- int idx = extra & 0x7f;
- _drag_event(idx, uMsg, wParam, lParam);
- if (idx != 0) {
- return 0;
- };
- // fallthrough for mouse event
- };
- */
Ref<InputEventMouseMotion> mm;
mm.instance();
@@ -448,18 +444,13 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
/*case WM_XBUTTONDOWN:
case WM_XBUTTONUP: */ {
- /*
- LPARAM extra = GetMessageExtraInfo();
- if (IsPenEvent(extra)) {
-
- int idx = extra & 0x7f;
- _touch_event(idx, uMsg, wParam, lParam);
- if (idx != 0) {
- return 0;
- };
- // fallthrough for mouse event
- };
- */
+ if (input->is_emulating_mouse_from_touch()) {
+ // Universal translation enabled; ignore OS translation
+ LPARAM extra = GetMessageExtraInfo();
+ if (IsPenEvent(extra)) {
+ break;
+ }
+ }
Ref<InputEventMouseButton> mb;
mb.instance();
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index 1928800d8c..336068cb1e 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -1690,6 +1690,11 @@ void OS_X11::process_xevents() {
if (touch.state.has(index)) // Defensive
break;
touch.state[index] = pos;
+ if (touch.state.size() == 1) {
+ // X11 may send a motion event when a touch gesture begins, that would result
+ // in a spurious mouse motion event being sent to Godot; remember it to be able to filter it out
+ touch.mouse_pos_to_filter = pos;
+ }
input->parse_input_event(st);
} else {
if (!touch.state.has(index)) // Defensive
@@ -1896,6 +1901,18 @@ void OS_X11::process_xevents() {
// to be able to send relative motion events.
Point2i pos(event.xmotion.x, event.xmotion.y);
+ // Avoidance of spurious mouse motion (see handling of touch)
+ bool filter = false;
+ // Adding some tolerance to match better Point2i to Vector2
+ if (touch.state.size() && Vector2(pos).distance_squared_to(touch.mouse_pos_to_filter) < 2) {
+ filter = true;
+ }
+ // Invalidate to avoid filtering a possible legitimate similar event coming later
+ touch.mouse_pos_to_filter = Vector2(1e10, 1e10);
+ if (filter) {
+ break;
+ }
+
if (mouse_mode == MOUSE_MODE_CAPTURED) {
if (pos == Point2i(current_videomode.width / 2, current_videomode.height / 2)) {
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
index 610dba0716..0a39da77de 100644
--- a/platform/x11/os_x11.h
+++ b/platform/x11/os_x11.h
@@ -127,6 +127,7 @@ class OS_X11 : public OS_Unix {
Vector<int> devices;
XIEventMask event_mask;
Map<int, Vector2> state;
+ Vector2 mouse_pos_to_filter;
} touch;
#endif
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index bf5bf29b2e..eed26f5399 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -430,6 +430,71 @@ Vector2 Polygon2D::get_offset() const {
return offset;
}
+void Polygon2D::add_bone(const NodePath &p_path, const PoolVector<float> &p_weights) {
+
+ Bone bone;
+ bone.path = p_path;
+ bone.weights = p_weights;
+ bone_weights.push_back(bone);
+}
+int Polygon2D::get_bone_count() const {
+ return bone_weights.size();
+}
+NodePath Polygon2D::get_bone_path(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, bone_weights.size(), NodePath());
+ return bone_weights[p_index].path;
+}
+PoolVector<float> Polygon2D::get_bone_weights(int p_index) const {
+
+ ERR_FAIL_INDEX_V(p_index, bone_weights.size(), PoolVector<float>());
+ return bone_weights[p_index].weights;
+}
+void Polygon2D::erase_bone(int p_idx) {
+
+ ERR_FAIL_INDEX(p_idx, bone_weights.size());
+ bone_weights.remove(p_idx);
+}
+
+void Polygon2D::clear_bones() {
+ bone_weights.clear();
+}
+
+void Polygon2D::set_bone_weights(int p_index, const PoolVector<float> &p_weights) {
+ ERR_FAIL_INDEX(p_index, bone_weights.size());
+ bone_weights[p_index].weights = p_weights;
+ update();
+}
+void Polygon2D::set_bone_path(int p_index, const NodePath &p_path) {
+ ERR_FAIL_INDEX(p_index, bone_weights.size());
+ bone_weights[p_index].path = p_path;
+ update();
+}
+
+Array Polygon2D::_get_bones() const {
+ Array bones;
+ for (int i = 0; i < get_bone_count(); i++) {
+ bones.push_back(get_bone_path(i));
+ bones.push_back(get_bone_weights(i));
+ }
+ return bones;
+}
+void Polygon2D::_set_bones(const Array &p_bones) {
+
+ ERR_FAIL_COND(p_bones.size() & 1);
+ clear_bones();
+ for (int i = 0; i < p_bones.size(); i += 2) {
+ add_bone(p_bones[i], p_bones[i + 1]);
+ }
+}
+
+void Polygon2D::set_skeleton(const NodePath &p_skeleton) {
+ skeleton = p_skeleton;
+ update();
+}
+NodePath Polygon2D::get_skeleton() const {
+ return skeleton;
+}
+
void Polygon2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_polygon", "polygon"), &Polygon2D::set_polygon);
@@ -474,6 +539,21 @@ void Polygon2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_offset", "offset"), &Polygon2D::set_offset);
ClassDB::bind_method(D_METHOD("get_offset"), &Polygon2D::get_offset);
+ ClassDB::bind_method(D_METHOD("add_bone", "path", "weights"), &Polygon2D::add_bone);
+ ClassDB::bind_method(D_METHOD("get_bone_count"), &Polygon2D::get_bone_count);
+ ClassDB::bind_method(D_METHOD("get_bone_path", "index"), &Polygon2D::get_bone_path);
+ ClassDB::bind_method(D_METHOD("get_bone_weights", "index"), &Polygon2D::get_bone_weights);
+ ClassDB::bind_method(D_METHOD("erase_bone", "index"), &Polygon2D::erase_bone);
+ ClassDB::bind_method(D_METHOD("clear_bones"), &Polygon2D::clear_bones);
+ ClassDB::bind_method(D_METHOD("set_bone_path", "index", "path"), &Polygon2D::set_bone_path);
+ ClassDB::bind_method(D_METHOD("set_bone_weights", "index", "weights"), &Polygon2D::set_bone_weights);
+
+ ClassDB::bind_method(D_METHOD("set_skeleton", "skeleton"), &Polygon2D::set_skeleton);
+ ClassDB::bind_method(D_METHOD("get_skeleton"), &Polygon2D::get_skeleton);
+
+ ClassDB::bind_method(D_METHOD("_set_bones", "bones"), &Polygon2D::_set_bones);
+ ClassDB::bind_method(D_METHOD("_get_bones"), &Polygon2D::_get_bones);
+
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon");
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "uv"), "set_uv", "get_uv");
ADD_PROPERTY(PropertyInfo(Variant::POOL_INT_ARRAY, "splits"), "set_splits", "get_splits");
@@ -488,10 +568,14 @@ void Polygon2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_scale"), "set_texture_scale", "get_texture_scale");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation_degrees", PROPERTY_HINT_RANGE, "-1440,1440,0.1"), "set_texture_rotation_degrees", "get_texture_rotation_degrees");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation", PROPERTY_HINT_NONE, "", 0), "set_texture_rotation", "get_texture_rotation");
+ ADD_GROUP("Skeleton", "");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton"), "set_skeleton", "get_skeleton");
ADD_GROUP("Invert", "invert_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert_enable"), "set_invert", "get_invert");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "invert_border", PROPERTY_HINT_RANGE, "0.1,16384,0.1"), "set_invert_border", "get_invert_border");
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bones", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_bones", "_get_bones");
}
Polygon2D::Polygon2D() {
diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h
index 262208f2f1..575f71d74a 100644
--- a/scene/2d/polygon_2d.h
+++ b/scene/2d/polygon_2d.h
@@ -42,6 +42,13 @@ class Polygon2D : public Node2D {
PoolVector<Color> vertex_colors;
PoolVector<int> splits;
+ struct Bone {
+ NodePath path;
+ PoolVector<float> weights;
+ };
+
+ Vector<Bone> bone_weights;
+
Color color;
Ref<Texture> texture;
Size2 tex_scale;
@@ -56,6 +63,11 @@ class Polygon2D : public Node2D {
mutable bool rect_cache_dirty;
mutable Rect2 item_rect;
+ NodePath skeleton;
+
+ Array _get_bones() const;
+ void _set_bones(const Array &p_bones);
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -114,6 +126,18 @@ public:
void set_offset(const Vector2 &p_offset);
Vector2 get_offset() const;
+ void add_bone(const NodePath &p_path = NodePath(), const PoolVector<float> &p_weights = PoolVector<float>());
+ int get_bone_count() const;
+ NodePath get_bone_path(int p_index) const;
+ PoolVector<float> get_bone_weights(int p_index) const;
+ void erase_bone(int p_idx);
+ void clear_bones();
+ void set_bone_weights(int p_index, const PoolVector<float> &p_weights);
+ void set_bone_path(int p_index, const NodePath &p_path);
+
+ void set_skeleton(const NodePath &p_skeleton);
+ NodePath get_skeleton() const;
+
Polygon2D();
};
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index 705e82bcbb..3b3561bc1c 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -12,6 +12,8 @@ void Bone2D::_notification(int p_what) {
break;
if (!Object::cast_to<Bone2D>(parent))
break; //skeletons must be chained to Bone2Ds.
+
+ parent = parent->get_parent();
}
if (skeleton) {
diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp
index 42fa20068b..afdb8b6f71 100644
--- a/scene/animation/animation_tree_player.cpp
+++ b/scene/animation/animation_tree_player.cpp
@@ -812,8 +812,6 @@ void AnimationTreePlayer::_process_animation(float p_delta) {
t.value = t.object->get_indexed(t.subpath);
t.value.zero();
-
- t.skip = false;
}
/* STEP 2 PROCESS ANIMATIONS */
@@ -886,7 +884,7 @@ void AnimationTreePlayer::_process_animation(float p_delta) {
Track &t = E->get();
- if (t.skip || !t.object)
+ if (!t.object)
continue;
if (t.subpath.size()) { // value track
diff --git a/scene/animation/animation_tree_player.h b/scene/animation/animation_tree_player.h
index 09d6f6fcb4..873ff8a9da 100644
--- a/scene/animation/animation_tree_player.h
+++ b/scene/animation/animation_tree_player.h
@@ -107,8 +107,6 @@ private:
Vector3 scale;
Variant value;
-
- bool skip;
};
typedef Map<TrackKey, Track> TrackMap;
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index fcf8768094..001b8cfd0b 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -979,9 +979,23 @@ void Node::_set_name_nocheck(const StringName &p_name) {
data.name = p_name;
}
+String Node::invalid_character = ". : @ / \"";
+
+bool Node::_validate_node_name(String &p_name) {
+ String name = p_name;
+ Vector<String> chars = Node::invalid_character.split(" ");
+ for (int i = 0; i < chars.size(); i++) {
+ name = name.replace(chars[i], "");
+ }
+ bool is_valid = name == p_name;
+ p_name = name;
+ return is_valid;
+}
+
void Node::set_name(const String &p_name) {
- String name = p_name.replace(":", "").replace("/", "").replace("@", "");
+ String name = p_name;
+ _validate_node_name(name);
ERR_FAIL_COND(name == "");
data.name = name;
diff --git a/scene/main/node.h b/scene/main/node.h
index b9bafb1ed1..a0b6399486 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -190,6 +190,12 @@ private:
void _set_tree(SceneTree *p_tree);
+#ifdef TOOLS_ENABLED
+ friend class SceneTreeEditor;
+#endif
+ static String invalid_character;
+ static bool _validate_node_name(String &p_name);
+
protected:
void _block() { data.blocked++; }
void _unblock() { data.blocked--; }
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 4419dfe70f..727807dbcd 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -33,6 +33,7 @@
#include "editor/editor_node.h"
#include "io/marshalls.h"
#include "io/resource_loader.h"
+#include "main/input_default.h"
#include "message_queue.h"
#include "node.h"
#include "os/keyboard.h"
@@ -620,6 +621,13 @@ void SceneTree::_notification(int p_notification) {
case NOTIFICATION_WM_FOCUS_IN:
case NOTIFICATION_WM_FOCUS_OUT: {
+ if (p_notification == NOTIFICATION_WM_FOCUS_IN) {
+ InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
+ if (id) {
+ id->ensure_touch_mouse_raised();
+ }
+ }
+
get_root()->propagate_notification(p_notification);
} break;
case NOTIFICATION_TRANSLATION_CHANGED: {
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 19d8f09ebe..d94b32afd7 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -58,6 +58,7 @@
#include "scene/2d/ray_cast_2d.h"
#include "scene/2d/remote_transform_2d.h"
#include "scene/2d/screen_button.h"
+#include "scene/2d/skeleton_2d.h"
#include "scene/2d/sprite.h"
#include "scene/2d/tile_map.h"
#include "scene/2d/visibility_notifier_2d.h"
@@ -449,6 +450,8 @@ void register_scene_types() {
ClassDB::register_class<VisibilityNotifier2D>();
ClassDB::register_class<VisibilityEnabler2D>();
ClassDB::register_class<Polygon2D>();
+ ClassDB::register_class<Skeleton2D>();
+ ClassDB::register_class<Bone2D>();
ClassDB::register_class<Light2D>();
ClassDB::register_class<LightOccluder2D>();
ClassDB::register_class<OccluderPolygon2D>();
diff --git a/servers/physics/body_pair_sw.cpp b/servers/physics/body_pair_sw.cpp
index 882d201f61..2a6a9e08ae 100644
--- a/servers/physics/body_pair_sw.cpp
+++ b/servers/physics/body_pair_sw.cpp
@@ -78,6 +78,7 @@ void BodyPairSW::contact_added_callback(const Vector3 &p_point_A, const Vector3
contact.local_A = local_A;
contact.local_B = local_B;
contact.normal = (p_point_A - p_point_B).normalized();
+ contact.mass_normal = 0; // will be computed in setup()
// attempt to determine if the contact will be reused
real_t contact_recycle_radius = space->get_contact_recycle_radius();
diff --git a/servers/physics_2d/body_pair_2d_sw.cpp b/servers/physics_2d/body_pair_2d_sw.cpp
index f51882b5ee..61c0e0063f 100644
--- a/servers/physics_2d/body_pair_2d_sw.cpp
+++ b/servers/physics_2d/body_pair_2d_sw.cpp
@@ -62,6 +62,7 @@ void BodyPair2DSW::_contact_added_callback(const Vector2 &p_point_A, const Vecto
contact.local_B = local_B;
contact.reused = true;
contact.normal = (p_point_A - p_point_B).normalized();
+ contact.mass_normal = 0; // will be computed in setup()
// attempt to determine if the contact will be reused
diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h
index e8cdf1f897..2e3881179a 100644
--- a/servers/visual/shader_language.h
+++ b/servers/visual/shader_language.h
@@ -425,6 +425,7 @@ public:
FunctionNode() {
type = TYPE_FUNCTION;
+ return_type = TYPE_VOID;
return_precision = PRECISION_DEFAULT;
can_discard = false;
}