diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/editors/armature/armature_edit.c | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (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.c | 2864 |
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", ""); } |