diff options
Diffstat (limited to 'editor/plugins')
-rw-r--r-- | editor/plugins/animation_player_editor_plugin.cpp | 7 | ||||
-rw-r--r-- | editor/plugins/asset_library_editor_plugin.cpp | 14 | ||||
-rw-r--r-- | editor/plugins/asset_library_editor_plugin.h | 1 | ||||
-rw-r--r-- | editor/plugins/canvas_item_editor_plugin.cpp | 442 | ||||
-rw-r--r-- | editor/plugins/canvas_item_editor_plugin.h | 32 | ||||
-rw-r--r-- | editor/plugins/navigation_mesh_generator.cpp | 34 | ||||
-rw-r--r-- | editor/plugins/path_editor_plugin.cpp | 11 | ||||
-rw-r--r-- | editor/plugins/polygon_2d_editor_plugin.cpp | 510 | ||||
-rw-r--r-- | editor/plugins/polygon_2d_editor_plugin.h | 31 | ||||
-rw-r--r-- | editor/plugins/script_text_editor.cpp | 6 | ||||
-rw-r--r-- | editor/plugins/spatial_editor_plugin.cpp | 2 | ||||
-rw-r--r-- | editor/plugins/sprite_frames_editor_plugin.cpp | 26 | ||||
-rw-r--r-- | editor/plugins/theme_editor_plugin.cpp | 56 | ||||
-rw-r--r-- | editor/plugins/tile_map_editor_plugin.cpp | 15 | ||||
-rw-r--r-- | editor/plugins/tile_map_editor_plugin.h | 19 | ||||
-rw-r--r-- | editor/plugins/tile_set_editor_plugin.cpp | 7 |
16 files changed, 863 insertions, 350 deletions
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 220003eb73..b387972558 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -459,6 +459,12 @@ void AnimationPlayerEditor::_animation_remove_confirmed() { Ref<Animation> anim = player->get_animation(current); undo_redo->create_action(TTR("Remove Animation")); + if (player->get_autoplay() == current) { + undo_redo->add_do_method(player, "set_autoplay", ""); + undo_redo->add_undo_method(player, "set_autoplay", current); + // Avoid having the autoplay icon linger around if there is only one animation in the player + undo_redo->add_do_method(this, "_animation_player_changed", player); + } undo_redo->add_do_method(player, "remove_animation", current); undo_redo->add_undo_method(player, "add_animation", current, anim); undo_redo->add_do_method(this, "_animation_player_changed", player); @@ -822,6 +828,7 @@ void AnimationPlayerEditor::_update_player() { save_anim->set_disabled(animlist.size() == 0); tool_anim->set_disabled(player == NULL); onion_skinning->set_disabled(player == NULL); + pin->set_disabled(player == NULL); int active_idx = -1; for (List<StringName>::Element *E = animlist.front(); E; E = E->next()) { 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 cd8723930c..93aeca6632 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -44,6 +44,7 @@ #include "scene/2d/particles_2d.h" #include "scene/2d/polygon_2d.h" #include "scene/2d/screen_button.h" +#include "scene/2d/skeleton_2d.h" #include "scene/2d/sprite.h" #include "scene/gui/grid_container.h" #include "scene/gui/nine_patch_rect.h" @@ -457,7 +458,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,21 +467,18 @@ 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_")))) { - 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); - } 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); - } - if (limit != 0 && r_items.size() >= limit) - return; + 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, 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, p_limit, Transform2D(), cl ? cl->get_transform() : p_canvas_xform); } + 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_"))) { + 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)) { @@ -497,6 +495,41 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no 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, or editable + while (node && node != get_tree()->get_edited_scene_root() && node->get_owner() != scene && !scene->is_editable_instance(node->get_owner())) { + node = node->get_parent(); + }; + + // Replace the node by the group if grouped + CanvasItem *canvas_item = Object::cast_to<CanvasItem>(node); + while (node && node != scene->get_parent()) { + 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())) || (canvas_item->has_meta("_edit_lock_") && canvas_item->get_meta("_edit_lock_"))) { + 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; @@ -504,13 +537,13 @@ void CanvasItemEditor::_find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_n return; CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node); + Node *scene = editor->get_edited_scene(); - bool inherited = p_node != get_tree()->get_edited_scene_root() && p_node->get_filename() != ""; - bool editable = !inherited || EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(p_node); + bool editable = p_node == scene || p_node->get_owner() == scene || scene->is_editable_instance(p_node->get_owner()); bool lock_children = p_node->has_meta("_edit_group_") && p_node->get_meta("_edit_group_"); bool locked = p_node->has_meta("_edit_lock_") && p_node->get_meta("_edit_lock_"); - if (!lock_children && !locked && editable) { + if (!lock_children || !editable) { for (int i = p_node->get_child_count() - 1; i >= 0; i--) { if (canvas_item && !canvas_item->is_set_as_toplevel()) { _find_canvas_items_in_rect(p_rect, p_node->get_child(i), r_items, p_parent_xform * canvas_item->get_transform(), p_canvas_xform); @@ -521,7 +554,7 @@ void CanvasItemEditor::_find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_n } } - if (canvas_item && canvas_item->is_visible_in_tree() && !canvas_item->has_meta("_edit_lock_")) { + if (canvas_item && canvas_item->is_visible_in_tree() && !locked && editable) { Transform2D xform = p_parent_xform * p_canvas_xform * canvas_item->get_transform(); if (canvas_item->_edit_use_rect()) { @@ -628,7 +661,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); @@ -896,7 +929,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> b = p_event; if (b.is_valid()) { - if (b->get_button_index() == BUTTON_WHEEL_DOWN) { + if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_DOWN) { // Scroll or pan down if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) { view_offset.y += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor(); @@ -908,7 +941,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) { return true; } - if (b->get_button_index() == BUTTON_WHEEL_UP) { + if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_UP) { // Scroll or pan up if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) { view_offset.y -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor(); @@ -920,7 +953,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) { return true; } - if (b->get_button_index() == BUTTON_WHEEL_LEFT) { + if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_LEFT) { // Pan left if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) { view_offset.x -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor(); @@ -930,7 +963,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) { } } - if (b->get_button_index() == BUTTON_WHEEL_RIGHT) { + if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_RIGHT) { // Pan right if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) { view_offset.x += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor(); @@ -939,28 +972,57 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) { return true; } } - } - Ref<InputEventMouseMotion> m = p_event; - if (m.is_valid()) { if (drag_type == DRAG_NONE) { - if (((m->get_button_mask() & BUTTON_MASK_LEFT) && tool == TOOL_PAN) || - (m->get_button_mask() & BUTTON_MASK_MIDDLE) || - ((m->get_button_mask() & BUTTON_MASK_LEFT) && Input::get_singleton()->is_key_pressed(KEY_SPACE)) || - (EditorSettings::get_singleton()->get("editors/2d/simple_spacebar_panning") && Input::get_singleton()->is_key_pressed(KEY_SPACE))) { + if (b->is_pressed() && + (b->get_button_index() == BUTTON_MIDDLE || + (b->get_button_index() == BUTTON_LEFT && tool == TOOL_PAN) || + (b->get_button_index() == BUTTON_LEFT && !EditorSettings::get_singleton()->get("editors/2d/simple_spacebar_panning") && Input::get_singleton()->is_key_pressed(KEY_SPACE)))) { // Pan the viewport - Point2i relative; - if (bool(EditorSettings::get_singleton()->get("editors/2d/warped_mouse_panning"))) { - relative = Input::get_singleton()->warp_mouse_motion(m, viewport->get_global_rect()); - } else { - relative = m->get_relative(); + drag_type = DRAG_PAN; + } + } + + if (drag_type == DRAG_PAN) { + if (!b->is_pressed()) { + // Stop panning the viewport (for any mouse button press) + drag_type = DRAG_NONE; + } + } + } + + Ref<InputEventKey> k = p_event; + if (k.is_valid()) { + if (k->get_scancode() == KEY_SPACE && EditorSettings::get_singleton()->get("editors/2d/simple_spacebar_panning")) { + if (drag_type == DRAG_NONE) { + if (k->is_pressed() && !k->is_echo()) { + //Pan the viewport + drag_type = DRAG_PAN; } - view_offset.x -= relative.x / zoom; - view_offset.y -= relative.y / zoom; - _update_scrollbars(); - viewport->update(); - return true; + } else if (drag_type == DRAG_PAN) { + if (!k->is_pressed()) { + // Stop panning the viewport (for any mouse button press) + drag_type = DRAG_NONE; + } + } + } + } + + Ref<InputEventMouseMotion> m = p_event; + if (m.is_valid()) { + if (drag_type == DRAG_PAN) { + // Pan the viewport + Point2i relative; + if (bool(EditorSettings::get_singleton()->get("editors/2d/warped_mouse_panning"))) { + relative = Input::get_singleton()->warp_mouse_motion(m, viewport->get_global_rect()); + } else { + relative = m->get_relative(); } + view_offset.x -= relative.x / zoom; + view_offset.y -= relative.y / zoom; + _update_scrollbars(); + viewport->update(); + return true; } } @@ -1675,17 +1737,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; @@ -1735,7 +1787,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)) { @@ -1754,23 +1806,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()) { @@ -1855,11 +1890,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()) { @@ -1903,10 +1937,10 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { //printf("Rotate\n"); } else if ((accepted = _gui_input_move(p_event))) { //printf("Move\n"); - } else if ((accepted = _gui_input_select(p_event))) { - //printf("Selection\n"); } else if ((accepted = _gui_input_zoom_or_pan(p_event))) { //printf("Zoom or pan\n"); + } else if ((accepted = _gui_input_select(p_event))) { + //printf("Selection\n"); } if (accepted) @@ -1919,22 +1953,18 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { CursorShape c = CURSOR_ARROW; switch (drag_type) { case DRAG_NONE: - if (Input::get_singleton()->is_mouse_button_pressed(BUTTON_MIDDLE) || Input::get_singleton()->is_key_pressed(KEY_SPACE)) { - c = CURSOR_DRAG; - } else { - switch (tool) { - case TOOL_MOVE: - c = CURSOR_MOVE; - break; - case TOOL_EDIT_PIVOT: - c = CURSOR_CROSS; - break; - case TOOL_PAN: - c = CURSOR_DRAG; - break; - default: - break; - } + switch (tool) { + case TOOL_MOVE: + c = CURSOR_MOVE; + break; + case TOOL_EDIT_PIVOT: + c = CURSOR_CROSS; + break; + case TOOL_PAN: + c = CURSOR_DRAG; + break; + default: + break; } break; case DRAG_LEFT: @@ -1956,6 +1986,8 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { case DRAG_ALL: c = CURSOR_MOVE; break; + case DRAG_PAN: + c = CURSOR_DRAG; default: break; } @@ -2551,43 +2583,52 @@ void CanvasItemEditor::_draw_bones() { Color bone_color1 = EditorSettings::get_singleton()->get("editors/2d/bone_color1"); Color bone_color2 = EditorSettings::get_singleton()->get("editors/2d/bone_color2"); Color bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color"); + Color bone_outline_color = EditorSettings::get_singleton()->get("editors/2d/bone_outline_color"); Color bone_selected_color = EditorSettings::get_singleton()->get("editors/2d/bone_selected_color"); + int bone_outline_size = EditorSettings::get_singleton()->get("editors/2d/bone_outline_size"); - for (Map<ObjectID, BoneList>::Element *E = bone_list.front(); E; E = E->next()) { + for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) { - E->get().from = Vector2(); - E->get().to = Vector2(); + Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().from)); + Node2D *to_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().to)); - Node2D *n2d = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key())); - if (!n2d) + if (!from_node->is_inside_tree()) + continue; //may have been removed + if (!from_node) continue; - if (!n2d->get_parent()) + if (!to_node && E->get().length == 0) continue; - CanvasItem *pi = n2d->get_parent_item(); + Vector2 from = transform.xform(from_node->get_global_position()); + Vector2 to; - Node2D *pn2d = Object::cast_to<Node2D>(n2d->get_parent()); - - if (!pn2d) - continue; - - Vector2 from = transform.xform(pn2d->get_global_position()); - Vector2 to = transform.xform(n2d->get_global_position()); - - E->get().from = from; - E->get().to = to; + if (to_node) + to = transform.xform(to_node->get_global_position()); + else + to = transform.xform(from_node->get_global_transform().xform(Vector2(E->get().length, 0))); Vector2 rel = to - from; Vector2 relt = rel.tangent().normalized() * bone_width; + Vector2 reln = rel.normalized(); + Vector2 reltn = relt.normalized(); Vector<Vector2> bone_shape; bone_shape.push_back(from); bone_shape.push_back(from + rel * 0.2 + relt); bone_shape.push_back(to); bone_shape.push_back(from + rel * 0.2 - relt); + + Vector<Vector2> bone_shape_outline; + bone_shape_outline.push_back(from + (-reln - reltn) * bone_outline_size); + bone_shape_outline.push_back(from + (-reln + reltn) * bone_outline_size); + bone_shape_outline.push_back(from + rel * 0.2 + relt + reltn * bone_outline_size); + bone_shape_outline.push_back(to + (reln + reltn) * bone_outline_size); + bone_shape_outline.push_back(to + (reln - reltn) * bone_outline_size); + bone_shape_outline.push_back(from + rel * 0.2 - relt - reltn * bone_outline_size); + Vector<Color> colors; - if (pi->has_meta("_edit_ik_")) { + if (from_node->has_meta("_edit_ik_")) { colors.push_back(bone_ik_color); colors.push_back(bone_ik_color); @@ -2600,14 +2641,26 @@ void CanvasItemEditor::_draw_bones() { colors.push_back(bone_color2); } - VisualServer::get_singleton()->canvas_item_add_primitive(ci, bone_shape, colors, Vector<Vector2>(), RID()); - - if (editor_selection->is_selected(pi)) { - for (int i = 0; i < bone_shape.size(); i++) { + Vector<Color> outline_colors; - VisualServer::get_singleton()->canvas_item_add_line(ci, bone_shape[i], bone_shape[(i + 1) % bone_shape.size()], bone_selected_color, 2); - } + if (editor_selection->is_selected(from_node)) { + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + } else { + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); } + + VisualServer::get_singleton()->canvas_item_add_polygon(ci, bone_shape_outline, outline_colors); + VisualServer::get_singleton()->canvas_item_add_primitive(ci, bone_shape, colors, Vector<Vector2>(), RID()); } } } @@ -2616,7 +2669,7 @@ void CanvasItemEditor::_draw_invisible_nodes_positions(Node *p_node, const Trans ERR_FAIL_COND(!p_node); Node *scene = editor->get_edited_scene(); - if (p_node != scene && p_node->get_owner() != scene && !scene->is_editable_instance(p_node)) + if (p_node != scene && p_node->get_owner() != scene && !scene->is_editable_instance(p_node->get_owner())) return; CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node); if (canvas_item && !canvas_item->is_visible()) @@ -2731,26 +2784,70 @@ void CanvasItemEditor::_draw_locks_and_groups(Node *p_node, const Transform2D &p } } -void CanvasItemEditor::_build_bones_list(Node *p_node) { - ERR_FAIL_COND(!p_node); +bool CanvasItemEditor::_build_bones_list(Node *p_node) { + ERR_FAIL_COND_V(!p_node, false); + + bool has_child_bones = false; for (int i = 0; i < p_node->get_child_count(); i++) { - _build_bones_list(p_node->get_child(i)); + if (_build_bones_list(p_node->get_child(i))) { + has_child_bones = true; + } + } + + CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node); + Node *scene = editor->get_edited_scene(); + if (!canvas_item || !canvas_item->is_visible() || (canvas_item != scene && canvas_item->get_owner() != scene && !scene->is_editable_instance(canvas_item->get_owner()))) { + return false; } - CanvasItem *c = Object::cast_to<CanvasItem>(p_node); - if (c && c->is_visible_in_tree()) { - if (c->has_meta("_edit_bone_")) { + Node *parent = canvas_item->get_parent(); - ObjectID id = c->get_instance_id(); - if (!bone_list.has(id)) { - BoneList bone; - bone_list[id] = bone; + if (Object::cast_to<Bone2D>(canvas_item)) { + if (Object::cast_to<Bone2D>(parent)) { + // Add as bone->parent relationship + BoneKey bk; + bk.from = parent->get_instance_id(); + bk.to = canvas_item->get_instance_id(); + if (!bone_list.has(bk)) { + BoneList b; + b.length = 0; + bone_list[bk] = b; } - bone_list[id].last_pass = bone_last_frame; + bone_list[bk].last_pass = bone_last_frame; } + + if (!has_child_bones) { + // Add a last bone if the Bone2D has no Bone2D child + BoneKey bk; + bk.from = canvas_item->get_instance_id(); + bk.to = 0; + if (!bone_list.has(bk)) { + BoneList b; + b.length = 0; + bone_list[bk] = b; + } + bone_list[bk].last_pass = bone_last_frame; + } + + return true; } + + if (canvas_item->has_meta("_edit_bone_")) { + // Add a "custom bone" + BoneKey bk; + bk.from = parent->get_instance_id(); + bk.to = canvas_item->get_instance_id(); + if (!bone_list.has(bk)) { + BoneList b; + b.length = 0; + bone_list[bk] = b; + } + bone_list[bk].last_pass = bone_last_frame; + } + + return false; } void CanvasItemEditor::_draw_viewport() { @@ -2826,6 +2923,7 @@ void CanvasItemEditor::_notification(int p_what) { int nb_control = 0; int nb_having_pivot = 0; + // Update the viewport if the canvas_item changes List<CanvasItem *> selection = _get_edited_canvas_items(); for (List<CanvasItem *>::Element *E = selection.front(); E; E = E->next()) { CanvasItem *canvas_item = E->get(); @@ -2871,15 +2969,17 @@ void CanvasItemEditor::_notification(int p_what) { nb_having_pivot++; } } + // Activate / Deactivate the pivot tool pivot_button->set_disabled(nb_having_pivot == 0); // Show / Hide the layout button presets_menu->set_visible(nb_control > 0 && nb_control == selection.size()); - for (Map<ObjectID, BoneList>::Element *E = bone_list.front(); E; E = E->next()) { + // Update the viewport if bones changes + for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) { - Object *b = ObjectDB::get_instance(E->key()); + Object *b = ObjectDB::get_instance(E->key().from); if (!b) { viewport->update(); @@ -2887,13 +2987,22 @@ void CanvasItemEditor::_notification(int p_what) { } Node2D *b2 = Object::cast_to<Node2D>(b); - if (!b2) { + if (!b2 || !b2->is_inside_tree()) { continue; } - if (b2->get_global_transform() != E->get().xform) { + Transform2D global_xform = b2->get_global_transform(); + + if (global_xform != E->get().xform) { + + E->get().xform = global_xform; + viewport->update(); + } + + Bone2D *bone = Object::cast_to<Bone2D>(b); + if (bone && bone->get_default_length() != E->get().length) { - E->get().xform = b2->get_global_transform(); + E->get().length = bone->get_default_length(); viewport->update(); } } @@ -2909,12 +3018,19 @@ void CanvasItemEditor::_notification(int p_what) { AnimationPlayerEditor::singleton->get_key_editor()->connect("visibility_changed", this, "_keying_changed"); _keying_changed(); + get_tree()->connect("node_added", this, "_tree_changed", varray()); + get_tree()->connect("node_removed", this, "_tree_changed", varray()); } else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { select_sb->set_texture(get_icon("EditorRect2D", "EditorIcons")); } + if (p_what == NOTIFICATION_EXIT_TREE) { + get_tree()->disconnect("node_added", this, "_tree_changed"); + get_tree()->disconnect("node_removed", this, "_tree_changed"); + } + if (p_what == NOTIFICATION_ENTER_TREE || p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { select_button->set_icon(get_icon("ToolSelect", "EditorIcons")); list_select_button->set_icon(get_icon("ListSelect", "EditorIcons")); @@ -2999,6 +3115,47 @@ void CanvasItemEditor::edit(CanvasItem *p_canvas_item) { editor_selection->add_node(p_canvas_item); } +void CanvasItemEditor::_queue_update_bone_list() { + + if (bone_list_dirty) + return; + + call_deferred("_update_bone_list"); + bone_list_dirty = true; +} + +void CanvasItemEditor::_update_bone_list() { + + bone_last_frame++; + + if (editor->get_edited_scene()) { + _build_bones_list(editor->get_edited_scene()); + } + + List<Map<BoneKey, BoneList>::Element *> bone_to_erase; + for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) { + if (E->get().last_pass != bone_last_frame) { + bone_to_erase.push_back(E); + continue; + } + + Node *node = Object::cast_to<Node>(ObjectDB::get_instance(E->key().from)); + if (!node || !node->is_inside_tree() || (node != get_tree()->get_edited_scene_root() && !get_tree()->get_edited_scene_root()->is_a_parent_of(node))) { + bone_to_erase.push_back(E); + continue; + } + } + while (bone_to_erase.size()) { + bone_list.erase(bone_to_erase.front()->get()); + bone_to_erase.pop_front(); + } + bone_list_dirty = false; +} + +void CanvasItemEditor::_tree_changed(Node *) { + _queue_update_bone_list(); +} + void CanvasItemEditor::_update_scrollbars() { updating_scroll = true; @@ -3023,22 +3180,7 @@ void CanvasItemEditor::_update_scrollbars() { Size2 screen_rect = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height")); Rect2 local_rect = Rect2(Point2(), viewport->get_size() - Size2(vmin.width, hmin.height)); - bone_last_frame++; - - if (editor->get_edited_scene()) { - _build_bones_list(editor->get_edited_scene()); - } - - List<Map<ObjectID, BoneList>::Element *> bone_to_erase; - for (Map<ObjectID, BoneList>::Element *E = bone_list.front(); E; E = E->next()) { - if (E->get().last_pass != bone_last_frame) { - bone_to_erase.push_back(E); - } - } - while (bone_to_erase.size()) { - bone_list.erase(bone_to_erase.front()->get()); - bone_to_erase.pop_front(); - } + _queue_update_bone_list(); // Calculate scrollable area Rect2 canvas_item_rect = Rect2(Point2(), screen_rect); @@ -3802,6 +3944,9 @@ void CanvasItemEditor::_bind_methods() { ClassDB::bind_method("_draw_viewport", &CanvasItemEditor::_draw_viewport); ClassDB::bind_method("_gui_input_viewport", &CanvasItemEditor::_gui_input_viewport); ClassDB::bind_method("_snap_changed", &CanvasItemEditor::_snap_changed); + ClassDB::bind_method("_update_bone_list", &CanvasItemEditor::_update_bone_list); + ClassDB::bind_method("_tree_changed", &CanvasItemEditor::_tree_changed); + ClassDB::bind_method(D_METHOD("_selection_result_pressed"), &CanvasItemEditor::_selection_result_pressed); ClassDB::bind_method(D_METHOD("_selection_menu_hide"), &CanvasItemEditor::_selection_menu_hide); ClassDB::bind_method(D_METHOD("set_state"), &CanvasItemEditor::set_state); @@ -4005,6 +4150,7 @@ void CanvasItemEditor::focus_selection() { CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { + bone_list_dirty = false; tool = TOOL_SELECT; undo_redo = p_editor->get_undo_redo(); editor = p_editor; @@ -4189,13 +4335,13 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { p = skeleton_menu->get_popup(); p->set_hide_on_checkable_item_selection(false); - p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_make_bones", TTR("Make Bones"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_B), SKELETON_MAKE_BONES); - p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_clear_bones", TTR("Clear Bones")), SKELETON_CLEAR_BONES); - p->add_separator(); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_show_bones", TTR("Show Bones")), SKELETON_SHOW_BONES); p->add_separator(); p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_set_ik_chain", TTR("Make IK Chain")), SKELETON_SET_IK_CHAIN); p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_clear_ik_chain", TTR("Clear IK Chain")), SKELETON_CLEAR_IK_CHAIN); + p->add_separator(); + p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_make_bones", TTR("Make Custom Bone(s) from Node(s)"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_B), SKELETON_MAKE_BONES); + p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_clear_bones", TTR("Clear Custom Bones")), SKELETON_CLEAR_BONES); p->connect("id_pressed", this, "_popup_callback"); hb->add_child(memnew(VSeparator)); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 5ca8a37610..a1957b892e 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -194,7 +194,8 @@ class CanvasItemEditor : public VBoxContainer { DRAG_V_GUIDE, DRAG_H_GUIDE, DRAG_DOUBLE_GUIDE, - DRAG_KEY_MOVE + DRAG_KEY_MOVE, + DRAG_PAN }; EditorSelection *editor_selection; @@ -263,12 +264,24 @@ class CanvasItemEditor : public VBoxContainer { struct BoneList { Transform2D xform; - Vector2 from; - Vector2 to; + float length; uint64_t last_pass; }; + uint64_t bone_last_frame; - Map<ObjectID, BoneList> bone_list; + + struct BoneKey { + ObjectID from; + ObjectID to; + _FORCE_INLINE_ bool operator<(const BoneKey &p_key) const { + if (from == p_key.from) + return to < p_key.to; + else + return from < p_key.from; + } + }; + + Map<BoneKey, BoneList> bone_list; struct PoseClipboard { Vector2 pos; @@ -336,7 +349,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); @@ -363,7 +378,7 @@ class CanvasItemEditor : public VBoxContainer { void _selection_menu_hide(); UndoRedo *undo_redo; - void _build_bones_list(Node *p_node); + bool _build_bones_list(Node *p_node); List<CanvasItem *> _get_edited_canvas_items(bool retreive_locked = false, bool remove_canvas_item_if_parent_in_selection = true); Rect2 _get_encompassing_rect_from_list(List<CanvasItem *> p_list); @@ -430,6 +445,11 @@ class CanvasItemEditor : public VBoxContainer { HSplitContainer *palette_split; VSplitContainer *bottom_split; + bool bone_list_dirty; + void _queue_update_bone_list(); + void _update_bone_list(); + void _tree_changed(Node *); + friend class CanvasItemEditorPlugin; protected: diff --git a/editor/plugins/navigation_mesh_generator.cpp b/editor/plugins/navigation_mesh_generator.cpp index 5d4e5520f4..0537c5c31f 100644 --- a/editor/plugins/navigation_mesh_generator.cpp +++ b/editor/plugins/navigation_mesh_generator.cpp @@ -280,26 +280,20 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node) _build_recast_navigation_mesh(p_nav_mesh, &ep, hf, chf, cset, poly_mesh, detail_mesh, vertices, indices); - if (hf) { - rcFreeHeightField(hf); - hf = 0; - } - if (chf) { - rcFreeCompactHeightfield(chf); - chf = 0; - } - if (cset) { - rcFreeContourSet(cset); - cset = 0; - } - if (poly_mesh) { - rcFreePolyMesh(poly_mesh); - poly_mesh = 0; - } - if (detail_mesh) { - rcFreePolyMeshDetail(detail_mesh); - detail_mesh = 0; - } + rcFreeHeightField(hf); + hf = 0; + + rcFreeCompactHeightfield(chf); + chf = 0; + + rcFreeContourSet(cset); + cset = 0; + + rcFreePolyMesh(poly_mesh); + poly_mesh = 0; + + rcFreePolyMeshDetail(detail_mesh); + detail_mesh = 0; } ep.step(TTR("Done!"), 11); } diff --git a/editor/plugins/path_editor_plugin.cpp b/editor/plugins/path_editor_plugin.cpp index 056219a575..6dde639c54 100644 --- a/editor/plugins/path_editor_plugin.cpp +++ b/editor/plugins/path_editor_plugin.cpp @@ -167,18 +167,12 @@ void PathSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p Vector3 ofs; - if (p_cancel) { - - return; - } - if (t == 0) { - if (p_cancel) { - c->set_point_in(p_idx, p_restore); return; } + ur->create_action(TTR("Set Curve In Position")); ur->add_do_method(c.ptr(), "set_point_in", idx, c->get_point_in(idx)); ur->add_undo_method(c.ptr(), "set_point_in", idx, p_restore); @@ -186,10 +180,11 @@ void PathSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p } else { if (p_cancel) { - c->set_point_out(idx, p_restore); + return; } + ur->create_action(TTR("Set Curve Out Position")); ur->add_do_method(c.ptr(), "set_point_out", idx, c->get_point_out(idx)); ur->add_undo_method(c.ptr(), "set_point_out", idx, p_restore); diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index 3a169bd780..f04e0a801c 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(); @@ -176,6 +314,9 @@ void Polygon2DEditor::_menu_option(int p_option) { undo_redo->commit_action(); } break; + case UVEDIT_GRID_SETTINGS: { + grid_settings->popup_centered_minsize(); + } break; default: { AbstractPolygon2DEditor::_menu_option(p_option); } break; @@ -239,41 +380,44 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { uv_drag_from = Vector2(mb->get_position().x, mb->get_position().y); uv_drag = true; - uv_prev = node->get_uv(); + points_prev = node->get_uv(); if (uv_edit_mode[0]->is_pressed()) { //edit uv - uv_prev = node->get_uv(); + points_prev = node->get_uv(); } else { //edit polygon - uv_prev = node->get_polygon(); + points_prev = node->get_polygon(); } uv_move_current = uv_mode; if (uv_move_current == UV_MODE_CREATE) { if (!uv_create) { - uv_prev.resize(0); + points_prev.resize(0); Vector2 tuv = mtx.affine_inverse().xform(Vector2(mb->get_position().x, mb->get_position().y)); - uv_prev.push_back(tuv); + points_prev.push_back(tuv); uv_create_to = tuv; - uv_drag_index = 0; + point_drag_index = 0; uv_drag_from = tuv; uv_drag = true; 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); + node->set_polygon(points_prev); + node->set_uv(points_prev); } else { Vector2 tuv = mtx.affine_inverse().xform(Vector2(mb->get_position().x, mb->get_position().y)); - if (uv_prev.size() > 3 && tuv.distance_to(uv_prev[0]) < 8) { + if (points_prev.size() > 3 && tuv.distance_to(points_prev[0]) < 8) { undo_redo->create_action(TTR("Create Polygon & UV")); undo_redo->add_do_method(node, "set_uv", node->get_uv()); - undo_redo->add_undo_method(node, "set_uv", uv_prev); + undo_redo->add_undo_method(node, "set_uv", points_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_undo_method(node, "set_polygon", points_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(); @@ -281,12 +425,12 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { uv_create = false; _uv_mode(UV_MODE_EDIT_POINT); } else { - uv_prev.push_back(tuv); - uv_drag_index = uv_prev.size() - 1; + points_prev.push_back(tuv); + point_drag_index = points_prev.size() - 1; uv_drag_from = tuv; } - node->set_polygon(uv_prev); - node->set_uv(uv_prev); + node->set_polygon(points_prev); + node->set_uv(points_prev); } } @@ -302,34 +446,34 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { if (uv_move_current == UV_MODE_EDIT_POINT) { - uv_drag_index = -1; - for (int i = 0; i < uv_prev.size(); i++) { + point_drag_index = -1; + for (int i = 0; i < points_prev.size(); i++) { - Vector2 tuv = mtx.xform(uv_prev[i]); + Vector2 tuv = mtx.xform(points_prev[i]); if (tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y)) < 8) { uv_drag_from = tuv; - uv_drag_index = i; + point_drag_index = i; } } - if (uv_drag_index == -1) { + if (point_drag_index == -1) { uv_drag = false; } } if (uv_move_current == UV_MODE_ADD_SPLIT) { - int drag_index = -1; - drag_index = -1; - for (int i = 0; i < uv_prev.size(); i++) { + int split_to_index = -1; + split_to_index = -1; + for (int i = 0; i < points_prev.size(); i++) { - Vector2 tuv = mtx.xform(uv_prev[i]); + Vector2 tuv = mtx.xform(points_prev[i]); if (tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y)) < 8) { - drag_index = i; + split_to_index = i; } } - if (drag_index == -1) { + if (split_to_index == -1) { split_create = false; return; } @@ -337,41 +481,65 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { if (split_create) { split_create = false; - if (drag_index < uv_drag_index) { - SWAP(drag_index, uv_drag_index); + if (split_to_index < point_drag_index) { + SWAP(split_to_index, point_drag_index); } bool valid = true; - if (drag_index == uv_drag_index) { + String split_error; + if (split_to_index == point_drag_index) { + split_error = TTR("Split point with itself."); valid = false; } - if (drag_index + 1 == uv_drag_index) { + if (split_to_index + 1 == point_drag_index) { //not a split,goes along the edge + split_error = TTR("Split can't form an existing edge."); valid = false; } - if (drag_index == uv_prev.size() - 1 && uv_drag_index == 0) { + if (split_to_index == points_prev.size() - 1 && point_drag_index == 0) { //not a split,goes along the edge + split_error = TTR("Split can't form an existing edge."); valid = false; } + for (int i = 0; i < splits_prev.size(); i += 2) { - if (splits_prev[i] == uv_drag_index && splits_prev[i + 1] == drag_index) { + + if (splits_prev[i] == point_drag_index && splits_prev[i + 1] == split_to_index) { //already exists + split_error = TTR("Split already exists."); valid = false; + break; } - if (splits_prev[i] > uv_drag_index && splits_prev[i + 1] > drag_index) { - //crossing - valid = false; + + int a_state; //-1, outside split, 0 split point, +1, inside split + if (point_drag_index == splits_prev[i] || point_drag_index == splits_prev[i + 1]) { + a_state = 0; + } else if (point_drag_index < splits_prev[i] || point_drag_index > splits_prev[i + 1]) { + a_state = -1; + } else { + a_state = 1; } - if (splits_prev[i] < uv_drag_index && splits_prev[i + 1] < drag_index) { - //crossing opposite direction + int b_state; //-1, outside split, 0 split point, +1, inside split + if (split_to_index == splits_prev[i] || split_to_index == splits_prev[i + 1]) { + b_state = 0; + } else if (split_to_index < splits_prev[i] || split_to_index > splits_prev[i + 1]) { + b_state = -1; + } else { + b_state = 1; + } + + if (b_state * a_state < 0) { + //crossing + split_error = "Split crosses another split."; valid = false; + break; } } if (valid) { - splits_prev.push_back(uv_drag_index); - splits_prev.push_back(drag_index); + splits_prev.push_back(point_drag_index); + splits_prev.push_back(split_to_index); undo_redo->create_action(TTR("Add Split")); @@ -381,13 +549,14 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { undo_redo->add_undo_method(uv_edit_draw, "update"); undo_redo->commit_action(); } else { - error->set_text(TTR("Invalid Split")); + error->set_text(TTR("Invalid Split: ") + split_error); error->popup_centered_minsize(); } } else { - uv_drag_index = drag_index; + point_drag_index = split_to_index; split_create = true; + splits_prev = node->get_splits(); uv_create_to = mtx.affine_inverse().xform(Vector2(mb->get_position().x, mb->get_position().y)); } } @@ -395,11 +564,11 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { if (uv_move_current == UV_MODE_REMOVE_SPLIT) { for (int i = 0; i < splits_prev.size(); i += 2) { - if (splits_prev[i] < 0 || splits_prev[i] >= uv_prev.size()) + if (splits_prev[i] < 0 || splits_prev[i] >= points_prev.size()) continue; - if (splits_prev[i + 1] < 0 || splits_prev[i] >= uv_prev.size()) + if (splits_prev[i + 1] < 0 || splits_prev[i] >= points_prev.size()) continue; - Vector2 e[2] = { mtx.xform(uv_prev[splits_prev[i]]), mtx.xform(uv_prev[splits_prev[i + 1]]) }; + Vector2 e[2] = { mtx.xform(points_prev[splits_prev[i]]), mtx.xform(points_prev[splits_prev[i + 1]]) }; Vector2 mp = Vector2(mb->get_position().x, mb->get_position().y); Vector2 cp = Geometry::get_closest_point_to_segment_2d(mp, e); if (cp.distance_to(mp) < 8) { @@ -419,22 +588,50 @@ 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() == points_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")); if (uv_edit_mode[0]->is_pressed()) { //edit uv undo_redo->add_do_method(node, "set_uv", node->get_uv()); - undo_redo->add_undo_method(node, "set_uv", uv_prev); + undo_redo->add_undo_method(node, "set_uv", points_prev); } else if (uv_edit_mode[1]->is_pressed()) { //edit polygon undo_redo->add_do_method(node, "set_polygon", node->get_polygon()); - undo_redo->add_undo_method(node, "set_polygon", uv_prev); + undo_redo->add_undo_method(node, "set_polygon", points_prev); } undo_redo->add_do_method(uv_edit_draw, "update"); undo_redo->add_undo_method(uv_edit_draw, "update"); 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,20 +642,23 @@ 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) { uv_drag = false; if (uv_edit_mode[0]->is_pressed()) { //edit uv - node->set_uv(uv_prev); + node->set_uv(points_prev); } else if (uv_edit_mode[1]->is_pressed()) { //edit polygon - node->set_polygon(uv_prev); + node->set_polygon(points_prev); } uv_edit_draw->update(); } 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()) { @@ -494,8 +694,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } break; case UV_MODE_EDIT_POINT: { - PoolVector<Vector2> uv_new = uv_prev; - uv_new.set(uv_drag_index, uv_new[uv_drag_index] + drag); + PoolVector<Vector2> uv_new = points_prev; + uv_new.set(point_drag_index, uv_new[point_drag_index] + drag); if (uv_edit_mode[0]->is_pressed()) { //edit uv node->set_uv(uv_new); @@ -505,7 +705,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } break; case UV_MODE_MOVE: { - PoolVector<Vector2> uv_new = uv_prev; + PoolVector<Vector2> uv_new = points_prev; for (int i = 0; i < uv_new.size(); i++) uv_new.set(i, uv_new[i] + drag); @@ -519,16 +719,16 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { case UV_MODE_ROTATE: { Vector2 center; - PoolVector<Vector2> uv_new = uv_prev; + PoolVector<Vector2> uv_new = points_prev; for (int i = 0; i < uv_new.size(); i++) - center += uv_prev[i]; + center += points_prev[i]; center /= uv_new.size(); float angle = (uv_drag_from - mtx.xform(center)).normalized().angle_to((uv_drag_to - mtx.xform(center)).normalized()); for (int i = 0; i < uv_new.size(); i++) { - Vector2 rel = uv_prev[i] - center; + Vector2 rel = points_prev[i] - center; rel = rel.rotated(angle); uv_new.set(i, center + rel); } @@ -543,10 +743,10 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { case UV_MODE_SCALE: { Vector2 center; - PoolVector<Vector2> uv_new = uv_prev; + PoolVector<Vector2> uv_new = points_prev; for (int i = 0; i < uv_new.size(); i++) - center += uv_prev[i]; + center += points_prev[i]; center /= uv_new.size(); float from_dist = uv_drag_from.distance_to(mtx.xform(center)); @@ -557,7 +757,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { float scale = to_dist / from_dist; for (int i = 0; i < uv_new.size(); i++) { - Vector2 rel = uv_prev[i] - center; + Vector2 rel = points_prev[i] - center; rel = rel * scale; uv_new.set(i, center + rel); } @@ -569,10 +769,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 = points_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(); } } @@ -607,6 +837,8 @@ void Polygon2DEditor::_uv_draw() { if (base_tex.is_null()) return; + String warning; + Transform2D mtx; mtx.elements[2] = -uv_draw_ofs; mtx.scale_basis(Vector2(uv_draw_zoom, uv_draw_zoom)); @@ -649,6 +881,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,12 +912,19 @@ 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])); } if (split_create) { - Vector2 from = uvs[uv_drag_index]; + Vector2 from = uvs[point_drag_index]; Vector2 to = uv_create_to; uv_edit_draw->draw_line(mtx.xform(from), mtx.xform(to), Color(0.9, 0.5, 0.5), 2); } @@ -682,6 +939,55 @@ 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) { + + NodePath bone_path; + 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_path = node->get_bone_path(i); + break; + } + } + + //draw skeleton + NodePath skeleton_path = node->get_skeleton(); + if (node->has_node(skeleton_path)) { + Skeleton2D *skeleton = Object::cast_to<Skeleton2D>(node->get_node(skeleton_path)); + if (skeleton) { + for (int i = 0; i < skeleton->get_bone_count(); i++) { + + Bone2D *bone = skeleton->get_bone(i); + if (bone->get_rest() == Transform2D(0, 0, 0, 0, 0, 0)) + continue; //not set + + bool current = bone_path == skeleton->get_path_to(bone); + + for (int j = 0; j < bone->get_child_count(); j++) { + + Node2D *n = Object::cast_to<Node2D>(bone->get_child(j)); + if (!n) + continue; + + bool edit_bone = n->has_meta("_edit_bone_") && n->get_meta("_edit_bone_"); + if (edit_bone) { + + Transform2D bone_xform = node->get_global_transform().affine_inverse() * (skeleton->get_global_transform() * bone->get_skeleton_rest()); + Transform2D endpoint_xform = bone_xform * n->get_transform(); + + Color color = current ? Color(1, 1, 1) : Color(0.5, 0.5, 0.5); + uv_edit_draw->draw_line(mtx.xform(bone_xform.get_origin()), mtx.xform(endpoint_xform.get_origin()), Color(0, 0, 0), current ? 5 : 4); + uv_edit_draw->draw_line(mtx.xform(bone_xform.get_origin()), mtx.xform(endpoint_xform.get_origin()), color, current ? 3 : 2); + } + } + } + } + } + + //draw paint circle + 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 +1017,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 +1065,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 +1104,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); @@ -806,6 +1149,8 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : uv_menu->get_popup()->add_item(TTR("UV->Polygon"), UVEDIT_UV_TO_POLYGON); uv_menu->get_popup()->add_separator(); uv_menu->get_popup()->add_item(TTR("Clear UV"), UVEDIT_UV_CLEAR); + uv_menu->get_popup()->add_separator(); + uv_menu->get_popup()->add_item(TTR("Grid Settings"), UVEDIT_GRID_SETTINGS); uv_menu->get_popup()->connect("id_pressed", this, "_menu_option"); uv_mode_hb->add_child(memnew(VSeparator)); @@ -828,8 +1173,11 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : b_snap_grid->set_tooltip(TTR("Show Grid")); b_snap_grid->connect("toggled", this, "_set_show_grid"); - uv_mode_hb->add_child(memnew(VSeparator)); - uv_mode_hb->add_child(memnew(Label(TTR("Grid Offset:")))); + grid_settings = memnew(AcceptDialog); + grid_settings->set_title(TTR("Configure Grid:")); + add_child(grid_settings); + VBoxContainer *grid_settings_vb = memnew(VBoxContainer); + grid_settings->add_child(grid_settings_vb); SpinBox *sb_off_x = memnew(SpinBox); sb_off_x->set_min(-256); @@ -838,7 +1186,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : sb_off_x->set_value(snap_offset.x); sb_off_x->set_suffix("px"); sb_off_x->connect("value_changed", this, "_set_snap_off_x"); - uv_mode_hb->add_child(sb_off_x); + grid_settings_vb->add_margin_child(TTR("Grid Offset X:"), sb_off_x); SpinBox *sb_off_y = memnew(SpinBox); sb_off_y->set_min(-256); @@ -847,10 +1195,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : sb_off_y->set_value(snap_offset.y); sb_off_y->set_suffix("px"); sb_off_y->connect("value_changed", this, "_set_snap_off_y"); - uv_mode_hb->add_child(sb_off_y); - - uv_mode_hb->add_child(memnew(VSeparator)); - uv_mode_hb->add_child(memnew(Label(TTR("Grid Step:")))); + grid_settings_vb->add_margin_child(TTR("Grid Offset Y:"), sb_off_y); SpinBox *sb_step_x = memnew(SpinBox); sb_step_x->set_min(-256); @@ -859,7 +1204,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : sb_step_x->set_value(snap_step.x); sb_step_x->set_suffix("px"); sb_step_x->connect("value_changed", this, "_set_snap_step_x"); - uv_mode_hb->add_child(sb_step_x); + grid_settings_vb->add_margin_child(TTR("Grid Step X:"), sb_step_x); SpinBox *sb_step_y = memnew(SpinBox); sb_step_y->set_min(-256); @@ -868,7 +1213,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : sb_step_y->set_value(snap_step.y); sb_step_y->set_suffix("px"); sb_step_y->connect("value_changed", this, "_set_snap_step_y"); - uv_mode_hb->add_child(sb_step_y); + grid_settings_vb->add_margin_child(TTR("Grid Step Y:"), sb_step_y); uv_mode_hb->add_child(memnew(VSeparator)); uv_icon_zoom = memnew(TextureRect); @@ -878,8 +1223,10 @@ 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->set_custom_minimum_size(Size2(80 * EDSCALE, 0)); uv_zoom_value = memnew(SpinBox); uv_zoom->share(uv_zoom_value); uv_zoom_value->set_custom_minimum_size(Size2(50, 0)); @@ -893,14 +1240,29 @@ 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 to Polygon"))); + 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; - uv_drag_index = -1; + point_drag_index = -1; uv_drag = false; 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..f9b42a21c2 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> */ @@ -45,7 +45,8 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { MODE_EDIT_UV = MODE_CONT, UVEDIT_POLYGON_TO_UV, UVEDIT_UV_TO_POLYGON, - UVEDIT_UV_CLEAR + UVEDIT_UV_CLEAR, + UVEDIT_GRID_SETTINGS }; @@ -57,10 +58,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,15 +81,32 @@ 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; + AcceptDialog *grid_settings; + + void _sync_bones(); + void _update_bone_list(); + Vector2 uv_draw_ofs; float uv_draw_zoom; - PoolVector<Vector2> uv_prev; + PoolVector<Vector2> points_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; - int uv_drag_index; + int point_drag_index; bool uv_drag; bool uv_create; bool split_create; @@ -118,6 +138,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/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index c872a6f28b..45f5e667fa 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -746,6 +746,8 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c _goto_line(p_row); + result.class_name = result.class_name.trim_prefix("_"); + switch (result.type) { case ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION: { @@ -1007,6 +1009,10 @@ void ScriptTextEditor::_edit_option(int p_op) { } int next_line = to_line + 1; + if (to_line >= tx->get_line_count() - 1) { + tx->set_line(to_line, tx->get_line(to_line) + "\n"); + } + tx->begin_complex_operation(); for (int i = from_line; i <= to_line; i++) { diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 9543b4125e..bd0406a3cb 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -5083,8 +5083,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { ED_SHORTCUT("spatial_editor/tool_rotate", TTR("Tool Rotate"), KEY_E); ED_SHORTCUT("spatial_editor/tool_scale", TTR("Tool Scale"), KEY_R); - ED_SHORTCUT("spatial_editor/display_wireframe", TTR("Display Wireframe"), KEY_Z); - ED_SHORTCUT("spatial_editor/freelook_toggle", TTR("Toggle Freelook"), KEY_MASK_SHIFT + KEY_F); PopupMenu *p; 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/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 2427cd966b..92b95963f9 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -744,7 +744,7 @@ ThemeEditor::ThemeEditor() { item = test_tree->create_item(test_tree->get_root()); item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); item->set_editable(0, true); - item->set_text(0, "check"); + item->set_text(0, "Check"); item = test_tree->create_item(test_tree->get_root()); item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE); item->set_editable(0, true); @@ -753,7 +753,7 @@ ThemeEditor::ThemeEditor() { item = test_tree->create_item(test_tree->get_root()); item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE); item->set_editable(0, true); - item->set_text(0, TTR("Have,Many,Several,Options!")); + item->set_text(0, TTR("Has,Many,Options")); item->set_range(0, 2); VBoxContainer *third_vb = memnew(VBoxContainer); @@ -784,58 +784,6 @@ ThemeEditor::ThemeEditor() { main_hb->add_constant_override("separation", 20 * EDSCALE); - /* - test_h_scroll = memnew( HScrollBar ); - test_h_scroll->set_position( Point2( 25, 225 ) ); - test_h_scroll->set_size( Point2( 150, 5 ) ); - panel->add_child(test_h_scroll); - - line_edit = memnew( LineEdit ); - line_edit->set_position( Point2( 25, 275 ) ); - line_edit->set_size( Point2( 150, 5 ) ); - line_edit->set_text("Line Edit"); - panel->add_child(line_edit); - - test_v_scroll = memnew( VScrollBar ); - test_v_scroll->set_position( Point2( 200, 25 ) ); - test_v_scroll->set_size( Point2( 5, 150 ) ); - panel->add_child(test_v_scroll); - - test_tree = memnew(Tree); - test_tree->set_position( Point2( 300, 25 ) ); - test_tree->set_size( Point2( 200, 200 ) ); - panel->add_child(test_tree); - - - TreeItem *item = test_tree->create_item(); - item->set_editable(0,true); - item->set_text(0,"root"); - item = test_tree->create_item( test_tree->get_root() ); - item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); - item->set_editable(0,true); - item->set_text(0,"check"); - item = test_tree->create_item( test_tree->get_root() ); - item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE); - item->set_editable(0,true); - item->set_range_config(0,0,20,0.1); - item->set_range(0,2); - item = test_tree->create_item( test_tree->get_root() ); - item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE); - item->set_editable(0,true); - item->set_text(0,"Have,Many,Several,Options!")); - item->set_range(0,2); - - Button *fd_button= memnew( Button ); - fd_button->set_position(Point2(300,275)); - fd_button->set_text("Open File Dialog"); - panel->add_child(fd_button); - - test_file_dialog = memnew( EditorFileDialog ); - panel->add_child(test_file_dialog); - - fd_button->connect("pressed", this,"_open_file_dialog"); -*/ - add_del_dialog = memnew(ConfirmationDialog); add_del_dialog->hide(); add_child(add_del_dialog); diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index 14c584fa35..72b3af5a09 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -724,7 +724,11 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { if (mb->get_shift()) { +#ifdef APPLE_STYLE_KEYS + if (mb->get_command()) +#else if (mb->get_control()) +#endif tool = TOOL_RECTANGLE_PAINT; else tool = TOOL_LINE_PAINT; @@ -734,9 +738,11 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { return true; } - +#ifdef APPLE_STYLE_KEYS + if (mb->get_command()) { +#else if (mb->get_control()) { - +#endif tool = TOOL_PICKING; _pick_tile(over_tile); @@ -940,8 +946,11 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); if (mb->get_shift()) { - +#ifdef APPLE_STYLE_KEYS + if (mb->get_command()) +#else if (mb->get_control()) +#endif tool = TOOL_RECTANGLE_ERASE; else tool = TOOL_LINE_ERASE; 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 41692e805f..385fa24ad8 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -149,6 +149,7 @@ void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) { p_library->tile_set_light_occluder(id, occluder); p_library->tile_set_occluder_offset(id, -phys_offset); p_library->tile_set_navigation_polygon_offset(id, -phys_offset); + p_library->tile_set_z_index(id, mi->get_z_index()); } } @@ -805,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) { @@ -868,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) { @@ -1146,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; |