Made bone handling for actual Bone2D a special case. Make custom bones appear like a custom (less important) option now.

This commit is contained in:
Juan Linietsky 2018-05-04 16:46:32 -03:00
parent e68cbec1fa
commit bf561c4946
5 changed files with 186 additions and 36 deletions

View file

@ -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>

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -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"
@ -2590,27 +2591,27 @@ void CanvasItemEditor::_draw_bones() {
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)
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 (!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());
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;
@ -2635,7 +2636,7 @@ void CanvasItemEditor::_draw_bones() {
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);
@ -2649,7 +2650,8 @@ void CanvasItemEditor::_draw_bones() {
}
Vector<Color> outline_colors;
if (editor_selection->is_selected(pi)) {
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);
@ -2790,26 +2792,71 @@ 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;
ObjectID id = c->get_instance_id();
if (!bone_list.has(id)) {
BoneList bone;
bone_list[id] = bone;
CanvasItem *p = c->get_parent_item();
if (!p)
return false;
if (!p->is_visible())
return false;
if (Object::cast_to<Bone2D>(c)) {
if (Object::cast_to<Bone2D>(p)) {
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() {
@ -2936,9 +2983,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();
@ -2950,9 +2997,18 @@ void CanvasItemEditor::_notification(int p_what) {
continue;
}
if (b2->get_global_transform() != E->get().xform) {
Transform2D global_xform = b2->get_global_transform();
E->get().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().length = bone->get_default_length();
viewport->update();
}
}
@ -3088,8 +3144,8 @@ void CanvasItemEditor::_update_scrollbars() {
_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()) {
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);
}
@ -4248,13 +4304,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));

View file

@ -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);

View file

@ -56,7 +56,11 @@ void Bone2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_skeleton_rest"), &Bone2D::get_skeleton_rest);
ClassDB::bind_method(D_METHOD("get_index_in_skeleton"), &Bone2D::get_index_in_skeleton);
ClassDB::bind_method(D_METHOD("set_default_length", "default_length"), &Bone2D::set_default_length);
ClassDB::bind_method(D_METHOD("get_default_length"), &Bone2D::get_default_length);
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D,"rest"),"set_rest","get_rest");
ADD_PROPERTY(PropertyInfo(Variant::REAL,"default_length",PROPERTY_HINT_RANGE,"1,1024,1"),"set_default_length","get_default_length");
}
void Bone2D::set_rest(const Transform2D &p_rest) {
@ -84,6 +88,16 @@ void Bone2D::apply_rest() {
set_transform(rest);
}
void Bone2D::set_default_length(float p_length) {
default_length=p_length;
}
float Bone2D::get_default_length() const {
return default_length;
}
int Bone2D::get_index_in_skeleton() const {
ERR_FAIL_COND_V(!skeleton,-1);
skeleton->_update_bone_setup();
@ -118,6 +132,7 @@ Bone2D::Bone2D() {
skeleton = NULL;
parent_bone = NULL;
skeleton_index=-1;
default_length=16;
set_notify_local_transform(true);
//this is a clever hack so the bone knows no rest has been set yet, allowing to show an error.
for(int i=0;i<3;i++) {

View file

@ -11,6 +11,7 @@ class Bone2D : public Node2D {
Bone2D *parent_bone;
Skeleton2D *skeleton;
Transform2D rest;
float default_length;
friend class Skeleton2D;
int skeleton_index;
@ -27,6 +28,9 @@ public:
String get_configuration_warning() const;
void set_default_length(float p_length);
float get_default_length() const;
int get_index_in_skeleton() const;
Bone2D();