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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2019-04-17 07:17:24 +0300
committerCampbell Barton <ideasman42@gmail.com>2019-04-17 07:21:24 +0300
commite12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch)
tree8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/editors/armature/armature_edit.c
parentb3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff)
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211. For details on usage and instructions for migrating branches without conflicts, see: https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/editors/armature/armature_edit.c')
-rw-r--r--source/blender/editors/armature/armature_edit.c2864
1 files changed, 1448 insertions, 1416 deletions
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index e3db0ca8f2c..dfcd0bf69f7 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -64,135 +64,136 @@
void ED_armature_transform_apply(Main *bmain, Object *ob, float mat[4][4], const bool do_props)
{
- bArmature *arm = ob->data;
+ bArmature *arm = ob->data;
- /* Put the armature into editmode */
- ED_armature_to_edit(arm);
+ /* Put the armature into editmode */
+ ED_armature_to_edit(arm);
- /* Transform the bones */
- ED_armature_transform_bones(arm, mat, do_props);
+ /* Transform the bones */
+ ED_armature_transform_bones(arm, mat, do_props);
- /* Turn the list into an armature */
- ED_armature_from_edit(bmain, arm);
- ED_armature_edit_free(arm);
+ /* Turn the list into an armature */
+ ED_armature_from_edit(bmain, arm);
+ ED_armature_edit_free(arm);
}
void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4], const bool do_props)
{
- EditBone *ebone;
- float scale = mat4_to_scale(mat); /* store the scale of the matrix here to use on envelopes */
- float mat3[3][3];
-
- copy_m3_m4(mat3, mat);
- normalize_m3(mat3);
- /* Do the rotations */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- float tmat[3][3];
-
- /* find the current bone's roll matrix */
- ED_armature_ebone_to_mat3(ebone, tmat);
-
- /* transform the roll matrix */
- mul_m3_m3m3(tmat, mat3, tmat);
-
- /* transform the bone */
- mul_m4_v3(mat, ebone->head);
- mul_m4_v3(mat, ebone->tail);
-
- /* apply the transformed roll back */
- mat3_to_vec_roll(tmat, NULL, &ebone->roll);
-
- if (do_props) {
- ebone->rad_head *= scale;
- ebone->rad_tail *= scale;
- ebone->dist *= scale;
-
- /* we could be smarter and scale by the matrix along the x & z axis */
- ebone->xwidth *= scale;
- ebone->zwidth *= scale;
- }
- }
+ EditBone *ebone;
+ float scale = mat4_to_scale(mat); /* store the scale of the matrix here to use on envelopes */
+ float mat3[3][3];
+
+ copy_m3_m4(mat3, mat);
+ normalize_m3(mat3);
+ /* Do the rotations */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ float tmat[3][3];
+
+ /* find the current bone's roll matrix */
+ ED_armature_ebone_to_mat3(ebone, tmat);
+
+ /* transform the roll matrix */
+ mul_m3_m3m3(tmat, mat3, tmat);
+
+ /* transform the bone */
+ mul_m4_v3(mat, ebone->head);
+ mul_m4_v3(mat, ebone->tail);
+
+ /* apply the transformed roll back */
+ mat3_to_vec_roll(tmat, NULL, &ebone->roll);
+
+ if (do_props) {
+ ebone->rad_head *= scale;
+ ebone->rad_tail *= scale;
+ ebone->dist *= scale;
+
+ /* we could be smarter and scale by the matrix along the x & z axis */
+ ebone->xwidth *= scale;
+ ebone->zwidth *= scale;
+ }
+ }
}
void ED_armature_transform(Main *bmain, bArmature *arm, float mat[4][4], const bool do_props)
{
- if (arm->edbo) {
- ED_armature_transform_bones(arm, mat, do_props);
- }
- else {
- /* Put the armature into editmode */
- ED_armature_to_edit(arm);
-
- /* Transform the bones */
- ED_armature_transform_bones(arm, mat, do_props);
-
- /* Go back to object mode*/
- ED_armature_from_edit(bmain, arm);
- ED_armature_edit_free(arm);
- }
+ if (arm->edbo) {
+ ED_armature_transform_bones(arm, mat, do_props);
+ }
+ else {
+ /* Put the armature into editmode */
+ ED_armature_to_edit(arm);
+
+ /* Transform the bones */
+ ED_armature_transform_bones(arm, mat, do_props);
+
+ /* Go back to object mode*/
+ ED_armature_from_edit(bmain, arm);
+ ED_armature_edit_free(arm);
+ }
}
/* exported for use in editors/object/ */
/* 0 == do center, 1 == center new, 2 == center cursor */
-void ED_armature_origin_set(Main *bmain, Object *ob, const float cursor[3], int centermode, int around)
+void ED_armature_origin_set(
+ Main *bmain, Object *ob, const float cursor[3], int centermode, int around)
{
- const bool is_editmode = BKE_object_is_in_editmode(ob);
- EditBone *ebone;
- bArmature *arm = ob->data;
- float cent[3];
-
- /* Put the armature into editmode */
- if (is_editmode == false) {
- ED_armature_to_edit(arm);
- }
-
- /* Find the centerpoint */
- if (centermode == 2) {
- copy_v3_v3(cent, cursor);
- invert_m4_m4(ob->imat, ob->obmat);
- mul_m4_v3(ob->imat, cent);
- }
- else {
- if (around == V3D_AROUND_CENTER_MEDIAN) {
- int total = 0;
- zero_v3(cent);
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- total += 2;
- add_v3_v3(cent, ebone->head);
- add_v3_v3(cent, ebone->tail);
- }
- if (total) {
- mul_v3_fl(cent, 1.0f / (float)total);
- }
- }
- else {
- float min[3], max[3];
- INIT_MINMAX(min, max);
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- minmax_v3v3_v3(min, max, ebone->head);
- minmax_v3v3_v3(min, max, ebone->tail);
- }
- mid_v3_v3v3(cent, min, max);
- }
- }
-
- /* Do the adjustments */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- sub_v3_v3(ebone->head, cent);
- sub_v3_v3(ebone->tail, cent);
- }
-
- /* Turn the list into an armature */
- if (is_editmode == false) {
- ED_armature_from_edit(bmain, arm);
- ED_armature_edit_free(arm);
- }
-
- /* Adjust object location for new centerpoint */
- if (centermode && (is_editmode == false)) {
- mul_mat3_m4_v3(ob->obmat, cent); /* omit translation part */
- add_v3_v3(ob->loc, cent);
- }
+ const bool is_editmode = BKE_object_is_in_editmode(ob);
+ EditBone *ebone;
+ bArmature *arm = ob->data;
+ float cent[3];
+
+ /* Put the armature into editmode */
+ if (is_editmode == false) {
+ ED_armature_to_edit(arm);
+ }
+
+ /* Find the centerpoint */
+ if (centermode == 2) {
+ copy_v3_v3(cent, cursor);
+ invert_m4_m4(ob->imat, ob->obmat);
+ mul_m4_v3(ob->imat, cent);
+ }
+ else {
+ if (around == V3D_AROUND_CENTER_MEDIAN) {
+ int total = 0;
+ zero_v3(cent);
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ total += 2;
+ add_v3_v3(cent, ebone->head);
+ add_v3_v3(cent, ebone->tail);
+ }
+ if (total) {
+ mul_v3_fl(cent, 1.0f / (float)total);
+ }
+ }
+ else {
+ float min[3], max[3];
+ INIT_MINMAX(min, max);
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ minmax_v3v3_v3(min, max, ebone->head);
+ minmax_v3v3_v3(min, max, ebone->tail);
+ }
+ mid_v3_v3v3(cent, min, max);
+ }
+ }
+
+ /* Do the adjustments */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ sub_v3_v3(ebone->head, cent);
+ sub_v3_v3(ebone->tail, cent);
+ }
+
+ /* Turn the list into an armature */
+ if (is_editmode == false) {
+ ED_armature_from_edit(bmain, arm);
+ ED_armature_edit_free(arm);
+ }
+
+ /* Adjust object location for new centerpoint */
+ if (centermode && (is_editmode == false)) {
+ mul_mat3_m4_v3(ob->obmat, cent); /* omit translation part */
+ add_v3_v3(ob->loc, cent);
+ }
}
/* ********************************* Roll ******************************* */
@@ -200,651 +201,676 @@ void ED_armature_origin_set(Main *bmain, Object *ob, const float cursor[3], int
/* adjust bone roll to align Z axis with vector
* vec is in local space and is normalized
*/
-float ED_armature_ebone_roll_to_vector(const EditBone *bone, const float align_axis[3], const bool axis_only)
+float ED_armature_ebone_roll_to_vector(const EditBone *bone,
+ const float align_axis[3],
+ const bool axis_only)
{
- float mat[3][3], nor[3];
- float vec[3], align_axis_proj[3], roll = 0.0f;
+ float mat[3][3], nor[3];
+ float vec[3], align_axis_proj[3], roll = 0.0f;
- BLI_ASSERT_UNIT_V3(align_axis);
+ BLI_ASSERT_UNIT_V3(align_axis);
- sub_v3_v3v3(nor, bone->tail, bone->head);
+ sub_v3_v3v3(nor, bone->tail, bone->head);
- /* If tail == head or the bone is aligned with the axis... */
- if (normalize_v3(nor) <= FLT_EPSILON || (fabsf(dot_v3v3(align_axis, nor)) >= (1.0f - FLT_EPSILON))) {
- return roll;
- }
+ /* If tail == head or the bone is aligned with the axis... */
+ if (normalize_v3(nor) <= FLT_EPSILON ||
+ (fabsf(dot_v3v3(align_axis, nor)) >= (1.0f - FLT_EPSILON))) {
+ return roll;
+ }
- vec_roll_to_mat3_normalized(nor, 0.0f, mat);
+ vec_roll_to_mat3_normalized(nor, 0.0f, mat);
- /* project the new_up_axis along the normal */
- project_v3_v3v3_normalized(vec, align_axis, nor);
- sub_v3_v3v3(align_axis_proj, align_axis, vec);
+ /* project the new_up_axis along the normal */
+ project_v3_v3v3_normalized(vec, align_axis, nor);
+ sub_v3_v3v3(align_axis_proj, align_axis, vec);
- if (axis_only) {
- if (angle_v3v3(align_axis_proj, mat[2]) > (float)(M_PI_2)) {
- negate_v3(align_axis_proj);
- }
- }
+ if (axis_only) {
+ if (angle_v3v3(align_axis_proj, mat[2]) > (float)(M_PI_2)) {
+ negate_v3(align_axis_proj);
+ }
+ }
- roll = angle_v3v3(align_axis_proj, mat[2]);
+ roll = angle_v3v3(align_axis_proj, mat[2]);
- cross_v3_v3v3(vec, mat[2], align_axis_proj);
+ cross_v3_v3v3(vec, mat[2], align_axis_proj);
- if (dot_v3v3(vec, nor) < 0.0f) {
- return -roll;
- }
- return roll;
+ if (dot_v3v3(vec, nor) < 0.0f) {
+ return -roll;
+ }
+ return roll;
}
/* note, ranges arithmetic is used below */
typedef enum eCalcRollTypes {
- /* pos */
- CALC_ROLL_POS_X = 0,
- CALC_ROLL_POS_Y,
- CALC_ROLL_POS_Z,
-
- CALC_ROLL_TAN_POS_X,
- CALC_ROLL_TAN_POS_Z,
-
- /* neg */
- CALC_ROLL_NEG_X,
- CALC_ROLL_NEG_Y,
- CALC_ROLL_NEG_Z,
-
- CALC_ROLL_TAN_NEG_X,
- CALC_ROLL_TAN_NEG_Z,
-
- /* no sign */
- CALC_ROLL_ACTIVE,
- CALC_ROLL_VIEW,
- CALC_ROLL_CURSOR,
+ /* pos */
+ CALC_ROLL_POS_X = 0,
+ CALC_ROLL_POS_Y,
+ CALC_ROLL_POS_Z,
+
+ CALC_ROLL_TAN_POS_X,
+ CALC_ROLL_TAN_POS_Z,
+
+ /* neg */
+ CALC_ROLL_NEG_X,
+ CALC_ROLL_NEG_Y,
+ CALC_ROLL_NEG_Z,
+
+ CALC_ROLL_TAN_NEG_X,
+ CALC_ROLL_TAN_NEG_Z,
+
+ /* no sign */
+ CALC_ROLL_ACTIVE,
+ CALC_ROLL_VIEW,
+ CALC_ROLL_CURSOR,
} eCalcRollTypes;
static const EnumPropertyItem prop_calc_roll_types[] = {
- {0, "", 0, N_("Positive"), ""},
- {CALC_ROLL_TAN_POS_X, "POS_X", 0, "Local +X Tangent", ""},
- {CALC_ROLL_TAN_POS_Z, "POS_Z", 0, "Local +Z Tangent", ""},
+ {0, "", 0, N_("Positive"), ""},
+ {CALC_ROLL_TAN_POS_X, "POS_X", 0, "Local +X Tangent", ""},
+ {CALC_ROLL_TAN_POS_Z, "POS_Z", 0, "Local +Z Tangent", ""},
- {CALC_ROLL_POS_X, "GLOBAL_POS_X", 0, "Global +X Axis", ""},
- {CALC_ROLL_POS_Y, "GLOBAL_POS_Y", 0, "Global +Y Axis", ""},
- {CALC_ROLL_POS_Z, "GLOBAL_POS_Z", 0, "Global +Z Axis", ""},
+ {CALC_ROLL_POS_X, "GLOBAL_POS_X", 0, "Global +X Axis", ""},
+ {CALC_ROLL_POS_Y, "GLOBAL_POS_Y", 0, "Global +Y Axis", ""},
+ {CALC_ROLL_POS_Z, "GLOBAL_POS_Z", 0, "Global +Z Axis", ""},
- {0, "", 0, N_("Negative"), ""},
+ {0, "", 0, N_("Negative"), ""},
- {CALC_ROLL_TAN_NEG_X, "NEG_X", 0, "Local -X Tangent", ""},
- {CALC_ROLL_TAN_NEG_Z, "NEG_Z", 0, "Local -Z Tangent", ""},
+ {CALC_ROLL_TAN_NEG_X, "NEG_X", 0, "Local -X Tangent", ""},
+ {CALC_ROLL_TAN_NEG_Z, "NEG_Z", 0, "Local -Z Tangent", ""},
- {CALC_ROLL_NEG_X, "GLOBAL_NEG_X", 0, "Global -X Axis", ""},
- {CALC_ROLL_NEG_Y, "GLOBAL_NEG_Y", 0, "Global -Y Axis", ""},
- {CALC_ROLL_NEG_Z, "GLOBAL_NEG_Z", 0, "Global -Z Axis", ""},
+ {CALC_ROLL_NEG_X, "GLOBAL_NEG_X", 0, "Global -X Axis", ""},
+ {CALC_ROLL_NEG_Y, "GLOBAL_NEG_Y", 0, "Global -Y Axis", ""},
+ {CALC_ROLL_NEG_Z, "GLOBAL_NEG_Z", 0, "Global -Z Axis", ""},
- {0, "", 0, N_("Other"), ""},
- {CALC_ROLL_ACTIVE, "ACTIVE", 0, "Active Bone", ""},
- {CALC_ROLL_VIEW, "VIEW", 0, "View Axis", ""},
- {CALC_ROLL_CURSOR, "CURSOR", 0, "Cursor", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, "", 0, N_("Other"), ""},
+ {CALC_ROLL_ACTIVE, "ACTIVE", 0, "Active Bone", ""},
+ {CALC_ROLL_VIEW, "VIEW", 0, "View Axis", ""},
+ {CALC_ROLL_CURSOR, "CURSOR", 0, "Cursor", ""},
+ {0, NULL, 0, NULL, NULL},
};
-
static int armature_calc_roll_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob_active = CTX_data_edit_object(C);
- int ret = OPERATOR_FINISHED;
-
- eCalcRollTypes type = RNA_enum_get(op->ptr, "type");
- const bool axis_only = RNA_boolean_get(op->ptr, "axis_only");
- /* axis_flip when matching the active bone never makes sense */
- bool axis_flip = ((type >= CALC_ROLL_ACTIVE) ? RNA_boolean_get(op->ptr, "axis_flip") :
- (type >= CALC_ROLL_TAN_NEG_X) ? true : false);
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- bArmature *arm = ob->data;
- bool changed = false;
-
- float imat[3][3];
- EditBone *ebone;
-
- if ((type >= CALC_ROLL_NEG_X) && (type <= CALC_ROLL_TAN_NEG_Z)) {
- type -= (CALC_ROLL_ACTIVE - CALC_ROLL_NEG_X);
- axis_flip = true;
- }
-
- copy_m3_m4(imat, ob->obmat);
- invert_m3(imat);
-
- if (type == CALC_ROLL_CURSOR) { /* Cursor */
- Scene *scene = CTX_data_scene(C);
- float cursor_local[3];
- const View3DCursor *cursor = &scene->cursor;
-
- invert_m4_m4(ob->imat, ob->obmat);
- copy_v3_v3(cursor_local, cursor->location);
- mul_m4_v3(ob->imat, cursor_local);
-
- /* cursor */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
- float cursor_rel[3];
- sub_v3_v3v3(cursor_rel, cursor_local, ebone->head);
- if (axis_flip) negate_v3(cursor_rel);
- if (normalize_v3(cursor_rel) != 0.0f) {
- ebone->roll = ED_armature_ebone_roll_to_vector(ebone, cursor_rel, axis_only);
- changed = true;
- }
- }
- }
- }
- else if (ELEM(type, CALC_ROLL_TAN_POS_X, CALC_ROLL_TAN_POS_Z)) {
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (ebone->parent) {
- bool is_edit = (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone));
- bool is_edit_parent = (EBONE_VISIBLE(arm, ebone->parent) && EBONE_EDITABLE(ebone->parent));
-
- if (is_edit || is_edit_parent) {
- EditBone *ebone_other = ebone->parent;
- float dir_a[3];
- float dir_b[3];
- float vec[3];
- bool is_vec_zero;
-
- sub_v3_v3v3(dir_a, ebone->tail, ebone->head);
- normalize_v3(dir_a);
-
- /* find the first bone in the chane with a different direction */
- do {
- sub_v3_v3v3(dir_b, ebone_other->head, ebone_other->tail);
- normalize_v3(dir_b);
-
- if (type == CALC_ROLL_TAN_POS_Z) {
- cross_v3_v3v3(vec, dir_a, dir_b);
- }
- else {
- add_v3_v3v3(vec, dir_a, dir_b);
- }
- } while ((is_vec_zero = (normalize_v3(vec) < 0.00001f)) &&
- (ebone_other = ebone_other->parent));
-
- if (!is_vec_zero) {
- if (axis_flip) negate_v3(vec);
-
- if (is_edit) {
- ebone->roll = ED_armature_ebone_roll_to_vector(ebone, vec, axis_only);
- changed = true;
- }
-
- /* parentless bones use cross product with child */
- if (is_edit_parent) {
- if (ebone->parent->parent == NULL) {
- ebone->parent->roll = ED_armature_ebone_roll_to_vector(ebone->parent, vec, axis_only);
- changed = true;
- }
- }
- }
- }
- }
- }
- }
- else {
- float vec[3] = {0.0f, 0.0f, 0.0f};
- if (type == CALC_ROLL_VIEW) { /* View */
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- if (rv3d == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No region view3d available");
- ret = OPERATOR_CANCELLED;
- goto cleanup;
- }
-
- copy_v3_v3(vec, rv3d->viewinv[2]);
- mul_m3_v3(imat, vec);
- }
- else if (type == CALC_ROLL_ACTIVE) {
- float mat[3][3];
- bArmature *arm_active = ob_active->data;
- ebone = (EditBone *)arm_active->act_edbone;
- if (ebone == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No active bone set");
- ret = OPERATOR_CANCELLED;
- goto cleanup;
- }
-
- ED_armature_ebone_to_mat3(ebone, mat);
- copy_v3_v3(vec, mat[2]);
- }
- else { /* Axis */
- assert(type <= 5);
- if (type < 3) vec[type] = 1.0f;
- else vec[type - 2] = -1.0f;
- mul_m3_v3(imat, vec);
- normalize_v3(vec);
- }
-
- if (axis_flip) negate_v3(vec);
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
- /* roll func is a callback which assumes that all is well */
- ebone->roll = ED_armature_ebone_roll_to_vector(ebone, vec, axis_only);
- changed = true;
- }
- }
- }
-
- if (arm->flag & ARM_MIRROR_EDIT) {
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) {
- EditBone *ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
- if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) {
- ebone->roll = -ebone_mirr->roll;
- }
- }
- }
- }
-
- if (changed) {
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
- }
- }
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob_active = CTX_data_edit_object(C);
+ int ret = OPERATOR_FINISHED;
+
+ eCalcRollTypes type = RNA_enum_get(op->ptr, "type");
+ const bool axis_only = RNA_boolean_get(op->ptr, "axis_only");
+ /* axis_flip when matching the active bone never makes sense */
+ bool axis_flip = ((type >= CALC_ROLL_ACTIVE) ? RNA_boolean_get(op->ptr, "axis_flip") :
+ (type >= CALC_ROLL_TAN_NEG_X) ? true : false);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bool changed = false;
+
+ float imat[3][3];
+ EditBone *ebone;
+
+ if ((type >= CALC_ROLL_NEG_X) && (type <= CALC_ROLL_TAN_NEG_Z)) {
+ type -= (CALC_ROLL_ACTIVE - CALC_ROLL_NEG_X);
+ axis_flip = true;
+ }
+
+ copy_m3_m4(imat, ob->obmat);
+ invert_m3(imat);
+
+ if (type == CALC_ROLL_CURSOR) { /* Cursor */
+ Scene *scene = CTX_data_scene(C);
+ float cursor_local[3];
+ const View3DCursor *cursor = &scene->cursor;
+
+ invert_m4_m4(ob->imat, ob->obmat);
+ copy_v3_v3(cursor_local, cursor->location);
+ mul_m4_v3(ob->imat, cursor_local);
+
+ /* cursor */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
+ float cursor_rel[3];
+ sub_v3_v3v3(cursor_rel, cursor_local, ebone->head);
+ if (axis_flip)
+ negate_v3(cursor_rel);
+ if (normalize_v3(cursor_rel) != 0.0f) {
+ ebone->roll = ED_armature_ebone_roll_to_vector(ebone, cursor_rel, axis_only);
+ changed = true;
+ }
+ }
+ }
+ }
+ else if (ELEM(type, CALC_ROLL_TAN_POS_X, CALC_ROLL_TAN_POS_Z)) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->parent) {
+ bool is_edit = (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone));
+ bool is_edit_parent = (EBONE_VISIBLE(arm, ebone->parent) &&
+ EBONE_EDITABLE(ebone->parent));
+
+ if (is_edit || is_edit_parent) {
+ EditBone *ebone_other = ebone->parent;
+ float dir_a[3];
+ float dir_b[3];
+ float vec[3];
+ bool is_vec_zero;
+
+ sub_v3_v3v3(dir_a, ebone->tail, ebone->head);
+ normalize_v3(dir_a);
+
+ /* find the first bone in the chane with a different direction */
+ do {
+ sub_v3_v3v3(dir_b, ebone_other->head, ebone_other->tail);
+ normalize_v3(dir_b);
+
+ if (type == CALC_ROLL_TAN_POS_Z) {
+ cross_v3_v3v3(vec, dir_a, dir_b);
+ }
+ else {
+ add_v3_v3v3(vec, dir_a, dir_b);
+ }
+ } while ((is_vec_zero = (normalize_v3(vec) < 0.00001f)) &&
+ (ebone_other = ebone_other->parent));
+
+ if (!is_vec_zero) {
+ if (axis_flip)
+ negate_v3(vec);
+
+ if (is_edit) {
+ ebone->roll = ED_armature_ebone_roll_to_vector(ebone, vec, axis_only);
+ changed = true;
+ }
+
+ /* parentless bones use cross product with child */
+ if (is_edit_parent) {
+ if (ebone->parent->parent == NULL) {
+ ebone->parent->roll = ED_armature_ebone_roll_to_vector(
+ ebone->parent, vec, axis_only);
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else {
+ float vec[3] = {0.0f, 0.0f, 0.0f};
+ if (type == CALC_ROLL_VIEW) { /* View */
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (rv3d == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No region view3d available");
+ ret = OPERATOR_CANCELLED;
+ goto cleanup;
+ }
+
+ copy_v3_v3(vec, rv3d->viewinv[2]);
+ mul_m3_v3(imat, vec);
+ }
+ else if (type == CALC_ROLL_ACTIVE) {
+ float mat[3][3];
+ bArmature *arm_active = ob_active->data;
+ ebone = (EditBone *)arm_active->act_edbone;
+ if (ebone == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No active bone set");
+ ret = OPERATOR_CANCELLED;
+ goto cleanup;
+ }
+
+ ED_armature_ebone_to_mat3(ebone, mat);
+ copy_v3_v3(vec, mat[2]);
+ }
+ else { /* Axis */
+ assert(type <= 5);
+ if (type < 3)
+ vec[type] = 1.0f;
+ else
+ vec[type - 2] = -1.0f;
+ mul_m3_v3(imat, vec);
+ normalize_v3(vec);
+ }
+
+ if (axis_flip)
+ negate_v3(vec);
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
+ /* roll func is a callback which assumes that all is well */
+ ebone->roll = ED_armature_ebone_roll_to_vector(ebone, vec, axis_only);
+ changed = true;
+ }
+ }
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) {
+ EditBone *ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
+ if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) {
+ ebone->roll = -ebone_mirr->roll;
+ }
+ }
+ }
+ }
+
+ if (changed) {
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ }
cleanup:
- MEM_freeN(objects);
- return ret;
+ MEM_freeN(objects);
+ return ret;
}
void ARMATURE_OT_calculate_roll(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Recalculate Roll";
- ot->idname = "ARMATURE_OT_calculate_roll";
- ot->description = "Automatically fix alignment of select bones' axes";
-
- /* api callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = armature_calc_roll_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", prop_calc_roll_types, CALC_ROLL_TAN_POS_X, "Type", "");
- RNA_def_boolean(ot->srna, "axis_flip", 0, "Flip Axis", "Negate the alignment axis");
- RNA_def_boolean(ot->srna, "axis_only", 0, "Shortest Rotation", "Ignore the axis direction, use the shortest rotation to align");
+ /* identifiers */
+ ot->name = "Recalculate Roll";
+ ot->idname = "ARMATURE_OT_calculate_roll";
+ ot->description = "Automatically fix alignment of select bones' axes";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = armature_calc_roll_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_calc_roll_types, CALC_ROLL_TAN_POS_X, "Type", "");
+ RNA_def_boolean(ot->srna, "axis_flip", 0, "Flip Axis", "Negate the alignment axis");
+ RNA_def_boolean(ot->srna,
+ "axis_only",
+ 0,
+ "Shortest Rotation",
+ "Ignore the axis direction, use the shortest rotation to align");
}
static int armature_roll_clear_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const float roll = RNA_float_get(op->ptr, "roll");
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- bArmature *arm = ob->data;
- bool changed = false;
-
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
- /* Roll func is a callback which assumes that all is well. */
- ebone->roll = roll;
- changed = true;
- }
- }
-
- if (arm->flag & ARM_MIRROR_EDIT) {
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) {
- EditBone *ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
- if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) {
- ebone->roll = -ebone_mirr->roll;
- changed = true;
- }
- }
- }
- }
-
- if (changed) {
- /* Note, notifier might evolve. */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
- }
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const float roll = RNA_float_get(op->ptr, "roll");
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bool changed = false;
+
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
+ /* Roll func is a callback which assumes that all is well. */
+ ebone->roll = roll;
+ changed = true;
+ }
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) {
+ EditBone *ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
+ if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) {
+ ebone->roll = -ebone_mirr->roll;
+ changed = true;
+ }
+ }
+ }
+ }
+
+ if (changed) {
+ /* Note, notifier might evolve. */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ }
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_roll_clear(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Clear Roll";
- ot->idname = "ARMATURE_OT_roll_clear";
- ot->description = "Clear roll for selected bones";
-
- /* api callbacks */
- ot->exec = armature_roll_clear_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_float_rotation(
- ot->srna, "roll", 0, NULL, DEG2RADF(-360.0f), DEG2RADF(360.0f),
- "Roll", "", DEG2RADF(-360.0f), DEG2RADF(360.0f));
+ /* identifiers */
+ ot->name = "Clear Roll";
+ ot->idname = "ARMATURE_OT_roll_clear";
+ ot->description = "Clear roll for selected bones";
+
+ /* api callbacks */
+ ot->exec = armature_roll_clear_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_float_rotation(ot->srna,
+ "roll",
+ 0,
+ NULL,
+ DEG2RADF(-360.0f),
+ DEG2RADF(360.0f),
+ "Roll",
+ "",
+ DEG2RADF(-360.0f),
+ DEG2RADF(360.0f));
}
/* ******************************** Chain-Based Tools ********************************* */
/* temporary data-structure for merge/fill bones */
typedef struct EditBonePoint {
- struct EditBonePoint *next, *prev;
+ struct EditBonePoint *next, *prev;
- EditBone *head_owner; /* EditBone which uses this point as a 'head' point */
- EditBone *tail_owner; /* EditBone which uses this point as a 'tail' point */
+ EditBone *head_owner; /* EditBone which uses this point as a 'head' point */
+ EditBone *tail_owner; /* EditBone which uses this point as a 'tail' point */
- float vec[3]; /* the actual location of the point in local/EditMode space */
+ float vec[3]; /* the actual location of the point in local/EditMode space */
} EditBonePoint;
/* find chain-tips (i.e. bones without children) */
static void chains_find_tips(ListBase *edbo, ListBase *list)
{
- EditBone *curBone, *ebo;
- LinkData *ld;
-
- /* note: this is potentially very slow ... there's got to be a better way */
- for (curBone = edbo->first; curBone; curBone = curBone->next) {
- short stop = 0;
-
- /* is this bone contained within any existing chain? (skip if so) */
- for (ld = list->first; ld; ld = ld->next) {
- for (ebo = ld->data; ebo; ebo = ebo->parent) {
- if (ebo == curBone) {
- stop = 1;
- break;
- }
- }
-
- if (stop) break;
- }
- /* skip current bone if it is part of an existing chain */
- if (stop) continue;
-
- /* is any existing chain part of the chain formed by this bone? */
- stop = 0;
- for (ebo = curBone->parent; ebo; ebo = ebo->parent) {
- for (ld = list->first; ld; ld = ld->next) {
- if (ld->data == ebo) {
- ld->data = curBone;
- stop = 1;
- break;
- }
- }
-
- if (stop) break;
- }
- /* current bone has already been added to a chain? */
- if (stop) continue;
-
- /* add current bone to a new chain */
- ld = MEM_callocN(sizeof(LinkData), "BoneChain");
- ld->data = curBone;
- BLI_addtail(list, ld);
- }
+ EditBone *curBone, *ebo;
+ LinkData *ld;
+
+ /* note: this is potentially very slow ... there's got to be a better way */
+ for (curBone = edbo->first; curBone; curBone = curBone->next) {
+ short stop = 0;
+
+ /* is this bone contained within any existing chain? (skip if so) */
+ for (ld = list->first; ld; ld = ld->next) {
+ for (ebo = ld->data; ebo; ebo = ebo->parent) {
+ if (ebo == curBone) {
+ stop = 1;
+ break;
+ }
+ }
+
+ if (stop)
+ break;
+ }
+ /* skip current bone if it is part of an existing chain */
+ if (stop)
+ continue;
+
+ /* is any existing chain part of the chain formed by this bone? */
+ stop = 0;
+ for (ebo = curBone->parent; ebo; ebo = ebo->parent) {
+ for (ld = list->first; ld; ld = ld->next) {
+ if (ld->data == ebo) {
+ ld->data = curBone;
+ stop = 1;
+ break;
+ }
+ }
+
+ if (stop)
+ break;
+ }
+ /* current bone has already been added to a chain? */
+ if (stop)
+ continue;
+
+ /* add current bone to a new chain */
+ ld = MEM_callocN(sizeof(LinkData), "BoneChain");
+ ld->data = curBone;
+ BLI_addtail(list, ld);
+ }
}
/* --------------------- */
static void fill_add_joint(EditBone *ebo, short eb_tail, ListBase *points)
{
- EditBonePoint *ebp;
- float vec[3];
- short found = 0;
-
- if (eb_tail) {
- copy_v3_v3(vec, ebo->tail);
- }
- else {
- copy_v3_v3(vec, ebo->head);
- }
-
- for (ebp = points->first; ebp; ebp = ebp->next) {
- if (equals_v3v3(ebp->vec, vec)) {
- if (eb_tail) {
- if ((ebp->head_owner) && (ebp->head_owner->parent == ebo)) {
- /* so this bone's tail owner is this bone */
- ebp->tail_owner = ebo;
- found = 1;
- break;
- }
- }
- else {
- if ((ebp->tail_owner) && (ebo->parent == ebp->tail_owner)) {
- /* so this bone's head owner is this bone */
- ebp->head_owner = ebo;
- found = 1;
- break;
- }
- }
- }
- }
-
- /* allocate a new point if no existing point was related */
- if (found == 0) {
- ebp = MEM_callocN(sizeof(EditBonePoint), "EditBonePoint");
-
- if (eb_tail) {
- copy_v3_v3(ebp->vec, ebo->tail);
- ebp->tail_owner = ebo;
- }
- else {
- copy_v3_v3(ebp->vec, ebo->head);
- ebp->head_owner = ebo;
- }
-
- BLI_addtail(points, ebp);
- }
+ EditBonePoint *ebp;
+ float vec[3];
+ short found = 0;
+
+ if (eb_tail) {
+ copy_v3_v3(vec, ebo->tail);
+ }
+ else {
+ copy_v3_v3(vec, ebo->head);
+ }
+
+ for (ebp = points->first; ebp; ebp = ebp->next) {
+ if (equals_v3v3(ebp->vec, vec)) {
+ if (eb_tail) {
+ if ((ebp->head_owner) && (ebp->head_owner->parent == ebo)) {
+ /* so this bone's tail owner is this bone */
+ ebp->tail_owner = ebo;
+ found = 1;
+ break;
+ }
+ }
+ else {
+ if ((ebp->tail_owner) && (ebo->parent == ebp->tail_owner)) {
+ /* so this bone's head owner is this bone */
+ ebp->head_owner = ebo;
+ found = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ /* allocate a new point if no existing point was related */
+ if (found == 0) {
+ ebp = MEM_callocN(sizeof(EditBonePoint), "EditBonePoint");
+
+ if (eb_tail) {
+ copy_v3_v3(ebp->vec, ebo->tail);
+ ebp->tail_owner = ebo;
+ }
+ else {
+ copy_v3_v3(ebp->vec, ebo->head);
+ ebp->head_owner = ebo;
+ }
+
+ BLI_addtail(points, ebp);
+ }
}
/* bone adding between selected joints */
static int armature_fill_bones_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- ListBase points = {NULL, NULL};
- EditBone *newbone = NULL;
- int count;
- bool mixed_object_error = false;
-
- /* loop over all bones, and only consider if visible */
- bArmature *arm = NULL;
- CTX_DATA_BEGIN_WITH_ID(C, EditBone *, ebone, visible_bones, bArmature *, arm_iter)
- {
- bool check = false;
- if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL)) {
- fill_add_joint(ebone, 0, &points);
- check = true;
- }
- if (ebone->flag & BONE_TIPSEL) {
- fill_add_joint(ebone, 1, &points);
- check = true;
- }
-
- if (check) {
- if (arm && (arm != arm_iter)) {
- mixed_object_error = true;
- }
- arm = arm_iter;
- }
- }
- CTX_DATA_END;
-
- /* the number of joints determines how we fill:
- * 1) between joint and cursor (joint=head, cursor=tail)
- * 2) between the two joints (order is dependent on active-bone/hierarchy)
- * 3+) error (a smarter method involving finding chains needs to be worked out
- */
- count = BLI_listbase_count(&points);
-
- if (count == 0) {
- BKE_report(op->reports, RPT_ERROR, "No joints selected");
- return OPERATOR_CANCELLED;
- }
- else if (mixed_object_error) {
- BKE_report(op->reports, RPT_ERROR, "Bones for different objects selected");
- BLI_freelistN(&points);
- return OPERATOR_CANCELLED;
- }
-
- Object *obedit = NULL;
- {
- ViewLayer *view_layer = CTX_data_view_layer(C);
- FOREACH_OBJECT_IN_EDIT_MODE_BEGIN (view_layer, v3d, ob_iter) {
- if (ob_iter->data == arm) {
- obedit = ob_iter;
- }
- }
- FOREACH_OBJECT_IN_MODE_END;
- }
- BLI_assert(obedit != NULL);
-
- if (count == 1) {
- EditBonePoint *ebp;
- float curs[3];
-
- /* Get Points - selected joint */
- ebp = points.first;
-
- /* Get points - cursor (tail) */
- invert_m4_m4(obedit->imat, obedit->obmat);
- mul_v3_m4v3(curs, obedit->imat, scene->cursor.location);
-
- /* Create a bone */
- newbone = add_points_bone(obedit, ebp->vec, curs);
- }
- else if (count == 2) {
- EditBonePoint *ebp_a, *ebp_b;
- float head[3], tail[3];
- short headtail = 0;
-
- /* check that the points don't belong to the same bone */
- ebp_a = (EditBonePoint *)points.first;
- ebp_b = ebp_a->next;
-
- if (((ebp_a->head_owner == ebp_b->tail_owner) && (ebp_a->head_owner != NULL)) ||
- ((ebp_a->tail_owner == ebp_b->head_owner) && (ebp_a->tail_owner != NULL)))
- {
- BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
- BLI_freelistN(&points);
- return OPERATOR_CANCELLED;
- }
-
- /* find which one should be the 'head' */
- if ((ebp_a->head_owner && ebp_b->head_owner) || (ebp_a->tail_owner && ebp_b->tail_owner)) {
- /* use active, nice predictable */
- if (arm->act_edbone && ELEM(arm->act_edbone, ebp_a->head_owner, ebp_a->tail_owner)) {
- headtail = 1;
- }
- else if (arm->act_edbone && ELEM(arm->act_edbone, ebp_b->head_owner, ebp_b->tail_owner)) {
- headtail = 2;
- }
- else {
- /* rule: whichever one is closer to 3d-cursor */
- float curs[3];
- float dist_sq_a, dist_sq_b;
-
- /* get cursor location */
- invert_m4_m4(obedit->imat, obedit->obmat);
- mul_v3_m4v3(curs, obedit->imat, scene->cursor.location);
-
- /* get distances */
- dist_sq_a = len_squared_v3v3(ebp_a->vec, curs);
- dist_sq_b = len_squared_v3v3(ebp_b->vec, curs);
-
- /* compare distances - closer one therefore acts as direction for bone to go */
- headtail = (dist_sq_a < dist_sq_b) ? 2 : 1;
- }
- }
- else if (ebp_a->head_owner) {
- headtail = 1;
- }
- else if (ebp_b->head_owner) {
- headtail = 2;
- }
-
- /* assign head/tail combinations */
- if (headtail == 2) {
- copy_v3_v3(head, ebp_a->vec);
- copy_v3_v3(tail, ebp_b->vec);
- }
- else if (headtail == 1) {
- copy_v3_v3(head, ebp_b->vec);
- copy_v3_v3(tail, ebp_a->vec);
- }
-
- /* add new bone and parent it to the appropriate end */
- if (headtail) {
- newbone = add_points_bone(obedit, head, tail);
-
- /* do parenting (will need to set connected flag too) */
- if (headtail == 2) {
- /* ebp tail or head - tail gets priority */
- if (ebp_a->tail_owner)
- newbone->parent = ebp_a->tail_owner;
- else
- newbone->parent = ebp_a->head_owner;
- }
- else {
- /* ebp_b tail or head - tail gets priority */
- if (ebp_b->tail_owner)
- newbone->parent = ebp_b->tail_owner;
- else
- newbone->parent = ebp_b->head_owner;
- }
-
- /* don't set for bone connecting two head points of bones */
- if (ebp_a->tail_owner || ebp_b->tail_owner) {
- newbone->flag |= BONE_CONNECTED;
- }
- }
- }
- else {
- BKE_reportf(op->reports, RPT_ERROR, "Too many points selected: %d", count);
- BLI_freelistN(&points);
- return OPERATOR_CANCELLED;
- }
-
- if (newbone) {
- ED_armature_edit_deselect_all(obedit);
- arm->act_edbone = newbone;
- newbone->flag |= BONE_TIPSEL;
- }
-
- /* updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
-
- /* free points */
- BLI_freelistN(&points);
-
- return OPERATOR_FINISHED;
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ ListBase points = {NULL, NULL};
+ EditBone *newbone = NULL;
+ int count;
+ bool mixed_object_error = false;
+
+ /* loop over all bones, and only consider if visible */
+ bArmature *arm = NULL;
+ CTX_DATA_BEGIN_WITH_ID(C, EditBone *, ebone, visible_bones, bArmature *, arm_iter)
+ {
+ bool check = false;
+ if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL)) {
+ fill_add_joint(ebone, 0, &points);
+ check = true;
+ }
+ if (ebone->flag & BONE_TIPSEL) {
+ fill_add_joint(ebone, 1, &points);
+ check = true;
+ }
+
+ if (check) {
+ if (arm && (arm != arm_iter)) {
+ mixed_object_error = true;
+ }
+ arm = arm_iter;
+ }
+ }
+ CTX_DATA_END;
+
+ /* the number of joints determines how we fill:
+ * 1) between joint and cursor (joint=head, cursor=tail)
+ * 2) between the two joints (order is dependent on active-bone/hierarchy)
+ * 3+) error (a smarter method involving finding chains needs to be worked out
+ */
+ count = BLI_listbase_count(&points);
+
+ if (count == 0) {
+ BKE_report(op->reports, RPT_ERROR, "No joints selected");
+ return OPERATOR_CANCELLED;
+ }
+ else if (mixed_object_error) {
+ BKE_report(op->reports, RPT_ERROR, "Bones for different objects selected");
+ BLI_freelistN(&points);
+ return OPERATOR_CANCELLED;
+ }
+
+ Object *obedit = NULL;
+ {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ FOREACH_OBJECT_IN_EDIT_MODE_BEGIN (view_layer, v3d, ob_iter) {
+ if (ob_iter->data == arm) {
+ obedit = ob_iter;
+ }
+ }
+ FOREACH_OBJECT_IN_MODE_END;
+ }
+ BLI_assert(obedit != NULL);
+
+ if (count == 1) {
+ EditBonePoint *ebp;
+ float curs[3];
+
+ /* Get Points - selected joint */
+ ebp = points.first;
+
+ /* Get points - cursor (tail) */
+ invert_m4_m4(obedit->imat, obedit->obmat);
+ mul_v3_m4v3(curs, obedit->imat, scene->cursor.location);
+
+ /* Create a bone */
+ newbone = add_points_bone(obedit, ebp->vec, curs);
+ }
+ else if (count == 2) {
+ EditBonePoint *ebp_a, *ebp_b;
+ float head[3], tail[3];
+ short headtail = 0;
+
+ /* check that the points don't belong to the same bone */
+ ebp_a = (EditBonePoint *)points.first;
+ ebp_b = ebp_a->next;
+
+ if (((ebp_a->head_owner == ebp_b->tail_owner) && (ebp_a->head_owner != NULL)) ||
+ ((ebp_a->tail_owner == ebp_b->head_owner) && (ebp_a->tail_owner != NULL))) {
+ BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
+ BLI_freelistN(&points);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* find which one should be the 'head' */
+ if ((ebp_a->head_owner && ebp_b->head_owner) || (ebp_a->tail_owner && ebp_b->tail_owner)) {
+ /* use active, nice predictable */
+ if (arm->act_edbone && ELEM(arm->act_edbone, ebp_a->head_owner, ebp_a->tail_owner)) {
+ headtail = 1;
+ }
+ else if (arm->act_edbone && ELEM(arm->act_edbone, ebp_b->head_owner, ebp_b->tail_owner)) {
+ headtail = 2;
+ }
+ else {
+ /* rule: whichever one is closer to 3d-cursor */
+ float curs[3];
+ float dist_sq_a, dist_sq_b;
+
+ /* get cursor location */
+ invert_m4_m4(obedit->imat, obedit->obmat);
+ mul_v3_m4v3(curs, obedit->imat, scene->cursor.location);
+
+ /* get distances */
+ dist_sq_a = len_squared_v3v3(ebp_a->vec, curs);
+ dist_sq_b = len_squared_v3v3(ebp_b->vec, curs);
+
+ /* compare distances - closer one therefore acts as direction for bone to go */
+ headtail = (dist_sq_a < dist_sq_b) ? 2 : 1;
+ }
+ }
+ else if (ebp_a->head_owner) {
+ headtail = 1;
+ }
+ else if (ebp_b->head_owner) {
+ headtail = 2;
+ }
+
+ /* assign head/tail combinations */
+ if (headtail == 2) {
+ copy_v3_v3(head, ebp_a->vec);
+ copy_v3_v3(tail, ebp_b->vec);
+ }
+ else if (headtail == 1) {
+ copy_v3_v3(head, ebp_b->vec);
+ copy_v3_v3(tail, ebp_a->vec);
+ }
+
+ /* add new bone and parent it to the appropriate end */
+ if (headtail) {
+ newbone = add_points_bone(obedit, head, tail);
+
+ /* do parenting (will need to set connected flag too) */
+ if (headtail == 2) {
+ /* ebp tail or head - tail gets priority */
+ if (ebp_a->tail_owner)
+ newbone->parent = ebp_a->tail_owner;
+ else
+ newbone->parent = ebp_a->head_owner;
+ }
+ else {
+ /* ebp_b tail or head - tail gets priority */
+ if (ebp_b->tail_owner)
+ newbone->parent = ebp_b->tail_owner;
+ else
+ newbone->parent = ebp_b->head_owner;
+ }
+
+ /* don't set for bone connecting two head points of bones */
+ if (ebp_a->tail_owner || ebp_b->tail_owner) {
+ newbone->flag |= BONE_CONNECTED;
+ }
+ }
+ }
+ else {
+ BKE_reportf(op->reports, RPT_ERROR, "Too many points selected: %d", count);
+ BLI_freelistN(&points);
+ return OPERATOR_CANCELLED;
+ }
+
+ if (newbone) {
+ ED_armature_edit_deselect_all(obedit);
+ arm->act_edbone = newbone;
+ newbone->flag |= BONE_TIPSEL;
+ }
+
+ /* updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
+
+ /* free points */
+ BLI_freelistN(&points);
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_fill(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Fill Between Joints";
- ot->idname = "ARMATURE_OT_fill";
- ot->description = "Add bone between selected joint(s) and/or 3D-Cursor";
+ /* identifiers */
+ ot->name = "Fill Between Joints";
+ ot->idname = "ARMATURE_OT_fill";
+ ot->description = "Add bone between selected joint(s) and/or 3D-Cursor";
- /* callbacks */
- ot->exec = armature_fill_bones_exec;
- ot->poll = ED_operator_editarmature;
+ /* callbacks */
+ ot->exec = armature_fill_bones_exec;
+ ot->poll = ED_operator_editarmature;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* --------------------- */
@@ -852,194 +878,193 @@ void ARMATURE_OT_fill(wmOperatorType *ot)
/* this function merges between two bones, removes them and those in-between,
* and adjusts the parent relationships for those in-between
*/
-static void bones_merge(Object *obedit, EditBone *start, EditBone *end, EditBone *endchild, ListBase *chains)
+static void bones_merge(
+ Object *obedit, EditBone *start, EditBone *end, EditBone *endchild, ListBase *chains)
{
- bArmature *arm = obedit->data;
- EditBone *ebo, *ebone, *newbone;
- LinkData *chain;
- float head[3], tail[3];
-
- /* check if same bone */
- if (start == end) {
- if (G.debug & G_DEBUG) {
- printf("Error: same bone!\n");
- printf("\tstart = %s, end = %s\n", start->name, end->name);
- }
- }
-
- /* step 1: add a new bone
- * - head = head/tail of start (default head)
- * - tail = head/tail of end (default tail)
- * - parent = parent of start
- */
- if ((start->flag & BONE_TIPSEL) && (start->flag & BONE_SELECTED) == 0) {
- copy_v3_v3(head, start->tail);
- }
- else {
- copy_v3_v3(head, start->head);
- }
- if ((end->flag & BONE_ROOTSEL) && (end->flag & BONE_SELECTED) == 0) {
- copy_v3_v3(tail, end->head);
- }
- else {
- copy_v3_v3(tail, end->tail);
- }
- newbone = add_points_bone(obedit, head, tail);
- newbone->parent = start->parent;
-
- /* TODO, copy more things to the new bone */
- newbone->flag = start->flag & (BONE_HINGE | BONE_NO_DEFORM | BONE_NO_SCALE |
- BONE_NO_CYCLICOFFSET | BONE_NO_LOCAL_LOCATION | BONE_DONE);
-
- /* step 2a: reparent any side chains which may be parented to any bone in the chain of bones to merge
- * - potentially several tips for side chains leading to some tree exist...
- */
- for (chain = chains->first; chain; chain = chain->next) {
- /* traverse down chain until we hit the bottom or if we run into the tip of the chain of bones we're
- * merging (need to stop in this case to avoid corrupting this chain too!)
- */
- for (ebone = chain->data; (ebone) && (ebone != end); ebone = ebone->parent) {
- short found = 0;
-
- /* check if this bone is parented to one in the merging chain
- * ! WATCHIT: must only go check until end of checking chain
- */
- for (ebo = end; (ebo) && (ebo != start->parent); ebo = ebo->parent) {
- /* side-chain found? --> remap parent to new bone, then we're done with this chain :) */
- if (ebone->parent == ebo) {
- ebone->parent = newbone;
- found = 1;
- break;
- }
- }
-
- /* carry on to the next tip now */
- if (found)
- break;
- }
- }
-
- /* step 2b: parent child of end to newbone (child from this chain) */
- if (endchild)
- endchild->parent = newbone;
-
- /* step 3: delete all bones between and including start and end */
- for (ebo = end; ebo; ebo = ebone) {
- ebone = (ebo == start) ? (NULL) : (ebo->parent);
- bone_free(arm, ebo);
- }
-
- newbone->flag |= (BONE_ROOTSEL | BONE_TIPSEL | BONE_SELECTED);
- ED_armature_edit_sync_selection(arm->edbo);
+ bArmature *arm = obedit->data;
+ EditBone *ebo, *ebone, *newbone;
+ LinkData *chain;
+ float head[3], tail[3];
+
+ /* check if same bone */
+ if (start == end) {
+ if (G.debug & G_DEBUG) {
+ printf("Error: same bone!\n");
+ printf("\tstart = %s, end = %s\n", start->name, end->name);
+ }
+ }
+
+ /* step 1: add a new bone
+ * - head = head/tail of start (default head)
+ * - tail = head/tail of end (default tail)
+ * - parent = parent of start
+ */
+ if ((start->flag & BONE_TIPSEL) && (start->flag & BONE_SELECTED) == 0) {
+ copy_v3_v3(head, start->tail);
+ }
+ else {
+ copy_v3_v3(head, start->head);
+ }
+ if ((end->flag & BONE_ROOTSEL) && (end->flag & BONE_SELECTED) == 0) {
+ copy_v3_v3(tail, end->head);
+ }
+ else {
+ copy_v3_v3(tail, end->tail);
+ }
+ newbone = add_points_bone(obedit, head, tail);
+ newbone->parent = start->parent;
+
+ /* TODO, copy more things to the new bone */
+ newbone->flag = start->flag & (BONE_HINGE | BONE_NO_DEFORM | BONE_NO_SCALE |
+ BONE_NO_CYCLICOFFSET | BONE_NO_LOCAL_LOCATION | BONE_DONE);
+
+ /* step 2a: reparent any side chains which may be parented to any bone in the chain of bones to merge
+ * - potentially several tips for side chains leading to some tree exist...
+ */
+ for (chain = chains->first; chain; chain = chain->next) {
+ /* traverse down chain until we hit the bottom or if we run into the tip of the chain of bones we're
+ * merging (need to stop in this case to avoid corrupting this chain too!)
+ */
+ for (ebone = chain->data; (ebone) && (ebone != end); ebone = ebone->parent) {
+ short found = 0;
+
+ /* check if this bone is parented to one in the merging chain
+ * ! WATCHIT: must only go check until end of checking chain
+ */
+ for (ebo = end; (ebo) && (ebo != start->parent); ebo = ebo->parent) {
+ /* side-chain found? --> remap parent to new bone, then we're done with this chain :) */
+ if (ebone->parent == ebo) {
+ ebone->parent = newbone;
+ found = 1;
+ break;
+ }
+ }
+
+ /* carry on to the next tip now */
+ if (found)
+ break;
+ }
+ }
+
+ /* step 2b: parent child of end to newbone (child from this chain) */
+ if (endchild)
+ endchild->parent = newbone;
+
+ /* step 3: delete all bones between and including start and end */
+ for (ebo = end; ebo; ebo = ebone) {
+ ebone = (ebo == start) ? (NULL) : (ebo->parent);
+ bone_free(arm, ebo);
+ }
+
+ newbone->flag |= (BONE_ROOTSEL | BONE_TIPSEL | BONE_SELECTED);
+ ED_armature_edit_sync_selection(arm->edbo);
}
-
static int armature_merge_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const short type = RNA_enum_get(op->ptr, "type");
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- bArmature *arm = obedit->data;
-
- /* for now, there's only really one type of merging that's performed... */
- if (type == 1) {
- /* go down chains, merging bones */
- ListBase chains = {NULL, NULL};
- LinkData *chain, *nchain;
- EditBone *ebo;
-
- armature_tag_select_mirrored(arm);
-
- /* get chains (ends on chains) */
- chains_find_tips(arm->edbo, &chains);
- if (BLI_listbase_is_empty(&chains)) {
- continue;
- }
-
- /* each 'chain' is the last bone in the chain (with no children) */
- for (chain = chains.first; chain; chain = nchain) {
- EditBone *bstart = NULL, *bend = NULL;
- EditBone *bchild = NULL, *child = NULL;
-
- /* temporarily remove chain from list of chains */
- nchain = chain->next;
- BLI_remlink(&chains, chain);
-
- /* only consider bones that are visible and selected */
- for (ebo = chain->data; ebo; child = ebo, ebo = ebo->parent) {
- /* check if visible + selected */
- if (EBONE_VISIBLE(arm, ebo) &&
- ((ebo->flag & BONE_CONNECTED) || (ebo->parent == NULL)) &&
- (ebo->flag & BONE_SELECTED) )
- {
- /* set either end or start (end gets priority, unless it is already set) */
- if (bend == NULL) {
- bend = ebo;
- bchild = child;
- }
- else
- bstart = ebo;
- }
- else {
- /* chain is broken... merge any continuous segments then clear */
- if (bstart && bend)
- bones_merge(obedit, bstart, bend, bchild, &chains);
-
- bstart = NULL;
- bend = NULL;
- bchild = NULL;
- }
- }
-
- /* merge from bstart to bend if something not merged */
- if (bstart && bend)
- bones_merge(obedit, bstart, bend, bchild, &chains);
-
- /* put back link */
- BLI_insertlinkbefore(&chains, nchain, chain);
- }
-
- armature_tag_unselect(arm);
-
- BLI_freelistN(&chains);
- }
-
- /* updates */
- ED_armature_edit_sync_selection(arm->edbo);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const short type = RNA_enum_get(op->ptr, "type");
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
+
+ /* for now, there's only really one type of merging that's performed... */
+ if (type == 1) {
+ /* go down chains, merging bones */
+ ListBase chains = {NULL, NULL};
+ LinkData *chain, *nchain;
+ EditBone *ebo;
+
+ armature_tag_select_mirrored(arm);
+
+ /* get chains (ends on chains) */
+ chains_find_tips(arm->edbo, &chains);
+ if (BLI_listbase_is_empty(&chains)) {
+ continue;
+ }
+
+ /* each 'chain' is the last bone in the chain (with no children) */
+ for (chain = chains.first; chain; chain = nchain) {
+ EditBone *bstart = NULL, *bend = NULL;
+ EditBone *bchild = NULL, *child = NULL;
+
+ /* temporarily remove chain from list of chains */
+ nchain = chain->next;
+ BLI_remlink(&chains, chain);
+
+ /* only consider bones that are visible and selected */
+ for (ebo = chain->data; ebo; child = ebo, ebo = ebo->parent) {
+ /* check if visible + selected */
+ if (EBONE_VISIBLE(arm, ebo) && ((ebo->flag & BONE_CONNECTED) || (ebo->parent == NULL)) &&
+ (ebo->flag & BONE_SELECTED)) {
+ /* set either end or start (end gets priority, unless it is already set) */
+ if (bend == NULL) {
+ bend = ebo;
+ bchild = child;
+ }
+ else
+ bstart = ebo;
+ }
+ else {
+ /* chain is broken... merge any continuous segments then clear */
+ if (bstart && bend)
+ bones_merge(obedit, bstart, bend, bchild, &chains);
+
+ bstart = NULL;
+ bend = NULL;
+ bchild = NULL;
+ }
+ }
+
+ /* merge from bstart to bend if something not merged */
+ if (bstart && bend)
+ bones_merge(obedit, bstart, bend, bchild, &chains);
+
+ /* put back link */
+ BLI_insertlinkbefore(&chains, nchain, chain);
+ }
+
+ armature_tag_unselect(arm);
+
+ BLI_freelistN(&chains);
+ }
+
+ /* updates */
+ ED_armature_edit_sync_selection(arm->edbo);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
+ }
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_merge(wmOperatorType *ot)
{
- static const EnumPropertyItem merge_types[] = {
- {1, "WITHIN_CHAIN", 0, "Within Chains", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Merge Bones";
- ot->idname = "ARMATURE_OT_merge";
- ot->description = "Merge continuous chains of selected bones";
-
- /* callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = armature_merge_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", merge_types, 0, "Type", "");
+ static const EnumPropertyItem merge_types[] = {
+ {1, "WITHIN_CHAIN", 0, "Within Chains", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Merge Bones";
+ ot->idname = "ARMATURE_OT_merge";
+ ot->description = "Merge continuous chains of selected bones";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = armature_merge_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", merge_types, 0, "Type", "");
}
/* --------------------- */
@@ -1053,125 +1078,126 @@ void ARMATURE_OT_merge(wmOperatorType *ot)
/* helper to clear BONE_TRANSFORM flags */
static void armature_clear_swap_done_flags(bArmature *arm)
{
- EditBone *ebone;
+ EditBone *ebone;
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- ebone->flag &= ~BONE_TRANSFORM;
- }
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ ebone->flag &= ~BONE_TRANSFORM;
+ }
}
static int armature_switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- bArmature *arm = ob->data;
-
- ListBase chains = {NULL, NULL};
- LinkData *chain;
-
- /* get chains of bones (ends on chains) */
- chains_find_tips(arm->edbo, &chains);
- if (BLI_listbase_is_empty(&chains)) {
- continue;
- }
-
- /* ensure that mirror bones will also be operated on */
- armature_tag_select_mirrored(arm);
-
- /* clear BONE_TRANSFORM flags
- * - used to prevent duplicate/canceling operations from occurring [#34123]
- * - BONE_DONE cannot be used here as that's already used for mirroring
- */
- armature_clear_swap_done_flags(arm);
-
- /* loop over chains, only considering selected and visible bones */
- for (chain = chains.first; chain; chain = chain->next) {
- EditBone *ebo, *child = NULL, *parent = NULL;
-
- /* loop over bones in chain */
- for (ebo = chain->data; ebo; ebo = parent) {
- /* parent is this bone's original parent
- * - we store this, as the next bone that is checked is this one
- * but the value of ebo->parent may change here...
- */
- parent = ebo->parent;
-
- /* skip bone if already handled... [#34123] */
- if ((ebo->flag & BONE_TRANSFORM) == 0) {
- /* only if selected and editable */
- if (EBONE_VISIBLE(arm, ebo) && EBONE_EDITABLE(ebo)) {
- /* swap head and tail coordinates */
- swap_v3_v3(ebo->head, ebo->tail);
-
- /* do parent swapping:
- * - use 'child' as new parent
- * - connected flag is only set if points are coincidental
- */
- ebo->parent = child;
- if ((child) && equals_v3v3(ebo->head, child->tail))
- ebo->flag |= BONE_CONNECTED;
- else
- ebo->flag &= ~BONE_CONNECTED;
-
- /* get next bones
- * - child will become the new parent of next bone
- */
- child = ebo;
- }
- else {
- /* not swapping this bone, however, if its 'parent' got swapped, unparent us from it
- * as it will be facing in opposite direction
- */
- if ((parent) && (EBONE_VISIBLE(arm, parent) && EBONE_EDITABLE(parent))) {
- ebo->parent = NULL;
- ebo->flag &= ~BONE_CONNECTED;
- }
-
- /* get next bones
- * - child will become new parent of next bone (not swapping occurred,
- * so set to NULL to prevent infinite-loop)
- */
- child = NULL;
- }
-
- /* tag as done (to prevent double-swaps) */
- ebo->flag |= BONE_TRANSFORM;
- }
- }
- }
-
- /* free chains */
- BLI_freelistN(&chains);
-
- /* clear temp flags */
- armature_clear_swap_done_flags(arm);
- armature_tag_unselect(arm);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+
+ ListBase chains = {NULL, NULL};
+ LinkData *chain;
+
+ /* get chains of bones (ends on chains) */
+ chains_find_tips(arm->edbo, &chains);
+ if (BLI_listbase_is_empty(&chains)) {
+ continue;
+ }
+
+ /* ensure that mirror bones will also be operated on */
+ armature_tag_select_mirrored(arm);
+
+ /* clear BONE_TRANSFORM flags
+ * - used to prevent duplicate/canceling operations from occurring [#34123]
+ * - BONE_DONE cannot be used here as that's already used for mirroring
+ */
+ armature_clear_swap_done_flags(arm);
+
+ /* loop over chains, only considering selected and visible bones */
+ for (chain = chains.first; chain; chain = chain->next) {
+ EditBone *ebo, *child = NULL, *parent = NULL;
+
+ /* loop over bones in chain */
+ for (ebo = chain->data; ebo; ebo = parent) {
+ /* parent is this bone's original parent
+ * - we store this, as the next bone that is checked is this one
+ * but the value of ebo->parent may change here...
+ */
+ parent = ebo->parent;
+
+ /* skip bone if already handled... [#34123] */
+ if ((ebo->flag & BONE_TRANSFORM) == 0) {
+ /* only if selected and editable */
+ if (EBONE_VISIBLE(arm, ebo) && EBONE_EDITABLE(ebo)) {
+ /* swap head and tail coordinates */
+ swap_v3_v3(ebo->head, ebo->tail);
+
+ /* do parent swapping:
+ * - use 'child' as new parent
+ * - connected flag is only set if points are coincidental
+ */
+ ebo->parent = child;
+ if ((child) && equals_v3v3(ebo->head, child->tail))
+ ebo->flag |= BONE_CONNECTED;
+ else
+ ebo->flag &= ~BONE_CONNECTED;
+
+ /* get next bones
+ * - child will become the new parent of next bone
+ */
+ child = ebo;
+ }
+ else {
+ /* not swapping this bone, however, if its 'parent' got swapped, unparent us from it
+ * as it will be facing in opposite direction
+ */
+ if ((parent) && (EBONE_VISIBLE(arm, parent) && EBONE_EDITABLE(parent))) {
+ ebo->parent = NULL;
+ ebo->flag &= ~BONE_CONNECTED;
+ }
+
+ /* get next bones
+ * - child will become new parent of next bone (not swapping occurred,
+ * so set to NULL to prevent infinite-loop)
+ */
+ child = NULL;
+ }
+
+ /* tag as done (to prevent double-swaps) */
+ ebo->flag |= BONE_TRANSFORM;
+ }
+ }
+ }
+
+ /* free chains */
+ BLI_freelistN(&chains);
+
+ /* clear temp flags */
+ armature_clear_swap_done_flags(arm);
+ armature_tag_unselect(arm);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_switch_direction(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Switch Direction";
- ot->idname = "ARMATURE_OT_switch_direction";
- ot->description = "Change the direction that a chain of bones points in (head <-> tail swap)";
+ /* identifiers */
+ ot->name = "Switch Direction";
+ ot->idname = "ARMATURE_OT_switch_direction";
+ ot->description = "Change the direction that a chain of bones points in (head <-> tail swap)";
- /* api callbacks */
- ot->exec = armature_switch_direction_exec;
- ot->poll = ED_operator_editarmature;
+ /* api callbacks */
+ ot->exec = armature_switch_direction_exec;
+ ot->poll = ED_operator_editarmature;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ********************************* Align ******************************* */
@@ -1179,538 +1205,544 @@ void ARMATURE_OT_switch_direction(wmOperatorType *ot)
/* helper to fix a ebone position if its parent has moved due to alignment*/
static void fix_connected_bone(EditBone *ebone)
{
- float diff[3];
+ float diff[3];
- if (!(ebone->parent) || !(ebone->flag & BONE_CONNECTED) || equals_v3v3(ebone->parent->tail, ebone->head))
- return;
+ if (!(ebone->parent) || !(ebone->flag & BONE_CONNECTED) ||
+ equals_v3v3(ebone->parent->tail, ebone->head))
+ return;
- /* if the parent has moved we translate child's head and tail accordingly */
- sub_v3_v3v3(diff, ebone->parent->tail, ebone->head);
- add_v3_v3(ebone->head, diff);
- add_v3_v3(ebone->tail, diff);
+ /* if the parent has moved we translate child's head and tail accordingly */
+ sub_v3_v3v3(diff, ebone->parent->tail, ebone->head);
+ add_v3_v3(ebone->head, diff);
+ add_v3_v3(ebone->tail, diff);
}
/* helper to recursively find chains of connected bones starting at ebone and fix their position */
static void fix_editbone_connected_children(ListBase *edbo, EditBone *ebone)
{
- EditBone *selbone;
-
- for (selbone = edbo->first; selbone; selbone = selbone->next) {
- if ((selbone->parent) && (selbone->parent == ebone) && (selbone->flag & BONE_CONNECTED)) {
- fix_connected_bone(selbone);
- fix_editbone_connected_children(edbo, selbone);
- }
- }
+ EditBone *selbone;
+
+ for (selbone = edbo->first; selbone; selbone = selbone->next) {
+ if ((selbone->parent) && (selbone->parent == ebone) && (selbone->flag & BONE_CONNECTED)) {
+ fix_connected_bone(selbone);
+ fix_editbone_connected_children(edbo, selbone);
+ }
+ }
}
static void bone_align_to_bone(ListBase *edbo, EditBone *selbone, EditBone *actbone)
{
- float selboneaxis[3], actboneaxis[3], length;
+ float selboneaxis[3], actboneaxis[3], length;
- sub_v3_v3v3(actboneaxis, actbone->tail, actbone->head);
- normalize_v3(actboneaxis);
+ sub_v3_v3v3(actboneaxis, actbone->tail, actbone->head);
+ normalize_v3(actboneaxis);
- sub_v3_v3v3(selboneaxis, selbone->tail, selbone->head);
- length = len_v3(selboneaxis);
+ sub_v3_v3v3(selboneaxis, selbone->tail, selbone->head);
+ length = len_v3(selboneaxis);
- mul_v3_fl(actboneaxis, length);
- add_v3_v3v3(selbone->tail, selbone->head, actboneaxis);
- selbone->roll = actbone->roll;
+ mul_v3_fl(actboneaxis, length);
+ add_v3_v3v3(selbone->tail, selbone->head, actboneaxis);
+ selbone->roll = actbone->roll;
- /* if the bone being aligned has connected descendants they must be moved
- * according to their parent new position, otherwise they would be left
- * in an inconsistent state: connected but away from the parent*/
- fix_editbone_connected_children(edbo, selbone);
+ /* if the bone being aligned has connected descendants they must be moved
+ * according to their parent new position, otherwise they would be left
+ * in an inconsistent state: connected but away from the parent*/
+ fix_editbone_connected_children(edbo, selbone);
}
static int armature_align_bones_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_edit_object(C);
- bArmature *arm = (bArmature *)ob->data;
- EditBone *actbone = CTX_data_active_bone(C);
- EditBone *actmirb = NULL;
- int num_selected_bones;
-
- /* there must be an active bone */
- if (actbone == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
- return OPERATOR_CANCELLED;
- }
- else if (arm->flag & ARM_MIRROR_EDIT) {
- /* For X-Axis Mirror Editing option, we may need a mirror copy of actbone
- * - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone
- * (i.e. selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
- * This is useful for arm-chains, for example parenting lower arm to upper arm
- * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
- * then just use actbone. Useful when doing upper arm to spine.
- */
- actmirb = ED_armature_ebone_get_mirrored(arm->edbo, actbone);
- if (actmirb == NULL)
- actmirb = actbone;
- }
-
- /* if there is only 1 selected bone, we assume that that is the active bone,
- * since a user will need to have clicked on a bone (thus selecting it) to make it active
- */
- num_selected_bones = CTX_DATA_COUNT(C, selected_editable_bones);
- if (num_selected_bones <= 1) {
- /* When only the active bone is selected, and it has a parent,
- * align it to the parent, as that is the only possible outcome.
- */
- if (actbone->parent) {
- bone_align_to_bone(arm->edbo, actbone, actbone->parent);
-
- if ((arm->flag & ARM_MIRROR_EDIT) && (actmirb->parent))
- bone_align_to_bone(arm->edbo, actmirb, actmirb->parent);
-
- BKE_reportf(op->reports, RPT_INFO, "Aligned bone '%s' to parent", actbone->name);
- }
- }
- else {
- /* Align 'selected' bones to the active one
- * - the context iterator contains both selected bones and their mirrored copies,
- * so we assume that unselected bones are mirrored copies of some selected bone
- * - since the active one (and/or its mirror) will also be selected, we also need
- * to check that we are not trying to operate on them, since such an operation
- * would cause errors
- */
-
- /* align selected bones to the active one */
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
- {
- if (ELEM(ebone, actbone, actmirb) == 0) {
- if (ebone->flag & BONE_SELECTED)
- bone_align_to_bone(arm->edbo, ebone, actbone);
- else
- bone_align_to_bone(arm->edbo, ebone, actmirb);
- }
- }
- CTX_DATA_END;
-
- BKE_reportf(op->reports, RPT_INFO, "%d bones aligned to bone '%s'", num_selected_bones, actbone->name);
- }
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- return OPERATOR_FINISHED;
+ Object *ob = CTX_data_edit_object(C);
+ bArmature *arm = (bArmature *)ob->data;
+ EditBone *actbone = CTX_data_active_bone(C);
+ EditBone *actmirb = NULL;
+ int num_selected_bones;
+
+ /* there must be an active bone */
+ if (actbone == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
+ return OPERATOR_CANCELLED;
+ }
+ else if (arm->flag & ARM_MIRROR_EDIT) {
+ /* For X-Axis Mirror Editing option, we may need a mirror copy of actbone
+ * - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone
+ * (i.e. selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
+ * This is useful for arm-chains, for example parenting lower arm to upper arm
+ * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
+ * then just use actbone. Useful when doing upper arm to spine.
+ */
+ actmirb = ED_armature_ebone_get_mirrored(arm->edbo, actbone);
+ if (actmirb == NULL)
+ actmirb = actbone;
+ }
+
+ /* if there is only 1 selected bone, we assume that that is the active bone,
+ * since a user will need to have clicked on a bone (thus selecting it) to make it active
+ */
+ num_selected_bones = CTX_DATA_COUNT(C, selected_editable_bones);
+ if (num_selected_bones <= 1) {
+ /* When only the active bone is selected, and it has a parent,
+ * align it to the parent, as that is the only possible outcome.
+ */
+ if (actbone->parent) {
+ bone_align_to_bone(arm->edbo, actbone, actbone->parent);
+
+ if ((arm->flag & ARM_MIRROR_EDIT) && (actmirb->parent))
+ bone_align_to_bone(arm->edbo, actmirb, actmirb->parent);
+
+ BKE_reportf(op->reports, RPT_INFO, "Aligned bone '%s' to parent", actbone->name);
+ }
+ }
+ else {
+ /* Align 'selected' bones to the active one
+ * - the context iterator contains both selected bones and their mirrored copies,
+ * so we assume that unselected bones are mirrored copies of some selected bone
+ * - since the active one (and/or its mirror) will also be selected, we also need
+ * to check that we are not trying to operate on them, since such an operation
+ * would cause errors
+ */
+
+ /* align selected bones to the active one */
+ CTX_DATA_BEGIN (C, EditBone *, ebone, selected_editable_bones) {
+ if (ELEM(ebone, actbone, actmirb) == 0) {
+ if (ebone->flag & BONE_SELECTED)
+ bone_align_to_bone(arm->edbo, ebone, actbone);
+ else
+ bone_align_to_bone(arm->edbo, ebone, actmirb);
+ }
+ }
+ CTX_DATA_END;
+
+ BKE_reportf(
+ op->reports, RPT_INFO, "%d bones aligned to bone '%s'", num_selected_bones, actbone->name);
+ }
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_align(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Align Bones";
- ot->idname = "ARMATURE_OT_align";
- ot->description = "Align selected bones to the active bone (or to their parent)";
+ /* identifiers */
+ ot->name = "Align Bones";
+ ot->idname = "ARMATURE_OT_align";
+ ot->description = "Align selected bones to the active bone (or to their parent)";
- /* api callbacks */
- ot->exec = armature_align_bones_exec;
- ot->poll = ED_operator_editarmature;
+ /* api callbacks */
+ ot->exec = armature_align_bones_exec;
+ ot->poll = ED_operator_editarmature;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ********************************* Split ******************************* */
static int armature_split_exec(bContext *C, wmOperator *UNUSED(op))
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
- bArmature *arm = ob->data;
-
- for (EditBone *bone = arm->edbo->first; bone; bone = bone->next) {
- if (bone->parent && (bone->flag & BONE_SELECTED) != (bone->parent->flag & BONE_SELECTED)) {
- bone->parent = NULL;
- bone->flag &= ~BONE_CONNECTED;
- }
- }
- for (EditBone *bone = arm->edbo->first; bone; bone = bone->next) {
- ED_armature_ebone_select_set(bone, (bone->flag & BONE_SELECTED) != 0);
- }
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
- }
-
- MEM_freeN(objects);
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+
+ for (EditBone *bone = arm->edbo->first; bone; bone = bone->next) {
+ if (bone->parent && (bone->flag & BONE_SELECTED) != (bone->parent->flag & BONE_SELECTED)) {
+ bone->parent = NULL;
+ bone->flag &= ~BONE_CONNECTED;
+ }
+ }
+ for (EditBone *bone = arm->edbo->first; bone; bone = bone->next) {
+ ED_armature_ebone_select_set(bone, (bone->flag & BONE_SELECTED) != 0);
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+
+ MEM_freeN(objects);
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_split(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Split";
- ot->idname = "ARMATURE_OT_split";
- ot->description = "Split off selected bones from connected unselected bones";
+ /* identifiers */
+ ot->name = "Split";
+ ot->idname = "ARMATURE_OT_split";
+ ot->description = "Split off selected bones from connected unselected bones";
- /* api callbacks */
- ot->exec = armature_split_exec;
- ot->poll = ED_operator_editarmature;
+ /* api callbacks */
+ ot->exec = armature_split_exec;
+ ot->poll = ED_operator_editarmature;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ********************************* Delete ******************************* */
static bool armature_delete_ebone_cb(const char *bone_name, void *arm_p)
{
- bArmature *arm = arm_p;
- EditBone *ebone;
+ bArmature *arm = arm_p;
+ EditBone *ebone;
- ebone = ED_armature_ebone_find_name(arm->edbo, bone_name);
- return (ebone && (ebone->flag & BONE_SELECTED) && (arm->layer & ebone->layer));
+ ebone = ED_armature_ebone_find_name(arm->edbo, bone_name);
+ return (ebone && (ebone->flag & BONE_SELECTED) && (arm->layer & ebone->layer));
}
/* previously delete_armature */
/* only editmode! */
static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
{
- EditBone *curBone, *ebone_next;
- bool changed_multi = false;
-
- /* cancel if nothing selected */
- if (CTX_DATA_COUNT(C, selected_bones) == 0)
- return OPERATOR_CANCELLED;
-
- ViewLayer *view_layer = CTX_data_view_layer(C);
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- bArmature *arm = obedit->data;
- bool changed = false;
-
- armature_select_mirrored(arm);
-
- BKE_pose_channels_remove(obedit, armature_delete_ebone_cb, arm);
-
- for (curBone = arm->edbo->first; curBone; curBone = ebone_next) {
- ebone_next = curBone->next;
- if (arm->layer & curBone->layer) {
- if (curBone->flag & BONE_SELECTED) {
- if (curBone == arm->act_edbone) arm->act_edbone = NULL;
- ED_armature_ebone_remove(arm, curBone);
- changed = true;
- }
- }
- }
-
- if (changed) {
- changed_multi = true;
-
- ED_armature_edit_sync_selection(arm->edbo);
- BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
- }
- }
- MEM_freeN(objects);
-
- if (!changed_multi) {
- return OPERATOR_CANCELLED;
- }
-
- return OPERATOR_FINISHED;
+ EditBone *curBone, *ebone_next;
+ bool changed_multi = false;
+
+ /* cancel if nothing selected */
+ if (CTX_DATA_COUNT(C, selected_bones) == 0)
+ return OPERATOR_CANCELLED;
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
+ bool changed = false;
+
+ armature_select_mirrored(arm);
+
+ BKE_pose_channels_remove(obedit, armature_delete_ebone_cb, arm);
+
+ for (curBone = arm->edbo->first; curBone; curBone = ebone_next) {
+ ebone_next = curBone->next;
+ if (arm->layer & curBone->layer) {
+ if (curBone->flag & BONE_SELECTED) {
+ if (curBone == arm->act_edbone)
+ arm->act_edbone = NULL;
+ ED_armature_ebone_remove(arm, curBone);
+ changed = true;
+ }
+ }
+ }
+
+ if (changed) {
+ changed_multi = true;
+
+ ED_armature_edit_sync_selection(arm->edbo);
+ BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ }
+ }
+ MEM_freeN(objects);
+
+ if (!changed_multi) {
+ return OPERATOR_CANCELLED;
+ }
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_delete(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Delete Selected Bone(s)";
- ot->idname = "ARMATURE_OT_delete";
- ot->description = "Remove selected bones from the armature";
-
- /* api callbacks */
- ot->invoke = WM_operator_confirm;
- ot->exec = armature_delete_selected_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* identifiers */
+ ot->name = "Delete Selected Bone(s)";
+ ot->idname = "ARMATURE_OT_delete";
+ ot->description = "Remove selected bones from the armature";
+
+ /* api callbacks */
+ ot->invoke = WM_operator_confirm;
+ ot->exec = armature_delete_selected_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static bool armature_dissolve_ebone_cb(const char *bone_name, void *arm_p)
{
- bArmature *arm = arm_p;
- EditBone *ebone;
+ bArmature *arm = arm_p;
+ EditBone *ebone;
- ebone = ED_armature_ebone_find_name(arm->edbo, bone_name);
- return (ebone && (ebone->flag & BONE_DONE));
+ ebone = ED_armature_ebone_find_name(arm->edbo, bone_name);
+ return (ebone && (ebone->flag & BONE_DONE));
}
static int armature_dissolve_selected_exec(bContext *C, wmOperator *UNUSED(op))
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- EditBone *ebone, *ebone_next;
- bool changed_multi = false;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- bArmature *arm = obedit->data;
- bool changed = false;
-
- /* store for mirror */
- GHash *ebone_flag_orig = NULL;
- int ebone_num = 0;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- ebone->temp.p = NULL;
- ebone->flag &= ~BONE_DONE;
- ebone_num++;
- }
-
- if (arm->flag & ARM_MIRROR_EDIT) {
- GHashIterator gh_iter;
-
- ebone_flag_orig = BLI_ghash_ptr_new_ex(__func__, ebone_num);
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- union { int flag; void *p; } val = {0};
- val.flag = ebone->flag;
- BLI_ghash_insert(ebone_flag_orig, ebone, val.p);
- }
-
- armature_select_mirrored_ex(arm, BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
-
- GHASH_ITER (gh_iter, ebone_flag_orig) {
- union { int flag; void *p; } *val_p = (void *)BLI_ghashIterator_getValue_p(&gh_iter);
- ebone = BLI_ghashIterator_getKey(&gh_iter);
- val_p->flag = ebone->flag & ~val_p->flag;
- }
- }
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (ebone->parent && ebone->flag & BONE_CONNECTED) {
- if (ebone->parent->temp.ebone == ebone->parent) {
- /* ignore */
- }
- else if (ebone->parent->temp.ebone) {
- /* set ignored */
- ebone->parent->temp.ebone = ebone->parent;
- }
- else {
- /* set child */
- ebone->parent->temp.ebone = ebone;
- }
- }
- }
-
- /* cleanup multiple used bones */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (ebone->temp.ebone == ebone) {
- ebone->temp.ebone = NULL;
- }
- }
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- /* break connections for unseen bones */
- if (((arm->layer & ebone->layer) &&
- ((ED_armature_ebone_selectflag_get(ebone) & (BONE_TIPSEL | BONE_SELECTED)))) == 0)
- {
- ebone->temp.ebone = NULL;
- }
-
- if (((arm->layer & ebone->layer) &&
- ((ED_armature_ebone_selectflag_get(ebone) & (BONE_ROOTSEL | BONE_SELECTED)))) == 0)
- {
- if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
- ebone->parent->temp.ebone = NULL;
- }
-
- }
- }
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
-
- if (ebone->parent &&
- (ebone->parent->temp.ebone == ebone))
- {
- ebone->flag |= BONE_DONE;
- }
- }
-
- BKE_pose_channels_remove(obedit, armature_dissolve_ebone_cb, arm);
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone_next) {
- ebone_next = ebone->next;
-
- if (ebone->flag & BONE_DONE) {
- copy_v3_v3(ebone->parent->tail, ebone->tail);
- ebone->parent->rad_tail = ebone->rad_tail;
- SET_FLAG_FROM_TEST(ebone->parent->flag, ebone->flag & BONE_TIPSEL, BONE_TIPSEL);
-
- ED_armature_ebone_remove_ex(arm, ebone, false);
- changed = true;
- }
- }
-
- if (changed) {
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (ebone->parent &&
- ebone->parent->temp.ebone &&
- (ebone->flag & BONE_CONNECTED))
- {
- ebone->rad_head = ebone->parent->rad_tail;
- }
- }
-
- if (arm->flag & ARM_MIRROR_EDIT) {
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- union { int flag; void *p; } *val_p = (void *)BLI_ghash_lookup_p(ebone_flag_orig, ebone);
- if (val_p && val_p->flag) {
- ebone->flag &= ~val_p->flag;
- }
- }
- }
- }
-
- if (arm->flag & ARM_MIRROR_EDIT) {
- BLI_ghash_free(ebone_flag_orig, NULL, NULL);
- }
-
- if (changed) {
- changed_multi = true;
- ED_armature_edit_sync_selection(arm->edbo);
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
- }
- }
- MEM_freeN(objects);
-
- if (!changed_multi) {
- return OPERATOR_CANCELLED;
- }
-
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ EditBone *ebone, *ebone_next;
+ bool changed_multi = false;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
+ bool changed = false;
+
+ /* store for mirror */
+ GHash *ebone_flag_orig = NULL;
+ int ebone_num = 0;
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ ebone->temp.p = NULL;
+ ebone->flag &= ~BONE_DONE;
+ ebone_num++;
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ GHashIterator gh_iter;
+
+ ebone_flag_orig = BLI_ghash_ptr_new_ex(__func__, ebone_num);
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ union {
+ int flag;
+ void *p;
+ } val = {0};
+ val.flag = ebone->flag;
+ BLI_ghash_insert(ebone_flag_orig, ebone, val.p);
+ }
+
+ armature_select_mirrored_ex(arm, BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+
+ GHASH_ITER (gh_iter, ebone_flag_orig) {
+ union {
+ int flag;
+ void *p;
+ } *val_p = (void *)BLI_ghashIterator_getValue_p(&gh_iter);
+ ebone = BLI_ghashIterator_getKey(&gh_iter);
+ val_p->flag = ebone->flag & ~val_p->flag;
+ }
+ }
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->parent && ebone->flag & BONE_CONNECTED) {
+ if (ebone->parent->temp.ebone == ebone->parent) {
+ /* ignore */
+ }
+ else if (ebone->parent->temp.ebone) {
+ /* set ignored */
+ ebone->parent->temp.ebone = ebone->parent;
+ }
+ else {
+ /* set child */
+ ebone->parent->temp.ebone = ebone;
+ }
+ }
+ }
+
+ /* cleanup multiple used bones */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->temp.ebone == ebone) {
+ ebone->temp.ebone = NULL;
+ }
+ }
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ /* break connections for unseen bones */
+ if (((arm->layer & ebone->layer) &&
+ ((ED_armature_ebone_selectflag_get(ebone) & (BONE_TIPSEL | BONE_SELECTED)))) == 0) {
+ ebone->temp.ebone = NULL;
+ }
+
+ if (((arm->layer & ebone->layer) &&
+ ((ED_armature_ebone_selectflag_get(ebone) & (BONE_ROOTSEL | BONE_SELECTED)))) == 0) {
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ ebone->parent->temp.ebone = NULL;
+ }
+ }
+ }
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+
+ if (ebone->parent && (ebone->parent->temp.ebone == ebone)) {
+ ebone->flag |= BONE_DONE;
+ }
+ }
+
+ BKE_pose_channels_remove(obedit, armature_dissolve_ebone_cb, arm);
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone_next) {
+ ebone_next = ebone->next;
+
+ if (ebone->flag & BONE_DONE) {
+ copy_v3_v3(ebone->parent->tail, ebone->tail);
+ ebone->parent->rad_tail = ebone->rad_tail;
+ SET_FLAG_FROM_TEST(ebone->parent->flag, ebone->flag & BONE_TIPSEL, BONE_TIPSEL);
+
+ ED_armature_ebone_remove_ex(arm, ebone, false);
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->parent && ebone->parent->temp.ebone && (ebone->flag & BONE_CONNECTED)) {
+ ebone->rad_head = ebone->parent->rad_tail;
+ }
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ union {
+ int flag;
+ void *p;
+ } *val_p = (void *)BLI_ghash_lookup_p(ebone_flag_orig, ebone);
+ if (val_p && val_p->flag) {
+ ebone->flag &= ~val_p->flag;
+ }
+ }
+ }
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ BLI_ghash_free(ebone_flag_orig, NULL, NULL);
+ }
+
+ if (changed) {
+ changed_multi = true;
+ ED_armature_edit_sync_selection(arm->edbo);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ }
+ }
+ MEM_freeN(objects);
+
+ if (!changed_multi) {
+ return OPERATOR_CANCELLED;
+ }
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_dissolve(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Dissolve Selected Bone(s)";
- ot->idname = "ARMATURE_OT_dissolve";
- ot->description = "Dissolve selected bones from the armature";
+ /* identifiers */
+ ot->name = "Dissolve Selected Bone(s)";
+ ot->idname = "ARMATURE_OT_dissolve";
+ ot->description = "Dissolve selected bones from the armature";
- /* api callbacks */
- ot->exec = armature_dissolve_selected_exec;
- ot->poll = ED_operator_editarmature;
+ /* api callbacks */
+ ot->exec = armature_dissolve_selected_exec;
+ ot->poll = ED_operator_editarmature;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-
-
/* ********************************* Show/Hide ******************************* */
static int armature_hide_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const int invert = RNA_boolean_get(op->ptr, "unselected") ? BONE_SELECTED : 0;
-
- /* cancel if nothing selected */
- if (CTX_DATA_COUNT(C, selected_bones) == 0)
- return OPERATOR_CANCELLED;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- bArmature *arm = obedit->data;
- bool changed = false;
-
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if ((ebone->flag & BONE_SELECTED) != invert) {
- ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
- ebone->flag |= BONE_HIDDEN_A;
- changed = true;
- }
- }
- }
-
- if (!changed) {
- continue;
- }
- ED_armature_edit_validate_active(arm);
- ED_armature_edit_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
- }
- MEM_freeN(objects);
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const int invert = RNA_boolean_get(op->ptr, "unselected") ? BONE_SELECTED : 0;
+
+ /* cancel if nothing selected */
+ if (CTX_DATA_COUNT(C, selected_bones) == 0)
+ return OPERATOR_CANCELLED;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
+ bool changed = false;
+
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ if ((ebone->flag & BONE_SELECTED) != invert) {
+ ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ ebone->flag |= BONE_HIDDEN_A;
+ changed = true;
+ }
+ }
+ }
+
+ if (!changed) {
+ continue;
+ }
+ ED_armature_edit_validate_active(arm);
+ ED_armature_edit_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ }
+ MEM_freeN(objects);
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_hide(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Hide Selected";
- ot->idname = "ARMATURE_OT_hide";
- ot->description = "Tag selected bones to not be visible in Edit Mode";
+ /* identifiers */
+ ot->name = "Hide Selected";
+ ot->idname = "ARMATURE_OT_hide";
+ ot->description = "Tag selected bones to not be visible in Edit Mode";
- /* api callbacks */
- ot->exec = armature_hide_exec;
- ot->poll = ED_operator_editarmature;
+ /* api callbacks */
+ ot->exec = armature_hide_exec;
+ ot->poll = ED_operator_editarmature;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* props */
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
+ /* props */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
}
static int armature_reveal_exec(bContext *C, wmOperator *op)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const bool select = RNA_boolean_get(op->ptr, "select");
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- bArmature *arm = obedit->data;
- bool changed = false;
-
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (arm->layer & ebone->layer) {
- if (ebone->flag & BONE_HIDDEN_A) {
- if (!(ebone->flag & BONE_UNSELECTABLE)) {
- SET_FLAG_FROM_TEST(ebone->flag, select, (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL));
- }
- ebone->flag &= ~BONE_HIDDEN_A;
- changed = true;
- }
- }
- }
-
- if (changed) {
- ED_armature_edit_validate_active(arm);
- ED_armature_edit_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
- }
- }
- MEM_freeN(objects);
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const bool select = RNA_boolean_get(op->ptr, "select");
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
+ bool changed = false;
+
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (arm->layer & ebone->layer) {
+ if (ebone->flag & BONE_HIDDEN_A) {
+ if (!(ebone->flag & BONE_UNSELECTABLE)) {
+ SET_FLAG_FROM_TEST(ebone->flag, select, (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL));
+ }
+ ebone->flag &= ~BONE_HIDDEN_A;
+ changed = true;
+ }
+ }
+ }
+
+ if (changed) {
+ ED_armature_edit_validate_active(arm);
+ ED_armature_edit_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ }
+ }
+ MEM_freeN(objects);
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_reveal(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Reveal Hidden";
- ot->idname = "ARMATURE_OT_reveal";
- ot->description = "Reveal all bones hidden in Edit Mode";
+ /* identifiers */
+ ot->name = "Reveal Hidden";
+ ot->idname = "ARMATURE_OT_reveal";
+ ot->description = "Reveal all bones hidden in Edit Mode";
- /* api callbacks */
- ot->exec = armature_reveal_exec;
- ot->poll = ED_operator_editarmature;
+ /* api callbacks */
+ ot->exec = armature_reveal_exec;
+ ot->poll = ED_operator_editarmature;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "select", true, "Select", "");
+ RNA_def_boolean(ot->srna, "select", true, "Select", "");
}