From 4c3c510a807ee57c564e7b8b7885cf4fa113bbd5 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Wed, 2 May 2018 11:00:35 -0300 Subject: WIP Polygon2D weight editing --- editor/icons/icon_paint_vertex.svg | 58 ++++++ editor/icons/icon_unpaint_vertex.svg | 58 ++++++ editor/plugins/polygon_2d_editor_plugin.cpp | 296 +++++++++++++++++++++++++++- editor/plugins/polygon_2d_editor_plugin.h | 23 ++- scene/2d/polygon_2d.cpp | 84 ++++++++ scene/2d/polygon_2d.h | 24 +++ scene/2d/skeleton_2d.cpp | 2 + scene/register_scene_types.cpp | 3 + 8 files changed, 541 insertions(+), 7 deletions(-) create mode 100644 editor/icons/icon_paint_vertex.svg create mode 100644 editor/icons/icon_unpaint_vertex.svg 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 @@ + + + + + + image/svg+xml + + + + + + + + + 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 @@ + + + + + + image/svg+xml + + + + + + + + + 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(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 weights; + int wc = node->get_polygon().size(); + + for (int j = 0; j < prev_bones.size(); j += 2) { + NodePath pvp = prev_bones[j]; + PoolVector 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::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(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 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 &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 &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 &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(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 &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 &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 &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 &p_input) { } } break; } + + if (bone_painting) { + bone_paint_pos = Vector2(mm->get_position().x, mm->get_position().y); + PoolVector 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::Write w = painted_weights.write(); + PoolVector::Read r = prev_weights.read(); + PoolVector::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::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(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 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 */ @@ -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 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 prev_weights; + Vector2 bone_paint_pos; + + void _sync_bones(); + void _update_bone_list(); + Vector2 uv_draw_ofs; float uv_draw_zoom; PoolVector uv_prev; PoolVector uv_create_uv_prev; PoolVector uv_create_poly_prev; + Array uv_create_bones_prev; PoolVector 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/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 &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 Polygon2D::get_bone_weights(int p_index) const { + + ERR_FAIL_INDEX_V(p_index, bone_weights.size(), PoolVector()); + 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 &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 vertex_colors; PoolVector splits; + struct Bone { + NodePath path; + PoolVector weights; + }; + + Vector bone_weights; + Color color; Ref 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 &p_weights = PoolVector()); + int get_bone_count() const; + NodePath get_bone_path(int p_index) const; + PoolVector 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 &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(parent)) break; //skeletons must be chained to Bone2Ds. + + parent = parent->get_parent(); } if (skeleton) { 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(); ClassDB::register_class(); ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); -- cgit v1.2.3