diff options
author | Bastien Montagne <bastien@blender.org> | 2020-11-25 13:20:12 +0300 |
---|---|---|
committer | Bastien Montagne <bastien@blender.org> | 2020-11-27 18:18:59 +0300 |
commit | fbdf1af3555027696df5b687c7fe8d345e4c39e9 (patch) | |
tree | 722f9d0146507cc372a0a1edc9d5002a9ab8b7dd /source/blender/blenkernel/intern | |
parent | e4e7dfc1d8c0486530e5cabd2e448bf79b2fdb0b (diff) |
Fix T82758: Convert Proxy to Override: Local constraints aren't saved.
Ensure consistent order of pose bones. Now it should always match the
one from bones in armature obdata (as exposed by e.g. RNA, i.e.
children-first).
Previously when some pose bones would need to be added or removed from a
pose due to changes in the bone armature, or if bones in armature were
re-ordered, the bones order in pose would not match anymore the one from
armature, and could even become different between e.g. a proxy and its
linked source.
This was not really nice, but not a big issue before either. But with
diffing process of override, consistent order of items between reference
linked collection and local override one is crucial.
Reviewed By: #animation_rigging, sybren
Maniphest Tasks: T82758
Differential Revision: https://developer.blender.org/D9646
Diffstat (limited to 'source/blender/blenkernel/intern')
-rw-r--r-- | source/blender/blenkernel/intern/armature.c | 32 |
1 files changed, 29 insertions, 3 deletions
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index b5d3a04acb8..92146082557 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -2440,17 +2440,42 @@ static void pose_proxy_sync(Object *ob, Object *from, int layer_protected) } } -static int rebuild_pose_bone(bPose *pose, Bone *bone, bPoseChannel *parchan, int counter) +/** + * \param r_last_visited_bone_p the last bone handled by the last call to this function. + */ +static int rebuild_pose_bone( + bPose *pose, Bone *bone, bPoseChannel *parchan, int counter, Bone **r_last_visited_bone_p) { bPoseChannel *pchan = BKE_pose_channel_verify(pose, bone->name); /* verify checks and/or adds */ pchan->bone = bone; pchan->parent = parchan; + /* We ensure the current pchan is immediately after the one we just generated/updated in the + * previous call to `rebuild_pose_bone`. + * + * It may be either the parent, the previous sibling, or the last + * (grand-(grand-(...)))-child (as processed by the recursive, depth-first nature of this + * function) of the previous sibling. + * + * Note: In most cases there is nothing to do here, but pose list may get out of order when some + * bones are added, removed or moved in the armature data. */ + bPoseChannel *pchan_prev = pchan->prev; + const Bone *last_visited_bone = *r_last_visited_bone_p; + if ((pchan_prev == NULL && last_visited_bone != NULL) || + (pchan_prev != NULL && pchan_prev->bone != last_visited_bone)) { + pchan_prev = last_visited_bone != NULL ? + BKE_pose_channel_find_name(pose, last_visited_bone->name) : + NULL; + BLI_remlink(&pose->chanbase, pchan); + BLI_insertlinkafter(&pose->chanbase, pchan_prev, pchan); + } + + *r_last_visited_bone_p = pchan->bone; counter++; for (bone = bone->childbase.first; bone; bone = bone->next) { - counter = rebuild_pose_bone(pose, bone, pchan, counter); + counter = rebuild_pose_bone(pose, bone, pchan, counter, r_last_visited_bone_p); /* for quick detecting of next bone in chain, only b-bone uses it now */ if (bone->flag & BONE_CONNECTED) { pchan->child = BKE_pose_channel_find_name(pose, bone->name); @@ -2520,8 +2545,9 @@ void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm, const bool do_id_ BKE_pose_clear_pointers(pose); /* first step, check if all channels are there */ + Bone *prev_bone = NULL; for (bone = arm->bonebase.first; bone; bone = bone->next) { - counter = rebuild_pose_bone(pose, bone, NULL, counter); + counter = rebuild_pose_bone(pose, bone, NULL, counter, &prev_bone); } /* and a check for garbage */ |