diff options
Diffstat (limited to 'scene/2d')
-rw-r--r-- | scene/2d/line_2d.cpp | 3 | ||||
-rw-r--r-- | scene/2d/polygon_2d.cpp | 86 | ||||
-rw-r--r-- | scene/2d/skeleton_2d.cpp | 69 | ||||
-rw-r--r-- | scene/2d/skeleton_2d.h | 7 |
4 files changed, 152 insertions, 13 deletions
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index 229c2c6fe8..3e61dd05f4 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -270,7 +270,8 @@ void Line2D::_draw() { lb.indices, lb.vertices, lb.colors, - lb.uvs, + lb.uvs, Vector<int>(), Vector<float>(), + texture_rid); // DEBUG diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index eed26f5399..4d6ebc81c3 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -30,7 +30,7 @@ #include "polygon_2d.h" #include "core/math/geometry.h" - +#include "skeleton_2d.h" Dictionary Polygon2D::_edit_get_state() const { Dictionary state = Node2D::_edit_get_state(); state["offset"] = offset; @@ -91,8 +91,20 @@ void Polygon2D::_notification(int p_what) { if (polygon.size() < 3) return; + Skeleton2D *skeleton_node = NULL; + if (has_node(skeleton)) { + skeleton_node = Object::cast_to<Skeleton2D>(get_node(skeleton)); + } + + if (skeleton_node) + VS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), skeleton_node->get_skeleton()); + else + VS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), RID()); + Vector<Vector2> points; Vector<Vector2> uvs; + Vector<int> bones; + Vector<float> weights; points.resize(polygon.size()); @@ -180,6 +192,70 @@ void Polygon2D::_notification(int p_what) { } } + if (!invert && bone_weights.size()) { + //a skeleton is set! fill indices and weights + int vc = points.size(); + bones.resize(vc * 4); + weights.resize(vc * 4); + + int *bonesw = bones.ptrw(); + float *weightsw = weights.ptrw(); + + for (int i = 0; i < vc * 4; i++) { + bonesw[i] = 0; + weightsw[i] = 0; + } + + for (int i = 0; i < bone_weights.size(); i++) { + if (bone_weights[i].weights.size() != points.size()) { + continue; //different number of vertices, sorry not using. + } + if (!skeleton_node->has_node(bone_weights[i].path)) { + continue; //node does not exist + } + Bone2D *bone = Object::cast_to<Bone2D>(skeleton_node->get_node(bone_weights[i].path)); + if (!bone) { + continue; + } + + int bone_index = bone->get_index_in_skeleton(); + PoolVector<float>::Read r = bone_weights[i].weights.read(); + for (int j = 0; j < vc; j++) { + if (r[j] == 0.0) + continue; //weight is unpainted, skip + //find an index with a weight + for (int k = 0; k < 4; k++) { + if (weightsw[j * 4 + k] < r[j]) { + //this is less than this weight, insert weight! + for (int l = 3; l > k; l--) { + weightsw[j * 4 + l] = weightsw[j * 4 + l - 1]; + bonesw[j * 4 + l] = bonesw[j * 4 + l - 1]; + } + weightsw[j * 4 + k] = r[j]; + bonesw[j * 4 + k] = bone_index; + break; + } + } + } + } + + //normalize the weights + for (int i = 0; i < vc; i++) { + float tw = 0; + for (int j = 0; j < 4; j++) { + tw += weightsw[i * 4 + j]; + } + if (tw == 0) + continue; //unpainted, do nothing + + //normalize + for (int j = 0; j < 4; j++) { + weightsw[i * 4 + j] /= tw; + // print_line("point " + itos(i) + " idx " + itos(j) + " index: " + itos(bonesw[i * 4 + j]) + " weight: " + rtos(weightsw[i * 4 + j])); + } + } + } + Vector<Color> colors; int color_len = vertex_colors.size(); colors.resize(len); @@ -197,7 +273,8 @@ void Polygon2D::_notification(int p_what) { // VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, texture.is_valid() ? texture->get_rid() : RID()); if (invert || splits.size() == 0) { - VS::get_singleton()->canvas_item_add_polygon(get_canvas_item(), points, colors, uvs, texture.is_valid() ? texture->get_rid() : RID(), RID(), antialiased); + Vector<int> indices = Geometry::triangulate_polygon(points); + VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID()); } else { //use splits Vector<int> loop; @@ -268,7 +345,7 @@ void Polygon2D::_notification(int p_what) { //print_line("loops: " + itos(loops.size()) + " indices: " + itos(indices.size())); - VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, texture.is_valid() ? texture->get_rid() : RID()); + VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID()); } } break; @@ -488,9 +565,12 @@ void Polygon2D::_set_bones(const Array &p_bones) { } void Polygon2D::set_skeleton(const NodePath &p_skeleton) { + if (skeleton == p_skeleton) + return; skeleton = p_skeleton; update(); } + NodePath Polygon2D::get_skeleton() const { return skeleton; } diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp index 3b3561bc1c..9197127235 100644 --- a/scene/2d/skeleton_2d.cpp +++ b/scene/2d/skeleton_2d.cpp @@ -28,6 +28,11 @@ void Bone2D::_notification(int p_what) { skeleton->_make_transform_dirty(); } } + if (p_what == NOTIFICATION_MOVED_IN_PARENT) { + if (skeleton) { + skeleton->_make_bone_setup_dirty(); + } + } if (p_what == NOTIFICATION_EXIT_TREE) { if (skeleton) { @@ -48,12 +53,18 @@ void Bone2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_rest", "rest"), &Bone2D::set_rest); ClassDB::bind_method(D_METHOD("get_rest"), &Bone2D::get_rest); ClassDB::bind_method(D_METHOD("apply_rest"), &Bone2D::apply_rest); + 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); + + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D,"rest"),"set_rest","get_rest"); } void Bone2D::set_rest(const Transform2D &p_rest) { rest = p_rest; if (skeleton) skeleton->_make_bone_setup_dirty(); + + update_configuration_warning(); } Transform2D Bone2D::get_rest() const { @@ -73,22 +84,45 @@ void Bone2D::apply_rest() { set_transform(rest); } +int Bone2D::get_index_in_skeleton() const { + ERR_FAIL_COND_V(!skeleton,-1); + skeleton->_update_bone_setup(); + return skeleton_index; +} String Bone2D::get_configuration_warning() const { + + String warning = Node2D::get_configuration_warning(); if (!skeleton) { + if (warning!=String()) { + warning+="\n"; + } if (parent_bone) { - return TTR("This Bone2D chain should end at a Skeleton2D node."); + warning+=TTR("This Bone2D chain should end at a Skeleton2D node."); } else { - return TTR("A Bone2D only works with a Skeleton2D or another Bone2D as parent node."); + warning+=TTR("A Bone2D only works with a Skeleton2D or another Bone2D as parent node."); + } + } + + if (rest==Transform2D(0,0,0,0,0,0)) { + if (warning!=String()) { + warning+="\n"; } + warning+=TTR("This bone lacks a proper REST pose. Go to the Skeleton2D node and set one."); + } - return Node2D::get_configuration_warning(); + return warning; } Bone2D::Bone2D() { skeleton = NULL; parent_bone = NULL; + skeleton_index=-1; 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++) { + rest[i]=Vector2(0,0); + } } ////////////////////////////////////// @@ -114,7 +148,14 @@ void Skeleton2D::_update_bone_setup() { bones.sort(); //sorty so they are always in the same order/index for (int i = 0; i < bones.size(); i++) { - bones[i].rest_inverse = bones[i].bone->get_skeleton_rest(); //bind pose + bones[i].rest_inverse = bones[i].bone->get_skeleton_rest().affine_inverse(); //bind pose + bones[i].bone->skeleton_index=i; + Bone2D *parent_bone = Object::cast_to<Bone2D>(bones[i].bone->get_parent()); + if (parent_bone) { + bones[i].parent_index=parent_bone->skeleton_index; + } else { + bones[i].parent_index=-1; + } } transform_dirty = true; @@ -142,13 +183,20 @@ void Skeleton2D::_update_transform() { transform_dirty = false; - Transform2D global_xform = get_global_transform(); - Transform2D global_xform_inverse = global_xform.affine_inverse(); + for (int i = 0; i < bones.size(); i++) { + + ERR_CONTINUE(bones[i].parent_index>=i); + if (bones[i].parent_index>=0) { + bones[i].accum_transform = bones[bones[i].parent_index].accum_transform * bones[i].bone->get_transform(); + } else { + bones[i].accum_transform = bones[i].bone->get_transform(); + } + } for (int i = 0; i < bones.size(); i++) { - Transform2D final_xform = bones[i].rest_inverse * bones[i].bone->get_relative_transform_to_parent(this); - VS::get_singleton()->skeleton_bone_set_transform_2d(skeleton, i, global_xform * (final_xform * global_xform_inverse)); + Transform2D final_xform = bones[i].accum_transform * bones[i].rest_inverse; + VS::get_singleton()->skeleton_bone_set_transform_2d(skeleton, i, final_xform); } } @@ -179,10 +227,12 @@ void Skeleton2D::_notification(int p_what) { _update_bone_setup(); if (transform_dirty) _update_transform(); + + request_ready(); } if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { - _make_transform_dirty(); + VS::get_singleton()->skeleton_set_base_transform_2d(skeleton,get_global_transform()); } } @@ -203,6 +253,7 @@ void Skeleton2D::_bind_methods() { Skeleton2D::Skeleton2D() { bone_setup_dirty = true; transform_dirty = true; + skeleton = VS::get_singleton()->skeleton_create(); } diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h index 49199f684f..9ae74b56d3 100644 --- a/scene/2d/skeleton_2d.h +++ b/scene/2d/skeleton_2d.h @@ -12,6 +12,9 @@ class Bone2D : public Node2D { Skeleton2D *skeleton; Transform2D rest; +friend class Skeleton2D; + int skeleton_index; + protected: void _notification(int p_what); static void _bind_methods(); @@ -24,6 +27,8 @@ public: String get_configuration_warning() const; + int get_index_in_skeleton() const; + Bone2D(); }; @@ -37,6 +42,8 @@ class Skeleton2D : public Node2D { return p_bone.bone->is_greater_than(bone); } Bone2D *bone; + int parent_index; + Transform2D accum_transform; Transform2D rest_inverse; }; |