diff options
author | Joshua Leung <aligorith@gmail.com> | 2013-02-28 03:34:29 +0400 |
---|---|---|
committer | Joshua Leung <aligorith@gmail.com> | 2013-02-28 03:34:29 +0400 |
commit | 28a84a2c3a204bfab21541df0d6a78d718248f42 (patch) | |
tree | 1829518e5a0952bb8e52e7380007ed906992290d /source/blender/editors/armature/editarmature.c | |
parent | 07cd75d7b04836e6d4b19f35f79c9c1283458aaa (diff) |
Code Maintenance - Splitting up Armature/Pose Editing Files
This commit splits editarmature.c and poseobject.c into several files, such that
certain types of functionality are (mostly) self-contained within particular
files (instead of being mixed in with other functionality in a large file).
In particular, this was done so that:
1) Armature EditMode tools are now in the armature_*.c files only, and Pose Mode
tools in pose_*.c files only.
- In one or two cases, this hasn't been possible as the two modes rely on
much of the same shared infrastructure.
2) The "clear loc/rot/scale" operators and pose show/hide are no longer housed
in editarmature.c
3) Selection operators, Transform operators, structural (add/delete) operators,
and supporting utilities for the modes (enter/exit/roll-calculations) are not
all interleaved in an ad-hoc manner
Notes:
* I've tried to ensure that the history of the new files has been maintained by
doing
svn copy {editarmature.c/poseobject.c} {armature_*.c/pose_*.c}
Unfortunately, this means that the diffs are a bit messy.
* There should be no functional/logic changes here. Just code moving around and
cosmetic comment tweaks where needed.
* #includes have largely been untouched for now, but could be cleaned up later
* CMake changes untested, but should work in theory.
Diffstat (limited to 'source/blender/editors/armature/editarmature.c')
-rw-r--r-- | source/blender/editors/armature/editarmature.c | 6199 |
1 files changed, 0 insertions, 6199 deletions
diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c deleted file mode 100644 index 574cf18773b..00000000000 --- a/source/blender/editors/armature/editarmature.c +++ /dev/null @@ -1,6199 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * Contributor(s): Blender Foundation, 2002-2009 full recode. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/armature/editarmature.c - * \ingroup edarmature - */ - - -#include <ctype.h> -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include <math.h> -#include <float.h> -#include <assert.h> - - -#include "DNA_anim_types.h" -#include "DNA_mesh_types.h" -#include "DNA_armature_types.h" -#include "DNA_constraint_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" - -#include "MEM_guardedalloc.h" - -#include "BLI_blenlib.h" -#include "BLI_math.h" -#include "BLI_utildefines.h" -#include "BLI_ghash.h" - -#include "BLF_translation.h" - -#include "BKE_animsys.h" -#include "BKE_action.h" -#include "BKE_armature.h" -#include "BKE_constraint.h" -#include "BKE_context.h" -#include "BKE_deform.h" -#include "BKE_depsgraph.h" -#include "BKE_DerivedMesh.h" -#include "BKE_global.h" -#include "BKE_idprop.h" -#include "BKE_main.h" -#include "BKE_object.h" -#include "BKE_report.h" -#include "BKE_subsurf.h" -#include "BKE_modifier.h" -#include "DNA_object_types.h" - -#include "BIF_gl.h" - -#include "RNA_access.h" -#include "RNA_define.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "ED_armature.h" -#include "ED_keyframing.h" -#include "ED_mesh.h" -#include "ED_object.h" -#include "ED_screen.h" -#include "ED_util.h" -#include "ED_view3d.h" - -#include "UI_interface.h" -#include "UI_resources.h" - -#include "armature_intern.h" -#include "meshlaplacian.h" - -#if 0 -#include "reeb.h" -#endif - -/* **************** tools on Editmode Armature **************** */ - -/* Sync selection to parent for connected children */ -void ED_armature_sync_selection(ListBase *edbo) -{ - EditBone *ebo; - - for (ebo = edbo->first; ebo; ebo = ebo->next) { - /* if bone is not selectable, we shouldn't alter this setting... */ - if ((ebo->flag & BONE_UNSELECTABLE) == 0) { - if ((ebo->flag & BONE_CONNECTED) && (ebo->parent)) { - if (ebo->parent->flag & BONE_TIPSEL) - ebo->flag |= BONE_ROOTSEL; - else - ebo->flag &= ~BONE_ROOTSEL; - } - - if ((ebo->flag & BONE_TIPSEL) && (ebo->flag & BONE_ROOTSEL)) - ebo->flag |= BONE_SELECTED; - else - ebo->flag &= ~BONE_SELECTED; - } - } -} - -void ED_armature_validate_active(struct bArmature *arm) -{ - EditBone *ebone = arm->act_edbone; - - if (ebone) { - if (ebone->flag & BONE_HIDDEN_A) - arm->act_edbone = NULL; - } -} - -static void bone_free(bArmature *arm, EditBone *bone) -{ - if (arm->act_edbone == bone) - arm->act_edbone = NULL; - - if (bone->prop) { - IDP_FreeProperty(bone->prop); - MEM_freeN(bone->prop); - } - - BLI_freelinkN(arm->edbo, bone); -} - -void ED_armature_edit_bone_remove(bArmature *arm, EditBone *exBone) -{ - EditBone *curBone; - - /* Find any bones that refer to this bone */ - for (curBone = arm->edbo->first; curBone; curBone = curBone->next) { - if (curBone->parent == exBone) { - curBone->parent = exBone->parent; - curBone->flag &= ~BONE_CONNECTED; - } - } - - bone_free(arm, exBone); -} - -/* context: editmode armature */ -EditBone *ED_armature_bone_get_mirrored(ListBase *edbo, EditBone *ebo) -{ - EditBone *eboflip = NULL; - char name[MAXBONENAME]; - - if (ebo == NULL) - return NULL; - - flip_side_name(name, ebo->name, FALSE); - - for (eboflip = edbo->first; eboflip; eboflip = eboflip->next) { - if (ebo != eboflip) { - if (!strcmp(name, eboflip->name)) - break; - } - } - - return eboflip; -} - -/* helper function for tools to work on mirrored parts. - * it leaves mirrored bones selected then too, which is a good indication of what happened */ -static void armature_select_mirrored(bArmature *arm) -{ - /* 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) { - ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, curBone); - if (ebone_mirr) - ebone_mirr->flag |= BONE_SELECTED; - } - } - } - } - -} - -static void armature_tag_select_mirrored(bArmature *arm) -{ - EditBone *curBone; - - /* always untag */ - for (curBone = arm->edbo->first; curBone; curBone = curBone->next) { - curBone->flag &= ~BONE_DONE; - } - - /* Select mirrored bones */ - if (arm->flag & ARM_MIRROR_EDIT) { - for (curBone = arm->edbo->first; curBone; curBone = curBone->next) { - if (arm->layer & curBone->layer) { - if (curBone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) { - EditBone *ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, curBone); - if (ebone_mirr && (ebone_mirr->flag & BONE_SELECTED) == 0) { - ebone_mirr->flag |= BONE_DONE; - } - } - } - } - - for (curBone = arm->edbo->first; curBone; curBone = curBone->next) { - if (curBone->flag & BONE_DONE) { - EditBone *ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, curBone); - curBone->flag |= ebone_mirr->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL); - } - } - } -} - - -/* only works when tagged */ -static void armature_tag_unselect(bArmature *arm) -{ - EditBone *curBone; - - for (curBone = arm->edbo->first; curBone; curBone = curBone->next) { - if (curBone->flag & BONE_DONE) { - curBone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL | BONE_DONE); - } - } -} - -/* converts Bones to EditBone list, used for tools as well */ -EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone *actBone) -{ - EditBone *eBone; - EditBone *eBoneAct = NULL; - EditBone *eBoneTest = NULL; - Bone *curBone; - - for (curBone = bones->first; curBone; curBone = curBone->next) { - eBone = MEM_callocN(sizeof(EditBone), "make_editbone"); - - /* Copy relevant data from bone to eBone */ - eBone->parent = parent; - BLI_strncpy(eBone->name, curBone->name, sizeof(eBone->name)); - eBone->flag = curBone->flag; - - /* fix selection flags */ - - if (eBone->flag & BONE_SELECTED) { - /* if the bone is selected the copy its root selection to the parents tip */ - eBone->flag |= BONE_TIPSEL; - if (eBone->parent && (eBone->flag & BONE_CONNECTED)) { - eBone->parent->flag |= BONE_TIPSEL; - eBone->flag &= ~BONE_ROOTSEL; /* this is ignored when there is a connected parent, so unset it */ - } - else { - eBone->flag |= BONE_ROOTSEL; - } - } - else { - /* if the bone is not selected, but connected to its parent - * copy the parents tip selection state */ - if (eBone->parent && (eBone->flag & BONE_CONNECTED)) { - /* selecting with the mouse gives this behavior */ - if (eBone->parent->flag & BONE_TIPSEL) { - eBone->flag |= BONE_ROOTSEL; - } - else { - eBone->flag &= ~BONE_ROOTSEL; - } - - /* probably not selected but just in case */ - eBone->flag &= ~BONE_TIPSEL; - } - } - - copy_v3_v3(eBone->head, curBone->arm_head); - copy_v3_v3(eBone->tail, curBone->arm_tail); - eBone->roll = curBone->arm_roll; - - /* rest of stuff copy */ - eBone->length = curBone->length; - eBone->dist = curBone->dist; - eBone->weight = curBone->weight; - eBone->xwidth = curBone->xwidth; - eBone->zwidth = curBone->zwidth; - eBone->ease1 = curBone->ease1; - eBone->ease2 = curBone->ease2; - eBone->rad_head = curBone->rad_head; - eBone->rad_tail = curBone->rad_tail; - eBone->segments = curBone->segments; - eBone->layer = curBone->layer; - - if (curBone->prop) - eBone->prop = IDP_CopyProperty(curBone->prop); - - BLI_addtail(edbo, eBone); - - /* Add children if necessary */ - if (curBone->childbase.first) { - eBoneTest = make_boneList(edbo, &curBone->childbase, eBone, actBone); - if (eBoneTest) - eBoneAct = eBoneTest; - } - - if (curBone == actBone) - eBoneAct = eBone; - } - - 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) -{ - Bone *curBone; - EditBone *ebone; - float premat[3][3]; - float postmat[3][3]; - float difmat[3][3]; - float imat[3][3]; - float delta[3]; - - for (curBone = bonelist->first; curBone; curBone = curBone->next) { - /* sets local matrix and arm_mat (restpos) */ - BKE_armature_where_is_bone(curBone, curBone->parent); - - /* Find the associated editbone */ - for (ebone = editbonelist->first; ebone; ebone = ebone->next) - if ((Bone *)ebone->temp == curBone) - break; - - if (ebone) { - /* Get the ebone premat */ - sub_v3_v3v3(delta, ebone->tail, ebone->head); - vec_roll_to_mat3(delta, ebone->roll, premat); - - /* Get the bone postmat */ - copy_m3_m4(postmat, curBone->arm_mat); - - invert_m3_m3(imat, premat); - 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]))); -#endif - curBone->roll = (float)-atan2(difmat[2][0], difmat[2][2]); - - /* and set restposition again */ - BKE_armature_where_is_bone(curBone, curBone->parent); - } - fix_bonelist_roll(&curBone->childbase, editbonelist); - } -} - -/* put EditMode back in Object */ -void ED_armature_from_edit(Object *obedit) -{ - bArmature *arm = obedit->data; - EditBone *eBone, *neBone; - Bone *newBone; - Object *obt; - - /* armature bones */ - BKE_armature_bonelist_free(&arm->bonebase); - - /* remove zero sized bones, this gives instable restposes */ - for (eBone = arm->edbo->first; eBone; eBone = neBone) { - float len = len_v3v3(eBone->head, eBone->tail); - neBone = eBone->next; - if (len <= 0.000001f) { /* FLT_EPSILON is too large? */ - EditBone *fBone; - - /* Find any bones that refer to this bone */ - for (fBone = arm->edbo->first; fBone; fBone = fBone->next) { - if (fBone->parent == eBone) - fBone->parent = eBone->parent; - } - if (G.debug & G_DEBUG) - printf("Warning: removed zero sized bone: %s\n", eBone->name); - bone_free(arm, eBone); - } - } - - /* Copy the bones from the editData into the armature */ - for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { - newBone = MEM_callocN(sizeof(Bone), "bone"); - eBone->temp = newBone; /* Associate the real Bones with the EditBones */ - - BLI_strncpy(newBone->name, eBone->name, sizeof(newBone->name)); - copy_v3_v3(newBone->arm_head, eBone->head); - copy_v3_v3(newBone->arm_tail, eBone->tail); - newBone->arm_roll = eBone->roll; - - newBone->flag = eBone->flag; - - if (eBone == arm->act_edbone) { - /* don't change active selection, this messes up separate which uses - * editmode toggle and can separate active bone which is de-selected originally */ - /* newBone->flag |= BONE_SELECTED; */ /* important, editbones can be active with only 1 point selected */ - arm->act_edbone = NULL; - arm->act_bone = newBone; - } - newBone->roll = 0.0f; - - newBone->weight = eBone->weight; - newBone->dist = eBone->dist; - - newBone->xwidth = eBone->xwidth; - newBone->zwidth = eBone->zwidth; - newBone->ease1 = eBone->ease1; - newBone->ease2 = eBone->ease2; - newBone->rad_head = eBone->rad_head; - newBone->rad_tail = eBone->rad_tail; - newBone->segments = eBone->segments; - newBone->layer = eBone->layer; - - if (eBone->prop) - newBone->prop = IDP_CopyProperty(eBone->prop); - } - - /* Fix parenting in a separate pass to ensure ebone->bone connections - * are valid at this point */ - for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { - newBone = (Bone *)eBone->temp; - if (eBone->parent) { - newBone->parent = (Bone *)eBone->parent->temp; - BLI_addtail(&newBone->parent->childbase, newBone); - - { - float M_parentRest[3][3]; - float iM_parentRest[3][3]; - float delta[3]; - - /* Get the parent's matrix (rotation only) */ - sub_v3_v3v3(delta, eBone->parent->tail, eBone->parent->head); - vec_roll_to_mat3(delta, eBone->parent->roll, 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); - - /* so all users of this armature should get rebuilt */ - for (obt = G.main->object.first; obt; obt = obt->id.next) { - if (obt->data == arm) - BKE_pose_rebuild(obt, arm); - } - - DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); -} - -void ED_armature_apply_transform(Object *ob, float mat[4][4]) -{ - EditBone *ebone; - bArmature *arm = ob->data; - float scale = mat4_to_scale(mat); /* store the scale of the matrix here to use on envelopes */ - float mat3[3][3]; - - copy_m3_m4(mat3, mat); - normalize_m3(mat3); - - /* Put the armature into editmode */ - ED_armature_to_edit(ob); - - /* Do the rotations */ - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - float delta[3], tmat[3][3]; - - /* find the current bone's roll matrix */ - sub_v3_v3v3(delta, ebone->tail, ebone->head); - vec_roll_to_mat3(delta, ebone->roll, tmat); - - /* transform the roll matrix */ - mul_m3_m3m3(tmat, mat3, tmat); - - /* transform the bone */ - mul_m4_v3(mat, ebone->head); - mul_m4_v3(mat, ebone->tail); - - /* apply the transfiormed roll back */ - mat3_to_vec_roll(tmat, NULL, &ebone->roll); - - ebone->rad_head *= scale; - ebone->rad_tail *= scale; - ebone->dist *= scale; - - /* we could be smarter and scale by the matrix along the x & z axis */ - ebone->xwidth *= scale; - ebone->zwidth *= scale; - } - - /* Turn the list into an armature */ - ED_armature_from_edit(ob); - ED_armature_edit_free(ob); -} - -/* exported for use in editors/object/ */ -/* 0 == do center, 1 == center new, 2 == center cursor */ -void docenter_armature(Scene *scene, Object *ob, float cursor[3], int centermode, int around) -{ - Object *obedit = scene->obedit; // XXX get from context - EditBone *ebone; - bArmature *arm = ob->data; - float cent[3]; - - /* Put the armature into editmode */ - if (ob != obedit) { - ED_armature_to_edit(ob); - obedit = NULL; /* we cant use this so behave as if there is no obedit */ - } - - /* Find the centerpoint */ - if (centermode == 2) { - copy_v3_v3(cent, cursor); - invert_m4_m4(ob->imat, ob->obmat); - mul_m4_v3(ob->imat, cent); - } - else { - if (around == V3D_CENTROID) { - int total = 0; - zero_v3(cent); - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - total += 2; - add_v3_v3(cent, ebone->head); - add_v3_v3(cent, ebone->tail); - } - if (total) { - mul_v3_fl(cent, 1.0f / (float)total); - } - } - else { - float min[3], max[3]; - INIT_MINMAX(min, max); - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - minmax_v3v3_v3(min, max, ebone->head); - minmax_v3v3_v3(min, max, ebone->tail); - } - mid_v3_v3v3(cent, min, max); - } - } - - /* Do the adjustments */ - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - sub_v3_v3(ebone->head, cent); - sub_v3_v3(ebone->tail, cent); - } - - /* Turn the list into an armature */ - if (obedit == NULL) { - ED_armature_from_edit(ob); - ED_armature_edit_free(ob); - } - - /* Adjust object location for new centerpoint */ - if (centermode && obedit == NULL) { - mul_mat3_m4_v3(ob->obmat, cent); /* ommit translation part */ - add_v3_v3(ob->loc, cent); - } -} - -/* ---------------------- */ - -/* checks if an EditBone with a matching name already, returning the matching bone if it exists */ -static EditBone *editbone_name_exists(ListBase *edbo, const char *name) -{ - return BLI_findstring(edbo, name, offsetof(EditBone, name)); -} - -/* note: there's a unique_bone_name() too! */ -static int editbone_unique_check(void *arg, const char *name) -{ - struct {ListBase *lb; void *bone; } *data = arg; - EditBone *dupli = editbone_name_exists(data->lb, name); - return dupli && dupli != data->bone; -} - -void unique_editbone_name(ListBase *edbo, char *name, EditBone *bone) -{ - struct {ListBase *lb; void *bone; } data; - data.lb = edbo; - data.bone = bone; - - BLI_uniquename_cb(editbone_unique_check, &data, "Bone", '.', name, sizeof(bone->name)); -} - -/* helper for apply_armature_pose2bones - fixes parenting of objects that are bone-parented to armature */ -static void applyarmature_fix_boneparents(Scene *scene, Object *armob) -{ - Object workob, *ob; - - /* go through all objects in database */ - for (ob = G.main->object.first; ob; ob = ob->id.next) { - /* if parent is bone in this armature, apply corrections */ - if ((ob->parent == armob) && (ob->partype == PARBONE)) { - /* apply current transform from parent (not yet destroyed), - * then calculate new parent inverse matrix - */ - BKE_object_apply_mat4(ob, ob->obmat, FALSE, FALSE); - - BKE_object_workob_calc_parent(scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); - } - } -} - -/* set the current pose as the restpose */ -static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) -{ - Scene *scene = CTX_data_scene(C); - Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); // must be active object, not edit-object - bArmature *arm = BKE_armature_from_object(ob); - bPose *pose; - bPoseChannel *pchan; - EditBone *curbone; - - /* don't check if editmode (should be done by caller) */ - if (ob->type != OB_ARMATURE) - return OPERATOR_CANCELLED; - if (BKE_object_obdata_is_libdata(ob)) { - BKE_report(op->reports, RPT_ERROR, "Cannot apply pose to lib-linked armature"); /* error_libdata(); */ - return OPERATOR_CANCELLED; - } - - /* helpful warnings... */ - /* TODO: add warnings to be careful about actions, applying deforms first, etc. */ - if (ob->adt && ob->adt->action) - BKE_report(op->reports, RPT_WARNING, - "Actions on this armature will be destroyed by this new rest pose as the " - "transforms stored are relative to the old rest pose"); - - /* Get editbones of active armature to alter */ - ED_armature_to_edit(ob); - - /* get pose of active object and move it out of posemode */ - pose = ob->pose; - - for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { - curbone = editbone_name_exists(arm->edbo, pchan->name); - - /* simply copy the head/tail values from pchan over to curbone */ - copy_v3_v3(curbone->head, pchan->pose_head); - copy_v3_v3(curbone->tail, pchan->pose_tail); - - /* fix roll: - * 1. find auto-calculated roll value for this bone now - * 2. remove this from the 'visual' y-rotation - */ - { - float premat[3][3], imat[3][3], pmat[3][3], tmat[3][3]; - float delta[3], eul[3]; - - /* obtain new auto y-rotation */ - sub_v3_v3v3(delta, curbone->tail, curbone->head); - vec_roll_to_mat3(delta, 0.0f, premat); - invert_m3_m3(imat, premat); - - /* get pchan 'visual' matrix */ - copy_m3_m4(pmat, pchan->pose_mat); - - /* remove auto from visual and get euler rotation */ - mul_m3_m3m3(tmat, imat, pmat); - mat3_to_eul(eul, tmat); - - /* just use this euler-y as new roll value */ - curbone->roll = eul[1]; - } - - /* clear transform values for pchan */ - zero_v3(pchan->loc); - zero_v3(pchan->eul); - unit_qt(pchan->quat); - unit_axis_angle(pchan->rotAxis, &pchan->rotAngle); - pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f; - - /* set anim lock */ - curbone->flag |= BONE_UNKEYED; - } - - /* convert editbones back to bones, and then free the edit-data */ - ED_armature_from_edit(ob); - ED_armature_edit_free(ob); - - /* flush positions of posebones */ - BKE_pose_where_is(scene, ob); - - /* fix parenting of objects which are bone-parented */ - applyarmature_fix_boneparents(scene, ob); - - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); - - return OPERATOR_FINISHED; -} - -void POSE_OT_armature_apply(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Apply Pose as Rest Pose"; - ot->idname = "POSE_OT_armature_apply"; - ot->description = "Apply the current pose as the new rest pose"; - - /* callbacks */ - ot->exec = apply_armature_pose2bones_exec; - ot->poll = ED_operator_posemode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - - -/* set the current pose as the restpose */ -static int pose_visual_transform_apply_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); // must be active object, not edit-object - - /* don't check if editmode (should be done by caller) */ - if (ob->type != OB_ARMATURE) - return OPERATOR_CANCELLED; - - /* loop over all selected pchans - * - * TODO, loop over children before parents if multiple bones - * at once are to be predictable*/ - CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones) - { - float delta_mat[4][4]; - - /* chan_mat already contains the delta transform from rest pose to pose-mode pose - * as that is baked into there so that B-Bones will work. Once we've set this as the - * new raw-transform components, don't recalc the poses yet, otherwise IK result will - * change, thus changing the result we may be trying to record. - */ - copy_m4_m4(delta_mat, pchan->chan_mat); - BKE_pchan_apply_mat4(pchan, delta_mat, TRUE); - } - CTX_DATA_END; - - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); - - return OPERATOR_FINISHED; -} - -void POSE_OT_visual_transform_apply(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Apply Visual Transform to Pose"; - ot->idname = "POSE_OT_visual_transform_apply"; - ot->description = "Apply final constrained position of pose bones to their transform"; - - /* callbacks */ - ot->exec = pose_visual_transform_apply_exec; - ot->poll = ED_operator_posemode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/* ---------------------- */ - -/* Helper function for armature joining - link fixing */ -static void joined_armature_fix_links(Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone) -{ - Object *ob; - bPose *pose; - bPoseChannel *pchant; - bConstraint *con; - - /* let's go through all objects in database */ - for (ob = G.main->object.first; ob; ob = ob->id.next) { - /* do some object-type specific things */ - if (ob->type == OB_ARMATURE) { - pose = ob->pose; - for (pchant = pose->chanbase.first; pchant; pchant = pchant->next) { - for (con = pchant->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - /* constraint targets */ - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - if (ct->tar == srcArm) { - if (ct->subtarget[0] == '\0') { - ct->tar = tarArm; - } - else if (strcmp(ct->subtarget, pchan->name) == 0) { - ct->tar = tarArm; - BLI_strncpy(ct->subtarget, curbone->name, sizeof(ct->subtarget)); - } - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 0); - } - - /* action constraint? */ - if (con->type == CONSTRAINT_TYPE_ACTION) { - bActionConstraint *data = con->data; // XXX old animation system - bAction *act; - bActionChannel *achan; - - if (data->act) { - act = data->act; - - for (achan = act->chanbase.first; achan; achan = achan->next) { - if (strcmp(achan->name, pchan->name) == 0) - BLI_strncpy(achan->name, curbone->name, sizeof(achan->name)); - } - } - } - - } - } - } - - /* fix object-level constraints */ - if (ob != srcArm) { - for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - /* constraint targets */ - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - if (ct->tar == srcArm) { - if (ct->subtarget[0] == '\0') { - ct->tar = tarArm; - } - else if (strcmp(ct->subtarget, pchan->name) == 0) { - ct->tar = tarArm; - BLI_strncpy(ct->subtarget, curbone->name, sizeof(ct->subtarget)); - } - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 0); - } - } - } - - /* See if an object is parented to this armature */ - if (ob->parent && (ob->parent == srcArm)) { - /* Is object parented to a bone of this src armature? */ - if (ob->partype == PARBONE) { - /* bone name in object */ - if (!strcmp(ob->parsubstr, pchan->name)) - BLI_strncpy(ob->parsubstr, curbone->name, sizeof(ob->parsubstr)); - } - - /* make tar armature be new parent */ - ob->parent = tarArm; - } - } -} - -/* join armature exec is exported for use in object->join objects operator... */ -int join_armature_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - Object *ob = CTX_data_active_object(C); - bArmature *arm = (ob) ? ob->data : NULL; - bPose *pose, *opose; - bPoseChannel *pchan, *pchann; - EditBone *curbone; - float mat[4][4], oimat[4][4]; - - /* Ensure we're not in editmode and that the active object is an armature*/ - if (!ob || ob->type != OB_ARMATURE) - return OPERATOR_CANCELLED; - if (!arm || arm->edbo) - return OPERATOR_CANCELLED; - - /* Get editbones of active armature to add editbones to */ - ED_armature_to_edit(ob); - - /* get pose of active object and move it out of posemode */ - pose = ob->pose; - ob->mode &= ~OB_MODE_POSE; - - CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases) - { - if ((base->object->type == OB_ARMATURE) && (base->object != ob)) { - bArmature *curarm = base->object->data; - - /* Make a list of editbones in current armature */ - ED_armature_to_edit(base->object); - - /* Get Pose of current armature */ - opose = base->object->pose; - base->object->mode &= ~OB_MODE_POSE; - //BASACT->flag &= ~OB_MODE_POSE; - - /* Find the difference matrix */ - invert_m4_m4(oimat, ob->obmat); - mult_m4_m4m4(mat, oimat, base->object->obmat); - - /* Copy bones and posechannels from the object to the edit armature */ - for (pchan = opose->chanbase.first; pchan; pchan = pchann) { - pchann = pchan->next; - curbone = editbone_name_exists(curarm->edbo, pchan->name); - - /* Get new name */ - unique_editbone_name(arm->edbo, curbone->name, NULL); - - /* Transform the bone */ - { - float premat[4][4]; - float postmat[4][4]; - float difmat[4][4]; - float imat[4][4]; - float temp[3][3]; - float delta[3]; - - /* Get the premat */ - sub_v3_v3v3(delta, curbone->tail, curbone->head); - vec_roll_to_mat3(delta, curbone->roll, temp); - - unit_m4(premat); /* Mat4MulMat34 only sets 3x3 part */ - mul_m4_m3m4(premat, temp, mat); - - mul_m4_v3(mat, curbone->head); - mul_m4_v3(mat, curbone->tail); - - /* Get the postmat */ - sub_v3_v3v3(delta, curbone->tail, curbone->head); - vec_roll_to_mat3(delta, curbone->roll, temp); - copy_m4_m3(postmat, temp); - - /* Find the roll */ - invert_m4_m4(imat, premat); - mult_m4_m4m4(difmat, imat, postmat); - - curbone->roll -= (float)atan2(difmat[2][0], difmat[2][2]); - } - - /* Fix Constraints and Other Links to this Bone and Armature */ - joined_armature_fix_links(ob, base->object, pchan, curbone); - - /* Rename pchan */ - BLI_strncpy(pchan->name, curbone->name, sizeof(pchan->name)); - - /* Jump Ship! */ - BLI_remlink(curarm->edbo, curbone); - BLI_addtail(arm->edbo, curbone); - - BLI_remlink(&opose->chanbase, pchan); - BLI_addtail(&pose->chanbase, pchan); - BKE_pose_channels_hash_free(opose); - BKE_pose_channels_hash_free(pose); - } - - ED_base_object_free_and_unlink(bmain, scene, base); - } - } - CTX_DATA_END; - - DAG_relations_tag_update(bmain); /* because we removed object(s) */ - - ED_armature_from_edit(ob); - ED_armature_edit_free(ob); - - WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); - - return OPERATOR_FINISHED; -} - -/* ---------------------- */ - -/* Helper function for armature separating - link fixing */ -static void separated_armature_fix_links(Object *origArm, Object *newArm) -{ - Object *ob; - bPoseChannel *pchan; - bConstraint *con; - ListBase *opchans, *npchans; - - /* get reference to list of bones in original and new armatures */ - opchans = &origArm->pose->chanbase; - npchans = &newArm->pose->chanbase; - - /* let's go through all objects in database */ - for (ob = G.main->object.first; ob; ob = ob->id.next) { - /* do some object-type specific things */ - if (ob->type == OB_ARMATURE) { - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - /* constraint targets */ - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - /* any targets which point to original armature are redirected to the new one only if: - * - the target isn't origArm/newArm itself - * - the target is one that can be found in newArm/origArm - */ - if (ct->subtarget[0] != 0) { - if (ct->tar == origArm) { - if (BLI_findstring(npchans, ct->subtarget, offsetof(bPoseChannel, name))) { - ct->tar = newArm; - } - } - else if (ct->tar == newArm) { - if (BLI_findstring(opchans, ct->subtarget, offsetof(bPoseChannel, name))) { - ct->tar = origArm; - } - } - } - } - - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, 0); - } - } - } - } - } - - /* fix object-level constraints */ - if (ob != origArm) { - for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - /* constraint targets */ - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - /* any targets which point to original armature are redirected to the new one only if: - * - the target isn't origArm/newArm itself - * - the target is one that can be found in newArm/origArm - */ - if (ct->subtarget[0] != '\0') { - if (ct->tar == origArm) { - if (BLI_findstring(npchans, ct->subtarget, offsetof(bPoseChannel, name))) { - ct->tar = newArm; - } - } - else if (ct->tar == newArm) { - if (BLI_findstring(opchans, ct->subtarget, offsetof(bPoseChannel, name))) { - ct->tar = origArm; - } - } - } - } - - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, 0); - } - } - } - } - - /* See if an object is parented to this armature */ - if (ob->parent && (ob->parent == origArm)) { - /* Is object parented to a bone of this src armature? */ - if ((ob->partype == PARBONE) && (ob->parsubstr[0] != '\0')) { - if (BLI_findstring(npchans, ob->parsubstr, offsetof(bPoseChannel, name))) { - ob->parent = newArm; - } - } - } - } -} - -/* Helper function for armature separating - remove certain bones from the given armature - * sel: remove selected bones from the armature, otherwise the unselected bones are removed - * (ob is not in editmode) - */ -static void separate_armature_bones(Object *ob, short sel) -{ - bArmature *arm = (bArmature *)ob->data; - bPoseChannel *pchan, *pchann; - EditBone *curbone; - - /* make local set of editbones to manipulate here */ - ED_armature_to_edit(ob); - - /* go through pose-channels, checking if a bone should be removed */ - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchann) { - pchann = pchan->next; - curbone = editbone_name_exists(arm->edbo, pchan->name); - - /* check if bone needs to be removed */ - if ( (sel && (curbone->flag & BONE_SELECTED)) || - (!sel && !(curbone->flag & BONE_SELECTED)) ) - { - EditBone *ebo; - bPoseChannel *pchn; - - /* clear the bone->parent var of any bone that had this as its parent */ - for (ebo = arm->edbo->first; ebo; ebo = ebo->next) { - if (ebo->parent == curbone) { - ebo->parent = NULL; - ebo->temp = NULL; /* this is needed to prevent random crashes with in ED_armature_from_edit */ - ebo->flag &= ~BONE_CONNECTED; - } - } - - /* clear the pchan->parent var of any pchan that had this as its parent */ - for (pchn = ob->pose->chanbase.first; pchn; pchn = pchn->next) { - if (pchn->parent == pchan) - pchn->parent = NULL; - } - - /* free any of the extra-data this pchan might have */ - BKE_pose_channel_free(pchan); - BKE_pose_channels_hash_free(ob->pose); - - /* get rid of unneeded bone */ - bone_free(arm, curbone); - BLI_freelinkN(&ob->pose->chanbase, pchan); - } - } - - /* exit editmode (recalculates pchans too) */ - ED_armature_from_edit(ob); - ED_armature_edit_free(ob); -} - -/* separate selected bones into their armature */ -static int separate_armature_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - Object *oldob, *newob; - Base *oldbase, *newbase; - - /* sanity checks */ - if (obedit == NULL) - return OPERATOR_CANCELLED; - - /* set wait cursor in case this takes a while */ - WM_cursor_wait(1); - - /* we are going to do this as follows (unlike every other instance of separate): - * 1. exit editmode +posemode for active armature/base. Take note of what this is. - * 2. duplicate base - BASACT is the new one now - * 3. for each of the two armatures, enter editmode -> remove appropriate bones -> exit editmode + recalc - * 4. fix constraint links - * 5. make original armature active and enter editmode - */ - - /* 1) only edit-base selected */ - /* TODO: use context iterators for this? */ - CTX_DATA_BEGIN(C, Base *, base, visible_bases) - { - if (base->object == obedit) base->flag |= 1; - else base->flag &= ~1; - } - CTX_DATA_END; - - /* 1) store starting settings and exit editmode */ - oldob = obedit; - oldbase = BASACT; - oldob->mode &= ~OB_MODE_POSE; - //oldbase->flag &= ~OB_POSEMODE; - - ED_armature_from_edit(obedit); - ED_armature_edit_free(obedit); - - /* 2) duplicate base */ - newbase = ED_object_add_duplicate(bmain, scene, oldbase, USER_DUP_ARM); /* only duplicate linked armature */ - DAG_relations_tag_update(bmain); - - newob = newbase->object; - newbase->flag &= ~SELECT; - - - /* 3) remove bones that shouldn't still be around on both armatures */ - separate_armature_bones(oldob, 1); - separate_armature_bones(newob, 0); - - - /* 4) fix links before depsgraph flushes */ // err... or after? - separated_armature_fix_links(oldob, newob); - - DAG_id_tag_update(&oldob->id, OB_RECALC_DATA); /* this is the original one */ - DAG_id_tag_update(&newob->id, OB_RECALC_DATA); /* this is the separated one */ - - - /* 5) restore original conditions */ - obedit = oldob; - - ED_armature_to_edit(obedit); - - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit); - - /* recalc/redraw + cleanup */ - WM_cursor_wait(0); - - return OPERATOR_FINISHED; -} - -void ARMATURE_OT_separate(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Separate Bones"; - ot->idname = "ARMATURE_OT_separate"; - ot->description = "Isolate selected bones into a separate armature"; - - /* callbacks */ - ot->invoke = WM_operator_confirm; - ot->exec = separate_armature_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/* **************** END tools on Editmode Armature **************** */ -/* **************** PoseMode & EditMode *************************** */ - -/* only for opengl selection indices */ -Bone *get_indexed_bone(Object *ob, int index) -{ - bPoseChannel *pchan; - if (ob->pose == NULL) return NULL; - index >>= 16; // bone selection codes use left 2 bytes - - pchan = BLI_findlink(&ob->pose->chanbase, index); - return pchan ? pchan->bone : NULL; -} - -/* See if there are any selected bones in this buffer */ -/* only bones from base are checked on */ -static void *get_bone_from_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, short hits, short findunsel) -{ - Object *obedit = scene->obedit; // XXX get from context - Bone *bone; - EditBone *ebone; - void *firstunSel = NULL, *firstSel = NULL, *data; - unsigned int hitresult; - short i, takeNext = 0, sel; - - for (i = 0; i < hits; i++) { - hitresult = buffer[3 + (i * 4)]; - - if (!(hitresult & BONESEL_NOSEL)) { // -1 - if (hitresult & BONESEL_ANY) { // to avoid including objects in selection - - hitresult &= ~(BONESEL_ANY); - /* Determine what the current bone is */ - if (obedit == NULL || base->object != obedit) { - /* no singular posemode, so check for correct object */ - if (base->selcol == (hitresult & 0xFFFF)) { - bone = get_indexed_bone(base->object, hitresult); - - if (findunsel) - sel = (bone->flag & BONE_SELECTED); - else - sel = !(bone->flag & BONE_SELECTED); - - data = bone; - } - else { - data = NULL; - sel = 0; - } - } - else { - bArmature *arm = obedit->data; - - ebone = BLI_findlink(arm->edbo, hitresult); - if (findunsel) - sel = (ebone->flag & BONE_SELECTED); - else - sel = !(ebone->flag & BONE_SELECTED); - - data = ebone; - } - - if (data) { - if (sel) { - if (!firstSel) firstSel = data; - takeNext = 1; - } - else { - if (!firstunSel) - firstunSel = data; - if (takeNext) - return data; - } - } - } - } - } - - if (firstunSel) - return firstunSel; - else - return firstSel; -} - - - -/* used by posemode as well editmode */ -/* only checks scene->basact! */ -/* x and y are mouse coords (area space) */ -static void *get_nearest_bone(bContext *C, short findunsel, int x, int y) -{ - ViewContext vc; - rcti rect; - unsigned int buffer[MAXPICKBUF]; - short hits; - - view3d_set_viewcontext(C, &vc); - - // rect.xmin = ... mouseco! - rect.xmin = rect.xmax = x; - rect.ymin = rect.ymax = y; - - glInitNames(); - hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect); - - if (hits > 0) - return get_bone_from_selectbuffer(vc.scene, vc.scene->basact, buffer, hits, findunsel); - - return NULL; -} - -/* 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; -} - -/* **************** END PoseMode & EditMode *************************** */ -/* **************** Posemode stuff ********************** */ - - -static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend) -{ - Bone *curBone; - - /* stop when unconnected child is encontered, or when unselectable bone is encountered */ - if (!(bone->flag & BONE_CONNECTED) || (bone->flag & BONE_UNSELECTABLE)) - return; - - /* XXX old cruft! use notifiers instead */ - //select_actionchannel_by_name (ob->action, bone->name, !(shift)); - - if (extend) - bone->flag &= ~BONE_SELECTED; - else - bone->flag |= BONE_SELECTED; - - for (curBone = bone->childbase.first; curBone; curBone = curBone->next) - selectconnected_posebonechildren(ob, curBone, extend); -} - -/* within active object context */ -/* previously known as "selectconnected_posearmature" */ -static int pose_select_connected_invoke(bContext *C, wmOperator *op, wmEvent *event) -{ - Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); - bArmature *arm = (bArmature *)ob->data; - Bone *bone, *curBone, *next = NULL; - int extend = RNA_boolean_get(op->ptr, "extend"); - - view3d_operator_needs_opengl(C); - - if (extend) - bone = get_nearest_bone(C, 0, event->mval[0], event->mval[1]); - else - bone = get_nearest_bone(C, 1, event->mval[0], event->mval[1]); - - if (!bone) - return OPERATOR_CANCELLED; - - /* Select parents */ - for (curBone = bone; curBone; curBone = next) { - /* ignore bone if cannot be selected */ - if ((curBone->flag & BONE_UNSELECTABLE) == 0) { - // XXX old cruft! use notifiers instead - //select_actionchannel_by_name (ob->action, curBone->name, !(shift)); - - if (extend) - curBone->flag &= ~BONE_SELECTED; - else - curBone->flag |= BONE_SELECTED; - - if (curBone->flag & BONE_CONNECTED) - next = curBone->parent; - else - next = NULL; - } - else - next = NULL; - } - - /* Select children */ - for (curBone = bone->childbase.first; curBone; curBone = next) - selectconnected_posebonechildren(ob, curBone, extend); - - /* updates */ - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); - - if (arm->flag & ARM_HAS_VIZ_DEPS) { - /* mask modifier ('armature' mode), etc. */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - } - - return OPERATOR_FINISHED; -} - -static int pose_select_linked_poll(bContext *C) -{ - return (ED_operator_view3d_active(C) && ED_operator_posemode(C)); -} - -void POSE_OT_select_linked(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select Connected"; - ot->idname = "POSE_OT_select_linked"; - ot->description = "Select bones related to selected ones by parent/child relationships"; - - /* api callbacks */ - ot->exec = NULL; - ot->invoke = pose_select_connected_invoke; - ot->poll = pose_select_linked_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* props */ - RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first"); -} - -/* **************** END Posemode stuff ********************** */ -/* **************** EditMode stuff ********************** */ - -/* called in space.c */ -/* previously "selectconnected_armature" */ -static int armature_select_linked_invoke(bContext *C, wmOperator *op, wmEvent *event) -{ - bArmature *arm; - EditBone *bone, *curBone, *next; - int extend = RNA_boolean_get(op->ptr, "extend"); - Object *obedit = CTX_data_edit_object(C); - arm = obedit->data; - - view3d_operator_needs_opengl(C); - - if (extend) - bone = get_nearest_bone(C, 0, event->mval[0], event->mval[1]); - else - bone = get_nearest_bone(C, 1, event->mval[0], event->mval[1]); - - if (!bone) - return OPERATOR_CANCELLED; - - /* Select parents */ - for (curBone = bone; curBone; curBone = next) { - if ((curBone->flag & BONE_UNSELECTABLE) == 0) { - if (extend) { - curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } - else { - curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } - } - - if (curBone->flag & BONE_CONNECTED) - next = curBone->parent; - else - next = NULL; - } - - /* Select children */ - while (bone) { - for (curBone = arm->edbo->first; curBone; curBone = next) { - next = curBone->next; - if ((curBone->parent == bone) && (curBone->flag & BONE_UNSELECTABLE) == 0) { - if (curBone->flag & BONE_CONNECTED) { - if (extend) - curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - else - curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - bone = curBone; - break; - } - else { - bone = NULL; - break; - } - } - } - if (!curBone) - bone = NULL; - } - - ED_armature_sync_selection(arm->edbo); - - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); - - return OPERATOR_FINISHED; -} - -static int armature_select_linked_poll(bContext *C) -{ - return (ED_operator_view3d_active(C) && ED_operator_editarmature(C) ); -} - -void ARMATURE_OT_select_linked(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select Connected"; - ot->idname = "ARMATURE_OT_select_linked"; - ot->description = "Select bones related to selected ones by parent/child relationships"; - - /* api callbacks */ - ot->exec = NULL; - ot->invoke = armature_select_linked_invoke; - ot->poll = armature_select_linked_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first"); -} - -/* does bones and points */ -/* note that BONE ROOT only gets drawn for root bones (or without IK) */ -static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2], - ListBase *edbo, int findunsel, int *selmask) -{ - EditBone *ebone; - rcti rect; - unsigned int buffer[MAXPICKBUF]; - unsigned int hitresult, besthitresult = BONESEL_NOSEL; - int i, mindep = 4; - short hits; - - glInitNames(); - - rect.xmin = mval[0] - 5; - rect.xmax = mval[0] + 5; - rect.ymin = mval[1] - 5; - rect.ymax = mval[1] + 5; - - hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect); - if (hits == 0) { - rect.xmin = mval[0] - 12; - rect.xmax = mval[0] + 12; - rect.ymin = mval[1] - 12; - rect.ymax = mval[1] + 12; - hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect); - } - /* See if there are any selected bones in this group */ - if (hits > 0) { - - if (hits == 1) { - if (!(buffer[3] & BONESEL_NOSEL)) - besthitresult = buffer[3]; - } - else { - for (i = 0; i < hits; i++) { - hitresult = buffer[3 + (i * 4)]; - if (!(hitresult & BONESEL_NOSEL)) { - int dep; - - ebone = BLI_findlink(edbo, hitresult & ~BONESEL_ANY); - - /* clicks on bone points get advantage */ - if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) { - /* but also the unselected one */ - if (findunsel) { - if ( (hitresult & BONESEL_ROOT) && (ebone->flag & BONE_ROOTSEL) == 0) - dep = 1; - else if ( (hitresult & BONESEL_TIP) && (ebone->flag & BONE_TIPSEL) == 0) - dep = 1; - else - dep = 2; - } - else dep = 2; - } - else { - /* bone found */ - if (findunsel) { - if ((ebone->flag & BONE_SELECTED) == 0) - dep = 2; - else - dep = 3; - } - else dep = 3; - } - if (dep < mindep) { - mindep = dep; - besthitresult = hitresult; - } - } - } - } - - if (!(besthitresult & BONESEL_NOSEL)) { - - ebone = BLI_findlink(edbo, besthitresult & ~BONESEL_ANY); - - *selmask = 0; - if (besthitresult & BONESEL_ROOT) - *selmask |= BONE_ROOTSEL; - if (besthitresult & BONESEL_TIP) - *selmask |= BONE_TIPSEL; - if (besthitresult & BONESEL_BONE) - *selmask |= BONE_SELECTED; - return ebone; - } - } - *selmask = 0; - return NULL; -} - -/* 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 - arm = obedit->data; - - /* cancel if nothing selected */ - if (CTX_DATA_COUNT(C, selected_bones) == 0) - return OPERATOR_CANCELLED; - - 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 = editbone_name_exists(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_get_typeinfo(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 = editbone_name_exists(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); - } - } - } - } - } - - - for (curBone = arm->edbo->first; curBone; curBone = ebone_next) { - ebone_next = curBone->next; - if (arm->layer & curBone->layer) { - if (curBone->flag & BONE_SELECTED) { - if (curBone == arm->act_edbone) arm->act_edbone = NULL; - ED_armature_edit_bone_remove(arm, curBone); - } - } - } - - - ED_armature_sync_selection(arm->edbo); - - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); - - return OPERATOR_FINISHED; -} - -void ARMATURE_OT_delete(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Delete Selected Bone(s)"; - ot->idname = "ARMATURE_OT_delete"; - ot->description = "Remove selected bones from the armature"; - - /* api callbacks */ - ot->invoke = WM_operator_confirm; - ot->exec = armature_delete_selected_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/* 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) -{ - 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; - - /* 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; - } - } - - ED_armature_sync_selection(arm->edbo); -} - -void ED_armature_deselect_all_visible(Object *obedit) -{ - bArmature *arm = obedit->data; - EditBone *ebone; - - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - /* first and foremost, bone must be visible and selected */ - if (EBONE_SELECTABLE(arm, ebone)) { - ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } - } - - ED_armature_sync_selection(arm->edbo); -} - -/* accounts for connected parents */ -static int ebone_select_flag(EditBone *ebone) -{ - if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { - return ((ebone->parent->flag & BONE_TIPSEL) ? BONE_ROOTSEL : 0) | (ebone->flag & (BONE_SELECTED | BONE_TIPSEL)); - } - else { - return ebone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL); - } -} - -/* context: editmode armature in view3d */ -int mouse_armature(bContext *C, const int mval[2], int extend, int deselect, int toggle) -{ - Object *obedit = CTX_data_edit_object(C); - bArmature *arm = obedit->data; - ViewContext vc; - EditBone *nearBone = NULL; - int selmask; - - view3d_set_viewcontext(C, &vc); - - BIF_sk_selectStroke(C, mval, extend); - - nearBone = get_nearest_editbonepoint(&vc, mval, arm->edbo, 1, &selmask); - if (nearBone) { - - if (!extend && !deselect && !toggle) - ED_armature_deselect_all(obedit, 0); - - /* by definition the non-root connected bones have no root point drawn, - * so a root selection needs to be delivered to the parent tip */ - - if (selmask & BONE_SELECTED) { - if (nearBone->parent && (nearBone->flag & BONE_CONNECTED)) { - /* click in a chain */ - if (extend) { - /* select this bone */ - nearBone->flag |= BONE_TIPSEL; - nearBone->parent->flag |= BONE_TIPSEL; - } - else if (deselect) { - /* deselect this bone */ - nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED); - /* only deselect parent tip if it is not selected */ - if (!(nearBone->parent->flag & BONE_SELECTED)) - nearBone->parent->flag &= ~BONE_TIPSEL; - } - else if (toggle) { - /* hold shift inverts this bone's selection */ - if (nearBone->flag & BONE_SELECTED) { - /* deselect this bone */ - nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED); - /* only deselect parent tip if it is not selected */ - if (!(nearBone->parent->flag & BONE_SELECTED)) - nearBone->parent->flag &= ~BONE_TIPSEL; - } - else { - /* select this bone */ - nearBone->flag |= BONE_TIPSEL; - nearBone->parent->flag |= BONE_TIPSEL; - } - } - else { - /* select this bone */ - nearBone->flag |= BONE_TIPSEL; - nearBone->parent->flag |= BONE_TIPSEL; - } - } - else { - if (extend) { - nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL); - } - else if (deselect) { - nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL); - } - else if (toggle) { - /* hold shift inverts this bone's selection */ - if (nearBone->flag & BONE_SELECTED) - nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL); - else - nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL); - } - else - nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL); - } - } - else { - if (extend) - nearBone->flag |= selmask; - else if (deselect) - nearBone->flag &= ~selmask; - else if (toggle && (nearBone->flag & selmask)) - nearBone->flag &= ~selmask; - else - nearBone->flag |= selmask; - } - - ED_armature_sync_selection(arm->edbo); - - if (nearBone) { - /* then now check for active status */ - if (ebone_select_flag(nearBone)) { - arm->act_edbone = nearBone; - } - } - - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit); - return 1; - } - - return 0; -} - -void ED_armature_edit_free(struct Object *ob) -{ - bArmature *arm = ob->data; - EditBone *eBone; - - /* Clear the editbones list */ - if (arm->edbo) { - if (arm->edbo->first) { - for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { - if (eBone->prop) { - IDP_FreeProperty(eBone->prop); - MEM_freeN(eBone->prop); - } - } - - BLI_freelistN(arm->edbo); - } - MEM_freeN(arm->edbo); - arm->edbo = NULL; - } -} - -/* Put armature in EditMode */ -void ED_armature_to_edit(Object *ob) -{ - bArmature *arm = ob->data; - - ED_armature_edit_free(ob); - arm->edbo = MEM_callocN(sizeof(ListBase), "edbo armature"); - arm->act_edbone = make_boneList(arm->edbo, &arm->bonebase, NULL, arm->act_bone); - arm->act_bone = NULL; - -// BIF_freeTemplates(); /* force template update when entering editmode */ -} - - -/* adjust bone roll to align Z axis with vector - * vec is in local space and is normalized - */ - -float ED_rollBoneToVector(EditBone *bone, const float align_axis[3], const short axis_only) -{ - float mat[3][3], nor[3]; - - sub_v3_v3v3(nor, bone->tail, bone->head); - vec_roll_to_mat3(nor, 0.0f, mat); - - /* check the bone isn't aligned with the axis */ - if (!is_zero_v3(align_axis) && angle_v3v3(align_axis, mat[2]) > FLT_EPSILON) { - float vec[3], align_axis_proj[3], roll; - - /* project the new_up_axis along the normal */ - project_v3_v3v3(vec, align_axis, nor); - sub_v3_v3v3(align_axis_proj, align_axis, vec); - - if (axis_only) { - if (angle_v3v3(align_axis_proj, mat[2]) > (float)(M_PI / 2.0)) { - negate_v3(align_axis_proj); - } - } - - roll = angle_v3v3(align_axis_proj, mat[2]); - - cross_v3_v3v3(vec, mat[2], align_axis_proj); - - if (dot_v3v3(vec, nor) < 0) { - roll = -roll; - } - - return roll; - } - - return 0.0f; -} - - -static EnumPropertyItem prop_calc_roll_types[] = { - {0, "X", 0, "X Axis", ""}, - {1, "Y", 0, "Y Axis", ""}, - {2, "Z", 0, "Z Axis", ""}, - {5, "ACTIVE", 0, "Active Bone", ""}, - {6, "VIEW", 0, "View Axis", ""}, - {7, "CURSOR", 0, "Cursor", ""}, - {0, NULL, 0, NULL, NULL} -}; - - -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"); - const short axis_only = RNA_boolean_get(op->ptr, "axis_only"); - const short axis_flip = RNA_boolean_get(op->ptr, "axis_flip"); - - float imat[3][3]; - - bArmature *arm = ob->data; - EditBone *ebone; - - copy_m3_m4(imat, ob->obmat); - invert_m3(imat); - - if (type == 7) { /* Cursor */ - Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); /* can be NULL */ - float cursor_local[3]; - const float *cursor = give_cursor(scene, v3d); - - - copy_v3_v3(cursor_local, cursor); - mul_m3_v3(imat, cursor_local); - - /* cursor */ - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) { - float cursor_rel[3]; - sub_v3_v3v3(cursor_rel, cursor_local, ebone->head); - if (axis_flip) negate_v3(cursor_rel); - ebone->roll = ED_rollBoneToVector(ebone, cursor_rel, axis_only); - } - } - } - else { - float vec[3] = {0.0f, 0.0f, 0.0f}; - if (type == 6) { /* View */ - RegionView3D *rv3d = CTX_wm_region_view3d(C); - if (rv3d == NULL) { - BKE_report(op->reports, RPT_ERROR, "No region view3d available"); - return OPERATOR_CANCELLED; - } - - copy_v3_v3(vec, rv3d->viewinv[2]); - mul_m3_v3(imat, vec); - } - else if (type == 5) { - float mat[3][3], nor[3]; - ebone = (EditBone *)arm->act_edbone; - if (ebone == NULL) { - BKE_report(op->reports, RPT_ERROR, "No active bone set"); - return OPERATOR_CANCELLED; - } - - sub_v3_v3v3(nor, ebone->tail, ebone->head); - vec_roll_to_mat3(nor, ebone->roll, mat); - copy_v3_v3(vec, mat[2]); - } - else { /* Axis */ - assert(type >= 0 && type <= 5); - if (type < 3) vec[type] = 1.0f; - else vec[type - 2] = -1.0f; - mul_m3_v3(imat, vec); - } - - if (axis_flip) negate_v3(vec); - - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) { - /* roll func is a callback which assumes that all is well */ - ebone->roll = ED_rollBoneToVector(ebone, vec, axis_only); - } - } - } - - if (arm->flag & ARM_MIRROR_EDIT) { - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) { - EditBone *ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, ebone); - if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) { - ebone->roll = -ebone_mirr->roll; - } - } - } - } - - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); - - return OPERATOR_FINISHED; -} - -void ARMATURE_OT_calculate_roll(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Recalculate Roll"; - ot->idname = "ARMATURE_OT_calculate_roll"; - ot->description = "Automatically fix alignment of select bones' axes"; - - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = armature_calc_roll_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", prop_calc_roll_types, 0, "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"); -} - -/* **************** undo for armatures ************** */ - -typedef struct UndoArmature { - EditBone *act_edbone; - ListBase lb; -} UndoArmature; - -static void undoBones_to_editBones(void *uarmv, void *armv, void *UNUSED(data)) -{ - UndoArmature *uarm = uarmv; - bArmature *arm = armv; - EditBone *ebo, *newebo; - - BLI_freelistN(arm->edbo); - - /* copy */ - for (ebo = uarm->lb.first; ebo; ebo = ebo->next) { - newebo = MEM_dupallocN(ebo); - ebo->temp = newebo; - BLI_addtail(arm->edbo, newebo); - } - - /* active bone */ - if (uarm->act_edbone) { - ebo = uarm->act_edbone; - arm->act_edbone = ebo->temp; - } - else - arm->act_edbone = NULL; - - /* set pointers */ - for (newebo = arm->edbo->first; newebo; newebo = newebo->next) { - if (newebo->parent) newebo->parent = newebo->parent->temp; - } - /* be sure they don't hang ever */ - for (newebo = arm->edbo->first; newebo; newebo = newebo->next) { - newebo->temp = NULL; - } -} - -static void *editBones_to_undoBones(void *armv, void *UNUSED(obdata)) -{ - bArmature *arm = armv; - UndoArmature *uarm; - EditBone *ebo, *newebo; - - uarm = MEM_callocN(sizeof(UndoArmature), "listbase undo"); - - /* copy */ - for (ebo = arm->edbo->first; ebo; ebo = ebo->next) { - newebo = MEM_dupallocN(ebo); - ebo->temp = newebo; - BLI_addtail(&uarm->lb, newebo); - } - - /* active bone */ - if (arm->act_edbone) { - ebo = arm->act_edbone; - uarm->act_edbone = ebo->temp; - } - - /* set pointers */ - for (newebo = uarm->lb.first; newebo; newebo = newebo->next) { - if (newebo->parent) newebo->parent = newebo->parent->temp; - } - - return uarm; -} - -static void free_undoBones(void *uarmv) -{ - UndoArmature *uarm = uarmv; - - BLI_freelistN(&uarm->lb); - MEM_freeN(uarm); -} - -static void *get_armature_edit(bContext *C) -{ - Object *obedit = CTX_data_edit_object(C); - if (obedit && obedit->type == OB_ARMATURE) { - return obedit->data; - } - return NULL; -} - -/* and this is all the undo system needs to know */ -void undo_push_armature(bContext *C, const char *name) -{ - // XXX solve getdata() - undo_editmode_push(C, name, get_armature_edit, free_undoBones, undoBones_to_editBones, editBones_to_undoBones, NULL); -} - - - -/* **************** END EditMode stuff ********************** */ -/* *************** Adding stuff in editmode *************** */ - -/* default bone add, returns it selected, but without tail set */ -/* XXX should be used everywhere, now it mallocs bones still locally in functions */ -EditBone *ED_armature_edit_bone_add(bArmature *arm, const char *name) -{ - EditBone *bone = MEM_callocN(sizeof(EditBone), "eBone"); - - BLI_strncpy(bone->name, name, sizeof(bone->name)); - unique_editbone_name(arm->edbo, bone->name, NULL); - - BLI_addtail(arm->edbo, bone); - - bone->flag |= BONE_TIPSEL; - bone->weight = 1.0f; - bone->dist = 0.25f; - bone->xwidth = 0.1f; - bone->zwidth = 0.1f; - bone->ease1 = 1.0f; - bone->ease2 = 1.0f; - bone->rad_head = 0.10f; - bone->rad_tail = 0.05f; - bone->segments = 1; - bone->layer = arm->layer; - - return bone; -} - -/* v3d and rv3d are allowed to be NULL */ -void add_primitive_bone(Scene *scene, View3D *v3d, RegionView3D *rv3d) -{ - Object *obedit = scene->obedit; // XXX get from context - bArmature *arm = obedit->data; - float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3]; - EditBone *bone; - - /* Get inverse point for head and orientation for tail */ - invert_m4_m4(obedit->imat, obedit->obmat); - mul_v3_m4v3(curs, obedit->imat, give_cursor(scene, v3d)); - - if (rv3d && (U.flag & USER_ADD_VIEWALIGNED)) - copy_m3_m4(obmat, rv3d->viewmat); - else unit_m3(obmat); - - copy_m3_m4(viewmat, obedit->obmat); - mul_m3_m3m3(totmat, obmat, viewmat); - invert_m3_m3(imat, totmat); - - ED_armature_deselect_all(obedit, 0); - - /* Create a bone */ - bone = ED_armature_edit_bone_add(arm, "Bone"); - - arm->act_edbone = bone; - - copy_v3_v3(bone->head, curs); - - if (rv3d && (U.flag & USER_ADD_VIEWALIGNED)) - add_v3_v3v3(bone->tail, bone->head, imat[1]); // bone with unit length 1 - else - add_v3_v3v3(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z -} - - -/* previously addvert_armature */ -/* the ctrl-click method */ -static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op)) -{ - View3D *v3d; - bArmature *arm; - EditBone *ebone, *newbone, *flipbone; - float mat[3][3], imat[3][3]; - const float *curs; - int a, to_root = 0; - Object *obedit; - Scene *scene; - - scene = CTX_data_scene(C); - v3d = CTX_wm_view3d(C); - obedit = CTX_data_edit_object(C); - arm = obedit->data; - - /* find the active or selected bone */ - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_VISIBLE(arm, ebone)) { - if (ebone->flag & BONE_TIPSEL || arm->act_edbone == ebone) - break; - } - } - - if (ebone == NULL) { - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_VISIBLE(arm, ebone)) { - if (ebone->flag & BONE_ROOTSEL || arm->act_edbone == ebone) - break; - } - } - if (ebone == NULL) - return OPERATOR_CANCELLED; - - to_root = 1; - } - - ED_armature_deselect_all(obedit, 0); - - /* we re-use code for mirror editing... */ - flipbone = NULL; - if (arm->flag & ARM_MIRROR_EDIT) - flipbone = ED_armature_bone_get_mirrored(arm->edbo, ebone); - - for (a = 0; a < 2; a++) { - if (a == 1) { - if (flipbone == NULL) - break; - else { - SWAP(EditBone *, flipbone, ebone); - } - } - - newbone = ED_armature_edit_bone_add(arm, ebone->name); - arm->act_edbone = newbone; - - if (to_root) { - copy_v3_v3(newbone->head, ebone->head); - newbone->rad_head = ebone->rad_tail; - newbone->parent = ebone->parent; - } - else { - copy_v3_v3(newbone->head, ebone->tail); - newbone->rad_head = ebone->rad_tail; - newbone->parent = ebone; - newbone->flag |= BONE_CONNECTED; - } - - curs = give_cursor(scene, v3d); - copy_v3_v3(newbone->tail, curs); - sub_v3_v3v3(newbone->tail, newbone->tail, obedit->obmat[3]); - - if (a == 1) - newbone->tail[0] = -newbone->tail[0]; - - copy_m3_m4(mat, obedit->obmat); - invert_m3_m3(imat, mat); - mul_m3_v3(imat, newbone->tail); - - newbone->length = len_v3v3(newbone->head, newbone->tail); - newbone->rad_tail = newbone->length * 0.05f; - newbone->dist = newbone->length * 0.25f; - - } - - ED_armature_sync_selection(arm->edbo); - - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); - - return OPERATOR_FINISHED; -} - -static int armature_click_extrude_invoke(bContext *C, wmOperator *op, wmEvent *event) -{ - /* TODO most of this code is copied from set3dcursor_invoke, - * it would be better to reuse code in set3dcursor_invoke */ - - /* temporarily change 3d cursor position */ - Scene *scene; - ARegion *ar; - View3D *v3d; - float *fp, tvec[3], oldcurs[3], mval_f[2]; - int retv; - - scene = CTX_data_scene(C); - ar = CTX_wm_region(C); - v3d = CTX_wm_view3d(C); - - fp = give_cursor(scene, v3d); - - copy_v3_v3(oldcurs, fp); - - VECCOPY2D(mval_f, event->mval); - ED_view3d_win_to_3d(ar, fp, mval_f, tvec); - copy_v3_v3(fp, tvec); - - /* extrude to the where new cursor is and store the operation result */ - retv = armature_click_extrude_exec(C, op); - - /* restore previous 3d cursor position */ - copy_v3_v3(fp, oldcurs); - - return retv; -} - -void ARMATURE_OT_click_extrude(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Click-Extrude"; - ot->idname = "ARMATURE_OT_click_extrude"; - ot->description = "Create a new bone going from the last selected joint to the mouse position"; - - /* api callbacks */ - ot->invoke = armature_click_extrude_invoke; - ot->exec = armature_click_extrude_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* props */ -} - -/* adds an EditBone between the nominated locations (should be in the right space) */ -static EditBone *add_points_bone(Object *obedit, float head[], float tail[]) -{ - EditBone *ebo; - - ebo = ED_armature_edit_bone_add(obedit->data, "Bone"); - - copy_v3_v3(ebo->head, head); - copy_v3_v3(ebo->tail, tail); - - return ebo; -} - - -static EditBone *get_named_editbone(ListBase *edbo, char *name) -{ - EditBone *eBone; - - if (name) { - for (eBone = edbo->first; eBone; eBone = eBone->next) { - if (!strcmp(name, eBone->name)) - return eBone; - } - } - - return NULL; -} - -/* Call this before doing any duplications - * */ -void preEditBoneDuplicate(ListBase *editbones) -{ - EditBone *eBone; - - /* clear temp */ - for (eBone = editbones->first; eBone; eBone = eBone->next) { - eBone->temp = NULL; - } -} - -/* - * Note: When duplicating cross objects, editbones here is the list of bones - * from the SOURCE object but ob is the DESTINATION object - * */ -void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Object *src_ob, Object *dst_ob) -{ - /* If an edit bone has been duplicated, lets - * update it's constraints if the subtarget - * they point to has also been duplicated - */ - EditBone *oldtarget, *newtarget; - bPoseChannel *pchan; - bConstraint *curcon; - ListBase *conlist; - - if ( (pchan = BKE_pose_channel_verify(dst_ob->pose, dupBone->name)) ) { - if ( (conlist = &pchan->constraints) ) { - for (curcon = conlist->first; curcon; curcon = curcon->next) { - /* does this constraint have a subtarget in - * this armature? - */ - bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(curcon); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(curcon, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - if ((ct->tar == src_ob) && (ct->subtarget[0])) { - ct->tar = dst_ob; /* update target */ - oldtarget = get_named_editbone(editbones, ct->subtarget); - if (oldtarget) { - /* was the subtarget bone duplicated too? If - * so, update the constraint to point at the - * duplicate of the old subtarget. - */ - if (oldtarget->temp) { - newtarget = (EditBone *) oldtarget->temp; - BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget)); - } - } - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(curcon, &targets, 0); - } - } - } - } -} - -void updateDuplicateSubtarget(EditBone *dupBone, ListBase *editbones, Object *ob) -{ - updateDuplicateSubtargetObjects(dupBone, editbones, ob, ob); -} - - -EditBone *duplicateEditBoneObjects(EditBone *curBone, const char *name, ListBase *editbones, - Object *src_ob, Object *dst_ob) -{ - EditBone *eBone = MEM_mallocN(sizeof(EditBone), "addup_editbone"); - - /* Copy data from old bone to new bone */ - memcpy(eBone, curBone, sizeof(EditBone)); - - curBone->temp = eBone; - eBone->temp = curBone; - - if (name != NULL) { - BLI_strncpy(eBone->name, name, sizeof(eBone->name)); - } - - unique_editbone_name(editbones, eBone->name, NULL); - BLI_addtail(editbones, eBone); - - /* copy the ID property */ - if (curBone->prop) - eBone->prop = IDP_CopyProperty(curBone->prop); - - /* Lets duplicate the list of constraints that the - * current bone has. - */ - if (src_ob->pose) { - bPoseChannel *chanold, *channew; - - chanold = BKE_pose_channel_verify(src_ob->pose, curBone->name); - if (chanold) { - /* WARNING: this creates a new posechannel, but there will not be an attached bone - * yet as the new bones created here are still 'EditBones' not 'Bones'. - */ - channew = BKE_pose_channel_verify(dst_ob->pose, eBone->name); - - if (channew) { - BKE_pose_channel_copy_data(channew, chanold); - } - } - } - - return eBone; -} - -EditBone *duplicateEditBone(EditBone *curBone, const char *name, ListBase *editbones, Object *ob) -{ - 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 */ - - Object *obedit = CTX_data_edit_object(C); - 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 */ - 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; - } - } - } - } - - - /* 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; - - } - } - } - - /* 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 - */ - 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; - } - - /* 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); - } - - ED_armature_validate_active(arm); - - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); - - return OPERATOR_FINISHED; -} - - -void ARMATURE_OT_duplicate(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Duplicate Selected Bone(s)"; - ot->idname = "ARMATURE_OT_duplicate"; - ot->description = "Make copies of the selected bones within the same armature"; - - /* api callbacks */ - ot->exec = armature_duplicate_selected_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - - -/* *************** END Adding stuff in editmode *************** */ -/* ************** Add/Remove stuff in editmode **************** */ - -/* temporary data-structure for merge/fill bones */ -typedef struct EditBonePoint { - struct EditBonePoint *next, *prev; - - EditBone *head_owner; /* EditBone which uses this point as a 'head' point */ - EditBone *tail_owner; /* EditBone which uses this point as a 'tail' point */ - - float vec[3]; /* the actual location of the point in local/EditMode space */ -} EditBonePoint; - -/* find chain-tips (i.e. bones without children) */ -static void chains_find_tips(ListBase *edbo, ListBase *list) -{ - EditBone *curBone, *ebo; - LinkData *ld; - - /* note: this is potentially very slow ... there's got to be a better way */ - for (curBone = edbo->first; curBone; curBone = curBone->next) { - short stop = 0; - - /* is this bone contained within any existing chain? (skip if so) */ - for (ld = list->first; ld; ld = ld->next) { - for (ebo = ld->data; ebo; ebo = ebo->parent) { - if (ebo == curBone) { - stop = 1; - break; - } - } - - if (stop) break; - } - /* skip current bone if it is part of an existing chain */ - if (stop) continue; - - /* is any existing chain part of the chain formed by this bone? */ - stop = 0; - for (ebo = curBone->parent; ebo; ebo = ebo->parent) { - for (ld = list->first; ld; ld = ld->next) { - if (ld->data == ebo) { - ld->data = curBone; - stop = 1; - break; - } - } - - if (stop) break; - } - /* current bone has already been added to a chain? */ - if (stop) continue; - - /* add current bone to a new chain */ - ld = MEM_callocN(sizeof(LinkData), "BoneChain"); - ld->data = curBone; - BLI_addtail(list, ld); - } -} - -/* --------------------- */ - -static void fill_add_joint(EditBone *ebo, short eb_tail, ListBase *points) -{ - EditBonePoint *ebp; - float vec[3]; - short found = 0; - - if (eb_tail) { - copy_v3_v3(vec, ebo->tail); - } - else { - copy_v3_v3(vec, ebo->head); - } - - for (ebp = points->first; ebp; ebp = ebp->next) { - if (equals_v3v3(ebp->vec, vec)) { - if (eb_tail) { - if ((ebp->head_owner) && (ebp->head_owner->parent == ebo)) { - /* so this bone's tail owner is this bone */ - ebp->tail_owner = ebo; - found = 1; - break; - } - } - else { - if ((ebp->tail_owner) && (ebo->parent == ebp->tail_owner)) { - /* so this bone's head owner is this bone */ - ebp->head_owner = ebo; - found = 1; - break; - } - } - } - } - - /* allocate a new point if no existing point was related */ - if (found == 0) { - ebp = MEM_callocN(sizeof(EditBonePoint), "EditBonePoint"); - - if (eb_tail) { - copy_v3_v3(ebp->vec, ebo->tail); - ebp->tail_owner = ebo; - } - else { - copy_v3_v3(ebp->vec, ebo->head); - ebp->head_owner = ebo; - } - - BLI_addtail(points, ebp); - } -} - -/* bone adding between selected joints */ -static int armature_fill_bones_exec(bContext *C, wmOperator *op) -{ - Object *obedit = CTX_data_edit_object(C); - bArmature *arm = (obedit) ? obedit->data : NULL; - Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); - ListBase points = {NULL, NULL}; - int count; - - /* sanity checks */ - if (ELEM(NULL, obedit, arm)) - return OPERATOR_CANCELLED; - - /* loop over all bones, and only consider if visible */ - CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones) - { - if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL)) - fill_add_joint(ebone, 0, &points); - if (ebone->flag & BONE_TIPSEL) - fill_add_joint(ebone, 1, &points); - } - CTX_DATA_END; - - /* the number of joints determines how we fill: - * 1) between joint and cursor (joint=head, cursor=tail) - * 2) between the two joints (order is dependent on active-bone/hierachy) - * 3+) error (a smarter method involving finding chains needs to be worked out - */ - count = BLI_countlist(&points); - - if (count == 0) { - BKE_report(op->reports, RPT_ERROR, "No joints selected"); - return OPERATOR_CANCELLED; - } - else if (count == 1) { - EditBonePoint *ebp; - float curs[3]; - - /* Get Points - selected joint */ - ebp = (EditBonePoint *)points.first; - - /* Get points - cursor (tail) */ - invert_m4_m4(obedit->imat, obedit->obmat); - mul_v3_m4v3(curs, obedit->imat, give_cursor(scene, v3d)); - - /* Create a bone */ - /* newbone = */ add_points_bone(obedit, ebp->vec, curs); - } - else if (count == 2) { - EditBonePoint *ebp, *ebp2; - 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; - - 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)) { - 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, give_cursor(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; - } - else if (ebp->head_owner) { - headtail = 1; - } - else if (ebp2->head_owner) { - headtail = 2; - } - - /* assign head/tail combinations */ - if (headtail == 2) { - copy_v3_v3(head, ebp->vec); - copy_v3_v3(tail, ebp2->vec); - } - else if (headtail == 1) { - copy_v3_v3(head, ebp2->vec); - copy_v3_v3(tail, ebp->vec); - } - - /* add new bone and parent it to the appropriate end */ - if (headtail) { - EditBone *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; - else - newbone->parent = ebp->head_owner; - } - else { - /* ebp2 tail or head - tail gets priority */ - if (ebp2->tail_owner) - newbone->parent = ebp2->tail_owner; - else - newbone->parent = ebp2->head_owner; - } - - newbone->flag |= BONE_CONNECTED; - } - } - else { - /* FIXME.. figure out a method for multiple bones */ - BKE_reportf(op->reports, RPT_ERROR, "Too many points selected: %d", count); - BLI_freelistN(&points); - return OPERATOR_CANCELLED; - } - - /* updates */ - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit); - - /* free points */ - BLI_freelistN(&points); - - return OPERATOR_FINISHED; -} - -void ARMATURE_OT_fill(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Fill Between Joints"; - ot->idname = "ARMATURE_OT_fill"; - ot->description = "Add bone between selected joint(s) and/or 3D-Cursor"; - - /* callbacks */ - ot->exec = armature_fill_bones_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/* --------------------- */ - -/* this function merges between two bones, removes them and those in-between, - * and adjusts the parent relationships for those in-between - */ -static void bones_merge(Object *obedit, EditBone *start, EditBone *end, EditBone *endchild, ListBase *chains) -{ - bArmature *arm = obedit->data; - EditBone *ebo, *ebone, *newbone; - LinkData *chain; - float head[3], tail[3]; - - /* check if same bone */ - if (start == end) { - if (G.debug & G_DEBUG) { - printf("Error: same bone!\n"); - printf("\tstart = %s, end = %s\n", start->name, end->name); - } - } - - /* step 1: add a new bone - * - head = head/tail of start (default head) - * - tail = head/tail of end (default tail) - * - parent = parent of start - */ - if ((start->flag & BONE_TIPSEL) && (start->flag & BONE_SELECTED) == 0) { - copy_v3_v3(head, start->tail); - } - else { - copy_v3_v3(head, start->head); - } - if ((end->flag & BONE_ROOTSEL) && (end->flag & BONE_SELECTED) == 0) { - copy_v3_v3(tail, end->head); - } - else { - copy_v3_v3(tail, end->tail); - } - newbone = add_points_bone(obedit, head, tail); - newbone->parent = start->parent; - - /* TODO, copy more things to the new bone */ - newbone->flag = start->flag & (BONE_HINGE | BONE_NO_DEFORM | BONE_NO_SCALE | - BONE_NO_CYCLICOFFSET | BONE_NO_LOCAL_LOCATION | BONE_DONE); - - /* step 2a: reparent any side chains which may be parented to any bone in the chain of bones to merge - * - potentially several tips for side chains leading to some tree exist... - */ - for (chain = chains->first; chain; chain = chain->next) { - /* traverse down chain until we hit the bottom or if we run into the tip of the chain of bones we're - * merging (need to stop in this case to avoid corrupting this chain too!) - */ - for (ebone = chain->data; (ebone) && (ebone != end); ebone = ebone->parent) { - short found = 0; - - /* check if this bone is parented to one in the merging chain - * ! WATCHIT: must only go check until end of checking chain - */ - for (ebo = end; (ebo) && (ebo != start->parent); ebo = ebo->parent) { - /* side-chain found? --> remap parent to new bone, then we're done with this chain :) */ - if (ebone->parent == ebo) { - ebone->parent = newbone; - found = 1; - break; - } - } - - /* carry on to the next tip now */ - if (found) - break; - } - } - - /* step 2b: parent child of end to newbone (child from this chain) */ - if (endchild) - endchild->parent = newbone; - - /* step 3: delete all bones between and including start and end */ - for (ebo = end; ebo; ebo = ebone) { - ebone = (ebo == start) ? (NULL) : (ebo->parent); - bone_free(arm, ebo); - } - - newbone->flag |= (BONE_ROOTSEL | BONE_TIPSEL | BONE_SELECTED); - ED_armature_sync_selection(arm->edbo); -} - - -static int armature_merge_exec(bContext *C, wmOperator *op) -{ - Object *obedit = CTX_data_edit_object(C); - bArmature *arm = (obedit) ? obedit->data : NULL; - short type = RNA_enum_get(op->ptr, "type"); - - /* sanity checks */ - if (ELEM(NULL, obedit, arm)) - return OPERATOR_CANCELLED; - - /* for now, there's only really one type of merging that's performed... */ - if (type == 1) { - /* go down chains, merging bones */ - ListBase chains = {NULL, NULL}; - LinkData *chain, *nchain; - EditBone *ebo; - - armature_tag_select_mirrored(arm); - - /* get chains (ends on chains) */ - chains_find_tips(arm->edbo, &chains); - if (chains.first == NULL) return OPERATOR_CANCELLED; - - /* each 'chain' is the last bone in the chain (with no children) */ - for (chain = chains.first; chain; chain = nchain) { - EditBone *bstart = NULL, *bend = NULL; - EditBone *bchild = NULL, *child = NULL; - - /* temporarily remove chain from list of chains */ - nchain = chain->next; - BLI_remlink(&chains, chain); - - /* only consider bones that are visible and selected */ - for (ebo = chain->data; ebo; child = ebo, ebo = ebo->parent) { - /* check if visible + selected */ - if (EBONE_VISIBLE(arm, ebo) && - ((ebo->flag & BONE_CONNECTED) || (ebo->parent == NULL)) && - (ebo->flag & BONE_SELECTED) ) - { - /* set either end or start (end gets priority, unless it is already set) */ - if (bend == NULL) { - bend = ebo; - bchild = child; - } - else - bstart = ebo; - } - else { - /* chain is broken... merge any continous segments then clear */ - if (bstart && bend) - bones_merge(obedit, bstart, bend, bchild, &chains); - - bstart = NULL; - bend = NULL; - bchild = NULL; - } - } - - /* merge from bstart to bend if something not merged */ - if (bstart && bend) - bones_merge(obedit, bstart, bend, bchild, &chains); - - /* put back link */ - BLI_insertlinkbefore(&chains, nchain, chain); - } - - armature_tag_unselect(arm); - - BLI_freelistN(&chains); - } - - /* updates */ - ED_armature_sync_selection(arm->edbo); - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit); - - return OPERATOR_FINISHED; -} - -void ARMATURE_OT_merge(wmOperatorType *ot) -{ - static EnumPropertyItem merge_types[] = { - {1, "WITHIN_CHAIN", 0, "Within Chains", ""}, - {0, NULL, 0, NULL, NULL} - }; - - /* identifiers */ - ot->name = "Merge Bones"; - ot->idname = "ARMATURE_OT_merge"; - ot->description = "Merge continuous chains of selected bones"; - - /* callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = armature_merge_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", merge_types, 0, "Type", ""); -} - -/* ************** END Add/Remove stuff in editmode ************ */ -/* *************** Tools in editmode *********** */ - -static int armature_hide_exec(bContext *C, wmOperator *op) -{ - Object *obedit = CTX_data_edit_object(C); - bArmature *arm = obedit->data; - EditBone *ebone; - const int invert = RNA_boolean_get(op->ptr, "unselected") ? BONE_SELECTED : 0; - - /* cancel if nothing selected */ - if (CTX_DATA_COUNT(C, selected_bones) == 0) - return OPERATOR_CANCELLED; - - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_VISIBLE(arm, ebone)) { - if ((ebone->flag & BONE_SELECTED) != invert) { - ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); - ebone->flag |= BONE_HIDDEN_A; - } - } - } - ED_armature_validate_active(arm); - ED_armature_sync_selection(arm->edbo); - - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); - - return OPERATOR_FINISHED; -} - -void ARMATURE_OT_hide(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Hide Selected Bones"; - ot->idname = "ARMATURE_OT_hide"; - ot->description = "Tag selected bones to not be visible in Edit Mode"; - - /* api callbacks */ - ot->exec = armature_hide_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* props */ - RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected"); -} - -static int armature_reveal_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obedit = CTX_data_edit_object(C); - bArmature *arm = obedit->data; - EditBone *ebone; - - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (arm->layer & ebone->layer) { - if (ebone->flag & BONE_HIDDEN_A) { - ebone->flag |= (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); - ebone->flag &= ~BONE_HIDDEN_A; - } - } - } - ED_armature_validate_active(arm); - ED_armature_sync_selection(arm->edbo); - - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); - - return OPERATOR_FINISHED; -} - -void ARMATURE_OT_reveal(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Reveal Bones"; - ot->idname = "ARMATURE_OT_reveal"; - ot->description = "Unhide all bones that have been tagged to be hidden in Edit Mode"; - - /* api callbacks */ - ot->exec = armature_reveal_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - -} -#if 0 // remove this? -static void hide_selected_armature_bones(Scene *scene) -{ - Object *obedit = scene->obedit; // XXX get from context - bArmature *arm = obedit->data; - EditBone *ebone; - - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_VISIBLE(arm, ebone)) { - if (ebone->flag & BONE_SELECTED) { - ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); - ebone->flag |= BONE_HIDDEN_A; - } - } - } - ED_armature_validate_active(arm); - ED_armature_sync_selection(arm->edbo); -} - -static void hide_unselected_armature_bones(Scene *scene) -{ - Object *obedit = scene->obedit; // XXX get from context - bArmature *arm = obedit->data; - EditBone *ebone; - - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - bArmature *arm = obedit->data; - if (EBONE_VISIBLE(arm, ebone)) { - if (ebone->flag & (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL)) { - /* pass */ - } - else { - ebone->flag |= BONE_HIDDEN_A; - } - } - } - - ED_armature_validate_active(arm); - ED_armature_sync_selection(arm->edbo); -} - -void show_all_armature_bones(Scene *scene) -{ - Object *obedit = scene->obedit; // XXX get from context - bArmature *arm = obedit->data; - EditBone *ebone; - - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (arm->layer & ebone->layer) { - if (ebone->flag & BONE_HIDDEN_A) { - ebone->flag |= (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); - ebone->flag &= ~BONE_HIDDEN_A; - } - } - } - ED_armature_validate_active(arm); - ED_armature_sync_selection(arm->edbo); -} -#endif - -/* previously extrude_armature */ -/* context; editmode armature */ -/* if forked && mirror-edit: makes two bones with flipped names */ -static int armature_extrude_exec(bContext *C, wmOperator *op) -{ - Object *obedit; - bArmature *arm; - EditBone *newbone, *ebone, *flipbone, *first = NULL; - int a, totbone = 0, do_extrude; - int forked = RNA_boolean_get(op->ptr, "forked"); - - obedit = CTX_data_edit_object(C); - arm = obedit->data; - - /* since we allow root extrude too, we have to make sure selection is OK */ - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_VISIBLE(arm, ebone)) { - if (ebone->flag & BONE_ROOTSEL) { - if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { - if (ebone->parent->flag & BONE_TIPSEL) - ebone->flag &= ~BONE_ROOTSEL; - } - } - } - } - - /* Duplicate the necessary bones */ - for (ebone = arm->edbo->first; ((ebone) && (ebone != first)); ebone = ebone->next) { - if (EBONE_VISIBLE(arm, ebone)) { - /* we extrude per definition the tip */ - do_extrude = FALSE; - if (ebone->flag & (BONE_TIPSEL | BONE_SELECTED)) { - do_extrude = TRUE; - } - else if (ebone->flag & BONE_ROOTSEL) { - /* but, a bone with parent deselected we do the root... */ - if (ebone->parent && (ebone->parent->flag & BONE_TIPSEL)) { - /* pass */ - } - else { - do_extrude = 2; - } - } - - if (do_extrude) { - /* we re-use code for mirror editing... */ - flipbone = NULL; - if (arm->flag & ARM_MIRROR_EDIT) { - flipbone = ED_armature_bone_get_mirrored(arm->edbo, ebone); - if (flipbone) { - forked = 0; // we extrude 2 different bones - if (flipbone->flag & (BONE_TIPSEL | BONE_ROOTSEL | BONE_SELECTED)) - /* don't want this bone to be selected... */ - flipbone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); - } - if ((flipbone == NULL) && (forked)) - flipbone = ebone; - } - - for (a = 0; a < 2; a++) { - if (a == 1) { - if (flipbone == NULL) - break; - else { - SWAP(EditBone *, flipbone, ebone); - } - } - - totbone++; - newbone = MEM_callocN(sizeof(EditBone), "extrudebone"); - - if (do_extrude == TRUE) { - copy_v3_v3(newbone->head, ebone->tail); - copy_v3_v3(newbone->tail, newbone->head); - newbone->parent = ebone; - - newbone->flag = ebone->flag & (BONE_TIPSEL | BONE_RELATIVE_PARENTING); // copies it, in case mirrored bone - - if (newbone->parent) newbone->flag |= BONE_CONNECTED; - } - else { - copy_v3_v3(newbone->head, ebone->head); - copy_v3_v3(newbone->tail, ebone->head); - newbone->parent = ebone->parent; - - newbone->flag = BONE_TIPSEL; - - if (newbone->parent && (ebone->flag & BONE_CONNECTED)) { - newbone->flag |= BONE_CONNECTED; - } - } - - newbone->weight = ebone->weight; - newbone->dist = ebone->dist; - newbone->xwidth = ebone->xwidth; - newbone->zwidth = ebone->zwidth; - newbone->ease1 = ebone->ease1; - newbone->ease2 = ebone->ease2; - newbone->rad_head = ebone->rad_tail; // don't copy entire bone... - newbone->rad_tail = ebone->rad_tail; - newbone->segments = 1; - newbone->layer = ebone->layer; - - BLI_strncpy(newbone->name, ebone->name, sizeof(newbone->name)); - - if (flipbone && forked) { // only set if mirror edit - if (strlen(newbone->name) < 30) { - if (a == 0) strcat(newbone->name, "_L"); - else strcat(newbone->name, "_R"); - } - } - unique_editbone_name(arm->edbo, newbone->name, NULL); - - /* Add the new bone to the list */ - BLI_addtail(arm->edbo, newbone); - if (!first) - first = newbone; - - /* restore ebone if we were flipping */ - if (a == 1 && flipbone) - SWAP(EditBone *, flipbone, ebone); - } - } - - /* Deselect the old bone */ - ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); - } - } - /* if only one bone, make this one active */ - if (totbone == 1 && first) arm->act_edbone = first; - - if (totbone == 0) return OPERATOR_CANCELLED; - - /* Transform the endpoints */ - ED_armature_sync_selection(arm->edbo); - - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); - - return OPERATOR_FINISHED; -} - -void ARMATURE_OT_extrude(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Extrude"; - ot->idname = "ARMATURE_OT_extrude"; - ot->description = "Create new bones from the selected joints"; - - /* api callbacks */ - ot->exec = armature_extrude_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* props */ - RNA_def_boolean(ot->srna, "forked", 0, "Forked", ""); -} -/* ********************** Bone Add ********************/ - -/*op makes a new bone and returns it with its tip selected */ - -static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op) -{ - RegionView3D *rv3d = CTX_wm_region_view3d(C); - Object *obedit = CTX_data_edit_object(C); - EditBone *bone; - float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3]; - char name[MAXBONENAME]; - - RNA_string_get(op->ptr, "name", name); - - copy_v3_v3(curs, give_cursor(CTX_data_scene(C), CTX_wm_view3d(C))); - - /* Get inverse point for head and orientation for tail */ - invert_m4_m4(obedit->imat, obedit->obmat); - mul_m4_v3(obedit->imat, curs); - - if (rv3d && (U.flag & USER_ADD_VIEWALIGNED)) - copy_m3_m4(obmat, rv3d->viewmat); - else unit_m3(obmat); - - copy_m3_m4(viewmat, obedit->obmat); - mul_m3_m3m3(totmat, obmat, viewmat); - invert_m3_m3(imat, totmat); - - ED_armature_deselect_all(obedit, 0); - - /* Create a bone */ - bone = ED_armature_edit_bone_add(obedit->data, name); - - copy_v3_v3(bone->head, curs); - - if (rv3d && (U.flag & USER_ADD_VIEWALIGNED)) - add_v3_v3v3(bone->tail, bone->head, imat[1]); // bone with unit length 1 - else - add_v3_v3v3(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z - - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); - - return OPERATOR_FINISHED; -} - -void ARMATURE_OT_bone_primitive_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Bone"; - ot->idname = "ARMATURE_OT_bone_primitive_add"; - ot->description = "Add a new bone located at the 3D-Cursor"; - - /* api callbacks */ - ot->exec = armature_bone_primitive_add_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_string(ot->srna, "name", "Bone", MAXBONENAME, "Name", "Name of the newly created bone"); - -} - - -/* ----------- */ - -/* Subdivide Operators: - * This group of operators all use the same 'exec' callback, but they are called - * through several different operators - a combined menu (which just calls the exec in the - * appropriate ways), and two separate ones. - */ - -static int armature_subdivide_exec(bContext *C, wmOperator *op) -{ - Object *obedit = CTX_data_edit_object(C); - bArmature *arm = obedit->data; - EditBone *newbone, *tbone; - int cuts, i; - - /* there may not be a number_cuts property defined (for 'simple' subdivide) */ - cuts = RNA_int_get(op->ptr, "number_cuts"); - - /* loop over all editable bones */ - // XXX the old code did this in reverse order though! - CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) - { - for (i = cuts + 1; i > 1; i--) { - /* compute cut ratio first */ - float cutratio = 1.0f / (float)i; - float cutratioI = 1.0f - cutratio; - - float val1[3]; - float val2[3]; - float val3[3]; - - newbone = MEM_mallocN(sizeof(EditBone), "ebone subdiv"); - *newbone = *ebone; - BLI_addtail(arm->edbo, newbone); - - /* calculate location of newbone->head */ - copy_v3_v3(val1, ebone->head); - copy_v3_v3(val2, ebone->tail); - copy_v3_v3(val3, newbone->head); - - val3[0] = val1[0] * cutratio + val2[0] * cutratioI; - val3[1] = val1[1] * cutratio + val2[1] * cutratioI; - val3[2] = val1[2] * cutratio + val2[2] * cutratioI; - - copy_v3_v3(newbone->head, val3); - copy_v3_v3(newbone->tail, ebone->tail); - copy_v3_v3(ebone->tail, newbone->head); - - newbone->rad_head = 0.5f * (ebone->rad_head + ebone->rad_tail); - ebone->rad_tail = newbone->rad_head; - - newbone->flag |= BONE_CONNECTED; - - unique_editbone_name(arm->edbo, newbone->name, NULL); - - /* correct parent bones */ - for (tbone = arm->edbo->first; tbone; tbone = tbone->next) { - if (tbone->parent == ebone) - tbone->parent = newbone; - } - newbone->parent = ebone; - } - } - CTX_DATA_END; - - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); - - return OPERATOR_FINISHED; -} - -void ARMATURE_OT_subdivide(wmOperatorType *ot) -{ - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Subdivide Multi"; - ot->idname = "ARMATURE_OT_subdivide"; - ot->description = "Break selected bones into chains of smaller bones"; - - /* api callbacks */ - ot->exec = armature_subdivide_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* Properties */ - prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "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); -} - -/* ----------- */ - -/* Switch Direction operator: - * Currently, this does not use context loops, as context loops do not make it - * easy to retrieve any hierarchical/chain relationships which are necessary for - * this to be done easily. - */ - -/* helper to clear BONE_TRANSFORM flags */ -static void armature_clear_swap_done_flags(bArmature *arm) -{ - EditBone *ebone; - - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - ebone->flag &= ~BONE_TRANSFORM; - } -} - -static int armature_switch_direction_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *ob = CTX_data_edit_object(C); - bArmature *arm = (bArmature *)ob->data; - ListBase chains = {NULL, NULL}; - LinkData *chain; - - /* get chains of bones (ends on chains) */ - chains_find_tips(arm->edbo, &chains); - if (chains.first == NULL) return OPERATOR_CANCELLED; - - /* ensure that mirror bones will also be operated on */ - armature_tag_select_mirrored(arm); - - /* clear BONE_TRANSFORM flags - * - used to prevent duplicate/cancelling operations from occurring [#34123] - * - BONE_DONE cannot be used here as that's already used for mirroring - */ - armature_clear_swap_done_flags(arm); - - /* loop over chains, only considering selected and visible bones */ - for (chain = chains.first; chain; chain = chain->next) { - EditBone *ebo, *child = NULL, *parent = NULL; - - /* loop over bones in chain */ - for (ebo = chain->data; ebo; ebo = parent) { - /* parent is this bone's original parent - * - we store this, as the next bone that is checked is this one - * but the value of ebo->parent may change here... - */ - parent = ebo->parent; - - /* skip bone if already handled... [#34123] */ - if ((ebo->flag & BONE_TRANSFORM) == 0) { - /* only if selected and editable */ - if (EBONE_VISIBLE(arm, ebo) && EBONE_EDITABLE(ebo)) { - /* swap head and tail coordinates */ - SWAP(float, ebo->head[0], ebo->tail[0]); - SWAP(float, ebo->head[1], ebo->tail[1]); - SWAP(float, ebo->head[2], ebo->tail[2]); - - /* do parent swapping: - * - use 'child' as new parent - * - connected flag is only set if points are coincidental - */ - ebo->parent = child; - if ((child) && equals_v3v3(ebo->head, child->tail)) - ebo->flag |= BONE_CONNECTED; - else - ebo->flag &= ~BONE_CONNECTED; - - /* get next bones - * - child will become the new parent of next bone - */ - child = ebo; - } - else { - /* not swapping this bone, however, if its 'parent' got swapped, unparent us from it - * as it will be facing in opposite direction - */ - if ((parent) && (EBONE_VISIBLE(arm, parent) && EBONE_EDITABLE(parent))) { - ebo->parent = NULL; - ebo->flag &= ~BONE_CONNECTED; - } - - /* get next bones - * - child will become new parent of next bone (not swapping occurred, - * so set to NULL to prevent infinite-loop) - */ - child = NULL; - } - - /* tag as done (to prevent double-swaps) */ - ebo->flag |= BONE_TRANSFORM; - } - } - } - - /* free chains */ - BLI_freelistN(&chains); - - /* clear temp flags */ - armature_clear_swap_done_flags(arm); - armature_tag_unselect(arm); - - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); - - return OPERATOR_FINISHED; -} - -void ARMATURE_OT_switch_direction(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Switch Direction"; - ot->idname = "ARMATURE_OT_switch_direction"; - ot->description = "Change the direction that a chain of bones points in (head <-> tail swap)"; - - /* api callbacks */ - ot->exec = armature_switch_direction_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} -/* ***************** Parenting *********************** */ - -/* armature parenting options */ -#define ARM_PAR_CONNECT 1 -#define ARM_PAR_OFFSET 2 - -/* check for null, before calling! */ -static void bone_connect_to_existing_parent(EditBone *bone) -{ - bone->flag |= BONE_CONNECTED; - copy_v3_v3(bone->head, bone->parent->tail); - bone->rad_head = bone->parent->rad_tail; -} - -static void bone_connect_to_new_parent(ListBase *edbo, EditBone *selbone, EditBone *actbone, short mode) -{ - EditBone *ebone; - float offset[3]; - - if ((selbone->parent) && (selbone->flag & BONE_CONNECTED)) - selbone->parent->flag &= ~(BONE_TIPSEL); - - /* make actbone the parent of selbone */ - selbone->parent = actbone; - - /* in actbone tree we cannot have a loop */ - for (ebone = actbone->parent; ebone; ebone = ebone->parent) { - if (ebone->parent == selbone) { - ebone->parent = NULL; - ebone->flag &= ~BONE_CONNECTED; - } - } - - if (mode == ARM_PAR_CONNECT) { - /* Connected: Child bones will be moved to the parent tip */ - selbone->flag |= BONE_CONNECTED; - sub_v3_v3v3(offset, actbone->tail, selbone->head); - - copy_v3_v3(selbone->head, actbone->tail); - selbone->rad_head = actbone->rad_tail; - - add_v3_v3(selbone->tail, offset); - - /* offset for all its children */ - for (ebone = edbo->first; ebone; ebone = ebone->next) { - EditBone *par; - - for (par = ebone->parent; par; par = par->parent) { - if (par == selbone) { - add_v3_v3(ebone->head, offset); - add_v3_v3(ebone->tail, offset); - break; - } - } - } - } - else { - /* Offset: Child bones will retain their distance from the parent tip */ - selbone->flag &= ~BONE_CONNECTED; - } -} - -static EnumPropertyItem prop_editarm_make_parent_types[] = { - {ARM_PAR_CONNECT, "CONNECTED", 0, "Connected", ""}, - {ARM_PAR_OFFSET, "OFFSET", 0, "Keep Offset", ""}, - {0, NULL, 0, NULL, NULL} -}; - -static int armature_parent_set_exec(bContext *C, wmOperator *op) -{ - Object *ob = CTX_data_edit_object(C); - bArmature *arm = (bArmature *)ob->data; - EditBone *actbone = CTX_data_active_bone(C); - EditBone *actmirb = NULL; - short val = RNA_enum_get(op->ptr, "type"); - - /* there must be an active bone */ - if (actbone == NULL) { - BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone"); - return OPERATOR_CANCELLED; - } - else if (arm->flag & ARM_MIRROR_EDIT) { - /* For X-Axis Mirror Editing option, we may need a mirror copy of actbone - * - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone - * (i.e. selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R"). - * This is useful for arm-chains, for example parenting lower arm to upper arm - * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent") - * then just use actbone. Useful when doing upper arm to spine. - */ - actmirb = ED_armature_bone_get_mirrored(arm->edbo, actbone); - if (actmirb == NULL) - actmirb = actbone; - } - - /* if there is only 1 selected bone, we assume that that is the active bone, - * since a user will need to have clicked on a bone (thus selecting it) to make it active - */ - if (CTX_DATA_COUNT(C, selected_editable_bones) <= 1) { - /* When only the active bone is selected, and it has a parent, - * connect it to the parent, as that is the only possible outcome. - */ - if (actbone->parent) { - bone_connect_to_existing_parent(actbone); - - if ((arm->flag & ARM_MIRROR_EDIT) && (actmirb->parent)) - bone_connect_to_existing_parent(actmirb); - } - } - else { - /* Parent 'selected' bones to the active one - * - the context iterator contains both selected bones and their mirrored copies, - * so we assume that unselected bones are mirrored copies of some selected bone - * - since the active one (and/or its mirror) will also be selected, we also need - * to check that we are not trying to operate on them, since such an operation - * would cause errors - */ - - /* parent selected bones to the active one */ - CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) - { - if (ELEM(ebone, actbone, actmirb) == 0) { - if (ebone->flag & BONE_SELECTED) - bone_connect_to_new_parent(arm->edbo, ebone, actbone, val); - else - bone_connect_to_new_parent(arm->edbo, ebone, actmirb, val); - } - } - CTX_DATA_END; - } - - - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); - - return OPERATOR_FINISHED; -} - -static int armature_parent_set_invoke(bContext *C, wmOperator *UNUSED(op), 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); - int allchildbones = 0; - - CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) - { - if (ebone != actbone) { - if (ebone->parent != actbone) allchildbones = 1; - } - } - CTX_DATA_END; - - uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_CONNECT); - - /* ob becomes parent, make the associated menus */ - if (allchildbones) - uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_OFFSET); - - uiPupMenuEnd(C, pup); - - return OPERATOR_CANCELLED; -} - -void ARMATURE_OT_parent_set(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Make Parent"; - ot->idname = "ARMATURE_OT_parent_set"; - ot->description = "Set the active bone as the parent of the selected bones"; - - /* api callbacks */ - ot->invoke = armature_parent_set_invoke; - ot->exec = armature_parent_set_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_enum(ot->srna, "type", prop_editarm_make_parent_types, 0, "ParentType", "Type of parenting"); -} - -static EnumPropertyItem prop_editarm_clear_parent_types[] = { - {1, "CLEAR", 0, "Clear Parent", ""}, - {2, "DISCONNECT", 0, "Disconnect Bone", ""}, - {0, NULL, 0, NULL, NULL} -}; - -static void editbone_clear_parent(EditBone *ebone, int mode) -{ - if (ebone->parent) { - /* for nice selection */ - ebone->parent->flag &= ~(BONE_TIPSEL); - } - - if (mode == 1) ebone->parent = NULL; - ebone->flag &= ~BONE_CONNECTED; -} - -static int armature_parent_clear_exec(bContext *C, wmOperator *op) -{ - Object *ob = CTX_data_edit_object(C); - bArmature *arm = (bArmature *)ob->data; - int val = RNA_enum_get(op->ptr, "type"); - - CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) - { - editbone_clear_parent(ebone, val); - } - CTX_DATA_END; - - ED_armature_sync_selection(arm->edbo); - - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); - - return OPERATOR_FINISHED; -} - -void ARMATURE_OT_parent_clear(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Clear Parent"; - ot->idname = "ARMATURE_OT_parent_clear"; - ot->description = "Remove the parent-child relationship between selected bones and their parents"; - - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = armature_parent_clear_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - ot->prop = RNA_def_enum(ot->srna, "type", prop_editarm_clear_parent_types, 0, "ClearType", "What way to clear parenting"); -} - -/* **************** Selections ******************/ - -static int armature_select_inverse_exec(bContext *C, wmOperator *UNUSED(op)) -{ - /* Set the flags */ - CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones) - { - /* ignore bone if selection can't change */ - if ((ebone->flag & BONE_UNSELECTABLE) == 0) { - /* select bone */ - ebone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } - } - CTX_DATA_END; - - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL); - - return OPERATOR_FINISHED; -} - -void ARMATURE_OT_select_inverse(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select Inverse"; - ot->idname = "ARMATURE_OT_select_inverse"; - ot->description = "Flip the selection status of bones (selected -> unselected, unselected -> selected)"; - - /* api callbacks */ - ot->exec = armature_select_inverse_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - -} -static int armature_de_select_all_exec(bContext *C, wmOperator *op) -{ - int action = RNA_enum_get(op->ptr, "action"); - - if (action == SEL_TOGGLE) { - action = SEL_SELECT; - /* Determine if there are any selected bones - * And therefore whether we are selecting or deselecting */ - if (CTX_DATA_COUNT(C, selected_bones) > 0) - action = SEL_DESELECT; - } - - /* Set the flags */ - CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones) - { - /* ignore bone if selection can't change */ - if ((ebone->flag & BONE_UNSELECTABLE) == 0) { - switch (action) { - case SEL_SELECT: - ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - if (ebone->parent) - ebone->parent->flag |= (BONE_TIPSEL); - break; - case SEL_DESELECT: - ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - break; - case SEL_INVERT: - if (ebone->flag & BONE_SELECTED) { - ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } - else { - ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - if (ebone->parent) - ebone->parent->flag |= (BONE_TIPSEL); - } - break; - } - } - } - CTX_DATA_END; - - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL); - - return OPERATOR_FINISHED; -} - -void ARMATURE_OT_select_all(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "(De)select All"; - ot->idname = "ARMATURE_OT_select_all"; - ot->description = "Toggle selection status of all bones"; - - /* api callbacks */ - ot->exec = armature_de_select_all_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - WM_operator_properties_select_all(ot); -} - -enum { - SIMEDBONE_LENGTH = 1, - SIMEDBONE_DIRECTION, - SIMEDBONE_PREFIX, - SIMEDBONE_SUFFIX, - SIMEDBONE_LAYER -}; - -static EnumPropertyItem prop_similar_types[] = { - {SIMEDBONE_LENGTH, "LENGTH", 0, "Length", ""}, - {SIMEDBONE_DIRECTION, "DIRECTION", 0, "Direction (Y axis)", ""}, - {SIMEDBONE_PREFIX, "PREFIX", 0, "Prefix", ""}, - {SIMEDBONE_SUFFIX, "SUFFIX", 0, "Suffix", ""}, - {SIMEDBONE_LAYER, "LAYER", 0, "Layer", ""}, - {0, NULL, 0, NULL, NULL} -}; - -/* could be used in more places */ -static void ED_armature_edit_bone_select(EditBone *ebone) -{ - BLI_assert((ebone->flag & BONE_UNSELECTABLE) == 0); - ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - - if ((ebone->flag & BONE_CONNECTED) && (ebone->parent != NULL)) { - ebone->parent->flag |= BONE_TIPSEL; - } -} - -static void select_similar_length(bArmature *arm, EditBone *ebone_act, const float thresh) -{ - EditBone *ebone; - - /* thresh is always relative to current length */ - const float len_min = ebone_act->length / (1.0f + thresh); - const float len_max = ebone_act->length * (1.0f + thresh); - - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_SELECTABLE(arm, ebone)) { - if ((ebone->length >= len_min) && - (ebone->length <= len_max)) - { - ED_armature_edit_bone_select(ebone); - } - } - } -} - -static void select_similar_direction(bArmature *arm, EditBone *ebone_act, const float thresh) -{ - EditBone *ebone; - float dir_act[3]; - sub_v3_v3v3(dir_act, ebone_act->head, ebone_act->tail); - - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_SELECTABLE(arm, ebone)) { - float dir[3]; - sub_v3_v3v3(dir, ebone->head, ebone->tail); - - if (angle_v3v3(dir_act, dir) / (float)M_PI < thresh) { - ED_armature_edit_bone_select(ebone); - } - } - } -} - -static void select_similar_layer(bArmature *arm, EditBone *ebone_act) -{ - EditBone *ebone; - - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_SELECTABLE(arm, ebone)) { - if (ebone->layer & ebone_act->layer) { - ED_armature_edit_bone_select(ebone); - } - } - } -} - -static void select_similar_prefix(bArmature *arm, EditBone *ebone_act) -{ - EditBone *ebone; - - char body_tmp[MAX_VGROUP_NAME]; - char prefix_act[MAX_VGROUP_NAME]; - - BKE_deform_split_prefix(ebone_act->name, prefix_act, body_tmp); - - if (prefix_act[0] == '\0') - return; - - /* Find matches */ - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_SELECTABLE(arm, ebone)) { - char prefix_other[MAX_VGROUP_NAME]; - BKE_deform_split_prefix(ebone->name, prefix_other, body_tmp); - if (!strcmp(prefix_act, prefix_other)) { - ED_armature_edit_bone_select(ebone); - } - } - } -} - -static void select_similar_suffix(bArmature *arm, EditBone *ebone_act) -{ - EditBone *ebone; - - char body_tmp[MAX_VGROUP_NAME]; - char suffix_act[MAX_VGROUP_NAME]; - - BKE_deform_split_suffix(ebone_act->name, body_tmp, suffix_act); - - if (suffix_act[0] == '\0') - return; - - /* Find matches */ - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (EBONE_SELECTABLE(arm, ebone)) { - char suffix_other[MAX_VGROUP_NAME]; - BKE_deform_split_suffix(ebone->name, body_tmp, suffix_other); - if (!strcmp(suffix_act, suffix_other)) { - ED_armature_edit_bone_select(ebone); - } - } - } -} - -static int armature_select_similar_exec(bContext *C, wmOperator *op) -{ - Object *obedit = CTX_data_edit_object(C); - bArmature *arm = obedit->data; - EditBone *ebone_act = CTX_data_active_bone(C); - - /* Get props */ - int type = RNA_enum_get(op->ptr, "type"); - float thresh = RNA_float_get(op->ptr, "threshold"); - - /* Check for active bone */ - if (ebone_act == NULL) { - BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone"); - return OPERATOR_CANCELLED; - } - - switch (type) { - case SIMEDBONE_LENGTH: - select_similar_length(arm, ebone_act, thresh); - break; - case SIMEDBONE_DIRECTION: - select_similar_direction(arm, ebone_act, thresh); - break; - case SIMEDBONE_PREFIX: - select_similar_prefix(arm, ebone_act); - break; - case SIMEDBONE_SUFFIX: - select_similar_suffix(arm, ebone_act); - break; - case SIMEDBONE_LAYER: - select_similar_layer(arm, ebone_act); - break; - } - - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); - - return OPERATOR_FINISHED; -} - -void ARMATURE_OT_select_similar(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select Similar"; - ot->idname = "ARMATURE_OT_select_similar"; - - /* callback functions */ - ot->invoke = WM_menu_invoke; - ot->exec = armature_select_similar_exec; - ot->poll = ED_operator_editarmature; - ot->description = "Select similar bones by property types"; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, 0, "Type", ""); - RNA_def_float(ot->srna, "threshold", 0.1f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f); -} - -/* ********************* select hierarchy operator ************** */ - -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; - int direction = RNA_enum_get(op->ptr, "direction"); - int add_to_sel = RNA_boolean_get(op->ptr, "extend"); - - 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; - } - - } - 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; - } - break; - } - } - } - } - } - - ED_armature_sync_selection(arm->edbo); - - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); - - return OPERATOR_FINISHED; -} - -void ARMATURE_OT_select_hierarchy(wmOperatorType *ot) -{ - static EnumPropertyItem direction_items[] = { - {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""}, - {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""}, - {0, NULL, 0, NULL, NULL} - }; - - /* identifiers */ - ot->name = "Select Hierarchy"; - ot->idname = "ARMATURE_OT_select_hierarchy"; - ot->description = "Select immediate parent/children of selected bones"; - - /* api callbacks */ - ot->exec = armature_select_hierarchy_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* props */ - RNA_def_enum(ot->srna, "direction", direction_items, - BONE_SELECT_PARENT, "Direction", ""); - RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection"); -} - -/* ***************** EditBone Alignment ********************* */ - -/* helper to fix a ebone position if its parent has moved due to alignment*/ -static void fix_connected_bone(EditBone *ebone) -{ - float diff[3]; - - if (!(ebone->parent) || !(ebone->flag & BONE_CONNECTED) || equals_v3v3(ebone->parent->tail, ebone->head)) - return; - - /* if the parent has moved we translate child's head and tail accordingly*/ - sub_v3_v3v3(diff, ebone->parent->tail, ebone->head); - add_v3_v3(ebone->head, diff); - add_v3_v3(ebone->tail, diff); - return; -} - -/* helper to recursively find chains of connected bones starting at ebone and fix their position */ -static void fix_editbone_connected_children(ListBase *edbo, EditBone *ebone) -{ - EditBone *selbone; - - for (selbone = edbo->first; selbone; selbone = selbone->next) { - if ((selbone->parent) && (selbone->parent == ebone) && (selbone->flag & BONE_CONNECTED)) { - fix_connected_bone(selbone); - fix_editbone_connected_children(edbo, selbone); - } - } - return; -} - -static void bone_align_to_bone(ListBase *edbo, EditBone *selbone, EditBone *actbone) -{ - float selboneaxis[3], actboneaxis[3], length; - - sub_v3_v3v3(actboneaxis, actbone->tail, actbone->head); - normalize_v3(actboneaxis); - - sub_v3_v3v3(selboneaxis, selbone->tail, selbone->head); - length = len_v3(selboneaxis); - - mul_v3_fl(actboneaxis, length); - add_v3_v3v3(selbone->tail, selbone->head, actboneaxis); - selbone->roll = actbone->roll; - - /* if the bone being aligned has connected descendants they must be moved - * according to their parent new position, otherwise they would be left - * in an inconsistent state: connected but away from the parent*/ - fix_editbone_connected_children(edbo, selbone); - return; -} - -static int armature_align_bones_exec(bContext *C, wmOperator *op) -{ - Object *ob = CTX_data_edit_object(C); - bArmature *arm = (bArmature *)ob->data; - EditBone *actbone = CTX_data_active_bone(C); - EditBone *actmirb = NULL; - - /* there must be an active bone */ - if (actbone == NULL) { - BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone"); - return OPERATOR_CANCELLED; - } - else if (arm->flag & ARM_MIRROR_EDIT) { - /* For X-Axis Mirror Editing option, we may need a mirror copy of actbone - * - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone - * (i.e. selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R"). - * This is useful for arm-chains, for example parenting lower arm to upper arm - * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent") - * then just use actbone. Useful when doing upper arm to spine. - */ - actmirb = ED_armature_bone_get_mirrored(arm->edbo, actbone); - if (actmirb == NULL) - actmirb = actbone; - } - - /* if there is only 1 selected bone, we assume that that is the active bone, - * since a user will need to have clicked on a bone (thus selecting it) to make it active - */ - if (CTX_DATA_COUNT(C, selected_editable_bones) <= 1) { - /* When only the active bone is selected, and it has a parent, - * align it to the parent, as that is the only possible outcome. - */ - if (actbone->parent) { - bone_align_to_bone(arm->edbo, actbone, actbone->parent); - - if ((arm->flag & ARM_MIRROR_EDIT) && (actmirb->parent)) - bone_align_to_bone(arm->edbo, actmirb, actmirb->parent); - } - } - else { - /* Align 'selected' bones to the active one - * - the context iterator contains both selected bones and their mirrored copies, - * so we assume that unselected bones are mirrored copies of some selected bone - * - since the active one (and/or its mirror) will also be selected, we also need - * to check that we are not trying to operate on them, since such an operation - * would cause errors - */ - - /* align selected bones to the active one */ - CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) - { - if (ELEM(ebone, actbone, actmirb) == 0) { - if (ebone->flag & BONE_SELECTED) - bone_align_to_bone(arm->edbo, ebone, actbone); - else - bone_align_to_bone(arm->edbo, ebone, actmirb); - } - } - CTX_DATA_END; - } - - - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob); - - return OPERATOR_FINISHED; -} - -void ARMATURE_OT_align(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Align Bones"; - ot->idname = "ARMATURE_OT_align"; - ot->description = "Align selected bones to the active bone (or to their parent)"; - - /* api callbacks */ - ot->invoke = WM_operator_confirm; - ot->exec = armature_align_bones_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/* ***************** Pose tools ********************* */ - -/* XXX bone_looper is only to be used when we want to access settings - * (i.e. editability/visibility/selected) that context doesn't offer */ -static int bone_looper(Object *ob, Bone *bone, void *data, - int (*bone_func)(Object *, Bone *, void *)) -{ - /* We want to apply the function bone_func to every bone - * in an armature -- feed bone_looper the first bone and - * a pointer to the bone_func and watch it go!. The int count - * can be useful for counting bones with a certain property - * (e.g. skinnable) - */ - int count = 0; - - if (bone) { - /* only do bone_func if the bone is non null */ - count += bone_func(ob, bone, data); - - /* try to execute bone_func for the first child */ - count += bone_looper(ob, bone->childbase.first, data, bone_func); - - /* try to execute bone_func for the next bone at this - * depth of the recursion. - */ - count += bone_looper(ob, bone->next, data, bone_func); - } - - return count; -} - -/* called from editview.c, for mode-less pose selection */ -/* assumes scene obact and basact is still on old situation */ -int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, short hits, - short extend, short deselect, short toggle) -{ - Object *ob = base->object; - Bone *nearBone; - - if (!ob || !ob->pose) return 0; - - nearBone = get_bone_from_selectbuffer(scene, base, buffer, hits, 1); - - /* if the bone cannot be affected, don't do anything */ - if ((nearBone) && !(nearBone->flag & BONE_UNSELECTABLE)) { - Object *ob_act = OBACT; - bArmature *arm = ob->data; - - /* since we do unified select, we don't shift+select a bone if the - * armature object was not active yet. - * note, special exception for armature mode so we can do multi-select - * we could check for multi-select explicitly but think its fine to - * always give predictable behavior in weight paint mode - campbell */ - if ((!extend && !deselect && !toggle) || - ((ob_act && (ob_act != ob) && (ob_act->mode & OB_MODE_WEIGHT_PAINT) == 0))) - { - ED_pose_deselectall(ob, 0); - nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - arm->act_bone = nearBone; - } - else { - if (extend) { - nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - arm->act_bone = nearBone; - } - else if (deselect) { - nearBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } - else if (toggle) { - if (nearBone->flag & BONE_SELECTED) { - /* if not active, we make it active */ - if (nearBone != arm->act_bone) { - arm->act_bone = nearBone; - } - else { - nearBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } - } - else { - nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - arm->act_bone = nearBone; - } - } - } - - if (ob_act) { - /* in weightpaint we select the associated vertex group too */ - if (ob_act->mode & OB_MODE_WEIGHT_PAINT) { - if (nearBone == arm->act_bone) { - ED_vgroup_select_by_name(ob_act, nearBone->name); - DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA); - } - } - /* if there are some dependencies for visualizing armature state - * (e.g. Mask Modifier in 'Armature' mode), force update - */ - else if (arm->flag & ARM_HAS_VIZ_DEPS) { - DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA); - } - } - } - - return nearBone != NULL; -} - -/* test==0: deselect all - * test==1: swap select (apply to all the opposite of current situation) - * test==2: only clear active tag - * test==3: swap select (no test / inverse selection status of all independently) - */ -void ED_pose_deselectall(Object *ob, int test) -{ - bArmature *arm = ob->data; - bPoseChannel *pchan; - int selectmode = 0; - - /* we call this from outliner too */ - if (ob->pose == NULL) { - return; - } - - /* Determine if we're selecting or deselecting */ - if (test == 1) { - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if (PBONE_VISIBLE(arm, pchan->bone)) { - if (pchan->bone->flag & BONE_SELECTED) - break; - } - } - - if (pchan == NULL) - selectmode = 1; - } - else if (test == 2) - selectmode = 2; - - /* Set the flags accordingly */ - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - /* ignore the pchan if it isn't visible or if its selection cannot be changed */ - if ((pchan->bone->layer & arm->layer) && !(pchan->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) { - if (test == 3) { - pchan->bone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } - else { - if (selectmode == 0) pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - else if (selectmode == 1) pchan->bone->flag |= BONE_SELECTED; - } - } - } -} - -static int bone_skinnable_cb(Object *ob, Bone *bone, void *datap) -{ - /* Bones that are deforming - * are regarded to be "skinnable" and are eligible for - * auto-skinning. - * - * This function performs 2 functions: - * - * a) It returns 1 if the bone is skinnable. - * If we loop over all bones with this - * function, we can count the number of - * skinnable bones. - * b) If the pointer data is non null, - * it is treated like a handle to a - * bone pointer -- the bone pointer - * is set to point at this bone, and - * the pointer the handle points to - * is incremented to point to the - * next member of an array of pointers - * to bones. This way we can loop using - * this function to construct an array of - * pointers to bones that point to all - * skinnable bones. - */ - Bone ***hbone; - int a, segments; - struct { Object *armob; void *list; int heat; } *data = datap; - - if (!(ob->mode & OB_MODE_WEIGHT_PAINT) || !(bone->flag & BONE_HIDDEN_P)) { - if (!(bone->flag & BONE_NO_DEFORM)) { - if (data->heat && data->armob->pose && BKE_pose_channel_find_name(data->armob->pose, bone->name)) - segments = bone->segments; - else - segments = 1; - - if (data->list != NULL) { - hbone = (Bone ***) &data->list; - - for (a = 0; a < segments; a++) { - **hbone = bone; - ++*hbone; - } - } - return segments; - } - } - return 0; -} - -static int vgroup_add_unique_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr)) -{ - /* This group creates a vertex group to ob that has the - * same name as bone (provided the bone is skinnable). - * If such a vertex group aleady exist the routine exits. - */ - if (!(bone->flag & BONE_NO_DEFORM)) { - if (!defgroup_find_name(ob, bone->name)) { - ED_vgroup_add_name(ob, bone->name); - return 1; - } - } - return 0; -} - -static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap) -{ - /* Bones that are deforming - * are regarded to be "skinnable" and are eligible for - * auto-skinning. - * - * This function performs 2 functions: - * - * a) If the bone is skinnable, it creates - * a vertex group for ob that has - * the name of the skinnable bone - * (if one doesn't exist already). - * b) If the pointer data is non null, - * it is treated like a handle to a - * bDeformGroup pointer -- the - * bDeformGroup pointer is set to point - * to the deform group with the bone's - * name, and the pointer the handle - * points to is incremented to point to the - * next member of an array of pointers - * to bDeformGroups. This way we can loop using - * this function to construct an array of - * pointers to bDeformGroups, all with names - * of skinnable bones. - */ - bDeformGroup ***hgroup, *defgroup = NULL; - int a, segments; - struct { Object *armob; void *list; int heat; } *data = datap; - int wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT); - bArmature *arm = data->armob->data; - - if (!wpmode || !(bone->flag & BONE_HIDDEN_P)) { - if (!(bone->flag & BONE_NO_DEFORM)) { - if (data->heat && data->armob->pose && BKE_pose_channel_find_name(data->armob->pose, bone->name)) - segments = bone->segments; - else - segments = 1; - - if (!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 (data->list != NULL) { - hgroup = (bDeformGroup ***) &data->list; - - for (a = 0; a < segments; a++) { - **hgroup = defgroup; - ++*hgroup; - } - } - return segments; - } - } - return 0; -} - -static void add_vgroups__mapFunc(void *userData, int index, const float co[3], - const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) -{ - /* DerivedMesh mapFunc for getting final coords in weight paint mode */ - - float (*verts)[3] = userData; - copy_v3_v3(verts[index], co); -} - -static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], int numbones, Bone **bonelist, - bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, - float (*root)[3], float (*tip)[3], int *selected, float scale) -{ - /* Create vertex group weights from envelopes */ - - Bone *bone; - bDeformGroup *dgroup; - float distance; - int i, iflip, j; - - /* for each vertex in the mesh */ - for (i = 0; i < mesh->totvert; i++) { - iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, i) : 0; - - /* for each skinnable bone */ - for (j = 0; j < numbones; ++j) { - if (!selected[j]) - continue; - - bone = bonelist[j]; - dgroup = dgrouplist[j]; - - /* store the distance-factor from the vertex to the bone */ - distance = distfactor_to_bone(verts[i], root[j], tip[j], - bone->rad_head * scale, bone->rad_tail * scale, bone->dist * scale); - - /* add the vert to the deform group if (weight != 0.0) */ - if (distance != 0.0f) - ED_vgroup_vert_add(ob, dgroup, i, distance, WEIGHT_REPLACE); - else - ED_vgroup_vert_remove(ob, dgroup, i); - - /* do same for mirror */ - if (dgroupflip && dgroupflip[j] && iflip >= 0) { - if (distance != 0.0f) - ED_vgroup_vert_add(ob, dgroupflip[j], iflip, distance, - WEIGHT_REPLACE); - else - ED_vgroup_vert_remove(ob, dgroupflip[j], iflip); - } - } - } -} - -static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, Object *par, int heat, int mirror) -{ - /* This functions implements the automatic computation of vertex group - * weights, either through envelopes or using a heat equilibrium. - * - * This function can be called both when parenting a mesh to an armature, - * or in weightpaint + posemode. In the latter case selection is taken - * into account and vertex weights can be mirrored. - * - * The mesh vertex positions used are either the final deformed coords - * from the derivedmesh in weightpaint mode, the final subsurf coords - * when parenting, or simply the original mesh coords. - */ - - bArmature *arm = par->data; - Bone **bonelist, *bone; - bDeformGroup **dgrouplist, **dgroupflip; - bDeformGroup *dgroup; - bPoseChannel *pchan; - Mesh *mesh; - Mat4 *bbone = NULL; - float (*root)[3], (*tip)[3], (*verts)[3]; - int *selected; - int numbones, vertsfilled = 0, i, j, segments = 0; - int wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT); - struct { Object *armob; void *list; int heat; } looper_data; - - looper_data.armob = par; - looper_data.heat = heat; - looper_data.list = NULL; - - /* count the number of skinnable bones */ - numbones = bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb); - - if (numbones == 0) - return; - - if (ED_vgroup_data_create(ob->data) == FALSE) - return; - - /* create an array of pointer to bones that are skinnable - * and fill it with all of the skinnable bones */ - bonelist = MEM_callocN(numbones * sizeof(Bone *), "bonelist"); - looper_data.list = bonelist; - bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb); - - /* create an array of pointers to the deform groups that - * correspond to the skinnable bones (creating them - * as necessary. */ - dgrouplist = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgrouplist"); - dgroupflip = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgroupflip"); - - looper_data.list = dgrouplist; - bone_looper(ob, arm->bonebase.first, &looper_data, dgroup_skinnable_cb); - - /* create an array of root and tip positions transformed into - * global coords */ - root = MEM_callocN(numbones * sizeof(float) * 3, "root"); - tip = MEM_callocN(numbones * sizeof(float) * 3, "tip"); - selected = MEM_callocN(numbones * sizeof(int), "selected"); - - for (j = 0; j < numbones; ++j) { - bone = bonelist[j]; - dgroup = dgrouplist[j]; - - /* handle bbone */ - if (heat) { - if (segments == 0) { - segments = 1; - bbone = NULL; - - if ((par->pose) && (pchan = BKE_pose_channel_find_name(par->pose, bone->name))) { - if (bone->segments > 1) { - segments = bone->segments; - bbone = b_bone_spline_setup(pchan, 1); - } - } - } - - segments--; - } - - /* compute root and tip */ - if (bbone) { - mul_v3_m4v3(root[j], bone->arm_mat, bbone[segments].mat[3]); - if ((segments + 1) < bone->segments) { - mul_v3_m4v3(tip[j], bone->arm_mat, bbone[segments + 1].mat[3]); - } - else { - copy_v3_v3(tip[j], bone->arm_tail); - } - } - else { - copy_v3_v3(root[j], bone->arm_head); - copy_v3_v3(tip[j], bone->arm_tail); - } - - mul_m4_v3(par->obmat, root[j]); - mul_m4_v3(par->obmat, tip[j]); - - /* set selected */ - if (wpmode) { - if ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED)) - selected[j] = 1; - } - else - selected[j] = 1; - - /* find flipped group */ - if (dgroup && mirror) { - char name[MAXBONENAME]; - - // 0 = don't strip off number extensions - flip_side_name(name, dgroup->name, FALSE); - dgroupflip[j] = defgroup_find_name(ob, name); - } - } - - /* create verts */ - mesh = (Mesh *)ob->data; - verts = MEM_callocN(mesh->totvert * sizeof(*verts), "closestboneverts"); - - if (wpmode) { - /* if in weight paint mode, use final verts from derivedmesh */ - DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); - - if (dm->foreachMappedVert) { - dm->foreachMappedVert(dm, add_vgroups__mapFunc, (void *)verts); - vertsfilled = 1; - } - - dm->release(dm); - } - else if (modifiers_findByType(ob, eModifierType_Subsurf)) { - /* is subsurf on? Lets use the verts on the limit surface then. - * = same amount of vertices as mesh, but vertices moved to the - * subsurfed position, like for 'optimal'. */ - subsurf_calculate_limit_positions(mesh, verts); - vertsfilled = 1; - } - - /* transform verts to global space */ - for (i = 0; i < mesh->totvert; i++) { - if (!vertsfilled) - copy_v3_v3(verts[i], mesh->mvert[i].co); - mul_m4_v3(ob->obmat, verts[i]); - } - - /* compute the weights based on gathered vertices and bones */ - if (heat) { - const char *error = NULL; - heat_bone_weighting(ob, mesh, verts, numbones, dgrouplist, dgroupflip, - root, tip, selected, &error); - - if (error) { - BKE_report(reports, RPT_WARNING, error); - } - } - else { - envelope_bone_weighting(ob, mesh, verts, numbones, bonelist, dgrouplist, - dgroupflip, root, tip, selected, mat4_to_scale(par->obmat)); - } - - /* only generated in some cases but can call anyway */ - mesh_octree_table(ob, NULL, NULL, 'e'); - - /* free the memory allocated */ - MEM_freeN(bonelist); - MEM_freeN(dgrouplist); - MEM_freeN(dgroupflip); - MEM_freeN(root); - MEM_freeN(tip); - MEM_freeN(selected); - MEM_freeN(verts); -} - -void create_vgroups_from_armature(ReportList *reports, Scene *scene, Object *ob, Object *par, int mode, int mirror) -{ - /* Lets try to create some vertex groups - * based on the bones of the parent armature. - */ - bArmature *arm = par->data; - - if (mode == ARM_GROUPS_NAME) { - const int defbase_tot = BLI_countlist(&ob->defbase); - int defbase_add; - /* Traverse the bone list, trying to create empty vertex - * groups corresponding to the bone. - */ - defbase_add = bone_looper(ob, arm->bonebase.first, NULL, vgroup_add_unique_bone_cb); - - if (defbase_add) { - /* its possible there are DWeight's outside the range of the current - * objects deform groups, in this case the new groups wont be empty [#33889] */ - ED_vgroup_data_clamp_range(ob->data, defbase_tot); - } - } - else if (mode == ARM_GROUPS_ENVELOPE || mode == ARM_GROUPS_AUTO) { - /* Traverse the bone list, trying to create vertex groups - * that are populated with the vertices for which the - * bone is closest. - */ - add_verts_to_dgroups(reports, scene, ob, par, (mode == ARM_GROUPS_AUTO), mirror); - } -} -/* ************* Clear Pose *****************************/ - -/* clear scale of pose-channel */ -static void pchan_clear_scale(bPoseChannel *pchan) -{ - if ((pchan->protectflag & OB_LOCK_SCALEX) == 0) - pchan->size[0] = 1.0f; - if ((pchan->protectflag & OB_LOCK_SCALEY) == 0) - pchan->size[1] = 1.0f; - if ((pchan->protectflag & OB_LOCK_SCALEZ) == 0) - pchan->size[2] = 1.0f; -} - -/* clear location of pose-channel */ -static void pchan_clear_loc(bPoseChannel *pchan) -{ - if ((pchan->protectflag & OB_LOCK_LOCX) == 0) - pchan->loc[0] = 0.0f; - if ((pchan->protectflag & OB_LOCK_LOCY) == 0) - pchan->loc[1] = 0.0f; - if ((pchan->protectflag & OB_LOCK_LOCZ) == 0) - pchan->loc[2] = 0.0f; -} - -/* clear rotation of pose-channel */ -static void pchan_clear_rot(bPoseChannel *pchan) -{ - if (pchan->protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) { - /* check if convert to eulers for locking... */ - if (pchan->protectflag & OB_LOCK_ROT4D) { - /* perform clamping on a component by component basis */ - if (pchan->rotmode == ROT_MODE_AXISANGLE) { - if ((pchan->protectflag & OB_LOCK_ROTW) == 0) - pchan->rotAngle = 0.0f; - if ((pchan->protectflag & OB_LOCK_ROTX) == 0) - pchan->rotAxis[0] = 0.0f; - if ((pchan->protectflag & OB_LOCK_ROTY) == 0) - pchan->rotAxis[1] = 0.0f; - if ((pchan->protectflag & OB_LOCK_ROTZ) == 0) - pchan->rotAxis[2] = 0.0f; - - /* check validity of axis - axis should never be 0,0,0 (if so, then we make it rotate about y) */ - if (IS_EQF(pchan->rotAxis[0], pchan->rotAxis[1]) && IS_EQF(pchan->rotAxis[1], pchan->rotAxis[2])) - pchan->rotAxis[1] = 1.0f; - } - else if (pchan->rotmode == ROT_MODE_QUAT) { - if ((pchan->protectflag & OB_LOCK_ROTW) == 0) - pchan->quat[0] = 1.0f; - if ((pchan->protectflag & OB_LOCK_ROTX) == 0) - pchan->quat[1] = 0.0f; - if ((pchan->protectflag & OB_LOCK_ROTY) == 0) - pchan->quat[2] = 0.0f; - if ((pchan->protectflag & OB_LOCK_ROTZ) == 0) - pchan->quat[3] = 0.0f; - } - else { - /* the flag may have been set for the other modes, so just ignore the extra flag... */ - if ((pchan->protectflag & OB_LOCK_ROTX) == 0) - pchan->eul[0] = 0.0f; - if ((pchan->protectflag & OB_LOCK_ROTY) == 0) - pchan->eul[1] = 0.0f; - if ((pchan->protectflag & OB_LOCK_ROTZ) == 0) - pchan->eul[2] = 0.0f; - } - } - else { - /* perform clamping using euler form (3-components) */ - float eul[3], oldeul[3], quat1[4] = {0}; - float qlen = 0.0f; - - if (pchan->rotmode == ROT_MODE_QUAT) { - qlen = normalize_qt_qt(quat1, pchan->quat); - quat_to_eul(oldeul, quat1); - } - else if (pchan->rotmode == ROT_MODE_AXISANGLE) { - axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle); - } - else { - copy_v3_v3(oldeul, pchan->eul); - } - - eul[0] = eul[1] = eul[2] = 0.0f; - - if (pchan->protectflag & OB_LOCK_ROTX) - eul[0] = oldeul[0]; - if (pchan->protectflag & OB_LOCK_ROTY) - eul[1] = oldeul[1]; - if (pchan->protectflag & OB_LOCK_ROTZ) - eul[2] = oldeul[2]; - - if (pchan->rotmode == ROT_MODE_QUAT) { - eul_to_quat(pchan->quat, eul); - - /* restore original quat size */ - mul_qt_fl(pchan->quat, qlen); - - /* quaternions flip w sign to accumulate rotations correctly */ - if ((quat1[0] < 0.0f && pchan->quat[0] > 0.0f) || (quat1[0] > 0.0f && pchan->quat[0] < 0.0f)) { - mul_qt_fl(pchan->quat, -1.0f); - } - } - else if (pchan->rotmode == ROT_MODE_AXISANGLE) { - eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT); - } - else { - copy_v3_v3(pchan->eul, eul); - } - } - } /* Duplicated in source/blender/editors/object/object_transform.c */ - else { - if (pchan->rotmode == ROT_MODE_QUAT) { - unit_qt(pchan->quat); - } - else if (pchan->rotmode == ROT_MODE_AXISANGLE) { - /* by default, make rotation of 0 radians around y-axis (roll) */ - unit_axis_angle(pchan->rotAxis, &pchan->rotAngle); - } - else { - zero_v3(pchan->eul); - } - } -} - -/* clear loc/rot/scale of pose-channel */ -static void pchan_clear_transforms(bPoseChannel *pchan) -{ - pchan_clear_loc(pchan); - pchan_clear_rot(pchan); - pchan_clear_scale(pchan); -} - -/* --------------- */ - -/* generic exec for clear-pose operators */ -static int pose_clear_transform_generic_exec(bContext *C, wmOperator *op, - void (*clear_func)(bPoseChannel *), const char default_ksName[]) -{ - Scene *scene = CTX_data_scene(C); - Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); - short autokey = 0; - - /* sanity checks */ - if (ELEM(NULL, clear_func, default_ksName)) { - BKE_report(op->reports, RPT_ERROR, "Programming error: missing clear transform function or keying set name"); - return OPERATOR_CANCELLED; - } - - /* only clear relevant transforms for selected bones */ - CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones) - { - /* run provided clearing function */ - clear_func(pchan); - - /* do auto-keyframing as appropriate */ - if (autokeyframe_cfra_can_key(scene, &ob->id)) { - /* clear any unkeyed tags */ - if (pchan->bone) - pchan->bone->flag &= ~BONE_UNKEYED; - - /* tag for autokeying later */ - autokey = 1; - } - else { - /* add unkeyed tags */ - if (pchan->bone) - pchan->bone->flag |= BONE_UNKEYED; - } - } - CTX_DATA_END; - - /* perform autokeying on the bones if needed */ - if (autokey) { - /* get KeyingSet to use */ - KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName); - - /* insert keyframes */ - ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); - - /* now recalculate paths */ - if ((ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) - ED_pose_recalculate_paths(scene, ob); - } - - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob); - - return OPERATOR_FINISHED; -} - -/* --------------- */ - -static int pose_clear_scale_exec(bContext *C, wmOperator *op) -{ - return pose_clear_transform_generic_exec(C, op, pchan_clear_scale, ANIM_KS_SCALING_ID); -} - -void POSE_OT_scale_clear(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Clear Pose Scale"; - ot->idname = "POSE_OT_scale_clear"; - ot->description = "Reset scaling of selected bones to their default values"; - - /* api callbacks */ - ot->exec = pose_clear_scale_exec; - ot->poll = ED_operator_posemode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - - -static int pose_clear_rot_exec(bContext *C, wmOperator *op) -{ - return pose_clear_transform_generic_exec(C, op, pchan_clear_rot, ANIM_KS_ROTATION_ID); -} - -void POSE_OT_rot_clear(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Clear Pose Rotation"; - ot->idname = "POSE_OT_rot_clear"; - ot->description = "Reset rotations of selected bones to their default values"; - - /* api callbacks */ - ot->exec = pose_clear_rot_exec; - ot->poll = ED_operator_posemode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - - -static int pose_clear_loc_exec(bContext *C, wmOperator *op) -{ - return pose_clear_transform_generic_exec(C, op, pchan_clear_loc, ANIM_KS_LOCATION_ID); -} - -void POSE_OT_loc_clear(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Clear Pose Location"; - ot->idname = "POSE_OT_loc_clear"; - ot->description = "Reset locations of selected bones to their default values"; - - /* api callbacks */ - ot->exec = pose_clear_loc_exec; - ot->poll = ED_operator_posemode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - - -static int pose_clear_transforms_exec(bContext *C, wmOperator *op) -{ - return pose_clear_transform_generic_exec(C, op, pchan_clear_transforms, ANIM_KS_LOC_ROT_SCALE_ID); -} - -void POSE_OT_transforms_clear(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Clear Pose Transforms"; - ot->idname = "POSE_OT_transforms_clear"; - ot->description = "Reset location, rotation, and scaling of selected bones to their default values"; - - /* api callbacks */ - ot->exec = pose_clear_transforms_exec; - ot->poll = ED_operator_posemode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/* ***************** selections ********************** */ - -static int pose_de_select_all_exec(bContext *C, wmOperator *op) -{ - int action = RNA_enum_get(op->ptr, "action"); - - Scene *scene = CTX_data_scene(C); - Object *ob = ED_object_context(C); - bArmature *arm = ob->data; - int multipaint = scene->toolsettings->multipaint; - - if (action == SEL_TOGGLE) { - action = CTX_DATA_COUNT(C, selected_pose_bones) ? SEL_DESELECT : SEL_SELECT; - } - - /* Set the flags */ - CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) - { - /* select pchan only if selectable, but deselect works always */ - switch (action) { - case SEL_SELECT: - if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) - pchan->bone->flag |= BONE_SELECTED; - break; - case SEL_DESELECT: - pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - break; - case SEL_INVERT: - if (pchan->bone->flag & BONE_SELECTED) { - pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } - else if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) { - pchan->bone->flag |= BONE_SELECTED; - } - break; - } - } - CTX_DATA_END; - - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL); - - /* weightpaint or mask modifiers need depsgraph updates */ - if (multipaint || (arm->flag & ARM_HAS_VIZ_DEPS)) { - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - } - - return OPERATOR_FINISHED; -} - -void POSE_OT_select_all(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "(De)select All"; - ot->idname = "POSE_OT_select_all"; - ot->description = "Toggle selection status of all bones"; - - /* api callbacks */ - ot->exec = pose_de_select_all_exec; - ot->poll = ED_operator_posemode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - WM_operator_properties_select_all(ot); -} - -static int pose_select_parent_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); - bArmature *arm = (bArmature *)ob->data; - bPoseChannel *pchan, *parent; - - /* Determine if there is an active bone */ - pchan = CTX_data_active_pose_bone(C); - if (pchan) { - parent = pchan->parent; - if ((parent) && !(parent->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) { - parent->bone->flag |= BONE_SELECTED; - arm->act_bone = parent->bone; - } - else { - return OPERATOR_CANCELLED; - } - } - else { - return OPERATOR_CANCELLED; - } - - /* updates */ - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); - - if (arm->flag & ARM_HAS_VIZ_DEPS) { - /* mask modifier ('armature' mode), etc. */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - } - - return OPERATOR_FINISHED; -} - -void POSE_OT_select_parent(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select Parent Bone"; - ot->idname = "POSE_OT_select_parent"; - ot->description = "Select bones that are parents of the currently selected bones"; - - /* api callbacks */ - ot->exec = pose_select_parent_exec; - ot->poll = ED_operator_posemode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - -} - -/* ************* hide/unhide pose bones ******************* */ - -static int hide_selected_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr)) -{ - bArmature *arm = ob->data; - - if (arm->layer & bone->layer) { - if (bone->flag & BONE_SELECTED) { - bone->flag |= BONE_HIDDEN_P; - bone->flag &= ~BONE_SELECTED; - if (arm->act_bone == bone) - arm->act_bone = NULL; - } - } - return 0; -} - -static int hide_unselected_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr)) -{ - bArmature *arm = ob->data; - - if (arm->layer & bone->layer) { - /* hrm... typo here? */ - if ((bone->flag & BONE_SELECTED) == 0) { - bone->flag |= BONE_HIDDEN_P; - if (arm->act_bone == bone) - arm->act_bone = NULL; - } - } - return 0; -} - -/* active object is armature in posemode, poll checked */ -static int pose_hide_exec(bContext *C, wmOperator *op) -{ - Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); - bArmature *arm = ob->data; - - if (RNA_boolean_get(op->ptr, "unselected")) - bone_looper(ob, arm->bonebase.first, NULL, hide_unselected_pose_bone_cb); - else - bone_looper(ob, arm->bonebase.first, NULL, hide_selected_pose_bone_cb); - - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); - - return OPERATOR_FINISHED; -} - -void POSE_OT_hide(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Hide Selected"; - ot->idname = "POSE_OT_hide"; - ot->description = "Tag selected bones to not be visible in Pose Mode"; - - /* api callbacks */ - ot->exec = pose_hide_exec; - ot->poll = ED_operator_posemode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* props */ - RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", ""); -} - -static int show_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr)) -{ - bArmature *arm = ob->data; - - if (arm->layer & bone->layer) { - if (bone->flag & BONE_HIDDEN_P) { - bone->flag &= ~BONE_HIDDEN_P; - bone->flag |= BONE_SELECTED; - } - } - - return 0; -} - -/* active object is armature in posemode, poll checked */ -static int pose_reveal_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); - bArmature *arm = ob->data; - - bone_looper(ob, arm->bonebase.first, NULL, show_pose_bone_cb); - - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); - - return OPERATOR_FINISHED; -} - -void POSE_OT_reveal(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Reveal Selected"; - ot->idname = "POSE_OT_reveal"; - ot->description = "Unhide all bones that have been tagged to be hidden in Pose Mode"; - - /* api callbacks */ - ot->exec = pose_reveal_exec; - ot->poll = ED_operator_posemode; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/* ************* RENAMING DISASTERS ************ */ - -static int bone_unique_check(void *arg, const char *name) -{ - return BKE_armature_find_bone_name((bArmature *)arg, name) != NULL; -} - -static void unique_bone_name(bArmature *arm, char *name) -{ - BLI_uniquename_cb(bone_unique_check, (void *)arm, "Bone", '.', name, sizeof(((Bone *)NULL)->name)); -} - -/* helper call for armature_bone_rename */ -static void constraint_bone_name_fix(Object *ob, ListBase *conlist, char *oldname, char *newname) -{ - bConstraint *curcon; - bConstraintTarget *ct; - - for (curcon = conlist->first; curcon; curcon = curcon->next) { - bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(curcon); - ListBase targets = {NULL, NULL}; - - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(curcon, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - if (ct->tar == ob) { - if (!strcmp(ct->subtarget, oldname) ) - BLI_strncpy(ct->subtarget, newname, MAXBONENAME); - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(curcon, &targets, 0); - } - } -} - -/* called by UI for renaming a bone */ -/* warning: make sure the original bone was not renamed yet! */ -/* seems messy, but thats what you get with not using pointers but channel names :) */ -void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *newnamep) -{ - Object *ob; - char newname[MAXBONENAME]; - char oldname[MAXBONENAME]; - - /* names better differ! */ - if (strncmp(oldnamep, newnamep, MAXBONENAME)) { - - /* we alter newname string... so make copy */ - BLI_strncpy(newname, newnamep, MAXBONENAME); - /* we use oldname for search... so make copy */ - BLI_strncpy(oldname, oldnamep, MAXBONENAME); - - /* now check if we're in editmode, we need to find the unique name */ - if (arm->edbo) { - EditBone *eBone = editbone_name_exists(arm->edbo, oldname); - - if (eBone) { - unique_editbone_name(arm->edbo, newname, NULL); - BLI_strncpy(eBone->name, newname, MAXBONENAME); - } - else return; - } - else { - Bone *bone = BKE_armature_find_bone_name(arm, oldname); - - if (bone) { - unique_bone_name(arm, newname); - BLI_strncpy(bone->name, newname, MAXBONENAME); - } - else return; - } - - /* do entire dbase - objects */ - for (ob = G.main->object.first; ob; ob = ob->id.next) { - ModifierData *md; - - /* we have the object using the armature */ - if (arm == ob->data) { - Object *cob; - - /* Rename the pose channel, if it exists */ - if (ob->pose) { - bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, oldname); - if (pchan) { - BLI_strncpy(pchan->name, newname, MAXBONENAME); - - if (ob->pose->chanhash) { - GHash *gh = ob->pose->chanhash; - - /* remove the old hash entry, and replace with the new name */ - BLI_ghash_remove(gh, oldname, NULL, NULL); - BLI_ghash_insert(gh, pchan->name, pchan); - } - } - } - - /* Update any object constraints to use the new bone name */ - for (cob = G.main->object.first; cob; cob = cob->id.next) { - if (cob->constraints.first) - constraint_bone_name_fix(ob, &cob->constraints, oldname, newname); - if (cob->pose) { - bPoseChannel *pchan; - for (pchan = cob->pose->chanbase.first; pchan; pchan = pchan->next) { - constraint_bone_name_fix(ob, &pchan->constraints, oldname, newname); - } - } - } - } - - /* See if an object is parented to this armature */ - if (ob->parent && (ob->parent->data == arm)) { - if (ob->partype == PARBONE) { - /* bone name in object */ - if (!strcmp(ob->parsubstr, oldname)) - BLI_strncpy(ob->parsubstr, newname, MAXBONENAME); - } - } - - if (modifiers_usesArmature(ob, arm)) { - bDeformGroup *dg = defgroup_find_name(ob, oldname); - if (dg) { - BLI_strncpy(dg->name, newname, MAXBONENAME); - } - } - - /* fix modifiers that might be using this name */ - for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Hook) { - HookModifierData *hmd = (HookModifierData *)md; - - /* uses armature, so may use the affected bone name */ - if (hmd->object && (hmd->object->data == arm)) { - if (!strcmp(hmd->subtarget, oldname)) - BLI_strncpy(hmd->subtarget, newname, MAXBONENAME); - } - } - } - } - - /* 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] - */ - { - - BKE_all_animdata_fix_paths_rename(&arm->id, "pose.bones", oldname, newname); - } - - /* correct view locking */ - { - bScreen *screen; - for (screen = G.main->screen.first; screen; screen = screen->id.next) { - ScrArea *sa; - /* add regions */ - for (sa = screen->areabase.first; sa; sa = sa->next) { - SpaceLink *sl; - for (sl = sa->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_VIEW3D) { - View3D *v3d = (View3D *)sl; - if (v3d->ob_centre && v3d->ob_centre->data == arm) { - if (!strcmp(v3d->ob_centre_bone, oldname)) { - BLI_strncpy(v3d->ob_centre_bone, newname, MAXBONENAME); - } - } - } - } - } - } - } - } -} - - -static int armature_flip_names_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *ob = CTX_data_edit_object(C); - bArmature *arm; - char newname[MAXBONENAME]; - - /* paranoia checks */ - if (ELEM(NULL, ob, ob->pose)) - return OPERATOR_CANCELLED; - arm = ob->data; - - /* loop through selected bones, auto-naming them */ - CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) - { - flip_side_name(newname, ebone->name, TRUE); // 1 = do strip off number extensions - ED_armature_bone_rename(arm, ebone->name, newname); - } - CTX_DATA_END; - - /* since we renamed stuff... */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); - - return OPERATOR_FINISHED; -} - -void ARMATURE_OT_flip_names(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Flip Names"; - ot->idname = "ARMATURE_OT_flip_names"; - ot->description = "Flips (and corrects) the axis suffixes of the names of selected bones"; - - /* api callbacks */ - ot->exec = armature_flip_names_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - - -static int armature_autoside_names_exec(bContext *C, wmOperator *op) -{ - Object *ob = CTX_data_edit_object(C); - bArmature *arm; - char newname[MAXBONENAME]; - short axis = RNA_enum_get(op->ptr, "type"); - - /* paranoia checks */ - if (ELEM(NULL, ob, ob->pose)) - return OPERATOR_CANCELLED; - arm = ob->data; - - /* loop through selected bones, auto-naming them */ - CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) - { - BLI_strncpy(newname, ebone->name, sizeof(newname)); - if (bone_autoside_name(newname, 1, axis, ebone->head[axis], ebone->tail[axis])) - ED_armature_bone_rename(arm, ebone->name, newname); - } - CTX_DATA_END; - - /* since we renamed stuff... */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); - - return OPERATOR_FINISHED; -} - -void ARMATURE_OT_autoside_names(wmOperatorType *ot) -{ - static EnumPropertyItem axis_items[] = { - {0, "XAXIS", 0, "X-Axis", "Left/Right"}, - {1, "YAXIS", 0, "Y-Axis", "Front/Back"}, - {2, "ZAXIS", 0, "Z-Axis", "Top/Bottom"}, - {0, NULL, 0, NULL, NULL} - }; - - /* identifiers */ - ot->name = "AutoName by Axis"; - ot->idname = "ARMATURE_OT_autoside_names"; - ot->description = "Automatically renames the selected bones according to which side of the target axis they fall on"; - - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = armature_autoside_names_exec; - ot->poll = ED_operator_editarmature; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* settings */ - ot->prop = RNA_def_enum(ot->srna, "type", axis_items, 0, "Axis", "Axis tag names with"); -} - - - -/* if editbone (partial) selected, copy data */ -/* context; editmode armature, with mirror editing enabled */ -void transform_armature_mirror_update(Object *obedit) -{ - bArmature *arm = obedit->data; - EditBone *ebo, *eboflip; - - for (ebo = arm->edbo->first; ebo; ebo = ebo->next) { - /* no layer check, correct mirror is more important */ - if (ebo->flag & (BONE_TIPSEL | BONE_ROOTSEL)) { - eboflip = ED_armature_bone_get_mirrored(arm->edbo, ebo); - - if (eboflip) { - /* we assume X-axis flipping for now */ - if (ebo->flag & BONE_TIPSEL) { - EditBone *children; - - eboflip->tail[0] = -ebo->tail[0]; - eboflip->tail[1] = ebo->tail[1]; - eboflip->tail[2] = ebo->tail[2]; - eboflip->rad_tail = ebo->rad_tail; - eboflip->roll = -ebo->roll; - - /* Also move connected children, in case children's name aren't mirrored properly */ - for (children = arm->edbo->first; children; children = children->next) { - if (children->parent == eboflip && children->flag & BONE_CONNECTED) { - copy_v3_v3(children->head, eboflip->tail); - children->rad_head = ebo->rad_tail; - } - } - } - if (ebo->flag & BONE_ROOTSEL) { - eboflip->head[0] = -ebo->head[0]; - eboflip->head[1] = ebo->head[1]; - eboflip->head[2] = ebo->head[2]; - eboflip->rad_head = ebo->rad_head; - eboflip->roll = -ebo->roll; - - /* Also move connected parent, in case parent's name isn't mirrored properly */ - if (eboflip->parent && eboflip->flag & BONE_CONNECTED) { - EditBone *parent = eboflip->parent; - copy_v3_v3(parent->tail, eboflip->head); - parent->rad_tail = ebo->rad_head; - } - } - if (ebo->flag & BONE_SELECTED) { - eboflip->dist = ebo->dist; - eboflip->roll = -ebo->roll; - eboflip->xwidth = ebo->xwidth; - eboflip->zwidth = ebo->zwidth; - } - } - } - } -} - - -/*****************************************************************************************************/ -/*************************************** SKELETON GENERATOR ******************************************/ -/*****************************************************************************************************/ - -#if 0 - -/**************************************** SUBDIVISION ALGOS ******************************************/ - -EditBone *subdivideByAngle(Scene *scene, Object *obedit, ReebArc *arc, ReebNode *head, ReebNode *tail) -{ - bArmature *arm = obedit->data; - EditBone *lastBone = NULL; - - if (scene->toolsettings->skgen_options & SKGEN_CUT_ANGLE) { - ReebArcIterator arc_iter; - BArcIterator *iter = (BArcIterator *)&arc_iter; - float *previous = NULL, *current = NULL; - EditBone *child = NULL; - EditBone *parent = NULL; - EditBone *root = NULL; - float angleLimit = (float)cos(scene->toolsettings->skgen_angle_limit * M_PI / 180.0f); - - parent = ED_armature_edit_bone_add(arm, "Bone"); - parent->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL; - copy_v3_v3(parent->head, head->p); - - root = parent; - - initArcIterator(iter, arc, head); - IT_next(iter); - previous = iter->p; - - for (IT_next(iter); - IT_stopped(iter) == 0; - previous = iter->p, IT_next(iter)) - { - float vec1[3], vec2[3]; - float len1, len2; - - current = iter->p; - - sub_v3_v3v3(vec1, previous, parent->head); - sub_v3_v3v3(vec2, current, previous); - - len1 = normalize_v3(vec1); - len2 = normalize_v3(vec2); - - if (len1 > 0.0f && len2 > 0.0f && dot_v3v3(vec1, vec2) < angleLimit) { - copy_v3_v3(parent->tail, previous); - - child = ED_armature_edit_bone_add(arm, "Bone"); - copy_v3_v3(child->head, parent->tail); - child->parent = parent; - child->flag |= BONE_CONNECTED | BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL; - - parent = child; /* new child is next parent */ - } - } - copy_v3_v3(parent->tail, tail->p); - - /* If the bone wasn't subdivided, delete it and return NULL - * to let subsequent subdivision methods do their thing. - * */ - if (parent == root) { - if (parent == arm->act_edbone) arm->act_edbone = NULL; - ED_armature_edit_bone_remove(arm, parent); - parent = NULL; - } - - lastBone = parent; /* set last bone in the chain */ - } - - return lastBone; -} - -EditBone *test_subdivideByCorrelation(Scene *scene, Object *obedit, ReebArc *arc, ReebNode *head, ReebNode *tail) -{ - EditBone *lastBone = NULL; - - if (scene->toolsettings->skgen_options & SKGEN_CUT_CORRELATION) { - float invmat[4][4] = MAT4_UNITY; - float tmat[3][3] = MAT3_UNITY; - ReebArcIterator arc_iter; - BArcIterator *iter = (BArcIterator *)&arc_iter; - bArmature *arm = obedit->data; - - initArcIterator(iter, arc, head); - - lastBone = subdivideArcBy(arm, arm->edbo, iter, invmat, tmat, nextAdaptativeSubdivision); - } - - return lastBone; -} - -float arcLengthRatio(ReebArc *arc) -{ - float arcLength = 0.0f; - float embedLength = 0.0f; - int i; - - arcLength = len_v3v3(arc->head->p, arc->tail->p); - - if (arc->bcount > 0) { - /* Add the embedding */ - for (i = 1; i < arc->bcount; i++) { - embedLength += len_v3v3(arc->buckets[i - 1].p, arc->buckets[i].p); - } - /* Add head and tail -> embedding vectors */ - embedLength += len_v3v3(arc->head->p, arc->buckets[0].p); - embedLength += len_v3v3(arc->tail->p, arc->buckets[arc->bcount - 1].p); - } - else { - embedLength = arcLength; - } - - return embedLength / arcLength; -} - -EditBone *test_subdivideByLength(Scene *scene, Object *obedit, ReebArc *arc, ReebNode *head, ReebNode *tail) -{ - EditBone *lastBone = NULL; - if ((scene->toolsettings->skgen_options & SKGEN_CUT_LENGTH) && - arcLengthRatio(arc) >= G.scene->toolsettings->skgen_length_ratio) - { - float invmat[4][4] = MAT4_UNITY; - float tmat[3][3] = MAT3_UNITY; - ReebArcIterator arc_iter; - BArcIterator *iter = (BArcIterator *)&arc_iter; - bArmature *arm = obedit->data; - - initArcIterator(iter, arc, head); - - lastBone = subdivideArcBy(arm, arm->edbo, iter, invmat, tmat, nextLengthSubdivision); - } - - return lastBone; -} - -/***************************************** MAIN ALGORITHM ********************************************/ - -void generateSkeletonFromReebGraph(Scene *scene, ReebGraph *rg) -{ - Object *obedit = scene->obedit; // XXX get from context - GHash *arcBoneMap = NULL; - ReebArc *arc = NULL; - ReebNode *node = NULL; - Object *src = NULL; - Object *dst = NULL; - - src = scene->basact->object; - - if (obedit != NULL) { - ED_armature_from_edit(obedit); - ED_armature_edit_free(obedit); - } - - dst = BKE_object_add(scene, OB_ARMATURE); - ED_object_base_init_transform(NULL, scene->basact, NULL, NULL); // XXX NULL is C, loc, rot - obedit = scene->basact->object; - - /* Copy orientation from source */ - copy_v3_v3(dst->loc, src->obmat[3]); - mat4_to_eul(dst->rot, src->obmat); - mat4_to_size(dst->size, src->obmat); - - BKE_object_where_is_calc(scene, obedit); - - ED_armature_to_edit(obedit); - - arcBoneMap = BLI_ghash_ptr_new("SkeletonFromReebGraph gh"); - - BLI_markdownSymmetry((BGraph *)rg, rg->nodes.first, scene->toolsettings->skgen_symmetry_limit); - - for (arc = rg->arcs.first; arc; arc = arc->next) - { - EditBone *lastBone = NULL; - ReebNode *head, *tail; - int i; - - /* Find out the direction of the arc through simple heuristics (in order of priority) : - * - * 1- Arcs on primary symmetry axis (symmetry == 1) point up (head: high weight -> tail: low weight) - * 2- Arcs starting on a primary axis point away from it (head: node on primary axis) - * 3- Arcs point down (head: low weight -> tail: high weight) - * - * Finally, the arc direction is stored in its flag: 1 (low -> high), -1 (high -> low) - */ - - /* if arc is a symmetry axis, internal bones go up the tree */ - if (arc->symmetry_level == 1 && arc->tail->degree != 1) { - head = arc->tail; - tail = arc->head; - - arc->flag = -1; /* mark arc direction */ - } - /* Bones point AWAY from the symmetry axis */ - else if (arc->head->symmetry_level == 1) { - head = arc->head; - tail = arc->tail; - - arc->flag = 1; /* mark arc direction */ - } - else if (arc->tail->symmetry_level == 1) { - head = arc->tail; - tail = arc->head; - - arc->flag = -1; /* mark arc direction */ - } - /* otherwise, always go from low weight to high weight */ - else { - head = arc->head; - tail = arc->tail; - - arc->flag = 1; /* mark arc direction */ - } - - /* Loop over subdivision methods */ - for (i = 0; lastBone == NULL && i < SKGEN_SUB_TOTAL; i++) { - switch (scene->toolsettings->skgen_subdivisions[i]) { - case SKGEN_SUB_LENGTH: - lastBone = test_subdivideByLength(scene, obedit, arc, head, tail); - break; - case SKGEN_SUB_ANGLE: - lastBone = subdivideByAngle(scene, obedit, arc, head, tail); - break; - case SKGEN_SUB_CORRELATION: - lastBone = test_subdivideByCorrelation(scene, obedit, arc, head, tail); - break; - } - } - - if (lastBone == NULL) { - EditBone *bone; - bone = ED_armature_edit_bone_add(obedit->data, "Bone"); - bone->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL; - - copy_v3_v3(bone->head, head->p); - copy_v3_v3(bone->tail, tail->p); - - /* set first and last bone, since there's only one */ - lastBone = bone; - } - - BLI_ghash_insert(arcBoneMap, arc, lastBone); - } - - /* Second pass, setup parent relationship between arcs */ - for (node = rg->nodes.first; node; node = node->next) - { - ReebArc *incomingArc = NULL; - int i; - - for (i = 0; i < node->degree; i++) { - arc = (ReebArc *)node->arcs[i]; - - /* if arc is incoming into the node */ - if ((arc->head == node && arc->flag == -1) || - (arc->tail == node && arc->flag == 1)) - { - if (incomingArc == NULL) { - incomingArc = arc; - /* loop further to make sure there's only one incoming arc */ - } - else { - /* skip this node if more than one incomingArc */ - incomingArc = NULL; - break; /* No need to look further, we are skipping already */ - } - } - } - - if (incomingArc != NULL) { - EditBone *parentBone = BLI_ghash_lookup(arcBoneMap, incomingArc); - - /* Look for outgoing arcs and parent their bones */ - for (i = 0; i < node->degree; i++) - { - arc = node->arcs[i]; - - /* if arc is outgoing from the node */ - if ((arc->head == node && arc->flag == 1) || (arc->tail == node && arc->flag == -1)) { - EditBone *childBone = BLI_ghash_lookup(arcBoneMap, arc); - - /* find the root bone */ - while (childBone->parent != NULL) - { - childBone = childBone->parent; - } - - childBone->parent = parentBone; - childBone->flag |= BONE_CONNECTED; - } - } - } - } - - BLI_ghash_free(arcBoneMap, NULL, NULL); -} - -void generateSkeleton(Scene *scene) -{ - ReebGraph *reebg; - -// setcursor_space(SPACE_VIEW3D, CURSOR_WAIT); - - reebg = BIF_ReebGraphFromEditMesh(); - - generateSkeletonFromReebGraph(scene, reebg); - - REEB_freeGraph(reebg); - - //setcursor_space(SPACE_VIEW3D, CURSOR_EDIT); -} - -#endif |