Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2019-04-17 07:17:24 +0300
committerCampbell Barton <ideasman42@gmail.com>2019-04-17 07:21:24 +0300
commite12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch)
tree8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/editors/armature
parentb3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff)
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211. For details on usage and instructions for migrating branches without conflicts, see: https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/editors/armature')
-rw-r--r--source/blender/editors/armature/CMakeLists.txt72
-rw-r--r--source/blender/editors/armature/armature_add.c1919
-rw-r--r--source/blender/editors/armature/armature_edit.c2864
-rw-r--r--source/blender/editors/armature/armature_intern.h109
-rw-r--r--source/blender/editors/armature/armature_naming.c871
-rw-r--r--source/blender/editors/armature/armature_ops.c295
-rw-r--r--source/blender/editors/armature/armature_relations.c1498
-rw-r--r--source/blender/editors/armature/armature_select.c3046
-rw-r--r--source/blender/editors/armature/armature_skinning.c789
-rw-r--r--source/blender/editors/armature/armature_utils.c1187
-rw-r--r--source/blender/editors/armature/editarmature_undo.c241
-rw-r--r--source/blender/editors/armature/meshlaplacian.c2581
-rw-r--r--source/blender/editors/armature/meshlaplacian.h16
-rw-r--r--source/blender/editors/armature/pose_edit.c1558
-rw-r--r--source/blender/editors/armature/pose_group.c693
-rw-r--r--source/blender/editors/armature/pose_lib.c2881
-rw-r--r--source/blender/editors/armature/pose_select.c1802
-rw-r--r--source/blender/editors/armature/pose_slide.c2827
-rw-r--r--source/blender/editors/armature/pose_transform.c1591
-rw-r--r--source/blender/editors/armature/pose_utils.c498
20 files changed, 13874 insertions, 13464 deletions
diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt
index 27eddd7e1dd..274fa86184d 100644
--- a/source/blender/editors/armature/CMakeLists.txt
+++ b/source/blender/editors/armature/CMakeLists.txt
@@ -16,55 +16,55 @@
# ***** END GPL LICENSE BLOCK *****
set(INC
- ../include
- ../../blenkernel
- ../../blenlib
- ../../blentranslation
- ../../depsgraph
- ../../gpu
- ../../makesdna
- ../../makesrna
- ../../windowmanager
- ../../../../intern/clog
- ../../../../intern/guardedalloc
- ../../../../intern/eigen
- ../../../../intern/glew-mx
+ ../include
+ ../../blenkernel
+ ../../blenlib
+ ../../blentranslation
+ ../../depsgraph
+ ../../gpu
+ ../../makesdna
+ ../../makesrna
+ ../../windowmanager
+ ../../../../intern/clog
+ ../../../../intern/guardedalloc
+ ../../../../intern/eigen
+ ../../../../intern/glew-mx
)
set(INC_SYS
- ${GLEW_INCLUDE_PATH}
+ ${GLEW_INCLUDE_PATH}
)
set(SRC
- armature_add.c
- armature_edit.c
- armature_naming.c
- armature_ops.c
- armature_relations.c
- armature_select.c
- armature_skinning.c
- armature_utils.c
- editarmature_undo.c
- meshlaplacian.c
- pose_edit.c
- pose_group.c
- pose_lib.c
- pose_select.c
- pose_slide.c
- pose_transform.c
- pose_utils.c
+ armature_add.c
+ armature_edit.c
+ armature_naming.c
+ armature_ops.c
+ armature_relations.c
+ armature_select.c
+ armature_skinning.c
+ armature_utils.c
+ editarmature_undo.c
+ meshlaplacian.c
+ pose_edit.c
+ pose_group.c
+ pose_lib.c
+ pose_select.c
+ pose_slide.c
+ pose_transform.c
+ pose_utils.c
- armature_intern.h
- meshlaplacian.h
+ armature_intern.h
+ meshlaplacian.h
)
set(LIB
- bf_blenkernel
- bf_blenlib
+ bf_blenkernel
+ bf_blenlib
)
if(WITH_INTERNATIONAL)
- add_definitions(-DWITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
endif()
add_definitions(${GL_DEFINITIONS})
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index 20978a42812..6943d6bdc54 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -59,59 +59,58 @@
/* XXX should be used everywhere, now it mallocs bones still locally in functions */
EditBone *ED_armature_ebone_add(bArmature *arm, const char *name)
{
- EditBone *bone = MEM_callocN(sizeof(EditBone), "eBone");
-
- BLI_strncpy(bone->name, name, sizeof(bone->name));
- ED_armature_ebone_unique_name(arm->edbo, bone->name, NULL);
-
- BLI_addtail(arm->edbo, bone);
-
- bone->flag |= BONE_TIPSEL;
- bone->weight = 1.0f;
- bone->dist = 0.25f;
- bone->xwidth = 0.1f;
- bone->zwidth = 0.1f;
- bone->rad_head = 0.10f;
- bone->rad_tail = 0.05f;
- bone->segments = 1;
- bone->layer = arm->layer;
-
- /* Bendy-Bone parameters */
- bone->roll1 = 0.0f;
- bone->roll2 = 0.0f;
- bone->curveInX = 0.0f;
- bone->curveInY = 0.0f;
- bone->curveOutX = 0.0f;
- bone->curveOutY = 0.0f;
- bone->ease1 = 1.0f;
- bone->ease2 = 1.0f;
- bone->scaleIn = 1.0f;
- bone->scaleOut = 1.0f;
-
- return bone;
+ EditBone *bone = MEM_callocN(sizeof(EditBone), "eBone");
+
+ BLI_strncpy(bone->name, name, sizeof(bone->name));
+ ED_armature_ebone_unique_name(arm->edbo, bone->name, NULL);
+
+ BLI_addtail(arm->edbo, bone);
+
+ bone->flag |= BONE_TIPSEL;
+ bone->weight = 1.0f;
+ bone->dist = 0.25f;
+ bone->xwidth = 0.1f;
+ bone->zwidth = 0.1f;
+ bone->rad_head = 0.10f;
+ bone->rad_tail = 0.05f;
+ bone->segments = 1;
+ bone->layer = arm->layer;
+
+ /* Bendy-Bone parameters */
+ bone->roll1 = 0.0f;
+ bone->roll2 = 0.0f;
+ bone->curveInX = 0.0f;
+ bone->curveInY = 0.0f;
+ bone->curveOutX = 0.0f;
+ bone->curveOutY = 0.0f;
+ bone->ease1 = 1.0f;
+ bone->ease2 = 1.0f;
+ bone->scaleIn = 1.0f;
+ bone->scaleOut = 1.0f;
+
+ return bone;
}
EditBone *ED_armature_ebone_add_primitive(Object *obedit_arm, float length, bool view_aligned)
{
- bArmature *arm = obedit_arm->data;
- EditBone *bone;
+ bArmature *arm = obedit_arm->data;
+ EditBone *bone;
- ED_armature_edit_deselect_all(obedit_arm);
+ ED_armature_edit_deselect_all(obedit_arm);
- /* Create a bone */
- bone = ED_armature_ebone_add(arm, "Bone");
+ /* Create a bone */
+ bone = ED_armature_ebone_add(arm, "Bone");
- arm->act_edbone = bone;
+ arm->act_edbone = bone;
- zero_v3(bone->head);
- zero_v3(bone->tail);
+ zero_v3(bone->head);
+ zero_v3(bone->tail);
- bone->tail[view_aligned ? 1 : 2] = length;
+ bone->tail[view_aligned ? 1 : 2] = length;
- return bone;
+ return bone;
}
-
/* previously addvert_armature */
/* the ctrl-click method */
@@ -124,517 +123,520 @@ EditBone *ED_armature_ebone_add_primitive(Object *obedit_arm, float length, bool
*/
static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op))
{
- bArmature *arm;
- EditBone *ebone, *newbone, *flipbone;
- float mat[3][3], imat[3][3];
- int a, to_root = 0;
- Object *obedit;
- Scene *scene;
-
- scene = CTX_data_scene(C);
- obedit = CTX_data_edit_object(C);
- arm = obedit->data;
-
- /* find the active or selected bone */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if (ebone->flag & BONE_TIPSEL || arm->act_edbone == ebone)
- break;
- }
- }
-
- if (ebone == NULL) {
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if (ebone->flag & BONE_ROOTSEL || arm->act_edbone == ebone)
- break;
- }
- }
- if (ebone == NULL)
- return OPERATOR_CANCELLED;
-
- to_root = 1;
- }
-
- ED_armature_edit_deselect_all(obedit);
-
- /* we re-use code for mirror editing... */
- flipbone = NULL;
- if (arm->flag & ARM_MIRROR_EDIT)
- flipbone = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
-
- for (a = 0; a < 2; a++) {
- if (a == 1) {
- if (flipbone == NULL)
- break;
- else {
- SWAP(EditBone *, flipbone, ebone);
- }
- }
-
- newbone = ED_armature_ebone_add(arm, ebone->name);
- arm->act_edbone = newbone;
-
- if (to_root) {
- copy_v3_v3(newbone->head, ebone->head);
- newbone->rad_head = ebone->rad_tail;
- newbone->parent = ebone->parent;
- }
- else {
- copy_v3_v3(newbone->head, ebone->tail);
- newbone->rad_head = ebone->rad_tail;
- newbone->parent = ebone;
- newbone->flag |= BONE_CONNECTED;
- }
-
- const View3DCursor *curs = &scene->cursor;
- copy_v3_v3(newbone->tail, curs->location);
- sub_v3_v3v3(newbone->tail, newbone->tail, obedit->obmat[3]);
-
- if (a == 1)
- newbone->tail[0] = -newbone->tail[0];
-
- copy_m3_m4(mat, obedit->obmat);
- invert_m3_m3(imat, mat);
- mul_m3_v3(imat, newbone->tail);
-
- newbone->length = len_v3v3(newbone->head, newbone->tail);
- newbone->rad_tail = newbone->length * 0.05f;
- newbone->dist = newbone->length * 0.25f;
-
- }
-
- ED_armature_edit_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
+ bArmature *arm;
+ EditBone *ebone, *newbone, *flipbone;
+ float mat[3][3], imat[3][3];
+ int a, to_root = 0;
+ Object *obedit;
+ Scene *scene;
+
+ scene = CTX_data_scene(C);
+ obedit = CTX_data_edit_object(C);
+ arm = obedit->data;
+
+ /* find the active or selected bone */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ if (ebone->flag & BONE_TIPSEL || arm->act_edbone == ebone)
+ break;
+ }
+ }
+
+ if (ebone == NULL) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ if (ebone->flag & BONE_ROOTSEL || arm->act_edbone == ebone)
+ break;
+ }
+ }
+ if (ebone == NULL)
+ return OPERATOR_CANCELLED;
+
+ to_root = 1;
+ }
+
+ ED_armature_edit_deselect_all(obedit);
+
+ /* we re-use code for mirror editing... */
+ flipbone = NULL;
+ if (arm->flag & ARM_MIRROR_EDIT)
+ flipbone = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
+
+ for (a = 0; a < 2; a++) {
+ if (a == 1) {
+ if (flipbone == NULL)
+ break;
+ else {
+ SWAP(EditBone *, flipbone, ebone);
+ }
+ }
+
+ newbone = ED_armature_ebone_add(arm, ebone->name);
+ arm->act_edbone = newbone;
+
+ if (to_root) {
+ copy_v3_v3(newbone->head, ebone->head);
+ newbone->rad_head = ebone->rad_tail;
+ newbone->parent = ebone->parent;
+ }
+ else {
+ copy_v3_v3(newbone->head, ebone->tail);
+ newbone->rad_head = ebone->rad_tail;
+ newbone->parent = ebone;
+ newbone->flag |= BONE_CONNECTED;
+ }
+
+ const View3DCursor *curs = &scene->cursor;
+ copy_v3_v3(newbone->tail, curs->location);
+ sub_v3_v3v3(newbone->tail, newbone->tail, obedit->obmat[3]);
+
+ if (a == 1)
+ newbone->tail[0] = -newbone->tail[0];
+
+ copy_m3_m4(mat, obedit->obmat);
+ invert_m3_m3(imat, mat);
+ mul_m3_v3(imat, newbone->tail);
+
+ newbone->length = len_v3v3(newbone->head, newbone->tail);
+ newbone->rad_tail = newbone->length * 0.05f;
+ newbone->dist = newbone->length * 0.25f;
+ }
+
+ ED_armature_edit_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
}
static int armature_click_extrude_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- /* TODO most of this code is copied from set3dcursor_invoke,
- * it would be better to reuse code in set3dcursor_invoke */
+ /* TODO most of this code is copied from set3dcursor_invoke,
+ * it would be better to reuse code in set3dcursor_invoke */
- /* temporarily change 3d cursor position */
- Scene *scene;
- ARegion *ar;
- View3D *v3d;
- float tvec[3], oldcurs[3], mval_f[2];
- int retv;
+ /* temporarily change 3d cursor position */
+ Scene *scene;
+ ARegion *ar;
+ View3D *v3d;
+ float tvec[3], oldcurs[3], mval_f[2];
+ int retv;
- scene = CTX_data_scene(C);
- ar = CTX_wm_region(C);
- v3d = CTX_wm_view3d(C);
+ scene = CTX_data_scene(C);
+ ar = CTX_wm_region(C);
+ v3d = CTX_wm_view3d(C);
- View3DCursor *cursor = &scene->cursor;
+ View3DCursor *cursor = &scene->cursor;
- copy_v3_v3(oldcurs, cursor->location);
+ copy_v3_v3(oldcurs, cursor->location);
- copy_v2fl_v2i(mval_f, event->mval);
- ED_view3d_win_to_3d(v3d, ar, cursor->location, mval_f, tvec);
- copy_v3_v3(cursor->location, tvec);
+ copy_v2fl_v2i(mval_f, event->mval);
+ ED_view3d_win_to_3d(v3d, ar, cursor->location, mval_f, tvec);
+ copy_v3_v3(cursor->location, tvec);
- /* extrude to the where new cursor is and store the operation result */
- retv = armature_click_extrude_exec(C, op);
+ /* extrude to the where new cursor is and store the operation result */
+ retv = armature_click_extrude_exec(C, op);
- /* restore previous 3d cursor position */
- copy_v3_v3(cursor->location, oldcurs);
+ /* restore previous 3d cursor position */
+ copy_v3_v3(cursor->location, oldcurs);
- return retv;
+ return retv;
}
void ARMATURE_OT_click_extrude(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Click-Extrude";
- ot->idname = "ARMATURE_OT_click_extrude";
- ot->description = "Create a new bone going from the last selected joint to the mouse position";
+ /* identifiers */
+ ot->name = "Click-Extrude";
+ ot->idname = "ARMATURE_OT_click_extrude";
+ ot->description = "Create a new bone going from the last selected joint to the mouse position";
- /* api callbacks */
- ot->invoke = armature_click_extrude_invoke;
- ot->exec = armature_click_extrude_exec;
- ot->poll = ED_operator_editarmature;
+ /* api callbacks */
+ ot->invoke = armature_click_extrude_invoke;
+ ot->exec = armature_click_extrude_exec;
+ ot->poll = ED_operator_editarmature;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* props */
+ /* props */
}
/* adds an EditBone between the nominated locations (should be in the right space) */
EditBone *add_points_bone(Object *obedit, float head[3], float tail[3])
{
- EditBone *ebo;
+ EditBone *ebo;
- ebo = ED_armature_ebone_add(obedit->data, "Bone");
+ ebo = ED_armature_ebone_add(obedit->data, "Bone");
- copy_v3_v3(ebo->head, head);
- copy_v3_v3(ebo->tail, tail);
+ copy_v3_v3(ebo->head, head);
+ copy_v3_v3(ebo->tail, tail);
- return ebo;
+ return ebo;
}
-
static EditBone *get_named_editbone(ListBase *edbo, const char *name)
{
- EditBone *eBone;
+ EditBone *eBone;
- if (name) {
- for (eBone = edbo->first; eBone; eBone = eBone->next) {
- if (STREQ(name, eBone->name))
- return eBone;
- }
- }
+ if (name) {
+ for (eBone = edbo->first; eBone; eBone = eBone->next) {
+ if (STREQ(name, eBone->name))
+ return eBone;
+ }
+ }
- return NULL;
+ return NULL;
}
/* Call this before doing any duplications
* */
void preEditBoneDuplicate(ListBase *editbones)
{
- /* clear temp */
- ED_armature_ebone_listbase_temp_clear(editbones);
+ /* clear temp */
+ ED_armature_ebone_listbase_temp_clear(editbones);
}
/**
* Helper function for #postEditBoneDuplicate,
* return the destination pchan from the original.
*/
-static bPoseChannel *pchan_duplicate_map(const bPose *pose, GHash *name_map, bPoseChannel *pchan_src)
+static bPoseChannel *pchan_duplicate_map(const bPose *pose,
+ GHash *name_map,
+ bPoseChannel *pchan_src)
{
- bPoseChannel *pchan_dst = NULL;
- const char *name_src = pchan_src->name;
- const char *name_dst = BLI_ghash_lookup(name_map, name_src);
- if (name_dst) {
- pchan_dst = BKE_pose_channel_find_name(pose, name_dst);
- }
-
- if (pchan_dst == NULL) {
- pchan_dst = pchan_src;
- }
-
- return pchan_dst;
+ bPoseChannel *pchan_dst = NULL;
+ const char *name_src = pchan_src->name;
+ const char *name_dst = BLI_ghash_lookup(name_map, name_src);
+ if (name_dst) {
+ pchan_dst = BKE_pose_channel_find_name(pose, name_dst);
+ }
+
+ if (pchan_dst == NULL) {
+ pchan_dst = pchan_src;
+ }
+
+ return pchan_dst;
}
void postEditBoneDuplicate(struct ListBase *editbones, Object *ob)
{
- if (ob->pose == NULL) {
- return;
- }
-
- BKE_pose_channels_hash_free(ob->pose);
- BKE_pose_channels_hash_make(ob->pose);
-
- GHash *name_map = BLI_ghash_str_new(__func__);
-
- for (EditBone *ebone_src = editbones->first; ebone_src; ebone_src = ebone_src->next) {
- EditBone *ebone_dst = ebone_src->temp.ebone;
- if (!ebone_dst) {
- ebone_dst = ED_armature_ebone_get_mirrored(editbones, ebone_src);
- }
- if (ebone_dst) {
- BLI_ghash_insert(name_map, ebone_src->name, ebone_dst->name);
- }
- }
-
- for (EditBone *ebone_src = editbones->first; ebone_src; ebone_src = ebone_src->next) {
- EditBone *ebone_dst = ebone_src->temp.ebone;
- if (ebone_dst) {
- bPoseChannel *pchan_src = BKE_pose_channel_find_name(ob->pose, ebone_src->name);
- if (pchan_src) {
- bPoseChannel *pchan_dst = BKE_pose_channel_find_name(ob->pose, ebone_dst->name);
- if (pchan_dst) {
- if (pchan_src->custom_tx) {
- pchan_dst->custom_tx = pchan_duplicate_map(ob->pose, name_map, pchan_src->custom_tx);
- }
- if (pchan_src->bbone_prev) {
- pchan_dst->bbone_prev = pchan_duplicate_map(ob->pose, name_map, pchan_src->bbone_prev);
- }
- if (pchan_src->bbone_next) {
- pchan_dst->bbone_next = pchan_duplicate_map(ob->pose, name_map, pchan_src->bbone_next);
- }
- }
- }
- }
- }
-
- BLI_ghash_free(name_map, NULL, NULL);
+ if (ob->pose == NULL) {
+ return;
+ }
+
+ BKE_pose_channels_hash_free(ob->pose);
+ BKE_pose_channels_hash_make(ob->pose);
+
+ GHash *name_map = BLI_ghash_str_new(__func__);
+
+ for (EditBone *ebone_src = editbones->first; ebone_src; ebone_src = ebone_src->next) {
+ EditBone *ebone_dst = ebone_src->temp.ebone;
+ if (!ebone_dst) {
+ ebone_dst = ED_armature_ebone_get_mirrored(editbones, ebone_src);
+ }
+ if (ebone_dst) {
+ BLI_ghash_insert(name_map, ebone_src->name, ebone_dst->name);
+ }
+ }
+
+ for (EditBone *ebone_src = editbones->first; ebone_src; ebone_src = ebone_src->next) {
+ EditBone *ebone_dst = ebone_src->temp.ebone;
+ if (ebone_dst) {
+ bPoseChannel *pchan_src = BKE_pose_channel_find_name(ob->pose, ebone_src->name);
+ if (pchan_src) {
+ bPoseChannel *pchan_dst = BKE_pose_channel_find_name(ob->pose, ebone_dst->name);
+ if (pchan_dst) {
+ if (pchan_src->custom_tx) {
+ pchan_dst->custom_tx = pchan_duplicate_map(ob->pose, name_map, pchan_src->custom_tx);
+ }
+ if (pchan_src->bbone_prev) {
+ pchan_dst->bbone_prev = pchan_duplicate_map(ob->pose, name_map, pchan_src->bbone_prev);
+ }
+ if (pchan_src->bbone_next) {
+ pchan_dst->bbone_next = pchan_duplicate_map(ob->pose, name_map, pchan_src->bbone_next);
+ }
+ }
+ }
+ }
+ }
+
+ BLI_ghash_free(name_map, NULL, NULL);
}
/*
* Note: When duplicating cross objects, editbones here is the list of bones
* from the SOURCE object but ob is the DESTINATION object
* */
-void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Object *src_ob, Object *dst_ob)
+void updateDuplicateSubtargetObjects(EditBone *dupBone,
+ ListBase *editbones,
+ Object *src_ob,
+ Object *dst_ob)
{
- /* If an edit bone has been duplicated, lets
- * update it's constraints if the subtarget
- * they point to has also been duplicated
- */
- EditBone *oldtarget, *newtarget;
- bPoseChannel *pchan;
- bConstraint *curcon;
- ListBase *conlist;
-
- if ((pchan = BKE_pose_channel_verify(dst_ob->pose, dupBone->name))) {
- if ((conlist = &pchan->constraints)) {
- for (curcon = conlist->first; curcon; curcon = curcon->next) {
- /* does this constraint have a subtarget in
- * this armature?
- */
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(curcon, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if ((ct->tar == src_ob) && (ct->subtarget[0])) {
- ct->tar = dst_ob; /* update target */
- oldtarget = get_named_editbone(editbones, ct->subtarget);
- if (oldtarget) {
- /* was the subtarget bone duplicated too? If
- * so, update the constraint to point at the
- * duplicate of the old subtarget.
- */
- if (oldtarget->temp.ebone) {
- newtarget = oldtarget->temp.ebone;
- BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget));
- }
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(curcon, &targets, 0);
- }
- }
- }
- }
+ /* If an edit bone has been duplicated, lets
+ * update it's constraints if the subtarget
+ * they point to has also been duplicated
+ */
+ EditBone *oldtarget, *newtarget;
+ bPoseChannel *pchan;
+ bConstraint *curcon;
+ ListBase *conlist;
+
+ if ((pchan = BKE_pose_channel_verify(dst_ob->pose, dupBone->name))) {
+ if ((conlist = &pchan->constraints)) {
+ for (curcon = conlist->first; curcon; curcon = curcon->next) {
+ /* does this constraint have a subtarget in
+ * this armature?
+ */
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(curcon, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ if ((ct->tar == src_ob) && (ct->subtarget[0])) {
+ ct->tar = dst_ob; /* update target */
+ oldtarget = get_named_editbone(editbones, ct->subtarget);
+ if (oldtarget) {
+ /* was the subtarget bone duplicated too? If
+ * so, update the constraint to point at the
+ * duplicate of the old subtarget.
+ */
+ if (oldtarget->temp.ebone) {
+ newtarget = oldtarget->temp.ebone;
+ BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget));
+ }
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(curcon, &targets, 0);
+ }
+ }
+ }
+ }
}
void updateDuplicateSubtarget(EditBone *dupBone, ListBase *editbones, Object *ob)
{
- updateDuplicateSubtargetObjects(dupBone, editbones, ob, ob);
+ updateDuplicateSubtargetObjects(dupBone, editbones, ob, ob);
}
-
-EditBone *duplicateEditBoneObjects(EditBone *curBone, const char *name, ListBase *editbones,
- Object *src_ob, Object *dst_ob)
+EditBone *duplicateEditBoneObjects(
+ EditBone *curBone, const char *name, ListBase *editbones, Object *src_ob, Object *dst_ob)
{
- EditBone *eBone = MEM_mallocN(sizeof(EditBone), "addup_editbone");
+ EditBone *eBone = MEM_mallocN(sizeof(EditBone), "addup_editbone");
- /* Copy data from old bone to new bone */
- memcpy(eBone, curBone, sizeof(EditBone));
+ /* Copy data from old bone to new bone */
+ memcpy(eBone, curBone, sizeof(EditBone));
- curBone->temp.ebone = eBone;
- eBone->temp.ebone = curBone;
+ curBone->temp.ebone = eBone;
+ eBone->temp.ebone = curBone;
- if (name != NULL) {
- BLI_strncpy(eBone->name, name, sizeof(eBone->name));
- }
+ if (name != NULL) {
+ BLI_strncpy(eBone->name, name, sizeof(eBone->name));
+ }
- ED_armature_ebone_unique_name(editbones, eBone->name, NULL);
- BLI_addtail(editbones, eBone);
+ ED_armature_ebone_unique_name(editbones, eBone->name, NULL);
+ BLI_addtail(editbones, eBone);
- /* copy the ID property */
- if (curBone->prop)
- eBone->prop = IDP_CopyProperty(curBone->prop);
+ /* copy the ID property */
+ if (curBone->prop)
+ eBone->prop = IDP_CopyProperty(curBone->prop);
- /* Lets duplicate the list of constraints that the
- * current bone has.
- */
- if (src_ob->pose) {
- bPoseChannel *chanold, *channew;
+ /* Lets duplicate the list of constraints that the
+ * current bone has.
+ */
+ if (src_ob->pose) {
+ bPoseChannel *chanold, *channew;
- chanold = BKE_pose_channel_verify(src_ob->pose, curBone->name);
- if (chanold) {
- /* WARNING: this creates a new posechannel, but there will not be an attached bone
- * yet as the new bones created here are still 'EditBones' not 'Bones'.
- */
- channew = BKE_pose_channel_verify(dst_ob->pose, eBone->name);
+ chanold = BKE_pose_channel_verify(src_ob->pose, curBone->name);
+ if (chanold) {
+ /* WARNING: this creates a new posechannel, but there will not be an attached bone
+ * yet as the new bones created here are still 'EditBones' not 'Bones'.
+ */
+ channew = BKE_pose_channel_verify(dst_ob->pose, eBone->name);
- if (channew) {
- BKE_pose_channel_copy_data(channew, chanold);
- }
- }
- }
+ if (channew) {
+ BKE_pose_channel_copy_data(channew, chanold);
+ }
+ }
+ }
- return eBone;
+ return eBone;
}
EditBone *duplicateEditBone(EditBone *curBone, const char *name, ListBase *editbones, Object *ob)
{
- return duplicateEditBoneObjects(curBone, name, editbones, ob, ob);
+ return duplicateEditBoneObjects(curBone, name, editbones, ob, ob);
}
static int armature_duplicate_selected_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const bool do_flip_names = RNA_boolean_get(op->ptr, "do_flip_names");
-
- /* cancel if nothing selected */
- if (CTX_DATA_COUNT(C, selected_bones) == 0)
- return OPERATOR_CANCELLED;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- EditBone *ebone_iter;
- /* The beginning of the duplicated bones in the edbo list */
- EditBone *ebone_first_dupe = NULL;
-
- Object *ob = objects[ob_index];
- bArmature *arm = ob->data;
-
- ED_armature_edit_sync_selection(arm->edbo); // XXX why is this needed?
-
- preEditBoneDuplicate(arm->edbo);
-
- /* Select mirrored bones */
- if (arm->flag & ARM_MIRROR_EDIT) {
- for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
- if (EBONE_VISIBLE(arm, ebone_iter) &&
- (ebone_iter->flag & BONE_SELECTED))
- {
- EditBone *ebone;
-
- ebone = ED_armature_ebone_get_mirrored(arm->edbo, ebone_iter);
- if (ebone) {
- ebone->flag |= BONE_SELECTED;
- }
- }
- }
- }
-
- /* Find the selected bones and duplicate them as needed */
- for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
- if (EBONE_VISIBLE(arm, ebone_iter) &&
- (ebone_iter->flag & BONE_SELECTED))
- {
- EditBone *ebone;
- char new_bone_name_buff[MAXBONENAME];
- char *new_bone_name = ebone_iter->name;
-
- if (do_flip_names) {
- BLI_string_flip_side_name(new_bone_name_buff, ebone_iter->name, false, sizeof(new_bone_name_buff));
-
- /* Only use flipped name if not yet in use. Otherwise we'd get again inconsistent namings
- * (different numbers), better keep default behavior in this case. */
- if (ED_armature_ebone_find_name(arm->edbo, new_bone_name_buff) == NULL) {
- new_bone_name = new_bone_name_buff;
- }
- }
-
- ebone = duplicateEditBone(ebone_iter, new_bone_name, arm->edbo, ob);
-
- if (!ebone_first_dupe) {
- ebone_first_dupe = ebone;
- }
- }
- }
-
- /* Run though the list and fix the pointers */
- for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
- if (EBONE_VISIBLE(arm, ebone_iter) &&
- (ebone_iter->flag & BONE_SELECTED))
- {
- EditBone *ebone = ebone_iter->temp.ebone;
-
- if (!ebone_iter->parent) {
- /* If this bone has no parent,
- * Set the duplicate->parent to NULL
- */
- ebone->parent = NULL;
- }
- else if (ebone_iter->parent->temp.ebone) {
- /* If this bone has a parent that was duplicated,
- * Set the duplicate->parent to the curBone->parent->temp
- */
- ebone->parent = ebone_iter->parent->temp.ebone;
- }
- else {
- /* If this bone has a parent that IS not selected,
- * Set the duplicate->parent to the curBone->parent
- */
- ebone->parent = (EditBone *) ebone_iter->parent;
- ebone->flag &= ~BONE_CONNECTED;
- }
-
- /* Update custom handle links. */
- if (ebone_iter->bbone_prev && ebone_iter->bbone_prev->temp.ebone) {
- ebone->bbone_prev = ebone_iter->bbone_prev->temp.ebone;
- }
- if (ebone_iter->bbone_next && ebone_iter->bbone_next->temp.ebone) {
- ebone->bbone_next = ebone_iter->bbone_next->temp.ebone;
- }
-
- /* Lets try to fix any constraint subtargets that might
- * have been duplicated
- */
- updateDuplicateSubtarget(ebone, arm->edbo, ob);
- }
- }
-
- /* correct the active bone */
- if (arm->act_edbone && arm->act_edbone->temp.ebone) {
- arm->act_edbone = arm->act_edbone->temp.ebone;
- }
-
- /* Deselect the old bones and select the new ones */
- for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
- if (EBONE_VISIBLE(arm, ebone_iter)) {
- ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- }
-
- postEditBoneDuplicate(arm->edbo, ob);
-
- ED_armature_edit_validate_active(arm);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const bool do_flip_names = RNA_boolean_get(op->ptr, "do_flip_names");
+
+ /* cancel if nothing selected */
+ if (CTX_DATA_COUNT(C, selected_bones) == 0)
+ return OPERATOR_CANCELLED;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ EditBone *ebone_iter;
+ /* The beginning of the duplicated bones in the edbo list */
+ EditBone *ebone_first_dupe = NULL;
+
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+
+ ED_armature_edit_sync_selection(arm->edbo); // XXX why is this needed?
+
+ preEditBoneDuplicate(arm->edbo);
+
+ /* Select mirrored bones */
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED)) {
+ EditBone *ebone;
+
+ ebone = ED_armature_ebone_get_mirrored(arm->edbo, ebone_iter);
+ if (ebone) {
+ ebone->flag |= BONE_SELECTED;
+ }
+ }
+ }
+ }
+
+ /* Find the selected bones and duplicate them as needed */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe;
+ ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED)) {
+ EditBone *ebone;
+ char new_bone_name_buff[MAXBONENAME];
+ char *new_bone_name = ebone_iter->name;
+
+ if (do_flip_names) {
+ BLI_string_flip_side_name(
+ new_bone_name_buff, ebone_iter->name, false, sizeof(new_bone_name_buff));
+
+ /* Only use flipped name if not yet in use. Otherwise we'd get again inconsistent namings
+ * (different numbers), better keep default behavior in this case. */
+ if (ED_armature_ebone_find_name(arm->edbo, new_bone_name_buff) == NULL) {
+ new_bone_name = new_bone_name_buff;
+ }
+ }
+
+ ebone = duplicateEditBone(ebone_iter, new_bone_name, arm->edbo, ob);
+
+ if (!ebone_first_dupe) {
+ ebone_first_dupe = ebone;
+ }
+ }
+ }
+
+ /* Run though the list and fix the pointers */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe;
+ ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED)) {
+ EditBone *ebone = ebone_iter->temp.ebone;
+
+ if (!ebone_iter->parent) {
+ /* If this bone has no parent,
+ * Set the duplicate->parent to NULL
+ */
+ ebone->parent = NULL;
+ }
+ else if (ebone_iter->parent->temp.ebone) {
+ /* If this bone has a parent that was duplicated,
+ * Set the duplicate->parent to the curBone->parent->temp
+ */
+ ebone->parent = ebone_iter->parent->temp.ebone;
+ }
+ else {
+ /* If this bone has a parent that IS not selected,
+ * Set the duplicate->parent to the curBone->parent
+ */
+ ebone->parent = (EditBone *)ebone_iter->parent;
+ ebone->flag &= ~BONE_CONNECTED;
+ }
+
+ /* Update custom handle links. */
+ if (ebone_iter->bbone_prev && ebone_iter->bbone_prev->temp.ebone) {
+ ebone->bbone_prev = ebone_iter->bbone_prev->temp.ebone;
+ }
+ if (ebone_iter->bbone_next && ebone_iter->bbone_next->temp.ebone) {
+ ebone->bbone_next = ebone_iter->bbone_next->temp.ebone;
+ }
+
+ /* Lets try to fix any constraint subtargets that might
+ * have been duplicated
+ */
+ updateDuplicateSubtarget(ebone, arm->edbo, ob);
+ }
+ }
+
+ /* correct the active bone */
+ if (arm->act_edbone && arm->act_edbone->temp.ebone) {
+ arm->act_edbone = arm->act_edbone->temp.ebone;
+ }
+
+ /* Deselect the old bones and select the new ones */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe;
+ ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter)) {
+ ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+
+ postEditBoneDuplicate(arm->edbo, ob);
+
+ ED_armature_edit_validate_active(arm);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
}
-
void ARMATURE_OT_duplicate(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Duplicate Selected Bone(s)";
- ot->idname = "ARMATURE_OT_duplicate";
- ot->description = "Make copies of the selected bones within the same armature";
-
- /* api callbacks */
- ot->exec = armature_duplicate_selected_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_boolean(
- ot->srna, "do_flip_names", false,
- "Flip Names", "Try to flip names of the bones, if possible, instead of adding a number extension");
+ /* identifiers */
+ ot->name = "Duplicate Selected Bone(s)";
+ ot->idname = "ARMATURE_OT_duplicate";
+ ot->description = "Make copies of the selected bones within the same armature";
+
+ /* api callbacks */
+ ot->exec = armature_duplicate_selected_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(
+ ot->srna,
+ "do_flip_names",
+ false,
+ "Flip Names",
+ "Try to flip names of the bones, if possible, instead of adding a number extension");
}
/* Get the duplicated or existing mirrored copy of the bone. */
static EditBone *get_symmetrized_bone(bArmature *arm, EditBone *bone)
{
- if (bone == NULL) {
- return NULL;
- }
- else if (bone->temp.ebone != NULL) {
- return bone->temp.ebone;
- }
- else {
- EditBone *mirror = ED_armature_ebone_get_mirrored(arm->edbo, bone);
- return (mirror != NULL) ? mirror : bone;
- }
+ if (bone == NULL) {
+ return NULL;
+ }
+ else if (bone->temp.ebone != NULL) {
+ return bone->temp.ebone;
+ }
+ else {
+ EditBone *mirror = ED_armature_ebone_get_mirrored(arm->edbo, bone);
+ return (mirror != NULL) ? mirror : bone;
+ }
}
/**
@@ -643,222 +645,220 @@ static EditBone *get_symmetrized_bone(bArmature *arm, EditBone *bone)
*/
static int armature_symmetrize_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const int direction = RNA_enum_get(op->ptr, "direction");
- const int axis = 0;
-
- /* cancel if nothing selected */
- if (CTX_DATA_COUNT(C, selected_bones) == 0) {
- return OPERATOR_CANCELLED;
- }
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- bArmature *arm = obedit->data;
-
- EditBone *ebone_iter;
- /* The beginning of the duplicated mirrored bones in the edbo list */
- EditBone *ebone_first_dupe = NULL;
-
- ED_armature_edit_sync_selection(arm->edbo); // XXX why is this needed?
-
- preEditBoneDuplicate(arm->edbo);
-
- /* Select mirrored bones */
- for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
- if (EBONE_VISIBLE(arm, ebone_iter) &&
- (ebone_iter->flag & BONE_SELECTED))
- {
- char name_flip[MAXBONENAME];
-
- BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip));
-
- if (STREQ(name_flip, ebone_iter->name)) {
- /* if the name matches, we don't have the potential to be mirrored, just skip */
- ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else {
- EditBone *ebone = ED_armature_ebone_find_name(arm->edbo, name_flip);
-
- if (ebone) {
- if ((ebone->flag & BONE_SELECTED) == 0) {
- /* simple case, we're selected, the other bone isn't! */
- ebone_iter->temp.ebone = ebone;
- }
- else {
- /* complicated - choose which direction to copy */
- float axis_delta;
-
- axis_delta = ebone->head[axis] - ebone_iter->head[axis];
- if (axis_delta == 0.0f) {
- axis_delta = ebone->tail[axis] - ebone_iter->tail[axis];
- }
-
- if (axis_delta == 0.0f) {
- /* both mirrored bones exist and point to eachother and overlap exactly.
- *
- * in this case there's no well defined solution, so de-select both and skip.
- */
- ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else {
- EditBone *ebone_src, *ebone_dst;
- if (((axis_delta < 0.0f) ? -1 : 1) == direction) {
- ebone_src = ebone;
- ebone_dst = ebone_iter;
- }
- else {
- ebone_src = ebone_iter;
- ebone_dst = ebone;
- }
-
- ebone_src->temp.ebone = ebone_dst;
- ebone_dst->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- }
- }
- }
- }
- }
-
- /* Find the selected bones and duplicate them as needed, with mirrored name */
- for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
- if (EBONE_VISIBLE(arm, ebone_iter) &&
- (ebone_iter->flag & BONE_SELECTED) &&
- /* will be set if the mirror bone already exists (no need to make a new one) */
- (ebone_iter->temp.ebone == NULL))
- {
- char name_flip[MAXBONENAME];
-
- BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip));
-
- /* bones must have a side-suffix */
- if (!STREQ(name_flip, ebone_iter->name)) {
- EditBone *ebone;
-
- ebone = duplicateEditBone(ebone_iter, name_flip, arm->edbo, obedit);
-
- if (!ebone_first_dupe) {
- ebone_first_dupe = ebone;
- }
- }
- }
- }
-
- /* Run through the list and fix the pointers */
- for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
- if (ebone_iter->temp.ebone) {
- /* copy all flags except for ... */
- const int flag_copy = ((int)~0) & ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
-
- EditBone *ebone = ebone_iter->temp.ebone;
-
- /* copy flags incase bone is pre-existing data */
- ebone->flag = (ebone->flag & ~flag_copy) | (ebone_iter->flag & flag_copy);
-
- if (ebone_iter->parent == NULL) {
- /* If this bone has no parent,
- * Set the duplicate->parent to NULL
- */
- ebone->parent = NULL;
- ebone->flag &= ~BONE_CONNECTED;
- }
- else {
- /* the parent may have been duplicated, if not lookup the mirror parent */
- EditBone *ebone_parent = get_symmetrized_bone(arm, ebone_iter->parent);
-
- if (ebone_parent == ebone_iter->parent) {
- /* If the mirror lookup failed, (but the current bone has a parent)
- * then we can assume the parent has no L/R but is a center bone.
- * So just use the same parent for both.
- */
- ebone->flag &= ~BONE_CONNECTED;
- }
-
- ebone->parent = ebone_parent;
- }
-
- /* Update custom handle links. */
- ebone->bbone_prev = get_symmetrized_bone(arm, ebone_iter->bbone_prev);
- ebone->bbone_next = get_symmetrized_bone(arm, ebone_iter->bbone_next);
-
- /* Lets try to fix any constraint subtargets that might
- * have been duplicated
- */
- updateDuplicateSubtarget(ebone, arm->edbo, obedit);
- }
- }
-
- ED_armature_edit_transform_mirror_update(obedit);
-
- /* Selected bones now have their 'temp' pointer set,
- * so we don't need this anymore */
-
- /* Deselect the old bones and select the new ones */
- for (ebone_iter = arm->edbo->first;
- ebone_iter && ebone_iter != ebone_first_dupe;
- ebone_iter = ebone_iter->next)
- {
- if (EBONE_VISIBLE(arm, ebone_iter)) {
- ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- }
-
- /* New bones will be selected, but some of the bones may already exist */
- for (ebone_iter = arm->edbo->first;
- ebone_iter && ebone_iter != ebone_first_dupe;
- ebone_iter = ebone_iter->next)
- {
- EditBone *ebone = ebone_iter->temp.ebone;
- if (ebone && EBONE_SELECTABLE(arm, ebone)) {
- ED_armature_ebone_select_set(ebone, true);
- }
- }
-
- /* correct the active bone */
- if (arm->act_edbone && arm->act_edbone->temp.ebone) {
- arm->act_edbone = arm->act_edbone->temp.ebone;
- }
-
- postEditBoneDuplicate(arm->edbo, obedit);
-
- ED_armature_edit_validate_active(arm);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const int direction = RNA_enum_get(op->ptr, "direction");
+ const int axis = 0;
+
+ /* cancel if nothing selected */
+ if (CTX_DATA_COUNT(C, selected_bones) == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
+
+ EditBone *ebone_iter;
+ /* The beginning of the duplicated mirrored bones in the edbo list */
+ EditBone *ebone_first_dupe = NULL;
+
+ ED_armature_edit_sync_selection(arm->edbo); // XXX why is this needed?
+
+ preEditBoneDuplicate(arm->edbo);
+
+ /* Select mirrored bones */
+ for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED)) {
+ char name_flip[MAXBONENAME];
+
+ BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip));
+
+ if (STREQ(name_flip, ebone_iter->name)) {
+ /* if the name matches, we don't have the potential to be mirrored, just skip */
+ ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else {
+ EditBone *ebone = ED_armature_ebone_find_name(arm->edbo, name_flip);
+
+ if (ebone) {
+ if ((ebone->flag & BONE_SELECTED) == 0) {
+ /* simple case, we're selected, the other bone isn't! */
+ ebone_iter->temp.ebone = ebone;
+ }
+ else {
+ /* complicated - choose which direction to copy */
+ float axis_delta;
+
+ axis_delta = ebone->head[axis] - ebone_iter->head[axis];
+ if (axis_delta == 0.0f) {
+ axis_delta = ebone->tail[axis] - ebone_iter->tail[axis];
+ }
+
+ if (axis_delta == 0.0f) {
+ /* both mirrored bones exist and point to eachother and overlap exactly.
+ *
+ * in this case there's no well defined solution, so de-select both and skip.
+ */
+ ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else {
+ EditBone *ebone_src, *ebone_dst;
+ if (((axis_delta < 0.0f) ? -1 : 1) == direction) {
+ ebone_src = ebone;
+ ebone_dst = ebone_iter;
+ }
+ else {
+ ebone_src = ebone_iter;
+ ebone_dst = ebone;
+ }
+
+ ebone_src->temp.ebone = ebone_dst;
+ ebone_dst->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Find the selected bones and duplicate them as needed, with mirrored name */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe;
+ ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED) &&
+ /* will be set if the mirror bone already exists (no need to make a new one) */
+ (ebone_iter->temp.ebone == NULL)) {
+ char name_flip[MAXBONENAME];
+
+ BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip));
+
+ /* bones must have a side-suffix */
+ if (!STREQ(name_flip, ebone_iter->name)) {
+ EditBone *ebone;
+
+ ebone = duplicateEditBone(ebone_iter, name_flip, arm->edbo, obedit);
+
+ if (!ebone_first_dupe) {
+ ebone_first_dupe = ebone;
+ }
+ }
+ }
+ }
+
+ /* Run through the list and fix the pointers */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe;
+ ebone_iter = ebone_iter->next) {
+ if (ebone_iter->temp.ebone) {
+ /* copy all flags except for ... */
+ const int flag_copy = ((int)~0) & ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+
+ EditBone *ebone = ebone_iter->temp.ebone;
+
+ /* copy flags incase bone is pre-existing data */
+ ebone->flag = (ebone->flag & ~flag_copy) | (ebone_iter->flag & flag_copy);
+
+ if (ebone_iter->parent == NULL) {
+ /* If this bone has no parent,
+ * Set the duplicate->parent to NULL
+ */
+ ebone->parent = NULL;
+ ebone->flag &= ~BONE_CONNECTED;
+ }
+ else {
+ /* the parent may have been duplicated, if not lookup the mirror parent */
+ EditBone *ebone_parent = get_symmetrized_bone(arm, ebone_iter->parent);
+
+ if (ebone_parent == ebone_iter->parent) {
+ /* If the mirror lookup failed, (but the current bone has a parent)
+ * then we can assume the parent has no L/R but is a center bone.
+ * So just use the same parent for both.
+ */
+ ebone->flag &= ~BONE_CONNECTED;
+ }
+
+ ebone->parent = ebone_parent;
+ }
+
+ /* Update custom handle links. */
+ ebone->bbone_prev = get_symmetrized_bone(arm, ebone_iter->bbone_prev);
+ ebone->bbone_next = get_symmetrized_bone(arm, ebone_iter->bbone_next);
+
+ /* Lets try to fix any constraint subtargets that might
+ * have been duplicated
+ */
+ updateDuplicateSubtarget(ebone, arm->edbo, obedit);
+ }
+ }
+
+ ED_armature_edit_transform_mirror_update(obedit);
+
+ /* Selected bones now have their 'temp' pointer set,
+ * so we don't need this anymore */
+
+ /* Deselect the old bones and select the new ones */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe;
+ ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter)) {
+ ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+
+ /* New bones will be selected, but some of the bones may already exist */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe;
+ ebone_iter = ebone_iter->next) {
+ EditBone *ebone = ebone_iter->temp.ebone;
+ if (ebone && EBONE_SELECTABLE(arm, ebone)) {
+ ED_armature_ebone_select_set(ebone, true);
+ }
+ }
+
+ /* correct the active bone */
+ if (arm->act_edbone && arm->act_edbone->temp.ebone) {
+ arm->act_edbone = arm->act_edbone->temp.ebone;
+ }
+
+ postEditBoneDuplicate(arm->edbo, obedit);
+
+ ED_armature_edit_validate_active(arm);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ }
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
}
/* following conventions from #MESH_OT_symmetrize */
void ARMATURE_OT_symmetrize(wmOperatorType *ot)
{
- /* subset of 'rna_enum_symmetrize_direction_items' */
- static const EnumPropertyItem arm_symmetrize_direction_items[] = {
- {-1, "NEGATIVE_X", 0, "-X to +X", ""},
- {+1, "POSITIVE_X", 0, "+X to -X", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Symmetrize";
- ot->idname = "ARMATURE_OT_symmetrize";
- ot->description = "Enforce symmetry, make copies of the selection or use existing";
-
- /* api callbacks */
- ot->exec = armature_symmetrize_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- ot->prop = RNA_def_enum(
- ot->srna, "direction", arm_symmetrize_direction_items, -1,
- "Direction", "Which sides to copy from and to (when both are selected)");
+ /* subset of 'rna_enum_symmetrize_direction_items' */
+ static const EnumPropertyItem arm_symmetrize_direction_items[] = {
+ {-1, "NEGATIVE_X", 0, "-X to +X", ""},
+ {+1, "POSITIVE_X", 0, "+X to -X", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Symmetrize";
+ ot->idname = "ARMATURE_OT_symmetrize";
+ ot->description = "Enforce symmetry, make copies of the selection or use existing";
+
+ /* api callbacks */
+ ot->exec = armature_symmetrize_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna,
+ "direction",
+ arm_symmetrize_direction_items,
+ -1,
+ "Direction",
+ "Which sides to copy from and to (when both are selected)");
}
/* ------------------------------------------ */
@@ -868,186 +868,189 @@ void ARMATURE_OT_symmetrize(wmOperatorType *ot)
/* if forked && mirror-edit: makes two bones with flipped names */
static int armature_extrude_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const bool forked = RNA_boolean_get(op->ptr, "forked");
- bool changed_multi = false;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- bArmature *arm = ob->data;
- bool forked_iter = forked;
-
- EditBone *newbone = NULL, *ebone, *flipbone, *first = NULL;
- int a, totbone = 0, do_extrude;
-
- /* since we allow root extrude too, we have to make sure selection is OK */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if (ebone->flag & BONE_ROOTSEL) {
- if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
- if (ebone->parent->flag & BONE_TIPSEL)
- ebone->flag &= ~BONE_ROOTSEL;
- }
- }
- }
- }
-
- /* Duplicate the necessary bones */
- for (ebone = arm->edbo->first; ((ebone) && (ebone != first)); ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- /* we extrude per definition the tip */
- do_extrude = false;
- if (ebone->flag & (BONE_TIPSEL | BONE_SELECTED)) {
- do_extrude = true;
- }
- else if (ebone->flag & BONE_ROOTSEL) {
- /* but, a bone with parent deselected we do the root... */
- if (ebone->parent && (ebone->parent->flag & BONE_TIPSEL)) {
- /* pass */
- }
- else {
- do_extrude = 2;
- }
- }
-
- if (do_extrude) {
- /* we re-use code for mirror editing... */
- flipbone = NULL;
- if (arm->flag & ARM_MIRROR_EDIT) {
- flipbone = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
- if (flipbone) {
- forked_iter = 0; // we extrude 2 different bones
- if (flipbone->flag & (BONE_TIPSEL | BONE_ROOTSEL | BONE_SELECTED))
- /* don't want this bone to be selected... */
- flipbone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
- }
- if ((flipbone == NULL) && (forked_iter))
- flipbone = ebone;
- }
-
- for (a = 0; a < 2; a++) {
- if (a == 1) {
- if (flipbone == NULL)
- break;
- else {
- SWAP(EditBone *, flipbone, ebone);
- }
- }
-
- totbone++;
- newbone = MEM_callocN(sizeof(EditBone), "extrudebone");
-
- if (do_extrude == true) {
- copy_v3_v3(newbone->head, ebone->tail);
- copy_v3_v3(newbone->tail, newbone->head);
- newbone->parent = ebone;
-
- /* copies it, in case mirrored bone */
- newbone->flag = ebone->flag & (BONE_TIPSEL | BONE_RELATIVE_PARENTING);
-
- if (newbone->parent) newbone->flag |= BONE_CONNECTED;
- }
- else {
- copy_v3_v3(newbone->head, ebone->head);
- copy_v3_v3(newbone->tail, ebone->head);
- newbone->parent = ebone->parent;
-
- newbone->flag = BONE_TIPSEL;
-
- if (newbone->parent && (ebone->flag & BONE_CONNECTED)) {
- newbone->flag |= BONE_CONNECTED;
- }
- }
-
- newbone->weight = ebone->weight;
- newbone->dist = ebone->dist;
- newbone->xwidth = ebone->xwidth;
- newbone->zwidth = ebone->zwidth;
- newbone->rad_head = ebone->rad_tail; // don't copy entire bone...
- newbone->rad_tail = ebone->rad_tail;
- newbone->segments = 1;
- newbone->layer = ebone->layer;
-
- /* Bendy-Bone parameters */
- newbone->roll1 = ebone->roll1;
- newbone->roll2 = ebone->roll2;
- newbone->curveInX = ebone->curveInX;
- newbone->curveInY = ebone->curveInY;
- newbone->curveOutX = ebone->curveOutX;
- newbone->curveOutY = ebone->curveOutY;
- newbone->ease1 = ebone->ease1;
- newbone->ease2 = ebone->ease2;
- newbone->scaleIn = ebone->scaleIn;
- newbone->scaleOut = ebone->scaleOut;
-
-
- BLI_strncpy(newbone->name, ebone->name, sizeof(newbone->name));
-
- if (flipbone && forked_iter) { // only set if mirror edit
- if (strlen(newbone->name) < (MAXBONENAME - 2)) {
- if (a == 0) strcat(newbone->name, "_L");
- else strcat(newbone->name, "_R");
- }
- }
- ED_armature_ebone_unique_name(arm->edbo, newbone->name, NULL);
-
- /* Add the new bone to the list */
- BLI_addtail(arm->edbo, newbone);
- if (!first)
- first = newbone;
-
- /* restore ebone if we were flipping */
- if (a == 1 && flipbone)
- SWAP(EditBone *, flipbone, ebone);
- }
- }
-
- /* Deselect the old bone */
- ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
- }
- }
- /* if only one bone, make this one active */
- if (totbone == 1 && first) {
- arm->act_edbone = first;
- }
- else {
- arm->act_edbone = newbone;
- }
-
- if (totbone == 0) {
- continue;
- }
-
- changed_multi = true;
-
- /* Transform the endpoints */
- ED_armature_edit_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
- }
- MEM_freeN(objects);
-
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const bool forked = RNA_boolean_get(op->ptr, "forked");
+ bool changed_multi = false;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bool forked_iter = forked;
+
+ EditBone *newbone = NULL, *ebone, *flipbone, *first = NULL;
+ int a, totbone = 0, do_extrude;
+
+ /* since we allow root extrude too, we have to make sure selection is OK */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ if (ebone->flag & BONE_ROOTSEL) {
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ if (ebone->parent->flag & BONE_TIPSEL)
+ ebone->flag &= ~BONE_ROOTSEL;
+ }
+ }
+ }
+ }
+
+ /* Duplicate the necessary bones */
+ for (ebone = arm->edbo->first; ((ebone) && (ebone != first)); ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ /* we extrude per definition the tip */
+ do_extrude = false;
+ if (ebone->flag & (BONE_TIPSEL | BONE_SELECTED)) {
+ do_extrude = true;
+ }
+ else if (ebone->flag & BONE_ROOTSEL) {
+ /* but, a bone with parent deselected we do the root... */
+ if (ebone->parent && (ebone->parent->flag & BONE_TIPSEL)) {
+ /* pass */
+ }
+ else {
+ do_extrude = 2;
+ }
+ }
+
+ if (do_extrude) {
+ /* we re-use code for mirror editing... */
+ flipbone = NULL;
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ flipbone = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
+ if (flipbone) {
+ forked_iter = 0; // we extrude 2 different bones
+ if (flipbone->flag & (BONE_TIPSEL | BONE_ROOTSEL | BONE_SELECTED))
+ /* don't want this bone to be selected... */
+ flipbone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ }
+ if ((flipbone == NULL) && (forked_iter))
+ flipbone = ebone;
+ }
+
+ for (a = 0; a < 2; a++) {
+ if (a == 1) {
+ if (flipbone == NULL)
+ break;
+ else {
+ SWAP(EditBone *, flipbone, ebone);
+ }
+ }
+
+ totbone++;
+ newbone = MEM_callocN(sizeof(EditBone), "extrudebone");
+
+ if (do_extrude == true) {
+ copy_v3_v3(newbone->head, ebone->tail);
+ copy_v3_v3(newbone->tail, newbone->head);
+ newbone->parent = ebone;
+
+ /* copies it, in case mirrored bone */
+ newbone->flag = ebone->flag & (BONE_TIPSEL | BONE_RELATIVE_PARENTING);
+
+ if (newbone->parent)
+ newbone->flag |= BONE_CONNECTED;
+ }
+ else {
+ copy_v3_v3(newbone->head, ebone->head);
+ copy_v3_v3(newbone->tail, ebone->head);
+ newbone->parent = ebone->parent;
+
+ newbone->flag = BONE_TIPSEL;
+
+ if (newbone->parent && (ebone->flag & BONE_CONNECTED)) {
+ newbone->flag |= BONE_CONNECTED;
+ }
+ }
+
+ newbone->weight = ebone->weight;
+ newbone->dist = ebone->dist;
+ newbone->xwidth = ebone->xwidth;
+ newbone->zwidth = ebone->zwidth;
+ newbone->rad_head = ebone->rad_tail; // don't copy entire bone...
+ newbone->rad_tail = ebone->rad_tail;
+ newbone->segments = 1;
+ newbone->layer = ebone->layer;
+
+ /* Bendy-Bone parameters */
+ newbone->roll1 = ebone->roll1;
+ newbone->roll2 = ebone->roll2;
+ newbone->curveInX = ebone->curveInX;
+ newbone->curveInY = ebone->curveInY;
+ newbone->curveOutX = ebone->curveOutX;
+ newbone->curveOutY = ebone->curveOutY;
+ newbone->ease1 = ebone->ease1;
+ newbone->ease2 = ebone->ease2;
+ newbone->scaleIn = ebone->scaleIn;
+ newbone->scaleOut = ebone->scaleOut;
+
+ BLI_strncpy(newbone->name, ebone->name, sizeof(newbone->name));
+
+ if (flipbone && forked_iter) { // only set if mirror edit
+ if (strlen(newbone->name) < (MAXBONENAME - 2)) {
+ if (a == 0)
+ strcat(newbone->name, "_L");
+ else
+ strcat(newbone->name, "_R");
+ }
+ }
+ ED_armature_ebone_unique_name(arm->edbo, newbone->name, NULL);
+
+ /* Add the new bone to the list */
+ BLI_addtail(arm->edbo, newbone);
+ if (!first)
+ first = newbone;
+
+ /* restore ebone if we were flipping */
+ if (a == 1 && flipbone)
+ SWAP(EditBone *, flipbone, ebone);
+ }
+ }
+
+ /* Deselect the old bone */
+ ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ }
+ }
+ /* if only one bone, make this one active */
+ if (totbone == 1 && first) {
+ arm->act_edbone = first;
+ }
+ else {
+ arm->act_edbone = newbone;
+ }
+
+ if (totbone == 0) {
+ continue;
+ }
+
+ changed_multi = true;
+
+ /* Transform the endpoints */
+ ED_armature_edit_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ MEM_freeN(objects);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void ARMATURE_OT_extrude(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Extrude";
- ot->idname = "ARMATURE_OT_extrude";
- ot->description = "Create new bones from the selected joints";
+ /* identifiers */
+ ot->name = "Extrude";
+ ot->idname = "ARMATURE_OT_extrude";
+ ot->description = "Create new bones from the selected joints";
- /* api callbacks */
- ot->exec = armature_extrude_exec;
- ot->poll = ED_operator_editarmature;
+ /* api callbacks */
+ ot->exec = armature_extrude_exec;
+ ot->poll = ED_operator_editarmature;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* props */
- RNA_def_boolean(ot->srna, "forked", 0, "Forked", "");
+ /* props */
+ RNA_def_boolean(ot->srna, "forked", 0, "Forked", "");
}
/* ********************** Bone Add *************************************/
@@ -1056,62 +1059,62 @@ void ARMATURE_OT_extrude(wmOperatorType *ot)
static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op)
{
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- Object *obedit = CTX_data_edit_object(C);
- EditBone *bone;
- float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3];
- char name[MAXBONENAME];
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ Object *obedit = CTX_data_edit_object(C);
+ EditBone *bone;
+ float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3];
+ char name[MAXBONENAME];
- RNA_string_get(op->ptr, "name", name);
+ RNA_string_get(op->ptr, "name", name);
- copy_v3_v3(curs, CTX_data_scene(C)->cursor.location);
+ copy_v3_v3(curs, CTX_data_scene(C)->cursor.location);
- /* Get inverse point for head and orientation for tail */
- invert_m4_m4(obedit->imat, obedit->obmat);
- mul_m4_v3(obedit->imat, curs);
+ /* Get inverse point for head and orientation for tail */
+ invert_m4_m4(obedit->imat, obedit->obmat);
+ mul_m4_v3(obedit->imat, curs);
- if (rv3d && (U.flag & USER_ADD_VIEWALIGNED))
- copy_m3_m4(obmat, rv3d->viewmat);
- else unit_m3(obmat);
+ if (rv3d && (U.flag & USER_ADD_VIEWALIGNED))
+ copy_m3_m4(obmat, rv3d->viewmat);
+ else
+ unit_m3(obmat);
- copy_m3_m4(viewmat, obedit->obmat);
- mul_m3_m3m3(totmat, obmat, viewmat);
- invert_m3_m3(imat, totmat);
+ copy_m3_m4(viewmat, obedit->obmat);
+ mul_m3_m3m3(totmat, obmat, viewmat);
+ invert_m3_m3(imat, totmat);
- ED_armature_edit_deselect_all(obedit);
+ ED_armature_edit_deselect_all(obedit);
- /* Create a bone */
- bone = ED_armature_ebone_add(obedit->data, name);
+ /* Create a bone */
+ bone = ED_armature_ebone_add(obedit->data, name);
- copy_v3_v3(bone->head, curs);
+ copy_v3_v3(bone->head, curs);
- if (rv3d && (U.flag & USER_ADD_VIEWALIGNED))
- add_v3_v3v3(bone->tail, bone->head, imat[1]); // bone with unit length 1
- else
- add_v3_v3v3(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z
+ if (rv3d && (U.flag & USER_ADD_VIEWALIGNED))
+ add_v3_v3v3(bone->tail, bone->head, imat[1]); // bone with unit length 1
+ else
+ add_v3_v3v3(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_bone_primitive_add(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Add Bone";
- ot->idname = "ARMATURE_OT_bone_primitive_add";
- ot->description = "Add a new bone located at the 3D-Cursor";
-
- /* api callbacks */
- ot->exec = armature_bone_primitive_add_exec;
- ot->poll = ED_operator_editarmature;
+ /* identifiers */
+ ot->name = "Add Bone";
+ ot->idname = "ARMATURE_OT_bone_primitive_add";
+ ot->description = "Add a new bone located at the 3D-Cursor";
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* api callbacks */
+ ot->exec = armature_bone_primitive_add_exec;
+ ot->poll = ED_operator_editarmature;
- RNA_def_string(ot->srna, "name", "Bone", MAXBONENAME, "Name", "Name of the newly created bone");
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ RNA_def_string(ot->srna, "name", "Bone", MAXBONENAME, "Name", "Name of the newly created bone");
}
/* ********************** Subdivide *******************************/
@@ -1124,86 +1127,86 @@ void ARMATURE_OT_bone_primitive_add(wmOperatorType *ot)
static int armature_subdivide_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- EditBone *newbone, *tbone;
- int cuts, i;
-
- /* there may not be a number_cuts property defined (for 'simple' subdivide) */
- cuts = RNA_int_get(op->ptr, "number_cuts");
-
- /* loop over all editable bones */
- // XXX the old code did this in reverse order though!
- CTX_DATA_BEGIN_WITH_ID(C, EditBone *, ebone, selected_editable_bones, bArmature *, arm)
- {
- for (i = cuts + 1; i > 1; i--) {
- /* compute cut ratio first */
- float cutratio = 1.0f / (float)i;
- float cutratioI = 1.0f - cutratio;
-
- float val1[3];
- float val2[3];
- float val3[3];
-
- newbone = MEM_mallocN(sizeof(EditBone), "ebone subdiv");
- *newbone = *ebone;
- BLI_addtail(arm->edbo, newbone);
-
- /* calculate location of newbone->head */
- copy_v3_v3(val1, ebone->head);
- copy_v3_v3(val2, ebone->tail);
- copy_v3_v3(val3, newbone->head);
-
- val3[0] = val1[0] * cutratio + val2[0] * cutratioI;
- val3[1] = val1[1] * cutratio + val2[1] * cutratioI;
- val3[2] = val1[2] * cutratio + val2[2] * cutratioI;
-
- copy_v3_v3(newbone->head, val3);
- copy_v3_v3(newbone->tail, ebone->tail);
- copy_v3_v3(ebone->tail, newbone->head);
-
- newbone->rad_head = ((ebone->rad_head * cutratio) + (ebone->rad_tail * cutratioI));
- ebone->rad_tail = newbone->rad_head;
-
- newbone->flag |= BONE_CONNECTED;
-
- newbone->prop = NULL;
-
- ED_armature_ebone_unique_name(arm->edbo, newbone->name, NULL);
-
- /* correct parent bones */
- for (tbone = arm->edbo->first; tbone; tbone = tbone->next) {
- if (tbone->parent == ebone)
- tbone->parent = newbone;
- }
- newbone->parent = ebone;
- }
- }
- CTX_DATA_END;
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
+ Object *obedit = CTX_data_edit_object(C);
+ EditBone *newbone, *tbone;
+ int cuts, i;
+
+ /* there may not be a number_cuts property defined (for 'simple' subdivide) */
+ cuts = RNA_int_get(op->ptr, "number_cuts");
+
+ /* loop over all editable bones */
+ // XXX the old code did this in reverse order though!
+ CTX_DATA_BEGIN_WITH_ID(C, EditBone *, ebone, selected_editable_bones, bArmature *, arm)
+ {
+ for (i = cuts + 1; i > 1; i--) {
+ /* compute cut ratio first */
+ float cutratio = 1.0f / (float)i;
+ float cutratioI = 1.0f - cutratio;
+
+ float val1[3];
+ float val2[3];
+ float val3[3];
+
+ newbone = MEM_mallocN(sizeof(EditBone), "ebone subdiv");
+ *newbone = *ebone;
+ BLI_addtail(arm->edbo, newbone);
+
+ /* calculate location of newbone->head */
+ copy_v3_v3(val1, ebone->head);
+ copy_v3_v3(val2, ebone->tail);
+ copy_v3_v3(val3, newbone->head);
+
+ val3[0] = val1[0] * cutratio + val2[0] * cutratioI;
+ val3[1] = val1[1] * cutratio + val2[1] * cutratioI;
+ val3[2] = val1[2] * cutratio + val2[2] * cutratioI;
+
+ copy_v3_v3(newbone->head, val3);
+ copy_v3_v3(newbone->tail, ebone->tail);
+ copy_v3_v3(ebone->tail, newbone->head);
+
+ newbone->rad_head = ((ebone->rad_head * cutratio) + (ebone->rad_tail * cutratioI));
+ ebone->rad_tail = newbone->rad_head;
+
+ newbone->flag |= BONE_CONNECTED;
+
+ newbone->prop = NULL;
+
+ ED_armature_ebone_unique_name(arm->edbo, newbone->name, NULL);
+
+ /* correct parent bones */
+ for (tbone = arm->edbo->first; tbone; tbone = tbone->next) {
+ if (tbone->parent == ebone)
+ tbone->parent = newbone;
+ }
+ newbone->parent = ebone;
+ }
+ }
+ CTX_DATA_END;
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_subdivide(wmOperatorType *ot)
{
- PropertyRNA *prop;
+ PropertyRNA *prop;
- /* identifiers */
- ot->name = "Subdivide Multi";
- ot->idname = "ARMATURE_OT_subdivide";
- ot->description = "Break selected bones into chains of smaller bones";
+ /* identifiers */
+ ot->name = "Subdivide Multi";
+ ot->idname = "ARMATURE_OT_subdivide";
+ ot->description = "Break selected bones into chains of smaller bones";
- /* api callbacks */
- ot->exec = armature_subdivide_exec;
- ot->poll = ED_operator_editarmature;
+ /* api callbacks */
+ ot->exec = armature_subdivide_exec;
+ ot->poll = ED_operator_editarmature;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* Properties */
- prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 1000, "Number of Cuts", "", 1, 10);
- /* avoid re-using last var because it can cause _very_ high poly meshes and annoy users (or worse crash) */
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ /* Properties */
+ prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 1000, "Number of Cuts", "", 1, 10);
+ /* avoid re-using last var because it can cause _very_ high poly meshes and annoy users (or worse crash) */
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index e3db0ca8f2c..dfcd0bf69f7 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -64,135 +64,136 @@
void ED_armature_transform_apply(Main *bmain, Object *ob, float mat[4][4], const bool do_props)
{
- bArmature *arm = ob->data;
+ bArmature *arm = ob->data;
- /* Put the armature into editmode */
- ED_armature_to_edit(arm);
+ /* Put the armature into editmode */
+ ED_armature_to_edit(arm);
- /* Transform the bones */
- ED_armature_transform_bones(arm, mat, do_props);
+ /* Transform the bones */
+ ED_armature_transform_bones(arm, mat, do_props);
- /* Turn the list into an armature */
- ED_armature_from_edit(bmain, arm);
- ED_armature_edit_free(arm);
+ /* Turn the list into an armature */
+ ED_armature_from_edit(bmain, arm);
+ ED_armature_edit_free(arm);
}
void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4], const bool do_props)
{
- EditBone *ebone;
- float scale = mat4_to_scale(mat); /* store the scale of the matrix here to use on envelopes */
- float mat3[3][3];
-
- copy_m3_m4(mat3, mat);
- normalize_m3(mat3);
- /* Do the rotations */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- float tmat[3][3];
-
- /* find the current bone's roll matrix */
- ED_armature_ebone_to_mat3(ebone, tmat);
-
- /* transform the roll matrix */
- mul_m3_m3m3(tmat, mat3, tmat);
-
- /* transform the bone */
- mul_m4_v3(mat, ebone->head);
- mul_m4_v3(mat, ebone->tail);
-
- /* apply the transformed roll back */
- mat3_to_vec_roll(tmat, NULL, &ebone->roll);
-
- if (do_props) {
- ebone->rad_head *= scale;
- ebone->rad_tail *= scale;
- ebone->dist *= scale;
-
- /* we could be smarter and scale by the matrix along the x & z axis */
- ebone->xwidth *= scale;
- ebone->zwidth *= scale;
- }
- }
+ EditBone *ebone;
+ float scale = mat4_to_scale(mat); /* store the scale of the matrix here to use on envelopes */
+ float mat3[3][3];
+
+ copy_m3_m4(mat3, mat);
+ normalize_m3(mat3);
+ /* Do the rotations */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ float tmat[3][3];
+
+ /* find the current bone's roll matrix */
+ ED_armature_ebone_to_mat3(ebone, tmat);
+
+ /* transform the roll matrix */
+ mul_m3_m3m3(tmat, mat3, tmat);
+
+ /* transform the bone */
+ mul_m4_v3(mat, ebone->head);
+ mul_m4_v3(mat, ebone->tail);
+
+ /* apply the transformed roll back */
+ mat3_to_vec_roll(tmat, NULL, &ebone->roll);
+
+ if (do_props) {
+ ebone->rad_head *= scale;
+ ebone->rad_tail *= scale;
+ ebone->dist *= scale;
+
+ /* we could be smarter and scale by the matrix along the x & z axis */
+ ebone->xwidth *= scale;
+ ebone->zwidth *= scale;
+ }
+ }
}
void ED_armature_transform(Main *bmain, bArmature *arm, float mat[4][4], const bool do_props)
{
- if (arm->edbo) {
- ED_armature_transform_bones(arm, mat, do_props);
- }
- else {
- /* Put the armature into editmode */
- ED_armature_to_edit(arm);
-
- /* Transform the bones */
- ED_armature_transform_bones(arm, mat, do_props);
-
- /* Go back to object mode*/
- ED_armature_from_edit(bmain, arm);
- ED_armature_edit_free(arm);
- }
+ if (arm->edbo) {
+ ED_armature_transform_bones(arm, mat, do_props);
+ }
+ else {
+ /* Put the armature into editmode */
+ ED_armature_to_edit(arm);
+
+ /* Transform the bones */
+ ED_armature_transform_bones(arm, mat, do_props);
+
+ /* Go back to object mode*/
+ ED_armature_from_edit(bmain, arm);
+ ED_armature_edit_free(arm);
+ }
}
/* exported for use in editors/object/ */
/* 0 == do center, 1 == center new, 2 == center cursor */
-void ED_armature_origin_set(Main *bmain, Object *ob, const float cursor[3], int centermode, int around)
+void ED_armature_origin_set(
+ Main *bmain, Object *ob, const float cursor[3], int centermode, int around)
{
- const bool is_editmode = BKE_object_is_in_editmode(ob);
- EditBone *ebone;
- bArmature *arm = ob->data;
- float cent[3];
-
- /* Put the armature into editmode */
- if (is_editmode == false) {
- ED_armature_to_edit(arm);
- }
-
- /* Find the centerpoint */
- if (centermode == 2) {
- copy_v3_v3(cent, cursor);
- invert_m4_m4(ob->imat, ob->obmat);
- mul_m4_v3(ob->imat, cent);
- }
- else {
- if (around == V3D_AROUND_CENTER_MEDIAN) {
- int total = 0;
- zero_v3(cent);
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- total += 2;
- add_v3_v3(cent, ebone->head);
- add_v3_v3(cent, ebone->tail);
- }
- if (total) {
- mul_v3_fl(cent, 1.0f / (float)total);
- }
- }
- else {
- float min[3], max[3];
- INIT_MINMAX(min, max);
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- minmax_v3v3_v3(min, max, ebone->head);
- minmax_v3v3_v3(min, max, ebone->tail);
- }
- mid_v3_v3v3(cent, min, max);
- }
- }
-
- /* Do the adjustments */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- sub_v3_v3(ebone->head, cent);
- sub_v3_v3(ebone->tail, cent);
- }
-
- /* Turn the list into an armature */
- if (is_editmode == false) {
- ED_armature_from_edit(bmain, arm);
- ED_armature_edit_free(arm);
- }
-
- /* Adjust object location for new centerpoint */
- if (centermode && (is_editmode == false)) {
- mul_mat3_m4_v3(ob->obmat, cent); /* omit translation part */
- add_v3_v3(ob->loc, cent);
- }
+ const bool is_editmode = BKE_object_is_in_editmode(ob);
+ EditBone *ebone;
+ bArmature *arm = ob->data;
+ float cent[3];
+
+ /* Put the armature into editmode */
+ if (is_editmode == false) {
+ ED_armature_to_edit(arm);
+ }
+
+ /* Find the centerpoint */
+ if (centermode == 2) {
+ copy_v3_v3(cent, cursor);
+ invert_m4_m4(ob->imat, ob->obmat);
+ mul_m4_v3(ob->imat, cent);
+ }
+ else {
+ if (around == V3D_AROUND_CENTER_MEDIAN) {
+ int total = 0;
+ zero_v3(cent);
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ total += 2;
+ add_v3_v3(cent, ebone->head);
+ add_v3_v3(cent, ebone->tail);
+ }
+ if (total) {
+ mul_v3_fl(cent, 1.0f / (float)total);
+ }
+ }
+ else {
+ float min[3], max[3];
+ INIT_MINMAX(min, max);
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ minmax_v3v3_v3(min, max, ebone->head);
+ minmax_v3v3_v3(min, max, ebone->tail);
+ }
+ mid_v3_v3v3(cent, min, max);
+ }
+ }
+
+ /* Do the adjustments */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ sub_v3_v3(ebone->head, cent);
+ sub_v3_v3(ebone->tail, cent);
+ }
+
+ /* Turn the list into an armature */
+ if (is_editmode == false) {
+ ED_armature_from_edit(bmain, arm);
+ ED_armature_edit_free(arm);
+ }
+
+ /* Adjust object location for new centerpoint */
+ if (centermode && (is_editmode == false)) {
+ mul_mat3_m4_v3(ob->obmat, cent); /* omit translation part */
+ add_v3_v3(ob->loc, cent);
+ }
}
/* ********************************* Roll ******************************* */
@@ -200,651 +201,676 @@ void ED_armature_origin_set(Main *bmain, Object *ob, const float cursor[3], int
/* adjust bone roll to align Z axis with vector
* vec is in local space and is normalized
*/
-float ED_armature_ebone_roll_to_vector(const EditBone *bone, const float align_axis[3], const bool axis_only)
+float ED_armature_ebone_roll_to_vector(const EditBone *bone,
+ const float align_axis[3],
+ const bool axis_only)
{
- float mat[3][3], nor[3];
- float vec[3], align_axis_proj[3], roll = 0.0f;
+ float mat[3][3], nor[3];
+ float vec[3], align_axis_proj[3], roll = 0.0f;
- BLI_ASSERT_UNIT_V3(align_axis);
+ BLI_ASSERT_UNIT_V3(align_axis);
- sub_v3_v3v3(nor, bone->tail, bone->head);
+ sub_v3_v3v3(nor, bone->tail, bone->head);
- /* If tail == head or the bone is aligned with the axis... */
- if (normalize_v3(nor) <= FLT_EPSILON || (fabsf(dot_v3v3(align_axis, nor)) >= (1.0f - FLT_EPSILON))) {
- return roll;
- }
+ /* If tail == head or the bone is aligned with the axis... */
+ if (normalize_v3(nor) <= FLT_EPSILON ||
+ (fabsf(dot_v3v3(align_axis, nor)) >= (1.0f - FLT_EPSILON))) {
+ return roll;
+ }
- vec_roll_to_mat3_normalized(nor, 0.0f, mat);
+ vec_roll_to_mat3_normalized(nor, 0.0f, mat);
- /* project the new_up_axis along the normal */
- project_v3_v3v3_normalized(vec, align_axis, nor);
- sub_v3_v3v3(align_axis_proj, align_axis, vec);
+ /* project the new_up_axis along the normal */
+ project_v3_v3v3_normalized(vec, align_axis, nor);
+ sub_v3_v3v3(align_axis_proj, align_axis, vec);
- if (axis_only) {
- if (angle_v3v3(align_axis_proj, mat[2]) > (float)(M_PI_2)) {
- negate_v3(align_axis_proj);
- }
- }
+ if (axis_only) {
+ if (angle_v3v3(align_axis_proj, mat[2]) > (float)(M_PI_2)) {
+ negate_v3(align_axis_proj);
+ }
+ }
- roll = angle_v3v3(align_axis_proj, mat[2]);
+ roll = angle_v3v3(align_axis_proj, mat[2]);
- cross_v3_v3v3(vec, mat[2], align_axis_proj);
+ cross_v3_v3v3(vec, mat[2], align_axis_proj);
- if (dot_v3v3(vec, nor) < 0.0f) {
- return -roll;
- }
- return roll;
+ if (dot_v3v3(vec, nor) < 0.0f) {
+ return -roll;
+ }
+ return roll;
}
/* note, ranges arithmetic is used below */
typedef enum eCalcRollTypes {
- /* pos */
- CALC_ROLL_POS_X = 0,
- CALC_ROLL_POS_Y,
- CALC_ROLL_POS_Z,
-
- CALC_ROLL_TAN_POS_X,
- CALC_ROLL_TAN_POS_Z,
-
- /* neg */
- CALC_ROLL_NEG_X,
- CALC_ROLL_NEG_Y,
- CALC_ROLL_NEG_Z,
-
- CALC_ROLL_TAN_NEG_X,
- CALC_ROLL_TAN_NEG_Z,
-
- /* no sign */
- CALC_ROLL_ACTIVE,
- CALC_ROLL_VIEW,
- CALC_ROLL_CURSOR,
+ /* pos */
+ CALC_ROLL_POS_X = 0,
+ CALC_ROLL_POS_Y,
+ CALC_ROLL_POS_Z,
+
+ CALC_ROLL_TAN_POS_X,
+ CALC_ROLL_TAN_POS_Z,
+
+ /* neg */
+ CALC_ROLL_NEG_X,
+ CALC_ROLL_NEG_Y,
+ CALC_ROLL_NEG_Z,
+
+ CALC_ROLL_TAN_NEG_X,
+ CALC_ROLL_TAN_NEG_Z,
+
+ /* no sign */
+ CALC_ROLL_ACTIVE,
+ CALC_ROLL_VIEW,
+ CALC_ROLL_CURSOR,
} eCalcRollTypes;
static const EnumPropertyItem prop_calc_roll_types[] = {
- {0, "", 0, N_("Positive"), ""},
- {CALC_ROLL_TAN_POS_X, "POS_X", 0, "Local +X Tangent", ""},
- {CALC_ROLL_TAN_POS_Z, "POS_Z", 0, "Local +Z Tangent", ""},
+ {0, "", 0, N_("Positive"), ""},
+ {CALC_ROLL_TAN_POS_X, "POS_X", 0, "Local +X Tangent", ""},
+ {CALC_ROLL_TAN_POS_Z, "POS_Z", 0, "Local +Z Tangent", ""},
- {CALC_ROLL_POS_X, "GLOBAL_POS_X", 0, "Global +X Axis", ""},
- {CALC_ROLL_POS_Y, "GLOBAL_POS_Y", 0, "Global +Y Axis", ""},
- {CALC_ROLL_POS_Z, "GLOBAL_POS_Z", 0, "Global +Z Axis", ""},
+ {CALC_ROLL_POS_X, "GLOBAL_POS_X", 0, "Global +X Axis", ""},
+ {CALC_ROLL_POS_Y, "GLOBAL_POS_Y", 0, "Global +Y Axis", ""},
+ {CALC_ROLL_POS_Z, "GLOBAL_POS_Z", 0, "Global +Z Axis", ""},
- {0, "", 0, N_("Negative"), ""},
+ {0, "", 0, N_("Negative"), ""},
- {CALC_ROLL_TAN_NEG_X, "NEG_X", 0, "Local -X Tangent", ""},
- {CALC_ROLL_TAN_NEG_Z, "NEG_Z", 0, "Local -Z Tangent", ""},
+ {CALC_ROLL_TAN_NEG_X, "NEG_X", 0, "Local -X Tangent", ""},
+ {CALC_ROLL_TAN_NEG_Z, "NEG_Z", 0, "Local -Z Tangent", ""},
- {CALC_ROLL_NEG_X, "GLOBAL_NEG_X", 0, "Global -X Axis", ""},
- {CALC_ROLL_NEG_Y, "GLOBAL_NEG_Y", 0, "Global -Y Axis", ""},
- {CALC_ROLL_NEG_Z, "GLOBAL_NEG_Z", 0, "Global -Z Axis", ""},
+ {CALC_ROLL_NEG_X, "GLOBAL_NEG_X", 0, "Global -X Axis", ""},
+ {CALC_ROLL_NEG_Y, "GLOBAL_NEG_Y", 0, "Global -Y Axis", ""},
+ {CALC_ROLL_NEG_Z, "GLOBAL_NEG_Z", 0, "Global -Z Axis", ""},
- {0, "", 0, N_("Other"), ""},
- {CALC_ROLL_ACTIVE, "ACTIVE", 0, "Active Bone", ""},
- {CALC_ROLL_VIEW, "VIEW", 0, "View Axis", ""},
- {CALC_ROLL_CURSOR, "CURSOR", 0, "Cursor", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, "", 0, N_("Other"), ""},
+ {CALC_ROLL_ACTIVE, "ACTIVE", 0, "Active Bone", ""},
+ {CALC_ROLL_VIEW, "VIEW", 0, "View Axis", ""},
+ {CALC_ROLL_CURSOR, "CURSOR", 0, "Cursor", ""},
+ {0, NULL, 0, NULL, NULL},
};
-
static int armature_calc_roll_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob_active = CTX_data_edit_object(C);
- int ret = OPERATOR_FINISHED;
-
- eCalcRollTypes type = RNA_enum_get(op->ptr, "type");
- const bool axis_only = RNA_boolean_get(op->ptr, "axis_only");
- /* axis_flip when matching the active bone never makes sense */
- bool axis_flip = ((type >= CALC_ROLL_ACTIVE) ? RNA_boolean_get(op->ptr, "axis_flip") :
- (type >= CALC_ROLL_TAN_NEG_X) ? true : false);
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- bArmature *arm = ob->data;
- bool changed = false;
-
- float imat[3][3];
- EditBone *ebone;
-
- if ((type >= CALC_ROLL_NEG_X) && (type <= CALC_ROLL_TAN_NEG_Z)) {
- type -= (CALC_ROLL_ACTIVE - CALC_ROLL_NEG_X);
- axis_flip = true;
- }
-
- copy_m3_m4(imat, ob->obmat);
- invert_m3(imat);
-
- if (type == CALC_ROLL_CURSOR) { /* Cursor */
- Scene *scene = CTX_data_scene(C);
- float cursor_local[3];
- const View3DCursor *cursor = &scene->cursor;
-
- invert_m4_m4(ob->imat, ob->obmat);
- copy_v3_v3(cursor_local, cursor->location);
- mul_m4_v3(ob->imat, cursor_local);
-
- /* cursor */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
- float cursor_rel[3];
- sub_v3_v3v3(cursor_rel, cursor_local, ebone->head);
- if (axis_flip) negate_v3(cursor_rel);
- if (normalize_v3(cursor_rel) != 0.0f) {
- ebone->roll = ED_armature_ebone_roll_to_vector(ebone, cursor_rel, axis_only);
- changed = true;
- }
- }
- }
- }
- else if (ELEM(type, CALC_ROLL_TAN_POS_X, CALC_ROLL_TAN_POS_Z)) {
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (ebone->parent) {
- bool is_edit = (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone));
- bool is_edit_parent = (EBONE_VISIBLE(arm, ebone->parent) && EBONE_EDITABLE(ebone->parent));
-
- if (is_edit || is_edit_parent) {
- EditBone *ebone_other = ebone->parent;
- float dir_a[3];
- float dir_b[3];
- float vec[3];
- bool is_vec_zero;
-
- sub_v3_v3v3(dir_a, ebone->tail, ebone->head);
- normalize_v3(dir_a);
-
- /* find the first bone in the chane with a different direction */
- do {
- sub_v3_v3v3(dir_b, ebone_other->head, ebone_other->tail);
- normalize_v3(dir_b);
-
- if (type == CALC_ROLL_TAN_POS_Z) {
- cross_v3_v3v3(vec, dir_a, dir_b);
- }
- else {
- add_v3_v3v3(vec, dir_a, dir_b);
- }
- } while ((is_vec_zero = (normalize_v3(vec) < 0.00001f)) &&
- (ebone_other = ebone_other->parent));
-
- if (!is_vec_zero) {
- if (axis_flip) negate_v3(vec);
-
- if (is_edit) {
- ebone->roll = ED_armature_ebone_roll_to_vector(ebone, vec, axis_only);
- changed = true;
- }
-
- /* parentless bones use cross product with child */
- if (is_edit_parent) {
- if (ebone->parent->parent == NULL) {
- ebone->parent->roll = ED_armature_ebone_roll_to_vector(ebone->parent, vec, axis_only);
- changed = true;
- }
- }
- }
- }
- }
- }
- }
- else {
- float vec[3] = {0.0f, 0.0f, 0.0f};
- if (type == CALC_ROLL_VIEW) { /* View */
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- if (rv3d == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No region view3d available");
- ret = OPERATOR_CANCELLED;
- goto cleanup;
- }
-
- copy_v3_v3(vec, rv3d->viewinv[2]);
- mul_m3_v3(imat, vec);
- }
- else if (type == CALC_ROLL_ACTIVE) {
- float mat[3][3];
- bArmature *arm_active = ob_active->data;
- ebone = (EditBone *)arm_active->act_edbone;
- if (ebone == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No active bone set");
- ret = OPERATOR_CANCELLED;
- goto cleanup;
- }
-
- ED_armature_ebone_to_mat3(ebone, mat);
- copy_v3_v3(vec, mat[2]);
- }
- else { /* Axis */
- assert(type <= 5);
- if (type < 3) vec[type] = 1.0f;
- else vec[type - 2] = -1.0f;
- mul_m3_v3(imat, vec);
- normalize_v3(vec);
- }
-
- if (axis_flip) negate_v3(vec);
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
- /* roll func is a callback which assumes that all is well */
- ebone->roll = ED_armature_ebone_roll_to_vector(ebone, vec, axis_only);
- changed = true;
- }
- }
- }
-
- if (arm->flag & ARM_MIRROR_EDIT) {
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) {
- EditBone *ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
- if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) {
- ebone->roll = -ebone_mirr->roll;
- }
- }
- }
- }
-
- if (changed) {
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
- }
- }
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob_active = CTX_data_edit_object(C);
+ int ret = OPERATOR_FINISHED;
+
+ eCalcRollTypes type = RNA_enum_get(op->ptr, "type");
+ const bool axis_only = RNA_boolean_get(op->ptr, "axis_only");
+ /* axis_flip when matching the active bone never makes sense */
+ bool axis_flip = ((type >= CALC_ROLL_ACTIVE) ? RNA_boolean_get(op->ptr, "axis_flip") :
+ (type >= CALC_ROLL_TAN_NEG_X) ? true : false);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bool changed = false;
+
+ float imat[3][3];
+ EditBone *ebone;
+
+ if ((type >= CALC_ROLL_NEG_X) && (type <= CALC_ROLL_TAN_NEG_Z)) {
+ type -= (CALC_ROLL_ACTIVE - CALC_ROLL_NEG_X);
+ axis_flip = true;
+ }
+
+ copy_m3_m4(imat, ob->obmat);
+ invert_m3(imat);
+
+ if (type == CALC_ROLL_CURSOR) { /* Cursor */
+ Scene *scene = CTX_data_scene(C);
+ float cursor_local[3];
+ const View3DCursor *cursor = &scene->cursor;
+
+ invert_m4_m4(ob->imat, ob->obmat);
+ copy_v3_v3(cursor_local, cursor->location);
+ mul_m4_v3(ob->imat, cursor_local);
+
+ /* cursor */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
+ float cursor_rel[3];
+ sub_v3_v3v3(cursor_rel, cursor_local, ebone->head);
+ if (axis_flip)
+ negate_v3(cursor_rel);
+ if (normalize_v3(cursor_rel) != 0.0f) {
+ ebone->roll = ED_armature_ebone_roll_to_vector(ebone, cursor_rel, axis_only);
+ changed = true;
+ }
+ }
+ }
+ }
+ else if (ELEM(type, CALC_ROLL_TAN_POS_X, CALC_ROLL_TAN_POS_Z)) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->parent) {
+ bool is_edit = (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone));
+ bool is_edit_parent = (EBONE_VISIBLE(arm, ebone->parent) &&
+ EBONE_EDITABLE(ebone->parent));
+
+ if (is_edit || is_edit_parent) {
+ EditBone *ebone_other = ebone->parent;
+ float dir_a[3];
+ float dir_b[3];
+ float vec[3];
+ bool is_vec_zero;
+
+ sub_v3_v3v3(dir_a, ebone->tail, ebone->head);
+ normalize_v3(dir_a);
+
+ /* find the first bone in the chane with a different direction */
+ do {
+ sub_v3_v3v3(dir_b, ebone_other->head, ebone_other->tail);
+ normalize_v3(dir_b);
+
+ if (type == CALC_ROLL_TAN_POS_Z) {
+ cross_v3_v3v3(vec, dir_a, dir_b);
+ }
+ else {
+ add_v3_v3v3(vec, dir_a, dir_b);
+ }
+ } while ((is_vec_zero = (normalize_v3(vec) < 0.00001f)) &&
+ (ebone_other = ebone_other->parent));
+
+ if (!is_vec_zero) {
+ if (axis_flip)
+ negate_v3(vec);
+
+ if (is_edit) {
+ ebone->roll = ED_armature_ebone_roll_to_vector(ebone, vec, axis_only);
+ changed = true;
+ }
+
+ /* parentless bones use cross product with child */
+ if (is_edit_parent) {
+ if (ebone->parent->parent == NULL) {
+ ebone->parent->roll = ED_armature_ebone_roll_to_vector(
+ ebone->parent, vec, axis_only);
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else {
+ float vec[3] = {0.0f, 0.0f, 0.0f};
+ if (type == CALC_ROLL_VIEW) { /* View */
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (rv3d == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No region view3d available");
+ ret = OPERATOR_CANCELLED;
+ goto cleanup;
+ }
+
+ copy_v3_v3(vec, rv3d->viewinv[2]);
+ mul_m3_v3(imat, vec);
+ }
+ else if (type == CALC_ROLL_ACTIVE) {
+ float mat[3][3];
+ bArmature *arm_active = ob_active->data;
+ ebone = (EditBone *)arm_active->act_edbone;
+ if (ebone == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No active bone set");
+ ret = OPERATOR_CANCELLED;
+ goto cleanup;
+ }
+
+ ED_armature_ebone_to_mat3(ebone, mat);
+ copy_v3_v3(vec, mat[2]);
+ }
+ else { /* Axis */
+ assert(type <= 5);
+ if (type < 3)
+ vec[type] = 1.0f;
+ else
+ vec[type - 2] = -1.0f;
+ mul_m3_v3(imat, vec);
+ normalize_v3(vec);
+ }
+
+ if (axis_flip)
+ negate_v3(vec);
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
+ /* roll func is a callback which assumes that all is well */
+ ebone->roll = ED_armature_ebone_roll_to_vector(ebone, vec, axis_only);
+ changed = true;
+ }
+ }
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) {
+ EditBone *ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
+ if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) {
+ ebone->roll = -ebone_mirr->roll;
+ }
+ }
+ }
+ }
+
+ if (changed) {
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ }
cleanup:
- MEM_freeN(objects);
- return ret;
+ MEM_freeN(objects);
+ return ret;
}
void ARMATURE_OT_calculate_roll(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Recalculate Roll";
- ot->idname = "ARMATURE_OT_calculate_roll";
- ot->description = "Automatically fix alignment of select bones' axes";
-
- /* api callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = armature_calc_roll_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", prop_calc_roll_types, CALC_ROLL_TAN_POS_X, "Type", "");
- RNA_def_boolean(ot->srna, "axis_flip", 0, "Flip Axis", "Negate the alignment axis");
- RNA_def_boolean(ot->srna, "axis_only", 0, "Shortest Rotation", "Ignore the axis direction, use the shortest rotation to align");
+ /* identifiers */
+ ot->name = "Recalculate Roll";
+ ot->idname = "ARMATURE_OT_calculate_roll";
+ ot->description = "Automatically fix alignment of select bones' axes";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = armature_calc_roll_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_calc_roll_types, CALC_ROLL_TAN_POS_X, "Type", "");
+ RNA_def_boolean(ot->srna, "axis_flip", 0, "Flip Axis", "Negate the alignment axis");
+ RNA_def_boolean(ot->srna,
+ "axis_only",
+ 0,
+ "Shortest Rotation",
+ "Ignore the axis direction, use the shortest rotation to align");
}
static int armature_roll_clear_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const float roll = RNA_float_get(op->ptr, "roll");
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- bArmature *arm = ob->data;
- bool changed = false;
-
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
- /* Roll func is a callback which assumes that all is well. */
- ebone->roll = roll;
- changed = true;
- }
- }
-
- if (arm->flag & ARM_MIRROR_EDIT) {
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) {
- EditBone *ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
- if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) {
- ebone->roll = -ebone_mirr->roll;
- changed = true;
- }
- }
- }
- }
-
- if (changed) {
- /* Note, notifier might evolve. */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
- }
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const float roll = RNA_float_get(op->ptr, "roll");
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bool changed = false;
+
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
+ /* Roll func is a callback which assumes that all is well. */
+ ebone->roll = roll;
+ changed = true;
+ }
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) {
+ EditBone *ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
+ if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) {
+ ebone->roll = -ebone_mirr->roll;
+ changed = true;
+ }
+ }
+ }
+ }
+
+ if (changed) {
+ /* Note, notifier might evolve. */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ }
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_roll_clear(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Clear Roll";
- ot->idname = "ARMATURE_OT_roll_clear";
- ot->description = "Clear roll for selected bones";
-
- /* api callbacks */
- ot->exec = armature_roll_clear_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_float_rotation(
- ot->srna, "roll", 0, NULL, DEG2RADF(-360.0f), DEG2RADF(360.0f),
- "Roll", "", DEG2RADF(-360.0f), DEG2RADF(360.0f));
+ /* identifiers */
+ ot->name = "Clear Roll";
+ ot->idname = "ARMATURE_OT_roll_clear";
+ ot->description = "Clear roll for selected bones";
+
+ /* api callbacks */
+ ot->exec = armature_roll_clear_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_float_rotation(ot->srna,
+ "roll",
+ 0,
+ NULL,
+ DEG2RADF(-360.0f),
+ DEG2RADF(360.0f),
+ "Roll",
+ "",
+ DEG2RADF(-360.0f),
+ DEG2RADF(360.0f));
}
/* ******************************** Chain-Based Tools ********************************* */
/* temporary data-structure for merge/fill bones */
typedef struct EditBonePoint {
- struct EditBonePoint *next, *prev;
+ struct EditBonePoint *next, *prev;
- EditBone *head_owner; /* EditBone which uses this point as a 'head' point */
- EditBone *tail_owner; /* EditBone which uses this point as a 'tail' point */
+ EditBone *head_owner; /* EditBone which uses this point as a 'head' point */
+ EditBone *tail_owner; /* EditBone which uses this point as a 'tail' point */
- float vec[3]; /* the actual location of the point in local/EditMode space */
+ float vec[3]; /* the actual location of the point in local/EditMode space */
} EditBonePoint;
/* find chain-tips (i.e. bones without children) */
static void chains_find_tips(ListBase *edbo, ListBase *list)
{
- EditBone *curBone, *ebo;
- LinkData *ld;
-
- /* note: this is potentially very slow ... there's got to be a better way */
- for (curBone = edbo->first; curBone; curBone = curBone->next) {
- short stop = 0;
-
- /* is this bone contained within any existing chain? (skip if so) */
- for (ld = list->first; ld; ld = ld->next) {
- for (ebo = ld->data; ebo; ebo = ebo->parent) {
- if (ebo == curBone) {
- stop = 1;
- break;
- }
- }
-
- if (stop) break;
- }
- /* skip current bone if it is part of an existing chain */
- if (stop) continue;
-
- /* is any existing chain part of the chain formed by this bone? */
- stop = 0;
- for (ebo = curBone->parent; ebo; ebo = ebo->parent) {
- for (ld = list->first; ld; ld = ld->next) {
- if (ld->data == ebo) {
- ld->data = curBone;
- stop = 1;
- break;
- }
- }
-
- if (stop) break;
- }
- /* current bone has already been added to a chain? */
- if (stop) continue;
-
- /* add current bone to a new chain */
- ld = MEM_callocN(sizeof(LinkData), "BoneChain");
- ld->data = curBone;
- BLI_addtail(list, ld);
- }
+ EditBone *curBone, *ebo;
+ LinkData *ld;
+
+ /* note: this is potentially very slow ... there's got to be a better way */
+ for (curBone = edbo->first; curBone; curBone = curBone->next) {
+ short stop = 0;
+
+ /* is this bone contained within any existing chain? (skip if so) */
+ for (ld = list->first; ld; ld = ld->next) {
+ for (ebo = ld->data; ebo; ebo = ebo->parent) {
+ if (ebo == curBone) {
+ stop = 1;
+ break;
+ }
+ }
+
+ if (stop)
+ break;
+ }
+ /* skip current bone if it is part of an existing chain */
+ if (stop)
+ continue;
+
+ /* is any existing chain part of the chain formed by this bone? */
+ stop = 0;
+ for (ebo = curBone->parent; ebo; ebo = ebo->parent) {
+ for (ld = list->first; ld; ld = ld->next) {
+ if (ld->data == ebo) {
+ ld->data = curBone;
+ stop = 1;
+ break;
+ }
+ }
+
+ if (stop)
+ break;
+ }
+ /* current bone has already been added to a chain? */
+ if (stop)
+ continue;
+
+ /* add current bone to a new chain */
+ ld = MEM_callocN(sizeof(LinkData), "BoneChain");
+ ld->data = curBone;
+ BLI_addtail(list, ld);
+ }
}
/* --------------------- */
static void fill_add_joint(EditBone *ebo, short eb_tail, ListBase *points)
{
- EditBonePoint *ebp;
- float vec[3];
- short found = 0;
-
- if (eb_tail) {
- copy_v3_v3(vec, ebo->tail);
- }
- else {
- copy_v3_v3(vec, ebo->head);
- }
-
- for (ebp = points->first; ebp; ebp = ebp->next) {
- if (equals_v3v3(ebp->vec, vec)) {
- if (eb_tail) {
- if ((ebp->head_owner) && (ebp->head_owner->parent == ebo)) {
- /* so this bone's tail owner is this bone */
- ebp->tail_owner = ebo;
- found = 1;
- break;
- }
- }
- else {
- if ((ebp->tail_owner) && (ebo->parent == ebp->tail_owner)) {
- /* so this bone's head owner is this bone */
- ebp->head_owner = ebo;
- found = 1;
- break;
- }
- }
- }
- }
-
- /* allocate a new point if no existing point was related */
- if (found == 0) {
- ebp = MEM_callocN(sizeof(EditBonePoint), "EditBonePoint");
-
- if (eb_tail) {
- copy_v3_v3(ebp->vec, ebo->tail);
- ebp->tail_owner = ebo;
- }
- else {
- copy_v3_v3(ebp->vec, ebo->head);
- ebp->head_owner = ebo;
- }
-
- BLI_addtail(points, ebp);
- }
+ EditBonePoint *ebp;
+ float vec[3];
+ short found = 0;
+
+ if (eb_tail) {
+ copy_v3_v3(vec, ebo->tail);
+ }
+ else {
+ copy_v3_v3(vec, ebo->head);
+ }
+
+ for (ebp = points->first; ebp; ebp = ebp->next) {
+ if (equals_v3v3(ebp->vec, vec)) {
+ if (eb_tail) {
+ if ((ebp->head_owner) && (ebp->head_owner->parent == ebo)) {
+ /* so this bone's tail owner is this bone */
+ ebp->tail_owner = ebo;
+ found = 1;
+ break;
+ }
+ }
+ else {
+ if ((ebp->tail_owner) && (ebo->parent == ebp->tail_owner)) {
+ /* so this bone's head owner is this bone */
+ ebp->head_owner = ebo;
+ found = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ /* allocate a new point if no existing point was related */
+ if (found == 0) {
+ ebp = MEM_callocN(sizeof(EditBonePoint), "EditBonePoint");
+
+ if (eb_tail) {
+ copy_v3_v3(ebp->vec, ebo->tail);
+ ebp->tail_owner = ebo;
+ }
+ else {
+ copy_v3_v3(ebp->vec, ebo->head);
+ ebp->head_owner = ebo;
+ }
+
+ BLI_addtail(points, ebp);
+ }
}
/* bone adding between selected joints */
static int armature_fill_bones_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- ListBase points = {NULL, NULL};
- EditBone *newbone = NULL;
- int count;
- bool mixed_object_error = false;
-
- /* loop over all bones, and only consider if visible */
- bArmature *arm = NULL;
- CTX_DATA_BEGIN_WITH_ID(C, EditBone *, ebone, visible_bones, bArmature *, arm_iter)
- {
- bool check = false;
- if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL)) {
- fill_add_joint(ebone, 0, &points);
- check = true;
- }
- if (ebone->flag & BONE_TIPSEL) {
- fill_add_joint(ebone, 1, &points);
- check = true;
- }
-
- if (check) {
- if (arm && (arm != arm_iter)) {
- mixed_object_error = true;
- }
- arm = arm_iter;
- }
- }
- CTX_DATA_END;
-
- /* the number of joints determines how we fill:
- * 1) between joint and cursor (joint=head, cursor=tail)
- * 2) between the two joints (order is dependent on active-bone/hierarchy)
- * 3+) error (a smarter method involving finding chains needs to be worked out
- */
- count = BLI_listbase_count(&points);
-
- if (count == 0) {
- BKE_report(op->reports, RPT_ERROR, "No joints selected");
- return OPERATOR_CANCELLED;
- }
- else if (mixed_object_error) {
- BKE_report(op->reports, RPT_ERROR, "Bones for different objects selected");
- BLI_freelistN(&points);
- return OPERATOR_CANCELLED;
- }
-
- Object *obedit = NULL;
- {
- ViewLayer *view_layer = CTX_data_view_layer(C);
- FOREACH_OBJECT_IN_EDIT_MODE_BEGIN (view_layer, v3d, ob_iter) {
- if (ob_iter->data == arm) {
- obedit = ob_iter;
- }
- }
- FOREACH_OBJECT_IN_MODE_END;
- }
- BLI_assert(obedit != NULL);
-
- if (count == 1) {
- EditBonePoint *ebp;
- float curs[3];
-
- /* Get Points - selected joint */
- ebp = points.first;
-
- /* Get points - cursor (tail) */
- invert_m4_m4(obedit->imat, obedit->obmat);
- mul_v3_m4v3(curs, obedit->imat, scene->cursor.location);
-
- /* Create a bone */
- newbone = add_points_bone(obedit, ebp->vec, curs);
- }
- else if (count == 2) {
- EditBonePoint *ebp_a, *ebp_b;
- float head[3], tail[3];
- short headtail = 0;
-
- /* check that the points don't belong to the same bone */
- ebp_a = (EditBonePoint *)points.first;
- ebp_b = ebp_a->next;
-
- if (((ebp_a->head_owner == ebp_b->tail_owner) && (ebp_a->head_owner != NULL)) ||
- ((ebp_a->tail_owner == ebp_b->head_owner) && (ebp_a->tail_owner != NULL)))
- {
- BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
- BLI_freelistN(&points);
- return OPERATOR_CANCELLED;
- }
-
- /* find which one should be the 'head' */
- if ((ebp_a->head_owner && ebp_b->head_owner) || (ebp_a->tail_owner && ebp_b->tail_owner)) {
- /* use active, nice predictable */
- if (arm->act_edbone && ELEM(arm->act_edbone, ebp_a->head_owner, ebp_a->tail_owner)) {
- headtail = 1;
- }
- else if (arm->act_edbone && ELEM(arm->act_edbone, ebp_b->head_owner, ebp_b->tail_owner)) {
- headtail = 2;
- }
- else {
- /* rule: whichever one is closer to 3d-cursor */
- float curs[3];
- float dist_sq_a, dist_sq_b;
-
- /* get cursor location */
- invert_m4_m4(obedit->imat, obedit->obmat);
- mul_v3_m4v3(curs, obedit->imat, scene->cursor.location);
-
- /* get distances */
- dist_sq_a = len_squared_v3v3(ebp_a->vec, curs);
- dist_sq_b = len_squared_v3v3(ebp_b->vec, curs);
-
- /* compare distances - closer one therefore acts as direction for bone to go */
- headtail = (dist_sq_a < dist_sq_b) ? 2 : 1;
- }
- }
- else if (ebp_a->head_owner) {
- headtail = 1;
- }
- else if (ebp_b->head_owner) {
- headtail = 2;
- }
-
- /* assign head/tail combinations */
- if (headtail == 2) {
- copy_v3_v3(head, ebp_a->vec);
- copy_v3_v3(tail, ebp_b->vec);
- }
- else if (headtail == 1) {
- copy_v3_v3(head, ebp_b->vec);
- copy_v3_v3(tail, ebp_a->vec);
- }
-
- /* add new bone and parent it to the appropriate end */
- if (headtail) {
- newbone = add_points_bone(obedit, head, tail);
-
- /* do parenting (will need to set connected flag too) */
- if (headtail == 2) {
- /* ebp tail or head - tail gets priority */
- if (ebp_a->tail_owner)
- newbone->parent = ebp_a->tail_owner;
- else
- newbone->parent = ebp_a->head_owner;
- }
- else {
- /* ebp_b tail or head - tail gets priority */
- if (ebp_b->tail_owner)
- newbone->parent = ebp_b->tail_owner;
- else
- newbone->parent = ebp_b->head_owner;
- }
-
- /* don't set for bone connecting two head points of bones */
- if (ebp_a->tail_owner || ebp_b->tail_owner) {
- newbone->flag |= BONE_CONNECTED;
- }
- }
- }
- else {
- BKE_reportf(op->reports, RPT_ERROR, "Too many points selected: %d", count);
- BLI_freelistN(&points);
- return OPERATOR_CANCELLED;
- }
-
- if (newbone) {
- ED_armature_edit_deselect_all(obedit);
- arm->act_edbone = newbone;
- newbone->flag |= BONE_TIPSEL;
- }
-
- /* updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
-
- /* free points */
- BLI_freelistN(&points);
-
- return OPERATOR_FINISHED;
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ ListBase points = {NULL, NULL};
+ EditBone *newbone = NULL;
+ int count;
+ bool mixed_object_error = false;
+
+ /* loop over all bones, and only consider if visible */
+ bArmature *arm = NULL;
+ CTX_DATA_BEGIN_WITH_ID(C, EditBone *, ebone, visible_bones, bArmature *, arm_iter)
+ {
+ bool check = false;
+ if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL)) {
+ fill_add_joint(ebone, 0, &points);
+ check = true;
+ }
+ if (ebone->flag & BONE_TIPSEL) {
+ fill_add_joint(ebone, 1, &points);
+ check = true;
+ }
+
+ if (check) {
+ if (arm && (arm != arm_iter)) {
+ mixed_object_error = true;
+ }
+ arm = arm_iter;
+ }
+ }
+ CTX_DATA_END;
+
+ /* the number of joints determines how we fill:
+ * 1) between joint and cursor (joint=head, cursor=tail)
+ * 2) between the two joints (order is dependent on active-bone/hierarchy)
+ * 3+) error (a smarter method involving finding chains needs to be worked out
+ */
+ count = BLI_listbase_count(&points);
+
+ if (count == 0) {
+ BKE_report(op->reports, RPT_ERROR, "No joints selected");
+ return OPERATOR_CANCELLED;
+ }
+ else if (mixed_object_error) {
+ BKE_report(op->reports, RPT_ERROR, "Bones for different objects selected");
+ BLI_freelistN(&points);
+ return OPERATOR_CANCELLED;
+ }
+
+ Object *obedit = NULL;
+ {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ FOREACH_OBJECT_IN_EDIT_MODE_BEGIN (view_layer, v3d, ob_iter) {
+ if (ob_iter->data == arm) {
+ obedit = ob_iter;
+ }
+ }
+ FOREACH_OBJECT_IN_MODE_END;
+ }
+ BLI_assert(obedit != NULL);
+
+ if (count == 1) {
+ EditBonePoint *ebp;
+ float curs[3];
+
+ /* Get Points - selected joint */
+ ebp = points.first;
+
+ /* Get points - cursor (tail) */
+ invert_m4_m4(obedit->imat, obedit->obmat);
+ mul_v3_m4v3(curs, obedit->imat, scene->cursor.location);
+
+ /* Create a bone */
+ newbone = add_points_bone(obedit, ebp->vec, curs);
+ }
+ else if (count == 2) {
+ EditBonePoint *ebp_a, *ebp_b;
+ float head[3], tail[3];
+ short headtail = 0;
+
+ /* check that the points don't belong to the same bone */
+ ebp_a = (EditBonePoint *)points.first;
+ ebp_b = ebp_a->next;
+
+ if (((ebp_a->head_owner == ebp_b->tail_owner) && (ebp_a->head_owner != NULL)) ||
+ ((ebp_a->tail_owner == ebp_b->head_owner) && (ebp_a->tail_owner != NULL))) {
+ BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
+ BLI_freelistN(&points);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* find which one should be the 'head' */
+ if ((ebp_a->head_owner && ebp_b->head_owner) || (ebp_a->tail_owner && ebp_b->tail_owner)) {
+ /* use active, nice predictable */
+ if (arm->act_edbone && ELEM(arm->act_edbone, ebp_a->head_owner, ebp_a->tail_owner)) {
+ headtail = 1;
+ }
+ else if (arm->act_edbone && ELEM(arm->act_edbone, ebp_b->head_owner, ebp_b->tail_owner)) {
+ headtail = 2;
+ }
+ else {
+ /* rule: whichever one is closer to 3d-cursor */
+ float curs[3];
+ float dist_sq_a, dist_sq_b;
+
+ /* get cursor location */
+ invert_m4_m4(obedit->imat, obedit->obmat);
+ mul_v3_m4v3(curs, obedit->imat, scene->cursor.location);
+
+ /* get distances */
+ dist_sq_a = len_squared_v3v3(ebp_a->vec, curs);
+ dist_sq_b = len_squared_v3v3(ebp_b->vec, curs);
+
+ /* compare distances - closer one therefore acts as direction for bone to go */
+ headtail = (dist_sq_a < dist_sq_b) ? 2 : 1;
+ }
+ }
+ else if (ebp_a->head_owner) {
+ headtail = 1;
+ }
+ else if (ebp_b->head_owner) {
+ headtail = 2;
+ }
+
+ /* assign head/tail combinations */
+ if (headtail == 2) {
+ copy_v3_v3(head, ebp_a->vec);
+ copy_v3_v3(tail, ebp_b->vec);
+ }
+ else if (headtail == 1) {
+ copy_v3_v3(head, ebp_b->vec);
+ copy_v3_v3(tail, ebp_a->vec);
+ }
+
+ /* add new bone and parent it to the appropriate end */
+ if (headtail) {
+ newbone = add_points_bone(obedit, head, tail);
+
+ /* do parenting (will need to set connected flag too) */
+ if (headtail == 2) {
+ /* ebp tail or head - tail gets priority */
+ if (ebp_a->tail_owner)
+ newbone->parent = ebp_a->tail_owner;
+ else
+ newbone->parent = ebp_a->head_owner;
+ }
+ else {
+ /* ebp_b tail or head - tail gets priority */
+ if (ebp_b->tail_owner)
+ newbone->parent = ebp_b->tail_owner;
+ else
+ newbone->parent = ebp_b->head_owner;
+ }
+
+ /* don't set for bone connecting two head points of bones */
+ if (ebp_a->tail_owner || ebp_b->tail_owner) {
+ newbone->flag |= BONE_CONNECTED;
+ }
+ }
+ }
+ else {
+ BKE_reportf(op->reports, RPT_ERROR, "Too many points selected: %d", count);
+ BLI_freelistN(&points);
+ return OPERATOR_CANCELLED;
+ }
+
+ if (newbone) {
+ ED_armature_edit_deselect_all(obedit);
+ arm->act_edbone = newbone;
+ newbone->flag |= BONE_TIPSEL;
+ }
+
+ /* updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
+
+ /* free points */
+ BLI_freelistN(&points);
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_fill(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Fill Between Joints";
- ot->idname = "ARMATURE_OT_fill";
- ot->description = "Add bone between selected joint(s) and/or 3D-Cursor";
+ /* identifiers */
+ ot->name = "Fill Between Joints";
+ ot->idname = "ARMATURE_OT_fill";
+ ot->description = "Add bone between selected joint(s) and/or 3D-Cursor";
- /* callbacks */
- ot->exec = armature_fill_bones_exec;
- ot->poll = ED_operator_editarmature;
+ /* callbacks */
+ ot->exec = armature_fill_bones_exec;
+ ot->poll = ED_operator_editarmature;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* --------------------- */
@@ -852,194 +878,193 @@ void ARMATURE_OT_fill(wmOperatorType *ot)
/* this function merges between two bones, removes them and those in-between,
* and adjusts the parent relationships for those in-between
*/
-static void bones_merge(Object *obedit, EditBone *start, EditBone *end, EditBone *endchild, ListBase *chains)
+static void bones_merge(
+ Object *obedit, EditBone *start, EditBone *end, EditBone *endchild, ListBase *chains)
{
- bArmature *arm = obedit->data;
- EditBone *ebo, *ebone, *newbone;
- LinkData *chain;
- float head[3], tail[3];
-
- /* check if same bone */
- if (start == end) {
- if (G.debug & G_DEBUG) {
- printf("Error: same bone!\n");
- printf("\tstart = %s, end = %s\n", start->name, end->name);
- }
- }
-
- /* step 1: add a new bone
- * - head = head/tail of start (default head)
- * - tail = head/tail of end (default tail)
- * - parent = parent of start
- */
- if ((start->flag & BONE_TIPSEL) && (start->flag & BONE_SELECTED) == 0) {
- copy_v3_v3(head, start->tail);
- }
- else {
- copy_v3_v3(head, start->head);
- }
- if ((end->flag & BONE_ROOTSEL) && (end->flag & BONE_SELECTED) == 0) {
- copy_v3_v3(tail, end->head);
- }
- else {
- copy_v3_v3(tail, end->tail);
- }
- newbone = add_points_bone(obedit, head, tail);
- newbone->parent = start->parent;
-
- /* TODO, copy more things to the new bone */
- newbone->flag = start->flag & (BONE_HINGE | BONE_NO_DEFORM | BONE_NO_SCALE |
- BONE_NO_CYCLICOFFSET | BONE_NO_LOCAL_LOCATION | BONE_DONE);
-
- /* step 2a: reparent any side chains which may be parented to any bone in the chain of bones to merge
- * - potentially several tips for side chains leading to some tree exist...
- */
- for (chain = chains->first; chain; chain = chain->next) {
- /* traverse down chain until we hit the bottom or if we run into the tip of the chain of bones we're
- * merging (need to stop in this case to avoid corrupting this chain too!)
- */
- for (ebone = chain->data; (ebone) && (ebone != end); ebone = ebone->parent) {
- short found = 0;
-
- /* check if this bone is parented to one in the merging chain
- * ! WATCHIT: must only go check until end of checking chain
- */
- for (ebo = end; (ebo) && (ebo != start->parent); ebo = ebo->parent) {
- /* side-chain found? --> remap parent to new bone, then we're done with this chain :) */
- if (ebone->parent == ebo) {
- ebone->parent = newbone;
- found = 1;
- break;
- }
- }
-
- /* carry on to the next tip now */
- if (found)
- break;
- }
- }
-
- /* step 2b: parent child of end to newbone (child from this chain) */
- if (endchild)
- endchild->parent = newbone;
-
- /* step 3: delete all bones between and including start and end */
- for (ebo = end; ebo; ebo = ebone) {
- ebone = (ebo == start) ? (NULL) : (ebo->parent);
- bone_free(arm, ebo);
- }
-
- newbone->flag |= (BONE_ROOTSEL | BONE_TIPSEL | BONE_SELECTED);
- ED_armature_edit_sync_selection(arm->edbo);
+ bArmature *arm = obedit->data;
+ EditBone *ebo, *ebone, *newbone;
+ LinkData *chain;
+ float head[3], tail[3];
+
+ /* check if same bone */
+ if (start == end) {
+ if (G.debug & G_DEBUG) {
+ printf("Error: same bone!\n");
+ printf("\tstart = %s, end = %s\n", start->name, end->name);
+ }
+ }
+
+ /* step 1: add a new bone
+ * - head = head/tail of start (default head)
+ * - tail = head/tail of end (default tail)
+ * - parent = parent of start
+ */
+ if ((start->flag & BONE_TIPSEL) && (start->flag & BONE_SELECTED) == 0) {
+ copy_v3_v3(head, start->tail);
+ }
+ else {
+ copy_v3_v3(head, start->head);
+ }
+ if ((end->flag & BONE_ROOTSEL) && (end->flag & BONE_SELECTED) == 0) {
+ copy_v3_v3(tail, end->head);
+ }
+ else {
+ copy_v3_v3(tail, end->tail);
+ }
+ newbone = add_points_bone(obedit, head, tail);
+ newbone->parent = start->parent;
+
+ /* TODO, copy more things to the new bone */
+ newbone->flag = start->flag & (BONE_HINGE | BONE_NO_DEFORM | BONE_NO_SCALE |
+ BONE_NO_CYCLICOFFSET | BONE_NO_LOCAL_LOCATION | BONE_DONE);
+
+ /* step 2a: reparent any side chains which may be parented to any bone in the chain of bones to merge
+ * - potentially several tips for side chains leading to some tree exist...
+ */
+ for (chain = chains->first; chain; chain = chain->next) {
+ /* traverse down chain until we hit the bottom or if we run into the tip of the chain of bones we're
+ * merging (need to stop in this case to avoid corrupting this chain too!)
+ */
+ for (ebone = chain->data; (ebone) && (ebone != end); ebone = ebone->parent) {
+ short found = 0;
+
+ /* check if this bone is parented to one in the merging chain
+ * ! WATCHIT: must only go check until end of checking chain
+ */
+ for (ebo = end; (ebo) && (ebo != start->parent); ebo = ebo->parent) {
+ /* side-chain found? --> remap parent to new bone, then we're done with this chain :) */
+ if (ebone->parent == ebo) {
+ ebone->parent = newbone;
+ found = 1;
+ break;
+ }
+ }
+
+ /* carry on to the next tip now */
+ if (found)
+ break;
+ }
+ }
+
+ /* step 2b: parent child of end to newbone (child from this chain) */
+ if (endchild)
+ endchild->parent = newbone;
+
+ /* step 3: delete all bones between and including start and end */
+ for (ebo = end; ebo; ebo = ebone) {
+ ebone = (ebo == start) ? (NULL) : (ebo->parent);
+ bone_free(arm, ebo);
+ }
+
+ newbone->flag |= (BONE_ROOTSEL | BONE_TIPSEL | BONE_SELECTED);
+ ED_armature_edit_sync_selection(arm->edbo);
}
-
static int armature_merge_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const short type = RNA_enum_get(op->ptr, "type");
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- bArmature *arm = obedit->data;
-
- /* for now, there's only really one type of merging that's performed... */
- if (type == 1) {
- /* go down chains, merging bones */
- ListBase chains = {NULL, NULL};
- LinkData *chain, *nchain;
- EditBone *ebo;
-
- armature_tag_select_mirrored(arm);
-
- /* get chains (ends on chains) */
- chains_find_tips(arm->edbo, &chains);
- if (BLI_listbase_is_empty(&chains)) {
- continue;
- }
-
- /* each 'chain' is the last bone in the chain (with no children) */
- for (chain = chains.first; chain; chain = nchain) {
- EditBone *bstart = NULL, *bend = NULL;
- EditBone *bchild = NULL, *child = NULL;
-
- /* temporarily remove chain from list of chains */
- nchain = chain->next;
- BLI_remlink(&chains, chain);
-
- /* only consider bones that are visible and selected */
- for (ebo = chain->data; ebo; child = ebo, ebo = ebo->parent) {
- /* check if visible + selected */
- if (EBONE_VISIBLE(arm, ebo) &&
- ((ebo->flag & BONE_CONNECTED) || (ebo->parent == NULL)) &&
- (ebo->flag & BONE_SELECTED) )
- {
- /* set either end or start (end gets priority, unless it is already set) */
- if (bend == NULL) {
- bend = ebo;
- bchild = child;
- }
- else
- bstart = ebo;
- }
- else {
- /* chain is broken... merge any continuous segments then clear */
- if (bstart && bend)
- bones_merge(obedit, bstart, bend, bchild, &chains);
-
- bstart = NULL;
- bend = NULL;
- bchild = NULL;
- }
- }
-
- /* merge from bstart to bend if something not merged */
- if (bstart && bend)
- bones_merge(obedit, bstart, bend, bchild, &chains);
-
- /* put back link */
- BLI_insertlinkbefore(&chains, nchain, chain);
- }
-
- armature_tag_unselect(arm);
-
- BLI_freelistN(&chains);
- }
-
- /* updates */
- ED_armature_edit_sync_selection(arm->edbo);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const short type = RNA_enum_get(op->ptr, "type");
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
+
+ /* for now, there's only really one type of merging that's performed... */
+ if (type == 1) {
+ /* go down chains, merging bones */
+ ListBase chains = {NULL, NULL};
+ LinkData *chain, *nchain;
+ EditBone *ebo;
+
+ armature_tag_select_mirrored(arm);
+
+ /* get chains (ends on chains) */
+ chains_find_tips(arm->edbo, &chains);
+ if (BLI_listbase_is_empty(&chains)) {
+ continue;
+ }
+
+ /* each 'chain' is the last bone in the chain (with no children) */
+ for (chain = chains.first; chain; chain = nchain) {
+ EditBone *bstart = NULL, *bend = NULL;
+ EditBone *bchild = NULL, *child = NULL;
+
+ /* temporarily remove chain from list of chains */
+ nchain = chain->next;
+ BLI_remlink(&chains, chain);
+
+ /* only consider bones that are visible and selected */
+ for (ebo = chain->data; ebo; child = ebo, ebo = ebo->parent) {
+ /* check if visible + selected */
+ if (EBONE_VISIBLE(arm, ebo) && ((ebo->flag & BONE_CONNECTED) || (ebo->parent == NULL)) &&
+ (ebo->flag & BONE_SELECTED)) {
+ /* set either end or start (end gets priority, unless it is already set) */
+ if (bend == NULL) {
+ bend = ebo;
+ bchild = child;
+ }
+ else
+ bstart = ebo;
+ }
+ else {
+ /* chain is broken... merge any continuous segments then clear */
+ if (bstart && bend)
+ bones_merge(obedit, bstart, bend, bchild, &chains);
+
+ bstart = NULL;
+ bend = NULL;
+ bchild = NULL;
+ }
+ }
+
+ /* merge from bstart to bend if something not merged */
+ if (bstart && bend)
+ bones_merge(obedit, bstart, bend, bchild, &chains);
+
+ /* put back link */
+ BLI_insertlinkbefore(&chains, nchain, chain);
+ }
+
+ armature_tag_unselect(arm);
+
+ BLI_freelistN(&chains);
+ }
+
+ /* updates */
+ ED_armature_edit_sync_selection(arm->edbo);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
+ }
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_merge(wmOperatorType *ot)
{
- static const EnumPropertyItem merge_types[] = {
- {1, "WITHIN_CHAIN", 0, "Within Chains", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Merge Bones";
- ot->idname = "ARMATURE_OT_merge";
- ot->description = "Merge continuous chains of selected bones";
-
- /* callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = armature_merge_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", merge_types, 0, "Type", "");
+ static const EnumPropertyItem merge_types[] = {
+ {1, "WITHIN_CHAIN", 0, "Within Chains", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Merge Bones";
+ ot->idname = "ARMATURE_OT_merge";
+ ot->description = "Merge continuous chains of selected bones";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = armature_merge_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", merge_types, 0, "Type", "");
}
/* --------------------- */
@@ -1053,125 +1078,126 @@ void ARMATURE_OT_merge(wmOperatorType *ot)
/* helper to clear BONE_TRANSFORM flags */
static void armature_clear_swap_done_flags(bArmature *arm)
{
- EditBone *ebone;
+ EditBone *ebone;
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- ebone->flag &= ~BONE_TRANSFORM;
- }
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ ebone->flag &= ~BONE_TRANSFORM;
+ }
}
static int armature_switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- bArmature *arm = ob->data;
-
- ListBase chains = {NULL, NULL};
- LinkData *chain;
-
- /* get chains of bones (ends on chains) */
- chains_find_tips(arm->edbo, &chains);
- if (BLI_listbase_is_empty(&chains)) {
- continue;
- }
-
- /* ensure that mirror bones will also be operated on */
- armature_tag_select_mirrored(arm);
-
- /* clear BONE_TRANSFORM flags
- * - used to prevent duplicate/canceling operations from occurring [#34123]
- * - BONE_DONE cannot be used here as that's already used for mirroring
- */
- armature_clear_swap_done_flags(arm);
-
- /* loop over chains, only considering selected and visible bones */
- for (chain = chains.first; chain; chain = chain->next) {
- EditBone *ebo, *child = NULL, *parent = NULL;
-
- /* loop over bones in chain */
- for (ebo = chain->data; ebo; ebo = parent) {
- /* parent is this bone's original parent
- * - we store this, as the next bone that is checked is this one
- * but the value of ebo->parent may change here...
- */
- parent = ebo->parent;
-
- /* skip bone if already handled... [#34123] */
- if ((ebo->flag & BONE_TRANSFORM) == 0) {
- /* only if selected and editable */
- if (EBONE_VISIBLE(arm, ebo) && EBONE_EDITABLE(ebo)) {
- /* swap head and tail coordinates */
- swap_v3_v3(ebo->head, ebo->tail);
-
- /* do parent swapping:
- * - use 'child' as new parent
- * - connected flag is only set if points are coincidental
- */
- ebo->parent = child;
- if ((child) && equals_v3v3(ebo->head, child->tail))
- ebo->flag |= BONE_CONNECTED;
- else
- ebo->flag &= ~BONE_CONNECTED;
-
- /* get next bones
- * - child will become the new parent of next bone
- */
- child = ebo;
- }
- else {
- /* not swapping this bone, however, if its 'parent' got swapped, unparent us from it
- * as it will be facing in opposite direction
- */
- if ((parent) && (EBONE_VISIBLE(arm, parent) && EBONE_EDITABLE(parent))) {
- ebo->parent = NULL;
- ebo->flag &= ~BONE_CONNECTED;
- }
-
- /* get next bones
- * - child will become new parent of next bone (not swapping occurred,
- * so set to NULL to prevent infinite-loop)
- */
- child = NULL;
- }
-
- /* tag as done (to prevent double-swaps) */
- ebo->flag |= BONE_TRANSFORM;
- }
- }
- }
-
- /* free chains */
- BLI_freelistN(&chains);
-
- /* clear temp flags */
- armature_clear_swap_done_flags(arm);
- armature_tag_unselect(arm);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+
+ ListBase chains = {NULL, NULL};
+ LinkData *chain;
+
+ /* get chains of bones (ends on chains) */
+ chains_find_tips(arm->edbo, &chains);
+ if (BLI_listbase_is_empty(&chains)) {
+ continue;
+ }
+
+ /* ensure that mirror bones will also be operated on */
+ armature_tag_select_mirrored(arm);
+
+ /* clear BONE_TRANSFORM flags
+ * - used to prevent duplicate/canceling operations from occurring [#34123]
+ * - BONE_DONE cannot be used here as that's already used for mirroring
+ */
+ armature_clear_swap_done_flags(arm);
+
+ /* loop over chains, only considering selected and visible bones */
+ for (chain = chains.first; chain; chain = chain->next) {
+ EditBone *ebo, *child = NULL, *parent = NULL;
+
+ /* loop over bones in chain */
+ for (ebo = chain->data; ebo; ebo = parent) {
+ /* parent is this bone's original parent
+ * - we store this, as the next bone that is checked is this one
+ * but the value of ebo->parent may change here...
+ */
+ parent = ebo->parent;
+
+ /* skip bone if already handled... [#34123] */
+ if ((ebo->flag & BONE_TRANSFORM) == 0) {
+ /* only if selected and editable */
+ if (EBONE_VISIBLE(arm, ebo) && EBONE_EDITABLE(ebo)) {
+ /* swap head and tail coordinates */
+ swap_v3_v3(ebo->head, ebo->tail);
+
+ /* do parent swapping:
+ * - use 'child' as new parent
+ * - connected flag is only set if points are coincidental
+ */
+ ebo->parent = child;
+ if ((child) && equals_v3v3(ebo->head, child->tail))
+ ebo->flag |= BONE_CONNECTED;
+ else
+ ebo->flag &= ~BONE_CONNECTED;
+
+ /* get next bones
+ * - child will become the new parent of next bone
+ */
+ child = ebo;
+ }
+ else {
+ /* not swapping this bone, however, if its 'parent' got swapped, unparent us from it
+ * as it will be facing in opposite direction
+ */
+ if ((parent) && (EBONE_VISIBLE(arm, parent) && EBONE_EDITABLE(parent))) {
+ ebo->parent = NULL;
+ ebo->flag &= ~BONE_CONNECTED;
+ }
+
+ /* get next bones
+ * - child will become new parent of next bone (not swapping occurred,
+ * so set to NULL to prevent infinite-loop)
+ */
+ child = NULL;
+ }
+
+ /* tag as done (to prevent double-swaps) */
+ ebo->flag |= BONE_TRANSFORM;
+ }
+ }
+ }
+
+ /* free chains */
+ BLI_freelistN(&chains);
+
+ /* clear temp flags */
+ armature_clear_swap_done_flags(arm);
+ armature_tag_unselect(arm);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_switch_direction(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Switch Direction";
- ot->idname = "ARMATURE_OT_switch_direction";
- ot->description = "Change the direction that a chain of bones points in (head <-> tail swap)";
+ /* identifiers */
+ ot->name = "Switch Direction";
+ ot->idname = "ARMATURE_OT_switch_direction";
+ ot->description = "Change the direction that a chain of bones points in (head <-> tail swap)";
- /* api callbacks */
- ot->exec = armature_switch_direction_exec;
- ot->poll = ED_operator_editarmature;
+ /* api callbacks */
+ ot->exec = armature_switch_direction_exec;
+ ot->poll = ED_operator_editarmature;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ********************************* Align ******************************* */
@@ -1179,538 +1205,544 @@ void ARMATURE_OT_switch_direction(wmOperatorType *ot)
/* helper to fix a ebone position if its parent has moved due to alignment*/
static void fix_connected_bone(EditBone *ebone)
{
- float diff[3];
+ float diff[3];
- if (!(ebone->parent) || !(ebone->flag & BONE_CONNECTED) || equals_v3v3(ebone->parent->tail, ebone->head))
- return;
+ if (!(ebone->parent) || !(ebone->flag & BONE_CONNECTED) ||
+ equals_v3v3(ebone->parent->tail, ebone->head))
+ return;
- /* if the parent has moved we translate child's head and tail accordingly */
- sub_v3_v3v3(diff, ebone->parent->tail, ebone->head);
- add_v3_v3(ebone->head, diff);
- add_v3_v3(ebone->tail, diff);
+ /* if the parent has moved we translate child's head and tail accordingly */
+ sub_v3_v3v3(diff, ebone->parent->tail, ebone->head);
+ add_v3_v3(ebone->head, diff);
+ add_v3_v3(ebone->tail, diff);
}
/* helper to recursively find chains of connected bones starting at ebone and fix their position */
static void fix_editbone_connected_children(ListBase *edbo, EditBone *ebone)
{
- EditBone *selbone;
-
- for (selbone = edbo->first; selbone; selbone = selbone->next) {
- if ((selbone->parent) && (selbone->parent == ebone) && (selbone->flag & BONE_CONNECTED)) {
- fix_connected_bone(selbone);
- fix_editbone_connected_children(edbo, selbone);
- }
- }
+ EditBone *selbone;
+
+ for (selbone = edbo->first; selbone; selbone = selbone->next) {
+ if ((selbone->parent) && (selbone->parent == ebone) && (selbone->flag & BONE_CONNECTED)) {
+ fix_connected_bone(selbone);
+ fix_editbone_connected_children(edbo, selbone);
+ }
+ }
}
static void bone_align_to_bone(ListBase *edbo, EditBone *selbone, EditBone *actbone)
{
- float selboneaxis[3], actboneaxis[3], length;
+ float selboneaxis[3], actboneaxis[3], length;
- sub_v3_v3v3(actboneaxis, actbone->tail, actbone->head);
- normalize_v3(actboneaxis);
+ sub_v3_v3v3(actboneaxis, actbone->tail, actbone->head);
+ normalize_v3(actboneaxis);
- sub_v3_v3v3(selboneaxis, selbone->tail, selbone->head);
- length = len_v3(selboneaxis);
+ sub_v3_v3v3(selboneaxis, selbone->tail, selbone->head);
+ length = len_v3(selboneaxis);
- mul_v3_fl(actboneaxis, length);
- add_v3_v3v3(selbone->tail, selbone->head, actboneaxis);
- selbone->roll = actbone->roll;
+ mul_v3_fl(actboneaxis, length);
+ add_v3_v3v3(selbone->tail, selbone->head, actboneaxis);
+ selbone->roll = actbone->roll;
- /* if the bone being aligned has connected descendants they must be moved
- * according to their parent new position, otherwise they would be left
- * in an inconsistent state: connected but away from the parent*/
- fix_editbone_connected_children(edbo, selbone);
+ /* if the bone being aligned has connected descendants they must be moved
+ * according to their parent new position, otherwise they would be left
+ * in an inconsistent state: connected but away from the parent*/
+ fix_editbone_connected_children(edbo, selbone);
}
static int armature_align_bones_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_edit_object(C);
- bArmature *arm = (bArmature *)ob->data;
- EditBone *actbone = CTX_data_active_bone(C);
- EditBone *actmirb = NULL;
- int num_selected_bones;
-
- /* there must be an active bone */
- if (actbone == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
- return OPERATOR_CANCELLED;
- }
- else if (arm->flag & ARM_MIRROR_EDIT) {
- /* For X-Axis Mirror Editing option, we may need a mirror copy of actbone
- * - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone
- * (i.e. selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
- * This is useful for arm-chains, for example parenting lower arm to upper arm
- * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
- * then just use actbone. Useful when doing upper arm to spine.
- */
- actmirb = ED_armature_ebone_get_mirrored(arm->edbo, actbone);
- if (actmirb == NULL)
- actmirb = actbone;
- }
-
- /* if there is only 1 selected bone, we assume that that is the active bone,
- * since a user will need to have clicked on a bone (thus selecting it) to make it active
- */
- num_selected_bones = CTX_DATA_COUNT(C, selected_editable_bones);
- if (num_selected_bones <= 1) {
- /* When only the active bone is selected, and it has a parent,
- * align it to the parent, as that is the only possible outcome.
- */
- if (actbone->parent) {
- bone_align_to_bone(arm->edbo, actbone, actbone->parent);
-
- if ((arm->flag & ARM_MIRROR_EDIT) && (actmirb->parent))
- bone_align_to_bone(arm->edbo, actmirb, actmirb->parent);
-
- BKE_reportf(op->reports, RPT_INFO, "Aligned bone '%s' to parent", actbone->name);
- }
- }
- else {
- /* Align 'selected' bones to the active one
- * - the context iterator contains both selected bones and their mirrored copies,
- * so we assume that unselected bones are mirrored copies of some selected bone
- * - since the active one (and/or its mirror) will also be selected, we also need
- * to check that we are not trying to operate on them, since such an operation
- * would cause errors
- */
-
- /* align selected bones to the active one */
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
- {
- if (ELEM(ebone, actbone, actmirb) == 0) {
- if (ebone->flag & BONE_SELECTED)
- bone_align_to_bone(arm->edbo, ebone, actbone);
- else
- bone_align_to_bone(arm->edbo, ebone, actmirb);
- }
- }
- CTX_DATA_END;
-
- BKE_reportf(op->reports, RPT_INFO, "%d bones aligned to bone '%s'", num_selected_bones, actbone->name);
- }
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- return OPERATOR_FINISHED;
+ Object *ob = CTX_data_edit_object(C);
+ bArmature *arm = (bArmature *)ob->data;
+ EditBone *actbone = CTX_data_active_bone(C);
+ EditBone *actmirb = NULL;
+ int num_selected_bones;
+
+ /* there must be an active bone */
+ if (actbone == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
+ return OPERATOR_CANCELLED;
+ }
+ else if (arm->flag & ARM_MIRROR_EDIT) {
+ /* For X-Axis Mirror Editing option, we may need a mirror copy of actbone
+ * - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone
+ * (i.e. selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
+ * This is useful for arm-chains, for example parenting lower arm to upper arm
+ * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
+ * then just use actbone. Useful when doing upper arm to spine.
+ */
+ actmirb = ED_armature_ebone_get_mirrored(arm->edbo, actbone);
+ if (actmirb == NULL)
+ actmirb = actbone;
+ }
+
+ /* if there is only 1 selected bone, we assume that that is the active bone,
+ * since a user will need to have clicked on a bone (thus selecting it) to make it active
+ */
+ num_selected_bones = CTX_DATA_COUNT(C, selected_editable_bones);
+ if (num_selected_bones <= 1) {
+ /* When only the active bone is selected, and it has a parent,
+ * align it to the parent, as that is the only possible outcome.
+ */
+ if (actbone->parent) {
+ bone_align_to_bone(arm->edbo, actbone, actbone->parent);
+
+ if ((arm->flag & ARM_MIRROR_EDIT) && (actmirb->parent))
+ bone_align_to_bone(arm->edbo, actmirb, actmirb->parent);
+
+ BKE_reportf(op->reports, RPT_INFO, "Aligned bone '%s' to parent", actbone->name);
+ }
+ }
+ else {
+ /* Align 'selected' bones to the active one
+ * - the context iterator contains both selected bones and their mirrored copies,
+ * so we assume that unselected bones are mirrored copies of some selected bone
+ * - since the active one (and/or its mirror) will also be selected, we also need
+ * to check that we are not trying to operate on them, since such an operation
+ * would cause errors
+ */
+
+ /* align selected bones to the active one */
+ CTX_DATA_BEGIN (C, EditBone *, ebone, selected_editable_bones) {
+ if (ELEM(ebone, actbone, actmirb) == 0) {
+ if (ebone->flag & BONE_SELECTED)
+ bone_align_to_bone(arm->edbo, ebone, actbone);
+ else
+ bone_align_to_bone(arm->edbo, ebone, actmirb);
+ }
+ }
+ CTX_DATA_END;
+
+ BKE_reportf(
+ op->reports, RPT_INFO, "%d bones aligned to bone '%s'", num_selected_bones, actbone->name);
+ }
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_align(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Align Bones";
- ot->idname = "ARMATURE_OT_align";
- ot->description = "Align selected bones to the active bone (or to their parent)";
+ /* identifiers */
+ ot->name = "Align Bones";
+ ot->idname = "ARMATURE_OT_align";
+ ot->description = "Align selected bones to the active bone (or to their parent)";
- /* api callbacks */
- ot->exec = armature_align_bones_exec;
- ot->poll = ED_operator_editarmature;
+ /* api callbacks */
+ ot->exec = armature_align_bones_exec;
+ ot->poll = ED_operator_editarmature;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ********************************* Split ******************************* */
static int armature_split_exec(bContext *C, wmOperator *UNUSED(op))
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- bArmature *arm = ob->data;
-
- for (EditBone *bone = arm->edbo->first; bone; bone = bone->next) {
- if (bone->parent && (bone->flag & BONE_SELECTED) != (bone->parent->flag & BONE_SELECTED)) {
- bone->parent = NULL;
- bone->flag &= ~BONE_CONNECTED;
- }
- }
- for (EditBone *bone = arm->edbo->first; bone; bone = bone->next) {
- ED_armature_ebone_select_set(bone, (bone->flag & BONE_SELECTED) != 0);
- }
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
- }
-
- MEM_freeN(objects);
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+
+ for (EditBone *bone = arm->edbo->first; bone; bone = bone->next) {
+ if (bone->parent && (bone->flag & BONE_SELECTED) != (bone->parent->flag & BONE_SELECTED)) {
+ bone->parent = NULL;
+ bone->flag &= ~BONE_CONNECTED;
+ }
+ }
+ for (EditBone *bone = arm->edbo->first; bone; bone = bone->next) {
+ ED_armature_ebone_select_set(bone, (bone->flag & BONE_SELECTED) != 0);
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+
+ MEM_freeN(objects);
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_split(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Split";
- ot->idname = "ARMATURE_OT_split";
- ot->description = "Split off selected bones from connected unselected bones";
+ /* identifiers */
+ ot->name = "Split";
+ ot->idname = "ARMATURE_OT_split";
+ ot->description = "Split off selected bones from connected unselected bones";
- /* api callbacks */
- ot->exec = armature_split_exec;
- ot->poll = ED_operator_editarmature;
+ /* api callbacks */
+ ot->exec = armature_split_exec;
+ ot->poll = ED_operator_editarmature;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ********************************* Delete ******************************* */
static bool armature_delete_ebone_cb(const char *bone_name, void *arm_p)
{
- bArmature *arm = arm_p;
- EditBone *ebone;
+ bArmature *arm = arm_p;
+ EditBone *ebone;
- ebone = ED_armature_ebone_find_name(arm->edbo, bone_name);
- return (ebone && (ebone->flag & BONE_SELECTED) && (arm->layer & ebone->layer));
+ ebone = ED_armature_ebone_find_name(arm->edbo, bone_name);
+ return (ebone && (ebone->flag & BONE_SELECTED) && (arm->layer & ebone->layer));
}
/* previously delete_armature */
/* only editmode! */
static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
{
- EditBone *curBone, *ebone_next;
- bool changed_multi = false;
-
- /* cancel if nothing selected */
- if (CTX_DATA_COUNT(C, selected_bones) == 0)
- return OPERATOR_CANCELLED;
-
- ViewLayer *view_layer = CTX_data_view_layer(C);
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- bArmature *arm = obedit->data;
- bool changed = false;
-
- armature_select_mirrored(arm);
-
- BKE_pose_channels_remove(obedit, armature_delete_ebone_cb, arm);
-
- for (curBone = arm->edbo->first; curBone; curBone = ebone_next) {
- ebone_next = curBone->next;
- if (arm->layer & curBone->layer) {
- if (curBone->flag & BONE_SELECTED) {
- if (curBone == arm->act_edbone) arm->act_edbone = NULL;
- ED_armature_ebone_remove(arm, curBone);
- changed = true;
- }
- }
- }
-
- if (changed) {
- changed_multi = true;
-
- ED_armature_edit_sync_selection(arm->edbo);
- BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
- }
- }
- MEM_freeN(objects);
-
- if (!changed_multi) {
- return OPERATOR_CANCELLED;
- }
-
- return OPERATOR_FINISHED;
+ EditBone *curBone, *ebone_next;
+ bool changed_multi = false;
+
+ /* cancel if nothing selected */
+ if (CTX_DATA_COUNT(C, selected_bones) == 0)
+ return OPERATOR_CANCELLED;
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
+ bool changed = false;
+
+ armature_select_mirrored(arm);
+
+ BKE_pose_channels_remove(obedit, armature_delete_ebone_cb, arm);
+
+ for (curBone = arm->edbo->first; curBone; curBone = ebone_next) {
+ ebone_next = curBone->next;
+ if (arm->layer & curBone->layer) {
+ if (curBone->flag & BONE_SELECTED) {
+ if (curBone == arm->act_edbone)
+ arm->act_edbone = NULL;
+ ED_armature_ebone_remove(arm, curBone);
+ changed = true;
+ }
+ }
+ }
+
+ if (changed) {
+ changed_multi = true;
+
+ ED_armature_edit_sync_selection(arm->edbo);
+ BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ }
+ }
+ MEM_freeN(objects);
+
+ if (!changed_multi) {
+ return OPERATOR_CANCELLED;
+ }
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_delete(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Delete Selected Bone(s)";
- ot->idname = "ARMATURE_OT_delete";
- ot->description = "Remove selected bones from the armature";
-
- /* api callbacks */
- ot->invoke = WM_operator_confirm;
- ot->exec = armature_delete_selected_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* identifiers */
+ ot->name = "Delete Selected Bone(s)";
+ ot->idname = "ARMATURE_OT_delete";
+ ot->description = "Remove selected bones from the armature";
+
+ /* api callbacks */
+ ot->invoke = WM_operator_confirm;
+ ot->exec = armature_delete_selected_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static bool armature_dissolve_ebone_cb(const char *bone_name, void *arm_p)
{
- bArmature *arm = arm_p;
- EditBone *ebone;
+ bArmature *arm = arm_p;
+ EditBone *ebone;
- ebone = ED_armature_ebone_find_name(arm->edbo, bone_name);
- return (ebone && (ebone->flag & BONE_DONE));
+ ebone = ED_armature_ebone_find_name(arm->edbo, bone_name);
+ return (ebone && (ebone->flag & BONE_DONE));
}
static int armature_dissolve_selected_exec(bContext *C, wmOperator *UNUSED(op))
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- EditBone *ebone, *ebone_next;
- bool changed_multi = false;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- bArmature *arm = obedit->data;
- bool changed = false;
-
- /* store for mirror */
- GHash *ebone_flag_orig = NULL;
- int ebone_num = 0;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- ebone->temp.p = NULL;
- ebone->flag &= ~BONE_DONE;
- ebone_num++;
- }
-
- if (arm->flag & ARM_MIRROR_EDIT) {
- GHashIterator gh_iter;
-
- ebone_flag_orig = BLI_ghash_ptr_new_ex(__func__, ebone_num);
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- union { int flag; void *p; } val = {0};
- val.flag = ebone->flag;
- BLI_ghash_insert(ebone_flag_orig, ebone, val.p);
- }
-
- armature_select_mirrored_ex(arm, BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
-
- GHASH_ITER (gh_iter, ebone_flag_orig) {
- union { int flag; void *p; } *val_p = (void *)BLI_ghashIterator_getValue_p(&gh_iter);
- ebone = BLI_ghashIterator_getKey(&gh_iter);
- val_p->flag = ebone->flag & ~val_p->flag;
- }
- }
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (ebone->parent && ebone->flag & BONE_CONNECTED) {
- if (ebone->parent->temp.ebone == ebone->parent) {
- /* ignore */
- }
- else if (ebone->parent->temp.ebone) {
- /* set ignored */
- ebone->parent->temp.ebone = ebone->parent;
- }
- else {
- /* set child */
- ebone->parent->temp.ebone = ebone;
- }
- }
- }
-
- /* cleanup multiple used bones */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (ebone->temp.ebone == ebone) {
- ebone->temp.ebone = NULL;
- }
- }
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- /* break connections for unseen bones */
- if (((arm->layer & ebone->layer) &&
- ((ED_armature_ebone_selectflag_get(ebone) & (BONE_TIPSEL | BONE_SELECTED)))) == 0)
- {
- ebone->temp.ebone = NULL;
- }
-
- if (((arm->layer & ebone->layer) &&
- ((ED_armature_ebone_selectflag_get(ebone) & (BONE_ROOTSEL | BONE_SELECTED)))) == 0)
- {
- if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
- ebone->parent->temp.ebone = NULL;
- }
-
- }
- }
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
-
- if (ebone->parent &&
- (ebone->parent->temp.ebone == ebone))
- {
- ebone->flag |= BONE_DONE;
- }
- }
-
- BKE_pose_channels_remove(obedit, armature_dissolve_ebone_cb, arm);
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone_next) {
- ebone_next = ebone->next;
-
- if (ebone->flag & BONE_DONE) {
- copy_v3_v3(ebone->parent->tail, ebone->tail);
- ebone->parent->rad_tail = ebone->rad_tail;
- SET_FLAG_FROM_TEST(ebone->parent->flag, ebone->flag & BONE_TIPSEL, BONE_TIPSEL);
-
- ED_armature_ebone_remove_ex(arm, ebone, false);
- changed = true;
- }
- }
-
- if (changed) {
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (ebone->parent &&
- ebone->parent->temp.ebone &&
- (ebone->flag & BONE_CONNECTED))
- {
- ebone->rad_head = ebone->parent->rad_tail;
- }
- }
-
- if (arm->flag & ARM_MIRROR_EDIT) {
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- union { int flag; void *p; } *val_p = (void *)BLI_ghash_lookup_p(ebone_flag_orig, ebone);
- if (val_p && val_p->flag) {
- ebone->flag &= ~val_p->flag;
- }
- }
- }
- }
-
- if (arm->flag & ARM_MIRROR_EDIT) {
- BLI_ghash_free(ebone_flag_orig, NULL, NULL);
- }
-
- if (changed) {
- changed_multi = true;
- ED_armature_edit_sync_selection(arm->edbo);
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
- }
- }
- MEM_freeN(objects);
-
- if (!changed_multi) {
- return OPERATOR_CANCELLED;
- }
-
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ EditBone *ebone, *ebone_next;
+ bool changed_multi = false;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
+ bool changed = false;
+
+ /* store for mirror */
+ GHash *ebone_flag_orig = NULL;
+ int ebone_num = 0;
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ ebone->temp.p = NULL;
+ ebone->flag &= ~BONE_DONE;
+ ebone_num++;
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ GHashIterator gh_iter;
+
+ ebone_flag_orig = BLI_ghash_ptr_new_ex(__func__, ebone_num);
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ union {
+ int flag;
+ void *p;
+ } val = {0};
+ val.flag = ebone->flag;
+ BLI_ghash_insert(ebone_flag_orig, ebone, val.p);
+ }
+
+ armature_select_mirrored_ex(arm, BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+
+ GHASH_ITER (gh_iter, ebone_flag_orig) {
+ union {
+ int flag;
+ void *p;
+ } *val_p = (void *)BLI_ghashIterator_getValue_p(&gh_iter);
+ ebone = BLI_ghashIterator_getKey(&gh_iter);
+ val_p->flag = ebone->flag & ~val_p->flag;
+ }
+ }
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->parent && ebone->flag & BONE_CONNECTED) {
+ if (ebone->parent->temp.ebone == ebone->parent) {
+ /* ignore */
+ }
+ else if (ebone->parent->temp.ebone) {
+ /* set ignored */
+ ebone->parent->temp.ebone = ebone->parent;
+ }
+ else {
+ /* set child */
+ ebone->parent->temp.ebone = ebone;
+ }
+ }
+ }
+
+ /* cleanup multiple used bones */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->temp.ebone == ebone) {
+ ebone->temp.ebone = NULL;
+ }
+ }
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ /* break connections for unseen bones */
+ if (((arm->layer & ebone->layer) &&
+ ((ED_armature_ebone_selectflag_get(ebone) & (BONE_TIPSEL | BONE_SELECTED)))) == 0) {
+ ebone->temp.ebone = NULL;
+ }
+
+ if (((arm->layer & ebone->layer) &&
+ ((ED_armature_ebone_selectflag_get(ebone) & (BONE_ROOTSEL | BONE_SELECTED)))) == 0) {
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ ebone->parent->temp.ebone = NULL;
+ }
+ }
+ }
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+
+ if (ebone->parent && (ebone->parent->temp.ebone == ebone)) {
+ ebone->flag |= BONE_DONE;
+ }
+ }
+
+ BKE_pose_channels_remove(obedit, armature_dissolve_ebone_cb, arm);
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone_next) {
+ ebone_next = ebone->next;
+
+ if (ebone->flag & BONE_DONE) {
+ copy_v3_v3(ebone->parent->tail, ebone->tail);
+ ebone->parent->rad_tail = ebone->rad_tail;
+ SET_FLAG_FROM_TEST(ebone->parent->flag, ebone->flag & BONE_TIPSEL, BONE_TIPSEL);
+
+ ED_armature_ebone_remove_ex(arm, ebone, false);
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->parent && ebone->parent->temp.ebone && (ebone->flag & BONE_CONNECTED)) {
+ ebone->rad_head = ebone->parent->rad_tail;
+ }
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ union {
+ int flag;
+ void *p;
+ } *val_p = (void *)BLI_ghash_lookup_p(ebone_flag_orig, ebone);
+ if (val_p && val_p->flag) {
+ ebone->flag &= ~val_p->flag;
+ }
+ }
+ }
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ BLI_ghash_free(ebone_flag_orig, NULL, NULL);
+ }
+
+ if (changed) {
+ changed_multi = true;
+ ED_armature_edit_sync_selection(arm->edbo);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ }
+ }
+ MEM_freeN(objects);
+
+ if (!changed_multi) {
+ return OPERATOR_CANCELLED;
+ }
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_dissolve(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Dissolve Selected Bone(s)";
- ot->idname = "ARMATURE_OT_dissolve";
- ot->description = "Dissolve selected bones from the armature";
+ /* identifiers */
+ ot->name = "Dissolve Selected Bone(s)";
+ ot->idname = "ARMATURE_OT_dissolve";
+ ot->description = "Dissolve selected bones from the armature";
- /* api callbacks */
- ot->exec = armature_dissolve_selected_exec;
- ot->poll = ED_operator_editarmature;
+ /* api callbacks */
+ ot->exec = armature_dissolve_selected_exec;
+ ot->poll = ED_operator_editarmature;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-
-
/* ********************************* Show/Hide ******************************* */
static int armature_hide_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const int invert = RNA_boolean_get(op->ptr, "unselected") ? BONE_SELECTED : 0;
-
- /* cancel if nothing selected */
- if (CTX_DATA_COUNT(C, selected_bones) == 0)
- return OPERATOR_CANCELLED;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- bArmature *arm = obedit->data;
- bool changed = false;
-
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if ((ebone->flag & BONE_SELECTED) != invert) {
- ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
- ebone->flag |= BONE_HIDDEN_A;
- changed = true;
- }
- }
- }
-
- if (!changed) {
- continue;
- }
- ED_armature_edit_validate_active(arm);
- ED_armature_edit_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
- }
- MEM_freeN(objects);
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const int invert = RNA_boolean_get(op->ptr, "unselected") ? BONE_SELECTED : 0;
+
+ /* cancel if nothing selected */
+ if (CTX_DATA_COUNT(C, selected_bones) == 0)
+ return OPERATOR_CANCELLED;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
+ bool changed = false;
+
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ if ((ebone->flag & BONE_SELECTED) != invert) {
+ ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ ebone->flag |= BONE_HIDDEN_A;
+ changed = true;
+ }
+ }
+ }
+
+ if (!changed) {
+ continue;
+ }
+ ED_armature_edit_validate_active(arm);
+ ED_armature_edit_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ }
+ MEM_freeN(objects);
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_hide(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Hide Selected";
- ot->idname = "ARMATURE_OT_hide";
- ot->description = "Tag selected bones to not be visible in Edit Mode";
+ /* identifiers */
+ ot->name = "Hide Selected";
+ ot->idname = "ARMATURE_OT_hide";
+ ot->description = "Tag selected bones to not be visible in Edit Mode";
- /* api callbacks */
- ot->exec = armature_hide_exec;
- ot->poll = ED_operator_editarmature;
+ /* api callbacks */
+ ot->exec = armature_hide_exec;
+ ot->poll = ED_operator_editarmature;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* props */
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
+ /* props */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
}
static int armature_reveal_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const bool select = RNA_boolean_get(op->ptr, "select");
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- bArmature *arm = obedit->data;
- bool changed = false;
-
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (arm->layer & ebone->layer) {
- if (ebone->flag & BONE_HIDDEN_A) {
- if (!(ebone->flag & BONE_UNSELECTABLE)) {
- SET_FLAG_FROM_TEST(ebone->flag, select, (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL));
- }
- ebone->flag &= ~BONE_HIDDEN_A;
- changed = true;
- }
- }
- }
-
- if (changed) {
- ED_armature_edit_validate_active(arm);
- ED_armature_edit_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
- }
- }
- MEM_freeN(objects);
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const bool select = RNA_boolean_get(op->ptr, "select");
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
+ bool changed = false;
+
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (arm->layer & ebone->layer) {
+ if (ebone->flag & BONE_HIDDEN_A) {
+ if (!(ebone->flag & BONE_UNSELECTABLE)) {
+ SET_FLAG_FROM_TEST(ebone->flag, select, (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL));
+ }
+ ebone->flag &= ~BONE_HIDDEN_A;
+ changed = true;
+ }
+ }
+ }
+
+ if (changed) {
+ ED_armature_edit_validate_active(arm);
+ ED_armature_edit_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ }
+ }
+ MEM_freeN(objects);
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_reveal(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Reveal Hidden";
- ot->idname = "ARMATURE_OT_reveal";
- ot->description = "Reveal all bones hidden in Edit Mode";
+ /* identifiers */
+ ot->name = "Reveal Hidden";
+ ot->idname = "ARMATURE_OT_reveal";
+ ot->description = "Reveal all bones hidden in Edit Mode";
- /* api callbacks */
- ot->exec = armature_reveal_exec;
- ot->poll = ED_operator_editarmature;
+ /* api callbacks */
+ ot->exec = armature_reveal_exec;
+ ot->poll = ED_operator_editarmature;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "select", true, "Select", "");
+ RNA_def_boolean(ot->srna, "select", true, "Select", "");
}
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index 7fe4810762e..09e4c1acae7 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -138,37 +138,37 @@ void POSE_OT_bone_layers(struct wmOperatorType *ot);
/* Temporary data linking PoseChannels with the F-Curves they affect */
typedef struct tPChanFCurveLink {
- struct tPChanFCurveLink *next, *prev;
-
- /** Object this Pose Channel belongs to. */
- struct Object *ob;
-
- /** F-Curves for this PoseChannel (wrapped with LinkData) */
- ListBase fcurves;
- /** Pose Channel which data is attached to */
- struct bPoseChannel *pchan;
-
- /** RNA Path to this Pose Channel (needs to be freed when we're done) */
- char *pchan_path;
-
- /** transform values at start of operator (to be restored before each modal step) */
- float oldloc[3];
- float oldrot[3];
- float oldscale[3];
- float oldquat[4];
- float oldangle;
- float oldaxis[3];
-
- /** old bbone values (to be restored along with the transform properties) */
- float roll1, roll2;
- /** (NOTE: we haven't renamed these this time, as their names are already long enough) */
- float curveInX, curveInY;
- float curveOutX, curveOutY;
- float ease1, ease2;
- float scaleIn, scaleOut;
-
- /** copy of custom properties at start of operator (to be restored before each modal step) */
- struct IDProperty *oldprops;
+ struct tPChanFCurveLink *next, *prev;
+
+ /** Object this Pose Channel belongs to. */
+ struct Object *ob;
+
+ /** F-Curves for this PoseChannel (wrapped with LinkData) */
+ ListBase fcurves;
+ /** Pose Channel which data is attached to */
+ struct bPoseChannel *pchan;
+
+ /** RNA Path to this Pose Channel (needs to be freed when we're done) */
+ char *pchan_path;
+
+ /** transform values at start of operator (to be restored before each modal step) */
+ float oldloc[3];
+ float oldrot[3];
+ float oldscale[3];
+ float oldquat[4];
+ float oldangle;
+ float oldaxis[3];
+
+ /** old bbone values (to be restored along with the transform properties) */
+ float roll1, roll2;
+ /** (NOTE: we haven't renamed these this time, as their names are already long enough) */
+ float curveInX, curveInY;
+ float curveOutX, curveOutY;
+ float ease1, ease2;
+ float scaleIn, scaleOut;
+
+ /** copy of custom properties at start of operator (to be restored before each modal step) */
+ struct IDProperty *oldprops;
} tPChanFCurveLink;
/* ----------- */
@@ -179,7 +179,10 @@ void poseAnim_mapping_free(ListBase *pfLinks);
void poseAnim_mapping_refresh(struct bContext *C, struct Scene *scene, struct Object *ob);
void poseAnim_mapping_reset(ListBase *pfLinks);
-void poseAnim_mapping_autoKeyframe(struct bContext *C, struct Scene *scene, ListBase *pfLinks, float cframe);
+void poseAnim_mapping_autoKeyframe(struct bContext *C,
+ struct Scene *scene,
+ ListBase *pfLinks,
+ float cframe);
LinkData *poseAnim_mapping_getNextFCurve(ListBase *fcuLinks, LinkData *prev, const char *path);
@@ -222,15 +225,27 @@ EditBone *make_boneList(struct ListBase *edbo, struct ListBase *bones, struct Bo
/* duplicate method */
void preEditBoneDuplicate(struct ListBase *editbones);
void postEditBoneDuplicate(struct ListBase *editbones, struct Object *ob);
-struct EditBone *duplicateEditBone(struct EditBone *curBone, const char *name, struct ListBase *editbones, struct Object *ob);
-void updateDuplicateSubtarget(struct EditBone *dupBone, struct ListBase *editbones, struct Object *ob);
+struct EditBone *duplicateEditBone(struct EditBone *curBone,
+ const char *name,
+ struct ListBase *editbones,
+ struct Object *ob);
+void updateDuplicateSubtarget(struct EditBone *dupBone,
+ struct ListBase *editbones,
+ struct Object *ob);
/* duplicate method (cross objects) */
/* editbones is the target list */
-struct EditBone *duplicateEditBoneObjects(struct EditBone *curBone, const char *name, struct ListBase *editbones, struct Object *src_ob, struct Object *dst_ob);
+struct EditBone *duplicateEditBoneObjects(struct EditBone *curBone,
+ const char *name,
+ struct ListBase *editbones,
+ struct Object *src_ob,
+ struct Object *dst_ob);
/* editbones is the source list */
-void updateDuplicateSubtargetObjects(struct EditBone *dupBone, struct ListBase *editbones, struct Object *src_ob, struct Object *dst_ob);
+void updateDuplicateSubtargetObjects(struct EditBone *dupBone,
+ struct ListBase *editbones,
+ struct Object *src_ob,
+ struct Object *dst_ob);
EditBone *add_points_bone(struct Object *obedit, float head[3], float tail[3]);
void bone_free(struct bArmature *arm, struct EditBone *bone);
@@ -240,18 +255,20 @@ void armature_select_mirrored_ex(struct bArmature *arm, const int flag);
void armature_select_mirrored(struct bArmature *arm);
void armature_tag_unselect(struct bArmature *arm);
-void *get_nearest_bone(
- struct bContext *C, const int xy[2], bool findunsel,
- struct Base **r_base);
+void *get_nearest_bone(struct bContext *C, const int xy[2], bool findunsel, struct Base **r_base);
-void *get_bone_from_selectbuffer(
- struct Base **bases, uint bases_len,
- bool is_editmode, const unsigned int *buffer, short hits,
- bool findunsel, bool do_nearest,
- struct Base **r_base);
+void *get_bone_from_selectbuffer(struct Base **bases,
+ uint bases_len,
+ bool is_editmode,
+ const unsigned int *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ struct Base **r_base);
-int bone_looper(struct Object *ob, struct Bone *bone, void *data,
+int bone_looper(struct Object *ob,
+ struct Bone *bone,
+ void *data,
int (*bone_func)(struct Object *, struct Bone *, void *));
-
#endif /* __ARMATURE_INTERN_H__ */
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index 6d4babe9674..b1f0297bb29 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -71,18 +71,24 @@
/* note: there's a unique_bone_name() too! */
static bool editbone_unique_check(void *arg, const char *name)
{
- struct {ListBase *lb; void *bone; } *data = arg;
- EditBone *dupli = ED_armature_ebone_find_name(data->lb, name);
- return dupli && dupli != data->bone;
+ struct {
+ ListBase *lb;
+ void *bone;
+ } *data = arg;
+ EditBone *dupli = ED_armature_ebone_find_name(data->lb, name);
+ return dupli && dupli != data->bone;
}
void ED_armature_ebone_unique_name(ListBase *edbo, char *name, EditBone *bone)
{
- struct {ListBase *lb; void *bone; } data;
- data.lb = edbo;
- data.bone = bone;
-
- BLI_uniquename_cb(editbone_unique_check, &data, DATA_("Bone"), '.', name, sizeof(bone->name));
+ struct {
+ ListBase *lb;
+ void *bone;
+ } data;
+ data.lb = edbo;
+ data.bone = bone;
+
+ BLI_uniquename_cb(editbone_unique_check, &data, DATA_("Bone"), '.', name, sizeof(bone->name));
}
/* ************************************************** */
@@ -90,261 +96,265 @@ void ED_armature_ebone_unique_name(ListBase *edbo, char *name, EditBone *bone)
static bool bone_unique_check(void *arg, const char *name)
{
- return BKE_armature_find_bone_name((bArmature *)arg, name) != NULL;
+ return BKE_armature_find_bone_name((bArmature *)arg, name) != NULL;
}
static void unique_bone_name(bArmature *arm, char *name)
{
- BLI_uniquename_cb(bone_unique_check, (void *)arm, DATA_("Bone"), '.', name, sizeof(((Bone *)NULL)->name));
+ BLI_uniquename_cb(
+ bone_unique_check, (void *)arm, DATA_("Bone"), '.', name, sizeof(((Bone *)NULL)->name));
}
/* helper call for armature_bone_rename */
-static void constraint_bone_name_fix(Object *ob, ListBase *conlist, const char *oldname, const char *newname)
+static void constraint_bone_name_fix(Object *ob,
+ ListBase *conlist,
+ const char *oldname,
+ const char *newname)
{
- bConstraint *curcon;
- bConstraintTarget *ct;
-
- for (curcon = conlist->first; curcon; curcon = curcon->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
- ListBase targets = {NULL, NULL};
-
- /* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(curcon, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar == ob) {
- if (STREQ(ct->subtarget, oldname)) {
- BLI_strncpy(ct->subtarget, newname, MAXBONENAME);
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(curcon, &targets, 0);
- }
-
- /* action constraints */
- if (curcon->type == CONSTRAINT_TYPE_ACTION) {
- bActionConstraint *actcon = (bActionConstraint *)curcon->data;
- BKE_action_fix_paths_rename(&ob->id, actcon->act, "pose.bones", oldname, newname, 0, 0, 1);
- }
- }
+ bConstraint *curcon;
+ bConstraintTarget *ct;
+
+ for (curcon = conlist->first; curcon; curcon = curcon->next) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
+ ListBase targets = {NULL, NULL};
+
+ /* constraint targets */
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(curcon, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ if (ct->tar == ob) {
+ if (STREQ(ct->subtarget, oldname)) {
+ BLI_strncpy(ct->subtarget, newname, MAXBONENAME);
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(curcon, &targets, 0);
+ }
+
+ /* action constraints */
+ if (curcon->type == CONSTRAINT_TYPE_ACTION) {
+ bActionConstraint *actcon = (bActionConstraint *)curcon->data;
+ BKE_action_fix_paths_rename(&ob->id, actcon->act, "pose.bones", oldname, newname, 0, 0, 1);
+ }
+ }
}
/* called by UI for renaming a bone */
/* warning: make sure the original bone was not renamed yet! */
/* seems messy, but that's what you get with not using pointers but channel names :) */
-void ED_armature_bone_rename(Main *bmain, bArmature *arm, const char *oldnamep, const char *newnamep)
+void ED_armature_bone_rename(Main *bmain,
+ bArmature *arm,
+ const char *oldnamep,
+ const char *newnamep)
{
- Object *ob;
- char newname[MAXBONENAME];
- char oldname[MAXBONENAME];
-
- /* names better differ! */
- if (!STREQLEN(oldnamep, newnamep, MAXBONENAME)) {
-
- /* we alter newname string... so make copy */
- BLI_strncpy(newname, newnamep, MAXBONENAME);
- /* we use oldname for search... so make copy */
- BLI_strncpy(oldname, oldnamep, MAXBONENAME);
-
- /* now check if we're in editmode, we need to find the unique name */
- if (arm->edbo) {
- EditBone *eBone = ED_armature_ebone_find_name(arm->edbo, oldname);
-
- if (eBone) {
- ED_armature_ebone_unique_name(arm->edbo, newname, NULL);
- BLI_strncpy(eBone->name, newname, MAXBONENAME);
- }
- else {
- return;
- }
- }
- else {
- Bone *bone = BKE_armature_find_bone_name(arm, oldname);
-
- if (bone) {
- unique_bone_name(arm, newname);
- BLI_strncpy(bone->name, newname, MAXBONENAME);
- }
- else {
- return;
- }
- }
-
- /* force copy on write to update database */
- DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
-
- /* do entire dbase - objects */
- for (ob = bmain->objects.first; ob; ob = ob->id.next) {
- ModifierData *md;
-
- /* we have the object using the armature */
- if (arm == ob->data) {
- Object *cob;
-
- /* Rename the pose channel, if it exists */
- if (ob->pose) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, oldname);
- if (pchan) {
- GHash *gh = ob->pose->chanhash;
-
- /* remove the old hash entry, and replace with the new name */
- if (gh) {
- BLI_assert(BLI_ghash_haskey(gh, pchan->name));
- BLI_ghash_remove(gh, pchan->name, NULL, NULL);
- }
-
- BLI_strncpy(pchan->name, newname, MAXBONENAME);
-
- if (gh) {
- BLI_ghash_insert(gh, pchan->name, pchan);
- }
- }
-
- BLI_assert(BKE_pose_channels_is_valid(ob->pose) == true);
- }
-
- /* Update any object constraints to use the new bone name */
- for (cob = bmain->objects.first; cob; cob = cob->id.next) {
- if (cob->constraints.first)
- constraint_bone_name_fix(ob, &cob->constraints, oldname, newname);
- if (cob->pose) {
- bPoseChannel *pchan;
- for (pchan = cob->pose->chanbase.first; pchan; pchan = pchan->next) {
- constraint_bone_name_fix(ob, &pchan->constraints, oldname, newname);
- }
- }
- }
- }
-
- /* See if an object is parented to this armature */
- if (ob->parent && (ob->parent->data == arm)) {
- if (ob->partype == PARBONE) {
- /* bone name in object */
- if (STREQ(ob->parsubstr, oldname))
- BLI_strncpy(ob->parsubstr, newname, MAXBONENAME);
- }
- }
-
- if (modifiers_usesArmature(ob, arm)) {
- bDeformGroup *dg = defgroup_find_name(ob, oldname);
- if (dg) {
- BLI_strncpy(dg->name, newname, MAXBONENAME);
- }
- }
-
- /* fix modifiers that might be using this name */
- for (md = ob->modifiers.first; md; md = md->next) {
- switch (md->type) {
- case eModifierType_Hook:
- {
- HookModifierData *hmd = (HookModifierData *)md;
-
- if (hmd->object && (hmd->object->data == arm)) {
- if (STREQ(hmd->subtarget, oldname))
- BLI_strncpy(hmd->subtarget, newname, MAXBONENAME);
- }
- break;
- }
- case eModifierType_UVWarp:
- {
- UVWarpModifierData *umd = (UVWarpModifierData *)md;
-
- if (umd->object_src && (umd->object_src->data == arm)) {
- if (STREQ(umd->bone_src, oldname))
- BLI_strncpy(umd->bone_src, newname, MAXBONENAME);
- }
- if (umd->object_dst && (umd->object_dst->data == arm)) {
- if (STREQ(umd->bone_dst, oldname))
- BLI_strncpy(umd->bone_dst, newname, MAXBONENAME);
- }
- break;
- }
- default:
- break;
- }
- }
-
- /* fix grease pencil modifiers and vertex groups */
- if (ob->type == OB_GPENCIL) {
-
- bGPdata *gpd = (bGPdata *)ob->data;
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if ((gpl->parent != NULL) && (gpl->parent->data == arm)) {
- if (STREQ(gpl->parsubstr, oldname))
- BLI_strncpy(gpl->parsubstr, newname, MAXBONENAME);
- }
- }
-
- for (GpencilModifierData *gp_md = ob->greasepencil_modifiers.first; gp_md; gp_md = gp_md->next) {
- switch (gp_md->type) {
- case eGpencilModifierType_Armature:
- {
- ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)gp_md;
- if (mmd->object && mmd->object->data == arm) {
- bDeformGroup *dg = defgroup_find_name(ob, oldname);
- if (dg) {
- BLI_strncpy(dg->name, newname, MAXBONENAME);
- }
- }
- break;
- }
- case eGpencilModifierType_Hook:
- {
- HookGpencilModifierData *hgp_md = (HookGpencilModifierData *)gp_md;
- if (hgp_md->object && (hgp_md->object->data == arm)) {
- if (STREQ(hgp_md->subtarget, oldname))
- BLI_strncpy(hgp_md->subtarget, newname, MAXBONENAME);
- }
- break;
- }
- default:
- break;
- }
- }
- }
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
- }
-
- /* Fix all animdata that may refer to this bone - we can't just do the ones attached to objects, since
- * other ID-blocks may have drivers referring to this bone [#29822]
- */
- // XXX: the ID here is for armatures, but most bone drivers are actually on the object instead...
- {
-
- BKE_animdata_fix_paths_rename_all(&arm->id, "pose.bones", oldname, newname);
- }
-
- /* correct view locking */
- {
- bScreen *screen;
- for (screen = bmain->screens.first; screen; screen = screen->id.next) {
- ScrArea *sa;
- /* add regions */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *)sl;
- if (v3d->ob_centre && v3d->ob_centre->data == arm) {
- if (STREQ(v3d->ob_centre_bone, oldname)) {
- BLI_strncpy(v3d->ob_centre_bone, newname, MAXBONENAME);
- }
- }
- }
- }
- }
- }
- }
- }
+ Object *ob;
+ char newname[MAXBONENAME];
+ char oldname[MAXBONENAME];
+
+ /* names better differ! */
+ if (!STREQLEN(oldnamep, newnamep, MAXBONENAME)) {
+
+ /* we alter newname string... so make copy */
+ BLI_strncpy(newname, newnamep, MAXBONENAME);
+ /* we use oldname for search... so make copy */
+ BLI_strncpy(oldname, oldnamep, MAXBONENAME);
+
+ /* now check if we're in editmode, we need to find the unique name */
+ if (arm->edbo) {
+ EditBone *eBone = ED_armature_ebone_find_name(arm->edbo, oldname);
+
+ if (eBone) {
+ ED_armature_ebone_unique_name(arm->edbo, newname, NULL);
+ BLI_strncpy(eBone->name, newname, MAXBONENAME);
+ }
+ else {
+ return;
+ }
+ }
+ else {
+ Bone *bone = BKE_armature_find_bone_name(arm, oldname);
+
+ if (bone) {
+ unique_bone_name(arm, newname);
+ BLI_strncpy(bone->name, newname, MAXBONENAME);
+ }
+ else {
+ return;
+ }
+ }
+
+ /* force copy on write to update database */
+ DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
+
+ /* do entire dbase - objects */
+ for (ob = bmain->objects.first; ob; ob = ob->id.next) {
+ ModifierData *md;
+
+ /* we have the object using the armature */
+ if (arm == ob->data) {
+ Object *cob;
+
+ /* Rename the pose channel, if it exists */
+ if (ob->pose) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, oldname);
+ if (pchan) {
+ GHash *gh = ob->pose->chanhash;
+
+ /* remove the old hash entry, and replace with the new name */
+ if (gh) {
+ BLI_assert(BLI_ghash_haskey(gh, pchan->name));
+ BLI_ghash_remove(gh, pchan->name, NULL, NULL);
+ }
+
+ BLI_strncpy(pchan->name, newname, MAXBONENAME);
+
+ if (gh) {
+ BLI_ghash_insert(gh, pchan->name, pchan);
+ }
+ }
+
+ BLI_assert(BKE_pose_channels_is_valid(ob->pose) == true);
+ }
+
+ /* Update any object constraints to use the new bone name */
+ for (cob = bmain->objects.first; cob; cob = cob->id.next) {
+ if (cob->constraints.first)
+ constraint_bone_name_fix(ob, &cob->constraints, oldname, newname);
+ if (cob->pose) {
+ bPoseChannel *pchan;
+ for (pchan = cob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ constraint_bone_name_fix(ob, &pchan->constraints, oldname, newname);
+ }
+ }
+ }
+ }
+
+ /* See if an object is parented to this armature */
+ if (ob->parent && (ob->parent->data == arm)) {
+ if (ob->partype == PARBONE) {
+ /* bone name in object */
+ if (STREQ(ob->parsubstr, oldname))
+ BLI_strncpy(ob->parsubstr, newname, MAXBONENAME);
+ }
+ }
+
+ if (modifiers_usesArmature(ob, arm)) {
+ bDeformGroup *dg = defgroup_find_name(ob, oldname);
+ if (dg) {
+ BLI_strncpy(dg->name, newname, MAXBONENAME);
+ }
+ }
+
+ /* fix modifiers that might be using this name */
+ for (md = ob->modifiers.first; md; md = md->next) {
+ switch (md->type) {
+ case eModifierType_Hook: {
+ HookModifierData *hmd = (HookModifierData *)md;
+
+ if (hmd->object && (hmd->object->data == arm)) {
+ if (STREQ(hmd->subtarget, oldname))
+ BLI_strncpy(hmd->subtarget, newname, MAXBONENAME);
+ }
+ break;
+ }
+ case eModifierType_UVWarp: {
+ UVWarpModifierData *umd = (UVWarpModifierData *)md;
+
+ if (umd->object_src && (umd->object_src->data == arm)) {
+ if (STREQ(umd->bone_src, oldname))
+ BLI_strncpy(umd->bone_src, newname, MAXBONENAME);
+ }
+ if (umd->object_dst && (umd->object_dst->data == arm)) {
+ if (STREQ(umd->bone_dst, oldname))
+ BLI_strncpy(umd->bone_dst, newname, MAXBONENAME);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ /* fix grease pencil modifiers and vertex groups */
+ if (ob->type == OB_GPENCIL) {
+
+ bGPdata *gpd = (bGPdata *)ob->data;
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if ((gpl->parent != NULL) && (gpl->parent->data == arm)) {
+ if (STREQ(gpl->parsubstr, oldname))
+ BLI_strncpy(gpl->parsubstr, newname, MAXBONENAME);
+ }
+ }
+
+ for (GpencilModifierData *gp_md = ob->greasepencil_modifiers.first; gp_md;
+ gp_md = gp_md->next) {
+ switch (gp_md->type) {
+ case eGpencilModifierType_Armature: {
+ ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)gp_md;
+ if (mmd->object && mmd->object->data == arm) {
+ bDeformGroup *dg = defgroup_find_name(ob, oldname);
+ if (dg) {
+ BLI_strncpy(dg->name, newname, MAXBONENAME);
+ }
+ }
+ break;
+ }
+ case eGpencilModifierType_Hook: {
+ HookGpencilModifierData *hgp_md = (HookGpencilModifierData *)gp_md;
+ if (hgp_md->object && (hgp_md->object->data == arm)) {
+ if (STREQ(hgp_md->subtarget, oldname))
+ BLI_strncpy(hgp_md->subtarget, newname, MAXBONENAME);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+ }
+
+ /* Fix all animdata that may refer to this bone - we can't just do the ones attached to objects, since
+ * other ID-blocks may have drivers referring to this bone [#29822]
+ */
+ // XXX: the ID here is for armatures, but most bone drivers are actually on the object instead...
+ {
+
+ BKE_animdata_fix_paths_rename_all(&arm->id, "pose.bones", oldname, newname);
+ }
+
+ /* correct view locking */
+ {
+ bScreen *screen;
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *sa;
+ /* add regions */
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ SpaceLink *sl;
+ for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ if (v3d->ob_centre && v3d->ob_centre->data == arm) {
+ if (STREQ(v3d->ob_centre_bone, oldname)) {
+ BLI_strncpy(v3d->ob_centre_bone, newname, MAXBONENAME);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
typedef struct BoneFlipNameData {
- struct BoneFlipNameData *next, *prev;
- char *name;
- char name_flip[MAXBONENAME];
+ struct BoneFlipNameData *next, *prev;
+ char *name;
+ char name_flip[MAXBONENAME];
} BoneFlipNameData;
/**
@@ -357,38 +367,41 @@ typedef struct BoneFlipNameData {
* \param bones_names: List of BoneConflict elems.
* \param do_strip_numbers: if set, try to get rid of dot-numbers at end of bone names.
*/
-void ED_armature_bones_flip_names(Main *bmain, bArmature *arm, ListBase *bones_names, const bool do_strip_numbers)
+void ED_armature_bones_flip_names(Main *bmain,
+ bArmature *arm,
+ ListBase *bones_names,
+ const bool do_strip_numbers)
{
- ListBase bones_names_conflicts = {NULL};
- BoneFlipNameData *bfn;
-
- /* First pass: generate flip names, and blindly rename.
- * If rename did not yield expected result, store both bone's name and expected flipped one into temp list
- * for second pass. */
- for (LinkData *link = bones_names->first; link; link = link->next) {
- char name_flip[MAXBONENAME];
- char *name = link->data;
-
- /* WARNING: if do_strip_numbers is set, expect completely mismatched names in cases like
- * Bone.R, Bone.R.001, Bone.R.002, etc. */
- BLI_string_flip_side_name(name_flip, name, do_strip_numbers, sizeof(name_flip));
-
- ED_armature_bone_rename(bmain, arm, name, name_flip);
-
- if (!STREQ(name, name_flip)) {
- bfn = alloca(sizeof(BoneFlipNameData));
- bfn->name = name;
- BLI_strncpy(bfn->name_flip, name_flip, sizeof(bfn->name_flip));
- BLI_addtail(&bones_names_conflicts, bfn);
- }
- }
-
- /* Second pass to handle the bones that have naming conflicts with other bones.
- * Note that if the other bone was not selected, its name was not flipped, so conflict remains and that second
- * rename simply generates a new numbered alternative name. */
- for (bfn = bones_names_conflicts.first; bfn; bfn = bfn->next) {
- ED_armature_bone_rename(bmain, arm, bfn->name, bfn->name_flip);
- }
+ ListBase bones_names_conflicts = {NULL};
+ BoneFlipNameData *bfn;
+
+ /* First pass: generate flip names, and blindly rename.
+ * If rename did not yield expected result, store both bone's name and expected flipped one into temp list
+ * for second pass. */
+ for (LinkData *link = bones_names->first; link; link = link->next) {
+ char name_flip[MAXBONENAME];
+ char *name = link->data;
+
+ /* WARNING: if do_strip_numbers is set, expect completely mismatched names in cases like
+ * Bone.R, Bone.R.001, Bone.R.002, etc. */
+ BLI_string_flip_side_name(name_flip, name, do_strip_numbers, sizeof(name_flip));
+
+ ED_armature_bone_rename(bmain, arm, name, name_flip);
+
+ if (!STREQ(name, name_flip)) {
+ bfn = alloca(sizeof(BoneFlipNameData));
+ bfn->name = name;
+ BLI_strncpy(bfn->name_flip, name_flip, sizeof(bfn->name_flip));
+ BLI_addtail(&bones_names_conflicts, bfn);
+ }
+ }
+
+ /* Second pass to handle the bones that have naming conflicts with other bones.
+ * Note that if the other bone was not selected, its name was not flipped, so conflict remains and that second
+ * rename simply generates a new numbered alternative name. */
+ for (bfn = bones_names_conflicts.first; bfn; bfn = bfn->next) {
+ ED_armature_bone_rename(bmain, arm, bfn->name, bfn->name_flip);
+ }
}
/* ************************************************** */
@@ -396,165 +409,171 @@ void ED_armature_bones_flip_names(Main *bmain, bArmature *arm, ListBase *bones_n
static int armature_flip_names_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob_active = CTX_data_edit_object(C);
-
- const bool do_strip_numbers = RNA_boolean_get(op->ptr, "do_strip_numbers");
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- bArmature *arm = ob->data;
-
- /* Paranoia check. */
- if (ob_active->pose == NULL) {
- continue;
- }
-
- ListBase bones_names = {NULL};
-
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if (ebone->flag & BONE_SELECTED) {
- BLI_addtail(&bones_names, BLI_genericNodeN(ebone->name));
-
- if (arm->flag & ARM_MIRROR_EDIT) {
- EditBone *flipbone = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
- if ((flipbone) && !(flipbone->flag & BONE_SELECTED)) {
- BLI_addtail(&bones_names, BLI_genericNodeN(flipbone->name));
- }
- }
- }
- }
- }
-
- if (BLI_listbase_is_empty(&bones_names)) {
- continue;
- }
-
- ED_armature_bones_flip_names(bmain, arm, &bones_names, do_strip_numbers);
-
- BLI_freelistN(&bones_names);
-
- /* since we renamed stuff... */
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
-
- /* copied from #rna_Bone_update_renamed */
- /* redraw view */
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
-
- /* update animation channels */
- WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, ob->data);
-
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
+ Main *bmain = CTX_data_main(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob_active = CTX_data_edit_object(C);
+
+ const bool do_strip_numbers = RNA_boolean_get(op->ptr, "do_strip_numbers");
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+
+ /* Paranoia check. */
+ if (ob_active->pose == NULL) {
+ continue;
+ }
+
+ ListBase bones_names = {NULL};
+
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ if (ebone->flag & BONE_SELECTED) {
+ BLI_addtail(&bones_names, BLI_genericNodeN(ebone->name));
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ EditBone *flipbone = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
+ if ((flipbone) && !(flipbone->flag & BONE_SELECTED)) {
+ BLI_addtail(&bones_names, BLI_genericNodeN(flipbone->name));
+ }
+ }
+ }
+ }
+ }
+
+ if (BLI_listbase_is_empty(&bones_names)) {
+ continue;
+ }
+
+ ED_armature_bones_flip_names(bmain, arm, &bones_names, do_strip_numbers);
+
+ BLI_freelistN(&bones_names);
+
+ /* since we renamed stuff... */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+
+ /* copied from #rna_Bone_update_renamed */
+ /* redraw view */
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+
+ /* update animation channels */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, ob->data);
+ }
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_flip_names(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Flip Names";
- ot->idname = "ARMATURE_OT_flip_names";
- ot->description = "Flips (and corrects) the axis suffixes of the names of selected bones";
-
- /* api callbacks */
- ot->exec = armature_flip_names_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_boolean(ot->srna, "do_strip_numbers", false, "Strip Numbers",
- "Try to remove right-most dot-number from flipped names "
- "(WARNING: may result in incoherent naming in some cases)");
+ /* identifiers */
+ ot->name = "Flip Names";
+ ot->idname = "ARMATURE_OT_flip_names";
+ ot->description = "Flips (and corrects) the axis suffixes of the names of selected bones";
+
+ /* api callbacks */
+ ot->exec = armature_flip_names_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna,
+ "do_strip_numbers",
+ false,
+ "Strip Numbers",
+ "Try to remove right-most dot-number from flipped names "
+ "(WARNING: may result in incoherent naming in some cases)");
}
static int armature_autoside_names_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Main *bmain = CTX_data_main(C);
- char newname[MAXBONENAME];
- const short axis = RNA_enum_get(op->ptr, "type");
- bool changed_multi = false;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- bArmature *arm = ob->data;
- bool changed = false;
-
- /* Paranoia checks. */
- if (ELEM(NULL, ob, ob->pose)) {
- continue;
- }
-
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_EDITABLE(ebone)) {
-
- /* We first need to do the flipped bone, then the original one.
- * Otherwise we can't find the flipped one because of the bone name change. */
- if (arm->flag & ARM_MIRROR_EDIT) {
- EditBone *flipbone = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
- if ((flipbone) && !(flipbone->flag & BONE_SELECTED)) {
- BLI_strncpy(newname, flipbone->name, sizeof(newname));
- if (bone_autoside_name(newname, 1, axis, flipbone->head[axis], flipbone->tail[axis])) {
- ED_armature_bone_rename(bmain, arm, flipbone->name, newname);
- changed = true;
- }
- }
- }
-
- BLI_strncpy(newname, ebone->name, sizeof(newname));
- if (bone_autoside_name(newname, 1, axis, ebone->head[axis], ebone->tail[axis])) {
- ED_armature_bone_rename(bmain, arm, ebone->name, newname);
- changed = true;
- }
- }
- }
-
- if (!changed) {
- continue;
- }
-
- changed_multi = true;
-
- /* Since we renamed stuff... */
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
-
- /* Note, notifier might evolve. */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
- }
- MEM_freeN(objects);
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Main *bmain = CTX_data_main(C);
+ char newname[MAXBONENAME];
+ const short axis = RNA_enum_get(op->ptr, "type");
+ bool changed_multi = false;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bool changed = false;
+
+ /* Paranoia checks. */
+ if (ELEM(NULL, ob, ob->pose)) {
+ continue;
+ }
+
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_EDITABLE(ebone)) {
+
+ /* We first need to do the flipped bone, then the original one.
+ * Otherwise we can't find the flipped one because of the bone name change. */
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ EditBone *flipbone = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
+ if ((flipbone) && !(flipbone->flag & BONE_SELECTED)) {
+ BLI_strncpy(newname, flipbone->name, sizeof(newname));
+ if (bone_autoside_name(newname, 1, axis, flipbone->head[axis], flipbone->tail[axis])) {
+ ED_armature_bone_rename(bmain, arm, flipbone->name, newname);
+ changed = true;
+ }
+ }
+ }
+
+ BLI_strncpy(newname, ebone->name, sizeof(newname));
+ if (bone_autoside_name(newname, 1, axis, ebone->head[axis], ebone->tail[axis])) {
+ ED_armature_bone_rename(bmain, arm, ebone->name, newname);
+ changed = true;
+ }
+ }
+ }
+
+ if (!changed) {
+ continue;
+ }
+
+ changed_multi = true;
+
+ /* Since we renamed stuff... */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+
+ /* Note, notifier might evolve. */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ }
+ MEM_freeN(objects);
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void ARMATURE_OT_autoside_names(wmOperatorType *ot)
{
- static const EnumPropertyItem axis_items[] = {
- {0, "XAXIS", 0, "X-Axis", "Left/Right"},
- {1, "YAXIS", 0, "Y-Axis", "Front/Back"},
- {2, "ZAXIS", 0, "Z-Axis", "Top/Bottom"},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "AutoName by Axis";
- ot->idname = "ARMATURE_OT_autoside_names";
- ot->description = "Automatically renames the selected bones according to which side of the target axis they fall on";
-
- /* api callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = armature_autoside_names_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* settings */
- ot->prop = RNA_def_enum(ot->srna, "type", axis_items, 0, "Axis", "Axis tag names with");
+ static const EnumPropertyItem axis_items[] = {
+ {0, "XAXIS", 0, "X-Axis", "Left/Right"},
+ {1, "YAXIS", 0, "Y-Axis", "Front/Back"},
+ {2, "ZAXIS", 0, "Z-Axis", "Top/Bottom"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "AutoName by Axis";
+ ot->idname = "ARMATURE_OT_autoside_names";
+ ot->description =
+ "Automatically renames the selected bones according to which side of the target axis they "
+ "fall on";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = armature_autoside_names_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* settings */
+ ot->prop = RNA_def_enum(ot->srna, "type", axis_items, 0, "Axis", "Axis tag names with");
}
diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c
index 36ca3dd486d..c820077fbf9 100644
--- a/source/blender/editors/armature/armature_ops.c
+++ b/source/blender/editors/armature/armature_ops.c
@@ -38,160 +38,163 @@
/* Both operators ARMATURE_OT_xxx and POSE_OT_xxx here */
void ED_operatortypes_armature(void)
{
- /* EDIT ARMATURE */
- WM_operatortype_append(ARMATURE_OT_bone_primitive_add);
-
- WM_operatortype_append(ARMATURE_OT_align);
- WM_operatortype_append(ARMATURE_OT_calculate_roll);
- WM_operatortype_append(ARMATURE_OT_roll_clear);
- WM_operatortype_append(ARMATURE_OT_switch_direction);
- WM_operatortype_append(ARMATURE_OT_subdivide);
-
- WM_operatortype_append(ARMATURE_OT_parent_set);
- WM_operatortype_append(ARMATURE_OT_parent_clear);
-
- WM_operatortype_append(ARMATURE_OT_select_all);
- WM_operatortype_append(ARMATURE_OT_select_mirror);
- WM_operatortype_append(ARMATURE_OT_select_more);
- WM_operatortype_append(ARMATURE_OT_select_less);
- WM_operatortype_append(ARMATURE_OT_select_hierarchy);
- WM_operatortype_append(ARMATURE_OT_select_linked);
- WM_operatortype_append(ARMATURE_OT_select_similar);
- WM_operatortype_append(ARMATURE_OT_shortest_path_pick);
-
- WM_operatortype_append(ARMATURE_OT_delete);
- WM_operatortype_append(ARMATURE_OT_dissolve);
- WM_operatortype_append(ARMATURE_OT_duplicate);
- WM_operatortype_append(ARMATURE_OT_symmetrize);
- WM_operatortype_append(ARMATURE_OT_extrude);
- WM_operatortype_append(ARMATURE_OT_hide);
- WM_operatortype_append(ARMATURE_OT_reveal);
- WM_operatortype_append(ARMATURE_OT_click_extrude);
- WM_operatortype_append(ARMATURE_OT_fill);
- WM_operatortype_append(ARMATURE_OT_merge);
- WM_operatortype_append(ARMATURE_OT_separate);
- WM_operatortype_append(ARMATURE_OT_split);
-
- WM_operatortype_append(ARMATURE_OT_autoside_names);
- WM_operatortype_append(ARMATURE_OT_flip_names);
-
- WM_operatortype_append(ARMATURE_OT_layers_show_all);
- WM_operatortype_append(ARMATURE_OT_armature_layers);
- WM_operatortype_append(ARMATURE_OT_bone_layers);
-
- /* POSE */
- WM_operatortype_append(POSE_OT_hide);
- WM_operatortype_append(POSE_OT_reveal);
-
- WM_operatortype_append(POSE_OT_armature_apply);
- WM_operatortype_append(POSE_OT_visual_transform_apply);
-
- WM_operatortype_append(POSE_OT_rot_clear);
- WM_operatortype_append(POSE_OT_loc_clear);
- WM_operatortype_append(POSE_OT_scale_clear);
- WM_operatortype_append(POSE_OT_transforms_clear);
- WM_operatortype_append(POSE_OT_user_transforms_clear);
-
- WM_operatortype_append(POSE_OT_copy);
- WM_operatortype_append(POSE_OT_paste);
-
- WM_operatortype_append(POSE_OT_select_all);
-
- WM_operatortype_append(POSE_OT_select_parent);
- WM_operatortype_append(POSE_OT_select_hierarchy);
- WM_operatortype_append(POSE_OT_select_linked);
- WM_operatortype_append(POSE_OT_select_constraint_target);
- WM_operatortype_append(POSE_OT_select_grouped);
- WM_operatortype_append(POSE_OT_select_mirror);
-
- WM_operatortype_append(POSE_OT_group_add);
- WM_operatortype_append(POSE_OT_group_remove);
- WM_operatortype_append(POSE_OT_group_move);
- WM_operatortype_append(POSE_OT_group_sort);
- WM_operatortype_append(POSE_OT_group_assign);
- WM_operatortype_append(POSE_OT_group_unassign);
- WM_operatortype_append(POSE_OT_group_select);
- WM_operatortype_append(POSE_OT_group_deselect);
-
- WM_operatortype_append(POSE_OT_paths_calculate);
- WM_operatortype_append(POSE_OT_paths_update);
- WM_operatortype_append(POSE_OT_paths_clear);
- WM_operatortype_append(POSE_OT_paths_range_update);
-
- WM_operatortype_append(POSE_OT_autoside_names);
- WM_operatortype_append(POSE_OT_flip_names);
-
- WM_operatortype_append(POSE_OT_rotation_mode_set);
-
- WM_operatortype_append(POSE_OT_quaternions_flip);
-
- WM_operatortype_append(POSE_OT_bone_layers);
-
- WM_operatortype_append(POSE_OT_propagate);
-
- /* POSELIB */
- WM_operatortype_append(POSELIB_OT_browse_interactive);
- WM_operatortype_append(POSELIB_OT_apply_pose);
-
- WM_operatortype_append(POSELIB_OT_pose_add);
- WM_operatortype_append(POSELIB_OT_pose_remove);
- WM_operatortype_append(POSELIB_OT_pose_rename);
- WM_operatortype_append(POSELIB_OT_pose_move);
-
- WM_operatortype_append(POSELIB_OT_new);
- WM_operatortype_append(POSELIB_OT_unlink);
-
- WM_operatortype_append(POSELIB_OT_action_sanitize);
-
- /* POSE SLIDING */
- WM_operatortype_append(POSE_OT_push);
- WM_operatortype_append(POSE_OT_relax);
- WM_operatortype_append(POSE_OT_breakdown);
+ /* EDIT ARMATURE */
+ WM_operatortype_append(ARMATURE_OT_bone_primitive_add);
+
+ WM_operatortype_append(ARMATURE_OT_align);
+ WM_operatortype_append(ARMATURE_OT_calculate_roll);
+ WM_operatortype_append(ARMATURE_OT_roll_clear);
+ WM_operatortype_append(ARMATURE_OT_switch_direction);
+ WM_operatortype_append(ARMATURE_OT_subdivide);
+
+ WM_operatortype_append(ARMATURE_OT_parent_set);
+ WM_operatortype_append(ARMATURE_OT_parent_clear);
+
+ WM_operatortype_append(ARMATURE_OT_select_all);
+ WM_operatortype_append(ARMATURE_OT_select_mirror);
+ WM_operatortype_append(ARMATURE_OT_select_more);
+ WM_operatortype_append(ARMATURE_OT_select_less);
+ WM_operatortype_append(ARMATURE_OT_select_hierarchy);
+ WM_operatortype_append(ARMATURE_OT_select_linked);
+ WM_operatortype_append(ARMATURE_OT_select_similar);
+ WM_operatortype_append(ARMATURE_OT_shortest_path_pick);
+
+ WM_operatortype_append(ARMATURE_OT_delete);
+ WM_operatortype_append(ARMATURE_OT_dissolve);
+ WM_operatortype_append(ARMATURE_OT_duplicate);
+ WM_operatortype_append(ARMATURE_OT_symmetrize);
+ WM_operatortype_append(ARMATURE_OT_extrude);
+ WM_operatortype_append(ARMATURE_OT_hide);
+ WM_operatortype_append(ARMATURE_OT_reveal);
+ WM_operatortype_append(ARMATURE_OT_click_extrude);
+ WM_operatortype_append(ARMATURE_OT_fill);
+ WM_operatortype_append(ARMATURE_OT_merge);
+ WM_operatortype_append(ARMATURE_OT_separate);
+ WM_operatortype_append(ARMATURE_OT_split);
+
+ WM_operatortype_append(ARMATURE_OT_autoside_names);
+ WM_operatortype_append(ARMATURE_OT_flip_names);
+
+ WM_operatortype_append(ARMATURE_OT_layers_show_all);
+ WM_operatortype_append(ARMATURE_OT_armature_layers);
+ WM_operatortype_append(ARMATURE_OT_bone_layers);
+
+ /* POSE */
+ WM_operatortype_append(POSE_OT_hide);
+ WM_operatortype_append(POSE_OT_reveal);
+
+ WM_operatortype_append(POSE_OT_armature_apply);
+ WM_operatortype_append(POSE_OT_visual_transform_apply);
+
+ WM_operatortype_append(POSE_OT_rot_clear);
+ WM_operatortype_append(POSE_OT_loc_clear);
+ WM_operatortype_append(POSE_OT_scale_clear);
+ WM_operatortype_append(POSE_OT_transforms_clear);
+ WM_operatortype_append(POSE_OT_user_transforms_clear);
+
+ WM_operatortype_append(POSE_OT_copy);
+ WM_operatortype_append(POSE_OT_paste);
+
+ WM_operatortype_append(POSE_OT_select_all);
+
+ WM_operatortype_append(POSE_OT_select_parent);
+ WM_operatortype_append(POSE_OT_select_hierarchy);
+ WM_operatortype_append(POSE_OT_select_linked);
+ WM_operatortype_append(POSE_OT_select_constraint_target);
+ WM_operatortype_append(POSE_OT_select_grouped);
+ WM_operatortype_append(POSE_OT_select_mirror);
+
+ WM_operatortype_append(POSE_OT_group_add);
+ WM_operatortype_append(POSE_OT_group_remove);
+ WM_operatortype_append(POSE_OT_group_move);
+ WM_operatortype_append(POSE_OT_group_sort);
+ WM_operatortype_append(POSE_OT_group_assign);
+ WM_operatortype_append(POSE_OT_group_unassign);
+ WM_operatortype_append(POSE_OT_group_select);
+ WM_operatortype_append(POSE_OT_group_deselect);
+
+ WM_operatortype_append(POSE_OT_paths_calculate);
+ WM_operatortype_append(POSE_OT_paths_update);
+ WM_operatortype_append(POSE_OT_paths_clear);
+ WM_operatortype_append(POSE_OT_paths_range_update);
+
+ WM_operatortype_append(POSE_OT_autoside_names);
+ WM_operatortype_append(POSE_OT_flip_names);
+
+ WM_operatortype_append(POSE_OT_rotation_mode_set);
+
+ WM_operatortype_append(POSE_OT_quaternions_flip);
+
+ WM_operatortype_append(POSE_OT_bone_layers);
+
+ WM_operatortype_append(POSE_OT_propagate);
+
+ /* POSELIB */
+ WM_operatortype_append(POSELIB_OT_browse_interactive);
+ WM_operatortype_append(POSELIB_OT_apply_pose);
+
+ WM_operatortype_append(POSELIB_OT_pose_add);
+ WM_operatortype_append(POSELIB_OT_pose_remove);
+ WM_operatortype_append(POSELIB_OT_pose_rename);
+ WM_operatortype_append(POSELIB_OT_pose_move);
+
+ WM_operatortype_append(POSELIB_OT_new);
+ WM_operatortype_append(POSELIB_OT_unlink);
+
+ WM_operatortype_append(POSELIB_OT_action_sanitize);
+
+ /* POSE SLIDING */
+ WM_operatortype_append(POSE_OT_push);
+ WM_operatortype_append(POSE_OT_relax);
+ WM_operatortype_append(POSE_OT_breakdown);
}
void ED_operatormacros_armature(void)
{
- wmOperatorType *ot;
- wmOperatorTypeMacro *otmacro;
-
- ot = WM_operatortype_append_macro("ARMATURE_OT_duplicate_move", "Duplicate",
- "Make copies of the selected bones within the same armature and move them",
- OPTYPE_UNDO | OPTYPE_REGISTER);
- WM_operatortype_macro_define(ot, "ARMATURE_OT_duplicate");
- otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
- RNA_enum_set(otmacro->ptr, "proportional", 0);
-
- ot = WM_operatortype_append_macro("ARMATURE_OT_extrude_move", "Extrude",
- "Create new bones from the selected joints and move them",
- OPTYPE_UNDO | OPTYPE_REGISTER);
- otmacro = WM_operatortype_macro_define(ot, "ARMATURE_OT_extrude");
- RNA_boolean_set(otmacro->ptr, "forked", false);
- otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
- RNA_enum_set(otmacro->ptr, "proportional", 0);
-
- /* XXX would it be nicer to just be able to have standard extrude_move, but set the forked property separate?
- * that would require fixing a properties bug 19733 */
- ot = WM_operatortype_append_macro("ARMATURE_OT_extrude_forked", "Extrude Forked",
- "Create new bones from the selected joints and move them",
- OPTYPE_UNDO | OPTYPE_REGISTER);
- otmacro = WM_operatortype_macro_define(ot, "ARMATURE_OT_extrude");
- RNA_boolean_set(otmacro->ptr, "forked", true);
- otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
- RNA_enum_set(otmacro->ptr, "proportional", 0);
+ wmOperatorType *ot;
+ wmOperatorTypeMacro *otmacro;
+
+ ot = WM_operatortype_append_macro(
+ "ARMATURE_OT_duplicate_move",
+ "Duplicate",
+ "Make copies of the selected bones within the same armature and move them",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ WM_operatortype_macro_define(ot, "ARMATURE_OT_duplicate");
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_enum_set(otmacro->ptr, "proportional", 0);
+
+ ot = WM_operatortype_append_macro("ARMATURE_OT_extrude_move",
+ "Extrude",
+ "Create new bones from the selected joints and move them",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ otmacro = WM_operatortype_macro_define(ot, "ARMATURE_OT_extrude");
+ RNA_boolean_set(otmacro->ptr, "forked", false);
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_enum_set(otmacro->ptr, "proportional", 0);
+
+ /* XXX would it be nicer to just be able to have standard extrude_move, but set the forked property separate?
+ * that would require fixing a properties bug 19733 */
+ ot = WM_operatortype_append_macro("ARMATURE_OT_extrude_forked",
+ "Extrude Forked",
+ "Create new bones from the selected joints and move them",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ otmacro = WM_operatortype_macro_define(ot, "ARMATURE_OT_extrude");
+ RNA_boolean_set(otmacro->ptr, "forked", true);
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_enum_set(otmacro->ptr, "proportional", 0);
}
void ED_keymap_armature(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap;
+ wmKeyMap *keymap;
- /* Armature ------------------------ */
- /* only set in editmode armature, by space_view3d listener */
- keymap = WM_keymap_ensure(keyconf, "Armature", 0, 0);
- keymap->poll = ED_operator_editarmature;
-
- /* Pose ------------------------ */
- /* only set in posemode, by space_view3d listener */
- keymap = WM_keymap_ensure(keyconf, "Pose", 0, 0);
- keymap->poll = ED_operator_posemode;
+ /* Armature ------------------------ */
+ /* only set in editmode armature, by space_view3d listener */
+ keymap = WM_keymap_ensure(keyconf, "Armature", 0, 0);
+ keymap->poll = ED_operator_editarmature;
+ /* Pose ------------------------ */
+ /* only set in posemode, by space_view3d listener */
+ keymap = WM_keymap_ensure(keyconf, "Pose", 0, 0);
+ keymap->poll = ED_operator_posemode;
}
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index 5928e1cd12c..6226059e794 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -67,55 +67,53 @@
/* NOTE: no operator define here as this is exported to the Object-level operator */
static void joined_armature_fix_links_constraints(
- Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone,
- ListBase *lb)
+ Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone, ListBase *lb)
{
- bConstraint *con;
-
- for (con = lb->first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- /* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar == srcArm) {
- if (ct->subtarget[0] == '\0') {
- ct->tar = tarArm;
- }
- else if (STREQ(ct->subtarget, pchan->name)) {
- ct->tar = tarArm;
- BLI_strncpy(ct->subtarget, curbone->name, sizeof(ct->subtarget));
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
-
- /* action constraint? (pose constraints only) */
- if (con->type == CONSTRAINT_TYPE_ACTION) {
- bActionConstraint *data = con->data;
-
- if (data->act) {
- BKE_action_fix_paths_rename(&tarArm->id, data->act, "pose.bones[",
- pchan->name, curbone->name, 0, 0, false);
- }
- }
-
- }
+ bConstraint *con;
+
+ for (con = lb->first; con; con = con->next) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ /* constraint targets */
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ if (ct->tar == srcArm) {
+ if (ct->subtarget[0] == '\0') {
+ ct->tar = tarArm;
+ }
+ else if (STREQ(ct->subtarget, pchan->name)) {
+ ct->tar = tarArm;
+ BLI_strncpy(ct->subtarget, curbone->name, sizeof(ct->subtarget));
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+
+ /* action constraint? (pose constraints only) */
+ if (con->type == CONSTRAINT_TYPE_ACTION) {
+ bActionConstraint *data = con->data;
+
+ if (data->act) {
+ BKE_action_fix_paths_rename(
+ &tarArm->id, data->act, "pose.bones[", pchan->name, curbone->name, 0, 0, false);
+ }
+ }
+ }
}
/* userdata for joined_armature_fix_animdata_cb() */
typedef struct tJoinArmature_AdtFixData {
- Object *srcArm;
- Object *tarArm;
+ Object *srcArm;
+ Object *tarArm;
- GHash *names_map;
+ GHash *names_map;
} tJoinArmature_AdtFixData;
/* Callback to pass to BKE_animdata_main_cb() for fixing driver ID's to point to the new ID */
@@ -124,282 +122,281 @@ typedef struct tJoinArmature_AdtFixData {
*/
static void joined_armature_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data)
{
- tJoinArmature_AdtFixData *afd = (tJoinArmature_AdtFixData *)user_data;
- ID *src_id = &afd->srcArm->id;
- ID *dst_id = &afd->tarArm->id;
-
- GHashIterator gh_iter;
-
- /* Fix paths - If this is the target object, it will have some "dirty" paths */
- if ((id == src_id) && strstr(fcu->rna_path, "pose.bones[")) {
- GHASH_ITER(gh_iter, afd->names_map) {
- const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
- const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
-
- /* only remap if changed; this still means there will be some
- * waste if there aren't many drivers/keys */
- if (!STREQ(old_name, new_name) && strstr(fcu->rna_path, old_name)) {
- fcu->rna_path = BKE_animsys_fix_rna_path_rename(id, fcu->rna_path, "pose.bones",
- old_name, new_name, 0, 0, false);
-
- /* we don't want to apply a second remapping on this driver now,
- * so stop trying names, but keep fixing drivers
- */
- break;
- }
- }
- }
-
-
- /* Driver targets */
- if (fcu->driver) {
- ChannelDriver *driver = fcu->driver;
- DriverVar *dvar;
-
- /* Fix driver references to invalid ID's */
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- /* only change the used targets, since the others will need fixing manually anyway */
- DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar)
- {
- /* change the ID's used... */
- if (dtar->id == src_id) {
- dtar->id = dst_id;
-
- /* also check on the subtarget...
- * XXX: We duplicate the logic from drivers_path_rename_fix() here, with our own
- * little twists so that we know that it isn't going to clobber the wrong data
- */
- if ((dtar->rna_path && strstr(dtar->rna_path, "pose.bones[")) || (dtar->pchan_name[0])) {
- GHASH_ITER(gh_iter, afd->names_map) {
- const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
- const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
-
- /* only remap if changed */
- if (!STREQ(old_name, new_name)) {
- if ((dtar->rna_path) && strstr(dtar->rna_path, old_name)) {
- /* Fix up path */
- dtar->rna_path = BKE_animsys_fix_rna_path_rename(id, dtar->rna_path, "pose.bones",
- old_name, new_name, 0, 0, false);
- break; /* no need to try any more names for bone path */
- }
- else if (STREQ(dtar->pchan_name, old_name)) {
- /* Change target bone name */
- BLI_strncpy(dtar->pchan_name, new_name, sizeof(dtar->pchan_name));
- break; /* no need to try any more names for bone subtarget */
- }
- }
- }
- }
- }
- }
- DRIVER_TARGETS_LOOPER_END;
- }
- }
+ tJoinArmature_AdtFixData *afd = (tJoinArmature_AdtFixData *)user_data;
+ ID *src_id = &afd->srcArm->id;
+ ID *dst_id = &afd->tarArm->id;
+
+ GHashIterator gh_iter;
+
+ /* Fix paths - If this is the target object, it will have some "dirty" paths */
+ if ((id == src_id) && strstr(fcu->rna_path, "pose.bones[")) {
+ GHASH_ITER (gh_iter, afd->names_map) {
+ const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
+ const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
+
+ /* only remap if changed; this still means there will be some
+ * waste if there aren't many drivers/keys */
+ if (!STREQ(old_name, new_name) && strstr(fcu->rna_path, old_name)) {
+ fcu->rna_path = BKE_animsys_fix_rna_path_rename(
+ id, fcu->rna_path, "pose.bones", old_name, new_name, 0, 0, false);
+
+ /* we don't want to apply a second remapping on this driver now,
+ * so stop trying names, but keep fixing drivers
+ */
+ break;
+ }
+ }
+ }
+
+ /* Driver targets */
+ if (fcu->driver) {
+ ChannelDriver *driver = fcu->driver;
+ DriverVar *dvar;
+
+ /* Fix driver references to invalid ID's */
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ /* only change the used targets, since the others will need fixing manually anyway */
+ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
+ /* change the ID's used... */
+ if (dtar->id == src_id) {
+ dtar->id = dst_id;
+
+ /* also check on the subtarget...
+ * XXX: We duplicate the logic from drivers_path_rename_fix() here, with our own
+ * little twists so that we know that it isn't going to clobber the wrong data
+ */
+ if ((dtar->rna_path && strstr(dtar->rna_path, "pose.bones[")) || (dtar->pchan_name[0])) {
+ GHASH_ITER (gh_iter, afd->names_map) {
+ const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
+ const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
+
+ /* only remap if changed */
+ if (!STREQ(old_name, new_name)) {
+ if ((dtar->rna_path) && strstr(dtar->rna_path, old_name)) {
+ /* Fix up path */
+ dtar->rna_path = BKE_animsys_fix_rna_path_rename(
+ id, dtar->rna_path, "pose.bones", old_name, new_name, 0, 0, false);
+ break; /* no need to try any more names for bone path */
+ }
+ else if (STREQ(dtar->pchan_name, old_name)) {
+ /* Change target bone name */
+ BLI_strncpy(dtar->pchan_name, new_name, sizeof(dtar->pchan_name));
+ break; /* no need to try any more names for bone subtarget */
+ }
+ }
+ }
+ }
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+ }
+ }
}
/* Helper function for armature joining - link fixing */
-static void joined_armature_fix_links(Main *bmain, Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone)
+static void joined_armature_fix_links(
+ Main *bmain, Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone)
{
- Object *ob;
- bPose *pose;
- bPoseChannel *pchant;
-
- /* let's go through all objects in database */
- for (ob = bmain->objects.first; ob; ob = ob->id.next) {
- /* do some object-type specific things */
- if (ob->type == OB_ARMATURE) {
- pose = ob->pose;
- for (pchant = pose->chanbase.first; pchant; pchant = pchant->next) {
- joined_armature_fix_links_constraints(tarArm, srcArm, pchan, curbone, &pchant->constraints);
- }
- }
-
- /* fix object-level constraints */
- if (ob != srcArm) {
- joined_armature_fix_links_constraints(tarArm, srcArm, pchan, curbone, &ob->constraints);
- }
-
- /* See if an object is parented to this armature */
- if (ob->parent && (ob->parent == srcArm)) {
- /* Is object parented to a bone of this src armature? */
- if (ob->partype == PARBONE) {
- /* bone name in object */
- if (STREQ(ob->parsubstr, pchan->name)) {
- BLI_strncpy(ob->parsubstr, curbone->name, sizeof(ob->parsubstr));
- }
- }
-
- /* make tar armature be new parent */
- ob->parent = tarArm;
- }
- }
+ Object *ob;
+ bPose *pose;
+ bPoseChannel *pchant;
+
+ /* let's go through all objects in database */
+ for (ob = bmain->objects.first; ob; ob = ob->id.next) {
+ /* do some object-type specific things */
+ if (ob->type == OB_ARMATURE) {
+ pose = ob->pose;
+ for (pchant = pose->chanbase.first; pchant; pchant = pchant->next) {
+ joined_armature_fix_links_constraints(
+ tarArm, srcArm, pchan, curbone, &pchant->constraints);
+ }
+ }
+
+ /* fix object-level constraints */
+ if (ob != srcArm) {
+ joined_armature_fix_links_constraints(tarArm, srcArm, pchan, curbone, &ob->constraints);
+ }
+
+ /* See if an object is parented to this armature */
+ if (ob->parent && (ob->parent == srcArm)) {
+ /* Is object parented to a bone of this src armature? */
+ if (ob->partype == PARBONE) {
+ /* bone name in object */
+ if (STREQ(ob->parsubstr, pchan->name)) {
+ BLI_strncpy(ob->parsubstr, curbone->name, sizeof(ob->parsubstr));
+ }
+ }
+
+ /* make tar armature be new parent */
+ ob->parent = tarArm;
+ }
+ }
}
/* join armature exec is exported for use in object->join objects operator... */
int join_armature_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob_active = CTX_data_active_object(C);
- bArmature *arm = (ob_active) ? ob_active->data : NULL;
- bPose *pose, *opose;
- bPoseChannel *pchan, *pchann;
- EditBone *curbone;
- float mat[4][4], oimat[4][4];
- bool ok = false;
-
- /* Ensure we're not in editmode and that the active object is an armature*/
- if (!ob_active || ob_active->type != OB_ARMATURE)
- return OPERATOR_CANCELLED;
- if (!arm || arm->edbo)
- return OPERATOR_CANCELLED;
-
- CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
- {
- if (ob_iter == ob_active) {
- ok = true;
- break;
- }
- }
- CTX_DATA_END;
-
- /* that way the active object is always selected */
- if (ok == false) {
- BKE_report(op->reports, RPT_WARNING, "Active object is not a selected armature");
- return OPERATOR_CANCELLED;
- }
-
- /* Get editbones of active armature to add editbones to */
- ED_armature_to_edit(arm);
-
- /* get pose of active object and move it out of posemode */
- pose = ob_active->pose;
- ob_active->mode &= ~OB_MODE_POSE;
-
- CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
- {
- if ((ob_iter->type == OB_ARMATURE) && (ob_iter != ob_active)) {
- tJoinArmature_AdtFixData afd = {NULL};
- bArmature *curarm = ob_iter->data;
-
- /* we assume that each armature datablock is only used in a single place */
- BLI_assert(ob_active->data != ob_iter->data);
-
- /* init callback data for fixing up AnimData links later */
- afd.srcArm = ob_iter;
- afd.tarArm = ob_active;
- afd.names_map = BLI_ghash_str_new("join_armature_adt_fix");
-
- /* Make a list of editbones in current armature */
- ED_armature_to_edit(ob_iter->data);
-
- /* Get Pose of current armature */
- opose = ob_iter->pose;
- ob_iter->mode &= ~OB_MODE_POSE;
- //BASACT->flag &= ~OB_MODE_POSE;
-
- /* Find the difference matrix */
- invert_m4_m4(oimat, ob_active->obmat);
- mul_m4_m4m4(mat, oimat, ob_iter->obmat);
-
- /* Copy bones and posechannels from the object to the edit armature */
- for (pchan = opose->chanbase.first; pchan; pchan = pchann) {
- pchann = pchan->next;
- curbone = ED_armature_ebone_find_name(curarm->edbo, pchan->name);
-
- /* Get new name */
- ED_armature_ebone_unique_name(arm->edbo, curbone->name, NULL);
- BLI_ghash_insert(afd.names_map, BLI_strdup(pchan->name), curbone->name);
-
- /* Transform the bone */
- {
- float premat[4][4];
- float postmat[4][4];
- float difmat[4][4];
- float imat[4][4];
- float temp[3][3];
-
- /* Get the premat */
- ED_armature_ebone_to_mat3(curbone, temp);
-
- unit_m4(premat); /* mul_m4_m3m4 only sets 3x3 part */
- mul_m4_m3m4(premat, temp, mat);
-
- mul_m4_v3(mat, curbone->head);
- mul_m4_v3(mat, curbone->tail);
-
- /* Get the postmat */
- ED_armature_ebone_to_mat3(curbone, temp);
- copy_m4_m3(postmat, temp);
-
- /* Find the roll */
- invert_m4_m4(imat, premat);
- mul_m4_m4m4(difmat, imat, postmat);
-
- curbone->roll -= atan2f(difmat[2][0], difmat[2][2]);
- }
-
- /* Fix Constraints and Other Links to this Bone and Armature */
- joined_armature_fix_links(bmain, ob_active, ob_iter, pchan, curbone);
-
- /* Rename pchan */
- BLI_strncpy(pchan->name, curbone->name, sizeof(pchan->name));
-
- /* Jump Ship! */
- BLI_remlink(curarm->edbo, curbone);
- BLI_addtail(arm->edbo, curbone);
-
- BLI_remlink(&opose->chanbase, pchan);
- BLI_addtail(&pose->chanbase, pchan);
- BKE_pose_channels_hash_free(opose);
- BKE_pose_channels_hash_free(pose);
- }
-
- /* Fix all the drivers (and animation data) */
- BKE_fcurves_main_cb(bmain, joined_armature_fix_animdata_cb, &afd);
- BLI_ghash_free(afd.names_map, MEM_freeN, NULL);
-
- /* Only copy over animdata now, after all the remapping has been done,
- * so that we don't have to worry about ambiguities re which armature
- * a bone came from!
- */
- if (ob_iter->adt) {
- if (ob_active->adt == NULL) {
- /* no animdata, so just use a copy of the whole thing */
- ob_active->adt = BKE_animdata_copy(bmain, ob_iter->adt, 0);
- }
- else {
- /* merge in data - we'll fix the drivers manually */
- BKE_animdata_merge_copy(bmain, &ob_active->id, &ob_iter->id, ADT_MERGECOPY_KEEP_DST, false);
- }
- }
-
- if (curarm->adt) {
- if (arm->adt == NULL) {
- /* no animdata, so just use a copy of the whole thing */
- arm->adt = BKE_animdata_copy(bmain, curarm->adt, 0);
- }
- else {
- /* merge in data - we'll fix the drivers manually */
- BKE_animdata_merge_copy(bmain, &arm->id, &curarm->id, ADT_MERGECOPY_KEEP_DST, false);
- }
- }
-
- /* Free the old object data */
- ED_object_base_free_and_unlink(bmain, scene, ob_iter);
- }
- }
- CTX_DATA_END;
-
- DEG_relations_tag_update(bmain); /* because we removed object(s) */
-
- ED_armature_from_edit(bmain, arm);
- ED_armature_edit_free(arm);
-
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
-
- return OPERATOR_FINISHED;
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob_active = CTX_data_active_object(C);
+ bArmature *arm = (ob_active) ? ob_active->data : NULL;
+ bPose *pose, *opose;
+ bPoseChannel *pchan, *pchann;
+ EditBone *curbone;
+ float mat[4][4], oimat[4][4];
+ bool ok = false;
+
+ /* Ensure we're not in editmode and that the active object is an armature*/
+ if (!ob_active || ob_active->type != OB_ARMATURE)
+ return OPERATOR_CANCELLED;
+ if (!arm || arm->edbo)
+ return OPERATOR_CANCELLED;
+
+ CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
+ if (ob_iter == ob_active) {
+ ok = true;
+ break;
+ }
+ }
+ CTX_DATA_END;
+
+ /* that way the active object is always selected */
+ if (ok == false) {
+ BKE_report(op->reports, RPT_WARNING, "Active object is not a selected armature");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Get editbones of active armature to add editbones to */
+ ED_armature_to_edit(arm);
+
+ /* get pose of active object and move it out of posemode */
+ pose = ob_active->pose;
+ ob_active->mode &= ~OB_MODE_POSE;
+
+ CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
+ if ((ob_iter->type == OB_ARMATURE) && (ob_iter != ob_active)) {
+ tJoinArmature_AdtFixData afd = {NULL};
+ bArmature *curarm = ob_iter->data;
+
+ /* we assume that each armature datablock is only used in a single place */
+ BLI_assert(ob_active->data != ob_iter->data);
+
+ /* init callback data for fixing up AnimData links later */
+ afd.srcArm = ob_iter;
+ afd.tarArm = ob_active;
+ afd.names_map = BLI_ghash_str_new("join_armature_adt_fix");
+
+ /* Make a list of editbones in current armature */
+ ED_armature_to_edit(ob_iter->data);
+
+ /* Get Pose of current armature */
+ opose = ob_iter->pose;
+ ob_iter->mode &= ~OB_MODE_POSE;
+ //BASACT->flag &= ~OB_MODE_POSE;
+
+ /* Find the difference matrix */
+ invert_m4_m4(oimat, ob_active->obmat);
+ mul_m4_m4m4(mat, oimat, ob_iter->obmat);
+
+ /* Copy bones and posechannels from the object to the edit armature */
+ for (pchan = opose->chanbase.first; pchan; pchan = pchann) {
+ pchann = pchan->next;
+ curbone = ED_armature_ebone_find_name(curarm->edbo, pchan->name);
+
+ /* Get new name */
+ ED_armature_ebone_unique_name(arm->edbo, curbone->name, NULL);
+ BLI_ghash_insert(afd.names_map, BLI_strdup(pchan->name), curbone->name);
+
+ /* Transform the bone */
+ {
+ float premat[4][4];
+ float postmat[4][4];
+ float difmat[4][4];
+ float imat[4][4];
+ float temp[3][3];
+
+ /* Get the premat */
+ ED_armature_ebone_to_mat3(curbone, temp);
+
+ unit_m4(premat); /* mul_m4_m3m4 only sets 3x3 part */
+ mul_m4_m3m4(premat, temp, mat);
+
+ mul_m4_v3(mat, curbone->head);
+ mul_m4_v3(mat, curbone->tail);
+
+ /* Get the postmat */
+ ED_armature_ebone_to_mat3(curbone, temp);
+ copy_m4_m3(postmat, temp);
+
+ /* Find the roll */
+ invert_m4_m4(imat, premat);
+ mul_m4_m4m4(difmat, imat, postmat);
+
+ curbone->roll -= atan2f(difmat[2][0], difmat[2][2]);
+ }
+
+ /* Fix Constraints and Other Links to this Bone and Armature */
+ joined_armature_fix_links(bmain, ob_active, ob_iter, pchan, curbone);
+
+ /* Rename pchan */
+ BLI_strncpy(pchan->name, curbone->name, sizeof(pchan->name));
+
+ /* Jump Ship! */
+ BLI_remlink(curarm->edbo, curbone);
+ BLI_addtail(arm->edbo, curbone);
+
+ BLI_remlink(&opose->chanbase, pchan);
+ BLI_addtail(&pose->chanbase, pchan);
+ BKE_pose_channels_hash_free(opose);
+ BKE_pose_channels_hash_free(pose);
+ }
+
+ /* Fix all the drivers (and animation data) */
+ BKE_fcurves_main_cb(bmain, joined_armature_fix_animdata_cb, &afd);
+ BLI_ghash_free(afd.names_map, MEM_freeN, NULL);
+
+ /* Only copy over animdata now, after all the remapping has been done,
+ * so that we don't have to worry about ambiguities re which armature
+ * a bone came from!
+ */
+ if (ob_iter->adt) {
+ if (ob_active->adt == NULL) {
+ /* no animdata, so just use a copy of the whole thing */
+ ob_active->adt = BKE_animdata_copy(bmain, ob_iter->adt, 0);
+ }
+ else {
+ /* merge in data - we'll fix the drivers manually */
+ BKE_animdata_merge_copy(
+ bmain, &ob_active->id, &ob_iter->id, ADT_MERGECOPY_KEEP_DST, false);
+ }
+ }
+
+ if (curarm->adt) {
+ if (arm->adt == NULL) {
+ /* no animdata, so just use a copy of the whole thing */
+ arm->adt = BKE_animdata_copy(bmain, curarm->adt, 0);
+ }
+ else {
+ /* merge in data - we'll fix the drivers manually */
+ BKE_animdata_merge_copy(bmain, &arm->id, &curarm->id, ADT_MERGECOPY_KEEP_DST, false);
+ }
+ }
+
+ /* Free the old object data */
+ ED_object_base_free_and_unlink(bmain, scene, ob_iter);
+ }
+ }
+ CTX_DATA_END;
+
+ DEG_relations_tag_update(bmain); /* because we removed object(s) */
+
+ ED_armature_from_edit(bmain, arm);
+ ED_armature_edit_free(arm);
+
+ DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+
+ return OPERATOR_FINISHED;
}
/* *********************************** Separate *********************************************** */
@@ -407,103 +404,103 @@ int join_armature_exec(bContext *C, wmOperator *op)
/* Helper function for armature separating - link fixing */
static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *newArm)
{
- Object *ob;
- bPoseChannel *pchan;
- bConstraint *con;
- ListBase *opchans, *npchans;
-
- /* get reference to list of bones in original and new armatures */
- opchans = &origArm->pose->chanbase;
- npchans = &newArm->pose->chanbase;
-
- /* let's go through all objects in database */
- for (ob = bmain->objects.first; ob; ob = ob->id.next) {
- /* do some object-type specific things */
- if (ob->type == OB_ARMATURE) {
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- for (con = pchan->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- /* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- /* any targets which point to original armature are redirected to the new one only if:
- * - the target isn't origArm/newArm itself
- * - the target is one that can be found in newArm/origArm
- */
- if (ct->subtarget[0] != 0) {
- if (ct->tar == origArm) {
- if (BLI_findstring(npchans, ct->subtarget, offsetof(bPoseChannel, name))) {
- ct->tar = newArm;
- }
- }
- else if (ct->tar == newArm) {
- if (BLI_findstring(opchans, ct->subtarget, offsetof(bPoseChannel, name))) {
- ct->tar = origArm;
- }
- }
- }
- }
-
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
- }
- }
-
- /* fix object-level constraints */
- if (ob != origArm) {
- for (con = ob->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- /* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- /* any targets which point to original armature are redirected to the new one only if:
- * - the target isn't origArm/newArm itself
- * - the target is one that can be found in newArm/origArm
- */
- if (ct->subtarget[0] != '\0') {
- if (ct->tar == origArm) {
- if (BLI_findstring(npchans, ct->subtarget, offsetof(bPoseChannel, name))) {
- ct->tar = newArm;
- }
- }
- else if (ct->tar == newArm) {
- if (BLI_findstring(opchans, ct->subtarget, offsetof(bPoseChannel, name))) {
- ct->tar = origArm;
- }
- }
- }
- }
-
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
- }
-
- /* See if an object is parented to this armature */
- if (ob->parent && (ob->parent == origArm)) {
- /* Is object parented to a bone of this src armature? */
- if ((ob->partype == PARBONE) && (ob->parsubstr[0] != '\0')) {
- if (BLI_findstring(npchans, ob->parsubstr, offsetof(bPoseChannel, name))) {
- ob->parent = newArm;
- }
- }
- }
- }
+ Object *ob;
+ bPoseChannel *pchan;
+ bConstraint *con;
+ ListBase *opchans, *npchans;
+
+ /* get reference to list of bones in original and new armatures */
+ opchans = &origArm->pose->chanbase;
+ npchans = &newArm->pose->chanbase;
+
+ /* let's go through all objects in database */
+ for (ob = bmain->objects.first; ob; ob = ob->id.next) {
+ /* do some object-type specific things */
+ if (ob->type == OB_ARMATURE) {
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ for (con = pchan->constraints.first; con; con = con->next) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ /* constraint targets */
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ /* any targets which point to original armature are redirected to the new one only if:
+ * - the target isn't origArm/newArm itself
+ * - the target is one that can be found in newArm/origArm
+ */
+ if (ct->subtarget[0] != 0) {
+ if (ct->tar == origArm) {
+ if (BLI_findstring(npchans, ct->subtarget, offsetof(bPoseChannel, name))) {
+ ct->tar = newArm;
+ }
+ }
+ else if (ct->tar == newArm) {
+ if (BLI_findstring(opchans, ct->subtarget, offsetof(bPoseChannel, name))) {
+ ct->tar = origArm;
+ }
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets) {
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+ }
+ }
+ }
+
+ /* fix object-level constraints */
+ if (ob != origArm) {
+ for (con = ob->constraints.first; con; con = con->next) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ /* constraint targets */
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ /* any targets which point to original armature are redirected to the new one only if:
+ * - the target isn't origArm/newArm itself
+ * - the target is one that can be found in newArm/origArm
+ */
+ if (ct->subtarget[0] != '\0') {
+ if (ct->tar == origArm) {
+ if (BLI_findstring(npchans, ct->subtarget, offsetof(bPoseChannel, name))) {
+ ct->tar = newArm;
+ }
+ }
+ else if (ct->tar == newArm) {
+ if (BLI_findstring(opchans, ct->subtarget, offsetof(bPoseChannel, name))) {
+ ct->tar = origArm;
+ }
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets) {
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+ }
+ }
+
+ /* See if an object is parented to this armature */
+ if (ob->parent && (ob->parent == origArm)) {
+ /* Is object parented to a bone of this src armature? */
+ if ((ob->partype == PARBONE) && (ob->parsubstr[0] != '\0')) {
+ if (BLI_findstring(npchans, ob->parsubstr, offsetof(bPoseChannel, name))) {
+ ob->parent = newArm;
+ }
+ }
+ }
+ }
}
/* Helper function for armature separating - remove certain bones from the given armature
@@ -512,429 +509,432 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
*/
static void separate_armature_bones(Main *bmain, Object *ob, short sel)
{
- bArmature *arm = (bArmature *)ob->data;
- bPoseChannel *pchan, *pchann;
- EditBone *curbone;
-
- /* make local set of editbones to manipulate here */
- ED_armature_to_edit(arm);
-
- /* go through pose-channels, checking if a bone should be removed */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchann) {
- pchann = pchan->next;
- curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name);
-
- /* check if bone needs to be removed */
- if ( (sel && (curbone->flag & BONE_SELECTED)) ||
- (!sel && !(curbone->flag & BONE_SELECTED)) )
- {
- EditBone *ebo;
- bPoseChannel *pchn;
-
- /* clear the bone->parent var of any bone that had this as its parent */
- for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
- if (ebo->parent == curbone) {
- ebo->parent = NULL;
- /* this is needed to prevent random crashes with in ED_armature_from_edit */
- ebo->temp.p = NULL;
- ebo->flag &= ~BONE_CONNECTED;
- }
- }
-
- /* clear the pchan->parent var of any pchan that had this as its parent */
- for (pchn = ob->pose->chanbase.first; pchn; pchn = pchn->next) {
- if (pchn->parent == pchan) {
- pchn->parent = NULL;
- }
- if (pchn->bbone_next == pchan) {
- pchn->bbone_next = NULL;
- }
- if (pchn->bbone_prev == pchan) {
- pchn->bbone_prev = NULL;
- }
- }
-
- /* free any of the extra-data this pchan might have */
- BKE_pose_channel_free(pchan);
- BKE_pose_channels_hash_free(ob->pose);
-
- /* get rid of unneeded bone */
- bone_free(arm, curbone);
- BLI_freelinkN(&ob->pose->chanbase, pchan);
- }
- }
-
- /* exit editmode (recalculates pchans too) */
- ED_armature_from_edit(bmain, ob->data);
- ED_armature_edit_free(ob->data);
+ bArmature *arm = (bArmature *)ob->data;
+ bPoseChannel *pchan, *pchann;
+ EditBone *curbone;
+
+ /* make local set of editbones to manipulate here */
+ ED_armature_to_edit(arm);
+
+ /* go through pose-channels, checking if a bone should be removed */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchann) {
+ pchann = pchan->next;
+ curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name);
+
+ /* check if bone needs to be removed */
+ if ((sel && (curbone->flag & BONE_SELECTED)) || (!sel && !(curbone->flag & BONE_SELECTED))) {
+ EditBone *ebo;
+ bPoseChannel *pchn;
+
+ /* clear the bone->parent var of any bone that had this as its parent */
+ for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ if (ebo->parent == curbone) {
+ ebo->parent = NULL;
+ /* this is needed to prevent random crashes with in ED_armature_from_edit */
+ ebo->temp.p = NULL;
+ ebo->flag &= ~BONE_CONNECTED;
+ }
+ }
+
+ /* clear the pchan->parent var of any pchan that had this as its parent */
+ for (pchn = ob->pose->chanbase.first; pchn; pchn = pchn->next) {
+ if (pchn->parent == pchan) {
+ pchn->parent = NULL;
+ }
+ if (pchn->bbone_next == pchan) {
+ pchn->bbone_next = NULL;
+ }
+ if (pchn->bbone_prev == pchan) {
+ pchn->bbone_prev = NULL;
+ }
+ }
+
+ /* free any of the extra-data this pchan might have */
+ BKE_pose_channel_free(pchan);
+ BKE_pose_channels_hash_free(ob->pose);
+
+ /* get rid of unneeded bone */
+ bone_free(arm, curbone);
+ BLI_freelinkN(&ob->pose->chanbase, pchan);
+ }
+ }
+
+ /* exit editmode (recalculates pchans too) */
+ ED_armature_from_edit(bmain, ob->data);
+ ED_armature_edit_free(ob->data);
}
/* separate selected bones into their armature */
static int separate_armature_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- bool ok = false;
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ bool ok = false;
- /* set wait cursor in case this takes a while */
- WM_cursor_wait(1);
+ /* set wait cursor in case this takes a while */
+ WM_cursor_wait(1);
- uint bases_len = 0;
- Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &bases_len);
+ uint bases_len = 0;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &bases_len);
- CTX_DATA_BEGIN(C, Base *, base, visible_bases)
- {
- ED_object_base_select(base, BA_DESELECT);
- }
- CTX_DATA_END;
+ CTX_DATA_BEGIN (C, Base *, base, visible_bases) {
+ ED_object_base_select(base, BA_DESELECT);
+ }
+ CTX_DATA_END;
- for (uint base_index = 0; base_index < bases_len; base_index++) {
- Base *base_iter = bases[base_index];
- Object *obedit = base_iter->object;
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Base *base_iter = bases[base_index];
+ Object *obedit = base_iter->object;
- Object *oldob, *newob;
- Base *oldbase, *newbase;
+ Object *oldob, *newob;
+ Base *oldbase, *newbase;
- /* we are going to do this as follows (unlike every other instance of separate):
- * 1. exit editmode +posemode for active armature/base. Take note of what this is.
- * 2. duplicate base - BASACT is the new one now
- * 3. for each of the two armatures, enter editmode -> remove appropriate bones -> exit editmode + recalc
- * 4. fix constraint links
- * 5. make original armature active and enter editmode
- */
+ /* we are going to do this as follows (unlike every other instance of separate):
+ * 1. exit editmode +posemode for active armature/base. Take note of what this is.
+ * 2. duplicate base - BASACT is the new one now
+ * 3. for each of the two armatures, enter editmode -> remove appropriate bones -> exit editmode + recalc
+ * 4. fix constraint links
+ * 5. make original armature active and enter editmode
+ */
- /* 1) only edit-base selected */
- ED_object_base_select(base_iter, BA_SELECT);
+ /* 1) only edit-base selected */
+ ED_object_base_select(base_iter, BA_SELECT);
- /* 1) store starting settings and exit editmode */
- oldob = obedit;
- oldbase = base_iter;
- oldob->mode &= ~OB_MODE_POSE;
- //oldbase->flag &= ~OB_POSEMODE;
+ /* 1) store starting settings and exit editmode */
+ oldob = obedit;
+ oldbase = base_iter;
+ oldob->mode &= ~OB_MODE_POSE;
+ //oldbase->flag &= ~OB_POSEMODE;
- ED_armature_from_edit(bmain, obedit->data);
- ED_armature_edit_free(obedit->data);
+ ED_armature_from_edit(bmain, obedit->data);
+ ED_armature_edit_free(obedit->data);
- /* 2) duplicate base */
+ /* 2) duplicate base */
- /* only duplicate linked armature */
- newbase = ED_object_add_duplicate(bmain, scene, view_layer, oldbase, USER_DUP_ARM);
+ /* only duplicate linked armature */
+ newbase = ED_object_add_duplicate(bmain, scene, view_layer, oldbase, USER_DUP_ARM);
- DEG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
- newob = newbase->object;
- newbase->flag &= ~BASE_SELECTED;
+ newob = newbase->object;
+ newbase->flag &= ~BASE_SELECTED;
+ /* 3) remove bones that shouldn't still be around on both armatures */
+ separate_armature_bones(bmain, oldob, 1);
+ separate_armature_bones(bmain, newob, 0);
- /* 3) remove bones that shouldn't still be around on both armatures */
- separate_armature_bones(bmain, oldob, 1);
- separate_armature_bones(bmain, newob, 0);
+ /* 4) fix links before depsgraph flushes */ // err... or after?
+ separated_armature_fix_links(bmain, oldob, newob);
+ DEG_id_tag_update(&oldob->id, ID_RECALC_GEOMETRY); /* this is the original one */
+ DEG_id_tag_update(&newob->id, ID_RECALC_GEOMETRY); /* this is the separated one */
- /* 4) fix links before depsgraph flushes */ // err... or after?
- separated_armature_fix_links(bmain, oldob, newob);
+ /* 5) restore original conditions */
+ obedit = oldob;
- DEG_id_tag_update(&oldob->id, ID_RECALC_GEOMETRY); /* this is the original one */
- DEG_id_tag_update(&newob->id, ID_RECALC_GEOMETRY); /* this is the separated one */
+ ED_armature_to_edit(obedit->data);
+ /* parents tips remain selected when connected children are removed. */
+ ED_armature_edit_deselect_all(obedit);
- /* 5) restore original conditions */
- obedit = oldob;
+ ok = true;
- ED_armature_to_edit(obedit->data);
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
+ }
+ MEM_freeN(bases);
- /* parents tips remain selected when connected children are removed. */
- ED_armature_edit_deselect_all(obedit);
+ /* recalc/redraw + cleanup */
+ WM_cursor_wait(0);
- ok = true;
+ if (ok) {
+ BKE_report(op->reports, RPT_INFO, "Separated bones");
+ }
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
- }
- MEM_freeN(bases);
-
- /* recalc/redraw + cleanup */
- WM_cursor_wait(0);
-
- if (ok) {
- BKE_report(op->reports, RPT_INFO, "Separated bones");
- }
-
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_separate(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Separate Bones";
- ot->idname = "ARMATURE_OT_separate";
- ot->description = "Isolate selected bones into a separate armature";
-
- /* callbacks */
- ot->invoke = WM_operator_confirm;
- ot->exec = separate_armature_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* identifiers */
+ ot->name = "Separate Bones";
+ ot->idname = "ARMATURE_OT_separate";
+ ot->description = "Isolate selected bones into a separate armature";
+
+ /* callbacks */
+ ot->invoke = WM_operator_confirm;
+ ot->exec = separate_armature_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ******************************************** Parenting ************************************************* */
/* armature parenting options */
#define ARM_PAR_CONNECT 1
-#define ARM_PAR_OFFSET 2
-
+#define ARM_PAR_OFFSET 2
/* check for null, before calling! */
static void bone_connect_to_existing_parent(EditBone *bone)
{
- bone->flag |= BONE_CONNECTED;
- copy_v3_v3(bone->head, bone->parent->tail);
- bone->rad_head = bone->parent->rad_tail;
+ bone->flag |= BONE_CONNECTED;
+ copy_v3_v3(bone->head, bone->parent->tail);
+ bone->rad_head = bone->parent->rad_tail;
}
-static void bone_connect_to_new_parent(ListBase *edbo, EditBone *selbone, EditBone *actbone, short mode)
+static void bone_connect_to_new_parent(ListBase *edbo,
+ EditBone *selbone,
+ EditBone *actbone,
+ short mode)
{
- EditBone *ebone;
- float offset[3];
-
- if ((selbone->parent) && (selbone->flag & BONE_CONNECTED))
- selbone->parent->flag &= ~(BONE_TIPSEL);
-
- /* make actbone the parent of selbone */
- selbone->parent = actbone;
-
- /* in actbone tree we cannot have a loop */
- for (ebone = actbone->parent; ebone; ebone = ebone->parent) {
- if (ebone->parent == selbone) {
- ebone->parent = NULL;
- ebone->flag &= ~BONE_CONNECTED;
- }
- }
-
- if (mode == ARM_PAR_CONNECT) {
- /* Connected: Child bones will be moved to the parent tip */
- selbone->flag |= BONE_CONNECTED;
- sub_v3_v3v3(offset, actbone->tail, selbone->head);
-
- copy_v3_v3(selbone->head, actbone->tail);
- selbone->rad_head = actbone->rad_tail;
-
- add_v3_v3(selbone->tail, offset);
-
- /* offset for all its children */
- for (ebone = edbo->first; ebone; ebone = ebone->next) {
- EditBone *par;
-
- for (par = ebone->parent; par; par = par->parent) {
- if (par == selbone) {
- add_v3_v3(ebone->head, offset);
- add_v3_v3(ebone->tail, offset);
- break;
- }
- }
- }
- }
- else {
- /* Offset: Child bones will retain their distance from the parent tip */
- selbone->flag &= ~BONE_CONNECTED;
- }
+ EditBone *ebone;
+ float offset[3];
+
+ if ((selbone->parent) && (selbone->flag & BONE_CONNECTED))
+ selbone->parent->flag &= ~(BONE_TIPSEL);
+
+ /* make actbone the parent of selbone */
+ selbone->parent = actbone;
+
+ /* in actbone tree we cannot have a loop */
+ for (ebone = actbone->parent; ebone; ebone = ebone->parent) {
+ if (ebone->parent == selbone) {
+ ebone->parent = NULL;
+ ebone->flag &= ~BONE_CONNECTED;
+ }
+ }
+
+ if (mode == ARM_PAR_CONNECT) {
+ /* Connected: Child bones will be moved to the parent tip */
+ selbone->flag |= BONE_CONNECTED;
+ sub_v3_v3v3(offset, actbone->tail, selbone->head);
+
+ copy_v3_v3(selbone->head, actbone->tail);
+ selbone->rad_head = actbone->rad_tail;
+
+ add_v3_v3(selbone->tail, offset);
+
+ /* offset for all its children */
+ for (ebone = edbo->first; ebone; ebone = ebone->next) {
+ EditBone *par;
+
+ for (par = ebone->parent; par; par = par->parent) {
+ if (par == selbone) {
+ add_v3_v3(ebone->head, offset);
+ add_v3_v3(ebone->tail, offset);
+ break;
+ }
+ }
+ }
+ }
+ else {
+ /* Offset: Child bones will retain their distance from the parent tip */
+ selbone->flag &= ~BONE_CONNECTED;
+ }
}
-
static const EnumPropertyItem prop_editarm_make_parent_types[] = {
- {ARM_PAR_CONNECT, "CONNECTED", 0, "Connected", ""},
- {ARM_PAR_OFFSET, "OFFSET", 0, "Keep Offset", ""},
- {0, NULL, 0, NULL, NULL},
+ {ARM_PAR_CONNECT, "CONNECTED", 0, "Connected", ""},
+ {ARM_PAR_OFFSET, "OFFSET", 0, "Keep Offset", ""},
+ {0, NULL, 0, NULL, NULL},
};
static int armature_parent_set_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_edit_object(C);
- bArmature *arm = (bArmature *)ob->data;
- EditBone *actbone = CTX_data_active_bone(C);
- EditBone *actmirb = NULL;
- short val = RNA_enum_get(op->ptr, "type");
-
- /* there must be an active bone */
- if (actbone == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
- return OPERATOR_CANCELLED;
- }
- else if (arm->flag & ARM_MIRROR_EDIT) {
- /* For X-Axis Mirror Editing option, we may need a mirror copy of actbone
- * - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone
- * (i.e. selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
- * This is useful for arm-chains, for example parenting lower arm to upper arm
- * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
- * then just use actbone. Useful when doing upper arm to spine.
- */
- actmirb = ED_armature_ebone_get_mirrored(arm->edbo, actbone);
- if (actmirb == NULL)
- actmirb = actbone;
- }
-
- /* if there is only 1 selected bone, we assume that that is the active bone,
- * since a user will need to have clicked on a bone (thus selecting it) to make it active
- */
- if (CTX_DATA_COUNT(C, selected_editable_bones) <= 1) {
- /* When only the active bone is selected, and it has a parent,
- * connect it to the parent, as that is the only possible outcome.
- */
- if (actbone->parent) {
- bone_connect_to_existing_parent(actbone);
-
- if ((arm->flag & ARM_MIRROR_EDIT) && (actmirb->parent))
- bone_connect_to_existing_parent(actmirb);
- }
- }
- else {
- /* Parent 'selected' bones to the active one
- * - the context iterator contains both selected bones and their mirrored copies,
- * so we assume that unselected bones are mirrored copies of some selected bone
- * - since the active one (and/or its mirror) will also be selected, we also need
- * to check that we are not trying to operate on them, since such an operation
- * would cause errors
- */
-
- /* parent selected bones to the active one */
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
- {
- if (ELEM(ebone, actbone, actmirb) == 0) {
- if (ebone->flag & BONE_SELECTED)
- bone_connect_to_new_parent(arm->edbo, ebone, actbone, val);
- else
- bone_connect_to_new_parent(arm->edbo, ebone, actmirb, val);
- }
- }
- CTX_DATA_END;
- }
-
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- return OPERATOR_FINISHED;
+ Object *ob = CTX_data_edit_object(C);
+ bArmature *arm = (bArmature *)ob->data;
+ EditBone *actbone = CTX_data_active_bone(C);
+ EditBone *actmirb = NULL;
+ short val = RNA_enum_get(op->ptr, "type");
+
+ /* there must be an active bone */
+ if (actbone == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
+ return OPERATOR_CANCELLED;
+ }
+ else if (arm->flag & ARM_MIRROR_EDIT) {
+ /* For X-Axis Mirror Editing option, we may need a mirror copy of actbone
+ * - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone
+ * (i.e. selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
+ * This is useful for arm-chains, for example parenting lower arm to upper arm
+ * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
+ * then just use actbone. Useful when doing upper arm to spine.
+ */
+ actmirb = ED_armature_ebone_get_mirrored(arm->edbo, actbone);
+ if (actmirb == NULL)
+ actmirb = actbone;
+ }
+
+ /* if there is only 1 selected bone, we assume that that is the active bone,
+ * since a user will need to have clicked on a bone (thus selecting it) to make it active
+ */
+ if (CTX_DATA_COUNT(C, selected_editable_bones) <= 1) {
+ /* When only the active bone is selected, and it has a parent,
+ * connect it to the parent, as that is the only possible outcome.
+ */
+ if (actbone->parent) {
+ bone_connect_to_existing_parent(actbone);
+
+ if ((arm->flag & ARM_MIRROR_EDIT) && (actmirb->parent))
+ bone_connect_to_existing_parent(actmirb);
+ }
+ }
+ else {
+ /* Parent 'selected' bones to the active one
+ * - the context iterator contains both selected bones and their mirrored copies,
+ * so we assume that unselected bones are mirrored copies of some selected bone
+ * - since the active one (and/or its mirror) will also be selected, we also need
+ * to check that we are not trying to operate on them, since such an operation
+ * would cause errors
+ */
+
+ /* parent selected bones to the active one */
+ CTX_DATA_BEGIN (C, EditBone *, ebone, selected_editable_bones) {
+ if (ELEM(ebone, actbone, actmirb) == 0) {
+ if (ebone->flag & BONE_SELECTED)
+ bone_connect_to_new_parent(arm->edbo, ebone, actbone, val);
+ else
+ bone_connect_to_new_parent(arm->edbo, ebone, actmirb, val);
+ }
+ }
+ CTX_DATA_END;
+ }
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ return OPERATOR_FINISHED;
}
-static int armature_parent_set_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
+static int armature_parent_set_invoke(bContext *C,
+ wmOperator *UNUSED(op),
+ const wmEvent *UNUSED(event))
{
- EditBone *actbone = CTX_data_active_bone(C);
- uiPopupMenu *pup = UI_popup_menu_begin(C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Parent"), ICON_NONE);
- uiLayout *layout = UI_popup_menu_layout(pup);
- int allchildbones = 0;
+ EditBone *actbone = CTX_data_active_bone(C);
+ uiPopupMenu *pup = UI_popup_menu_begin(
+ C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Parent"), ICON_NONE);
+ uiLayout *layout = UI_popup_menu_layout(pup);
+ int allchildbones = 0;
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
- {
- if (ebone != actbone) {
- if (ebone->parent != actbone) allchildbones = 1;
- }
- }
- CTX_DATA_END;
+ CTX_DATA_BEGIN (C, EditBone *, ebone, selected_editable_bones) {
+ if (ebone != actbone) {
+ if (ebone->parent != actbone)
+ allchildbones = 1;
+ }
+ }
+ CTX_DATA_END;
- uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_CONNECT);
+ uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_CONNECT);
- /* ob becomes parent, make the associated menus */
- if (allchildbones)
- uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_OFFSET);
+ /* ob becomes parent, make the associated menus */
+ if (allchildbones)
+ uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_OFFSET);
- UI_popup_menu_end(C, pup);
+ UI_popup_menu_end(C, pup);
- return OPERATOR_INTERFACE;
+ return OPERATOR_INTERFACE;
}
void ARMATURE_OT_parent_set(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Make Parent";
- ot->idname = "ARMATURE_OT_parent_set";
- ot->description = "Set the active bone as the parent of the selected bones";
+ /* identifiers */
+ ot->name = "Make Parent";
+ ot->idname = "ARMATURE_OT_parent_set";
+ ot->description = "Set the active bone as the parent of the selected bones";
- /* api callbacks */
- ot->invoke = armature_parent_set_invoke;
- ot->exec = armature_parent_set_exec;
- ot->poll = ED_operator_editarmature;
+ /* api callbacks */
+ ot->invoke = armature_parent_set_invoke;
+ ot->exec = armature_parent_set_exec;
+ ot->poll = ED_operator_editarmature;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_enum(ot->srna, "type", prop_editarm_make_parent_types, 0, "ParentType", "Type of parenting");
+ RNA_def_enum(
+ ot->srna, "type", prop_editarm_make_parent_types, 0, "ParentType", "Type of parenting");
}
-
-
static const EnumPropertyItem prop_editarm_clear_parent_types[] = {
- {1, "CLEAR", 0, "Clear Parent", ""},
- {2, "DISCONNECT", 0, "Disconnect Bone", ""},
- {0, NULL, 0, NULL, NULL},
+ {1, "CLEAR", 0, "Clear Parent", ""},
+ {2, "DISCONNECT", 0, "Disconnect Bone", ""},
+ {0, NULL, 0, NULL, NULL},
};
static void editbone_clear_parent(EditBone *ebone, int mode)
{
- if (ebone->parent) {
- /* for nice selection */
- ebone->parent->flag &= ~(BONE_TIPSEL);
- }
-
- if (mode == 1) ebone->parent = NULL;
- ebone->flag &= ~BONE_CONNECTED;
+ if (ebone->parent) {
+ /* for nice selection */
+ ebone->parent->flag &= ~(BONE_TIPSEL);
+ }
+
+ if (mode == 1)
+ ebone->parent = NULL;
+ ebone->flag &= ~BONE_CONNECTED;
}
static int armature_parent_clear_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const int val = RNA_enum_get(op->ptr, "type");
-
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
- {
- editbone_clear_parent(ebone, val);
- }
- CTX_DATA_END;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- bArmature *arm = ob->data;
- bool changed = false;
-
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_EDITABLE(ebone)) {
- changed = true;
- break;
- }
- }
-
- if (!changed) {
- continue;
- }
-
- ED_armature_edit_sync_selection(arm->edbo);
-
- /* Note, notifier might evolve. */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const int val = RNA_enum_get(op->ptr, "type");
+
+ CTX_DATA_BEGIN (C, EditBone *, ebone, selected_editable_bones) {
+ editbone_clear_parent(ebone, val);
+ }
+ CTX_DATA_END;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bool changed = false;
+
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_EDITABLE(ebone)) {
+ changed = true;
+ break;
+ }
+ }
+
+ if (!changed) {
+ continue;
+ }
+
+ ED_armature_edit_sync_selection(arm->edbo);
+
+ /* Note, notifier might evolve. */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_parent_clear(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Clear Parent";
- ot->idname = "ARMATURE_OT_parent_clear";
- ot->description = "Remove the parent-child relationship between selected bones and their parents";
-
- /* api callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = armature_parent_clear_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- ot->prop = RNA_def_enum(ot->srna, "type", prop_editarm_clear_parent_types, 0, "ClearType", "What way to clear parenting");
+ /* identifiers */
+ ot->name = "Clear Parent";
+ ot->idname = "ARMATURE_OT_parent_clear";
+ ot->description =
+ "Remove the parent-child relationship between selected bones and their parents";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = armature_parent_clear_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna,
+ "type",
+ prop_editarm_clear_parent_types,
+ 0,
+ "ClearType",
+ "What way to clear parenting");
}
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index 4aab80bcbdd..0c493672d9e 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -60,695 +60,713 @@
/* **************** PoseMode & EditMode Selection Buffer Queries *************************** */
-Base *ED_armature_base_and_ebone_from_select_buffer(
- Base **bases, uint bases_len, int hit, EditBone **r_ebone)
+Base *ED_armature_base_and_ebone_from_select_buffer(Base **bases,
+ uint bases_len,
+ int hit,
+ EditBone **r_ebone)
{
- const uint hit_object = hit & 0xFFFF;
- Base *base = NULL;
- EditBone *ebone = NULL;
- /* TODO(campbell): optimize, eg: sort & binary search. */
- for (uint base_index = 0; base_index < bases_len; base_index++) {
- if (bases[base_index]->object->select_id == hit_object) {
- base = bases[base_index];
- break;
- }
- }
- if (base != NULL) {
- const uint hit_bone = (hit & ~BONESEL_ANY) >> 16;
- bArmature *arm = base->object->data;
- ebone = BLI_findlink(arm->edbo, hit_bone);
- }
- *r_ebone = ebone;
- return base;
+ const uint hit_object = hit & 0xFFFF;
+ Base *base = NULL;
+ EditBone *ebone = NULL;
+ /* TODO(campbell): optimize, eg: sort & binary search. */
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ if (bases[base_index]->object->select_id == hit_object) {
+ base = bases[base_index];
+ break;
+ }
+ }
+ if (base != NULL) {
+ const uint hit_bone = (hit & ~BONESEL_ANY) >> 16;
+ bArmature *arm = base->object->data;
+ ebone = BLI_findlink(arm->edbo, hit_bone);
+ }
+ *r_ebone = ebone;
+ return base;
}
-Object *ED_armature_object_and_ebone_from_select_buffer(
- Object **objects, uint objects_len, int hit, EditBone **r_ebone)
+Object *ED_armature_object_and_ebone_from_select_buffer(Object **objects,
+ uint objects_len,
+ int hit,
+ EditBone **r_ebone)
{
- const uint hit_object = hit & 0xFFFF;
- Object *ob = NULL;
- EditBone *ebone = NULL;
- /* TODO(campbell): optimize, eg: sort & binary search. */
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- if (objects[ob_index]->select_id == hit_object) {
- ob = objects[ob_index];
- break;
- }
- }
- if (ob != NULL) {
- const uint hit_bone = (hit & ~BONESEL_ANY) >> 16;
- bArmature *arm = ob->data;
- ebone = BLI_findlink(arm->edbo, hit_bone);
- }
- *r_ebone = ebone;
- return ob;
+ const uint hit_object = hit & 0xFFFF;
+ Object *ob = NULL;
+ EditBone *ebone = NULL;
+ /* TODO(campbell): optimize, eg: sort & binary search. */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ if (objects[ob_index]->select_id == hit_object) {
+ ob = objects[ob_index];
+ break;
+ }
+ }
+ if (ob != NULL) {
+ const uint hit_bone = (hit & ~BONESEL_ANY) >> 16;
+ bArmature *arm = ob->data;
+ ebone = BLI_findlink(arm->edbo, hit_bone);
+ }
+ *r_ebone = ebone;
+ return ob;
}
-Base *ED_armature_base_and_bone_from_select_buffer(
- Base **bases, uint bases_len, int hit, Bone **r_bone)
+Base *ED_armature_base_and_bone_from_select_buffer(Base **bases,
+ uint bases_len,
+ int hit,
+ Bone **r_bone)
{
- const uint hit_object = hit & 0xFFFF;
- Base *base = NULL;
- Bone *bone = NULL;
- /* TODO(campbell): optimize, eg: sort & binary search. */
- for (uint base_index = 0; base_index < bases_len; base_index++) {
- if (bases[base_index]->object->select_id == hit_object) {
- base = bases[base_index];
- break;
- }
- }
- if (base != NULL) {
- if (base->object->pose != NULL) {
- const uint hit_bone = (hit & ~BONESEL_ANY) >> 16;
- bPoseChannel *pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone);
- bone = pchan ? pchan->bone : NULL;
- }
- }
- *r_bone = bone;
- return base;
+ const uint hit_object = hit & 0xFFFF;
+ Base *base = NULL;
+ Bone *bone = NULL;
+ /* TODO(campbell): optimize, eg: sort & binary search. */
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ if (bases[base_index]->object->select_id == hit_object) {
+ base = bases[base_index];
+ break;
+ }
+ }
+ if (base != NULL) {
+ if (base->object->pose != NULL) {
+ const uint hit_bone = (hit & ~BONESEL_ANY) >> 16;
+ bPoseChannel *pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone);
+ bone = pchan ? pchan->bone : NULL;
+ }
+ }
+ *r_bone = bone;
+ return base;
}
/* See if there are any selected bones in this buffer */
/* only bones from base are checked on */
-void *get_bone_from_selectbuffer(
- Base **bases, uint bases_len, bool is_editmode, const unsigned int *buffer, short hits,
- bool findunsel, bool do_nearest, Base **r_base)
+void *get_bone_from_selectbuffer(Base **bases,
+ uint bases_len,
+ bool is_editmode,
+ const unsigned int *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ Base **r_base)
{
- Bone *bone;
- EditBone *ebone;
- void *firstunSel = NULL, *firstSel = NULL, *data;
- Base *firstunSel_base = NULL, *firstSel_base = NULL;
- unsigned int hitresult;
- short i;
- bool takeNext = false;
- int minsel = 0xffffffff, minunsel = 0xffffffff;
-
- for (i = 0; i < hits; i++) {
- hitresult = buffer[3 + (i * 4)];
-
- if (!(hitresult & BONESEL_NOSEL)) {
- if (hitresult & BONESEL_ANY) { /* to avoid including objects in selection */
- Base *base = NULL;
- bool sel;
-
- hitresult &= ~(BONESEL_ANY);
- /* Determine what the current bone is */
- if (is_editmode == false) {
- base = ED_armature_base_and_bone_from_select_buffer(bases, bases_len, hitresult, &bone);
- if (bone != NULL) {
- if (findunsel)
- sel = (bone->flag & BONE_SELECTED);
- else
- sel = !(bone->flag & BONE_SELECTED);
-
- data = bone;
- }
- else {
- data = NULL;
- sel = 0;
- }
- }
- else {
- base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone);
- if (findunsel)
- sel = (ebone->flag & BONE_SELECTED);
- else
- sel = !(ebone->flag & BONE_SELECTED);
-
- data = ebone;
- }
-
- if (data) {
- if (sel) {
- if (do_nearest) {
- if (minsel > buffer[4 * i + 1]) {
- firstSel = data;
- firstSel_base = base;
- minsel = buffer[4 * i + 1];
- }
- }
- else {
- if (!firstSel) {
- firstSel = data;
- firstSel_base = base;
- }
- takeNext = 1;
- }
- }
- else {
- if (do_nearest) {
- if (minunsel > buffer[4 * i + 1]) {
- firstunSel = data;
- firstunSel_base = base;
- minunsel = buffer[4 * i + 1];
- }
- }
- else {
- if (!firstunSel) {
- firstunSel = data;
- firstunSel_base = base;
- }
- if (takeNext) {
- *r_base = base;
- return data;
- }
- }
- }
- }
- }
- }
- }
-
- if (firstunSel) {
- *r_base = firstunSel_base;
- return firstunSel;
- }
- else {
- *r_base = firstSel_base;
- return firstSel;
- }
+ Bone *bone;
+ EditBone *ebone;
+ void *firstunSel = NULL, *firstSel = NULL, *data;
+ Base *firstunSel_base = NULL, *firstSel_base = NULL;
+ unsigned int hitresult;
+ short i;
+ bool takeNext = false;
+ int minsel = 0xffffffff, minunsel = 0xffffffff;
+
+ for (i = 0; i < hits; i++) {
+ hitresult = buffer[3 + (i * 4)];
+
+ if (!(hitresult & BONESEL_NOSEL)) {
+ if (hitresult & BONESEL_ANY) { /* to avoid including objects in selection */
+ Base *base = NULL;
+ bool sel;
+
+ hitresult &= ~(BONESEL_ANY);
+ /* Determine what the current bone is */
+ if (is_editmode == false) {
+ base = ED_armature_base_and_bone_from_select_buffer(bases, bases_len, hitresult, &bone);
+ if (bone != NULL) {
+ if (findunsel)
+ sel = (bone->flag & BONE_SELECTED);
+ else
+ sel = !(bone->flag & BONE_SELECTED);
+
+ data = bone;
+ }
+ else {
+ data = NULL;
+ sel = 0;
+ }
+ }
+ else {
+ base = ED_armature_base_and_ebone_from_select_buffer(
+ bases, bases_len, hitresult, &ebone);
+ if (findunsel)
+ sel = (ebone->flag & BONE_SELECTED);
+ else
+ sel = !(ebone->flag & BONE_SELECTED);
+
+ data = ebone;
+ }
+
+ if (data) {
+ if (sel) {
+ if (do_nearest) {
+ if (minsel > buffer[4 * i + 1]) {
+ firstSel = data;
+ firstSel_base = base;
+ minsel = buffer[4 * i + 1];
+ }
+ }
+ else {
+ if (!firstSel) {
+ firstSel = data;
+ firstSel_base = base;
+ }
+ takeNext = 1;
+ }
+ }
+ else {
+ if (do_nearest) {
+ if (minunsel > buffer[4 * i + 1]) {
+ firstunSel = data;
+ firstunSel_base = base;
+ minunsel = buffer[4 * i + 1];
+ }
+ }
+ else {
+ if (!firstunSel) {
+ firstunSel = data;
+ firstunSel_base = base;
+ }
+ if (takeNext) {
+ *r_base = base;
+ return data;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (firstunSel) {
+ *r_base = firstunSel_base;
+ return firstunSel;
+ }
+ else {
+ *r_base = firstSel_base;
+ return firstSel;
+ }
}
/* used by posemode as well editmode */
/* only checks scene->basact! */
/* x and y are mouse coords (area space) */
-void *get_nearest_bone(
- bContext *C, const int xy[2], bool findunsel,
- Base **r_base)
+void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel, Base **r_base)
{
- ViewContext vc;
- rcti rect;
- unsigned int buffer[MAXPICKBUF];
- short hits;
-
- ED_view3d_viewcontext_init(C, &vc);
-
- // rect.xmin = ... mouseco!
- rect.xmin = rect.xmax = xy[0];
- rect.ymin = rect.ymax = xy[1];
-
- hits = view3d_opengl_select(
- &vc, buffer, MAXPICKBUF, &rect,
- VIEW3D_SELECT_PICK_NEAREST, VIEW3D_SELECT_FILTER_NOP);
-
- *r_base = NULL;
-
- if (hits > 0) {
- uint bases_len = 0;
- Base **bases;
-
- if (vc.obedit != NULL) {
- bases = BKE_view_layer_array_from_bases_in_mode(
- vc.view_layer, vc.v3d, &bases_len, {
- .object_mode = OB_MODE_EDIT,
- });
- }
- else {
- bases = BKE_object_pose_base_array_get(vc.view_layer, vc.v3d, &bases_len);
- }
-
- void *bone = get_bone_from_selectbuffer(
- bases, bases_len, vc.obedit != NULL, buffer, hits, findunsel, true, r_base);
-
- MEM_freeN(bases);
- return bone;
- }
- return NULL;
+ ViewContext vc;
+ rcti rect;
+ unsigned int buffer[MAXPICKBUF];
+ short hits;
+
+ ED_view3d_viewcontext_init(C, &vc);
+
+ // rect.xmin = ... mouseco!
+ rect.xmin = rect.xmax = xy[0];
+ rect.ymin = rect.ymax = xy[1];
+
+ hits = view3d_opengl_select(
+ &vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST, VIEW3D_SELECT_FILTER_NOP);
+
+ *r_base = NULL;
+
+ if (hits > 0) {
+ uint bases_len = 0;
+ Base **bases;
+
+ if (vc.obedit != NULL) {
+ bases = BKE_view_layer_array_from_bases_in_mode(vc.view_layer,
+ vc.v3d,
+ &bases_len,
+ {
+ .object_mode = OB_MODE_EDIT,
+ });
+ }
+ else {
+ bases = BKE_object_pose_base_array_get(vc.view_layer, vc.v3d, &bases_len);
+ }
+
+ void *bone = get_bone_from_selectbuffer(
+ bases, bases_len, vc.obedit != NULL, buffer, hits, findunsel, true, r_base);
+
+ MEM_freeN(bases);
+ return bone;
+ }
+ return NULL;
}
/* **************** EditMode stuff ********************** */
static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- bArmature *arm;
- EditBone *bone, *curBone, *next;
- const bool sel = !RNA_boolean_get(op->ptr, "deselect");
-
- view3d_operator_needs_opengl(C);
-
- Base *base = NULL;
- bone = get_nearest_bone(C, event->mval, true, &base);
-
- if (!bone)
- return OPERATOR_CANCELLED;
-
- arm = base->object->data;
-
- /* Select parents */
- for (curBone = bone; curBone; curBone = next) {
- if ((curBone->flag & BONE_UNSELECTABLE) == 0) {
- if (sel) {
- curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else {
- curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- }
-
- if (curBone->flag & BONE_CONNECTED)
- next = curBone->parent;
- else
- next = NULL;
- }
-
- /* Select children */
- while (bone) {
- for (curBone = arm->edbo->first; curBone; curBone = next) {
- next = curBone->next;
- if ((curBone->parent == bone) && (curBone->flag & BONE_UNSELECTABLE) == 0) {
- if (curBone->flag & BONE_CONNECTED) {
- if (sel) {
- curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else {
- curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- bone = curBone;
- break;
- }
- else {
- bone = NULL;
- break;
- }
- }
- }
- if (!curBone)
- bone = NULL;
- }
-
- ED_armature_edit_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object);
-
- return OPERATOR_FINISHED;
+ bArmature *arm;
+ EditBone *bone, *curBone, *next;
+ const bool sel = !RNA_boolean_get(op->ptr, "deselect");
+
+ view3d_operator_needs_opengl(C);
+
+ Base *base = NULL;
+ bone = get_nearest_bone(C, event->mval, true, &base);
+
+ if (!bone)
+ return OPERATOR_CANCELLED;
+
+ arm = base->object->data;
+
+ /* Select parents */
+ for (curBone = bone; curBone; curBone = next) {
+ if ((curBone->flag & BONE_UNSELECTABLE) == 0) {
+ if (sel) {
+ curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else {
+ curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+
+ if (curBone->flag & BONE_CONNECTED)
+ next = curBone->parent;
+ else
+ next = NULL;
+ }
+
+ /* Select children */
+ while (bone) {
+ for (curBone = arm->edbo->first; curBone; curBone = next) {
+ next = curBone->next;
+ if ((curBone->parent == bone) && (curBone->flag & BONE_UNSELECTABLE) == 0) {
+ if (curBone->flag & BONE_CONNECTED) {
+ if (sel) {
+ curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else {
+ curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ bone = curBone;
+ break;
+ }
+ else {
+ bone = NULL;
+ break;
+ }
+ }
+ }
+ if (!curBone)
+ bone = NULL;
+ }
+
+ ED_armature_edit_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object);
+
+ return OPERATOR_FINISHED;
}
static bool armature_select_linked_poll(bContext *C)
{
- return (ED_operator_view3d_active(C) && ED_operator_editarmature(C));
+ return (ED_operator_view3d_active(C) && ED_operator_editarmature(C));
}
void ARMATURE_OT_select_linked(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select Connected";
- ot->idname = "ARMATURE_OT_select_linked";
- ot->description = "Select bones related to selected ones by parent/child relationships";
+ /* identifiers */
+ ot->name = "Select Connected";
+ ot->idname = "ARMATURE_OT_select_linked";
+ ot->description = "Select bones related to selected ones by parent/child relationships";
- /* api callbacks */
- /* leave 'exec' unset */
- ot->invoke = armature_select_linked_invoke;
- ot->poll = armature_select_linked_poll;
+ /* api callbacks */
+ /* leave 'exec' unset */
+ ot->invoke = armature_select_linked_invoke;
+ ot->poll = armature_select_linked_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
+ RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
}
/* utility function for get_nearest_editbonepoint */
static int selectbuffer_ret_hits_12(unsigned int *UNUSED(buffer), const int hits12)
{
- return hits12;
+ return hits12;
}
static int selectbuffer_ret_hits_5(unsigned int *buffer, const int hits12, const int hits5)
{
- const int offs = 4 * hits12;
- memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(unsigned int));
- return hits5;
+ const int offs = 4 * hits12;
+ memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(unsigned int));
+ return hits5;
}
/* does bones and points */
/* note that BONE ROOT only gets drawn for root bones (or without IK) */
static EditBone *get_nearest_editbonepoint(
- ViewContext *vc,
- bool findunsel, bool use_cycle,
- Base **r_base, int *r_selmask)
+ ViewContext *vc, bool findunsel, bool use_cycle, Base **r_base, int *r_selmask)
{
- uint buffer[MAXPICKBUF];
- struct {
- uint hitresult;
- Base *base;
- EditBone *ebone;
- } best = {
- .hitresult = BONESEL_NOSEL,
- .base = NULL,
- .ebone = NULL,
- };
-
- /* find the bone after the current active bone, so as to bump up its chances in selection.
- * this way overlapping bones will cycle selection state as with objects. */
- EditBone *ebone_next_act = ((bArmature *)vc->obedit->data)->act_edbone;
- {
- bArmature *arm = (bArmature *)vc->obedit->data;
- if (ebone_next_act &&
- EBONE_VISIBLE(arm, ebone_next_act) &&
- ebone_next_act->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL))
- {
- ebone_next_act = ebone_next_act->next ? ebone_next_act->next : arm->edbo->first;
- }
- else {
- ebone_next_act = NULL;
- }
- }
-
- bool do_nearest = false;
-
- /* define if we use solid nearest select or not */
- if (use_cycle) {
- static int last_mval[2] = {-100, -100};
-
- if (!XRAY_ACTIVE(vc->v3d)) {
- do_nearest = true;
- if (len_manhattan_v2v2_int(vc->mval, last_mval) <= WM_EVENT_CURSOR_MOTION_THRESHOLD) {
- do_nearest = false;
- }
- }
- copy_v2_v2_int(last_mval, vc->mval);
- }
- else {
- if (!XRAY_ACTIVE(vc->v3d)) {
- do_nearest = true;
- }
- }
-
- /* matching logic from 'mixed_bones_object_selectbuffer' */
- int hits = 0;
-
- /* we _must_ end cache before return, use 'goto cache_end' */
- view3d_opengl_select_cache_begin();
-
- {
- const int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL);
- const eV3DSelectObjectFilter select_filter = VIEW3D_SELECT_FILTER_NOP;
-
- rcti rect;
- BLI_rcti_init_pt_radius(&rect, vc->mval, 12);
- const int hits12 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode, select_filter);
- if (hits12 == 1) {
- hits = selectbuffer_ret_hits_12(buffer, hits12);
- goto cache_end;
- }
- else if (hits12 > 0) {
- int offs;
-
- offs = 4 * hits12;
- BLI_rcti_init_pt_radius(&rect, vc->mval, 5);
- const int hits5 = view3d_opengl_select(
- vc, buffer + offs, MAXPICKBUF - offs, &rect,
- select_mode, select_filter);
-
- if (hits5 == 1) {
- hits = selectbuffer_ret_hits_5(buffer, hits12, hits5);
- goto cache_end;
- }
-
- if (hits5 > 0) { hits = selectbuffer_ret_hits_5(buffer, hits12, hits5); goto cache_end; }
- else { hits = selectbuffer_ret_hits_12(buffer, hits12); goto cache_end; }
- }
- }
+ uint buffer[MAXPICKBUF];
+ struct {
+ uint hitresult;
+ Base *base;
+ EditBone *ebone;
+ } best = {
+ .hitresult = BONESEL_NOSEL,
+ .base = NULL,
+ .ebone = NULL,
+ };
+
+ /* find the bone after the current active bone, so as to bump up its chances in selection.
+ * this way overlapping bones will cycle selection state as with objects. */
+ EditBone *ebone_next_act = ((bArmature *)vc->obedit->data)->act_edbone;
+ {
+ bArmature *arm = (bArmature *)vc->obedit->data;
+ if (ebone_next_act && EBONE_VISIBLE(arm, ebone_next_act) &&
+ ebone_next_act->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) {
+ ebone_next_act = ebone_next_act->next ? ebone_next_act->next : arm->edbo->first;
+ }
+ else {
+ ebone_next_act = NULL;
+ }
+ }
+
+ bool do_nearest = false;
+
+ /* define if we use solid nearest select or not */
+ if (use_cycle) {
+ static int last_mval[2] = {-100, -100};
+
+ if (!XRAY_ACTIVE(vc->v3d)) {
+ do_nearest = true;
+ if (len_manhattan_v2v2_int(vc->mval, last_mval) <= WM_EVENT_CURSOR_MOTION_THRESHOLD) {
+ do_nearest = false;
+ }
+ }
+ copy_v2_v2_int(last_mval, vc->mval);
+ }
+ else {
+ if (!XRAY_ACTIVE(vc->v3d)) {
+ do_nearest = true;
+ }
+ }
+
+ /* matching logic from 'mixed_bones_object_selectbuffer' */
+ int hits = 0;
+
+ /* we _must_ end cache before return, use 'goto cache_end' */
+ view3d_opengl_select_cache_begin();
+
+ {
+ const int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL);
+ const eV3DSelectObjectFilter select_filter = VIEW3D_SELECT_FILTER_NOP;
+
+ rcti rect;
+ BLI_rcti_init_pt_radius(&rect, vc->mval, 12);
+ const int hits12 = view3d_opengl_select(
+ vc, buffer, MAXPICKBUF, &rect, select_mode, select_filter);
+ if (hits12 == 1) {
+ hits = selectbuffer_ret_hits_12(buffer, hits12);
+ goto cache_end;
+ }
+ else if (hits12 > 0) {
+ int offs;
+
+ offs = 4 * hits12;
+ BLI_rcti_init_pt_radius(&rect, vc->mval, 5);
+ const int hits5 = view3d_opengl_select(
+ vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode, select_filter);
+
+ if (hits5 == 1) {
+ hits = selectbuffer_ret_hits_5(buffer, hits12, hits5);
+ goto cache_end;
+ }
+
+ if (hits5 > 0) {
+ hits = selectbuffer_ret_hits_5(buffer, hits12, hits5);
+ goto cache_end;
+ }
+ else {
+ hits = selectbuffer_ret_hits_12(buffer, hits12);
+ goto cache_end;
+ }
+ }
+ }
cache_end:
- view3d_opengl_select_cache_end();
-
- uint bases_len;
- Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(vc->view_layer, vc->v3d, &bases_len);
-
- /* See if there are any selected bones in this group */
- if (hits > 0) {
- if (hits == 1) {
- if (!(buffer[3] & BONESEL_NOSEL)) {
- best.hitresult = buffer[3];
- best.base = ED_armature_base_and_ebone_from_select_buffer(
- bases, bases_len, best.hitresult, &best.ebone);
- }
- }
- else {
- int dep_min = 5;
- for (int i = 0; i < hits; i++) {
- const uint hitresult = buffer[3 + (i * 4)];
- if (!(hitresult & BONESEL_NOSEL)) {
- Base *base = NULL;
- EditBone *ebone;
- base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone);
- /* If this fails, selection code is setting the selection ID's incorrectly. */
- BLI_assert(base && ebone);
-
- int dep;
- /* clicks on bone points get advantage */
- if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) {
- /* but also the unselected one */
- if (findunsel) {
- if ( (hitresult & BONESEL_ROOT) && (ebone->flag & BONE_ROOTSEL) == 0)
- dep = 1;
- else if ( (hitresult & BONESEL_TIP) && (ebone->flag & BONE_TIPSEL) == 0)
- dep = 1;
- else
- dep = 2;
- }
- else {
- dep = 1;
- }
- }
- else {
- /* bone found */
- if (findunsel) {
- if ((ebone->flag & BONE_SELECTED) == 0)
- dep = 3;
- else
- dep = 4;
- }
- else {
- dep = 3;
- }
- }
-
- if (ebone == ebone_next_act) {
- dep -= 1;
- }
-
- if (dep < dep_min) {
- dep_min = dep;
- best.hitresult = hitresult;
- best.base = base;
- best.ebone = ebone;
- }
- }
- }
- }
-
- if (!(best.hitresult & BONESEL_NOSEL)) {
- *r_base = best.base;
-
- *r_selmask = 0;
- if (best.hitresult & BONESEL_ROOT) {
- *r_selmask |= BONE_ROOTSEL;
- }
- if (best.hitresult & BONESEL_TIP) {
- *r_selmask |= BONE_TIPSEL;
- }
- if (best.hitresult & BONESEL_BONE) {
- *r_selmask |= BONE_SELECTED;
- }
- MEM_freeN(bases);
- return best.ebone;
- }
- }
- *r_selmask = 0;
- *r_base = NULL;
- MEM_freeN(bases);
- return NULL;
+ view3d_opengl_select_cache_end();
+
+ uint bases_len;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
+ vc->view_layer, vc->v3d, &bases_len);
+
+ /* See if there are any selected bones in this group */
+ if (hits > 0) {
+ if (hits == 1) {
+ if (!(buffer[3] & BONESEL_NOSEL)) {
+ best.hitresult = buffer[3];
+ best.base = ED_armature_base_and_ebone_from_select_buffer(
+ bases, bases_len, best.hitresult, &best.ebone);
+ }
+ }
+ else {
+ int dep_min = 5;
+ for (int i = 0; i < hits; i++) {
+ const uint hitresult = buffer[3 + (i * 4)];
+ if (!(hitresult & BONESEL_NOSEL)) {
+ Base *base = NULL;
+ EditBone *ebone;
+ base = ED_armature_base_and_ebone_from_select_buffer(
+ bases, bases_len, hitresult, &ebone);
+ /* If this fails, selection code is setting the selection ID's incorrectly. */
+ BLI_assert(base && ebone);
+
+ int dep;
+ /* clicks on bone points get advantage */
+ if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) {
+ /* but also the unselected one */
+ if (findunsel) {
+ if ((hitresult & BONESEL_ROOT) && (ebone->flag & BONE_ROOTSEL) == 0)
+ dep = 1;
+ else if ((hitresult & BONESEL_TIP) && (ebone->flag & BONE_TIPSEL) == 0)
+ dep = 1;
+ else
+ dep = 2;
+ }
+ else {
+ dep = 1;
+ }
+ }
+ else {
+ /* bone found */
+ if (findunsel) {
+ if ((ebone->flag & BONE_SELECTED) == 0)
+ dep = 3;
+ else
+ dep = 4;
+ }
+ else {
+ dep = 3;
+ }
+ }
+
+ if (ebone == ebone_next_act) {
+ dep -= 1;
+ }
+
+ if (dep < dep_min) {
+ dep_min = dep;
+ best.hitresult = hitresult;
+ best.base = base;
+ best.ebone = ebone;
+ }
+ }
+ }
+ }
+
+ if (!(best.hitresult & BONESEL_NOSEL)) {
+ *r_base = best.base;
+
+ *r_selmask = 0;
+ if (best.hitresult & BONESEL_ROOT) {
+ *r_selmask |= BONE_ROOTSEL;
+ }
+ if (best.hitresult & BONESEL_TIP) {
+ *r_selmask |= BONE_TIPSEL;
+ }
+ if (best.hitresult & BONESEL_BONE) {
+ *r_selmask |= BONE_SELECTED;
+ }
+ MEM_freeN(bases);
+ return best.ebone;
+ }
+ }
+ *r_selmask = 0;
+ *r_base = NULL;
+ MEM_freeN(bases);
+ return NULL;
}
bool ED_armature_edit_deselect_all(Object *obedit)
{
- bArmature *arm = obedit->data;
- bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
- ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- changed = true;
- }
- }
- return changed;
+ bArmature *arm = obedit->data;
+ bool changed = false;
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
+ ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ changed = true;
+ }
+ }
+ return changed;
}
bool ED_armature_edit_deselect_all_visible(Object *obedit)
{
- bArmature *arm = obedit->data;
- bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- /* first and foremost, bone must be visible and selected */
- if (EBONE_VISIBLE(arm, ebone)) {
- if (ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
- ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- changed = true;
- }
- }
- }
-
- if (changed) {
- ED_armature_edit_sync_selection(arm->edbo);
- }
- return changed;
+ bArmature *arm = obedit->data;
+ bool changed = false;
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ /* first and foremost, bone must be visible and selected */
+ if (EBONE_VISIBLE(arm, ebone)) {
+ if (ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
+ ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ changed = true;
+ }
+ }
+ }
+
+ if (changed) {
+ ED_armature_edit_sync_selection(arm->edbo);
+ }
+ return changed;
}
-
bool ED_armature_edit_deselect_all_multi_ex(struct Base **bases, uint bases_len)
{
- bool changed_multi = false;
- for (uint base_index = 0; base_index < bases_len; base_index++) {
- Object *obedit = bases[base_index]->object;
- changed_multi |= ED_armature_edit_deselect_all(obedit);
- }
- return changed_multi;
+ bool changed_multi = false;
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Object *obedit = bases[base_index]->object;
+ changed_multi |= ED_armature_edit_deselect_all(obedit);
+ }
+ return changed_multi;
}
bool ED_armature_edit_deselect_all_visible_multi_ex(struct Base **bases, uint bases_len)
{
- bool changed_multi = false;
- for (uint base_index = 0; base_index < bases_len; base_index++) {
- Object *obedit = bases[base_index]->object;
- changed_multi |= ED_armature_edit_deselect_all_visible(obedit);
- }
- return changed_multi;
+ bool changed_multi = false;
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Object *obedit = bases[base_index]->object;
+ changed_multi |= ED_armature_edit_deselect_all_visible(obedit);
+ }
+ return changed_multi;
}
bool ED_armature_edit_deselect_all_visible_multi(bContext *C)
{
- ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
- uint bases_len = 0;
- Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(vc.view_layer, vc.v3d, &bases_len);
- bool changed_multi = ED_armature_edit_deselect_all_multi_ex(bases, bases_len);
- MEM_freeN(bases);
- return changed_multi;
+ ViewContext vc;
+ ED_view3d_viewcontext_init(C, &vc);
+ uint bases_len = 0;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
+ vc.view_layer, vc.v3d, &bases_len);
+ bool changed_multi = ED_armature_edit_deselect_all_multi_ex(bases, bases_len);
+ MEM_freeN(bases);
+ return changed_multi;
}
/* accounts for connected parents */
static int ebone_select_flag(EditBone *ebone)
{
- if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
- return ((ebone->parent->flag & BONE_TIPSEL) ? BONE_ROOTSEL : 0) | (ebone->flag & (BONE_SELECTED | BONE_TIPSEL));
- }
- else {
- return ebone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
- }
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ return ((ebone->parent->flag & BONE_TIPSEL) ? BONE_ROOTSEL : 0) |
+ (ebone->flag & (BONE_SELECTED | BONE_TIPSEL));
+ }
+ else {
+ return ebone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+ }
}
/* context: editmode armature in view3d */
-bool ED_armature_edit_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
+bool ED_armature_edit_select_pick(
+ bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
- ViewContext vc;
- EditBone *nearBone = NULL;
- int selmask;
- Base *basact = NULL;
-
- ED_view3d_viewcontext_init(C, &vc);
- vc.mval[0] = mval[0];
- vc.mval[1] = mval[1];
-
- nearBone = get_nearest_editbonepoint(&vc, true, true, &basact, &selmask);
- if (nearBone) {
- ED_view3d_viewcontext_init_object(&vc, basact->object);
- bArmature *arm = vc.obedit->data;
-
- if (!EBONE_SELECTABLE(arm, nearBone)) {
- return false;
- }
-
- if (!extend && !deselect && !toggle) {
- uint bases_len = 0;
- Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(vc.view_layer, vc.v3d, &bases_len);
- ED_armature_edit_deselect_all_multi_ex(bases, bases_len);
- MEM_freeN(bases);
- }
-
- /* by definition the non-root connected bones have no root point drawn,
- * so a root selection needs to be delivered to the parent tip */
-
- if (selmask & BONE_SELECTED) {
- if (nearBone->parent && (nearBone->flag & BONE_CONNECTED)) {
- /* click in a chain */
- if (extend) {
- /* select this bone */
- nearBone->flag |= BONE_TIPSEL;
- nearBone->parent->flag |= BONE_TIPSEL;
- }
- else if (deselect) {
- /* deselect this bone */
- nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
- /* only deselect parent tip if it is not selected */
- if (!(nearBone->parent->flag & BONE_SELECTED))
- nearBone->parent->flag &= ~BONE_TIPSEL;
- }
- else if (toggle) {
- /* hold shift inverts this bone's selection */
- if (nearBone->flag & BONE_SELECTED) {
- /* deselect this bone */
- nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
- /* only deselect parent tip if it is not selected */
- if (!(nearBone->parent->flag & BONE_SELECTED))
- nearBone->parent->flag &= ~BONE_TIPSEL;
- }
- else {
- /* select this bone */
- nearBone->flag |= BONE_TIPSEL;
- nearBone->parent->flag |= BONE_TIPSEL;
- }
- }
- else {
- /* select this bone */
- nearBone->flag |= BONE_TIPSEL;
- nearBone->parent->flag |= BONE_TIPSEL;
- }
- }
- else {
- if (extend) {
- nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
- }
- else if (deselect) {
- nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
- }
- else if (toggle) {
- /* hold shift inverts this bone's selection */
- if (nearBone->flag & BONE_SELECTED)
- nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
- else
- nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
- }
- else
- nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
- }
- }
- else {
- if (extend)
- nearBone->flag |= selmask;
- else if (deselect)
- nearBone->flag &= ~selmask;
- else if (toggle && (nearBone->flag & selmask))
- nearBone->flag &= ~selmask;
- else
- nearBone->flag |= selmask;
- }
-
- ED_armature_edit_sync_selection(arm->edbo);
-
- /* then now check for active status */
- if (ebone_select_flag(nearBone)) {
- arm->act_edbone = nearBone;
- }
-
- if (vc.view_layer->basact != basact) {
- ED_object_base_activate(C, basact);
- }
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object);
- return true;
- }
-
- return false;
+ ViewContext vc;
+ EditBone *nearBone = NULL;
+ int selmask;
+ Base *basact = NULL;
+
+ ED_view3d_viewcontext_init(C, &vc);
+ vc.mval[0] = mval[0];
+ vc.mval[1] = mval[1];
+
+ nearBone = get_nearest_editbonepoint(&vc, true, true, &basact, &selmask);
+ if (nearBone) {
+ ED_view3d_viewcontext_init_object(&vc, basact->object);
+ bArmature *arm = vc.obedit->data;
+
+ if (!EBONE_SELECTABLE(arm, nearBone)) {
+ return false;
+ }
+
+ if (!extend && !deselect && !toggle) {
+ uint bases_len = 0;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
+ vc.view_layer, vc.v3d, &bases_len);
+ ED_armature_edit_deselect_all_multi_ex(bases, bases_len);
+ MEM_freeN(bases);
+ }
+
+ /* by definition the non-root connected bones have no root point drawn,
+ * so a root selection needs to be delivered to the parent tip */
+
+ if (selmask & BONE_SELECTED) {
+ if (nearBone->parent && (nearBone->flag & BONE_CONNECTED)) {
+ /* click in a chain */
+ if (extend) {
+ /* select this bone */
+ nearBone->flag |= BONE_TIPSEL;
+ nearBone->parent->flag |= BONE_TIPSEL;
+ }
+ else if (deselect) {
+ /* deselect this bone */
+ nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
+ /* only deselect parent tip if it is not selected */
+ if (!(nearBone->parent->flag & BONE_SELECTED))
+ nearBone->parent->flag &= ~BONE_TIPSEL;
+ }
+ else if (toggle) {
+ /* hold shift inverts this bone's selection */
+ if (nearBone->flag & BONE_SELECTED) {
+ /* deselect this bone */
+ nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
+ /* only deselect parent tip if it is not selected */
+ if (!(nearBone->parent->flag & BONE_SELECTED))
+ nearBone->parent->flag &= ~BONE_TIPSEL;
+ }
+ else {
+ /* select this bone */
+ nearBone->flag |= BONE_TIPSEL;
+ nearBone->parent->flag |= BONE_TIPSEL;
+ }
+ }
+ else {
+ /* select this bone */
+ nearBone->flag |= BONE_TIPSEL;
+ nearBone->parent->flag |= BONE_TIPSEL;
+ }
+ }
+ else {
+ if (extend) {
+ nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else if (deselect) {
+ nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else if (toggle) {
+ /* hold shift inverts this bone's selection */
+ if (nearBone->flag & BONE_SELECTED)
+ nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
+ else
+ nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else
+ nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+ else {
+ if (extend)
+ nearBone->flag |= selmask;
+ else if (deselect)
+ nearBone->flag &= ~selmask;
+ else if (toggle && (nearBone->flag & selmask))
+ nearBone->flag &= ~selmask;
+ else
+ nearBone->flag |= selmask;
+ }
+
+ ED_armature_edit_sync_selection(arm->edbo);
+
+ /* then now check for active status */
+ if (ebone_select_flag(nearBone)) {
+ arm->act_edbone = nearBone;
+ }
+
+ if (vc.view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object);
+ return true;
+ }
+
+ return false;
}
/* -------------------------------------------------------------------- */
@@ -757,69 +775,73 @@ bool ED_armature_edit_select_pick(bContext *C, const int mval[2], bool extend, b
* Implements #ED_armature_edit_select_op_from_tagged
* \{ */
-static bool armature_edit_select_op_apply(
- bArmature *arm, EditBone *ebone, const eSelectOp sel_op, int is_ignore_flag, int is_inside_flag)
+static bool armature_edit_select_op_apply(bArmature *arm,
+ EditBone *ebone,
+ const eSelectOp sel_op,
+ int is_ignore_flag,
+ int is_inside_flag)
{
- BLI_assert(!(is_ignore_flag & ~(BONESEL_ROOT | BONESEL_TIP)));
- BLI_assert(!(is_inside_flag & ~(BONESEL_ROOT | BONESEL_TIP | BONESEL_BONE)));
- BLI_assert(EBONE_VISIBLE(arm, ebone));
- bool changed = false;
- bool is_point_done = false;
- int points_proj_tot = 0;
- BLI_assert(ebone->flag == ebone->temp.i);
- const int ebone_flag_prev = ebone->flag;
-
- if ((is_ignore_flag & BONE_ROOTSEL) == 0) {
- points_proj_tot++;
- const bool is_select = ebone->flag & BONE_ROOTSEL;
- const bool is_inside = is_inside_flag & BONESEL_ROOT;
- const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
- if (sel_op_result != -1) {
- if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) {
- SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_ROOTSEL);
- }
- }
- is_point_done |= is_inside;
- }
-
- if ((is_ignore_flag & BONE_TIPSEL) == 0) {
- points_proj_tot++;
- const bool is_select = ebone->flag & BONE_TIPSEL;
- const bool is_inside = is_inside_flag & BONESEL_TIP;
- const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
- if (sel_op_result != -1) {
- if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) {
- SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_TIPSEL);
- }
- }
- is_point_done |= is_inside;
- }
-
- /* if one of points selected, we skip the bone itself */
- if ((is_point_done == false) && (points_proj_tot == 2)) {
- const bool is_select = ebone->flag & BONE_SELECTED;
- {
- const bool is_inside = is_inside_flag & BONESEL_BONE;
- const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
- if (sel_op_result != -1) {
- if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) {
- SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
- }
- }
- }
-
- changed = true;
- }
- changed |= is_point_done;
-
- if (ebone_flag_prev != ebone->flag) {
- ebone->temp.i = ebone->flag;
- ebone->flag = ebone_flag_prev;
- ebone->flag = ebone_flag_prev | BONE_DONE;
- changed = true;
- }
-
- return changed;
+ BLI_assert(!(is_ignore_flag & ~(BONESEL_ROOT | BONESEL_TIP)));
+ BLI_assert(!(is_inside_flag & ~(BONESEL_ROOT | BONESEL_TIP | BONESEL_BONE)));
+ BLI_assert(EBONE_VISIBLE(arm, ebone));
+ bool changed = false;
+ bool is_point_done = false;
+ int points_proj_tot = 0;
+ BLI_assert(ebone->flag == ebone->temp.i);
+ const int ebone_flag_prev = ebone->flag;
+
+ if ((is_ignore_flag & BONE_ROOTSEL) == 0) {
+ points_proj_tot++;
+ const bool is_select = ebone->flag & BONE_ROOTSEL;
+ const bool is_inside = is_inside_flag & BONESEL_ROOT;
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) {
+ SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_ROOTSEL);
+ }
+ }
+ is_point_done |= is_inside;
+ }
+
+ if ((is_ignore_flag & BONE_TIPSEL) == 0) {
+ points_proj_tot++;
+ const bool is_select = ebone->flag & BONE_TIPSEL;
+ const bool is_inside = is_inside_flag & BONESEL_TIP;
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) {
+ SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_TIPSEL);
+ }
+ }
+ is_point_done |= is_inside;
+ }
+
+ /* if one of points selected, we skip the bone itself */
+ if ((is_point_done == false) && (points_proj_tot == 2)) {
+ const bool is_select = ebone->flag & BONE_SELECTED;
+ {
+ const bool is_inside = is_inside_flag & BONESEL_BONE;
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) {
+ SET_FLAG_FROM_TEST(
+ ebone->flag, sel_op_result, BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+ }
+ }
+ }
+
+ changed = true;
+ }
+ changed |= is_point_done;
+
+ if (ebone_flag_prev != ebone->flag) {
+ ebone->temp.i = ebone->flag;
+ ebone->flag = ebone_flag_prev;
+ ebone->flag = ebone_flag_prev | BONE_DONE;
+ changed = true;
+ }
+
+ return changed;
}
/**
@@ -836,101 +858,97 @@ static bool armature_edit_select_op_apply(
*/
bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
{
- bool changed = false;
-
- /* Initialize flags. */
- {
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
-
- /* Flush the parent flag to this bone
- * so we don't need to check the parent when adjusting the selection. */
- if ((ebone->flag & BONE_CONNECTED) && ebone->parent) {
- if (ebone->parent->flag & BONE_TIPSEL) {
- ebone->flag |= BONE_ROOTSEL;
- }
- else {
- ebone->flag &= ~BONE_ROOTSEL;
- }
-
- /* Flush the 'temp.i' flag. */
- if (ebone->parent->temp.i & BONESEL_TIP) {
- ebone->temp.i |= BONESEL_ROOT;
- }
- }
- ebone->flag &= ~BONE_DONE;
- }
- }
-
- /* Apply selection from bone selection flags. */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (ebone->temp.i != 0) {
- int is_ignore_flag = ((ebone->temp.i << 16) & (BONESEL_ROOT | BONESEL_TIP));
- int is_inside_flag = (ebone->temp.i & (BONESEL_ROOT | BONESEL_TIP | BONESEL_BONE));
-
- /* Use as previous bone flag from now on. */
- ebone->temp.i = ebone->flag;
-
- /* When there is a partial selection without both endpoints, only select an endpoint. */
- if ((is_inside_flag & BONESEL_BONE) &&
- (is_inside_flag & (BONESEL_ROOT | BONESEL_TIP)) &&
- ((is_inside_flag & (BONESEL_ROOT | BONESEL_TIP)) != (BONESEL_ROOT | BONESEL_TIP)))
- {
- is_inside_flag &= ~BONESEL_BONE;
- }
-
- changed |= armature_edit_select_op_apply(arm, ebone, sel_op, is_ignore_flag, is_inside_flag);
- }
- }
-
- if (changed) {
- /* Cleanup flags. */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (ebone->flag & BONE_DONE) {
- SWAP(int, ebone->temp.i, ebone->flag);
- ebone->flag |= BONE_DONE;
- if ((ebone->flag & BONE_CONNECTED) && ebone->parent) {
- if ((ebone->parent->flag & BONE_DONE) == 0) {
- /* Checked below. */
- ebone->parent->temp.i = ebone->parent->flag;
- }
- }
- }
- }
-
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (ebone->flag & BONE_DONE) {
- if ((ebone->flag & BONE_CONNECTED) && ebone->parent) {
- bool is_parent_tip_changed = (ebone->parent->flag & BONE_TIPSEL) != (ebone->parent->temp.i & BONE_TIPSEL);
- if ((ebone->temp.i & BONE_ROOTSEL) == 0) {
- if ((ebone->flag & BONE_ROOTSEL) != 0) {
- ebone->parent->flag |= BONE_TIPSEL;
- }
- }
- else {
- if ((ebone->flag & BONE_ROOTSEL) == 0) {
- ebone->parent->flag &= ~BONE_TIPSEL;
-
- }
- }
-
-
- if (is_parent_tip_changed == false) {
- /* Keep tip selected if the parent remains selected. */
- if (ebone->parent->flag & BONE_SELECTED) {
- ebone->parent->flag |= BONE_TIPSEL;
- }
- }
-
- }
- ebone->flag &= ~BONE_DONE;
- }
- }
-
- ED_armature_edit_sync_selection(arm->edbo);
- ED_armature_edit_validate_active(arm);
- }
-
- return changed;
+ bool changed = false;
+
+ /* Initialize flags. */
+ {
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+
+ /* Flush the parent flag to this bone
+ * so we don't need to check the parent when adjusting the selection. */
+ if ((ebone->flag & BONE_CONNECTED) && ebone->parent) {
+ if (ebone->parent->flag & BONE_TIPSEL) {
+ ebone->flag |= BONE_ROOTSEL;
+ }
+ else {
+ ebone->flag &= ~BONE_ROOTSEL;
+ }
+
+ /* Flush the 'temp.i' flag. */
+ if (ebone->parent->temp.i & BONESEL_TIP) {
+ ebone->temp.i |= BONESEL_ROOT;
+ }
+ }
+ ebone->flag &= ~BONE_DONE;
+ }
+ }
+
+ /* Apply selection from bone selection flags. */
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->temp.i != 0) {
+ int is_ignore_flag = ((ebone->temp.i << 16) & (BONESEL_ROOT | BONESEL_TIP));
+ int is_inside_flag = (ebone->temp.i & (BONESEL_ROOT | BONESEL_TIP | BONESEL_BONE));
+
+ /* Use as previous bone flag from now on. */
+ ebone->temp.i = ebone->flag;
+
+ /* When there is a partial selection without both endpoints, only select an endpoint. */
+ if ((is_inside_flag & BONESEL_BONE) && (is_inside_flag & (BONESEL_ROOT | BONESEL_TIP)) &&
+ ((is_inside_flag & (BONESEL_ROOT | BONESEL_TIP)) != (BONESEL_ROOT | BONESEL_TIP))) {
+ is_inside_flag &= ~BONESEL_BONE;
+ }
+
+ changed |= armature_edit_select_op_apply(arm, ebone, sel_op, is_ignore_flag, is_inside_flag);
+ }
+ }
+
+ if (changed) {
+ /* Cleanup flags. */
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->flag & BONE_DONE) {
+ SWAP(int, ebone->temp.i, ebone->flag);
+ ebone->flag |= BONE_DONE;
+ if ((ebone->flag & BONE_CONNECTED) && ebone->parent) {
+ if ((ebone->parent->flag & BONE_DONE) == 0) {
+ /* Checked below. */
+ ebone->parent->temp.i = ebone->parent->flag;
+ }
+ }
+ }
+ }
+
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->flag & BONE_DONE) {
+ if ((ebone->flag & BONE_CONNECTED) && ebone->parent) {
+ bool is_parent_tip_changed = (ebone->parent->flag & BONE_TIPSEL) !=
+ (ebone->parent->temp.i & BONE_TIPSEL);
+ if ((ebone->temp.i & BONE_ROOTSEL) == 0) {
+ if ((ebone->flag & BONE_ROOTSEL) != 0) {
+ ebone->parent->flag |= BONE_TIPSEL;
+ }
+ }
+ else {
+ if ((ebone->flag & BONE_ROOTSEL) == 0) {
+ ebone->parent->flag &= ~BONE_TIPSEL;
+ }
+ }
+
+ if (is_parent_tip_changed == false) {
+ /* Keep tip selected if the parent remains selected. */
+ if (ebone->parent->flag & BONE_SELECTED) {
+ ebone->parent->flag |= BONE_TIPSEL;
+ }
+ }
+ }
+ ebone->flag &= ~BONE_DONE;
+ }
+ }
+
+ ED_armature_edit_sync_selection(arm->edbo);
+ ED_armature_edit_validate_active(arm);
+ }
+
+ return changed;
}
/** \} */
@@ -939,613 +957,612 @@ bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
static int armature_de_select_all_exec(bContext *C, wmOperator *op)
{
- int action = RNA_enum_get(op->ptr, "action");
-
- if (action == SEL_TOGGLE) {
- /* Determine if there are any selected bones
- * And therefore whether we are selecting or deselecting */
- action = SEL_SELECT;
- CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones)
- {
- if (ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
- action = SEL_DESELECT;
- break;
- }
- }
- CTX_DATA_END;
- }
-
- /* Set the flags */
- CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones)
- {
- /* ignore bone if selection can't change */
- switch (action) {
- case SEL_SELECT:
- if ((ebone->flag & BONE_UNSELECTABLE) == 0) {
- ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- if (ebone->parent) {
- ebone->parent->flag |= (BONE_TIPSEL);
- }
- }
- break;
- case SEL_DESELECT:
- ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- break;
- case SEL_INVERT:
- if (ebone->flag & BONE_SELECTED) {
- ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else {
- if ((ebone->flag & BONE_UNSELECTABLE) == 0) {
- ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- if (ebone->parent) {
- ebone->parent->flag |= (BONE_TIPSEL);
- }
- }
- }
- break;
- }
- }
- CTX_DATA_END;
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
-
- return OPERATOR_FINISHED;
+ int action = RNA_enum_get(op->ptr, "action");
+
+ if (action == SEL_TOGGLE) {
+ /* Determine if there are any selected bones
+ * And therefore whether we are selecting or deselecting */
+ action = SEL_SELECT;
+ CTX_DATA_BEGIN (C, EditBone *, ebone, visible_bones) {
+ if (ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
+ action = SEL_DESELECT;
+ break;
+ }
+ }
+ CTX_DATA_END;
+ }
+
+ /* Set the flags */
+ CTX_DATA_BEGIN (C, EditBone *, ebone, visible_bones) {
+ /* ignore bone if selection can't change */
+ switch (action) {
+ case SEL_SELECT:
+ if ((ebone->flag & BONE_UNSELECTABLE) == 0) {
+ ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ if (ebone->parent) {
+ ebone->parent->flag |= (BONE_TIPSEL);
+ }
+ }
+ break;
+ case SEL_DESELECT:
+ ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ break;
+ case SEL_INVERT:
+ if (ebone->flag & BONE_SELECTED) {
+ ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else {
+ if ((ebone->flag & BONE_UNSELECTABLE) == 0) {
+ ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ if (ebone->parent) {
+ ebone->parent->flag |= (BONE_TIPSEL);
+ }
+ }
+ }
+ break;
+ }
+ }
+ CTX_DATA_END;
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_select_all(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "(De)select All";
- ot->idname = "ARMATURE_OT_select_all";
- ot->description = "Toggle selection status of all bones";
+ /* identifiers */
+ ot->name = "(De)select All";
+ ot->idname = "ARMATURE_OT_select_all";
+ ot->description = "Toggle selection status of all bones";
- /* api callbacks */
- ot->exec = armature_de_select_all_exec;
- ot->poll = ED_operator_editarmature;
+ /* api callbacks */
+ ot->exec = armature_de_select_all_exec;
+ ot->poll = ED_operator_editarmature;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- WM_operator_properties_select_all(ot);
+ WM_operator_properties_select_all(ot);
}
/**************** Select more/less **************/
static void armature_select_more(bArmature *arm, EditBone *ebone)
{
- if ((EBONE_PREV_FLAG_GET(ebone) & (BONE_ROOTSEL | BONE_TIPSEL)) != 0) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- ED_armature_ebone_select_set(ebone, true);
- }
- }
-
- if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
- /* to parent */
- if ((EBONE_PREV_FLAG_GET(ebone) & BONE_ROOTSEL) != 0) {
- if (EBONE_SELECTABLE(arm, ebone->parent)) {
- ED_armature_ebone_selectflag_enable(ebone->parent, (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL));
- }
- }
-
- /* from parent (difference from select less) */
- if ((EBONE_PREV_FLAG_GET(ebone->parent) & BONE_TIPSEL) != 0) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- ED_armature_ebone_selectflag_enable(ebone, (BONE_SELECTED | BONE_ROOTSEL));
- }
- }
- }
+ if ((EBONE_PREV_FLAG_GET(ebone) & (BONE_ROOTSEL | BONE_TIPSEL)) != 0) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ ED_armature_ebone_select_set(ebone, true);
+ }
+ }
+
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ /* to parent */
+ if ((EBONE_PREV_FLAG_GET(ebone) & BONE_ROOTSEL) != 0) {
+ if (EBONE_SELECTABLE(arm, ebone->parent)) {
+ ED_armature_ebone_selectflag_enable(ebone->parent,
+ (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL));
+ }
+ }
+
+ /* from parent (difference from select less) */
+ if ((EBONE_PREV_FLAG_GET(ebone->parent) & BONE_TIPSEL) != 0) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ ED_armature_ebone_selectflag_enable(ebone, (BONE_SELECTED | BONE_ROOTSEL));
+ }
+ }
+ }
}
static void armature_select_less(bArmature *UNUSED(arm), EditBone *ebone)
{
- if ((EBONE_PREV_FLAG_GET(ebone) & (BONE_ROOTSEL | BONE_TIPSEL)) != (BONE_ROOTSEL | BONE_TIPSEL)) {
- ED_armature_ebone_select_set(ebone, false);
- }
-
- if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
- /* to parent */
- if ((EBONE_PREV_FLAG_GET(ebone) & BONE_SELECTED) == 0) {
- ED_armature_ebone_selectflag_disable(ebone->parent, (BONE_SELECTED | BONE_TIPSEL));
- }
-
- /* from parent (difference from select more) */
- if ((EBONE_PREV_FLAG_GET(ebone->parent) & BONE_SELECTED) == 0) {
- ED_armature_ebone_selectflag_disable(ebone, (BONE_SELECTED | BONE_ROOTSEL));
- }
- }
+ if ((EBONE_PREV_FLAG_GET(ebone) & (BONE_ROOTSEL | BONE_TIPSEL)) !=
+ (BONE_ROOTSEL | BONE_TIPSEL)) {
+ ED_armature_ebone_select_set(ebone, false);
+ }
+
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ /* to parent */
+ if ((EBONE_PREV_FLAG_GET(ebone) & BONE_SELECTED) == 0) {
+ ED_armature_ebone_selectflag_disable(ebone->parent, (BONE_SELECTED | BONE_TIPSEL));
+ }
+
+ /* from parent (difference from select more) */
+ if ((EBONE_PREV_FLAG_GET(ebone->parent) & BONE_SELECTED) == 0) {
+ ED_armature_ebone_selectflag_disable(ebone, (BONE_SELECTED | BONE_ROOTSEL));
+ }
+ }
}
static void armature_select_more_less(Object *ob, bool more)
{
- bArmature *arm = (bArmature *)ob->data;
- EditBone *ebone;
-
- /* XXX, eventually we shouldn't need this - campbell */
- ED_armature_edit_sync_selection(arm->edbo);
-
- /* count bones & store selection state */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- EBONE_PREV_FLAG_SET(ebone, ED_armature_ebone_selectflag_get(ebone));
- }
-
- /* do selection */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if (more) {
- armature_select_more(arm, ebone);
- }
- else {
- armature_select_less(arm, ebone);
- }
- }
- }
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if (more == false) {
- if (ebone->flag & BONE_SELECTED) {
- ED_armature_ebone_select_set(ebone, true);
- }
- }
- }
- ebone->temp.p = NULL;
- }
-
- ED_armature_edit_sync_selection(arm->edbo);
+ bArmature *arm = (bArmature *)ob->data;
+ EditBone *ebone;
+
+ /* XXX, eventually we shouldn't need this - campbell */
+ ED_armature_edit_sync_selection(arm->edbo);
+
+ /* count bones & store selection state */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ EBONE_PREV_FLAG_SET(ebone, ED_armature_ebone_selectflag_get(ebone));
+ }
+
+ /* do selection */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ if (more) {
+ armature_select_more(arm, ebone);
+ }
+ else {
+ armature_select_less(arm, ebone);
+ }
+ }
+ }
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ if (more == false) {
+ if (ebone->flag & BONE_SELECTED) {
+ ED_armature_ebone_select_set(ebone, true);
+ }
+ }
+ }
+ ebone->temp.p = NULL;
+ }
+
+ ED_armature_edit_sync_selection(arm->edbo);
}
static int armature_de_select_more_exec(bContext *C, wmOperator *UNUSED(op))
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- armature_select_more_less(ob, true);
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
- }
- MEM_freeN(objects);
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ armature_select_more_less(ob, true);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ MEM_freeN(objects);
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_select_more(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select More";
- ot->idname = "ARMATURE_OT_select_more";
- ot->description = "Select those bones connected to the initial selection";
+ /* identifiers */
+ ot->name = "Select More";
+ ot->idname = "ARMATURE_OT_select_more";
+ ot->description = "Select those bones connected to the initial selection";
- /* api callbacks */
- ot->exec = armature_de_select_more_exec;
- ot->poll = ED_operator_editarmature;
+ /* api callbacks */
+ ot->exec = armature_de_select_more_exec;
+ ot->poll = ED_operator_editarmature;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int armature_de_select_less_exec(bContext *C, wmOperator *UNUSED(op))
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- armature_select_more_less(ob, false);
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
- }
- MEM_freeN(objects);
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ armature_select_more_less(ob, false);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ MEM_freeN(objects);
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_select_less(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select Less";
- ot->idname = "ARMATURE_OT_select_less";
- ot->description = "Deselect those bones at the boundary of each selection region";
+ /* identifiers */
+ ot->name = "Select Less";
+ ot->idname = "ARMATURE_OT_select_less";
+ ot->description = "Deselect those bones at the boundary of each selection region";
- /* api callbacks */
- ot->exec = armature_de_select_less_exec;
- ot->poll = ED_operator_editarmature;
+ /* api callbacks */
+ ot->exec = armature_de_select_less_exec;
+ ot->poll = ED_operator_editarmature;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
enum {
- SIMEDBONE_CHILDREN = 1,
- SIMEDBONE_CHILDREN_IMMEDIATE,
- SIMEDBONE_SIBLINGS,
- SIMEDBONE_LENGTH,
- SIMEDBONE_DIRECTION,
- SIMEDBONE_PREFIX,
- SIMEDBONE_SUFFIX,
- SIMEDBONE_LAYER,
- SIMEDBONE_GROUP,
- SIMEDBONE_SHAPE,
+ SIMEDBONE_CHILDREN = 1,
+ SIMEDBONE_CHILDREN_IMMEDIATE,
+ SIMEDBONE_SIBLINGS,
+ SIMEDBONE_LENGTH,
+ SIMEDBONE_DIRECTION,
+ SIMEDBONE_PREFIX,
+ SIMEDBONE_SUFFIX,
+ SIMEDBONE_LAYER,
+ SIMEDBONE_GROUP,
+ SIMEDBONE_SHAPE,
};
static const EnumPropertyItem prop_similar_types[] = {
- {SIMEDBONE_CHILDREN, "CHILDREN", 0, "Children", ""},
- {SIMEDBONE_CHILDREN_IMMEDIATE, "CHILDREN_IMMEDIATE", 0, "Immediate children", ""},
- {SIMEDBONE_SIBLINGS, "SIBLINGS", 0, "Siblings", ""},
- {SIMEDBONE_LENGTH, "LENGTH", 0, "Length", ""},
- {SIMEDBONE_DIRECTION, "DIRECTION", 0, "Direction (Y axis)", ""},
- {SIMEDBONE_PREFIX, "PREFIX", 0, "Prefix", ""},
- {SIMEDBONE_SUFFIX, "SUFFIX", 0, "Suffix", ""},
- {SIMEDBONE_LAYER, "LAYER", 0, "Layer", ""},
- {SIMEDBONE_GROUP, "GROUP", 0, "Group", ""},
- {SIMEDBONE_SHAPE, "SHAPE", 0, "Shape", ""},
- {0, NULL, 0, NULL, NULL},
+ {SIMEDBONE_CHILDREN, "CHILDREN", 0, "Children", ""},
+ {SIMEDBONE_CHILDREN_IMMEDIATE, "CHILDREN_IMMEDIATE", 0, "Immediate children", ""},
+ {SIMEDBONE_SIBLINGS, "SIBLINGS", 0, "Siblings", ""},
+ {SIMEDBONE_LENGTH, "LENGTH", 0, "Length", ""},
+ {SIMEDBONE_DIRECTION, "DIRECTION", 0, "Direction (Y axis)", ""},
+ {SIMEDBONE_PREFIX, "PREFIX", 0, "Prefix", ""},
+ {SIMEDBONE_SUFFIX, "SUFFIX", 0, "Suffix", ""},
+ {SIMEDBONE_LAYER, "LAYER", 0, "Layer", ""},
+ {SIMEDBONE_GROUP, "GROUP", 0, "Group", ""},
+ {SIMEDBONE_SHAPE, "SHAPE", 0, "Shape", ""},
+ {0, NULL, 0, NULL, NULL},
};
static float bone_length_squared_worldspace_get(Object *ob, EditBone *ebone)
{
- float v1[3], v2[3];
- mul_v3_mat3_m4v3(v1, ob->obmat, ebone->head);
- mul_v3_mat3_m4v3(v2, ob->obmat, ebone->tail);
- return len_squared_v3v3(v1, v2);
+ float v1[3], v2[3];
+ mul_v3_mat3_m4v3(v1, ob->obmat, ebone->head);
+ mul_v3_mat3_m4v3(v2, ob->obmat, ebone->tail);
+ return len_squared_v3v3(v1, v2);
}
static void select_similar_length(bContext *C, const float thresh)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob_act = CTX_data_edit_object(C);
- EditBone *ebone_act = CTX_data_active_bone(C);
-
- /* Thresh is always relative to current length. */
- const float len = bone_length_squared_worldspace_get(ob_act, ebone_act);
- const float len_min = len / (1.0f + (thresh - FLT_EPSILON));
- const float len_max = len * (1.0f + (thresh + FLT_EPSILON));
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- bArmature *arm = ob->data;
- bool changed = false;
-
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- const float len_iter = bone_length_squared_worldspace_get(ob, ebone);
- if ((len_iter > len_min) &&
- (len_iter < len_max))
- {
- ED_armature_ebone_select_set(ebone, true);
- changed = true;
- }
- }
- }
-
- if (changed) {
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
- }
- }
- MEM_freeN(objects);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob_act = CTX_data_edit_object(C);
+ EditBone *ebone_act = CTX_data_active_bone(C);
+
+ /* Thresh is always relative to current length. */
+ const float len = bone_length_squared_worldspace_get(ob_act, ebone_act);
+ const float len_min = len / (1.0f + (thresh - FLT_EPSILON));
+ const float len_max = len * (1.0f + (thresh + FLT_EPSILON));
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bool changed = false;
+
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ const float len_iter = bone_length_squared_worldspace_get(ob, ebone);
+ if ((len_iter > len_min) && (len_iter < len_max)) {
+ ED_armature_ebone_select_set(ebone, true);
+ changed = true;
+ }
+ }
+ }
+
+ if (changed) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ }
+ MEM_freeN(objects);
}
static void bone_direction_worldspace_get(Object *ob, EditBone *ebone, float *r_dir)
{
- float v1[3], v2[3];
- copy_v3_v3(v1, ebone->head);
- copy_v3_v3(v2, ebone->tail);
+ float v1[3], v2[3];
+ copy_v3_v3(v1, ebone->head);
+ copy_v3_v3(v2, ebone->tail);
- mul_m4_v3(ob->obmat, v1);
- mul_m4_v3(ob->obmat, v2);
+ mul_m4_v3(ob->obmat, v1);
+ mul_m4_v3(ob->obmat, v2);
- sub_v3_v3v3(r_dir, v1, v2);
- normalize_v3(r_dir);
+ sub_v3_v3v3(r_dir, v1, v2);
+ normalize_v3(r_dir);
}
static void select_similar_direction(bContext *C, const float thresh)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob_act = CTX_data_edit_object(C);
- EditBone *ebone_act = CTX_data_active_bone(C);
-
- float dir_act[3];
- bone_direction_worldspace_get(ob_act, ebone_act, dir_act);
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- bArmature *arm = ob->data;
- bool changed = false;
-
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- float dir[3];
- bone_direction_worldspace_get(ob, ebone, dir);
-
- if (angle_v3v3(dir_act, dir) / (float)M_PI < (thresh + FLT_EPSILON)) {
- ED_armature_ebone_select_set(ebone, true);
- changed = true;
- }
- }
- }
-
- if (changed) {
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
- }
- }
- MEM_freeN(objects);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob_act = CTX_data_edit_object(C);
+ EditBone *ebone_act = CTX_data_active_bone(C);
+
+ float dir_act[3];
+ bone_direction_worldspace_get(ob_act, ebone_act, dir_act);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bool changed = false;
+
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ float dir[3];
+ bone_direction_worldspace_get(ob, ebone, dir);
+
+ if (angle_v3v3(dir_act, dir) / (float)M_PI < (thresh + FLT_EPSILON)) {
+ ED_armature_ebone_select_set(ebone, true);
+ changed = true;
+ }
+ }
+ }
+
+ if (changed) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ }
+ MEM_freeN(objects);
}
static void select_similar_layer(bContext *C)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- EditBone *ebone_act = CTX_data_active_bone(C);
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- bArmature *arm = ob->data;
- bool changed = false;
-
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- if (ebone->layer & ebone_act->layer) {
- ED_armature_ebone_select_set(ebone, true);
- changed = true;
- }
- }
- }
-
- if (changed) {
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
- }
- }
- MEM_freeN(objects);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ EditBone *ebone_act = CTX_data_active_bone(C);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bool changed = false;
+
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ if (ebone->layer & ebone_act->layer) {
+ ED_armature_ebone_select_set(ebone, true);
+ changed = true;
+ }
+ }
+ }
+
+ if (changed) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ }
+ MEM_freeN(objects);
}
static void select_similar_prefix(bContext *C)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- EditBone *ebone_act = CTX_data_active_bone(C);
-
- char body_tmp[MAXBONENAME];
- char prefix_act[MAXBONENAME];
-
- BLI_string_split_prefix(ebone_act->name, prefix_act, body_tmp, sizeof(ebone_act->name));
-
- if (prefix_act[0] == '\0') {
- return;
- }
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- bArmature *arm = ob->data;
- bool changed = false;
-
- /* Find matches */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- char prefix_other[MAXBONENAME];
- BLI_string_split_prefix(ebone->name, prefix_other, body_tmp, sizeof(ebone->name));
- if (STREQ(prefix_act, prefix_other)) {
- ED_armature_ebone_select_set(ebone, true);
- changed = true;
- }
- }
- }
-
- if (changed) {
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
- }
- }
- MEM_freeN(objects);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ EditBone *ebone_act = CTX_data_active_bone(C);
+
+ char body_tmp[MAXBONENAME];
+ char prefix_act[MAXBONENAME];
+
+ BLI_string_split_prefix(ebone_act->name, prefix_act, body_tmp, sizeof(ebone_act->name));
+
+ if (prefix_act[0] == '\0') {
+ return;
+ }
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bool changed = false;
+
+ /* Find matches */
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ char prefix_other[MAXBONENAME];
+ BLI_string_split_prefix(ebone->name, prefix_other, body_tmp, sizeof(ebone->name));
+ if (STREQ(prefix_act, prefix_other)) {
+ ED_armature_ebone_select_set(ebone, true);
+ changed = true;
+ }
+ }
+ }
+
+ if (changed) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ }
+ MEM_freeN(objects);
}
static void select_similar_suffix(bContext *C)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- EditBone *ebone_act = CTX_data_active_bone(C);
-
- char body_tmp[MAXBONENAME];
- char suffix_act[MAXBONENAME];
-
- BLI_string_split_suffix(ebone_act->name, body_tmp, suffix_act, sizeof(ebone_act->name));
-
- if (suffix_act[0] == '\0')
- return;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- bArmature *arm = ob->data;
- bool changed = false;
-
- /* Find matches */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- char suffix_other[MAXBONENAME];
- BLI_string_split_suffix(ebone->name, body_tmp, suffix_other, sizeof(ebone->name));
- if (STREQ(suffix_act, suffix_other)) {
- ED_armature_ebone_select_set(ebone, true);
- changed = true;
- }
- }
- }
-
- if (changed) {
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
- }
- }
- MEM_freeN(objects);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ EditBone *ebone_act = CTX_data_active_bone(C);
+
+ char body_tmp[MAXBONENAME];
+ char suffix_act[MAXBONENAME];
+
+ BLI_string_split_suffix(ebone_act->name, body_tmp, suffix_act, sizeof(ebone_act->name));
+
+ if (suffix_act[0] == '\0')
+ return;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bool changed = false;
+
+ /* Find matches */
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ char suffix_other[MAXBONENAME];
+ BLI_string_split_suffix(ebone->name, body_tmp, suffix_other, sizeof(ebone->name));
+ if (STREQ(suffix_act, suffix_other)) {
+ ED_armature_ebone_select_set(ebone, true);
+ changed = true;
+ }
+ }
+ }
+
+ if (changed) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ }
+ MEM_freeN(objects);
}
/** Use for matching any pose channel data. */
-static void select_similar_data_pchan(
- bContext *C,
- const size_t bytes_size, const int offset)
+static void select_similar_data_pchan(bContext *C, const size_t bytes_size, const int offset)
{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = obedit->data;
- EditBone *ebone_act = CTX_data_active_bone(C);
-
- const bPoseChannel *pchan_active = BKE_pose_channel_find_name(obedit->pose, ebone_act->name);
- const char *data_active = (const char *)POINTER_OFFSET(pchan_active, offset);
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- const bPoseChannel *pchan = BKE_pose_channel_find_name(obedit->pose, ebone->name);
- if (pchan) {
- const char *data_test = (const char *)POINTER_OFFSET(pchan, offset);
- if (memcmp(data_active, data_test, bytes_size) == 0) {
- ED_armature_ebone_select_set(ebone, true);
- }
- }
- }
- }
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = obedit->data;
+ EditBone *ebone_act = CTX_data_active_bone(C);
+
+ const bPoseChannel *pchan_active = BKE_pose_channel_find_name(obedit->pose, ebone_act->name);
+ const char *data_active = (const char *)POINTER_OFFSET(pchan_active, offset);
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ const bPoseChannel *pchan = BKE_pose_channel_find_name(obedit->pose, ebone->name);
+ if (pchan) {
+ const char *data_test = (const char *)POINTER_OFFSET(pchan, offset);
+ if (memcmp(data_active, data_test, bytes_size) == 0) {
+ ED_armature_ebone_select_set(ebone, true);
+ }
+ }
+ }
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
}
static void is_ancestor(EditBone *bone, EditBone *ancestor)
{
- if (bone->temp.ebone == ancestor || bone->temp.ebone == NULL)
- return;
+ if (bone->temp.ebone == ancestor || bone->temp.ebone == NULL)
+ return;
- if (bone->temp.ebone->temp.ebone != NULL && bone->temp.ebone->temp.ebone != ancestor)
- is_ancestor(bone->temp.ebone, ancestor);
+ if (bone->temp.ebone->temp.ebone != NULL && bone->temp.ebone->temp.ebone != ancestor)
+ is_ancestor(bone->temp.ebone, ancestor);
- bone->temp.ebone = bone->temp.ebone->temp.ebone;
+ bone->temp.ebone = bone->temp.ebone->temp.ebone;
}
static void select_similar_children(bContext *C)
{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = obedit->data;
- EditBone *ebone_act = CTX_data_active_bone(C);
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = obedit->data;
+ EditBone *ebone_act = CTX_data_active_bone(C);
- for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
- ebone_iter->temp.ebone = ebone_iter->parent;
- }
+ for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ ebone_iter->temp.ebone = ebone_iter->parent;
+ }
- for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
- is_ancestor(ebone_iter, ebone_act);
+ for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ is_ancestor(ebone_iter, ebone_act);
- if (ebone_iter->temp.ebone == ebone_act && EBONE_SELECTABLE(arm, ebone_iter))
- ED_armature_ebone_select_set(ebone_iter, true);
- }
+ if (ebone_iter->temp.ebone == ebone_act && EBONE_SELECTABLE(arm, ebone_iter))
+ ED_armature_ebone_select_set(ebone_iter, true);
+ }
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
}
static void select_similar_children_immediate(bContext *C)
{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = obedit->data;
- EditBone *ebone_act = CTX_data_active_bone(C);
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = obedit->data;
+ EditBone *ebone_act = CTX_data_active_bone(C);
- for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
- if (ebone_iter->parent == ebone_act && EBONE_SELECTABLE(arm, ebone_iter)) {
- ED_armature_ebone_select_set(ebone_iter, true);
- }
- }
+ for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ if (ebone_iter->parent == ebone_act && EBONE_SELECTABLE(arm, ebone_iter)) {
+ ED_armature_ebone_select_set(ebone_iter, true);
+ }
+ }
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
}
static void select_similar_siblings(bContext *C)
{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = obedit->data;
- EditBone *ebone_act = CTX_data_active_bone(C);
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = obedit->data;
+ EditBone *ebone_act = CTX_data_active_bone(C);
- if (ebone_act->parent == NULL) {
- return;
- }
+ if (ebone_act->parent == NULL) {
+ return;
+ }
- for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
- if (ebone_iter->parent == ebone_act->parent && EBONE_SELECTABLE(arm, ebone_iter)) {
- ED_armature_ebone_select_set(ebone_iter, true);
- }
- }
+ for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ if (ebone_iter->parent == ebone_act->parent && EBONE_SELECTABLE(arm, ebone_iter)) {
+ ED_armature_ebone_select_set(ebone_iter, true);
+ }
+ }
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
}
static int armature_select_similar_exec(bContext *C, wmOperator *op)
{
- /* Get props */
- int type = RNA_enum_get(op->ptr, "type");
- float thresh = RNA_float_get(op->ptr, "threshold");
+ /* Get props */
+ int type = RNA_enum_get(op->ptr, "type");
+ float thresh = RNA_float_get(op->ptr, "threshold");
- /* Check for active bone */
- if (CTX_data_active_bone(C) == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
- return OPERATOR_CANCELLED;
- }
+ /* Check for active bone */
+ if (CTX_data_active_bone(C) == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
+ return OPERATOR_CANCELLED;
+ }
#define STRUCT_SIZE_AND_OFFSET(_struct, _member) \
- sizeof(((_struct *)NULL)->_member), offsetof(_struct, _member)
-
- switch (type) {
- case SIMEDBONE_CHILDREN:
- select_similar_children(C);
- break;
- case SIMEDBONE_CHILDREN_IMMEDIATE:
- select_similar_children_immediate(C);
- break;
- case SIMEDBONE_SIBLINGS:
- select_similar_siblings(C);
- break;
- case SIMEDBONE_LENGTH:
- select_similar_length(C, thresh);
- break;
- case SIMEDBONE_DIRECTION:
- select_similar_direction(C, thresh);
- break;
- case SIMEDBONE_PREFIX:
- select_similar_prefix(C);
- break;
- case SIMEDBONE_SUFFIX:
- select_similar_suffix(C);
- break;
- case SIMEDBONE_LAYER:
- select_similar_layer(C);
- break;
- case SIMEDBONE_GROUP:
- select_similar_data_pchan(
- C,
- STRUCT_SIZE_AND_OFFSET(bPoseChannel, agrp_index));
- break;
- case SIMEDBONE_SHAPE:
- select_similar_data_pchan(
- C,
- STRUCT_SIZE_AND_OFFSET(bPoseChannel, custom));
- break;
- }
+ sizeof(((_struct *)NULL)->_member), offsetof(_struct, _member)
+
+ switch (type) {
+ case SIMEDBONE_CHILDREN:
+ select_similar_children(C);
+ break;
+ case SIMEDBONE_CHILDREN_IMMEDIATE:
+ select_similar_children_immediate(C);
+ break;
+ case SIMEDBONE_SIBLINGS:
+ select_similar_siblings(C);
+ break;
+ case SIMEDBONE_LENGTH:
+ select_similar_length(C, thresh);
+ break;
+ case SIMEDBONE_DIRECTION:
+ select_similar_direction(C, thresh);
+ break;
+ case SIMEDBONE_PREFIX:
+ select_similar_prefix(C);
+ break;
+ case SIMEDBONE_SUFFIX:
+ select_similar_suffix(C);
+ break;
+ case SIMEDBONE_LAYER:
+ select_similar_layer(C);
+ break;
+ case SIMEDBONE_GROUP:
+ select_similar_data_pchan(C, STRUCT_SIZE_AND_OFFSET(bPoseChannel, agrp_index));
+ break;
+ case SIMEDBONE_SHAPE:
+ select_similar_data_pchan(C, STRUCT_SIZE_AND_OFFSET(bPoseChannel, custom));
+ break;
+ }
#undef STRUCT_SIZE_AND_OFFSET
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_select_similar(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select Similar";
- ot->idname = "ARMATURE_OT_select_similar";
-
- /* callback functions */
- ot->invoke = WM_menu_invoke;
- ot->exec = armature_select_similar_exec;
- ot->poll = ED_operator_editarmature;
- ot->description = "Select similar bones by property types";
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, SIMEDBONE_LENGTH, "Type", "");
- RNA_def_float(ot->srna, "threshold", 0.1f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
+ /* identifiers */
+ ot->name = "Select Similar";
+ ot->idname = "ARMATURE_OT_select_similar";
+
+ /* callback functions */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = armature_select_similar_exec;
+ ot->poll = ED_operator_editarmature;
+ ot->description = "Select similar bones by property types";
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, SIMEDBONE_LENGTH, "Type", "");
+ RNA_def_float(ot->srna, "threshold", 0.1f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
}
/* ********************* select hierarchy operator ************** */
@@ -1554,103 +1571,101 @@ void ARMATURE_OT_select_similar(wmOperatorType *ot)
* selected we then keep the non-active objects untouched (selected/unselected). */
static int armature_select_hierarchy_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_edit_object(C);
- EditBone *ebone_active;
- int direction = RNA_enum_get(op->ptr, "direction");
- const bool add_to_sel = RNA_boolean_get(op->ptr, "extend");
- bool changed = false;
- bArmature *arm = (bArmature *)ob->data;
-
- ebone_active = arm->act_edbone;
- if (ebone_active == NULL) {
- return OPERATOR_CANCELLED;
- }
-
- if (direction == BONE_SELECT_PARENT) {
- if (ebone_active->parent) {
- EditBone *ebone_parent;
-
- ebone_parent = ebone_active->parent;
-
- if (EBONE_SELECTABLE(arm, ebone_parent)) {
- arm->act_edbone = ebone_parent;
-
- if (!add_to_sel) {
- ED_armature_ebone_select_set(ebone_active, false);
- }
- ED_armature_ebone_select_set(ebone_parent, true);
-
- changed = true;
- }
- }
-
- }
- else { /* BONE_SELECT_CHILD */
- EditBone *ebone_iter, *ebone_child = NULL;
- int pass;
-
- /* first pass, only connected bones (the logical direct child) */
- for (pass = 0; pass < 2 && (ebone_child == NULL); pass++) {
- for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
- /* possible we have multiple children, some invisible */
- if (EBONE_SELECTABLE(arm, ebone_iter)) {
- if (ebone_iter->parent == ebone_active) {
- if ((pass == 1) || (ebone_iter->flag & BONE_CONNECTED)) {
- ebone_child = ebone_iter;
- break;
- }
- }
- }
- }
- }
-
- if (ebone_child) {
- arm->act_edbone = ebone_child;
-
- if (!add_to_sel) {
- ED_armature_ebone_select_set(ebone_active, false);
- }
- ED_armature_ebone_select_set(ebone_child, true);
-
- changed = true;
- }
- }
-
- if (changed == false) {
- return OPERATOR_CANCELLED;
- }
-
- ED_armature_edit_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- return OPERATOR_FINISHED;
+ Object *ob = CTX_data_edit_object(C);
+ EditBone *ebone_active;
+ int direction = RNA_enum_get(op->ptr, "direction");
+ const bool add_to_sel = RNA_boolean_get(op->ptr, "extend");
+ bool changed = false;
+ bArmature *arm = (bArmature *)ob->data;
+
+ ebone_active = arm->act_edbone;
+ if (ebone_active == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (direction == BONE_SELECT_PARENT) {
+ if (ebone_active->parent) {
+ EditBone *ebone_parent;
+
+ ebone_parent = ebone_active->parent;
+
+ if (EBONE_SELECTABLE(arm, ebone_parent)) {
+ arm->act_edbone = ebone_parent;
+
+ if (!add_to_sel) {
+ ED_armature_ebone_select_set(ebone_active, false);
+ }
+ ED_armature_ebone_select_set(ebone_parent, true);
+
+ changed = true;
+ }
+ }
+ }
+ else { /* BONE_SELECT_CHILD */
+ EditBone *ebone_iter, *ebone_child = NULL;
+ int pass;
+
+ /* first pass, only connected bones (the logical direct child) */
+ for (pass = 0; pass < 2 && (ebone_child == NULL); pass++) {
+ for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ /* possible we have multiple children, some invisible */
+ if (EBONE_SELECTABLE(arm, ebone_iter)) {
+ if (ebone_iter->parent == ebone_active) {
+ if ((pass == 1) || (ebone_iter->flag & BONE_CONNECTED)) {
+ ebone_child = ebone_iter;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (ebone_child) {
+ arm->act_edbone = ebone_child;
+
+ if (!add_to_sel) {
+ ED_armature_ebone_select_set(ebone_active, false);
+ }
+ ED_armature_ebone_select_set(ebone_child, true);
+
+ changed = true;
+ }
+ }
+
+ if (changed == false) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ED_armature_edit_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_select_hierarchy(wmOperatorType *ot)
{
- static const EnumPropertyItem direction_items[] = {
- {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""},
- {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Select Hierarchy";
- ot->idname = "ARMATURE_OT_select_hierarchy";
- ot->description = "Select immediate parent/children of selected bones";
-
- /* api callbacks */
- ot->exec = armature_select_hierarchy_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* props */
- RNA_def_enum(ot->srna, "direction", direction_items,
- BONE_SELECT_PARENT, "Direction", "");
- RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
+ static const EnumPropertyItem direction_items[] = {
+ {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""},
+ {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Select Hierarchy";
+ ot->idname = "ARMATURE_OT_select_hierarchy";
+ ot->description = "Select immediate parent/children of selected bones";
+
+ /* api callbacks */
+ ot->exec = armature_select_hierarchy_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_enum(ot->srna, "direction", direction_items, BONE_SELECT_PARENT, "Direction", "");
+ RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
/****************** Mirror Select ****************/
@@ -1660,202 +1675,199 @@ void ARMATURE_OT_select_hierarchy(wmOperatorType *ot)
*/
static int armature_select_mirror_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const bool active_only = RNA_boolean_get(op->ptr, "only_active");
- const bool extend = RNA_boolean_get(op->ptr, "extend");
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- bArmature *arm = ob->data;
-
- EditBone *ebone, *ebone_mirror_act = NULL;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- const int flag = ED_armature_ebone_selectflag_get(ebone);
- EBONE_PREV_FLAG_SET(ebone, flag);
- }
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- EditBone *ebone_mirror;
- int flag_new = extend ? EBONE_PREV_FLAG_GET(ebone) : 0;
-
- if ((ebone_mirror = ED_armature_ebone_get_mirrored(arm->edbo, ebone)) &&
- (EBONE_VISIBLE(arm, ebone_mirror)))
- {
- const int flag_mirror = EBONE_PREV_FLAG_GET(ebone_mirror);
- flag_new |= flag_mirror;
-
- if (ebone == arm->act_edbone) {
- ebone_mirror_act = ebone_mirror;
- }
-
- /* skip all but the active or its mirror */
- if (active_only && !ELEM(arm->act_edbone, ebone, ebone_mirror)) {
- continue;
- }
- }
-
- ED_armature_ebone_selectflag_set(ebone, flag_new);
- }
- }
-
- if (ebone_mirror_act) {
- arm->act_edbone = ebone_mirror_act;
- }
-
- ED_armature_edit_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const bool active_only = RNA_boolean_get(op->ptr, "only_active");
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+
+ EditBone *ebone, *ebone_mirror_act = NULL;
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ const int flag = ED_armature_ebone_selectflag_get(ebone);
+ EBONE_PREV_FLAG_SET(ebone, flag);
+ }
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ EditBone *ebone_mirror;
+ int flag_new = extend ? EBONE_PREV_FLAG_GET(ebone) : 0;
+
+ if ((ebone_mirror = ED_armature_ebone_get_mirrored(arm->edbo, ebone)) &&
+ (EBONE_VISIBLE(arm, ebone_mirror))) {
+ const int flag_mirror = EBONE_PREV_FLAG_GET(ebone_mirror);
+ flag_new |= flag_mirror;
+
+ if (ebone == arm->act_edbone) {
+ ebone_mirror_act = ebone_mirror;
+ }
+
+ /* skip all but the active or its mirror */
+ if (active_only && !ELEM(arm->act_edbone, ebone, ebone_mirror)) {
+ continue;
+ }
+ }
+
+ ED_armature_ebone_selectflag_set(ebone, flag_new);
+ }
+ }
+
+ if (ebone_mirror_act) {
+ arm->act_edbone = ebone_mirror_act;
+ }
+
+ ED_armature_edit_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_select_mirror(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Flip Active/Selected Bone";
- ot->idname = "ARMATURE_OT_select_mirror";
- ot->description = "Mirror the bone selection";
-
- /* api callbacks */
- ot->exec = armature_select_mirror_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "only_active", false, "Active Only", "Only operate on the active bone");
- RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
+ /* identifiers */
+ ot->name = "Flip Active/Selected Bone";
+ ot->idname = "ARMATURE_OT_select_mirror";
+ ot->description = "Mirror the bone selection";
+
+ /* api callbacks */
+ ot->exec = armature_select_mirror_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(
+ ot->srna, "only_active", false, "Active Only", "Only operate on the active bone");
+ RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
-
/****************** Select Path ****************/
-static bool armature_shortest_path_select(bArmature *arm, EditBone *ebone_parent, EditBone *ebone_child,
- bool use_parent, bool is_test)
+static bool armature_shortest_path_select(
+ bArmature *arm, EditBone *ebone_parent, EditBone *ebone_child, bool use_parent, bool is_test)
{
- do {
+ do {
- if (!use_parent && (ebone_child == ebone_parent))
- break;
+ if (!use_parent && (ebone_child == ebone_parent))
+ break;
- if (is_test) {
- if (!EBONE_SELECTABLE(arm, ebone_child)) {
- return false;
- }
- }
- else {
- ED_armature_ebone_selectflag_set(ebone_child, (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL));
- }
+ if (is_test) {
+ if (!EBONE_SELECTABLE(arm, ebone_child)) {
+ return false;
+ }
+ }
+ else {
+ ED_armature_ebone_selectflag_set(ebone_child, (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL));
+ }
- if (ebone_child == ebone_parent)
- break;
+ if (ebone_child == ebone_parent)
+ break;
- ebone_child = ebone_child->parent;
- } while (true);
+ ebone_child = ebone_child->parent;
+ } while (true);
- return true;
+ return true;
}
static int armature_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = obedit->data;
- EditBone *ebone_src, *ebone_dst;
- EditBone *ebone_isect_parent = NULL;
- EditBone *ebone_isect_child[2];
- bool changed;
- Base *base_dst = NULL;
-
- view3d_operator_needs_opengl(C);
-
- ebone_src = arm->act_edbone;
- ebone_dst = get_nearest_bone(C, event->mval, false, &base_dst);
-
- /* fallback to object selection */
- if (ELEM(NULL, ebone_src, ebone_dst) || (ebone_src == ebone_dst)) {
- return OPERATOR_PASS_THROUGH;
- }
-
- if (base_dst && base_dst->object != obedit) {
- /* Disconnected, ignore. */
- return OPERATOR_CANCELLED;
- }
-
- ebone_isect_child[0] = ebone_src;
- ebone_isect_child[1] = ebone_dst;
-
-
- /* ensure 'ebone_src' is the parent of 'ebone_dst', or set 'ebone_isect_parent' */
- if (ED_armature_ebone_is_child_recursive(ebone_src, ebone_dst)) {
- /* pass */
- }
- else if (ED_armature_ebone_is_child_recursive(ebone_dst, ebone_src)) {
- SWAP(EditBone *, ebone_src, ebone_dst);
- }
- else if ((ebone_isect_parent = ED_armature_ebone_find_shared_parent(ebone_isect_child, 2))) {
- /* pass */
- }
- else {
- /* disconnected bones */
- return OPERATOR_CANCELLED;
- }
-
-
- if (ebone_isect_parent) {
- if (armature_shortest_path_select(arm, ebone_isect_parent, ebone_src, false, true) &&
- armature_shortest_path_select(arm, ebone_isect_parent, ebone_dst, false, true))
- {
- armature_shortest_path_select(arm, ebone_isect_parent, ebone_src, false, false);
- armature_shortest_path_select(arm, ebone_isect_parent, ebone_dst, false, false);
- changed = true;
- }
- else {
- /* unselectable */
- changed = false;
- }
- }
- else {
- if (armature_shortest_path_select(arm, ebone_src, ebone_dst, true, true)) {
- armature_shortest_path_select(arm, ebone_src, ebone_dst, true, false);
- changed = true;
- }
- else {
- /* unselectable */
- changed = false;
- }
- }
-
- if (changed) {
- arm->act_edbone = ebone_dst;
- ED_armature_edit_sync_selection(arm->edbo);
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
- }
- else {
- BKE_report(op->reports, RPT_WARNING, "Unselectable bone in chain");
- return OPERATOR_CANCELLED;
- }
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = obedit->data;
+ EditBone *ebone_src, *ebone_dst;
+ EditBone *ebone_isect_parent = NULL;
+ EditBone *ebone_isect_child[2];
+ bool changed;
+ Base *base_dst = NULL;
+
+ view3d_operator_needs_opengl(C);
+
+ ebone_src = arm->act_edbone;
+ ebone_dst = get_nearest_bone(C, event->mval, false, &base_dst);
+
+ /* fallback to object selection */
+ if (ELEM(NULL, ebone_src, ebone_dst) || (ebone_src == ebone_dst)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ if (base_dst && base_dst->object != obedit) {
+ /* Disconnected, ignore. */
+ return OPERATOR_CANCELLED;
+ }
+
+ ebone_isect_child[0] = ebone_src;
+ ebone_isect_child[1] = ebone_dst;
+
+ /* ensure 'ebone_src' is the parent of 'ebone_dst', or set 'ebone_isect_parent' */
+ if (ED_armature_ebone_is_child_recursive(ebone_src, ebone_dst)) {
+ /* pass */
+ }
+ else if (ED_armature_ebone_is_child_recursive(ebone_dst, ebone_src)) {
+ SWAP(EditBone *, ebone_src, ebone_dst);
+ }
+ else if ((ebone_isect_parent = ED_armature_ebone_find_shared_parent(ebone_isect_child, 2))) {
+ /* pass */
+ }
+ else {
+ /* disconnected bones */
+ return OPERATOR_CANCELLED;
+ }
+
+ if (ebone_isect_parent) {
+ if (armature_shortest_path_select(arm, ebone_isect_parent, ebone_src, false, true) &&
+ armature_shortest_path_select(arm, ebone_isect_parent, ebone_dst, false, true)) {
+ armature_shortest_path_select(arm, ebone_isect_parent, ebone_src, false, false);
+ armature_shortest_path_select(arm, ebone_isect_parent, ebone_dst, false, false);
+ changed = true;
+ }
+ else {
+ /* unselectable */
+ changed = false;
+ }
+ }
+ else {
+ if (armature_shortest_path_select(arm, ebone_src, ebone_dst, true, true)) {
+ armature_shortest_path_select(arm, ebone_src, ebone_dst, true, false);
+ changed = true;
+ }
+ else {
+ /* unselectable */
+ changed = false;
+ }
+ }
+
+ if (changed) {
+ arm->act_edbone = ebone_dst;
+ ED_armature_edit_sync_selection(arm->edbo);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_WARNING, "Unselectable bone in chain");
+ return OPERATOR_CANCELLED;
+ }
}
void ARMATURE_OT_shortest_path_pick(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Pick Shortest Path";
- ot->idname = "ARMATURE_OT_shortest_path_pick";
- ot->description = "Select shortest path between two bones";
+ /* identifiers */
+ ot->name = "Pick Shortest Path";
+ ot->idname = "ARMATURE_OT_shortest_path_pick";
+ ot->description = "Select shortest path between two bones";
- /* api callbacks */
- ot->invoke = armature_shortest_path_pick_invoke;
- ot->poll = ED_operator_editarmature;
+ /* api callbacks */
+ ot->invoke = armature_shortest_path_pick_invoke;
+ ot->poll = ED_operator_editarmature;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c
index 5aec55bd1ed..afbeb8e4377 100644
--- a/source/blender/editors/armature/armature_skinning.c
+++ b/source/blender/editors/armature/armature_skinning.c
@@ -59,395 +59,436 @@
static int bone_skinnable_cb(Object *UNUSED(ob), Bone *bone, void *datap)
{
- /* Bones that are deforming
- * are regarded to be "skinnable" and are eligible for
- * auto-skinning.
- *
- * This function performs 2 functions:
- *
- * a) It returns 1 if the bone is skinnable.
- * If we loop over all bones with this
- * function, we can count the number of
- * skinnable bones.
- * b) If the pointer data is non null,
- * it is treated like a handle to a
- * bone pointer -- the bone pointer
- * is set to point at this bone, and
- * the pointer the handle points to
- * is incremented to point to the
- * next member of an array of pointers
- * to bones. This way we can loop using
- * this function to construct an array of
- * pointers to bones that point to all
- * skinnable bones.
- */
- Bone ***hbone;
- int a, segments;
- struct { Object *armob; void *list; int heat; bool is_weight_paint; } *data = datap;
-
- if (!(data->is_weight_paint) || !(bone->flag & BONE_HIDDEN_P)) {
- if (!(bone->flag & BONE_NO_DEFORM)) {
- if (data->heat && data->armob->pose && BKE_pose_channel_find_name(data->armob->pose, bone->name))
- segments = bone->segments;
- else
- segments = 1;
-
- if (data->list != NULL) {
- hbone = (Bone ***) &data->list;
-
- for (a = 0; a < segments; a++) {
- **hbone = bone;
- (*hbone)++;
- }
- }
- return segments;
- }
- }
- return 0;
+ /* Bones that are deforming
+ * are regarded to be "skinnable" and are eligible for
+ * auto-skinning.
+ *
+ * This function performs 2 functions:
+ *
+ * a) It returns 1 if the bone is skinnable.
+ * If we loop over all bones with this
+ * function, we can count the number of
+ * skinnable bones.
+ * b) If the pointer data is non null,
+ * it is treated like a handle to a
+ * bone pointer -- the bone pointer
+ * is set to point at this bone, and
+ * the pointer the handle points to
+ * is incremented to point to the
+ * next member of an array of pointers
+ * to bones. This way we can loop using
+ * this function to construct an array of
+ * pointers to bones that point to all
+ * skinnable bones.
+ */
+ Bone ***hbone;
+ int a, segments;
+ struct {
+ Object *armob;
+ void *list;
+ int heat;
+ bool is_weight_paint;
+ } *data = datap;
+
+ if (!(data->is_weight_paint) || !(bone->flag & BONE_HIDDEN_P)) {
+ if (!(bone->flag & BONE_NO_DEFORM)) {
+ if (data->heat && data->armob->pose &&
+ BKE_pose_channel_find_name(data->armob->pose, bone->name))
+ segments = bone->segments;
+ else
+ segments = 1;
+
+ if (data->list != NULL) {
+ hbone = (Bone ***)&data->list;
+
+ for (a = 0; a < segments; a++) {
+ **hbone = bone;
+ (*hbone)++;
+ }
+ }
+ return segments;
+ }
+ }
+ return 0;
}
static int vgroup_add_unique_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
{
- /* This group creates a vertex group to ob that has the
- * same name as bone (provided the bone is skinnable).
- * If such a vertex group already exist the routine exits.
- */
- if (!(bone->flag & BONE_NO_DEFORM)) {
- if (!defgroup_find_name(ob, bone->name)) {
- BKE_object_defgroup_add_name(ob, bone->name);
- return 1;
- }
- }
- return 0;
+ /* This group creates a vertex group to ob that has the
+ * same name as bone (provided the bone is skinnable).
+ * If such a vertex group already exist the routine exits.
+ */
+ if (!(bone->flag & BONE_NO_DEFORM)) {
+ if (!defgroup_find_name(ob, bone->name)) {
+ BKE_object_defgroup_add_name(ob, bone->name);
+ return 1;
+ }
+ }
+ return 0;
}
static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap)
{
- /* Bones that are deforming
- * are regarded to be "skinnable" and are eligible for
- * auto-skinning.
- *
- * This function performs 2 functions:
- *
- * a) If the bone is skinnable, it creates
- * a vertex group for ob that has
- * the name of the skinnable bone
- * (if one doesn't exist already).
- * b) If the pointer data is non null,
- * it is treated like a handle to a
- * bDeformGroup pointer -- the
- * bDeformGroup pointer is set to point
- * to the deform group with the bone's
- * name, and the pointer the handle
- * points to is incremented to point to the
- * next member of an array of pointers
- * to bDeformGroups. This way we can loop using
- * this function to construct an array of
- * pointers to bDeformGroups, all with names
- * of skinnable bones.
- */
- bDeformGroup ***hgroup, *defgroup = NULL;
- int a, segments;
- struct { Object *armob; void *list; int heat; bool is_weight_paint; } *data = datap;
- bArmature *arm = data->armob->data;
-
- if (!data->is_weight_paint || !(bone->flag & BONE_HIDDEN_P)) {
- if (!(bone->flag & BONE_NO_DEFORM)) {
- if (data->heat && data->armob->pose && BKE_pose_channel_find_name(data->armob->pose, bone->name))
- segments = bone->segments;
- else
- segments = 1;
-
- if (!data->is_weight_paint || ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))) {
- if (!(defgroup = defgroup_find_name(ob, bone->name))) {
- defgroup = BKE_object_defgroup_add_name(ob, bone->name);
- }
- else if (defgroup->flag & DG_LOCK_WEIGHT) {
- /* In case vgroup already exists and is locked, do not modify it here. See T43814. */
- defgroup = NULL;
- }
- }
-
- if (data->list != NULL) {
- hgroup = (bDeformGroup ***) &data->list;
-
- for (a = 0; a < segments; a++) {
- **hgroup = defgroup;
- (*hgroup)++;
- }
- }
- return segments;
- }
- }
- return 0;
+ /* Bones that are deforming
+ * are regarded to be "skinnable" and are eligible for
+ * auto-skinning.
+ *
+ * This function performs 2 functions:
+ *
+ * a) If the bone is skinnable, it creates
+ * a vertex group for ob that has
+ * the name of the skinnable bone
+ * (if one doesn't exist already).
+ * b) If the pointer data is non null,
+ * it is treated like a handle to a
+ * bDeformGroup pointer -- the
+ * bDeformGroup pointer is set to point
+ * to the deform group with the bone's
+ * name, and the pointer the handle
+ * points to is incremented to point to the
+ * next member of an array of pointers
+ * to bDeformGroups. This way we can loop using
+ * this function to construct an array of
+ * pointers to bDeformGroups, all with names
+ * of skinnable bones.
+ */
+ bDeformGroup ***hgroup, *defgroup = NULL;
+ int a, segments;
+ struct {
+ Object *armob;
+ void *list;
+ int heat;
+ bool is_weight_paint;
+ } *data = datap;
+ bArmature *arm = data->armob->data;
+
+ if (!data->is_weight_paint || !(bone->flag & BONE_HIDDEN_P)) {
+ if (!(bone->flag & BONE_NO_DEFORM)) {
+ if (data->heat && data->armob->pose &&
+ BKE_pose_channel_find_name(data->armob->pose, bone->name))
+ segments = bone->segments;
+ else
+ segments = 1;
+
+ if (!data->is_weight_paint || ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))) {
+ if (!(defgroup = defgroup_find_name(ob, bone->name))) {
+ defgroup = BKE_object_defgroup_add_name(ob, bone->name);
+ }
+ else if (defgroup->flag & DG_LOCK_WEIGHT) {
+ /* In case vgroup already exists and is locked, do not modify it here. See T43814. */
+ defgroup = NULL;
+ }
+ }
+
+ if (data->list != NULL) {
+ hgroup = (bDeformGroup ***)&data->list;
+
+ for (a = 0; a < segments; a++) {
+ **hgroup = defgroup;
+ (*hgroup)++;
+ }
+ }
+ return segments;
+ }
+ }
+ return 0;
}
-static void envelope_bone_weighting(
- Object *ob, Mesh *mesh, float (*verts)[3], int numbones, Bone **bonelist,
- bDeformGroup **dgrouplist, bDeformGroup **dgroupflip,
- float (*root)[3], float (*tip)[3], const int *selected, float scale)
+static void envelope_bone_weighting(Object *ob,
+ Mesh *mesh,
+ float (*verts)[3],
+ int numbones,
+ Bone **bonelist,
+ bDeformGroup **dgrouplist,
+ bDeformGroup **dgroupflip,
+ float (*root)[3],
+ float (*tip)[3],
+ const int *selected,
+ float scale)
{
- /* Create vertex group weights from envelopes */
-
- Bone *bone;
- bDeformGroup *dgroup;
- float distance;
- int i, iflip, j;
- bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0;
- bool use_mask = false;
-
- if ((ob->mode & OB_MODE_WEIGHT_PAINT) &&
- (mesh->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)))
- {
- use_mask = true;
- }
-
- /* for each vertex in the mesh */
- for (i = 0; i < mesh->totvert; i++) {
-
- if (use_mask && !(mesh->mvert[i].flag & SELECT)) {
- continue;
- }
-
- iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, NULL, i, use_topology) : -1;
-
- /* for each skinnable bone */
- for (j = 0; j < numbones; ++j) {
- if (!selected[j])
- continue;
-
- bone = bonelist[j];
- dgroup = dgrouplist[j];
-
- /* store the distance-factor from the vertex to the bone */
- distance = distfactor_to_bone(verts[i], root[j], tip[j],
- bone->rad_head * scale, bone->rad_tail * scale, bone->dist * scale);
-
- /* add the vert to the deform group if (weight != 0.0) */
- if (distance != 0.0f)
- ED_vgroup_vert_add(ob, dgroup, i, distance, WEIGHT_REPLACE);
- else
- ED_vgroup_vert_remove(ob, dgroup, i);
-
- /* do same for mirror */
- if (dgroupflip && dgroupflip[j] && iflip != -1) {
- if (distance != 0.0f)
- ED_vgroup_vert_add(ob, dgroupflip[j], iflip, distance,
- WEIGHT_REPLACE);
- else
- ED_vgroup_vert_remove(ob, dgroupflip[j], iflip);
- }
- }
- }
+ /* Create vertex group weights from envelopes */
+
+ Bone *bone;
+ bDeformGroup *dgroup;
+ float distance;
+ int i, iflip, j;
+ bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0;
+ bool use_mask = false;
+
+ if ((ob->mode & OB_MODE_WEIGHT_PAINT) &&
+ (mesh->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL))) {
+ use_mask = true;
+ }
+
+ /* for each vertex in the mesh */
+ for (i = 0; i < mesh->totvert; i++) {
+
+ if (use_mask && !(mesh->mvert[i].flag & SELECT)) {
+ continue;
+ }
+
+ iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, NULL, i, use_topology) : -1;
+
+ /* for each skinnable bone */
+ for (j = 0; j < numbones; ++j) {
+ if (!selected[j])
+ continue;
+
+ bone = bonelist[j];
+ dgroup = dgrouplist[j];
+
+ /* store the distance-factor from the vertex to the bone */
+ distance = distfactor_to_bone(verts[i],
+ root[j],
+ tip[j],
+ bone->rad_head * scale,
+ bone->rad_tail * scale,
+ bone->dist * scale);
+
+ /* add the vert to the deform group if (weight != 0.0) */
+ if (distance != 0.0f)
+ ED_vgroup_vert_add(ob, dgroup, i, distance, WEIGHT_REPLACE);
+ else
+ ED_vgroup_vert_remove(ob, dgroup, i);
+
+ /* do same for mirror */
+ if (dgroupflip && dgroupflip[j] && iflip != -1) {
+ if (distance != 0.0f)
+ ED_vgroup_vert_add(ob, dgroupflip[j], iflip, distance, WEIGHT_REPLACE);
+ else
+ ED_vgroup_vert_remove(ob, dgroupflip[j], iflip);
+ }
+ }
+ }
}
-static void add_verts_to_dgroups(
- ReportList *reports, Depsgraph *depsgraph, Scene *UNUSED(scene), Object *ob, Object *par,
- int heat, const bool mirror)
+static void add_verts_to_dgroups(ReportList *reports,
+ Depsgraph *depsgraph,
+ Scene *UNUSED(scene),
+ Object *ob,
+ Object *par,
+ int heat,
+ const bool mirror)
{
- /* This functions implements the automatic computation of vertex group
- * weights, either through envelopes or using a heat equilibrium.
- *
- * This function can be called both when parenting a mesh to an armature,
- * or in weightpaint + posemode. In the latter case selection is taken
- * into account and vertex weights can be mirrored.
- *
- * The mesh vertex positions used are either the final deformed coords
- * from the evaluated mesh in weightpaint mode, the final subsurf coords
- * when parenting, or simply the original mesh coords.
- */
-
- bArmature *arm = par->data;
- Bone **bonelist, *bone;
- bDeformGroup **dgrouplist, **dgroupflip;
- bDeformGroup *dgroup;
- bPoseChannel *pchan;
- Mesh *mesh;
- Mat4 bbone_array[MAX_BBONE_SUBDIV], *bbone = NULL;
- float (*root)[3], (*tip)[3], (*verts)[3];
- int *selected;
- int numbones, vertsfilled = 0, i, j, segments = 0;
- const bool wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT);
- struct { Object *armob; void *list; int heat; bool is_weight_paint; } looper_data;
-
- looper_data.armob = par;
- looper_data.heat = heat;
- looper_data.list = NULL;
- looper_data.is_weight_paint = wpmode;
-
- /* count the number of skinnable bones */
- numbones = bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb);
-
- if (numbones == 0)
- return;
-
- if (BKE_object_defgroup_data_create(ob->data) == NULL)
- return;
-
- /* create an array of pointer to bones that are skinnable
- * and fill it with all of the skinnable bones */
- bonelist = MEM_callocN(numbones * sizeof(Bone *), "bonelist");
- looper_data.list = bonelist;
- bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb);
-
- /* create an array of pointers to the deform groups that
- * correspond to the skinnable bones (creating them
- * as necessary. */
- dgrouplist = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgrouplist");
- dgroupflip = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgroupflip");
-
- looper_data.list = dgrouplist;
- bone_looper(ob, arm->bonebase.first, &looper_data, dgroup_skinnable_cb);
-
- /* create an array of root and tip positions transformed into
- * global coords */
- root = MEM_callocN(numbones * sizeof(float) * 3, "root");
- tip = MEM_callocN(numbones * sizeof(float) * 3, "tip");
- selected = MEM_callocN(numbones * sizeof(int), "selected");
-
- for (j = 0; j < numbones; ++j) {
- bone = bonelist[j];
- dgroup = dgrouplist[j];
-
- /* handle bbone */
- if (heat) {
- if (segments == 0) {
- segments = 1;
- bbone = NULL;
-
- if ((par->pose) && (pchan = BKE_pose_channel_find_name(par->pose, bone->name))) {
- if (bone->segments > 1) {
- segments = bone->segments;
- BKE_pchan_bbone_spline_setup(pchan, true, false, bbone_array);
- bbone = bbone_array;
- }
- }
- }
-
- segments--;
- }
-
- /* compute root and tip */
- if (bbone) {
- mul_v3_m4v3(root[j], bone->arm_mat, bbone[segments].mat[3]);
- if ((segments + 1) < bone->segments) {
- mul_v3_m4v3(tip[j], bone->arm_mat, bbone[segments + 1].mat[3]);
- }
- else {
- copy_v3_v3(tip[j], bone->arm_tail);
- }
- }
- else {
- copy_v3_v3(root[j], bone->arm_head);
- copy_v3_v3(tip[j], bone->arm_tail);
- }
-
- mul_m4_v3(par->obmat, root[j]);
- mul_m4_v3(par->obmat, tip[j]);
-
- /* set selected */
- if (wpmode) {
- if ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))
- selected[j] = 1;
- }
- else
- selected[j] = 1;
-
- /* find flipped group */
- if (dgroup && mirror) {
- char name_flip[MAXBONENAME];
-
- BLI_string_flip_side_name(name_flip, dgroup->name, false, sizeof(name_flip));
- dgroupflip[j] = defgroup_find_name(ob, name_flip);
- }
- }
-
- /* create verts */
- mesh = (Mesh *)ob->data;
- verts = MEM_callocN(mesh->totvert * sizeof(*verts), "closestboneverts");
-
- if (wpmode) {
- /* if in weight paint mode, use final verts from evaluated mesh */
- Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
-
- BKE_mesh_foreach_mapped_vert_coords_get(me_eval, verts, mesh->totvert);
- vertsfilled = 1;
- }
- else if (modifiers_findByType(ob, eModifierType_Subsurf)) {
- /* is subsurf on? Lets use the verts on the limit surface then.
- * = same amount of vertices as mesh, but vertices moved to the
- * subsurfed position, like for 'optimal'. */
- subsurf_calculate_limit_positions(mesh, verts);
- vertsfilled = 1;
- }
-
- /* transform verts to global space */
- for (i = 0; i < mesh->totvert; i++) {
- if (!vertsfilled)
- copy_v3_v3(verts[i], mesh->mvert[i].co);
- mul_m4_v3(ob->obmat, verts[i]);
- }
-
- /* compute the weights based on gathered vertices and bones */
- if (heat) {
- const char *error = NULL;
-
- heat_bone_weighting(
- ob, mesh, verts, numbones, dgrouplist, dgroupflip,
- root, tip, selected, &error);
- if (error) {
- BKE_report(reports, RPT_WARNING, error);
- }
- }
- else {
- envelope_bone_weighting(
- ob, mesh, verts, numbones, bonelist, dgrouplist,
- dgroupflip, root, tip, selected, mat4_to_scale(par->obmat));
- }
-
- /* only generated in some cases but can call anyway */
- ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 'e');
-
- /* free the memory allocated */
- MEM_freeN(bonelist);
- MEM_freeN(dgrouplist);
- MEM_freeN(dgroupflip);
- MEM_freeN(root);
- MEM_freeN(tip);
- MEM_freeN(selected);
- MEM_freeN(verts);
+ /* This functions implements the automatic computation of vertex group
+ * weights, either through envelopes or using a heat equilibrium.
+ *
+ * This function can be called both when parenting a mesh to an armature,
+ * or in weightpaint + posemode. In the latter case selection is taken
+ * into account and vertex weights can be mirrored.
+ *
+ * The mesh vertex positions used are either the final deformed coords
+ * from the evaluated mesh in weightpaint mode, the final subsurf coords
+ * when parenting, or simply the original mesh coords.
+ */
+
+ bArmature *arm = par->data;
+ Bone **bonelist, *bone;
+ bDeformGroup **dgrouplist, **dgroupflip;
+ bDeformGroup *dgroup;
+ bPoseChannel *pchan;
+ Mesh *mesh;
+ Mat4 bbone_array[MAX_BBONE_SUBDIV], *bbone = NULL;
+ float(*root)[3], (*tip)[3], (*verts)[3];
+ int *selected;
+ int numbones, vertsfilled = 0, i, j, segments = 0;
+ const bool wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT);
+ struct {
+ Object *armob;
+ void *list;
+ int heat;
+ bool is_weight_paint;
+ } looper_data;
+
+ looper_data.armob = par;
+ looper_data.heat = heat;
+ looper_data.list = NULL;
+ looper_data.is_weight_paint = wpmode;
+
+ /* count the number of skinnable bones */
+ numbones = bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb);
+
+ if (numbones == 0)
+ return;
+
+ if (BKE_object_defgroup_data_create(ob->data) == NULL)
+ return;
+
+ /* create an array of pointer to bones that are skinnable
+ * and fill it with all of the skinnable bones */
+ bonelist = MEM_callocN(numbones * sizeof(Bone *), "bonelist");
+ looper_data.list = bonelist;
+ bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb);
+
+ /* create an array of pointers to the deform groups that
+ * correspond to the skinnable bones (creating them
+ * as necessary. */
+ dgrouplist = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgrouplist");
+ dgroupflip = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgroupflip");
+
+ looper_data.list = dgrouplist;
+ bone_looper(ob, arm->bonebase.first, &looper_data, dgroup_skinnable_cb);
+
+ /* create an array of root and tip positions transformed into
+ * global coords */
+ root = MEM_callocN(numbones * sizeof(float) * 3, "root");
+ tip = MEM_callocN(numbones * sizeof(float) * 3, "tip");
+ selected = MEM_callocN(numbones * sizeof(int), "selected");
+
+ for (j = 0; j < numbones; ++j) {
+ bone = bonelist[j];
+ dgroup = dgrouplist[j];
+
+ /* handle bbone */
+ if (heat) {
+ if (segments == 0) {
+ segments = 1;
+ bbone = NULL;
+
+ if ((par->pose) && (pchan = BKE_pose_channel_find_name(par->pose, bone->name))) {
+ if (bone->segments > 1) {
+ segments = bone->segments;
+ BKE_pchan_bbone_spline_setup(pchan, true, false, bbone_array);
+ bbone = bbone_array;
+ }
+ }
+ }
+
+ segments--;
+ }
+
+ /* compute root and tip */
+ if (bbone) {
+ mul_v3_m4v3(root[j], bone->arm_mat, bbone[segments].mat[3]);
+ if ((segments + 1) < bone->segments) {
+ mul_v3_m4v3(tip[j], bone->arm_mat, bbone[segments + 1].mat[3]);
+ }
+ else {
+ copy_v3_v3(tip[j], bone->arm_tail);
+ }
+ }
+ else {
+ copy_v3_v3(root[j], bone->arm_head);
+ copy_v3_v3(tip[j], bone->arm_tail);
+ }
+
+ mul_m4_v3(par->obmat, root[j]);
+ mul_m4_v3(par->obmat, tip[j]);
+
+ /* set selected */
+ if (wpmode) {
+ if ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))
+ selected[j] = 1;
+ }
+ else
+ selected[j] = 1;
+
+ /* find flipped group */
+ if (dgroup && mirror) {
+ char name_flip[MAXBONENAME];
+
+ BLI_string_flip_side_name(name_flip, dgroup->name, false, sizeof(name_flip));
+ dgroupflip[j] = defgroup_find_name(ob, name_flip);
+ }
+ }
+
+ /* create verts */
+ mesh = (Mesh *)ob->data;
+ verts = MEM_callocN(mesh->totvert * sizeof(*verts), "closestboneverts");
+
+ if (wpmode) {
+ /* if in weight paint mode, use final verts from evaluated mesh */
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
+
+ BKE_mesh_foreach_mapped_vert_coords_get(me_eval, verts, mesh->totvert);
+ vertsfilled = 1;
+ }
+ else if (modifiers_findByType(ob, eModifierType_Subsurf)) {
+ /* is subsurf on? Lets use the verts on the limit surface then.
+ * = same amount of vertices as mesh, but vertices moved to the
+ * subsurfed position, like for 'optimal'. */
+ subsurf_calculate_limit_positions(mesh, verts);
+ vertsfilled = 1;
+ }
+
+ /* transform verts to global space */
+ for (i = 0; i < mesh->totvert; i++) {
+ if (!vertsfilled)
+ copy_v3_v3(verts[i], mesh->mvert[i].co);
+ mul_m4_v3(ob->obmat, verts[i]);
+ }
+
+ /* compute the weights based on gathered vertices and bones */
+ if (heat) {
+ const char *error = NULL;
+
+ heat_bone_weighting(
+ ob, mesh, verts, numbones, dgrouplist, dgroupflip, root, tip, selected, &error);
+ if (error) {
+ BKE_report(reports, RPT_WARNING, error);
+ }
+ }
+ else {
+ envelope_bone_weighting(ob,
+ mesh,
+ verts,
+ numbones,
+ bonelist,
+ dgrouplist,
+ dgroupflip,
+ root,
+ tip,
+ selected,
+ mat4_to_scale(par->obmat));
+ }
+
+ /* only generated in some cases but can call anyway */
+ ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 'e');
+
+ /* free the memory allocated */
+ MEM_freeN(bonelist);
+ MEM_freeN(dgrouplist);
+ MEM_freeN(dgroupflip);
+ MEM_freeN(root);
+ MEM_freeN(tip);
+ MEM_freeN(selected);
+ MEM_freeN(verts);
}
-void ED_object_vgroup_calc_from_armature(
- ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, Object *par,
- const int mode, const bool mirror)
+void ED_object_vgroup_calc_from_armature(ReportList *reports,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ Object *par,
+ const int mode,
+ const bool mirror)
{
- /* Lets try to create some vertex groups
- * based on the bones of the parent armature.
- */
- bArmature *arm = par->data;
-
- if (mode == ARM_GROUPS_NAME) {
- const int defbase_tot = BLI_listbase_count(&ob->defbase);
- int defbase_add;
- /* Traverse the bone list, trying to create empty vertex
- * groups corresponding to the bone.
- */
- defbase_add = bone_looper(ob, arm->bonebase.first, NULL, vgroup_add_unique_bone_cb);
-
- if (defbase_add) {
- /* its possible there are DWeight's outside the range of the current
- * objects deform groups, in this case the new groups wont be empty [#33889] */
- ED_vgroup_data_clamp_range(ob->data, defbase_tot);
- }
- }
- else if (ELEM(mode, ARM_GROUPS_ENVELOPE, ARM_GROUPS_AUTO)) {
- /* Traverse the bone list, trying to create vertex groups
- * that are populated with the vertices for which the
- * bone is closest.
- */
- add_verts_to_dgroups(reports, depsgraph, scene, ob, par, (mode == ARM_GROUPS_AUTO), mirror);
- }
+ /* Lets try to create some vertex groups
+ * based on the bones of the parent armature.
+ */
+ bArmature *arm = par->data;
+
+ if (mode == ARM_GROUPS_NAME) {
+ const int defbase_tot = BLI_listbase_count(&ob->defbase);
+ int defbase_add;
+ /* Traverse the bone list, trying to create empty vertex
+ * groups corresponding to the bone.
+ */
+ defbase_add = bone_looper(ob, arm->bonebase.first, NULL, vgroup_add_unique_bone_cb);
+
+ if (defbase_add) {
+ /* its possible there are DWeight's outside the range of the current
+ * objects deform groups, in this case the new groups wont be empty [#33889] */
+ ED_vgroup_data_clamp_range(ob->data, defbase_tot);
+ }
+ }
+ else if (ELEM(mode, ARM_GROUPS_ENVELOPE, ARM_GROUPS_AUTO)) {
+ /* Traverse the bone list, trying to create vertex groups
+ * that are populated with the vertices for which the
+ * bone is closest.
+ */
+ add_verts_to_dgroups(reports, depsgraph, scene, ob, par, (mode == ARM_GROUPS_AUTO), mirror);
+ }
}
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index 465209eb9c5..50289197ed4 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -50,34 +50,34 @@
/* Sync selection to parent for connected children */
void ED_armature_edit_sync_selection(ListBase *edbo)
{
- EditBone *ebo;
-
- for (ebo = edbo->first; ebo; ebo = ebo->next) {
- /* if bone is not selectable, we shouldn't alter this setting... */
- if ((ebo->flag & BONE_UNSELECTABLE) == 0) {
- if ((ebo->flag & BONE_CONNECTED) && (ebo->parent)) {
- if (ebo->parent->flag & BONE_TIPSEL)
- ebo->flag |= BONE_ROOTSEL;
- else
- ebo->flag &= ~BONE_ROOTSEL;
- }
-
- if ((ebo->flag & BONE_TIPSEL) && (ebo->flag & BONE_ROOTSEL))
- ebo->flag |= BONE_SELECTED;
- else
- ebo->flag &= ~BONE_SELECTED;
- }
- }
+ EditBone *ebo;
+
+ for (ebo = edbo->first; ebo; ebo = ebo->next) {
+ /* if bone is not selectable, we shouldn't alter this setting... */
+ if ((ebo->flag & BONE_UNSELECTABLE) == 0) {
+ if ((ebo->flag & BONE_CONNECTED) && (ebo->parent)) {
+ if (ebo->parent->flag & BONE_TIPSEL)
+ ebo->flag |= BONE_ROOTSEL;
+ else
+ ebo->flag &= ~BONE_ROOTSEL;
+ }
+
+ if ((ebo->flag & BONE_TIPSEL) && (ebo->flag & BONE_ROOTSEL))
+ ebo->flag |= BONE_SELECTED;
+ else
+ ebo->flag &= ~BONE_SELECTED;
+ }
+ }
}
void ED_armature_edit_validate_active(struct bArmature *arm)
{
- EditBone *ebone = arm->act_edbone;
+ EditBone *ebone = arm->act_edbone;
- if (ebone) {
- if (ebone->flag & BONE_HIDDEN_A)
- arm->act_edbone = NULL;
- }
+ if (ebone) {
+ if (ebone->flag & BONE_HIDDEN_A)
+ arm->act_edbone = NULL;
+ }
}
/* *************************************************************** */
@@ -85,31 +85,30 @@ void ED_armature_edit_validate_active(struct bArmature *arm)
/* XXX bone_looper is only to be used when we want to access settings
* (i.e. editability/visibility/selected) that context doesn't offer */
-int bone_looper(Object *ob, Bone *bone, void *data,
- int (*bone_func)(Object *, Bone *, void *))
+int bone_looper(Object *ob, Bone *bone, void *data, int (*bone_func)(Object *, Bone *, void *))
{
- /* We want to apply the function bone_func to every bone
- * in an armature -- feed bone_looper the first bone and
- * a pointer to the bone_func and watch it go!. The int count
- * can be useful for counting bones with a certain property
- * (e.g. skinnable)
- */
- int count = 0;
+ /* We want to apply the function bone_func to every bone
+ * in an armature -- feed bone_looper the first bone and
+ * a pointer to the bone_func and watch it go!. The int count
+ * can be useful for counting bones with a certain property
+ * (e.g. skinnable)
+ */
+ int count = 0;
- if (bone) {
- /* only do bone_func if the bone is non null */
- count += bone_func(ob, bone, data);
+ if (bone) {
+ /* only do bone_func if the bone is non null */
+ count += bone_func(ob, bone, data);
- /* try to execute bone_func for the first child */
- count += bone_looper(ob, bone->childbase.first, data, bone_func);
+ /* try to execute bone_func for the first child */
+ count += bone_looper(ob, bone->childbase.first, data, bone_func);
- /* try to execute bone_func for the next bone at this
- * depth of the recursion.
- */
- count += bone_looper(ob, bone->next, data, bone_func);
- }
+ /* try to execute bone_func for the next bone at this
+ * depth of the recursion.
+ */
+ count += bone_looper(ob, bone->next, data, bone_func);
+ }
- return count;
+ return count;
}
/* *************************************************************** */
@@ -117,25 +116,25 @@ int bone_looper(Object *ob, Bone *bone, void *data,
void bone_free(bArmature *arm, EditBone *bone)
{
- if (arm->act_edbone == bone)
- arm->act_edbone = NULL;
+ if (arm->act_edbone == bone)
+ arm->act_edbone = NULL;
- if (bone->prop) {
- IDP_FreeProperty(bone->prop);
- MEM_freeN(bone->prop);
- }
+ if (bone->prop) {
+ IDP_FreeProperty(bone->prop);
+ MEM_freeN(bone->prop);
+ }
- /* Clear references from other edit bones. */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (ebone->bbone_next == bone) {
- ebone->bbone_next = NULL;
- }
- if (ebone->bbone_prev == bone) {
- ebone->bbone_prev = NULL;
- }
- }
+ /* Clear references from other edit bones. */
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->bbone_next == bone) {
+ ebone->bbone_next = NULL;
+ }
+ if (ebone->bbone_prev == bone) {
+ ebone->bbone_prev = NULL;
+ }
+ }
- BLI_freelinkN(arm->edbo, bone);
+ BLI_freelinkN(arm->edbo, bone);
}
/**
@@ -143,33 +142,33 @@ void bone_free(bArmature *arm, EditBone *bone)
*/
void ED_armature_ebone_remove_ex(bArmature *arm, EditBone *exBone, bool clear_connected)
{
- EditBone *curBone;
+ EditBone *curBone;
- /* Find any bones that refer to this bone */
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- if (curBone->parent == exBone) {
- curBone->parent = exBone->parent;
- if (clear_connected) {
- curBone->flag &= ~BONE_CONNECTED;
- }
- }
- }
+ /* Find any bones that refer to this bone */
+ for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
+ if (curBone->parent == exBone) {
+ curBone->parent = exBone->parent;
+ if (clear_connected) {
+ curBone->flag &= ~BONE_CONNECTED;
+ }
+ }
+ }
- bone_free(arm, exBone);
+ bone_free(arm, exBone);
}
void ED_armature_ebone_remove(bArmature *arm, EditBone *exBone)
{
- ED_armature_ebone_remove_ex(arm, exBone, true);
+ ED_armature_ebone_remove_ex(arm, exBone, true);
}
bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebone_child)
{
- for (ebone_child = ebone_child->parent; ebone_child; ebone_child = ebone_child->parent) {
- if (ebone_child == ebone_parent)
- return true;
- }
- return false;
+ for (ebone_child = ebone_child->parent; ebone_child; ebone_child = ebone_child->parent) {
+ if (ebone_child == ebone_parent)
+ return true;
+ }
+ return false;
}
/**
@@ -179,81 +178,82 @@ bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebon
* \param ebone_child_tot: Size of the ebone_child array
* \return The shared parent or NULL.
*/
-EditBone *ED_armature_ebone_find_shared_parent(EditBone *ebone_child[], const unsigned int ebone_child_tot)
+EditBone *ED_armature_ebone_find_shared_parent(EditBone *ebone_child[],
+ const unsigned int ebone_child_tot)
{
- unsigned int i;
- EditBone *ebone_iter;
+ unsigned int i;
+ EditBone *ebone_iter;
#define EBONE_TEMP_UINT(ebone) (*((unsigned int *)(&((ebone)->temp))))
- /* clear all */
- for (i = 0; i < ebone_child_tot; i++) {
- for (ebone_iter = ebone_child[i]; ebone_iter; ebone_iter = ebone_iter->parent) {
- EBONE_TEMP_UINT(ebone_iter) = 0;
- }
- }
-
- /* accumulate */
- for (i = 0; i < ebone_child_tot; i++) {
- for (ebone_iter = ebone_child[i]->parent; ebone_iter; ebone_iter = ebone_iter->parent) {
- EBONE_TEMP_UINT(ebone_iter) += 1;
- }
- }
-
- /* only need search the first chain */
- for (ebone_iter = ebone_child[0]->parent; ebone_iter; ebone_iter = ebone_iter->parent) {
- if (EBONE_TEMP_UINT(ebone_iter) == ebone_child_tot) {
- return ebone_iter;
- }
- }
+ /* clear all */
+ for (i = 0; i < ebone_child_tot; i++) {
+ for (ebone_iter = ebone_child[i]; ebone_iter; ebone_iter = ebone_iter->parent) {
+ EBONE_TEMP_UINT(ebone_iter) = 0;
+ }
+ }
+
+ /* accumulate */
+ for (i = 0; i < ebone_child_tot; i++) {
+ for (ebone_iter = ebone_child[i]->parent; ebone_iter; ebone_iter = ebone_iter->parent) {
+ EBONE_TEMP_UINT(ebone_iter) += 1;
+ }
+ }
+
+ /* only need search the first chain */
+ for (ebone_iter = ebone_child[0]->parent; ebone_iter; ebone_iter = ebone_iter->parent) {
+ if (EBONE_TEMP_UINT(ebone_iter) == ebone_child_tot) {
+ return ebone_iter;
+ }
+ }
#undef EBONE_TEMP_UINT
- return NULL;
+ return NULL;
}
void ED_armature_ebone_to_mat3(EditBone *ebone, float mat[3][3])
{
- float delta[3];
+ float delta[3];
- /* Find the current bone matrix */
- sub_v3_v3v3(delta, ebone->tail, ebone->head);
- vec_roll_to_mat3(delta, ebone->roll, mat);
+ /* Find the current bone matrix */
+ sub_v3_v3v3(delta, ebone->tail, ebone->head);
+ vec_roll_to_mat3(delta, ebone->roll, mat);
}
void ED_armature_ebone_to_mat4(EditBone *ebone, float mat[4][4])
{
- float m3[3][3];
+ float m3[3][3];
- ED_armature_ebone_to_mat3(ebone, m3);
+ ED_armature_ebone_to_mat3(ebone, m3);
- copy_m4_m3(mat, m3);
- copy_v3_v3(mat[3], ebone->head);
+ copy_m4_m3(mat, m3);
+ copy_v3_v3(mat[3], ebone->head);
}
void ED_armature_ebone_from_mat3(EditBone *ebone, float mat[3][3])
{
- float vec[3], roll;
- const float len = len_v3v3(ebone->head, ebone->tail);
+ float vec[3], roll;
+ const float len = len_v3v3(ebone->head, ebone->tail);
- mat3_to_vec_roll(mat, vec, &roll);
+ mat3_to_vec_roll(mat, vec, &roll);
- madd_v3_v3v3fl(ebone->tail, ebone->head, vec, len);
- ebone->roll = roll;
+ madd_v3_v3v3fl(ebone->tail, ebone->head, vec, len);
+ ebone->roll = roll;
}
void ED_armature_ebone_from_mat4(EditBone *ebone, float mat[4][4])
{
- float mat3[3][3];
+ float mat3[3][3];
- copy_m3_m4(mat3, mat);
- /* We want normalized matrix here, to be consistent with ebone_to_mat. */
- BLI_ASSERT_UNIT_M3(mat3);
+ copy_m3_m4(mat3, mat);
+ /* We want normalized matrix here, to be consistent with ebone_to_mat. */
+ BLI_ASSERT_UNIT_M3(mat3);
- sub_v3_v3(ebone->tail, ebone->head);
- copy_v3_v3(ebone->head, mat[3]);
- add_v3_v3(ebone->tail, mat[3]);
- ED_armature_ebone_from_mat3(ebone, mat3);
+ sub_v3_v3(ebone->tail, ebone->head);
+ copy_v3_v3(ebone->head, mat[3]);
+ add_v3_v3(ebone->tail, mat[3]);
+ ED_armature_ebone_from_mat3(ebone, mat3);
}
/**
@@ -261,10 +261,9 @@ void ED_armature_ebone_from_mat4(EditBone *ebone, float mat[4][4])
*/
EditBone *ED_armature_ebone_find_name(const ListBase *edbo, const char *name)
{
- return BLI_findstring(edbo, name, offsetof(EditBone, name));
+ return BLI_findstring(edbo, name, offsetof(EditBone, name));
}
-
/* *************************************************************** */
/* Mirroring */
@@ -273,18 +272,18 @@ EditBone *ED_armature_ebone_find_name(const ListBase *edbo, const char *name)
*/
EditBone *ED_armature_ebone_get_mirrored(const ListBase *edbo, EditBone *ebo)
{
- char name_flip[MAXBONENAME];
+ char name_flip[MAXBONENAME];
- if (ebo == NULL)
- return NULL;
+ if (ebo == NULL)
+ return NULL;
- BLI_string_flip_side_name(name_flip, ebo->name, false, sizeof(name_flip));
+ BLI_string_flip_side_name(name_flip, ebo->name, false, sizeof(name_flip));
- if (!STREQ(name_flip, ebo->name)) {
- return ED_armature_ebone_find_name(edbo, name_flip);
- }
+ if (!STREQ(name_flip, ebo->name)) {
+ return ED_armature_ebone_find_name(edbo, name_flip);
+ }
- return NULL;
+ return NULL;
}
/* ------------------------------------- */
@@ -293,70 +292,69 @@ EditBone *ED_armature_ebone_get_mirrored(const ListBase *edbo, EditBone *ebo)
* it leaves mirrored bones selected then too, which is a good indication of what happened */
void armature_select_mirrored_ex(bArmature *arm, const int flag)
{
- BLI_assert((flag & ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) == 0);
- /* Select mirrored bones */
- if (arm->flag & ARM_MIRROR_EDIT) {
- EditBone *curBone, *ebone_mirr;
-
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- if (arm->layer & curBone->layer) {
- if (curBone->flag & flag) {
- ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, curBone);
- if (ebone_mirr)
- ebone_mirr->flag |= (curBone->flag & flag);
- }
- }
- }
- }
+ BLI_assert((flag & ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) == 0);
+ /* Select mirrored bones */
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ EditBone *curBone, *ebone_mirr;
+ for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
+ if (arm->layer & curBone->layer) {
+ if (curBone->flag & flag) {
+ ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, curBone);
+ if (ebone_mirr)
+ ebone_mirr->flag |= (curBone->flag & flag);
+ }
+ }
+ }
+ }
}
void armature_select_mirrored(bArmature *arm)
{
- armature_select_mirrored_ex(arm, BONE_SELECTED);
+ armature_select_mirrored_ex(arm, BONE_SELECTED);
}
void armature_tag_select_mirrored(bArmature *arm)
{
- EditBone *curBone;
-
- /* always untag */
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- curBone->flag &= ~BONE_DONE;
- }
-
- /* Select mirrored bones */
- if (arm->flag & ARM_MIRROR_EDIT) {
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- if (arm->layer & curBone->layer) {
- if (curBone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) {
- EditBone *ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, curBone);
- if (ebone_mirr && (ebone_mirr->flag & BONE_SELECTED) == 0) {
- ebone_mirr->flag |= BONE_DONE;
- }
- }
- }
- }
-
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- if (curBone->flag & BONE_DONE) {
- EditBone *ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, curBone);
- curBone->flag |= ebone_mirr->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
- }
- }
- }
+ EditBone *curBone;
+
+ /* always untag */
+ for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
+ curBone->flag &= ~BONE_DONE;
+ }
+
+ /* Select mirrored bones */
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
+ if (arm->layer & curBone->layer) {
+ if (curBone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) {
+ EditBone *ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, curBone);
+ if (ebone_mirr && (ebone_mirr->flag & BONE_SELECTED) == 0) {
+ ebone_mirr->flag |= BONE_DONE;
+ }
+ }
+ }
+ }
+
+ for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
+ if (curBone->flag & BONE_DONE) {
+ EditBone *ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, curBone);
+ curBone->flag |= ebone_mirr->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+ }
+ }
+ }
}
/* only works when tagged */
void armature_tag_unselect(bArmature *arm)
{
- EditBone *curBone;
+ EditBone *curBone;
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- if (curBone->flag & BONE_DONE) {
- curBone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL | BONE_DONE);
- }
- }
+ for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
+ if (curBone->flag & BONE_DONE) {
+ curBone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL | BONE_DONE);
+ }
+ }
}
/* ------------------------------------- */
@@ -365,186 +363,189 @@ void armature_tag_unselect(bArmature *arm)
/* context; editmode armature, with mirror editing enabled */
void ED_armature_edit_transform_mirror_update(Object *obedit)
{
- bArmature *arm = obedit->data;
- EditBone *ebo, *eboflip;
-
- for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
- /* no layer check, correct mirror is more important */
- if (ebo->flag & (BONE_TIPSEL | BONE_ROOTSEL)) {
- eboflip = ED_armature_ebone_get_mirrored(arm->edbo, ebo);
-
- if (eboflip) {
- /* we assume X-axis flipping for now */
- if (ebo->flag & BONE_TIPSEL) {
- EditBone *children;
-
- eboflip->tail[0] = -ebo->tail[0];
- eboflip->tail[1] = ebo->tail[1];
- eboflip->tail[2] = ebo->tail[2];
- eboflip->rad_tail = ebo->rad_tail;
- eboflip->roll = -ebo->roll;
- eboflip->curveOutX = -ebo->curveOutX;
- eboflip->roll2 = -ebo->roll2;
-
- /* Also move connected children, in case children's name aren't mirrored properly */
- for (children = arm->edbo->first; children; children = children->next) {
- if (children->parent == eboflip && children->flag & BONE_CONNECTED) {
- copy_v3_v3(children->head, eboflip->tail);
- children->rad_head = ebo->rad_tail;
- }
- }
- }
- if (ebo->flag & BONE_ROOTSEL) {
- eboflip->head[0] = -ebo->head[0];
- eboflip->head[1] = ebo->head[1];
- eboflip->head[2] = ebo->head[2];
- eboflip->rad_head = ebo->rad_head;
- eboflip->roll = -ebo->roll;
- eboflip->curveInX = -ebo->curveInX;
- eboflip->roll1 = -ebo->roll1;
-
- /* Also move connected parent, in case parent's name isn't mirrored properly */
- if (eboflip->parent && eboflip->flag & BONE_CONNECTED) {
- EditBone *parent = eboflip->parent;
- copy_v3_v3(parent->tail, eboflip->head);
- parent->rad_tail = ebo->rad_head;
- }
- }
- if (ebo->flag & BONE_SELECTED) {
- eboflip->dist = ebo->dist;
- eboflip->roll = -ebo->roll;
- eboflip->xwidth = ebo->xwidth;
- eboflip->zwidth = ebo->zwidth;
-
- eboflip->curveInX = -ebo->curveInX;
- eboflip->curveOutX = -ebo->curveOutX;
- eboflip->roll1 = -ebo->roll1;
- eboflip->roll2 = -ebo->roll2;
- }
- }
- }
- }
+ bArmature *arm = obedit->data;
+ EditBone *ebo, *eboflip;
+
+ for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ /* no layer check, correct mirror is more important */
+ if (ebo->flag & (BONE_TIPSEL | BONE_ROOTSEL)) {
+ eboflip = ED_armature_ebone_get_mirrored(arm->edbo, ebo);
+
+ if (eboflip) {
+ /* we assume X-axis flipping for now */
+ if (ebo->flag & BONE_TIPSEL) {
+ EditBone *children;
+
+ eboflip->tail[0] = -ebo->tail[0];
+ eboflip->tail[1] = ebo->tail[1];
+ eboflip->tail[2] = ebo->tail[2];
+ eboflip->rad_tail = ebo->rad_tail;
+ eboflip->roll = -ebo->roll;
+ eboflip->curveOutX = -ebo->curveOutX;
+ eboflip->roll2 = -ebo->roll2;
+
+ /* Also move connected children, in case children's name aren't mirrored properly */
+ for (children = arm->edbo->first; children; children = children->next) {
+ if (children->parent == eboflip && children->flag & BONE_CONNECTED) {
+ copy_v3_v3(children->head, eboflip->tail);
+ children->rad_head = ebo->rad_tail;
+ }
+ }
+ }
+ if (ebo->flag & BONE_ROOTSEL) {
+ eboflip->head[0] = -ebo->head[0];
+ eboflip->head[1] = ebo->head[1];
+ eboflip->head[2] = ebo->head[2];
+ eboflip->rad_head = ebo->rad_head;
+ eboflip->roll = -ebo->roll;
+ eboflip->curveInX = -ebo->curveInX;
+ eboflip->roll1 = -ebo->roll1;
+
+ /* Also move connected parent, in case parent's name isn't mirrored properly */
+ if (eboflip->parent && eboflip->flag & BONE_CONNECTED) {
+ EditBone *parent = eboflip->parent;
+ copy_v3_v3(parent->tail, eboflip->head);
+ parent->rad_tail = ebo->rad_head;
+ }
+ }
+ if (ebo->flag & BONE_SELECTED) {
+ eboflip->dist = ebo->dist;
+ eboflip->roll = -ebo->roll;
+ eboflip->xwidth = ebo->xwidth;
+ eboflip->zwidth = ebo->zwidth;
+
+ eboflip->curveInX = -ebo->curveInX;
+ eboflip->curveOutX = -ebo->curveOutX;
+ eboflip->roll1 = -ebo->roll1;
+ eboflip->roll2 = -ebo->roll2;
+ }
+ }
+ }
+ }
}
/* *************************************************************** */
/* Armature EditMode Conversions */
/* converts Bones to EditBone list, used for tools as well */
-static EditBone *make_boneList_rec(ListBase *edbo, ListBase *bones, EditBone *parent, Bone *actBone)
-{
- EditBone *eBone;
- EditBone *eBoneAct = NULL;
- EditBone *eBoneTest = NULL;
- Bone *curBone;
-
- for (curBone = bones->first; curBone; curBone = curBone->next) {
- eBone = MEM_callocN(sizeof(EditBone), "make_editbone");
- eBone->temp.bone = curBone;
-
- /* Copy relevant data from bone to eBone
- * Keep selection logic in sync with ED_armature_edit_sync_selection.
- */
- eBone->parent = parent;
- BLI_strncpy(eBone->name, curBone->name, sizeof(eBone->name));
- eBone->flag = curBone->flag;
-
- /* fix selection flags */
- if (eBone->flag & BONE_SELECTED) {
- /* if the bone is selected the copy its root selection to the parents tip */
- eBone->flag |= BONE_TIPSEL;
- if (eBone->parent && (eBone->flag & BONE_CONNECTED)) {
- eBone->parent->flag |= BONE_TIPSEL;
- }
-
- /* For connected bones, take care when changing the selection when we have a connected parent,
- * this flag is a copy of '(eBone->parent->flag & BONE_TIPSEL)'. */
- eBone->flag |= BONE_ROOTSEL;
- }
- else {
- /* if the bone is not selected, but connected to its parent
- * always use the parents tip selection state */
- if (eBone->parent && (eBone->flag & BONE_CONNECTED)) {
- eBone->flag &= ~BONE_ROOTSEL;
- }
- }
-
- copy_v3_v3(eBone->head, curBone->arm_head);
- copy_v3_v3(eBone->tail, curBone->arm_tail);
- eBone->roll = curBone->arm_roll;
-
- /* rest of stuff copy */
- eBone->length = curBone->length;
- eBone->dist = curBone->dist;
- eBone->weight = curBone->weight;
- eBone->xwidth = curBone->xwidth;
- eBone->zwidth = curBone->zwidth;
- eBone->rad_head = curBone->rad_head;
- eBone->rad_tail = curBone->rad_tail;
- eBone->segments = curBone->segments;
- eBone->layer = curBone->layer;
-
- /* Bendy-Bone parameters */
- eBone->roll1 = curBone->roll1;
- eBone->roll2 = curBone->roll2;
- eBone->curveInX = curBone->curveInX;
- eBone->curveInY = curBone->curveInY;
- eBone->curveOutX = curBone->curveOutX;
- eBone->curveOutY = curBone->curveOutY;
- eBone->ease1 = curBone->ease1;
- eBone->ease2 = curBone->ease2;
- eBone->scaleIn = curBone->scaleIn;
- eBone->scaleOut = curBone->scaleOut;
-
- eBone->bbone_prev_type = curBone->bbone_prev_type;
- eBone->bbone_next_type = curBone->bbone_next_type;
-
- if (curBone->prop)
- eBone->prop = IDP_CopyProperty(curBone->prop);
-
- BLI_addtail(edbo, eBone);
-
- /* Add children if necessary */
- if (curBone->childbase.first) {
- eBoneTest = make_boneList_rec(edbo, &curBone->childbase, eBone, actBone);
- if (eBoneTest)
- eBoneAct = eBoneTest;
- }
-
- if (curBone == actBone)
- eBoneAct = eBone;
- }
-
- return eBoneAct;
+static EditBone *make_boneList_rec(ListBase *edbo,
+ ListBase *bones,
+ EditBone *parent,
+ Bone *actBone)
+{
+ EditBone *eBone;
+ EditBone *eBoneAct = NULL;
+ EditBone *eBoneTest = NULL;
+ Bone *curBone;
+
+ for (curBone = bones->first; curBone; curBone = curBone->next) {
+ eBone = MEM_callocN(sizeof(EditBone), "make_editbone");
+ eBone->temp.bone = curBone;
+
+ /* Copy relevant data from bone to eBone
+ * Keep selection logic in sync with ED_armature_edit_sync_selection.
+ */
+ eBone->parent = parent;
+ BLI_strncpy(eBone->name, curBone->name, sizeof(eBone->name));
+ eBone->flag = curBone->flag;
+
+ /* fix selection flags */
+ if (eBone->flag & BONE_SELECTED) {
+ /* if the bone is selected the copy its root selection to the parents tip */
+ eBone->flag |= BONE_TIPSEL;
+ if (eBone->parent && (eBone->flag & BONE_CONNECTED)) {
+ eBone->parent->flag |= BONE_TIPSEL;
+ }
+
+ /* For connected bones, take care when changing the selection when we have a connected parent,
+ * this flag is a copy of '(eBone->parent->flag & BONE_TIPSEL)'. */
+ eBone->flag |= BONE_ROOTSEL;
+ }
+ else {
+ /* if the bone is not selected, but connected to its parent
+ * always use the parents tip selection state */
+ if (eBone->parent && (eBone->flag & BONE_CONNECTED)) {
+ eBone->flag &= ~BONE_ROOTSEL;
+ }
+ }
+
+ copy_v3_v3(eBone->head, curBone->arm_head);
+ copy_v3_v3(eBone->tail, curBone->arm_tail);
+ eBone->roll = curBone->arm_roll;
+
+ /* rest of stuff copy */
+ eBone->length = curBone->length;
+ eBone->dist = curBone->dist;
+ eBone->weight = curBone->weight;
+ eBone->xwidth = curBone->xwidth;
+ eBone->zwidth = curBone->zwidth;
+ eBone->rad_head = curBone->rad_head;
+ eBone->rad_tail = curBone->rad_tail;
+ eBone->segments = curBone->segments;
+ eBone->layer = curBone->layer;
+
+ /* Bendy-Bone parameters */
+ eBone->roll1 = curBone->roll1;
+ eBone->roll2 = curBone->roll2;
+ eBone->curveInX = curBone->curveInX;
+ eBone->curveInY = curBone->curveInY;
+ eBone->curveOutX = curBone->curveOutX;
+ eBone->curveOutY = curBone->curveOutY;
+ eBone->ease1 = curBone->ease1;
+ eBone->ease2 = curBone->ease2;
+ eBone->scaleIn = curBone->scaleIn;
+ eBone->scaleOut = curBone->scaleOut;
+
+ eBone->bbone_prev_type = curBone->bbone_prev_type;
+ eBone->bbone_next_type = curBone->bbone_next_type;
+
+ if (curBone->prop)
+ eBone->prop = IDP_CopyProperty(curBone->prop);
+
+ BLI_addtail(edbo, eBone);
+
+ /* Add children if necessary */
+ if (curBone->childbase.first) {
+ eBoneTest = make_boneList_rec(edbo, &curBone->childbase, eBone, actBone);
+ if (eBoneTest)
+ eBoneAct = eBoneTest;
+ }
+
+ if (curBone == actBone)
+ eBoneAct = eBone;
+ }
+
+ return eBoneAct;
}
static EditBone *find_ebone_link(ListBase *edbo, Bone *link)
{
- if (link != NULL) {
- for (EditBone *ebone = edbo->first; ebone; ebone = ebone->next) {
- if (ebone->temp.bone == link) {
- return ebone;
- }
- }
- }
+ if (link != NULL) {
+ for (EditBone *ebone = edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->temp.bone == link) {
+ return ebone;
+ }
+ }
+ }
- return NULL;
+ return NULL;
}
EditBone *make_boneList(ListBase *edbo, ListBase *bones, struct Bone *actBone)
{
- BLI_assert(!edbo->first && !edbo->last);
+ BLI_assert(!edbo->first && !edbo->last);
- EditBone *active = make_boneList_rec(edbo, bones, NULL, actBone);
+ EditBone *active = make_boneList_rec(edbo, bones, NULL, actBone);
- for (EditBone *ebone = edbo->first; ebone; ebone = ebone->next) {
- Bone *bone = ebone->temp.bone;
+ for (EditBone *ebone = edbo->first; ebone; ebone = ebone->next) {
+ Bone *bone = ebone->temp.bone;
- /* Convert custom B-Bone handle links. */
- ebone->bbone_prev = find_ebone_link(edbo, bone->bbone_prev);
- ebone->bbone_next = find_ebone_link(edbo, bone->bbone_next);
- }
+ /* Convert custom B-Bone handle links. */
+ ebone->bbone_prev = find_ebone_link(edbo, bone->bbone_prev);
+ ebone->bbone_next = find_ebone_link(edbo, bone->bbone_next);
+ }
- return active;
+ return active;
}
/**
@@ -559,217 +560,217 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, struct Bone *actBone)
*/
static void armature_finalize_restpose(ListBase *bonelist, ListBase *editbonelist)
{
- Bone *curBone;
- EditBone *ebone;
+ Bone *curBone;
+ EditBone *ebone;
- for (curBone = bonelist->first; curBone; curBone = curBone->next) {
- /* Set bone's local head/tail.
- * Note that it's important to use final parent's restpose (arm_mat) here, instead of setting those values
- * from editbone's matrix (see T46010). */
- if (curBone->parent) {
- float parmat_inv[4][4];
+ for (curBone = bonelist->first; curBone; curBone = curBone->next) {
+ /* Set bone's local head/tail.
+ * Note that it's important to use final parent's restpose (arm_mat) here, instead of setting those values
+ * from editbone's matrix (see T46010). */
+ if (curBone->parent) {
+ float parmat_inv[4][4];
- invert_m4_m4(parmat_inv, curBone->parent->arm_mat);
+ invert_m4_m4(parmat_inv, curBone->parent->arm_mat);
- /* Get the new head and tail */
- sub_v3_v3v3(curBone->head, curBone->arm_head, curBone->parent->arm_tail);
- sub_v3_v3v3(curBone->tail, curBone->arm_tail, curBone->parent->arm_tail);
+ /* Get the new head and tail */
+ sub_v3_v3v3(curBone->head, curBone->arm_head, curBone->parent->arm_tail);
+ sub_v3_v3v3(curBone->tail, curBone->arm_tail, curBone->parent->arm_tail);
- mul_mat3_m4_v3(parmat_inv, curBone->head);
- mul_mat3_m4_v3(parmat_inv, curBone->tail);
- }
- else {
- copy_v3_v3(curBone->head, curBone->arm_head);
- copy_v3_v3(curBone->tail, curBone->arm_tail);
- }
+ mul_mat3_m4_v3(parmat_inv, curBone->head);
+ mul_mat3_m4_v3(parmat_inv, curBone->tail);
+ }
+ else {
+ copy_v3_v3(curBone->head, curBone->arm_head);
+ copy_v3_v3(curBone->tail, curBone->arm_tail);
+ }
- /* Set local matrix and arm_mat (restpose).
- * Do not recurse into children here, armature_finalize_restpose() is already recursive. */
- BKE_armature_where_is_bone(curBone, curBone->parent, false);
+ /* Set local matrix and arm_mat (restpose).
+ * Do not recurse into children here, armature_finalize_restpose() is already recursive. */
+ BKE_armature_where_is_bone(curBone, curBone->parent, false);
- /* Find the associated editbone */
- for (ebone = editbonelist->first; ebone; ebone = ebone->next) {
- if (ebone->temp.bone == curBone) {
- float premat[3][3];
- float postmat[3][3];
- float difmat[3][3];
- float imat[3][3];
+ /* Find the associated editbone */
+ for (ebone = editbonelist->first; ebone; ebone = ebone->next) {
+ if (ebone->temp.bone == curBone) {
+ float premat[3][3];
+ float postmat[3][3];
+ float difmat[3][3];
+ float imat[3][3];
- /* Get the ebone premat and its inverse. */
- ED_armature_ebone_to_mat3(ebone, premat);
- invert_m3_m3(imat, premat);
+ /* Get the ebone premat and its inverse. */
+ ED_armature_ebone_to_mat3(ebone, premat);
+ invert_m3_m3(imat, premat);
- /* Get the bone postmat. */
- copy_m3_m4(postmat, curBone->arm_mat);
+ /* Get the bone postmat. */
+ copy_m3_m4(postmat, curBone->arm_mat);
- mul_m3_m3m3(difmat, imat, postmat);
+ mul_m3_m3m3(difmat, imat, postmat);
#if 0
- printf("Bone %s\n", curBone->name);
- print_m4("premat", premat);
- print_m4("postmat", postmat);
- print_m4("difmat", difmat);
- printf("Roll = %f\n", RAD2DEGF(-atan2(difmat[2][0], difmat[2][2])));
+ printf("Bone %s\n", curBone->name);
+ print_m4("premat", premat);
+ print_m4("postmat", postmat);
+ print_m4("difmat", difmat);
+ printf("Roll = %f\n", RAD2DEGF(-atan2(difmat[2][0], difmat[2][2])));
#endif
- curBone->roll = -atan2f(difmat[2][0], difmat[2][2]);
+ curBone->roll = -atan2f(difmat[2][0], difmat[2][2]);
- /* and set restposition again */
- BKE_armature_where_is_bone(curBone, curBone->parent, false);
- break;
- }
- }
+ /* and set restposition again */
+ BKE_armature_where_is_bone(curBone, curBone->parent, false);
+ break;
+ }
+ }
- /* Recurse into children... */
- armature_finalize_restpose(&curBone->childbase, editbonelist);
- }
+ /* Recurse into children... */
+ armature_finalize_restpose(&curBone->childbase, editbonelist);
+ }
}
/* put EditMode back in Object */
void ED_armature_from_edit(Main *bmain, bArmature *arm)
{
- EditBone *eBone, *neBone;
- Bone *newBone;
- Object *obt;
-
- /* armature bones */
- BKE_armature_bonelist_free(&arm->bonebase);
- arm->act_bone = NULL;
-
- /* remove zero sized bones, this gives unstable restposes */
- for (eBone = arm->edbo->first; eBone; eBone = neBone) {
- float len_sq = len_squared_v3v3(eBone->head, eBone->tail);
- neBone = eBone->next;
- if (len_sq <= SQUARE(0.000001f)) { /* FLT_EPSILON is too large? */
- EditBone *fBone;
-
- /* Find any bones that refer to this bone */
- for (fBone = arm->edbo->first; fBone; fBone = fBone->next) {
- if (fBone->parent == eBone)
- fBone->parent = eBone->parent;
- }
- if (G.debug & G_DEBUG)
- printf("Warning: removed zero sized bone: %s\n", eBone->name);
- bone_free(arm, eBone);
- }
- }
-
- /* Copy the bones from the editData into the armature */
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- newBone = MEM_callocN(sizeof(Bone), "bone");
- eBone->temp.bone = newBone; /* Associate the real Bones with the EditBones */
-
- BLI_strncpy(newBone->name, eBone->name, sizeof(newBone->name));
- copy_v3_v3(newBone->arm_head, eBone->head);
- copy_v3_v3(newBone->arm_tail, eBone->tail);
- newBone->arm_roll = eBone->roll;
-
- newBone->flag = eBone->flag;
-
- if (eBone == arm->act_edbone) {
- /* don't change active selection, this messes up separate which uses
- * editmode toggle and can separate active bone which is de-selected originally */
-
- /* important, editbones can be active with only 1 point selected */
- /* newBone->flag |= BONE_SELECTED; */
- arm->act_bone = newBone;
- }
- newBone->roll = 0.0f;
-
- newBone->weight = eBone->weight;
- newBone->dist = eBone->dist;
-
- newBone->xwidth = eBone->xwidth;
- newBone->zwidth = eBone->zwidth;
- newBone->rad_head = eBone->rad_head;
- newBone->rad_tail = eBone->rad_tail;
- newBone->segments = eBone->segments;
- newBone->layer = eBone->layer;
-
- /* Bendy-Bone parameters */
- newBone->roll1 = eBone->roll1;
- newBone->roll2 = eBone->roll2;
- newBone->curveInX = eBone->curveInX;
- newBone->curveInY = eBone->curveInY;
- newBone->curveOutX = eBone->curveOutX;
- newBone->curveOutY = eBone->curveOutY;
- newBone->ease1 = eBone->ease1;
- newBone->ease2 = eBone->ease2;
- newBone->scaleIn = eBone->scaleIn;
- newBone->scaleOut = eBone->scaleOut;
-
- newBone->bbone_prev_type = eBone->bbone_prev_type;
- newBone->bbone_next_type = eBone->bbone_next_type;
-
- if (eBone->prop)
- newBone->prop = IDP_CopyProperty(eBone->prop);
- }
-
- /* Fix parenting in a separate pass to ensure ebone->bone connections are valid at this point.
- * Do not set bone->head/tail here anymore,
- * using EditBone data for that is not OK since our later fiddling with parent's arm_mat
- * (for roll conversion) may have some small but visible impact on locations (T46010). */
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- newBone = eBone->temp.bone;
- if (eBone->parent) {
- newBone->parent = eBone->parent->temp.bone;
- BLI_addtail(&newBone->parent->childbase, newBone);
- }
- /* ...otherwise add this bone to the armature's bonebase */
- else {
- BLI_addtail(&arm->bonebase, newBone);
- }
-
- /* Also transfer B-Bone custom handles. */
- if (eBone->bbone_prev) {
- newBone->bbone_prev = eBone->bbone_prev->temp.bone;
- }
- if (eBone->bbone_next) {
- newBone->bbone_next = eBone->bbone_next->temp.bone;
- }
- }
-
- /* Finalize definition of restpose data (roll, bone_mat, arm_mat, head/tail...). */
- armature_finalize_restpose(&arm->bonebase, arm->edbo);
-
- /* so all users of this armature should get rebuilt */
- for (obt = bmain->objects.first; obt; obt = obt->id.next) {
- if (obt->data == arm) {
- BKE_pose_rebuild(bmain, obt, arm, true);
- }
- }
-
- DEG_id_tag_update(&arm->id, 0);
+ EditBone *eBone, *neBone;
+ Bone *newBone;
+ Object *obt;
+
+ /* armature bones */
+ BKE_armature_bonelist_free(&arm->bonebase);
+ arm->act_bone = NULL;
+
+ /* remove zero sized bones, this gives unstable restposes */
+ for (eBone = arm->edbo->first; eBone; eBone = neBone) {
+ float len_sq = len_squared_v3v3(eBone->head, eBone->tail);
+ neBone = eBone->next;
+ if (len_sq <= SQUARE(0.000001f)) { /* FLT_EPSILON is too large? */
+ EditBone *fBone;
+
+ /* Find any bones that refer to this bone */
+ for (fBone = arm->edbo->first; fBone; fBone = fBone->next) {
+ if (fBone->parent == eBone)
+ fBone->parent = eBone->parent;
+ }
+ if (G.debug & G_DEBUG)
+ printf("Warning: removed zero sized bone: %s\n", eBone->name);
+ bone_free(arm, eBone);
+ }
+ }
+
+ /* Copy the bones from the editData into the armature */
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ newBone = MEM_callocN(sizeof(Bone), "bone");
+ eBone->temp.bone = newBone; /* Associate the real Bones with the EditBones */
+
+ BLI_strncpy(newBone->name, eBone->name, sizeof(newBone->name));
+ copy_v3_v3(newBone->arm_head, eBone->head);
+ copy_v3_v3(newBone->arm_tail, eBone->tail);
+ newBone->arm_roll = eBone->roll;
+
+ newBone->flag = eBone->flag;
+
+ if (eBone == arm->act_edbone) {
+ /* don't change active selection, this messes up separate which uses
+ * editmode toggle and can separate active bone which is de-selected originally */
+
+ /* important, editbones can be active with only 1 point selected */
+ /* newBone->flag |= BONE_SELECTED; */
+ arm->act_bone = newBone;
+ }
+ newBone->roll = 0.0f;
+
+ newBone->weight = eBone->weight;
+ newBone->dist = eBone->dist;
+
+ newBone->xwidth = eBone->xwidth;
+ newBone->zwidth = eBone->zwidth;
+ newBone->rad_head = eBone->rad_head;
+ newBone->rad_tail = eBone->rad_tail;
+ newBone->segments = eBone->segments;
+ newBone->layer = eBone->layer;
+
+ /* Bendy-Bone parameters */
+ newBone->roll1 = eBone->roll1;
+ newBone->roll2 = eBone->roll2;
+ newBone->curveInX = eBone->curveInX;
+ newBone->curveInY = eBone->curveInY;
+ newBone->curveOutX = eBone->curveOutX;
+ newBone->curveOutY = eBone->curveOutY;
+ newBone->ease1 = eBone->ease1;
+ newBone->ease2 = eBone->ease2;
+ newBone->scaleIn = eBone->scaleIn;
+ newBone->scaleOut = eBone->scaleOut;
+
+ newBone->bbone_prev_type = eBone->bbone_prev_type;
+ newBone->bbone_next_type = eBone->bbone_next_type;
+
+ if (eBone->prop)
+ newBone->prop = IDP_CopyProperty(eBone->prop);
+ }
+
+ /* Fix parenting in a separate pass to ensure ebone->bone connections are valid at this point.
+ * Do not set bone->head/tail here anymore,
+ * using EditBone data for that is not OK since our later fiddling with parent's arm_mat
+ * (for roll conversion) may have some small but visible impact on locations (T46010). */
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ newBone = eBone->temp.bone;
+ if (eBone->parent) {
+ newBone->parent = eBone->parent->temp.bone;
+ BLI_addtail(&newBone->parent->childbase, newBone);
+ }
+ /* ...otherwise add this bone to the armature's bonebase */
+ else {
+ BLI_addtail(&arm->bonebase, newBone);
+ }
+
+ /* Also transfer B-Bone custom handles. */
+ if (eBone->bbone_prev) {
+ newBone->bbone_prev = eBone->bbone_prev->temp.bone;
+ }
+ if (eBone->bbone_next) {
+ newBone->bbone_next = eBone->bbone_next->temp.bone;
+ }
+ }
+
+ /* Finalize definition of restpose data (roll, bone_mat, arm_mat, head/tail...). */
+ armature_finalize_restpose(&arm->bonebase, arm->edbo);
+
+ /* so all users of this armature should get rebuilt */
+ for (obt = bmain->objects.first; obt; obt = obt->id.next) {
+ if (obt->data == arm) {
+ BKE_pose_rebuild(bmain, obt, arm, true);
+ }
+ }
+
+ DEG_id_tag_update(&arm->id, 0);
}
void ED_armature_edit_free(struct bArmature *arm)
{
- EditBone *eBone;
+ EditBone *eBone;
- /* Clear the editbones list */
- if (arm->edbo) {
- if (arm->edbo->first) {
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- if (eBone->prop) {
- IDP_FreeProperty(eBone->prop);
- MEM_freeN(eBone->prop);
- }
- }
+ /* Clear the editbones list */
+ if (arm->edbo) {
+ if (arm->edbo->first) {
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ if (eBone->prop) {
+ IDP_FreeProperty(eBone->prop);
+ MEM_freeN(eBone->prop);
+ }
+ }
- BLI_freelistN(arm->edbo);
- }
- MEM_freeN(arm->edbo);
- arm->edbo = NULL;
- arm->act_edbone = NULL;
- }
+ BLI_freelistN(arm->edbo);
+ }
+ MEM_freeN(arm->edbo);
+ arm->edbo = NULL;
+ arm->act_edbone = NULL;
+ }
}
/* Put armature in EditMode */
void ED_armature_to_edit(bArmature *arm)
{
- ED_armature_edit_free(arm);
- arm->edbo = MEM_callocN(sizeof(ListBase), "edbo armature");
- arm->act_edbone = make_boneList(arm->edbo, &arm->bonebase, arm->act_bone);
+ ED_armature_edit_free(arm);
+ arm->edbo = MEM_callocN(sizeof(ListBase), "edbo armature");
+ arm->act_edbone = make_boneList(arm->edbo, &arm->bonebase, arm->act_bone);
}
/* *************************************************************** */
@@ -779,59 +780,59 @@ void ED_armature_to_edit(bArmature *arm)
void ED_armature_ebone_listbase_free(ListBase *lb)
{
- EditBone *ebone, *ebone_next;
+ EditBone *ebone, *ebone_next;
- for (ebone = lb->first; ebone; ebone = ebone_next) {
- ebone_next = ebone->next;
+ for (ebone = lb->first; ebone; ebone = ebone_next) {
+ ebone_next = ebone->next;
- if (ebone->prop) {
- IDP_FreeProperty(ebone->prop);
- MEM_freeN(ebone->prop);
- }
+ if (ebone->prop) {
+ IDP_FreeProperty(ebone->prop);
+ MEM_freeN(ebone->prop);
+ }
- MEM_freeN(ebone);
- }
+ MEM_freeN(ebone);
+ }
- BLI_listbase_clear(lb);
+ BLI_listbase_clear(lb);
}
void ED_armature_ebone_listbase_copy(ListBase *lb_dst, ListBase *lb_src)
{
- EditBone *ebone_src;
- EditBone *ebone_dst;
-
- BLI_assert(BLI_listbase_is_empty(lb_dst));
-
- for (ebone_src = lb_src->first; ebone_src; ebone_src = ebone_src->next) {
- ebone_dst = MEM_dupallocN(ebone_src);
- if (ebone_dst->prop) {
- ebone_dst->prop = IDP_CopyProperty(ebone_dst->prop);
- }
- ebone_src->temp.ebone = ebone_dst;
- BLI_addtail(lb_dst, ebone_dst);
- }
-
- /* set pointers */
- for (ebone_dst = lb_dst->first; ebone_dst; ebone_dst = ebone_dst->next) {
- if (ebone_dst->parent) {
- ebone_dst->parent = ebone_dst->parent->temp.ebone;
- }
- if (ebone_dst->bbone_next) {
- ebone_dst->bbone_next = ebone_dst->bbone_next->temp.ebone;
- }
- if (ebone_dst->bbone_prev) {
- ebone_dst->bbone_prev = ebone_dst->bbone_prev->temp.ebone;
- }
- }
+ EditBone *ebone_src;
+ EditBone *ebone_dst;
+
+ BLI_assert(BLI_listbase_is_empty(lb_dst));
+
+ for (ebone_src = lb_src->first; ebone_src; ebone_src = ebone_src->next) {
+ ebone_dst = MEM_dupallocN(ebone_src);
+ if (ebone_dst->prop) {
+ ebone_dst->prop = IDP_CopyProperty(ebone_dst->prop);
+ }
+ ebone_src->temp.ebone = ebone_dst;
+ BLI_addtail(lb_dst, ebone_dst);
+ }
+
+ /* set pointers */
+ for (ebone_dst = lb_dst->first; ebone_dst; ebone_dst = ebone_dst->next) {
+ if (ebone_dst->parent) {
+ ebone_dst->parent = ebone_dst->parent->temp.ebone;
+ }
+ if (ebone_dst->bbone_next) {
+ ebone_dst->bbone_next = ebone_dst->bbone_next->temp.ebone;
+ }
+ if (ebone_dst->bbone_prev) {
+ ebone_dst->bbone_prev = ebone_dst->bbone_prev->temp.ebone;
+ }
+ }
}
void ED_armature_ebone_listbase_temp_clear(ListBase *lb)
{
- EditBone *ebone;
- /* be sure they don't hang ever */
- for (ebone = lb->first; ebone; ebone = ebone->next) {
- ebone->temp.p = NULL;
- }
+ EditBone *ebone;
+ /* be sure they don't hang ever */
+ for (ebone = lb->first; ebone; ebone = ebone->next) {
+ ebone->temp.p = NULL;
+ }
}
/* *************************************************************** */
@@ -841,54 +842,54 @@ void ED_armature_ebone_listbase_temp_clear(ListBase *lb)
int ED_armature_ebone_selectflag_get(const EditBone *ebone)
{
- if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
- return ((ebone->flag & (BONE_SELECTED | BONE_TIPSEL)) |
- ((ebone->parent->flag & BONE_TIPSEL) ? BONE_ROOTSEL : 0));
- }
- else {
- return (ebone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL));
- }
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ return ((ebone->flag & (BONE_SELECTED | BONE_TIPSEL)) |
+ ((ebone->parent->flag & BONE_TIPSEL) ? BONE_ROOTSEL : 0));
+ }
+ else {
+ return (ebone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL));
+ }
}
void ED_armature_ebone_selectflag_set(EditBone *ebone, int flag)
{
- flag = flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+ flag = flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
- if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
- ebone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
- ebone->parent->flag &= ~BONE_TIPSEL;
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ ebone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+ ebone->parent->flag &= ~BONE_TIPSEL;
- ebone->flag |= flag;
- ebone->parent->flag |= (flag & BONE_ROOTSEL) ? BONE_TIPSEL : 0;
- }
- else {
- ebone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
- ebone->flag |= flag;
- }
+ ebone->flag |= flag;
+ ebone->parent->flag |= (flag & BONE_ROOTSEL) ? BONE_TIPSEL : 0;
+ }
+ else {
+ ebone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+ ebone->flag |= flag;
+ }
}
void ED_armature_ebone_selectflag_enable(EditBone *ebone, int flag)
{
- BLI_assert((flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) != 0);
- ED_armature_ebone_selectflag_set(ebone, ebone->flag | flag);
+ BLI_assert((flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) != 0);
+ ED_armature_ebone_selectflag_set(ebone, ebone->flag | flag);
}
void ED_armature_ebone_selectflag_disable(EditBone *ebone, int flag)
{
- BLI_assert((flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) != 0);
- ED_armature_ebone_selectflag_set(ebone, ebone->flag & ~flag);
+ BLI_assert((flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) != 0);
+ ED_armature_ebone_selectflag_set(ebone, ebone->flag & ~flag);
}
/* could be used in more places */
void ED_armature_ebone_select_set(EditBone *ebone, bool select)
{
- int flag;
- if (select) {
- BLI_assert((ebone->flag & BONE_UNSELECTABLE) == 0);
- flag = (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else {
- flag = 0;
- }
- ED_armature_ebone_selectflag_set(ebone, flag);
+ int flag;
+ if (select) {
+ BLI_assert((ebone->flag & BONE_UNSELECTABLE) == 0);
+ flag = (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else {
+ flag = 0;
+ }
+ ED_armature_ebone_selectflag_set(ebone, flag);
}
diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c
index 39e8371a824..3a2440af2da 100644
--- a/source/blender/editors/armature/editarmature_undo.c
+++ b/source/blender/editors/armature/editarmature_undo.c
@@ -23,7 +23,6 @@
#include "MEM_guardedalloc.h"
-
#include "CLG_log.h"
#include "DNA_armature_types.h"
@@ -53,69 +52,69 @@ static CLG_LogRef LOG = {"ed.undo.armature"};
* \{ */
typedef struct UndoArmature {
- EditBone *act_edbone;
- ListBase lb;
- size_t undo_size;
+ EditBone *act_edbone;
+ ListBase lb;
+ size_t undo_size;
} UndoArmature;
static void undoarm_to_editarm(UndoArmature *uarm, bArmature *arm)
{
- EditBone *ebone;
+ EditBone *ebone;
- ED_armature_ebone_listbase_free(arm->edbo);
- ED_armature_ebone_listbase_copy(arm->edbo, &uarm->lb);
+ ED_armature_ebone_listbase_free(arm->edbo);
+ ED_armature_ebone_listbase_copy(arm->edbo, &uarm->lb);
- /* active bone */
- if (uarm->act_edbone) {
- ebone = uarm->act_edbone;
- arm->act_edbone = ebone->temp.ebone;
- }
- else {
- arm->act_edbone = NULL;
- }
+ /* active bone */
+ if (uarm->act_edbone) {
+ ebone = uarm->act_edbone;
+ arm->act_edbone = ebone->temp.ebone;
+ }
+ else {
+ arm->act_edbone = NULL;
+ }
- ED_armature_ebone_listbase_temp_clear(arm->edbo);
+ ED_armature_ebone_listbase_temp_clear(arm->edbo);
}
static void *undoarm_from_editarm(UndoArmature *uarm, bArmature *arm)
{
- BLI_assert(BLI_array_is_zeroed(uarm, 1));
+ BLI_assert(BLI_array_is_zeroed(uarm, 1));
- /* TODO: include size of ID-properties. */
- uarm->undo_size = 0;
+ /* TODO: include size of ID-properties. */
+ uarm->undo_size = 0;
- ED_armature_ebone_listbase_copy(&uarm->lb, arm->edbo);
+ ED_armature_ebone_listbase_copy(&uarm->lb, arm->edbo);
- /* active bone */
- if (arm->act_edbone) {
- EditBone *ebone = arm->act_edbone;
- uarm->act_edbone = ebone->temp.ebone;
- }
+ /* active bone */
+ if (arm->act_edbone) {
+ EditBone *ebone = arm->act_edbone;
+ uarm->act_edbone = ebone->temp.ebone;
+ }
- ED_armature_ebone_listbase_temp_clear(&uarm->lb);
+ ED_armature_ebone_listbase_temp_clear(&uarm->lb);
- for (EditBone *ebone = uarm->lb.first; ebone; ebone = ebone->next) {
- uarm->undo_size += sizeof(EditBone);
- }
+ for (EditBone *ebone = uarm->lb.first; ebone; ebone = ebone->next) {
+ uarm->undo_size += sizeof(EditBone);
+ }
- return uarm;
+ return uarm;
}
static void undoarm_free_data(UndoArmature *uarm)
{
- ED_armature_ebone_listbase_free(&uarm->lb);
+ ED_armature_ebone_listbase_free(&uarm->lb);
}
static Object *editarm_object_from_context(bContext *C)
{
- Object *obedit = CTX_data_edit_object(C);
- if (obedit && obedit->type == OB_ARMATURE) {
- bArmature *arm = obedit->data;
- if (arm->edbo != NULL) {
- return obedit;
- }
- }
- return NULL;
+ Object *obedit = CTX_data_edit_object(C);
+ if (obedit && obedit->type == OB_ARMATURE) {
+ bArmature *arm = obedit->data;
+ if (arm->edbo != NULL) {
+ return obedit;
+ }
+ }
+ return NULL;
}
/** \} */
@@ -127,112 +126,124 @@ static Object *editarm_object_from_context(bContext *C)
* \{ */
typedef struct ArmatureUndoStep_Elem {
- struct ArmatureUndoStep_Elem *next, *prev;
- UndoRefID_Object obedit_ref;
- UndoArmature data;
+ struct ArmatureUndoStep_Elem *next, *prev;
+ UndoRefID_Object obedit_ref;
+ UndoArmature data;
} ArmatureUndoStep_Elem;
typedef struct ArmatureUndoStep {
- UndoStep step;
- ArmatureUndoStep_Elem *elems;
- uint elems_len;
+ UndoStep step;
+ ArmatureUndoStep_Elem *elems;
+ uint elems_len;
} ArmatureUndoStep;
static bool armature_undosys_poll(bContext *C)
{
- return editarm_object_from_context(C) != NULL;
+ return editarm_object_from_context(C) != NULL;
}
-static bool armature_undosys_step_encode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p)
+static bool armature_undosys_step_encode(struct bContext *C,
+ struct Main *UNUSED(bmain),
+ UndoStep *us_p)
{
- ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
-
- /* Important not to use the 3D view when getting objects because all objects
- * outside of this list will be moved out of edit-mode when reading back undo steps. */
- ViewLayer *view_layer = CTX_data_view_layer(C);
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, NULL, &objects_len);
-
- us->elems = MEM_callocN(sizeof(*us->elems) * objects_len, __func__);
- us->elems_len = objects_len;
-
- for (uint i = 0; i < objects_len; i++) {
- Object *ob = objects[i];
- ArmatureUndoStep_Elem *elem = &us->elems[i];
-
- elem->obedit_ref.ptr = ob;
- bArmature *arm = elem->obedit_ref.ptr->data;
- undoarm_from_editarm(&elem->data, arm);
- us->step.data_size += elem->data.undo_size;
- }
- MEM_freeN(objects);
- return true;
+ ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
+
+ /* Important not to use the 3D view when getting objects because all objects
+ * outside of this list will be moved out of edit-mode when reading back undo steps. */
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, NULL, &objects_len);
+
+ us->elems = MEM_callocN(sizeof(*us->elems) * objects_len, __func__);
+ us->elems_len = objects_len;
+
+ for (uint i = 0; i < objects_len; i++) {
+ Object *ob = objects[i];
+ ArmatureUndoStep_Elem *elem = &us->elems[i];
+
+ elem->obedit_ref.ptr = ob;
+ bArmature *arm = elem->obedit_ref.ptr->data;
+ undoarm_from_editarm(&elem->data, arm);
+ us->step.data_size += elem->data.undo_size;
+ }
+ MEM_freeN(objects);
+ return true;
}
-static void armature_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, int UNUSED(dir))
+static void armature_undosys_step_decode(struct bContext *C,
+ struct Main *UNUSED(bmain),
+ UndoStep *us_p,
+ int UNUSED(dir))
{
- ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
-
- /* Load all our objects into edit-mode, clear everything else. */
- ED_undo_object_editmode_restore_helper(C, &us->elems[0].obedit_ref.ptr, us->elems_len, sizeof(*us->elems));
-
- BLI_assert(armature_undosys_poll(C));
-
- for (uint i = 0; i < us->elems_len; i++) {
- ArmatureUndoStep_Elem *elem = &us->elems[i];
- Object *obedit = elem->obedit_ref.ptr;
- bArmature *arm = obedit->data;
- if (arm->edbo == NULL) {
- /* Should never fail, may not crash but can give odd behavior. */
- CLOG_ERROR(&LOG, "name='%s', failed to enter edit-mode for object '%s', undo state invalid", us_p->name, obedit->id.name);
- continue;
- }
- undoarm_to_editarm(&elem->data, arm);
- DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
- }
-
- /* The first element is always active */
- ED_undo_object_set_active_or_warn(CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG);
-
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
+ ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
+
+ /* Load all our objects into edit-mode, clear everything else. */
+ ED_undo_object_editmode_restore_helper(
+ C, &us->elems[0].obedit_ref.ptr, us->elems_len, sizeof(*us->elems));
+
+ BLI_assert(armature_undosys_poll(C));
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ ArmatureUndoStep_Elem *elem = &us->elems[i];
+ Object *obedit = elem->obedit_ref.ptr;
+ bArmature *arm = obedit->data;
+ if (arm->edbo == NULL) {
+ /* Should never fail, may not crash but can give odd behavior. */
+ CLOG_ERROR(&LOG,
+ "name='%s', failed to enter edit-mode for object '%s', undo state invalid",
+ us_p->name,
+ obedit->id.name);
+ continue;
+ }
+ undoarm_to_editarm(&elem->data, arm);
+ DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
+ }
+
+ /* The first element is always active */
+ ED_undo_object_set_active_or_warn(
+ CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG);
+
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
}
static void armature_undosys_step_free(UndoStep *us_p)
{
- ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
+ ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
- for (uint i = 0; i < us->elems_len; i++) {
- ArmatureUndoStep_Elem *elem = &us->elems[i];
- undoarm_free_data(&elem->data);
- }
- MEM_freeN(us->elems);
+ for (uint i = 0; i < us->elems_len; i++) {
+ ArmatureUndoStep_Elem *elem = &us->elems[i];
+ undoarm_free_data(&elem->data);
+ }
+ MEM_freeN(us->elems);
}
-static void armature_undosys_foreach_ID_ref(
- UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
+static void armature_undosys_foreach_ID_ref(UndoStep *us_p,
+ UndoTypeForEachIDRefFn foreach_ID_ref_fn,
+ void *user_data)
{
- ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
+ ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
- for (uint i = 0; i < us->elems_len; i++) {
- ArmatureUndoStep_Elem *elem = &us->elems[i];
- foreach_ID_ref_fn(user_data, ((UndoRefID *)&elem->obedit_ref));
- }
+ for (uint i = 0; i < us->elems_len; i++) {
+ ArmatureUndoStep_Elem *elem = &us->elems[i];
+ foreach_ID_ref_fn(user_data, ((UndoRefID *)&elem->obedit_ref));
+ }
}
/* Export for ED_undo_sys. */
void ED_armature_undosys_type(UndoType *ut)
{
- ut->name = "Edit Armature";
- ut->poll = armature_undosys_poll;
- ut->step_encode = armature_undosys_step_encode;
- ut->step_decode = armature_undosys_step_decode;
- ut->step_free = armature_undosys_step_free;
+ ut->name = "Edit Armature";
+ ut->poll = armature_undosys_poll;
+ ut->step_encode = armature_undosys_step_encode;
+ ut->step_decode = armature_undosys_step_decode;
+ ut->step_free = armature_undosys_step_free;
- ut->step_foreach_ID_ref = armature_undosys_foreach_ID_ref;
+ ut->step_foreach_ID_ref = armature_undosys_foreach_ID_ref;
- ut->use_context = true;
+ ut->use_context = true;
- ut->step_size = sizeof(ArmatureUndoStep);
+ ut->step_size = sizeof(ArmatureUndoStep);
}
/** \} */
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index 66bd7a8db80..febe2a49174 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -49,53 +49,63 @@
#include "meshlaplacian.h"
/* ************* XXX *************** */
-static void waitcursor(int UNUSED(val)) {}
-static void progress_bar(int UNUSED(dummy_val), const char *UNUSED(dummy)) {}
-static void start_progress_bar(void) {}
-static void end_progress_bar(void) {}
-static void error(const char *str) { printf("error: %s\n", str); }
+static void waitcursor(int UNUSED(val))
+{
+}
+static void progress_bar(int UNUSED(dummy_val), const char *UNUSED(dummy))
+{
+}
+static void start_progress_bar(void)
+{
+}
+static void end_progress_bar(void)
+{
+}
+static void error(const char *str)
+{
+ printf("error: %s\n", str);
+}
/* ************* XXX *************** */
-
/************************** Laplacian System *****************************/
struct LaplacianSystem {
- LinearSolver *context; /* linear solver */
-
- int totvert, totface;
-
- float **verts; /* vertex coordinates */
- float *varea; /* vertex weights for laplacian computation */
- char *vpinned; /* vertex pinning */
- int (*faces)[3]; /* face vertex indices */
- float (*fweights)[3]; /* cotangent weights per face */
-
- int areaweights; /* use area in cotangent weights? */
- int storeweights; /* store cotangent weights in fweights */
- bool variablesdone; /* variables set in linear system */
-
- EdgeHash *edgehash; /* edge hash for construction */
-
- struct HeatWeighting {
- const MLoopTri *mlooptri;
- const MLoop *mloop; /* needed to find vertices by index */
- int totvert;
- int tottri;
- float (*verts)[3]; /* vertex coordinates */
- float (*vnors)[3]; /* vertex normals */
-
- float (*root)[3]; /* bone root */
- float (*tip)[3]; /* bone tip */
- float (*source)[3]; /* vertex source */
- int numsource;
-
- float *H; /* diagonal H matrix */
- float *p; /* values from all p vectors */
- float *mindist; /* minimum distance to a bone for all vertices */
-
- BVHTree *bvhtree; /* ray tracing acceleration structure */
- const MLoopTri **vltree; /* a looptri that the vertex belongs to */
- } heat;
+ LinearSolver *context; /* linear solver */
+
+ int totvert, totface;
+
+ float **verts; /* vertex coordinates */
+ float *varea; /* vertex weights for laplacian computation */
+ char *vpinned; /* vertex pinning */
+ int (*faces)[3]; /* face vertex indices */
+ float (*fweights)[3]; /* cotangent weights per face */
+
+ int areaweights; /* use area in cotangent weights? */
+ int storeweights; /* store cotangent weights in fweights */
+ bool variablesdone; /* variables set in linear system */
+
+ EdgeHash *edgehash; /* edge hash for construction */
+
+ struct HeatWeighting {
+ const MLoopTri *mlooptri;
+ const MLoop *mloop; /* needed to find vertices by index */
+ int totvert;
+ int tottri;
+ float (*verts)[3]; /* vertex coordinates */
+ float (*vnors)[3]; /* vertex normals */
+
+ float (*root)[3]; /* bone root */
+ float (*tip)[3]; /* bone tip */
+ float (*source)[3]; /* vertex source */
+ int numsource;
+
+ float *H; /* diagonal H matrix */
+ float *p; /* values from all p vectors */
+ float *mindist; /* minimum distance to a bone for all vertices */
+
+ BVHTree *bvhtree; /* ray tracing acceleration structure */
+ const MLoopTri **vltree; /* a looptri that the vertex belongs to */
+ } heat;
};
/* Laplacian matrix construction */
@@ -110,676 +120,685 @@ struct LaplacianSystem {
static void laplacian_increase_edge_count(EdgeHash *edgehash, int v1, int v2)
{
- void **p;
+ void **p;
- if (BLI_edgehash_ensure_p(edgehash, v1, v2, &p))
- *p = (void *)((intptr_t)*p + (intptr_t)1);
- else
- *p = (void *)((intptr_t)1);
+ if (BLI_edgehash_ensure_p(edgehash, v1, v2, &p))
+ *p = (void *)((intptr_t)*p + (intptr_t)1);
+ else
+ *p = (void *)((intptr_t)1);
}
static int laplacian_edge_count(EdgeHash *edgehash, int v1, int v2)
{
- return (int)(intptr_t)BLI_edgehash_lookup(edgehash, v1, v2);
+ return (int)(intptr_t)BLI_edgehash_lookup(edgehash, v1, v2);
}
static void laplacian_triangle_area(LaplacianSystem *sys, int i1, int i2, int i3)
{
- float t1, t2, t3, len1, len2, len3, area;
- float *varea = sys->varea, *v1, *v2, *v3;
- int obtuse = 0;
-
- v1 = sys->verts[i1];
- v2 = sys->verts[i2];
- v3 = sys->verts[i3];
-
- t1 = cotangent_tri_weight_v3(v1, v2, v3);
- t2 = cotangent_tri_weight_v3(v2, v3, v1);
- t3 = cotangent_tri_weight_v3(v3, v1, v2);
-
- if (angle_v3v3v3(v2, v1, v3) > DEG2RADF(90.0f)) obtuse = 1;
- else if (angle_v3v3v3(v1, v2, v3) > DEG2RADF(90.0f)) obtuse = 2;
- else if (angle_v3v3v3(v1, v3, v2) > DEG2RADF(90.0f)) obtuse = 3;
-
- if (obtuse > 0) {
- area = area_tri_v3(v1, v2, v3);
-
- varea[i1] += (obtuse == 1) ? area : area * 0.5f;
- varea[i2] += (obtuse == 2) ? area : area * 0.5f;
- varea[i3] += (obtuse == 3) ? area : area * 0.5f;
- }
- else {
- len1 = len_v3v3(v2, v3);
- len2 = len_v3v3(v1, v3);
- len3 = len_v3v3(v1, v2);
-
- t1 *= len1 * len1;
- t2 *= len2 * len2;
- t3 *= len3 * len3;
-
- varea[i1] += (t2 + t3) * 0.25f;
- varea[i2] += (t1 + t3) * 0.25f;
- varea[i3] += (t1 + t2) * 0.25f;
- }
+ float t1, t2, t3, len1, len2, len3, area;
+ float *varea = sys->varea, *v1, *v2, *v3;
+ int obtuse = 0;
+
+ v1 = sys->verts[i1];
+ v2 = sys->verts[i2];
+ v3 = sys->verts[i3];
+
+ t1 = cotangent_tri_weight_v3(v1, v2, v3);
+ t2 = cotangent_tri_weight_v3(v2, v3, v1);
+ t3 = cotangent_tri_weight_v3(v3, v1, v2);
+
+ if (angle_v3v3v3(v2, v1, v3) > DEG2RADF(90.0f))
+ obtuse = 1;
+ else if (angle_v3v3v3(v1, v2, v3) > DEG2RADF(90.0f))
+ obtuse = 2;
+ else if (angle_v3v3v3(v1, v3, v2) > DEG2RADF(90.0f))
+ obtuse = 3;
+
+ if (obtuse > 0) {
+ area = area_tri_v3(v1, v2, v3);
+
+ varea[i1] += (obtuse == 1) ? area : area * 0.5f;
+ varea[i2] += (obtuse == 2) ? area : area * 0.5f;
+ varea[i3] += (obtuse == 3) ? area : area * 0.5f;
+ }
+ else {
+ len1 = len_v3v3(v2, v3);
+ len2 = len_v3v3(v1, v3);
+ len3 = len_v3v3(v1, v2);
+
+ t1 *= len1 * len1;
+ t2 *= len2 * len2;
+ t3 *= len3 * len3;
+
+ varea[i1] += (t2 + t3) * 0.25f;
+ varea[i2] += (t1 + t3) * 0.25f;
+ varea[i3] += (t1 + t2) * 0.25f;
+ }
}
static void laplacian_triangle_weights(LaplacianSystem *sys, int f, int i1, int i2, int i3)
{
- float t1, t2, t3;
- float *varea = sys->varea, *v1, *v2, *v3;
+ float t1, t2, t3;
+ float *varea = sys->varea, *v1, *v2, *v3;
- v1 = sys->verts[i1];
- v2 = sys->verts[i2];
- v3 = sys->verts[i3];
+ v1 = sys->verts[i1];
+ v2 = sys->verts[i2];
+ v3 = sys->verts[i3];
- /* instead of *0.5 we divided by the number of faces of the edge, it still
- * needs to be verified that this is indeed the correct thing to do! */
- t1 = cotangent_tri_weight_v3(v1, v2, v3) / laplacian_edge_count(sys->edgehash, i2, i3);
- t2 = cotangent_tri_weight_v3(v2, v3, v1) / laplacian_edge_count(sys->edgehash, i3, i1);
- t3 = cotangent_tri_weight_v3(v3, v1, v2) / laplacian_edge_count(sys->edgehash, i1, i2);
+ /* instead of *0.5 we divided by the number of faces of the edge, it still
+ * needs to be verified that this is indeed the correct thing to do! */
+ t1 = cotangent_tri_weight_v3(v1, v2, v3) / laplacian_edge_count(sys->edgehash, i2, i3);
+ t2 = cotangent_tri_weight_v3(v2, v3, v1) / laplacian_edge_count(sys->edgehash, i3, i1);
+ t3 = cotangent_tri_weight_v3(v3, v1, v2) / laplacian_edge_count(sys->edgehash, i1, i2);
- EIG_linear_solver_matrix_add(sys->context, i1, i1, (t2 + t3) * varea[i1]);
- EIG_linear_solver_matrix_add(sys->context, i2, i2, (t1 + t3) * varea[i2]);
- EIG_linear_solver_matrix_add(sys->context, i3, i3, (t1 + t2) * varea[i3]);
+ EIG_linear_solver_matrix_add(sys->context, i1, i1, (t2 + t3) * varea[i1]);
+ EIG_linear_solver_matrix_add(sys->context, i2, i2, (t1 + t3) * varea[i2]);
+ EIG_linear_solver_matrix_add(sys->context, i3, i3, (t1 + t2) * varea[i3]);
- EIG_linear_solver_matrix_add(sys->context, i1, i2, -t3 * varea[i1]);
- EIG_linear_solver_matrix_add(sys->context, i2, i1, -t3 * varea[i2]);
+ EIG_linear_solver_matrix_add(sys->context, i1, i2, -t3 * varea[i1]);
+ EIG_linear_solver_matrix_add(sys->context, i2, i1, -t3 * varea[i2]);
- EIG_linear_solver_matrix_add(sys->context, i2, i3, -t1 * varea[i2]);
- EIG_linear_solver_matrix_add(sys->context, i3, i2, -t1 * varea[i3]);
+ EIG_linear_solver_matrix_add(sys->context, i2, i3, -t1 * varea[i2]);
+ EIG_linear_solver_matrix_add(sys->context, i3, i2, -t1 * varea[i3]);
- EIG_linear_solver_matrix_add(sys->context, i3, i1, -t2 * varea[i3]);
- EIG_linear_solver_matrix_add(sys->context, i1, i3, -t2 * varea[i1]);
+ EIG_linear_solver_matrix_add(sys->context, i3, i1, -t2 * varea[i3]);
+ EIG_linear_solver_matrix_add(sys->context, i1, i3, -t2 * varea[i1]);
- if (sys->storeweights) {
- sys->fweights[f][0] = t1 * varea[i1];
- sys->fweights[f][1] = t2 * varea[i2];
- sys->fweights[f][2] = t3 * varea[i3];
- }
+ if (sys->storeweights) {
+ sys->fweights[f][0] = t1 * varea[i1];
+ sys->fweights[f][1] = t2 * varea[i2];
+ sys->fweights[f][2] = t3 * varea[i3];
+ }
}
static LaplacianSystem *laplacian_system_construct_begin(int totvert, int totface, int lsq)
{
- LaplacianSystem *sys;
+ LaplacianSystem *sys;
- sys = MEM_callocN(sizeof(LaplacianSystem), "LaplacianSystem");
+ sys = MEM_callocN(sizeof(LaplacianSystem), "LaplacianSystem");
- sys->verts = MEM_callocN(sizeof(float *) * totvert, "LaplacianSystemVerts");
- sys->vpinned = MEM_callocN(sizeof(char) * totvert, "LaplacianSystemVpinned");
- sys->faces = MEM_callocN(sizeof(int) * 3 * totface, "LaplacianSystemFaces");
+ sys->verts = MEM_callocN(sizeof(float *) * totvert, "LaplacianSystemVerts");
+ sys->vpinned = MEM_callocN(sizeof(char) * totvert, "LaplacianSystemVpinned");
+ sys->faces = MEM_callocN(sizeof(int) * 3 * totface, "LaplacianSystemFaces");
- sys->totvert = 0;
- sys->totface = 0;
+ sys->totvert = 0;
+ sys->totface = 0;
- sys->areaweights = 1;
- sys->storeweights = 0;
+ sys->areaweights = 1;
+ sys->storeweights = 0;
- /* create linear solver */
- if (lsq)
- sys->context = EIG_linear_least_squares_solver_new(0, totvert, 1);
- else
- sys->context = EIG_linear_solver_new(0, totvert, 1);
+ /* create linear solver */
+ if (lsq)
+ sys->context = EIG_linear_least_squares_solver_new(0, totvert, 1);
+ else
+ sys->context = EIG_linear_solver_new(0, totvert, 1);
- return sys;
+ return sys;
}
void laplacian_add_vertex(LaplacianSystem *sys, float *co, int pinned)
{
- sys->verts[sys->totvert] = co;
- sys->vpinned[sys->totvert] = pinned;
- sys->totvert++;
+ sys->verts[sys->totvert] = co;
+ sys->vpinned[sys->totvert] = pinned;
+ sys->totvert++;
}
void laplacian_add_triangle(LaplacianSystem *sys, int v1, int v2, int v3)
{
- sys->faces[sys->totface][0] = v1;
- sys->faces[sys->totface][1] = v2;
- sys->faces[sys->totface][2] = v3;
- sys->totface++;
+ sys->faces[sys->totface][0] = v1;
+ sys->faces[sys->totface][1] = v2;
+ sys->faces[sys->totface][2] = v3;
+ sys->totface++;
}
static void laplacian_system_construct_end(LaplacianSystem *sys)
{
- int (*face)[3];
- int a, totvert = sys->totvert, totface = sys->totface;
+ int(*face)[3];
+ int a, totvert = sys->totvert, totface = sys->totface;
- laplacian_begin_solve(sys, 0);
+ laplacian_begin_solve(sys, 0);
- sys->varea = MEM_callocN(sizeof(float) * totvert, "LaplacianSystemVarea");
+ sys->varea = MEM_callocN(sizeof(float) * totvert, "LaplacianSystemVarea");
- sys->edgehash = BLI_edgehash_new_ex(__func__, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(sys->totface));
- for (a = 0, face = sys->faces; a < sys->totface; a++, face++) {
- laplacian_increase_edge_count(sys->edgehash, (*face)[0], (*face)[1]);
- laplacian_increase_edge_count(sys->edgehash, (*face)[1], (*face)[2]);
- laplacian_increase_edge_count(sys->edgehash, (*face)[2], (*face)[0]);
- }
+ sys->edgehash = BLI_edgehash_new_ex(__func__, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(sys->totface));
+ for (a = 0, face = sys->faces; a < sys->totface; a++, face++) {
+ laplacian_increase_edge_count(sys->edgehash, (*face)[0], (*face)[1]);
+ laplacian_increase_edge_count(sys->edgehash, (*face)[1], (*face)[2]);
+ laplacian_increase_edge_count(sys->edgehash, (*face)[2], (*face)[0]);
+ }
- if (sys->areaweights)
- for (a = 0, face = sys->faces; a < sys->totface; a++, face++)
- laplacian_triangle_area(sys, (*face)[0], (*face)[1], (*face)[2]);
+ if (sys->areaweights)
+ for (a = 0, face = sys->faces; a < sys->totface; a++, face++)
+ laplacian_triangle_area(sys, (*face)[0], (*face)[1], (*face)[2]);
- for (a = 0; a < totvert; a++) {
- if (sys->areaweights) {
- if (sys->varea[a] != 0.0f)
- sys->varea[a] = 0.5f / sys->varea[a];
- }
- else
- sys->varea[a] = 1.0f;
+ for (a = 0; a < totvert; a++) {
+ if (sys->areaweights) {
+ if (sys->varea[a] != 0.0f)
+ sys->varea[a] = 0.5f / sys->varea[a];
+ }
+ else
+ sys->varea[a] = 1.0f;
- /* for heat weighting */
- if (sys->heat.H)
- EIG_linear_solver_matrix_add(sys->context, a, a, sys->heat.H[a]);
- }
+ /* for heat weighting */
+ if (sys->heat.H)
+ EIG_linear_solver_matrix_add(sys->context, a, a, sys->heat.H[a]);
+ }
- if (sys->storeweights)
- sys->fweights = MEM_callocN(sizeof(float) * 3 * totface, "LaplacianFWeight");
+ if (sys->storeweights)
+ sys->fweights = MEM_callocN(sizeof(float) * 3 * totface, "LaplacianFWeight");
- for (a = 0, face = sys->faces; a < totface; a++, face++)
- laplacian_triangle_weights(sys, a, (*face)[0], (*face)[1], (*face)[2]);
+ for (a = 0, face = sys->faces; a < totface; a++, face++)
+ laplacian_triangle_weights(sys, a, (*face)[0], (*face)[1], (*face)[2]);
- MEM_freeN(sys->faces);
- sys->faces = NULL;
+ MEM_freeN(sys->faces);
+ sys->faces = NULL;
- if (sys->varea) {
- MEM_freeN(sys->varea);
- sys->varea = NULL;
- }
+ if (sys->varea) {
+ MEM_freeN(sys->varea);
+ sys->varea = NULL;
+ }
- BLI_edgehash_free(sys->edgehash, NULL);
- sys->edgehash = NULL;
+ BLI_edgehash_free(sys->edgehash, NULL);
+ sys->edgehash = NULL;
}
static void laplacian_system_delete(LaplacianSystem *sys)
{
- if (sys->verts) MEM_freeN(sys->verts);
- if (sys->varea) MEM_freeN(sys->varea);
- if (sys->vpinned) MEM_freeN(sys->vpinned);
- if (sys->faces) MEM_freeN(sys->faces);
- if (sys->fweights) MEM_freeN(sys->fweights);
-
- EIG_linear_solver_delete(sys->context);
- MEM_freeN(sys);
+ if (sys->verts)
+ MEM_freeN(sys->verts);
+ if (sys->varea)
+ MEM_freeN(sys->varea);
+ if (sys->vpinned)
+ MEM_freeN(sys->vpinned);
+ if (sys->faces)
+ MEM_freeN(sys->faces);
+ if (sys->fweights)
+ MEM_freeN(sys->fweights);
+
+ EIG_linear_solver_delete(sys->context);
+ MEM_freeN(sys);
}
void laplacian_begin_solve(LaplacianSystem *sys, int index)
{
- int a;
-
- if (!sys->variablesdone) {
- if (index >= 0) {
- for (a = 0; a < sys->totvert; a++) {
- if (sys->vpinned[a]) {
- EIG_linear_solver_variable_set(sys->context, 0, a, sys->verts[a][index]);
- EIG_linear_solver_variable_lock(sys->context, a);
- }
- }
- }
-
- sys->variablesdone = true;
- }
+ int a;
+
+ if (!sys->variablesdone) {
+ if (index >= 0) {
+ for (a = 0; a < sys->totvert; a++) {
+ if (sys->vpinned[a]) {
+ EIG_linear_solver_variable_set(sys->context, 0, a, sys->verts[a][index]);
+ EIG_linear_solver_variable_lock(sys->context, a);
+ }
+ }
+ }
+
+ sys->variablesdone = true;
+ }
}
void laplacian_add_right_hand_side(LaplacianSystem *sys, int v, float value)
{
- EIG_linear_solver_right_hand_side_add(sys->context, 0, v, value);
+ EIG_linear_solver_right_hand_side_add(sys->context, 0, v, value);
}
int laplacian_system_solve(LaplacianSystem *sys)
{
- sys->variablesdone = false;
+ sys->variablesdone = false;
- //EIG_linear_solver_print_matrix(sys->context, );
+ //EIG_linear_solver_print_matrix(sys->context, );
- return EIG_linear_solver_solve(sys->context);
+ return EIG_linear_solver_solve(sys->context);
}
float laplacian_system_get_solution(LaplacianSystem *sys, int v)
{
- return EIG_linear_solver_variable_get(sys->context, 0, v);
+ return EIG_linear_solver_variable_get(sys->context, 0, v);
}
/************************* Heat Bone Weighting ******************************/
/* From "Automatic Rigging and Animation of 3D Characters"
* Ilya Baran and Jovan Popovic, SIGGRAPH 2007 */
-#define C_WEIGHT 1.0f
-#define WEIGHT_LIMIT_START 0.05f
-#define WEIGHT_LIMIT_END 0.025f
-#define DISTANCE_EPSILON 1e-4f
+#define C_WEIGHT 1.0f
+#define WEIGHT_LIMIT_START 0.05f
+#define WEIGHT_LIMIT_END 0.025f
+#define DISTANCE_EPSILON 1e-4f
typedef struct BVHCallbackUserData {
- float start[3];
- float vec[3];
- LaplacianSystem *sys;
+ float start[3];
+ float vec[3];
+ LaplacianSystem *sys;
} BVHCallbackUserData;
static void bvh_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
{
- BVHCallbackUserData *data = (struct BVHCallbackUserData *)userdata;
- const MLoopTri *lt = &data->sys->heat.mlooptri[index];
- const MLoop *mloop = data->sys->heat.mloop;
- float (*verts)[3] = data->sys->heat.verts;
- const float *vtri_co[3];
- float dist_test;
+ BVHCallbackUserData *data = (struct BVHCallbackUserData *)userdata;
+ const MLoopTri *lt = &data->sys->heat.mlooptri[index];
+ const MLoop *mloop = data->sys->heat.mloop;
+ float(*verts)[3] = data->sys->heat.verts;
+ const float *vtri_co[3];
+ float dist_test;
- vtri_co[0] = verts[mloop[lt->tri[0]].v];
- vtri_co[1] = verts[mloop[lt->tri[1]].v];
- vtri_co[2] = verts[mloop[lt->tri[2]].v];
+ vtri_co[0] = verts[mloop[lt->tri[0]].v];
+ vtri_co[1] = verts[mloop[lt->tri[1]].v];
+ vtri_co[2] = verts[mloop[lt->tri[2]].v];
#ifdef USE_KDOPBVH_WATERTIGHT
- if (isect_ray_tri_watertight_v3(data->start, ray->isect_precalc, UNPACK3(vtri_co), &dist_test, NULL))
+ if (isect_ray_tri_watertight_v3(
+ data->start, ray->isect_precalc, UNPACK3(vtri_co), &dist_test, NULL))
#else
- UNUSED_VARS(ray);
- if (isect_ray_tri_v3(data->start, data->vec, UNPACK3(vtri_co), &dist_test, NULL))
+ UNUSED_VARS(ray);
+ if (isect_ray_tri_v3(data->start, data->vec, UNPACK3(vtri_co), &dist_test, NULL))
#endif
- {
- if (dist_test < hit->dist) {
- float n[3];
- normal_tri_v3(n, UNPACK3(vtri_co));
- if (dot_v3v3(n, data->vec) < -1e-5f) {
- hit->index = index;
- hit->dist = dist_test;
- }
- }
- }
+ {
+ if (dist_test < hit->dist) {
+ float n[3];
+ normal_tri_v3(n, UNPACK3(vtri_co));
+ if (dot_v3v3(n, data->vec) < -1e-5f) {
+ hit->index = index;
+ hit->dist = dist_test;
+ }
+ }
+ }
}
/* Raytracing for vertex to bone/vertex visibility */
static void heat_ray_tree_create(LaplacianSystem *sys)
{
- const MLoopTri *looptri = sys->heat.mlooptri;
- const MLoop *mloop = sys->heat.mloop;
- float (*verts)[3] = sys->heat.verts;
- int tottri = sys->heat.tottri;
- int totvert = sys->heat.totvert;
- int a;
-
- sys->heat.bvhtree = BLI_bvhtree_new(tottri, 0.0f, 4, 6);
- sys->heat.vltree = MEM_callocN(sizeof(MLoopTri *) * totvert, "HeatVFaces");
-
- for (a = 0; a < tottri; a++) {
- const MLoopTri *lt = &looptri[a];
- float bb[6];
- int vtri[3];
-
- vtri[0] = mloop[lt->tri[0]].v;
- vtri[1] = mloop[lt->tri[1]].v;
- vtri[2] = mloop[lt->tri[2]].v;
-
- INIT_MINMAX(bb, bb + 3);
- minmax_v3v3_v3(bb, bb + 3, verts[vtri[0]]);
- minmax_v3v3_v3(bb, bb + 3, verts[vtri[1]]);
- minmax_v3v3_v3(bb, bb + 3, verts[vtri[2]]);
-
- BLI_bvhtree_insert(sys->heat.bvhtree, a, bb, 2);
-
- //Setup inverse pointers to use on isect.orig
- sys->heat.vltree[vtri[0]] = lt;
- sys->heat.vltree[vtri[1]] = lt;
- sys->heat.vltree[vtri[2]] = lt;
- }
-
- BLI_bvhtree_balance(sys->heat.bvhtree);
+ const MLoopTri *looptri = sys->heat.mlooptri;
+ const MLoop *mloop = sys->heat.mloop;
+ float(*verts)[3] = sys->heat.verts;
+ int tottri = sys->heat.tottri;
+ int totvert = sys->heat.totvert;
+ int a;
+
+ sys->heat.bvhtree = BLI_bvhtree_new(tottri, 0.0f, 4, 6);
+ sys->heat.vltree = MEM_callocN(sizeof(MLoopTri *) * totvert, "HeatVFaces");
+
+ for (a = 0; a < tottri; a++) {
+ const MLoopTri *lt = &looptri[a];
+ float bb[6];
+ int vtri[3];
+
+ vtri[0] = mloop[lt->tri[0]].v;
+ vtri[1] = mloop[lt->tri[1]].v;
+ vtri[2] = mloop[lt->tri[2]].v;
+
+ INIT_MINMAX(bb, bb + 3);
+ minmax_v3v3_v3(bb, bb + 3, verts[vtri[0]]);
+ minmax_v3v3_v3(bb, bb + 3, verts[vtri[1]]);
+ minmax_v3v3_v3(bb, bb + 3, verts[vtri[2]]);
+
+ BLI_bvhtree_insert(sys->heat.bvhtree, a, bb, 2);
+
+ //Setup inverse pointers to use on isect.orig
+ sys->heat.vltree[vtri[0]] = lt;
+ sys->heat.vltree[vtri[1]] = lt;
+ sys->heat.vltree[vtri[2]] = lt;
+ }
+
+ BLI_bvhtree_balance(sys->heat.bvhtree);
}
static int heat_ray_source_visible(LaplacianSystem *sys, int vertex, int source)
{
- BVHTreeRayHit hit;
- BVHCallbackUserData data;
- const MLoopTri *lt;
- float end[3];
- int visible;
+ BVHTreeRayHit hit;
+ BVHCallbackUserData data;
+ const MLoopTri *lt;
+ float end[3];
+ int visible;
- lt = sys->heat.vltree[vertex];
- if (lt == NULL)
- return 1;
+ lt = sys->heat.vltree[vertex];
+ if (lt == NULL)
+ return 1;
- data.sys = sys;
- copy_v3_v3(data.start, sys->heat.verts[vertex]);
+ data.sys = sys;
+ copy_v3_v3(data.start, sys->heat.verts[vertex]);
- closest_to_line_segment_v3(end, data.start, sys->heat.root[source], sys->heat.tip[source]);
+ closest_to_line_segment_v3(end, data.start, sys->heat.root[source], sys->heat.tip[source]);
- sub_v3_v3v3(data.vec, end, data.start);
- madd_v3_v3v3fl(data.start, data.start, data.vec, 1e-5);
- mul_v3_fl(data.vec, 1.0f - 2e-5f);
+ sub_v3_v3v3(data.vec, end, data.start);
+ madd_v3_v3v3fl(data.start, data.start, data.vec, 1e-5);
+ mul_v3_fl(data.vec, 1.0f - 2e-5f);
- /* pass normalized vec + distance to bvh */
- hit.index = -1;
- hit.dist = normalize_v3(data.vec);
+ /* pass normalized vec + distance to bvh */
+ hit.index = -1;
+ hit.dist = normalize_v3(data.vec);
- visible = BLI_bvhtree_ray_cast(sys->heat.bvhtree, data.start, data.vec, 0.0f, &hit, bvh_callback, (void *)&data) == -1;
+ visible =
+ BLI_bvhtree_ray_cast(
+ sys->heat.bvhtree, data.start, data.vec, 0.0f, &hit, bvh_callback, (void *)&data) == -1;
- return visible;
+ return visible;
}
static float heat_source_distance(LaplacianSystem *sys, int vertex, int source)
{
- float closest[3], d[3], dist, cosine;
+ float closest[3], d[3], dist, cosine;
- /* compute euclidian distance */
- closest_to_line_segment_v3(closest, sys->heat.verts[vertex], sys->heat.root[source], sys->heat.tip[source]);
+ /* compute euclidian distance */
+ closest_to_line_segment_v3(
+ closest, sys->heat.verts[vertex], sys->heat.root[source], sys->heat.tip[source]);
- sub_v3_v3v3(d, sys->heat.verts[vertex], closest);
- dist = normalize_v3(d);
+ sub_v3_v3v3(d, sys->heat.verts[vertex], closest);
+ dist = normalize_v3(d);
- /* if the vertex normal does not point along the bone, increase distance */
- cosine = dot_v3v3(d, sys->heat.vnors[vertex]);
+ /* if the vertex normal does not point along the bone, increase distance */
+ cosine = dot_v3v3(d, sys->heat.vnors[vertex]);
- return dist / (0.5f * (cosine + 1.001f));
+ return dist / (0.5f * (cosine + 1.001f));
}
static int heat_source_closest(LaplacianSystem *sys, int vertex, int source)
{
- float dist;
+ float dist;
- dist = heat_source_distance(sys, vertex, source);
+ dist = heat_source_distance(sys, vertex, source);
- if (dist <= sys->heat.mindist[vertex] * (1.0f + DISTANCE_EPSILON))
- if (heat_ray_source_visible(sys, vertex, source))
- return 1;
+ if (dist <= sys->heat.mindist[vertex] * (1.0f + DISTANCE_EPSILON))
+ if (heat_ray_source_visible(sys, vertex, source))
+ return 1;
- return 0;
+ return 0;
}
static void heat_set_H(LaplacianSystem *sys, int vertex)
{
- float dist, mindist, h;
- int j, numclosest = 0;
+ float dist, mindist, h;
+ int j, numclosest = 0;
- mindist = 1e10;
+ mindist = 1e10;
- /* compute minimum distance */
- for (j = 0; j < sys->heat.numsource; j++) {
- dist = heat_source_distance(sys, vertex, j);
+ /* compute minimum distance */
+ for (j = 0; j < sys->heat.numsource; j++) {
+ dist = heat_source_distance(sys, vertex, j);
- if (dist < mindist)
- mindist = dist;
- }
+ if (dist < mindist)
+ mindist = dist;
+ }
- sys->heat.mindist[vertex] = mindist;
+ sys->heat.mindist[vertex] = mindist;
- /* count number of sources with approximately this minimum distance */
- for (j = 0; j < sys->heat.numsource; j++)
- if (heat_source_closest(sys, vertex, j))
- numclosest++;
+ /* count number of sources with approximately this minimum distance */
+ for (j = 0; j < sys->heat.numsource; j++)
+ if (heat_source_closest(sys, vertex, j))
+ numclosest++;
- sys->heat.p[vertex] = (numclosest > 0) ? 1.0f / numclosest : 0.0f;
+ sys->heat.p[vertex] = (numclosest > 0) ? 1.0f / numclosest : 0.0f;
- /* compute H entry */
- if (numclosest > 0) {
- mindist = max_ff(mindist, 1e-4f);
- h = numclosest * C_WEIGHT / (mindist * mindist);
- }
- else
- h = 0.0f;
+ /* compute H entry */
+ if (numclosest > 0) {
+ mindist = max_ff(mindist, 1e-4f);
+ h = numclosest * C_WEIGHT / (mindist * mindist);
+ }
+ else
+ h = 0.0f;
- sys->heat.H[vertex] = h;
+ sys->heat.H[vertex] = h;
}
static void heat_calc_vnormals(LaplacianSystem *sys)
{
- float fnor[3];
- int a, v1, v2, v3, (*face)[3];
+ float fnor[3];
+ int a, v1, v2, v3, (*face)[3];
- sys->heat.vnors = MEM_callocN(sizeof(float) * 3 * sys->totvert, "HeatVNors");
+ sys->heat.vnors = MEM_callocN(sizeof(float) * 3 * sys->totvert, "HeatVNors");
- for (a = 0, face = sys->faces; a < sys->totface; a++, face++) {
- v1 = (*face)[0];
- v2 = (*face)[1];
- v3 = (*face)[2];
+ for (a = 0, face = sys->faces; a < sys->totface; a++, face++) {
+ v1 = (*face)[0];
+ v2 = (*face)[1];
+ v3 = (*face)[2];
- normal_tri_v3(fnor, sys->verts[v1], sys->verts[v2], sys->verts[v3]);
+ normal_tri_v3(fnor, sys->verts[v1], sys->verts[v2], sys->verts[v3]);
- add_v3_v3(sys->heat.vnors[v1], fnor);
- add_v3_v3(sys->heat.vnors[v2], fnor);
- add_v3_v3(sys->heat.vnors[v3], fnor);
- }
+ add_v3_v3(sys->heat.vnors[v1], fnor);
+ add_v3_v3(sys->heat.vnors[v2], fnor);
+ add_v3_v3(sys->heat.vnors[v3], fnor);
+ }
- for (a = 0; a < sys->totvert; a++)
- normalize_v3(sys->heat.vnors[a]);
+ for (a = 0; a < sys->totvert; a++)
+ normalize_v3(sys->heat.vnors[a]);
}
static void heat_laplacian_create(LaplacianSystem *sys)
{
- const MLoopTri *mlooptri = sys->heat.mlooptri, *lt;
- const MLoop *mloop = sys->heat.mloop;
- int tottri = sys->heat.tottri;
- int totvert = sys->heat.totvert;
- int a;
-
- /* heat specific definitions */
- sys->heat.mindist = MEM_callocN(sizeof(float) * totvert, "HeatMinDist");
- sys->heat.H = MEM_callocN(sizeof(float) * totvert, "HeatH");
- sys->heat.p = MEM_callocN(sizeof(float) * totvert, "HeatP");
-
- /* add verts and faces to laplacian */
- for (a = 0; a < totvert; a++)
- laplacian_add_vertex(sys, sys->heat.verts[a], 0);
-
- for (a = 0, lt = mlooptri; a < tottri; a++, lt++) {
- int vtri[3];
- vtri[0] = mloop[lt->tri[0]].v;
- vtri[1] = mloop[lt->tri[1]].v;
- vtri[2] = mloop[lt->tri[2]].v;
- laplacian_add_triangle(sys, UNPACK3(vtri));
- }
-
- /* for distance computation in set_H */
- heat_calc_vnormals(sys);
-
- for (a = 0; a < totvert; a++)
- heat_set_H(sys, a);
+ const MLoopTri *mlooptri = sys->heat.mlooptri, *lt;
+ const MLoop *mloop = sys->heat.mloop;
+ int tottri = sys->heat.tottri;
+ int totvert = sys->heat.totvert;
+ int a;
+
+ /* heat specific definitions */
+ sys->heat.mindist = MEM_callocN(sizeof(float) * totvert, "HeatMinDist");
+ sys->heat.H = MEM_callocN(sizeof(float) * totvert, "HeatH");
+ sys->heat.p = MEM_callocN(sizeof(float) * totvert, "HeatP");
+
+ /* add verts and faces to laplacian */
+ for (a = 0; a < totvert; a++)
+ laplacian_add_vertex(sys, sys->heat.verts[a], 0);
+
+ for (a = 0, lt = mlooptri; a < tottri; a++, lt++) {
+ int vtri[3];
+ vtri[0] = mloop[lt->tri[0]].v;
+ vtri[1] = mloop[lt->tri[1]].v;
+ vtri[2] = mloop[lt->tri[2]].v;
+ laplacian_add_triangle(sys, UNPACK3(vtri));
+ }
+
+ /* for distance computation in set_H */
+ heat_calc_vnormals(sys);
+
+ for (a = 0; a < totvert; a++)
+ heat_set_H(sys, a);
}
static void heat_system_free(LaplacianSystem *sys)
{
- BLI_bvhtree_free(sys->heat.bvhtree);
- MEM_freeN((void *)sys->heat.vltree);
- MEM_freeN((void *)sys->heat.mlooptri);
-
- MEM_freeN(sys->heat.mindist);
- MEM_freeN(sys->heat.H);
- MEM_freeN(sys->heat.p);
- MEM_freeN(sys->heat.vnors);
+ BLI_bvhtree_free(sys->heat.bvhtree);
+ MEM_freeN((void *)sys->heat.vltree);
+ MEM_freeN((void *)sys->heat.mlooptri);
+
+ MEM_freeN(sys->heat.mindist);
+ MEM_freeN(sys->heat.H);
+ MEM_freeN(sys->heat.p);
+ MEM_freeN(sys->heat.vnors);
}
static float heat_limit_weight(float weight)
{
- float t;
-
- if (weight < WEIGHT_LIMIT_END) {
- return 0.0f;
- }
- else if (weight < WEIGHT_LIMIT_START) {
- t = (weight - WEIGHT_LIMIT_END) / (WEIGHT_LIMIT_START - WEIGHT_LIMIT_END);
- return t * WEIGHT_LIMIT_START;
- }
- else
- return weight;
+ float t;
+
+ if (weight < WEIGHT_LIMIT_END) {
+ return 0.0f;
+ }
+ else if (weight < WEIGHT_LIMIT_START) {
+ t = (weight - WEIGHT_LIMIT_END) / (WEIGHT_LIMIT_START - WEIGHT_LIMIT_END);
+ return t * WEIGHT_LIMIT_START;
+ }
+ else
+ return weight;
}
-void heat_bone_weighting(
- Object *ob, Mesh *me, float (*verts)[3], int numsource,
- bDeformGroup **dgrouplist, bDeformGroup **dgroupflip,
- float (*root)[3], float (*tip)[3], int *selected, const char **err_str)
+void heat_bone_weighting(Object *ob,
+ Mesh *me,
+ float (*verts)[3],
+ int numsource,
+ bDeformGroup **dgrouplist,
+ bDeformGroup **dgroupflip,
+ float (*root)[3],
+ float (*tip)[3],
+ int *selected,
+ const char **err_str)
{
- LaplacianSystem *sys;
- MLoopTri *mlooptri;
- MPoly *mp;
- MLoop *ml;
- float solution, weight;
- int *vertsflipped = NULL, *mask = NULL;
- int a, tottri, j, bbone, firstsegment, lastsegment;
- bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
-
- MVert *mvert = me->mvert;
- bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
- bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
-
- *err_str = NULL;
-
- /* bone heat needs triangulated faces */
- tottri = poly_to_tri_count(me->totpoly, me->totloop);
-
- /* count triangles and create mask */
- if (ob->mode & OB_MODE_WEIGHT_PAINT &&
- (use_face_sel || use_vert_sel))
- {
- mask = MEM_callocN(sizeof(int) * me->totvert, "heat_bone_weighting mask");
-
- /* (added selectedVerts content for vertex mask, they used to just equal 1) */
- if (use_vert_sel) {
- for (a = 0, mp = me->mpoly; a < me->totpoly; mp++, a++) {
- for (j = 0, ml = me->mloop + mp->loopstart; j < mp->totloop; j++, ml++) {
- mask[ml->v] = (mvert[ml->v].flag & SELECT) != 0;
- }
- }
- }
- else if (use_face_sel) {
- for (a = 0, mp = me->mpoly; a < me->totpoly; mp++, a++) {
- if (mp->flag & ME_FACE_SEL) {
- for (j = 0, ml = me->mloop + mp->loopstart; j < mp->totloop; j++, ml++) {
- mask[ml->v] = 1;
- }
- }
- }
- }
- }
-
- /* create laplacian */
- sys = laplacian_system_construct_begin(me->totvert, tottri, 1);
-
- sys->heat.tottri = poly_to_tri_count(me->totpoly, me->totloop);
- mlooptri = MEM_mallocN(sizeof(*sys->heat.mlooptri) * sys->heat.tottri, __func__);
-
- BKE_mesh_recalc_looptri(
- me->mloop, me->mpoly,
- me->mvert,
- me->totloop, me->totpoly,
- mlooptri);
-
- sys->heat.mlooptri = mlooptri;
- sys->heat.mloop = me->mloop;
- sys->heat.totvert = me->totvert;
- sys->heat.verts = verts;
- sys->heat.root = root;
- sys->heat.tip = tip;
- sys->heat.numsource = numsource;
-
- heat_ray_tree_create(sys);
- heat_laplacian_create(sys);
-
- laplacian_system_construct_end(sys);
-
- if (dgroupflip) {
- vertsflipped = MEM_callocN(sizeof(int) * me->totvert, "vertsflipped");
- for (a = 0; a < me->totvert; a++)
- vertsflipped[a] = mesh_get_x_mirror_vert(ob, NULL, a, use_topology);
- }
-
- /* compute weights per bone */
- for (j = 0; j < numsource; j++) {
- if (!selected[j])
- continue;
-
- firstsegment = (j == 0 || dgrouplist[j - 1] != dgrouplist[j]);
- lastsegment = (j == numsource - 1 || dgrouplist[j] != dgrouplist[j + 1]);
- bbone = !(firstsegment && lastsegment);
-
- /* clear weights */
- if (bbone && firstsegment) {
- for (a = 0; a < me->totvert; a++) {
- if (mask && !mask[a])
- continue;
-
- ED_vgroup_vert_remove(ob, dgrouplist[j], a);
- if (vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0)
- ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
- }
- }
-
- /* fill right hand side */
- laplacian_begin_solve(sys, -1);
-
- for (a = 0; a < me->totvert; a++)
- if (heat_source_closest(sys, a, j))
- laplacian_add_right_hand_side(sys, a,
- sys->heat.H[a] * sys->heat.p[a]);
-
- /* solve */
- if (laplacian_system_solve(sys)) {
- /* load solution into vertex groups */
- for (a = 0; a < me->totvert; a++) {
- if (mask && !mask[a])
- continue;
-
- solution = laplacian_system_get_solution(sys, a);
-
- if (bbone) {
- if (solution > 0.0f)
- ED_vgroup_vert_add(ob, dgrouplist[j], a, solution,
- WEIGHT_ADD);
- }
- else {
- weight = heat_limit_weight(solution);
- if (weight > 0.0f)
- ED_vgroup_vert_add(ob, dgrouplist[j], a, weight,
- WEIGHT_REPLACE);
- else
- ED_vgroup_vert_remove(ob, dgrouplist[j], a);
- }
-
- /* do same for mirror */
- if (vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) {
- if (bbone) {
- if (solution > 0.0f)
- ED_vgroup_vert_add(ob, dgroupflip[j], vertsflipped[a],
- solution, WEIGHT_ADD);
- }
- else {
- weight = heat_limit_weight(solution);
- if (weight > 0.0f)
- ED_vgroup_vert_add(ob, dgroupflip[j], vertsflipped[a],
- weight, WEIGHT_REPLACE);
- else
- ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
- }
- }
- }
- }
- else if (*err_str == NULL) {
- *err_str = N_("Bone Heat Weighting: failed to find solution for one or more bones");
- break;
- }
-
- /* remove too small vertex weights */
- if (bbone && lastsegment) {
- for (a = 0; a < me->totvert; a++) {
- if (mask && !mask[a])
- continue;
-
- weight = ED_vgroup_vert_weight(ob, dgrouplist[j], a);
- weight = heat_limit_weight(weight);
- if (weight <= 0.0f)
- ED_vgroup_vert_remove(ob, dgrouplist[j], a);
-
- if (vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) {
- weight = ED_vgroup_vert_weight(ob, dgroupflip[j], vertsflipped[a]);
- weight = heat_limit_weight(weight);
- if (weight <= 0.0f)
- ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
- }
- }
- }
- }
-
- /* free */
- if (vertsflipped) MEM_freeN(vertsflipped);
- if (mask) MEM_freeN(mask);
-
- heat_system_free(sys);
-
- laplacian_system_delete(sys);
+ LaplacianSystem *sys;
+ MLoopTri *mlooptri;
+ MPoly *mp;
+ MLoop *ml;
+ float solution, weight;
+ int *vertsflipped = NULL, *mask = NULL;
+ int a, tottri, j, bbone, firstsegment, lastsegment;
+ bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
+
+ MVert *mvert = me->mvert;
+ bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+
+ *err_str = NULL;
+
+ /* bone heat needs triangulated faces */
+ tottri = poly_to_tri_count(me->totpoly, me->totloop);
+
+ /* count triangles and create mask */
+ if (ob->mode & OB_MODE_WEIGHT_PAINT && (use_face_sel || use_vert_sel)) {
+ mask = MEM_callocN(sizeof(int) * me->totvert, "heat_bone_weighting mask");
+
+ /* (added selectedVerts content for vertex mask, they used to just equal 1) */
+ if (use_vert_sel) {
+ for (a = 0, mp = me->mpoly; a < me->totpoly; mp++, a++) {
+ for (j = 0, ml = me->mloop + mp->loopstart; j < mp->totloop; j++, ml++) {
+ mask[ml->v] = (mvert[ml->v].flag & SELECT) != 0;
+ }
+ }
+ }
+ else if (use_face_sel) {
+ for (a = 0, mp = me->mpoly; a < me->totpoly; mp++, a++) {
+ if (mp->flag & ME_FACE_SEL) {
+ for (j = 0, ml = me->mloop + mp->loopstart; j < mp->totloop; j++, ml++) {
+ mask[ml->v] = 1;
+ }
+ }
+ }
+ }
+ }
+
+ /* create laplacian */
+ sys = laplacian_system_construct_begin(me->totvert, tottri, 1);
+
+ sys->heat.tottri = poly_to_tri_count(me->totpoly, me->totloop);
+ mlooptri = MEM_mallocN(sizeof(*sys->heat.mlooptri) * sys->heat.tottri, __func__);
+
+ BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, mlooptri);
+
+ sys->heat.mlooptri = mlooptri;
+ sys->heat.mloop = me->mloop;
+ sys->heat.totvert = me->totvert;
+ sys->heat.verts = verts;
+ sys->heat.root = root;
+ sys->heat.tip = tip;
+ sys->heat.numsource = numsource;
+
+ heat_ray_tree_create(sys);
+ heat_laplacian_create(sys);
+
+ laplacian_system_construct_end(sys);
+
+ if (dgroupflip) {
+ vertsflipped = MEM_callocN(sizeof(int) * me->totvert, "vertsflipped");
+ for (a = 0; a < me->totvert; a++)
+ vertsflipped[a] = mesh_get_x_mirror_vert(ob, NULL, a, use_topology);
+ }
+
+ /* compute weights per bone */
+ for (j = 0; j < numsource; j++) {
+ if (!selected[j])
+ continue;
+
+ firstsegment = (j == 0 || dgrouplist[j - 1] != dgrouplist[j]);
+ lastsegment = (j == numsource - 1 || dgrouplist[j] != dgrouplist[j + 1]);
+ bbone = !(firstsegment && lastsegment);
+
+ /* clear weights */
+ if (bbone && firstsegment) {
+ for (a = 0; a < me->totvert; a++) {
+ if (mask && !mask[a])
+ continue;
+
+ ED_vgroup_vert_remove(ob, dgrouplist[j], a);
+ if (vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0)
+ ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
+ }
+ }
+
+ /* fill right hand side */
+ laplacian_begin_solve(sys, -1);
+
+ for (a = 0; a < me->totvert; a++)
+ if (heat_source_closest(sys, a, j))
+ laplacian_add_right_hand_side(sys, a, sys->heat.H[a] * sys->heat.p[a]);
+
+ /* solve */
+ if (laplacian_system_solve(sys)) {
+ /* load solution into vertex groups */
+ for (a = 0; a < me->totvert; a++) {
+ if (mask && !mask[a])
+ continue;
+
+ solution = laplacian_system_get_solution(sys, a);
+
+ if (bbone) {
+ if (solution > 0.0f)
+ ED_vgroup_vert_add(ob, dgrouplist[j], a, solution, WEIGHT_ADD);
+ }
+ else {
+ weight = heat_limit_weight(solution);
+ if (weight > 0.0f)
+ ED_vgroup_vert_add(ob, dgrouplist[j], a, weight, WEIGHT_REPLACE);
+ else
+ ED_vgroup_vert_remove(ob, dgrouplist[j], a);
+ }
+
+ /* do same for mirror */
+ if (vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) {
+ if (bbone) {
+ if (solution > 0.0f)
+ ED_vgroup_vert_add(ob, dgroupflip[j], vertsflipped[a], solution, WEIGHT_ADD);
+ }
+ else {
+ weight = heat_limit_weight(solution);
+ if (weight > 0.0f)
+ ED_vgroup_vert_add(ob, dgroupflip[j], vertsflipped[a], weight, WEIGHT_REPLACE);
+ else
+ ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
+ }
+ }
+ }
+ }
+ else if (*err_str == NULL) {
+ *err_str = N_("Bone Heat Weighting: failed to find solution for one or more bones");
+ break;
+ }
+
+ /* remove too small vertex weights */
+ if (bbone && lastsegment) {
+ for (a = 0; a < me->totvert; a++) {
+ if (mask && !mask[a])
+ continue;
+
+ weight = ED_vgroup_vert_weight(ob, dgrouplist[j], a);
+ weight = heat_limit_weight(weight);
+ if (weight <= 0.0f)
+ ED_vgroup_vert_remove(ob, dgrouplist[j], a);
+
+ if (vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) {
+ weight = ED_vgroup_vert_weight(ob, dgroupflip[j], vertsflipped[a]);
+ weight = heat_limit_weight(weight);
+ if (weight <= 0.0f)
+ ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
+ }
+ }
+ }
+ }
+
+ /* free */
+ if (vertsflipped)
+ MEM_freeN(vertsflipped);
+ if (mask)
+ MEM_freeN(mask);
+
+ heat_system_free(sys);
+
+ laplacian_system_delete(sys);
}
/************************** Harmonic Coordinates ****************************/
@@ -789,7 +808,7 @@ void heat_bone_weighting(
#define EPSILON 0.0001f
-#define MESHDEFORM_TAG_UNTYPED 0
+#define MESHDEFORM_TAG_UNTYPED 0
#define MESHDEFORM_TAG_BOUNDARY 1
#define MESHDEFORM_TAG_INTERIOR 2
#define MESHDEFORM_TAG_EXTERIOR 3
@@ -800,828 +819,874 @@ void heat_bone_weighting(
#define MESHDEFORM_MIN_INFLUENCE 0.0005f
static const int MESHDEFORM_OFFSET[7][3] = {
- {0, 0, 0}, {1, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}, {0, 0, 1}, {0, 0, -1},
+ {0, 0, 0},
+ {1, 0, 0},
+ {-1, 0, 0},
+ {0, 1, 0},
+ {0, -1, 0},
+ {0, 0, 1},
+ {0, 0, -1},
};
typedef struct MDefBoundIsect {
- /* intersection on the cage 'cagecos' */
- float co[3];
- /* non-facing intersections are considered interior */
- bool facing;
- /* ray-cast index aligned with MPoly (ray-hit-triangle isn't needed) */
- int poly_index;
- /* distance from 'co' to the ray-cast start (clamped to avoid zero division) */
- float len;
- /* weights aligned with the MPoly's loop indices */
- float poly_weights[0];
+ /* intersection on the cage 'cagecos' */
+ float co[3];
+ /* non-facing intersections are considered interior */
+ bool facing;
+ /* ray-cast index aligned with MPoly (ray-hit-triangle isn't needed) */
+ int poly_index;
+ /* distance from 'co' to the ray-cast start (clamped to avoid zero division) */
+ float len;
+ /* weights aligned with the MPoly's loop indices */
+ float poly_weights[0];
} MDefBoundIsect;
typedef struct MDefBindInfluence {
- struct MDefBindInfluence *next;
- float weight;
- int vertex;
+ struct MDefBindInfluence *next;
+ float weight;
+ int vertex;
} MDefBindInfluence;
typedef struct MeshDeformBind {
- /* grid dimensions */
- float min[3], max[3];
- float width[3], halfwidth[3];
- int size, size3;
-
- /* meshes */
- Mesh *cagemesh;
- float (*cagecos)[3];
- float (*vertexcos)[3];
- int totvert, totcagevert;
-
- /* grids */
- MemArena *memarena;
- MDefBoundIsect *(*boundisect)[6];
- int *semibound;
- int *tag;
- float *phi, *totalphi;
-
- /* mesh stuff */
- int *inside;
- float *weights;
- MDefBindInfluence **dyngrid;
- float cagemat[4][4];
-
- /* direct solver */
- int *varidx;
-
- BVHTree *bvhtree;
- BVHTreeFromMesh bvhdata;
-
- /* avoid DM function calls during intersections */
- struct {
- const MPoly *mpoly;
- const MLoop *mloop;
- const MLoopTri *looptri;
- const float (*poly_nors)[3];
- } cagemesh_cache;
+ /* grid dimensions */
+ float min[3], max[3];
+ float width[3], halfwidth[3];
+ int size, size3;
+
+ /* meshes */
+ Mesh *cagemesh;
+ float (*cagecos)[3];
+ float (*vertexcos)[3];
+ int totvert, totcagevert;
+
+ /* grids */
+ MemArena *memarena;
+ MDefBoundIsect *(*boundisect)[6];
+ int *semibound;
+ int *tag;
+ float *phi, *totalphi;
+
+ /* mesh stuff */
+ int *inside;
+ float *weights;
+ MDefBindInfluence **dyngrid;
+ float cagemat[4][4];
+
+ /* direct solver */
+ int *varidx;
+
+ BVHTree *bvhtree;
+ BVHTreeFromMesh bvhdata;
+
+ /* avoid DM function calls during intersections */
+ struct {
+ const MPoly *mpoly;
+ const MLoop *mloop;
+ const MLoopTri *looptri;
+ const float (*poly_nors)[3];
+ } cagemesh_cache;
} MeshDeformBind;
typedef struct MeshDeformIsect {
- float start[3];
- float vec[3];
- float vec_length;
- float lambda;
+ float start[3];
+ float vec[3];
+ float vec_length;
+ float lambda;
- bool isect;
- float u, v;
+ bool isect;
+ float u, v;
} MeshDeformIsect;
/* ray intersection */
struct MeshRayCallbackData {
- MeshDeformBind *mdb;
- MeshDeformIsect *isec;
+ MeshDeformBind *mdb;
+ MeshDeformIsect *isec;
};
-static void harmonic_ray_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+static void harmonic_ray_callback(void *userdata,
+ int index,
+ const BVHTreeRay *ray,
+ BVHTreeRayHit *hit)
{
- struct MeshRayCallbackData *data = userdata;
- MeshDeformBind *mdb = data->mdb;
- const MLoop *mloop = mdb->cagemesh_cache.mloop;
- const MLoopTri *looptri = mdb->cagemesh_cache.looptri, *lt;
- const float (*poly_nors)[3] = mdb->cagemesh_cache.poly_nors;
- MeshDeformIsect *isec = data->isec;
- float no[3], co[3], dist;
- float *face[3];
-
- lt = &looptri[index];
-
- face[0] = mdb->cagecos[mloop[lt->tri[0]].v];
- face[1] = mdb->cagecos[mloop[lt->tri[1]].v];
- face[2] = mdb->cagecos[mloop[lt->tri[2]].v];
-
- bool isect_ray_tri = isect_ray_tri_watertight_v3(
- ray->origin, ray->isect_precalc, UNPACK3(face), &dist, NULL);
-
- if (!isect_ray_tri || dist > isec->vec_length) {
- return;
- }
-
- if (poly_nors) {
- copy_v3_v3(no, poly_nors[lt->poly]);
- }
- else {
- normal_tri_v3(no, UNPACK3(face));
- }
-
- madd_v3_v3v3fl(co, ray->origin, ray->direction, dist);
- dist /= isec->vec_length;
- if (dist < hit->dist) {
- hit->index = index;
- hit->dist = dist;
- copy_v3_v3(hit->co, co);
-
- isec->isect = (dot_v3v3(no, ray->direction) <= 0.0f);
- isec->lambda = dist;
- }
+ struct MeshRayCallbackData *data = userdata;
+ MeshDeformBind *mdb = data->mdb;
+ const MLoop *mloop = mdb->cagemesh_cache.mloop;
+ const MLoopTri *looptri = mdb->cagemesh_cache.looptri, *lt;
+ const float(*poly_nors)[3] = mdb->cagemesh_cache.poly_nors;
+ MeshDeformIsect *isec = data->isec;
+ float no[3], co[3], dist;
+ float *face[3];
+
+ lt = &looptri[index];
+
+ face[0] = mdb->cagecos[mloop[lt->tri[0]].v];
+ face[1] = mdb->cagecos[mloop[lt->tri[1]].v];
+ face[2] = mdb->cagecos[mloop[lt->tri[2]].v];
+
+ bool isect_ray_tri = isect_ray_tri_watertight_v3(
+ ray->origin, ray->isect_precalc, UNPACK3(face), &dist, NULL);
+
+ if (!isect_ray_tri || dist > isec->vec_length) {
+ return;
+ }
+
+ if (poly_nors) {
+ copy_v3_v3(no, poly_nors[lt->poly]);
+ }
+ else {
+ normal_tri_v3(no, UNPACK3(face));
+ }
+
+ madd_v3_v3v3fl(co, ray->origin, ray->direction, dist);
+ dist /= isec->vec_length;
+ if (dist < hit->dist) {
+ hit->index = index;
+ hit->dist = dist;
+ copy_v3_v3(hit->co, co);
+
+ isec->isect = (dot_v3v3(no, ray->direction) <= 0.0f);
+ isec->lambda = dist;
+ }
}
-static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, const float co1[3], const float co2[3])
+static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb,
+ const float co1[3],
+ const float co2[3])
{
- BVHTreeRayHit hit;
- MeshDeformIsect isect_mdef;
- struct MeshRayCallbackData data = {
- mdb,
- &isect_mdef,
- };
- float end[3], vec_normal[3];
-
- /* happens binding when a cage has no faces */
- if (UNLIKELY(mdb->bvhtree == NULL))
- return NULL;
-
- /* setup isec */
- memset(&isect_mdef, 0, sizeof(isect_mdef));
- isect_mdef.lambda = 1e10f;
-
- copy_v3_v3(isect_mdef.start, co1);
- copy_v3_v3(end, co2);
- sub_v3_v3v3(isect_mdef.vec, end, isect_mdef.start);
- isect_mdef.vec_length = normalize_v3_v3(vec_normal, isect_mdef.vec);
-
- hit.index = -1;
- hit.dist = BVH_RAYCAST_DIST_MAX;
- if (BLI_bvhtree_ray_cast_ex(mdb->bvhtree, isect_mdef.start, vec_normal,
- 0.0, &hit, harmonic_ray_callback, &data, BVH_RAYCAST_WATERTIGHT) != -1)
- {
- const MLoop *mloop = mdb->cagemesh_cache.mloop;
- const MLoopTri *lt = &mdb->cagemesh_cache.looptri[hit.index];
- const MPoly *mp = &mdb->cagemesh_cache.mpoly[lt->poly];
- const float (*cagecos)[3] = mdb->cagecos;
- const float len = isect_mdef.lambda;
- MDefBoundIsect *isect;
-
- float (*mp_cagecos)[3] = BLI_array_alloca(mp_cagecos, mp->totloop);
- int i;
-
- /* create MDefBoundIsect, and extra for 'poly_weights[]' */
- isect = BLI_memarena_alloc(mdb->memarena, sizeof(*isect) + (sizeof(float) * mp->totloop));
-
- /* compute intersection coordinate */
- madd_v3_v3v3fl(isect->co, co1, isect_mdef.vec, len);
-
- isect->facing = isect_mdef.isect;
-
- isect->poly_index = lt->poly;
-
- isect->len = max_ff(len_v3v3(co1, isect->co), MESHDEFORM_LEN_THRESHOLD);
-
- /* compute mean value coordinates for interpolation */
- for (i = 0; i < mp->totloop; i++) {
- copy_v3_v3(mp_cagecos[i], cagecos[mloop[mp->loopstart + i].v]);
- }
-
- interp_weights_poly_v3(isect->poly_weights, mp_cagecos, mp->totloop, isect->co);
-
- return isect;
- }
-
- return NULL;
+ BVHTreeRayHit hit;
+ MeshDeformIsect isect_mdef;
+ struct MeshRayCallbackData data = {
+ mdb,
+ &isect_mdef,
+ };
+ float end[3], vec_normal[3];
+
+ /* happens binding when a cage has no faces */
+ if (UNLIKELY(mdb->bvhtree == NULL))
+ return NULL;
+
+ /* setup isec */
+ memset(&isect_mdef, 0, sizeof(isect_mdef));
+ isect_mdef.lambda = 1e10f;
+
+ copy_v3_v3(isect_mdef.start, co1);
+ copy_v3_v3(end, co2);
+ sub_v3_v3v3(isect_mdef.vec, end, isect_mdef.start);
+ isect_mdef.vec_length = normalize_v3_v3(vec_normal, isect_mdef.vec);
+
+ hit.index = -1;
+ hit.dist = BVH_RAYCAST_DIST_MAX;
+ if (BLI_bvhtree_ray_cast_ex(mdb->bvhtree,
+ isect_mdef.start,
+ vec_normal,
+ 0.0,
+ &hit,
+ harmonic_ray_callback,
+ &data,
+ BVH_RAYCAST_WATERTIGHT) != -1) {
+ const MLoop *mloop = mdb->cagemesh_cache.mloop;
+ const MLoopTri *lt = &mdb->cagemesh_cache.looptri[hit.index];
+ const MPoly *mp = &mdb->cagemesh_cache.mpoly[lt->poly];
+ const float(*cagecos)[3] = mdb->cagecos;
+ const float len = isect_mdef.lambda;
+ MDefBoundIsect *isect;
+
+ float(*mp_cagecos)[3] = BLI_array_alloca(mp_cagecos, mp->totloop);
+ int i;
+
+ /* create MDefBoundIsect, and extra for 'poly_weights[]' */
+ isect = BLI_memarena_alloc(mdb->memarena, sizeof(*isect) + (sizeof(float) * mp->totloop));
+
+ /* compute intersection coordinate */
+ madd_v3_v3v3fl(isect->co, co1, isect_mdef.vec, len);
+
+ isect->facing = isect_mdef.isect;
+
+ isect->poly_index = lt->poly;
+
+ isect->len = max_ff(len_v3v3(co1, isect->co), MESHDEFORM_LEN_THRESHOLD);
+
+ /* compute mean value coordinates for interpolation */
+ for (i = 0; i < mp->totloop; i++) {
+ copy_v3_v3(mp_cagecos[i], cagecos[mloop[mp->loopstart + i].v]);
+ }
+
+ interp_weights_poly_v3(isect->poly_weights, mp_cagecos, mp->totloop, isect->co);
+
+ return isect;
+ }
+
+ return NULL;
}
static int meshdeform_inside_cage(MeshDeformBind *mdb, float *co)
{
- MDefBoundIsect *isect;
- float outside[3], start[3], dir[3];
- int i;
+ MDefBoundIsect *isect;
+ float outside[3], start[3], dir[3];
+ int i;
- for (i = 1; i <= 6; i++) {
- outside[0] = co[0] + (mdb->max[0] - mdb->min[0] + 1.0f) * MESHDEFORM_OFFSET[i][0];
- outside[1] = co[1] + (mdb->max[1] - mdb->min[1] + 1.0f) * MESHDEFORM_OFFSET[i][1];
- outside[2] = co[2] + (mdb->max[2] - mdb->min[2] + 1.0f) * MESHDEFORM_OFFSET[i][2];
+ for (i = 1; i <= 6; i++) {
+ outside[0] = co[0] + (mdb->max[0] - mdb->min[0] + 1.0f) * MESHDEFORM_OFFSET[i][0];
+ outside[1] = co[1] + (mdb->max[1] - mdb->min[1] + 1.0f) * MESHDEFORM_OFFSET[i][1];
+ outside[2] = co[2] + (mdb->max[2] - mdb->min[2] + 1.0f) * MESHDEFORM_OFFSET[i][2];
- copy_v3_v3(start, co);
- sub_v3_v3v3(dir, outside, start);
- normalize_v3(dir);
+ copy_v3_v3(start, co);
+ sub_v3_v3v3(dir, outside, start);
+ normalize_v3(dir);
- isect = meshdeform_ray_tree_intersect(mdb, start, outside);
- if (isect && !isect->facing)
- return 1;
- }
+ isect = meshdeform_ray_tree_intersect(mdb, start, outside);
+ if (isect && !isect->facing)
+ return 1;
+ }
- return 0;
+ return 0;
}
/* solving */
BLI_INLINE int meshdeform_index(MeshDeformBind *mdb, int x, int y, int z, int n)
{
- int size = mdb->size;
+ int size = mdb->size;
- x += MESHDEFORM_OFFSET[n][0];
- y += MESHDEFORM_OFFSET[n][1];
- z += MESHDEFORM_OFFSET[n][2];
+ x += MESHDEFORM_OFFSET[n][0];
+ y += MESHDEFORM_OFFSET[n][1];
+ z += MESHDEFORM_OFFSET[n][2];
- if (x < 0 || x >= mdb->size)
- return -1;
- if (y < 0 || y >= mdb->size)
- return -1;
- if (z < 0 || z >= mdb->size)
- return -1;
+ if (x < 0 || x >= mdb->size)
+ return -1;
+ if (y < 0 || y >= mdb->size)
+ return -1;
+ if (z < 0 || z >= mdb->size)
+ return -1;
- return x + y * size + z * size * size;
+ return x + y * size + z * size * size;
}
-BLI_INLINE void meshdeform_cell_center(MeshDeformBind *mdb, int x, int y, int z, int n, float *center)
+BLI_INLINE void meshdeform_cell_center(
+ MeshDeformBind *mdb, int x, int y, int z, int n, float *center)
{
- x += MESHDEFORM_OFFSET[n][0];
- y += MESHDEFORM_OFFSET[n][1];
- z += MESHDEFORM_OFFSET[n][2];
+ x += MESHDEFORM_OFFSET[n][0];
+ y += MESHDEFORM_OFFSET[n][1];
+ z += MESHDEFORM_OFFSET[n][2];
- center[0] = mdb->min[0] + x * mdb->width[0] + mdb->halfwidth[0];
- center[1] = mdb->min[1] + y * mdb->width[1] + mdb->halfwidth[1];
- center[2] = mdb->min[2] + z * mdb->width[2] + mdb->halfwidth[2];
+ center[0] = mdb->min[0] + x * mdb->width[0] + mdb->halfwidth[0];
+ center[1] = mdb->min[1] + y * mdb->width[1] + mdb->halfwidth[1];
+ center[2] = mdb->min[2] + z * mdb->width[2] + mdb->halfwidth[2];
}
static void meshdeform_add_intersections(MeshDeformBind *mdb, int x, int y, int z)
{
- MDefBoundIsect *isect;
- float center[3], ncenter[3];
- int i, a;
-
- a = meshdeform_index(mdb, x, y, z, 0);
- meshdeform_cell_center(mdb, x, y, z, 0, center);
-
- /* check each outgoing edge for intersection */
- for (i = 1; i <= 6; i++) {
- if (meshdeform_index(mdb, x, y, z, i) == -1)
- continue;
-
- meshdeform_cell_center(mdb, x, y, z, i, ncenter);
-
- isect = meshdeform_ray_tree_intersect(mdb, center, ncenter);
- if (isect) {
- mdb->boundisect[a][i - 1] = isect;
- mdb->tag[a] = MESHDEFORM_TAG_BOUNDARY;
- }
- }
+ MDefBoundIsect *isect;
+ float center[3], ncenter[3];
+ int i, a;
+
+ a = meshdeform_index(mdb, x, y, z, 0);
+ meshdeform_cell_center(mdb, x, y, z, 0, center);
+
+ /* check each outgoing edge for intersection */
+ for (i = 1; i <= 6; i++) {
+ if (meshdeform_index(mdb, x, y, z, i) == -1)
+ continue;
+
+ meshdeform_cell_center(mdb, x, y, z, i, ncenter);
+
+ isect = meshdeform_ray_tree_intersect(mdb, center, ncenter);
+ if (isect) {
+ mdb->boundisect[a][i - 1] = isect;
+ mdb->tag[a] = MESHDEFORM_TAG_BOUNDARY;
+ }
+ }
}
static void meshdeform_bind_floodfill(MeshDeformBind *mdb)
{
- int *stack, *tag = mdb->tag;
- int a, b, i, xyz[3], stacksize, size = mdb->size;
-
- stack = MEM_callocN(sizeof(int) * mdb->size3, "MeshDeformBindStack");
-
- /* we know lower left corner is EXTERIOR because of padding */
- tag[0] = MESHDEFORM_TAG_EXTERIOR;
- stack[0] = 0;
- stacksize = 1;
-
- /* floodfill exterior tag */
- while (stacksize > 0) {
- a = stack[--stacksize];
-
- xyz[2] = a / (size * size);
- xyz[1] = (a - xyz[2] * size * size) / size;
- xyz[0] = a - xyz[1] * size - xyz[2] * size * size;
-
- for (i = 1; i <= 6; i++) {
- b = meshdeform_index(mdb, xyz[0], xyz[1], xyz[2], i);
-
- if (b != -1) {
- if (tag[b] == MESHDEFORM_TAG_UNTYPED ||
- (tag[b] == MESHDEFORM_TAG_BOUNDARY && !mdb->boundisect[a][i - 1]))
- {
- tag[b] = MESHDEFORM_TAG_EXTERIOR;
- stack[stacksize++] = b;
- }
- }
- }
- }
-
- /* other cells are interior */
- for (a = 0; a < size * size * size; a++)
- if (tag[a] == MESHDEFORM_TAG_UNTYPED)
- tag[a] = MESHDEFORM_TAG_INTERIOR;
+ int *stack, *tag = mdb->tag;
+ int a, b, i, xyz[3], stacksize, size = mdb->size;
+
+ stack = MEM_callocN(sizeof(int) * mdb->size3, "MeshDeformBindStack");
+
+ /* we know lower left corner is EXTERIOR because of padding */
+ tag[0] = MESHDEFORM_TAG_EXTERIOR;
+ stack[0] = 0;
+ stacksize = 1;
+
+ /* floodfill exterior tag */
+ while (stacksize > 0) {
+ a = stack[--stacksize];
+
+ xyz[2] = a / (size * size);
+ xyz[1] = (a - xyz[2] * size * size) / size;
+ xyz[0] = a - xyz[1] * size - xyz[2] * size * size;
+
+ for (i = 1; i <= 6; i++) {
+ b = meshdeform_index(mdb, xyz[0], xyz[1], xyz[2], i);
+
+ if (b != -1) {
+ if (tag[b] == MESHDEFORM_TAG_UNTYPED ||
+ (tag[b] == MESHDEFORM_TAG_BOUNDARY && !mdb->boundisect[a][i - 1])) {
+ tag[b] = MESHDEFORM_TAG_EXTERIOR;
+ stack[stacksize++] = b;
+ }
+ }
+ }
+ }
+
+ /* other cells are interior */
+ for (a = 0; a < size * size * size; a++)
+ if (tag[a] == MESHDEFORM_TAG_UNTYPED)
+ tag[a] = MESHDEFORM_TAG_INTERIOR;
#if 0
- {
- int tb, ti, te, ts;
- tb = ti = te = ts = 0;
- for (a = 0; a < size * size * size; a++)
- if (tag[a] == MESHDEFORM_TAG_BOUNDARY)
- tb++;
- else if (tag[a] == MESHDEFORM_TAG_INTERIOR)
- ti++;
- else if (tag[a] == MESHDEFORM_TAG_EXTERIOR) {
- te++;
-
- if (mdb->semibound[a])
- ts++;
- }
-
- printf("interior %d exterior %d boundary %d semi-boundary %d\n", ti, te, tb, ts);
- }
+ {
+ int tb, ti, te, ts;
+ tb = ti = te = ts = 0;
+ for (a = 0; a < size * size * size; a++)
+ if (tag[a] == MESHDEFORM_TAG_BOUNDARY)
+ tb++;
+ else if (tag[a] == MESHDEFORM_TAG_INTERIOR)
+ ti++;
+ else if (tag[a] == MESHDEFORM_TAG_EXTERIOR) {
+ te++;
+
+ if (mdb->semibound[a])
+ ts++;
+ }
+
+ printf("interior %d exterior %d boundary %d semi-boundary %d\n", ti, te, tb, ts);
+ }
#endif
- MEM_freeN(stack);
+ MEM_freeN(stack);
}
-static float meshdeform_boundary_phi(const MeshDeformBind *mdb, const MDefBoundIsect *isect, int cagevert)
+static float meshdeform_boundary_phi(const MeshDeformBind *mdb,
+ const MDefBoundIsect *isect,
+ int cagevert)
{
- const MLoop *mloop = mdb->cagemesh_cache.mloop;
- const MPoly *mp = &mdb->cagemesh_cache.mpoly[isect->poly_index];
- int i;
+ const MLoop *mloop = mdb->cagemesh_cache.mloop;
+ const MPoly *mp = &mdb->cagemesh_cache.mpoly[isect->poly_index];
+ int i;
- for (i = 0; i < mp->totloop; i++) {
- if (mloop[mp->loopstart + i].v == cagevert) {
- return isect->poly_weights[i];
- }
- }
+ for (i = 0; i < mp->totloop; i++) {
+ if (mloop[mp->loopstart + i].v == cagevert) {
+ return isect->poly_weights[i];
+ }
+ }
- return 0.0f;
+ return 0.0f;
}
-static float meshdeform_interp_w(MeshDeformBind *mdb, float *gridvec, float *UNUSED(vec), int UNUSED(cagevert))
+static float meshdeform_interp_w(MeshDeformBind *mdb,
+ float *gridvec,
+ float *UNUSED(vec),
+ int UNUSED(cagevert))
{
- float dvec[3], ivec[3], wx, wy, wz, result = 0.0f;
- float weight, totweight = 0.0f;
- int i, a, x, y, z;
-
- for (i = 0; i < 3; i++) {
- ivec[i] = (int)gridvec[i];
- dvec[i] = gridvec[i] - ivec[i];
- }
-
- for (i = 0; i < 8; i++) {
- if (i & 1) { x = ivec[0] + 1; wx = dvec[0]; }
- else { x = ivec[0]; wx = 1.0f - dvec[0]; }
-
- if (i & 2) { y = ivec[1] + 1; wy = dvec[1]; }
- else { y = ivec[1]; wy = 1.0f - dvec[1]; }
-
- if (i & 4) { z = ivec[2] + 1; wz = dvec[2]; }
- else { z = ivec[2]; wz = 1.0f - dvec[2]; }
-
- CLAMP(x, 0, mdb->size - 1);
- CLAMP(y, 0, mdb->size - 1);
- CLAMP(z, 0, mdb->size - 1);
-
- a = meshdeform_index(mdb, x, y, z, 0);
- weight = wx * wy * wz;
- result += weight * mdb->phi[a];
- totweight += weight;
- }
-
- if (totweight > 0.0f)
- result /= totweight;
-
- return result;
+ float dvec[3], ivec[3], wx, wy, wz, result = 0.0f;
+ float weight, totweight = 0.0f;
+ int i, a, x, y, z;
+
+ for (i = 0; i < 3; i++) {
+ ivec[i] = (int)gridvec[i];
+ dvec[i] = gridvec[i] - ivec[i];
+ }
+
+ for (i = 0; i < 8; i++) {
+ if (i & 1) {
+ x = ivec[0] + 1;
+ wx = dvec[0];
+ }
+ else {
+ x = ivec[0];
+ wx = 1.0f - dvec[0];
+ }
+
+ if (i & 2) {
+ y = ivec[1] + 1;
+ wy = dvec[1];
+ }
+ else {
+ y = ivec[1];
+ wy = 1.0f - dvec[1];
+ }
+
+ if (i & 4) {
+ z = ivec[2] + 1;
+ wz = dvec[2];
+ }
+ else {
+ z = ivec[2];
+ wz = 1.0f - dvec[2];
+ }
+
+ CLAMP(x, 0, mdb->size - 1);
+ CLAMP(y, 0, mdb->size - 1);
+ CLAMP(z, 0, mdb->size - 1);
+
+ a = meshdeform_index(mdb, x, y, z, 0);
+ weight = wx * wy * wz;
+ result += weight * mdb->phi[a];
+ totweight += weight;
+ }
+
+ if (totweight > 0.0f)
+ result /= totweight;
+
+ return result;
}
static void meshdeform_check_semibound(MeshDeformBind *mdb, int x, int y, int z)
{
- int i, a;
+ int i, a;
- a = meshdeform_index(mdb, x, y, z, 0);
- if (mdb->tag[a] != MESHDEFORM_TAG_EXTERIOR)
- return;
+ a = meshdeform_index(mdb, x, y, z, 0);
+ if (mdb->tag[a] != MESHDEFORM_TAG_EXTERIOR)
+ return;
- for (i = 1; i <= 6; i++)
- if (mdb->boundisect[a][i - 1])
- mdb->semibound[a] = 1;
+ for (i = 1; i <= 6; i++)
+ if (mdb->boundisect[a][i - 1])
+ mdb->semibound[a] = 1;
}
static float meshdeform_boundary_total_weight(MeshDeformBind *mdb, int x, int y, int z)
{
- float weight, totweight = 0.0f;
- int i, a;
+ float weight, totweight = 0.0f;
+ int i, a;
- a = meshdeform_index(mdb, x, y, z, 0);
+ a = meshdeform_index(mdb, x, y, z, 0);
- /* count weight for neighbor cells */
- for (i = 1; i <= 6; i++) {
- if (meshdeform_index(mdb, x, y, z, i) == -1)
- continue;
+ /* count weight for neighbor cells */
+ for (i = 1; i <= 6; i++) {
+ if (meshdeform_index(mdb, x, y, z, i) == -1)
+ continue;
- if (mdb->boundisect[a][i - 1])
- weight = 1.0f / mdb->boundisect[a][i - 1]->len;
- else if (!mdb->semibound[a])
- weight = 1.0f / mdb->width[0];
- else
- weight = 0.0f;
+ if (mdb->boundisect[a][i - 1])
+ weight = 1.0f / mdb->boundisect[a][i - 1]->len;
+ else if (!mdb->semibound[a])
+ weight = 1.0f / mdb->width[0];
+ else
+ weight = 0.0f;
- totweight += weight;
- }
+ totweight += weight;
+ }
- return totweight;
+ return totweight;
}
-static void meshdeform_matrix_add_cell(MeshDeformBind *mdb, LinearSolver *context, int x, int y, int z)
+static void meshdeform_matrix_add_cell(
+ MeshDeformBind *mdb, LinearSolver *context, int x, int y, int z)
{
- MDefBoundIsect *isect;
- float weight, totweight;
- int i, a, acenter;
-
- acenter = meshdeform_index(mdb, x, y, z, 0);
- if (mdb->tag[acenter] == MESHDEFORM_TAG_EXTERIOR)
- return;
-
- EIG_linear_solver_matrix_add(context, mdb->varidx[acenter], mdb->varidx[acenter], 1.0f);
-
- totweight = meshdeform_boundary_total_weight(mdb, x, y, z);
- for (i = 1; i <= 6; i++) {
- a = meshdeform_index(mdb, x, y, z, i);
- if (a == -1 || mdb->tag[a] == MESHDEFORM_TAG_EXTERIOR)
- continue;
-
- isect = mdb->boundisect[acenter][i - 1];
- if (!isect) {
- weight = (1.0f / mdb->width[0]) / totweight;
- EIG_linear_solver_matrix_add(context, mdb->varidx[acenter], mdb->varidx[a], -weight);
- }
- }
+ MDefBoundIsect *isect;
+ float weight, totweight;
+ int i, a, acenter;
+
+ acenter = meshdeform_index(mdb, x, y, z, 0);
+ if (mdb->tag[acenter] == MESHDEFORM_TAG_EXTERIOR)
+ return;
+
+ EIG_linear_solver_matrix_add(context, mdb->varidx[acenter], mdb->varidx[acenter], 1.0f);
+
+ totweight = meshdeform_boundary_total_weight(mdb, x, y, z);
+ for (i = 1; i <= 6; i++) {
+ a = meshdeform_index(mdb, x, y, z, i);
+ if (a == -1 || mdb->tag[a] == MESHDEFORM_TAG_EXTERIOR)
+ continue;
+
+ isect = mdb->boundisect[acenter][i - 1];
+ if (!isect) {
+ weight = (1.0f / mdb->width[0]) / totweight;
+ EIG_linear_solver_matrix_add(context, mdb->varidx[acenter], mdb->varidx[a], -weight);
+ }
+ }
}
-static void meshdeform_matrix_add_rhs(MeshDeformBind *mdb, LinearSolver *context, int x, int y, int z, int cagevert)
+static void meshdeform_matrix_add_rhs(
+ MeshDeformBind *mdb, LinearSolver *context, int x, int y, int z, int cagevert)
{
- MDefBoundIsect *isect;
- float rhs, weight, totweight;
- int i, a, acenter;
-
- acenter = meshdeform_index(mdb, x, y, z, 0);
- if (mdb->tag[acenter] == MESHDEFORM_TAG_EXTERIOR)
- return;
-
- totweight = meshdeform_boundary_total_weight(mdb, x, y, z);
- for (i = 1; i <= 6; i++) {
- a = meshdeform_index(mdb, x, y, z, i);
- if (a == -1)
- continue;
-
- isect = mdb->boundisect[acenter][i - 1];
-
- if (isect) {
- weight = (1.0f / isect->len) / totweight;
- rhs = weight * meshdeform_boundary_phi(mdb, isect, cagevert);
- EIG_linear_solver_right_hand_side_add(context, 0, mdb->varidx[acenter], rhs);
- }
- }
+ MDefBoundIsect *isect;
+ float rhs, weight, totweight;
+ int i, a, acenter;
+
+ acenter = meshdeform_index(mdb, x, y, z, 0);
+ if (mdb->tag[acenter] == MESHDEFORM_TAG_EXTERIOR)
+ return;
+
+ totweight = meshdeform_boundary_total_weight(mdb, x, y, z);
+ for (i = 1; i <= 6; i++) {
+ a = meshdeform_index(mdb, x, y, z, i);
+ if (a == -1)
+ continue;
+
+ isect = mdb->boundisect[acenter][i - 1];
+
+ if (isect) {
+ weight = (1.0f / isect->len) / totweight;
+ rhs = weight * meshdeform_boundary_phi(mdb, isect, cagevert);
+ EIG_linear_solver_right_hand_side_add(context, 0, mdb->varidx[acenter], rhs);
+ }
+ }
}
-static void meshdeform_matrix_add_semibound_phi(MeshDeformBind *mdb, int x, int y, int z, int cagevert)
+static void meshdeform_matrix_add_semibound_phi(
+ MeshDeformBind *mdb, int x, int y, int z, int cagevert)
{
- MDefBoundIsect *isect;
- float rhs, weight, totweight;
- int i, a;
-
- a = meshdeform_index(mdb, x, y, z, 0);
- if (!mdb->semibound[a])
- return;
-
- mdb->phi[a] = 0.0f;
-
- totweight = meshdeform_boundary_total_weight(mdb, x, y, z);
- for (i = 1; i <= 6; i++) {
- isect = mdb->boundisect[a][i - 1];
-
- if (isect) {
- weight = (1.0f / isect->len) / totweight;
- rhs = weight * meshdeform_boundary_phi(mdb, isect, cagevert);
- mdb->phi[a] += rhs;
- }
- }
+ MDefBoundIsect *isect;
+ float rhs, weight, totweight;
+ int i, a;
+
+ a = meshdeform_index(mdb, x, y, z, 0);
+ if (!mdb->semibound[a])
+ return;
+
+ mdb->phi[a] = 0.0f;
+
+ totweight = meshdeform_boundary_total_weight(mdb, x, y, z);
+ for (i = 1; i <= 6; i++) {
+ isect = mdb->boundisect[a][i - 1];
+
+ if (isect) {
+ weight = (1.0f / isect->len) / totweight;
+ rhs = weight * meshdeform_boundary_phi(mdb, isect, cagevert);
+ mdb->phi[a] += rhs;
+ }
+ }
}
-static void meshdeform_matrix_add_exterior_phi(MeshDeformBind *mdb, int x, int y, int z, int UNUSED(cagevert))
+static void meshdeform_matrix_add_exterior_phi(
+ MeshDeformBind *mdb, int x, int y, int z, int UNUSED(cagevert))
{
- float phi, totweight;
- int i, a, acenter;
-
- acenter = meshdeform_index(mdb, x, y, z, 0);
- if (mdb->tag[acenter] != MESHDEFORM_TAG_EXTERIOR || mdb->semibound[acenter])
- return;
-
- phi = 0.0f;
- totweight = 0.0f;
- for (i = 1; i <= 6; i++) {
- a = meshdeform_index(mdb, x, y, z, i);
-
- if (a != -1 && mdb->semibound[a]) {
- phi += mdb->phi[a];
- totweight += 1.0f;
- }
- }
-
- if (totweight != 0.0f)
- mdb->phi[acenter] = phi / totweight;
+ float phi, totweight;
+ int i, a, acenter;
+
+ acenter = meshdeform_index(mdb, x, y, z, 0);
+ if (mdb->tag[acenter] != MESHDEFORM_TAG_EXTERIOR || mdb->semibound[acenter])
+ return;
+
+ phi = 0.0f;
+ totweight = 0.0f;
+ for (i = 1; i <= 6; i++) {
+ a = meshdeform_index(mdb, x, y, z, i);
+
+ if (a != -1 && mdb->semibound[a]) {
+ phi += mdb->phi[a];
+ totweight += 1.0f;
+ }
+ }
+
+ if (totweight != 0.0f)
+ mdb->phi[acenter] = phi / totweight;
}
static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind *mdb)
{
- LinearSolver *context;
- float vec[3], gridvec[3];
- int a, b, x, y, z, totvar;
- char message[256];
-
- /* setup variable indices */
- mdb->varidx = MEM_callocN(sizeof(int) * mdb->size3, "MeshDeformDSvaridx");
- for (a = 0, totvar = 0; a < mdb->size3; a++)
- mdb->varidx[a] = (mdb->tag[a] == MESHDEFORM_TAG_EXTERIOR) ? -1 : totvar++;
-
- if (totvar == 0) {
- MEM_freeN(mdb->varidx);
- return;
- }
-
- progress_bar(0, "Starting mesh deform solve");
-
- /* setup linear solver */
- context = EIG_linear_solver_new(totvar, totvar, 1);
-
- /* build matrix */
- for (z = 0; z < mdb->size; z++)
- for (y = 0; y < mdb->size; y++)
- for (x = 0; x < mdb->size; x++)
- meshdeform_matrix_add_cell(mdb, context, x, y, z);
-
- /* solve for each cage vert */
- for (a = 0; a < mdb->totcagevert; a++) {
- /* fill in right hand side and solve */
- for (z = 0; z < mdb->size; z++)
- for (y = 0; y < mdb->size; y++)
- for (x = 0; x < mdb->size; x++)
- meshdeform_matrix_add_rhs(mdb, context, x, y, z, a);
-
- if (EIG_linear_solver_solve(context)) {
- for (z = 0; z < mdb->size; z++)
- for (y = 0; y < mdb->size; y++)
- for (x = 0; x < mdb->size; x++)
- meshdeform_matrix_add_semibound_phi(mdb, x, y, z, a);
-
- for (z = 0; z < mdb->size; z++)
- for (y = 0; y < mdb->size; y++)
- for (x = 0; x < mdb->size; x++)
- meshdeform_matrix_add_exterior_phi(mdb, x, y, z, a);
-
- for (b = 0; b < mdb->size3; b++) {
- if (mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR)
- mdb->phi[b] = EIG_linear_solver_variable_get(context, 0, mdb->varidx[b]);
- mdb->totalphi[b] += mdb->phi[b];
- }
-
- if (mdb->weights) {
- /* static bind : compute weights for each vertex */
- for (b = 0; b < mdb->totvert; b++) {
- if (mdb->inside[b]) {
- copy_v3_v3(vec, mdb->vertexcos[b]);
- gridvec[0] = (vec[0] - mdb->min[0] - mdb->halfwidth[0]) / mdb->width[0];
- gridvec[1] = (vec[1] - mdb->min[1] - mdb->halfwidth[1]) / mdb->width[1];
- gridvec[2] = (vec[2] - mdb->min[2] - mdb->halfwidth[2]) / mdb->width[2];
-
- mdb->weights[b * mdb->totcagevert + a] = meshdeform_interp_w(mdb, gridvec, vec, a);
- }
- }
- }
- else {
- MDefBindInfluence *inf;
-
- /* dynamic bind */
- for (b = 0; b < mdb->size3; b++) {
- if (mdb->phi[b] >= MESHDEFORM_MIN_INFLUENCE) {
- inf = BLI_memarena_alloc(mdb->memarena, sizeof(*inf));
- inf->vertex = a;
- inf->weight = mdb->phi[b];
- inf->next = mdb->dyngrid[b];
- mdb->dyngrid[b] = inf;
- }
- }
- }
- }
- else {
- modifier_setError(&mmd->modifier, "Failed to find bind solution (increase precision?)");
- error("Mesh Deform: failed to find bind solution.");
- break;
- }
-
- BLI_snprintf(message, sizeof(message), "Mesh deform solve %d / %d |||", a + 1, mdb->totcagevert);
- progress_bar((float)(a + 1) / (float)(mdb->totcagevert), message);
- }
+ LinearSolver *context;
+ float vec[3], gridvec[3];
+ int a, b, x, y, z, totvar;
+ char message[256];
+
+ /* setup variable indices */
+ mdb->varidx = MEM_callocN(sizeof(int) * mdb->size3, "MeshDeformDSvaridx");
+ for (a = 0, totvar = 0; a < mdb->size3; a++)
+ mdb->varidx[a] = (mdb->tag[a] == MESHDEFORM_TAG_EXTERIOR) ? -1 : totvar++;
+
+ if (totvar == 0) {
+ MEM_freeN(mdb->varidx);
+ return;
+ }
+
+ progress_bar(0, "Starting mesh deform solve");
+
+ /* setup linear solver */
+ context = EIG_linear_solver_new(totvar, totvar, 1);
+
+ /* build matrix */
+ for (z = 0; z < mdb->size; z++)
+ for (y = 0; y < mdb->size; y++)
+ for (x = 0; x < mdb->size; x++)
+ meshdeform_matrix_add_cell(mdb, context, x, y, z);
+
+ /* solve for each cage vert */
+ for (a = 0; a < mdb->totcagevert; a++) {
+ /* fill in right hand side and solve */
+ for (z = 0; z < mdb->size; z++)
+ for (y = 0; y < mdb->size; y++)
+ for (x = 0; x < mdb->size; x++)
+ meshdeform_matrix_add_rhs(mdb, context, x, y, z, a);
+
+ if (EIG_linear_solver_solve(context)) {
+ for (z = 0; z < mdb->size; z++)
+ for (y = 0; y < mdb->size; y++)
+ for (x = 0; x < mdb->size; x++)
+ meshdeform_matrix_add_semibound_phi(mdb, x, y, z, a);
+
+ for (z = 0; z < mdb->size; z++)
+ for (y = 0; y < mdb->size; y++)
+ for (x = 0; x < mdb->size; x++)
+ meshdeform_matrix_add_exterior_phi(mdb, x, y, z, a);
+
+ for (b = 0; b < mdb->size3; b++) {
+ if (mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR)
+ mdb->phi[b] = EIG_linear_solver_variable_get(context, 0, mdb->varidx[b]);
+ mdb->totalphi[b] += mdb->phi[b];
+ }
+
+ if (mdb->weights) {
+ /* static bind : compute weights for each vertex */
+ for (b = 0; b < mdb->totvert; b++) {
+ if (mdb->inside[b]) {
+ copy_v3_v3(vec, mdb->vertexcos[b]);
+ gridvec[0] = (vec[0] - mdb->min[0] - mdb->halfwidth[0]) / mdb->width[0];
+ gridvec[1] = (vec[1] - mdb->min[1] - mdb->halfwidth[1]) / mdb->width[1];
+ gridvec[2] = (vec[2] - mdb->min[2] - mdb->halfwidth[2]) / mdb->width[2];
+
+ mdb->weights[b * mdb->totcagevert + a] = meshdeform_interp_w(mdb, gridvec, vec, a);
+ }
+ }
+ }
+ else {
+ MDefBindInfluence *inf;
+
+ /* dynamic bind */
+ for (b = 0; b < mdb->size3; b++) {
+ if (mdb->phi[b] >= MESHDEFORM_MIN_INFLUENCE) {
+ inf = BLI_memarena_alloc(mdb->memarena, sizeof(*inf));
+ inf->vertex = a;
+ inf->weight = mdb->phi[b];
+ inf->next = mdb->dyngrid[b];
+ mdb->dyngrid[b] = inf;
+ }
+ }
+ }
+ }
+ else {
+ modifier_setError(&mmd->modifier, "Failed to find bind solution (increase precision?)");
+ error("Mesh Deform: failed to find bind solution.");
+ break;
+ }
+
+ BLI_snprintf(
+ message, sizeof(message), "Mesh deform solve %d / %d |||", a + 1, mdb->totcagevert);
+ progress_bar((float)(a + 1) / (float)(mdb->totcagevert), message);
+ }
#if 0
- /* sanity check */
- for (b = 0; b < mdb->size3; b++)
- if (mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR)
- if (fabsf(mdb->totalphi[b] - 1.0f) > 1e-4f)
- printf("totalphi deficiency [%s|%d] %d: %.10f\n",
- (mdb->tag[b] == MESHDEFORM_TAG_INTERIOR) ? "interior" : "boundary", mdb->semibound[b], mdb->varidx[b], mdb->totalphi[b]);
+ /* sanity check */
+ for (b = 0; b < mdb->size3; b++)
+ if (mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR)
+ if (fabsf(mdb->totalphi[b] - 1.0f) > 1e-4f)
+ printf("totalphi deficiency [%s|%d] %d: %.10f\n",
+ (mdb->tag[b] == MESHDEFORM_TAG_INTERIOR) ? "interior" : "boundary", mdb->semibound[b], mdb->varidx[b], mdb->totalphi[b]);
#endif
- /* free */
- MEM_freeN(mdb->varidx);
+ /* free */
+ MEM_freeN(mdb->varidx);
- EIG_linear_solver_delete(context);
+ EIG_linear_solver_delete(context);
}
static void harmonic_coordinates_bind(MeshDeformModifierData *mmd, MeshDeformBind *mdb)
{
- MDefBindInfluence *inf;
- MDefInfluence *mdinf;
- MDefCell *cell;
- float center[3], vec[3], maxwidth, totweight;
- int a, b, x, y, z, totinside, offset;
-
- /* compute bounding box of the cage mesh */
- INIT_MINMAX(mdb->min, mdb->max);
-
- for (a = 0; a < mdb->totcagevert; a++)
- minmax_v3v3_v3(mdb->min, mdb->max, mdb->cagecos[a]);
-
- /* allocate memory */
- mdb->size = (2 << (mmd->gridsize - 1)) + 2;
- mdb->size3 = mdb->size * mdb->size * mdb->size;
- mdb->tag = MEM_callocN(sizeof(int) * mdb->size3, "MeshDeformBindTag");
- mdb->phi = MEM_callocN(sizeof(float) * mdb->size3, "MeshDeformBindPhi");
- mdb->totalphi = MEM_callocN(sizeof(float) * mdb->size3, "MeshDeformBindTotalPhi");
- mdb->boundisect = MEM_callocN(sizeof(*mdb->boundisect) * mdb->size3, "MDefBoundIsect");
- mdb->semibound = MEM_callocN(sizeof(int) * mdb->size3, "MDefSemiBound");
- mdb->bvhtree = BKE_bvhtree_from_mesh_get(&mdb->bvhdata, mdb->cagemesh, BVHTREE_FROM_LOOPTRI, 4);
- mdb->inside = MEM_callocN(sizeof(int) * mdb->totvert, "MDefInside");
-
- if (mmd->flag & MOD_MDEF_DYNAMIC_BIND)
- mdb->dyngrid = MEM_callocN(sizeof(MDefBindInfluence *) * mdb->size3, "MDefDynGrid");
- else
- mdb->weights = MEM_callocN(sizeof(float) * mdb->totvert * mdb->totcagevert, "MDefWeights");
-
- mdb->memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "harmonic coords arena");
- BLI_memarena_use_calloc(mdb->memarena);
-
- /* initialize data from 'cagedm' for reuse */
- {
- Mesh *me = mdb->cagemesh;
- mdb->cagemesh_cache.mpoly = me->mpoly;
- mdb->cagemesh_cache.mloop = me->mloop;
- mdb->cagemesh_cache.looptri = BKE_mesh_runtime_looptri_ensure(me);
- /* can be NULL */
- mdb->cagemesh_cache.poly_nors = CustomData_get_layer(&me->pdata, CD_NORMAL);
- }
-
- /* make bounding box equal size in all directions, add padding, and compute
- * width of the cells */
- maxwidth = -1.0f;
- for (a = 0; a < 3; a++)
- if (mdb->max[a] - mdb->min[a] > maxwidth)
- maxwidth = mdb->max[a] - mdb->min[a];
-
- for (a = 0; a < 3; a++) {
- center[a] = (mdb->min[a] + mdb->max[a]) * 0.5f;
- mdb->min[a] = center[a] - maxwidth * 0.5f;
- mdb->max[a] = center[a] + maxwidth * 0.5f;
-
- mdb->width[a] = (mdb->max[a] - mdb->min[a]) / (mdb->size - 4);
- mdb->min[a] -= 2.1f * mdb->width[a];
- mdb->max[a] += 2.1f * mdb->width[a];
-
- mdb->width[a] = (mdb->max[a] - mdb->min[a]) / mdb->size;
- mdb->halfwidth[a] = mdb->width[a] * 0.5f;
- }
-
- progress_bar(0, "Setting up mesh deform system");
-
- totinside = 0;
- for (a = 0; a < mdb->totvert; a++) {
- copy_v3_v3(vec, mdb->vertexcos[a]);
- mdb->inside[a] = meshdeform_inside_cage(mdb, vec);
- if (mdb->inside[a])
- totinside++;
- }
-
- /* free temporary MDefBoundIsects */
- BLI_memarena_free(mdb->memarena);
- mdb->memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "harmonic coords arena");
-
- /* start with all cells untyped */
- for (a = 0; a < mdb->size3; a++)
- mdb->tag[a] = MESHDEFORM_TAG_UNTYPED;
-
- /* detect intersections and tag boundary cells */
- for (z = 0; z < mdb->size; z++)
- for (y = 0; y < mdb->size; y++)
- for (x = 0; x < mdb->size; x++)
- meshdeform_add_intersections(mdb, x, y, z);
-
- /* compute exterior and interior tags */
- meshdeform_bind_floodfill(mdb);
-
- for (z = 0; z < mdb->size; z++)
- for (y = 0; y < mdb->size; y++)
- for (x = 0; x < mdb->size; x++)
- meshdeform_check_semibound(mdb, x, y, z);
-
- /* solve */
- meshdeform_matrix_solve(mmd, mdb);
-
- /* assign results */
- if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) {
- mmd->totinfluence = 0;
- for (a = 0; a < mdb->size3; a++)
- for (inf = mdb->dyngrid[a]; inf; inf = inf->next)
- mmd->totinfluence++;
-
- /* convert MDefBindInfluences to smaller MDefInfluences */
- mmd->dyngrid = MEM_callocN(sizeof(MDefCell) * mdb->size3, "MDefDynGrid");
- mmd->dyninfluences = MEM_callocN(sizeof(MDefInfluence) * mmd->totinfluence, "MDefInfluence");
- offset = 0;
- for (a = 0; a < mdb->size3; a++) {
- cell = &mmd->dyngrid[a];
- cell->offset = offset;
-
- totweight = 0.0f;
- mdinf = mmd->dyninfluences + cell->offset;
- for (inf = mdb->dyngrid[a]; inf; inf = inf->next, mdinf++) {
- mdinf->weight = inf->weight;
- mdinf->vertex = inf->vertex;
- totweight += mdinf->weight;
- cell->totinfluence++;
- }
-
- if (totweight > 0.0f) {
- mdinf = mmd->dyninfluences + cell->offset;
- for (b = 0; b < cell->totinfluence; b++, mdinf++)
- mdinf->weight /= totweight;
- }
-
- offset += cell->totinfluence;
- }
-
- mmd->dynverts = mdb->inside;
- mmd->dyngridsize = mdb->size;
- copy_v3_v3(mmd->dyncellmin, mdb->min);
- mmd->dyncellwidth = mdb->width[0];
- MEM_freeN(mdb->dyngrid);
- }
- else {
- mmd->bindweights = mdb->weights;
- MEM_freeN(mdb->inside);
- }
-
- MEM_freeN(mdb->tag);
- MEM_freeN(mdb->phi);
- MEM_freeN(mdb->totalphi);
- MEM_freeN(mdb->boundisect);
- MEM_freeN(mdb->semibound);
- BLI_memarena_free(mdb->memarena);
- free_bvhtree_from_mesh(&mdb->bvhdata);
+ MDefBindInfluence *inf;
+ MDefInfluence *mdinf;
+ MDefCell *cell;
+ float center[3], vec[3], maxwidth, totweight;
+ int a, b, x, y, z, totinside, offset;
+
+ /* compute bounding box of the cage mesh */
+ INIT_MINMAX(mdb->min, mdb->max);
+
+ for (a = 0; a < mdb->totcagevert; a++)
+ minmax_v3v3_v3(mdb->min, mdb->max, mdb->cagecos[a]);
+
+ /* allocate memory */
+ mdb->size = (2 << (mmd->gridsize - 1)) + 2;
+ mdb->size3 = mdb->size * mdb->size * mdb->size;
+ mdb->tag = MEM_callocN(sizeof(int) * mdb->size3, "MeshDeformBindTag");
+ mdb->phi = MEM_callocN(sizeof(float) * mdb->size3, "MeshDeformBindPhi");
+ mdb->totalphi = MEM_callocN(sizeof(float) * mdb->size3, "MeshDeformBindTotalPhi");
+ mdb->boundisect = MEM_callocN(sizeof(*mdb->boundisect) * mdb->size3, "MDefBoundIsect");
+ mdb->semibound = MEM_callocN(sizeof(int) * mdb->size3, "MDefSemiBound");
+ mdb->bvhtree = BKE_bvhtree_from_mesh_get(&mdb->bvhdata, mdb->cagemesh, BVHTREE_FROM_LOOPTRI, 4);
+ mdb->inside = MEM_callocN(sizeof(int) * mdb->totvert, "MDefInside");
+
+ if (mmd->flag & MOD_MDEF_DYNAMIC_BIND)
+ mdb->dyngrid = MEM_callocN(sizeof(MDefBindInfluence *) * mdb->size3, "MDefDynGrid");
+ else
+ mdb->weights = MEM_callocN(sizeof(float) * mdb->totvert * mdb->totcagevert, "MDefWeights");
+
+ mdb->memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "harmonic coords arena");
+ BLI_memarena_use_calloc(mdb->memarena);
+
+ /* initialize data from 'cagedm' for reuse */
+ {
+ Mesh *me = mdb->cagemesh;
+ mdb->cagemesh_cache.mpoly = me->mpoly;
+ mdb->cagemesh_cache.mloop = me->mloop;
+ mdb->cagemesh_cache.looptri = BKE_mesh_runtime_looptri_ensure(me);
+ /* can be NULL */
+ mdb->cagemesh_cache.poly_nors = CustomData_get_layer(&me->pdata, CD_NORMAL);
+ }
+
+ /* make bounding box equal size in all directions, add padding, and compute
+ * width of the cells */
+ maxwidth = -1.0f;
+ for (a = 0; a < 3; a++)
+ if (mdb->max[a] - mdb->min[a] > maxwidth)
+ maxwidth = mdb->max[a] - mdb->min[a];
+
+ for (a = 0; a < 3; a++) {
+ center[a] = (mdb->min[a] + mdb->max[a]) * 0.5f;
+ mdb->min[a] = center[a] - maxwidth * 0.5f;
+ mdb->max[a] = center[a] + maxwidth * 0.5f;
+
+ mdb->width[a] = (mdb->max[a] - mdb->min[a]) / (mdb->size - 4);
+ mdb->min[a] -= 2.1f * mdb->width[a];
+ mdb->max[a] += 2.1f * mdb->width[a];
+
+ mdb->width[a] = (mdb->max[a] - mdb->min[a]) / mdb->size;
+ mdb->halfwidth[a] = mdb->width[a] * 0.5f;
+ }
+
+ progress_bar(0, "Setting up mesh deform system");
+
+ totinside = 0;
+ for (a = 0; a < mdb->totvert; a++) {
+ copy_v3_v3(vec, mdb->vertexcos[a]);
+ mdb->inside[a] = meshdeform_inside_cage(mdb, vec);
+ if (mdb->inside[a])
+ totinside++;
+ }
+
+ /* free temporary MDefBoundIsects */
+ BLI_memarena_free(mdb->memarena);
+ mdb->memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "harmonic coords arena");
+
+ /* start with all cells untyped */
+ for (a = 0; a < mdb->size3; a++)
+ mdb->tag[a] = MESHDEFORM_TAG_UNTYPED;
+
+ /* detect intersections and tag boundary cells */
+ for (z = 0; z < mdb->size; z++)
+ for (y = 0; y < mdb->size; y++)
+ for (x = 0; x < mdb->size; x++)
+ meshdeform_add_intersections(mdb, x, y, z);
+
+ /* compute exterior and interior tags */
+ meshdeform_bind_floodfill(mdb);
+
+ for (z = 0; z < mdb->size; z++)
+ for (y = 0; y < mdb->size; y++)
+ for (x = 0; x < mdb->size; x++)
+ meshdeform_check_semibound(mdb, x, y, z);
+
+ /* solve */
+ meshdeform_matrix_solve(mmd, mdb);
+
+ /* assign results */
+ if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) {
+ mmd->totinfluence = 0;
+ for (a = 0; a < mdb->size3; a++)
+ for (inf = mdb->dyngrid[a]; inf; inf = inf->next)
+ mmd->totinfluence++;
+
+ /* convert MDefBindInfluences to smaller MDefInfluences */
+ mmd->dyngrid = MEM_callocN(sizeof(MDefCell) * mdb->size3, "MDefDynGrid");
+ mmd->dyninfluences = MEM_callocN(sizeof(MDefInfluence) * mmd->totinfluence, "MDefInfluence");
+ offset = 0;
+ for (a = 0; a < mdb->size3; a++) {
+ cell = &mmd->dyngrid[a];
+ cell->offset = offset;
+
+ totweight = 0.0f;
+ mdinf = mmd->dyninfluences + cell->offset;
+ for (inf = mdb->dyngrid[a]; inf; inf = inf->next, mdinf++) {
+ mdinf->weight = inf->weight;
+ mdinf->vertex = inf->vertex;
+ totweight += mdinf->weight;
+ cell->totinfluence++;
+ }
+
+ if (totweight > 0.0f) {
+ mdinf = mmd->dyninfluences + cell->offset;
+ for (b = 0; b < cell->totinfluence; b++, mdinf++)
+ mdinf->weight /= totweight;
+ }
+
+ offset += cell->totinfluence;
+ }
+
+ mmd->dynverts = mdb->inside;
+ mmd->dyngridsize = mdb->size;
+ copy_v3_v3(mmd->dyncellmin, mdb->min);
+ mmd->dyncellwidth = mdb->width[0];
+ MEM_freeN(mdb->dyngrid);
+ }
+ else {
+ mmd->bindweights = mdb->weights;
+ MEM_freeN(mdb->inside);
+ }
+
+ MEM_freeN(mdb->tag);
+ MEM_freeN(mdb->phi);
+ MEM_freeN(mdb->totalphi);
+ MEM_freeN(mdb->boundisect);
+ MEM_freeN(mdb->semibound);
+ BLI_memarena_free(mdb->memarena);
+ free_bvhtree_from_mesh(&mdb->bvhdata);
}
-void ED_mesh_deform_bind_callback(
- MeshDeformModifierData *mmd, Mesh *cagemesh,
- float *vertexcos, int totvert, float cagemat[4][4])
+void ED_mesh_deform_bind_callback(MeshDeformModifierData *mmd,
+ Mesh *cagemesh,
+ float *vertexcos,
+ int totvert,
+ float cagemat[4][4])
{
- MeshDeformModifierData *mmd_orig =
- (MeshDeformModifierData *)modifier_get_original(&mmd->modifier);
- MeshDeformBind mdb;
- MVert *mvert;
- int a;
+ MeshDeformModifierData *mmd_orig = (MeshDeformModifierData *)modifier_get_original(
+ &mmd->modifier);
+ MeshDeformBind mdb;
+ MVert *mvert;
+ int a;
- waitcursor(1);
- start_progress_bar();
+ waitcursor(1);
+ start_progress_bar();
- memset(&mdb, 0, sizeof(MeshDeformBind));
+ memset(&mdb, 0, sizeof(MeshDeformBind));
- /* get mesh and cage mesh */
- mdb.vertexcos = MEM_callocN(sizeof(float) * 3 * totvert, "MeshDeformCos");
- mdb.totvert = totvert;
+ /* get mesh and cage mesh */
+ mdb.vertexcos = MEM_callocN(sizeof(float) * 3 * totvert, "MeshDeformCos");
+ mdb.totvert = totvert;
- mdb.cagemesh = cagemesh;
- mdb.totcagevert = mdb.cagemesh->totvert;
- mdb.cagecos = MEM_callocN(sizeof(*mdb.cagecos) * mdb.totcagevert, "MeshDeformBindCos");
- copy_m4_m4(mdb.cagemat, cagemat);
+ mdb.cagemesh = cagemesh;
+ mdb.totcagevert = mdb.cagemesh->totvert;
+ mdb.cagecos = MEM_callocN(sizeof(*mdb.cagecos) * mdb.totcagevert, "MeshDeformBindCos");
+ copy_m4_m4(mdb.cagemat, cagemat);
- mvert = mdb.cagemesh->mvert;
- for (a = 0; a < mdb.totcagevert; a++)
- copy_v3_v3(mdb.cagecos[a], mvert[a].co);
- for (a = 0; a < mdb.totvert; a++)
- mul_v3_m4v3(mdb.vertexcos[a], mdb.cagemat, vertexcos + a * 3);
+ mvert = mdb.cagemesh->mvert;
+ for (a = 0; a < mdb.totcagevert; a++)
+ copy_v3_v3(mdb.cagecos[a], mvert[a].co);
+ for (a = 0; a < mdb.totvert; a++)
+ mul_v3_m4v3(mdb.vertexcos[a], mdb.cagemat, vertexcos + a * 3);
- /* solve */
- harmonic_coordinates_bind(mmd_orig, &mdb);
+ /* solve */
+ harmonic_coordinates_bind(mmd_orig, &mdb);
- /* assign bind variables */
- mmd_orig->bindcagecos = (float *)mdb.cagecos;
- mmd_orig->totvert = mdb.totvert;
- mmd_orig->totcagevert = mdb.totcagevert;
- copy_m4_m4(mmd_orig->bindmat, mmd_orig->object->obmat);
+ /* assign bind variables */
+ mmd_orig->bindcagecos = (float *)mdb.cagecos;
+ mmd_orig->totvert = mdb.totvert;
+ mmd_orig->totcagevert = mdb.totcagevert;
+ copy_m4_m4(mmd_orig->bindmat, mmd_orig->object->obmat);
- /* transform bindcagecos to world space */
- for (a = 0; a < mdb.totcagevert; a++)
- mul_m4_v3(mmd_orig->object->obmat, mmd_orig->bindcagecos + a * 3);
+ /* transform bindcagecos to world space */
+ for (a = 0; a < mdb.totcagevert; a++)
+ mul_m4_v3(mmd_orig->object->obmat, mmd_orig->bindcagecos + a * 3);
- /* free */
- MEM_freeN(mdb.vertexcos);
+ /* free */
+ MEM_freeN(mdb.vertexcos);
- /* compact weights */
- modifier_mdef_compact_influences((ModifierData *)mmd_orig);
+ /* compact weights */
+ modifier_mdef_compact_influences((ModifierData *)mmd_orig);
- end_progress_bar();
- waitcursor(0);
+ end_progress_bar();
+ waitcursor(0);
}
diff --git a/source/blender/editors/armature/meshlaplacian.h b/source/blender/editors/armature/meshlaplacian.h
index cf0c1de6b67..ef4759eab4a 100644
--- a/source/blender/editors/armature/meshlaplacian.h
+++ b/source/blender/editors/armature/meshlaplacian.h
@@ -20,7 +20,6 @@
* \ingroup edarmature
*/
-
#ifndef __MESHLAPLACIAN_H__
#define __MESHLAPLACIAN_H__
@@ -49,11 +48,16 @@ float laplacian_system_get_solution(LaplacianSystem *sys, int v);
/* Heat Weighting */
-void heat_bone_weighting(
- struct Object *ob, struct Mesh *me, float (*verts)[3],
- int numbones, struct bDeformGroup **dgrouplist,
- struct bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3],
- int *selected, const char **error);
+void heat_bone_weighting(struct Object *ob,
+ struct Mesh *me,
+ float (*verts)[3],
+ int numbones,
+ struct bDeformGroup **dgrouplist,
+ struct bDeformGroup **dgroupflip,
+ float (*root)[3],
+ float (*tip)[3],
+ int *selected,
+ const char **error);
#ifdef RIGID_DEFORM
/* As-Rigid-As-Possible Deformation */
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 9323e00db65..51641041ea1 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -65,7 +65,6 @@
#include "armature_intern.h"
-
#define DEBUG_TIME
#include "PIL_time.h"
@@ -73,81 +72,80 @@
# include "PIL_time_utildefines.h"
#endif
-
/* matches logic with ED_operator_posemode_context() */
Object *ED_pose_object_from_context(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- Object *ob;
-
- /* since this call may also be used from the buttons window, we need to check for where to get the object */
- if (sa && sa->spacetype == SPACE_PROPERTIES) {
- ob = ED_object_context(C);
- }
- else {
- ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- }
-
- return ob;
+ ScrArea *sa = CTX_wm_area(C);
+ Object *ob;
+
+ /* since this call may also be used from the buttons window, we need to check for where to get the object */
+ if (sa && sa->spacetype == SPACE_PROPERTIES) {
+ ob = ED_object_context(C);
+ }
+ else {
+ ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ }
+
+ return ob;
}
/* This function is used to process the necessary updates for */
bool ED_object_posemode_enter_ex(struct Main *bmain, Object *ob)
{
- BLI_assert(!ID_IS_LINKED(ob));
- bool ok = false;
-
- switch (ob->type) {
- case OB_ARMATURE:
- ob->restore_mode = ob->mode;
- ob->mode |= OB_MODE_POSE;
- /* Inform all CoW versions that we changed the mode. */
- DEG_id_tag_update_ex(bmain, &ob->id, ID_RECALC_COPY_ON_WRITE);
- ok = true;
-
- break;
- default:
- break;
- }
-
- return ok;
+ BLI_assert(!ID_IS_LINKED(ob));
+ bool ok = false;
+
+ switch (ob->type) {
+ case OB_ARMATURE:
+ ob->restore_mode = ob->mode;
+ ob->mode |= OB_MODE_POSE;
+ /* Inform all CoW versions that we changed the mode. */
+ DEG_id_tag_update_ex(bmain, &ob->id, ID_RECALC_COPY_ON_WRITE);
+ ok = true;
+
+ break;
+ default:
+ break;
+ }
+
+ return ok;
}
bool ED_object_posemode_enter(bContext *C, Object *ob)
{
- ReportList *reports = CTX_wm_reports(C);
- if (ID_IS_LINKED(ob)) {
- BKE_report(reports, RPT_WARNING, "Cannot pose libdata");
- return false;
- }
- struct Main *bmain = CTX_data_main(C);
- bool ok = ED_object_posemode_enter_ex(bmain, ob);
- if (ok) {
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, NULL);
- }
- return ok;
+ ReportList *reports = CTX_wm_reports(C);
+ if (ID_IS_LINKED(ob)) {
+ BKE_report(reports, RPT_WARNING, "Cannot pose libdata");
+ return false;
+ }
+ struct Main *bmain = CTX_data_main(C);
+ bool ok = ED_object_posemode_enter_ex(bmain, ob);
+ if (ok) {
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, NULL);
+ }
+ return ok;
}
bool ED_object_posemode_exit_ex(struct Main *bmain, Object *ob)
{
- bool ok = false;
- if (ob) {
- ob->restore_mode = ob->mode;
- ob->mode &= ~OB_MODE_POSE;
-
- /* Inform all CoW versions that we changed the mode. */
- DEG_id_tag_update_ex(bmain, &ob->id, ID_RECALC_COPY_ON_WRITE);
- ok = true;
- }
- return ok;
+ bool ok = false;
+ if (ob) {
+ ob->restore_mode = ob->mode;
+ ob->mode &= ~OB_MODE_POSE;
+
+ /* Inform all CoW versions that we changed the mode. */
+ DEG_id_tag_update_ex(bmain, &ob->id, ID_RECALC_COPY_ON_WRITE);
+ ok = true;
+ }
+ return ok;
}
bool ED_object_posemode_exit(bContext *C, Object *ob)
{
- struct Main *bmain = CTX_data_main(C);
- bool ok = ED_object_posemode_exit_ex(bmain, ob);
- if (ok) {
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
- }
- return ok;
+ struct Main *bmain = CTX_data_main(C);
+ bool ok = ED_object_posemode_exit_ex(bmain, ob);
+ if (ok) {
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
+ }
+ return ok;
}
/* if a selected or active bone is protected, throw error (oonly if warn == 1) and return 1 */
@@ -155,25 +153,25 @@ bool ED_object_posemode_exit(bContext *C, Object *ob)
#if 0 /* UNUSED 2.5 */
static bool pose_has_protected_selected(Object *ob, short warn)
{
- /* check protection */
- if (ob->proxy) {
- bPoseChannel *pchan;
- bArmature *arm = ob->data;
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone && (pchan->bone->layer & arm->layer)) {
- if (pchan->bone->layer & arm->layer_protected) {
- if (pchan->bone->flag & BONE_SELECTED)
- break;
- }
- }
- }
- if (pchan) {
- if (warn) error("Cannot change Proxy protected bones");
- return 1;
- }
- }
- return 0;
+ /* check protection */
+ if (ob->proxy) {
+ bPoseChannel *pchan;
+ bArmature *arm = ob->data;
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone && (pchan->bone->layer & arm->layer)) {
+ if (pchan->bone->layer & arm->layer_protected) {
+ if (pchan->bone->flag & BONE_SELECTED)
+ break;
+ }
+ }
+ }
+ if (pchan) {
+ if (warn) error("Cannot change Proxy protected bones");
+ return 1;
+ }
+ }
+ return 0;
}
#endif
@@ -187,101 +185,100 @@ static bool pose_has_protected_selected(Object *ob, short warn)
*/
void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool current_frame_only)
{
- /* Transform doesn't always have context available to do update. */
- if (C == NULL) {
- return;
- }
+ /* Transform doesn't always have context available to do update. */
+ if (C == NULL) {
+ return;
+ }
- Main *bmain = CTX_data_main(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- ListBase targets = {NULL, NULL};
- bool free_depsgraph = false;
+ Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ListBase targets = {NULL, NULL};
+ bool free_depsgraph = false;
- /* Override depsgraph with a filtered, simpler copy */
- if (!current_frame_only && G.debug_value != -1) {
- DEG_FilterQuery query = {{0}};
+ /* Override depsgraph with a filtered, simpler copy */
+ if (!current_frame_only && G.debug_value != -1) {
+ DEG_FilterQuery query = {{0}};
- DEG_FilterTarget *dft_ob = MEM_callocN(sizeof(DEG_FilterTarget), "DEG_FilterTarget");
- dft_ob->id = &ob->id;
- BLI_addtail(&query.targets, dft_ob);
+ DEG_FilterTarget *dft_ob = MEM_callocN(sizeof(DEG_FilterTarget), "DEG_FilterTarget");
+ dft_ob->id = &ob->id;
+ BLI_addtail(&query.targets, dft_ob);
#ifdef DEBUG_TIME
- TIMEIT_START(filter_pose_depsgraph);
+ TIMEIT_START(filter_pose_depsgraph);
#endif
- depsgraph = DEG_graph_filter(depsgraph, bmain, &query);
+ depsgraph = DEG_graph_filter(depsgraph, bmain, &query);
#ifdef DEBUG_TIME
- TIMEIT_END(filter_pose_depsgraph);
+ TIMEIT_END(filter_pose_depsgraph);
#endif
- free_depsgraph = true;
- MEM_freeN(dft_ob);
+ free_depsgraph = true;
+ MEM_freeN(dft_ob);
#ifdef DEBUG_TIME
- TIMEIT_START(filter_pose_update);
+ TIMEIT_START(filter_pose_update);
#endif
- BKE_scene_graph_update_tagged(depsgraph, bmain);
+ BKE_scene_graph_update_tagged(depsgraph, bmain);
#ifdef DEBUG_TIME
- TIMEIT_END(filter_pose_update);
+ TIMEIT_END(filter_pose_update);
#endif
- }
+ }
- /* set flag to force recalc, then grab the relevant bones to target */
- ob->pose->avs.recalc |= ANIMVIZ_RECALC_PATHS;
- animviz_get_object_motionpaths(ob, &targets);
+ /* set flag to force recalc, then grab the relevant bones to target */
+ ob->pose->avs.recalc |= ANIMVIZ_RECALC_PATHS;
+ animviz_get_object_motionpaths(ob, &targets);
- /* recalculate paths, then free */
+ /* recalculate paths, then free */
#ifdef DEBUG_TIME
- TIMEIT_START(pose_path_calc);
+ TIMEIT_START(pose_path_calc);
#endif
- animviz_calc_motionpaths(depsgraph, bmain, scene, &targets, !free_depsgraph, current_frame_only);
+ animviz_calc_motionpaths(depsgraph, bmain, scene, &targets, !free_depsgraph, current_frame_only);
#ifdef DEBUG_TIME
- TIMEIT_END(pose_path_calc);
+ TIMEIT_END(pose_path_calc);
#endif
- BLI_freelistN(&targets);
+ BLI_freelistN(&targets);
- if (!current_frame_only) {
- /* Tag armature object for copy on write - so paths will draw/redraw.
- * For currently frame only we update evaluated object directly. */
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
- }
+ if (!current_frame_only) {
+ /* Tag armature object for copy on write - so paths will draw/redraw.
+ * For currently frame only we update evaluated object directly. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+ }
- /* Free temporary depsgraph instance */
- if (free_depsgraph) {
- DEG_graph_free(depsgraph);
- }
+ /* Free temporary depsgraph instance */
+ if (free_depsgraph) {
+ DEG_graph_free(depsgraph);
+ }
}
-
/* show popup to determine settings */
static int pose_calculate_paths_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
- /* set default settings from existing/stored settings */
- {
- bAnimVizSettings *avs = &ob->pose->avs;
- PointerRNA avs_ptr;
+ /* set default settings from existing/stored settings */
+ {
+ bAnimVizSettings *avs = &ob->pose->avs;
+ PointerRNA avs_ptr;
- RNA_int_set(op->ptr, "start_frame", avs->path_sf);
- RNA_int_set(op->ptr, "end_frame", avs->path_ef);
+ RNA_int_set(op->ptr, "start_frame", avs->path_sf);
+ RNA_int_set(op->ptr, "end_frame", avs->path_ef);
- RNA_pointer_create(NULL, &RNA_AnimVizMotionPaths, avs, &avs_ptr);
- RNA_enum_set(op->ptr, "bake_location", RNA_enum_get(&avs_ptr, "bake_location"));
- }
+ RNA_pointer_create(NULL, &RNA_AnimVizMotionPaths, avs, &avs_ptr);
+ RNA_enum_set(op->ptr, "bake_location", RNA_enum_get(&avs_ptr, "bake_location"));
+ }
- /* show popup dialog to allow editing of range... */
- // FIXME: hardcoded dimensions here are just arbitrary
- return WM_operator_props_dialog_popup(C, op, 200, 200);
+ /* show popup dialog to allow editing of range... */
+ // FIXME: hardcoded dimensions here are just arbitrary
+ return WM_operator_props_dialog_popup(C, op, 200, 200);
}
/* For the object with pose/action: create path curves for selected bones
@@ -289,120 +286,135 @@ static int pose_calculate_paths_invoke(bContext *C, wmOperator *op, const wmEven
*/
static int pose_calculate_paths_exec(bContext *C, wmOperator *op)
{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- Scene *scene = CTX_data_scene(C);
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ Scene *scene = CTX_data_scene(C);
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
- /* grab baking settings from operator settings */
- {
- bAnimVizSettings *avs = &ob->pose->avs;
- PointerRNA avs_ptr;
+ /* grab baking settings from operator settings */
+ {
+ bAnimVizSettings *avs = &ob->pose->avs;
+ PointerRNA avs_ptr;
- avs->path_sf = RNA_int_get(op->ptr, "start_frame");
- avs->path_ef = RNA_int_get(op->ptr, "end_frame");
+ avs->path_sf = RNA_int_get(op->ptr, "start_frame");
+ avs->path_ef = RNA_int_get(op->ptr, "end_frame");
- RNA_pointer_create(NULL, &RNA_AnimVizMotionPaths, avs, &avs_ptr);
- RNA_enum_set(&avs_ptr, "bake_location", RNA_enum_get(op->ptr, "bake_location"));
- }
+ RNA_pointer_create(NULL, &RNA_AnimVizMotionPaths, avs, &avs_ptr);
+ RNA_enum_set(&avs_ptr, "bake_location", RNA_enum_get(op->ptr, "bake_location"));
+ }
- /* set up path data for bones being calculated */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones_from_active_object)
- {
- /* verify makes sure that the selected bone has a bone with the appropriate settings */
- animviz_verify_motionpaths(op->reports, scene, ob, pchan);
- }
- CTX_DATA_END;
+ /* set up path data for bones being calculated */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones_from_active_object) {
+ /* verify makes sure that the selected bone has a bone with the appropriate settings */
+ animviz_verify_motionpaths(op->reports, scene, ob, pchan);
+ }
+ CTX_DATA_END;
#ifdef DEBUG_TIME
- TIMEIT_START(recalc_pose_paths);
+ TIMEIT_START(recalc_pose_paths);
#endif
- /* calculate the bones that now have motionpaths... */
- /* TODO: only make for the selected bones? */
- ED_pose_recalculate_paths(C, scene, ob, false);
+ /* calculate the bones that now have motionpaths... */
+ /* TODO: only make for the selected bones? */
+ ED_pose_recalculate_paths(C, scene, ob, false);
#ifdef DEBUG_TIME
- TIMEIT_END(recalc_pose_paths);
+ TIMEIT_END(recalc_pose_paths);
#endif
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void POSE_OT_paths_calculate(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Calculate Bone Paths";
- ot->idname = "POSE_OT_paths_calculate";
- ot->description = "Calculate paths for the selected bones";
-
- /* api callbacks */
- ot->invoke = pose_calculate_paths_invoke;
- ot->exec = pose_calculate_paths_exec;
- ot->poll = ED_operator_posemode_exclusive;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_int(ot->srna, "start_frame", 1, MINAFRAME, MAXFRAME, "Start",
- "First frame to calculate bone paths on", MINFRAME, MAXFRAME / 2.0);
- RNA_def_int(ot->srna, "end_frame", 250, MINAFRAME, MAXFRAME, "End",
- "Last frame to calculate bone paths on", MINFRAME, MAXFRAME / 2.0);
-
- RNA_def_enum(ot->srna, "bake_location", rna_enum_motionpath_bake_location_items,
- MOTIONPATH_BAKE_HEADS,
- "Bake Location",
- "Which point on the bones is used when calculating paths");
+ /* identifiers */
+ ot->name = "Calculate Bone Paths";
+ ot->idname = "POSE_OT_paths_calculate";
+ ot->description = "Calculate paths for the selected bones";
+
+ /* api callbacks */
+ ot->invoke = pose_calculate_paths_invoke;
+ ot->exec = pose_calculate_paths_exec;
+ ot->poll = ED_operator_posemode_exclusive;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_int(ot->srna,
+ "start_frame",
+ 1,
+ MINAFRAME,
+ MAXFRAME,
+ "Start",
+ "First frame to calculate bone paths on",
+ MINFRAME,
+ MAXFRAME / 2.0);
+ RNA_def_int(ot->srna,
+ "end_frame",
+ 250,
+ MINAFRAME,
+ MAXFRAME,
+ "End",
+ "Last frame to calculate bone paths on",
+ MINFRAME,
+ MAXFRAME / 2.0);
+
+ RNA_def_enum(ot->srna,
+ "bake_location",
+ rna_enum_motionpath_bake_location_items,
+ MOTIONPATH_BAKE_HEADS,
+ "Bake Location",
+ "Which point on the bones is used when calculating paths");
}
/* --------- */
static bool pose_update_paths_poll(bContext *C)
{
- if (ED_operator_posemode_exclusive(C)) {
- Object *ob = CTX_data_active_object(C);
- return (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0;
- }
+ if (ED_operator_posemode_exclusive(C)) {
+ Object *ob = CTX_data_active_object(C);
+ return (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0;
+ }
- return false;
+ return false;
}
static int pose_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- Scene *scene = CTX_data_scene(C);
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ Scene *scene = CTX_data_scene(C);
- if (ELEM(NULL, ob, scene))
- return OPERATOR_CANCELLED;
+ if (ELEM(NULL, ob, scene))
+ return OPERATOR_CANCELLED;
- /* calculate the bones that now have motionpaths... */
- /* TODO: only make for the selected bones? */
- ED_pose_recalculate_paths(C, scene, ob, false);
+ /* calculate the bones that now have motionpaths... */
+ /* TODO: only make for the selected bones? */
+ ED_pose_recalculate_paths(C, scene, ob, false);
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void POSE_OT_paths_update(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Update Bone Paths";
- ot->idname = "POSE_OT_paths_update";
- ot->description = "Recalculate paths for bones that already have them";
+ /* identifiers */
+ ot->name = "Update Bone Paths";
+ ot->idname = "POSE_OT_paths_update";
+ ot->description = "Recalculate paths for bones that already have them";
- /* api callbakcs */
- ot->exec = pose_update_paths_exec;
- ot->poll = pose_update_paths_poll;
+ /* api callbakcs */
+ ot->exec = pose_update_paths_exec;
+ ot->poll = pose_update_paths_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* --------- */
@@ -410,354 +422,358 @@ void POSE_OT_paths_update(wmOperatorType *ot)
/* for the object with pose/action: clear path curves for selected bones only */
static void ED_pose_clear_paths(Object *ob, bool only_selected)
{
- bPoseChannel *pchan;
- bool skipped = false;
-
- if (ELEM(NULL, ob, ob->pose))
- return;
-
- /* free the motionpath blocks for all bones - This is easier for users to quickly clear all */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->mpath) {
- if ((only_selected == false) || ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))) {
- animviz_free_motionpath(pchan->mpath);
- pchan->mpath = NULL;
- }
- else {
- skipped = true;
- }
- }
- }
-
- /* if nothing was skipped, there should be no paths left! */
- if (skipped == false)
- ob->pose->avs.path_bakeflag &= ~MOTIONPATH_BAKE_HAS_PATHS;
-
- /* tag armature object for copy on write - so removed paths don't still show */
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+ bPoseChannel *pchan;
+ bool skipped = false;
+
+ if (ELEM(NULL, ob, ob->pose))
+ return;
+
+ /* free the motionpath blocks for all bones - This is easier for users to quickly clear all */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->mpath) {
+ if ((only_selected == false) || ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))) {
+ animviz_free_motionpath(pchan->mpath);
+ pchan->mpath = NULL;
+ }
+ else {
+ skipped = true;
+ }
+ }
+ }
+
+ /* if nothing was skipped, there should be no paths left! */
+ if (skipped == false)
+ ob->pose->avs.path_bakeflag &= ~MOTIONPATH_BAKE_HAS_PATHS;
+
+ /* tag armature object for copy on write - so removed paths don't still show */
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
}
/* operator callback - wrapper for the backend function */
static int pose_clear_paths_exec(bContext *C, wmOperator *op)
{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bool only_selected = RNA_boolean_get(op->ptr, "only_selected");
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bool only_selected = RNA_boolean_get(op->ptr, "only_selected");
- /* only continue if there's an object */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
+ /* only continue if there's an object */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
- /* use the backend function for this */
- ED_pose_clear_paths(ob, only_selected);
+ /* use the backend function for this */
+ ED_pose_clear_paths(ob, only_selected);
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
/* operator callback/wrapper */
static int pose_clear_paths_invoke(bContext *C, wmOperator *op, const wmEvent *evt)
{
- if ((evt->shift) && !RNA_struct_property_is_set(op->ptr, "only_selected")) {
- RNA_boolean_set(op->ptr, "only_selected", true);
- }
- return pose_clear_paths_exec(C, op);
+ if ((evt->shift) && !RNA_struct_property_is_set(op->ptr, "only_selected")) {
+ RNA_boolean_set(op->ptr, "only_selected", true);
+ }
+ return pose_clear_paths_exec(C, op);
}
void POSE_OT_paths_clear(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Clear Bone Paths";
- ot->idname = "POSE_OT_paths_clear";
- ot->description = "Clear path caches for all bones, hold Shift key for selected bones only";
-
- /* api callbacks */
- ot->invoke = pose_clear_paths_invoke;
- ot->exec = pose_clear_paths_exec;
- ot->poll = ED_operator_posemode_exclusive;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_boolean(ot->srna, "only_selected", false, "Only Selected",
- "Only clear paths from selected bones");
- RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
+ /* identifiers */
+ ot->name = "Clear Bone Paths";
+ ot->idname = "POSE_OT_paths_clear";
+ ot->description = "Clear path caches for all bones, hold Shift key for selected bones only";
+
+ /* api callbacks */
+ ot->invoke = pose_clear_paths_invoke;
+ ot->exec = pose_clear_paths_exec;
+ ot->poll = ED_operator_posemode_exclusive;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_boolean(
+ ot->srna, "only_selected", false, "Only Selected", "Only clear paths from selected bones");
+ RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
}
/* --------- */
static int pose_update_paths_range_exec(bContext *C, wmOperator *UNUSED(op))
{
- Scene *scene = CTX_data_scene(C);
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- if (ELEM(NULL, scene, ob, ob->pose)) {
- return OPERATOR_CANCELLED;
- }
+ if (ELEM(NULL, scene, ob, ob->pose)) {
+ return OPERATOR_CANCELLED;
+ }
- /* use Preview Range or Full Frame Range - whichever is in use */
- ob->pose->avs.path_sf = PSFRA;
- ob->pose->avs.path_ef = PEFRA;
+ /* use Preview Range or Full Frame Range - whichever is in use */
+ ob->pose->avs.path_sf = PSFRA;
+ ob->pose->avs.path_ef = PEFRA;
- /* tag for updates */
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ /* tag for updates */
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void POSE_OT_paths_range_update(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Update Range from Scene";
- ot->idname = "POSE_OT_paths_range_update";
- ot->description = "Update frame range for motion paths from the Scene's current frame range";
+ /* identifiers */
+ ot->name = "Update Range from Scene";
+ ot->idname = "POSE_OT_paths_range_update";
+ ot->description = "Update frame range for motion paths from the Scene's current frame range";
- /* callbacks */
- ot->exec = pose_update_paths_range_exec;
- ot->poll = ED_operator_posemode_exclusive;
+ /* callbacks */
+ ot->exec = pose_update_paths_range_exec;
+ ot->poll = ED_operator_posemode_exclusive;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ********************************************** */
static int pose_flip_names_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- View3D *v3d = CTX_wm_view3d(C);
- const bool do_strip_numbers = RNA_boolean_get(op->ptr, "do_strip_numbers");
+ Main *bmain = CTX_data_main(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ const bool do_strip_numbers = RNA_boolean_get(op->ptr, "do_strip_numbers");
- FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob)
- {
- bArmature *arm = ob->data;
- ListBase bones_names = {NULL};
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
+ bArmature *arm = ob->data;
+ ListBase bones_names = {NULL};
- FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob, pchan)
- {
- BLI_addtail(&bones_names, BLI_genericNodeN(pchan->name));
- }
- FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob, pchan) {
+ BLI_addtail(&bones_names, BLI_genericNodeN(pchan->name));
+ }
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
- ED_armature_bones_flip_names(bmain, arm, &bones_names, do_strip_numbers);
+ ED_armature_bones_flip_names(bmain, arm, &bones_names, do_strip_numbers);
- BLI_freelistN(&bones_names);
+ BLI_freelistN(&bones_names);
- /* since we renamed stuff... */
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ /* since we renamed stuff... */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
- }
- FOREACH_OBJECT_IN_MODE_END;
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ }
+ FOREACH_OBJECT_IN_MODE_END;
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void POSE_OT_flip_names(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Flip Names";
- ot->idname = "POSE_OT_flip_names";
- ot->description = "Flips (and corrects) the axis suffixes of the names of selected bones";
-
- /* api callbacks */
- ot->exec = pose_flip_names_exec;
- ot->poll = ED_operator_posemode_local;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_boolean(ot->srna, "do_strip_numbers", false, "Strip Numbers",
- "Try to remove right-most dot-number from flipped names "
- "(WARNING: may result in incoherent naming in some cases)");
+ /* identifiers */
+ ot->name = "Flip Names";
+ ot->idname = "POSE_OT_flip_names";
+ ot->description = "Flips (and corrects) the axis suffixes of the names of selected bones";
+
+ /* api callbacks */
+ ot->exec = pose_flip_names_exec;
+ ot->poll = ED_operator_posemode_local;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna,
+ "do_strip_numbers",
+ false,
+ "Strip Numbers",
+ "Try to remove right-most dot-number from flipped names "
+ "(WARNING: may result in incoherent naming in some cases)");
}
/* ------------------ */
static int pose_autoside_names_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- char newname[MAXBONENAME];
- short axis = RNA_enum_get(op->ptr, "axis");
- Object *ob_prev = NULL;
-
- /* loop through selected bones, auto-naming them */
- CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob)
- {
- bArmature *arm = ob->data;
- BLI_strncpy(newname, pchan->name, sizeof(newname));
- if (bone_autoside_name(newname, 1, axis, pchan->bone->head[axis], pchan->bone->tail[axis])) {
- ED_armature_bone_rename(bmain, arm, pchan->name, newname);
- }
-
- if (ob_prev != ob) {
- /* since we renamed stuff... */
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
- ob_prev = ob;
- }
- }
- CTX_DATA_END;
-
- return OPERATOR_FINISHED;
+ Main *bmain = CTX_data_main(C);
+ char newname[MAXBONENAME];
+ short axis = RNA_enum_get(op->ptr, "axis");
+ Object *ob_prev = NULL;
+
+ /* loop through selected bones, auto-naming them */
+ CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob)
+ {
+ bArmature *arm = ob->data;
+ BLI_strncpy(newname, pchan->name, sizeof(newname));
+ if (bone_autoside_name(newname, 1, axis, pchan->bone->head[axis], pchan->bone->tail[axis])) {
+ ED_armature_bone_rename(bmain, arm, pchan->name, newname);
+ }
+
+ if (ob_prev != ob) {
+ /* since we renamed stuff... */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ ob_prev = ob;
+ }
+ }
+ CTX_DATA_END;
+
+ return OPERATOR_FINISHED;
}
void POSE_OT_autoside_names(wmOperatorType *ot)
{
- static const EnumPropertyItem axis_items[] = {
- {0, "XAXIS", 0, "X-Axis", "Left/Right"},
- {1, "YAXIS", 0, "Y-Axis", "Front/Back"},
- {2, "ZAXIS", 0, "Z-Axis", "Top/Bottom"},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "AutoName by Axis";
- ot->idname = "POSE_OT_autoside_names";
- ot->description = "Automatically renames the selected bones according to which side of the target axis they fall on";
-
- /* api callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = pose_autoside_names_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* settings */
- ot->prop = RNA_def_enum(ot->srna, "axis", axis_items, 0, "Axis", "Axis tag names with");
+ static const EnumPropertyItem axis_items[] = {
+ {0, "XAXIS", 0, "X-Axis", "Left/Right"},
+ {1, "YAXIS", 0, "Y-Axis", "Front/Back"},
+ {2, "ZAXIS", 0, "Z-Axis", "Top/Bottom"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "AutoName by Axis";
+ ot->idname = "POSE_OT_autoside_names";
+ ot->description =
+ "Automatically renames the selected bones according to which side of the target axis they "
+ "fall on";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = pose_autoside_names_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* settings */
+ ot->prop = RNA_def_enum(ot->srna, "axis", axis_items, 0, "Axis", "Axis tag names with");
}
/* ********************************************** */
static int pose_bone_rotmode_exec(bContext *C, wmOperator *op)
{
- const int mode = RNA_enum_get(op->ptr, "type");
- Object *prev_ob = NULL;
-
- /* set rotation mode of selected bones */
- CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob)
- {
- pchan->rotmode = mode;
-
- if (prev_ob != ob) {
- /* Notifiers and updates. */
- DEG_id_tag_update((ID *)ob, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
- prev_ob = ob;
- }
- }
- CTX_DATA_END;
-
- return OPERATOR_FINISHED;
+ const int mode = RNA_enum_get(op->ptr, "type");
+ Object *prev_ob = NULL;
+
+ /* set rotation mode of selected bones */
+ CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob)
+ {
+ pchan->rotmode = mode;
+
+ if (prev_ob != ob) {
+ /* Notifiers and updates. */
+ DEG_id_tag_update((ID *)ob, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ prev_ob = ob;
+ }
+ }
+ CTX_DATA_END;
+
+ return OPERATOR_FINISHED;
}
void POSE_OT_rotation_mode_set(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Set Rotation Mode";
- ot->idname = "POSE_OT_rotation_mode_set";
- ot->description = "Set the rotation representation used by selected bones";
-
- /* callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = pose_bone_rotmode_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(
- ot->srna, "type", rna_enum_object_rotation_mode_items, 0, "Rotation Mode", "");
+ /* identifiers */
+ ot->name = "Set Rotation Mode";
+ ot->idname = "POSE_OT_rotation_mode_set";
+ ot->description = "Set the rotation representation used by selected bones";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = pose_bone_rotmode_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(
+ ot->srna, "type", rna_enum_object_rotation_mode_items, 0, "Rotation Mode", "");
}
/* ********************************************** */
static bool armature_layers_poll(bContext *C)
{
- /* Armature layers operators can be used in posemode OR editmode for armatures */
- return ED_operator_posemode(C) || ED_operator_editarmature(C);
+ /* Armature layers operators can be used in posemode OR editmode for armatures */
+ return ED_operator_posemode(C) || ED_operator_editarmature(C);
}
static bArmature *armature_layers_get_data(Object **ob)
{
- bArmature *arm = NULL;
-
- /* Sanity checking and handling of posemode. */
- if (*ob) {
- Object *tob = BKE_object_pose_armature_get(*ob);
- if (tob) {
- *ob = tob;
- arm = (*ob)->data;
- }
- else if ((*ob)->type == OB_ARMATURE) {
- arm = (*ob)->data;
- }
- }
-
- return arm;
+ bArmature *arm = NULL;
+
+ /* Sanity checking and handling of posemode. */
+ if (*ob) {
+ Object *tob = BKE_object_pose_armature_get(*ob);
+ if (tob) {
+ *ob = tob;
+ arm = (*ob)->data;
+ }
+ else if ((*ob)->type == OB_ARMATURE) {
+ arm = (*ob)->data;
+ }
+ }
+
+ return arm;
}
/* Show all armature layers */
static int pose_armature_layers_showall_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_active_object(C);
- bArmature *arm = armature_layers_get_data(&ob);
- PointerRNA ptr;
- int maxLayers = (RNA_boolean_get(op->ptr, "all")) ? 32 : 16;
- /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
- bool layers[32] = {false};
- int i;
-
- /* sanity checking */
- if (arm == NULL)
- return OPERATOR_CANCELLED;
-
- /* use RNA to set the layers
- * although it would be faster to just set directly using bitflags, we still
- * need to setup a RNA pointer so that we get the "update" callbacks for free...
- */
- RNA_id_pointer_create(&arm->id, &ptr);
-
- for (i = 0; i < maxLayers; i++)
- layers[i] = 1;
-
- RNA_boolean_set_array(&ptr, "layers", layers);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
- DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
-
- /* done */
- return OPERATOR_FINISHED;
+ Object *ob = CTX_data_active_object(C);
+ bArmature *arm = armature_layers_get_data(&ob);
+ PointerRNA ptr;
+ int maxLayers = (RNA_boolean_get(op->ptr, "all")) ? 32 : 16;
+ /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+ bool layers[32] = {false};
+ int i;
+
+ /* sanity checking */
+ if (arm == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* use RNA to set the layers
+ * although it would be faster to just set directly using bitflags, we still
+ * need to setup a RNA pointer so that we get the "update" callbacks for free...
+ */
+ RNA_id_pointer_create(&arm->id, &ptr);
+
+ for (i = 0; i < maxLayers; i++)
+ layers[i] = 1;
+
+ RNA_boolean_set_array(&ptr, "layers", layers);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
+
+ /* done */
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_layers_show_all(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Show All Layers";
- ot->idname = "ARMATURE_OT_layers_show_all";
- ot->description = "Make all armature layers visible";
+ /* identifiers */
+ ot->name = "Show All Layers";
+ ot->idname = "ARMATURE_OT_layers_show_all";
+ ot->description = "Make all armature layers visible";
- /* callbacks */
- ot->exec = pose_armature_layers_showall_exec;
- ot->poll = armature_layers_poll;
+ /* callbacks */
+ ot->exec = pose_armature_layers_showall_exec;
+ ot->poll = armature_layers_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
- ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All Layers", "Enable all layers or just the first 16 (top row)");
+ /* properties */
+ ot->prop = RNA_def_boolean(
+ ot->srna, "all", 1, "All Layers", "Enable all layers or just the first 16 (top row)");
}
/* ------------------- */
@@ -765,69 +781,70 @@ void ARMATURE_OT_layers_show_all(wmOperatorType *ot)
/* Present a popup to get the layers that should be used */
static int armature_layers_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Object *ob = CTX_data_active_object(C);
- bArmature *arm = armature_layers_get_data(&ob);
- PointerRNA ptr;
- /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
- bool layers[32];
-
- /* sanity checking */
- if (arm == NULL)
- return OPERATOR_CANCELLED;
-
- /* get RNA pointer to armature data to use that to retrieve the layers as ints to init the operator */
- RNA_id_pointer_create((ID *)arm, &ptr);
- RNA_boolean_get_array(&ptr, "layers", layers);
- RNA_boolean_set_array(op->ptr, "layers", layers);
-
- /* part to sync with other similar operators... */
- return WM_operator_props_popup(C, op, event);
+ Object *ob = CTX_data_active_object(C);
+ bArmature *arm = armature_layers_get_data(&ob);
+ PointerRNA ptr;
+ /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+ bool layers[32];
+
+ /* sanity checking */
+ if (arm == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* get RNA pointer to armature data to use that to retrieve the layers as ints to init the operator */
+ RNA_id_pointer_create((ID *)arm, &ptr);
+ RNA_boolean_get_array(&ptr, "layers", layers);
+ RNA_boolean_set_array(op->ptr, "layers", layers);
+
+ /* part to sync with other similar operators... */
+ return WM_operator_props_popup(C, op, event);
}
/* Set the visible layers for the active armature (edit and pose modes) */
static int armature_layers_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_active_object(C);
- bArmature *arm = armature_layers_get_data(&ob);
- PointerRNA ptr;
- /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
- bool layers[32];
+ Object *ob = CTX_data_active_object(C);
+ bArmature *arm = armature_layers_get_data(&ob);
+ PointerRNA ptr;
+ /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+ bool layers[32];
- if (arm == NULL) {
- return OPERATOR_CANCELLED;
- }
+ if (arm == NULL) {
+ return OPERATOR_CANCELLED;
+ }
- /* get the values set in the operator properties */
- RNA_boolean_get_array(op->ptr, "layers", layers);
+ /* get the values set in the operator properties */
+ RNA_boolean_get_array(op->ptr, "layers", layers);
- /* get pointer for armature, and write data there... */
- RNA_id_pointer_create((ID *)arm, &ptr);
- RNA_boolean_set_array(&ptr, "layers", layers);
+ /* get pointer for armature, and write data there... */
+ RNA_id_pointer_create((ID *)arm, &ptr);
+ RNA_boolean_set_array(&ptr, "layers", layers);
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
- DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_armature_layers(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Change Armature Layers";
- ot->idname = "ARMATURE_OT_armature_layers";
- ot->description = "Change the visible armature layers";
-
- /* callbacks */
- ot->invoke = armature_layers_invoke;
- ot->exec = armature_layers_exec;
- ot->poll = armature_layers_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers to make visible");
+ /* identifiers */
+ ot->name = "Change Armature Layers";
+ ot->idname = "ARMATURE_OT_armature_layers";
+ ot->description = "Change the visible armature layers";
+
+ /* callbacks */
+ ot->invoke = armature_layers_invoke;
+ ot->exec = armature_layers_exec;
+ ot->poll = armature_layers_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean_layer_member(
+ ot->srna, "layers", 32, NULL, "Layer", "Armature layers to make visible");
}
/* ------------------- */
@@ -835,75 +852,75 @@ void ARMATURE_OT_armature_layers(wmOperatorType *ot)
/* Present a popup to get the layers that should be used */
static int pose_bone_layers_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
- bool layers[32] = {0};
-
- /* get layers that are active already */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
- {
- short bit;
-
- /* loop over the bits for this pchan's layers, adding layers where they're needed */
- for (bit = 0; bit < 32; bit++) {
- layers[bit] = (pchan->bone->layer & (1u << bit)) != 0;
- }
- }
- CTX_DATA_END;
-
- /* copy layers to operator */
- RNA_boolean_set_array(op->ptr, "layers", layers);
-
- /* part to sync with other similar operators... */
- return WM_operator_props_popup(C, op, event);
+ /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+ bool layers[32] = {0};
+
+ /* get layers that are active already */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones) {
+ short bit;
+
+ /* loop over the bits for this pchan's layers, adding layers where they're needed */
+ for (bit = 0; bit < 32; bit++) {
+ layers[bit] = (pchan->bone->layer & (1u << bit)) != 0;
+ }
+ }
+ CTX_DATA_END;
+
+ /* copy layers to operator */
+ RNA_boolean_set_array(op->ptr, "layers", layers);
+
+ /* part to sync with other similar operators... */
+ return WM_operator_props_popup(C, op, event);
}
/* Set the visible layers for the active armature (edit and pose modes) */
static int pose_bone_layers_exec(bContext *C, wmOperator *op)
{
- PointerRNA ptr;
- /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
- bool layers[32];
-
- /* get the values set in the operator properties */
- RNA_boolean_get_array(op->ptr, "layers", layers);
-
- Object *prev_ob = NULL;
-
- /* set layers of pchans based on the values set in the operator props */
- CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob)
- {
- /* get pointer for pchan, and write flags this way */
- RNA_pointer_create((ID *)ob->data, &RNA_Bone, pchan->bone, &ptr);
- RNA_boolean_set_array(&ptr, "layers", layers);
-
- if (prev_ob != ob) {
- /* Note, notifier might evolve. */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
- DEG_id_tag_update((ID *)ob->data, ID_RECALC_COPY_ON_WRITE);
- prev_ob = ob;
- }
- }
- CTX_DATA_END;
- return OPERATOR_FINISHED;
+ PointerRNA ptr;
+ /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+ bool layers[32];
+
+ /* get the values set in the operator properties */
+ RNA_boolean_get_array(op->ptr, "layers", layers);
+
+ Object *prev_ob = NULL;
+
+ /* set layers of pchans based on the values set in the operator props */
+ CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob)
+ {
+ /* get pointer for pchan, and write flags this way */
+ RNA_pointer_create((ID *)ob->data, &RNA_Bone, pchan->bone, &ptr);
+ RNA_boolean_set_array(&ptr, "layers", layers);
+
+ if (prev_ob != ob) {
+ /* Note, notifier might evolve. */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ DEG_id_tag_update((ID *)ob->data, ID_RECALC_COPY_ON_WRITE);
+ prev_ob = ob;
+ }
+ }
+ CTX_DATA_END;
+ return OPERATOR_FINISHED;
}
void POSE_OT_bone_layers(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Change Bone Layers";
- ot->idname = "POSE_OT_bone_layers";
- ot->description = "Change the layers that the selected bones belong to";
-
- /* callbacks */
- ot->invoke = pose_bone_layers_invoke;
- ot->exec = pose_bone_layers_exec;
- ot->poll = ED_operator_posemode_exclusive;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers that bone belongs to");
+ /* identifiers */
+ ot->name = "Change Bone Layers";
+ ot->idname = "POSE_OT_bone_layers";
+ ot->description = "Change the layers that the selected bones belong to";
+
+ /* callbacks */
+ ot->invoke = pose_bone_layers_invoke;
+ ot->exec = pose_bone_layers_exec;
+ ot->poll = ED_operator_posemode_exclusive;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean_layer_member(
+ ot->srna, "layers", 32, NULL, "Layer", "Armature layers that bone belongs to");
}
/* ------------------- */
@@ -911,73 +928,73 @@ void POSE_OT_bone_layers(wmOperatorType *ot)
/* Present a popup to get the layers that should be used */
static int armature_bone_layers_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
- bool layers[32] = {0};
-
- /* get layers that are active already */
- CTX_DATA_BEGIN (C, EditBone *, ebone, selected_editable_bones)
- {
- short bit;
-
- /* loop over the bits for this pchan's layers, adding layers where they're needed */
- for (bit = 0; bit < 32; bit++) {
- if (ebone->layer & (1u << bit)) {
- layers[bit] = 1;
- }
- }
- }
- CTX_DATA_END;
-
- /* copy layers to operator */
- RNA_boolean_set_array(op->ptr, "layers", layers);
-
- /* part to sync with other similar operators... */
- return WM_operator_props_popup(C, op, event);
+ /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+ bool layers[32] = {0};
+
+ /* get layers that are active already */
+ CTX_DATA_BEGIN (C, EditBone *, ebone, selected_editable_bones) {
+ short bit;
+
+ /* loop over the bits for this pchan's layers, adding layers where they're needed */
+ for (bit = 0; bit < 32; bit++) {
+ if (ebone->layer & (1u << bit)) {
+ layers[bit] = 1;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* copy layers to operator */
+ RNA_boolean_set_array(op->ptr, "layers", layers);
+
+ /* part to sync with other similar operators... */
+ return WM_operator_props_popup(C, op, event);
}
/* Set the visible layers for the active armature (edit and pose modes) */
static int armature_bone_layers_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_edit_object(C);
- PointerRNA ptr;
- /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
- bool layers[32];
-
- /* get the values set in the operator properties */
- RNA_boolean_get_array(op->ptr, "layers", layers);
-
- /* set layers of pchans based on the values set in the operator props */
- CTX_DATA_BEGIN_WITH_ID (C, EditBone *, ebone, selected_editable_bones, bArmature *, arm)
- {
- /* get pointer for pchan, and write flags this way */
- RNA_pointer_create((ID *)arm, &RNA_EditBone, ebone, &ptr);
- RNA_boolean_set_array(&ptr, "layers", layers);
- }
- CTX_DATA_END;
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
+ Object *ob = CTX_data_edit_object(C);
+ PointerRNA ptr;
+ /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+ bool layers[32];
+
+ /* get the values set in the operator properties */
+ RNA_boolean_get_array(op->ptr, "layers", layers);
+
+ /* set layers of pchans based on the values set in the operator props */
+ CTX_DATA_BEGIN_WITH_ID(C, EditBone *, ebone, selected_editable_bones, bArmature *, arm)
+ {
+ /* get pointer for pchan, and write flags this way */
+ RNA_pointer_create((ID *)arm, &RNA_EditBone, ebone, &ptr);
+ RNA_boolean_set_array(&ptr, "layers", layers);
+ }
+ CTX_DATA_END;
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_bone_layers(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Change Bone Layers";
- ot->idname = "ARMATURE_OT_bone_layers";
- ot->description = "Change the layers that the selected bones belong to";
-
- /* callbacks */
- ot->invoke = armature_bone_layers_invoke;
- ot->exec = armature_bone_layers_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers that bone belongs to");
+ /* identifiers */
+ ot->name = "Change Bone Layers";
+ ot->idname = "ARMATURE_OT_bone_layers";
+ ot->description = "Change the layers that the selected bones belong to";
+
+ /* callbacks */
+ ot->invoke = armature_bone_layers_invoke;
+ ot->exec = armature_bone_layers_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean_layer_member(
+ ot->srna, "layers", 32, NULL, "Layer", "Armature layers that bone belongs to");
}
/* ********************************************** */
@@ -985,132 +1002,133 @@ void ARMATURE_OT_bone_layers(wmOperatorType *ot)
static int hide_pose_bone_fn(Object *ob, Bone *bone, void *ptr)
{
- bArmature *arm = ob->data;
- const bool hide_select = (bool)POINTER_AS_INT(ptr);
- int count = 0;
- if (arm->layer & bone->layer) {
- if (((bone->flag & BONE_SELECTED) != 0) == hide_select) {
- bone->flag |= BONE_HIDDEN_P;
- /* only needed when 'hide_select' is true, but harmless. */
- bone->flag &= ~BONE_SELECTED;
- if (arm->act_bone == bone) {
- arm->act_bone = NULL;
- }
- count += 1;
- }
- }
- return count;
+ bArmature *arm = ob->data;
+ const bool hide_select = (bool)POINTER_AS_INT(ptr);
+ int count = 0;
+ if (arm->layer & bone->layer) {
+ if (((bone->flag & BONE_SELECTED) != 0) == hide_select) {
+ bone->flag |= BONE_HIDDEN_P;
+ /* only needed when 'hide_select' is true, but harmless. */
+ bone->flag &= ~BONE_SELECTED;
+ if (arm->act_bone == bone) {
+ arm->act_bone = NULL;
+ }
+ count += 1;
+ }
+ }
+ return count;
}
/* active object is armature in posemode, poll checked */
static int pose_hide_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- uint objects_len;
- Object **objects = BKE_object_pose_array_get_unique(view_layer, CTX_wm_view3d(C), &objects_len);
- bool changed_multi = false;
-
- const int hide_select = !RNA_boolean_get(op->ptr, "unselected");
- void *hide_select_p = POINTER_FROM_INT(hide_select);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob_iter = objects[ob_index];
- bArmature *arm = ob_iter->data;
-
- if (ob_iter->proxy != NULL) {
- BKE_report(op->reports, RPT_INFO, "Undo of hiding can only be done with Reveal Selected");
- }
-
- bool changed = bone_looper(ob_iter, arm->bonebase.first, hide_select_p, hide_pose_bone_fn) != 0;
- if (changed) {
- changed_multi = true;
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob_iter);
- DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
- }
- }
- MEM_freeN(objects);
-
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len;
+ Object **objects = BKE_object_pose_array_get_unique(view_layer, CTX_wm_view3d(C), &objects_len);
+ bool changed_multi = false;
+
+ const int hide_select = !RNA_boolean_get(op->ptr, "unselected");
+ void *hide_select_p = POINTER_FROM_INT(hide_select);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ bArmature *arm = ob_iter->data;
+
+ if (ob_iter->proxy != NULL) {
+ BKE_report(op->reports, RPT_INFO, "Undo of hiding can only be done with Reveal Selected");
+ }
+
+ bool changed = bone_looper(ob_iter, arm->bonebase.first, hide_select_p, hide_pose_bone_fn) !=
+ 0;
+ if (changed) {
+ changed_multi = true;
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob_iter);
+ DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
+ }
+ }
+ MEM_freeN(objects);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void POSE_OT_hide(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Hide Selected";
- ot->idname = "POSE_OT_hide";
- ot->description = "Tag selected bones to not be visible in Pose Mode";
+ /* identifiers */
+ ot->name = "Hide Selected";
+ ot->idname = "POSE_OT_hide";
+ ot->description = "Tag selected bones to not be visible in Pose Mode";
- /* api callbacks */
- ot->exec = pose_hide_exec;
- ot->poll = ED_operator_posemode;
+ /* api callbacks */
+ ot->exec = pose_hide_exec;
+ ot->poll = ED_operator_posemode;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* props */
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "");
+ /* props */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "");
}
static int show_pose_bone_cb(Object *ob, Bone *bone, void *data)
{
- const bool select = POINTER_AS_INT(data);
-
- bArmature *arm = ob->data;
- int count = 0;
- if (arm->layer & bone->layer) {
- if (bone->flag & BONE_HIDDEN_P) {
- if (!(bone->flag & BONE_UNSELECTABLE)) {
- SET_FLAG_FROM_TEST(bone->flag, select, BONE_SELECTED);
- }
- bone->flag &= ~BONE_HIDDEN_P;
- count += 1;
- }
- }
-
- return count;
+ const bool select = POINTER_AS_INT(data);
+
+ bArmature *arm = ob->data;
+ int count = 0;
+ if (arm->layer & bone->layer) {
+ if (bone->flag & BONE_HIDDEN_P) {
+ if (!(bone->flag & BONE_UNSELECTABLE)) {
+ SET_FLAG_FROM_TEST(bone->flag, select, BONE_SELECTED);
+ }
+ bone->flag &= ~BONE_HIDDEN_P;
+ count += 1;
+ }
+ }
+
+ return count;
}
/* active object is armature in posemode, poll checked */
static int pose_reveal_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- uint objects_len;
- Object **objects = BKE_object_pose_array_get_unique(view_layer, CTX_wm_view3d(C), &objects_len);
- bool changed_multi = false;
- const bool select = RNA_boolean_get(op->ptr, "select");
- void *select_p = POINTER_FROM_INT(select);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob_iter = objects[ob_index];
- bArmature *arm = ob_iter->data;
-
- bool changed = bone_looper(ob_iter, arm->bonebase.first, select_p, show_pose_bone_cb);
- if (changed) {
- changed_multi = true;
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob_iter);
- DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
- }
- }
- MEM_freeN(objects);
-
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len;
+ Object **objects = BKE_object_pose_array_get_unique(view_layer, CTX_wm_view3d(C), &objects_len);
+ bool changed_multi = false;
+ const bool select = RNA_boolean_get(op->ptr, "select");
+ void *select_p = POINTER_FROM_INT(select);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ bArmature *arm = ob_iter->data;
+
+ bool changed = bone_looper(ob_iter, arm->bonebase.first, select_p, show_pose_bone_cb);
+ if (changed) {
+ changed_multi = true;
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob_iter);
+ DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
+ }
+ }
+ MEM_freeN(objects);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void POSE_OT_reveal(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Reveal Selected";
- ot->idname = "POSE_OT_reveal";
- ot->description = "Reveal all bones hidden in Pose Mode";
+ /* identifiers */
+ ot->name = "Reveal Selected";
+ ot->idname = "POSE_OT_reveal";
+ ot->description = "Reveal all bones hidden in Pose Mode";
- /* api callbacks */
- ot->exec = pose_reveal_exec;
- ot->poll = ED_operator_posemode;
+ /* api callbacks */
+ ot->exec = pose_reveal_exec;
+ ot->poll = ED_operator_posemode;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "select", true, "Select", "");
+ RNA_def_boolean(ot->srna, "select", true, "Select", "");
}
/* ********************************************** */
@@ -1118,49 +1136,53 @@ void POSE_OT_reveal(wmOperatorType *ot)
static int pose_flip_quats_exec(bContext *C, wmOperator *UNUSED(op))
{
- Scene *scene = CTX_data_scene(C);
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
-
- bool changed_multi = false;
-
- ViewLayer *view_layer = CTX_data_view_layer(C);
- View3D *v3d = CTX_wm_view3d(C);
- FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob_iter) {
- bool changed = false;
- /* loop through all selected pchans, flipping and keying (as needed) */
- FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob_iter, pchan) {
- /* only if bone is using quaternion rotation */
- if (pchan->rotmode == ROT_MODE_QUAT) {
- changed = true;
- /* quaternions have 720 degree range */
- negate_v4(pchan->quat);
-
- ED_autokeyframe_pchan(C, scene, ob_iter, pchan, ks);
- }
- } FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
-
- if (changed) {
- changed_multi = true;
- /* notifiers and updates */
- DEG_id_tag_update(&ob_iter->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob_iter);
- }
- } FOREACH_OBJECT_IN_MODE_END;
-
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ Scene *scene = CTX_data_scene(C);
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
+
+ bool changed_multi = false;
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob_iter) {
+ bool changed = false;
+ /* loop through all selected pchans, flipping and keying (as needed) */
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob_iter, pchan) {
+ /* only if bone is using quaternion rotation */
+ if (pchan->rotmode == ROT_MODE_QUAT) {
+ changed = true;
+ /* quaternions have 720 degree range */
+ negate_v4(pchan->quat);
+
+ ED_autokeyframe_pchan(C, scene, ob_iter, pchan, ks);
+ }
+ }
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
+
+ if (changed) {
+ changed_multi = true;
+ /* notifiers and updates */
+ DEG_id_tag_update(&ob_iter->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob_iter);
+ }
+ }
+ FOREACH_OBJECT_IN_MODE_END;
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void POSE_OT_quaternions_flip(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Flip Quats";
- ot->idname = "POSE_OT_quaternions_flip";
- ot->description = "Flip quaternion values to achieve desired rotations, while maintaining the same orientations";
-
- /* callbacks */
- ot->exec = pose_flip_quats_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* identifiers */
+ ot->name = "Flip Quats";
+ ot->idname = "POSE_OT_quaternions_flip";
+ ot->description =
+ "Flip quaternion values to achieve desired rotations, while maintaining the same "
+ "orientations";
+
+ /* callbacks */
+ ot->exec = pose_flip_quats_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c
index 596e64b54fe..0d100a09dfd 100644
--- a/source/blender/editors/armature/pose_group.c
+++ b/source/blender/editors/armature/pose_group.c
@@ -56,68 +56,67 @@
static int pose_group_add_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = ED_pose_object_from_context(C);
+ Object *ob = ED_pose_object_from_context(C);
- /* only continue if there's an object and pose */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
+ /* only continue if there's an object and pose */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
- /* for now, just call the API function for this */
- BKE_pose_add_group(ob->pose, NULL);
+ /* for now, just call the API function for this */
+ BKE_pose_add_group(ob->pose, NULL);
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void POSE_OT_group_add(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Add Bone Group";
- ot->idname = "POSE_OT_group_add";
- ot->description = "Add a new bone group";
+ /* identifiers */
+ ot->name = "Add Bone Group";
+ ot->idname = "POSE_OT_group_add";
+ ot->description = "Add a new bone group";
- /* api callbacks */
- ot->exec = pose_group_add_exec;
- ot->poll = ED_operator_posemode_context;
+ /* api callbacks */
+ ot->exec = pose_group_add_exec;
+ ot->poll = ED_operator_posemode_context;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-
static int pose_group_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = ED_pose_object_from_context(C);
+ Object *ob = ED_pose_object_from_context(C);
- /* only continue if there's an object and pose */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
+ /* only continue if there's an object and pose */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
- /* for now, just call the API function for this */
- BKE_pose_remove_group_index(ob->pose, ob->pose->active_group);
+ /* for now, just call the API function for this */
+ BKE_pose_remove_group_index(ob->pose, ob->pose->active_group);
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void POSE_OT_group_remove(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Remove Bone Group";
- ot->idname = "POSE_OT_group_remove";
- ot->description = "Remove the active bone group";
+ /* identifiers */
+ ot->name = "Remove Bone Group";
+ ot->idname = "POSE_OT_group_remove";
+ ot->description = "Remove the active bone group";
- /* api callbacks */
- ot->exec = pose_group_remove_exec;
- ot->poll = ED_operator_posemode_context;
+ /* api callbacks */
+ ot->exec = pose_group_remove_exec;
+ ot->poll = ED_operator_posemode_context;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ------------ */
@@ -125,397 +124,397 @@ void POSE_OT_group_remove(wmOperatorType *ot)
/* invoke callback which presents a list of bone-groups for the user to choose from */
static int pose_groups_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- Object *ob = ED_pose_object_from_context(C);
- bPose *pose;
- PropertyRNA *prop = RNA_struct_find_property(op->ptr, "type");
-
- uiPopupMenu *pup;
- uiLayout *layout;
- bActionGroup *grp;
- int i;
-
- /* only continue if there's an object, and a pose there too */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
- pose = ob->pose;
-
- /* If group index is set, try to use it! */
- if (RNA_property_is_set(op->ptr, prop)) {
- const int num_groups = BLI_listbase_count(&pose->agroups);
- const int group = RNA_property_int_get(op->ptr, prop);
-
- /* just use the active group index, and call the exec callback for the calling operator */
- if (group > 0 && group <= num_groups) {
- return op->type->exec(C, op);
- }
- }
-
- /* if there's no active group (or active is invalid), create a new menu to find it */
- if (pose->active_group <= 0) {
- /* create a new menu, and start populating it with group names */
- pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
- layout = UI_popup_menu_layout(pup);
-
- /* special entry - allow to create new group, then use that
- * (not to be used for removing though)
- */
- if (strstr(op->idname, "assign")) {
- uiItemIntO(layout, "New Group", ICON_NONE, op->idname, "type", 0);
- uiItemS(layout);
- }
-
- /* add entries for each group */
- for (grp = pose->agroups.first, i = 1; grp; grp = grp->next, i++)
- uiItemIntO(layout, grp->name, ICON_NONE, op->idname, "type", i);
-
- /* finish building the menu, and process it (should result in calling self again) */
- UI_popup_menu_end(C, pup);
-
- return OPERATOR_INTERFACE;
- }
- else {
- /* just use the active group index, and call the exec callback for the calling operator */
- RNA_int_set(op->ptr, "type", pose->active_group);
- return op->type->exec(C, op);
- }
+ Object *ob = ED_pose_object_from_context(C);
+ bPose *pose;
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "type");
+
+ uiPopupMenu *pup;
+ uiLayout *layout;
+ bActionGroup *grp;
+ int i;
+
+ /* only continue if there's an object, and a pose there too */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+ pose = ob->pose;
+
+ /* If group index is set, try to use it! */
+ if (RNA_property_is_set(op->ptr, prop)) {
+ const int num_groups = BLI_listbase_count(&pose->agroups);
+ const int group = RNA_property_int_get(op->ptr, prop);
+
+ /* just use the active group index, and call the exec callback for the calling operator */
+ if (group > 0 && group <= num_groups) {
+ return op->type->exec(C, op);
+ }
+ }
+
+ /* if there's no active group (or active is invalid), create a new menu to find it */
+ if (pose->active_group <= 0) {
+ /* create a new menu, and start populating it with group names */
+ pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
+
+ /* special entry - allow to create new group, then use that
+ * (not to be used for removing though)
+ */
+ if (strstr(op->idname, "assign")) {
+ uiItemIntO(layout, "New Group", ICON_NONE, op->idname, "type", 0);
+ uiItemS(layout);
+ }
+
+ /* add entries for each group */
+ for (grp = pose->agroups.first, i = 1; grp; grp = grp->next, i++)
+ uiItemIntO(layout, grp->name, ICON_NONE, op->idname, "type", i);
+
+ /* finish building the menu, and process it (should result in calling self again) */
+ UI_popup_menu_end(C, pup);
+
+ return OPERATOR_INTERFACE;
+ }
+ else {
+ /* just use the active group index, and call the exec callback for the calling operator */
+ RNA_int_set(op->ptr, "type", pose->active_group);
+ return op->type->exec(C, op);
+ }
}
/* Assign selected pchans to the bone group that the user selects */
static int pose_group_assign_exec(bContext *C, wmOperator *op)
{
- Object *ob = ED_pose_object_from_context(C);
- bPose *pose;
- bool done = false;
-
- /* only continue if there's an object, and a pose there too */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
-
- pose = ob->pose;
-
- /* set the active group number to the one from operator props
- * - if 0 after this, make a new group...
- */
- pose->active_group = RNA_int_get(op->ptr, "type");
- if (pose->active_group == 0)
- BKE_pose_add_group(ob->pose, NULL);
-
- /* add selected bones to group then */
- FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob, pchan)
- {
- pchan->agrp_index = pose->active_group;
- done = true;
- }
- FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
-
- /* report done status */
- if (done)
- return OPERATOR_FINISHED;
- else
- return OPERATOR_CANCELLED;
+ Object *ob = ED_pose_object_from_context(C);
+ bPose *pose;
+ bool done = false;
+
+ /* only continue if there's an object, and a pose there too */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+
+ pose = ob->pose;
+
+ /* set the active group number to the one from operator props
+ * - if 0 after this, make a new group...
+ */
+ pose->active_group = RNA_int_get(op->ptr, "type");
+ if (pose->active_group == 0)
+ BKE_pose_add_group(ob->pose, NULL);
+
+ /* add selected bones to group then */
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob, pchan) {
+ pchan->agrp_index = pose->active_group;
+ done = true;
+ }
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+
+ /* report done status */
+ if (done)
+ return OPERATOR_FINISHED;
+ else
+ return OPERATOR_CANCELLED;
}
void POSE_OT_group_assign(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Add Selected to Bone Group";
- ot->idname = "POSE_OT_group_assign";
- ot->description = "Add selected bones to the chosen bone group";
+ /* identifiers */
+ ot->name = "Add Selected to Bone Group";
+ ot->idname = "POSE_OT_group_assign";
+ ot->description = "Add selected bones to the chosen bone group";
- /* api callbacks */
- ot->invoke = pose_groups_menu_invoke;
- ot->exec = pose_group_assign_exec;
- ot->poll = ED_operator_posemode_context;
+ /* api callbacks */
+ ot->invoke = pose_groups_menu_invoke;
+ ot->exec = pose_group_assign_exec;
+ ot->poll = ED_operator_posemode_context;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
- RNA_def_int(ot->srna, "type", 0, 0, INT_MAX, "Bone Group Index", "", 0, 10);
+ /* properties */
+ RNA_def_int(ot->srna, "type", 0, 0, INT_MAX, "Bone Group Index", "", 0, 10);
}
-
static int pose_group_unassign_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = ED_pose_object_from_context(C);
- bool done = false;
-
- /* only continue if there's an object, and a pose there too */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
-
- /* find selected bones to remove from all bone groups */
- FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob, pchan)
- {
- if (pchan->agrp_index) {
- pchan->agrp_index = 0;
- done = true;
- }
- }
- FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
-
- /* report done status */
- if (done)
- return OPERATOR_FINISHED;
- else
- return OPERATOR_CANCELLED;
+ Object *ob = ED_pose_object_from_context(C);
+ bool done = false;
+
+ /* only continue if there's an object, and a pose there too */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+
+ /* find selected bones to remove from all bone groups */
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob, pchan) {
+ if (pchan->agrp_index) {
+ pchan->agrp_index = 0;
+ done = true;
+ }
+ }
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+
+ /* report done status */
+ if (done)
+ return OPERATOR_FINISHED;
+ else
+ return OPERATOR_CANCELLED;
}
void POSE_OT_group_unassign(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Remove Selected from Bone Groups";
- ot->idname = "POSE_OT_group_unassign";
- ot->description = "Remove selected bones from all bone groups";
+ /* identifiers */
+ ot->name = "Remove Selected from Bone Groups";
+ ot->idname = "POSE_OT_group_unassign";
+ ot->description = "Remove selected bones from all bone groups";
- /* api callbacks */
- ot->exec = pose_group_unassign_exec;
- ot->poll = ED_operator_posemode_context;
+ /* api callbacks */
+ ot->exec = pose_group_unassign_exec;
+ ot->poll = ED_operator_posemode_context;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int group_move_exec(bContext *C, wmOperator *op)
{
- Object *ob = ED_pose_object_from_context(C);
- bPose *pose = (ob) ? ob->pose : NULL;
- bPoseChannel *pchan;
- bActionGroup *grp;
- int dir = RNA_enum_get(op->ptr, "direction");
-
- if (ELEM(NULL, ob, pose))
- return OPERATOR_CANCELLED;
- if (pose->active_group <= 0)
- return OPERATOR_CANCELLED;
-
- /* get group to move */
- grp = BLI_findlink(&pose->agroups, pose->active_group - 1);
- if (grp == NULL)
- return OPERATOR_CANCELLED;
-
- /* move bone group */
- if (BLI_listbase_link_move(&pose->agroups, grp, dir)) {
- int grpIndexA = pose->active_group;
- int grpIndexB = grpIndexA + dir;
-
- pose->active_group += dir;
- /* fix changed bone group indices in bones (swap grpIndexA with grpIndexB) */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->agrp_index == grpIndexB) {
- pchan->agrp_index = grpIndexA;
- }
- else if (pchan->agrp_index == grpIndexA) {
- pchan->agrp_index = grpIndexB;
- }
- }
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
- }
-
- return OPERATOR_FINISHED;
+ Object *ob = ED_pose_object_from_context(C);
+ bPose *pose = (ob) ? ob->pose : NULL;
+ bPoseChannel *pchan;
+ bActionGroup *grp;
+ int dir = RNA_enum_get(op->ptr, "direction");
+
+ if (ELEM(NULL, ob, pose))
+ return OPERATOR_CANCELLED;
+ if (pose->active_group <= 0)
+ return OPERATOR_CANCELLED;
+
+ /* get group to move */
+ grp = BLI_findlink(&pose->agroups, pose->active_group - 1);
+ if (grp == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* move bone group */
+ if (BLI_listbase_link_move(&pose->agroups, grp, dir)) {
+ int grpIndexA = pose->active_group;
+ int grpIndexB = grpIndexA + dir;
+
+ pose->active_group += dir;
+ /* fix changed bone group indices in bones (swap grpIndexA with grpIndexB) */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->agrp_index == grpIndexB) {
+ pchan->agrp_index = grpIndexA;
+ }
+ else if (pchan->agrp_index == grpIndexA) {
+ pchan->agrp_index = grpIndexB;
+ }
+ }
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ }
+
+ return OPERATOR_FINISHED;
}
void POSE_OT_group_move(wmOperatorType *ot)
{
- static const EnumPropertyItem group_slot_move[] = {
- {-1, "UP", 0, "Up", ""},
- {1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Move Bone Group";
- ot->idname = "POSE_OT_group_move";
- ot->description = "Change position of active Bone Group in list of Bone Groups";
-
- /* api callbacks */
- ot->exec = group_move_exec;
- ot->poll = ED_operator_posemode_context;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_enum(ot->srna, "direction", group_slot_move, 0, "Direction",
- "Direction to move the active Bone Group towards");
+ static const EnumPropertyItem group_slot_move[] = {
+ {-1, "UP", 0, "Up", ""},
+ {1, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Move Bone Group";
+ ot->idname = "POSE_OT_group_move";
+ ot->description = "Change position of active Bone Group in list of Bone Groups";
+
+ /* api callbacks */
+ ot->exec = group_move_exec;
+ ot->poll = ED_operator_posemode_context;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna,
+ "direction",
+ group_slot_move,
+ 0,
+ "Direction",
+ "Direction to move the active Bone Group towards");
}
/* bone group sort element */
typedef struct tSortActionGroup {
- bActionGroup *agrp;
- int index;
+ bActionGroup *agrp;
+ int index;
} tSortActionGroup;
/* compare bone groups by name */
static int compare_agroup(const void *sgrp_a_ptr, const void *sgrp_b_ptr)
{
- const tSortActionGroup *sgrp_a = sgrp_a_ptr;
- const tSortActionGroup *sgrp_b = sgrp_b_ptr;
+ const tSortActionGroup *sgrp_a = sgrp_a_ptr;
+ const tSortActionGroup *sgrp_b = sgrp_b_ptr;
- return strcmp(sgrp_a->agrp->name, sgrp_b->agrp->name);
+ return strcmp(sgrp_a->agrp->name, sgrp_b->agrp->name);
}
static int group_sort_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = ED_pose_object_from_context(C);
- bPose *pose = (ob) ? ob->pose : NULL;
- bPoseChannel *pchan;
- tSortActionGroup *agrp_array;
- bActionGroup *agrp;
- int agrp_count;
- int i;
-
- if (ELEM(NULL, ob, pose))
- return OPERATOR_CANCELLED;
- if (pose->active_group <= 0)
- return OPERATOR_CANCELLED;
-
- /* create temporary array with bone groups and indices */
- agrp_count = BLI_listbase_count(&pose->agroups);
- agrp_array = MEM_mallocN(sizeof(tSortActionGroup) * agrp_count, "sort bone groups");
- for (agrp = pose->agroups.first, i = 0; agrp; agrp = agrp->next, i++) {
- BLI_assert(i < agrp_count);
- agrp_array[i].agrp = agrp;
- agrp_array[i].index = i + 1;
- }
-
- /* sort bone groups by name */
- qsort(agrp_array, agrp_count, sizeof(tSortActionGroup), compare_agroup);
-
- /* create sorted bone group list from sorted array */
- BLI_listbase_clear(&pose->agroups);
- for (i = 0; i < agrp_count; i++) {
- BLI_addtail(&pose->agroups, agrp_array[i].agrp);
- }
-
- /* fix changed bone group indizes in bones */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- for (i = 0; i < agrp_count; i++) {
- if (pchan->agrp_index == agrp_array[i].index) {
- pchan->agrp_index = i + 1;
- break;
- }
- }
- }
-
- /* free temp resources */
- MEM_freeN(agrp_array);
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
-
- return OPERATOR_FINISHED;
+ Object *ob = ED_pose_object_from_context(C);
+ bPose *pose = (ob) ? ob->pose : NULL;
+ bPoseChannel *pchan;
+ tSortActionGroup *agrp_array;
+ bActionGroup *agrp;
+ int agrp_count;
+ int i;
+
+ if (ELEM(NULL, ob, pose))
+ return OPERATOR_CANCELLED;
+ if (pose->active_group <= 0)
+ return OPERATOR_CANCELLED;
+
+ /* create temporary array with bone groups and indices */
+ agrp_count = BLI_listbase_count(&pose->agroups);
+ agrp_array = MEM_mallocN(sizeof(tSortActionGroup) * agrp_count, "sort bone groups");
+ for (agrp = pose->agroups.first, i = 0; agrp; agrp = agrp->next, i++) {
+ BLI_assert(i < agrp_count);
+ agrp_array[i].agrp = agrp;
+ agrp_array[i].index = i + 1;
+ }
+
+ /* sort bone groups by name */
+ qsort(agrp_array, agrp_count, sizeof(tSortActionGroup), compare_agroup);
+
+ /* create sorted bone group list from sorted array */
+ BLI_listbase_clear(&pose->agroups);
+ for (i = 0; i < agrp_count; i++) {
+ BLI_addtail(&pose->agroups, agrp_array[i].agrp);
+ }
+
+ /* fix changed bone group indizes in bones */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ for (i = 0; i < agrp_count; i++) {
+ if (pchan->agrp_index == agrp_array[i].index) {
+ pchan->agrp_index = i + 1;
+ break;
+ }
+ }
+ }
+
+ /* free temp resources */
+ MEM_freeN(agrp_array);
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+
+ return OPERATOR_FINISHED;
}
void POSE_OT_group_sort(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Sort Bone Groups";
- ot->idname = "POSE_OT_group_sort";
- ot->description = "Sort Bone Groups by their names in ascending order";
+ /* identifiers */
+ ot->name = "Sort Bone Groups";
+ ot->idname = "POSE_OT_group_sort";
+ ot->description = "Sort Bone Groups by their names in ascending order";
- /* api callbacks */
- ot->exec = group_sort_exec;
- ot->poll = ED_operator_posemode_context;
+ /* api callbacks */
+ ot->exec = group_sort_exec;
+ ot->poll = ED_operator_posemode_context;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static void pose_group_select(Object *ob, bool select)
{
- bPose *pose = ob->pose;
-
- FOREACH_PCHAN_VISIBLE_IN_OBJECT_BEGIN (ob, pchan)
- {
- if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
- if (select) {
- if (pchan->agrp_index == pose->active_group)
- pchan->bone->flag |= BONE_SELECTED;
- }
- else {
- if (pchan->agrp_index == pose->active_group)
- pchan->bone->flag &= ~BONE_SELECTED;
- }
- }
- }
- FOREACH_PCHAN_VISIBLE_IN_OBJECT_END;
+ bPose *pose = ob->pose;
+
+ FOREACH_PCHAN_VISIBLE_IN_OBJECT_BEGIN (ob, pchan) {
+ if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
+ if (select) {
+ if (pchan->agrp_index == pose->active_group)
+ pchan->bone->flag |= BONE_SELECTED;
+ }
+ else {
+ if (pchan->agrp_index == pose->active_group)
+ pchan->bone->flag &= ~BONE_SELECTED;
+ }
+ }
+ }
+ FOREACH_PCHAN_VISIBLE_IN_OBJECT_END;
}
static int pose_group_select_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = ED_pose_object_from_context(C);
+ Object *ob = ED_pose_object_from_context(C);
- /* only continue if there's an object, and a pose there too */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
+ /* only continue if there's an object, and a pose there too */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
- pose_group_select(ob, 1);
+ pose_group_select(ob, 1);
- /* notifiers for updates */
- bArmature *arm = ob->data;
- DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ /* notifiers for updates */
+ bArmature *arm = ob->data;
+ DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void POSE_OT_group_select(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select Bones of Bone Group";
- ot->idname = "POSE_OT_group_select";
- ot->description = "Select bones in active Bone Group";
+ /* identifiers */
+ ot->name = "Select Bones of Bone Group";
+ ot->idname = "POSE_OT_group_select";
+ ot->description = "Select bones in active Bone Group";
- /* api callbacks */
- ot->exec = pose_group_select_exec;
- ot->poll = ED_operator_posemode_context;
+ /* api callbacks */
+ ot->exec = pose_group_select_exec;
+ ot->poll = ED_operator_posemode_context;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int pose_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = ED_pose_object_from_context(C);
+ Object *ob = ED_pose_object_from_context(C);
- /* only continue if there's an object, and a pose there too */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
+ /* only continue if there's an object, and a pose there too */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
- pose_group_select(ob, 0);
+ pose_group_select(ob, 0);
- /* notifiers for updates */
- bArmature *arm = ob->data;
- DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ /* notifiers for updates */
+ bArmature *arm = ob->data;
+ DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void POSE_OT_group_deselect(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Deselect Bone Group";
- ot->idname = "POSE_OT_group_deselect";
- ot->description = "Deselect bones of active Bone Group";
+ /* identifiers */
+ ot->name = "Deselect Bone Group";
+ ot->idname = "POSE_OT_group_deselect";
+ ot->description = "Deselect bones of active Bone Group";
- /* api callbacks */
- ot->exec = pose_group_deselect_exec;
- ot->poll = ED_operator_posemode_context;
+ /* api callbacks */
+ ot->exec = pose_group_deselect_exec;
+ ot->poll = ED_operator_posemode_context;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ********************************************** */
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index 41df3086fa8..443bcdde028 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -72,7 +72,9 @@
/* ******* XXX ********** */
-static void action_set_activemarker(void *UNUSED(a), void *UNUSED(b), void *UNUSED(c)) {}
+static void action_set_activemarker(void *UNUSED(a), void *UNUSED(b), void *UNUSED(c))
+{
+}
/* ************************************************************* */
/* == POSE-LIBRARY TOOL FOR BLENDER ==
@@ -93,84 +95,84 @@ static void action_set_activemarker(void *UNUSED(a), void *UNUSED(b), void *UNUS
*/
/* ************************************************************* */
-
/* gets the first available frame in poselib to store a pose on
* - frames start from 1, and a pose should occur on every frame... 0 is error!
*/
static int poselib_get_free_index(bAction *act)
{
- TimeMarker *marker;
- int low = 0, high = 0;
- bool changed = false;
-
- /* sanity checks */
- if (ELEM(NULL, act, act->markers.first)) return 1;
-
- /* As poses are not stored in chronological order, we must iterate over this list
- * a few times until we don't make any new discoveries (mostly about the lower bound).
- * Prevents problems with deleting then trying to add new poses [#27412]
- */
- do {
- changed = false;
-
- for (marker = act->markers.first; marker; marker = marker->next) {
- /* only increase low if value is 1 greater than low, to find "gaps" where
- * poses were removed from the poselib
- */
- if (marker->frame == (low + 1)) {
- low++;
- changed = true;
- }
-
- /* value replaces high if it is the highest value encountered yet */
- if (marker->frame > high) {
- high = marker->frame;
- changed = true;
- }
- }
- } while (changed != 0);
-
- /* - if low is not equal to high, then low+1 is a gap
- * - if low is equal to high, then high+1 is the next index (add at end)
- */
- if (low < high)
- return (low + 1);
- else
- return (high + 1);
+ TimeMarker *marker;
+ int low = 0, high = 0;
+ bool changed = false;
+
+ /* sanity checks */
+ if (ELEM(NULL, act, act->markers.first))
+ return 1;
+
+ /* As poses are not stored in chronological order, we must iterate over this list
+ * a few times until we don't make any new discoveries (mostly about the lower bound).
+ * Prevents problems with deleting then trying to add new poses [#27412]
+ */
+ do {
+ changed = false;
+
+ for (marker = act->markers.first; marker; marker = marker->next) {
+ /* only increase low if value is 1 greater than low, to find "gaps" where
+ * poses were removed from the poselib
+ */
+ if (marker->frame == (low + 1)) {
+ low++;
+ changed = true;
+ }
+
+ /* value replaces high if it is the highest value encountered yet */
+ if (marker->frame > high) {
+ high = marker->frame;
+ changed = true;
+ }
+ }
+ } while (changed != 0);
+
+ /* - if low is not equal to high, then low+1 is a gap
+ * - if low is equal to high, then high+1 is the next index (add at end)
+ */
+ if (low < high)
+ return (low + 1);
+ else
+ return (high + 1);
}
/* returns the active pose for a poselib */
static TimeMarker *poselib_get_active_pose(bAction *act)
{
- if ((act) && (act->active_marker))
- return BLI_findlink(&act->markers, act->active_marker - 1);
- else
- return NULL;
+ if ((act) && (act->active_marker))
+ return BLI_findlink(&act->markers, act->active_marker - 1);
+ else
+ return NULL;
}
/* Get object that Pose Lib should be found on */
/* XXX C can be zero */
static Object *get_poselib_object(bContext *C)
{
- ScrArea *sa;
+ ScrArea *sa;
- /* sanity check */
- if (C == NULL)
- return NULL;
+ /* sanity check */
+ if (C == NULL)
+ return NULL;
- sa = CTX_wm_area(C);
+ sa = CTX_wm_area(C);
- if (sa && (sa->spacetype == SPACE_PROPERTIES))
- return ED_object_context(C);
- else
- return BKE_object_pose_armature_get(CTX_data_active_object(C));
+ if (sa && (sa->spacetype == SPACE_PROPERTIES))
+ return ED_object_context(C);
+ else
+ return BKE_object_pose_armature_get(CTX_data_active_object(C));
}
/* Poll callback for operators that require existing PoseLib data (with poses) to work */
static bool has_poselib_pose_data_poll(bContext *C)
{
- Object *ob = get_poselib_object(C);
- return (ob && ob->poselib);
+ Object *ob = get_poselib_object(C);
+ return (ob && ob->poselib);
}
/* Poll callback for operators that require existing PoseLib data (with poses)
@@ -178,8 +180,8 @@ static bool has_poselib_pose_data_poll(bContext *C)
*/
static bool has_poselib_pose_data_for_editing_poll(bContext *C)
{
- Object *ob = get_poselib_object(C);
- return (ob && ob->poselib && !ID_IS_LINKED(ob->poselib));
+ Object *ob = get_poselib_object(C);
+ return (ob && ob->poselib && !ID_IS_LINKED(ob->poselib));
}
/* ----------------------------------- */
@@ -187,29 +189,29 @@ static bool has_poselib_pose_data_for_editing_poll(bContext *C)
/* Initialize a new poselib (whether it is needed or not) */
static bAction *poselib_init_new(Main *bmain, Object *ob)
{
- /* sanity checks - only for armatures */
- if (ELEM(NULL, ob, ob->pose))
- return NULL;
+ /* sanity checks - only for armatures */
+ if (ELEM(NULL, ob, ob->pose))
+ return NULL;
- /* init object's poselib action (unlink old one if there) */
- if (ob->poselib)
- id_us_min(&ob->poselib->id);
+ /* init object's poselib action (unlink old one if there) */
+ if (ob->poselib)
+ id_us_min(&ob->poselib->id);
- ob->poselib = BKE_action_add(bmain, "PoseLib");
- ob->poselib->idroot = ID_OB;
+ ob->poselib = BKE_action_add(bmain, "PoseLib");
+ ob->poselib->idroot = ID_OB;
- return ob->poselib;
+ return ob->poselib;
}
/* Initialize a new poselib (checks if that needs to happen) */
static bAction *poselib_validate(Main *bmain, Object *ob)
{
- if (ELEM(NULL, ob, ob->pose))
- return NULL;
- else if (ob->poselib == NULL)
- return poselib_init_new(bmain, ob);
- else
- return ob->poselib;
+ if (ELEM(NULL, ob, ob->pose))
+ return NULL;
+ else if (ob->poselib == NULL)
+ return poselib_init_new(bmain, ob);
+ else
+ return ob->poselib;
}
/* ************************************************************* */
@@ -217,70 +219,70 @@ static bAction *poselib_validate(Main *bmain, Object *ob)
static int poselib_new_exec(bContext *C, wmOperator *UNUSED(op))
{
- Main *bmain = CTX_data_main(C);
- Object *ob = get_poselib_object(C);
+ Main *bmain = CTX_data_main(C);
+ Object *ob = get_poselib_object(C);
- /* sanity checks */
- if (ob == NULL)
- return OPERATOR_CANCELLED;
+ /* sanity checks */
+ if (ob == NULL)
+ return OPERATOR_CANCELLED;
- /* new method here deals with the rest... */
- poselib_init_new(bmain, ob);
+ /* new method here deals with the rest... */
+ poselib_init_new(bmain, ob);
- /* notifier here might evolve? */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ /* notifier here might evolve? */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void POSELIB_OT_new(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "New Pose Library";
- ot->idname = "POSELIB_OT_new";
- ot->description = "Add New Pose Library to active Object";
+ /* identifiers */
+ ot->name = "New Pose Library";
+ ot->idname = "POSELIB_OT_new";
+ ot->description = "Add New Pose Library to active Object";
- /* callbacks */
- ot->exec = poselib_new_exec;
- ot->poll = ED_operator_posemode;
+ /* callbacks */
+ ot->exec = poselib_new_exec;
+ ot->poll = ED_operator_posemode;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ------------------------------------------------ */
static int poselib_unlink_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = get_poselib_object(C);
+ Object *ob = get_poselib_object(C);
- /* sanity checks */
- if (ELEM(NULL, ob, ob->poselib))
- return OPERATOR_CANCELLED;
+ /* sanity checks */
+ if (ELEM(NULL, ob, ob->poselib))
+ return OPERATOR_CANCELLED;
- /* there should be a poselib (we just checked above!), so just lower its user count and remove */
- id_us_min(&ob->poselib->id);
- ob->poselib = NULL;
+ /* there should be a poselib (we just checked above!), so just lower its user count and remove */
+ id_us_min(&ob->poselib->id);
+ ob->poselib = NULL;
- /* notifier here might evolve? */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ /* notifier here might evolve? */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void POSELIB_OT_unlink(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Unlink Pose Library";
- ot->idname = "POSELIB_OT_unlink";
- ot->description = "Remove Pose Library from active Object";
+ /* identifiers */
+ ot->name = "Unlink Pose Library";
+ ot->idname = "POSELIB_OT_unlink";
+ ot->description = "Remove Pose Library from active Object";
- /* callbacks */
- ot->exec = poselib_unlink_exec;
- ot->poll = has_poselib_pose_data_poll;
+ /* callbacks */
+ ot->exec = poselib_unlink_exec;
+ ot->poll = has_poselib_pose_data_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ************************************************************* */
@@ -291,81 +293,81 @@ void POSELIB_OT_unlink(wmOperatorType *ot)
*/
static int poselib_sanitize_exec(bContext *C, wmOperator *op)
{
- Object *ob = get_poselib_object(C);
- bAction *act = (ob) ? ob->poselib : NULL;
- DLRBT_Tree keys;
- ActKeyColumn *ak;
- TimeMarker *marker, *markern;
-
- /* validate action */
- if (act == NULL) {
- BKE_report(op->reports, RPT_WARNING, "No action to validate");
- return OPERATOR_CANCELLED;
- }
-
- /* determine which frames have keys */
- BLI_dlrbTree_init(&keys);
- action_to_keylist(NULL, act, &keys, 0);
-
- /* for each key, make sure there is a corresponding pose */
- for (ak = keys.first; ak; ak = ak->next) {
- /* check if any pose matches this */
- /* TODO: don't go looking through the list like this every time... */
- for (marker = act->markers.first; marker; marker = marker->next) {
- if (IS_EQ((double)marker->frame, (double)ak->cfra)) {
- marker->flag = -1;
- break;
- }
- }
-
- /* add new if none found */
- if (marker == NULL) {
- /* add pose to poselib */
- marker = MEM_callocN(sizeof(TimeMarker), "ActionMarker");
-
- BLI_snprintf(marker->name, sizeof(marker->name), "F%d Pose", (int)ak->cfra);
-
- marker->frame = (int)ak->cfra;
- marker->flag = -1;
-
- BLI_addtail(&act->markers, marker);
- }
- }
-
- /* remove all untagged poses (unused), and remove all tags */
- for (marker = act->markers.first; marker; marker = markern) {
- markern = marker->next;
-
- if (marker->flag != -1)
- BLI_freelinkN(&act->markers, marker);
- else
- marker->flag = 0;
- }
-
- /* free temp memory */
- BLI_dlrbTree_free(&keys);
-
- /* send notifiers for this - using keyframe editing notifiers, since action
- * may be being shown in anim editors as active action
- */
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
+ Object *ob = get_poselib_object(C);
+ bAction *act = (ob) ? ob->poselib : NULL;
+ DLRBT_Tree keys;
+ ActKeyColumn *ak;
+ TimeMarker *marker, *markern;
+
+ /* validate action */
+ if (act == NULL) {
+ BKE_report(op->reports, RPT_WARNING, "No action to validate");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* determine which frames have keys */
+ BLI_dlrbTree_init(&keys);
+ action_to_keylist(NULL, act, &keys, 0);
+
+ /* for each key, make sure there is a corresponding pose */
+ for (ak = keys.first; ak; ak = ak->next) {
+ /* check if any pose matches this */
+ /* TODO: don't go looking through the list like this every time... */
+ for (marker = act->markers.first; marker; marker = marker->next) {
+ if (IS_EQ((double)marker->frame, (double)ak->cfra)) {
+ marker->flag = -1;
+ break;
+ }
+ }
+
+ /* add new if none found */
+ if (marker == NULL) {
+ /* add pose to poselib */
+ marker = MEM_callocN(sizeof(TimeMarker), "ActionMarker");
+
+ BLI_snprintf(marker->name, sizeof(marker->name), "F%d Pose", (int)ak->cfra);
+
+ marker->frame = (int)ak->cfra;
+ marker->flag = -1;
+
+ BLI_addtail(&act->markers, marker);
+ }
+ }
+
+ /* remove all untagged poses (unused), and remove all tags */
+ for (marker = act->markers.first; marker; marker = markern) {
+ markern = marker->next;
+
+ if (marker->flag != -1)
+ BLI_freelinkN(&act->markers, marker);
+ else
+ marker->flag = 0;
+ }
+
+ /* free temp memory */
+ BLI_dlrbTree_free(&keys);
+
+ /* send notifiers for this - using keyframe editing notifiers, since action
+ * may be being shown in anim editors as active action
+ */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
void POSELIB_OT_action_sanitize(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Sanitize Pose Library Action";
- ot->idname = "POSELIB_OT_action_sanitize";
- ot->description = "Make action suitable for use as a Pose Library";
+ /* identifiers */
+ ot->name = "Sanitize Pose Library Action";
+ ot->idname = "POSELIB_OT_action_sanitize";
+ ot->description = "Make action suitable for use as a Pose Library";
- /* callbacks */
- ot->exec = poselib_sanitize_exec;
- ot->poll = has_poselib_pose_data_for_editing_poll;
+ /* callbacks */
+ ot->exec = poselib_sanitize_exec;
+ ot->poll = has_poselib_pose_data_for_editing_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ------------------------------------------ */
@@ -373,615 +375,631 @@ void POSELIB_OT_action_sanitize(wmOperatorType *ot)
/* Poll callback for adding poses to a PoseLib */
static bool poselib_add_poll(bContext *C)
{
- /* There are 2 cases we need to be careful with:
- * 1) When this operator is invoked from a hotkey, there may be no PoseLib yet
- * 2) If a PoseLib already exists, we can't edit the action if it is a lib-linked
- * actions, as data will be lost when saving the file
- */
- if (ED_operator_posemode(C)) {
- Object *ob = get_poselib_object(C);
- if (ob) {
- if ((ob->poselib == NULL) || !ID_IS_LINKED(ob->poselib)) {
- return true;
- }
- }
- }
- return false;
+ /* There are 2 cases we need to be careful with:
+ * 1) When this operator is invoked from a hotkey, there may be no PoseLib yet
+ * 2) If a PoseLib already exists, we can't edit the action if it is a lib-linked
+ * actions, as data will be lost when saving the file
+ */
+ if (ED_operator_posemode(C)) {
+ Object *ob = get_poselib_object(C);
+ if (ob) {
+ if ((ob->poselib == NULL) || !ID_IS_LINKED(ob->poselib)) {
+ return true;
+ }
+ }
+ }
+ return false;
}
static void poselib_add_menu_invoke__replacemenu(bContext *C, uiLayout *layout, void *UNUSED(arg))
{
- Object *ob = get_poselib_object(C);
- bAction *act = ob->poselib; /* never NULL */
- TimeMarker *marker;
-
- wmOperatorType *ot = WM_operatortype_find("POSELIB_OT_pose_add", 1);
-
- BLI_assert(ot != NULL);
-
- /* set the operator execution context correctly */
- uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
-
- /* add each marker to this menu */
- for (marker = act->markers.first; marker; marker = marker->next) {
- PointerRNA props_ptr;
- uiItemFullO_ptr(
- layout, ot,
- marker->name, ICON_ARMATURE_DATA, NULL,
- WM_OP_EXEC_DEFAULT, 0, &props_ptr);
- RNA_int_set(&props_ptr, "frame", marker->frame);
- RNA_string_set(&props_ptr, "name", marker->name);
- }
-}
-
-static int poselib_add_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- Scene *scene = CTX_data_scene(C);
- Object *ob = get_poselib_object(C);
- bPose *pose = (ob) ? ob->pose : NULL;
- uiPopupMenu *pup;
- uiLayout *layout;
-
- /* sanity check */
- if (ELEM(NULL, ob, pose))
- return OPERATOR_CANCELLED;
-
- /* start building */
- pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
- layout = UI_popup_menu_layout(pup);
- uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
+ Object *ob = get_poselib_object(C);
+ bAction *act = ob->poselib; /* never NULL */
+ TimeMarker *marker;
- /* add new (adds to the first unoccupied frame) */
- uiItemIntO(layout, IFACE_("Add New"), ICON_NONE, "POSELIB_OT_pose_add", "frame", poselib_get_free_index(ob->poselib));
+ wmOperatorType *ot = WM_operatortype_find("POSELIB_OT_pose_add", 1);
- /* check if we have any choices to add a new pose in any other way */
- if ((ob->poselib) && (ob->poselib->markers.first)) {
- /* add new (on current frame) */
- uiItemIntO(layout, IFACE_("Add New (Current Frame)"), ICON_NONE, "POSELIB_OT_pose_add", "frame", CFRA);
+ BLI_assert(ot != NULL);
- /* replace existing - submenu */
- uiItemMenuF(layout, IFACE_("Replace Existing..."), 0, poselib_add_menu_invoke__replacemenu, NULL);
- }
+ /* set the operator execution context correctly */
+ uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
- UI_popup_menu_end(C, pup);
-
- /* this operator is only for a menu, not used further */
- return OPERATOR_INTERFACE;
+ /* add each marker to this menu */
+ for (marker = act->markers.first; marker; marker = marker->next) {
+ PointerRNA props_ptr;
+ uiItemFullO_ptr(
+ layout, ot, marker->name, ICON_ARMATURE_DATA, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr);
+ RNA_int_set(&props_ptr, "frame", marker->frame);
+ RNA_string_set(&props_ptr, "name", marker->name);
+ }
}
+static int poselib_add_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = get_poselib_object(C);
+ bPose *pose = (ob) ? ob->pose : NULL;
+ uiPopupMenu *pup;
+ uiLayout *layout;
+
+ /* sanity check */
+ if (ELEM(NULL, ob, pose))
+ return OPERATOR_CANCELLED;
+
+ /* start building */
+ pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
+ uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
+
+ /* add new (adds to the first unoccupied frame) */
+ uiItemIntO(layout,
+ IFACE_("Add New"),
+ ICON_NONE,
+ "POSELIB_OT_pose_add",
+ "frame",
+ poselib_get_free_index(ob->poselib));
+
+ /* check if we have any choices to add a new pose in any other way */
+ if ((ob->poselib) && (ob->poselib->markers.first)) {
+ /* add new (on current frame) */
+ uiItemIntO(layout,
+ IFACE_("Add New (Current Frame)"),
+ ICON_NONE,
+ "POSELIB_OT_pose_add",
+ "frame",
+ CFRA);
+
+ /* replace existing - submenu */
+ uiItemMenuF(
+ layout, IFACE_("Replace Existing..."), 0, poselib_add_menu_invoke__replacemenu, NULL);
+ }
+
+ UI_popup_menu_end(C, pup);
+
+ /* this operator is only for a menu, not used further */
+ return OPERATOR_INTERFACE;
+}
static int poselib_add_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- Object *ob = get_poselib_object(C);
- bAction *act = poselib_validate(bmain, ob);
- bPose *pose = (ob) ? ob->pose : NULL;
- TimeMarker *marker;
- KeyingSet *ks;
- int frame = RNA_int_get(op->ptr, "frame");
- char name[64];
-
- /* sanity check (invoke should have checked this anyway) */
- if (ELEM(NULL, ob, pose))
- return OPERATOR_CANCELLED;
-
- /* get name to give to pose */
- RNA_string_get(op->ptr, "name", name);
-
- /* add pose to poselib - replaces any existing pose there
- * - for the 'replace' option, this should end up finding the appropriate marker,
- * so no new one will be added
- */
- for (marker = act->markers.first; marker; marker = marker->next) {
- if (marker->frame == frame) {
- BLI_strncpy(marker->name, name, sizeof(marker->name));
- break;
- }
- }
- if (marker == NULL) {
- marker = MEM_callocN(sizeof(TimeMarker), "ActionMarker");
-
- BLI_strncpy(marker->name, name, sizeof(marker->name));
- marker->frame = frame;
-
- BLI_addtail(&act->markers, marker);
- }
-
- /* validate name */
- BLI_uniquename(&act->markers, marker, DATA_("Pose"), '.', offsetof(TimeMarker, name), sizeof(marker->name));
-
- /* use Keying Set to determine what to store for the pose */
-
- /* this includes custom props :)*/
- ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_WHOLE_CHARACTER_SELECTED_ID);
-
- ANIM_apply_keyingset(C, NULL, act, ks, MODIFYKEY_MODE_INSERT, (float)frame);
-
- /* store new 'active' pose number */
- act->active_marker = BLI_listbase_count(&act->markers);
- DEG_id_tag_update(&act->id, ID_RECALC_COPY_ON_WRITE);
-
- /* done */
- return OPERATOR_FINISHED;
+ Main *bmain = CTX_data_main(C);
+ Object *ob = get_poselib_object(C);
+ bAction *act = poselib_validate(bmain, ob);
+ bPose *pose = (ob) ? ob->pose : NULL;
+ TimeMarker *marker;
+ KeyingSet *ks;
+ int frame = RNA_int_get(op->ptr, "frame");
+ char name[64];
+
+ /* sanity check (invoke should have checked this anyway) */
+ if (ELEM(NULL, ob, pose))
+ return OPERATOR_CANCELLED;
+
+ /* get name to give to pose */
+ RNA_string_get(op->ptr, "name", name);
+
+ /* add pose to poselib - replaces any existing pose there
+ * - for the 'replace' option, this should end up finding the appropriate marker,
+ * so no new one will be added
+ */
+ for (marker = act->markers.first; marker; marker = marker->next) {
+ if (marker->frame == frame) {
+ BLI_strncpy(marker->name, name, sizeof(marker->name));
+ break;
+ }
+ }
+ if (marker == NULL) {
+ marker = MEM_callocN(sizeof(TimeMarker), "ActionMarker");
+
+ BLI_strncpy(marker->name, name, sizeof(marker->name));
+ marker->frame = frame;
+
+ BLI_addtail(&act->markers, marker);
+ }
+
+ /* validate name */
+ BLI_uniquename(
+ &act->markers, marker, DATA_("Pose"), '.', offsetof(TimeMarker, name), sizeof(marker->name));
+
+ /* use Keying Set to determine what to store for the pose */
+
+ /* this includes custom props :)*/
+ ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_WHOLE_CHARACTER_SELECTED_ID);
+
+ ANIM_apply_keyingset(C, NULL, act, ks, MODIFYKEY_MODE_INSERT, (float)frame);
+
+ /* store new 'active' pose number */
+ act->active_marker = BLI_listbase_count(&act->markers);
+ DEG_id_tag_update(&act->id, ID_RECALC_COPY_ON_WRITE);
+
+ /* done */
+ return OPERATOR_FINISHED;
}
void POSELIB_OT_pose_add(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "PoseLib Add Pose";
- ot->idname = "POSELIB_OT_pose_add";
- ot->description = "Add the current Pose to the active Pose Library";
-
- /* api callbacks */
- ot->invoke = poselib_add_menu_invoke;
- ot->exec = poselib_add_exec;
- ot->poll = poselib_add_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_int(ot->srna, "frame", 1, 0, INT_MAX, "Frame", "Frame to store pose on", 0, INT_MAX);
- RNA_def_string(ot->srna, "name", "Pose", 64, "Pose Name", "Name of newly added Pose");
+ /* identifiers */
+ ot->name = "PoseLib Add Pose";
+ ot->idname = "POSELIB_OT_pose_add";
+ ot->description = "Add the current Pose to the active Pose Library";
+
+ /* api callbacks */
+ ot->invoke = poselib_add_menu_invoke;
+ ot->exec = poselib_add_exec;
+ ot->poll = poselib_add_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_int(ot->srna, "frame", 1, 0, INT_MAX, "Frame", "Frame to store pose on", 0, INT_MAX);
+ RNA_def_string(ot->srna, "name", "Pose", 64, "Pose Name", "Name of newly added Pose");
}
/* ----- */
/* can be called with C == NULL */
-static const EnumPropertyItem *poselib_stored_pose_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+static const EnumPropertyItem *poselib_stored_pose_itemf(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
{
- Object *ob = get_poselib_object(C);
- bAction *act = (ob) ? ob->poselib : NULL;
- TimeMarker *marker;
- EnumPropertyItem *item = NULL, item_tmp = {0};
- int totitem = 0;
- int i = 0;
-
- if (C == NULL) {
- return DummyRNA_NULL_items;
- }
-
- /* check that the action exists */
- if (act) {
- /* add each marker to the list */
- for (marker = act->markers.first, i = 0; marker; marker = marker->next, i++) {
- item_tmp.identifier = item_tmp.name = marker->name;
- item_tmp.icon = ICON_ARMATURE_DATA;
- item_tmp.value = i;
- RNA_enum_item_add(&item, &totitem, &item_tmp);
- }
- }
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
+ Object *ob = get_poselib_object(C);
+ bAction *act = (ob) ? ob->poselib : NULL;
+ TimeMarker *marker;
+ EnumPropertyItem *item = NULL, item_tmp = {0};
+ int totitem = 0;
+ int i = 0;
+
+ if (C == NULL) {
+ return DummyRNA_NULL_items;
+ }
+
+ /* check that the action exists */
+ if (act) {
+ /* add each marker to the list */
+ for (marker = act->markers.first, i = 0; marker; marker = marker->next, i++) {
+ item_tmp.identifier = item_tmp.name = marker->name;
+ item_tmp.icon = ICON_ARMATURE_DATA;
+ item_tmp.value = i;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
}
static int poselib_remove_exec(bContext *C, wmOperator *op)
{
- Object *ob = get_poselib_object(C);
- bAction *act = (ob) ? ob->poselib : NULL;
- TimeMarker *marker;
- int marker_index;
- FCurve *fcu;
- PropertyRNA *prop;
-
- /* check if valid poselib */
- if (act == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Object does not have pose lib data");
- return OPERATOR_CANCELLED;
- }
-
- prop = RNA_struct_find_property(op->ptr, "pose");
- if (RNA_property_is_set(op->ptr, prop)) {
- marker_index = RNA_property_enum_get(op->ptr, prop);
- }
- else {
- marker_index = act->active_marker - 1;
- }
-
- /* get index (and pointer) of pose to remove */
- marker = BLI_findlink(&act->markers, marker_index);
- if (marker == NULL) {
- BKE_reportf(op->reports, RPT_ERROR, "Invalid pose specified %d", marker_index);
- return OPERATOR_CANCELLED;
- }
-
- /* remove relevant keyframes */
- for (fcu = act->curves.first; fcu; fcu = fcu->next) {
- BezTriple *bezt;
- unsigned int i;
-
- if (fcu->bezt) {
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- /* check if remove */
- if (IS_EQF(bezt->vec[1][0], (float)marker->frame)) {
- delete_fcurve_key(fcu, i, 1);
- break;
- }
- }
- }
- }
-
- /* remove poselib from list */
- BLI_freelinkN(&act->markers, marker);
-
- /* fix active pose number */
- act->active_marker = 0;
-
- /* send notifiers for this - using keyframe editing notifiers, since action
- * may be being shown in anim editors as active action
- */
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
- DEG_id_tag_update(&act->id, ID_RECALC_COPY_ON_WRITE);
-
- /* done */
- return OPERATOR_FINISHED;
+ Object *ob = get_poselib_object(C);
+ bAction *act = (ob) ? ob->poselib : NULL;
+ TimeMarker *marker;
+ int marker_index;
+ FCurve *fcu;
+ PropertyRNA *prop;
+
+ /* check if valid poselib */
+ if (act == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Object does not have pose lib data");
+ return OPERATOR_CANCELLED;
+ }
+
+ prop = RNA_struct_find_property(op->ptr, "pose");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ marker_index = RNA_property_enum_get(op->ptr, prop);
+ }
+ else {
+ marker_index = act->active_marker - 1;
+ }
+
+ /* get index (and pointer) of pose to remove */
+ marker = BLI_findlink(&act->markers, marker_index);
+ if (marker == NULL) {
+ BKE_reportf(op->reports, RPT_ERROR, "Invalid pose specified %d", marker_index);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* remove relevant keyframes */
+ for (fcu = act->curves.first; fcu; fcu = fcu->next) {
+ BezTriple *bezt;
+ unsigned int i;
+
+ if (fcu->bezt) {
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ /* check if remove */
+ if (IS_EQF(bezt->vec[1][0], (float)marker->frame)) {
+ delete_fcurve_key(fcu, i, 1);
+ break;
+ }
+ }
+ }
+ }
+
+ /* remove poselib from list */
+ BLI_freelinkN(&act->markers, marker);
+
+ /* fix active pose number */
+ act->active_marker = 0;
+
+ /* send notifiers for this - using keyframe editing notifiers, since action
+ * may be being shown in anim editors as active action
+ */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ DEG_id_tag_update(&act->id, ID_RECALC_COPY_ON_WRITE);
+
+ /* done */
+ return OPERATOR_FINISHED;
}
void POSELIB_OT_pose_remove(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "PoseLib Remove Pose";
- ot->idname = "POSELIB_OT_pose_remove";
- ot->description = "Remove nth pose from the active Pose Library";
-
- /* api callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = poselib_remove_exec;
- ot->poll = has_poselib_pose_data_for_editing_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- prop = RNA_def_enum(ot->srna, "pose", DummyRNA_NULL_items, 0, "Pose", "The pose to remove");
- RNA_def_enum_funcs(prop, poselib_stored_pose_itemf);
- RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
- ot->prop = prop;
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "PoseLib Remove Pose";
+ ot->idname = "POSELIB_OT_pose_remove";
+ ot->description = "Remove nth pose from the active Pose Library";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = poselib_remove_exec;
+ ot->poll = has_poselib_pose_data_for_editing_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_enum(ot->srna, "pose", DummyRNA_NULL_items, 0, "Pose", "The pose to remove");
+ RNA_def_enum_funcs(prop, poselib_stored_pose_itemf);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ ot->prop = prop;
}
static int poselib_rename_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Object *ob = get_poselib_object(C);
- bAction *act = (ob) ? ob->poselib : NULL;
- TimeMarker *marker;
-
- /* check if valid poselib */
- if (act == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Object does not have pose lib data");
- return OPERATOR_CANCELLED;
- }
-
- /* get index (and pointer) of pose to remove */
- marker = BLI_findlink(&act->markers, act->active_marker - 1);
- if (marker == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Invalid index for pose");
- return OPERATOR_CANCELLED;
- }
- else {
- /* use the existing name of the marker as the name, and use the active marker as the one to rename */
- RNA_enum_set(op->ptr, "pose", act->active_marker - 1);
- RNA_string_set(op->ptr, "name", marker->name);
- }
-
- /* part to sync with other similar operators... */
- return WM_operator_props_popup_confirm(C, op, event);
+ Object *ob = get_poselib_object(C);
+ bAction *act = (ob) ? ob->poselib : NULL;
+ TimeMarker *marker;
+
+ /* check if valid poselib */
+ if (act == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Object does not have pose lib data");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* get index (and pointer) of pose to remove */
+ marker = BLI_findlink(&act->markers, act->active_marker - 1);
+ if (marker == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Invalid index for pose");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ /* use the existing name of the marker as the name, and use the active marker as the one to rename */
+ RNA_enum_set(op->ptr, "pose", act->active_marker - 1);
+ RNA_string_set(op->ptr, "name", marker->name);
+ }
+
+ /* part to sync with other similar operators... */
+ return WM_operator_props_popup_confirm(C, op, event);
}
static int poselib_rename_exec(bContext *C, wmOperator *op)
{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bAction *act = (ob) ? ob->poselib : NULL;
- TimeMarker *marker;
- char newname[64];
-
- /* check if valid poselib */
- if (act == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Object does not have pose lib data");
- return OPERATOR_CANCELLED;
- }
-
- /* get index (and pointer) of pose to remove */
- marker = BLI_findlink(&act->markers, RNA_enum_get(op->ptr, "pose"));
- if (marker == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Invalid index for pose");
- return OPERATOR_CANCELLED;
- }
-
- /* get new name */
- RNA_string_get(op->ptr, "name", newname);
-
- /* copy name and validate it */
- BLI_strncpy(marker->name, newname, sizeof(marker->name));
- BLI_uniquename(&act->markers, marker, DATA_("Pose"), '.', offsetof(TimeMarker, name), sizeof(marker->name));
-
- /* send notifiers for this - using keyframe editing notifiers, since action
- * may be being shown in anim editors as active action
- */
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
-
- /* done */
- return OPERATOR_FINISHED;
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bAction *act = (ob) ? ob->poselib : NULL;
+ TimeMarker *marker;
+ char newname[64];
+
+ /* check if valid poselib */
+ if (act == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Object does not have pose lib data");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* get index (and pointer) of pose to remove */
+ marker = BLI_findlink(&act->markers, RNA_enum_get(op->ptr, "pose"));
+ if (marker == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Invalid index for pose");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* get new name */
+ RNA_string_get(op->ptr, "name", newname);
+
+ /* copy name and validate it */
+ BLI_strncpy(marker->name, newname, sizeof(marker->name));
+ BLI_uniquename(
+ &act->markers, marker, DATA_("Pose"), '.', offsetof(TimeMarker, name), sizeof(marker->name));
+
+ /* send notifiers for this - using keyframe editing notifiers, since action
+ * may be being shown in anim editors as active action
+ */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+ /* done */
+ return OPERATOR_FINISHED;
}
void POSELIB_OT_pose_rename(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "PoseLib Rename Pose";
- ot->idname = "POSELIB_OT_pose_rename";
- ot->description = "Rename specified pose from the active Pose Library";
-
- /* api callbacks */
- ot->invoke = poselib_rename_invoke;
- ot->exec = poselib_rename_exec;
- ot->poll = has_poselib_pose_data_for_editing_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- /* NOTE: name not pose is the operator's "main" property,
- * so that it will get activated in the popup for easy renaming */
- ot->prop = RNA_def_string(ot->srna, "name", "RenamedPose", 64, "New Pose Name", "New name for pose");
- prop = RNA_def_enum(ot->srna, "pose", DummyRNA_NULL_items, 0, "Pose", "The pose to rename");
- RNA_def_enum_funcs(prop, poselib_stored_pose_itemf);
- RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "PoseLib Rename Pose";
+ ot->idname = "POSELIB_OT_pose_rename";
+ ot->description = "Rename specified pose from the active Pose Library";
+
+ /* api callbacks */
+ ot->invoke = poselib_rename_invoke;
+ ot->exec = poselib_rename_exec;
+ ot->poll = has_poselib_pose_data_for_editing_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ /* NOTE: name not pose is the operator's "main" property,
+ * so that it will get activated in the popup for easy renaming */
+ ot->prop = RNA_def_string(
+ ot->srna, "name", "RenamedPose", 64, "New Pose Name", "New name for pose");
+ prop = RNA_def_enum(ot->srna, "pose", DummyRNA_NULL_items, 0, "Pose", "The pose to rename");
+ RNA_def_enum_funcs(prop, poselib_stored_pose_itemf);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
}
static int poselib_move_exec(bContext *C, wmOperator *op)
{
- Object *ob = get_poselib_object(C);
- bAction *act = (ob) ? ob->poselib : NULL;
- TimeMarker *marker;
- int marker_index;
- int dir;
- PropertyRNA *prop;
-
- /* check if valid poselib */
- if (act == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Object does not have pose lib data");
- return OPERATOR_CANCELLED;
- }
-
- prop = RNA_struct_find_property(op->ptr, "pose");
- if (RNA_property_is_set(op->ptr, prop)) {
- marker_index = RNA_property_enum_get(op->ptr, prop);
- }
- else {
- marker_index = act->active_marker - 1;
- }
-
- /* get index (and pointer) of pose to remove */
- marker = BLI_findlink(&act->markers, marker_index);
- if (marker == NULL) {
- BKE_reportf(op->reports, RPT_ERROR, "Invalid pose specified %d", marker_index);
- return OPERATOR_CANCELLED;
- }
-
- dir = RNA_enum_get(op->ptr, "direction");
-
- /* move pose */
- if (BLI_listbase_link_move(&act->markers, marker, dir)) {
- act->active_marker = marker_index + dir + 1;
-
- /* send notifiers for this - using keyframe editing notifiers, since action
- * may be being shown in anim editors as active action
- */
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
- }
- else {
- return OPERATOR_CANCELLED;
- }
-
- /* done */
- return OPERATOR_FINISHED;
+ Object *ob = get_poselib_object(C);
+ bAction *act = (ob) ? ob->poselib : NULL;
+ TimeMarker *marker;
+ int marker_index;
+ int dir;
+ PropertyRNA *prop;
+
+ /* check if valid poselib */
+ if (act == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Object does not have pose lib data");
+ return OPERATOR_CANCELLED;
+ }
+
+ prop = RNA_struct_find_property(op->ptr, "pose");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ marker_index = RNA_property_enum_get(op->ptr, prop);
+ }
+ else {
+ marker_index = act->active_marker - 1;
+ }
+
+ /* get index (and pointer) of pose to remove */
+ marker = BLI_findlink(&act->markers, marker_index);
+ if (marker == NULL) {
+ BKE_reportf(op->reports, RPT_ERROR, "Invalid pose specified %d", marker_index);
+ return OPERATOR_CANCELLED;
+ }
+
+ dir = RNA_enum_get(op->ptr, "direction");
+
+ /* move pose */
+ if (BLI_listbase_link_move(&act->markers, marker, dir)) {
+ act->active_marker = marker_index + dir + 1;
+
+ /* send notifiers for this - using keyframe editing notifiers, since action
+ * may be being shown in anim editors as active action
+ */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* done */
+ return OPERATOR_FINISHED;
}
void POSELIB_OT_pose_move(wmOperatorType *ot)
{
- PropertyRNA *prop;
- static const EnumPropertyItem pose_lib_pose_move[] = {
- {-1, "UP", 0, "Up", ""},
- {1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "PoseLib Move Pose";
- ot->idname = "POSELIB_OT_pose_move";
- ot->description = "Move the pose up or down in the active Pose Library";
-
- /* api callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = poselib_move_exec;
- ot->poll = has_poselib_pose_data_for_editing_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- prop = RNA_def_enum(ot->srna, "pose", DummyRNA_NULL_items, 0, "Pose", "The pose to move");
- RNA_def_enum_funcs(prop, poselib_stored_pose_itemf);
- RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
- ot->prop = prop;
-
- RNA_def_enum(ot->srna, "direction", pose_lib_pose_move, 0, "Direction",
- "Direction to move the chosen pose towards");
+ PropertyRNA *prop;
+ static const EnumPropertyItem pose_lib_pose_move[] = {
+ {-1, "UP", 0, "Up", ""},
+ {1, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "PoseLib Move Pose";
+ ot->idname = "POSELIB_OT_pose_move";
+ ot->description = "Move the pose up or down in the active Pose Library";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = poselib_move_exec;
+ ot->poll = has_poselib_pose_data_for_editing_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_enum(ot->srna, "pose", DummyRNA_NULL_items, 0, "Pose", "The pose to move");
+ RNA_def_enum_funcs(prop, poselib_stored_pose_itemf);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ ot->prop = prop;
+
+ RNA_def_enum(ot->srna,
+ "direction",
+ pose_lib_pose_move,
+ 0,
+ "Direction",
+ "Direction to move the chosen pose towards");
}
-
-
/* ************************************************************* */
/* Pose-Lib Browsing/Previewing Operator */
/* Simple struct for storing settings/data for use during PoseLib preview */
typedef struct tPoseLib_PreviewData {
- /** tPoseLib_Backup structs for restoring poses. */
- ListBase backups;
- /** LinkData structs storing list of poses which match the current search-string. */
- ListBase searchp;
-
- /** active scene. */
- Scene *scene;
- /** active area. */
- ScrArea *sa;
-
- /** RNA-Pointer to Object 'ob' .*/
- PointerRNA rna_ptr;
- /** object to work on. */
- Object *ob;
- /** object's armature data. */
- bArmature *arm;
- /** object's pose. */
- bPose *pose;
- /** poselib to use. */
- bAction *act;
- /** 'active' pose. */
- TimeMarker *marker;
-
- /** total number of elements to work on. */
- int totcount;
-
- /** state of main loop. */
- short state;
- /** redraw/update settings during main loop. */
- short redraw;
- /** flags for various settings. */
- short flag;
-
- /** position of cursor in searchstr (cursor occurs before the item at the nominated index) */
- short search_cursor;
- /** (Part of) Name to search for to filter poses that get shown. */
- char searchstr[64];
- /** Previously set searchstr (from last loop run),
- * so that we can detected when to rebuild searchp. */
- char searchold[64];
-
- /** Info-text to print in header. */
- char headerstr[UI_MAX_DRAW_STR];
+ /** tPoseLib_Backup structs for restoring poses. */
+ ListBase backups;
+ /** LinkData structs storing list of poses which match the current search-string. */
+ ListBase searchp;
+
+ /** active scene. */
+ Scene *scene;
+ /** active area. */
+ ScrArea *sa;
+
+ /** RNA-Pointer to Object 'ob' .*/
+ PointerRNA rna_ptr;
+ /** object to work on. */
+ Object *ob;
+ /** object's armature data. */
+ bArmature *arm;
+ /** object's pose. */
+ bPose *pose;
+ /** poselib to use. */
+ bAction *act;
+ /** 'active' pose. */
+ TimeMarker *marker;
+
+ /** total number of elements to work on. */
+ int totcount;
+
+ /** state of main loop. */
+ short state;
+ /** redraw/update settings during main loop. */
+ short redraw;
+ /** flags for various settings. */
+ short flag;
+
+ /** position of cursor in searchstr (cursor occurs before the item at the nominated index) */
+ short search_cursor;
+ /** (Part of) Name to search for to filter poses that get shown. */
+ char searchstr[64];
+ /** Previously set searchstr (from last loop run),
+ * so that we can detected when to rebuild searchp. */
+ char searchold[64];
+
+ /** Info-text to print in header. */
+ char headerstr[UI_MAX_DRAW_STR];
} tPoseLib_PreviewData;
/* defines for tPoseLib_PreviewData->state values */
enum {
- PL_PREVIEW_ERROR = -1,
- PL_PREVIEW_RUNNING,
- PL_PREVIEW_CONFIRM,
- PL_PREVIEW_CANCEL,
- PL_PREVIEW_RUNONCE,
+ PL_PREVIEW_ERROR = -1,
+ PL_PREVIEW_RUNNING,
+ PL_PREVIEW_CONFIRM,
+ PL_PREVIEW_CANCEL,
+ PL_PREVIEW_RUNONCE,
};
/* defines for tPoseLib_PreviewData->redraw values */
enum {
- PL_PREVIEW_NOREDRAW = 0,
- PL_PREVIEW_REDRAWALL,
- PL_PREVIEW_REDRAWHEADER,
+ PL_PREVIEW_NOREDRAW = 0,
+ PL_PREVIEW_REDRAWALL,
+ PL_PREVIEW_REDRAWHEADER,
};
/* defines for tPoseLib_PreviewData->flag values */
enum {
- PL_PREVIEW_FIRSTTIME = (1 << 0),
- PL_PREVIEW_SHOWORIGINAL = (1 << 1),
- PL_PREVIEW_ANY_BONE_SELECTED = (1 << 2),
+ PL_PREVIEW_FIRSTTIME = (1 << 0),
+ PL_PREVIEW_SHOWORIGINAL = (1 << 1),
+ PL_PREVIEW_ANY_BONE_SELECTED = (1 << 2),
};
/* ---------------------------- */
/* simple struct for storing backup info */
typedef struct tPoseLib_Backup {
- struct tPoseLib_Backup *next, *prev;
+ struct tPoseLib_Backup *next, *prev;
- bPoseChannel *pchan; /* pose channel backups are for */
+ bPoseChannel *pchan; /* pose channel backups are for */
- bPoseChannel olddata; /* copy of pose channel's old data (at start) */
- IDProperty *oldprops; /* copy (needs freeing) of pose channel's properties (at start) */
+ bPoseChannel olddata; /* copy of pose channel's old data (at start) */
+ IDProperty *oldprops; /* copy (needs freeing) of pose channel's properties (at start) */
} tPoseLib_Backup;
/* Makes a copy of the current pose for restoration purposes - doesn't do constraints currently */
static void poselib_backup_posecopy(tPoseLib_PreviewData *pld)
{
- bActionGroup *agrp;
- bPoseChannel *pchan;
- bool selected = false;
-
- /* determine whether any bone is selected. */
- LISTBASE_FOREACH (bPoseChannel *, bchan, &pld->pose->chanbase) {
- selected = bchan->bone != NULL && bchan->bone->flag & BONE_SELECTED;
- if (selected) {
- pld->flag |= PL_PREVIEW_ANY_BONE_SELECTED;
- break;
- }
- }
- if (!selected) {
- pld->flag &= ~PL_PREVIEW_ANY_BONE_SELECTED;
- }
-
- /* for each posechannel that has an actionchannel in */
- for (agrp = pld->act->groups.first; agrp; agrp = agrp->next) {
- /* try to find posechannel */
- pchan = BKE_pose_channel_find_name(pld->pose, agrp->name);
-
- /* backup data if available */
- if (pchan) {
- tPoseLib_Backup *plb;
-
- /* store backup */
- plb = MEM_callocN(sizeof(tPoseLib_Backup), "tPoseLib_Backup");
-
- plb->pchan = pchan;
- memcpy(&plb->olddata, plb->pchan, sizeof(bPoseChannel));
-
- if (pchan->prop)
- plb->oldprops = IDP_CopyProperty(pchan->prop);
-
- BLI_addtail(&pld->backups, plb);
-
- /* mark as being affected */
- pld->totcount++;
- }
- }
+ bActionGroup *agrp;
+ bPoseChannel *pchan;
+ bool selected = false;
+
+ /* determine whether any bone is selected. */
+ LISTBASE_FOREACH (bPoseChannel *, bchan, &pld->pose->chanbase) {
+ selected = bchan->bone != NULL && bchan->bone->flag & BONE_SELECTED;
+ if (selected) {
+ pld->flag |= PL_PREVIEW_ANY_BONE_SELECTED;
+ break;
+ }
+ }
+ if (!selected) {
+ pld->flag &= ~PL_PREVIEW_ANY_BONE_SELECTED;
+ }
+
+ /* for each posechannel that has an actionchannel in */
+ for (agrp = pld->act->groups.first; agrp; agrp = agrp->next) {
+ /* try to find posechannel */
+ pchan = BKE_pose_channel_find_name(pld->pose, agrp->name);
+
+ /* backup data if available */
+ if (pchan) {
+ tPoseLib_Backup *plb;
+
+ /* store backup */
+ plb = MEM_callocN(sizeof(tPoseLib_Backup), "tPoseLib_Backup");
+
+ plb->pchan = pchan;
+ memcpy(&plb->olddata, plb->pchan, sizeof(bPoseChannel));
+
+ if (pchan->prop)
+ plb->oldprops = IDP_CopyProperty(pchan->prop);
+
+ BLI_addtail(&pld->backups, plb);
+
+ /* mark as being affected */
+ pld->totcount++;
+ }
+ }
}
/* Restores original pose */
static void poselib_backup_restore(tPoseLib_PreviewData *pld)
{
- tPoseLib_Backup *plb;
+ tPoseLib_Backup *plb;
- for (plb = pld->backups.first; plb; plb = plb->next) {
- /* copy most of data straight back */
- memcpy(plb->pchan, &plb->olddata, sizeof(bPoseChannel));
+ for (plb = pld->backups.first; plb; plb = plb->next) {
+ /* copy most of data straight back */
+ memcpy(plb->pchan, &plb->olddata, sizeof(bPoseChannel));
- /* just overwrite values of properties from the stored copies (there should be some) */
- if (plb->oldprops)
- IDP_SyncGroupValues(plb->pchan->prop, plb->oldprops);
+ /* just overwrite values of properties from the stored copies (there should be some) */
+ if (plb->oldprops)
+ IDP_SyncGroupValues(plb->pchan->prop, plb->oldprops);
- /* TODO: constraints settings aren't restored yet,
- * even though these could change (though not that likely) */
- }
+ /* TODO: constraints settings aren't restored yet,
+ * even though these could change (though not that likely) */
+ }
}
/* Free list of backups, including any side data it may use */
static void poselib_backup_free_data(tPoseLib_PreviewData *pld)
{
- tPoseLib_Backup *plb, *plbn;
+ tPoseLib_Backup *plb, *plbn;
- for (plb = pld->backups.first; plb; plb = plbn) {
- plbn = plb->next;
+ for (plb = pld->backups.first; plb; plb = plbn) {
+ plbn = plb->next;
- /* free custom data */
- if (plb->oldprops) {
- IDP_FreeProperty(plb->oldprops);
- MEM_freeN(plb->oldprops);
- }
+ /* free custom data */
+ if (plb->oldprops) {
+ IDP_FreeProperty(plb->oldprops);
+ MEM_freeN(plb->oldprops);
+ }
- /* free backup element now */
- BLI_freelinkN(&pld->backups, plb);
- }
+ /* free backup element now */
+ BLI_freelinkN(&pld->backups, plb);
+ }
}
/* ---------------------------- */
@@ -993,186 +1011,187 @@ static void poselib_backup_free_data(tPoseLib_PreviewData *pld)
*/
static void poselib_apply_pose(tPoseLib_PreviewData *pld)
{
- PointerRNA *ptr = &pld->rna_ptr;
- bArmature *arm = pld->arm;
- bPose *pose = pld->pose;
- bPoseChannel *pchan;
- bAction *act = pld->act;
- bActionGroup *agrp;
-
- KeyframeEditData ked = {{NULL}};
- KeyframeEditFunc group_ok_cb;
- int frame = 1;
- const bool any_bone_selected = pld->flag & PL_PREVIEW_ANY_BONE_SELECTED;
-
- /* get the frame */
- if (pld->marker)
- frame = pld->marker->frame;
- else
- return;
-
-
- /* init settings for testing groups for keyframes */
- group_ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE);
- ked.f1 = ((float)frame) - 0.5f;
- ked.f2 = ((float)frame) + 0.5f;
-
- /* start applying - only those channels which have a key at this point in time! */
- for (agrp = act->groups.first; agrp; agrp = agrp->next) {
- /* check if group has any keyframes */
- if (ANIM_animchanneldata_keyframes_loop(&ked, NULL, agrp, ALE_GROUP, NULL, group_ok_cb, NULL)) {
- /* has keyframe on this frame, so try to get a PoseChannel with this name */
- pchan = BKE_pose_channel_find_name(pose, agrp->name);
-
- if (pchan) {
- bool ok = 0;
-
- /* check if this bone should get any animation applied */
- if (!any_bone_selected) {
- /* if no bones are selected, then any bone is ok */
- ok = 1;
- }
- else if (pchan->bone) {
- /* only ok if bone is visible and selected */
- if ((pchan->bone->flag & BONE_SELECTED) &&
- (pchan->bone->flag & BONE_HIDDEN_P) == 0 &&
- (pchan->bone->layer & arm->layer))
- {
- ok = 1;
- }
- }
-
- if (ok)
- animsys_evaluate_action_group(ptr, act, agrp, (float)frame);
- }
- }
- }
+ PointerRNA *ptr = &pld->rna_ptr;
+ bArmature *arm = pld->arm;
+ bPose *pose = pld->pose;
+ bPoseChannel *pchan;
+ bAction *act = pld->act;
+ bActionGroup *agrp;
+
+ KeyframeEditData ked = {{NULL}};
+ KeyframeEditFunc group_ok_cb;
+ int frame = 1;
+ const bool any_bone_selected = pld->flag & PL_PREVIEW_ANY_BONE_SELECTED;
+
+ /* get the frame */
+ if (pld->marker)
+ frame = pld->marker->frame;
+ else
+ return;
+
+ /* init settings for testing groups for keyframes */
+ group_ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE);
+ ked.f1 = ((float)frame) - 0.5f;
+ ked.f2 = ((float)frame) + 0.5f;
+
+ /* start applying - only those channels which have a key at this point in time! */
+ for (agrp = act->groups.first; agrp; agrp = agrp->next) {
+ /* check if group has any keyframes */
+ if (ANIM_animchanneldata_keyframes_loop(
+ &ked, NULL, agrp, ALE_GROUP, NULL, group_ok_cb, NULL)) {
+ /* has keyframe on this frame, so try to get a PoseChannel with this name */
+ pchan = BKE_pose_channel_find_name(pose, agrp->name);
+
+ if (pchan) {
+ bool ok = 0;
+
+ /* check if this bone should get any animation applied */
+ if (!any_bone_selected) {
+ /* if no bones are selected, then any bone is ok */
+ ok = 1;
+ }
+ else if (pchan->bone) {
+ /* only ok if bone is visible and selected */
+ if ((pchan->bone->flag & BONE_SELECTED) && (pchan->bone->flag & BONE_HIDDEN_P) == 0 &&
+ (pchan->bone->layer & arm->layer)) {
+ ok = 1;
+ }
+ }
+
+ if (ok)
+ animsys_evaluate_action_group(ptr, act, agrp, (float)frame);
+ }
+ }
+ }
}
/* Auto-keys/tags bones affected by the pose used from the poselib */
static void poselib_keytag_pose(bContext *C, Scene *scene, tPoseLib_PreviewData *pld)
{
- bPose *pose = pld->pose;
- bPoseChannel *pchan;
- bAction *act = pld->act;
- bActionGroup *agrp;
-
- KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID);
- ListBase dsources = {NULL, NULL};
- bool autokey = autokeyframe_cfra_can_key(scene, &pld->ob->id);
- const bool any_bone_selected = pld->flag & PL_PREVIEW_ANY_BONE_SELECTED;
-
- /* start tagging/keying */
- for (agrp = act->groups.first; agrp; agrp = agrp->next) {
- /* only for selected bones unless there aren't any selected, in which case all are included */
- pchan = BKE_pose_channel_find_name(pose, agrp->name);
-
- if (pchan) {
- if (!any_bone_selected || ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))) {
- if (autokey) {
- /* add datasource override for the PoseChannel, to be used later */
- ANIM_relative_keyingset_add_source(&dsources, &pld->ob->id, &RNA_PoseBone, pchan);
-
- /* clear any unkeyed tags */
- if (pchan->bone)
- pchan->bone->flag &= ~BONE_UNKEYED;
- }
- else {
- /* add unkeyed tags */
- if (pchan->bone)
- pchan->bone->flag |= BONE_UNKEYED;
- }
- }
- }
- }
-
- /* perform actual auto-keying now */
- if (autokey) {
- /* insert keyframes for all relevant bones in one go */
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
- BLI_freelistN(&dsources);
- }
-
- /* send notifiers for this */
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ bPose *pose = pld->pose;
+ bPoseChannel *pchan;
+ bAction *act = pld->act;
+ bActionGroup *agrp;
+
+ KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID);
+ ListBase dsources = {NULL, NULL};
+ bool autokey = autokeyframe_cfra_can_key(scene, &pld->ob->id);
+ const bool any_bone_selected = pld->flag & PL_PREVIEW_ANY_BONE_SELECTED;
+
+ /* start tagging/keying */
+ for (agrp = act->groups.first; agrp; agrp = agrp->next) {
+ /* only for selected bones unless there aren't any selected, in which case all are included */
+ pchan = BKE_pose_channel_find_name(pose, agrp->name);
+
+ if (pchan) {
+ if (!any_bone_selected || ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))) {
+ if (autokey) {
+ /* add datasource override for the PoseChannel, to be used later */
+ ANIM_relative_keyingset_add_source(&dsources, &pld->ob->id, &RNA_PoseBone, pchan);
+
+ /* clear any unkeyed tags */
+ if (pchan->bone)
+ pchan->bone->flag &= ~BONE_UNKEYED;
+ }
+ else {
+ /* add unkeyed tags */
+ if (pchan->bone)
+ pchan->bone->flag |= BONE_UNKEYED;
+ }
+ }
+ }
+ }
+
+ /* perform actual auto-keying now */
+ if (autokey) {
+ /* insert keyframes for all relevant bones in one go */
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+ BLI_freelistN(&dsources);
+ }
+
+ /* send notifiers for this */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
}
/* Apply the relevant changes to the pose */
static void poselib_preview_apply(bContext *C, wmOperator *op)
{
- tPoseLib_PreviewData *pld = (tPoseLib_PreviewData *)op->customdata;
-
- /* only recalc pose (and its dependencies) if pose has changed */
- if (pld->redraw == PL_PREVIEW_REDRAWALL) {
- /* don't clear pose if firsttime */
- if ((pld->flag & PL_PREVIEW_FIRSTTIME) == 0)
- poselib_backup_restore(pld);
- else
- pld->flag &= ~PL_PREVIEW_FIRSTTIME;
-
- /* pose should be the right one to draw (unless we're temporarily not showing it) */
- if ((pld->flag & PL_PREVIEW_SHOWORIGINAL) == 0) {
- RNA_int_set(op->ptr, "pose_index", BLI_findindex(&pld->act->markers, pld->marker));
- poselib_apply_pose(pld);
- }
- else
- RNA_int_set(op->ptr, "pose_index", -2); /* -2 means don't apply any pose */
-
- /* old optimize trick... this enforces to bypass the depsgraph
- * - note: code copied from transform_generics.c -> recalcData()
- */
- // FIXME: shouldn't this use the builtin stuff?
- if ((pld->arm->flag & ARM_DELAYDEFORM) == 0)
- DEG_id_tag_update(&pld->ob->id, ID_RECALC_GEOMETRY); /* sets recalc flags */
- else
- BKE_pose_where_is(CTX_data_depsgraph(C), pld->scene, pld->ob);
- }
-
- /* do header print - if interactively previewing */
- if (pld->state == PL_PREVIEW_RUNNING) {
- if (pld->flag & PL_PREVIEW_SHOWORIGINAL) {
- ED_area_status_text(pld->sa, IFACE_("PoseLib Previewing Pose: [Showing Original Pose]"));
- ED_workspace_status_text(C, IFACE_("Use Tab to start previewing poses again"));
- }
- else if (pld->searchstr[0]) {
- char tempstr[65];
- char markern[64];
- short index;
-
- /* get search-string */
- index = pld->search_cursor;
-
- if (index >= 0 && index < sizeof(tempstr) - 1) {
- memcpy(&tempstr[0], &pld->searchstr[0], index);
- tempstr[index] = '|';
- memcpy(&tempstr[index + 1], &pld->searchstr[index], (sizeof(tempstr) - 1) - index);
- }
- else {
- BLI_strncpy(tempstr, pld->searchstr, sizeof(tempstr));
- }
-
- /* get marker name */
- BLI_strncpy(markern, pld->marker ? pld->marker->name : "No Matches", sizeof(markern));
-
- BLI_snprintf(pld->headerstr, sizeof(pld->headerstr),
- IFACE_("PoseLib Previewing Pose: Filter - [%s] | "
- "Current Pose - \"%s\""),
- tempstr, markern);
- ED_area_status_text(pld->sa, pld->headerstr);
- ED_workspace_status_text(C, IFACE_("Use ScrollWheel or PageUp/Down to change pose"));
- }
- else {
- BLI_snprintf(pld->headerstr, sizeof(pld->headerstr),
- IFACE_("PoseLib Previewing Pose: \"%s\""),
- pld->marker->name);
- ED_area_status_text(pld->sa, pld->headerstr);
- ED_workspace_status_text(C, NULL);
- }
- }
-
- /* request drawing of view + clear redraw flag */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, pld->ob);
- pld->redraw = PL_PREVIEW_NOREDRAW;
+ tPoseLib_PreviewData *pld = (tPoseLib_PreviewData *)op->customdata;
+
+ /* only recalc pose (and its dependencies) if pose has changed */
+ if (pld->redraw == PL_PREVIEW_REDRAWALL) {
+ /* don't clear pose if firsttime */
+ if ((pld->flag & PL_PREVIEW_FIRSTTIME) == 0)
+ poselib_backup_restore(pld);
+ else
+ pld->flag &= ~PL_PREVIEW_FIRSTTIME;
+
+ /* pose should be the right one to draw (unless we're temporarily not showing it) */
+ if ((pld->flag & PL_PREVIEW_SHOWORIGINAL) == 0) {
+ RNA_int_set(op->ptr, "pose_index", BLI_findindex(&pld->act->markers, pld->marker));
+ poselib_apply_pose(pld);
+ }
+ else
+ RNA_int_set(op->ptr, "pose_index", -2); /* -2 means don't apply any pose */
+
+ /* old optimize trick... this enforces to bypass the depsgraph
+ * - note: code copied from transform_generics.c -> recalcData()
+ */
+ // FIXME: shouldn't this use the builtin stuff?
+ if ((pld->arm->flag & ARM_DELAYDEFORM) == 0)
+ DEG_id_tag_update(&pld->ob->id, ID_RECALC_GEOMETRY); /* sets recalc flags */
+ else
+ BKE_pose_where_is(CTX_data_depsgraph(C), pld->scene, pld->ob);
+ }
+
+ /* do header print - if interactively previewing */
+ if (pld->state == PL_PREVIEW_RUNNING) {
+ if (pld->flag & PL_PREVIEW_SHOWORIGINAL) {
+ ED_area_status_text(pld->sa, IFACE_("PoseLib Previewing Pose: [Showing Original Pose]"));
+ ED_workspace_status_text(C, IFACE_("Use Tab to start previewing poses again"));
+ }
+ else if (pld->searchstr[0]) {
+ char tempstr[65];
+ char markern[64];
+ short index;
+
+ /* get search-string */
+ index = pld->search_cursor;
+
+ if (index >= 0 && index < sizeof(tempstr) - 1) {
+ memcpy(&tempstr[0], &pld->searchstr[0], index);
+ tempstr[index] = '|';
+ memcpy(&tempstr[index + 1], &pld->searchstr[index], (sizeof(tempstr) - 1) - index);
+ }
+ else {
+ BLI_strncpy(tempstr, pld->searchstr, sizeof(tempstr));
+ }
+
+ /* get marker name */
+ BLI_strncpy(markern, pld->marker ? pld->marker->name : "No Matches", sizeof(markern));
+
+ BLI_snprintf(pld->headerstr,
+ sizeof(pld->headerstr),
+ IFACE_("PoseLib Previewing Pose: Filter - [%s] | "
+ "Current Pose - \"%s\""),
+ tempstr,
+ markern);
+ ED_area_status_text(pld->sa, pld->headerstr);
+ ED_workspace_status_text(C, IFACE_("Use ScrollWheel or PageUp/Down to change pose"));
+ }
+ else {
+ BLI_snprintf(pld->headerstr,
+ sizeof(pld->headerstr),
+ IFACE_("PoseLib Previewing Pose: \"%s\""),
+ pld->marker->name);
+ ED_area_status_text(pld->sa, pld->headerstr);
+ ED_workspace_status_text(C, NULL);
+ }
+ }
+
+ /* request drawing of view + clear redraw flag */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, pld->ob);
+ pld->redraw = PL_PREVIEW_NOREDRAW;
}
/* ---------------------------- */
@@ -1182,351 +1201,373 @@ static void poselib_preview_apply(bContext *C, wmOperator *op)
*/
static void poselib_preview_get_next(tPoseLib_PreviewData *pld, int step)
{
- /* stop if not going anywhere, as we assume that there is a direction to move in */
- if (step == 0)
- return;
-
- /* search-string dictates a special approach */
- if (pld->searchstr[0]) {
- TimeMarker *marker;
- LinkData *ld, *ldn, *ldc;
-
- /* free and rebuild if needed (i.e. if search-str changed) */
- if (!STREQ(pld->searchstr, pld->searchold)) {
- /* free list of temporary search matches */
- BLI_freelistN(&pld->searchp);
-
- /* generate a new list of search matches */
- for (marker = pld->act->markers.first; marker; marker = marker->next) {
- /* does the name partially match?
- * - don't worry about case, to make it easier for users to quickly input a name (or
- * part of one), which is the whole point of this feature
- */
- if (BLI_strcasestr(marker->name, pld->searchstr)) {
- /* make link-data to store reference to it */
- ld = MEM_callocN(sizeof(LinkData), "PoseMatch");
- ld->data = marker;
- BLI_addtail(&pld->searchp, ld);
- }
- }
-
- /* set current marker to NULL (so that we start from first) */
- pld->marker = NULL;
- }
-
- /* check if any matches */
- if (BLI_listbase_is_empty(&pld->searchp)) {
- pld->marker = NULL;
- return;
- }
-
- /* find first match */
- for (ldc = pld->searchp.first; ldc; ldc = ldc->next) {
- if (ldc->data == pld->marker)
- break;
- }
- if (ldc == NULL)
- ldc = pld->searchp.first;
-
- /* Loop through the matches in a cyclic fashion, incrementing/decrementing step as appropriate
- * until step == 0. At this point, marker should be the correct marker.
- */
- if (step > 0) {
- for (ld = ldc; ld && step; ld = ldn, step--)
- ldn = (ld->next) ? ld->next : pld->searchp.first;
- }
- else {
- for (ld = ldc; ld && step; ld = ldn, step++)
- ldn = (ld->prev) ? ld->prev : pld->searchp.last;
- }
-
- /* set marker */
- if (ld)
- pld->marker = ld->data;
- }
- else {
- TimeMarker *marker, *next;
-
- /* if no marker, because we just ended searching, then set that to the start of the list */
- if (pld->marker == NULL)
- pld->marker = pld->act->markers.first;
-
- /* Loop through the markers in a cyclic fashion, incrementing/decrementing step as appropriate
- * until step == 0. At this point, marker should be the correct marker.
- */
- if (step > 0) {
- for (marker = pld->marker; marker && step; marker = next, step--)
- next = (marker->next) ? marker->next : pld->act->markers.first;
- }
- else {
- for (marker = pld->marker; marker && step; marker = next, step++)
- next = (marker->prev) ? marker->prev : pld->act->markers.last;
- }
-
- /* it should be fairly impossible for marker to be NULL */
- if (marker)
- pld->marker = marker;
- }
+ /* stop if not going anywhere, as we assume that there is a direction to move in */
+ if (step == 0)
+ return;
+
+ /* search-string dictates a special approach */
+ if (pld->searchstr[0]) {
+ TimeMarker *marker;
+ LinkData *ld, *ldn, *ldc;
+
+ /* free and rebuild if needed (i.e. if search-str changed) */
+ if (!STREQ(pld->searchstr, pld->searchold)) {
+ /* free list of temporary search matches */
+ BLI_freelistN(&pld->searchp);
+
+ /* generate a new list of search matches */
+ for (marker = pld->act->markers.first; marker; marker = marker->next) {
+ /* does the name partially match?
+ * - don't worry about case, to make it easier for users to quickly input a name (or
+ * part of one), which is the whole point of this feature
+ */
+ if (BLI_strcasestr(marker->name, pld->searchstr)) {
+ /* make link-data to store reference to it */
+ ld = MEM_callocN(sizeof(LinkData), "PoseMatch");
+ ld->data = marker;
+ BLI_addtail(&pld->searchp, ld);
+ }
+ }
+
+ /* set current marker to NULL (so that we start from first) */
+ pld->marker = NULL;
+ }
+
+ /* check if any matches */
+ if (BLI_listbase_is_empty(&pld->searchp)) {
+ pld->marker = NULL;
+ return;
+ }
+
+ /* find first match */
+ for (ldc = pld->searchp.first; ldc; ldc = ldc->next) {
+ if (ldc->data == pld->marker)
+ break;
+ }
+ if (ldc == NULL)
+ ldc = pld->searchp.first;
+
+ /* Loop through the matches in a cyclic fashion, incrementing/decrementing step as appropriate
+ * until step == 0. At this point, marker should be the correct marker.
+ */
+ if (step > 0) {
+ for (ld = ldc; ld && step; ld = ldn, step--)
+ ldn = (ld->next) ? ld->next : pld->searchp.first;
+ }
+ else {
+ for (ld = ldc; ld && step; ld = ldn, step++)
+ ldn = (ld->prev) ? ld->prev : pld->searchp.last;
+ }
+
+ /* set marker */
+ if (ld)
+ pld->marker = ld->data;
+ }
+ else {
+ TimeMarker *marker, *next;
+
+ /* if no marker, because we just ended searching, then set that to the start of the list */
+ if (pld->marker == NULL)
+ pld->marker = pld->act->markers.first;
+
+ /* Loop through the markers in a cyclic fashion, incrementing/decrementing step as appropriate
+ * until step == 0. At this point, marker should be the correct marker.
+ */
+ if (step > 0) {
+ for (marker = pld->marker; marker && step; marker = next, step--)
+ next = (marker->next) ? marker->next : pld->act->markers.first;
+ }
+ else {
+ for (marker = pld->marker; marker && step; marker = next, step++)
+ next = (marker->prev) ? marker->prev : pld->act->markers.last;
+ }
+
+ /* it should be fairly impossible for marker to be NULL */
+ if (marker)
+ pld->marker = marker;
+ }
}
/* specially handle events for searching */
-static void poselib_preview_handle_search(tPoseLib_PreviewData *pld, unsigned short event, char ascii)
+static void poselib_preview_handle_search(tPoseLib_PreviewData *pld,
+ unsigned short event,
+ char ascii)
{
- /* try doing some form of string manipulation first */
- switch (event) {
- case BACKSPACEKEY:
- if (pld->searchstr[0] && pld->search_cursor) {
- short len = strlen(pld->searchstr);
- short index = pld->search_cursor;
- short i;
-
- for (i = index; i <= len; i++)
- pld->searchstr[i - 1] = pld->searchstr[i];
-
- pld->search_cursor--;
-
- poselib_preview_get_next(pld, 1);
- pld->redraw = PL_PREVIEW_REDRAWALL;
- return;
- }
- break;
-
- case DELKEY:
- if (pld->searchstr[0] && pld->searchstr[1]) {
- short len = strlen(pld->searchstr);
- short index = pld->search_cursor;
- int i;
-
- if (index < len) {
- for (i = index; i < len; i++)
- pld->searchstr[i] = pld->searchstr[i + 1];
-
- poselib_preview_get_next(pld, 1);
- pld->redraw = PL_PREVIEW_REDRAWALL;
- return;
- }
- }
- break;
- }
-
- if (ascii) {
- /* character to add to the string */
- short index = pld->search_cursor;
- short len = (pld->searchstr[0]) ? strlen(pld->searchstr) : 0;
- short i;
-
- if (len) {
- for (i = len; i > index; i--)
- pld->searchstr[i] = pld->searchstr[i - 1];
- }
- else
- pld->searchstr[1] = 0;
-
- pld->searchstr[index] = ascii;
- pld->search_cursor++;
-
- poselib_preview_get_next(pld, 1);
- pld->redraw = PL_PREVIEW_REDRAWALL;
- }
+ /* try doing some form of string manipulation first */
+ switch (event) {
+ case BACKSPACEKEY:
+ if (pld->searchstr[0] && pld->search_cursor) {
+ short len = strlen(pld->searchstr);
+ short index = pld->search_cursor;
+ short i;
+
+ for (i = index; i <= len; i++)
+ pld->searchstr[i - 1] = pld->searchstr[i];
+
+ pld->search_cursor--;
+
+ poselib_preview_get_next(pld, 1);
+ pld->redraw = PL_PREVIEW_REDRAWALL;
+ return;
+ }
+ break;
+
+ case DELKEY:
+ if (pld->searchstr[0] && pld->searchstr[1]) {
+ short len = strlen(pld->searchstr);
+ short index = pld->search_cursor;
+ int i;
+
+ if (index < len) {
+ for (i = index; i < len; i++)
+ pld->searchstr[i] = pld->searchstr[i + 1];
+
+ poselib_preview_get_next(pld, 1);
+ pld->redraw = PL_PREVIEW_REDRAWALL;
+ return;
+ }
+ }
+ break;
+ }
+
+ if (ascii) {
+ /* character to add to the string */
+ short index = pld->search_cursor;
+ short len = (pld->searchstr[0]) ? strlen(pld->searchstr) : 0;
+ short i;
+
+ if (len) {
+ for (i = len; i > index; i--)
+ pld->searchstr[i] = pld->searchstr[i - 1];
+ }
+ else
+ pld->searchstr[1] = 0;
+
+ pld->searchstr[index] = ascii;
+ pld->search_cursor++;
+
+ poselib_preview_get_next(pld, 1);
+ pld->redraw = PL_PREVIEW_REDRAWALL;
+ }
}
/* handle events for poselib_preview_poses */
static int poselib_preview_handle_event(bContext *UNUSED(C), wmOperator *op, const wmEvent *event)
{
- tPoseLib_PreviewData *pld = op->customdata;
- int ret = OPERATOR_RUNNING_MODAL;
-
- /* only accept 'press' event, and ignore 'release', so that we don't get double actions */
- if (ELEM(event->val, KM_PRESS, KM_NOTHING) == 0) {
- //printf("PoseLib: skipping event with type '%s' and val %d\n", WM_key_event_string(event->type, false), event->val);
- return ret;
- }
-
- /* backup stuff that needs to occur before every operation
- * - make a copy of searchstr, so that we know if cache needs to be rebuilt
- */
- BLI_strncpy(pld->searchold, pld->searchstr, sizeof(pld->searchold));
-
- /* if we're currently showing the original pose, only certain events are handled */
- if (pld->flag & PL_PREVIEW_SHOWORIGINAL) {
- switch (event->type) {
- /* exit - cancel */
- case ESCKEY:
- case RIGHTMOUSE:
- pld->state = PL_PREVIEW_CANCEL;
- break;
-
- /* exit - confirm */
- case LEFTMOUSE:
- case RETKEY:
- case PADENTER:
- case SPACEKEY:
- pld->state = PL_PREVIEW_CONFIRM;
- break;
-
- /* view manipulation */
- /* we add pass through here, so that the operators responsible for these can still run,
- * even though we still maintain control (as RUNNING_MODAL flag is still set too)
- */
- case PAD0: case PAD1: case PAD2: case PAD3: case PAD4:
- case PAD5: case PAD6: case PAD7: case PAD8: case PAD9:
- case PADPLUSKEY: case PADMINUS:
- case MIDDLEMOUSE: case MOUSEMOVE:
- //pld->redraw = PL_PREVIEW_REDRAWHEADER;
- ret = OPERATOR_PASS_THROUGH;
- break;
-
- /* quicky compare to original */
- case TABKEY:
- pld->flag &= ~PL_PREVIEW_SHOWORIGINAL;
- pld->redraw = PL_PREVIEW_REDRAWALL;
- break;
- }
-
- /* EXITS HERE... */
- return ret;
- }
-
- /* NORMAL EVENT HANDLING... */
- /* searching takes priority over normal activity */
- switch (event->type) {
- /* exit - cancel */
- case ESCKEY:
- case RIGHTMOUSE:
- pld->state = PL_PREVIEW_CANCEL;
- break;
-
- /* exit - confirm */
- case LEFTMOUSE:
- case RETKEY:
- case PADENTER:
- case SPACEKEY:
- pld->state = PL_PREVIEW_CONFIRM;
- break;
-
- /* toggle between original pose and poselib pose*/
- case TABKEY:
- pld->flag |= PL_PREVIEW_SHOWORIGINAL;
- pld->redraw = PL_PREVIEW_REDRAWALL;
- break;
-
- /* change to previous pose (cyclic) */
- case PAGEUPKEY:
- case WHEELUPMOUSE:
- poselib_preview_get_next(pld, -1);
- pld->redraw = PL_PREVIEW_REDRAWALL;
- break;
-
- /* change to next pose (cyclic) */
- case PAGEDOWNKEY:
- case WHEELDOWNMOUSE:
- poselib_preview_get_next(pld, 1);
- pld->redraw = PL_PREVIEW_REDRAWALL;
- break;
-
- /* jump 5 poses (cyclic, back) */
- case DOWNARROWKEY:
- poselib_preview_get_next(pld, -5);
- pld->redraw = PL_PREVIEW_REDRAWALL;
- break;
-
- /* jump 5 poses (cyclic, forward) */
- case UPARROWKEY:
- poselib_preview_get_next(pld, 5);
- pld->redraw = PL_PREVIEW_REDRAWALL;
- break;
-
- /* change to next pose or searching cursor control */
- case RIGHTARROWKEY:
- if (pld->searchstr[0]) {
- /* move text-cursor to the right */
- if (pld->search_cursor < strlen(pld->searchstr))
- pld->search_cursor++;
- pld->redraw = PL_PREVIEW_REDRAWHEADER;
- }
- else {
- /* change to next pose (cyclic) */
- poselib_preview_get_next(pld, 1);
- pld->redraw = PL_PREVIEW_REDRAWALL;
- }
- break;
-
- /* change to next pose or searching cursor control */
- case LEFTARROWKEY:
- if (pld->searchstr[0]) {
- /* move text-cursor to the left */
- if (pld->search_cursor)
- pld->search_cursor--;
- pld->redraw = PL_PREVIEW_REDRAWHEADER;
- }
- else {
- /* change to previous pose (cyclic) */
- poselib_preview_get_next(pld, -1);
- pld->redraw = PL_PREVIEW_REDRAWALL;
- }
- break;
-
- /* change to first pose or start of searching string */
- case HOMEKEY:
- if (pld->searchstr[0]) {
- pld->search_cursor = 0;
- pld->redraw = PL_PREVIEW_REDRAWHEADER;
- }
- else {
- /* change to first pose */
- pld->marker = pld->act->markers.first;
- pld->act->active_marker = 1;
-
- pld->redraw = PL_PREVIEW_REDRAWALL;
- }
- break;
-
- /* change to last pose or start of searching string */
- case ENDKEY:
- if (pld->searchstr[0]) {
- pld->search_cursor = strlen(pld->searchstr);
- pld->redraw = PL_PREVIEW_REDRAWHEADER;
- }
- else {
- /* change to last pose */
- pld->marker = pld->act->markers.last;
- pld->act->active_marker = BLI_listbase_count(&pld->act->markers);
-
- pld->redraw = PL_PREVIEW_REDRAWALL;
- }
- break;
-
- /* view manipulation */
- /* we add pass through here, so that the operators responsible for these can still run,
- * even though we still maintain control (as RUNNING_MODAL flag is still set too)
- */
- case MIDDLEMOUSE: case MOUSEMOVE:
- //pld->redraw = PL_PREVIEW_REDRAWHEADER;
- ret = OPERATOR_PASS_THROUGH;
- break;
-
- /* view manipulation, or searching */
- case PAD0: case PAD1: case PAD2: case PAD3: case PAD4:
- case PAD5: case PAD6: case PAD7: case PAD8: case PAD9:
- case PADPLUSKEY: case PADMINUS:
- if (pld->searchstr[0]) {
- /* searching... */
- poselib_preview_handle_search(pld, event->type, event->ascii);
- }
- else {
- /* view manipulation (see above) */
- //pld->redraw = PL_PREVIEW_REDRAWHEADER;
- ret = OPERATOR_PASS_THROUGH;
- }
- break;
-
- /* otherwise, assume that searching might be able to handle it */
- default:
- poselib_preview_handle_search(pld, event->type, event->ascii);
- break;
- }
-
- return ret;
+ tPoseLib_PreviewData *pld = op->customdata;
+ int ret = OPERATOR_RUNNING_MODAL;
+
+ /* only accept 'press' event, and ignore 'release', so that we don't get double actions */
+ if (ELEM(event->val, KM_PRESS, KM_NOTHING) == 0) {
+ //printf("PoseLib: skipping event with type '%s' and val %d\n", WM_key_event_string(event->type, false), event->val);
+ return ret;
+ }
+
+ /* backup stuff that needs to occur before every operation
+ * - make a copy of searchstr, so that we know if cache needs to be rebuilt
+ */
+ BLI_strncpy(pld->searchold, pld->searchstr, sizeof(pld->searchold));
+
+ /* if we're currently showing the original pose, only certain events are handled */
+ if (pld->flag & PL_PREVIEW_SHOWORIGINAL) {
+ switch (event->type) {
+ /* exit - cancel */
+ case ESCKEY:
+ case RIGHTMOUSE:
+ pld->state = PL_PREVIEW_CANCEL;
+ break;
+
+ /* exit - confirm */
+ case LEFTMOUSE:
+ case RETKEY:
+ case PADENTER:
+ case SPACEKEY:
+ pld->state = PL_PREVIEW_CONFIRM;
+ break;
+
+ /* view manipulation */
+ /* we add pass through here, so that the operators responsible for these can still run,
+ * even though we still maintain control (as RUNNING_MODAL flag is still set too)
+ */
+ case PAD0:
+ case PAD1:
+ case PAD2:
+ case PAD3:
+ case PAD4:
+ case PAD5:
+ case PAD6:
+ case PAD7:
+ case PAD8:
+ case PAD9:
+ case PADPLUSKEY:
+ case PADMINUS:
+ case MIDDLEMOUSE:
+ case MOUSEMOVE:
+ //pld->redraw = PL_PREVIEW_REDRAWHEADER;
+ ret = OPERATOR_PASS_THROUGH;
+ break;
+
+ /* quicky compare to original */
+ case TABKEY:
+ pld->flag &= ~PL_PREVIEW_SHOWORIGINAL;
+ pld->redraw = PL_PREVIEW_REDRAWALL;
+ break;
+ }
+
+ /* EXITS HERE... */
+ return ret;
+ }
+
+ /* NORMAL EVENT HANDLING... */
+ /* searching takes priority over normal activity */
+ switch (event->type) {
+ /* exit - cancel */
+ case ESCKEY:
+ case RIGHTMOUSE:
+ pld->state = PL_PREVIEW_CANCEL;
+ break;
+
+ /* exit - confirm */
+ case LEFTMOUSE:
+ case RETKEY:
+ case PADENTER:
+ case SPACEKEY:
+ pld->state = PL_PREVIEW_CONFIRM;
+ break;
+
+ /* toggle between original pose and poselib pose*/
+ case TABKEY:
+ pld->flag |= PL_PREVIEW_SHOWORIGINAL;
+ pld->redraw = PL_PREVIEW_REDRAWALL;
+ break;
+
+ /* change to previous pose (cyclic) */
+ case PAGEUPKEY:
+ case WHEELUPMOUSE:
+ poselib_preview_get_next(pld, -1);
+ pld->redraw = PL_PREVIEW_REDRAWALL;
+ break;
+
+ /* change to next pose (cyclic) */
+ case PAGEDOWNKEY:
+ case WHEELDOWNMOUSE:
+ poselib_preview_get_next(pld, 1);
+ pld->redraw = PL_PREVIEW_REDRAWALL;
+ break;
+
+ /* jump 5 poses (cyclic, back) */
+ case DOWNARROWKEY:
+ poselib_preview_get_next(pld, -5);
+ pld->redraw = PL_PREVIEW_REDRAWALL;
+ break;
+
+ /* jump 5 poses (cyclic, forward) */
+ case UPARROWKEY:
+ poselib_preview_get_next(pld, 5);
+ pld->redraw = PL_PREVIEW_REDRAWALL;
+ break;
+
+ /* change to next pose or searching cursor control */
+ case RIGHTARROWKEY:
+ if (pld->searchstr[0]) {
+ /* move text-cursor to the right */
+ if (pld->search_cursor < strlen(pld->searchstr))
+ pld->search_cursor++;
+ pld->redraw = PL_PREVIEW_REDRAWHEADER;
+ }
+ else {
+ /* change to next pose (cyclic) */
+ poselib_preview_get_next(pld, 1);
+ pld->redraw = PL_PREVIEW_REDRAWALL;
+ }
+ break;
+
+ /* change to next pose or searching cursor control */
+ case LEFTARROWKEY:
+ if (pld->searchstr[0]) {
+ /* move text-cursor to the left */
+ if (pld->search_cursor)
+ pld->search_cursor--;
+ pld->redraw = PL_PREVIEW_REDRAWHEADER;
+ }
+ else {
+ /* change to previous pose (cyclic) */
+ poselib_preview_get_next(pld, -1);
+ pld->redraw = PL_PREVIEW_REDRAWALL;
+ }
+ break;
+
+ /* change to first pose or start of searching string */
+ case HOMEKEY:
+ if (pld->searchstr[0]) {
+ pld->search_cursor = 0;
+ pld->redraw = PL_PREVIEW_REDRAWHEADER;
+ }
+ else {
+ /* change to first pose */
+ pld->marker = pld->act->markers.first;
+ pld->act->active_marker = 1;
+
+ pld->redraw = PL_PREVIEW_REDRAWALL;
+ }
+ break;
+
+ /* change to last pose or start of searching string */
+ case ENDKEY:
+ if (pld->searchstr[0]) {
+ pld->search_cursor = strlen(pld->searchstr);
+ pld->redraw = PL_PREVIEW_REDRAWHEADER;
+ }
+ else {
+ /* change to last pose */
+ pld->marker = pld->act->markers.last;
+ pld->act->active_marker = BLI_listbase_count(&pld->act->markers);
+
+ pld->redraw = PL_PREVIEW_REDRAWALL;
+ }
+ break;
+
+ /* view manipulation */
+ /* we add pass through here, so that the operators responsible for these can still run,
+ * even though we still maintain control (as RUNNING_MODAL flag is still set too)
+ */
+ case MIDDLEMOUSE:
+ case MOUSEMOVE:
+ //pld->redraw = PL_PREVIEW_REDRAWHEADER;
+ ret = OPERATOR_PASS_THROUGH;
+ break;
+
+ /* view manipulation, or searching */
+ case PAD0:
+ case PAD1:
+ case PAD2:
+ case PAD3:
+ case PAD4:
+ case PAD5:
+ case PAD6:
+ case PAD7:
+ case PAD8:
+ case PAD9:
+ case PADPLUSKEY:
+ case PADMINUS:
+ if (pld->searchstr[0]) {
+ /* searching... */
+ poselib_preview_handle_search(pld, event->type, event->ascii);
+ }
+ else {
+ /* view manipulation (see above) */
+ //pld->redraw = PL_PREVIEW_REDRAWHEADER;
+ ret = OPERATOR_PASS_THROUGH;
+ }
+ break;
+
+ /* otherwise, assume that searching might be able to handle it */
+ default:
+ poselib_preview_handle_search(pld, event->type, event->ascii);
+ break;
+ }
+
+ return ret;
}
/* ---------------------------- */
@@ -1534,277 +1575,295 @@ static int poselib_preview_handle_event(bContext *UNUSED(C), wmOperator *op, con
/* Init PoseLib Previewing data */
static void poselib_preview_init_data(bContext *C, wmOperator *op)
{
- tPoseLib_PreviewData *pld;
- Object *ob = get_poselib_object(C);
- int pose_index = RNA_int_get(op->ptr, "pose_index");
-
- /* set up preview state info */
- op->customdata = pld = MEM_callocN(sizeof(tPoseLib_PreviewData), "PoseLib Preview Data");
-
- /* get basic data */
- pld->ob = ob;
- pld->arm = (ob) ? (ob->data) : NULL;
- pld->pose = (ob) ? (ob->pose) : NULL;
- pld->act = (ob) ? (ob->poselib) : NULL;
-
- pld->scene = CTX_data_scene(C);
- pld->sa = CTX_wm_area(C);
-
- /* get starting pose based on RNA-props for this operator */
- if (pose_index == -1)
- pld->marker = poselib_get_active_pose(pld->act);
- else if (pose_index == -2)
- pld->flag |= PL_PREVIEW_SHOWORIGINAL;
- else
- pld->marker = (pld->act) ? BLI_findlink(&pld->act->markers, pose_index) : NULL;
-
- /* check if valid poselib */
- if (ELEM(NULL, pld->ob, pld->pose, pld->arm)) {
- BKE_report(op->reports, RPT_ERROR, "Pose lib is only for armatures in pose mode");
- pld->state = PL_PREVIEW_ERROR;
- return;
- }
- if (pld->act == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Object does not have a valid pose lib");
- pld->state = PL_PREVIEW_ERROR;
- return;
- }
- if (pld->marker == NULL) {
- if (pld->act->markers.first) {
- /* just use first one then... */
- pld->marker = pld->act->markers.first;
- if (pose_index > -2)
- BKE_report(op->reports, RPT_WARNING, "Pose lib had no active pose");
- }
- else {
- BKE_report(op->reports, RPT_ERROR, "Pose lib has no poses to preview/apply");
- pld->state = PL_PREVIEW_ERROR;
- return;
- }
- }
-
- /* get ID pointer for applying poses */
- RNA_id_pointer_create(&ob->id, &pld->rna_ptr);
-
- /* make backups for restoring pose */
- poselib_backup_posecopy(pld);
-
- /* set flags for running */
- pld->state = PL_PREVIEW_RUNNING;
- pld->redraw = PL_PREVIEW_REDRAWALL;
- pld->flag |= PL_PREVIEW_FIRSTTIME;
-
- /* set depsgraph flags */
- /* make sure the lock is set OK, unlock can be accidentally saved? */
- pld->pose->flag |= POSE_LOCKED;
- pld->pose->flag &= ~POSE_DO_UNLOCK;
-
- /* clear strings + search */
- pld->headerstr[0] = pld->searchstr[0] = pld->searchold[0] = '\0';
- pld->search_cursor = 0;
+ tPoseLib_PreviewData *pld;
+ Object *ob = get_poselib_object(C);
+ int pose_index = RNA_int_get(op->ptr, "pose_index");
+
+ /* set up preview state info */
+ op->customdata = pld = MEM_callocN(sizeof(tPoseLib_PreviewData), "PoseLib Preview Data");
+
+ /* get basic data */
+ pld->ob = ob;
+ pld->arm = (ob) ? (ob->data) : NULL;
+ pld->pose = (ob) ? (ob->pose) : NULL;
+ pld->act = (ob) ? (ob->poselib) : NULL;
+
+ pld->scene = CTX_data_scene(C);
+ pld->sa = CTX_wm_area(C);
+
+ /* get starting pose based on RNA-props for this operator */
+ if (pose_index == -1)
+ pld->marker = poselib_get_active_pose(pld->act);
+ else if (pose_index == -2)
+ pld->flag |= PL_PREVIEW_SHOWORIGINAL;
+ else
+ pld->marker = (pld->act) ? BLI_findlink(&pld->act->markers, pose_index) : NULL;
+
+ /* check if valid poselib */
+ if (ELEM(NULL, pld->ob, pld->pose, pld->arm)) {
+ BKE_report(op->reports, RPT_ERROR, "Pose lib is only for armatures in pose mode");
+ pld->state = PL_PREVIEW_ERROR;
+ return;
+ }
+ if (pld->act == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Object does not have a valid pose lib");
+ pld->state = PL_PREVIEW_ERROR;
+ return;
+ }
+ if (pld->marker == NULL) {
+ if (pld->act->markers.first) {
+ /* just use first one then... */
+ pld->marker = pld->act->markers.first;
+ if (pose_index > -2)
+ BKE_report(op->reports, RPT_WARNING, "Pose lib had no active pose");
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "Pose lib has no poses to preview/apply");
+ pld->state = PL_PREVIEW_ERROR;
+ return;
+ }
+ }
+
+ /* get ID pointer for applying poses */
+ RNA_id_pointer_create(&ob->id, &pld->rna_ptr);
+
+ /* make backups for restoring pose */
+ poselib_backup_posecopy(pld);
+
+ /* set flags for running */
+ pld->state = PL_PREVIEW_RUNNING;
+ pld->redraw = PL_PREVIEW_REDRAWALL;
+ pld->flag |= PL_PREVIEW_FIRSTTIME;
+
+ /* set depsgraph flags */
+ /* make sure the lock is set OK, unlock can be accidentally saved? */
+ pld->pose->flag |= POSE_LOCKED;
+ pld->pose->flag &= ~POSE_DO_UNLOCK;
+
+ /* clear strings + search */
+ pld->headerstr[0] = pld->searchstr[0] = pld->searchold[0] = '\0';
+ pld->search_cursor = 0;
}
/* After previewing poses */
static void poselib_preview_cleanup(bContext *C, wmOperator *op)
{
- tPoseLib_PreviewData *pld = (tPoseLib_PreviewData *)op->customdata;
- Scene *scene = pld->scene;
- Object *ob = pld->ob;
- bPose *pose = pld->pose;
- bArmature *arm = pld->arm;
- bAction *act = pld->act;
- TimeMarker *marker = pld->marker;
-
- /* redraw the header so that it doesn't show any of our stuff anymore */
- ED_area_status_text(pld->sa, NULL);
- ED_workspace_status_text(C, NULL);
-
- /* this signal does one recalc on pose, then unlocks, so ESC or edit will work */
- pose->flag |= POSE_DO_UNLOCK;
-
- /* clear pose if canceled */
- if (pld->state == PL_PREVIEW_CANCEL) {
- poselib_backup_restore(pld);
-
- /* old optimize trick... this enforces to bypass the depgraph
- * - note: code copied from transform_generics.c -> recalcData()
- */
- if ((arm->flag & ARM_DELAYDEFORM) == 0)
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); /* sets recalc flags */
- else
- BKE_pose_where_is(CTX_data_depsgraph(C), scene, ob);
- }
- else if (pld->state == PL_PREVIEW_CONFIRM) {
- /* tag poses as appropriate */
- poselib_keytag_pose(C, scene, pld);
-
- /* change active pose setting */
- act->active_marker = BLI_findindex(&act->markers, marker) + 1;
- action_set_activemarker(act, marker, NULL);
-
- /* Update event for pose and deformation children */
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
-
- /* updates */
- if (IS_AUTOKEY_MODE(scene, NORMAL)) {
- //remake_action_ipos(ob->action);
- }
- else
- BKE_pose_where_is(CTX_data_depsgraph(C), scene, ob);
- }
-
- /* Request final redraw of the view. */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, pld->ob);
-
- /* free memory used for backups and searching */
- poselib_backup_free_data(pld);
- BLI_freelistN(&pld->searchp);
-
- /* free temp data for operator */
- MEM_freeN(pld);
- op->customdata = NULL;
+ tPoseLib_PreviewData *pld = (tPoseLib_PreviewData *)op->customdata;
+ Scene *scene = pld->scene;
+ Object *ob = pld->ob;
+ bPose *pose = pld->pose;
+ bArmature *arm = pld->arm;
+ bAction *act = pld->act;
+ TimeMarker *marker = pld->marker;
+
+ /* redraw the header so that it doesn't show any of our stuff anymore */
+ ED_area_status_text(pld->sa, NULL);
+ ED_workspace_status_text(C, NULL);
+
+ /* this signal does one recalc on pose, then unlocks, so ESC or edit will work */
+ pose->flag |= POSE_DO_UNLOCK;
+
+ /* clear pose if canceled */
+ if (pld->state == PL_PREVIEW_CANCEL) {
+ poselib_backup_restore(pld);
+
+ /* old optimize trick... this enforces to bypass the depgraph
+ * - note: code copied from transform_generics.c -> recalcData()
+ */
+ if ((arm->flag & ARM_DELAYDEFORM) == 0)
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); /* sets recalc flags */
+ else
+ BKE_pose_where_is(CTX_data_depsgraph(C), scene, ob);
+ }
+ else if (pld->state == PL_PREVIEW_CONFIRM) {
+ /* tag poses as appropriate */
+ poselib_keytag_pose(C, scene, pld);
+
+ /* change active pose setting */
+ act->active_marker = BLI_findindex(&act->markers, marker) + 1;
+ action_set_activemarker(act, marker, NULL);
+
+ /* Update event for pose and deformation children */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+
+ /* updates */
+ if (IS_AUTOKEY_MODE(scene, NORMAL)) {
+ //remake_action_ipos(ob->action);
+ }
+ else
+ BKE_pose_where_is(CTX_data_depsgraph(C), scene, ob);
+ }
+
+ /* Request final redraw of the view. */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, pld->ob);
+
+ /* free memory used for backups and searching */
+ poselib_backup_free_data(pld);
+ BLI_freelistN(&pld->searchp);
+
+ /* free temp data for operator */
+ MEM_freeN(pld);
+ op->customdata = NULL;
}
/* End previewing operation */
static int poselib_preview_exit(bContext *C, wmOperator *op)
{
- tPoseLib_PreviewData *pld = op->customdata;
- int exit_state = pld->state;
+ tPoseLib_PreviewData *pld = op->customdata;
+ int exit_state = pld->state;
- /* finish up */
- poselib_preview_cleanup(C, op);
+ /* finish up */
+ poselib_preview_cleanup(C, op);
- if (ELEM(exit_state, PL_PREVIEW_CANCEL, PL_PREVIEW_ERROR))
- return OPERATOR_CANCELLED;
- else
- return OPERATOR_FINISHED;
+ if (ELEM(exit_state, PL_PREVIEW_CANCEL, PL_PREVIEW_ERROR))
+ return OPERATOR_CANCELLED;
+ else
+ return OPERATOR_FINISHED;
}
/* Cancel previewing operation (called when exiting Blender) */
static void poselib_preview_cancel(bContext *C, wmOperator *op)
{
- poselib_preview_exit(C, op);
+ poselib_preview_exit(C, op);
}
/* main modal status check */
static int poselib_preview_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- tPoseLib_PreviewData *pld = op->customdata;
- int ret;
+ tPoseLib_PreviewData *pld = op->customdata;
+ int ret;
- /* 1) check state to see if we're still running */
- if (pld->state != PL_PREVIEW_RUNNING)
- return poselib_preview_exit(C, op);
+ /* 1) check state to see if we're still running */
+ if (pld->state != PL_PREVIEW_RUNNING)
+ return poselib_preview_exit(C, op);
- /* 2) handle events */
- ret = poselib_preview_handle_event(C, op, event);
+ /* 2) handle events */
+ ret = poselib_preview_handle_event(C, op, event);
- /* 3) apply changes and redraw, otherwise, confirming goes wrong */
- if (pld->redraw)
- poselib_preview_apply(C, op);
+ /* 3) apply changes and redraw, otherwise, confirming goes wrong */
+ if (pld->redraw)
+ poselib_preview_apply(C, op);
- return ret;
+ return ret;
}
/* Modal Operator init */
static int poselib_preview_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- tPoseLib_PreviewData *pld;
+ tPoseLib_PreviewData *pld;
- /* check if everything is ok, and init settings for modal operator */
- poselib_preview_init_data(C, op);
- pld = (tPoseLib_PreviewData *)op->customdata;
+ /* check if everything is ok, and init settings for modal operator */
+ poselib_preview_init_data(C, op);
+ pld = (tPoseLib_PreviewData *)op->customdata;
- if (pld->state == PL_PREVIEW_ERROR) {
- /* an error occurred, so free temp mem used */
- poselib_preview_cleanup(C, op);
- return OPERATOR_CANCELLED;
- }
+ if (pld->state == PL_PREVIEW_ERROR) {
+ /* an error occurred, so free temp mem used */
+ poselib_preview_cleanup(C, op);
+ return OPERATOR_CANCELLED;
+ }
- /* do initial apply to have something to look at */
- poselib_preview_apply(C, op);
+ /* do initial apply to have something to look at */
+ poselib_preview_apply(C, op);
- /* add temp handler if we're running as a modal operator */
- WM_event_add_modal_handler(C, op);
+ /* add temp handler if we're running as a modal operator */
+ WM_event_add_modal_handler(C, op);
- return OPERATOR_RUNNING_MODAL;
+ return OPERATOR_RUNNING_MODAL;
}
/* Repeat operator */
static int poselib_preview_exec(bContext *C, wmOperator *op)
{
- tPoseLib_PreviewData *pld;
+ tPoseLib_PreviewData *pld;
- /* check if everything is ok, and init settings for modal operator */
- poselib_preview_init_data(C, op);
- pld = (tPoseLib_PreviewData *)op->customdata;
+ /* check if everything is ok, and init settings for modal operator */
+ poselib_preview_init_data(C, op);
+ pld = (tPoseLib_PreviewData *)op->customdata;
- if (pld->state == PL_PREVIEW_ERROR) {
- /* an error occurred, so free temp mem used */
- poselib_preview_cleanup(C, op);
- return OPERATOR_CANCELLED;
- }
+ if (pld->state == PL_PREVIEW_ERROR) {
+ /* an error occurred, so free temp mem used */
+ poselib_preview_cleanup(C, op);
+ return OPERATOR_CANCELLED;
+ }
- /* the exec() callback is effectively a 'run-once' scenario, so set the state to that
- * so that everything draws correctly
- */
- pld->state = PL_PREVIEW_RUNONCE;
+ /* the exec() callback is effectively a 'run-once' scenario, so set the state to that
+ * so that everything draws correctly
+ */
+ pld->state = PL_PREVIEW_RUNONCE;
- /* apply the active pose */
- poselib_preview_apply(C, op);
+ /* apply the active pose */
+ poselib_preview_apply(C, op);
- /* now, set the status to exit */
- pld->state = PL_PREVIEW_CONFIRM;
+ /* now, set the status to exit */
+ pld->state = PL_PREVIEW_CONFIRM;
- /* cleanup */
- return poselib_preview_exit(C, op);
+ /* cleanup */
+ return poselib_preview_exit(C, op);
}
void POSELIB_OT_browse_interactive(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "PoseLib Browse Poses";
- ot->idname = "POSELIB_OT_browse_interactive";
- ot->description = "Interactively browse poses in 3D-View";
-
- /* callbacks */
- ot->invoke = poselib_preview_invoke;
- ot->modal = poselib_preview_modal;
- ot->cancel = poselib_preview_cancel;
- ot->exec = poselib_preview_exec;
- ot->poll = has_poselib_pose_data_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
-
- /* properties */
- // TODO: make the pose_index into a proper enum instead of a cryptic int...
- ot->prop = RNA_def_int(ot->srna, "pose_index", -1, -2, INT_MAX, "Pose", "Index of the pose to apply (-2 for no change to pose, -1 for poselib active pose)", 0, INT_MAX);
-
- // XXX: percentage vs factor?
- /* not used yet */
+ /* identifiers */
+ ot->name = "PoseLib Browse Poses";
+ ot->idname = "POSELIB_OT_browse_interactive";
+ ot->description = "Interactively browse poses in 3D-View";
+
+ /* callbacks */
+ ot->invoke = poselib_preview_invoke;
+ ot->modal = poselib_preview_modal;
+ ot->cancel = poselib_preview_cancel;
+ ot->exec = poselib_preview_exec;
+ ot->poll = has_poselib_pose_data_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* properties */
+ // TODO: make the pose_index into a proper enum instead of a cryptic int...
+ ot->prop = RNA_def_int(
+ ot->srna,
+ "pose_index",
+ -1,
+ -2,
+ INT_MAX,
+ "Pose",
+ "Index of the pose to apply (-2 for no change to pose, -1 for poselib active pose)",
+ 0,
+ INT_MAX);
+
+ // XXX: percentage vs factor?
+ /* not used yet */
#if 0
- RNA_def_float_factor(
- ot->srna, "blend_factor", 1.0f, 0.0f, 1.0f, "Blend Factor",
- "Amount that the pose is applied on top of the existing poses", 0.0f, 1.0f);
+ RNA_def_float_factor(
+ ot->srna, "blend_factor", 1.0f, 0.0f, 1.0f, "Blend Factor",
+ "Amount that the pose is applied on top of the existing poses", 0.0f, 1.0f);
#endif
}
void POSELIB_OT_apply_pose(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Apply Pose Library Pose";
- ot->idname = "POSELIB_OT_apply_pose";
- ot->description = "Apply specified Pose Library pose to the rig";
-
- /* callbacks */
- ot->exec = poselib_preview_exec;
- ot->poll = has_poselib_pose_data_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- /* TODO: make the pose_index into a proper enum instead of a cryptic int... */
- ot->prop = RNA_def_int(ot->srna, "pose_index", -1, -2, INT_MAX, "Pose", "Index of the pose to apply (-2 for no change to pose, -1 for poselib active pose)", 0, INT_MAX);
+ /* identifiers */
+ ot->name = "Apply Pose Library Pose";
+ ot->idname = "POSELIB_OT_apply_pose";
+ ot->description = "Apply specified Pose Library pose to the rig";
+
+ /* callbacks */
+ ot->exec = poselib_preview_exec;
+ ot->poll = has_poselib_pose_data_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ /* TODO: make the pose_index into a proper enum instead of a cryptic int... */
+ ot->prop = RNA_def_int(
+ ot->srna,
+ "pose_index",
+ -1,
+ -2,
+ INT_MAX,
+ "Pose",
+ "Index of the pose to apply (-2 for no change to pose, -1 for poselib active pose)",
+ 0,
+ INT_MAX);
}
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index 5ef61f0f6c6..b825d821fe8 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -63,172 +63,178 @@
#define PBONE_PREV_FLAG_GET(pchan) ((void)0, (POINTER_AS_INT((pchan)->temp)))
#define PBONE_PREV_FLAG_SET(pchan, val) ((pchan)->temp = POINTER_FROM_INT(val))
-
/* ***************** Pose Select Utilities ********************* */
/* Note: SEL_TOGGLE is assumed to have already been handled! */
static void pose_do_bone_select(bPoseChannel *pchan, const int select_mode)
{
- /* select pchan only if selectable, but deselect works always */
- switch (select_mode) {
- case SEL_SELECT:
- if (!(pchan->bone->flag & BONE_UNSELECTABLE))
- pchan->bone->flag |= BONE_SELECTED;
- break;
- case SEL_DESELECT:
- pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- break;
- case SEL_INVERT:
- if (pchan->bone->flag & BONE_SELECTED) {
- pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else if (!(pchan->bone->flag & BONE_UNSELECTABLE)) {
- pchan->bone->flag |= BONE_SELECTED;
- }
- break;
- }
+ /* select pchan only if selectable, but deselect works always */
+ switch (select_mode) {
+ case SEL_SELECT:
+ if (!(pchan->bone->flag & BONE_UNSELECTABLE))
+ pchan->bone->flag |= BONE_SELECTED;
+ break;
+ case SEL_DESELECT:
+ pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ break;
+ case SEL_INVERT:
+ if (pchan->bone->flag & BONE_SELECTED) {
+ pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else if (!(pchan->bone->flag & BONE_UNSELECTABLE)) {
+ pchan->bone->flag |= BONE_SELECTED;
+ }
+ break;
+ }
}
void ED_pose_bone_select_tag_update(Object *ob)
{
- BLI_assert(ob->type == OB_ARMATURE);
- bArmature *arm = ob->data;
- WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, ob);
- WM_main_add_notifier(NC_GEOM | ND_DATA, ob);
+ BLI_assert(ob->type == OB_ARMATURE);
+ bArmature *arm = ob->data;
+ WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, ob);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, ob);
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* mask modifier ('armature' mode), etc. */
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
+ if (arm->flag & ARM_HAS_VIZ_DEPS) {
+ /* mask modifier ('armature' mode), etc. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
- DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
+ DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
}
-
/* Utility method for changing the selection status of a bone */
void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
{
- bArmature *arm;
-
- /* sanity checks */
- // XXX: actually, we can probably still get away with no object - at most we have no updates
- if (ELEM(NULL, ob, ob->pose, pchan, pchan->bone))
- return;
-
- arm = ob->data;
-
- /* can only change selection state if bone can be modified */
- if (PBONE_SELECTABLE(arm, pchan->bone)) {
- /* change selection state - activate too if selected */
- if (select) {
- pchan->bone->flag |= BONE_SELECTED;
- arm->act_bone = pchan->bone;
- }
- else {
- pchan->bone->flag &= ~BONE_SELECTED;
- arm->act_bone = NULL;
- }
-
- // TODO: select and activate corresponding vgroup?
- ED_pose_bone_select_tag_update(ob);
- }
+ bArmature *arm;
+
+ /* sanity checks */
+ // XXX: actually, we can probably still get away with no object - at most we have no updates
+ if (ELEM(NULL, ob, ob->pose, pchan, pchan->bone))
+ return;
+
+ arm = ob->data;
+
+ /* can only change selection state if bone can be modified */
+ if (PBONE_SELECTABLE(arm, pchan->bone)) {
+ /* change selection state - activate too if selected */
+ if (select) {
+ pchan->bone->flag |= BONE_SELECTED;
+ arm->act_bone = pchan->bone;
+ }
+ else {
+ pchan->bone->flag &= ~BONE_SELECTED;
+ arm->act_bone = NULL;
+ }
+
+ // TODO: select and activate corresponding vgroup?
+ ED_pose_bone_select_tag_update(ob);
+ }
}
/* called from editview.c, for mode-less pose selection */
/* assumes scene obact and basact is still on old situation */
-bool ED_armature_pose_select_pick_with_buffer(
- ViewLayer *view_layer, View3D *v3d, Base *base, const unsigned int *buffer, short hits,
- bool extend, bool deselect, bool toggle, bool do_nearest)
+bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer,
+ View3D *v3d,
+ Base *base,
+ const unsigned int *buffer,
+ short hits,
+ bool extend,
+ bool deselect,
+ bool toggle,
+ bool do_nearest)
{
- Object *ob = base->object;
- Bone *nearBone;
-
- if (!ob || !ob->pose) return 0;
-
- Object *ob_act = OBACT(view_layer);
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
-
- /* Callers happen to already get the active base */
- Base *base_dummy = NULL;
- nearBone = get_bone_from_selectbuffer(&base, 1, obedit != NULL, buffer, hits, 1, do_nearest, &base_dummy);
-
- /* if the bone cannot be affected, don't do anything */
- if ((nearBone) && !(nearBone->flag & BONE_UNSELECTABLE)) {
- bArmature *arm = ob->data;
-
- /* since we do unified select, we don't shift+select a bone if the
- * armature object was not active yet.
- * note, special exception for armature mode so we can do multi-select
- * we could check for multi-select explicitly but think its fine to
- * always give predictable behavior in weight paint mode - campbell */
- if ((ob_act == NULL) || ((ob_act != ob) && (ob_act->mode & OB_MODE_WEIGHT_PAINT) == 0)) {
- /* when we are entering into posemode via toggle-select,
- * from another active object - always select the bone. */
- if (!extend && !deselect && toggle) {
- /* re-select below */
- nearBone->flag &= ~BONE_SELECTED;
- }
- }
-
- if (!extend && !deselect && !toggle) {
- {
- uint bases_len = 0;
- Base **bases = BKE_object_pose_base_array_get_unique(view_layer, v3d, &bases_len);
- ED_pose_deselect_all_multi_ex(bases, bases_len, SEL_DESELECT, true);
- MEM_freeN(bases);
- }
- nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_bone = nearBone;
- }
- else {
- if (extend) {
- nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_bone = nearBone;
- }
- else if (deselect) {
- nearBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else if (toggle) {
- if (nearBone->flag & BONE_SELECTED) {
- /* if not active, we make it active */
- if (nearBone != arm->act_bone) {
- arm->act_bone = nearBone;
- }
- else {
- nearBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- }
- else {
- nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_bone = nearBone;
- }
- }
- }
-
- if (ob_act) {
- /* in weightpaint we select the associated vertex group too */
- if (ob_act->mode & OB_MODE_WEIGHT_PAINT) {
- if (nearBone == arm->act_bone) {
- ED_vgroup_select_by_name(ob_act, nearBone->name);
- DEG_id_tag_update(&ob_act->id, ID_RECALC_GEOMETRY);
- }
- }
- /* if there are some dependencies for visualizing armature state
- * (e.g. Mask Modifier in 'Armature' mode), force update
- */
- else if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* NOTE: ob not ob_act here is intentional - it's the source of the
- * bones being selected [T37247]
- */
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
-
- /* tag armature for copy-on-write update (since act_bone is in armature not object) */
- DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
- }
- }
-
- return nearBone != NULL;
+ Object *ob = base->object;
+ Bone *nearBone;
+
+ if (!ob || !ob->pose)
+ return 0;
+
+ Object *ob_act = OBACT(view_layer);
+ Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+
+ /* Callers happen to already get the active base */
+ Base *base_dummy = NULL;
+ nearBone = get_bone_from_selectbuffer(
+ &base, 1, obedit != NULL, buffer, hits, 1, do_nearest, &base_dummy);
+
+ /* if the bone cannot be affected, don't do anything */
+ if ((nearBone) && !(nearBone->flag & BONE_UNSELECTABLE)) {
+ bArmature *arm = ob->data;
+
+ /* since we do unified select, we don't shift+select a bone if the
+ * armature object was not active yet.
+ * note, special exception for armature mode so we can do multi-select
+ * we could check for multi-select explicitly but think its fine to
+ * always give predictable behavior in weight paint mode - campbell */
+ if ((ob_act == NULL) || ((ob_act != ob) && (ob_act->mode & OB_MODE_WEIGHT_PAINT) == 0)) {
+ /* when we are entering into posemode via toggle-select,
+ * from another active object - always select the bone. */
+ if (!extend && !deselect && toggle) {
+ /* re-select below */
+ nearBone->flag &= ~BONE_SELECTED;
+ }
+ }
+
+ if (!extend && !deselect && !toggle) {
+ {
+ uint bases_len = 0;
+ Base **bases = BKE_object_pose_base_array_get_unique(view_layer, v3d, &bases_len);
+ ED_pose_deselect_all_multi_ex(bases, bases_len, SEL_DESELECT, true);
+ MEM_freeN(bases);
+ }
+ nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ arm->act_bone = nearBone;
+ }
+ else {
+ if (extend) {
+ nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ arm->act_bone = nearBone;
+ }
+ else if (deselect) {
+ nearBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else if (toggle) {
+ if (nearBone->flag & BONE_SELECTED) {
+ /* if not active, we make it active */
+ if (nearBone != arm->act_bone) {
+ arm->act_bone = nearBone;
+ }
+ else {
+ nearBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+ else {
+ nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ arm->act_bone = nearBone;
+ }
+ }
+ }
+
+ if (ob_act) {
+ /* in weightpaint we select the associated vertex group too */
+ if (ob_act->mode & OB_MODE_WEIGHT_PAINT) {
+ if (nearBone == arm->act_bone) {
+ ED_vgroup_select_by_name(ob_act, nearBone->name);
+ DEG_id_tag_update(&ob_act->id, ID_RECALC_GEOMETRY);
+ }
+ }
+ /* if there are some dependencies for visualizing armature state
+ * (e.g. Mask Modifier in 'Armature' mode), force update
+ */
+ else if (arm->flag & ARM_HAS_VIZ_DEPS) {
+ /* NOTE: ob not ob_act here is intentional - it's the source of the
+ * bones being selected [T37247]
+ */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+
+ /* tag armature for copy-on-write update (since act_bone is in armature not object) */
+ DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
+ }
+ }
+
+ return nearBone != NULL;
}
/* 'select_mode' is usual SEL_SELECT/SEL_DESELECT/SEL_TOGGLE/SEL_INVERT.
@@ -236,340 +242,349 @@ bool ED_armature_pose_select_pick_with_buffer(
* (hidden or on hidden layers). */
bool ED_pose_deselect_all(Object *ob, int select_mode, const bool ignore_visibility)
{
- bArmature *arm = ob->data;
- bPoseChannel *pchan;
-
- /* we call this from outliner too */
- if (ob->pose == NULL) {
- return false;
- }
-
- /* Determine if we're selecting or deselecting */
- if (select_mode == SEL_TOGGLE) {
- select_mode = SEL_SELECT;
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) {
- if (pchan->bone->flag & BONE_SELECTED) {
- select_mode = SEL_DESELECT;
- break;
- }
- }
- }
- }
-
- /* Set the flags accordingly */
- bool changed = false;
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- /* ignore the pchan if it isn't visible or if its selection cannot be changed */
- if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) {
- int flag_prev = pchan->bone->flag;
- pose_do_bone_select(pchan, select_mode);
- changed = (changed || flag_prev != pchan->bone->flag);
- }
- }
- return changed;
+ bArmature *arm = ob->data;
+ bPoseChannel *pchan;
+
+ /* we call this from outliner too */
+ if (ob->pose == NULL) {
+ return false;
+ }
+
+ /* Determine if we're selecting or deselecting */
+ if (select_mode == SEL_TOGGLE) {
+ select_mode = SEL_SELECT;
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) {
+ if (pchan->bone->flag & BONE_SELECTED) {
+ select_mode = SEL_DESELECT;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Set the flags accordingly */
+ bool changed = false;
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ /* ignore the pchan if it isn't visible or if its selection cannot be changed */
+ if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) {
+ int flag_prev = pchan->bone->flag;
+ pose_do_bone_select(pchan, select_mode);
+ changed = (changed || flag_prev != pchan->bone->flag);
+ }
+ }
+ return changed;
}
static bool ed_pose_is_any_selected(Object *ob, bool ignore_visibility)
{
- bArmature *arm = ob->data;
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) {
- if (pchan->bone->flag & BONE_SELECTED) {
- return true;
- }
- }
- }
- return false;
+ bArmature *arm = ob->data;
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) {
+ if (pchan->bone->flag & BONE_SELECTED) {
+ return true;
+ }
+ }
+ }
+ return false;
}
static bool ed_pose_is_any_selected_multi(Base **bases, uint bases_len, bool ignore_visibility)
{
- for (uint base_index = 0; base_index < bases_len; base_index++) {
- Object *ob_iter = bases[base_index]->object;
- if (ed_pose_is_any_selected(ob_iter, ignore_visibility)) {
- return true;
- }
- }
- return false;
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Object *ob_iter = bases[base_index]->object;
+ if (ed_pose_is_any_selected(ob_iter, ignore_visibility)) {
+ return true;
+ }
+ }
+ return false;
}
-bool ED_pose_deselect_all_multi_ex(Base **bases, uint bases_len, int select_mode, const bool ignore_visibility)
+bool ED_pose_deselect_all_multi_ex(Base **bases,
+ uint bases_len,
+ int select_mode,
+ const bool ignore_visibility)
{
- if (select_mode == SEL_TOGGLE) {
- select_mode = ed_pose_is_any_selected_multi(
- bases, bases_len, ignore_visibility) ? SEL_DESELECT : SEL_SELECT;
- }
-
- bool changed_multi = false;
- for (uint base_index = 0; base_index < bases_len; base_index++) {
- Object *ob_iter = bases[base_index]->object;
- if (ED_pose_deselect_all(ob_iter, select_mode, ignore_visibility)) {
- ED_pose_bone_select_tag_update(ob_iter);
- changed_multi = true;
- }
- }
- return changed_multi;
+ if (select_mode == SEL_TOGGLE) {
+ select_mode = ed_pose_is_any_selected_multi(bases, bases_len, ignore_visibility) ?
+ SEL_DESELECT :
+ SEL_SELECT;
+ }
+
+ bool changed_multi = false;
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Object *ob_iter = bases[base_index]->object;
+ if (ED_pose_deselect_all(ob_iter, select_mode, ignore_visibility)) {
+ ED_pose_bone_select_tag_update(ob_iter);
+ changed_multi = true;
+ }
+ }
+ return changed_multi;
}
-
bool ED_pose_deselect_all_multi(bContext *C, int select_mode, const bool ignore_visibility)
{
- ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
- uint bases_len = 0;
- Base **bases = BKE_view_layer_array_from_bases_in_mode(vc.view_layer, vc.v3d, &bases_len, {.object_mode = OB_MODE_POSE,});
- bool changed_multi = ED_pose_deselect_all_multi_ex(bases, bases_len, select_mode, ignore_visibility);
- MEM_freeN(bases);
- return changed_multi;
+ ViewContext vc;
+ ED_view3d_viewcontext_init(C, &vc);
+ uint bases_len = 0;
+ Base **bases = BKE_view_layer_array_from_bases_in_mode(vc.view_layer,
+ vc.v3d,
+ &bases_len,
+ {
+ .object_mode = OB_MODE_POSE,
+ });
+ bool changed_multi = ED_pose_deselect_all_multi_ex(
+ bases, bases_len, select_mode, ignore_visibility);
+ MEM_freeN(bases);
+ return changed_multi;
}
/* ***************** Selections ********************** */
static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend)
{
- Bone *curBone;
+ Bone *curBone;
- /* stop when unconnected child is encountered, or when unselectable bone is encountered */
- if (!(bone->flag & BONE_CONNECTED) || (bone->flag & BONE_UNSELECTABLE))
- return;
+ /* stop when unconnected child is encountered, or when unselectable bone is encountered */
+ if (!(bone->flag & BONE_CONNECTED) || (bone->flag & BONE_UNSELECTABLE))
+ return;
- if (extend)
- bone->flag &= ~BONE_SELECTED;
- else
- bone->flag |= BONE_SELECTED;
+ if (extend)
+ bone->flag &= ~BONE_SELECTED;
+ else
+ bone->flag |= BONE_SELECTED;
- for (curBone = bone->childbase.first; curBone; curBone = curBone->next)
- selectconnected_posebonechildren(ob, curBone, extend);
+ for (curBone = bone->childbase.first; curBone; curBone = curBone->next)
+ selectconnected_posebonechildren(ob, curBone, extend);
}
/* within active object context */
/* previously known as "selectconnected_posearmature" */
static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Bone *bone, *curBone, *next = NULL;
- const bool extend = RNA_boolean_get(op->ptr, "extend");
-
- view3d_operator_needs_opengl(C);
-
- Base *base = NULL;
- bone = get_nearest_bone(C, event->mval, !extend, &base);
-
- if (!bone)
- return OPERATOR_CANCELLED;
-
- /* Select parents */
- for (curBone = bone; curBone; curBone = next) {
- /* ignore bone if cannot be selected */
- if ((curBone->flag & BONE_UNSELECTABLE) == 0) {
- if (extend)
- curBone->flag &= ~BONE_SELECTED;
- else
- curBone->flag |= BONE_SELECTED;
-
- if (curBone->flag & BONE_CONNECTED)
- next = curBone->parent;
- else
- next = NULL;
- }
- else
- next = NULL;
- }
-
- /* Select children */
- for (curBone = bone->childbase.first; curBone; curBone = next)
- selectconnected_posebonechildren(base->object, curBone, extend);
-
- ED_pose_bone_select_tag_update(base->object);
-
- return OPERATOR_FINISHED;
+ Bone *bone, *curBone, *next = NULL;
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+
+ view3d_operator_needs_opengl(C);
+
+ Base *base = NULL;
+ bone = get_nearest_bone(C, event->mval, !extend, &base);
+
+ if (!bone)
+ return OPERATOR_CANCELLED;
+
+ /* Select parents */
+ for (curBone = bone; curBone; curBone = next) {
+ /* ignore bone if cannot be selected */
+ if ((curBone->flag & BONE_UNSELECTABLE) == 0) {
+ if (extend)
+ curBone->flag &= ~BONE_SELECTED;
+ else
+ curBone->flag |= BONE_SELECTED;
+
+ if (curBone->flag & BONE_CONNECTED)
+ next = curBone->parent;
+ else
+ next = NULL;
+ }
+ else
+ next = NULL;
+ }
+
+ /* Select children */
+ for (curBone = bone->childbase.first; curBone; curBone = next)
+ selectconnected_posebonechildren(base->object, curBone, extend);
+
+ ED_pose_bone_select_tag_update(base->object);
+
+ return OPERATOR_FINISHED;
}
static bool pose_select_linked_poll(bContext *C)
{
- return (ED_operator_view3d_active(C) && ED_operator_posemode(C));
+ return (ED_operator_view3d_active(C) && ED_operator_posemode(C));
}
void POSE_OT_select_linked(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select Connected";
- ot->idname = "POSE_OT_select_linked";
- ot->description = "Select bones related to selected ones by parent/child relationships";
-
- /* callbacks */
- /* leave 'exec' unset */
- ot->invoke = pose_select_connected_invoke;
- ot->poll = pose_select_linked_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* props */
- RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first");
+ /* identifiers */
+ ot->name = "Select Connected";
+ ot->idname = "POSE_OT_select_linked";
+ ot->description = "Select bones related to selected ones by parent/child relationships";
+
+ /* callbacks */
+ /* leave 'exec' unset */
+ ot->invoke = pose_select_connected_invoke;
+ ot->poll = pose_select_linked_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna,
+ "extend",
+ false,
+ "Extend",
+ "Extend selection instead of deselecting everything first");
}
/* -------------------------------------- */
static int pose_de_select_all_exec(bContext *C, wmOperator *op)
{
- int action = RNA_enum_get(op->ptr, "action");
-
- Scene *scene = CTX_data_scene(C);
- int multipaint = scene->toolsettings->multipaint;
-
- if (action == SEL_TOGGLE) {
- action = CTX_DATA_COUNT(C, selected_pose_bones) ? SEL_DESELECT : SEL_SELECT;
- }
-
- Object *ob_prev = NULL;
-
- /* Set the flags */
- CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob)
- {
- bArmature *arm = ob->data;
- pose_do_bone_select(pchan, action);
-
- if (ob_prev != ob) {
- /* weightpaint or mask modifiers need depsgraph updates */
- if (multipaint || (arm->flag & ARM_HAS_VIZ_DEPS)) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
- /* need to tag armature for cow updates, or else selection doesn't update */
- DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
- ob_prev = ob;
- }
- }
- CTX_DATA_END;
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
-
- return OPERATOR_FINISHED;
+ int action = RNA_enum_get(op->ptr, "action");
+
+ Scene *scene = CTX_data_scene(C);
+ int multipaint = scene->toolsettings->multipaint;
+
+ if (action == SEL_TOGGLE) {
+ action = CTX_DATA_COUNT(C, selected_pose_bones) ? SEL_DESELECT : SEL_SELECT;
+ }
+
+ Object *ob_prev = NULL;
+
+ /* Set the flags */
+ CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob)
+ {
+ bArmature *arm = ob->data;
+ pose_do_bone_select(pchan, action);
+
+ if (ob_prev != ob) {
+ /* weightpaint or mask modifiers need depsgraph updates */
+ if (multipaint || (arm->flag & ARM_HAS_VIZ_DEPS)) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+ /* need to tag armature for cow updates, or else selection doesn't update */
+ DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
+ ob_prev = ob;
+ }
+ }
+ CTX_DATA_END;
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
+
+ return OPERATOR_FINISHED;
}
void POSE_OT_select_all(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "(De)select All";
- ot->idname = "POSE_OT_select_all";
- ot->description = "Toggle selection status of all bones";
+ /* identifiers */
+ ot->name = "(De)select All";
+ ot->idname = "POSE_OT_select_all";
+ ot->description = "Toggle selection status of all bones";
- /* api callbacks */
- ot->exec = pose_de_select_all_exec;
- ot->poll = ED_operator_posemode;
+ /* api callbacks */
+ ot->exec = pose_de_select_all_exec;
+ ot->poll = ED_operator_posemode;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- WM_operator_properties_select_all(ot);
+ WM_operator_properties_select_all(ot);
}
/* -------------------------------------- */
static int pose_select_parent_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = (bArmature *)ob->data;
- bPoseChannel *pchan, *parent;
-
- /* Determine if there is an active bone */
- pchan = CTX_data_active_pose_bone(C);
- if (pchan) {
- parent = pchan->parent;
- if ((parent) && !(parent->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) {
- parent->bone->flag |= BONE_SELECTED;
- arm->act_bone = parent->bone;
- }
- else {
- return OPERATOR_CANCELLED;
- }
- }
- else {
- return OPERATOR_CANCELLED;
- }
-
- ED_pose_bone_select_tag_update(ob);
- return OPERATOR_FINISHED;
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = (bArmature *)ob->data;
+ bPoseChannel *pchan, *parent;
+
+ /* Determine if there is an active bone */
+ pchan = CTX_data_active_pose_bone(C);
+ if (pchan) {
+ parent = pchan->parent;
+ if ((parent) && !(parent->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) {
+ parent->bone->flag |= BONE_SELECTED;
+ arm->act_bone = parent->bone;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+
+ ED_pose_bone_select_tag_update(ob);
+ return OPERATOR_FINISHED;
}
void POSE_OT_select_parent(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select Parent Bone";
- ot->idname = "POSE_OT_select_parent";
- ot->description = "Select bones that are parents of the currently selected bones";
+ /* identifiers */
+ ot->name = "Select Parent Bone";
+ ot->idname = "POSE_OT_select_parent";
+ ot->description = "Select bones that are parents of the currently selected bones";
- /* api callbacks */
- ot->exec = pose_select_parent_exec;
- ot->poll = ED_operator_posemode;
+ /* api callbacks */
+ ot->exec = pose_select_parent_exec;
+ ot->poll = ED_operator_posemode;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* -------------------------------------- */
static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op))
{
- bConstraint *con;
- int found = 0;
-
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- if (pchan->bone->flag & BONE_SELECTED) {
- for (con = pchan->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- Object *ob = ct->tar;
-
- /* Any armature that is also in pose mode should be selected. */
- if ((ct->subtarget[0] != '\0') &&
- (ob != NULL) &&
- (ob->type == OB_ARMATURE) &&
- (ob->mode == OB_MODE_POSE))
- {
- bPoseChannel *pchanc = BKE_pose_channel_find_name(ob->pose, ct->subtarget);
- if ((pchanc) && !(pchanc->bone->flag & BONE_UNSELECTABLE)) {
- pchanc->bone->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
- ED_pose_bone_select_tag_update(ob);
- found = 1;
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 1);
- }
- }
- }
- }
- CTX_DATA_END;
-
- if (!found)
- return OPERATOR_CANCELLED;
-
- return OPERATOR_FINISHED;
+ bConstraint *con;
+ int found = 0;
+
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones) {
+ if (pchan->bone->flag & BONE_SELECTED) {
+ for (con = pchan->constraints.first; con; con = con->next) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ Object *ob = ct->tar;
+
+ /* Any armature that is also in pose mode should be selected. */
+ if ((ct->subtarget[0] != '\0') && (ob != NULL) && (ob->type == OB_ARMATURE) &&
+ (ob->mode == OB_MODE_POSE)) {
+ bPoseChannel *pchanc = BKE_pose_channel_find_name(ob->pose, ct->subtarget);
+ if ((pchanc) && !(pchanc->bone->flag & BONE_UNSELECTABLE)) {
+ pchanc->bone->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
+ ED_pose_bone_select_tag_update(ob);
+ found = 1;
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 1);
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ if (!found)
+ return OPERATOR_CANCELLED;
+
+ return OPERATOR_FINISHED;
}
void POSE_OT_select_constraint_target(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select Constraint Target";
- ot->idname = "POSE_OT_select_constraint_target";
- ot->description = "Select bones used as targets for the currently selected bones";
+ /* identifiers */
+ ot->name = "Select Constraint Target";
+ ot->idname = "POSE_OT_select_constraint_target";
+ ot->description = "Select bones used as targets for the currently selected bones";
- /* api callbacks */
- ot->exec = pose_select_constraint_target_exec;
- ot->poll = ED_operator_posemode;
+ /* api callbacks */
+ ot->exec = pose_select_constraint_target_exec;
+ ot->poll = ED_operator_posemode;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* -------------------------------------- */
@@ -578,444 +593,457 @@ void POSE_OT_select_constraint_target(wmOperatorType *ot)
* selected we then keep the non-active objects untouched (selected/unselected). */
static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = ob->data;
- bPoseChannel *pchan_act;
- int direction = RNA_enum_get(op->ptr, "direction");
- const bool add_to_sel = RNA_boolean_get(op->ptr, "extend");
- bool changed = false;
-
- pchan_act = BKE_pose_channel_active(ob);
- if (pchan_act == NULL) {
- return OPERATOR_CANCELLED;
- }
-
- if (direction == BONE_SELECT_PARENT) {
- if (pchan_act->parent) {
- Bone *bone_parent;
- bone_parent = pchan_act->parent->bone;
-
- if (PBONE_SELECTABLE(arm, bone_parent)) {
- if (!add_to_sel) {
- pchan_act->bone->flag &= ~BONE_SELECTED;
- }
- bone_parent->flag |= BONE_SELECTED;
- arm->act_bone = bone_parent;
-
- changed = true;
- }
- }
- }
- else { /* direction == BONE_SELECT_CHILD */
- bPoseChannel *pchan_iter;
- Bone *bone_child = NULL;
- int pass;
-
- /* first pass, only connected bones (the logical direct child) */
- for (pass = 0; pass < 2 && (bone_child == NULL); pass++) {
- for (pchan_iter = ob->pose->chanbase.first; pchan_iter; pchan_iter = pchan_iter->next) {
- /* possible we have multiple children, some invisible */
- if (PBONE_SELECTABLE(arm, pchan_iter->bone)) {
- if (pchan_iter->parent == pchan_act) {
- if ((pass == 1) || (pchan_iter->bone->flag & BONE_CONNECTED)) {
- bone_child = pchan_iter->bone;
- break;
- }
- }
- }
- }
- }
-
- if (bone_child) {
- arm->act_bone = bone_child;
-
- if (!add_to_sel) {
- pchan_act->bone->flag &= ~BONE_SELECTED;
- }
- bone_child->flag |= BONE_SELECTED;
-
- changed = true;
- }
- }
-
- if (changed == false) {
- return OPERATOR_CANCELLED;
- }
-
- ED_pose_bone_select_tag_update(ob);
-
- return OPERATOR_FINISHED;
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = ob->data;
+ bPoseChannel *pchan_act;
+ int direction = RNA_enum_get(op->ptr, "direction");
+ const bool add_to_sel = RNA_boolean_get(op->ptr, "extend");
+ bool changed = false;
+
+ pchan_act = BKE_pose_channel_active(ob);
+ if (pchan_act == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (direction == BONE_SELECT_PARENT) {
+ if (pchan_act->parent) {
+ Bone *bone_parent;
+ bone_parent = pchan_act->parent->bone;
+
+ if (PBONE_SELECTABLE(arm, bone_parent)) {
+ if (!add_to_sel) {
+ pchan_act->bone->flag &= ~BONE_SELECTED;
+ }
+ bone_parent->flag |= BONE_SELECTED;
+ arm->act_bone = bone_parent;
+
+ changed = true;
+ }
+ }
+ }
+ else { /* direction == BONE_SELECT_CHILD */
+ bPoseChannel *pchan_iter;
+ Bone *bone_child = NULL;
+ int pass;
+
+ /* first pass, only connected bones (the logical direct child) */
+ for (pass = 0; pass < 2 && (bone_child == NULL); pass++) {
+ for (pchan_iter = ob->pose->chanbase.first; pchan_iter; pchan_iter = pchan_iter->next) {
+ /* possible we have multiple children, some invisible */
+ if (PBONE_SELECTABLE(arm, pchan_iter->bone)) {
+ if (pchan_iter->parent == pchan_act) {
+ if ((pass == 1) || (pchan_iter->bone->flag & BONE_CONNECTED)) {
+ bone_child = pchan_iter->bone;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (bone_child) {
+ arm->act_bone = bone_child;
+
+ if (!add_to_sel) {
+ pchan_act->bone->flag &= ~BONE_SELECTED;
+ }
+ bone_child->flag |= BONE_SELECTED;
+
+ changed = true;
+ }
+ }
+
+ if (changed == false) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ED_pose_bone_select_tag_update(ob);
+
+ return OPERATOR_FINISHED;
}
void POSE_OT_select_hierarchy(wmOperatorType *ot)
{
- static const EnumPropertyItem direction_items[] = {
- {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""},
- {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Select Hierarchy";
- ot->idname = "POSE_OT_select_hierarchy";
- ot->description = "Select immediate parent/children of selected bones";
-
- /* api callbacks */
- ot->exec = pose_select_hierarchy_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* props */
- ot->prop = RNA_def_enum(ot->srna, "direction", direction_items, BONE_SELECT_PARENT, "Direction", "");
- RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
+ static const EnumPropertyItem direction_items[] = {
+ {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""},
+ {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Select Hierarchy";
+ ot->idname = "POSE_OT_select_hierarchy";
+ ot->description = "Select immediate parent/children of selected bones";
+
+ /* api callbacks */
+ ot->exec = pose_select_hierarchy_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ ot->prop = RNA_def_enum(
+ ot->srna, "direction", direction_items, BONE_SELECT_PARENT, "Direction", "");
+ RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
/* -------------------------------------- */
/* modes for select same */
typedef enum ePose_SelectSame_Mode {
- POSE_SEL_SAME_LAYER = 0,
- POSE_SEL_SAME_GROUP = 1,
- POSE_SEL_SAME_KEYINGSET = 2,
+ POSE_SEL_SAME_LAYER = 0,
+ POSE_SEL_SAME_GROUP = 1,
+ POSE_SEL_SAME_KEYINGSET = 2,
} ePose_SelectSame_Mode;
static bool pose_select_same_group(bContext *C, bool extend)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- bool *group_flags_array;
- bool *group_flags = NULL;
- int groups_len = 0;
- bool changed = false, tagged = false;
- Object *ob_prev = NULL;
- uint ob_index;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len, OB_MODE_POSE);
- for (ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = BKE_object_pose_armature_get(objects[ob_index]);
- bArmature *arm = (ob) ? ob->data : NULL;
- bPose *pose = (ob) ? ob->pose : NULL;
-
- /* Sanity checks. */
- if (ELEM(NULL, ob, pose, arm)) {
- continue;
- }
-
- ob->id.tag &= ~LIB_TAG_DOIT;
- groups_len = MAX2(groups_len, BLI_listbase_count(&pose->agroups));
- }
-
- /* Nothing to do here. */
- if (groups_len == 0) {
- MEM_freeN(objects);
- return false;
- }
-
- /* alloc a small array to keep track of the groups to use
- * - each cell stores on/off state for whether group should be used
- * - size is (groups_len + 1), since (index = 0) is used for no-group
- */
- groups_len++;
- group_flags_array = MEM_callocN(objects_len * groups_len * sizeof(bool), "pose_select_same_group");
-
- group_flags = NULL;
- ob_index = -1;
- ob_prev = NULL;
- CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object, *ob)
- {
- if (ob != ob_prev) {
- ob_index++;
- group_flags = group_flags_array + (ob_index * groups_len);
- ob_prev = ob;
- }
-
- /* keep track of group as group to use later? */
- if (pchan->bone->flag & BONE_SELECTED) {
- group_flags[pchan->agrp_index] = true;
- tagged = true;
- }
-
- /* deselect all bones before selecting new ones? */
- if ((extend == false) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
- pchan->bone->flag &= ~BONE_SELECTED;
- }
- }
- CTX_DATA_END;
-
- /* small optimization: only loop through bones a second time if there are any groups tagged */
- if (tagged) {
- group_flags = NULL;
- ob_index = -1;
- ob_prev = NULL;
- /* only if group matches (and is not selected or current bone) */
- CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob)
- {
- if (ob != ob_prev) {
- ob_index++;
- group_flags = group_flags_array + (ob_index * groups_len);
- ob_prev = ob;
- }
-
- if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
- /* check if the group used by this bone is counted */
- if (group_flags[pchan->agrp_index]) {
- pchan->bone->flag |= BONE_SELECTED;
- ob->id.tag |= LIB_TAG_DOIT;
- }
- }
- }
- CTX_DATA_END;
- }
-
- for (ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- if (ob->id.tag & LIB_TAG_DOIT) {
- ED_pose_bone_select_tag_update(ob);
- changed = true;
- }
- }
-
- /* Cleanup. */
- MEM_freeN(group_flags_array);
- MEM_freeN(objects);
-
- return changed;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ bool *group_flags_array;
+ bool *group_flags = NULL;
+ int groups_len = 0;
+ bool changed = false, tagged = false;
+ Object *ob_prev = NULL;
+ uint ob_index;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len, OB_MODE_POSE);
+ for (ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = BKE_object_pose_armature_get(objects[ob_index]);
+ bArmature *arm = (ob) ? ob->data : NULL;
+ bPose *pose = (ob) ? ob->pose : NULL;
+
+ /* Sanity checks. */
+ if (ELEM(NULL, ob, pose, arm)) {
+ continue;
+ }
+
+ ob->id.tag &= ~LIB_TAG_DOIT;
+ groups_len = MAX2(groups_len, BLI_listbase_count(&pose->agroups));
+ }
+
+ /* Nothing to do here. */
+ if (groups_len == 0) {
+ MEM_freeN(objects);
+ return false;
+ }
+
+ /* alloc a small array to keep track of the groups to use
+ * - each cell stores on/off state for whether group should be used
+ * - size is (groups_len + 1), since (index = 0) is used for no-group
+ */
+ groups_len++;
+ group_flags_array = MEM_callocN(objects_len * groups_len * sizeof(bool),
+ "pose_select_same_group");
+
+ group_flags = NULL;
+ ob_index = -1;
+ ob_prev = NULL;
+ CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, pchan, visible_pose_bones, Object, *ob)
+ {
+ if (ob != ob_prev) {
+ ob_index++;
+ group_flags = group_flags_array + (ob_index * groups_len);
+ ob_prev = ob;
+ }
+
+ /* keep track of group as group to use later? */
+ if (pchan->bone->flag & BONE_SELECTED) {
+ group_flags[pchan->agrp_index] = true;
+ tagged = true;
+ }
+
+ /* deselect all bones before selecting new ones? */
+ if ((extend == false) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
+ pchan->bone->flag &= ~BONE_SELECTED;
+ }
+ }
+ CTX_DATA_END;
+
+ /* small optimization: only loop through bones a second time if there are any groups tagged */
+ if (tagged) {
+ group_flags = NULL;
+ ob_index = -1;
+ ob_prev = NULL;
+ /* only if group matches (and is not selected or current bone) */
+ CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob)
+ {
+ if (ob != ob_prev) {
+ ob_index++;
+ group_flags = group_flags_array + (ob_index * groups_len);
+ ob_prev = ob;
+ }
+
+ if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
+ /* check if the group used by this bone is counted */
+ if (group_flags[pchan->agrp_index]) {
+ pchan->bone->flag |= BONE_SELECTED;
+ ob->id.tag |= LIB_TAG_DOIT;
+ }
+ }
+ }
+ CTX_DATA_END;
+ }
+
+ for (ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ if (ob->id.tag & LIB_TAG_DOIT) {
+ ED_pose_bone_select_tag_update(ob);
+ changed = true;
+ }
+ }
+
+ /* Cleanup. */
+ MEM_freeN(group_flags_array);
+ MEM_freeN(objects);
+
+ return changed;
}
static bool pose_select_same_layer(bContext *C, bool extend)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- int *layers_array, *layers = NULL;
- Object *ob_prev = NULL;
- uint ob_index;
- bool changed = false;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len, OB_MODE_POSE);
- for (ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- ob->id.tag &= ~LIB_TAG_DOIT;
- }
-
- layers_array = MEM_callocN(objects_len * sizeof(*layers_array), "pose_select_same_layer");
-
- /* Figure out what bones are selected. */
- layers = NULL;
- ob_prev = NULL;
- ob_index = -1;
- CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob)
- {
- if (ob != ob_prev) {
- layers = &layers_array[++ob_index];
- ob_prev = ob;
- }
-
- /* Keep track of layers to use later? */
- if (pchan->bone->flag & BONE_SELECTED)
- *layers |= pchan->bone->layer;
-
- /* Deselect all bones before selecting new ones? */
- if ((extend == false) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0)
- pchan->bone->flag &= ~BONE_SELECTED;
- }
- CTX_DATA_END;
-
- bool any_layer = false;
- for (ob_index = 0; ob_index < objects_len; ob_index++) {
- if (layers_array[ob_index]) {
- any_layer = true;
- break;
- }
- }
-
- if (!any_layer) {
- goto cleanup;
- }
-
- /* Select bones that are on same layers as layers flag. */
- ob_prev = NULL;
- ob_index = -1;
- CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob)
- {
- if (ob != ob_prev) {
- layers = &layers_array[++ob_index];
- ob_prev = ob;
- }
-
- /* if bone is on a suitable layer, and the bone can have its selection changed, select it */
- if ((*layers & pchan->bone->layer) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
- pchan->bone->flag |= BONE_SELECTED;
- ob->id.tag |= LIB_TAG_DOIT;
- }
- }
- CTX_DATA_END;
-
- for (ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- if (ob->id.tag & LIB_TAG_DOIT) {
- ED_pose_bone_select_tag_update(ob);
- changed = true;
- }
- }
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ int *layers_array, *layers = NULL;
+ Object *ob_prev = NULL;
+ uint ob_index;
+ bool changed = false;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len, OB_MODE_POSE);
+ for (ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ ob->id.tag &= ~LIB_TAG_DOIT;
+ }
+
+ layers_array = MEM_callocN(objects_len * sizeof(*layers_array), "pose_select_same_layer");
+
+ /* Figure out what bones are selected. */
+ layers = NULL;
+ ob_prev = NULL;
+ ob_index = -1;
+ CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob)
+ {
+ if (ob != ob_prev) {
+ layers = &layers_array[++ob_index];
+ ob_prev = ob;
+ }
+
+ /* Keep track of layers to use later? */
+ if (pchan->bone->flag & BONE_SELECTED)
+ *layers |= pchan->bone->layer;
+
+ /* Deselect all bones before selecting new ones? */
+ if ((extend == false) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0)
+ pchan->bone->flag &= ~BONE_SELECTED;
+ }
+ CTX_DATA_END;
+
+ bool any_layer = false;
+ for (ob_index = 0; ob_index < objects_len; ob_index++) {
+ if (layers_array[ob_index]) {
+ any_layer = true;
+ break;
+ }
+ }
+
+ if (!any_layer) {
+ goto cleanup;
+ }
+
+ /* Select bones that are on same layers as layers flag. */
+ ob_prev = NULL;
+ ob_index = -1;
+ CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob)
+ {
+ if (ob != ob_prev) {
+ layers = &layers_array[++ob_index];
+ ob_prev = ob;
+ }
+
+ /* if bone is on a suitable layer, and the bone can have its selection changed, select it */
+ if ((*layers & pchan->bone->layer) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
+ pchan->bone->flag |= BONE_SELECTED;
+ ob->id.tag |= LIB_TAG_DOIT;
+ }
+ }
+ CTX_DATA_END;
+
+ for (ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ if (ob->id.tag & LIB_TAG_DOIT) {
+ ED_pose_bone_select_tag_update(ob);
+ changed = true;
+ }
+ }
cleanup:
- /* Cleanup. */
- MEM_freeN(layers_array);
- MEM_freeN(objects);
+ /* Cleanup. */
+ MEM_freeN(layers_array);
+ MEM_freeN(objects);
- return changed;
+ return changed;
}
static bool pose_select_same_keyingset(bContext *C, ReportList *reports, bool extend)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- bool changed_multi = false;
- KeyingSet *ks = ANIM_scene_get_active_keyingset(CTX_data_scene(C));
- KS_Path *ksp;
-
- /* sanity checks: validate Keying Set and object */
- if (ks == NULL) {
- BKE_report(reports, RPT_ERROR, "No active Keying Set to use");
- return false;
- }
- else if (ANIM_validate_keyingset(C, NULL, ks) != 0) {
- if (ks->paths.first == NULL) {
- if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) {
- BKE_report(reports, RPT_ERROR,
- "Use another Keying Set, as the active one depends on the currently "
- "selected items or cannot find any targets due to unsuitable context");
- }
- else {
- BKE_report(reports, RPT_ERROR, "Keying Set does not contain any paths");
- }
- }
- return false;
- }
-
- /* if not extending selection, deselect all selected first */
- if (extend == false) {
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0)
- pchan->bone->flag &= ~BONE_SELECTED;
- }
- CTX_DATA_END;
- }
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len, OB_MODE_POSE);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = BKE_object_pose_armature_get(objects[ob_index]);
- bArmature *arm = (ob) ? ob->data : NULL;
- bPose *pose = (ob) ? ob->pose : NULL;
- bool changed = false;
-
- /* Sanity checks. */
- if (ELEM(NULL, ob, pose, arm)) {
- continue;
- }
-
- /* iterate over elements in the Keying Set, setting selection depending on whether
- * that bone is visible or not...
- */
- for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
- /* only items related to this object will be relevant */
- if ((ksp->id == &ob->id) && (ksp->rna_path != NULL)) {
- if (strstr(ksp->rna_path, "bones")) {
- char *boneName = BLI_str_quoted_substrN(ksp->rna_path, "bones[");
-
- if (boneName) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(pose, boneName);
-
- if (pchan) {
- /* select if bone is visible and can be affected */
- if (PBONE_SELECTABLE(arm, pchan->bone)) {
- pchan->bone->flag |= BONE_SELECTED;
- changed = true;
- }
- }
-
- /* free temp memory */
- MEM_freeN(boneName);
- }
- }
- }
- }
-
- if (changed || !extend) {
- ED_pose_bone_select_tag_update(ob);
- changed_multi = true;
- }
- }
- MEM_freeN(objects);
-
- return changed_multi;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ bool changed_multi = false;
+ KeyingSet *ks = ANIM_scene_get_active_keyingset(CTX_data_scene(C));
+ KS_Path *ksp;
+
+ /* sanity checks: validate Keying Set and object */
+ if (ks == NULL) {
+ BKE_report(reports, RPT_ERROR, "No active Keying Set to use");
+ return false;
+ }
+ else if (ANIM_validate_keyingset(C, NULL, ks) != 0) {
+ if (ks->paths.first == NULL) {
+ if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) {
+ BKE_report(reports,
+ RPT_ERROR,
+ "Use another Keying Set, as the active one depends on the currently "
+ "selected items or cannot find any targets due to unsuitable context");
+ }
+ else {
+ BKE_report(reports, RPT_ERROR, "Keying Set does not contain any paths");
+ }
+ }
+ return false;
+ }
+
+ /* if not extending selection, deselect all selected first */
+ if (extend == false) {
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones) {
+ if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0)
+ pchan->bone->flag &= ~BONE_SELECTED;
+ }
+ CTX_DATA_END;
+ }
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len, OB_MODE_POSE);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = BKE_object_pose_armature_get(objects[ob_index]);
+ bArmature *arm = (ob) ? ob->data : NULL;
+ bPose *pose = (ob) ? ob->pose : NULL;
+ bool changed = false;
+
+ /* Sanity checks. */
+ if (ELEM(NULL, ob, pose, arm)) {
+ continue;
+ }
+
+ /* iterate over elements in the Keying Set, setting selection depending on whether
+ * that bone is visible or not...
+ */
+ for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
+ /* only items related to this object will be relevant */
+ if ((ksp->id == &ob->id) && (ksp->rna_path != NULL)) {
+ if (strstr(ksp->rna_path, "bones")) {
+ char *boneName = BLI_str_quoted_substrN(ksp->rna_path, "bones[");
+
+ if (boneName) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(pose, boneName);
+
+ if (pchan) {
+ /* select if bone is visible and can be affected */
+ if (PBONE_SELECTABLE(arm, pchan->bone)) {
+ pchan->bone->flag |= BONE_SELECTED;
+ changed = true;
+ }
+ }
+
+ /* free temp memory */
+ MEM_freeN(boneName);
+ }
+ }
+ }
+ }
+
+ if (changed || !extend) {
+ ED_pose_bone_select_tag_update(ob);
+ changed_multi = true;
+ }
+ }
+ MEM_freeN(objects);
+
+ return changed_multi;
}
static int pose_select_grouped_exec(bContext *C, wmOperator *op)
{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- const ePose_SelectSame_Mode type = RNA_enum_get(op->ptr, "type");
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- bool changed = false;
-
- /* sanity check */
- if (ob->pose == NULL)
- return OPERATOR_CANCELLED;
-
- /* selection types */
- switch (type) {
- case POSE_SEL_SAME_LAYER: /* layer */
- changed = pose_select_same_layer(C, extend);
- break;
-
- case POSE_SEL_SAME_GROUP: /* group */
- changed = pose_select_same_group(C, extend);
- break;
-
- case POSE_SEL_SAME_KEYINGSET: /* Keying Set */
- changed = pose_select_same_keyingset(C, op->reports, extend);
- break;
-
- default:
- printf("pose_select_grouped() - Unknown selection type %u\n", type);
- break;
- }
-
- /* report done status */
- if (changed)
- return OPERATOR_FINISHED;
- else
- return OPERATOR_CANCELLED;
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ const ePose_SelectSame_Mode type = RNA_enum_get(op->ptr, "type");
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+ bool changed = false;
+
+ /* sanity check */
+ if (ob->pose == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* selection types */
+ switch (type) {
+ case POSE_SEL_SAME_LAYER: /* layer */
+ changed = pose_select_same_layer(C, extend);
+ break;
+
+ case POSE_SEL_SAME_GROUP: /* group */
+ changed = pose_select_same_group(C, extend);
+ break;
+
+ case POSE_SEL_SAME_KEYINGSET: /* Keying Set */
+ changed = pose_select_same_keyingset(C, op->reports, extend);
+ break;
+
+ default:
+ printf("pose_select_grouped() - Unknown selection type %u\n", type);
+ break;
+ }
+
+ /* report done status */
+ if (changed)
+ return OPERATOR_FINISHED;
+ else
+ return OPERATOR_CANCELLED;
}
void POSE_OT_select_grouped(wmOperatorType *ot)
{
- static const EnumPropertyItem prop_select_grouped_types[] = {
- {POSE_SEL_SAME_LAYER, "LAYER", 0, "Layer", "Shared layers"},
- {POSE_SEL_SAME_GROUP, "GROUP", 0, "Group", "Shared group"},
- {POSE_SEL_SAME_KEYINGSET, "KEYINGSET", 0, "Keying Set", "All bones affected by active Keying Set"},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Select Grouped";
- ot->description = "Select all visible bones grouped by similar properties";
- ot->idname = "POSE_OT_select_grouped";
-
- /* api callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = pose_select_grouped_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first");
- ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
+ static const EnumPropertyItem prop_select_grouped_types[] = {
+ {POSE_SEL_SAME_LAYER, "LAYER", 0, "Layer", "Shared layers"},
+ {POSE_SEL_SAME_GROUP, "GROUP", 0, "Group", "Shared group"},
+ {POSE_SEL_SAME_KEYINGSET,
+ "KEYINGSET",
+ 0,
+ "Keying Set",
+ "All bones affected by active Keying Set"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Select Grouped";
+ ot->description = "Select all visible bones grouped by similar properties";
+ ot->idname = "POSE_OT_select_grouped";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = pose_select_grouped_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna,
+ "extend",
+ false,
+ "Extend",
+ "Extend selection instead of deselecting everything first");
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
}
/* -------------------------------------- */
@@ -1025,85 +1053,87 @@ void POSE_OT_select_grouped(wmOperatorType *ot)
*/
static int pose_select_mirror_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob_active = CTX_data_active_object(C);
-
- const bool is_weight_paint = (ob_active->mode & OB_MODE_WEIGHT_PAINT) != 0;
- const bool active_only = RNA_boolean_get(op->ptr, "only_active");
- const bool extend = RNA_boolean_get(op->ptr, "extend");
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len, OB_MODE_POSE);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- bArmature *arm = ob->data;
- bPoseChannel *pchan, *pchan_mirror_act = NULL;
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- const int flag = (pchan->bone->flag & BONE_SELECTED);
- PBONE_PREV_FLAG_SET(pchan, flag);
- }
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (PBONE_SELECTABLE(arm, pchan->bone)) {
- bPoseChannel *pchan_mirror;
- int flag_new = extend ? PBONE_PREV_FLAG_GET(pchan) : 0;
-
- if ((pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) &&
- (PBONE_VISIBLE(arm, pchan_mirror->bone)))
- {
- const int flag_mirror = PBONE_PREV_FLAG_GET(pchan_mirror);
- flag_new |= flag_mirror;
-
- if (pchan->bone == arm->act_bone) {
- pchan_mirror_act = pchan_mirror;
- }
-
- /* Skip all but the active or its mirror. */
- if (active_only && !ELEM(arm->act_bone, pchan->bone, pchan_mirror->bone)) {
- continue;
- }
- }
-
- pchan->bone->flag = (pchan->bone->flag & ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) | flag_new;
- }
- }
-
- if (pchan_mirror_act) {
- arm->act_bone = pchan_mirror_act->bone;
-
- /* In weightpaint we select the associated vertex group too. */
- if (is_weight_paint) {
- ED_vgroup_select_by_name(ob, pchan_mirror_act->name);
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
- }
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- /* Need to tag armature for cow updates, or else selection doesn't update. */
- DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob_active = CTX_data_active_object(C);
+
+ const bool is_weight_paint = (ob_active->mode & OB_MODE_WEIGHT_PAINT) != 0;
+ const bool active_only = RNA_boolean_get(op->ptr, "only_active");
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len, OB_MODE_POSE);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bPoseChannel *pchan, *pchan_mirror_act = NULL;
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ const int flag = (pchan->bone->flag & BONE_SELECTED);
+ PBONE_PREV_FLAG_SET(pchan, flag);
+ }
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (PBONE_SELECTABLE(arm, pchan->bone)) {
+ bPoseChannel *pchan_mirror;
+ int flag_new = extend ? PBONE_PREV_FLAG_GET(pchan) : 0;
+
+ if ((pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) &&
+ (PBONE_VISIBLE(arm, pchan_mirror->bone))) {
+ const int flag_mirror = PBONE_PREV_FLAG_GET(pchan_mirror);
+ flag_new |= flag_mirror;
+
+ if (pchan->bone == arm->act_bone) {
+ pchan_mirror_act = pchan_mirror;
+ }
+
+ /* Skip all but the active or its mirror. */
+ if (active_only && !ELEM(arm->act_bone, pchan->bone, pchan_mirror->bone)) {
+ continue;
+ }
+ }
+
+ pchan->bone->flag = (pchan->bone->flag & ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) |
+ flag_new;
+ }
+ }
+
+ if (pchan_mirror_act) {
+ arm->act_bone = pchan_mirror_act->bone;
+
+ /* In weightpaint we select the associated vertex group too. */
+ if (is_weight_paint) {
+ ED_vgroup_select_by_name(ob, pchan_mirror_act->name);
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ /* Need to tag armature for cow updates, or else selection doesn't update. */
+ DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
+ }
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
}
void POSE_OT_select_mirror(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Flip Active/Selected Bone";
- ot->idname = "POSE_OT_select_mirror";
- ot->description = "Mirror the bone selection";
-
- /* api callbacks */
- ot->exec = pose_select_mirror_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "only_active", false, "Active Only", "Only operate on the active bone");
- RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
+ /* identifiers */
+ ot->name = "Flip Active/Selected Bone";
+ ot->idname = "POSE_OT_select_mirror";
+ ot->description = "Mirror the bone selection";
+
+ /* api callbacks */
+ ot->exec = pose_select_mirror_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(
+ ot->srna, "only_active", false, "Active Only", "Only operate on the active bone");
+ RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 90de331b3e0..cb9cfa64181 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -81,102 +81,104 @@
/* Temporary data shared between these operators */
typedef struct tPoseSlideOp {
- /** current scene */
- Scene *scene;
- /** area that we're operating in (needed for modal()) */
- ScrArea *sa;
- /** region that we're operating in (needed for modal()) */
- ARegion *ar;
- /** len of the PoseSlideObject array. */
- uint objects_len;
-
- /** links between posechannels and f-curves for all the pose objects. */
- ListBase pfLinks;
- /** binary tree for quicker searching for keyframes (when applicable) */
- DLRBT_Tree keys;
-
- /** current frame number - global time */
- int cframe;
-
- /** frame before current frame (blend-from) - global time */
- int prevFrame;
- /** frame after current frame (blend-to) - global time */
- int nextFrame;
-
- /** sliding mode (ePoseSlide_Modes) */
- short mode;
- /** unused for now, but can later get used for storing runtime settings.... */
- short flag;
-
- /** which transforms/channels are affected (ePoseSlide_Channels) */
- short channels;
- /** axis-limits for transforms (ePoseSlide_AxisLock) */
- short axislock;
-
- /** 0-1 value for determining the influence of whatever is relevant */
- float percentage;
-
- /** numeric input */
- NumInput num;
-
- struct tPoseSlideObject *ob_data_array;
+ /** current scene */
+ Scene *scene;
+ /** area that we're operating in (needed for modal()) */
+ ScrArea *sa;
+ /** region that we're operating in (needed for modal()) */
+ ARegion *ar;
+ /** len of the PoseSlideObject array. */
+ uint objects_len;
+
+ /** links between posechannels and f-curves for all the pose objects. */
+ ListBase pfLinks;
+ /** binary tree for quicker searching for keyframes (when applicable) */
+ DLRBT_Tree keys;
+
+ /** current frame number - global time */
+ int cframe;
+
+ /** frame before current frame (blend-from) - global time */
+ int prevFrame;
+ /** frame after current frame (blend-to) - global time */
+ int nextFrame;
+
+ /** sliding mode (ePoseSlide_Modes) */
+ short mode;
+ /** unused for now, but can later get used for storing runtime settings.... */
+ short flag;
+
+ /** which transforms/channels are affected (ePoseSlide_Channels) */
+ short channels;
+ /** axis-limits for transforms (ePoseSlide_AxisLock) */
+ short axislock;
+
+ /** 0-1 value for determining the influence of whatever is relevant */
+ float percentage;
+
+ /** numeric input */
+ NumInput num;
+
+ struct tPoseSlideObject *ob_data_array;
} tPoseSlideOp;
typedef struct tPoseSlideObject {
- Object *ob; /* active object that Pose Info comes from */
- float prevFrameF; /* prevFrame, but in local action time (for F-Curve lookups to work) */
- float nextFrameF; /* nextFrame, but in local action time (for F-Curve lookups to work) */
- bool valid;
+ Object *ob; /* active object that Pose Info comes from */
+ float prevFrameF; /* prevFrame, but in local action time (for F-Curve lookups to work) */
+ float nextFrameF; /* nextFrame, but in local action time (for F-Curve lookups to work) */
+ bool valid;
} tPoseSlideObject;
/* Pose Sliding Modes */
typedef enum ePoseSlide_Modes {
- POSESLIDE_PUSH = 0, /* exaggerate the pose... */
- POSESLIDE_RELAX, /* soften the pose... */
- POSESLIDE_BREAKDOWN, /* slide between the endpoint poses, finding a 'soft' spot */
+ POSESLIDE_PUSH = 0, /* exaggerate the pose... */
+ POSESLIDE_RELAX, /* soften the pose... */
+ POSESLIDE_BREAKDOWN, /* slide between the endpoint poses, finding a 'soft' spot */
} ePoseSlide_Modes;
-
/* Transforms/Channels to Affect */
typedef enum ePoseSlide_Channels {
- PS_TFM_ALL = 0, /* All transforms and properties */
+ PS_TFM_ALL = 0, /* All transforms and properties */
- PS_TFM_LOC, /* Loc/Rot/Scale */
- PS_TFM_ROT,
- PS_TFM_SIZE,
+ PS_TFM_LOC, /* Loc/Rot/Scale */
+ PS_TFM_ROT,
+ PS_TFM_SIZE,
- PS_TFM_BBONE_SHAPE, /* Bendy Bones */
+ PS_TFM_BBONE_SHAPE, /* Bendy Bones */
- PS_TFM_PROPS, /* Custom Properties */
+ PS_TFM_PROPS, /* Custom Properties */
} ePoseSlide_Channels;
/* Property enum for ePoseSlide_Channels */
static const EnumPropertyItem prop_channels_types[] = {
- {PS_TFM_ALL, "ALL", 0, "All Properties",
- "All properties, including transforms, bendy bone shape, and custom properties"},
- {PS_TFM_LOC, "LOC", 0, "Location", "Location only"},
- {PS_TFM_ROT, "ROT", 0, "Rotation", "Rotation only"},
- {PS_TFM_SIZE, "SIZE", 0, "Scale", "Scale only"},
- {PS_TFM_BBONE_SHAPE, "BBONE", 0, "Bendy Bone", "Bendy Bone shape properties"},
- {PS_TFM_PROPS, "CUSTOM", 0, "Custom Properties", "Custom properties"},
- {0, NULL, 0, NULL, NULL},
+ {PS_TFM_ALL,
+ "ALL",
+ 0,
+ "All Properties",
+ "All properties, including transforms, bendy bone shape, and custom properties"},
+ {PS_TFM_LOC, "LOC", 0, "Location", "Location only"},
+ {PS_TFM_ROT, "ROT", 0, "Rotation", "Rotation only"},
+ {PS_TFM_SIZE, "SIZE", 0, "Scale", "Scale only"},
+ {PS_TFM_BBONE_SHAPE, "BBONE", 0, "Bendy Bone", "Bendy Bone shape properties"},
+ {PS_TFM_PROPS, "CUSTOM", 0, "Custom Properties", "Custom properties"},
+ {0, NULL, 0, NULL, NULL},
};
/* Axis Locks */
typedef enum ePoseSlide_AxisLock {
- PS_LOCK_X = (1 << 0),
- PS_LOCK_Y = (1 << 1),
- PS_LOCK_Z = (1 << 2),
+ PS_LOCK_X = (1 << 0),
+ PS_LOCK_Y = (1 << 1),
+ PS_LOCK_Z = (1 << 2),
} ePoseSlide_AxisLock;
/* Property enum for ePoseSlide_AxisLock */
static const EnumPropertyItem prop_axis_lock_types[] = {
- {0, "FREE", 0, "Free", "All axes are affected"},
- {PS_LOCK_X, "X", 0, "X", "Only X-axis transforms are affected"},
- {PS_LOCK_Y, "Y", 0, "Y", "Only Y-axis transforms are affected"},
- {PS_LOCK_Z, "Z", 0, "Z", "Only Z-axis transforms are affected"},
- /* TODO: Combinations? */
- {0, NULL, 0, NULL, NULL},
+ {0, "FREE", 0, "Free", "All axes are affected"},
+ {PS_LOCK_X, "X", 0, "X", "Only X-axis transforms are affected"},
+ {PS_LOCK_Y, "Y", 0, "Y", "Only Y-axis transforms are affected"},
+ {PS_LOCK_Z, "Z", 0, "Z", "Only Z-axis transforms are affected"},
+ /* TODO: Combinations? */
+ {0, NULL, 0, NULL, NULL},
};
/* ------------------------------------ */
@@ -184,99 +186,100 @@ static const EnumPropertyItem prop_axis_lock_types[] = {
/* operator init */
static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
{
- tPoseSlideOp *pso;
-
- /* init slide-op data */
- pso = op->customdata = MEM_callocN(sizeof(tPoseSlideOp), "tPoseSlideOp");
-
- /* get info from context */
- pso->scene = CTX_data_scene(C);
- pso->sa = CTX_wm_area(C); /* only really needed when doing modal() */
- pso->ar = CTX_wm_region(C); /* only really needed when doing modal() */
-
- pso->cframe = pso->scene->r.cfra;
- pso->mode = mode;
-
- /* set range info from property values - these may get overridden for the invoke() */
- pso->percentage = RNA_float_get(op->ptr, "percentage");
- pso->prevFrame = RNA_int_get(op->ptr, "prev_frame");
- pso->nextFrame = RNA_int_get(op->ptr, "next_frame");
-
- /* get the set of properties/axes that can be operated on */
- pso->channels = RNA_enum_get(op->ptr, "channels");
- pso->axislock = RNA_enum_get(op->ptr, "axis_lock");
-
- /* for each Pose-Channel which gets affected, get the F-Curves for that channel
- * and set the relevant transform flags... */
- poseAnim_mapping_get(C, &pso->pfLinks);
-
- Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(CTX_data_view_layer(C),
- CTX_wm_view3d(C),
- &pso->objects_len,
- OB_MODE_POSE);
- pso->ob_data_array = MEM_callocN(pso->objects_len * sizeof(tPoseSlideObject), "pose slide objects data");
-
- for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
- tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
- Object *ob_iter = poseAnim_object_get(objects[ob_index]);
-
- /* Ensure validity of the settings from the context. */
- if (ob_iter == NULL) {
- continue;
- }
-
- ob_data->ob = ob_iter;
- ob_data->valid = true;
-
- /* apply NLA mapping corrections so the frame lookups work */
- ob_data->prevFrameF = BKE_nla_tweakedit_remap(ob_data->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
- ob_data->nextFrameF = BKE_nla_tweakedit_remap(ob_data->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP);
-
- /* set depsgraph flags */
- /* make sure the lock is set OK, unlock can be accidentally saved? */
- ob_data->ob->pose->flag |= POSE_LOCKED;
- ob_data->ob->pose->flag &= ~POSE_DO_UNLOCK;
- }
- MEM_freeN(objects);
-
- /* do basic initialize of RB-BST used for finding keyframes, but leave the filling of it up
- * to the caller of this (usually only invoke() will do it, to make things more efficient).
- */
- BLI_dlrbTree_init(&pso->keys);
-
- /* initialise numeric input */
- initNumInput(&pso->num);
- pso->num.idx_max = 0; /* one axis */
- pso->num.val_flag[0] |= NUM_NO_NEGATIVE;
- pso->num.unit_type[0] = B_UNIT_NONE; /* percentages don't have any units... */
-
- /* return status is whether we've got all the data we were requested to get */
- return 1;
+ tPoseSlideOp *pso;
+
+ /* init slide-op data */
+ pso = op->customdata = MEM_callocN(sizeof(tPoseSlideOp), "tPoseSlideOp");
+
+ /* get info from context */
+ pso->scene = CTX_data_scene(C);
+ pso->sa = CTX_wm_area(C); /* only really needed when doing modal() */
+ pso->ar = CTX_wm_region(C); /* only really needed when doing modal() */
+
+ pso->cframe = pso->scene->r.cfra;
+ pso->mode = mode;
+
+ /* set range info from property values - these may get overridden for the invoke() */
+ pso->percentage = RNA_float_get(op->ptr, "percentage");
+ pso->prevFrame = RNA_int_get(op->ptr, "prev_frame");
+ pso->nextFrame = RNA_int_get(op->ptr, "next_frame");
+
+ /* get the set of properties/axes that can be operated on */
+ pso->channels = RNA_enum_get(op->ptr, "channels");
+ pso->axislock = RNA_enum_get(op->ptr, "axis_lock");
+
+ /* for each Pose-Channel which gets affected, get the F-Curves for that channel
+ * and set the relevant transform flags... */
+ poseAnim_mapping_get(C, &pso->pfLinks);
+
+ Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(
+ CTX_data_view_layer(C), CTX_wm_view3d(C), &pso->objects_len, OB_MODE_POSE);
+ pso->ob_data_array = MEM_callocN(pso->objects_len * sizeof(tPoseSlideObject),
+ "pose slide objects data");
+
+ for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
+ tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
+ Object *ob_iter = poseAnim_object_get(objects[ob_index]);
+
+ /* Ensure validity of the settings from the context. */
+ if (ob_iter == NULL) {
+ continue;
+ }
+
+ ob_data->ob = ob_iter;
+ ob_data->valid = true;
+
+ /* apply NLA mapping corrections so the frame lookups work */
+ ob_data->prevFrameF = BKE_nla_tweakedit_remap(
+ ob_data->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
+ ob_data->nextFrameF = BKE_nla_tweakedit_remap(
+ ob_data->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP);
+
+ /* set depsgraph flags */
+ /* make sure the lock is set OK, unlock can be accidentally saved? */
+ ob_data->ob->pose->flag |= POSE_LOCKED;
+ ob_data->ob->pose->flag &= ~POSE_DO_UNLOCK;
+ }
+ MEM_freeN(objects);
+
+ /* do basic initialize of RB-BST used for finding keyframes, but leave the filling of it up
+ * to the caller of this (usually only invoke() will do it, to make things more efficient).
+ */
+ BLI_dlrbTree_init(&pso->keys);
+
+ /* initialise numeric input */
+ initNumInput(&pso->num);
+ pso->num.idx_max = 0; /* one axis */
+ pso->num.val_flag[0] |= NUM_NO_NEGATIVE;
+ pso->num.unit_type[0] = B_UNIT_NONE; /* percentages don't have any units... */
+
+ /* return status is whether we've got all the data we were requested to get */
+ return 1;
}
/* exiting the operator - free data */
static void pose_slide_exit(wmOperator *op)
{
- tPoseSlideOp *pso = op->customdata;
+ tPoseSlideOp *pso = op->customdata;
- /* if data exists, clear its data and exit */
- if (pso) {
- /* free the temp pchan links and their data */
- poseAnim_mapping_free(&pso->pfLinks);
+ /* if data exists, clear its data and exit */
+ if (pso) {
+ /* free the temp pchan links and their data */
+ poseAnim_mapping_free(&pso->pfLinks);
- /* free RB-BST for keyframes (if it contained data) */
- BLI_dlrbTree_free(&pso->keys);
+ /* free RB-BST for keyframes (if it contained data) */
+ BLI_dlrbTree_free(&pso->keys);
- if (pso->ob_data_array != NULL) {
- MEM_freeN(pso->ob_data_array);
- }
+ if (pso->ob_data_array != NULL) {
+ MEM_freeN(pso->ob_data_array);
+ }
- /* free data itself */
- MEM_freeN(pso);
- }
+ /* free data itself */
+ MEM_freeN(pso);
+ }
- /* cleanup */
- op->customdata = NULL;
+ /* cleanup */
+ op->customdata = NULL;
}
/* ------------------------------------ */
@@ -284,438 +287,437 @@ static void pose_slide_exit(wmOperator *op)
/* helper for apply() / reset() - refresh the data */
static void pose_slide_refresh(bContext *C, tPoseSlideOp *pso)
{
- /* wrapper around the generic version, allowing us to add some custom stuff later still */
- for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
- tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
- if (ob_data->valid) {
- poseAnim_mapping_refresh(C, pso->scene, ob_data->ob);
- }
- }
+ /* wrapper around the generic version, allowing us to add some custom stuff later still */
+ for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
+ tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
+ if (ob_data->valid) {
+ poseAnim_mapping_refresh(C, pso->scene, ob_data->ob);
+ }
+ }
}
/**
* Although this lookup is not ideal, we won't be dealing with a lot of objects at a given time.
* But if it comes to that we can instead store prev/next frame in the #tPChanFCurveLink.
*/
-static bool pose_frame_range_from_object_get(tPoseSlideOp *pso, Object *ob, float *prevFrameF, float *nextFrameF)
+static bool pose_frame_range_from_object_get(tPoseSlideOp *pso,
+ Object *ob,
+ float *prevFrameF,
+ float *nextFrameF)
{
- for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
- tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
- Object *ob_iter = ob_data->ob;
-
- if (ob_iter == ob) {
- *prevFrameF = ob_data->prevFrameF;
- *nextFrameF = ob_data->nextFrameF;
- return true;
- }
- }
- *prevFrameF = *nextFrameF = 0.0f;
- return false;
+ for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
+ tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
+ Object *ob_iter = ob_data->ob;
+
+ if (ob_iter == ob) {
+ *prevFrameF = ob_data->prevFrameF;
+ *nextFrameF = ob_data->nextFrameF;
+ return true;
+ }
+ }
+ *prevFrameF = *nextFrameF = 0.0f;
+ return false;
}
/* helper for apply() - perform sliding for some value */
-static void pose_slide_apply_val(
- tPoseSlideOp *pso,
- FCurve *fcu,
- Object *ob,
- float *val)
+static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, Object *ob, float *val)
{
- float prevFrameF, nextFrameF;
- float cframe = (float)pso->cframe;
- float sVal, eVal;
- float w1, w2;
-
- pose_frame_range_from_object_get(pso, ob, &prevFrameF, &nextFrameF);
-
- /* get keyframe values for endpoint poses to blend with */
- /* previous/start */
- sVal = evaluate_fcurve(fcu, prevFrameF);
- /* next/end */
- eVal = evaluate_fcurve(fcu, nextFrameF);
-
- /* if both values are equal, don't do anything */
- if (IS_EQF(sVal, eVal)) {
- (*val) = sVal;
- return;
- }
-
- /* calculate the relative weights of the endpoints */
- if (pso->mode == POSESLIDE_BREAKDOWN) {
- /* get weights from the percentage control */
- w1 = pso->percentage; /* this must come second */
- w2 = 1.0f - w1; /* this must come first */
- }
- else {
- /* - these weights are derived from the relative distance of these
- * poses from the current frame
- * - they then get normalized so that they only sum up to 1
- */
- float wtot;
-
- w1 = cframe - (float)pso->prevFrame;
- w2 = (float)pso->nextFrame - cframe;
-
- wtot = w1 + w2;
- w1 = (w1 / wtot);
- w2 = (w2 / wtot);
- }
-
- /* depending on the mode, calculate the new value
- * - in all of these, the start+end values are multiplied by w2 and w1 (respectively),
- * since multiplication in another order would decrease the value the current frame is closer to
- */
- switch (pso->mode) {
- case POSESLIDE_PUSH: /* make the current pose more pronounced */
- {
- /* perform a weighted average here, favoring the middle pose
- * - numerator should be larger than denominator to 'expand' the result
- * - perform this weighting a number of times given by the percentage...
- */
- /* TODO: maybe a sensitivity ctrl on top of this is needed */
- int iters = (int)ceil(10.0f * pso->percentage);
-
- while (iters-- > 0) {
- (*val) = (-((sVal * w2) + (eVal * w1)) + ((*val) * 6.0f) ) / 5.0f;
- }
- break;
- }
- case POSESLIDE_RELAX: /* make the current pose more like its surrounding ones */
- {
- /* perform a weighted average here, favoring the middle pose
- * - numerator should be smaller than denominator to 'relax' the result
- * - perform this weighting a number of times given by the percentage...
- */
- /* TODO: maybe a sensitivity ctrl on top of this is needed */
- int iters = (int)ceil(10.0f * pso->percentage);
-
- while (iters-- > 0) {
- (*val) = ( ((sVal * w2) + (eVal * w1)) + ((*val) * 5.0f) ) / 6.0f;
- }
- break;
- }
- case POSESLIDE_BREAKDOWN: /* make the current pose slide around between the endpoints */
- {
- /* perform simple linear interpolation - coefficient for start must come from pso->percentage... */
- /* TODO: make this use some kind of spline interpolation instead? */
- (*val) = ((sVal * w2) + (eVal * w1));
- break;
- }
- }
+ float prevFrameF, nextFrameF;
+ float cframe = (float)pso->cframe;
+ float sVal, eVal;
+ float w1, w2;
+
+ pose_frame_range_from_object_get(pso, ob, &prevFrameF, &nextFrameF);
+
+ /* get keyframe values for endpoint poses to blend with */
+ /* previous/start */
+ sVal = evaluate_fcurve(fcu, prevFrameF);
+ /* next/end */
+ eVal = evaluate_fcurve(fcu, nextFrameF);
+
+ /* if both values are equal, don't do anything */
+ if (IS_EQF(sVal, eVal)) {
+ (*val) = sVal;
+ return;
+ }
+
+ /* calculate the relative weights of the endpoints */
+ if (pso->mode == POSESLIDE_BREAKDOWN) {
+ /* get weights from the percentage control */
+ w1 = pso->percentage; /* this must come second */
+ w2 = 1.0f - w1; /* this must come first */
+ }
+ else {
+ /* - these weights are derived from the relative distance of these
+ * poses from the current frame
+ * - they then get normalized so that they only sum up to 1
+ */
+ float wtot;
+
+ w1 = cframe - (float)pso->prevFrame;
+ w2 = (float)pso->nextFrame - cframe;
+
+ wtot = w1 + w2;
+ w1 = (w1 / wtot);
+ w2 = (w2 / wtot);
+ }
+
+ /* depending on the mode, calculate the new value
+ * - in all of these, the start+end values are multiplied by w2 and w1 (respectively),
+ * since multiplication in another order would decrease the value the current frame is closer to
+ */
+ switch (pso->mode) {
+ case POSESLIDE_PUSH: /* make the current pose more pronounced */
+ {
+ /* perform a weighted average here, favoring the middle pose
+ * - numerator should be larger than denominator to 'expand' the result
+ * - perform this weighting a number of times given by the percentage...
+ */
+ /* TODO: maybe a sensitivity ctrl on top of this is needed */
+ int iters = (int)ceil(10.0f * pso->percentage);
+
+ while (iters-- > 0) {
+ (*val) = (-((sVal * w2) + (eVal * w1)) + ((*val) * 6.0f)) / 5.0f;
+ }
+ break;
+ }
+ case POSESLIDE_RELAX: /* make the current pose more like its surrounding ones */
+ {
+ /* perform a weighted average here, favoring the middle pose
+ * - numerator should be smaller than denominator to 'relax' the result
+ * - perform this weighting a number of times given by the percentage...
+ */
+ /* TODO: maybe a sensitivity ctrl on top of this is needed */
+ int iters = (int)ceil(10.0f * pso->percentage);
+
+ while (iters-- > 0) {
+ (*val) = (((sVal * w2) + (eVal * w1)) + ((*val) * 5.0f)) / 6.0f;
+ }
+ break;
+ }
+ case POSESLIDE_BREAKDOWN: /* make the current pose slide around between the endpoints */
+ {
+ /* perform simple linear interpolation - coefficient for start must come from pso->percentage... */
+ /* TODO: make this use some kind of spline interpolation instead? */
+ (*val) = ((sVal * w2) + (eVal * w1));
+ break;
+ }
+ }
}
/* helper for apply() - perform sliding for some 3-element vector */
-static void pose_slide_apply_vec3(tPoseSlideOp *pso, tPChanFCurveLink *pfl, float vec[3], const char propName[])
+static void pose_slide_apply_vec3(tPoseSlideOp *pso,
+ tPChanFCurveLink *pfl,
+ float vec[3],
+ const char propName[])
{
- LinkData *ld = NULL;
- char *path = NULL;
-
- /* get the path to use... */
- path = BLI_sprintfN("%s.%s", pfl->pchan_path, propName);
-
- /* using this path, find each matching F-Curve for the variables we're interested in */
- while ( (ld = poseAnim_mapping_getNextFCurve(&pfl->fcurves, ld, path)) ) {
- FCurve *fcu = (FCurve *)ld->data;
- const int idx = fcu->array_index;
- const int lock = pso->axislock;
-
- /* check if this F-Curve is ok given the current axis locks */
- BLI_assert(fcu->array_index < 3);
-
- if ((lock == 0) ||
- ((lock & PS_LOCK_X) && (idx == 0)) ||
- ((lock & PS_LOCK_Y) && (idx == 1)) ||
- ((lock & PS_LOCK_Z) && (idx == 2)))
- {
- /* just work on these channels one by one... there's no interaction between values */
- pose_slide_apply_val(pso, fcu, pfl->ob, &vec[fcu->array_index]);
- }
- }
-
- /* free the temp path we got */
- MEM_freeN(path);
+ LinkData *ld = NULL;
+ char *path = NULL;
+
+ /* get the path to use... */
+ path = BLI_sprintfN("%s.%s", pfl->pchan_path, propName);
+
+ /* using this path, find each matching F-Curve for the variables we're interested in */
+ while ((ld = poseAnim_mapping_getNextFCurve(&pfl->fcurves, ld, path))) {
+ FCurve *fcu = (FCurve *)ld->data;
+ const int idx = fcu->array_index;
+ const int lock = pso->axislock;
+
+ /* check if this F-Curve is ok given the current axis locks */
+ BLI_assert(fcu->array_index < 3);
+
+ if ((lock == 0) || ((lock & PS_LOCK_X) && (idx == 0)) || ((lock & PS_LOCK_Y) && (idx == 1)) ||
+ ((lock & PS_LOCK_Z) && (idx == 2))) {
+ /* just work on these channels one by one... there's no interaction between values */
+ pose_slide_apply_val(pso, fcu, pfl->ob, &vec[fcu->array_index]);
+ }
+ }
+
+ /* free the temp path we got */
+ MEM_freeN(path);
}
/* helper for apply() - perform sliding for custom properties or bbone properties */
-static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl, const char prop_prefix[])
+static void pose_slide_apply_props(tPoseSlideOp *pso,
+ tPChanFCurveLink *pfl,
+ const char prop_prefix[])
{
- PointerRNA ptr = {{NULL}};
- LinkData *ld;
- int len = strlen(pfl->pchan_path);
-
- /* setup pointer RNA for resolving paths */
- RNA_pointer_create(NULL, &RNA_PoseBone, pfl->pchan, &ptr);
-
- /* - custom properties are just denoted using ["..."][etc.] after the end of the base path,
- * so just check for opening pair after the end of the path
- * - bbone properties are similar, but they always start with a prefix "bbone_*",
- * so a similar method should work here for those too
- */
- for (ld = pfl->fcurves.first; ld; ld = ld->next) {
- FCurve *fcu = (FCurve *)ld->data;
- const char *bPtr, *pPtr;
-
- if (fcu->rna_path == NULL)
- continue;
-
- /* do we have a match?
- * - bPtr is the RNA Path with the standard part chopped off
- * - pPtr is the chunk of the path which is left over
- */
- bPtr = strstr(fcu->rna_path, pfl->pchan_path) + len;
- pPtr = strstr(bPtr, prop_prefix);
-
- if (pPtr) {
- /* use RNA to try and get a handle on this property, then, assuming that it is just
- * numerical, try and grab the value as a float for temp editing before setting back
- */
- PropertyRNA *prop = RNA_struct_find_property(&ptr, pPtr);
-
- if (prop) {
- switch (RNA_property_type(prop)) {
- /* continuous values that can be smoothly interpolated... */
- case PROP_FLOAT:
- {
- float tval = RNA_property_float_get(&ptr, prop);
- pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
- RNA_property_float_set(&ptr, prop, tval);
- break;
- }
- case PROP_INT:
- {
- float tval = (float)RNA_property_int_get(&ptr, prop);
- pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
- RNA_property_int_set(&ptr, prop, (int)tval);
- break;
- }
-
- /* values which can only take discrete values */
- case PROP_BOOLEAN:
- {
- float tval = (float)RNA_property_boolean_get(&ptr, prop);
- pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
- RNA_property_boolean_set(&ptr, prop, (int)tval); // XXX: do we need threshold clamping here?
- break;
- }
- case PROP_ENUM:
- {
- /* don't handle this case - these don't usually represent interchangeable
- * set of values which should be interpolated between
- */
- break;
- }
-
- default:
- /* cannot handle */
- //printf("Cannot Pose Slide non-numerical property\n");
- break;
- }
- }
- }
- }
+ PointerRNA ptr = {{NULL}};
+ LinkData *ld;
+ int len = strlen(pfl->pchan_path);
+
+ /* setup pointer RNA for resolving paths */
+ RNA_pointer_create(NULL, &RNA_PoseBone, pfl->pchan, &ptr);
+
+ /* - custom properties are just denoted using ["..."][etc.] after the end of the base path,
+ * so just check for opening pair after the end of the path
+ * - bbone properties are similar, but they always start with a prefix "bbone_*",
+ * so a similar method should work here for those too
+ */
+ for (ld = pfl->fcurves.first; ld; ld = ld->next) {
+ FCurve *fcu = (FCurve *)ld->data;
+ const char *bPtr, *pPtr;
+
+ if (fcu->rna_path == NULL)
+ continue;
+
+ /* do we have a match?
+ * - bPtr is the RNA Path with the standard part chopped off
+ * - pPtr is the chunk of the path which is left over
+ */
+ bPtr = strstr(fcu->rna_path, pfl->pchan_path) + len;
+ pPtr = strstr(bPtr, prop_prefix);
+
+ if (pPtr) {
+ /* use RNA to try and get a handle on this property, then, assuming that it is just
+ * numerical, try and grab the value as a float for temp editing before setting back
+ */
+ PropertyRNA *prop = RNA_struct_find_property(&ptr, pPtr);
+
+ if (prop) {
+ switch (RNA_property_type(prop)) {
+ /* continuous values that can be smoothly interpolated... */
+ case PROP_FLOAT: {
+ float tval = RNA_property_float_get(&ptr, prop);
+ pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
+ RNA_property_float_set(&ptr, prop, tval);
+ break;
+ }
+ case PROP_INT: {
+ float tval = (float)RNA_property_int_get(&ptr, prop);
+ pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
+ RNA_property_int_set(&ptr, prop, (int)tval);
+ break;
+ }
+
+ /* values which can only take discrete values */
+ case PROP_BOOLEAN: {
+ float tval = (float)RNA_property_boolean_get(&ptr, prop);
+ pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
+ RNA_property_boolean_set(
+ &ptr, prop, (int)tval); // XXX: do we need threshold clamping here?
+ break;
+ }
+ case PROP_ENUM: {
+ /* don't handle this case - these don't usually represent interchangeable
+ * set of values which should be interpolated between
+ */
+ break;
+ }
+
+ default:
+ /* cannot handle */
+ //printf("Cannot Pose Slide non-numerical property\n");
+ break;
+ }
+ }
+ }
+ }
}
/* helper for apply() - perform sliding for quaternion rotations (using quat blending) */
static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
{
- FCurve *fcu_w = NULL, *fcu_x = NULL, *fcu_y = NULL, *fcu_z = NULL;
- bPoseChannel *pchan = pfl->pchan;
- LinkData *ld = NULL;
- char *path = NULL;
- float cframe;
- float prevFrameF, nextFrameF;
-
- if (!pose_frame_range_from_object_get(pso, pfl->ob, &prevFrameF, &nextFrameF)) {
- BLI_assert(!"Invalid pfl data");
- return;
- }
-
- /* get the path to use - this should be quaternion rotations only (needs care) */
- path = BLI_sprintfN("%s.%s", pfl->pchan_path, "rotation_quaternion");
-
- /* get the current frame number */
- cframe = (float)pso->cframe;
-
- /* using this path, find each matching F-Curve for the variables we're interested in */
- while ( (ld = poseAnim_mapping_getNextFCurve(&pfl->fcurves, ld, path)) ) {
- FCurve *fcu = (FCurve *)ld->data;
-
- /* assign this F-Curve to one of the relevant pointers... */
- switch (fcu->array_index) {
- case 3: /* z */
- fcu_z = fcu;
- break;
- case 2: /* y */
- fcu_y = fcu;
- break;
- case 1: /* x */
- fcu_x = fcu;
- break;
- case 0: /* w */
- fcu_w = fcu;
- break;
- }
- }
-
- /* only if all channels exist, proceed */
- if (fcu_w && fcu_x && fcu_y && fcu_z) {
- float quat_prev[4], quat_prev_orig[4];
- float quat_next[4], quat_next_orig[4];
- float quat_curr[4], quat_curr_orig[4];
- float quat_final[4];
-
- copy_qt_qt(quat_curr_orig, pchan->quat);
-
- /* get 2 quats */
- quat_prev_orig[0] = evaluate_fcurve(fcu_w, prevFrameF);
- quat_prev_orig[1] = evaluate_fcurve(fcu_x, prevFrameF);
- quat_prev_orig[2] = evaluate_fcurve(fcu_y, prevFrameF);
- quat_prev_orig[3] = evaluate_fcurve(fcu_z, prevFrameF);
-
- quat_next_orig[0] = evaluate_fcurve(fcu_w, nextFrameF);
- quat_next_orig[1] = evaluate_fcurve(fcu_x, nextFrameF);
- quat_next_orig[2] = evaluate_fcurve(fcu_y, nextFrameF);
- quat_next_orig[3] = evaluate_fcurve(fcu_z, nextFrameF);
-
- normalize_qt_qt(quat_prev, quat_prev_orig);
- normalize_qt_qt(quat_next, quat_next_orig);
- normalize_qt_qt(quat_curr, quat_curr_orig);
-
- /* perform blending */
- if (pso->mode == POSESLIDE_BREAKDOWN) {
- /* just perform the interpol between quat_prev and quat_next using pso->percentage as a guide */
- interp_qt_qtqt(quat_final, quat_prev, quat_next, pso->percentage);
- }
- else if (pso->mode == POSESLIDE_PUSH) {
- float quat_diff[4];
-
- /* calculate the delta transform from the previous to the current */
- /* TODO: investigate ways to favour one transform more? */
- sub_qt_qtqt(quat_diff, quat_curr, quat_prev);
-
- /* increase the original by the delta transform, by an amount determined by percentage */
- add_qt_qtqt(quat_final, quat_curr, quat_diff, pso->percentage);
-
- normalize_qt(quat_final);
- }
- else {
- BLI_assert(pso->mode == POSESLIDE_RELAX);
- float quat_interp[4], quat_final_prev[4];
- /* TODO: maybe a sensitivity ctrl on top of this is needed */
- int iters = (int)ceil(10.0f * pso->percentage);
-
- copy_qt_qt(quat_final, quat_curr);
-
- /* perform this blending several times until a satisfactory result is reached */
- while (iters-- > 0) {
- /* calculate the interpolation between the endpoints */
- interp_qt_qtqt(quat_interp, quat_prev, quat_next, (cframe - pso->prevFrame) / (pso->nextFrame - pso->prevFrame));
-
- normalize_qt_qt(quat_final_prev, quat_final);
-
- /* tricky interpolations - blending between original and new */
- interp_qt_qtqt(quat_final, quat_final_prev, quat_interp, 1.0f / 6.0f);
- }
- }
-
- /* Apply final to the pose bone, keeping compatible for similar keyframe positions. */
- quat_to_compatible_quat(pchan->quat, quat_final, quat_curr_orig);
- }
-
- /* free the path now */
- MEM_freeN(path);
+ FCurve *fcu_w = NULL, *fcu_x = NULL, *fcu_y = NULL, *fcu_z = NULL;
+ bPoseChannel *pchan = pfl->pchan;
+ LinkData *ld = NULL;
+ char *path = NULL;
+ float cframe;
+ float prevFrameF, nextFrameF;
+
+ if (!pose_frame_range_from_object_get(pso, pfl->ob, &prevFrameF, &nextFrameF)) {
+ BLI_assert(!"Invalid pfl data");
+ return;
+ }
+
+ /* get the path to use - this should be quaternion rotations only (needs care) */
+ path = BLI_sprintfN("%s.%s", pfl->pchan_path, "rotation_quaternion");
+
+ /* get the current frame number */
+ cframe = (float)pso->cframe;
+
+ /* using this path, find each matching F-Curve for the variables we're interested in */
+ while ((ld = poseAnim_mapping_getNextFCurve(&pfl->fcurves, ld, path))) {
+ FCurve *fcu = (FCurve *)ld->data;
+
+ /* assign this F-Curve to one of the relevant pointers... */
+ switch (fcu->array_index) {
+ case 3: /* z */
+ fcu_z = fcu;
+ break;
+ case 2: /* y */
+ fcu_y = fcu;
+ break;
+ case 1: /* x */
+ fcu_x = fcu;
+ break;
+ case 0: /* w */
+ fcu_w = fcu;
+ break;
+ }
+ }
+
+ /* only if all channels exist, proceed */
+ if (fcu_w && fcu_x && fcu_y && fcu_z) {
+ float quat_prev[4], quat_prev_orig[4];
+ float quat_next[4], quat_next_orig[4];
+ float quat_curr[4], quat_curr_orig[4];
+ float quat_final[4];
+
+ copy_qt_qt(quat_curr_orig, pchan->quat);
+
+ /* get 2 quats */
+ quat_prev_orig[0] = evaluate_fcurve(fcu_w, prevFrameF);
+ quat_prev_orig[1] = evaluate_fcurve(fcu_x, prevFrameF);
+ quat_prev_orig[2] = evaluate_fcurve(fcu_y, prevFrameF);
+ quat_prev_orig[3] = evaluate_fcurve(fcu_z, prevFrameF);
+
+ quat_next_orig[0] = evaluate_fcurve(fcu_w, nextFrameF);
+ quat_next_orig[1] = evaluate_fcurve(fcu_x, nextFrameF);
+ quat_next_orig[2] = evaluate_fcurve(fcu_y, nextFrameF);
+ quat_next_orig[3] = evaluate_fcurve(fcu_z, nextFrameF);
+
+ normalize_qt_qt(quat_prev, quat_prev_orig);
+ normalize_qt_qt(quat_next, quat_next_orig);
+ normalize_qt_qt(quat_curr, quat_curr_orig);
+
+ /* perform blending */
+ if (pso->mode == POSESLIDE_BREAKDOWN) {
+ /* just perform the interpol between quat_prev and quat_next using pso->percentage as a guide */
+ interp_qt_qtqt(quat_final, quat_prev, quat_next, pso->percentage);
+ }
+ else if (pso->mode == POSESLIDE_PUSH) {
+ float quat_diff[4];
+
+ /* calculate the delta transform from the previous to the current */
+ /* TODO: investigate ways to favour one transform more? */
+ sub_qt_qtqt(quat_diff, quat_curr, quat_prev);
+
+ /* increase the original by the delta transform, by an amount determined by percentage */
+ add_qt_qtqt(quat_final, quat_curr, quat_diff, pso->percentage);
+
+ normalize_qt(quat_final);
+ }
+ else {
+ BLI_assert(pso->mode == POSESLIDE_RELAX);
+ float quat_interp[4], quat_final_prev[4];
+ /* TODO: maybe a sensitivity ctrl on top of this is needed */
+ int iters = (int)ceil(10.0f * pso->percentage);
+
+ copy_qt_qt(quat_final, quat_curr);
+
+ /* perform this blending several times until a satisfactory result is reached */
+ while (iters-- > 0) {
+ /* calculate the interpolation between the endpoints */
+ interp_qt_qtqt(quat_interp,
+ quat_prev,
+ quat_next,
+ (cframe - pso->prevFrame) / (pso->nextFrame - pso->prevFrame));
+
+ normalize_qt_qt(quat_final_prev, quat_final);
+
+ /* tricky interpolations - blending between original and new */
+ interp_qt_qtqt(quat_final, quat_final_prev, quat_interp, 1.0f / 6.0f);
+ }
+ }
+
+ /* Apply final to the pose bone, keeping compatible for similar keyframe positions. */
+ quat_to_compatible_quat(pchan->quat, quat_final, quat_curr_orig);
+ }
+
+ /* free the path now */
+ MEM_freeN(path);
}
/* apply() - perform the pose sliding based on weighting various poses */
static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
{
- tPChanFCurveLink *pfl;
-
- /* sanitise the frame ranges */
- if (pso->prevFrame == pso->nextFrame) {
- /* move out one step either side */
- pso->prevFrame--;
- pso->nextFrame++;
-
- for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
- tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
-
- if (!ob_data->valid) {
- continue;
- }
-
- /* apply NLA mapping corrections so the frame lookups work */
- ob_data->prevFrameF = BKE_nla_tweakedit_remap(ob_data->ob->adt,
- pso->prevFrame,
- NLATIME_CONVERT_UNMAP);
- ob_data->nextFrameF = BKE_nla_tweakedit_remap(ob_data->ob->adt,
- pso->nextFrame,
- NLATIME_CONVERT_UNMAP);
- }
- }
-
- /* for each link, handle each set of transforms */
- for (pfl = pso->pfLinks.first; pfl; pfl = pfl->next) {
- /* valid transforms for each PoseChannel should have been noted already
- * - sliding the pose should be a straightforward exercise for location+rotation,
- * but rotations get more complicated since we may want to use quaternion blending
- * for quaternions instead...
- */
- bPoseChannel *pchan = pfl->pchan;
-
- if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_LOC) && (pchan->flag & POSE_LOC)) {
- /* calculate these for the 'location' vector, and use location curves */
- pose_slide_apply_vec3(pso, pfl, pchan->loc, "location");
- }
-
- if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_SIZE) && (pchan->flag & POSE_SIZE)) {
- /* calculate these for the 'scale' vector, and use scale curves */
- pose_slide_apply_vec3(pso, pfl, pchan->size, "scale");
- }
-
- if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_ROT) && (pchan->flag & POSE_ROT)) {
- /* everything depends on the rotation mode */
- if (pchan->rotmode > 0) {
- /* eulers - so calculate these for the 'eul' vector, and use euler_rotation curves */
- pose_slide_apply_vec3(pso, pfl, pchan->eul, "rotation_euler");
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- /* TODO: need to figure out how to do this! */
- }
- else {
- /* quaternions - use quaternion blending */
- pose_slide_apply_quat(pso, pfl);
- }
- }
-
- if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_BBONE_SHAPE) && (pchan->flag & POSE_BBONE_SHAPE)) {
- /* bbone properties - they all start a "bbone_" prefix */
- pose_slide_apply_props(pso, pfl, "bbone_");
- }
-
- if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_PROPS) && (pfl->oldprops)) {
- /* not strictly a transform, but custom properties contribute to the pose produced in many rigs
- * (e.g. the facial rigs used in Sintel)
- */
- pose_slide_apply_props(pso, pfl, "[\""); /* dummy " for texteditor bugs */
- }
- }
-
- /* depsgraph updates + redraws */
- pose_slide_refresh(C, pso);
+ tPChanFCurveLink *pfl;
+
+ /* sanitise the frame ranges */
+ if (pso->prevFrame == pso->nextFrame) {
+ /* move out one step either side */
+ pso->prevFrame--;
+ pso->nextFrame++;
+
+ for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
+ tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
+
+ if (!ob_data->valid) {
+ continue;
+ }
+
+ /* apply NLA mapping corrections so the frame lookups work */
+ ob_data->prevFrameF = BKE_nla_tweakedit_remap(
+ ob_data->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
+ ob_data->nextFrameF = BKE_nla_tweakedit_remap(
+ ob_data->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP);
+ }
+ }
+
+ /* for each link, handle each set of transforms */
+ for (pfl = pso->pfLinks.first; pfl; pfl = pfl->next) {
+ /* valid transforms for each PoseChannel should have been noted already
+ * - sliding the pose should be a straightforward exercise for location+rotation,
+ * but rotations get more complicated since we may want to use quaternion blending
+ * for quaternions instead...
+ */
+ bPoseChannel *pchan = pfl->pchan;
+
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_LOC) && (pchan->flag & POSE_LOC)) {
+ /* calculate these for the 'location' vector, and use location curves */
+ pose_slide_apply_vec3(pso, pfl, pchan->loc, "location");
+ }
+
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_SIZE) && (pchan->flag & POSE_SIZE)) {
+ /* calculate these for the 'scale' vector, and use scale curves */
+ pose_slide_apply_vec3(pso, pfl, pchan->size, "scale");
+ }
+
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_ROT) && (pchan->flag & POSE_ROT)) {
+ /* everything depends on the rotation mode */
+ if (pchan->rotmode > 0) {
+ /* eulers - so calculate these for the 'eul' vector, and use euler_rotation curves */
+ pose_slide_apply_vec3(pso, pfl, pchan->eul, "rotation_euler");
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ /* TODO: need to figure out how to do this! */
+ }
+ else {
+ /* quaternions - use quaternion blending */
+ pose_slide_apply_quat(pso, pfl);
+ }
+ }
+
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_BBONE_SHAPE) && (pchan->flag & POSE_BBONE_SHAPE)) {
+ /* bbone properties - they all start a "bbone_" prefix */
+ pose_slide_apply_props(pso, pfl, "bbone_");
+ }
+
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_PROPS) && (pfl->oldprops)) {
+ /* not strictly a transform, but custom properties contribute to the pose produced in many rigs
+ * (e.g. the facial rigs used in Sintel)
+ */
+ pose_slide_apply_props(pso, pfl, "[\""); /* dummy " for texteditor bugs */
+ }
+ }
+
+ /* depsgraph updates + redraws */
+ pose_slide_refresh(C, pso);
}
/* perform auto-key-framing after changes were made + confirmed */
static void pose_slide_autoKeyframe(bContext *C, tPoseSlideOp *pso)
{
- /* wrapper around the generic call */
- poseAnim_mapping_autoKeyframe(C, pso->scene, &pso->pfLinks, (float)pso->cframe);
+ /* wrapper around the generic call */
+ poseAnim_mapping_autoKeyframe(C, pso->scene, &pso->pfLinks, (float)pso->cframe);
}
/* reset changes made to current pose */
static void pose_slide_reset(tPoseSlideOp *pso)
{
- /* wrapper around the generic call, so that custom stuff can be added later */
- poseAnim_mapping_reset(&pso->pfLinks);
+ /* wrapper around the generic call, so that custom stuff can be added later */
+ poseAnim_mapping_reset(&pso->pfLinks);
}
/* ------------------------------------ */
@@ -724,425 +726,472 @@ static void pose_slide_reset(tPoseSlideOp *pso)
// TODO: Include hints about locks here...
static void pose_slide_draw_status(tPoseSlideOp *pso)
{
- char status_str[UI_MAX_DRAW_STR];
- char limits_str[UI_MAX_DRAW_STR];
- char axis_str[50];
- char mode_str[32];
-
- switch (pso->mode) {
- case POSESLIDE_PUSH:
- strcpy(mode_str, "Push Pose");
- break;
- case POSESLIDE_RELAX:
- strcpy(mode_str, "Relax Pose");
- break;
- case POSESLIDE_BREAKDOWN:
- strcpy(mode_str, "Breakdown");
- break;
-
- default:
- /* unknown */
- strcpy(mode_str, "Sliding-Tool");
- break;
- }
-
- switch (pso->axislock) {
- case PS_LOCK_X:
- BLI_strncpy(axis_str, "[X]/Y/Z axis only (X to clear)", sizeof(axis_str));
- break;
- case PS_LOCK_Y:
- BLI_strncpy(axis_str, "X/[Y]/Z axis only (Y to clear)", sizeof(axis_str));
- break;
- case PS_LOCK_Z:
- BLI_strncpy(axis_str, "X/Y/[Z] axis only (Z to clear)", sizeof(axis_str));
- break;
-
- default:
- if (ELEM(pso->channels, PS_TFM_LOC, PS_TFM_ROT, PS_TFM_SIZE)) {
- BLI_strncpy(axis_str, "X/Y/Z = Axis Constraint", sizeof(axis_str));
- }
- else {
- axis_str[0] = '\0';
- }
- break;
- }
-
- switch (pso->channels) {
- case PS_TFM_LOC:
- BLI_snprintf(limits_str, sizeof(limits_str), "[G]/R/S/B/C - Location only (G to clear) | %s", axis_str);
- break;
- case PS_TFM_ROT:
- BLI_snprintf(limits_str, sizeof(limits_str), "G/[R]/S/B/C - Rotation only (R to clear) | %s", axis_str);
- break;
- case PS_TFM_SIZE:
- BLI_snprintf(limits_str, sizeof(limits_str), "G/R/[S]/B/C - Scale only (S to clear) | %s", axis_str);
- break;
- case PS_TFM_BBONE_SHAPE:
- BLI_strncpy(limits_str, "G/R/S/[B]/C - Bendy Bone properties only (B to clear) | %s", sizeof(limits_str));
- break;
- case PS_TFM_PROPS:
- BLI_strncpy(limits_str, "G/R/S/B/[C] - Custom Properties only (C to clear) | %s", sizeof(limits_str));
- break;
- default:
- BLI_strncpy(limits_str, "G/R/S/B/C - Limit to Transform/Property Set", sizeof(limits_str));
- break;
- }
-
- if (hasNumInput(&pso->num)) {
- Scene *scene = pso->scene;
- char str_offs[NUM_STR_REP_LEN];
-
- outputNumInput(&pso->num, str_offs, &scene->unit);
-
- BLI_snprintf(status_str, sizeof(status_str), "%s: %s | %s", mode_str, str_offs, limits_str);
- }
- else {
- BLI_snprintf(status_str, sizeof(status_str), "%s: %d %% | %s", mode_str, (int)(pso->percentage * 100.0f), limits_str);
- }
-
- ED_area_status_text(pso->sa, status_str);
+ char status_str[UI_MAX_DRAW_STR];
+ char limits_str[UI_MAX_DRAW_STR];
+ char axis_str[50];
+ char mode_str[32];
+
+ switch (pso->mode) {
+ case POSESLIDE_PUSH:
+ strcpy(mode_str, "Push Pose");
+ break;
+ case POSESLIDE_RELAX:
+ strcpy(mode_str, "Relax Pose");
+ break;
+ case POSESLIDE_BREAKDOWN:
+ strcpy(mode_str, "Breakdown");
+ break;
+
+ default:
+ /* unknown */
+ strcpy(mode_str, "Sliding-Tool");
+ break;
+ }
+
+ switch (pso->axislock) {
+ case PS_LOCK_X:
+ BLI_strncpy(axis_str, "[X]/Y/Z axis only (X to clear)", sizeof(axis_str));
+ break;
+ case PS_LOCK_Y:
+ BLI_strncpy(axis_str, "X/[Y]/Z axis only (Y to clear)", sizeof(axis_str));
+ break;
+ case PS_LOCK_Z:
+ BLI_strncpy(axis_str, "X/Y/[Z] axis only (Z to clear)", sizeof(axis_str));
+ break;
+
+ default:
+ if (ELEM(pso->channels, PS_TFM_LOC, PS_TFM_ROT, PS_TFM_SIZE)) {
+ BLI_strncpy(axis_str, "X/Y/Z = Axis Constraint", sizeof(axis_str));
+ }
+ else {
+ axis_str[0] = '\0';
+ }
+ break;
+ }
+
+ switch (pso->channels) {
+ case PS_TFM_LOC:
+ BLI_snprintf(limits_str,
+ sizeof(limits_str),
+ "[G]/R/S/B/C - Location only (G to clear) | %s",
+ axis_str);
+ break;
+ case PS_TFM_ROT:
+ BLI_snprintf(limits_str,
+ sizeof(limits_str),
+ "G/[R]/S/B/C - Rotation only (R to clear) | %s",
+ axis_str);
+ break;
+ case PS_TFM_SIZE:
+ BLI_snprintf(
+ limits_str, sizeof(limits_str), "G/R/[S]/B/C - Scale only (S to clear) | %s", axis_str);
+ break;
+ case PS_TFM_BBONE_SHAPE:
+ BLI_strncpy(limits_str,
+ "G/R/S/[B]/C - Bendy Bone properties only (B to clear) | %s",
+ sizeof(limits_str));
+ break;
+ case PS_TFM_PROPS:
+ BLI_strncpy(limits_str,
+ "G/R/S/B/[C] - Custom Properties only (C to clear) | %s",
+ sizeof(limits_str));
+ break;
+ default:
+ BLI_strncpy(limits_str, "G/R/S/B/C - Limit to Transform/Property Set", sizeof(limits_str));
+ break;
+ }
+
+ if (hasNumInput(&pso->num)) {
+ Scene *scene = pso->scene;
+ char str_offs[NUM_STR_REP_LEN];
+
+ outputNumInput(&pso->num, str_offs, &scene->unit);
+
+ BLI_snprintf(
+ status_str, sizeof(status_str), "%s: %s | %s", mode_str, str_offs, limits_str);
+ }
+ else {
+ BLI_snprintf(status_str,
+ sizeof(status_str),
+ "%s: %d %% | %s",
+ mode_str,
+ (int)(pso->percentage * 100.0f),
+ limits_str);
+ }
+
+ ED_area_status_text(pso->sa, status_str);
}
/* common code for invoke() methods */
static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *pso)
{
- tPChanFCurveLink *pfl;
- wmWindow *win = CTX_wm_window(C);
-
- /* for each link, add all its keyframes to the search tree */
- for (pfl = pso->pfLinks.first; pfl; pfl = pfl->next) {
- LinkData *ld;
-
- /* do this for each F-Curve */
- for (ld = pfl->fcurves.first; ld; ld = ld->next) {
- FCurve *fcu = (FCurve *)ld->data;
- fcurve_to_keylist(pfl->ob->adt, fcu, &pso->keys, 0);
- }
- }
-
- /* cancel if no keyframes found... */
- if (pso->keys.root) {
- ActKeyColumn *ak;
- float cframe = (float)pso->cframe;
-
- /* firstly, check if the current frame is a keyframe... */
- ak = (ActKeyColumn *)BLI_dlrbTree_search_exact(&pso->keys, compare_ak_cfraPtr, &cframe);
-
- if (ak == NULL) {
- /* current frame is not a keyframe, so search */
- ActKeyColumn *pk = (ActKeyColumn *)BLI_dlrbTree_search_prev(&pso->keys, compare_ak_cfraPtr, &cframe);
- ActKeyColumn *nk = (ActKeyColumn *)BLI_dlrbTree_search_next(&pso->keys, compare_ak_cfraPtr, &cframe);
-
- /* new set the frames */
- /* prev frame */
- pso->prevFrame = (pk) ? (pk->cfra) : (pso->cframe - 1);
- RNA_int_set(op->ptr, "prev_frame", pso->prevFrame);
- /* next frame */
- pso->nextFrame = (nk) ? (nk->cfra) : (pso->cframe + 1);
- RNA_int_set(op->ptr, "next_frame", pso->nextFrame);
- }
- else {
- /* current frame itself is a keyframe, so just take keyframes on either side */
- /* prev frame */
- pso->prevFrame = (ak->prev) ? (ak->prev->cfra) : (pso->cframe - 1);
- RNA_int_set(op->ptr, "prev_frame", pso->prevFrame);
- /* next frame */
- pso->nextFrame = (ak->next) ? (ak->next->cfra) : (pso->cframe + 1);
- RNA_int_set(op->ptr, "next_frame", pso->nextFrame);
- }
-
- /* apply NLA mapping corrections so the frame lookups work */
- for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
- tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
- if (ob_data->valid) {
- ob_data->prevFrameF = BKE_nla_tweakedit_remap(ob_data->ob->adt,
- pso->prevFrame,
- NLATIME_CONVERT_UNMAP);
- ob_data->nextFrameF = BKE_nla_tweakedit_remap(ob_data->ob->adt,
- pso->nextFrame,
- NLATIME_CONVERT_UNMAP);
- }
- }
- }
- else {
- BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between");
- pose_slide_exit(op);
- return OPERATOR_CANCELLED;
- }
-
- /* initial apply for operator... */
- /* TODO: need to calculate percentage for initial round too... */
- pose_slide_apply(C, pso);
-
- /* depsgraph updates + redraws */
- pose_slide_refresh(C, pso);
-
- /* set cursor to indicate modal */
- WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR);
-
- /* header print */
- pose_slide_draw_status(pso);
-
- /* add a modal handler for this operator */
- WM_event_add_modal_handler(C, op);
- return OPERATOR_RUNNING_MODAL;
+ tPChanFCurveLink *pfl;
+ wmWindow *win = CTX_wm_window(C);
+
+ /* for each link, add all its keyframes to the search tree */
+ for (pfl = pso->pfLinks.first; pfl; pfl = pfl->next) {
+ LinkData *ld;
+
+ /* do this for each F-Curve */
+ for (ld = pfl->fcurves.first; ld; ld = ld->next) {
+ FCurve *fcu = (FCurve *)ld->data;
+ fcurve_to_keylist(pfl->ob->adt, fcu, &pso->keys, 0);
+ }
+ }
+
+ /* cancel if no keyframes found... */
+ if (pso->keys.root) {
+ ActKeyColumn *ak;
+ float cframe = (float)pso->cframe;
+
+ /* firstly, check if the current frame is a keyframe... */
+ ak = (ActKeyColumn *)BLI_dlrbTree_search_exact(&pso->keys, compare_ak_cfraPtr, &cframe);
+
+ if (ak == NULL) {
+ /* current frame is not a keyframe, so search */
+ ActKeyColumn *pk = (ActKeyColumn *)BLI_dlrbTree_search_prev(
+ &pso->keys, compare_ak_cfraPtr, &cframe);
+ ActKeyColumn *nk = (ActKeyColumn *)BLI_dlrbTree_search_next(
+ &pso->keys, compare_ak_cfraPtr, &cframe);
+
+ /* new set the frames */
+ /* prev frame */
+ pso->prevFrame = (pk) ? (pk->cfra) : (pso->cframe - 1);
+ RNA_int_set(op->ptr, "prev_frame", pso->prevFrame);
+ /* next frame */
+ pso->nextFrame = (nk) ? (nk->cfra) : (pso->cframe + 1);
+ RNA_int_set(op->ptr, "next_frame", pso->nextFrame);
+ }
+ else {
+ /* current frame itself is a keyframe, so just take keyframes on either side */
+ /* prev frame */
+ pso->prevFrame = (ak->prev) ? (ak->prev->cfra) : (pso->cframe - 1);
+ RNA_int_set(op->ptr, "prev_frame", pso->prevFrame);
+ /* next frame */
+ pso->nextFrame = (ak->next) ? (ak->next->cfra) : (pso->cframe + 1);
+ RNA_int_set(op->ptr, "next_frame", pso->nextFrame);
+ }
+
+ /* apply NLA mapping corrections so the frame lookups work */
+ for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
+ tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
+ if (ob_data->valid) {
+ ob_data->prevFrameF = BKE_nla_tweakedit_remap(
+ ob_data->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
+ ob_data->nextFrameF = BKE_nla_tweakedit_remap(
+ ob_data->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP);
+ }
+ }
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between");
+ pose_slide_exit(op);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* initial apply for operator... */
+ /* TODO: need to calculate percentage for initial round too... */
+ pose_slide_apply(C, pso);
+
+ /* depsgraph updates + redraws */
+ pose_slide_refresh(C, pso);
+
+ /* set cursor to indicate modal */
+ WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR);
+
+ /* header print */
+ pose_slide_draw_status(pso);
+
+ /* add a modal handler for this operator */
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
}
/* calculate percentage based on position of mouse (we only use x-axis for now.
* since this is more convenient for users to do), and store new percentage value
*/
-static void pose_slide_mouse_update_percentage(tPoseSlideOp *pso, wmOperator *op, const wmEvent *event)
+static void pose_slide_mouse_update_percentage(tPoseSlideOp *pso,
+ wmOperator *op,
+ const wmEvent *event)
{
- pso->percentage = (event->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx);
- RNA_float_set(op->ptr, "percentage", pso->percentage);
+ pso->percentage = (event->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx);
+ RNA_float_set(op->ptr, "percentage", pso->percentage);
}
/* handle an event to toggle channels mode */
-static void pose_slide_toggle_channels_mode(wmOperator *op, tPoseSlideOp *pso, ePoseSlide_Channels channel)
+static void pose_slide_toggle_channels_mode(wmOperator *op,
+ tPoseSlideOp *pso,
+ ePoseSlide_Channels channel)
{
- /* Turn channel on or off? */
- if (pso->channels == channel) {
- /* Already limiting to transform only, so pressing this again turns it off */
- pso->channels = PS_TFM_ALL;
- }
- else {
- /* Only this set of channels */
- pso->channels = channel;
- }
- RNA_enum_set(op->ptr, "channels", pso->channels);
-
-
- /* Reset axis limits too for good measure */
- pso->axislock = 0;
- RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
+ /* Turn channel on or off? */
+ if (pso->channels == channel) {
+ /* Already limiting to transform only, so pressing this again turns it off */
+ pso->channels = PS_TFM_ALL;
+ }
+ else {
+ /* Only this set of channels */
+ pso->channels = channel;
+ }
+ RNA_enum_set(op->ptr, "channels", pso->channels);
+
+ /* Reset axis limits too for good measure */
+ pso->axislock = 0;
+ RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
}
/* handle an event to toggle axis locks - returns whether any change in state is needed */
-static bool pose_slide_toggle_axis_locks(wmOperator *op, tPoseSlideOp *pso, ePoseSlide_AxisLock axis)
+static bool pose_slide_toggle_axis_locks(wmOperator *op,
+ tPoseSlideOp *pso,
+ ePoseSlide_AxisLock axis)
{
- /* Axis can only be set when a transform is set - it doesn't make sense otherwise */
- if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_BBONE_SHAPE, PS_TFM_PROPS)) {
- pso->axislock = 0;
- RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
- return false;
- }
-
- /* Turn on or off? */
- if (pso->axislock == axis) {
- /* Already limiting on this axis, so turn off */
- pso->axislock = 0;
- }
- else {
- /* Only this axis */
- pso->axislock = axis;
- }
- RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
-
- /* Setting changed, so pose update is needed */
- return true;
+ /* Axis can only be set when a transform is set - it doesn't make sense otherwise */
+ if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_BBONE_SHAPE, PS_TFM_PROPS)) {
+ pso->axislock = 0;
+ RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
+ return false;
+ }
+
+ /* Turn on or off? */
+ if (pso->axislock == axis) {
+ /* Already limiting on this axis, so turn off */
+ pso->axislock = 0;
+ }
+ else {
+ /* Only this axis */
+ pso->axislock = axis;
+ }
+ RNA_enum_set(op->ptr, "axis_lock", pso->axislock);
+
+ /* Setting changed, so pose update is needed */
+ return true;
}
/* common code for modal() */
static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- tPoseSlideOp *pso = op->customdata;
- wmWindow *win = CTX_wm_window(C);
- bool do_pose_update = false;
-
- const bool has_numinput = hasNumInput(&pso->num);
-
- switch (event->type) {
- case LEFTMOUSE: /* confirm */
- case RETKEY:
- case PADENTER:
- {
- /* return to normal cursor and header status */
- ED_area_status_text(pso->sa, NULL);
- WM_cursor_modal_restore(win);
-
- /* insert keyframes as required... */
- pose_slide_autoKeyframe(C, pso);
- pose_slide_exit(op);
-
- /* done! */
- return OPERATOR_FINISHED;
- }
-
- case ESCKEY: /* cancel */
- case RIGHTMOUSE:
- {
- /* return to normal cursor and header status */
- ED_area_status_text(pso->sa, NULL);
- WM_cursor_modal_restore(win);
-
- /* reset transforms back to original state */
- pose_slide_reset(pso);
-
- /* depsgraph updates + redraws */
- pose_slide_refresh(C, pso);
-
- /* clean up temp data */
- pose_slide_exit(op);
-
- /* canceled! */
- return OPERATOR_CANCELLED;
- }
-
- /* Percentage Chane... */
- case MOUSEMOVE: /* calculate new position */
- {
- /* only handle mousemove if not doing numinput */
- if (has_numinput == false) {
- /* update percentage based on position of mouse */
- pose_slide_mouse_update_percentage(pso, op, event);
-
- /* update pose to reflect the new values (see below) */
- do_pose_update = true;
- }
- break;
- }
- default:
- {
- if ((event->val == KM_PRESS) && handleNumInput(C, &pso->num, event)) {
- float value;
-
- /* Grab percentage from numeric input, and store this new value for redo
- * NOTE: users see ints, while internally we use a 0-1 float
- */
- value = pso->percentage * 100.0f;
- applyNumInput(&pso->num, &value);
-
- pso->percentage = value / 100.0f;
- CLAMP(pso->percentage, 0.0f, 1.0f);
- RNA_float_set(op->ptr, "percentage", pso->percentage);
-
- /* Update pose to reflect the new values (see below) */
- do_pose_update = true;
- break;
- }
- else if (event->val == KM_PRESS) {
- switch (event->type) {
- /* Transform Channel Limits */
- /* XXX: Replace these hardcoded hotkeys with a modalmap that can be customised */
- case GKEY: /* Location */
- {
- pose_slide_toggle_channels_mode(op, pso, PS_TFM_LOC);
- do_pose_update = true;
- break;
- }
- case RKEY: /* Rotation */
- {
- pose_slide_toggle_channels_mode(op, pso, PS_TFM_ROT);
- do_pose_update = true;
- break;
- }
- case SKEY: /* Scale */
- {
- pose_slide_toggle_channels_mode(op, pso, PS_TFM_SIZE);
- do_pose_update = true;
- break;
- }
- case BKEY: /* Bendy Bones */
- {
- pose_slide_toggle_channels_mode(op, pso, PS_TFM_BBONE_SHAPE);
- do_pose_update = true;
- break;
- }
- case CKEY: /* Custom Properties */
- {
- pose_slide_toggle_channels_mode(op, pso, PS_TFM_PROPS);
- do_pose_update = true;
- break;
- }
-
-
- /* Axis Locks */
- /* XXX: Hardcoded... */
- case XKEY:
- {
- if (pose_slide_toggle_axis_locks(op, pso, PS_LOCK_X)) {
- do_pose_update = true;
- }
- break;
- }
- case YKEY:
- {
- if (pose_slide_toggle_axis_locks(op, pso, PS_LOCK_Y)) {
- do_pose_update = true;
- }
- break;
- }
- case ZKEY:
- {
- if (pose_slide_toggle_axis_locks(op, pso, PS_LOCK_Z)) {
- do_pose_update = true;
- }
- break;
- }
-
-
- default: /* Some other unhandled key... */
- break;
- }
- }
- else {
- /* unhandled event - maybe it was some view manip? */
- /* allow to pass through */
- return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
- }
- }
- }
-
-
- /* perform pose updates - in response to some user action (e.g. pressing a key or moving the mouse) */
- if (do_pose_update) {
- /* update percentage indicator in header */
- pose_slide_draw_status(pso);
-
- /* reset transforms (to avoid accumulation errors) */
- pose_slide_reset(pso);
-
- /* apply... */
- pose_slide_apply(C, pso);
- }
-
- /* still running... */
- return OPERATOR_RUNNING_MODAL;
+ tPoseSlideOp *pso = op->customdata;
+ wmWindow *win = CTX_wm_window(C);
+ bool do_pose_update = false;
+
+ const bool has_numinput = hasNumInput(&pso->num);
+
+ switch (event->type) {
+ case LEFTMOUSE: /* confirm */
+ case RETKEY:
+ case PADENTER: {
+ /* return to normal cursor and header status */
+ ED_area_status_text(pso->sa, NULL);
+ WM_cursor_modal_restore(win);
+
+ /* insert keyframes as required... */
+ pose_slide_autoKeyframe(C, pso);
+ pose_slide_exit(op);
+
+ /* done! */
+ return OPERATOR_FINISHED;
+ }
+
+ case ESCKEY: /* cancel */
+ case RIGHTMOUSE: {
+ /* return to normal cursor and header status */
+ ED_area_status_text(pso->sa, NULL);
+ WM_cursor_modal_restore(win);
+
+ /* reset transforms back to original state */
+ pose_slide_reset(pso);
+
+ /* depsgraph updates + redraws */
+ pose_slide_refresh(C, pso);
+
+ /* clean up temp data */
+ pose_slide_exit(op);
+
+ /* canceled! */
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Percentage Chane... */
+ case MOUSEMOVE: /* calculate new position */
+ {
+ /* only handle mousemove if not doing numinput */
+ if (has_numinput == false) {
+ /* update percentage based on position of mouse */
+ pose_slide_mouse_update_percentage(pso, op, event);
+
+ /* update pose to reflect the new values (see below) */
+ do_pose_update = true;
+ }
+ break;
+ }
+ default: {
+ if ((event->val == KM_PRESS) && handleNumInput(C, &pso->num, event)) {
+ float value;
+
+ /* Grab percentage from numeric input, and store this new value for redo
+ * NOTE: users see ints, while internally we use a 0-1 float
+ */
+ value = pso->percentage * 100.0f;
+ applyNumInput(&pso->num, &value);
+
+ pso->percentage = value / 100.0f;
+ CLAMP(pso->percentage, 0.0f, 1.0f);
+ RNA_float_set(op->ptr, "percentage", pso->percentage);
+
+ /* Update pose to reflect the new values (see below) */
+ do_pose_update = true;
+ break;
+ }
+ else if (event->val == KM_PRESS) {
+ switch (event->type) {
+ /* Transform Channel Limits */
+ /* XXX: Replace these hardcoded hotkeys with a modalmap that can be customised */
+ case GKEY: /* Location */
+ {
+ pose_slide_toggle_channels_mode(op, pso, PS_TFM_LOC);
+ do_pose_update = true;
+ break;
+ }
+ case RKEY: /* Rotation */
+ {
+ pose_slide_toggle_channels_mode(op, pso, PS_TFM_ROT);
+ do_pose_update = true;
+ break;
+ }
+ case SKEY: /* Scale */
+ {
+ pose_slide_toggle_channels_mode(op, pso, PS_TFM_SIZE);
+ do_pose_update = true;
+ break;
+ }
+ case BKEY: /* Bendy Bones */
+ {
+ pose_slide_toggle_channels_mode(op, pso, PS_TFM_BBONE_SHAPE);
+ do_pose_update = true;
+ break;
+ }
+ case CKEY: /* Custom Properties */
+ {
+ pose_slide_toggle_channels_mode(op, pso, PS_TFM_PROPS);
+ do_pose_update = true;
+ break;
+ }
+
+ /* Axis Locks */
+ /* XXX: Hardcoded... */
+ case XKEY: {
+ if (pose_slide_toggle_axis_locks(op, pso, PS_LOCK_X)) {
+ do_pose_update = true;
+ }
+ break;
+ }
+ case YKEY: {
+ if (pose_slide_toggle_axis_locks(op, pso, PS_LOCK_Y)) {
+ do_pose_update = true;
+ }
+ break;
+ }
+ case ZKEY: {
+ if (pose_slide_toggle_axis_locks(op, pso, PS_LOCK_Z)) {
+ do_pose_update = true;
+ }
+ break;
+ }
+
+ default: /* Some other unhandled key... */
+ break;
+ }
+ }
+ else {
+ /* unhandled event - maybe it was some view manip? */
+ /* allow to pass through */
+ return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
+ }
+ }
+ }
+
+ /* perform pose updates - in response to some user action (e.g. pressing a key or moving the mouse) */
+ if (do_pose_update) {
+ /* update percentage indicator in header */
+ pose_slide_draw_status(pso);
+
+ /* reset transforms (to avoid accumulation errors) */
+ pose_slide_reset(pso);
+
+ /* apply... */
+ pose_slide_apply(C, pso);
+ }
+
+ /* still running... */
+ return OPERATOR_RUNNING_MODAL;
}
/* common code for cancel() */
static void pose_slide_cancel(bContext *UNUSED(C), wmOperator *op)
{
- /* cleanup and done */
- pose_slide_exit(op);
+ /* cleanup and done */
+ pose_slide_exit(op);
}
/* common code for exec() methods */
static int pose_slide_exec_common(bContext *C, wmOperator *op, tPoseSlideOp *pso)
{
- /* settings should have been set up ok for applying, so just apply! */
- pose_slide_apply(C, pso);
+ /* settings should have been set up ok for applying, so just apply! */
+ pose_slide_apply(C, pso);
- /* insert keyframes if needed */
- pose_slide_autoKeyframe(C, pso);
+ /* insert keyframes if needed */
+ pose_slide_autoKeyframe(C, pso);
- /* cleanup and done */
- pose_slide_exit(op);
+ /* cleanup and done */
+ pose_slide_exit(op);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
/* common code for defining RNA properties */
/* TODO: Skip save on these? */
static void pose_slide_opdef_properties(wmOperatorType *ot)
{
- RNA_def_float_percentage(ot->srna, "percentage", 0.5f, 0.0f, 1.0f, "Percentage", "Weighting factor for which keyframe is favored more", 0.3, 0.7);
-
- RNA_def_int(ot->srna, "prev_frame", 0, MINAFRAME, MAXFRAME, "Previous Keyframe", "Frame number of keyframe immediately before the current frame", 0, 50);
- RNA_def_int(ot->srna, "next_frame", 0, MINAFRAME, MAXFRAME, "Next Keyframe", "Frame number of keyframe immediately after the current frame", 0, 50);
-
- RNA_def_enum(ot->srna, "channels", prop_channels_types, PS_TFM_ALL, "Channels", "Set of properties that are affected");
- RNA_def_enum(ot->srna, "axis_lock", prop_axis_lock_types, 0, "Axis Lock", "Transform axis to restrict effects to");
+ RNA_def_float_percentage(ot->srna,
+ "percentage",
+ 0.5f,
+ 0.0f,
+ 1.0f,
+ "Percentage",
+ "Weighting factor for which keyframe is favored more",
+ 0.3,
+ 0.7);
+
+ RNA_def_int(ot->srna,
+ "prev_frame",
+ 0,
+ MINAFRAME,
+ MAXFRAME,
+ "Previous Keyframe",
+ "Frame number of keyframe immediately before the current frame",
+ 0,
+ 50);
+ RNA_def_int(ot->srna,
+ "next_frame",
+ 0,
+ MINAFRAME,
+ MAXFRAME,
+ "Next Keyframe",
+ "Frame number of keyframe immediately after the current frame",
+ 0,
+ 50);
+
+ RNA_def_enum(ot->srna,
+ "channels",
+ prop_channels_types,
+ PS_TFM_ALL,
+ "Channels",
+ "Set of properties that are affected");
+ RNA_def_enum(ot->srna,
+ "axis_lock",
+ prop_axis_lock_types,
+ 0,
+ "Axis Lock",
+ "Transform axis to restrict effects to");
}
/* ------------------------------------ */
@@ -1150,59 +1199,59 @@ static void pose_slide_opdef_properties(wmOperatorType *ot)
/* invoke() - for 'push' mode */
static int pose_slide_push_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- tPoseSlideOp *pso;
+ tPoseSlideOp *pso;
- /* initialize data */
- if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
- pose_slide_exit(op);
- return OPERATOR_CANCELLED;
- }
- else
- pso = op->customdata;
+ /* initialize data */
+ if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
+ pose_slide_exit(op);
+ return OPERATOR_CANCELLED;
+ }
+ else
+ pso = op->customdata;
- /* initialise percentage so that it won't pop on first mouse move */
- pose_slide_mouse_update_percentage(pso, op, event);
+ /* initialise percentage so that it won't pop on first mouse move */
+ pose_slide_mouse_update_percentage(pso, op, event);
- /* do common setup work */
- return pose_slide_invoke_common(C, op, pso);
+ /* do common setup work */
+ return pose_slide_invoke_common(C, op, pso);
}
/* exec() - for push */
static int pose_slide_push_exec(bContext *C, wmOperator *op)
{
- tPoseSlideOp *pso;
-
- /* initialize data (from RNA-props) */
- if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
- pose_slide_exit(op);
- return OPERATOR_CANCELLED;
- }
- else
- pso = op->customdata;
-
- /* do common exec work */
- return pose_slide_exec_common(C, op, pso);
+ tPoseSlideOp *pso;
+
+ /* initialize data (from RNA-props) */
+ if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) {
+ pose_slide_exit(op);
+ return OPERATOR_CANCELLED;
+ }
+ else
+ pso = op->customdata;
+
+ /* do common exec work */
+ return pose_slide_exec_common(C, op, pso);
}
void POSE_OT_push(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Push Pose";
- ot->idname = "POSE_OT_push";
- ot->description = "Exaggerate the current pose";
-
- /* callbacks */
- ot->exec = pose_slide_push_exec;
- ot->invoke = pose_slide_push_invoke;
- ot->modal = pose_slide_modal;
- ot->cancel = pose_slide_cancel;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
-
- /* Properties */
- pose_slide_opdef_properties(ot);
+ /* identifiers */
+ ot->name = "Push Pose";
+ ot->idname = "POSE_OT_push";
+ ot->description = "Exaggerate the current pose";
+
+ /* callbacks */
+ ot->exec = pose_slide_push_exec;
+ ot->invoke = pose_slide_push_invoke;
+ ot->modal = pose_slide_modal;
+ ot->cancel = pose_slide_cancel;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* Properties */
+ pose_slide_opdef_properties(ot);
}
/* ........................ */
@@ -1210,59 +1259,59 @@ void POSE_OT_push(wmOperatorType *ot)
/* invoke() - for 'relax' mode */
static int pose_slide_relax_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- tPoseSlideOp *pso;
+ tPoseSlideOp *pso;
- /* initialize data */
- if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
- pose_slide_exit(op);
- return OPERATOR_CANCELLED;
- }
- else
- pso = op->customdata;
+ /* initialize data */
+ if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
+ pose_slide_exit(op);
+ return OPERATOR_CANCELLED;
+ }
+ else
+ pso = op->customdata;
- /* initialise percentage so that it won't pop on first mouse move */
- pose_slide_mouse_update_percentage(pso, op, event);
+ /* initialise percentage so that it won't pop on first mouse move */
+ pose_slide_mouse_update_percentage(pso, op, event);
- /* do common setup work */
- return pose_slide_invoke_common(C, op, pso);
+ /* do common setup work */
+ return pose_slide_invoke_common(C, op, pso);
}
/* exec() - for relax */
static int pose_slide_relax_exec(bContext *C, wmOperator *op)
{
- tPoseSlideOp *pso;
-
- /* initialize data (from RNA-props) */
- if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
- pose_slide_exit(op);
- return OPERATOR_CANCELLED;
- }
- else
- pso = op->customdata;
-
- /* do common exec work */
- return pose_slide_exec_common(C, op, pso);
+ tPoseSlideOp *pso;
+
+ /* initialize data (from RNA-props) */
+ if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) {
+ pose_slide_exit(op);
+ return OPERATOR_CANCELLED;
+ }
+ else
+ pso = op->customdata;
+
+ /* do common exec work */
+ return pose_slide_exec_common(C, op, pso);
}
void POSE_OT_relax(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Relax Pose";
- ot->idname = "POSE_OT_relax";
- ot->description = "Make the current pose more similar to its surrounding ones";
-
- /* callbacks */
- ot->exec = pose_slide_relax_exec;
- ot->invoke = pose_slide_relax_invoke;
- ot->modal = pose_slide_modal;
- ot->cancel = pose_slide_cancel;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
-
- /* Properties */
- pose_slide_opdef_properties(ot);
+ /* identifiers */
+ ot->name = "Relax Pose";
+ ot->idname = "POSE_OT_relax";
+ ot->description = "Make the current pose more similar to its surrounding ones";
+
+ /* callbacks */
+ ot->exec = pose_slide_relax_exec;
+ ot->invoke = pose_slide_relax_invoke;
+ ot->modal = pose_slide_modal;
+ ot->cancel = pose_slide_cancel;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* Properties */
+ pose_slide_opdef_properties(ot);
}
/* ........................ */
@@ -1270,59 +1319,59 @@ void POSE_OT_relax(wmOperatorType *ot)
/* invoke() - for 'breakdown' mode */
static int pose_slide_breakdown_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- tPoseSlideOp *pso;
+ tPoseSlideOp *pso;
- /* initialize data */
- if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
- pose_slide_exit(op);
- return OPERATOR_CANCELLED;
- }
- else
- pso = op->customdata;
+ /* initialize data */
+ if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
+ pose_slide_exit(op);
+ return OPERATOR_CANCELLED;
+ }
+ else
+ pso = op->customdata;
- /* initialise percentage so that it won't pop on first mouse move */
- pose_slide_mouse_update_percentage(pso, op, event);
+ /* initialise percentage so that it won't pop on first mouse move */
+ pose_slide_mouse_update_percentage(pso, op, event);
- /* do common setup work */
- return pose_slide_invoke_common(C, op, pso);
+ /* do common setup work */
+ return pose_slide_invoke_common(C, op, pso);
}
/* exec() - for breakdown */
static int pose_slide_breakdown_exec(bContext *C, wmOperator *op)
{
- tPoseSlideOp *pso;
-
- /* initialize data (from RNA-props) */
- if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
- pose_slide_exit(op);
- return OPERATOR_CANCELLED;
- }
- else
- pso = op->customdata;
-
- /* do common exec work */
- return pose_slide_exec_common(C, op, pso);
+ tPoseSlideOp *pso;
+
+ /* initialize data (from RNA-props) */
+ if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) {
+ pose_slide_exit(op);
+ return OPERATOR_CANCELLED;
+ }
+ else
+ pso = op->customdata;
+
+ /* do common exec work */
+ return pose_slide_exec_common(C, op, pso);
}
void POSE_OT_breakdown(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Pose Breakdowner";
- ot->idname = "POSE_OT_breakdown";
- ot->description = "Create a suitable breakdown pose on the current frame";
-
- /* callbacks */
- ot->exec = pose_slide_breakdown_exec;
- ot->invoke = pose_slide_breakdown_invoke;
- ot->modal = pose_slide_modal;
- ot->cancel = pose_slide_cancel;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
-
- /* Properties */
- pose_slide_opdef_properties(ot);
+ /* identifiers */
+ ot->name = "Pose Breakdowner";
+ ot->idname = "POSE_OT_breakdown";
+ ot->description = "Create a suitable breakdown pose on the current frame";
+
+ /* callbacks */
+ ot->exec = pose_slide_breakdown_exec;
+ ot->invoke = pose_slide_breakdown_invoke;
+ ot->modal = pose_slide_modal;
+ ot->cancel = pose_slide_cancel;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* Properties */
+ pose_slide_opdef_properties(ot);
}
/* **************************************************** */
@@ -1330,30 +1379,30 @@ void POSE_OT_breakdown(wmOperatorType *ot)
/* "termination conditions" - i.e. when we stop */
typedef enum ePosePropagate_Termination {
- /* stop after the current hold ends */
- POSE_PROPAGATE_SMART_HOLDS = 0,
- /* only do on the last keyframe */
- POSE_PROPAGATE_LAST_KEY,
- /* stop after the next keyframe */
- POSE_PROPAGATE_NEXT_KEY,
- /* stop after the specified frame */
- POSE_PROPAGATE_BEFORE_FRAME,
- /* stop when we run out of keyframes */
- POSE_PROPAGATE_BEFORE_END,
-
- /* only do on keyframes that are selected */
- POSE_PROPAGATE_SELECTED_KEYS,
- /* only do on the frames where markers are selected */
- POSE_PROPAGATE_SELECTED_MARKERS,
+ /* stop after the current hold ends */
+ POSE_PROPAGATE_SMART_HOLDS = 0,
+ /* only do on the last keyframe */
+ POSE_PROPAGATE_LAST_KEY,
+ /* stop after the next keyframe */
+ POSE_PROPAGATE_NEXT_KEY,
+ /* stop after the specified frame */
+ POSE_PROPAGATE_BEFORE_FRAME,
+ /* stop when we run out of keyframes */
+ POSE_PROPAGATE_BEFORE_END,
+
+ /* only do on keyframes that are selected */
+ POSE_PROPAGATE_SELECTED_KEYS,
+ /* only do on the frames where markers are selected */
+ POSE_PROPAGATE_SELECTED_MARKERS,
} ePosePropagate_Termination;
/* termination data needed for some modes - assumes only one of these entries will be needed at a time */
typedef union tPosePropagate_ModeData {
- /* smart holds + before frame: frame number to stop on */
- float end_frame;
+ /* smart holds + before frame: frame number to stop on */
+ float end_frame;
- /* selected markers: listbase for CfraElem's marking these frames */
- ListBase sel_markers;
+ /* selected markers: listbase for CfraElem's marking these frames */
+ ListBase sel_markers;
} tPosePropagate_ModeData;
/* --------------------------------- */
@@ -1365,333 +1414,371 @@ typedef union tPosePropagate_ModeData {
*/
static float pose_propagate_get_boneHoldEndFrame(tPChanFCurveLink *pfl, float startFrame)
{
- DLRBT_Tree keys;
-
- Object *ob = pfl->ob;
- AnimData *adt = ob->adt;
- LinkData *ld;
- float endFrame = startFrame;
-
- /* set up optimized data-structures for searching for relevant keyframes + holds */
- BLI_dlrbTree_init(&keys);
-
- for (ld = pfl->fcurves.first; ld; ld = ld->next) {
- FCurve *fcu = (FCurve *)ld->data;
- fcurve_to_keylist(adt, fcu, &keys, 0);
- }
-
- /* find the long keyframe (i.e. hold), and hence obtain the endFrame value
- * - the best case would be one that starts on the frame itself
- */
- ActKeyColumn *ab = (ActKeyColumn *)BLI_dlrbTree_search_exact(&keys, compare_ak_cfraPtr, &startFrame);
-
- /* There are only two cases for no-exact match:
- * 1) the current frame is just before another key but not on a key itself
- * 2) the current frame is on a key, but that key doesn't link to the next
- *
- * If we've got the first case, then we can search for another block,
- * otherwise forget it, as we'd be overwriting some valid data.
- */
- if (ab == NULL) {
- /* we've got case 1, so try the one after */
- ab = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &startFrame);
-
- if ((actkeyblock_get_valid_hold(ab) & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
- /* try the block before this frame then as last resort */
- ab = (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &startFrame);
- }
- }
-
- /* whatever happens, stop searching now... */
- if ((actkeyblock_get_valid_hold(ab) & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
- /* restrict range to just the frame itself
- * i.e. everything is in motion, so no holds to safely overwrite
- */
- ab = NULL;
- }
-
- /* check if we can go any further than we've already gone */
- if (ab) {
- /* go to next if it is also valid and meets "extension" criteria */
- while (ab->next) {
- ActKeyColumn *abn = ab->next;
-
- /* must be valid */
- if ((actkeyblock_get_valid_hold(abn) & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
- break;
- }
- /* should have the same number of curves */
- if (ab->totblock != abn->totblock) {
- break;
- }
-
- /* we can extend the bounds to the end of this "next" block now */
- ab = abn;
- }
-
- /* end frame can now take the value of the end of the block */
- endFrame = ab->next->cfra;
- }
-
- /* free temp memory */
- BLI_dlrbTree_free(&keys);
-
- /* return the end frame we've found */
- return endFrame;
+ DLRBT_Tree keys;
+
+ Object *ob = pfl->ob;
+ AnimData *adt = ob->adt;
+ LinkData *ld;
+ float endFrame = startFrame;
+
+ /* set up optimized data-structures for searching for relevant keyframes + holds */
+ BLI_dlrbTree_init(&keys);
+
+ for (ld = pfl->fcurves.first; ld; ld = ld->next) {
+ FCurve *fcu = (FCurve *)ld->data;
+ fcurve_to_keylist(adt, fcu, &keys, 0);
+ }
+
+ /* find the long keyframe (i.e. hold), and hence obtain the endFrame value
+ * - the best case would be one that starts on the frame itself
+ */
+ ActKeyColumn *ab = (ActKeyColumn *)BLI_dlrbTree_search_exact(
+ &keys, compare_ak_cfraPtr, &startFrame);
+
+ /* There are only two cases for no-exact match:
+ * 1) the current frame is just before another key but not on a key itself
+ * 2) the current frame is on a key, but that key doesn't link to the next
+ *
+ * If we've got the first case, then we can search for another block,
+ * otherwise forget it, as we'd be overwriting some valid data.
+ */
+ if (ab == NULL) {
+ /* we've got case 1, so try the one after */
+ ab = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &startFrame);
+
+ if ((actkeyblock_get_valid_hold(ab) & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
+ /* try the block before this frame then as last resort */
+ ab = (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &startFrame);
+ }
+ }
+
+ /* whatever happens, stop searching now... */
+ if ((actkeyblock_get_valid_hold(ab) & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
+ /* restrict range to just the frame itself
+ * i.e. everything is in motion, so no holds to safely overwrite
+ */
+ ab = NULL;
+ }
+
+ /* check if we can go any further than we've already gone */
+ if (ab) {
+ /* go to next if it is also valid and meets "extension" criteria */
+ while (ab->next) {
+ ActKeyColumn *abn = ab->next;
+
+ /* must be valid */
+ if ((actkeyblock_get_valid_hold(abn) & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
+ break;
+ }
+ /* should have the same number of curves */
+ if (ab->totblock != abn->totblock) {
+ break;
+ }
+
+ /* we can extend the bounds to the end of this "next" block now */
+ ab = abn;
+ }
+
+ /* end frame can now take the value of the end of the block */
+ endFrame = ab->next->cfra;
+ }
+
+ /* free temp memory */
+ BLI_dlrbTree_free(&keys);
+
+ /* return the end frame we've found */
+ return endFrame;
}
/* get reference value from F-Curve using RNA */
static bool pose_propagate_get_refVal(Object *ob, FCurve *fcu, float *value)
{
- PointerRNA id_ptr, ptr;
- PropertyRNA *prop;
- bool found = false;
-
- /* base pointer is always the object -> id_ptr */
- RNA_id_pointer_create(&ob->id, &id_ptr);
-
- /* resolve the property... */
- if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
- if (RNA_property_array_check(prop)) {
- /* array */
- if (fcu->array_index < RNA_property_array_length(&ptr, prop)) {
- found = true;
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- *value = (float)RNA_property_boolean_get_index(&ptr, prop, fcu->array_index);
- break;
- case PROP_INT:
- *value = (float)RNA_property_int_get_index(&ptr, prop, fcu->array_index);
- break;
- case PROP_FLOAT:
- *value = RNA_property_float_get_index(&ptr, prop, fcu->array_index);
- break;
- default:
- found = false;
- break;
- }
- }
- }
- else {
- /* not an array */
- found = true;
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- *value = (float)RNA_property_boolean_get(&ptr, prop);
- break;
- case PROP_INT:
- *value = (float)RNA_property_int_get(&ptr, prop);
- break;
- case PROP_ENUM:
- *value = (float)RNA_property_enum_get(&ptr, prop);
- break;
- case PROP_FLOAT:
- *value = RNA_property_float_get(&ptr, prop);
- break;
- default:
- found = false;
- break;
- }
- }
- }
-
- return found;
+ PointerRNA id_ptr, ptr;
+ PropertyRNA *prop;
+ bool found = false;
+
+ /* base pointer is always the object -> id_ptr */
+ RNA_id_pointer_create(&ob->id, &id_ptr);
+
+ /* resolve the property... */
+ if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
+ if (RNA_property_array_check(prop)) {
+ /* array */
+ if (fcu->array_index < RNA_property_array_length(&ptr, prop)) {
+ found = true;
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN:
+ *value = (float)RNA_property_boolean_get_index(&ptr, prop, fcu->array_index);
+ break;
+ case PROP_INT:
+ *value = (float)RNA_property_int_get_index(&ptr, prop, fcu->array_index);
+ break;
+ case PROP_FLOAT:
+ *value = RNA_property_float_get_index(&ptr, prop, fcu->array_index);
+ break;
+ default:
+ found = false;
+ break;
+ }
+ }
+ }
+ else {
+ /* not an array */
+ found = true;
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN:
+ *value = (float)RNA_property_boolean_get(&ptr, prop);
+ break;
+ case PROP_INT:
+ *value = (float)RNA_property_int_get(&ptr, prop);
+ break;
+ case PROP_ENUM:
+ *value = (float)RNA_property_enum_get(&ptr, prop);
+ break;
+ case PROP_FLOAT:
+ *value = RNA_property_float_get(&ptr, prop);
+ break;
+ default:
+ found = false;
+ break;
+ }
+ }
+ }
+
+ return found;
}
/* propagate just works along each F-Curve in turn */
-static void pose_propagate_fcurve(wmOperator *op, Object *ob, FCurve *fcu,
- float startFrame, tPosePropagate_ModeData modeData)
+static void pose_propagate_fcurve(
+ wmOperator *op, Object *ob, FCurve *fcu, float startFrame, tPosePropagate_ModeData modeData)
{
- const int mode = RNA_enum_get(op->ptr, "mode");
-
- BezTriple *bezt;
- float refVal = 0.0f;
- bool keyExists;
- int i, match;
- short first = 1;
-
- /* skip if no keyframes to edit */
- if ((fcu->bezt == NULL) || (fcu->totvert < 2))
- return;
-
- /* find the reference value from bones directly, which means that the user
- * doesn't need to firstly keyframe the pose (though this doesn't mean that
- * they can't either)
- */
- if (!pose_propagate_get_refVal(ob, fcu, &refVal))
- return;
-
- /* find the first keyframe to start propagating from
- * - if there's a keyframe on the current frame, we probably want to save this value there too
- * since it may be as of yet unkeyed
- * - if starting before the starting frame, don't touch the key, as it may have had some valid
- * values
- * - if only doing selected keyframes, start from the first one
- */
- if (mode != POSE_PROPAGATE_SELECTED_KEYS) {
- match = binarysearch_bezt_index(fcu->bezt, startFrame, fcu->totvert, &keyExists);
-
- if (fcu->bezt[match].vec[1][0] < startFrame)
- i = match + 1;
- else
- i = match;
- }
- else {
- /* selected - start from first keyframe */
- i = 0;
- }
-
- for (bezt = &fcu->bezt[i]; i < fcu->totvert; i++, bezt++) {
- /* additional termination conditions based on the operator 'mode' property go here... */
- if (ELEM(mode, POSE_PROPAGATE_BEFORE_FRAME, POSE_PROPAGATE_SMART_HOLDS)) {
- /* stop if keyframe is outside the accepted range */
- if (bezt->vec[1][0] > modeData.end_frame)
- break;
- }
- else if (mode == POSE_PROPAGATE_NEXT_KEY) {
- /* stop after the first keyframe has been processed */
- if (first == 0)
- break;
- }
- else if (mode == POSE_PROPAGATE_LAST_KEY) {
- /* only affect this frame if it will be the last one */
- if (i != (fcu->totvert - 1))
- continue;
- }
- else if (mode == POSE_PROPAGATE_SELECTED_MARKERS) {
- /* only allow if there's a marker on this frame */
- CfraElem *ce = NULL;
-
- /* stop on matching marker if there is one */
- for (ce = modeData.sel_markers.first; ce; ce = ce->next) {
- if (ce->cfra == round_fl_to_int(bezt->vec[1][0]))
- break;
- }
-
- /* skip this keyframe if no marker */
- if (ce == NULL)
- continue;
- }
- else if (mode == POSE_PROPAGATE_SELECTED_KEYS) {
- /* only allow if this keyframe is already selected - skip otherwise */
- if (BEZT_ISSEL_ANY(bezt) == 0)
- continue;
- }
-
- /* just flatten handles, since values will now be the same either side... */
- /* TODO: perhaps a fade-out modulation of the value is required here (optional once again)? */
- bezt->vec[0][1] = bezt->vec[1][1] = bezt->vec[2][1] = refVal;
-
- /* select keyframe to indicate that it's been changed */
- bezt->f2 |= SELECT;
- first = 0;
- }
+ const int mode = RNA_enum_get(op->ptr, "mode");
+
+ BezTriple *bezt;
+ float refVal = 0.0f;
+ bool keyExists;
+ int i, match;
+ short first = 1;
+
+ /* skip if no keyframes to edit */
+ if ((fcu->bezt == NULL) || (fcu->totvert < 2))
+ return;
+
+ /* find the reference value from bones directly, which means that the user
+ * doesn't need to firstly keyframe the pose (though this doesn't mean that
+ * they can't either)
+ */
+ if (!pose_propagate_get_refVal(ob, fcu, &refVal))
+ return;
+
+ /* find the first keyframe to start propagating from
+ * - if there's a keyframe on the current frame, we probably want to save this value there too
+ * since it may be as of yet unkeyed
+ * - if starting before the starting frame, don't touch the key, as it may have had some valid
+ * values
+ * - if only doing selected keyframes, start from the first one
+ */
+ if (mode != POSE_PROPAGATE_SELECTED_KEYS) {
+ match = binarysearch_bezt_index(fcu->bezt, startFrame, fcu->totvert, &keyExists);
+
+ if (fcu->bezt[match].vec[1][0] < startFrame)
+ i = match + 1;
+ else
+ i = match;
+ }
+ else {
+ /* selected - start from first keyframe */
+ i = 0;
+ }
+
+ for (bezt = &fcu->bezt[i]; i < fcu->totvert; i++, bezt++) {
+ /* additional termination conditions based on the operator 'mode' property go here... */
+ if (ELEM(mode, POSE_PROPAGATE_BEFORE_FRAME, POSE_PROPAGATE_SMART_HOLDS)) {
+ /* stop if keyframe is outside the accepted range */
+ if (bezt->vec[1][0] > modeData.end_frame)
+ break;
+ }
+ else if (mode == POSE_PROPAGATE_NEXT_KEY) {
+ /* stop after the first keyframe has been processed */
+ if (first == 0)
+ break;
+ }
+ else if (mode == POSE_PROPAGATE_LAST_KEY) {
+ /* only affect this frame if it will be the last one */
+ if (i != (fcu->totvert - 1))
+ continue;
+ }
+ else if (mode == POSE_PROPAGATE_SELECTED_MARKERS) {
+ /* only allow if there's a marker on this frame */
+ CfraElem *ce = NULL;
+
+ /* stop on matching marker if there is one */
+ for (ce = modeData.sel_markers.first; ce; ce = ce->next) {
+ if (ce->cfra == round_fl_to_int(bezt->vec[1][0]))
+ break;
+ }
+
+ /* skip this keyframe if no marker */
+ if (ce == NULL)
+ continue;
+ }
+ else if (mode == POSE_PROPAGATE_SELECTED_KEYS) {
+ /* only allow if this keyframe is already selected - skip otherwise */
+ if (BEZT_ISSEL_ANY(bezt) == 0)
+ continue;
+ }
+
+ /* just flatten handles, since values will now be the same either side... */
+ /* TODO: perhaps a fade-out modulation of the value is required here (optional once again)? */
+ bezt->vec[0][1] = bezt->vec[1][1] = bezt->vec[2][1] = refVal;
+
+ /* select keyframe to indicate that it's been changed */
+ bezt->f2 |= SELECT;
+ first = 0;
+ }
}
/* --------------------------------- */
static int pose_propagate_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- View3D *v3d = CTX_wm_view3d(C);
-
- ListBase pflinks = {NULL, NULL};
- tPChanFCurveLink *pfl;
-
- tPosePropagate_ModeData modeData;
- const int mode = RNA_enum_get(op->ptr, "mode");
-
- /* isolate F-Curves related to the selected bones */
- poseAnim_mapping_get(C, &pflinks);
-
- if (BLI_listbase_is_empty(&pflinks)) {
- /* There is a change the reason the list is empty is that there is no valid object to propagate poses for.
- * This is very unlikely though, so we focus on the most likely issue. */
- BKE_report(op->reports, RPT_ERROR, "No keyframed poses to propagate to");
- return OPERATOR_CANCELLED;
- }
-
- /* mode-specific data preprocessing (requiring no access to curves) */
- if (mode == POSE_PROPAGATE_SELECTED_MARKERS) {
- /* get a list of selected markers */
- ED_markers_make_cfra_list(&scene->markers, &modeData.sel_markers, SELECT);
- }
- else {
- /* assume everything else wants endFrame */
- modeData.end_frame = RNA_float_get(op->ptr, "end_frame");
- }
-
- /* for each bone, perform the copying required */
- for (pfl = pflinks.first; pfl; pfl = pfl->next) {
- LinkData *ld;
-
- /* mode-specific data preprocessing (requiring access to all curves) */
- if (mode == POSE_PROPAGATE_SMART_HOLDS) {
- /* we store in endFrame the end frame of the "long keyframe" (i.e. a held value) starting
- * from the keyframe that occurs after the current frame
- */
- modeData.end_frame = pose_propagate_get_boneHoldEndFrame(pfl, (float)CFRA);
- }
-
- /* go through propagating pose to keyframes, curve by curve */
- for (ld = pfl->fcurves.first; ld; ld = ld->next) {
- pose_propagate_fcurve(op, pfl->ob, (FCurve *)ld->data, (float)CFRA, modeData);
- }
- }
-
- /* free temp data */
- poseAnim_mapping_free(&pflinks);
-
- if (mode == POSE_PROPAGATE_SELECTED_MARKERS)
- BLI_freelistN(&modeData.sel_markers);
-
- /* updates + notifiers */
- FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
- poseAnim_mapping_refresh(C, scene, ob);
- } FOREACH_OBJECT_IN_MODE_END;
-
- return OPERATOR_FINISHED;
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+
+ ListBase pflinks = {NULL, NULL};
+ tPChanFCurveLink *pfl;
+
+ tPosePropagate_ModeData modeData;
+ const int mode = RNA_enum_get(op->ptr, "mode");
+
+ /* isolate F-Curves related to the selected bones */
+ poseAnim_mapping_get(C, &pflinks);
+
+ if (BLI_listbase_is_empty(&pflinks)) {
+ /* There is a change the reason the list is empty is that there is no valid object to propagate poses for.
+ * This is very unlikely though, so we focus on the most likely issue. */
+ BKE_report(op->reports, RPT_ERROR, "No keyframed poses to propagate to");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* mode-specific data preprocessing (requiring no access to curves) */
+ if (mode == POSE_PROPAGATE_SELECTED_MARKERS) {
+ /* get a list of selected markers */
+ ED_markers_make_cfra_list(&scene->markers, &modeData.sel_markers, SELECT);
+ }
+ else {
+ /* assume everything else wants endFrame */
+ modeData.end_frame = RNA_float_get(op->ptr, "end_frame");
+ }
+
+ /* for each bone, perform the copying required */
+ for (pfl = pflinks.first; pfl; pfl = pfl->next) {
+ LinkData *ld;
+
+ /* mode-specific data preprocessing (requiring access to all curves) */
+ if (mode == POSE_PROPAGATE_SMART_HOLDS) {
+ /* we store in endFrame the end frame of the "long keyframe" (i.e. a held value) starting
+ * from the keyframe that occurs after the current frame
+ */
+ modeData.end_frame = pose_propagate_get_boneHoldEndFrame(pfl, (float)CFRA);
+ }
+
+ /* go through propagating pose to keyframes, curve by curve */
+ for (ld = pfl->fcurves.first; ld; ld = ld->next) {
+ pose_propagate_fcurve(op, pfl->ob, (FCurve *)ld->data, (float)CFRA, modeData);
+ }
+ }
+
+ /* free temp data */
+ poseAnim_mapping_free(&pflinks);
+
+ if (mode == POSE_PROPAGATE_SELECTED_MARKERS)
+ BLI_freelistN(&modeData.sel_markers);
+
+ /* updates + notifiers */
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
+ poseAnim_mapping_refresh(C, scene, ob);
+ }
+ FOREACH_OBJECT_IN_MODE_END;
+
+ return OPERATOR_FINISHED;
}
/* --------------------------------- */
void POSE_OT_propagate(wmOperatorType *ot)
{
- static const EnumPropertyItem terminate_items[] = {
- {POSE_PROPAGATE_SMART_HOLDS, "WHILE_HELD", 0, "While Held",
- "Propagate pose to all keyframes after current frame that don't change (Default behavior)"},
- {POSE_PROPAGATE_NEXT_KEY, "NEXT_KEY", 0, "To Next Keyframe",
- "Propagate pose to first keyframe following the current frame only"},
- {POSE_PROPAGATE_LAST_KEY, "LAST_KEY", 0, "To Last Keyframe",
- "Propagate pose to the last keyframe only (i.e. making action cyclic)"},
- {POSE_PROPAGATE_BEFORE_FRAME, "BEFORE_FRAME", 0, "Before Frame",
- "Propagate pose to all keyframes between current frame and 'Frame' property"},
- {POSE_PROPAGATE_BEFORE_END, "BEFORE_END", 0, "Before Last Keyframe",
- "Propagate pose to all keyframes from current frame until no more are found"},
- {POSE_PROPAGATE_SELECTED_KEYS, "SELECTED_KEYS", 0, "On Selected Keyframes",
- "Propagate pose to all selected keyframes"},
- {POSE_PROPAGATE_SELECTED_MARKERS, "SELECTED_MARKERS", 0, "On Selected Markers",
- "Propagate pose to all keyframes occurring on frames with Scene Markers after the current frame"},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Propagate Pose";
- ot->idname = "POSE_OT_propagate";
- ot->description = "Copy selected aspects of the current pose to subsequent poses already keyframed";
-
- /* callbacks */
- ot->exec = pose_propagate_exec;
- ot->poll = ED_operator_posemode; /* XXX: needs selected bones! */
-
- /* flag */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- /* TODO: add "fade out" control for tapering off amount of propagation as time goes by? */
- ot->prop = RNA_def_enum(ot->srna, "mode", terminate_items, POSE_PROPAGATE_SMART_HOLDS, "Terminate Mode", "Method used to determine when to stop propagating pose to keyframes");
- RNA_def_float(ot->srna, "end_frame", 250.0, FLT_MIN, FLT_MAX, "End Frame", "Frame to stop propagating frames to (for 'Before Frame' mode)", 1.0, 250.0);
+ static const EnumPropertyItem terminate_items[] = {
+ {POSE_PROPAGATE_SMART_HOLDS,
+ "WHILE_HELD",
+ 0,
+ "While Held",
+ "Propagate pose to all keyframes after current frame that don't change (Default behavior)"},
+ {POSE_PROPAGATE_NEXT_KEY,
+ "NEXT_KEY",
+ 0,
+ "To Next Keyframe",
+ "Propagate pose to first keyframe following the current frame only"},
+ {POSE_PROPAGATE_LAST_KEY,
+ "LAST_KEY",
+ 0,
+ "To Last Keyframe",
+ "Propagate pose to the last keyframe only (i.e. making action cyclic)"},
+ {POSE_PROPAGATE_BEFORE_FRAME,
+ "BEFORE_FRAME",
+ 0,
+ "Before Frame",
+ "Propagate pose to all keyframes between current frame and 'Frame' property"},
+ {POSE_PROPAGATE_BEFORE_END,
+ "BEFORE_END",
+ 0,
+ "Before Last Keyframe",
+ "Propagate pose to all keyframes from current frame until no more are found"},
+ {POSE_PROPAGATE_SELECTED_KEYS,
+ "SELECTED_KEYS",
+ 0,
+ "On Selected Keyframes",
+ "Propagate pose to all selected keyframes"},
+ {POSE_PROPAGATE_SELECTED_MARKERS,
+ "SELECTED_MARKERS",
+ 0,
+ "On Selected Markers",
+ "Propagate pose to all keyframes occurring on frames with Scene Markers after the current "
+ "frame"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Propagate Pose";
+ ot->idname = "POSE_OT_propagate";
+ ot->description =
+ "Copy selected aspects of the current pose to subsequent poses already keyframed";
+
+ /* callbacks */
+ ot->exec = pose_propagate_exec;
+ ot->poll = ED_operator_posemode; /* XXX: needs selected bones! */
+
+ /* flag */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ /* TODO: add "fade out" control for tapering off amount of propagation as time goes by? */
+ ot->prop = RNA_def_enum(ot->srna,
+ "mode",
+ terminate_items,
+ POSE_PROPAGATE_SMART_HOLDS,
+ "Terminate Mode",
+ "Method used to determine when to stop propagating pose to keyframes");
+ RNA_def_float(ot->srna,
+ "end_frame",
+ 250.0,
+ FLT_MIN,
+ FLT_MAX,
+ "End Frame",
+ "Frame to stop propagating frames to (for 'Before Frame' mode)",
+ 1.0,
+ 250.0);
}
/* **************************************************** */
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index cbb6d63aefe..3a4413f8c1d 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -61,7 +61,6 @@
#include "armature_intern.h"
-
/* ********************************************** */
/* Pose Apply */
@@ -69,216 +68,214 @@
* that are bone-parented to armature */
static void applyarmature_fix_boneparents(const bContext *C, Scene *scene, Object *armob)
{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Main *bmain = CTX_data_main(C);
- Object workob, *ob;
-
- /* go through all objects in database */
- for (ob = bmain->objects.first; ob; ob = ob->id.next) {
- /* if parent is bone in this armature, apply corrections */
- if ((ob->parent == armob) && (ob->partype == PARBONE)) {
- /* apply current transform from parent (not yet destroyed),
- * then calculate new parent inverse matrix
- */
- BKE_object_apply_mat4(ob, ob->obmat, false, false);
-
- BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob);
- invert_m4_m4(ob->parentinv, workob.obmat);
- }
- }
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Main *bmain = CTX_data_main(C);
+ Object workob, *ob;
+
+ /* go through all objects in database */
+ for (ob = bmain->objects.first; ob; ob = ob->id.next) {
+ /* if parent is bone in this armature, apply corrections */
+ if ((ob->parent == armob) && (ob->partype == PARBONE)) {
+ /* apply current transform from parent (not yet destroyed),
+ * then calculate new parent inverse matrix
+ */
+ BKE_object_apply_mat4(ob, ob->obmat, false, false);
+
+ BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob);
+ invert_m4_m4(ob->parentinv, workob.obmat);
+ }
+ }
}
/* set the current pose as the restpose */
static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- // must be active object, not edit-object
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- bArmature *arm = BKE_armature_from_object(ob);
- bPose *pose;
- bPoseChannel *pchan;
- EditBone *curbone;
-
- /* don't check if editmode (should be done by caller) */
- if (ob->type != OB_ARMATURE)
- return OPERATOR_CANCELLED;
- if (BKE_object_obdata_is_libdata(ob)) {
- BKE_report(op->reports, RPT_ERROR, "Cannot apply pose to lib-linked armature");
- return OPERATOR_CANCELLED;
- }
-
- /* helpful warnings... */
- /* TODO: add warnings to be careful about actions, applying deforms first, etc. */
- if (ob->adt && ob->adt->action)
- BKE_report(op->reports, RPT_WARNING,
- "Actions on this armature will be destroyed by this new rest pose as the "
- "transforms stored are relative to the old rest pose");
-
- /* Get editbones of active armature to alter */
- ED_armature_to_edit(arm);
-
- /* get pose of active object and move it out of posemode */
- pose = ob->pose;
-
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- const bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
- curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name);
-
- /* simply copy the head/tail values from pchan over to curbone */
- copy_v3_v3(curbone->head, pchan_eval->pose_head);
- copy_v3_v3(curbone->tail, pchan_eval->pose_tail);
-
- /* fix roll:
- * 1. find auto-calculated roll value for this bone now
- * 2. remove this from the 'visual' y-rotation
- */
- {
- float premat[3][3], imat[3][3], pmat[3][3], tmat[3][3];
- float delta[3], eul[3];
-
- /* obtain new auto y-rotation */
- sub_v3_v3v3(delta, curbone->tail, curbone->head);
- vec_roll_to_mat3(delta, 0.0f, premat);
- invert_m3_m3(imat, premat);
-
- /* get pchan 'visual' matrix */
- copy_m3_m4(pmat, pchan_eval->pose_mat);
-
- /* remove auto from visual and get euler rotation */
- mul_m3_m3m3(tmat, imat, pmat);
- mat3_to_eul(eul, tmat);
-
- /* just use this euler-y as new roll value */
- curbone->roll = eul[1];
- }
-
- /* combine pose and rest values for bendy bone settings,
- * then clear the pchan values (so we don't get a double-up)
- */
- if (pchan->bone->segments > 1) {
- /* combine rest/pose values */
- curbone->curveInX += pchan_eval->curveInX;
- curbone->curveInY += pchan_eval->curveInY;
- curbone->curveOutX += pchan_eval->curveOutX;
- curbone->curveOutY += pchan_eval->curveOutY;
- curbone->roll1 += pchan_eval->roll1;
- curbone->roll2 += pchan_eval->roll2;
- curbone->ease1 += pchan_eval->ease1;
- curbone->ease2 += pchan_eval->ease2;
- curbone->scaleIn += pchan_eval->scaleIn;
- curbone->scaleOut += pchan_eval->scaleOut;
-
- /* reset pose values */
- pchan->curveInX = pchan->curveOutX = 0.0f;
- pchan->curveInY = pchan->curveOutY = 0.0f;
- pchan->roll1 = pchan->roll2 = 0.0f;
- pchan->ease1 = pchan->ease2 = 0.0f;
- pchan->scaleIn = pchan->scaleOut = 1.0f;
- }
-
- /* clear transform values for pchan */
- zero_v3(pchan->loc);
- zero_v3(pchan->eul);
- unit_qt(pchan->quat);
- unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
- pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f;
-
- /* set anim lock */
- curbone->flag |= BONE_UNKEYED;
- }
-
- /* convert editbones back to bones, and then free the edit-data */
- ED_armature_from_edit(bmain, arm);
- ED_armature_edit_free(arm);
-
- /* flush positions of posebones */
- BKE_pose_where_is(depsgraph, scene, ob);
-
- /* fix parenting of objects which are bone-parented */
- applyarmature_fix_boneparents(C, scene, ob);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
-
- return OPERATOR_FINISHED;
+ Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ // must be active object, not edit-object
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ bArmature *arm = BKE_armature_from_object(ob);
+ bPose *pose;
+ bPoseChannel *pchan;
+ EditBone *curbone;
+
+ /* don't check if editmode (should be done by caller) */
+ if (ob->type != OB_ARMATURE)
+ return OPERATOR_CANCELLED;
+ if (BKE_object_obdata_is_libdata(ob)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot apply pose to lib-linked armature");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* helpful warnings... */
+ /* TODO: add warnings to be careful about actions, applying deforms first, etc. */
+ if (ob->adt && ob->adt->action)
+ BKE_report(op->reports,
+ RPT_WARNING,
+ "Actions on this armature will be destroyed by this new rest pose as the "
+ "transforms stored are relative to the old rest pose");
+
+ /* Get editbones of active armature to alter */
+ ED_armature_to_edit(arm);
+
+ /* get pose of active object and move it out of posemode */
+ pose = ob->pose;
+
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ const bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
+ curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name);
+
+ /* simply copy the head/tail values from pchan over to curbone */
+ copy_v3_v3(curbone->head, pchan_eval->pose_head);
+ copy_v3_v3(curbone->tail, pchan_eval->pose_tail);
+
+ /* fix roll:
+ * 1. find auto-calculated roll value for this bone now
+ * 2. remove this from the 'visual' y-rotation
+ */
+ {
+ float premat[3][3], imat[3][3], pmat[3][3], tmat[3][3];
+ float delta[3], eul[3];
+
+ /* obtain new auto y-rotation */
+ sub_v3_v3v3(delta, curbone->tail, curbone->head);
+ vec_roll_to_mat3(delta, 0.0f, premat);
+ invert_m3_m3(imat, premat);
+
+ /* get pchan 'visual' matrix */
+ copy_m3_m4(pmat, pchan_eval->pose_mat);
+
+ /* remove auto from visual and get euler rotation */
+ mul_m3_m3m3(tmat, imat, pmat);
+ mat3_to_eul(eul, tmat);
+
+ /* just use this euler-y as new roll value */
+ curbone->roll = eul[1];
+ }
+
+ /* combine pose and rest values for bendy bone settings,
+ * then clear the pchan values (so we don't get a double-up)
+ */
+ if (pchan->bone->segments > 1) {
+ /* combine rest/pose values */
+ curbone->curveInX += pchan_eval->curveInX;
+ curbone->curveInY += pchan_eval->curveInY;
+ curbone->curveOutX += pchan_eval->curveOutX;
+ curbone->curveOutY += pchan_eval->curveOutY;
+ curbone->roll1 += pchan_eval->roll1;
+ curbone->roll2 += pchan_eval->roll2;
+ curbone->ease1 += pchan_eval->ease1;
+ curbone->ease2 += pchan_eval->ease2;
+ curbone->scaleIn += pchan_eval->scaleIn;
+ curbone->scaleOut += pchan_eval->scaleOut;
+
+ /* reset pose values */
+ pchan->curveInX = pchan->curveOutX = 0.0f;
+ pchan->curveInY = pchan->curveOutY = 0.0f;
+ pchan->roll1 = pchan->roll2 = 0.0f;
+ pchan->ease1 = pchan->ease2 = 0.0f;
+ pchan->scaleIn = pchan->scaleOut = 1.0f;
+ }
+
+ /* clear transform values for pchan */
+ zero_v3(pchan->loc);
+ zero_v3(pchan->eul);
+ unit_qt(pchan->quat);
+ unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
+ pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f;
+
+ /* set anim lock */
+ curbone->flag |= BONE_UNKEYED;
+ }
+
+ /* convert editbones back to bones, and then free the edit-data */
+ ED_armature_from_edit(bmain, arm);
+ ED_armature_edit_free(arm);
+
+ /* flush positions of posebones */
+ BKE_pose_where_is(depsgraph, scene, ob);
+
+ /* fix parenting of objects which are bone-parented */
+ applyarmature_fix_boneparents(C, scene, ob);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+
+ return OPERATOR_FINISHED;
}
void POSE_OT_armature_apply(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Apply Pose as Rest Pose";
- ot->idname = "POSE_OT_armature_apply";
- ot->description = "Apply the current pose as the new rest pose";
+ /* identifiers */
+ ot->name = "Apply Pose as Rest Pose";
+ ot->idname = "POSE_OT_armature_apply";
+ ot->description = "Apply the current pose as the new rest pose";
- /* callbacks */
- ot->exec = apply_armature_pose2bones_exec;
- ot->poll = ED_operator_posemode;
+ /* callbacks */
+ ot->exec = apply_armature_pose2bones_exec;
+ ot->poll = ED_operator_posemode;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-
/* set the current pose as the restpose */
static int pose_visual_transform_apply_exec(bContext *C, wmOperator *UNUSED(op))
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- View3D *v3d = CTX_wm_view3d(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
-
- FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob)
- {
- /* loop over all selected pchans
- *
- * TODO, loop over children before parents if multiple bones
- * at once are to be predictable*/
- FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob, pchan)
- {
- const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
- float delta_mat[4][4];
-
- /* chan_mat already contains the delta transform from rest pose to pose-mode pose
- * as that is baked into there so that B-Bones will work. Once we've set this as the
- * new raw-transform components, don't recalc the poses yet, otherwise IK result will
- * change, thus changing the result we may be trying to record.
- */
- /* XXX For some reason, we can't use pchan->chan_mat here, gives odd rotation/offset (see T38251).
- * Using pchan->pose_mat and bringing it back in bone space seems to work as expected!
- */
- BKE_armature_mat_pose_to_bone(pchan_eval, pchan_eval->pose_mat, delta_mat);
-
- BKE_pchan_apply_mat4(pchan, delta_mat, true);
- }
- FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
-
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
- }
- FOREACH_OBJECT_IN_MODE_END;
-
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
+ /* loop over all selected pchans
+ *
+ * TODO, loop over children before parents if multiple bones
+ * at once are to be predictable*/
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob, pchan) {
+ const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
+ float delta_mat[4][4];
+
+ /* chan_mat already contains the delta transform from rest pose to pose-mode pose
+ * as that is baked into there so that B-Bones will work. Once we've set this as the
+ * new raw-transform components, don't recalc the poses yet, otherwise IK result will
+ * change, thus changing the result we may be trying to record.
+ */
+ /* XXX For some reason, we can't use pchan->chan_mat here, gives odd rotation/offset (see T38251).
+ * Using pchan->pose_mat and bringing it back in bone space seems to work as expected!
+ */
+ BKE_armature_mat_pose_to_bone(pchan_eval, pchan_eval->pose_mat, delta_mat);
+
+ BKE_pchan_apply_mat4(pchan, delta_mat, true);
+ }
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ }
+ FOREACH_OBJECT_IN_MODE_END;
+
+ return OPERATOR_FINISHED;
}
void POSE_OT_visual_transform_apply(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Apply Visual Transform to Pose";
- ot->idname = "POSE_OT_visual_transform_apply";
- ot->description = "Apply final constrained position of pose bones to their transform";
+ /* identifiers */
+ ot->name = "Apply Visual Transform to Pose";
+ ot->idname = "POSE_OT_visual_transform_apply";
+ ot->description = "Apply final constrained position of pose bones to their transform";
- /* callbacks */
- ot->exec = pose_visual_transform_apply_exec;
- ot->poll = ED_operator_posemode;
+ /* callbacks */
+ ot->exec = pose_visual_transform_apply_exec;
+ ot->poll = ED_operator_posemode;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ********************************************** */
@@ -289,18 +286,18 @@ void POSE_OT_visual_transform_apply(wmOperatorType *ot)
*/
static void set_pose_keys(Object *ob)
{
- bArmature *arm = ob->data;
- bPoseChannel *chan;
-
- if (ob->pose) {
- for (chan = ob->pose->chanbase.first; chan; chan = chan->next) {
- Bone *bone = chan->bone;
- if ((bone) && (bone->flag & BONE_SELECTED) && (arm->layer & bone->layer))
- chan->flag |= POSE_KEY;
- else
- chan->flag &= ~POSE_KEY;
- }
- }
+ bArmature *arm = ob->data;
+ bPoseChannel *chan;
+
+ if (ob->pose) {
+ for (chan = ob->pose->chanbase.first; chan; chan = chan->next) {
+ Bone *bone = chan->bone;
+ if ((bone) && (bone->flag & BONE_SELECTED) && (arm->layer & bone->layer))
+ chan->flag |= POSE_KEY;
+ else
+ chan->flag &= ~POSE_KEY;
+ }
+ }
}
/**
@@ -312,304 +309,315 @@ static void set_pose_keys(Object *ob)
* \param flip: Flip on x-axis
* \return Whether the bone that we pasted to if we succeeded
*/
-static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, const bool selOnly, const bool flip)
+static bPoseChannel *pose_bone_do_paste(Object *ob,
+ bPoseChannel *chan,
+ const bool selOnly,
+ const bool flip)
{
- bPoseChannel *pchan;
- char name[MAXBONENAME];
- short paste_ok;
-
- /* get the name - if flipping, we must flip this first */
- if (flip)
- BLI_string_flip_side_name(name, chan->name, false, sizeof(name));
- else
- BLI_strncpy(name, chan->name, sizeof(name));
-
- /* only copy when:
- * 1) channel exists - poses are not meant to add random channels to anymore
- * 2) if selection-masking is on, channel is selected - only selected bones get pasted on, allowing making both sides symmetrical
- */
- pchan = BKE_pose_channel_find_name(ob->pose, name);
-
- if (selOnly)
- paste_ok = ((pchan) && (pchan->bone->flag & BONE_SELECTED));
- else
- paste_ok = (pchan != NULL);
-
- /* continue? */
- if (paste_ok) {
- /* only loc rot size
- * - only copies transform info for the pose
- */
- copy_v3_v3(pchan->loc, chan->loc);
- copy_v3_v3(pchan->size, chan->size);
- pchan->flag = chan->flag;
-
- /* check if rotation modes are compatible (i.e. do they need any conversions) */
- if (pchan->rotmode == chan->rotmode) {
- /* copy the type of rotation in use */
- if (pchan->rotmode > 0) {
- copy_v3_v3(pchan->eul, chan->eul);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- copy_v3_v3(pchan->rotAxis, chan->rotAxis);
- pchan->rotAngle = chan->rotAngle;
- }
- else {
- copy_qt_qt(pchan->quat, chan->quat);
- }
- }
- else if (pchan->rotmode > 0) {
- /* quat/axis-angle to euler */
- if (chan->rotmode == ROT_MODE_AXISANGLE)
- axis_angle_to_eulO(pchan->eul, pchan->rotmode, chan->rotAxis, chan->rotAngle);
- else
- quat_to_eulO(pchan->eul, pchan->rotmode, chan->quat);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- /* quat/euler to axis angle */
- if (chan->rotmode > 0)
- eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode);
- else
- quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat);
- }
- else {
- /* euler/axis-angle to quat */
- if (chan->rotmode > 0)
- eulO_to_quat(pchan->quat, chan->eul, chan->rotmode);
- else
- axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
- }
-
- /* B-Bone posing options should also be included... */
- pchan->curveInX = chan->curveInX;
- pchan->curveInY = chan->curveInY;
- pchan->curveOutX = chan->curveOutX;
- pchan->curveOutY = chan->curveOutY;
-
- pchan->roll1 = chan->roll1;
- pchan->roll2 = chan->roll2;
- pchan->ease1 = chan->ease1;
- pchan->ease2 = chan->ease2;
- pchan->scaleIn = chan->scaleIn;
- pchan->scaleOut = chan->scaleOut;
-
- /* paste flipped pose? */
- if (flip) {
- pchan->loc[0] *= -1;
-
- pchan->curveInX *= -1;
- pchan->curveOutX *= -1;
- pchan->roll1 *= -1; // XXX?
- pchan->roll2 *= -1; // XXX?
-
- /* has to be done as eulers... */
- if (pchan->rotmode > 0) {
- pchan->eul[1] *= -1;
- pchan->eul[2] *= -1;
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- float eul[3];
-
- axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
- eul[1] *= -1;
- eul[2] *= -1;
- eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
- }
- else {
- float eul[3];
-
- normalize_qt(pchan->quat);
- quat_to_eul(eul, pchan->quat);
- eul[1] *= -1;
- eul[2] *= -1;
- eul_to_quat(pchan->quat, eul);
- }
- }
-
- /* ID properties */
- if (chan->prop) {
- if (pchan->prop) {
- /* if we have existing properties on a bone, just copy over the values of
- * matching properties (i.e. ones which will have some impact) on to the
- * target instead of just blinding replacing all [
- */
- IDP_SyncGroupValues(pchan->prop, chan->prop);
- }
- else {
- /* no existing properties, so assume that we want copies too? */
- pchan->prop = IDP_CopyProperty(chan->prop);
- }
- }
- }
-
- /* return whether paste went ahead */
- return pchan;
+ bPoseChannel *pchan;
+ char name[MAXBONENAME];
+ short paste_ok;
+
+ /* get the name - if flipping, we must flip this first */
+ if (flip)
+ BLI_string_flip_side_name(name, chan->name, false, sizeof(name));
+ else
+ BLI_strncpy(name, chan->name, sizeof(name));
+
+ /* only copy when:
+ * 1) channel exists - poses are not meant to add random channels to anymore
+ * 2) if selection-masking is on, channel is selected - only selected bones get pasted on, allowing making both sides symmetrical
+ */
+ pchan = BKE_pose_channel_find_name(ob->pose, name);
+
+ if (selOnly)
+ paste_ok = ((pchan) && (pchan->bone->flag & BONE_SELECTED));
+ else
+ paste_ok = (pchan != NULL);
+
+ /* continue? */
+ if (paste_ok) {
+ /* only loc rot size
+ * - only copies transform info for the pose
+ */
+ copy_v3_v3(pchan->loc, chan->loc);
+ copy_v3_v3(pchan->size, chan->size);
+ pchan->flag = chan->flag;
+
+ /* check if rotation modes are compatible (i.e. do they need any conversions) */
+ if (pchan->rotmode == chan->rotmode) {
+ /* copy the type of rotation in use */
+ if (pchan->rotmode > 0) {
+ copy_v3_v3(pchan->eul, chan->eul);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ copy_v3_v3(pchan->rotAxis, chan->rotAxis);
+ pchan->rotAngle = chan->rotAngle;
+ }
+ else {
+ copy_qt_qt(pchan->quat, chan->quat);
+ }
+ }
+ else if (pchan->rotmode > 0) {
+ /* quat/axis-angle to euler */
+ if (chan->rotmode == ROT_MODE_AXISANGLE)
+ axis_angle_to_eulO(pchan->eul, pchan->rotmode, chan->rotAxis, chan->rotAngle);
+ else
+ quat_to_eulO(pchan->eul, pchan->rotmode, chan->quat);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ /* quat/euler to axis angle */
+ if (chan->rotmode > 0)
+ eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode);
+ else
+ quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat);
+ }
+ else {
+ /* euler/axis-angle to quat */
+ if (chan->rotmode > 0)
+ eulO_to_quat(pchan->quat, chan->eul, chan->rotmode);
+ else
+ axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
+ }
+
+ /* B-Bone posing options should also be included... */
+ pchan->curveInX = chan->curveInX;
+ pchan->curveInY = chan->curveInY;
+ pchan->curveOutX = chan->curveOutX;
+ pchan->curveOutY = chan->curveOutY;
+
+ pchan->roll1 = chan->roll1;
+ pchan->roll2 = chan->roll2;
+ pchan->ease1 = chan->ease1;
+ pchan->ease2 = chan->ease2;
+ pchan->scaleIn = chan->scaleIn;
+ pchan->scaleOut = chan->scaleOut;
+
+ /* paste flipped pose? */
+ if (flip) {
+ pchan->loc[0] *= -1;
+
+ pchan->curveInX *= -1;
+ pchan->curveOutX *= -1;
+ pchan->roll1 *= -1; // XXX?
+ pchan->roll2 *= -1; // XXX?
+
+ /* has to be done as eulers... */
+ if (pchan->rotmode > 0) {
+ pchan->eul[1] *= -1;
+ pchan->eul[2] *= -1;
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ float eul[3];
+
+ axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
+ eul[1] *= -1;
+ eul[2] *= -1;
+ eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
+ }
+ else {
+ float eul[3];
+
+ normalize_qt(pchan->quat);
+ quat_to_eul(eul, pchan->quat);
+ eul[1] *= -1;
+ eul[2] *= -1;
+ eul_to_quat(pchan->quat, eul);
+ }
+ }
+
+ /* ID properties */
+ if (chan->prop) {
+ if (pchan->prop) {
+ /* if we have existing properties on a bone, just copy over the values of
+ * matching properties (i.e. ones which will have some impact) on to the
+ * target instead of just blinding replacing all [
+ */
+ IDP_SyncGroupValues(pchan->prop, chan->prop);
+ }
+ else {
+ /* no existing properties, so assume that we want copies too? */
+ pchan->prop = IDP_CopyProperty(chan->prop);
+ }
+ }
+ }
+
+ /* return whether paste went ahead */
+ return pchan;
}
/* ---- */
static int pose_copy_exec(bContext *C, wmOperator *op)
{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- char str[FILE_MAX];
- /* Sanity checking. */
- if (ELEM(NULL, ob, ob->pose)) {
- BKE_report(op->reports, RPT_ERROR, "No pose to copy");
- return OPERATOR_CANCELLED;
- }
- /* Sets chan->flag to POSE_KEY if bone selected. */
- set_pose_keys(ob);
- /* Construct a local bmain and only put object and it's data into it,
- * o this way we don't expand any other objects into the copy buffer
- * file.
- *
- * TODO(sergey): Find an easier way to tell copy buffer to only store
- * data we are actually interested in. Maybe pass it a flag to skip
- * any datablock expansion?
- */
- Main *temp_bmain = BKE_main_new();
- Object ob_copy = *ob;
- bArmature arm_copy = *((bArmature *)ob->data);
- ob_copy.data = &arm_copy;
- BLI_addtail(&temp_bmain->objects, &ob_copy);
- BLI_addtail(&temp_bmain->armatures, &arm_copy);
- /* begin copy buffer on a temp bmain. */
- BKE_copybuffer_begin(temp_bmain);
- /* Store the whole object to the copy buffer because pose can't be
- * existing on it's own.
- */
- BKE_copybuffer_tag_ID(&ob_copy.id);
- BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer_pose.blend");
- BKE_copybuffer_save(temp_bmain, str, op->reports);
- /* We clear the lists so no datablocks gets freed,
- * This is required because objects in temp bmain shares same pointers
- * as the real ones.
- */
- BLI_listbase_clear(&temp_bmain->objects);
- BLI_listbase_clear(&temp_bmain->armatures);
- BKE_main_free(temp_bmain);
- /* We are all done! */
- BKE_report(op->reports, RPT_INFO, "Copied pose to buffer");
- return OPERATOR_FINISHED;
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ char str[FILE_MAX];
+ /* Sanity checking. */
+ if (ELEM(NULL, ob, ob->pose)) {
+ BKE_report(op->reports, RPT_ERROR, "No pose to copy");
+ return OPERATOR_CANCELLED;
+ }
+ /* Sets chan->flag to POSE_KEY if bone selected. */
+ set_pose_keys(ob);
+ /* Construct a local bmain and only put object and it's data into it,
+ * o this way we don't expand any other objects into the copy buffer
+ * file.
+ *
+ * TODO(sergey): Find an easier way to tell copy buffer to only store
+ * data we are actually interested in. Maybe pass it a flag to skip
+ * any datablock expansion?
+ */
+ Main *temp_bmain = BKE_main_new();
+ Object ob_copy = *ob;
+ bArmature arm_copy = *((bArmature *)ob->data);
+ ob_copy.data = &arm_copy;
+ BLI_addtail(&temp_bmain->objects, &ob_copy);
+ BLI_addtail(&temp_bmain->armatures, &arm_copy);
+ /* begin copy buffer on a temp bmain. */
+ BKE_copybuffer_begin(temp_bmain);
+ /* Store the whole object to the copy buffer because pose can't be
+ * existing on it's own.
+ */
+ BKE_copybuffer_tag_ID(&ob_copy.id);
+ BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer_pose.blend");
+ BKE_copybuffer_save(temp_bmain, str, op->reports);
+ /* We clear the lists so no datablocks gets freed,
+ * This is required because objects in temp bmain shares same pointers
+ * as the real ones.
+ */
+ BLI_listbase_clear(&temp_bmain->objects);
+ BLI_listbase_clear(&temp_bmain->armatures);
+ BKE_main_free(temp_bmain);
+ /* We are all done! */
+ BKE_report(op->reports, RPT_INFO, "Copied pose to buffer");
+ return OPERATOR_FINISHED;
}
void POSE_OT_copy(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Copy Pose";
- ot->idname = "POSE_OT_copy";
- ot->description = "Copies the current pose of the selected bones to copy/paste buffer";
+ /* identifiers */
+ ot->name = "Copy Pose";
+ ot->idname = "POSE_OT_copy";
+ ot->description = "Copies the current pose of the selected bones to copy/paste buffer";
- /* api callbacks */
- ot->exec = pose_copy_exec;
- ot->poll = ED_operator_posemode;
+ /* api callbacks */
+ ot->exec = pose_copy_exec;
+ ot->poll = ED_operator_posemode;
- /* flag */
- ot->flag = OPTYPE_REGISTER;
+ /* flag */
+ ot->flag = OPTYPE_REGISTER;
}
/* ---- */
static int pose_paste_exec(bContext *C, wmOperator *op)
{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- Scene *scene = CTX_data_scene(C);
- bPoseChannel *chan;
- const bool flip = RNA_boolean_get(op->ptr, "flipped");
- bool selOnly = RNA_boolean_get(op->ptr, "selected_mask");
-
- /* Get KeyingSet to use. */
- KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID);
-
- /* Sanity checks. */
- if (ELEM(NULL, ob, ob->pose)) {
- return OPERATOR_CANCELLED;
- }
-
- /* Read copy buffer .blend file. */
- char str[FILE_MAX];
- Main *tmp_bmain = BKE_main_new();
- BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer_pose.blend");
- if (!BKE_copybuffer_read(tmp_bmain, str, op->reports, FILTER_ID_OB)) {
- BKE_report(op->reports, RPT_ERROR, "Copy buffer is empty");
- BKE_main_free(tmp_bmain);
- return OPERATOR_CANCELLED;
- }
- /* Make sure data from this file is usable for pose paste. */
- if (BLI_listbase_count_at_most(&tmp_bmain->objects, 2) != 1) {
- BKE_report(op->reports, RPT_ERROR, "Copy buffer is not from pose mode");
- BKE_main_free(tmp_bmain);
- return OPERATOR_CANCELLED;
- }
-
- Object *object_from = tmp_bmain->objects.first;
- bPose *pose_from = object_from->pose;
- if (pose_from == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Copy buffer has no pose");
- BKE_main_free(tmp_bmain);
- return OPERATOR_CANCELLED;
- }
-
- /* If selOnly option is enabled, if user hasn't selected any bones,
- * just go back to default behavior to be more in line with other
- * pose tools.
- */
- if (selOnly) {
- if (CTX_DATA_COUNT(C, selected_pose_bones) == 0) {
- selOnly = false;
- }
- }
-
- /* Safely merge all of the channels in the buffer pose into any
- * existing pose.
- */
- for (chan = pose_from->chanbase.first; chan; chan = chan->next) {
- if (chan->flag & POSE_KEY) {
- /* Try to perform paste on this bone. */
- bPoseChannel *pchan = pose_bone_do_paste(ob, chan, selOnly, flip);
- if (pchan != NULL) {
- /* Keyframing tagging for successful paste, */
- ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
- }
- }
- }
- BKE_main_free(tmp_bmain);
-
- /* Update event for pose and deformation children. */
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
-
- /* Recalculate paths if any of the bones have paths... */
- if ((ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) {
- ED_pose_recalculate_paths(C, scene, ob, false);
- }
-
- /* Notifiers for updates, */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ Scene *scene = CTX_data_scene(C);
+ bPoseChannel *chan;
+ const bool flip = RNA_boolean_get(op->ptr, "flipped");
+ bool selOnly = RNA_boolean_get(op->ptr, "selected_mask");
+
+ /* Get KeyingSet to use. */
+ KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID);
+
+ /* Sanity checks. */
+ if (ELEM(NULL, ob, ob->pose)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Read copy buffer .blend file. */
+ char str[FILE_MAX];
+ Main *tmp_bmain = BKE_main_new();
+ BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer_pose.blend");
+ if (!BKE_copybuffer_read(tmp_bmain, str, op->reports, FILTER_ID_OB)) {
+ BKE_report(op->reports, RPT_ERROR, "Copy buffer is empty");
+ BKE_main_free(tmp_bmain);
+ return OPERATOR_CANCELLED;
+ }
+ /* Make sure data from this file is usable for pose paste. */
+ if (BLI_listbase_count_at_most(&tmp_bmain->objects, 2) != 1) {
+ BKE_report(op->reports, RPT_ERROR, "Copy buffer is not from pose mode");
+ BKE_main_free(tmp_bmain);
+ return OPERATOR_CANCELLED;
+ }
+
+ Object *object_from = tmp_bmain->objects.first;
+ bPose *pose_from = object_from->pose;
+ if (pose_from == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Copy buffer has no pose");
+ BKE_main_free(tmp_bmain);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* If selOnly option is enabled, if user hasn't selected any bones,
+ * just go back to default behavior to be more in line with other
+ * pose tools.
+ */
+ if (selOnly) {
+ if (CTX_DATA_COUNT(C, selected_pose_bones) == 0) {
+ selOnly = false;
+ }
+ }
+
+ /* Safely merge all of the channels in the buffer pose into any
+ * existing pose.
+ */
+ for (chan = pose_from->chanbase.first; chan; chan = chan->next) {
+ if (chan->flag & POSE_KEY) {
+ /* Try to perform paste on this bone. */
+ bPoseChannel *pchan = pose_bone_do_paste(ob, chan, selOnly, flip);
+ if (pchan != NULL) {
+ /* Keyframing tagging for successful paste, */
+ ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
+ }
+ }
+ }
+ BKE_main_free(tmp_bmain);
+
+ /* Update event for pose and deformation children. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+
+ /* Recalculate paths if any of the bones have paths... */
+ if ((ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) {
+ ED_pose_recalculate_paths(C, scene, ob, false);
+ }
+
+ /* Notifiers for updates, */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
}
void POSE_OT_paste(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Paste Pose";
- ot->idname = "POSE_OT_paste";
- ot->description = "Paste the stored pose on to the current pose";
-
- /* api callbacks */
- ot->exec = pose_paste_exec;
- ot->poll = ED_operator_posemode;
-
- /* flag */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- prop = RNA_def_boolean(ot->srna, "flipped", false, "Flipped on X-Axis", "Paste the stored pose flipped on to current pose");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- RNA_def_boolean(ot->srna, "selected_mask", false, "On Selected Only", "Only paste the stored pose on to selected bones in the current pose");
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Paste Pose";
+ ot->idname = "POSE_OT_paste";
+ ot->description = "Paste the stored pose on to the current pose";
+
+ /* api callbacks */
+ ot->exec = pose_paste_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flag */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_boolean(ot->srna,
+ "flipped",
+ false,
+ "Flipped on X-Axis",
+ "Paste the stored pose flipped on to current pose");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ RNA_def_boolean(ot->srna,
+ "selected_mask",
+ false,
+ "On Selected Only",
+ "Only paste the stored pose on to selected bones in the current pose");
}
/* ********************************************** */
@@ -618,313 +626,317 @@ void POSE_OT_paste(wmOperatorType *ot)
/* clear scale of pose-channel */
static void pchan_clear_scale(bPoseChannel *pchan)
{
- if ((pchan->protectflag & OB_LOCK_SCALEX) == 0)
- pchan->size[0] = 1.0f;
- if ((pchan->protectflag & OB_LOCK_SCALEY) == 0)
- pchan->size[1] = 1.0f;
- if ((pchan->protectflag & OB_LOCK_SCALEZ) == 0)
- pchan->size[2] = 1.0f;
-
- pchan->ease1 = 0.0f;
- pchan->ease2 = 0.0f;
- pchan->scaleIn = 1.0f;
- pchan->scaleOut = 1.0f;
+ if ((pchan->protectflag & OB_LOCK_SCALEX) == 0)
+ pchan->size[0] = 1.0f;
+ if ((pchan->protectflag & OB_LOCK_SCALEY) == 0)
+ pchan->size[1] = 1.0f;
+ if ((pchan->protectflag & OB_LOCK_SCALEZ) == 0)
+ pchan->size[2] = 1.0f;
+
+ pchan->ease1 = 0.0f;
+ pchan->ease2 = 0.0f;
+ pchan->scaleIn = 1.0f;
+ pchan->scaleOut = 1.0f;
}
/* clear location of pose-channel */
static void pchan_clear_loc(bPoseChannel *pchan)
{
- if ((pchan->protectflag & OB_LOCK_LOCX) == 0)
- pchan->loc[0] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_LOCY) == 0)
- pchan->loc[1] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_LOCZ) == 0)
- pchan->loc[2] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_LOCX) == 0)
+ pchan->loc[0] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_LOCY) == 0)
+ pchan->loc[1] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_LOCZ) == 0)
+ pchan->loc[2] = 0.0f;
}
/* clear rotation of pose-channel */
static void pchan_clear_rot(bPoseChannel *pchan)
{
- if (pchan->protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) {
- /* check if convert to eulers for locking... */
- if (pchan->protectflag & OB_LOCK_ROT4D) {
- /* perform clamping on a component by component basis */
- if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- if ((pchan->protectflag & OB_LOCK_ROTW) == 0)
- pchan->rotAngle = 0.0f;
- if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
- pchan->rotAxis[0] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
- pchan->rotAxis[1] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
- pchan->rotAxis[2] = 0.0f;
-
- /* check validity of axis - axis should never be 0,0,0 (if so, then we make it rotate about y) */
- if (IS_EQF(pchan->rotAxis[0], pchan->rotAxis[1]) && IS_EQF(pchan->rotAxis[1], pchan->rotAxis[2]))
- pchan->rotAxis[1] = 1.0f;
- }
- else if (pchan->rotmode == ROT_MODE_QUAT) {
- if ((pchan->protectflag & OB_LOCK_ROTW) == 0)
- pchan->quat[0] = 1.0f;
- if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
- pchan->quat[1] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
- pchan->quat[2] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
- pchan->quat[3] = 0.0f;
- }
- else {
- /* the flag may have been set for the other modes, so just ignore the extra flag... */
- if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
- pchan->eul[0] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
- pchan->eul[1] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
- pchan->eul[2] = 0.0f;
- }
- }
- else {
- /* perform clamping using euler form (3-components) */
- float eul[3], oldeul[3], quat1[4] = {0};
- float qlen = 0.0f;
-
- if (pchan->rotmode == ROT_MODE_QUAT) {
- qlen = normalize_qt_qt(quat1, pchan->quat);
- quat_to_eul(oldeul, quat1);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
- }
- else {
- copy_v3_v3(oldeul, pchan->eul);
- }
-
- eul[0] = eul[1] = eul[2] = 0.0f;
-
- if (pchan->protectflag & OB_LOCK_ROTX)
- eul[0] = oldeul[0];
- if (pchan->protectflag & OB_LOCK_ROTY)
- eul[1] = oldeul[1];
- if (pchan->protectflag & OB_LOCK_ROTZ)
- eul[2] = oldeul[2];
-
- if (pchan->rotmode == ROT_MODE_QUAT) {
- eul_to_quat(pchan->quat, eul);
-
- /* restore original quat size */
- mul_qt_fl(pchan->quat, qlen);
-
- /* quaternions flip w sign to accumulate rotations correctly */
- if ((quat1[0] < 0.0f && pchan->quat[0] > 0.0f) || (quat1[0] > 0.0f && pchan->quat[0] < 0.0f)) {
- mul_qt_fl(pchan->quat, -1.0f);
- }
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
- }
- else {
- copy_v3_v3(pchan->eul, eul);
- }
- }
- } /* Duplicated in source/blender/editors/object/object_transform.c */
- else {
- if (pchan->rotmode == ROT_MODE_QUAT) {
- unit_qt(pchan->quat);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- /* by default, make rotation of 0 radians around y-axis (roll) */
- unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
- }
- else {
- zero_v3(pchan->eul);
- }
- }
-
- /* Clear also Bendy Bone stuff - Roll is obvious,
- * but Curve X/Y stuff is also kindof rotational in nature... */
- pchan->roll1 = 0.0f;
- pchan->roll2 = 0.0f;
-
- pchan->curveInX = 0.0f;
- pchan->curveInY = 0.0f;
- pchan->curveOutX = 0.0f;
- pchan->curveOutY = 0.0f;
+ if (pchan->protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) {
+ /* check if convert to eulers for locking... */
+ if (pchan->protectflag & OB_LOCK_ROT4D) {
+ /* perform clamping on a component by component basis */
+ if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ if ((pchan->protectflag & OB_LOCK_ROTW) == 0)
+ pchan->rotAngle = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
+ pchan->rotAxis[0] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
+ pchan->rotAxis[1] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
+ pchan->rotAxis[2] = 0.0f;
+
+ /* check validity of axis - axis should never be 0,0,0 (if so, then we make it rotate about y) */
+ if (IS_EQF(pchan->rotAxis[0], pchan->rotAxis[1]) &&
+ IS_EQF(pchan->rotAxis[1], pchan->rotAxis[2]))
+ pchan->rotAxis[1] = 1.0f;
+ }
+ else if (pchan->rotmode == ROT_MODE_QUAT) {
+ if ((pchan->protectflag & OB_LOCK_ROTW) == 0)
+ pchan->quat[0] = 1.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
+ pchan->quat[1] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
+ pchan->quat[2] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
+ pchan->quat[3] = 0.0f;
+ }
+ else {
+ /* the flag may have been set for the other modes, so just ignore the extra flag... */
+ if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
+ pchan->eul[0] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
+ pchan->eul[1] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
+ pchan->eul[2] = 0.0f;
+ }
+ }
+ else {
+ /* perform clamping using euler form (3-components) */
+ float eul[3], oldeul[3], quat1[4] = {0};
+ float qlen = 0.0f;
+
+ if (pchan->rotmode == ROT_MODE_QUAT) {
+ qlen = normalize_qt_qt(quat1, pchan->quat);
+ quat_to_eul(oldeul, quat1);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
+ }
+ else {
+ copy_v3_v3(oldeul, pchan->eul);
+ }
+
+ eul[0] = eul[1] = eul[2] = 0.0f;
+
+ if (pchan->protectflag & OB_LOCK_ROTX)
+ eul[0] = oldeul[0];
+ if (pchan->protectflag & OB_LOCK_ROTY)
+ eul[1] = oldeul[1];
+ if (pchan->protectflag & OB_LOCK_ROTZ)
+ eul[2] = oldeul[2];
+
+ if (pchan->rotmode == ROT_MODE_QUAT) {
+ eul_to_quat(pchan->quat, eul);
+
+ /* restore original quat size */
+ mul_qt_fl(pchan->quat, qlen);
+
+ /* quaternions flip w sign to accumulate rotations correctly */
+ if ((quat1[0] < 0.0f && pchan->quat[0] > 0.0f) ||
+ (quat1[0] > 0.0f && pchan->quat[0] < 0.0f)) {
+ mul_qt_fl(pchan->quat, -1.0f);
+ }
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
+ }
+ else {
+ copy_v3_v3(pchan->eul, eul);
+ }
+ }
+ } /* Duplicated in source/blender/editors/object/object_transform.c */
+ else {
+ if (pchan->rotmode == ROT_MODE_QUAT) {
+ unit_qt(pchan->quat);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ /* by default, make rotation of 0 radians around y-axis (roll) */
+ unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
+ }
+ else {
+ zero_v3(pchan->eul);
+ }
+ }
+
+ /* Clear also Bendy Bone stuff - Roll is obvious,
+ * but Curve X/Y stuff is also kindof rotational in nature... */
+ pchan->roll1 = 0.0f;
+ pchan->roll2 = 0.0f;
+
+ pchan->curveInX = 0.0f;
+ pchan->curveInY = 0.0f;
+ pchan->curveOutX = 0.0f;
+ pchan->curveOutY = 0.0f;
}
/* clear loc/rot/scale of pose-channel */
static void pchan_clear_transforms(bPoseChannel *pchan)
{
- pchan_clear_loc(pchan);
- pchan_clear_rot(pchan);
- pchan_clear_scale(pchan);
+ pchan_clear_loc(pchan);
+ pchan_clear_rot(pchan);
+ pchan_clear_scale(pchan);
}
/* --------------- */
/* generic exec for clear-pose operators */
-static int pose_clear_transform_generic_exec(bContext *C, wmOperator *op,
- void (*clear_func)(bPoseChannel *), const char default_ksName[])
+static int pose_clear_transform_generic_exec(bContext *C,
+ wmOperator *op,
+ void (*clear_func)(bPoseChannel *),
+ const char default_ksName[])
{
- Scene *scene = CTX_data_scene(C);
- bool changed_multi = false;
-
- /* sanity checks */
- if (ELEM(NULL, clear_func, default_ksName)) {
- BKE_report(op->reports, RPT_ERROR, "Programming error: missing clear transform function or keying set name");
- return OPERATOR_CANCELLED;
- }
-
- /* only clear relevant transforms for selected bones */
- ViewLayer *view_layer = CTX_data_view_layer(C);
- View3D *v3d = CTX_wm_view3d(C);
- FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob_iter)
- {
- Object *ob_eval = DEG_get_evaluated_object(CTX_data_depsgraph(C), ob_iter); // XXX: UGLY HACK (for autokey + clear transforms)
- ListBase dsources = {NULL, NULL};
- bool changed = false;
-
- FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob_iter, pchan)
- {
- /* run provided clearing function */
- clear_func(pchan);
- changed = true;
-
- /* do auto-keyframing as appropriate */
- if (autokeyframe_cfra_can_key(scene, &ob_iter->id)) {
- /* clear any unkeyed tags */
- if (pchan->bone) {
- pchan->bone->flag &= ~BONE_UNKEYED;
- }
- /* tag for autokeying later */
- ANIM_relative_keyingset_add_source(&dsources, &ob_iter->id, &RNA_PoseBone, pchan);
-
-#if 1 /* XXX: Ugly Hack - Run clearing function on evaluated copy of pchan */
- bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
- clear_func(pchan_eval);
+ Scene *scene = CTX_data_scene(C);
+ bool changed_multi = false;
+
+ /* sanity checks */
+ if (ELEM(NULL, clear_func, default_ksName)) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Programming error: missing clear transform function or keying set name");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* only clear relevant transforms for selected bones */
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob_iter) {
+ Object *ob_eval = DEG_get_evaluated_object(
+ CTX_data_depsgraph(C), ob_iter); // XXX: UGLY HACK (for autokey + clear transforms)
+ ListBase dsources = {NULL, NULL};
+ bool changed = false;
+
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob_iter, pchan) {
+ /* run provided clearing function */
+ clear_func(pchan);
+ changed = true;
+
+ /* do auto-keyframing as appropriate */
+ if (autokeyframe_cfra_can_key(scene, &ob_iter->id)) {
+ /* clear any unkeyed tags */
+ if (pchan->bone) {
+ pchan->bone->flag &= ~BONE_UNKEYED;
+ }
+ /* tag for autokeying later */
+ ANIM_relative_keyingset_add_source(&dsources, &ob_iter->id, &RNA_PoseBone, pchan);
+
+#if 1 /* XXX: Ugly Hack - Run clearing function on evaluated copy of pchan */
+ bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
+ clear_func(pchan_eval);
#endif
- }
- else {
- /* add unkeyed tags */
- if (pchan->bone) {
- pchan->bone->flag |= BONE_UNKEYED;
- }
- }
- }
- FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
-
- if (changed) {
- changed_multi = true;
-
- /* perform autokeying on the bones if needed */
- if (!BLI_listbase_is_empty(&dsources)) {
- /* get KeyingSet to use */
- KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName);
-
- /* insert keyframes */
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
-
- /* now recalculate paths */
- if ((ob_iter->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) {
- ED_pose_recalculate_paths(C, scene, ob_iter, false);
- }
-
- BLI_freelistN(&dsources);
- }
-
- DEG_id_tag_update(&ob_iter->id, ID_RECALC_GEOMETRY);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob_iter);
- }
- }
- FOREACH_OBJECT_IN_MODE_END;
-
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ }
+ else {
+ /* add unkeyed tags */
+ if (pchan->bone) {
+ pchan->bone->flag |= BONE_UNKEYED;
+ }
+ }
+ }
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
+
+ if (changed) {
+ changed_multi = true;
+
+ /* perform autokeying on the bones if needed */
+ if (!BLI_listbase_is_empty(&dsources)) {
+ /* get KeyingSet to use */
+ KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName);
+
+ /* insert keyframes */
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+
+ /* now recalculate paths */
+ if ((ob_iter->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) {
+ ED_pose_recalculate_paths(C, scene, ob_iter, false);
+ }
+
+ BLI_freelistN(&dsources);
+ }
+
+ DEG_id_tag_update(&ob_iter->id, ID_RECALC_GEOMETRY);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob_iter);
+ }
+ }
+ FOREACH_OBJECT_IN_MODE_END;
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
/* --------------- */
static int pose_clear_scale_exec(bContext *C, wmOperator *op)
{
- return pose_clear_transform_generic_exec(C, op, pchan_clear_scale, ANIM_KS_SCALING_ID);
+ return pose_clear_transform_generic_exec(C, op, pchan_clear_scale, ANIM_KS_SCALING_ID);
}
void POSE_OT_scale_clear(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Clear Pose Scale";
- ot->idname = "POSE_OT_scale_clear";
- ot->description = "Reset scaling of selected bones to their default values";
+ /* identifiers */
+ ot->name = "Clear Pose Scale";
+ ot->idname = "POSE_OT_scale_clear";
+ ot->description = "Reset scaling of selected bones to their default values";
- /* api callbacks */
- ot->exec = pose_clear_scale_exec;
- ot->poll = ED_operator_posemode;
+ /* api callbacks */
+ ot->exec = pose_clear_scale_exec;
+ ot->poll = ED_operator_posemode;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-
static int pose_clear_rot_exec(bContext *C, wmOperator *op)
{
- return pose_clear_transform_generic_exec(C, op, pchan_clear_rot, ANIM_KS_ROTATION_ID);
+ return pose_clear_transform_generic_exec(C, op, pchan_clear_rot, ANIM_KS_ROTATION_ID);
}
void POSE_OT_rot_clear(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Clear Pose Rotation";
- ot->idname = "POSE_OT_rot_clear";
- ot->description = "Reset rotations of selected bones to their default values";
+ /* identifiers */
+ ot->name = "Clear Pose Rotation";
+ ot->idname = "POSE_OT_rot_clear";
+ ot->description = "Reset rotations of selected bones to their default values";
- /* api callbacks */
- ot->exec = pose_clear_rot_exec;
- ot->poll = ED_operator_posemode;
+ /* api callbacks */
+ ot->exec = pose_clear_rot_exec;
+ ot->poll = ED_operator_posemode;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-
static int pose_clear_loc_exec(bContext *C, wmOperator *op)
{
- return pose_clear_transform_generic_exec(C, op, pchan_clear_loc, ANIM_KS_LOCATION_ID);
+ return pose_clear_transform_generic_exec(C, op, pchan_clear_loc, ANIM_KS_LOCATION_ID);
}
void POSE_OT_loc_clear(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Clear Pose Location";
- ot->idname = "POSE_OT_loc_clear";
- ot->description = "Reset locations of selected bones to their default values";
+ /* identifiers */
+ ot->name = "Clear Pose Location";
+ ot->idname = "POSE_OT_loc_clear";
+ ot->description = "Reset locations of selected bones to their default values";
- /* api callbacks */
- ot->exec = pose_clear_loc_exec;
- ot->poll = ED_operator_posemode;
+ /* api callbacks */
+ ot->exec = pose_clear_loc_exec;
+ ot->poll = ED_operator_posemode;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-
static int pose_clear_transforms_exec(bContext *C, wmOperator *op)
{
- return pose_clear_transform_generic_exec(C, op, pchan_clear_transforms, ANIM_KS_LOC_ROT_SCALE_ID);
+ return pose_clear_transform_generic_exec(
+ C, op, pchan_clear_transforms, ANIM_KS_LOC_ROT_SCALE_ID);
}
void POSE_OT_transforms_clear(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Clear Pose Transforms";
- ot->idname = "POSE_OT_transforms_clear";
- ot->description = "Reset location, rotation, and scaling of selected bones to their default values";
-
- /* api callbacks */
- ot->exec = pose_clear_transforms_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* identifiers */
+ ot->name = "Clear Pose Transforms";
+ ot->idname = "POSE_OT_transforms_clear";
+ ot->description =
+ "Reset location, rotation, and scaling of selected bones to their default values";
+
+ /* api callbacks */
+ ot->exec = pose_clear_transforms_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ********************************************** */
@@ -932,80 +944,79 @@ void POSE_OT_transforms_clear(wmOperatorType *ot)
static int pose_clear_user_transforms_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- View3D *v3d = CTX_wm_view3d(C);
- Scene *scene = CTX_data_scene(C);
- float cframe = (float)CFRA;
- const bool only_select = RNA_boolean_get(op->ptr, "only_selected");
-
- FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob)
- {
- if ((ob->adt) && (ob->adt->action)) {
- /* XXX: this is just like this to avoid contaminating anything else;
- * just pose values should change, so this should be fine
- */
- bPose *dummyPose = NULL;
- Object workob = {{NULL}};
- bPoseChannel *pchan;
-
- /* execute animation step for current frame using a dummy copy of the pose */
- BKE_pose_copy_data(&dummyPose, ob->pose, 0);
-
- BLI_strncpy(workob.id.name, "OB<ClearTfmWorkOb>", sizeof(workob.id.name));
- workob.type = OB_ARMATURE;
- workob.data = ob->data;
- workob.adt = ob->adt;
- workob.pose = dummyPose;
-
- BKE_animsys_evaluate_animdata(NULL, scene, &workob.id, workob.adt, cframe, ADT_RECALC_ANIM);
-
- /* copy back values, but on selected bones only */
- for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) {
- pose_bone_do_paste(ob, pchan, only_select, 0);
- }
-
- /* free temp data - free manually as was copied without constraints */
- for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->prop) {
- IDP_FreeProperty(pchan->prop);
- MEM_freeN(pchan->prop);
- }
- }
-
- /* was copied without constraints */
- BLI_freelistN(&dummyPose->chanbase);
- MEM_freeN(dummyPose);
- }
- else {
- /* no animation, so just reset whole pose to rest pose
- * (cannot just restore for selected though)
- */
- BKE_pose_rest(ob->pose);
- }
-
- /* notifiers and updates */
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
- }
- FOREACH_OBJECT_IN_MODE_END;
-
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ Scene *scene = CTX_data_scene(C);
+ float cframe = (float)CFRA;
+ const bool only_select = RNA_boolean_get(op->ptr, "only_selected");
+
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
+ if ((ob->adt) && (ob->adt->action)) {
+ /* XXX: this is just like this to avoid contaminating anything else;
+ * just pose values should change, so this should be fine
+ */
+ bPose *dummyPose = NULL;
+ Object workob = {{NULL}};
+ bPoseChannel *pchan;
+
+ /* execute animation step for current frame using a dummy copy of the pose */
+ BKE_pose_copy_data(&dummyPose, ob->pose, 0);
+
+ BLI_strncpy(workob.id.name, "OB<ClearTfmWorkOb>", sizeof(workob.id.name));
+ workob.type = OB_ARMATURE;
+ workob.data = ob->data;
+ workob.adt = ob->adt;
+ workob.pose = dummyPose;
+
+ BKE_animsys_evaluate_animdata(NULL, scene, &workob.id, workob.adt, cframe, ADT_RECALC_ANIM);
+
+ /* copy back values, but on selected bones only */
+ for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) {
+ pose_bone_do_paste(ob, pchan, only_select, 0);
+ }
+
+ /* free temp data - free manually as was copied without constraints */
+ for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->prop) {
+ IDP_FreeProperty(pchan->prop);
+ MEM_freeN(pchan->prop);
+ }
+ }
+
+ /* was copied without constraints */
+ BLI_freelistN(&dummyPose->chanbase);
+ MEM_freeN(dummyPose);
+ }
+ else {
+ /* no animation, so just reset whole pose to rest pose
+ * (cannot just restore for selected though)
+ */
+ BKE_pose_rest(ob->pose);
+ }
+
+ /* notifiers and updates */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
+ }
+ FOREACH_OBJECT_IN_MODE_END;
+
+ return OPERATOR_FINISHED;
}
void POSE_OT_user_transforms_clear(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Clear User Transforms";
- ot->idname = "POSE_OT_user_transforms_clear";
- ot->description = "Reset pose on selected bones to keyframed state";
+ /* identifiers */
+ ot->name = "Clear User Transforms";
+ ot->idname = "POSE_OT_user_transforms_clear";
+ ot->description = "Reset pose on selected bones to keyframed state";
- /* callbacks */
- ot->exec = pose_clear_user_transforms_exec;
- ot->poll = ED_operator_posemode;
+ /* callbacks */
+ ot->exec = pose_clear_user_transforms_exec;
+ ot->poll = ED_operator_posemode;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
- RNA_def_boolean(ot->srna, "only_selected", true, "Only Selected", "Only visible/selected bones");
+ /* properties */
+ RNA_def_boolean(ot->srna, "only_selected", true, "Only Selected", "Only visible/selected bones");
}
diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c
index 25ddcee52cf..d8793bc2a1e 100644
--- a/source/blender/editors/armature/pose_utils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -63,64 +63,67 @@
/* FCurves <-> PoseChannels Links */
/* helper for poseAnim_mapping_get() -> get the relevant F-Curves per PoseChannel */
-static void fcurves_to_pchan_links_get(ListBase *pfLinks, Object *ob, bAction *act, bPoseChannel *pchan)
+static void fcurves_to_pchan_links_get(ListBase *pfLinks,
+ Object *ob,
+ bAction *act,
+ bPoseChannel *pchan)
{
- ListBase curves = {NULL, NULL};
- int transFlags = action_get_item_transforms(act, ob, pchan, &curves);
-
- pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE | POSE_BBONE_SHAPE);
-
- /* check if any transforms found... */
- if (transFlags) {
- /* make new linkage data */
- tPChanFCurveLink *pfl = MEM_callocN(sizeof(tPChanFCurveLink), "tPChanFCurveLink");
- PointerRNA ptr;
-
- pfl->ob = ob;
- pfl->fcurves = curves;
- pfl->pchan = pchan;
-
- /* get the RNA path to this pchan - this needs to be freed! */
- RNA_pointer_create((ID *)ob, &RNA_PoseBone, pchan, &ptr);
- pfl->pchan_path = RNA_path_from_ID_to_struct(&ptr);
-
- /* add linkage data to operator data */
- BLI_addtail(pfLinks, pfl);
-
- /* set pchan's transform flags */
- if (transFlags & ACT_TRANS_LOC)
- pchan->flag |= POSE_LOC;
- if (transFlags & ACT_TRANS_ROT)
- pchan->flag |= POSE_ROT;
- if (transFlags & ACT_TRANS_SCALE)
- pchan->flag |= POSE_SIZE;
- if (transFlags & ACT_TRANS_BBONE)
- pchan->flag |= POSE_BBONE_SHAPE;
-
- /* store current transforms */
- copy_v3_v3(pfl->oldloc, pchan->loc);
- copy_v3_v3(pfl->oldrot, pchan->eul);
- copy_v3_v3(pfl->oldscale, pchan->size);
- copy_qt_qt(pfl->oldquat, pchan->quat);
- copy_v3_v3(pfl->oldaxis, pchan->rotAxis);
- pfl->oldangle = pchan->rotAngle;
-
- /* store current bbone values */
- pfl->roll1 = pchan->roll1;
- pfl->roll2 = pchan->roll2;
- pfl->curveInX = pchan->curveInX;
- pfl->curveInY = pchan->curveInY;
- pfl->curveOutX = pchan->curveOutX;
- pfl->curveOutY = pchan->curveOutY;
- pfl->ease1 = pchan->ease1;
- pfl->ease2 = pchan->ease2;
- pfl->scaleIn = pchan->scaleIn;
- pfl->scaleOut = pchan->scaleOut;
-
- /* make copy of custom properties */
- if (pchan->prop && (transFlags & ACT_TRANS_PROP))
- pfl->oldprops = IDP_CopyProperty(pchan->prop);
- }
+ ListBase curves = {NULL, NULL};
+ int transFlags = action_get_item_transforms(act, ob, pchan, &curves);
+
+ pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE | POSE_BBONE_SHAPE);
+
+ /* check if any transforms found... */
+ if (transFlags) {
+ /* make new linkage data */
+ tPChanFCurveLink *pfl = MEM_callocN(sizeof(tPChanFCurveLink), "tPChanFCurveLink");
+ PointerRNA ptr;
+
+ pfl->ob = ob;
+ pfl->fcurves = curves;
+ pfl->pchan = pchan;
+
+ /* get the RNA path to this pchan - this needs to be freed! */
+ RNA_pointer_create((ID *)ob, &RNA_PoseBone, pchan, &ptr);
+ pfl->pchan_path = RNA_path_from_ID_to_struct(&ptr);
+
+ /* add linkage data to operator data */
+ BLI_addtail(pfLinks, pfl);
+
+ /* set pchan's transform flags */
+ if (transFlags & ACT_TRANS_LOC)
+ pchan->flag |= POSE_LOC;
+ if (transFlags & ACT_TRANS_ROT)
+ pchan->flag |= POSE_ROT;
+ if (transFlags & ACT_TRANS_SCALE)
+ pchan->flag |= POSE_SIZE;
+ if (transFlags & ACT_TRANS_BBONE)
+ pchan->flag |= POSE_BBONE_SHAPE;
+
+ /* store current transforms */
+ copy_v3_v3(pfl->oldloc, pchan->loc);
+ copy_v3_v3(pfl->oldrot, pchan->eul);
+ copy_v3_v3(pfl->oldscale, pchan->size);
+ copy_qt_qt(pfl->oldquat, pchan->quat);
+ copy_v3_v3(pfl->oldaxis, pchan->rotAxis);
+ pfl->oldangle = pchan->rotAngle;
+
+ /* store current bbone values */
+ pfl->roll1 = pchan->roll1;
+ pfl->roll2 = pchan->roll2;
+ pfl->curveInX = pchan->curveInX;
+ pfl->curveInY = pchan->curveInY;
+ pfl->curveOutX = pchan->curveOutX;
+ pfl->curveOutY = pchan->curveOutY;
+ pfl->ease1 = pchan->ease1;
+ pfl->ease2 = pchan->ease2;
+ pfl->scaleIn = pchan->scaleIn;
+ pfl->scaleOut = pchan->scaleOut;
+
+ /* make copy of custom properties */
+ if (pchan->prop && (transFlags & ACT_TRANS_PROP))
+ pfl->oldprops = IDP_CopyProperty(pchan->prop);
+ }
}
/**
@@ -128,96 +131,85 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks, Object *ob, bAction *a
*/
Object *poseAnim_object_get(Object *ob_)
{
- Object *ob = BKE_object_pose_armature_get(ob_);
- if (!ELEM(NULL,
- ob,
- ob->data,
- ob->adt,
- ob->adt->action))
- {
- return ob;
- }
- return NULL;
+ Object *ob = BKE_object_pose_armature_get(ob_);
+ if (!ELEM(NULL, ob, ob->data, ob->adt, ob->adt->action)) {
+ return ob;
+ }
+ return NULL;
}
/* get sets of F-Curves providing transforms for the bones in the Pose */
void poseAnim_mapping_get(bContext *C, ListBase *pfLinks)
{
- /* for each Pose-Channel which gets affected, get the F-Curves for that channel
- * and set the relevant transform flags...
- */
- Object *prev_ob, *ob_pose_armature;
-
- prev_ob = NULL;
- ob_pose_armature = NULL;
- CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob)
- {
- if (ob != prev_ob) {
- prev_ob = ob;
- ob_pose_armature = poseAnim_object_get(ob);
- }
-
- if (ob_pose_armature == NULL) {
- continue;
- }
-
- fcurves_to_pchan_links_get(pfLinks,
- ob_pose_armature,
- ob_pose_armature->adt->action,
- pchan);
- }
- CTX_DATA_END;
-
- /* if no PoseChannels were found, try a second pass, doing visible ones instead
- * i.e. if nothing selected, do whole pose
- */
- if (BLI_listbase_is_empty(pfLinks)) {
- prev_ob = NULL;
- ob_pose_armature = NULL;
- CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob)
- {
- if (ob != prev_ob) {
- prev_ob = ob;
- ob_pose_armature = poseAnim_object_get(ob);
- }
-
- if (ob_pose_armature == NULL) {
- continue;
- }
-
- fcurves_to_pchan_links_get(pfLinks,
- ob_pose_armature,
- ob_pose_armature->adt->action,
- pchan);
- }
- CTX_DATA_END;
- }
+ /* for each Pose-Channel which gets affected, get the F-Curves for that channel
+ * and set the relevant transform flags...
+ */
+ Object *prev_ob, *ob_pose_armature;
+
+ prev_ob = NULL;
+ ob_pose_armature = NULL;
+ CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob)
+ {
+ if (ob != prev_ob) {
+ prev_ob = ob;
+ ob_pose_armature = poseAnim_object_get(ob);
+ }
+
+ if (ob_pose_armature == NULL) {
+ continue;
+ }
+
+ fcurves_to_pchan_links_get(pfLinks, ob_pose_armature, ob_pose_armature->adt->action, pchan);
+ }
+ CTX_DATA_END;
+
+ /* if no PoseChannels were found, try a second pass, doing visible ones instead
+ * i.e. if nothing selected, do whole pose
+ */
+ if (BLI_listbase_is_empty(pfLinks)) {
+ prev_ob = NULL;
+ ob_pose_armature = NULL;
+ CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob)
+ {
+ if (ob != prev_ob) {
+ prev_ob = ob;
+ ob_pose_armature = poseAnim_object_get(ob);
+ }
+
+ if (ob_pose_armature == NULL) {
+ continue;
+ }
+
+ fcurves_to_pchan_links_get(pfLinks, ob_pose_armature, ob_pose_armature->adt->action, pchan);
+ }
+ CTX_DATA_END;
+ }
}
/* free F-Curve <-> PoseChannel links */
void poseAnim_mapping_free(ListBase *pfLinks)
{
- tPChanFCurveLink *pfl, *pfln = NULL;
+ tPChanFCurveLink *pfl, *pfln = NULL;
- /* free the temp pchan links and their data */
- for (pfl = pfLinks->first; pfl; pfl = pfln) {
- pfln = pfl->next;
+ /* free the temp pchan links and their data */
+ for (pfl = pfLinks->first; pfl; pfl = pfln) {
+ pfln = pfl->next;
- /* free custom properties */
- if (pfl->oldprops) {
- IDP_FreeProperty(pfl->oldprops);
- MEM_freeN(pfl->oldprops);
- }
+ /* free custom properties */
+ if (pfl->oldprops) {
+ IDP_FreeProperty(pfl->oldprops);
+ MEM_freeN(pfl->oldprops);
+ }
- /* free list of F-Curve reference links */
- BLI_freelistN(&pfl->fcurves);
+ /* free list of F-Curve reference links */
+ BLI_freelistN(&pfl->fcurves);
- /* free pchan RNA Path */
- MEM_freeN(pfl->pchan_path);
+ /* free pchan RNA Path */
+ MEM_freeN(pfl->pchan_path);
- /* free link itself */
- BLI_freelinkN(pfLinks, pfl);
- }
+ /* free link itself */
+ BLI_freelinkN(pfLinks, pfl);
+ }
}
/* ------------------------- */
@@ -225,125 +217,127 @@ void poseAnim_mapping_free(ListBase *pfLinks)
/* helper for apply() / reset() - refresh the data */
void poseAnim_mapping_refresh(bContext *C, Scene *scene, Object *ob)
{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- bArmature *arm = (bArmature *)ob->data;
-
- /* old optimize trick... this enforces to bypass the depgraph
- * - note: code copied from transform_generics.c -> recalcData()
- */
- /* FIXME: shouldn't this use the builtin stuff? */
- if ((arm->flag & ARM_DELAYDEFORM) == 0)
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); /* sets recalc flags */
- else
- BKE_pose_where_is(depsgraph, scene, ob);
-
- /* otherwise animation doesn't get updated */
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ bArmature *arm = (bArmature *)ob->data;
+
+ /* old optimize trick... this enforces to bypass the depgraph
+ * - note: code copied from transform_generics.c -> recalcData()
+ */
+ /* FIXME: shouldn't this use the builtin stuff? */
+ if ((arm->flag & ARM_DELAYDEFORM) == 0)
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); /* sets recalc flags */
+ else
+ BKE_pose_where_is(depsgraph, scene, ob);
+
+ /* otherwise animation doesn't get updated */
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
}
/* reset changes made to current pose */
void poseAnim_mapping_reset(ListBase *pfLinks)
{
- tPChanFCurveLink *pfl;
-
- /* iterate over each pose-channel affected, restoring all channels to their original values */
- for (pfl = pfLinks->first; pfl; pfl = pfl->next) {
- bPoseChannel *pchan = pfl->pchan;
-
- /* just copy all the values over regardless of whether they changed or not */
- copy_v3_v3(pchan->loc, pfl->oldloc);
- copy_v3_v3(pchan->eul, pfl->oldrot);
- copy_v3_v3(pchan->size, pfl->oldscale);
- copy_qt_qt(pchan->quat, pfl->oldquat);
- copy_v3_v3(pchan->rotAxis, pfl->oldaxis);
- pchan->rotAngle = pfl->oldangle;
-
- /* store current bbone values */
- pchan->roll1 = pfl->roll1;
- pchan->roll2 = pfl->roll2;
- pchan->curveInX = pfl->curveInX;
- pchan->curveInY = pfl->curveInY;
- pchan->curveOutX = pfl->curveOutX;
- pchan->curveOutY = pfl->curveOutY;
- pchan->ease1 = pfl->ease1;
- pchan->ease2 = pfl->ease2;
- pchan->scaleIn = pfl->scaleIn;
- pchan->scaleOut = pfl->scaleOut;
-
- /* just overwrite values of properties from the stored copies (there should be some) */
- if (pfl->oldprops)
- IDP_SyncGroupValues(pfl->pchan->prop, pfl->oldprops);
- }
+ tPChanFCurveLink *pfl;
+
+ /* iterate over each pose-channel affected, restoring all channels to their original values */
+ for (pfl = pfLinks->first; pfl; pfl = pfl->next) {
+ bPoseChannel *pchan = pfl->pchan;
+
+ /* just copy all the values over regardless of whether they changed or not */
+ copy_v3_v3(pchan->loc, pfl->oldloc);
+ copy_v3_v3(pchan->eul, pfl->oldrot);
+ copy_v3_v3(pchan->size, pfl->oldscale);
+ copy_qt_qt(pchan->quat, pfl->oldquat);
+ copy_v3_v3(pchan->rotAxis, pfl->oldaxis);
+ pchan->rotAngle = pfl->oldangle;
+
+ /* store current bbone values */
+ pchan->roll1 = pfl->roll1;
+ pchan->roll2 = pfl->roll2;
+ pchan->curveInX = pfl->curveInX;
+ pchan->curveInY = pfl->curveInY;
+ pchan->curveOutX = pfl->curveOutX;
+ pchan->curveOutY = pfl->curveOutY;
+ pchan->ease1 = pfl->ease1;
+ pchan->ease2 = pfl->ease2;
+ pchan->scaleIn = pfl->scaleIn;
+ pchan->scaleOut = pfl->scaleOut;
+
+ /* just overwrite values of properties from the stored copies (there should be some) */
+ if (pfl->oldprops)
+ IDP_SyncGroupValues(pfl->pchan->prop, pfl->oldprops);
+ }
}
/* perform auto-key-framing after changes were made + confirmed */
void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks, float cframe)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- View3D *v3d = CTX_wm_view3d(C);
- bool skip = true;
-
- FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
- ob->id.tag &= ~LIB_TAG_DOIT;
- ob = poseAnim_object_get(ob);
-
- /* Ensure validity of the settings from the context. */
- if (ob == NULL) {
- continue;
- }
-
- if (autokeyframe_cfra_can_key(scene, &ob->id)) {
- ob->id.tag |= LIB_TAG_DOIT;
- skip = false;
- }
- } FOREACH_OBJECT_IN_MODE_END;
-
- if (skip) {
- return;
- }
-
- /* Insert keyframes as necessary if auto-key-framing. */
- KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID);
- ListBase dsources = {NULL, NULL};
- tPChanFCurveLink *pfl;
-
- /* iterate over each pose-channel affected, tagging bones to be keyed */
- /* XXX: here we already have the information about what transforms exist, though
- * it might be easier to just overwrite all using normal mechanisms
- */
- for (pfl = pfLinks->first; pfl; pfl = pfl->next) {
- bPoseChannel *pchan = pfl->pchan;
-
- if ((pfl->ob->id.tag & LIB_TAG_DOIT) == 0) {
- continue;
- }
-
- /* add datasource override for the PoseChannel, to be used later */
- ANIM_relative_keyingset_add_source(&dsources, &pfl->ob->id, &RNA_PoseBone, pchan);
-
- /* clear any unkeyed tags */
- if (pchan->bone) {
- pchan->bone->flag &= ~BONE_UNKEYED;
- }
- }
-
- /* insert keyframes for all relevant bones in one go */
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cframe);
- BLI_freelistN(&dsources);
-
- /* do the bone paths
- * - only do this if keyframes should have been added
- * - do not calculate unless there are paths already to update...
- */
- FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
- if (ob->id.tag & LIB_TAG_DOIT) {
- if (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) {
- //ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear
- ED_pose_recalculate_paths(C, scene, ob, false);
- }
- }
- } FOREACH_OBJECT_IN_MODE_END;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ bool skip = true;
+
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
+ ob->id.tag &= ~LIB_TAG_DOIT;
+ ob = poseAnim_object_get(ob);
+
+ /* Ensure validity of the settings from the context. */
+ if (ob == NULL) {
+ continue;
+ }
+
+ if (autokeyframe_cfra_can_key(scene, &ob->id)) {
+ ob->id.tag |= LIB_TAG_DOIT;
+ skip = false;
+ }
+ }
+ FOREACH_OBJECT_IN_MODE_END;
+
+ if (skip) {
+ return;
+ }
+
+ /* Insert keyframes as necessary if auto-key-framing. */
+ KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID);
+ ListBase dsources = {NULL, NULL};
+ tPChanFCurveLink *pfl;
+
+ /* iterate over each pose-channel affected, tagging bones to be keyed */
+ /* XXX: here we already have the information about what transforms exist, though
+ * it might be easier to just overwrite all using normal mechanisms
+ */
+ for (pfl = pfLinks->first; pfl; pfl = pfl->next) {
+ bPoseChannel *pchan = pfl->pchan;
+
+ if ((pfl->ob->id.tag & LIB_TAG_DOIT) == 0) {
+ continue;
+ }
+
+ /* add datasource override for the PoseChannel, to be used later */
+ ANIM_relative_keyingset_add_source(&dsources, &pfl->ob->id, &RNA_PoseBone, pchan);
+
+ /* clear any unkeyed tags */
+ if (pchan->bone) {
+ pchan->bone->flag &= ~BONE_UNKEYED;
+ }
+ }
+
+ /* insert keyframes for all relevant bones in one go */
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cframe);
+ BLI_freelistN(&dsources);
+
+ /* do the bone paths
+ * - only do this if keyframes should have been added
+ * - do not calculate unless there are paths already to update...
+ */
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
+ if (ob->id.tag & LIB_TAG_DOIT) {
+ if (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) {
+ //ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear
+ ED_pose_recalculate_paths(C, scene, ob, false);
+ }
+ }
+ }
+ FOREACH_OBJECT_IN_MODE_END;
}
/* ------------------------- */
@@ -353,20 +347,20 @@ void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks,
*/
LinkData *poseAnim_mapping_getNextFCurve(ListBase *fcuLinks, LinkData *prev, const char *path)
{
- LinkData *first = (prev) ? prev->next : (fcuLinks) ? fcuLinks->first : NULL;
- LinkData *ld;
+ LinkData *first = (prev) ? prev->next : (fcuLinks) ? fcuLinks->first : NULL;
+ LinkData *ld;
- /* check each link to see if the linked F-Curve has a matching path */
- for (ld = first; ld; ld = ld->next) {
- FCurve *fcu = (FCurve *)ld->data;
+ /* check each link to see if the linked F-Curve has a matching path */
+ for (ld = first; ld; ld = ld->next) {
+ FCurve *fcu = (FCurve *)ld->data;
- /* check if paths match */
- if (STREQ(path, fcu->rna_path))
- return ld;
- }
+ /* check if paths match */
+ if (STREQ(path, fcu->rna_path))
+ return ld;
+ }
- /* none found */
- return NULL;
+ /* none found */
+ return NULL;
}
/* *********************************************** */