summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/editor_settings.cpp4
-rw-r--r--editor/icons/icon_bone_2_d.svg61
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp227
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h25
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp147
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.h4
6 files changed, 349 insertions, 119 deletions
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 15d3b28da8..9f55ae32b0 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -454,9 +454,11 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("editors/2d/guides_color", Color(0.6, 0.0, 0.8));
_initial_set("editors/2d/bone_width", 5);
_initial_set("editors/2d/bone_color1", Color(1.0, 1.0, 1.0, 0.9));
- _initial_set("editors/2d/bone_color2", Color(0.75, 0.75, 0.75, 0.9));
+ _initial_set("editors/2d/bone_color2", Color(0.6, 0.6, 0.6, 0.9));
_initial_set("editors/2d/bone_selected_color", Color(0.9, 0.45, 0.45, 0.9));
_initial_set("editors/2d/bone_ik_color", Color(0.9, 0.9, 0.45, 0.9));
+ _initial_set("editors/2d/bone_outline_color", Color(0.35, 0.35, 0.35));
+ _initial_set("editors/2d/bone_outline_size", 2);
_initial_set("editors/2d/keep_margins_when_changing_anchors", false);
_initial_set("editors/2d/warped_mouse_panning", true);
_initial_set("editors/2d/simple_spacebar_panning", false);
diff --git a/editor/icons/icon_bone_2_d.svg b/editor/icons/icon_bone_2_d.svg
new file mode 100644
index 0000000000..efcbc17e13
--- /dev/null
+++ b/editor/icons/icon_bone_2_d.svg
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ version="1.1"
+ viewBox="0 0 16 16"
+ id="svg6"
+ sodipodi:docname="icon_bone_2d.svg"
+ inkscape:version="0.92.3 (2405546, 2018-03-11)">
+ <metadata
+ id="metadata12">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs10" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="836"
+ inkscape:window-height="480"
+ id="namedview8"
+ showgrid="false"
+ inkscape:zoom="14.75"
+ inkscape:cx="8"
+ inkscape:cy="8"
+ inkscape:window-x="67"
+ inkscape:window-y="27"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="svg6" />
+ <g
+ transform="translate(0 -1036.4)"
+ id="g4"
+ style="fill:#a5b7f3;fill-opacity:1">
+ <path
+ d="m10.478 1037.4a2.4664 2.4663 0 0 0 -1.7804 0.7205 2.4664 2.4663 0 0 0 -0.31408 3.1041l-3.559 3.5608a2.4664 2.4663 0 0 0 -3.1023 0.3121 2.4664 2.4663 0 0 0 0 3.4876 2.4664 2.4663 0 0 0 1.397 0.6955 2.4664 2.4663 0 0 0 0.69561 1.397 2.4664 2.4663 0 0 0 3.4877 0 2.4664 2.4663 0 0 0 0.31408 -3.1041l3.5609-3.5608a2.4664 2.4663 0 0 0 3.1004 -0.3102 2.4664 2.4663 0 0 0 0 -3.4875 2.4664 2.4663 0 0 0 -1.397 -0.6974 2.4664 2.4663 0 0 0 -0.69561 -1.3971 2.4664 2.4663 0 0 0 -1.7072 -0.7205z"
+ fill="#fc9c9c"
+ id="path2"
+ style="fill:#a5b7f3;fill-opacity:1" />
+ </g>
+</svg>
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index ff38e12250..8cad40c9ce 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"
@@ -2586,43 +2587,58 @@ 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 *n2d = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key()));
- if (!n2d)
- continue;
+ 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));
- if (!n2d->get_parent())
+ if (!from_node->is_inside_tree())
+ continue; //may have been removed
+ if (!from_node)
continue;
- CanvasItem *pi = n2d->get_parent_item();
-
- Node2D *pn2d = Object::cast_to<Node2D>(n2d->get_parent());
-
- if (!pn2d)
+ if (!to_node && E->get().length == 0)
continue;
- Vector2 from = transform.xform(pn2d->get_global_position());
- Vector2 to = transform.xform(n2d->get_global_position());
+ Vector2 from = transform.xform(from_node->get_global_position());
+ Vector2 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)));
E->get().from = from;
E->get().to = to;
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);
@@ -2635,14 +2651,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());
}
}
}
@@ -2766,26 +2794,75 @@ 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 *c = Object::cast_to<CanvasItem>(p_node);
- if (c && c->is_visible_in_tree()) {
- if (c->has_meta("_edit_bone_")) {
+ if (!c) {
+ return false;
+ }
+
+ Node *p = c->get_parent();
+ if (!p) {
+ return false;
+ }
+
+ if (!c->is_visible()) {
+ return false;
+ }
+
+ if (Object::cast_to<Bone2D>(c)) {
- ObjectID id = c->get_instance_id();
- if (!bone_list.has(id)) {
- BoneList bone;
- bone_list[id] = bone;
+ if (Object::cast_to<Bone2D>(p)) {
+ //add as bone->parent relationship
+ BoneKey bk;
+ bk.from = p->get_instance_id();
+ bk.to = c->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) {
+ BoneKey bk;
+ bk.from = c->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 (c->has_meta("_edit_bone_")) {
+
+ BoneKey bk;
+ bk.from = c->get_parent()->get_instance_id();
+ bk.to = c->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() {
@@ -2912,9 +2989,9 @@ void CanvasItemEditor::_notification(int p_what) {
// 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()) {
+ 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();
@@ -2926,9 +3003,18 @@ void CanvasItemEditor::_notification(int p_what) {
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 = b2->get_global_transform();
+ 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().length = bone->get_default_length();
viewport->update();
}
}
@@ -2944,12 +3030,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"));
@@ -3034,6 +3127,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;
@@ -3058,22 +3192,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);
@@ -3837,6 +3956,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);
@@ -4040,6 +4162,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;
@@ -4224,13 +4347,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 373a4b799e..eb3595cae6 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -264,12 +264,26 @@ class CanvasItemEditor : public VBoxContainer {
struct BoneList {
Transform2D xform;
+ float length;
+ uint64_t last_pass;
Vector2 from;
Vector2 to;
- 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;
@@ -366,7 +380,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);
@@ -433,6 +447,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/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 14d2550000..f04e0a801c 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -380,23 +380,23 @@ 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;
@@ -404,18 +404,18 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
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");
@@ -425,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);
}
}
@@ -446,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;
}
@@ -481,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"));
@@ -525,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));
}
}
@@ -539,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) {
@@ -574,7 +599,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
}
}
- if (bone_selected != -1 && node->get_bone_weights(bone_selected).size() == uv_prev.size()) {
+ 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;
@@ -588,10 +613,10 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
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");
@@ -624,9 +649,9 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
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) {
@@ -669,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);
@@ -680,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);
@@ -694,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);
}
@@ -718,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));
@@ -732,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);
}
@@ -760,7 +785,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
PoolVector<float>::Write w = painted_weights.write();
PoolVector<float>::Read r = prev_weights.read();
- PoolVector<Vector2>::Read rv = uv_prev.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) {
@@ -899,7 +924,7 @@ void Polygon2DEditor::_uv_draw() {
}
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);
}
@@ -1232,7 +1257,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) :
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;
diff --git a/editor/plugins/polygon_2d_editor_plugin.h b/editor/plugins/polygon_2d_editor_plugin.h
index cf529b39f7..f9b42a21c2 100644
--- a/editor/plugins/polygon_2d_editor_plugin.h
+++ b/editor/plugins/polygon_2d_editor_plugin.h
@@ -99,14 +99,14 @@ class Polygon2DEditor : public AbstractPolygon2DEditor {
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;