diff options
Diffstat (limited to 'source/blender/editors/armature')
25 files changed, 1426 insertions, 739 deletions
diff --git a/source/blender/editors/armature/BIF_retarget.h b/source/blender/editors/armature/BIF_retarget.h index 21e85b6fe89..aa56f847f00 100644 --- a/source/blender/editors/armature/BIF_retarget.h +++ b/source/blender/editors/armature/BIF_retarget.h @@ -40,7 +40,6 @@ struct bContext; struct EditBone; -struct RigJoint; struct RigGraph; struct RigNode; struct RigArc; diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt index 9aa17f1e503..1ed70b3cd98 100644 --- a/source/blender/editors/armature/CMakeLists.txt +++ b/source/blender/editors/armature/CMakeLists.txt @@ -20,14 +20,15 @@ set(INC ../include - ../../blenfont ../../blenkernel ../../blenlib + ../../blentranslation + ../../gpu ../../makesdna ../../makesrna ../../windowmanager - ../../gpu ../../../../intern/guardedalloc + ../../../../intern/glew-mx ) set(INC_SYS @@ -74,4 +75,6 @@ if(WITH_OPENNL) ) endif() +add_definitions(${GL_DEFINITIONS}) + blender_add_lib(bf_editor_armature "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/editors/armature/SConscript b/source/blender/editors/armature/SConscript index c68045c9398..9c3959ecb5b 100644 --- a/source/blender/editors/armature/SConscript +++ b/source/blender/editors/armature/SConscript @@ -31,20 +31,22 @@ sources = env.Glob('*.c') incs = [ '#/intern/guardedalloc', - '#/extern/glew/include', + env['BF_GLEW_INC'], + '#/intern/glew-mx', '#/intern/opennl/extern', '../include', - '../../blenfont', '../../blenkernel', '../../blenlib', + '../../blentranslation', + '../../gpu', '../../makesdna', '../../makesrna', - '../../gpu', '../../windowmanager', ] incs = ' '.join(incs) defs = [] +defs += env['BF_GL_DEFINITIONS'] if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'): incs += ' ' + env['BF_PTHREADS_INC'] diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index eba1bc4d78d..59453f0ac71 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -43,6 +43,7 @@ #include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_idprop.h" +#include "BKE_deform.h" #include "RNA_access.h" #include "RNA_define.h" @@ -89,7 +90,7 @@ EditBone *ED_armature_edit_bone_add_primitive(Object *obedit_arm, float length, bArmature *arm = obedit_arm->data; EditBone *bone; - ED_armature_deselect_all(obedit_arm, 0); + ED_armature_deselect_all(obedit_arm); /* Create a bone */ bone = ED_armature_edit_bone_add(arm, "Bone"); @@ -144,7 +145,7 @@ static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op)) to_root = 1; } - ED_armature_deselect_all(obedit, 0); + ED_armature_deselect_all(obedit); /* we re-use code for mirror editing... */ flipbone = NULL; @@ -270,7 +271,7 @@ static EditBone *get_named_editbone(ListBase *edbo, const char *name) if (name) { for (eBone = edbo->first; eBone; eBone = eBone->next) { - if (!strcmp(name, eBone->name)) + if (STREQ(name, eBone->name)) return eBone; } } @@ -282,12 +283,8 @@ static EditBone *get_named_editbone(ListBase *edbo, const char *name) * */ void preEditBoneDuplicate(ListBase *editbones) { - EditBone *eBone; - /* clear temp */ - for (eBone = editbones->first; eBone; eBone = eBone->next) { - eBone->temp = NULL; - } + ED_armature_ebone_listbase_temp_clear(editbones); } /* @@ -311,7 +308,7 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Obj /* does this constraint have a subtarget in * this armature? */ - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -327,8 +324,8 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Obj * so, update the constraint to point at the * duplicate of the old subtarget. */ - if (oldtarget->temp) { - newtarget = (EditBone *) oldtarget->temp; + if (oldtarget->temp.ebone) { + newtarget = oldtarget->temp.ebone; BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget)); } } @@ -357,8 +354,8 @@ EditBone *duplicateEditBoneObjects(EditBone *curBone, const char *name, ListBase /* Copy data from old bone to new bone */ memcpy(eBone, curBone, sizeof(EditBone)); - curBone->temp = eBone; - eBone->temp = curBone; + curBone->temp.ebone = eBone; + eBone->temp.ebone = curBone; if (name != NULL) { BLI_strncpy(eBone->name, name, sizeof(eBone->name)); @@ -398,13 +395,11 @@ EditBone *duplicateEditBone(EditBone *curBone, const char *name, ListBase *editb return duplicateEditBoneObjects(curBone, name, editbones, ob, ob); } -/* previously adduplicate_armature */ static int armature_duplicate_selected_exec(bContext *C, wmOperator *UNUSED(op)) { bArmature *arm; - EditBone *eBone = NULL; - EditBone *curBone; - EditBone *firstDup = NULL; /* The beginning of the duplicated bones in the edbo list */ + EditBone *ebone_iter; + EditBone *ebone_first_dupe = NULL; /* The beginning of the duplicated bones in the edbo list */ Object *obedit = CTX_data_edit_object(C); arm = obedit->data; @@ -419,77 +414,80 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *UNUSED(op)) /* Select mirrored bones */ if (arm->flag & ARM_MIRROR_EDIT) { - for (curBone = arm->edbo->first; curBone; curBone = curBone->next) { - if (EBONE_VISIBLE(arm, curBone)) { - if (curBone->flag & BONE_SELECTED) { - eBone = ED_armature_bone_get_mirrored(arm->edbo, curBone); - if (eBone) - eBone->flag |= BONE_SELECTED; + for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) { + if (EBONE_VISIBLE(arm, ebone_iter) && + (ebone_iter->flag & BONE_SELECTED)) + { + EditBone *ebone; + + ebone = ED_armature_bone_get_mirrored(arm->edbo, ebone_iter); + if (ebone) { + ebone->flag |= BONE_SELECTED; } } } } - /* Find the selected bones and duplicate them as needed */ - for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) { - if (EBONE_VISIBLE(arm, curBone)) { - if (curBone->flag & BONE_SELECTED) { - - eBone = duplicateEditBone(curBone, curBone->name, arm->edbo, obedit); - - if (!firstDup) - firstDup = eBone; + /* Find the selected bones and duplicate them as needed */ + for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { + if (EBONE_VISIBLE(arm, ebone_iter) && + (ebone_iter->flag & BONE_SELECTED)) + { + EditBone *ebone; + ebone = duplicateEditBone(ebone_iter, ebone_iter->name, arm->edbo, obedit); + + if (!ebone_first_dupe) { + ebone_first_dupe = ebone; } } } - /* Run though the list and fix the pointers */ - for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) { - if (EBONE_VISIBLE(arm, curBone)) { - if (curBone->flag & BONE_SELECTED) { - eBone = (EditBone *) curBone->temp; - - if (!curBone->parent) { - /* If this bone has no parent, - * Set the duplicate->parent to NULL - */ - eBone->parent = NULL; - } - else if (curBone->parent->temp) { - /* If this bone has a parent that was duplicated, - * Set the duplicate->parent to the curBone->parent->temp - */ - eBone->parent = (EditBone *)curBone->parent->temp; - } - else { - /* If this bone has a parent that IS not selected, - * Set the duplicate->parent to the curBone->parent - */ - eBone->parent = (EditBone *) curBone->parent; - eBone->flag &= ~BONE_CONNECTED; - } - - /* Lets try to fix any constraint subtargets that might - * have been duplicated + /* Run though the list and fix the pointers */ + for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { + if (EBONE_VISIBLE(arm, ebone_iter) && + (ebone_iter->flag & BONE_SELECTED)) + { + EditBone *ebone = ebone_iter->temp.ebone; + + if (!ebone_iter->parent) { + /* If this bone has no parent, + * Set the duplicate->parent to NULL + */ + ebone->parent = NULL; + } + else if (ebone_iter->parent->temp.ebone) { + /* If this bone has a parent that was duplicated, + * Set the duplicate->parent to the curBone->parent->temp + */ + ebone->parent = ebone_iter->parent->temp.ebone; + } + else { + /* If this bone has a parent that IS not selected, + * Set the duplicate->parent to the curBone->parent */ - updateDuplicateSubtarget(eBone, arm->edbo, obedit); + ebone->parent = (EditBone *) ebone_iter->parent; + ebone->flag &= ~BONE_CONNECTED; } + + /* Lets try to fix any constraint subtargets that might + * have been duplicated + */ + updateDuplicateSubtarget(ebone, arm->edbo, obedit); } } /* correct the active bone */ - if (arm->act_edbone) { - eBone = arm->act_edbone; - if (eBone->temp) - arm->act_edbone = eBone->temp; + if (arm->act_edbone && arm->act_edbone->temp.ebone) { + arm->act_edbone = arm->act_edbone->temp.ebone; } - /* Deselect the old bones and select the new ones */ - for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) { - if (EBONE_VISIBLE(arm, curBone)) - curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + /* Deselect the old bones and select the new ones */ + for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { + if (EBONE_VISIBLE(arm, ebone_iter)) { + ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } } ED_armature_validate_active(arm); @@ -515,6 +513,214 @@ void ARMATURE_OT_duplicate(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** + * near duplicate of #armature_duplicate_selected_exec, + * except for parenting part (keep in sync) + */ +static int armature_symmetrize_exec(bContext *C, wmOperator *op) +{ + bArmature *arm; + EditBone *ebone_iter; + EditBone *ebone_first_dupe = NULL; /* The beginning of the duplicated mirrored bones in the edbo list */ + + Object *obedit = CTX_data_edit_object(C); + const int direction = RNA_enum_get(op->ptr, "direction"); + const int axis = 0; + + arm = obedit->data; + + /* cancel if nothing selected */ + if (CTX_DATA_COUNT(C, selected_bones) == 0) + return OPERATOR_CANCELLED; + + ED_armature_sync_selection(arm->edbo); // XXX why is this needed? + + preEditBoneDuplicate(arm->edbo); + + /* Select mirrored bones */ + for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) { + if (EBONE_VISIBLE(arm, ebone_iter) && + (ebone_iter->flag & BONE_SELECTED)) + { + char name_flip[MAX_VGROUP_NAME]; + + BKE_deform_flip_side_name(name_flip, ebone_iter->name, false); + + if (STREQ(name_flip, ebone_iter->name)) { + /* if the name matches, we don't have the potential to be mirrored, just skip */ + ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } + else { + EditBone *ebone = ED_armature_bone_find_name(arm->edbo, name_flip); + + if (ebone) { + if ((ebone->flag & BONE_SELECTED) == 0) { + /* simple case, we're selected, the other bone isn't! */ + ebone_iter->temp.ebone = ebone; + } + else { + /* complicated - choose which direction to copy */ + float axis_delta; + + axis_delta = ebone->head[axis] - ebone_iter->head[axis]; + if (axis_delta == 0.0f) { + axis_delta = ebone->tail[axis] - ebone_iter->tail[axis]; + } + + if (axis_delta == 0.0f) { + /* both mirrored bones exist and point to eachother and overlap exactly. + * + * in this case theres no well defined solution, so de-select both and skip. + */ + ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } + else { + EditBone *ebone_src, *ebone_dst; + if (((axis_delta < 0.0f) ? -1 : 1) == direction) { + ebone_src = ebone; + ebone_dst = ebone_iter; + } + else { + ebone_src = ebone_iter; + ebone_dst = ebone; + } + + ebone_src->temp.ebone = ebone_dst; + ebone_dst->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } + } + } + } + } + } + + /* Find the selected bones and duplicate them as needed, with mirrored name */ + for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { + if (EBONE_VISIBLE(arm, ebone_iter) && + (ebone_iter->flag & BONE_SELECTED) && + /* will be set if the mirror bone already exists (no need to make a new one) */ + (ebone_iter->temp.ebone == NULL)) + { + char name_flip[MAX_VGROUP_NAME]; + + BKE_deform_flip_side_name(name_flip, ebone_iter->name, false); + + /* bones must have a side-suffix */ + if (!STREQ(name_flip, ebone_iter->name)) { + EditBone *ebone; + + ebone = duplicateEditBone(ebone_iter, name_flip, arm->edbo, obedit); + + if (!ebone_first_dupe) { + ebone_first_dupe = ebone; + } + } + } + } + + /* Run though the list and fix the pointers */ + for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { + if (ebone_iter->temp.ebone) { + /* copy all flags except for ... */ + const int flag_copy = ((int)~0) & ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL); + + EditBone *ebone = ebone_iter->temp.ebone; + + /* copy flags incase bone is pre-existing data */ + ebone->flag = (ebone->flag & ~flag_copy) | (ebone_iter->flag & flag_copy); + + if (ebone_iter->parent == NULL) { + /* If this bone has no parent, + * Set the duplicate->parent to NULL + */ + ebone->parent = NULL; + ebone->flag &= ~BONE_CONNECTED; + } + else { + /* the parent may have been duplicated, if not lookup the mirror parent */ + EditBone *ebone_parent = + (ebone_iter->parent->temp.ebone ? + ebone_iter->parent->temp.ebone : ED_armature_bone_get_mirrored(arm->edbo, ebone_iter->parent)); + + if (ebone_parent == NULL) { + /* If the mirror lookup failed, (but the current bone has a parent) + * then we can assume the parent has no L/R but is a center bone. + * So just use the same parent for both. + */ + ebone_parent = ebone_iter->parent; + ebone->flag &= ~BONE_CONNECTED; + } + + ebone->parent = ebone_parent; + } + + /* Lets try to fix any constraint subtargets that might + * have been duplicated + */ + updateDuplicateSubtarget(ebone, arm->edbo, obedit); + } + } + + transform_armature_mirror_update(obedit); + + /* Selected bones now have their 'temp' pointer set, + * so we don't need this anymore */ + + /* Deselect the old bones and select the new ones */ + for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { + if (EBONE_VISIBLE(arm, ebone_iter)) { + ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } + } + + /* New bones will be selected, but some of the bones may already exist */ + for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { + EditBone *ebone = ebone_iter->temp.ebone; + if (ebone && EBONE_SELECTABLE(arm, ebone)) { + ED_armature_ebone_select_set(ebone, true); + } + } + + /* correct the active bone */ + if (arm->act_edbone && arm->act_edbone->temp.ebone) { + arm->act_edbone = arm->act_edbone->temp.ebone; + } + + ED_armature_validate_active(arm); + + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); + + return OPERATOR_FINISHED; +} + +/* following conventions from #MESH_OT_symmetrize */ +void ARMATURE_OT_symmetrize(wmOperatorType *ot) +{ + /* subset of 'symmetrize_direction_items' */ + static EnumPropertyItem arm_symmetrize_direction_items[] = { + {-1, "NEGATIVE_X", 0, "-X to +X", ""}, + {+1, "POSITIVE_X", 0, "+X to -X", ""}, + {0, NULL, 0, NULL, NULL} + }; + + /* identifiers */ + ot->name = "Symmetrize"; + ot->idname = "ARMATURE_OT_symmetrize"; + ot->description = "Enforce symmetry, make copies of the selection or use existing"; + + /* api callbacks */ + ot->exec = armature_symmetrize_exec; + ot->poll = ED_operator_editarmature; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum( + ot->srna, "direction", arm_symmetrize_direction_items, -1, + "Direction", "Which sides to copy from and to (when both are selected)"); +} + /* ------------------------------------------ */ /* previously extrude_armature */ @@ -704,7 +910,7 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op) mul_m3_m3m3(totmat, obmat, viewmat); invert_m3_m3(imat, totmat); - ED_armature_deselect_all(obedit, 0); + ED_armature_deselect_all(obedit); /* Create a bone */ bone = ED_armature_edit_bone_add(obedit->data, name); @@ -830,7 +1036,7 @@ void ARMATURE_OT_subdivide(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* Properties */ - prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of Cuts", "", 1, 10); + prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 1000, "Number of Cuts", "", 1, 10); /* avoid re-using last var because it can cause _very_ high poly meshes and annoy users (or worse crash) */ RNA_def_property_flag(prop, PROP_SKIP_SAVE); } diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index 1e4d9bac246..5a0e70dc5dd 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -38,8 +38,11 @@ #include "MEM_guardedalloc.h" +#include "BLT_translation.h" + #include "BLI_blenlib.h" #include "BLI_math.h" +#include "BLI_ghash.h" #include "BKE_action.h" #include "BKE_armature.h" @@ -70,7 +73,7 @@ void ED_armature_apply_transform(Object *ob, float mat[4][4]) /* Put the armature into editmode */ ED_armature_to_edit(arm); - /* Transform the bones*/ + /* Transform the bones */ ED_armature_transform_bones(arm, mat); /* Turn the list into an armature */ @@ -100,7 +103,7 @@ void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4]) mul_m4_v3(mat, ebone->head); mul_m4_v3(mat, ebone->tail); - /* apply the transfiormed roll back */ + /* apply the transformed roll back */ mat3_to_vec_roll(tmat, NULL, &ebone->roll); ebone->rad_head *= scale; @@ -190,7 +193,7 @@ void ED_armature_origin_set(Scene *scene, Object *ob, float cursor[3], int cente /* Adjust object location for new centerpoint */ if (centermode && obedit == NULL) { - mul_mat3_m4_v3(ob->obmat, cent); /* ommit translation part */ + mul_mat3_m4_v3(ob->obmat, cent); /* omit translation part */ add_v3_v3(ob->loc, cent); } } @@ -236,28 +239,49 @@ float ED_rollBoneToVector(EditBone *bone, const float align_axis[3], const bool return roll; } - +/* note, ranges arithmatic is used below */ typedef enum eCalcRollTypes { - CALC_ROLL_X = 0, - CALC_ROLL_Y = 1, - CALC_ROLL_Z = 2, - - CALC_ROLL_TAN_X = 3, - CALC_ROLL_TAN_Z = 4, - - CALC_ROLL_ACTIVE = 5, - CALC_ROLL_VIEW = 6, - CALC_ROLL_CURSOR = 7, + /* 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 EnumPropertyItem prop_calc_roll_types[] = { - {CALC_ROLL_TAN_X, "X", 0, "Local X Tangent", ""}, - {CALC_ROLL_TAN_Z, "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_X, "GLOBAL_X", 0, "Global X Axis", ""}, - {CALC_ROLL_Y, "GLOBAL_Y", 0, "Global Y Axis", ""}, - {CALC_ROLL_Z, "GLOBAL_Z", 0, "Global Z Axis", ""}, + {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_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", ""}, @@ -268,15 +292,22 @@ static EnumPropertyItem prop_calc_roll_types[] = { static int armature_calc_roll_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_edit_object(C); - const short type = RNA_enum_get(op->ptr, "type"); + eCalcRollTypes type = RNA_enum_get(op->ptr, "type"); const bool axis_only = RNA_boolean_get(op->ptr, "axis_only"); - const bool axis_flip = RNA_boolean_get(op->ptr, "axis_flip"); + /* 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); float imat[3][3]; bArmature *arm = ob->data; 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); @@ -296,11 +327,13 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op) float cursor_rel[3]; sub_v3_v3v3(cursor_rel, cursor_local, ebone->head); if (axis_flip) negate_v3(cursor_rel); - ebone->roll = ED_rollBoneToVector(ebone, cursor_rel, axis_only); + if (normalize_v3(cursor_rel) != 0.0f) { + ebone->roll = ED_rollBoneToVector(ebone, cursor_rel, axis_only); + } } } } - else if (ELEM(type, CALC_ROLL_TAN_X, CALC_ROLL_TAN_Z)) { + 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)); @@ -321,7 +354,7 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op) sub_v3_v3v3(dir_b, ebone_other->head, ebone_other->tail); normalize_v3(dir_b); - if (type == CALC_ROLL_TAN_Z) { + if (type == CALC_ROLL_TAN_POS_Z) { cross_v3_v3v3(vec, dir_a, dir_b); } else { @@ -372,7 +405,7 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op) copy_v3_v3(vec, mat[2]); } else { /* Axis */ - assert(type >= 0 && type <= 5); + assert(type <= 5); if (type < 3) vec[type] = 1.0f; else vec[type - 2] = -1.0f; mul_m3_v3(imat, vec); @@ -421,7 +454,7 @@ void ARMATURE_OT_calculate_roll(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", prop_calc_roll_types, CALC_ROLL_TAN_X, "Type", ""); + 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"); } @@ -546,6 +579,7 @@ 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; /* sanity checks */ @@ -567,7 +601,7 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op) * 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_countlist(&points); + count = BLI_listbase_count(&points); if (count == 0) { BKE_report(op->reports, RPT_ERROR, "No joints selected"); @@ -578,94 +612,97 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op) float curs[3]; /* Get Points - selected joint */ - ebp = (EditBonePoint *)points.first; + ebp = points.first; /* Get points - cursor (tail) */ invert_m4_m4(obedit->imat, obedit->obmat); mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d)); /* Create a bone */ - /* newbone = */ add_points_bone(obedit, ebp->vec, curs); + newbone = add_points_bone(obedit, ebp->vec, curs); } else if (count == 2) { - EditBonePoint *ebp, *ebp2; + 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 = (EditBonePoint *)points.first; - ebp2 = ebp->next; + ebp_a = (EditBonePoint *)points.first; + ebp_b = ebp_a->next; - if ((ebp->head_owner == ebp2->tail_owner) && (ebp->head_owner != NULL)) { - BKE_report(op->reports, RPT_ERROR, "Same bone selected..."); - BLI_freelistN(&points); - return OPERATOR_CANCELLED; - } - if ((ebp->tail_owner == ebp2->head_owner) && (ebp->tail_owner != NULL)) { + 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->head_owner && ebp2->head_owner) || (ebp->tail_owner && ebp2->tail_owner)) { - /* rule: whichever one is closer to 3d-cursor */ - float curs[3]; - float vecA[3], vecB[3]; - float distA, distB; - - /* get cursor location */ - invert_m4_m4(obedit->imat, obedit->obmat); - mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d)); - - /* get distances */ - sub_v3_v3v3(vecA, ebp->vec, curs); - sub_v3_v3v3(vecB, ebp2->vec, curs); - distA = len_v3(vecA); - distB = len_v3(vecB); - - /* compare distances - closer one therefore acts as direction for bone to go */ - headtail = (distA < distB) ? 2 : 1; + 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, ED_view3d_cursor3d_get(scene, v3d)); + + /* 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->head_owner) { + else if (ebp_a->head_owner) { headtail = 1; } - else if (ebp2->head_owner) { + else if (ebp_b->head_owner) { headtail = 2; } /* assign head/tail combinations */ if (headtail == 2) { - copy_v3_v3(head, ebp->vec); - copy_v3_v3(tail, ebp2->vec); + copy_v3_v3(head, ebp_a->vec); + copy_v3_v3(tail, ebp_b->vec); } else if (headtail == 1) { - copy_v3_v3(head, ebp2->vec); - copy_v3_v3(tail, ebp->vec); + 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) { - EditBone *newbone = add_points_bone(obedit, head, tail); + 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->tail_owner) - newbone->parent = ebp->tail_owner; + if (ebp_a->tail_owner) + newbone->parent = ebp_a->tail_owner; else - newbone->parent = ebp->head_owner; + newbone->parent = ebp_a->head_owner; } else { - /* ebp2 tail or head - tail gets priority */ - if (ebp2->tail_owner) - newbone->parent = ebp2->tail_owner; + /* ebp_b tail or head - tail gets priority */ + if (ebp_b->tail_owner) + newbone->parent = ebp_b->tail_owner; else - newbone->parent = ebp2->head_owner; + newbone->parent = ebp_b->head_owner; } /* don't set for bone connecting two head points of bones */ - if (ebp->tail_owner || ebp2->tail_owner) { + if (ebp_a->tail_owner || ebp_b->tail_owner) { newbone->flag |= BONE_CONNECTED; } } @@ -676,6 +713,12 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op) BLI_freelistN(&points); return OPERATOR_CANCELLED; } + + if (newbone) { + ED_armature_deselect_all(obedit); + arm->act_edbone = newbone; + newbone->flag |= BONE_TIPSEL; + } /* updates */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit); @@ -945,9 +988,7 @@ static int armature_switch_direction_exec(bContext *C, wmOperator *UNUSED(op)) /* only if selected and editable */ if (EBONE_VISIBLE(arm, ebo) && EBONE_EDITABLE(ebo)) { /* swap head and tail coordinates */ - SWAP(float, ebo->head[0], ebo->tail[0]); - SWAP(float, ebo->head[1], ebo->tail[1]); - SWAP(float, ebo->head[2], ebo->tail[2]); + swap_v3_v3(ebo->head, ebo->tail); /* do parent swapping: * - use 'child' as new parent @@ -1191,13 +1232,21 @@ void ARMATURE_OT_split(wmOperatorType *ot) /* ********************************* Delete ******************************* */ +static bool armature_delete_ebone_cb(const char *bone_name, void *arm_p) +{ + bArmature *arm = arm_p; + EditBone *ebone; + + ebone = ED_armature_bone_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)) { bArmature *arm; EditBone *curBone, *ebone_next; - bConstraint *con; Object *obedit = CTX_data_edit_object(C); // XXX get from context bool changed = false; arm = obedit->data; @@ -1208,48 +1257,8 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op)) armature_select_mirrored(arm); - /* First erase any associated pose channel */ - if (obedit->pose) { - bPoseChannel *pchan, *pchan_next; - for (pchan = obedit->pose->chanbase.first; pchan; pchan = pchan_next) { - pchan_next = pchan->next; - curBone = ED_armature_bone_find_name(arm->edbo, pchan->name); - - if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) { - BKE_pose_channel_free(pchan); - BKE_pose_channels_hash_free(obedit->pose); - BLI_freelinkN(&obedit->pose->chanbase, pchan); - } - else { - for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - if (ct->tar == obedit) { - if (ct->subtarget[0]) { - curBone = ED_armature_bone_find_name(arm->edbo, ct->subtarget); - if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) { - con->flag |= CONSTRAINT_DISABLE; - ct->subtarget[0] = 0; - } - } - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 0); - } - } - } - } - } - - + 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) { @@ -1287,6 +1296,170 @@ void ARMATURE_OT_delete(wmOperatorType *ot) 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; + + ebone = ED_armature_bone_find_name(arm->edbo, bone_name); + return (ebone && (ebone->flag & BONE_DONE)); +} + +static int armature_dissolve_selected_exec(bContext *C, wmOperator *UNUSED(op)) +{ + bArmature *arm; + EditBone *ebone, *ebone_next; + Object *obedit = CTX_data_edit_object(C); + bool changed = false; + + /* store for mirror */ + GHash *ebone_flag_orig = NULL; + int ebone_num = 0; + + arm = obedit->data; + + 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; + + ED_armature_edit_bone_remove(arm, ebone); + changed = true; + } + } + + if (changed) { + for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { + if (ebone->parent && + ebone->parent->temp.ebone && + (ebone->flag & BONE_CONNECTED) == 0) + { + ebone->flag |= BONE_CONNECTED; + ebone->rad_head = ebone->parent->rad_head; + } + } + + 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) { + return OPERATOR_CANCELLED; + } + + ED_armature_sync_selection(arm->edbo); + + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); + + 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"; + + /* api callbacks */ + ot->exec = armature_dissolve_selected_exec; + ot->poll = ED_operator_editarmature; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + + + /* ********************************* Show/Hide ******************************* */ static int armature_hide_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h index 6d616384b9a..2968851f2eb 100644 --- a/source/blender/editors/armature/armature_intern.h +++ b/source/blender/editors/armature/armature_intern.h @@ -71,7 +71,9 @@ void ARMATURE_OT_select_similar(struct wmOperatorType *ot); void ARMATURE_OT_shortest_path_pick(struct wmOperatorType *ot); void ARMATURE_OT_delete(struct wmOperatorType *ot); +void ARMATURE_OT_dissolve(struct wmOperatorType *ot); void ARMATURE_OT_duplicate(struct wmOperatorType *ot); +void ARMATURE_OT_symmetrize(struct wmOperatorType *ot); void ARMATURE_OT_extrude(struct wmOperatorType *ot); void ARMATURE_OT_hide(struct wmOperatorType *ot); void ARMATURE_OT_reveal(struct wmOperatorType *ot); @@ -215,7 +217,7 @@ void POSE_OT_propagate(struct wmOperatorType *ot); */ EditBone *make_boneList(struct ListBase *edbo, struct ListBase *bones, struct EditBone *parent, struct Bone *actBone); -void BIF_sk_selectStroke(struct bContext *C, const int mval[2], short extend); +bool BIF_sk_selectStroke(struct bContext *C, const int mval[2], const bool extend); /* duplicate method */ void preEditBoneDuplicate(struct ListBase *editbones); @@ -233,6 +235,7 @@ EditBone *add_points_bone(struct Object *obedit, float head[3], float tail[3]); void bone_free(struct bArmature *arm, struct EditBone *bone); void armature_tag_select_mirrored(struct bArmature *arm); +void armature_select_mirrored_ex(struct bArmature *arm, const int flag); void armature_select_mirrored(struct bArmature *arm); void armature_tag_unselect(struct bArmature *arm); diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index 9afc45955bd..56dbdb3a639 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -38,7 +38,7 @@ #include "BLI_blenlib.h" #include "BLI_ghash.h" -#include "BLF_translation.h" +#include "BLT_translation.h" #include "BKE_animsys.h" #include "BKE_action.h" @@ -104,7 +104,7 @@ static void constraint_bone_name_fix(Object *ob, ListBase *conlist, const char * bConstraintTarget *ct; for (curcon = conlist->first; curcon; curcon = curcon->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon); ListBase targets = {NULL, NULL}; /* constraint targets */ @@ -141,7 +141,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n char oldname[MAXBONENAME]; /* names better differ! */ - if (strncmp(oldnamep, newnamep, MAXBONENAME)) { + if (!STREQLEN(oldnamep, newnamep, MAXBONENAME)) { /* we alter newname string... so make copy */ BLI_strncpy(newname, newnamep, MAXBONENAME); @@ -219,7 +219,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n if (ob->parent && (ob->parent->data == arm)) { if (ob->partype == PARBONE) { /* bone name in object */ - if (!strcmp(ob->parsubstr, oldname)) + if (STREQ(ob->parsubstr, oldname)) BLI_strncpy(ob->parsubstr, newname, MAXBONENAME); } } @@ -267,9 +267,10 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n /* Fix all animdata that may refer to this bone - we can't just do the ones attached to objects, since * other ID-blocks may have drivers referring to this bone [#29822] */ + // XXX: the ID here is for armatures, but most bone drivers are actually on the object instead... { - BKE_all_animdata_fix_paths_rename(&arm->id, "pose.bones", oldname, newname); + BKE_animdata_fix_paths_rename_all(&arm->id, "pose.bones", oldname, newname); } /* correct view locking */ @@ -284,7 +285,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n if (sl->spacetype == SPACE_VIEW3D) { View3D *v3d = (View3D *)sl; if (v3d->ob_centre && v3d->ob_centre->data == arm) { - if (!strcmp(v3d->ob_centre_bone, oldname)) { + if (STREQ(v3d->ob_centre_bone, oldname)) { BLI_strncpy(v3d->ob_centre_bone, newname, MAXBONENAME); } } diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c index b7e38546ca2..e7f036f6911 100644 --- a/source/blender/editors/armature/armature_ops.c +++ b/source/blender/editors/armature/armature_ops.c @@ -28,8 +28,6 @@ * \ingroup edarmature */ -#include "BLI_math.h" - #include "RNA_access.h" #include "WM_api.h" @@ -67,7 +65,9 @@ void ED_operatortypes_armature(void) WM_operatortype_append(ARMATURE_OT_shortest_path_pick); WM_operatortype_append(ARMATURE_OT_delete); + WM_operatortype_append(ARMATURE_OT_dissolve); WM_operatortype_append(ARMATURE_OT_duplicate); + WM_operatortype_append(ARMATURE_OT_symmetrize); WM_operatortype_append(ARMATURE_OT_extrude); WM_operatortype_append(ARMATURE_OT_hide); WM_operatortype_append(ARMATURE_OT_reveal); @@ -267,8 +267,9 @@ void ED_keymap_armature(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "ARMATURE_OT_shortest_path_pick", SELECTMOUSE, KM_PRESS, KM_CTRL, 0); - WM_keymap_add_item(keymap, "ARMATURE_OT_delete", XKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "ARMATURE_OT_delete", DELKEY, KM_PRESS, 0, 0); + WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_armature_delete", XKEY, KM_PRESS, 0, 0); + WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_armature_delete", DELKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "ARMATURE_OT_dissolve", XKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "ARMATURE_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "ARMATURE_OT_extrude_move", EKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "ARMATURE_OT_extrude_forked", EKEY, KM_PRESS, KM_SHIFT, 0); @@ -277,7 +278,7 @@ void ED_keymap_armature(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "ARMATURE_OT_merge", MKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "ARMATURE_OT_split", YKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "ARMATURE_OT_separate", PKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); + WM_keymap_add_item(keymap, "ARMATURE_OT_separate", PKEY, KM_PRESS, 0, 0); /* set flags */ WM_keymap_add_menu(keymap, "VIEW3D_MT_bone_options_toggle", WKEY, KM_PRESS, KM_SHIFT, 0); @@ -368,7 +369,7 @@ void ED_keymap_armature(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "POSE_OT_select_linked", LKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "POSE_OT_select_grouped", GKEY, KM_PRESS, KM_SHIFT, 0); - WM_keymap_add_item(keymap, "POSE_OT_select_mirror", FKEY, KM_PRESS, KM_SHIFT, 0); + WM_keymap_add_item(keymap, "POSE_OT_select_mirror", FKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); WM_keymap_add_item(keymap, "POSE_OT_constraint_add_with_targets", CKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0); WM_keymap_add_item(keymap, "POSE_OT_constraints_clear", CKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); @@ -413,5 +414,6 @@ void ED_keymap_armature(wmKeyConfig *keyconf) /* menus */ WM_keymap_add_menu(keymap, "VIEW3D_MT_pose_specials", WKEY, KM_PRESS, 0, 0); + WM_keymap_add_menu(keymap, "VIEW3D_MT_pose_propagate", PKEY, KM_PRESS, KM_ALT, 0); } diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 75fa4a5433f..1c342657eec 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -29,20 +29,26 @@ * \ingroup edarmature */ +#include "MEM_guardedalloc.h" + +#include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_constraint_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "BLI_blenlib.h" +#include "BLI_ghash.h" #include "BLI_math.h" -#include "BLF_translation.h" +#include "BLT_translation.h" #include "BKE_action.h" +#include "BKE_animsys.h" #include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_depsgraph.h" +#include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_report.h" @@ -72,7 +78,7 @@ static void joined_armature_fix_links_constraints( bConstraint *con; for (con = lb->first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -98,33 +104,122 @@ static void joined_armature_fix_links_constraints( /* action constraint? (pose constraints only) */ if (con->type == CONSTRAINT_TYPE_ACTION) { - bActionConstraint *data = con->data; // XXX old animation system - bAction *act; - bActionChannel *achan; + bActionConstraint *data = con->data; if (data->act) { - act = data->act; + BKE_action_fix_paths_rename(&tarArm->id, data->act, "pose.bones[", + pchan->name, curbone->name, 0, 0, false); + } + } + + } +} - for (achan = act->chanbase.first; achan; achan = achan->next) { - if (STREQ(achan->name, pchan->name)) { - BLI_strncpy(achan->name, curbone->name, sizeof(achan->name)); +/* userdata for joined_armature_fix_animdata_cb() */ +typedef struct tJoinArmature_AdtFixData { + Object *srcArm; + Object *tarArm; + + GHash *names_map; +} tJoinArmature_AdtFixData; + +/* Callback to pass to void BKE_animdata_main_cb() for fixing driver ID's to point to the new ID */ +/* FIXME: For now, we only care about drivers here. When editing rigs, it's very rare to have animation + * on the rigs being edited already, so it should be safe to skip these. + */ +static void joined_armature_fix_animdata_cb(ID *id, AnimData *adt, void *user_data) +{ + tJoinArmature_AdtFixData *afd = (tJoinArmature_AdtFixData *)user_data; + ID *src_id = &afd->srcArm->id; + ID *dst_id = &afd->tarArm->id; + + GHashIterator gh_iter; + FCurve *fcu; + + /* Fix paths - If this is the target object, it will have some "dirty" paths */ + if (id == src_id) { + /* Fix drivers */ + for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { + /* skip driver if it doesn't affect the bones */ + if (strstr(fcu->rna_path, "pose.bones[") == NULL) { + continue; + } + + // FIXME: this is too crude... it just does everything! + GHASH_ITER(gh_iter, afd->names_map) { + const char *old_name = BLI_ghashIterator_getKey(&gh_iter); + const char *new_name = BLI_ghashIterator_getValue(&gh_iter); + + /* only remap if changed; this still means there will be some waste if there aren't many drivers/keys */ + if (!STREQ(old_name, new_name) && strstr(fcu->rna_path, old_name)) { + fcu->rna_path = BKE_animsys_fix_rna_path_rename(id, fcu->rna_path, "pose.bones", + old_name, new_name, 0, 0, false); + + /* we don't want to apply a second remapping on this driver now, + * so stop trying names, but keep fixing drivers + */ + break; + } + } + } + } + + + /* Driver targets */ + for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { + ChannelDriver *driver = fcu->driver; + DriverVar *dvar; + + /* Fix driver references to invalid ID's */ + for (dvar = driver->variables.first; dvar; dvar = dvar->next) { + /* only change the used targets, since the others will need fixing manually anyway */ + DRIVER_TARGETS_USED_LOOPER(dvar) + { + /* change the ID's used... */ + if (dtar->id == src_id) { + dtar->id = dst_id; + + /* also check on the subtarget... + * XXX: We duplicate the logic from drivers_path_rename_fix() here, with our own + * little twists so that we know that it isn't going to clobber the wrong data + */ + if ((dtar->rna_path && strstr(dtar->rna_path, "pose.bones[")) || (dtar->pchan_name[0])) { + GHASH_ITER(gh_iter, afd->names_map) { + const char *old_name = BLI_ghashIterator_getKey(&gh_iter); + const char *new_name = BLI_ghashIterator_getValue(&gh_iter); + + /* only remap if changed */ + if (!STREQ(old_name, new_name)) { + if ((dtar->rna_path) && strstr(dtar->rna_path, old_name)) { + /* Fix up path */ + dtar->rna_path = BKE_animsys_fix_rna_path_rename(id, dtar->rna_path, "pose.bones", + old_name, new_name, 0, 0, false); + break; /* no need to try any more names for bone path */ + } + else if (STREQ(dtar->pchan_name, old_name)) { + /* Change target bone name */ + BLI_strncpy(dtar->pchan_name, new_name, sizeof(dtar->pchan_name)); + break; /* no need to try any more names for bone subtarget */ + } + } + } } } } + DRIVER_TARGETS_LOOPER_END } - } } /* Helper function for armature joining - link fixing */ -static void joined_armature_fix_links(Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone) +static void joined_armature_fix_links(Main *bmain, Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone) { Object *ob; bPose *pose; bPoseChannel *pchant; /* let's go through all objects in database */ - for (ob = G.main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { /* do some object-type specific things */ if (ob->type == OB_ARMATURE) { pose = ob->pose; @@ -198,8 +293,17 @@ int join_armature_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases) { if ((base->object->type == OB_ARMATURE) && (base->object != ob)) { + tJoinArmature_AdtFixData afd = {NULL}; bArmature *curarm = base->object->data; + /* we assume that each armature datablock is only used in a single place */ + BLI_assert(ob->data != base->object->data); + + /* init callback data for fixing up AnimData links later */ + afd.srcArm = base->object; + afd.tarArm = ob; + afd.names_map = BLI_ghash_str_new("join_armature_adt_fix"); + /* Make a list of editbones in current armature */ ED_armature_to_edit(base->object->data); @@ -219,6 +323,7 @@ int join_armature_exec(bContext *C, wmOperator *op) /* Get new name */ unique_editbone_name(arm->edbo, curbone->name, NULL); + BLI_ghash_insert(afd.names_map, BLI_strdup(pchan->name), curbone->name); /* Transform the bone */ { @@ -249,7 +354,7 @@ int join_armature_exec(bContext *C, wmOperator *op) } /* Fix Constraints and Other Links to this Bone and Armature */ - joined_armature_fix_links(ob, base->object, pchan, curbone); + joined_armature_fix_links(bmain, ob, base->object, pchan, curbone); /* Rename pchan */ BLI_strncpy(pchan->name, curbone->name, sizeof(pchan->name)); @@ -264,6 +369,37 @@ int join_armature_exec(bContext *C, wmOperator *op) BKE_pose_channels_hash_free(pose); } + /* Fix all the drivers (and animation data) */ + BKE_animdata_main_cb(bmain, joined_armature_fix_animdata_cb, &afd); + BLI_ghash_free(afd.names_map, MEM_freeN, NULL); + + /* Only copy over animdata now, after all the remapping has been done, + * so that we don't have to worry about ambiguities re which armature + * a bone came from! + */ + if (base->object->adt) { + if (ob->adt == NULL) { + /* no animdata, so just use a copy of the whole thing */ + ob->adt = BKE_animdata_copy(base->object->adt, false); + } + else { + /* merge in data - we'll fix the drivers manually */ + BKE_animdata_merge_copy(&ob->id, &base->object->id, ADT_MERGECOPY_KEEP_DST, false); + } + } + + if (curarm->adt) { + if (arm->adt == NULL) { + /* no animdata, so just use a copy of the whole thing */ + arm->adt = BKE_animdata_copy(curarm->adt, false); + } + else { + /* merge in data - we'll fix the drivers manually */ + BKE_animdata_merge_copy(&arm->id, &curarm->id, ADT_MERGECOPY_KEEP_DST, false); + } + } + + /* Free the old object data */ ED_base_object_free_and_unlink(bmain, scene, base); } } @@ -299,7 +435,7 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm) if (ob->type == OB_ARMATURE) { for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -337,7 +473,7 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm) /* fix object-level constraints */ if (ob != origArm) { for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -412,7 +548,7 @@ static void separate_armature_bones(Object *ob, short sel) for (ebo = arm->edbo->first; ebo; ebo = ebo->next) { if (ebo->parent == curbone) { ebo->parent = NULL; - ebo->temp = NULL; /* this is needed to prevent random crashes with in ED_armature_from_edit */ + ebo->temp.p = NULL; /* this is needed to prevent random crashes with in ED_armature_from_edit */ ebo->flag &= ~BONE_CONNECTED; } } @@ -505,6 +641,9 @@ static int separate_armature_exec(bContext *C, wmOperator *op) ED_armature_to_edit(obedit->data); + /* parents tips remain selected when connected children are removed. */ + ED_armature_deselect_all(obedit); + BKE_report(op->reports, RPT_INFO, "Separated bones"); /* note, notifier might evolve */ @@ -524,6 +663,7 @@ void ARMATURE_OT_separate(wmOperatorType *ot) ot->description = "Isolate selected bones into a separate armature"; /* callbacks */ + ot->invoke = WM_operator_confirm; ot->exec = separate_armature_exec; ot->poll = ED_operator_editarmature; @@ -673,8 +813,8 @@ static int armature_parent_set_exec(bContext *C, wmOperator *op) static int armature_parent_set_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { EditBone *actbone = CTX_data_active_bone(C); - uiPopupMenu *pup = uiPupMenuBegin(C, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Make Parent"), ICON_NONE); - uiLayout *layout = uiPupMenuLayout(pup); + uiPopupMenu *pup = UI_popup_menu_begin(C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Parent"), ICON_NONE); + uiLayout *layout = UI_popup_menu_layout(pup); int allchildbones = 0; CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) @@ -691,9 +831,9 @@ static int armature_parent_set_invoke(bContext *C, wmOperator *UNUSED(op), const if (allchildbones) uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_OFFSET); - uiPupMenuEnd(C, pup); + UI_popup_menu_end(C, pup); - return OPERATOR_CANCELLED; + return OPERATOR_INTERFACE; } void ARMATURE_OT_parent_set(wmOperatorType *ot) diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index d85a730c88e..dbbdae280f2 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -54,9 +54,9 @@ #include "armature_intern.h" -/* utility macros fro storing a temp int in the bone (selection flag) */ -#define EBONE_PREV_FLAG_GET(ebone) ((void)0, (GET_INT_FROM_POINTER((ebone)->temp))) -#define EBONE_PREV_FLAG_SET(ebone, val) ((ebone)->temp = SET_INT_IN_POINTER(val)) +/* utility macros for storing a temp int in the bone (selection flag) */ +#define EBONE_PREV_FLAG_GET(ebone) ((void)0, (ebone)->temp.i) +#define EBONE_PREV_FLAG_SET(ebone, val) ((ebone)->temp.i = val) /* **************** PoseMode & EditMode Selection Buffer Queries *************************** */ @@ -126,7 +126,7 @@ void *get_bone_from_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, if (sel) { if (do_nearest) { if (minsel > buffer[4 * i + 1]) { - firstSel = bone; + firstSel = data; minsel = buffer[4 * i + 1]; } } @@ -138,12 +138,11 @@ void *get_bone_from_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, else { if (do_nearest) { if (minunsel > buffer[4 * i + 1]) { - firstunSel = bone; + firstunSel = data; minunsel = buffer[4 * i + 1]; } } - else - { + else { if (!firstunSel) firstunSel = data; if (takeNext) return data; } @@ -175,7 +174,6 @@ void *get_nearest_bone(bContext *C, short findunsel, int x, int y) rect.xmin = rect.xmax = x; rect.ymin = rect.ymax = y; - glInitNames(); hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true); if (hits > 0) @@ -255,7 +253,7 @@ static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEv static int armature_select_linked_poll(bContext *C) { - return (ED_operator_view3d_active(C) && ED_operator_editarmature(C) ); + return (ED_operator_view3d_active(C) && ED_operator_editarmature(C)); } void ARMATURE_OT_select_linked(wmOperatorType *ot) @@ -289,11 +287,9 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2], rcti rect; unsigned int buffer[MAXPICKBUF]; unsigned int hitresult, besthitresult = BONESEL_NOSEL; - int i, mindep = 4; + int i, mindep = 5; short hits; - glInitNames(); - /* find the bone after the current active bone, so as to bump up its chances in selection. * this way overlapping bones will cycle selection state as with objects. */ if (ebone_next_act && @@ -346,16 +342,16 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2], dep = 2; } else { - dep = 2; + dep = 1; } } else { /* bone found */ if (findunsel) { if ((ebone->flag & BONE_SELECTED) == 0) - dep = 2; - else dep = 3; + else + dep = 4; } else { dep = 3; @@ -392,61 +388,14 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2], return NULL; } - - -/* toggle==0: deselect - * toggle==1: swap (based on test) - * toggle==2: swap (no test), CURRENTLY UNUSED - */ -void ED_armature_deselect_all(Object *obedit, int toggle) +void ED_armature_deselect_all(Object *obedit) { bArmature *arm = obedit->data; - EditBone *eBone; - int sel = 1; - - if (toggle == 1) { - /* Determine if there are any selected bones - * and therefore whether we are selecting or deselecting */ - for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { - // if (arm->layer & eBone->layer) { - if (eBone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) { - sel = 0; - break; - } - // } - } - } - else { - sel = toggle; - } + EditBone *ebone; - /* Set the flags */ - for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { - if (sel == 2) { - /* invert selection of bone */ - if (EBONE_VISIBLE(arm, eBone)) { - eBone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - if (arm->act_edbone == eBone) - arm->act_edbone = NULL; - } - } - else if (sel == 1) { - /* select bone */ - if (EBONE_VISIBLE(arm, eBone)) { - eBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - if (eBone->parent) - eBone->parent->flag |= (BONE_TIPSEL); - } - } - else { - /* deselect bone */ - eBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - if (arm->act_edbone == eBone) - arm->act_edbone = NULL; - } + for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { + ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); } - - ED_armature_sync_selection(arm->edbo); } void ED_armature_deselect_all_visible(Object *obedit) @@ -486,13 +435,16 @@ bool mouse_armature(bContext *C, const int mval[2], bool extend, bool deselect, view3d_set_viewcontext(C, &vc); - BIF_sk_selectStroke(C, mval, extend); + if (BIF_sk_selectStroke(C, mval, extend)) { + return true; + } nearBone = get_nearest_editbonepoint(&vc, mval, arm->edbo, 1, &selmask); if (nearBone) { - if (!extend && !deselect && !toggle) - ED_armature_deselect_all(obedit, 0); + if (!extend && !deselect && !toggle) { + ED_armature_deselect_all(obedit); + } /* by definition the non-root connected bones have no root point drawn, * so a root selection needs to be delivered to the parent tip */ @@ -733,7 +685,7 @@ static void armature_select_more_less(Object *ob, bool more) } } } - ebone->temp = NULL; + ebone->temp.p = NULL; } ED_armature_sync_selection(arm->edbo); @@ -958,81 +910,84 @@ void ARMATURE_OT_select_similar(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, 0, "Type", ""); + ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, SIMEDBONE_LENGTH, "Type", ""); RNA_def_float(ot->srna, "threshold", 0.1f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f); } /* ********************* select hierarchy operator ************** */ -/* Get the first available child of an editbone */ -static EditBone *editbone_get_child(bArmature *arm, EditBone *pabone, short use_visibility) -{ - EditBone *curbone, *chbone = NULL; - - for (curbone = arm->edbo->first; curbone; curbone = curbone->next) { - if (curbone->parent == pabone) { - if (use_visibility) { - if ((arm->layer & curbone->layer) && !(pabone->flag & BONE_HIDDEN_A)) { - chbone = curbone; - } - } - else - chbone = curbone; - } - } - - return chbone; -} - static int armature_select_hierarchy_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); Object *ob; bArmature *arm; - EditBone *curbone, *pabone, *chbone; + EditBone *ebone_active; int direction = RNA_enum_get(op->ptr, "direction"); const bool add_to_sel = RNA_boolean_get(op->ptr, "extend"); + bool changed = false; ob = obedit; arm = (bArmature *)ob->data; - - for (curbone = arm->edbo->first; curbone; curbone = curbone->next) { - /* only work on bone if it is visible and its selection can change */ - if (EBONE_SELECTABLE(arm, curbone)) { - if (curbone == arm->act_edbone) { - if (direction == BONE_SELECT_PARENT) { - if (curbone->parent == NULL) continue; - else pabone = curbone->parent; - - if (EBONE_VISIBLE(arm, pabone)) { - pabone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - arm->act_edbone = pabone; - if (pabone->parent) pabone->parent->flag |= BONE_TIPSEL; - - if (!add_to_sel) curbone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - break; - } - + + ebone_active = arm->act_edbone; + if (ebone_active == NULL) { + return OPERATOR_CANCELLED; + } + + if (direction == BONE_SELECT_PARENT) { + if (ebone_active->parent) { + EditBone *ebone_parent; + + ebone_parent = ebone_active->parent; + + if (EBONE_SELECTABLE(arm, ebone_parent)) { + arm->act_edbone = ebone_parent; + + if (!add_to_sel) { + ED_armature_ebone_select_set(ebone_active, false); } - else { // BONE_SELECT_CHILD - chbone = editbone_get_child(arm, curbone, 1); - if (chbone == NULL) continue; - - if (EBONE_SELECTABLE(arm, chbone)) { - chbone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - arm->act_edbone = chbone; - - if (!add_to_sel) { - curbone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL); - if (curbone->parent) curbone->parent->flag &= ~BONE_TIPSEL; + ED_armature_ebone_select_set(ebone_parent, true); + + changed = true; + } + } + + } + else { /* BONE_SELECT_CHILD */ + EditBone *ebone_iter, *ebone_child = NULL; + int pass; + + /* first pass, only connected bones (the logical direct child) */ + for (pass = 0; pass < 2 && (ebone_child == NULL); pass++) { + for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) { + /* possible we have multiple children, some invisible */ + if (EBONE_SELECTABLE(arm, ebone_iter)) { + if (ebone_iter->parent == ebone_active) { + if ((pass == 1) || (ebone_iter->flag & BONE_CONNECTED)) { + ebone_child = ebone_iter; + break; } - break; } } } } + + if (ebone_child) { + arm->act_edbone = ebone_child; + + if (!add_to_sel) { + ED_armature_ebone_select_set(ebone_active, false); + } + ED_armature_ebone_select_set(ebone_child, true); + + changed = true; + } } + if (changed == false) { + return OPERATOR_CANCELLED; + } + ED_armature_sync_selection(arm->edbo); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c index fbc18e977ce..ea1a94fbba6 100644 --- a/source/blender/editors/armature/armature_skinning.c +++ b/source/blender/editors/armature/armature_skinning.c @@ -43,6 +43,7 @@ #include "BKE_action.h" #include "BKE_armature.h" #include "BKE_deform.h" +#include "BKE_object_deform.h" #include "BKE_report.h" #include "BKE_subsurf.h" #include "BKE_modifier.h" @@ -52,7 +53,10 @@ #include "armature_intern.h" -#include "meshlaplacian.h" + +#ifdef WITH_OPENNL +# include "meshlaplacian.h" +#endif #if 0 #include "reeb.h" @@ -117,7 +121,7 @@ static int vgroup_add_unique_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr)) */ if (!(bone->flag & BONE_NO_DEFORM)) { if (!defgroup_find_name(ob, bone->name)) { - ED_vgroup_add_name(ob, bone->name); + BKE_object_defgroup_add_name(ob, bone->name); return 1; } } @@ -162,9 +166,15 @@ static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap) else segments = 1; - if (!wpmode || ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))) - if (!(defgroup = defgroup_find_name(ob, bone->name))) - defgroup = ED_vgroup_add_name(ob, bone->name); + if (!wpmode || ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))) { + if (!(defgroup = defgroup_find_name(ob, bone->name))) { + defgroup = BKE_object_defgroup_add_name(ob, bone->name); + } + else if (defgroup->flag & DG_LOCK_WEIGHT) { + /* In case vgroup already exists and is locked, do not modify it here. See T43814. */ + defgroup = NULL; + } + } if (data->list != NULL) { hgroup = (bDeformGroup ***) &data->list; @@ -238,7 +248,8 @@ static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], i } } -static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, Object *par, int heat, bool mirror) +static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, Object *par, + int heat, const bool mirror) { /* This functions implements the automatic computation of vertex group * weights, either through envelopes or using a heat equilibrium. @@ -275,7 +286,7 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, if (numbones == 0) return; - if (ED_vgroup_data_create(ob->data) == false) + if (BKE_object_defgroup_data_create(ob->data) == NULL) return; /* create an array of pointer to bones that are skinnable @@ -418,7 +429,8 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, MEM_freeN(verts); } -void create_vgroups_from_armature(ReportList *reports, Scene *scene, Object *ob, Object *par, int mode, bool mirror) +void create_vgroups_from_armature(ReportList *reports, Scene *scene, Object *ob, Object *par, + const int mode, const bool mirror) { /* Lets try to create some vertex groups * based on the bones of the parent armature. @@ -426,7 +438,7 @@ void create_vgroups_from_armature(ReportList *reports, Scene *scene, Object *ob, bArmature *arm = par->data; if (mode == ARM_GROUPS_NAME) { - const int defbase_tot = BLI_countlist(&ob->defbase); + const int defbase_tot = BLI_listbase_count(&ob->defbase); int defbase_add; /* Traverse the bone list, trying to create empty vertex * groups corresponding to the bone. @@ -439,7 +451,7 @@ void create_vgroups_from_armature(ReportList *reports, Scene *scene, Object *ob, ED_vgroup_data_clamp_range(ob->data, defbase_tot); } } - else if (mode == ARM_GROUPS_ENVELOPE || mode == ARM_GROUPS_AUTO) { + else if (ELEM(mode, ARM_GROUPS_ENVELOPE, ARM_GROUPS_AUTO)) { /* Traverse the bone list, trying to create vertex groups * that are populated with the vertices for which the * bone is closest. diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index 97f69d86aee..61ed7fdc41b 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -276,18 +276,19 @@ EditBone *ED_armature_bone_get_mirrored(const ListBase *edbo, EditBone *ebo) /* helper function for tools to work on mirrored parts. * it leaves mirrored bones selected then too, which is a good indication of what happened */ -void armature_select_mirrored(bArmature *arm) +void armature_select_mirrored_ex(bArmature *arm, const int flag) { + BLI_assert((flag & ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) == 0); /* Select mirrored bones */ if (arm->flag & ARM_MIRROR_EDIT) { EditBone *curBone, *ebone_mirr; for (curBone = arm->edbo->first; curBone; curBone = curBone->next) { if (arm->layer & curBone->layer) { - if (curBone->flag & BONE_SELECTED) { + if (curBone->flag & flag) { ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, curBone); if (ebone_mirr) - ebone_mirr->flag |= BONE_SELECTED; + ebone_mirr->flag |= (curBone->flag & flag); } } } @@ -295,6 +296,11 @@ void armature_select_mirrored(bArmature *arm) } +void armature_select_mirrored(bArmature *arm) +{ + armature_select_mirrored_ex(arm, BONE_SELECTED); +} + void armature_tag_select_mirrored(bArmature *arm) { EditBone *curBone; @@ -471,48 +477,78 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone return eBoneAct; } -/* nasty stuff for converting roll in editbones into bones */ -/* also sets restposition in armature (arm_mat) */ -static void fix_bonelist_roll(ListBase *bonelist, ListBase *editbonelist) +/* This function: + * - sets local head/tail rest locations using parent bone's arm_mat. + * - calls BKE_armature_where_is_bone() which uses parent's transform (arm_mat) to define this bone's transform. + * - fixes (converts) EditBone roll into Bone roll. + * - calls again BKE_armature_where_is_bone(), since roll fiddling may have changed things for our bone... + * Note that order is crucial here, we can only handle child if all its parents in chain have already been handled + * (this is ensured by recursive process). */ +static void armature_finalize_restpose(ListBase *bonelist, ListBase *editbonelist) { Bone *curBone; EditBone *ebone; - float premat[3][3]; - float postmat[3][3]; - float difmat[3][3]; - float imat[3][3]; - + for (curBone = bonelist->first; curBone; curBone = curBone->next) { - /* sets local matrix and arm_mat (restpos) */ - BKE_armature_where_is_bone(curBone, curBone->parent); - + /* Set bone's local head/tail. + * Note that it's important to use final parent's restpose (arm_mat) here, instead of setting those values + * from editbone's matrix (see T46010). */ + if (curBone->parent) { + float parmat_inv[4][4]; + + invert_m4_m4(parmat_inv, curBone->parent->arm_mat); + + /* Get the new head and tail */ + sub_v3_v3v3(curBone->head, curBone->arm_head, curBone->parent->arm_tail); + sub_v3_v3v3(curBone->tail, curBone->arm_tail, curBone->parent->arm_tail); + + mul_mat3_m4_v3(parmat_inv, curBone->head); + mul_mat3_m4_v3(parmat_inv, curBone->tail); + } + else { + copy_v3_v3(curBone->head, curBone->arm_head); + copy_v3_v3(curBone->tail, curBone->arm_tail); + } + + /* Set local matrix and arm_mat (restpose). + * Do not recurse into children here, armature_finalize_restpose() is already recursive. */ + BKE_armature_where_is_bone(curBone, curBone->parent, false); + /* Find the associated editbone */ - for (ebone = editbonelist->first; ebone; ebone = ebone->next) - if ((Bone *)ebone->temp == curBone) - break; - - if (ebone) { - /* Get the ebone premat */ - ED_armature_ebone_to_mat3(ebone, premat); - - /* Get the bone postmat */ - copy_m3_m4(postmat, curBone->arm_mat); - - invert_m3_m3(imat, premat); - mul_m3_m3m3(difmat, imat, postmat); + for (ebone = editbonelist->first; ebone; ebone = ebone->next) { + if (ebone->temp.bone == curBone) { + float premat[3][3]; + float postmat[3][3]; + float difmat[3][3]; + float imat[3][3]; + + /* Get the ebone premat and its inverse. */ + ED_armature_ebone_to_mat3(ebone, premat); + invert_m3_m3(imat, premat); + + /* Get the bone postmat. */ + copy_m3_m4(postmat, curBone->arm_mat); + + mul_m3_m3m3(difmat, imat, postmat); + #if 0 - printf("Bone %s\n", curBone->name); - print_m4("premat", premat); - print_m4("postmat", postmat); - print_m4("difmat", difmat); - printf("Roll = %f\n", RAD2DEGF(-atan2(difmat[2][0], difmat[2][2]))); + printf("Bone %s\n", curBone->name); + print_m4("premat", premat); + print_m4("postmat", postmat); + print_m4("difmat", difmat); + printf("Roll = %f\n", RAD2DEGF(-atan2(difmat[2][0], difmat[2][2]))); #endif - curBone->roll = -atan2f(difmat[2][0], difmat[2][2]); - - /* and set restposition again */ - BKE_armature_where_is_bone(curBone, curBone->parent); + + curBone->roll = -atan2f(difmat[2][0], difmat[2][2]); + + /* and set restposition again */ + BKE_armature_where_is_bone(curBone, curBone->parent, false); + break; + } } - fix_bonelist_roll(&curBone->childbase, editbonelist); + + /* Recurse into children... */ + armature_finalize_restpose(&curBone->childbase, editbonelist); } } @@ -529,9 +565,9 @@ void ED_armature_from_edit(bArmature *arm) /* remove zero sized bones, this gives unstable restposes */ for (eBone = arm->edbo->first; eBone; eBone = neBone) { - float len = len_v3v3(eBone->head, eBone->tail); + float len_sq = len_squared_v3v3(eBone->head, eBone->tail); neBone = eBone->next; - if (len <= 0.000001f) { /* FLT_EPSILON is too large? */ + if (len_sq <= SQUARE(0.000001f)) { /* FLT_EPSILON is too large? */ EditBone *fBone; /* Find any bones that refer to this bone */ @@ -548,7 +584,7 @@ void ED_armature_from_edit(bArmature *arm) /* Copy the bones from the editData into the armature */ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { newBone = MEM_callocN(sizeof(Bone), "bone"); - eBone->temp = newBone; /* Associate the real Bones with the EditBones */ + eBone->temp.bone = newBone; /* Associate the real Bones with the EditBones */ BLI_strncpy(newBone->name, eBone->name, sizeof(newBone->name)); copy_v3_v3(newBone->arm_head, eBone->head); @@ -581,48 +617,29 @@ void ED_armature_from_edit(bArmature *arm) newBone->prop = IDP_CopyProperty(eBone->prop); } - /* Fix parenting in a separate pass to ensure ebone->bone connections - * are valid at this point */ + /* Fix parenting in a separate pass to ensure ebone->bone connections are valid at this point. + * Do not set bone->head/tail here anymore, using EditBone data for that is not OK since our later fiddling + * with parent's arm_mat (for roll conversion) may have some small but visible impact on locations (T46010). */ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { - newBone = (Bone *)eBone->temp; + newBone = eBone->temp.bone; if (eBone->parent) { - newBone->parent = (Bone *)eBone->parent->temp; + newBone->parent = eBone->parent->temp.bone; BLI_addtail(&newBone->parent->childbase, newBone); - - { - float M_parentRest[3][3]; - float iM_parentRest[3][3]; - - /* Get the parent's matrix (rotation only) */ - ED_armature_ebone_to_mat3(eBone->parent, M_parentRest); - - /* Invert the parent matrix */ - invert_m3_m3(iM_parentRest, M_parentRest); - - /* Get the new head and tail */ - sub_v3_v3v3(newBone->head, eBone->head, eBone->parent->tail); - sub_v3_v3v3(newBone->tail, eBone->tail, eBone->parent->tail); - - mul_m3_v3(iM_parentRest, newBone->head); - mul_m3_v3(iM_parentRest, newBone->tail); - } } /* ...otherwise add this bone to the armature's bonebase */ else { - copy_v3_v3(newBone->head, eBone->head); - copy_v3_v3(newBone->tail, eBone->tail); BLI_addtail(&arm->bonebase, newBone); } } - /* Make a pass through the new armature to fix rolling */ - /* also builds restposition again (like BKE_armature_where_is) */ - fix_bonelist_roll(&arm->bonebase, arm->edbo); + /* Finalize definition of restpose data (roll, bone_mat, arm_mat, head/tail...). */ + armature_finalize_restpose(&arm->bonebase, arm->edbo); /* so all users of this armature should get rebuilt */ for (obt = G.main->object.first; obt; obt = obt->id.next) { - if (obt->data == arm) + if (obt->data == arm) { BKE_pose_rebuild(obt, arm); + } } DAG_id_tag_update(&arm->id, 0); @@ -695,24 +712,24 @@ static void ED_armature_ebone_listbase_copy(ListBase *lb_dst, ListBase *lb_src) if (ebone_dst->prop) { ebone_dst->prop = IDP_CopyProperty(ebone_dst->prop); } - ebone_src->temp = ebone_dst; + ebone_src->temp.ebone = ebone_dst; BLI_addtail(lb_dst, ebone_dst); } /* set pointers */ for (ebone_dst = lb_dst->first; ebone_dst; ebone_dst = ebone_dst->next) { if (ebone_dst->parent) { - ebone_dst->parent = ebone_dst->parent->temp; + ebone_dst->parent = ebone_dst->parent->temp.ebone; } } } -static void ED_armature_ebone_listbase_temp_clear(ListBase *lb) +void ED_armature_ebone_listbase_temp_clear(ListBase *lb) { EditBone *ebone; /* be sure they don't hang ever */ for (ebone = lb->first; ebone; ebone = ebone->next) { - ebone->temp = NULL; + ebone->temp.p = NULL; } } @@ -733,7 +750,7 @@ static void undoBones_to_editBones(void *uarmv, void *armv, void *UNUSED(data)) /* active bone */ if (uarm->act_edbone) { ebone = uarm->act_edbone; - arm->act_edbone = ebone->temp; + arm->act_edbone = ebone->temp.ebone; } else { arm->act_edbone = NULL; @@ -755,7 +772,7 @@ static void *editBones_to_undoBones(void *armv, void *UNUSED(obdata)) /* active bone */ if (arm->act_edbone) { ebone = arm->act_edbone; - uarm->act_edbone = ebone->temp; + uarm->act_edbone = ebone->temp.ebone; } ED_armature_ebone_listbase_temp_clear(&uarm->lb); diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c index 647b640ee61..2235f9f92cc 100644 --- a/source/blender/editors/armature/editarmature_retarget.c +++ b/source/blender/editors/armature/editarmature_retarget.c @@ -707,7 +707,7 @@ static void RIG_reconnectControlBones(RigGraph *rg) /* DO SOME MAGIC HERE */ for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -718,7 +718,7 @@ static void RIG_reconnectControlBones(RigGraph *rg) cti->get_constraint_targets(con, &targets); for (target_index = 0, ct = targets.first; ct; target_index++, ct = ct->next) { - if ((ct->tar == rg->ob) && strcmp(ct->subtarget, ctrl->bone->name) == 0) { + if ((ct->tar == rg->ob) && STREQ(ct->subtarget, ctrl->bone->name)) { /* SET bone link to bone corresponding to pchan */ EditBone *link = BLI_ghash_lookup(rg->bones_map, pchan->name); @@ -832,7 +832,7 @@ static void RIG_reconnectControlBones(RigGraph *rg) /* DO SOME MAGIC HERE */ for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -841,7 +841,7 @@ static void RIG_reconnectControlBones(RigGraph *rg) cti->get_constraint_targets(con, &targets); for (ct = targets.first; ct; ct = ct->next) { - if ((ct->tar == rg->ob) && strcmp(ct->subtarget, ctrl->bone->name) == 0) { + if ((ct->tar == rg->ob) && STREQ(ct->subtarget, ctrl->bone->name)) { /* SET bone link to ctrl corresponding to pchan */ RigControl *link = BLI_ghash_lookup(rg->controls_map, pchan->name); @@ -1160,7 +1160,7 @@ static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bo last_bone = bone; - if (strcmp(bone->name, "head") == 0) { + if (STREQ(bone->name, "head")) { contain_head = 1; } } @@ -1205,7 +1205,7 @@ static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bo static void RIG_findHead(RigGraph *rg) { if (rg->head == NULL) { - if (BLI_countlist(&rg->arcs) == 1) { + if (BLI_listbase_is_single(&rg->arcs)) { RigArc *arc = rg->arcs.first; rg->head = (RigNode *)arc->head; @@ -1958,7 +1958,7 @@ static void retargetArctoArcAggresive(bContext *C, RigGraph *rigg, RigArc *iarc, #endif float *vec0, *vec1; int *best_positions; - int nb_edges = BLI_countlist(&iarc->edges); + int nb_edges = BLI_listbase_count(&iarc->edges); int nb_joints = nb_edges - 1; RetargetMethod method = METHOD_MEMOIZE; int i; @@ -2152,7 +2152,7 @@ void exec_retargetArctoArc(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(th RigNode *inode_start = p->inode_start; ReebArc *earc = iarc->link_mesh; - if (BLI_countlist(&iarc->edges) == 1) { + if (BLI_listbase_is_single(&iarc->edges)) { RigEdge *edge = iarc->edges.first; if (testFlipArc(iarc, inode_start)) { @@ -2454,7 +2454,7 @@ const char *RIG_nameBone(RigGraph *rg, int arc_index, int bone_index) return "None"; } - if (bone_index == BLI_countlist(&arc->edges)) { + if (bone_index == BLI_listbase_count(&arc->edges)) { return "Last joint"; } @@ -2476,10 +2476,10 @@ int RIG_nbJoints(RigGraph *rg) RigArc *arc; int total = 0; - total += BLI_countlist(&rg->nodes); + total += BLI_listbase_count(&rg->nodes); for (arc = rg->arcs.first; arc; arc = arc->next) { - total += BLI_countlist(&arc->edges) - 1; /* -1 because end nodes are already counted */ + total += BLI_listbase_count(&arc->edges) - 1; /* -1 because end nodes are already counted */ } return total; diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index d75a23a6322..e4c3f73dd94 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -31,8 +31,6 @@ #include "BLI_blenlib.h" #include "BLI_math.h" -#include "BLF_translation.h" - #include "BKE_context.h" #include "BKE_sketch.h" @@ -335,11 +333,11 @@ static void sk_autoname(bContext *C, ReebArc *arc) if (side[0] == '\0') { valid = 1; } - else if (strcmp(side, "R") == 0 || strcmp(side, "L") == 0) { + else if (STREQ(side, "R") || STREQ(side, "L")) { valid = 1; caps = 1; } - else if (strcmp(side, "r") == 0 || strcmp(side, "l") == 0) { + else if (STREQ(side, "r") || STREQ(side, "l")) { valid = 1; caps = 0; } @@ -403,9 +401,7 @@ static void sk_retargetStroke(bContext *C, SK_Stroke *stk) RigGraph *rg; invert_m4_m4(imat, obedit->obmat); - - copy_m3_m4(tmat, obedit->obmat); - transpose_m3(tmat); + transpose_m3_m4(tmat, obedit->obmat); arc = sk_strokeToArc(stk, imat, tmat); @@ -440,7 +436,7 @@ static float sk_clampPointSize(SK_Point *pt, float size) static void sk_drawPoint(GLUquadric *quad, SK_Point *pt, float size) { - glTranslatef(pt->p[0], pt->p[1], pt->p[2]); + glTranslate3fv(pt->p); gluSphere(quad, sk_clampPointSize(pt, size), 8, 8); } @@ -459,7 +455,7 @@ static void sk_drawEdge(GLUquadric *quad, SK_Point *pt0, SK_Point *pt1, float si angle = angle_normalized_v3v3(vec2, vec1); - glRotatef(angle * (float)(180.0 / M_PI) + 180.0f, axis[0], axis[1], axis[2]); + glRotate3fv(angle * (float)(180.0 / M_PI) + 180.0f, axis); gluCylinder(quad, sk_clampPointSize(pt1, size), sk_clampPointSize(pt0, size), length, 8, 8); } @@ -479,7 +475,7 @@ static void sk_drawNormal(GLUquadric *quad, SK_Point *pt, float size, float heig angle = angle_normalized_v3v3(vec2, pt->no); - glRotatef(angle * (float)(180.0 / M_PI), axis[0], axis[1], axis[2]); + glRotate3fv(angle * (float)(180.0 / M_PI), axis); glColor3f(0, 1, 1); gluCylinder(quad, sk_clampPointSize(pt, size), 0, sk_clampPointSize(pt, height), 10, 2); @@ -1358,9 +1354,7 @@ static void sk_convertStroke(bContext *C, SK_Stroke *stk) head = NULL; invert_m4_m4(invmat, obedit->obmat); - - copy_m3_m4(tmat, obedit->obmat); - transpose_m3(tmat); + transpose_m3_m4(tmat, obedit->obmat); for (i = 0; i < stk->nb_points; i++) { SK_Point *pt = stk->points + i; @@ -1579,7 +1573,7 @@ static int sk_getIntersections(bContext *C, ListBase *list, SK_Sketch *sketch, S added = MAX2(s_added, added); } - BLI_sortlist(list, cmpIntersections); + BLI_listbase_sort(list, cmpIntersections); return added; } @@ -1698,7 +1692,7 @@ int sk_detectCommandGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UN if (gest->nb_segments > 2 && gest->nb_intersections == 2 && gest->nb_self_intersections == 1) { SK_Intersection *isect, *self_isect; - /* get the the last intersection of the first pair */ + /* get the last intersection of the first pair */ for (isect = gest->intersections.first; isect; isect = isect->next) { if (isect->stroke == isect->next->stroke) { isect = isect->next; @@ -1957,7 +1951,7 @@ static void sk_applyGesture(bContext *C, SK_Sketch *sketch) /********************************************/ -static int sk_selectStroke(bContext *C, SK_Sketch *sketch, const int mval[2], int extend) +static bool sk_selectStroke(bContext *C, SK_Sketch *sketch, const int mval[2], const bool extend) { ViewContext vc; rcti rect; @@ -2118,7 +2112,7 @@ static void sk_drawSketch(Scene *scene, View3D *UNUSED(v3d), SK_Sketch *sketch, glColor3fv(colors[index]); glPushMatrix(); - glTranslatef(p->p[0], p->p[1], p->p[2]); + glTranslate3fv(p->p); gluSphere(quad, 0.02, 8, 8); glPopMatrix(); } @@ -2245,15 +2239,19 @@ static int sketch_delete(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNU return OPERATOR_FINISHED; } -void BIF_sk_selectStroke(bContext *C, const int mval[2], short extend) +bool BIF_sk_selectStroke(bContext *C, const int mval[2], const bool extend) { ToolSettings *ts = CTX_data_tool_settings(C); SK_Sketch *sketch = contextSketch(C, 0); if (sketch != NULL && ts->bone_sketching & BONE_SKETCHING) { - if (sk_selectStroke(C, sketch, mval, extend)) + if (sk_selectStroke(C, sketch, mval, extend)) { ED_area_tag_redraw(CTX_wm_area(C)); + return true; + } } + + return false; } void BIF_convertSketch(bContext *C) diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index 49650fcadbf..b8dc4e1e7ab 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -35,8 +35,9 @@ #include "BLI_edgehash.h" #include "BLI_memarena.h" #include "BLI_string.h" +#include "BLI_alloca.h" -#include "BLF_translation.h" +#include "BLT_translation.h" #include "BKE_DerivedMesh.h" #include "BKE_modifier.h" @@ -84,9 +85,10 @@ struct LaplacianSystem { EdgeHash *edgehash; /* edge hash for construction */ struct HeatWeighting { - MFace *mface; + const MLoopTri *mlooptri; + const MLoop *mloop; /* needed to find vertices by index */ int totvert; - int totface; + int tottri; float (*verts)[3]; /* vertex coordinates */ float (*vnors)[3]; /* vertex normals */ @@ -100,7 +102,7 @@ struct LaplacianSystem { float *mindist; /* minimum distance to a bone for all vertices */ BVHTree *bvhtree; /* ray tracing acceleration structure */ - MFace **vface; /* a face that the vertex belongs to */ + const MLoopTri **vltree; /* a looptri that the vertex belongs to */ } heat; #ifdef RIGID_DEFORM @@ -127,12 +129,12 @@ struct LaplacianSystem { static void laplacian_increase_edge_count(EdgeHash *edgehash, int v1, int v2) { - void **p = BLI_edgehash_lookup_p(edgehash, v1, v2); + void **p; - if (p) + if (BLI_edgehash_ensure_p(edgehash, v1, v2, &p)) *p = (void *)((intptr_t)*p + (intptr_t)1); else - BLI_edgehash_insert(edgehash, v1, v2, (void *)(intptr_t)1); + *p = (void *)((intptr_t)1); } static int laplacian_edge_count(EdgeHash *edgehash, int v1, int v2) @@ -377,30 +379,33 @@ typedef struct BVHCallbackUserData { LaplacianSystem *sys; } BVHCallbackUserData; -static void bvh_callback(void *userdata, int index, const BVHTreeRay *UNUSED(ray), BVHTreeRayHit *hit) +static void bvh_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) { BVHCallbackUserData *data = (struct BVHCallbackUserData *)userdata; - MFace *mf = data->sys->heat.mface + index; + const MLoopTri *lt = &data->sys->heat.mlooptri[index]; + const MLoop *mloop = data->sys->heat.mloop; float (*verts)[3] = data->sys->heat.verts; - float lambda, uv[2], n[3], dir[3]; + const float *vtri_co[3]; + float dist_test; - mul_v3_v3fl(dir, data->vec, hit->dist); + vtri_co[0] = verts[mloop[lt->tri[0]].v]; + vtri_co[1] = verts[mloop[lt->tri[1]].v]; + vtri_co[2] = verts[mloop[lt->tri[2]].v]; - if (isect_ray_tri_v3(data->start, dir, verts[mf->v1], verts[mf->v2], verts[mf->v3], &lambda, uv)) { - normal_tri_v3(n, verts[mf->v1], verts[mf->v2], verts[mf->v3]); - if (lambda < 1.0f && dot_v3v3(n, data->vec) < -1e-5f) { - hit->index = index; - hit->dist *= lambda; - } - } - - mul_v3_v3fl(dir, data->vec, hit->dist); - - if (isect_ray_tri_v3(data->start, dir, verts[mf->v1], verts[mf->v3], verts[mf->v4], &lambda, uv)) { - normal_tri_v3(n, verts[mf->v1], verts[mf->v3], verts[mf->v4]); - if (lambda < 1.0f && dot_v3v3(n, data->vec) < -1e-5f) { - hit->index = index; - hit->dist *= lambda; +#ifdef USE_KDOPBVH_WATERTIGHT + if (isect_ray_tri_watertight_v3(data->start, ray->isect_precalc, UNPACK3(vtri_co), &dist_test, NULL)) +#else + UNUSED_VARS(ray); + if (isect_ray_tri_v3(data->start, data->vec, UNPACK3(vtri_co), &dist_test, NULL)) +#endif + { + if (dist_test < hit->dist) { + float n[3]; + normal_tri_v3(n, UNPACK3(vtri_co)); + if (dot_v3v3(n, data->vec) < -1e-5f) { + hit->index = index; + hit->dist = dist_test; + } } } } @@ -408,34 +413,36 @@ static void bvh_callback(void *userdata, int index, const BVHTreeRay *UNUSED(ray /* Raytracing for vertex to bone/vertex visibility */ static void heat_ray_tree_create(LaplacianSystem *sys) { - MFace *mface = sys->heat.mface; + const MLoopTri *looptri = sys->heat.mlooptri; + const MLoop *mloop = sys->heat.mloop; float (*verts)[3] = sys->heat.verts; - int totface = sys->heat.totface; + int tottri = sys->heat.tottri; int totvert = sys->heat.totvert; int a; - sys->heat.bvhtree = BLI_bvhtree_new(totface, 0.0f, 4, 6); - sys->heat.vface = MEM_callocN(sizeof(MFace *) * totvert, "HeatVFaces"); + sys->heat.bvhtree = BLI_bvhtree_new(tottri, 0.0f, 4, 6); + sys->heat.vltree = MEM_callocN(sizeof(MLoopTri *) * totvert, "HeatVFaces"); - for (a = 0; a < totface; a++) { - MFace *mf = mface + a; + for (a = 0; a < tottri; a++) { + const MLoopTri *lt = &looptri[a]; float bb[6]; + int vtri[3]; + + vtri[0] = mloop[lt->tri[0]].v; + vtri[1] = mloop[lt->tri[1]].v; + vtri[2] = mloop[lt->tri[2]].v; INIT_MINMAX(bb, bb + 3); - minmax_v3v3_v3(bb, bb + 3, verts[mf->v1]); - minmax_v3v3_v3(bb, bb + 3, verts[mf->v2]); - minmax_v3v3_v3(bb, bb + 3, verts[mf->v3]); - if (mf->v4) { - minmax_v3v3_v3(bb, bb + 3, verts[mf->v4]); - } + minmax_v3v3_v3(bb, bb + 3, verts[vtri[0]]); + minmax_v3v3_v3(bb, bb + 3, verts[vtri[1]]); + minmax_v3v3_v3(bb, bb + 3, verts[vtri[2]]); BLI_bvhtree_insert(sys->heat.bvhtree, a, bb, 2); //Setup inverse pointers to use on isect.orig - sys->heat.vface[mf->v1] = mf; - sys->heat.vface[mf->v2] = mf; - sys->heat.vface[mf->v3] = mf; - if (mf->v4) sys->heat.vface[mf->v4] = mf; + sys->heat.vltree[vtri[0]] = lt; + sys->heat.vltree[vtri[1]] = lt; + sys->heat.vltree[vtri[2]] = lt; } BLI_bvhtree_balance(sys->heat.bvhtree); @@ -445,12 +452,12 @@ static int heat_ray_source_visible(LaplacianSystem *sys, int vertex, int source) { BVHTreeRayHit hit; BVHCallbackUserData data; - MFace *mface; + const MLoopTri *lt; float end[3]; int visible; - mface = sys->heat.vface[vertex]; - if (!mface) + lt = sys->heat.vltree[vertex]; + if (lt == NULL) return 1; data.sys = sys; @@ -568,8 +575,9 @@ static void heat_calc_vnormals(LaplacianSystem *sys) static void heat_laplacian_create(LaplacianSystem *sys) { - MFace *mface = sys->heat.mface, *mf; - int totface = sys->heat.totface; + const MLoopTri *mlooptri = sys->heat.mlooptri, *lt; + const MLoop *mloop = sys->heat.mloop; + int tottri = sys->heat.tottri; int totvert = sys->heat.totvert; int a; @@ -582,10 +590,12 @@ static void heat_laplacian_create(LaplacianSystem *sys) for (a = 0; a < totvert; a++) laplacian_add_vertex(sys, sys->heat.verts[a], 0); - for (a = 0, mf = mface; a < totface; a++, mf++) { - laplacian_add_triangle(sys, mf->v1, mf->v2, mf->v3); - if (mf->v4) - laplacian_add_triangle(sys, mf->v1, mf->v3, mf->v4); + for (a = 0, lt = mlooptri; a < tottri; a++, lt++) { + int vtri[3]; + vtri[0] = mloop[lt->tri[0]].v; + vtri[1] = mloop[lt->tri[1]].v; + vtri[2] = mloop[lt->tri[2]].v; + laplacian_add_triangle(sys, UNPACK3(vtri)); } /* for distance computation in set_H */ @@ -598,7 +608,8 @@ static void heat_laplacian_create(LaplacianSystem *sys) static void heat_system_free(LaplacianSystem *sys) { BLI_bvhtree_free(sys->heat.bvhtree); - MEM_freeN(sys->heat.vface); + MEM_freeN(sys->heat.vltree); + MEM_freeN((void *)sys->heat.mlooptri); MEM_freeN(sys->heat.mindist); MEM_freeN(sys->heat.H); @@ -626,9 +637,9 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, float (*root)[3], float (*tip)[3], int *selected, const char **err_str) { LaplacianSystem *sys; + MLoopTri *mlooptri; MPoly *mp; MLoop *ml; - MFace *mf; float solution, weight; int *vertsflipped = NULL, *mask = NULL; int a, tottri, j, bbone, firstsegment, lastsegment; @@ -641,15 +652,7 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, *err_str = NULL; /* bone heat needs triangulated faces */ - BKE_mesh_tessface_ensure(me); - - for (tottri = 0, a = 0, mf = me->mface; a < me->totface; mf++, a++) { - tottri++; - if (mf->v4) tottri++; - } - - if (tottri == 0) - return; + tottri = poly_to_tri_count(me->totpoly, me->totloop); /* count triangles and create mask */ if (ob->mode & OB_MODE_WEIGHT_PAINT && @@ -679,8 +682,17 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, /* create laplacian */ sys = laplacian_system_construct_begin(me->totvert, tottri, 1); - sys->heat.mface = me->mface; - sys->heat.totface = me->totface; + sys->heat.tottri = poly_to_tri_count(me->totpoly, me->totloop); + mlooptri = MEM_mallocN(sizeof(*sys->heat.mlooptri) * sys->heat.tottri, __func__); + + BKE_mesh_recalc_looptri( + me->mloop, me->mpoly, + me->mvert, + me->totloop, me->totpoly, + mlooptri); + + sys->heat.mlooptri = mlooptri; + sys->heat.mloop = me->mloop; sys->heat.totvert = me->totvert; sys->heat.verts = verts; sys->heat.root = root; @@ -1041,18 +1053,26 @@ void rigid_deform_end(int cancel) #define MESHDEFORM_TAG_INTERIOR 2 #define MESHDEFORM_TAG_EXTERIOR 3 +/** minimum length for #MDefBoundIsect.len */ #define MESHDEFORM_LEN_THRESHOLD 1e-6f #define MESHDEFORM_MIN_INFLUENCE 0.0005f -static int MESHDEFORM_OFFSET[7][3] = { +static const int MESHDEFORM_OFFSET[7][3] = { {0, 0, 0}, {1, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}, {0, 0, 1}, {0, 0, -1} }; typedef struct MDefBoundIsect { - float co[3], uvw[4]; - int nvert, v[4], facing; + /* intersection on the cage 'cagecos' */ + float co[3]; + /* non-facing intersections are considered interior */ + bool facing; + /* ray-cast index aligned with MPoly (ray-hit-triangle isn't needed) */ + int poly_index; + /* distance from 'co' to the ray-cast start (clamped to avoid zero division) */ float len; + /* weights aligned with the MPoly's loop indices */ + float poly_weights[0]; } MDefBoundIsect; typedef struct MDefBindInfluence { @@ -1091,15 +1111,23 @@ typedef struct MeshDeformBind { BVHTree *bvhtree; BVHTreeFromMesh bvhdata; + + /* avoid DM function calls during intersections */ + struct { + const MPoly *mpoly; + const MLoop *mloop; + const MLoopTri *looptri; + const float (*poly_nors)[3]; + } cagedm_cache; } MeshDeformBind; typedef struct MeshDeformIsect { float start[3]; float vec[3]; + float vec_length; float lambda; - void *face; - int isect; + bool isect; float u, v; } MeshDeformIsect; @@ -1169,34 +1197,41 @@ static int meshdeform_tri_intersect(const float orig[3], const float end[3], con return 1; } +struct MeshRayCallbackData { + MeshDeformBind *mdb; + MeshDeformIsect *isec; +}; + static void harmonic_ray_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) { - void **data = userdata; - MeshDeformBind *mdb = data[1]; - MFace *mface = data[0], *mf; - MeshDeformIsect *isec = data[2]; - float no[3], co[3], end[3], uvw[3], dist, face[4][3]; + struct MeshRayCallbackData *data = userdata; + MeshDeformBind *mdb = data->mdb; + const MLoop *mloop = mdb->cagedm_cache.mloop; + const MLoopTri *looptri = mdb->cagedm_cache.looptri, *lt; + const float (*poly_nors)[3] = mdb->cagedm_cache.poly_nors; + MeshDeformIsect *isec = data->isec; + float no[3], co[3], end[3], uvw[3], dist; + float *face[3]; - mf = mface + index; + lt = &looptri[index]; - copy_v3_v3(face[0], mdb->cagecos[mf->v1]); - copy_v3_v3(face[1], mdb->cagecos[mf->v2]); - copy_v3_v3(face[2], mdb->cagecos[mf->v3]); - if (mf->v4) - copy_v3_v3(face[3], mdb->cagecos[mf->v4]); + face[0] = mdb->cagecos[mloop[lt->tri[0]].v]; + face[1] = mdb->cagecos[mloop[lt->tri[1]].v]; + face[2] = mdb->cagecos[mloop[lt->tri[2]].v]; add_v3_v3v3(end, isec->start, isec->vec); - if (!meshdeform_tri_intersect(ray->origin, end, face[0], face[1], face[2], co, uvw)) - if (!mf->v4 || !meshdeform_tri_intersect(ray->origin, end, face[0], face[2], face[3], co, uvw)) - return; - - if (!mf->v4) - normal_tri_v3(no, face[0], face[1], face[2]); - else - normal_quad_v3(no, face[0], face[1], face[2], face[3]); - - dist = len_v3v3(ray->origin, co) / len_v3(isec->vec); + if (!meshdeform_tri_intersect(ray->origin, end, UNPACK3(face), co, uvw)) + return; + + if (poly_nors) { + copy_v3_v3(no, poly_nors[lt->poly]); + } + else { + normal_tri_v3(no, UNPACK3(face)); + } + + dist = len_v3v3(ray->origin, co) / isec->vec_length; if (dist < hit->dist) { hit->index = index; hit->dist = dist; @@ -1204,19 +1239,18 @@ static void harmonic_ray_callback(void *userdata, int index, const BVHTreeRay *r isec->isect = (dot_v3v3(no, ray->direction) <= 0.0f); isec->lambda = dist; - isec->face = mf; } } static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, const float co1[3], const float co2[3]) { - MDefBoundIsect *isect; BVHTreeRayHit hit; MeshDeformIsect isect_mdef; - float (*cagecos)[3]; - void *data[3] = {mdb->cagedm->getTessFaceArray(mdb->cagedm), mdb, &isect_mdef}; - MFace *mface1 = data[0], *mface; - float vert[4][3], len, end[3]; + struct MeshRayCallbackData data = { + mdb, + &isect_mdef, + }; + float end[3], vec_normal[3]; // static float epsilon[3] = {1e-4, 1e-4, 1e-4}; /* happens binding when a cage has no faces */ @@ -1235,42 +1269,41 @@ static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, const copy_v3_v3(end, co2); #endif sub_v3_v3v3(isect_mdef.vec, end, isect_mdef.start); + isect_mdef.vec_length = normalize_v3_v3(vec_normal, isect_mdef.vec); hit.index = -1; hit.dist = FLT_MAX; - if (BLI_bvhtree_ray_cast(mdb->bvhtree, isect_mdef.start, isect_mdef.vec, - 0.0, &hit, harmonic_ray_callback, data) != -1) + if (BLI_bvhtree_ray_cast(mdb->bvhtree, isect_mdef.start, vec_normal, + 0.0, &hit, harmonic_ray_callback, &data) != -1) { - len = isect_mdef.lambda; - isect_mdef.face = mface = mface1 + hit.index; + const MLoop *mloop = mdb->cagedm_cache.mloop; + const MLoopTri *lt = &mdb->cagedm_cache.looptri[hit.index]; + const MPoly *mp = &mdb->cagedm_cache.mpoly[lt->poly]; + const float (*cagecos)[3] = mdb->cagecos; + const float len = isect_mdef.lambda; + MDefBoundIsect *isect; - /* create MDefBoundIsect */ - isect = BLI_memarena_alloc(mdb->memarena, sizeof(*isect)); + float (*mp_cagecos)[3] = BLI_array_alloca(mp_cagecos, mp->totloop); + int i; + + /* create MDefBoundIsect, and extra for 'poly_weights[]' */ + isect = BLI_memarena_alloc(mdb->memarena, sizeof(*isect) + (sizeof(float) * mp->totloop)); /* compute intersection coordinate */ - isect->co[0] = co1[0] + isect_mdef.vec[0] * len; - isect->co[1] = co1[1] + isect_mdef.vec[1] * len; - isect->co[2] = co1[2] + isect_mdef.vec[2] * len; + madd_v3_v3v3fl(isect->co, co1, isect_mdef.vec, len); - isect->len = len_v3v3(co1, isect->co); - if (isect->len < MESHDEFORM_LEN_THRESHOLD) - isect->len = MESHDEFORM_LEN_THRESHOLD; + isect->facing = isect_mdef.isect; - isect->v[0] = mface->v1; - isect->v[1] = mface->v2; - isect->v[2] = mface->v3; - isect->v[3] = mface->v4; - isect->nvert = (mface->v4) ? 4 : 3; + isect->poly_index = lt->poly; - isect->facing = isect_mdef.isect; + isect->len = max_ff(len_v3v3(co1, isect->co), MESHDEFORM_LEN_THRESHOLD); /* compute mean value coordinates for interpolation */ - cagecos = mdb->cagecos; - copy_v3_v3(vert[0], cagecos[mface->v1]); - copy_v3_v3(vert[1], cagecos[mface->v2]); - copy_v3_v3(vert[2], cagecos[mface->v3]); - if (mface->v4) copy_v3_v3(vert[3], cagecos[mface->v4]); - interp_weights_poly_v3(isect->uvw, vert, isect->nvert, isect->co); + for (i = 0; i < mp->totloop; i++) { + copy_v3_v3(mp_cagecos[i], cagecos[mloop[mp->loopstart + i].v]); + } + + interp_weights_poly_v3(isect->poly_weights, mp_cagecos, mp->totloop, isect->co); return isect; } @@ -1303,7 +1336,7 @@ static int meshdeform_inside_cage(MeshDeformBind *mdb, float *co) /* solving */ -static int meshdeform_index(MeshDeformBind *mdb, int x, int y, int z, int n) +BLI_INLINE int meshdeform_index(MeshDeformBind *mdb, int x, int y, int z, int n) { int size = mdb->size; @@ -1321,7 +1354,7 @@ static int meshdeform_index(MeshDeformBind *mdb, int x, int y, int z, int n) return x + y * size + z * size * size; } -static void meshdeform_cell_center(MeshDeformBind *mdb, int x, int y, int z, int n, float *center) +BLI_INLINE void meshdeform_cell_center(MeshDeformBind *mdb, int x, int y, int z, int n, float *center) { x += MESHDEFORM_OFFSET[n][0]; y += MESHDEFORM_OFFSET[n][1]; @@ -1418,14 +1451,18 @@ static void meshdeform_bind_floodfill(MeshDeformBind *mdb) MEM_freeN(stack); } -static float meshdeform_boundary_phi(MeshDeformBind *UNUSED(mdb), MDefBoundIsect *isect, int cagevert) +static float meshdeform_boundary_phi(const MeshDeformBind *mdb, const MDefBoundIsect *isect, int cagevert) { - int a; + const MLoop *mloop = mdb->cagedm_cache.mloop; + const MPoly *mp = &mdb->cagedm_cache.mpoly[isect->poly_index]; + int i; + + for (i = 0; i < mp->totloop; i++) { + if (mloop[mp->loopstart + i].v == cagevert) { + return isect->poly_weights[i]; + } + } - for (a = 0; a < isect->nvert; a++) - if (isect->v[a] == cagevert) - return isect->uvw[a]; - return 0.0f; } @@ -1719,7 +1756,7 @@ static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind /* sanity check */ for (b = 0; b < mdb->size3; b++) if (mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR) - if (fabs(mdb->totalphi[b] - 1.0f) > 1e-4) + if (fabsf(mdb->totalphi[b] - 1.0f) > 1e-4f) printf("totalphi deficiency [%s|%d] %d: %.10f\n", (mdb->tag[b] == MESHDEFORM_TAG_INTERIOR) ? "interior" : "boundary", mdb->semibound[b], mdb->varidx[b], mdb->totalphi[b]); #endif @@ -1752,7 +1789,7 @@ static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierDa mdb->totalphi = MEM_callocN(sizeof(float) * mdb->size3, "MeshDeformBindTotalPhi"); mdb->boundisect = MEM_callocN(sizeof(*mdb->boundisect) * mdb->size3, "MDefBoundIsect"); mdb->semibound = MEM_callocN(sizeof(int) * mdb->size3, "MDefSemiBound"); - mdb->bvhtree = bvhtree_from_mesh_faces(&mdb->bvhdata, mdb->cagedm, FLT_EPSILON * 100, 4, 6); + mdb->bvhtree = bvhtree_from_mesh_looptri(&mdb->bvhdata, mdb->cagedm, FLT_EPSILON * 100, 4, 6); mdb->inside = MEM_callocN(sizeof(int) * mdb->totvert, "MDefInside"); if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) @@ -1763,6 +1800,15 @@ static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierDa mdb->memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "harmonic coords arena"); BLI_memarena_use_calloc(mdb->memarena); + /* initialize data from 'cagedm' for reuse */ + { + DerivedMesh *dm = mdb->cagedm; + mdb->cagedm_cache.mpoly = dm->getPolyArray(dm); + mdb->cagedm_cache.mloop = dm->getLoopArray(dm); + mdb->cagedm_cache.looptri = dm->getLoopTriArray(dm); + mdb->cagedm_cache.poly_nors = dm->getPolyDataArray(dm, CD_NORMAL); /* can be NULL */ + } + /* make bounding box equal size in all directions, add padding, and compute * width of the cells */ maxwidth = -1.0f; diff --git a/source/blender/editors/armature/meshlaplacian.h b/source/blender/editors/armature/meshlaplacian.h index 820aedc5467..1412136c1a8 100644 --- a/source/blender/editors/armature/meshlaplacian.h +++ b/source/blender/editors/armature/meshlaplacian.h @@ -29,11 +29,9 @@ //#define RIGID_DEFORM -struct Scene; struct Object; struct Mesh; struct bDeformGroup; -struct MeshDeformModifierData; #ifdef RIGID_DEFORM struct EditMesh; diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index da68108285f..e87c324d7ec 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -381,14 +381,14 @@ static void pose_copy_menu(Scene *scene) * but for constraints (just add local constraints) */ if (pose_has_protected_selected(ob, 0)) { - i = BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */ + i = BLI_listbase_count(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */ if (i < 25) nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4|Constraints... %x5"); else nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4"); } else { - i = BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */ + i = BLI_listbase_count(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */ if (i < 25) nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4|Constraints... %x5|%l|Transform Locks %x6|IK Limits %x7|Bone Shape %x8"); else @@ -436,7 +436,7 @@ static void pose_copy_menu(Scene *scene) pchan->constflag |= pchanact->constflag; if (ob->pose) - ob->pose->flag |= POSE_RECALC; + BKE_pose_tag_recalc(bmain, ob->pose); } break; case 6: /* Transform Locks */ @@ -503,7 +503,7 @@ static void pose_copy_menu(Scene *scene) /* build the puplist of constraints */ for (con = pchanact->constraints.first, i = 0; con; con = con->next, i++) { const_toggle[i] = 1; -// add_numbut(i, TOG|INT, con->name, 0, 0, &(const_toggle[i]), ""); +// add_numbut(i, UI_BTYPE_TOGGLE|INT, con->name, 0, 0, &(const_toggle[i]), ""); } // if (!do_clever_numbuts("Select Constraints", i, REDRAW)) { @@ -550,7 +550,7 @@ static void pose_copy_menu(Scene *scene) BKE_pose_update_constraint_flags(ob->pose); /* we could work out the flags but its simpler to do this */ if (ob->pose) - ob->pose->flag |= POSE_RECALC; + BKE_pose_tag_recalc(bmain, ob->pose); } DAG_id_tag_update(&ob->id, OB_RECALC_DATA); // and all its relations @@ -595,7 +595,7 @@ void POSE_OT_flip_names(wmOperatorType *ot) /* identifiers */ ot->name = "Flip Names"; ot->idname = "POSE_OT_flip_names"; - ot->description = "Flips (and corrects) the axis suffixes of the the names of selected bones"; + ot->description = "Flips (and corrects) the axis suffixes of the names of selected bones"; /* api callbacks */ ot->exec = pose_flip_names_exec; @@ -853,7 +853,7 @@ void ARMATURE_OT_armature_layers(wmOperatorType *ot) /* Present a popup to get the layers that should be used */ static int pose_bone_layers_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */ + int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */ /* get layers that are active already */ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones) @@ -862,8 +862,7 @@ static int pose_bone_layers_invoke(bContext *C, wmOperator *op, const wmEvent *e /* loop over the bits for this pchan's layers, adding layers where they're needed */ for (bit = 0; bit < 32; bit++) { - if (pchan->bone->layer & (1 << bit)) - layers[bit] = 1; + layers[bit] = (pchan->bone->layer & (1u << bit)) != 0; } } CTX_DATA_END; @@ -937,8 +936,9 @@ static int armature_bone_layers_invoke(bContext *C, wmOperator *op, const wmEven /* loop over the bits for this pchan's layers, adding layers where they're needed */ for (bit = 0; bit < 32; bit++) { - if (ebone->layer & (1 << bit)) + if (ebone->layer & (1u << bit)) { layers[bit] = 1; + } } } CTX_DATA_END; diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c index 50d9d300d15..4d9df06f33f 100644 --- a/source/blender/editors/armature/pose_group.c +++ b/source/blender/editors/armature/pose_group.c @@ -130,6 +130,7 @@ static int pose_groups_menu_invoke(bContext *C, wmOperator *op, const wmEvent *U { Object *ob = ED_pose_object_from_context(C); bPose *pose; + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "type"); uiPopupMenu *pup; uiLayout *layout; @@ -140,12 +141,23 @@ static int pose_groups_menu_invoke(bContext *C, wmOperator *op, const wmEvent *U if (ELEM(NULL, ob, ob->pose)) return OPERATOR_CANCELLED; pose = ob->pose; + + /* If group index is set, try to use it! */ + if (RNA_property_is_set(op->ptr, prop)) { + const int num_groups = BLI_listbase_count(&pose->agroups); + const int group = RNA_property_int_get(op->ptr, prop); + + /* just use the active group index, and call the exec callback for the calling operator */ + if (group > 0 && group <= num_groups) { + return op->type->exec(C, op); + } + } /* if there's no active group (or active is invalid), create a new menu to find it */ if (pose->active_group <= 0) { /* create a new menu, and start populating it with group names */ - pup = uiPupMenuBegin(C, op->type->name, ICON_NONE); - layout = uiPupMenuLayout(pup); + pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE); + layout = UI_popup_menu_layout(pup); /* special entry - allow to create new group, then use that * (not to be used for removing though) @@ -160,9 +172,9 @@ static int pose_groups_menu_invoke(bContext *C, wmOperator *op, const wmEvent *U uiItemIntO(layout, grp->name, ICON_NONE, op->idname, "type", i); /* finish building the menu, and process it (should result in calling self again) */ - uiPupMenuEnd(C, pup); + UI_popup_menu_end(C, pup); - return OPERATOR_CANCELLED; + return OPERATOR_INTERFACE; } else { /* just use the active group index, and call the exec callback for the calling operator */ @@ -365,8 +377,8 @@ typedef struct tSortActionGroup { /* compare bone groups by name */ static int compare_agroup(const void *sgrp_a_ptr, const void *sgrp_b_ptr) { - tSortActionGroup *sgrp_a = (tSortActionGroup *)sgrp_a_ptr; - tSortActionGroup *sgrp_b = (tSortActionGroup *)sgrp_b_ptr; + const tSortActionGroup *sgrp_a = sgrp_a_ptr; + const tSortActionGroup *sgrp_b = sgrp_b_ptr; return strcmp(sgrp_a->agrp->name, sgrp_b->agrp->name); } @@ -387,7 +399,7 @@ static int group_sort_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; /* create temporary array with bone groups and indices */ - agrp_count = BLI_countlist(&pose->agroups); + agrp_count = BLI_listbase_count(&pose->agroups); agrp_array = MEM_mallocN(sizeof(tSortActionGroup) * agrp_count, "sort bone groups"); for (agrp = pose->agroups.first, i = 0; agrp; agrp = agrp->next, i++) { BLI_assert(i < agrp_count); diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c index 0609fcc29e8..a984e5d1ccd 100644 --- a/source/blender/editors/armature/pose_lib.c +++ b/source/blender/editors/armature/pose_lib.c @@ -35,7 +35,7 @@ #include "BLI_blenlib.h" #include "BLI_dlrbTree.h" -#include "BLF_translation.h" +#include "BLT_translation.h" #include "DNA_anim_types.h" #include "DNA_armature_types.h" @@ -177,6 +177,15 @@ static int has_poselib_pose_data_poll(bContext *C) return (ob && ob->poselib); } +/* Poll callback for operators that require existing PoseLib data (with poses) + * as they need to do some editing work on those poses (i.e. not on lib-linked actions) + */ +static int has_poselib_pose_data_for_editing_poll(bContext *C) +{ + Object *ob = get_poselib_object(C); + return (ob && ob->poselib && !ob->poselib->id.lib); +} + /* ----------------------------------- */ /* Initialize a new poselib (whether it is needed or not) */ @@ -357,7 +366,7 @@ void POSELIB_OT_action_sanitize(wmOperatorType *ot) /* callbacks */ ot->exec = poselib_sanitize_exec; - ot->poll = has_poselib_pose_data_poll; + ot->poll = has_poselib_pose_data_for_editing_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -365,6 +374,25 @@ void POSELIB_OT_action_sanitize(wmOperatorType *ot) /* ------------------------------------------ */ +/* Poll callback for adding poses to a PoseLib */ +static int poselib_add_poll(bContext *C) +{ + /* There are 2 cases we need to be careful with: + * 1) When this operator is invoked from a hotkey, there may be no PoseLib yet + * 2) If a PoseLib already exists, we can't edit the action if it is a lib-linked + * actions, as data will be lost when saving the file + */ + if (ED_operator_posemode(C)) { + Object *ob = get_poselib_object(C); + if (ob) { + if ((ob->poselib == NULL) || (ob->poselib->id.lib == 0)) { + return true; + } + } + } + return false; +} + static void poselib_add_menu_invoke__replacemenu(bContext *C, uiLayout *layout, void *UNUSED(arg)) { Object *ob = get_poselib_object(C); @@ -404,8 +432,8 @@ static int poselib_add_menu_invoke(bContext *C, wmOperator *op, const wmEvent *U return OPERATOR_CANCELLED; /* start building */ - pup = uiPupMenuBegin(C, op->type->name, ICON_NONE); - layout = uiPupMenuLayout(pup); + pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE); + layout = UI_popup_menu_layout(pup); uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT); /* add new (adds to the first unoccupied frame) */ @@ -420,10 +448,10 @@ static int poselib_add_menu_invoke(bContext *C, wmOperator *op, const wmEvent *U uiItemMenuF(layout, IFACE_("Replace Existing..."), 0, poselib_add_menu_invoke__replacemenu, NULL); } - uiPupMenuEnd(C, pup); + UI_popup_menu_end(C, pup); /* this operator is only for a menu, not used further */ - return OPERATOR_CANCELLED; + return OPERATOR_INTERFACE; } @@ -472,7 +500,7 @@ static int poselib_add_exec(bContext *C, wmOperator *op) ANIM_apply_keyingset(C, NULL, act, ks, MODIFYKEY_MODE_INSERT, (float)frame); /* store new 'active' pose number */ - act->active_marker = BLI_countlist(&act->markers); + act->active_marker = BLI_listbase_count(&act->markers); /* done */ return OPERATOR_FINISHED; @@ -488,7 +516,7 @@ void POSELIB_OT_pose_add(wmOperatorType *ot) /* api callbacks */ ot->invoke = poselib_add_menu_invoke; ot->exec = poselib_add_exec; - ot->poll = ED_operator_posemode; + ot->poll = poselib_add_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -604,7 +632,7 @@ void POSELIB_OT_pose_remove(wmOperatorType *ot) /* api callbacks */ ot->invoke = WM_menu_invoke; ot->exec = poselib_remove_exec; - ot->poll = has_poselib_pose_data_poll; + ot->poll = has_poselib_pose_data_for_editing_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -692,7 +720,7 @@ void POSELIB_OT_pose_rename(wmOperatorType *ot) /* api callbacks */ ot->invoke = poselib_rename_invoke; ot->exec = poselib_rename_exec; - ot->poll = has_poselib_pose_data_poll; + ot->poll = has_poselib_pose_data_for_editing_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -916,7 +944,7 @@ static void poselib_keytag_pose(bContext *C, Scene *scene, tPoseLib_PreviewData KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID); ListBase dsources = {NULL, NULL}; - short autokey = autokeyframe_cfra_can_key(scene, &pld->ob->id); + bool autokey = autokeyframe_cfra_can_key(scene, &pld->ob->id); /* start tagging/keying */ for (agrp = act->groups.first; agrp; agrp = agrp->next) { @@ -1050,7 +1078,7 @@ static void poselib_preview_get_next(tPoseLib_PreviewData *pld, int step) LinkData *ld, *ldn, *ldc; /* free and rebuild if needed (i.e. if search-str changed) */ - if (strcmp(pld->searchstr, pld->searchold)) { + if (!STREQ(pld->searchstr, pld->searchold)) { /* free list of temporary search matches */ BLI_freelistN(&pld->searchp); @@ -1196,7 +1224,7 @@ static int poselib_preview_handle_event(bContext *UNUSED(C), wmOperator *op, con /* only accept 'press' event, and ignore 'release', so that we don't get double actions */ if (ELEM(event->val, KM_PRESS, KM_NOTHING) == 0) { - //printf("PoseLib: skipping event with type '%s' and val %d\n", WM_key_event_string(event->type), event->val); + //printf("PoseLib: skipping event with type '%s' and val %d\n", WM_key_event_string(event->type, false), event->val); return ret; } @@ -1348,7 +1376,7 @@ static int poselib_preview_handle_event(bContext *UNUSED(C), wmOperator *op, con else { /* change to last pose */ pld->marker = pld->act->markers.last; - pld->act->active_marker = BLI_countlist(&pld->act->markers); + pld->act->active_marker = BLI_listbase_count(&pld->act->markers); pld->redraw = PL_PREVIEW_REDRAWALL; } diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index ba5ef4f3b5d..44470c1f827 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -62,7 +62,7 @@ #include "armature_intern.h" -/* utility macros fro storing a temp int in the bone (selection flag) */ +/* utility macros for storing a temp int in the bone (selection flag) */ #define PBONE_PREV_FLAG_GET(pchan) ((void)0, (GET_INT_FROM_POINTER((pchan)->temp))) #define PBONE_PREV_FLAG_SET(pchan, val) ((pchan)->temp = SET_INT_IN_POINTER(val)) @@ -458,7 +458,7 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op { if (pchan->bone->flag & BONE_SELECTED) { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -518,71 +518,67 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op) { Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); bArmature *arm = ob->data; - Bone *curbone, *pabone, *chbone; + bPoseChannel *pchan_act; int direction = RNA_enum_get(op->ptr, "direction"); const bool add_to_sel = RNA_boolean_get(op->ptr, "extend"); - bool found = false; + bool changed = false; - CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones) - { - curbone = pchan->bone; - - if ((curbone->flag & BONE_UNSELECTABLE) == 0) { - if (curbone == arm->act_bone) { - if (direction == BONE_SELECT_PARENT) { - if (pchan->parent == NULL) continue; - else pabone = pchan->parent->bone; - - if (PBONE_SELECTABLE(arm, pabone)) { - if (!add_to_sel) curbone->flag &= ~BONE_SELECTED; - pabone->flag |= BONE_SELECTED; - arm->act_bone = pabone; - - found = 1; - break; - } + pchan_act = BKE_pose_channel_active(ob); + if (pchan_act == NULL) { + return OPERATOR_CANCELLED; + } + + if (direction == BONE_SELECT_PARENT) { + if (pchan_act->parent) { + Bone *bone_parent; + bone_parent = pchan_act->parent->bone; + + if (PBONE_SELECTABLE(arm, bone_parent)) { + if (!add_to_sel) { + pchan_act->bone->flag &= ~BONE_SELECTED; } - else { /* direction == BONE_SELECT_CHILD */ - /* the child member is only assigned to connected bones, see [#30340] */ -#if 0 - if (pchan->child == NULL) continue; - else chbone = pchan->child->bone; -#else - /* instead. find _any_ visible child bone, using the first one is a little arbitrary - campbell */ - chbone = pchan->child ? pchan->child->bone : NULL; - if (chbone == NULL) { - bPoseChannel *pchan_child; - - for (pchan_child = ob->pose->chanbase.first; pchan_child; pchan_child = pchan_child->next) { - /* possible we have multiple children, some invisible */ - if (PBONE_SELECTABLE(arm, pchan_child->bone)) { - if (pchan_child->parent == pchan) { - chbone = pchan_child->bone; - break; - } - } - } - } + bone_parent->flag |= BONE_SELECTED; + arm->act_bone = bone_parent; - if (chbone == NULL) continue; -#endif - - if (PBONE_SELECTABLE(arm, chbone)) { - if (!add_to_sel) curbone->flag &= ~BONE_SELECTED; - chbone->flag |= BONE_SELECTED; - arm->act_bone = chbone; - - found = 1; - break; + changed = true; + } + } + } + else { /* direction == BONE_SELECT_CHILD */ + bPoseChannel *pchan_iter; + Bone *bone_child = NULL; + int pass; + + /* first pass, only connected bones (the logical direct child) */ + for (pass = 0; pass < 2 && (bone_child == NULL); pass++) { + for (pchan_iter = ob->pose->chanbase.first; pchan_iter; pchan_iter = pchan_iter->next) { + /* possible we have multiple children, some invisible */ + if (PBONE_SELECTABLE(arm, pchan_iter->bone)) { + if (pchan_iter->parent == pchan_act) { + if ((pass == 1) || (pchan_iter->bone->flag & BONE_CONNECTED)) { + bone_child = pchan_iter->bone; + break; + } } } } } + + if (bone_child) { + arm->act_bone = bone_child; + + if (!add_to_sel) { + pchan_act->bone->flag &= ~BONE_SELECTED; + } + bone_child->flag |= BONE_SELECTED; + + changed = true; + } } - CTX_DATA_END; - if (found == 0) + if (changed == false) { return OPERATOR_CANCELLED; + } /* updates */ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); @@ -642,7 +638,7 @@ static bool pose_select_same_group(bContext *C, Object *ob, bool extend) return 0; /* count the number of groups */ - numGroups = BLI_countlist(&pose->agroups); + numGroups = BLI_listbase_count(&pose->agroups); if (numGroups == 0) return 0; @@ -825,7 +821,7 @@ static int pose_select_grouped_exec(bContext *C, wmOperator *op) break; default: - printf("pose_select_grouped() - Unknown selection type %d\n", type); + printf("pose_select_grouped() - Unknown selection type %u\n", type); break; } diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index 5f9f24d23a4..40328e0c06e 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -43,6 +43,7 @@ #include "BKE_context.h" #include "BKE_object.h" #include "BKE_report.h" +#include "BKE_unit.h" #include "RNA_access.h" #include "RNA_define.h" @@ -53,6 +54,7 @@ #include "ED_armature.h" #include "ED_keyframes_draw.h" #include "ED_markers.h" +#include "ED_numinput.h" #include "ED_screen.h" #include "armature_intern.h" @@ -98,6 +100,8 @@ typedef struct tPoseSlideOp { int flag; /* unused for now, but can later get used for storing runtime settings.... */ float percentage; /* 0-1 value for determining the influence of whatever is relevant */ + + NumInput num; /* numeric input */ } tPoseSlideOp; /* Pose Sliding Modes */ @@ -154,6 +158,12 @@ static int pose_slide_init(bContext *C, wmOperator *op, short mode) */ BLI_dlrbTree_init(&pso->keys); + /* initialise numeric input */ + initNumInput(&pso->num); + pso->num.idx_max = 0; /* one axis */ + pso->num.val_flag[0] |= NUM_NO_NEGATIVE; + pso->num.unit_type[0] = B_UNIT_NONE; /* percentages don't have any units... */ + /* return status is whether we've got all the data we were requested to get */ return 1; } @@ -201,6 +211,12 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, float *val) /* next/end */ eVal = evaluate_fcurve(fcu, (float)pso->nextFrame); + /* if both values are equal, don't do anything */ + if (IS_EQF(sVal, eVal)) { + (*val) = sVal; + return; + } + /* calculate the relative weights of the endpoints */ if (pso->mode == POSESLIDE_BREAKDOWN) { /* get weights from the percentage control */ @@ -234,7 +250,7 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, float *val) * - perform this weighting a number of times given by the percentage... */ int iters = (int)ceil(10.0f * pso->percentage); /* TODO: maybe a sensitivity ctrl on top of this is needed */ - + while (iters-- > 0) { (*val) = (-((sVal * w2) + (eVal * w1)) + ((*val) * 6.0f) ) / 5.0f; } @@ -247,7 +263,7 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, float *val) * - perform this weighting a number of times given by the percentage... */ int iters = (int)ceil(10.0f * pso->percentage); /* TODO: maybe a sensitivity ctrl on top of this is needed */ - + while (iters-- > 0) { (*val) = ( ((sVal * w2) + (eVal * w1)) + ((*val) * 5.0f) ) / 6.0f; } @@ -320,6 +336,7 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl) if (prop) { switch (RNA_property_type(prop)) { + /* continuous values that can be smoothly interpolated... */ case PROP_FLOAT: { float tval = RNA_property_float_get(&ptr, prop); @@ -327,8 +344,6 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl) RNA_property_float_set(&ptr, prop, tval); break; } - case PROP_BOOLEAN: - case PROP_ENUM: case PROP_INT: { float tval = (float)RNA_property_int_get(&ptr, prop); @@ -336,6 +351,23 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl) RNA_property_int_set(&ptr, prop, (int)tval); break; } + + /* values which can only take discrete values */ + case PROP_BOOLEAN: + { + float tval = (float)RNA_property_boolean_get(&ptr, prop); + pose_slide_apply_val(pso, fcu, &tval); + RNA_property_boolean_set(&ptr, prop, (int)tval); // XXX: do we need threshold clamping here? + break; + } + case PROP_ENUM: + { + /* don't handle this case - these don't usually represent interchangeable + * set of values which should be interpolated between + */ + break; + } + default: /* cannot handle */ //printf("Cannot Pose Slide non-numerical property\n"); @@ -404,11 +436,11 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl) } else if (pso->mode == POSESLIDE_PUSH) { float quat_diff[4], quat_orig[4]; - + /* calculate the delta transform from the previous to the current */ /* TODO: investigate ways to favour one transform more? */ sub_qt_qtqt(quat_diff, pchan->quat, quat_prev); - + /* make a copy of the original rotation */ copy_qt_qt(quat_orig, pchan->quat); @@ -418,7 +450,7 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl) else { float quat_interp[4], quat_orig[4]; int iters = (int)ceil(10.0f * pso->percentage); /* TODO: maybe a sensitivity ctrl on top of this is needed */ - + /* perform this blending several times until a satisfactory result is reached */ while (iters-- > 0) { /* calculate the interpolation between the endpoints */ @@ -512,7 +544,7 @@ static void pose_slide_reset(tPoseSlideOp *pso) /* draw percentage indicator in header */ static void pose_slide_draw_status(tPoseSlideOp *pso) { - char status_str[32]; + char status_str[256]; char mode_str[32]; switch (pso->mode) { @@ -532,7 +564,18 @@ static void pose_slide_draw_status(tPoseSlideOp *pso) break; } - BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%", mode_str, (int)(pso->percentage * 100.0f)); + if (hasNumInput(&pso->num)) { + Scene *scene = pso->scene; + char str_offs[NUM_STR_REP_LEN]; + + outputNumInput(&pso->num, str_offs, &scene->unit); + + BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_offs); + } + else { + BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%", mode_str, (int)(pso->percentage * 100.0f)); + } + ED_area_headerprint(pso->sa, status_str); } @@ -617,6 +660,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) { tPoseSlideOp *pso = op->customdata; wmWindow *win = CTX_wm_window(C); + const bool has_numinput = hasNumInput(&pso->num); switch (event->type) { case LEFTMOUSE: /* confirm */ @@ -656,25 +700,54 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) case MOUSEMOVE: /* calculate new position */ { - /* calculate percentage based on position of mouse (we only use x-axis for now. - * since this is more convenient for users to do), and store new percentage value - */ - pso->percentage = (event->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx); - RNA_float_set(op->ptr, "percentage", pso->percentage); - - /* update percentage indicator in header */ - pose_slide_draw_status(pso); - - /* reset transforms (to avoid accumulation errors) */ - pose_slide_reset(pso); - - /* apply... */ - pose_slide_apply(C, pso); + /* only handle mousemove if not doing numinput */ + if (has_numinput == false) { + /* calculate percentage based on position of mouse (we only use x-axis for now. + * since this is more convenient for users to do), and store new percentage value + */ + pso->percentage = (event->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx); + RNA_float_set(op->ptr, "percentage", pso->percentage); + + /* update percentage indicator in header */ + pose_slide_draw_status(pso); + + /* reset transforms (to avoid accumulation errors) */ + pose_slide_reset(pso); + + /* apply... */ + pose_slide_apply(C, pso); + } break; } - default: /* unhandled event (maybe it was some view manip? */ - /* allow to pass through */ - return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH; + default: + if ((event->val == KM_PRESS) && handleNumInput(C, &pso->num, event)) { + float value; + + /* Grab percentage from numeric input, and store this new value for redo + * NOTE: users see ints, while internally we use a 0-1 float + */ + value = pso->percentage * 100.0f; + applyNumInput(&pso->num, &value); + + pso->percentage = value / 100.0f; + CLAMP(pso->percentage, 0.0f, 1.0f); + RNA_float_set(op->ptr, "percentage", pso->percentage); + + /* update percentage indicator in header */ + pose_slide_draw_status(pso); + + /* reset transforms (to avoid accumulation errors) */ + pose_slide_reset(pso); + + /* apply... */ + pose_slide_apply(C, pso); + break; + } + else { + /* unhandled event - maybe it was some view manip? */ + /* allow to pass through */ + return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH; + } } /* still running... */ @@ -898,6 +971,8 @@ typedef enum ePosePropagate_Termination { /* stop when we run out of keyframes */ POSE_PROPAGATE_BEFORE_END, + /* only do on keyframes that are selected */ + POSE_PROPAGATE_SELECTED_KEYS, /* only do on the frames where markers are selected */ POSE_PROPAGATE_SELECTED_MARKERS } ePosePropagate_Termination; @@ -1098,13 +1173,20 @@ static void pose_propagate_fcurve(wmOperator *op, Object *ob, FCurve *fcu, * since it may be as of yet unkeyed * - if starting before the starting frame, don't touch the key, as it may have had some valid * values + * - if only doing selected keyframes, start from the first one */ - match = binarysearch_bezt_index(fcu->bezt, startFrame, fcu->totvert, &keyExists); - - if (fcu->bezt[match].vec[1][0] < startFrame) - i = match + 1; - else - i = match; + if (mode != POSE_PROPAGATE_SELECTED_KEYS) { + match = binarysearch_bezt_index(fcu->bezt, startFrame, fcu->totvert, &keyExists); + + if (fcu->bezt[match].vec[1][0] < startFrame) + i = match + 1; + else + i = match; + } + else { + /* selected - start from first keyframe */ + i = 0; + } for (bezt = &fcu->bezt[i]; i < fcu->totvert; i++, bezt++) { /* additional termination conditions based on the operator 'mode' property go here... */ @@ -1137,6 +1219,11 @@ static void pose_propagate_fcurve(wmOperator *op, Object *ob, FCurve *fcu, if (ce == NULL) continue; } + else if (mode == POSE_PROPAGATE_SELECTED_KEYS) { + /* only allow if this keyframe is already selected - skip otherwise */ + if (BEZT_ISSEL_ANY(bezt) == 0) + continue; + } /* just flatten handles, since values will now be the same either side... */ /* TODO: perhaps a fade-out modulation of the value is required here (optional once again)? */ @@ -1219,12 +1306,20 @@ static int pose_propagate_exec(bContext *C, wmOperator *op) void POSE_OT_propagate(wmOperatorType *ot) { static EnumPropertyItem terminate_items[] = { - {POSE_PROPAGATE_SMART_HOLDS, "WHILE_HELD", 0, "While Held", "Propagate pose to all keyframes after current frame that don't change (Default behavior)"}, - {POSE_PROPAGATE_NEXT_KEY, "NEXT_KEY", 0, "To Next Keyframe", "Propagate pose to first keyframe following the current frame only"}, - {POSE_PROPAGATE_LAST_KEY, "LAST_KEY", 0, "To Last Keyframe", "Propagate pose to the last keyframe only (i.e. making action cyclic)"}, - {POSE_PROPAGATE_BEFORE_FRAME, "BEFORE_FRAME", 0, "Before Frame", "Propagate pose to all keyframes between current frame and 'Frame' property"}, - {POSE_PROPAGATE_BEFORE_END, "BEFORE_END", 0, "Before Last Keyframe", "Propagate pose to all keyframes from current frame until no more are found"}, - {POSE_PROPAGATE_SELECTED_MARKERS, "SELECTED_MARKERS", 0, "On Selected Markers", "Propagate pose to all keyframes occurring on frames with Scene Markers after the current frame"}, + {POSE_PROPAGATE_SMART_HOLDS, "WHILE_HELD", 0, "While Held", + "Propagate pose to all keyframes after current frame that don't change (Default behavior)"}, + {POSE_PROPAGATE_NEXT_KEY, "NEXT_KEY", 0, "To Next Keyframe", + "Propagate pose to first keyframe following the current frame only"}, + {POSE_PROPAGATE_LAST_KEY, "LAST_KEY", 0, "To Last Keyframe", + "Propagate pose to the last keyframe only (i.e. making action cyclic)"}, + {POSE_PROPAGATE_BEFORE_FRAME, "BEFORE_FRAME", 0, "Before Frame", + "Propagate pose to all keyframes between current frame and 'Frame' property"}, + {POSE_PROPAGATE_BEFORE_END, "BEFORE_END", 0, "Before Last Keyframe", + "Propagate pose to all keyframes from current frame until no more are found"}, + {POSE_PROPAGATE_SELECTED_KEYS, "SELECTED_KEYS", 0, "On Selected Keyframes", + "Propagate pose to all selected keyframes"}, + {POSE_PROPAGATE_SELECTED_MARKERS, "SELECTED_MARKERS", 0, "On Selected Markers", + "Propagate pose to all keyframes occurring on frames with Scene Markers after the current frame"}, {0, NULL, 0, NULL, NULL}}; /* identifiers */ diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index 0cde8f30ace..01e16df9f08 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -320,7 +320,7 @@ static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, const bo if (selOnly) paste_ok = ((pchan) && (pchan->bone->flag & BONE_SELECTED)); else - paste_ok = ((pchan != NULL)); + paste_ok = (pchan != NULL); /* continue? */ if (paste_ok) { @@ -811,7 +811,7 @@ void POSE_OT_transforms_clear(wmOperatorType *ot) static int pose_clear_user_transforms_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Object *ob = CTX_data_active_object(C); + Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); float cframe = (float)CFRA; const bool only_select = RNA_boolean_get(op->ptr, "only_selected"); diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c index 380a3fffc6d..2ba1eedd33b 100644 --- a/source/blender/editors/armature/pose_utils.c +++ b/source/blender/editors/armature/pose_utils.c @@ -49,8 +49,6 @@ #include "WM_api.h" #include "WM_types.h" - - #include "ED_armature.h" #include "ED_keyframing.h" @@ -261,7 +259,7 @@ LinkData *poseAnim_mapping_getNextFCurve(ListBase *fcuLinks, LinkData *prev, con FCurve *fcu = (FCurve *)ld->data; /* check if paths match */ - if (strcmp(path, fcu->rna_path) == 0) + if (STREQ(path, fcu->rna_path)) return ld; } diff --git a/source/blender/editors/armature/reeb.c b/source/blender/editors/armature/reeb.c index 8cc6059e87b..f29d15ff416 100644 --- a/source/blender/editors/armature/reeb.c +++ b/source/blender/editors/armature/reeb.c @@ -107,7 +107,7 @@ static VertexData *allocVertexData(EditMesh *em) EditVert *eve; int totvert, index; - totvert = BLI_countlist(&em->verts); + totvert = BLI_listbase_count(&em->verts); data = MEM_callocN(sizeof(VertexData) * totvert, "VertexData"); @@ -1141,7 +1141,7 @@ static int compareNodesWeight(void *vnode1, void *vnode2) void sortNodes(ReebGraph *rg) { - BLI_sortlist(&rg->nodes, compareNodesWeight); + BLI_listbase_sort(&rg->nodes, compareNodesWeight); } static int compareArcsWeight(void *varc1, void *varc2) @@ -1166,7 +1166,7 @@ static int compareArcsWeight(void *varc1, void *varc2) void sortArcs(ReebGraph *rg) { - BLI_sortlist(&rg->arcs, compareArcsWeight); + BLI_listbase_sort(&rg->arcs, compareArcsWeight); } /******************************************* JOINING ***************************************************/ @@ -1512,7 +1512,7 @@ static int filterInternalExternalReebGraph(ReebGraph *rg, float threshold_intern ReebArc *arc = NULL, *nextArc = NULL; int value = 0; - BLI_sortlist(&rg->arcs, compareArcs); + BLI_listbase_sort(&rg->arcs, compareArcs); for (arc = rg->arcs.first; arc; arc = nextArc) { nextArc = arc->next; @@ -1632,7 +1632,7 @@ int filterSmartReebGraph(ReebGraph *UNUSED(rg), float UNUSED(threshold)) #if 0 //XXX ReebArc *arc = NULL, *nextArc = NULL; - BLI_sortlist(&rg->arcs, compareArcs); + BLI_listbase_sort(&rg->arcs, compareArcs); #ifdef DEBUG_REEB { @@ -1867,7 +1867,7 @@ static void spreadWeight(EditMesh *em) { EditVert **verts, *eve; float lastWeight = 0.0f; - int totvert = BLI_countlist(&em->verts); + int totvert = BLI_listbase_count(&em->verts); int i; int work_needed = 1; @@ -2399,9 +2399,9 @@ ReebGraph *generateReebGraph(EditMesh *em, int subdivisions) rg->resolution = subdivisions; - /*totvert = BLI_countlist(&em->verts);*/ /*UNUSED*/ + /*totvert = BLI_listbase_count(&em->verts);*/ /*UNUSED*/ #ifdef DEBUG_REEB - totfaces = BLI_countlist(&em->faces); + totfaces = BLI_listbase_count(&em->faces); #endif renormalizeWeight(em, 1.0f); @@ -2460,7 +2460,7 @@ void renormalizeWeight(EditMesh *em, float newmax) EditVert *eve; float minimum, maximum, range; - if (em == NULL || BLI_countlist(&em->verts) == 0) + if (em == NULL || BLI_listbase_is_empty(&em->verts)) return; /* First pass, determine maximum and minimum */ @@ -2486,7 +2486,7 @@ int weightFromLoc(EditMesh *em, int axis) { EditVert *eve; - if (em == NULL || BLI_countlist(&em->verts) == 0 || axis < 0 || axis > 2) + if (em == NULL || BLI_listbase_is_empty(&em->verts) || axis < 0 || axis > 2) return 0; /* Copy coordinate in weight */ @@ -2738,7 +2738,7 @@ static void buildIndexedEdges(EditMesh *em, EdgeIndex *indexed_edges) int tot_indexed = 0; int offset = 0; - totvert = BLI_countlist(&em->verts); + totvert = BLI_listbase_count(&em->verts); indexed_edges->offset = MEM_callocN(totvert * sizeof(int), "EdgeIndex offset"); @@ -2791,13 +2791,13 @@ int weightFromDistance(EditMesh *em, EdgeIndex *indexed_edges) int totvert = 0; int vCount = 0; - totvert = BLI_countlist(&em->verts); + totvert = BLI_listbase_count(&em->verts); if (em == NULL || totvert == 0) { return 0; } - totedge = BLI_countlist(&em->edges); + totedge = BLI_listbase_count(&em->edges); if (totedge == 0) { return 0; diff --git a/source/blender/editors/armature/reeb.h b/source/blender/editors/armature/reeb.h index b0e1fd3ae34..a6ef16fed67 100644 --- a/source/blender/editors/armature/reeb.h +++ b/source/blender/editors/armature/reeb.h @@ -140,6 +140,7 @@ typedef struct ReebArcIterator { int stride; } ReebArcIterator; +#if 0 struct EditMesh; struct EdgeIndex; @@ -152,6 +153,8 @@ void arcToVCol(struct ReebGraph *rg, struct EditMesh *em, int index); void renormalizeWeight(struct EditMesh *em, float newmax); ReebGraph *generateReebGraph(struct EditMesh *me, int subdivisions); +#endif + ReebGraph *newReebGraph(void); void initArcIterator(BArcIterator *iter, struct ReebArc *arc, struct ReebNode *head); |