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:
parent
e68cbec1fa
commit
bf561c4946
5 changed files with 186 additions and 36 deletions
61
editor/icons/icon_bone_2_d.svg
Normal file
61
editor/icons/icon_bone_2_d.svg
Normal 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 |
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue