diff options
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; } |