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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/armature/armature_edit.c')
-rw-r--r--source/blender/editors/armature/armature_edit.c317
1 files changed, 230 insertions, 87 deletions
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index 88c52989c07..b3297db6176 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -42,6 +42,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_ghash.h"
#include "BKE_action.h"
#include "BKE_armature.h"
@@ -578,6 +579,7 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ListBase points = {NULL, NULL};
+ EditBone *newbone = NULL;
int count;
/* sanity checks */
@@ -610,94 +612,97 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op)
float curs[3];
/* Get Points - selected joint */
- ebp = (EditBonePoint *)points.first;
+ ebp = points.first;
/* Get points - cursor (tail) */
invert_m4_m4(obedit->imat, obedit->obmat);
mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d));
/* Create a bone */
- /* newbone = */ add_points_bone(obedit, ebp->vec, curs);
+ newbone = add_points_bone(obedit, ebp->vec, curs);
}
else if (count == 2) {
- EditBonePoint *ebp, *ebp2;
+ EditBonePoint *ebp_a, *ebp_b;
float head[3], tail[3];
short headtail = 0;
/* check that the points don't belong to the same bone */
- ebp = (EditBonePoint *)points.first;
- ebp2 = ebp->next;
+ ebp_a = (EditBonePoint *)points.first;
+ ebp_b = ebp_a->next;
- if ((ebp->head_owner == ebp2->tail_owner) && (ebp->head_owner != NULL)) {
- BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
- BLI_freelistN(&points);
- return OPERATOR_CANCELLED;
- }
- if ((ebp->tail_owner == ebp2->head_owner) && (ebp->tail_owner != NULL)) {
+ if (((ebp_a->head_owner == ebp_b->tail_owner) && (ebp_a->head_owner != NULL)) ||
+ ((ebp_a->tail_owner == ebp_b->head_owner) && (ebp_a->tail_owner != NULL)))
+ {
BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
BLI_freelistN(&points);
return OPERATOR_CANCELLED;
}
/* find which one should be the 'head' */
- if ((ebp->head_owner && ebp2->head_owner) || (ebp->tail_owner && ebp2->tail_owner)) {
- /* rule: whichever one is closer to 3d-cursor */
- float curs[3];
- float vecA[3], vecB[3];
- float distA, distB;
-
- /* get cursor location */
- invert_m4_m4(obedit->imat, obedit->obmat);
- mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d));
-
- /* get distances */
- sub_v3_v3v3(vecA, ebp->vec, curs);
- sub_v3_v3v3(vecB, ebp2->vec, curs);
- distA = len_v3(vecA);
- distB = len_v3(vecB);
-
- /* compare distances - closer one therefore acts as direction for bone to go */
- headtail = (distA < distB) ? 2 : 1;
+ if ((ebp_a->head_owner && ebp_b->head_owner) || (ebp_a->tail_owner && ebp_b->tail_owner)) {
+ /* use active, nice predictable */
+ if (arm->act_edbone && ELEM(arm->act_edbone, ebp_a->head_owner, ebp_a->tail_owner)) {
+ headtail = 1;
+ }
+ else if (arm->act_edbone && ELEM(arm->act_edbone, ebp_b->head_owner, ebp_b->tail_owner)) {
+ headtail = 2;
+ }
+ else {
+ /* rule: whichever one is closer to 3d-cursor */
+ float curs[3];
+ float dist_sq_a, dist_sq_b;
+
+ /* get cursor location */
+ invert_m4_m4(obedit->imat, obedit->obmat);
+ mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d));
+
+ /* get distances */
+ dist_sq_a = len_squared_v3v3(ebp_a->vec, curs);
+ dist_sq_b = len_squared_v3v3(ebp_b->vec, curs);
+
+ /* compare distances - closer one therefore acts as direction for bone to go */
+ headtail = (dist_sq_a < dist_sq_b) ? 2 : 1;
+ }
}
- else if (ebp->head_owner) {
+ else if (ebp_a->head_owner) {
headtail = 1;
}
- else if (ebp2->head_owner) {
+ else if (ebp_b->head_owner) {
headtail = 2;
}
/* assign head/tail combinations */
if (headtail == 2) {
- copy_v3_v3(head, ebp->vec);
- copy_v3_v3(tail, ebp2->vec);
+ copy_v3_v3(head, ebp_a->vec);
+ copy_v3_v3(tail, ebp_b->vec);
}
else if (headtail == 1) {
- copy_v3_v3(head, ebp2->vec);
- copy_v3_v3(tail, ebp->vec);
+ copy_v3_v3(head, ebp_b->vec);
+ copy_v3_v3(tail, ebp_a->vec);
}
/* add new bone and parent it to the appropriate end */
if (headtail) {
- EditBone *newbone = add_points_bone(obedit, head, tail);
+ newbone = add_points_bone(obedit, head, tail);
/* do parenting (will need to set connected flag too) */
if (headtail == 2) {
/* ebp tail or head - tail gets priority */
- if (ebp->tail_owner)
- newbone->parent = ebp->tail_owner;
+ if (ebp_a->tail_owner)
+ newbone->parent = ebp_a->tail_owner;
else
- newbone->parent = ebp->head_owner;
+ newbone->parent = ebp_a->head_owner;
}
else {
- /* ebp2 tail or head - tail gets priority */
- if (ebp2->tail_owner)
- newbone->parent = ebp2->tail_owner;
+ /* ebp_b tail or head - tail gets priority */
+ if (ebp_b->tail_owner)
+ newbone->parent = ebp_b->tail_owner;
else
- newbone->parent = ebp2->head_owner;
+ newbone->parent = ebp_b->head_owner;
}
/* don't set for bone connecting two head points of bones */
- if (ebp->tail_owner || ebp2->tail_owner) {
+ if (ebp_a->tail_owner || ebp_b->tail_owner) {
newbone->flag |= BONE_CONNECTED;
}
}
@@ -708,6 +713,12 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op)
BLI_freelistN(&points);
return OPERATOR_CANCELLED;
}
+
+ if (newbone) {
+ ED_armature_deselect_all(obedit);
+ arm->act_edbone = newbone;
+ newbone->flag |= BONE_TIPSEL;
+ }
/* updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
@@ -1223,13 +1234,21 @@ void ARMATURE_OT_split(wmOperatorType *ot)
/* ********************************* Delete ******************************* */
+static bool armature_delete_ebone_cb(const char *bone_name, void *arm_p)
+{
+ bArmature *arm = arm_p;
+ EditBone *ebone;
+
+ ebone = ED_armature_bone_find_name(arm->edbo, bone_name);
+ return (ebone && (ebone->flag & BONE_SELECTED) && (arm->layer & ebone->layer));
+}
+
/* previously delete_armature */
/* only editmode! */
static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
{
bArmature *arm;
EditBone *curBone, *ebone_next;
- bConstraint *con;
Object *obedit = CTX_data_edit_object(C); // XXX get from context
bool changed = false;
arm = obedit->data;
@@ -1240,48 +1259,8 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
armature_select_mirrored(arm);
- /* First erase any associated pose channel */
- if (obedit->pose) {
- bPoseChannel *pchan, *pchan_next;
- for (pchan = obedit->pose->chanbase.first; pchan; pchan = pchan_next) {
- pchan_next = pchan->next;
- curBone = ED_armature_bone_find_name(arm->edbo, pchan->name);
-
- if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) {
- BKE_pose_channel_free(pchan);
- BKE_pose_channels_hash_free(obedit->pose);
- BLI_freelinkN(&obedit->pose->chanbase, pchan);
- }
- else {
- for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar == obedit) {
- if (ct->subtarget[0]) {
- curBone = ED_armature_bone_find_name(arm->edbo, ct->subtarget);
- if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) {
- con->flag |= CONSTRAINT_DISABLE;
- ct->subtarget[0] = 0;
- }
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
- }
- }
-
-
+ BKE_pose_channels_remove(obedit, armature_delete_ebone_cb, arm);
+
for (curBone = arm->edbo->first; curBone; curBone = ebone_next) {
ebone_next = curBone->next;
if (arm->layer & curBone->layer) {
@@ -1319,6 +1298,170 @@ void ARMATURE_OT_delete(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+static bool armature_dissolve_ebone_cb(const char *bone_name, void *arm_p)
+{
+ bArmature *arm = arm_p;
+ EditBone *ebone;
+
+ ebone = ED_armature_bone_find_name(arm->edbo, bone_name);
+ return (ebone && (ebone->flag & BONE_DONE));
+}
+
+static int armature_dissolve_selected_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bArmature *arm;
+ EditBone *ebone, *ebone_next;
+ Object *obedit = CTX_data_edit_object(C);
+ bool changed = false;
+
+ /* store for mirror */
+ GHash *ebone_flag_orig = NULL;
+ int ebone_num = 0;
+
+ arm = obedit->data;
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ ebone->temp.p = NULL;
+ ebone->flag &= ~BONE_DONE;
+ ebone_num++;
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ GHashIterator gh_iter;
+
+ ebone_flag_orig = BLI_ghash_ptr_new_ex(__func__, ebone_num);
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ union { int flag; void *p; } val = {0};
+ val.flag = ebone->flag;
+ BLI_ghash_insert(ebone_flag_orig, ebone, val.p);
+ }
+
+ armature_select_mirrored_ex(arm, BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+
+ GHASH_ITER (gh_iter, ebone_flag_orig) {
+ union { int flag; void *p; } *val_p = (void *)BLI_ghashIterator_getValue_p(&gh_iter);
+ ebone = BLI_ghashIterator_getKey(&gh_iter);
+ val_p->flag = ebone->flag & ~val_p->flag;
+ }
+ }
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->parent && ebone->flag & BONE_CONNECTED) {
+ if (ebone->parent->temp.ebone == ebone->parent) {
+ /* ignore */
+ }
+ else if (ebone->parent->temp.ebone) {
+ /* set ignored */
+ ebone->parent->temp.ebone = ebone->parent;
+ }
+ else {
+ /* set child */
+ ebone->parent->temp.ebone = ebone;
+ }
+ }
+ }
+
+ /* cleanup multiple used bones */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->temp.ebone == ebone) {
+ ebone->temp.ebone = NULL;
+ }
+ }
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ /* break connections for unseen bones */
+ if (((arm->layer & ebone->layer) &&
+ ((ED_armature_ebone_selectflag_get(ebone) & (BONE_TIPSEL | BONE_SELECTED)))) == 0)
+ {
+ ebone->temp.ebone = NULL;
+ }
+
+ if (((arm->layer & ebone->layer) &&
+ ((ED_armature_ebone_selectflag_get(ebone) & (BONE_ROOTSEL | BONE_SELECTED)))) == 0)
+ {
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ ebone->parent->temp.ebone = NULL;
+ }
+
+ }
+ }
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+
+ if (ebone->parent &&
+ (ebone->parent->temp.ebone == ebone))
+ {
+ ebone->flag |= BONE_DONE;
+ }
+ }
+
+ BKE_pose_channels_remove(obedit, armature_dissolve_ebone_cb, arm);
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone_next) {
+ ebone_next = ebone->next;
+
+ if (ebone->flag & BONE_DONE) {
+ copy_v3_v3(ebone->parent->tail, ebone->tail);
+ ebone->parent->rad_tail = ebone->rad_tail;
+
+ ED_armature_edit_bone_remove(arm, ebone);
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->parent &&
+ ebone->parent->temp.ebone &&
+ (ebone->flag & BONE_CONNECTED) == 0)
+ {
+ ebone->flag |= BONE_CONNECTED;
+ ebone->rad_head = ebone->parent->rad_head;
+ }
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ union { int flag; void *p; } *val_p = (void *)BLI_ghash_lookup_p(ebone_flag_orig, ebone);
+ if (val_p && val_p->flag) {
+ ebone->flag &= ~val_p->flag;
+ }
+ }
+ }
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ BLI_ghash_free(ebone_flag_orig, NULL, NULL);
+ }
+
+ if (!changed) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ED_armature_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_dissolve(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Dissolve Selected Bone(s)";
+ ot->idname = "ARMATURE_OT_dissolve";
+ ot->description = "Dissolve selected bones from the armature";
+
+ /* api callbacks */
+ ot->exec = armature_dissolve_selected_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+
/* ********************************* Show/Hide ******************************* */
static int armature_hide_exec(bContext *C, wmOperator *op)