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:
Diffstat (limited to 'source/blender/editors/armature')
-rw-r--r--source/blender/editors/armature/armature_add.c571
-rw-r--r--source/blender/editors/armature/armature_edit.c222
-rw-r--r--source/blender/editors/armature/armature_intern.h52
-rw-r--r--source/blender/editors/armature/armature_naming.c66
-rw-r--r--source/blender/editors/armature/armature_ops.c3
-rw-r--r--source/blender/editors/armature/armature_relations.c24
-rw-r--r--source/blender/editors/armature/armature_select.c803
-rw-r--r--source/blender/editors/armature/armature_skinning.c4
-rw-r--r--source/blender/editors/armature/armature_utils.c35
-rw-r--r--source/blender/editors/armature/editarmature_undo.c3
-rw-r--r--source/blender/editors/armature/meshlaplacian.c6
-rw-r--r--source/blender/editors/armature/pose_edit.c13
-rw-r--r--source/blender/editors/armature/pose_group.c3
-rw-r--r--source/blender/editors/armature/pose_lib.c24
-rw-r--r--source/blender/editors/armature/pose_select.c84
-rw-r--r--source/blender/editors/armature/pose_slide.c182
-rw-r--r--source/blender/editors/armature/pose_transform.c23
-rw-r--r--source/blender/editors/armature/pose_utils.c2
18 files changed, 1402 insertions, 718 deletions
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index e87040279af..895b4953992 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -22,6 +22,7 @@
* \ingroup edarmature
*/
+#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
#include "DNA_object_types.h"
@@ -38,8 +39,12 @@
#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_deform.h"
+#include "BKE_fcurve.h"
#include "BKE_idprop.h"
#include "BKE_layer.h"
+#include "BKE_lib_id.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -48,6 +53,7 @@
#include "WM_types.h"
#include "ED_armature.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -217,6 +223,7 @@ static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op))
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
return OPERATOR_FINISHED;
}
@@ -341,7 +348,7 @@ void postEditBoneDuplicate(struct ListBase *editbones, Object *ob)
GHash *name_map = BLI_ghash_str_new(__func__);
- for (EditBone *ebone_src = editbones->first; ebone_src; ebone_src = ebone_src->next) {
+ LISTBASE_FOREACH (EditBone *, ebone_src, editbones) {
EditBone *ebone_dst = ebone_src->temp.ebone;
if (!ebone_dst) {
ebone_dst = ED_armature_ebone_get_mirrored(editbones, ebone_src);
@@ -351,7 +358,7 @@ void postEditBoneDuplicate(struct ListBase *editbones, Object *ob)
}
}
- for (EditBone *ebone_src = editbones->first; ebone_src; ebone_src = ebone_src->next) {
+ LISTBASE_FOREACH (EditBone *, ebone_src, editbones) {
EditBone *ebone_dst = ebone_src->temp.ebone;
if (ebone_dst) {
bPoseChannel *pchan_src = BKE_pose_channel_find_name(ob->pose, ebone_src->name);
@@ -375,25 +382,20 @@ void postEditBoneDuplicate(struct ListBase *editbones, Object *ob)
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,
+static void updateDuplicateSubtarget(EditBone *dup_bone,
ListBase *editbones,
- Object *src_ob,
- Object *dst_ob)
+ Object *ob,
+ bool lookup_mirror_subtarget)
{
- /* If an edit bone has been duplicated, lets
- * update it's constraints if the subtarget
- * they point to has also been duplicated
+ /* 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 ((pchan = BKE_pose_channel_verify(ob->pose, dup_bone->name))) {
if ((conlist = &pchan->constraints)) {
for (curcon = conlist->first; curcon; curcon = curcon->next) {
/* does this constraint have a subtarget in
@@ -407,8 +409,7 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone,
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 */
+ if ((ct->tar == ob) && (ct->subtarget[0])) {
oldtarget = get_named_editbone(editbones, ct->subtarget);
if (oldtarget) {
/* was the subtarget bone duplicated too? If
@@ -419,6 +420,17 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone,
newtarget = oldtarget->temp.ebone;
BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget));
}
+ else if (lookup_mirror_subtarget) {
+ /* The subtarget was not selected for duplication, try to see if a mirror bone of
+ * the current target exists */
+ char name_flip[MAXBONENAME];
+
+ BLI_string_flip_side_name(name_flip, oldtarget->name, false, sizeof(name_flip));
+ newtarget = get_named_editbone(editbones, name_flip);
+ if (newtarget) {
+ BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget));
+ }
+ }
}
}
}
@@ -432,32 +444,434 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone,
}
}
-void updateDuplicateSubtarget(EditBone *dupBone, ListBase *editbones, Object *ob)
+static void updateDuplicateActionConstraintSettings(EditBone *dup_bone,
+ EditBone *orig_bone,
+ Object *ob,
+ bConstraint *curcon)
{
- updateDuplicateSubtargetObjects(dupBone, editbones, ob, ob);
+ bActionConstraint *act_con = (bActionConstraint *)curcon->data;
+ bAction *act = (bAction *)act_con->act;
+
+ float mat[4][4];
+
+ unit_m4(mat);
+ bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, act_con->subtarget);
+ BKE_constraint_mat_convertspace(
+ ob, target_pchan, mat, curcon->tarspace, CONSTRAINT_SPACE_LOCAL, false);
+
+ float max_axis_val = 0;
+ int max_axis = 0;
+ /* Which axis represents X now. IE, which axis defines the mirror plane. */
+ for (int i = 0; i < 3; i++) {
+ float cur_val = fabsf(mat[0][i]);
+ if (cur_val > max_axis_val) {
+ max_axis = i;
+ max_axis_val = cur_val;
+ }
+ }
+
+ /* data->type is mapped as follows for backwards compatibility:
+ * 00,01,02 - rotation (it used to be like this)
+ * 10,11,12 - scaling
+ * 20,21,22 - location
+ */
+ /* Mirror the target range */
+ if (act_con->type < 10 && act_con->type != max_axis) {
+ /* Y or Z rotation */
+ act_con->min = -act_con->min;
+ act_con->max = -act_con->max;
+ }
+ else if (act_con->type == max_axis + 10) {
+ /* X scaling */
+ }
+ else if (act_con->type == max_axis + 20) {
+ /* X location */
+ float imat[4][4];
+
+ invert_m4_m4(imat, mat);
+
+ float min_vec[3], max_vec[3];
+
+ zero_v3(min_vec);
+ zero_v3(max_vec);
+
+ min_vec[0] = act_con->min;
+ max_vec[0] = act_con->max;
+
+ /* convert values into local object space */
+ mul_m4_v3(mat, min_vec);
+ mul_m4_v3(mat, max_vec);
+
+ min_vec[0] *= -1;
+ max_vec[0] *= -1;
+
+ /* convert back to the settings space */
+ mul_m4_v3(imat, min_vec);
+ mul_m4_v3(imat, max_vec);
+
+ act_con->min = min_vec[0];
+ act_con->max = max_vec[0];
+ }
+
+ /* See if there is any channels that uses this bone */
+ ListBase ani_curves;
+ BLI_listbase_clear(&ani_curves);
+ if (BKE_fcurves_filter(&ani_curves, &act->curves, "pose.bones[", orig_bone->name)) {
+ /* Create a copy and mirror the animation */
+ for (LinkData *ld = ani_curves.first; ld; ld = ld->next) {
+ FCurve *old_curve = ld->data;
+ FCurve *new_curve = BKE_fcurve_copy(old_curve);
+ bActionGroup *agrp;
+
+ char *old_path = new_curve->rna_path;
+
+ new_curve->rna_path = BLI_str_replaceN(old_path, orig_bone->name, dup_bone->name);
+ MEM_freeN(old_path);
+
+ /* Flip the animation */
+ int i;
+ BezTriple *bezt;
+ for (i = 0, bezt = new_curve->bezt; i < new_curve->totvert; i++, bezt++) {
+ const size_t slength = strlen(new_curve->rna_path);
+ bool flip = false;
+ if (BLI_strn_endswith(new_curve->rna_path, "location", slength) &&
+ new_curve->array_index == 0) {
+ flip = true;
+ }
+ else if (BLI_strn_endswith(new_curve->rna_path, "rotation_quaternion", slength) &&
+ ELEM(new_curve->array_index, 2, 3)) {
+ flip = true;
+ }
+ else if (BLI_strn_endswith(new_curve->rna_path, "rotation_euler", slength) &&
+ ELEM(new_curve->array_index, 1, 2)) {
+ flip = true;
+ }
+ else if (BLI_strn_endswith(new_curve->rna_path, "rotation_axis_angle", slength) &&
+ ELEM(new_curve->array_index, 2, 3)) {
+ flip = true;
+ }
+
+ if (flip) {
+ bezt->vec[0][1] *= -1;
+ bezt->vec[1][1] *= -1;
+ bezt->vec[2][1] *= -1;
+ }
+ }
+
+ /* Make sure that a action group name for the new bone exists */
+ agrp = BKE_action_group_find_name(act, dup_bone->name);
+
+ if (agrp == NULL) {
+ agrp = action_groups_add_new(act, dup_bone->name);
+ }
+ BLI_assert(agrp != NULL);
+ action_groups_add_channel(act, agrp, new_curve);
+ }
+ }
+ BLI_freelistN(&ani_curves);
+
+ /* Make deps graph aware of our changes */
+ DEG_id_tag_update(&act->id, ID_RECALC_ANIMATION_NO_FLUSH);
}
-EditBone *duplicateEditBoneObjects(
- EditBone *curBone, const char *name, ListBase *editbones, Object *src_ob, Object *dst_ob)
+static void updateDuplicateKinematicConstraintSettings(bConstraint *curcon)
{
- EditBone *eBone = MEM_mallocN(sizeof(EditBone), "addup_editbone");
+ /* IK constraint */
+ bKinematicConstraint *ik = (bKinematicConstraint *)curcon->data;
+ ik->poleangle = -M_PI - ik->poleangle;
+ /* Wrap the angle to the +/-180.0f range (default soft limit of the input boxes). */
+ ik->poleangle = angle_wrap_rad(ik->poleangle);
+}
- /* Copy data from old bone to new bone */
- memcpy(eBone, curBone, sizeof(EditBone));
+static void updateDuplicateLocRotConstraintSettings(Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *curcon)
+{
+ /* This code assumes that bRotLimitConstraint and bLocLimitConstraint have the same fields in
+ * the same memory locations. */
+ BLI_assert(sizeof(bLocLimitConstraint) == sizeof(bRotLimitConstraint));
- curBone->temp.ebone = eBone;
- eBone->temp.ebone = curBone;
+ bRotLimitConstraint *limit = (bRotLimitConstraint *)curcon->data;
+ float local_mat[4][4], imat[4][4];
- if (name != NULL) {
- BLI_strncpy(eBone->name, name, sizeof(eBone->name));
+ float min_vec[3], max_vec[3];
+
+ min_vec[0] = limit->xmin;
+ min_vec[1] = limit->ymin;
+ min_vec[2] = limit->zmin;
+
+ max_vec[0] = limit->xmax;
+ max_vec[1] = limit->ymax;
+ max_vec[2] = limit->zmax;
+
+ unit_m4(local_mat);
+
+ BKE_constraint_mat_convertspace(
+ ob, pchan, local_mat, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false);
+
+ if (curcon->type == CONSTRAINT_TYPE_ROTLIMIT) {
+ /* Zero out any location translation */
+ local_mat[3][0] = local_mat[3][1] = local_mat[3][2] = 0;
+ }
+
+ invert_m4_m4(imat, local_mat);
+ /* convert values into local object space */
+ mul_m4_v3(local_mat, min_vec);
+ mul_m4_v3(local_mat, max_vec);
+
+ if (curcon->type == CONSTRAINT_TYPE_ROTLIMIT) {
+ float min_copy[3];
+
+ copy_v3_v3(min_copy, min_vec);
+
+ min_vec[1] = max_vec[1] * -1;
+ min_vec[2] = max_vec[2] * -1;
+
+ max_vec[1] = min_copy[1] * -1;
+ max_vec[2] = min_copy[2] * -1;
+ }
+ else {
+ float min_x_copy = min_vec[0];
+
+ min_vec[0] = max_vec[0] * -1;
+ max_vec[0] = min_x_copy * -1;
+ }
+
+ /* convert back to the settings space */
+ mul_m4_v3(imat, min_vec);
+ mul_m4_v3(imat, max_vec);
+
+ limit->xmin = min_vec[0];
+ limit->ymin = min_vec[1];
+ limit->zmin = min_vec[2];
+
+ limit->xmax = max_vec[0];
+ limit->ymax = max_vec[1];
+ limit->zmax = max_vec[2];
+}
+
+static void updateDuplicateTransformConstraintSettings(Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *curcon)
+{
+ bTransformConstraint *trans = (bTransformConstraint *)curcon->data;
+
+ float target_mat[4][4], own_mat[4][4], imat[4][4];
+
+ unit_m4(own_mat);
+ BKE_constraint_mat_convertspace(
+ ob, pchan, own_mat, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false);
+
+ /* ###Source map mirroring### */
+ float old_min, old_max;
+
+ /* Source location */
+ invert_m4_m4(imat, own_mat);
+
+ /* convert values into local object space */
+ mul_m4_v3(own_mat, trans->from_min);
+ mul_m4_v3(own_mat, trans->from_max);
+
+ old_min = trans->from_min[0];
+ old_max = trans->from_max[0];
+
+ trans->from_min[0] = -old_max;
+ trans->from_max[0] = -old_min;
+
+ /* convert back to the settings space */
+ mul_m4_v3(imat, trans->from_min);
+ mul_m4_v3(imat, trans->from_max);
+
+ /* Source rotation */
+
+ /* Zero out any location translation */
+ own_mat[3][0] = own_mat[3][1] = own_mat[3][2] = 0;
+
+ invert_m4_m4(imat, own_mat);
+
+ /* convert values into local object space */
+ mul_m4_v3(own_mat, trans->from_min_rot);
+ mul_m4_v3(own_mat, trans->from_max_rot);
+
+ old_min = trans->from_min_rot[1];
+ old_max = trans->from_max_rot[1];
+
+ trans->from_min_rot[1] = old_max * -1;
+ trans->from_max_rot[1] = old_min * -1;
+
+ old_min = trans->from_min_rot[2];
+ old_max = trans->from_max_rot[2];
+
+ trans->from_min_rot[2] = old_max * -1;
+ trans->from_max_rot[2] = old_min * -1;
+
+ /* convert back to the settings space */
+ mul_m4_v3(imat, trans->from_min_rot);
+ mul_m4_v3(imat, trans->from_max_rot);
+
+ /* Source scale does not require any mirroring */
+
+ /* ###Destination map mirroring### */
+ float temp_vec[3];
+ float imat_rot[4][4];
+
+ bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, trans->subtarget);
+ unit_m4(target_mat);
+ BKE_constraint_mat_convertspace(
+ ob, target_pchan, target_mat, curcon->tarspace, CONSTRAINT_SPACE_LOCAL, false);
+
+ invert_m4_m4(imat, target_mat);
+ /* convert values into local object space */
+ mul_m4_v3(target_mat, trans->to_min);
+ mul_m4_v3(target_mat, trans->to_max);
+ mul_m4_v3(target_mat, trans->to_min_scale);
+ mul_m4_v3(target_mat, trans->to_max_scale);
+
+ /* Zero out any location translation */
+ target_mat[3][0] = target_mat[3][1] = target_mat[3][2] = 0;
+ invert_m4_m4(imat_rot, target_mat);
+
+ mul_m4_v3(target_mat, trans->to_min_rot);
+ mul_m4_v3(target_mat, trans->to_max_rot);
+
+ /* TODO(sebpa): This does not support euler order, but doing so will make this way more complex.
+ * For now we have decided to not support all corner cases and advanced setups. */
+
+ /* Helper variables to denote the axis in trans->map */
+ const char X = 0;
+ const char Y = 1;
+ const char Z = 2;
+
+ switch (trans->to) {
+ case TRANS_SCALE:
+ copy_v3_v3(temp_vec, trans->to_max_scale);
+
+ for (int i = 0; i < 3; i++) {
+ if ((trans->from == TRANS_LOCATION && trans->map[i] == X) ||
+ (trans->from == TRANS_ROTATION && trans->map[i] != X)) {
+ /* X Loc to X/Y/Z Scale: Min/Max Flipped */
+ /* Y Rot to X/Y/Z Scale: Min/Max Flipped */
+ /* Z Rot to X/Y/Z Scale: Min/Max Flipped */
+ trans->to_max_scale[i] = trans->to_min_scale[i];
+ trans->to_min_scale[i] = temp_vec[i];
+ }
+ }
+ break;
+ case TRANS_LOCATION:
+ /* Invert the X location */
+ trans->to_min[0] *= -1;
+ trans->to_max[0] *= -1;
+
+ copy_v3_v3(temp_vec, trans->to_max);
+
+ for (int i = 0; i < 3; i++) {
+ if ((trans->from == TRANS_LOCATION && trans->map[i] == X) ||
+ (trans->from == TRANS_ROTATION && trans->map[i] != X)) {
+ /* X Loc to X/Y/Z Loc: Min/Max Flipped (and Inverted)
+ * Y Rot to X/Y/Z Loc: Min/Max Flipped
+ * Z Rot to X/Y/Z Loc: Min/Max Flipped */
+ trans->to_max[i] = trans->to_min[i];
+ trans->to_min[i] = temp_vec[i];
+ }
+ }
+ break;
+ case TRANS_ROTATION:
+ /* Invert the Z rotation */
+ trans->to_min_rot[2] *= -1;
+ trans->to_max_rot[2] *= -1;
+
+ if ((trans->from == TRANS_LOCATION && trans->map[1] != X) ||
+ (trans->from == TRANS_ROTATION && trans->map[1] != Y) || trans->from == TRANS_SCALE) {
+ /* Invert the Y rotation */
+ trans->to_min_rot[1] *= -1;
+ trans->to_max_rot[1] *= -1;
+ }
+
+ copy_v3_v3(temp_vec, trans->to_max_rot);
+
+ for (int i = 0; i < 3; i++) {
+ if ((trans->from == TRANS_LOCATION && trans->map[i] == X && i != 1) ||
+ (trans->from == TRANS_ROTATION && trans->map[i] == Y && i != 1) ||
+ (trans->from == TRANS_ROTATION && trans->map[i] == Z)) {
+ /* X Loc to X/Z Rot: Flipped
+ * Y Rot to X/Z Rot: Flipped
+ * Z Rot to X/Y/Z rot: Flipped */
+ trans->to_max_rot[i] = trans->to_min_rot[i];
+ trans->to_min_rot[i] = temp_vec[i];
+ }
+ }
+ break;
+ }
+ /* convert back to the settings space */
+ mul_m4_v3(imat, trans->to_min);
+ mul_m4_v3(imat, trans->to_max);
+ mul_m4_v3(imat_rot, trans->to_min_rot);
+ mul_m4_v3(imat_rot, trans->to_max_rot);
+ mul_m4_v3(imat, trans->to_min_scale);
+ mul_m4_v3(imat, trans->to_max_scale);
+}
+
+static void updateDuplicateConstraintSettings(EditBone *dup_bone, EditBone *orig_bone, Object *ob)
+{
+ /* If an edit bone has been duplicated, lets update it's constraints if the
+ * subtarget they point to has also been duplicated.
+ */
+ bPoseChannel *pchan;
+ bConstraint *curcon;
+ ListBase *conlist;
+
+ if ((pchan = BKE_pose_channel_verify(ob->pose, dup_bone->name)) == NULL ||
+ (conlist = &pchan->constraints) == NULL) {
+ return;
}
- ED_armature_ebone_unique_name(editbones, eBone->name, NULL);
- BLI_addtail(editbones, eBone);
+ for (curcon = conlist->first; curcon; curcon = curcon->next) {
+ switch (curcon->type) {
+ case CONSTRAINT_TYPE_ACTION:
+ updateDuplicateActionConstraintSettings(dup_bone, orig_bone, ob, curcon);
+ break;
+ case CONSTRAINT_TYPE_KINEMATIC:
+ updateDuplicateKinematicConstraintSettings(curcon);
+ break;
+ case CONSTRAINT_TYPE_LOCLIMIT:
+ case CONSTRAINT_TYPE_ROTLIMIT:
+ updateDuplicateLocRotConstraintSettings(ob, pchan, curcon);
+ break;
+ case CONSTRAINT_TYPE_TRANSFORM:
+ updateDuplicateTransformConstraintSettings(ob, pchan, curcon);
+ break;
+ }
+ }
+}
+static void updateDuplicateCustomBoneShapes(bContext *C, EditBone *dup_bone, Object *ob)
+{
+ if (ob->pose == NULL) {
+ return;
+ }
+ bPoseChannel *pchan;
+ pchan = BKE_pose_channel_verify(ob->pose, dup_bone->name);
+
+ if (pchan->custom != NULL) {
+ Main *bmain = CTX_data_main(C);
+ char name_flip[MAX_ID_NAME - 2];
+
+ /* Skip the first two chars in the object name as those are used to store object type */
+ BLI_string_flip_side_name(name_flip, pchan->custom->id.name + 2, false, sizeof(name_flip));
+ Object *shape_ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, name_flip);
+
+ if (shape_ob != NULL) {
+ /* A flipped shape object exists, use it! */
+ pchan->custom = shape_ob;
+ }
+ }
+}
+
+static void copy_pchan(EditBone *src_bone, EditBone *dst_bone, Object *src_ob, Object *dst_ob)
+{
/* copy the ID property */
- if (curBone->prop) {
- eBone->prop = IDP_CopyProperty(curBone->prop);
+ if (src_bone->prop) {
+ dst_bone->prop = IDP_CopyProperty(src_bone->prop);
}
/* Lets duplicate the list of constraints that the
@@ -466,25 +880,46 @@ EditBone *duplicateEditBoneObjects(
if (src_ob->pose) {
bPoseChannel *chanold, *channew;
- chanold = BKE_pose_channel_verify(src_ob->pose, curBone->name);
+ chanold = BKE_pose_channel_verify(src_ob->pose, src_bone->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);
+ channew = BKE_pose_channel_verify(dst_ob->pose, dst_bone->name);
if (channew) {
BKE_pose_channel_copy_data(channew, chanold);
}
}
}
+}
+
+EditBone *duplicateEditBoneObjects(
+ EditBone *cur_bone, const char *name, ListBase *editbones, Object *src_ob, Object *dst_ob)
+{
+ EditBone *e_bone = MEM_mallocN(sizeof(EditBone), "addup_editbone");
+
+ /* Copy data from old bone to new bone */
+ memcpy(e_bone, cur_bone, sizeof(EditBone));
+
+ cur_bone->temp.ebone = e_bone;
+ e_bone->temp.ebone = cur_bone;
+
+ if (name != NULL) {
+ BLI_strncpy(e_bone->name, name, sizeof(e_bone->name));
+ }
- return eBone;
+ ED_armature_ebone_unique_name(editbones, e_bone->name, NULL);
+ BLI_addtail(editbones, e_bone);
+
+ copy_pchan(cur_bone, e_bone, src_ob, dst_ob);
+
+ return e_bone;
}
-EditBone *duplicateEditBone(EditBone *curBone, const char *name, ListBase *editbones, Object *ob)
+EditBone *duplicateEditBone(EditBone *cur_bone, const char *name, ListBase *editbones, Object *ob)
{
- return duplicateEditBoneObjects(curBone, name, editbones, ob, ob);
+ return duplicateEditBoneObjects(cur_bone, name, editbones, ob, ob);
}
static int armature_duplicate_selected_exec(bContext *C, wmOperator *op)
@@ -538,8 +973,8 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op)
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. */
+ /* 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;
}
@@ -567,13 +1002,13 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op)
}
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
+ * Set the duplicate->parent to the cur_bone->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
+ * Set the duplicate->parent to the cur_bone->parent
*/
ebone->parent = (EditBone *)ebone_iter->parent;
ebone->flag &= ~BONE_CONNECTED;
@@ -590,7 +1025,7 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op)
/* Lets try to fix any constraint subtargets that might
* have been duplicated
*/
- updateDuplicateSubtarget(ebone, arm->edbo, ob);
+ updateDuplicateSubtarget(ebone, arm->edbo, ob, false);
}
}
@@ -616,6 +1051,8 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op)
}
MEM_freeN(objects);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
+
return OPERATOR_FINISHED;
}
@@ -742,12 +1179,24 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
}
}
- /* Find the selected bones and duplicate them as needed, with mirrored name */
+ /* 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)) {
+ if (EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED)) {
+ if (ebone_iter->temp.ebone != NULL) {
+ /* This will be set if the mirror bone already exists (no need to make a new one)
+ * but we do need to make sure that the 'pchan' settings (constraints etc)
+ * is synchronized. */
+ bPoseChannel *pchan;
+ /* Make sure we clean up the old data before overwriting it */
+ pchan = BKE_pose_channel_verify(obedit->pose, ebone_iter->temp.ebone->name);
+ BKE_pose_channel_free(pchan);
+ /* Sync pchan data */
+ copy_pchan(ebone_iter, ebone_iter->temp.ebone, obedit, obedit);
+ /* Sync scale mode */
+ ebone_iter->temp.ebone->inherit_scale_mode = ebone_iter->inherit_scale_mode;
+ continue;
+ }
char name_flip[MAXBONENAME];
BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip));
@@ -765,7 +1214,7 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
}
}
- /* Run through the list and fix the pointers */
+ /* 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) {
@@ -793,7 +1242,12 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
* 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;
+
+ if (ebone->head[axis] != 0.0f) {
+ /* The mirrored bone doesn't start on the mirror axis, so assume that this one should
+ * not be connected to the old parent */
+ ebone->flag &= ~BONE_CONNECTED;
+ }
}
ebone->parent = ebone_parent;
@@ -803,10 +1257,19 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
ebone->bbone_prev = get_symmetrized_bone(arm, ebone_iter->bbone_prev);
ebone->bbone_next = get_symmetrized_bone(arm, ebone_iter->bbone_next);
+ /* Sync bbone handle types */
+ ebone->bbone_prev_type = ebone_iter->bbone_prev_type;
+ ebone->bbone_next_type = ebone_iter->bbone_next_type;
+
/* Lets try to fix any constraint subtargets that might
* have been duplicated
*/
- updateDuplicateSubtarget(ebone, arm->edbo, obedit);
+ updateDuplicateSubtarget(ebone, arm->edbo, obedit, true);
+ /* Try to update constraint options so that they are mirrored as well
+ * (need to supply bone_iter as well in case we are working with existing bones) */
+ updateDuplicateConstraintSettings(ebone, ebone_iter, obedit);
+ /* Mirror bone shapes if possible */
+ updateDuplicateCustomBoneShapes(C, ebone, obedit);
}
}
@@ -1062,7 +1525,13 @@ static int armature_extrude_exec(bContext *C, wmOperator *op)
}
MEM_freeN(objects);
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ if (!changed_multi) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ED_outliner_select_sync_from_edit_bone_tag(C);
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_extrude(wmOperatorType *ot)
@@ -1116,7 +1585,7 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op)
ED_armature_edit_deselect_all(obedit);
- /* Create a bone */
+ /* Create a bone. */
bone = ED_armature_ebone_add(obedit->data, name);
copy_v3_v3(bone->head, curs);
@@ -1133,6 +1602,7 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op)
/* note, notifier might evolve */
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
return OPERATOR_FINISHED;
}
@@ -1223,6 +1693,7 @@ static int armature_subdivide_exec(bContext *C, wmOperator *op)
/* note, notifier might evolve */
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
return OPERATOR_FINISHED;
}
@@ -1232,7 +1703,7 @@ void ARMATURE_OT_subdivide(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Subdivide Multi";
+ ot->name = "Subdivide";
ot->idname = "ARMATURE_OT_subdivide";
ot->description = "Break selected bones into chains of smaller bones";
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index b8378c95a60..a7a705a6202 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -54,6 +54,7 @@
#include "WM_types.h"
#include "ED_armature.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -499,7 +500,7 @@ static int armature_roll_clear_exec(bContext *C, wmOperator *op)
bArmature *arm = ob->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
/* Roll func is a callback which assumes that all is well. */
ebone->roll = roll;
@@ -508,7 +509,7 @@ static int armature_roll_clear_exec(bContext *C, wmOperator *op)
}
if (arm->flag & ARM_MIRROR_EDIT) {
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
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))) {
@@ -889,213 +890,6 @@ void ARMATURE_OT_fill(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Merge Operator
- * \{ */
-
-/* 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)
-{
- 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_CYCLICOFFSET |
- BONE_NO_LOCAL_LOCATION | BONE_DONE);
-
- newbone->inherit_scale_mode = start->inherit_scale_mode;
-
- /* 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);
- ED_armature_edit_refresh_layer_used(arm);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
- DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
- }
- 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", "");
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Switch Direction Operator
*
* Currently, this does not use context loops, as context loops do not make it
@@ -1396,13 +1190,13 @@ static int armature_split_exec(bContext *C, wmOperator *UNUSED(op))
Object *ob = objects[ob_index];
bArmature *arm = ob->data;
- for (EditBone *bone = arm->edbo->first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (EditBone *, bone, arm->edbo) {
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) {
+ LISTBASE_FOREACH (EditBone *, bone, arm->edbo) {
ED_armature_ebone_select_set(bone, (bone->flag & BONE_SELECTED) != 0);
}
@@ -1490,6 +1284,7 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
}
}
MEM_freeN(objects);
@@ -1665,6 +1460,7 @@ static int armature_dissolve_selected_exec(bContext *C, wmOperator *UNUSED(op))
ED_armature_edit_refresh_layer_used(arm);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
}
}
MEM_freeN(objects);
@@ -1715,7 +1511,7 @@ static int armature_hide_exec(bContext *C, wmOperator *op)
bArmature *arm = obedit->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_VISIBLE(arm, ebone)) {
if ((ebone->flag & BONE_SELECTED) != invert) {
ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
@@ -1774,7 +1570,7 @@ static int armature_reveal_exec(bContext *C, wmOperator *op)
bArmature *arm = obedit->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (arm->layer & ebone->layer) {
if (ebone->flag & BONE_HIDDEN_A) {
if (!(ebone->flag & BONE_UNSELECTABLE)) {
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index fa562ab0f44..08d82bf13c9 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -59,6 +59,7 @@ void ARMATURE_OT_select_mirror(struct wmOperatorType *ot);
void ARMATURE_OT_select_more(struct wmOperatorType *ot);
void ARMATURE_OT_select_less(struct wmOperatorType *ot);
void ARMATURE_OT_select_hierarchy(struct wmOperatorType *ot);
+void ARMATURE_OT_select_linked_pick(struct wmOperatorType *ot);
void ARMATURE_OT_select_linked(struct wmOperatorType *ot);
void ARMATURE_OT_select_similar(struct wmOperatorType *ot);
void ARMATURE_OT_shortest_path_pick(struct wmOperatorType *ot);
@@ -72,7 +73,6 @@ void ARMATURE_OT_hide(struct wmOperatorType *ot);
void ARMATURE_OT_reveal(struct wmOperatorType *ot);
void ARMATURE_OT_click_extrude(struct wmOperatorType *ot);
void ARMATURE_OT_fill(struct wmOperatorType *ot);
-void ARMATURE_OT_merge(struct wmOperatorType *ot);
void ARMATURE_OT_separate(struct wmOperatorType *ot);
void ARMATURE_OT_split(struct wmOperatorType *ot);
@@ -104,6 +104,7 @@ void POSE_OT_select_all(struct wmOperatorType *ot);
void POSE_OT_select_parent(struct wmOperatorType *ot);
void POSE_OT_select_hierarchy(struct wmOperatorType *ot);
void POSE_OT_select_linked(struct wmOperatorType *ot);
+void POSE_OT_select_linked_pick(struct wmOperatorType *ot);
void POSE_OT_select_constraint_target(struct wmOperatorType *ot);
void POSE_OT_select_grouped(struct wmOperatorType *ot);
void POSE_OT_select_mirror(struct wmOperatorType *ot);
@@ -232,9 +233,6 @@ 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 */
@@ -244,12 +242,6 @@ struct EditBone *duplicateEditBoneObjects(struct EditBone *curBone,
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);
-
EditBone *add_points_bone(struct Object *obedit, float head[3], float tail[3]);
void bone_free(struct bArmature *arm, struct EditBone *bone);
@@ -258,16 +250,40 @@ 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_bone_from_selectbuffer(struct Base **bases,
- uint bases_len,
- bool is_editmode,
- const unsigned int *buffer,
- short hits,
+EditBone *ED_armature_pick_ebone(struct bContext *C,
+ const int xy[2],
bool findunsel,
- bool do_nearest,
struct Base **r_base);
+struct bPoseChannel *ED_armature_pick_pchan(struct bContext *C,
+ const int xy[2],
+ bool findunsel,
+ struct Base **r_base);
+struct Bone *ED_armature_pick_bone(struct bContext *C,
+ const int xy[2],
+ bool findunsel,
+ struct Base **r_base);
+
+struct EditBone *ED_armature_pick_ebone_from_selectbuffer(struct Base **bases,
+ uint bases_len,
+ const uint *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ struct Base **r_base);
+struct bPoseChannel *ED_armature_pick_pchan_from_selectbuffer(struct Base **bases,
+ uint bases_len,
+ const uint *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ struct Base **r_base);
+struct Bone *ED_armature_pick_bone_from_selectbuffer(struct Base **bases,
+ uint bases_len,
+ const uint *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ struct Base **r_base);
int bone_looper(struct Object *ob,
struct Bone *bone,
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index 13660244547..544d86d4c47 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -20,6 +20,8 @@
/** \file
* \ingroup edarmature
+ *
+ * This file contains functions/API's for renaming bones and/or working with them.
*/
#include <string.h>
@@ -63,12 +65,11 @@
#include "armature_intern.h"
-/* This file contains functions/API's for renaming bones and/or working with them */
-
-/* ************************************************** */
-/* EditBone Names */
+/* -------------------------------------------------------------------- */
+/** \name Unique Bone Name Utility (Edit Mode)
+ * \{ */
-/* note: there's a unique_bone_name() too! */
+/* note: there's a ed_armature_bone_unique_name() too! */
static bool editbone_unique_check(void *arg, const char *name)
{
struct {
@@ -92,20 +93,29 @@ void ED_armature_ebone_unique_name(ListBase *edbo, char *name, EditBone *bone)
BLI_uniquename_cb(editbone_unique_check, &data, DATA_("Bone"), '.', name, sizeof(bone->name));
}
-/* ************************************************** */
-/* Bone Renaming - API */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Unique Bone Name Utility (Object Mode)
+ * \{ */
static bool bone_unique_check(void *arg, const char *name)
{
return BKE_armature_find_bone_name((bArmature *)arg, name) != NULL;
}
-static void unique_bone_name(bArmature *arm, char *name)
+static void ed_armature_bone_unique_name(bArmature *arm, char *name)
{
BLI_uniquename_cb(
bone_unique_check, (void *)arm, DATA_("Bone"), '.', name, sizeof(((Bone *)NULL)->name));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Bone Renaming (Object & Edit Mode API)
+ * \{ */
+
/* helper call for armature_bone_rename */
static void constraint_bone_name_fix(Object *ob,
ListBase *conlist,
@@ -180,7 +190,7 @@ void ED_armature_bone_rename(Main *bmain,
Bone *bone = BKE_armature_find_bone_name(arm, oldname);
if (bone) {
- unique_bone_name(arm, newname);
+ ed_armature_bone_unique_name(arm, newname);
if (arm->bonehash) {
BLI_assert(BLI_ghash_haskey(arm->bonehash, bone->name));
@@ -255,7 +265,7 @@ void ED_armature_bone_rename(Main *bmain,
}
}
- if (modifiers_usesArmature(ob, arm)) {
+ if (BKE_modifiers_uses_armature(ob, arm)) {
bDeformGroup *dg = BKE_object_defgroup_find_name(ob, oldname);
if (dg) {
BLI_strncpy(dg->name, newname, MAXBONENAME);
@@ -307,8 +317,7 @@ void ED_armature_bone_rename(Main *bmain,
}
}
- for (GpencilModifierData *gp_md = ob->greasepencil_modifiers.first; gp_md;
- gp_md = gp_md->next) {
+ LISTBASE_FOREACH (GpencilModifierData *, gp_md, &ob->greasepencil_modifiers) {
switch (gp_md->type) {
case eGpencilModifierType_Armature: {
ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)gp_md;
@@ -352,11 +361,11 @@ void ED_armature_bone_rename(Main *bmain,
{
bScreen *screen;
for (screen = bmain->screens.first; screen; screen = screen->id.next) {
- ScrArea *sa;
+ ScrArea *area;
/* add regions */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
if (v3d->ob_center && v3d->ob_center->data == arm) {
@@ -372,6 +381,12 @@ void ED_armature_bone_rename(Main *bmain,
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Bone Flipping (Object & Edit Mode API)
+ * \{ */
+
typedef struct BoneFlipNameData {
struct BoneFlipNameData *next, *prev;
char *name;
@@ -399,7 +414,7 @@ void ED_armature_bones_flip_names(Main *bmain,
/* 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) {
+ LISTBASE_FOREACH (LinkData *, link, bones_names) {
char name_flip[MAXBONENAME];
char *name = link->data;
@@ -426,8 +441,11 @@ void ED_armature_bones_flip_names(Main *bmain,
}
}
-/* ************************************************** */
-/* Bone Renaming - EditMode */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Flip Bone Names (Edit Mode Operator)
+ * \{ */
static int armature_flip_names_exec(bContext *C, wmOperator *op)
{
@@ -451,7 +469,7 @@ static int armature_flip_names_exec(bContext *C, wmOperator *op)
ListBase bones_names = {NULL};
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_VISIBLE(arm, ebone)) {
if (ebone->flag & BONE_SELECTED) {
BLI_addtail(&bones_names, BLI_genericNodeN(ebone->name));
@@ -511,6 +529,12 @@ void ARMATURE_OT_flip_names(wmOperatorType *ot)
"(WARNING: may result in incoherent naming in some cases)");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Bone Auto Side Names (Edit Mode Operator)
+ * \{ */
+
static int armature_autoside_names_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -532,7 +556,7 @@ static int armature_autoside_names_exec(bContext *C, wmOperator *op)
continue;
}
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_EDITABLE(ebone)) {
/* We first need to do the flipped bone, then the original one.
@@ -599,3 +623,5 @@ void ARMATURE_OT_autoside_names(wmOperatorType *ot)
/* 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 a29d0f5f158..da1b29307b1 100644
--- a/source/blender/editors/armature/armature_ops.c
+++ b/source/blender/editors/armature/armature_ops.c
@@ -56,6 +56,7 @@ void ED_operatortypes_armature(void)
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_linked_pick);
WM_operatortype_append(ARMATURE_OT_select_similar);
WM_operatortype_append(ARMATURE_OT_shortest_path_pick);
@@ -68,7 +69,6 @@ void ED_operatortypes_armature(void)
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);
@@ -100,6 +100,7 @@ void ED_operatortypes_armature(void)
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_linked_pick);
WM_operatortype_append(POSE_OT_select_constraint_target);
WM_operatortype_append(POSE_OT_select_grouped);
WM_operatortype_append(POSE_OT_select_mirror);
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index 2c2bf3cd283..d3d00fc44f2 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -37,11 +37,12 @@
#include "BLT_translation.h"
#include "BKE_action.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_report.h"
@@ -57,6 +58,7 @@
#include "ED_armature.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "UI_interface.h"
@@ -280,7 +282,7 @@ int join_armature_exec(bContext *C, wmOperator *op)
float mat[4][4], oimat[4][4];
bool ok = false;
- /* Ensure we're not in editmode and that the active object is an armature*/
+ /* Ensure we're not in edit-mode and that the active object is an armature. */
if (!ob_active || ob_active->type != OB_ARMATURE) {
return OPERATOR_CANCELLED;
}
@@ -430,7 +432,6 @@ int join_armature_exec(bContext *C, wmOperator *op)
ED_armature_from_edit(bmain, arm);
ED_armature_edit_free(arm);
- BKE_armature_refresh_layer_used(arm);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
@@ -568,7 +569,7 @@ static void separate_armature_bones(Main *bmain, Object *ob, const bool is_selec
if (is_select == (EBONE_VISIBLE(arm, curbone) && (curbone->flag & BONE_SELECTED))) {
/* clear the bone->parent var of any bone that had this as its parent */
- for (EditBone *ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) {
if (ebo->parent == curbone) {
ebo->parent = NULL;
/* this is needed to prevent random crashes with in ED_armature_from_edit */
@@ -578,7 +579,7 @@ static void separate_armature_bones(Main *bmain, Object *ob, const bool is_selec
}
/* clear the pchan->parent var of any pchan that had this as its parent */
- for (bPoseChannel *pchn = ob->pose->chanbase.first; pchn; pchn = pchn->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchn, &ob->pose->chanbase) {
if (pchn->parent == pchan) {
pchn->parent = NULL;
}
@@ -629,7 +630,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
bArmature *arm_old = ob_old->data;
bool has_selected_bone = false;
bool has_selected_any = false;
- for (EditBone *ebone = arm_old->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm_old->edbo) {
if (EBONE_VISIBLE(arm_old, ebone)) {
if (ebone->flag & BONE_SELECTED) {
has_selected_bone = true;
@@ -687,9 +688,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
/* 5) restore original conditions */
ED_armature_to_edit(ob_old->data);
-
ED_armature_edit_refresh_layer_used(ob_old->data);
- BKE_armature_refresh_layer_used(ob_new->data);
/* parents tips remain selected when connected children are removed. */
ED_armature_edit_deselect_all(ob_old);
@@ -706,6 +705,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
if (ok) {
BKE_report(op->reports, RPT_INFO, "Separated bones");
+ ED_outliner_select_sync_from_object_tag(C);
}
return OPERATOR_FINISHED;
@@ -835,7 +835,7 @@ static int armature_parent_set_exec(bContext *C, wmOperator *op)
bool is_active_only_selected = false;
if (actbone->flag & BONE_SELECTED) {
is_active_only_selected = true;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_EDITABLE(ebone) && (ebone->flag & BONE_SELECTED)) {
if (ebone != actbone) {
is_active_only_selected = false;
@@ -867,7 +867,7 @@ static int armature_parent_set_exec(bContext *C, wmOperator *op)
*/
/* Parent selected bones to the active one. */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_EDITABLE(ebone) && (ebone->flag & BONE_SELECTED)) {
if (ebone != actbone) {
bone_connect_to_new_parent(arm->edbo, ebone, actbone, val);
@@ -901,7 +901,7 @@ static int armature_parent_set_invoke(bContext *C,
Object *ob = CTX_data_edit_object(C);
bArmature *arm = ob->data;
EditBone *actbone = arm->act_edbone;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_EDITABLE(ebone) && (ebone->flag & BONE_SELECTED)) {
if (ebone != actbone) {
if (ebone->parent != actbone) {
@@ -983,7 +983,7 @@ static int armature_parent_clear_exec(bContext *C, wmOperator *op)
bArmature *arm = ob->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_EDITABLE(ebone)) {
changed = true;
break;
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index 21eccd2ca1f..4b8bbe39a16 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -30,6 +30,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_rect.h"
#include "BLI_string_utils.h"
#include "BKE_action.h"
@@ -59,7 +60,9 @@
#define EBONE_PREV_FLAG_GET(ebone) ((void)0, (ebone)->temp.i)
#define EBONE_PREV_FLAG_SET(ebone, val) ((ebone)->temp.i = val)
-/* **************** PoseMode & EditMode Selection Buffer Queries *************************** */
+/* -------------------------------------------------------------------- */
+/** \name Select Buffer Queries for PoseMode & EditMode
+ * \{ */
Base *ED_armature_base_and_ebone_from_select_buffer(Base **bases,
uint bases_len,
@@ -109,14 +112,14 @@ Object *ED_armature_object_and_ebone_from_select_buffer(Object **objects,
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_pchan_from_select_buffer(Base **bases,
+ uint bases_len,
+ int hit,
+ bPoseChannel **r_pchan)
{
const uint hit_object = hit & 0xFFFF;
Base *base = NULL;
- Bone *bone = NULL;
+ bPoseChannel *pchan = NULL;
/* TODO(campbell): optimize, eg: sort & binary search. */
for (uint base_index = 0; base_index < bases_len; base_index++) {
if (bases[base_index]->object->runtime.select_id == hit_object) {
@@ -127,30 +130,53 @@ Base *ED_armature_base_and_bone_from_select_buffer(Base **bases,
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;
+ /* pchan may be NULL. */
+ pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone);
}
}
- *r_bone = bone;
+ *r_pchan = pchan;
+ return base;
+}
+
+/* For callers that don't need the pose channel. */
+Base *ED_armature_base_and_bone_from_select_buffer(Base **bases,
+ uint bases_len,
+ int hit,
+ Bone **r_bone)
+{
+ bPoseChannel *pchan = NULL;
+ Base *base = ED_armature_base_and_pchan_from_select_buffer(bases, bases_len, hit, &pchan);
+ *r_bone = pchan ? pchan->bone : NULL;
return base;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Cursor Pick from Select Buffer API
+ *
+ * Internal #ed_armature_pick_bone_from_selectbuffer_impl is exposed as:
+ * - #ED_armature_pick_ebone_from_selectbuffer
+ * - #ED_armature_pick_pchan_from_selectbuffer
+ * - #ED_armature_pick_bone_from_selectbuffer
+ * \{ */
+
/* 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)
+static void *ed_armature_pick_bone_from_selectbuffer_impl(const bool is_editmode,
+ Base **bases,
+ uint bases_len,
+ const uint *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ Base **r_base)
{
- Bone *bone;
+ bPoseChannel *pchan;
EditBone *ebone;
void *firstunSel = NULL, *firstSel = NULL, *data;
Base *firstunSel_base = NULL, *firstSel_base = NULL;
- unsigned int hitresult;
+ uint hitresult;
short i;
bool takeNext = false;
int minsel = 0xffffffff, minunsel = 0xffffffff;
@@ -158,77 +184,74 @@ void *get_bone_from_selectbuffer(Base **bases,
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;
+ 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;
+ hitresult &= ~(BONESEL_ANY);
+ /* Determine what the current bone is */
+ if (is_editmode == false) {
+ base = ED_armature_base_and_pchan_from_select_buffer(bases, bases_len, hitresult, &pchan);
+ if (pchan != NULL) {
+ if (findunsel) {
+ sel = (pchan->bone->flag & BONE_SELECTED);
}
else {
- data = NULL;
- sel = 0;
+ sel = !(pchan->bone->flag & BONE_SELECTED);
}
+
+ data = pchan;
}
else {
- base = ED_armature_base_and_ebone_from_select_buffer(
- bases, bases_len, hitresult, &ebone);
- if (findunsel) {
- sel = (ebone->flag & BONE_SELECTED);
+ 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 {
- sel = !(ebone->flag & BONE_SELECTED);
+ if (!firstSel) {
+ firstSel = data;
+ firstSel_base = base;
+ }
+ takeNext = 1;
}
-
- 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 (do_nearest) {
- if (minunsel > buffer[4 * i + 1]) {
- firstunSel = data;
- firstunSel_base = base;
- minunsel = buffer[4 * i + 1];
- }
+ if (!firstunSel) {
+ firstunSel = data;
+ firstunSel_base = base;
}
- else {
- if (!firstunSel) {
- firstunSel = data;
- firstunSel_base = base;
- }
- if (takeNext) {
- *r_base = base;
- return data;
- }
+ if (takeNext) {
+ *r_base = base;
+ return data;
}
}
}
@@ -246,22 +269,74 @@ void *get_bone_from_selectbuffer(Base **bases,
}
}
-/* 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)
+EditBone *ED_armature_pick_ebone_from_selectbuffer(Base **bases,
+ uint bases_len,
+ const uint *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ Base **r_base)
+{
+ const bool is_editmode = true;
+ return ed_armature_pick_bone_from_selectbuffer_impl(
+ is_editmode, bases, bases_len, buffer, hits, findunsel, do_nearest, r_base);
+}
+
+bPoseChannel *ED_armature_pick_pchan_from_selectbuffer(Base **bases,
+ uint bases_len,
+ const uint *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ Base **r_base)
+{
+ const bool is_editmode = false;
+ return ed_armature_pick_bone_from_selectbuffer_impl(
+ is_editmode, bases, bases_len, buffer, hits, findunsel, do_nearest, r_base);
+}
+
+Bone *ED_armature_pick_bone_from_selectbuffer(Base **bases,
+ uint bases_len,
+ const uint *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ Base **r_base)
+{
+ bPoseChannel *pchan = ED_armature_pick_pchan_from_selectbuffer(
+ bases, bases_len, buffer, hits, findunsel, do_nearest, r_base);
+ return pchan ? pchan->bone : NULL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Cursor Pick API
+ *
+ * Internal #ed_armature_pick_bone_impl is exposed as:
+ * - #ED_armature_pick_ebone
+ * - #ED_armature_pick_pchan
+ * - #ED_armature_pick_bone
+ * \{ */
+
+/**
+ * \param xy: Cursor coordinates (area space).
+ * \return An #EditBone when is_editmode, otherwise a #bPoseChannel.
+ * \note Only checks objects in the current mode (edit-mode or pose-mode).
+ */
+static void *ed_armature_pick_bone_impl(
+ const bool is_editmode, bContext *C, const int xy[2], bool findunsel, Base **r_base)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
rcti rect;
- unsigned int buffer[MAXPICKBUF];
+ uint buffer[MAXPICKBUF];
short hits;
ED_view3d_viewcontext_init(C, &vc, depsgraph);
+ BLI_assert((vc.obedit != NULL) == is_editmode);
- // rect.xmin = ... mouseco!
- rect.xmin = rect.xmax = xy[0];
- rect.ymin = rect.ymax = xy[1];
+ BLI_rcti_init_pt_radius(&rect, xy, 0);
hits = view3d_opengl_select(
&vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST, VIEW3D_SELECT_FILTER_NOP);
@@ -284,123 +359,287 @@ void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel, Base **r_ba
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);
+ void *bone = ed_armature_pick_bone_from_selectbuffer_impl(
+ is_editmode, bases, bases_len, buffer, hits, findunsel, true, r_base);
MEM_freeN(bases);
+
return bone;
}
return NULL;
}
-/* **************** EditMode stuff ********************** */
+EditBone *ED_armature_pick_ebone(bContext *C, const int xy[2], bool findunsel, Base **r_base)
+{
+ const bool is_editmode = true;
+ return ed_armature_pick_bone_impl(is_editmode, C, xy, findunsel, r_base);
+}
-static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+bPoseChannel *ED_armature_pick_pchan(bContext *C, const int xy[2], bool findunsel, Base **r_base)
{
- bArmature *arm;
- EditBone *bone, *curBone, *next;
- const bool sel = !RNA_boolean_get(op->ptr, "deselect");
+ const bool is_editmode = false;
+ return ed_armature_pick_bone_impl(is_editmode, C, xy, findunsel, r_base);
+}
- view3d_operator_needs_opengl(C);
- BKE_object_update_select_id(CTX_data_main(C));
+Bone *ED_armature_pick_bone(bContext *C, const int xy[2], bool findunsel, Base **r_base)
+{
+ bPoseChannel *pchan = ED_armature_pick_pchan(C, xy, findunsel, r_base);
+ return pchan ? pchan->bone : NULL;
+}
- Base *base = NULL;
- bone = get_nearest_bone(C, event->mval, true, &base);
+/** \} */
- if (!bone) {
- return OPERATOR_CANCELLED;
+/* -------------------------------------------------------------------- */
+/** \name Select Linked Implementation
+ *
+ * Shared logic for select linked all/pick.
+ *
+ * Use #BONE_DONE flag to select linked.
+ * \{ */
+
+/**
+ * \param all_forks: Control how chains are stepped over.
+ * true: select all connected bones traveling up & down forks.
+ * false: select all parents and all children, but not the children of the root bone.
+ */
+static bool armature_select_linked_impl(Object *ob, const bool select, const bool all_forks)
+{
+ bool changed = false;
+ bArmature *arm = ob->data;
+
+ /* Implementation note, this flood-fills selected bones with the 'TOUCH' flag,
+ * even though this is a loop-within a loop, walking up the parent chain only touches new bones.
+ * Bones that have been touched are skipped, so the complexity is OK. */
+
+ enum {
+ /* Bone has been walked over, it's LINK value can be read. */
+ TOUCH = (1 << 0),
+ /* When TOUCH has been set, this flag can be checked to see if the bone is connected. */
+ LINK = (1 << 1),
+ };
+
+#define CHECK_PARENT(ebone) \
+ (((ebone)->flag & BONE_CONNECTED) && \
+ ((ebone)->parent ? EBONE_SELECTABLE(arm, (ebone)->parent) : false))
+
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
+ ebone->temp.i = 0;
}
- arm = base->object->data;
+ /* Select parents. */
+ LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
+ if (ebone_iter->temp.i & TOUCH) {
+ continue;
+ }
+ if ((ebone_iter->flag & BONE_DONE) == 0) {
+ continue;
+ }
+
+ ebone_iter->temp.i |= TOUCH | LINK;
- /* Select parents */
- for (curBone = bone; curBone; curBone = next) {
- if ((curBone->flag & BONE_UNSELECTABLE) == 0) {
- if (sel) {
- curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ /* We have an un-touched link. */
+ for (EditBone *ebone = ebone_iter; ebone; ebone = CHECK_PARENT(ebone) ? ebone->parent : NULL) {
+ ED_armature_ebone_select_set(ebone, select);
+ changed = true;
+
+ if (all_forks) {
+ ebone->temp.i |= (TOUCH | LINK);
}
else {
- curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ ebone->temp.i |= TOUCH;
+ }
+ /* Don't walk onto links (messes up 'all_forks' logic). */
+ if (ebone->parent && ebone->parent->temp.i & LINK) {
+ break;
}
}
+ }
- if (curBone->flag & BONE_CONNECTED) {
- next = curBone->parent;
+ /* Select children. */
+ LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
+ /* No need to 'touch' this bone as it won't be walked over when scanning up the chain. */
+ if (!CHECK_PARENT(ebone_iter)) {
+ continue;
}
- else {
- next = NULL;
+ if (ebone_iter->temp.i & TOUCH) {
+ continue;
}
- }
- /* 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;
+ /* First check if we're marked. */
+ EditBone *ebone_touched_parent = NULL;
+ for (EditBone *ebone = ebone_iter; ebone; ebone = CHECK_PARENT(ebone) ? ebone->parent : NULL) {
+ if (ebone->temp.i & TOUCH) {
+ ebone_touched_parent = ebone;
+ break;
+ }
+ ebone->temp.i |= TOUCH;
+ }
+
+ if ((ebone_touched_parent != NULL) && (ebone_touched_parent->temp.i & LINK)) {
+ for (EditBone *ebone = ebone_iter; ebone != ebone_touched_parent; ebone = ebone->parent) {
+ if ((ebone->temp.i & LINK) == 0) {
+ ebone->temp.i |= LINK;
+ ED_armature_ebone_select_set(ebone, select);
+ changed = true;
}
}
}
- if (!curBone) {
- bone = NULL;
+ }
+
+#undef CHECK_PARENT
+
+ if (changed) {
+ ED_armature_edit_sync_selection(arm->edbo);
+ DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, ob);
+ }
+
+ return changed;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked Operator
+ * \{ */
+
+static int armature_select_linked_exec(bContext *C, wmOperator *op)
+{
+ const bool all_forks = RNA_boolean_get(op->ptr, "all_forks");
+
+ bool changed_multi = false;
+ 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;
+
+ bool found = false;
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
+ if (EBONE_VISIBLE(arm, ebone) &&
+ (ebone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL))) {
+ ebone->flag |= BONE_DONE;
+ found = true;
+ }
+ else {
+ ebone->flag &= ~BONE_DONE;
+ }
+ }
+
+ if (found) {
+ if (armature_select_linked_impl(ob, true, all_forks)) {
+ changed_multi = true;
+ }
}
}
+ MEM_freeN(objects);
- ED_outliner_select_sync_from_edit_bone_tag(C);
+ if (changed_multi) {
+ ED_outliner_select_sync_from_edit_bone_tag(C);
+ }
+ return OPERATOR_FINISHED;
+}
- ED_armature_edit_sync_selection(arm->edbo);
+void ARMATURE_OT_select_linked(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Linked All";
+ ot->idname = "ARMATURE_OT_select_linked";
+ ot->description = "Select all bones linked by parent/child connections to the current selection";
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object);
- DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
+ /* api callbacks */
+ ot->exec = armature_select_linked_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* Leave disabled by default as this matches pose mode. */
+ RNA_def_boolean(ot->srna, "all_forks", 0, "All Forks", "Follow forks in the parents chain");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked (Cursor Pick) Operator
+ * \{ */
+
+static int armature_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const bool select = !RNA_boolean_get(op->ptr, "deselect");
+ const bool all_forks = RNA_boolean_get(op->ptr, "all_forks");
+
+ view3d_operator_needs_opengl(C);
+ BKE_object_update_select_id(CTX_data_main(C));
+
+ Base *base = NULL;
+ EditBone *ebone_active = ED_armature_pick_ebone(C, event->mval, true, &base);
+
+ if (ebone_active == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ bArmature *arm = base->object->data;
+ if (!EBONE_SELECTABLE(arm, ebone_active)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Initialize flags. */
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
+ ebone->flag &= ~BONE_DONE;
+ }
+ ebone_active->flag |= BONE_DONE;
+
+ if (armature_select_linked_impl(base->object, select, all_forks)) {
+ ED_outliner_select_sync_from_edit_bone_tag(C);
+ }
return OPERATOR_FINISHED;
}
-static bool armature_select_linked_poll(bContext *C)
+static bool armature_select_linked_pick_poll(bContext *C)
{
return (ED_operator_view3d_active(C) && ED_operator_editarmature(C));
}
-void ARMATURE_OT_select_linked(wmOperatorType *ot)
+void ARMATURE_OT_select_linked_pick(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";
+ ot->name = "Select Linked";
+ ot->idname = "ARMATURE_OT_select_linked_pick";
+ ot->description = "(De)select bones linked by parent/child connections under the mouse cursor";
/* api callbacks */
/* leave 'exec' unset */
- ot->invoke = armature_select_linked_invoke;
- ot->poll = armature_select_linked_poll;
+ ot->invoke = armature_select_linked_pick_invoke;
+ ot->poll = armature_select_linked_pick_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
+ /* Leave disabled by default as this matches pose mode. */
+ RNA_def_boolean(ot->srna, "all_forks", 0, "All Forks", "Follow forks in the parents chain");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Buffer Queries EditMode
+ * \{ */
+
/* utility function for get_nearest_editbonepoint */
-static int selectbuffer_ret_hits_12(unsigned int *UNUSED(buffer), const int hits12)
+static int selectbuffer_ret_hits_12(uint *UNUSED(buffer), const int hits12)
{
return hits12;
}
-static int selectbuffer_ret_hits_5(unsigned int *buffer, const int hits12, const int hits5)
+static int selectbuffer_ret_hits_5(uint *buffer, const int hits12, const int hits5)
{
const int offs = 4 * hits12;
- memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(unsigned int));
+ memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(uint));
return hits5;
}
@@ -414,45 +653,28 @@ static EditBone *get_nearest_editbonepoint(
uint hitresult;
Base *base;
EditBone *ebone;
- } best = {
- .hitresult = BONESEL_NOSEL,
- .base = NULL,
- .ebone = NULL,
- };
+ } *result = NULL,
+
+ result_cycle = {.hitresult = -1, .base = NULL, .ebone = NULL},
+ result_bias = {.hitresult = -1, .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;
- }
+ Object *obedit_orig = vc->obedit;
+ EditBone *ebone_active_orig = ((bArmature *)obedit_orig->data)->act_edbone;
+ if (ebone_active_orig == NULL) {
+ use_cycle = false;
}
- 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;
- }
+ if ((len_manhattan_v2v2_int(vc->mval, last_mval) <= WM_EVENT_CURSOR_MOTION_THRESHOLD) == 0) {
+ use_cycle = false;
}
copy_v2_v2_int(last_mval, vc->mval);
}
- else {
- if (!XRAY_ACTIVE(vc->v3d)) {
- do_nearest = true;
- }
- }
+
+ const bool do_nearest = !(XRAY_ACTIVE(vc->v3d) || use_cycle);
/* matching logic from 'mixed_bones_object_selectbuffer' */
int hits = 0;
@@ -506,87 +728,144 @@ cache_end:
/* 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);
- }
+ result_bias.hitresult = buffer[3];
+ result_bias.base = ED_armature_base_and_ebone_from_select_buffer(
+ bases, bases_len, result_bias.hitresult, &result_bias.ebone);
}
else {
- int dep_min = 5;
+ int bias_max = INT_MIN;
+
+ /* Track Cycle Variables
+ * - Offset is always set to the active bone.
+ * - The object & bone indices subtracted by the 'offset.as_u32' value.
+ * Unsigned subtraction wrapping means we always select the next bone in the cycle.
+ */
+ struct {
+ union {
+ uint32_t as_u32;
+ struct {
+#ifdef __BIG_ENDIAN__
+ uint16_t ob;
+ uint16_t bone;
+#else
+ uint16_t bone;
+ uint16_t ob;
+#endif
+ };
+ } offset, test, best;
+ } cycle_order;
+
+ if (use_cycle) {
+ bArmature *arm = obedit_orig->data;
+ int ob_index = obedit_orig->runtime.select_id & 0xFFFF;
+ int bone_index = BLI_findindex(arm->edbo, ebone_active_orig);
+ /* Offset from the current active bone, so we cycle onto the next. */
+ cycle_order.offset.ob = ob_index;
+ cycle_order.offset.bone = bone_index;
+ /* The value of the active bone (with offset subtracted, a signal to always overwrite). */
+ cycle_order.best.as_u32 = 0;
+ }
+
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;
+
+ 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);
+
+ /* Prioritized selection. */
+ {
+ int bias;
/* 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;
+ bias = 4;
}
else if ((hitresult & BONESEL_TIP) && (ebone->flag & BONE_TIPSEL) == 0) {
- dep = 1;
+ bias = 4;
}
else {
- dep = 2;
+ bias = 3;
}
}
else {
- dep = 1;
+ bias = 4;
}
}
else {
/* bone found */
if (findunsel) {
if ((ebone->flag & BONE_SELECTED) == 0) {
- dep = 3;
+ bias = 2;
}
else {
- dep = 4;
+ bias = 1;
}
}
else {
- dep = 3;
+ bias = 2;
}
}
- if (ebone == ebone_next_act) {
- dep -= 1;
+ if (bias > bias_max) {
+ bias_max = bias;
+
+ result_bias.hitresult = hitresult;
+ result_bias.base = base;
+ result_bias.ebone = ebone;
}
+ }
- if (dep < dep_min) {
- dep_min = dep;
- best.hitresult = hitresult;
- best.base = base;
- best.ebone = ebone;
+ /* Cycle selected items (objects & bones). */
+ if (use_cycle) {
+ cycle_order.test.ob = hitresult & 0xFFFF;
+ cycle_order.test.bone = (hitresult & ~BONESEL_ANY) >> 16;
+ if (ebone == ebone_active_orig) {
+ BLI_assert(cycle_order.test.ob == cycle_order.offset.ob);
+ BLI_assert(cycle_order.test.bone == cycle_order.offset.bone);
+ }
+ /* Subtraction as a single value is needed to support cycling through bones
+ * from multiple objects. So once the last bone is selected,
+ * the bits for the bone index wrap into the object,
+ * causing the next object to be stepped onto. */
+ cycle_order.test.as_u32 -= cycle_order.offset.as_u32;
+
+ /* Even though this logic avoids stepping onto the active bone,
+ * always set the 'best' value for the first time.
+ * Otherwise ensure the value is the smallest it can be,
+ * relative to the active bone, as long as it's not the active bone. */
+ if ((cycle_order.best.as_u32 == 0) ||
+ (cycle_order.test.as_u32 && (cycle_order.test.as_u32 < cycle_order.best.as_u32))) {
+ cycle_order.best = cycle_order.test;
+ result_cycle.hitresult = hitresult;
+ result_cycle.base = base;
+ result_cycle.ebone = ebone;
}
}
}
}
- if (!(best.hitresult & BONESEL_NOSEL)) {
- *r_base = best.base;
+ result = (use_cycle && result_cycle.ebone) ? &result_cycle : &result_bias;
+
+ if (result->hitresult != -1) {
+ *r_base = result->base;
*r_selmask = 0;
- if (best.hitresult & BONESEL_ROOT) {
+ if (result->hitresult & BONESEL_ROOT) {
*r_selmask |= BONE_ROOTSEL;
}
- if (best.hitresult & BONESEL_TIP) {
+ if (result->hitresult & BONESEL_TIP) {
*r_selmask |= BONE_TIPSEL;
}
- if (best.hitresult & BONESEL_BONE) {
+ if (result->hitresult & BONESEL_BONE) {
*r_selmask |= BONE_SELECTED;
}
MEM_freeN(bases);
- return best.ebone;
+ return result->ebone;
}
}
*r_selmask = 0;
@@ -595,11 +874,17 @@ cache_end:
return NULL;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Utility Functions
+ * \{ */
+
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) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
changed = true;
@@ -612,7 +897,7 @@ 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) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
/* first and foremost, bone must be visible and selected */
if (EBONE_VISIBLE(arm, ebone)) {
if (ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
@@ -661,17 +946,11 @@ bool ED_armature_edit_deselect_all_visible_multi(bContext *C)
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);
- }
-}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Cursor Pick API
+ * \{ */
/* context: editmode armature in view3d */
bool ED_armature_edit_select_pick(
@@ -784,7 +1063,7 @@ bool ED_armature_edit_select_pick(
ED_armature_edit_sync_selection(arm->edbo);
/* then now check for active status */
- if (ebone_select_flag(nearBone)) {
+ if (ED_armature_ebone_selectflag_get(nearBone)) {
arm->act_edbone = nearBone;
}
@@ -800,6 +1079,8 @@ bool ED_armature_edit_select_pick(
return false;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Select Op From Tagged
*
@@ -893,7 +1174,7 @@ bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
/* Initialize flags. */
{
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
/* Flush the parent flag to this bone
* so we don't need to check the parent when adjusting the selection. */
@@ -915,7 +1196,7 @@ bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
}
/* Apply selection from bone selection flags. */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
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));
@@ -935,7 +1216,7 @@ bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
if (changed) {
/* Cleanup flags. */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (ebone->flag & BONE_DONE) {
SWAP(int, ebone->temp.i, ebone->flag);
ebone->flag |= BONE_DONE;
@@ -948,7 +1229,7 @@ bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
}
}
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (ebone->flag & BONE_DONE) {
if ((ebone->flag & BONE_CONNECTED) && ebone->parent) {
bool is_parent_tip_changed = (ebone->parent->flag & BONE_TIPSEL) !=
@@ -984,7 +1265,9 @@ bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
/** \} */
-/* **************** Selections ******************/
+/* -------------------------------------------------------------------- */
+/** \name (De)Select All Operator
+ * \{ */
static int armature_de_select_all_exec(bContext *C, wmOperator *op)
{
@@ -1003,7 +1286,7 @@ static int armature_de_select_all_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
}
- /* Set the flags */
+ /* Set the flags. */
CTX_DATA_BEGIN (C, EditBone *, ebone, visible_bones) {
/* ignore bone if selection can't change */
switch (action) {
@@ -1063,7 +1346,11 @@ void ARMATURE_OT_select_all(wmOperatorType *ot)
WM_operator_properties_select_all(ot);
}
-/**************** Select more/less **************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select More/Less Implementation
+ * \{ */
static void armature_select_more(bArmature *arm, EditBone *ebone)
{
@@ -1150,6 +1437,12 @@ static void armature_select_more_less(Object *ob, bool more)
ED_armature_edit_sync_selection(arm->edbo);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select More Operator
+ * \{ */
+
static int armature_de_select_more_exec(bContext *C, wmOperator *UNUSED(op))
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -1183,6 +1476,12 @@ void ARMATURE_OT_select_more(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Less Operator
+ * \{ */
+
static int armature_de_select_less_exec(bContext *C, wmOperator *UNUSED(op))
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -1216,6 +1515,12 @@ void ARMATURE_OT_select_less(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Similar
+ * \{ */
+
enum {
SIMEDBONE_CHILDREN = 1,
SIMEDBONE_CHILDREN_IMMEDIATE,
@@ -1270,7 +1575,7 @@ static void select_similar_length(bContext *C, const float thresh)
bArmature *arm = ob->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
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)) {
@@ -1318,7 +1623,7 @@ static void select_similar_direction(bContext *C, const float thresh)
bArmature *arm = ob->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_SELECTABLE(arm, ebone)) {
float dir[3];
bone_direction_worldspace_get(ob, ebone, dir);
@@ -1352,7 +1657,7 @@ static void select_similar_layer(bContext *C)
bArmature *arm = ob->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_SELECTABLE(arm, ebone)) {
if (ebone->layer & ebone_act->layer) {
ED_armature_ebone_select_set(ebone, true);
@@ -1392,7 +1697,7 @@ static void select_similar_prefix(bContext *C)
bool changed = false;
/* Find matches */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_SELECTABLE(arm, ebone)) {
char prefix_other[MAXBONENAME];
BLI_string_split_prefix(ebone->name, prefix_other, body_tmp, sizeof(ebone->name));
@@ -1434,7 +1739,7 @@ static void select_similar_suffix(bContext *C)
bool changed = false;
/* Find matches */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_SELECTABLE(arm, ebone)) {
char suffix_other[MAXBONENAME];
BLI_string_split_suffix(ebone->name, body_tmp, suffix_other, sizeof(ebone->name));
@@ -1469,7 +1774,7 @@ static void select_similar_data_pchan(bContext *C, const size_t bytes_size, cons
}
const char *data_active = (const char *)POINTER_OFFSET(pchan_active, offset);
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_SELECTABLE(arm, ebone)) {
const bPoseChannel *pchan = BKE_pose_channel_find_name(obedit->pose, ebone->name);
if (pchan) {
@@ -1504,11 +1809,11 @@ static void select_similar_children(bContext *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) {
+ LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
ebone_iter->temp.ebone = ebone_iter->parent;
}
- for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
is_ancestor(ebone_iter, ebone_act);
if (ebone_iter->temp.ebone == ebone_act && EBONE_SELECTABLE(arm, ebone_iter)) {
@@ -1526,7 +1831,7 @@ static void select_similar_children_immediate(bContext *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) {
+ LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
if (ebone_iter->parent == ebone_act && EBONE_SELECTABLE(arm, ebone_iter)) {
ED_armature_ebone_select_set(ebone_iter, true);
}
@@ -1546,7 +1851,7 @@ static void select_similar_siblings(bContext *C)
return;
}
- for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
if (ebone_iter->parent == ebone_act->parent && EBONE_SELECTABLE(arm, ebone_iter)) {
ED_armature_ebone_select_set(ebone_iter, true);
}
@@ -1631,7 +1936,11 @@ void ARMATURE_OT_select_similar(wmOperatorType *ot)
RNA_def_float(ot->srna, "threshold", 0.1f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
}
-/* ********************* select hierarchy operator ************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Hierarchy Operator
+ * \{ */
/* No need to convert to multi-objects. Just like we keep the non-active bones
* selected we then keep the non-active objects untouched (selected/unselected). */
@@ -1737,7 +2046,11 @@ void ARMATURE_OT_select_hierarchy(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
-/****************** Mirror Select ****************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Mirror Operator
+ * \{ */
/**
* \note clone of #pose_select_mirror_exec keep in sync
@@ -1822,7 +2135,11 @@ void ARMATURE_OT_select_mirror(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
-/****************** Select Path ****************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Path Operator
+ * \{ */
static bool armature_shortest_path_select(
bArmature *arm, EditBone *ebone_parent, EditBone *ebone_child, bool use_parent, bool is_test)
@@ -1866,7 +2183,7 @@ static int armature_shortest_path_pick_invoke(bContext *C, wmOperator *op, const
BKE_object_update_select_id(CTX_data_main(C));
ebone_src = arm->act_edbone;
- ebone_dst = get_nearest_bone(C, event->mval, false, &base_dst);
+ ebone_dst = ED_armature_pick_ebone(C, event->mval, false, &base_dst);
/* fallback to object selection */
if (ELEM(NULL, ebone_src, ebone_dst) || (ebone_src == ebone_dst)) {
@@ -1948,3 +2265,5 @@ void ARMATURE_OT_shortest_path_pick(wmOperatorType *ot)
/* 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 87f980db7b9..61d8856afbc 100644
--- a/source/blender/editors/armature/armature_skinning.c
+++ b/source/blender/editors/armature/armature_skinning.c
@@ -418,7 +418,7 @@ static void add_verts_to_dgroups(ReportList *reports,
BKE_mesh_foreach_mapped_vert_coords_get(me_eval, verts, mesh->totvert);
vertsfilled = 1;
}
- else if (modifiers_findByType(ob, eModifierType_Subsurf)) {
+ else if (BKE_modifiers_findby_type(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'. */
@@ -459,7 +459,7 @@ static void add_verts_to_dgroups(ReportList *reports,
}
/* only generated in some cases but can call anyway */
- ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 'e');
+ ED_mesh_mirror_spatial_table_end(ob);
/* free the memory allocated */
MEM_freeN(bonelist);
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index 76361f6785b..cf7f6699e5e 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -92,7 +92,7 @@ void ED_armature_edit_validate_active(struct bArmature *arm)
void ED_armature_edit_refresh_layer_used(bArmature *arm)
{
arm->layer_used = 0;
- for (EditBone *ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) {
arm->layer_used |= ebo->layer;
}
}
@@ -142,7 +142,7 @@ void bone_free(bArmature *arm, EditBone *bone)
}
/* Clear references from other edit bones. */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (ebone->bbone_next == bone) {
ebone->bbone_next = NULL;
}
@@ -196,13 +196,12 @@ 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 uint ebone_child_tot)
{
- unsigned int i;
+ uint i;
EditBone *ebone_iter;
-#define EBONE_TEMP_UINT(ebone) (*((unsigned int *)(&((ebone)->temp))))
+#define EBONE_TEMP_UINT(ebone) (*((uint *)(&((ebone)->temp))))
/* clear all */
for (i = 0; i < ebone_child_tot; i++) {
@@ -473,7 +472,7 @@ void ED_armature_ebone_transform_mirror_update(bArmature *arm, EditBone *ebo, bo
void ED_armature_edit_transform_mirror_update(Object *obedit)
{
bArmature *arm = obedit->data;
- for (EditBone *ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) {
ED_armature_ebone_transform_mirror_update(arm, ebo, true);
}
}
@@ -482,10 +481,10 @@ void ED_armature_edit_transform_mirror_update(Object *obedit)
/* 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)
+static EditBone *make_boneList_recursive(ListBase *edbo,
+ ListBase *bones,
+ EditBone *parent,
+ Bone *actBone)
{
EditBone *eBone;
EditBone *eBoneAct = NULL;
@@ -562,9 +561,9 @@ static EditBone *make_boneList_rec(ListBase *edbo,
BLI_addtail(edbo, eBone);
- /* Add children if necessary */
+ /* Add children if necessary. */
if (curBone->childbase.first) {
- eBoneTest = make_boneList_rec(edbo, &curBone->childbase, eBone, actBone);
+ eBoneTest = make_boneList_recursive(edbo, &curBone->childbase, eBone, actBone);
if (eBoneTest) {
eBoneAct = eBoneTest;
}
@@ -581,7 +580,7 @@ static EditBone *make_boneList_rec(ListBase *edbo,
static EditBone *find_ebone_link(ListBase *edbo, Bone *link)
{
if (link != NULL) {
- for (EditBone *ebone = edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, edbo) {
if (ebone->temp.bone == link) {
return ebone;
}
@@ -595,9 +594,9 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, struct Bone *actBone)
{
BLI_assert(!edbo->first && !edbo->last);
- EditBone *active = make_boneList_rec(edbo, bones, NULL, actBone);
+ EditBone *active = make_boneList_recursive(edbo, bones, NULL, actBone);
- for (EditBone *ebone = edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, edbo) {
Bone *bone = ebone->temp.bone;
/* Convert custom B-Bone handle links. */
@@ -721,7 +720,7 @@ void ED_armature_from_edit(Main *bmain, bArmature *arm)
}
}
- /* Copy the bones from the editData into the armature */
+ /* Copy the bones from the edit-data 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 */
@@ -819,7 +818,7 @@ void ED_armature_edit_free(struct bArmature *arm)
{
EditBone *eBone;
- /* Clear the editbones list */
+ /* Clear the edit-bones list. */
if (arm->edbo) {
if (arm->edbo->first) {
for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c
index c73f8f69fdd..a3a73f8d509 100644
--- a/source/blender/editors/armature/editarmature_undo.c
+++ b/source/blender/editors/armature/editarmature_undo.c
@@ -29,6 +29,7 @@
#include "DNA_object_types.h"
#include "BLI_array_utils.h"
+#include "BLI_listbase.h"
#include "BKE_context.h"
#include "BKE_layer.h"
@@ -94,7 +95,7 @@ static void *undoarm_from_editarm(UndoArmature *uarm, bArmature *arm)
ED_armature_ebone_listbase_temp_clear(&uarm->lb);
- for (EditBone *ebone = uarm->lb.first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, &uarm->lb) {
uarm->undo_size += sizeof(EditBone);
}
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index 6028ddb216f..d8a6a22a7df 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -1549,7 +1549,7 @@ static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind
}
}
else {
- modifier_setError(&mmd->modifier, "Failed to find bind solution (increase precision?)");
+ BKE_modifier_set_error(&mmd->modifier, "Failed to find bind solution (increase precision?)");
error("Mesh Deform: failed to find bind solution.");
break;
}
@@ -1753,7 +1753,7 @@ void ED_mesh_deform_bind_callback(MeshDeformModifierData *mmd,
int totvert,
float cagemat[4][4])
{
- MeshDeformModifierData *mmd_orig = (MeshDeformModifierData *)modifier_get_original(
+ MeshDeformModifierData *mmd_orig = (MeshDeformModifierData *)BKE_modifier_get_original(
&mmd->modifier);
MeshDeformBind mdb;
MVert *mvert;
@@ -1799,7 +1799,7 @@ void ED_mesh_deform_bind_callback(MeshDeformModifierData *mmd,
MEM_freeN(mdb.vertexcos);
/* compact weights */
- modifier_mdef_compact_influences((ModifierData *)mmd_orig);
+ BKE_modifier_mdef_compact_influences((ModifierData *)mmd_orig);
end_progress_bar();
waitcursor(0);
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 09b6cd9c8cc..0cd3afc9cf9 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -33,7 +33,7 @@
#include "DNA_scene_types.h"
#include "BKE_action.h"
-#include "BKE_anim.h"
+#include "BKE_anim_visualization.h"
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_deform.h"
@@ -75,12 +75,12 @@
/* matches logic with ED_operator_posemode_context() */
Object *ED_pose_object_from_context(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = 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) {
+ if (area && area->spacetype == SPACE_PROPERTIES) {
ob = ED_object_context(C);
}
else {
@@ -665,6 +665,11 @@ static int pose_bone_rotmode_exec(bContext *C, wmOperator *op)
/* set rotation mode of selected bones */
CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob) {
+ /* use API Method for conversions... */
+ BKE_rotMode_change_values(
+ pchan->quat, pchan->eul, pchan->rotAxis, &pchan->rotAngle, pchan->rotmode, (short)mode);
+
+ /* finally, set the new rotation type */
pchan->rotmode = mode;
if (prev_ob != ob) {
@@ -901,8 +906,6 @@ static int pose_bone_layers_exec(bContext *C, wmOperator *op)
RNA_boolean_set_array(&ptr, "layers", layers);
if (prev_ob != ob) {
- BKE_armature_refresh_layer_used(ob->data);
-
/* 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);
diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c
index 9cd87f476d4..c10e204e3a4 100644
--- a/source/blender/editors/armature/pose_group.c
+++ b/source/blender/editors/armature/pose_group.c
@@ -44,6 +44,7 @@
#include "WM_types.h"
#include "ED_armature.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "UI_interface.h"
@@ -484,6 +485,7 @@ static int pose_group_select_exec(bContext *C, wmOperator *UNUSED(op))
bArmature *arm = ob->data;
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ ED_outliner_select_sync_from_pose_bone_tag(C);
return OPERATOR_FINISHED;
}
@@ -518,6 +520,7 @@ static int pose_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
bArmature *arm = ob->data;
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ ED_outliner_select_sync_from_pose_bone_tag(C);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index f759808d08e..aa57fb5844d 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -161,16 +161,16 @@ static TimeMarker *poselib_get_active_pose(bAction *act)
/* XXX C can be zero */
static Object *get_poselib_object(bContext *C)
{
- ScrArea *sa;
+ ScrArea *area;
/* sanity check */
if (C == NULL) {
return NULL;
}
- sa = CTX_wm_area(C);
+ area = CTX_wm_area(C);
- if (sa && (sa->spacetype == SPACE_PROPERTIES)) {
+ if (area && (area->spacetype == SPACE_PROPERTIES)) {
return ED_object_context(C);
}
else {
@@ -626,7 +626,7 @@ static int poselib_remove_exec(bContext *C, wmOperator *op)
/* remove relevant keyframes */
for (fcu = act->curves.first; fcu; fcu = fcu->next) {
BezTriple *bezt;
- unsigned int i;
+ uint i;
if (fcu->bezt) {
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
@@ -870,7 +870,7 @@ typedef struct tPoseLib_PreviewData {
/** active scene. */
Scene *scene;
/** active area. */
- ScrArea *sa;
+ ScrArea *area;
/** RNA-Pointer to Object 'ob' .*/
PointerRNA rna_ptr;
@@ -1171,7 +1171,7 @@ static void poselib_preview_apply(bContext *C, wmOperator *op)
/* do header print - if interactively previewing */
if (pld->state == PL_PREVIEW_RUNNING) {
if (pld->flag & PL_PREVIEW_SHOWORIGINAL) {
- ED_area_status_text(pld->sa, TIP_("PoseLib Previewing Pose: [Showing Original Pose]"));
+ ED_area_status_text(pld->area, TIP_("PoseLib Previewing Pose: [Showing Original Pose]"));
ED_workspace_status_text(C, TIP_("Use Tab to start previewing poses again"));
}
else if (pld->searchstr[0]) {
@@ -1200,7 +1200,7 @@ static void poselib_preview_apply(bContext *C, wmOperator *op)
"Current Pose - \"%s\""),
tempstr,
markern);
- ED_area_status_text(pld->sa, pld->headerstr);
+ ED_area_status_text(pld->area, pld->headerstr);
ED_workspace_status_text(C, TIP_("Use ScrollWheel or PageUp/Down to change pose"));
}
else {
@@ -1208,7 +1208,7 @@ static void poselib_preview_apply(bContext *C, wmOperator *op)
sizeof(pld->headerstr),
TIP_("PoseLib Previewing Pose: \"%s\""),
pld->marker->name);
- ED_area_status_text(pld->sa, pld->headerstr);
+ ED_area_status_text(pld->area, pld->headerstr);
ED_workspace_status_text(C, NULL);
}
}
@@ -1323,9 +1323,7 @@ static void poselib_preview_get_next(tPoseLib_PreviewData *pld, int step)
}
/* 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, ushort event, char ascii)
{
/* try doing some form of string manipulation first */
switch (event) {
@@ -1633,7 +1631,7 @@ static void poselib_preview_init_data(bContext *C, wmOperator *op)
pld->act = (ob) ? (ob->poselib) : NULL;
pld->scene = CTX_data_scene(C);
- pld->sa = CTX_wm_area(C);
+ pld->area = CTX_wm_area(C);
/* get starting pose based on RNA-props for this operator */
if (pose_index == -1) {
@@ -1704,7 +1702,7 @@ static void poselib_preview_cleanup(bContext *C, wmOperator *op)
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_area_status_text(pld->area, NULL);
ED_workspace_status_text(C, NULL);
/* this signal does one recalc on pose, then unlocks, so ESC or edit will work */
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index 07be2baf1ae..9525fcf2154 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -141,7 +141,7 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer,
View3D *v3d,
Base *base,
- const unsigned int *buffer,
+ const uint *buffer,
short hits,
bool extend,
bool deselect,
@@ -156,12 +156,12 @@ bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer,
}
Object *ob_act = OBACT(view_layer);
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ BLI_assert(OBEDIT_FROM_VIEW_LAYER(view_layer) == NULL);
/* 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);
+ nearBone = ED_armature_pick_bone_from_selectbuffer(
+ &base, 1, buffer, hits, 1, do_nearest, &base_dummy);
/* if the bone cannot be affected, don't do anything */
if ((nearBone) && !(nearBone->flag & BONE_UNSELECTABLE)) {
@@ -263,7 +263,7 @@ void ED_armature_pose_select_in_wpaint_mode(ViewLayer *view_layer, Base *base_se
Object *ob_active = OBACT(view_layer);
BLI_assert(ob_active && (ob_active->mode & OB_MODE_WEIGHT_PAINT));
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob_active, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob_active, &virtualModifierData);
for (; md; md = md->next) {
if (md->type == eModifierType_Armature) {
ArmatureModifierData *amd = (ArmatureModifierData *)md;
@@ -323,7 +323,7 @@ bool ED_pose_deselect_all(Object *ob, int select_mode, const bool ignore_visibil
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) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) {
if (pchan->bone->flag & BONE_SELECTED) {
return true;
@@ -413,7 +413,7 @@ static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEve
view3d_operator_needs_opengl(C);
Base *base = NULL;
- bone = get_nearest_bone(C, event->mval, !extend, &base);
+ bone = ED_armature_pick_bone(C, event->mval, !extend, &base);
if (!bone) {
return OPERATOR_CANCELLED;
@@ -443,7 +443,7 @@ static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEve
}
/* Select children */
- for (curBone = bone->childbase.first; curBone; curBone = next) {
+ for (curBone = bone->childbase.first; curBone; curBone = curBone->next) {
selectconnected_posebonechildren(base->object, curBone, extend);
}
@@ -454,22 +454,22 @@ static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEve
return OPERATOR_FINISHED;
}
-static bool pose_select_linked_poll(bContext *C)
+static bool pose_select_linked_pick_poll(bContext *C)
{
return (ED_operator_view3d_active(C) && ED_operator_posemode(C));
}
-void POSE_OT_select_linked(wmOperatorType *ot)
+void POSE_OT_select_linked_pick(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";
+ ot->idname = "POSE_OT_select_linked_pick";
+ ot->description = "Select bones linked by parent/child connections under the mouse cursor";
/* callbacks */
/* leave 'exec' unset */
ot->invoke = pose_select_connected_invoke;
- ot->poll = pose_select_linked_poll;
+ ot->poll = pose_select_linked_pick_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -482,6 +482,62 @@ void POSE_OT_select_linked(wmOperatorType *ot)
"Extend selection instead of deselecting everything first");
}
+static int pose_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Bone *curBone, *next = NULL;
+
+ CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob) {
+ if ((pchan->bone->flag & BONE_SELECTED) == 0) {
+ continue;
+ }
+
+ bArmature *arm = ob->data;
+
+ /* Select parents */
+ for (curBone = pchan->bone; curBone; curBone = next) {
+ if (PBONE_SELECTABLE(arm, curBone)) {
+ curBone->flag |= BONE_SELECTED;
+
+ if (curBone->flag & BONE_CONNECTED) {
+ next = curBone->parent;
+ }
+ else {
+ next = NULL;
+ }
+ }
+ else {
+ next = NULL;
+ }
+ }
+
+ /* Select children */
+ for (curBone = pchan->bone->childbase.first; curBone; curBone = curBone->next) {
+ selectconnected_posebonechildren(ob, curBone, false);
+ }
+ ED_pose_bone_select_tag_update(ob);
+ }
+ CTX_DATA_END;
+
+ ED_outliner_select_sync_from_pose_bone_tag(C);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_select_linked(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Connected";
+ ot->idname = "POSE_OT_select_linked";
+ ot->description = "Select all bones linked by parent/child connections to the current selection";
+
+ /* callbacks */
+ ot->exec = pose_select_linked_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* -------------------------------------- */
static int pose_de_select_all_exec(bContext *C, wmOperator *op)
@@ -497,7 +553,7 @@ static int pose_de_select_all_exec(bContext *C, wmOperator *op)
Object *ob_prev = NULL;
- /* Set the flags */
+ /* 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);
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 336d09f71b5..d9621dba730 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -86,7 +86,7 @@ typedef struct tPoseSlideOp {
/** current scene */
Scene *scene;
/** area that we're operating in (needed for modal()) */
- ScrArea *sa;
+ ScrArea *area;
/** region that we're operating in (needed for modal()) */
ARegion *region;
/** len of the PoseSlideObject array. */
@@ -197,7 +197,7 @@ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
/* get info from context */
pso->scene = CTX_data_scene(C);
- pso->sa = CTX_wm_area(C); /* only really needed when doing modal() */
+ pso->area = CTX_wm_area(C); /* only really needed when doing modal() */
pso->region = CTX_wm_region(C); /* only really needed when doing modal() */
pso->cframe = pso->scene->r.cfra;
@@ -544,71 +544,56 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
/* 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 interpolation 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];
+ float quat_prev[4];
+ float quat_next[4];
+
+ quat_prev[0] = evaluate_fcurve(fcu_w, prevFrameF);
+ quat_prev[1] = evaluate_fcurve(fcu_x, prevFrameF);
+ quat_prev[2] = evaluate_fcurve(fcu_y, prevFrameF);
+ quat_prev[3] = evaluate_fcurve(fcu_z, prevFrameF);
- /* calculate the delta transform from the previous to the current */
- /* TODO: investigate ways to favor one transform more? */
- sub_qt_qtqt(quat_diff, quat_curr, quat_prev);
+ quat_next[0] = evaluate_fcurve(fcu_w, nextFrameF);
+ quat_next[1] = evaluate_fcurve(fcu_x, nextFrameF);
+ quat_next[2] = evaluate_fcurve(fcu_y, nextFrameF);
+ quat_next[3] = evaluate_fcurve(fcu_z, nextFrameF);
- /* 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_prev);
+ normalize_qt(quat_next);
- normalize_qt(quat_final);
+ interp_qt_qtqt(quat_final, quat_prev, quat_next, pso->percentage);
}
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);
+ /* POSESLIDE_PUSH and POSESLIDE_RELAX. */
+ float quat_breakdown[4];
+ float quat_curr[4];
- copy_qt_qt(quat_final, quat_curr);
+ copy_qt_qt(quat_curr, pchan->quat);
- /* 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));
+ quat_breakdown[0] = evaluate_fcurve(fcu_w, cframe);
+ quat_breakdown[1] = evaluate_fcurve(fcu_x, cframe);
+ quat_breakdown[2] = evaluate_fcurve(fcu_y, cframe);
+ quat_breakdown[3] = evaluate_fcurve(fcu_z, cframe);
- normalize_qt_qt(quat_final_prev, quat_final);
+ normalize_qt(quat_breakdown);
+ normalize_qt(quat_curr);
- /* tricky interpolations - blending between original and new */
- interp_qt_qtqt(quat_final, quat_final_prev, quat_interp, 1.0f / 6.0f);
+ if (pso->mode == POSESLIDE_PUSH) {
+ interp_qt_qtqt(quat_final, quat_breakdown, quat_curr, 1.0f + pso->percentage);
+ }
+ else {
+ BLI_assert(pso->mode == POSESLIDE_RELAX);
+ interp_qt_qtqt(quat_final, quat_curr, quat_breakdown, pso->percentage);
}
}
/* Apply final to the pose bone, keeping compatible for similar keyframe positions. */
- quat_to_compatible_quat(pchan->quat, quat_final, quat_curr_orig);
+ quat_to_compatible_quat(pchan->quat, quat_final, pchan->quat);
}
/* free the path now */
@@ -904,7 +889,7 @@ static void pose_slide_draw_status(tPoseSlideOp *pso)
limits_str);
}
- ED_area_status_text(pso->sa, status_str);
+ ED_area_status_text(pso->area, status_str);
}
/* common code for invoke() methods */
@@ -1071,7 +1056,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
case EVT_PADENTER: {
if (event->val == KM_PRESS) {
/* return to normal cursor and header status */
- ED_area_status_text(pso->sa, NULL);
+ ED_area_status_text(pso->area, NULL);
WM_cursor_modal_restore(win);
/* insert keyframes as required... */
@@ -1088,7 +1073,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
case RIGHTMOUSE: {
if (event->val == KM_PRESS) {
/* return to normal cursor and header status */
- ED_area_status_text(pso->sa, NULL);
+ ED_area_status_text(pso->area, NULL);
WM_cursor_modal_restore(win);
/* reset transforms back to original state */
@@ -1254,51 +1239,60 @@ static int pose_slide_exec_common(bContext *C, wmOperator *op, tPoseSlideOp *pso
return OPERATOR_FINISHED;
}
-/* common code for defining RNA properties */
-/* TODO: Skip save on these? */
+/**
+ * Common code for defining RNA properties.
+ */
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.0,
- 1.0);
-
- 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");
+ PropertyRNA *prop;
+
+ prop = RNA_def_float_percentage(ot->srna,
+ "percentage",
+ 0.5f,
+ 0.0f,
+ 1.0f,
+ "Percentage",
+ "Weighting factor for which keyframe is favored more",
+ 0.0,
+ 1.0);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = 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_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = 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_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_enum(ot->srna,
+ "channels",
+ prop_channels_types,
+ PS_TFM_ALL,
+ "Channels",
+ "Set of properties that are affected");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_enum(ot->srna,
+ "axis_lock",
+ prop_axis_lock_types,
+ 0,
+ "Axis Lock",
+ "Transform axis to restrict effects to");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* ------------------------------------ */
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index fe79894a351..1d2bf152777 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -207,12 +207,12 @@ typedef struct ApplyArmature_ParentState {
} ApplyArmature_ParentState;
/* Recursive walk for Apply To Selected mode; pstate NULL unless child of an applied bone. */
-static void applyarmature_process_selected_rec(bArmature *arm,
- bPose *pose,
- bPose *pose_eval,
- Bone *bone,
- ListBase *selected,
- ApplyArmature_ParentState *pstate)
+static void applyarmature_process_selected_recursive(bArmature *arm,
+ bPose *pose,
+ bPose *pose_eval,
+ Bone *bone,
+ ListBase *selected,
+ ApplyArmature_ParentState *pstate)
{
bPoseChannel *pchan = BKE_pose_channel_find_name(pose, bone->name);
const bPoseChannel *pchan_eval = BKE_pose_channel_find_name(pose_eval, bone->name);
@@ -333,8 +333,8 @@ static void applyarmature_process_selected_rec(bArmature *arm,
pstate = &new_pstate;
}
- for (Bone *child = bone->childbase.first; child; child = child->next) {
- applyarmature_process_selected_rec(arm, pose, pose_eval, child, selected, pstate);
+ LISTBASE_FOREACH (Bone *, child, &bone->childbase) {
+ applyarmature_process_selected_recursive(arm, pose, pose_eval, child, selected, pstate);
}
}
@@ -389,8 +389,9 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op)
if (use_selected) {
/* The selected only mode requires a recursive walk to handle parent-child relations. */
- for (Bone *bone = arm->bonebase.first; bone; bone = bone->next) {
- applyarmature_process_selected_rec(arm, pose, ob_eval->pose, bone, &selected_bones, NULL);
+ LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) {
+ applyarmature_process_selected_recursive(
+ arm, pose, ob_eval->pose, bone, &selected_bones, NULL);
}
BLI_freelistN(&selected_bones);
@@ -1239,7 +1240,7 @@ static int pose_clear_user_transforms_exec(bContext *C, wmOperator *op)
workob.adt = ob->adt;
workob.pose = dummyPose;
- BKE_animsys_evaluate_animdata(scene, &workob.id, workob.adt, cframe, ADT_RECALC_ANIM, false);
+ BKE_animsys_evaluate_animdata(&workob.id, workob.adt, cframe, ADT_RECALC_ANIM, false);
/* copy back values, but on selected bones only */
for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) {
diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c
index efb568178d9..e2038bdd2a3 100644
--- a/source/blender/editors/armature/pose_utils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -32,7 +32,7 @@
#include "DNA_scene_types.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_armature.h"
#include "BKE_idprop.h"
#include "BKE_layer.h"