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/pose_select.c')
-rw-r--r--source/blender/editors/armature/pose_select.c314
1 files changed, 183 insertions, 131 deletions
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index ecfaa41b0b5..eb178d422ae 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -43,9 +43,11 @@
#include "BKE_armature.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_object.h"
#include "BKE_report.h"
+#include "BKE_layer.h"
+
+#include "DEG_depsgraph.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -58,6 +60,7 @@
#include "ED_mesh.h"
#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_view3d.h"
#include "armature_intern.h"
@@ -92,6 +95,23 @@ static void pose_do_bone_select(bPoseChannel *pchan, const int select_mode)
}
}
+void ED_pose_bone_select_tag_update(Object *ob)
+{
+ BLI_assert(ob->type == OB_ARMATURE);
+ bArmature *arm = ob->data;
+ WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, ob);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, ob);
+
+ if (arm->flag & ARM_HAS_VIZ_DEPS) {
+ /* mask modifier ('armature' mode), etc. */
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+
+ /* copy on write tag is needed (for the armature), or else no refresh happens */
+ DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
+}
+
+
/* Utility method for changing the selection status of a bone */
void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
{
@@ -117,23 +137,14 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
}
// TODO: select and activate corresponding vgroup?
-
- /* tag necessary depsgraph updates
- * (see rna_Bone_select_update() in rna_armature.c for details)
- */
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
- /* send necessary notifiers */
- WM_main_add_notifier(NC_GEOM | ND_DATA, ob);
+ ED_pose_bone_select_tag_update(ob);
}
}
/* called from editview.c, for mode-less pose selection */
/* assumes scene obact and basact is still on old situation */
bool ED_armature_pose_select_pick_with_buffer(
- Scene *scene, Base *base, const unsigned int *buffer, short hits,
+ ViewLayer *view_layer, Base *base, const unsigned int *buffer, short hits,
bool extend, bool deselect, bool toggle, bool do_nearest)
{
Object *ob = base->object;
@@ -141,11 +152,15 @@ bool ED_armature_pose_select_pick_with_buffer(
if (!ob || !ob->pose) return 0;
- nearBone = get_bone_from_selectbuffer(scene, base, buffer, hits, 1, do_nearest);
+ Object *ob_act = OBACT(view_layer);
+ Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+
+ /* Callers happen to already get the active base */
+ Base *base_dummy = NULL;
+ nearBone = get_bone_from_selectbuffer(&base, 1, obedit != NULL, buffer, hits, 1, do_nearest, &base_dummy);
/* 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
@@ -163,7 +178,12 @@ bool ED_armature_pose_select_pick_with_buffer(
}
if (!extend && !deselect && !toggle) {
- ED_pose_deselect_all(ob, SEL_DESELECT, true);
+ {
+ uint objects_len = 0;
+ Object **objects = BKE_object_pose_array_get_unique(view_layer, &objects_len);
+ ED_pose_deselect_all_multi(objects, objects_len, SEL_DESELECT, true);
+ MEM_freeN(objects);
+ }
nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
arm->act_bone = nearBone;
}
@@ -197,7 +217,7 @@ bool ED_armature_pose_select_pick_with_buffer(
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);
+ DEG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
}
}
/* if there are some dependencies for visualizing armature state
@@ -207,8 +227,11 @@ bool ED_armature_pose_select_pick_with_buffer(
/* NOTE: ob not ob_act here is intentional - it's the source of the
* bones being selected [T37247]
*/
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
+
+ /* tag armature for copy-on-write update (since act_bone is in armature not object) */
+ DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
}
}
@@ -217,14 +240,14 @@ bool ED_armature_pose_select_pick_with_buffer(
/* 'select_mode' is usual SEL_SELECT/SEL_DESELECT/SEL_TOGGLE/SEL_INVERT.
* When true, 'ignore_visibility' makes this func also affect invisible bones (hidden or on hidden layers). */
-void ED_pose_deselect_all(Object *ob, int select_mode, const bool ignore_visibility)
+bool ED_pose_deselect_all(Object *ob, int select_mode, const bool ignore_visibility)
{
bArmature *arm = ob->data;
bPoseChannel *pchan;
/* we call this from outliner too */
if (ob->pose == NULL) {
- return;
+ return false;
}
/* Determine if we're selecting or deselecting */
@@ -241,10 +264,53 @@ void ED_pose_deselect_all(Object *ob, int select_mode, const bool ignore_visibil
}
/* Set the flags accordingly */
+ bool changed = false;
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 (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) {
+ int flag_prev = pchan->bone->flag;
pose_do_bone_select(pchan, select_mode);
+ changed = (changed || flag_prev != pchan->bone->flag);
+ }
+ }
+ return changed;
+}
+
+static bool ed_pose_is_any_selected(Object *ob, bool ignore_visibility)
+{
+ bArmature *arm = ob->data;
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) {
+ if (pchan->bone->flag & BONE_SELECTED) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static bool ed_pose_is_any_selected_multi(Object **objects, uint objects_len, bool ignore_visibility)
+{
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ if (ed_pose_is_any_selected(ob_iter, ignore_visibility)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void ED_pose_deselect_all_multi(Object **objects, uint objects_len, int select_mode, const bool ignore_visibility)
+{
+ if (select_mode == SEL_TOGGLE) {
+ select_mode = ed_pose_is_any_selected_multi(
+ objects, objects_len, ignore_visibility) ? SEL_DESELECT : SEL_SELECT;
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ if (ED_pose_deselect_all(ob_iter, select_mode, ignore_visibility)) {
+ ED_pose_bone_select_tag_update(ob_iter);
}
}
}
@@ -259,9 +325,6 @@ static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend)
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
@@ -275,14 +338,13 @@ static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend)
/* previously known as "selectconnected_posearmature" */
static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = (bArmature *)ob->data;
Bone *bone, *curBone, *next = NULL;
const bool extend = RNA_boolean_get(op->ptr, "extend");
view3d_operator_needs_opengl(C);
- bone = get_nearest_bone(C, event->mval, !extend);
+ Base *base = NULL;
+ bone = get_nearest_bone(C, event->mval, !extend, &base);
if (!bone)
return OPERATOR_CANCELLED;
@@ -307,15 +369,9 @@ static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEve
/* 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);
+ selectconnected_posebonechildren(base->object, curBone, extend);
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
+ ED_pose_bone_select_tag_update(base->object);
return OPERATOR_FINISHED;
}
@@ -332,7 +388,7 @@ void POSE_OT_select_linked(wmOperatorType *ot)
ot->idname = "POSE_OT_select_linked";
ot->description = "Select bones related to selected ones by parent/child relationships";
- /* api callbacks */
+ /* callbacks */
/* leave 'exec' unset */
ot->invoke = pose_select_connected_invoke;
ot->poll = pose_select_linked_poll;
@@ -351,28 +407,34 @@ 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;
}
+ Object *ob_prev = NULL;
+
/* Set the flags */
- CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones)
+ CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob)
{
+ bArmature *arm = ob->data;
pose_do_bone_select(pchan, action);
+
+ if (ob_prev != ob) {
+ /* weightpaint or mask modifiers need depsgraph updates */
+ if (multipaint || (arm->flag & ARM_HAS_VIZ_DEPS)) {
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+ /* need to tag armature for cow updates, or else selection doesn't update */
+ DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
+ ob_prev = ob;
+ }
}
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;
}
@@ -397,33 +459,33 @@ void POSE_OT_select_all(wmOperatorType *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);
+ /* only clear relevant transforms for selected bones */
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, OB_MODE_POSE, ob_iter)
+ {
+ Object *ob = ob_iter;
+ bArmature *arm = (bArmature *)ob->data;
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob_iter, pchan)
+ {
+ if (pchan) {
+ bPoseChannel *parent = pchan->parent;
+ if ((parent) && !(parent->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) {
+ parent->bone->flag |= BONE_SELECTED;
+ arm->act_bone = parent->bone;
+ }
+ else {
+ continue;
+ }
+ }
+ else {
+ continue;
+ }
+ ED_pose_bone_select_tag_update(ob);
+ }
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
}
+ FOREACH_OBJECT_IN_MODE_END;
return OPERATOR_FINISHED;
}
@@ -447,12 +509,11 @@ void POSE_OT_select_parent(wmOperatorType *ot)
static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = (bArmature *)ob->data;
bConstraint *con;
int found = 0;
+ Object *ob_prev = NULL;
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob)
{
if (pchan->bone->flag & BONE_SELECTED) {
for (con = pchan->constraints.first; con; con = con->next) {
@@ -469,6 +530,11 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
if ((pchanc) && !(pchanc->bone->flag & BONE_UNSELECTABLE)) {
pchanc->bone->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
found = 1;
+
+ if (ob != ob_prev) {
+ ED_pose_bone_select_tag_update(ob);
+ ob_prev = ob;
+ }
}
}
}
@@ -484,14 +550,6 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
if (!found)
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;
}
@@ -578,13 +636,7 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
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);
- }
+ ED_pose_bone_select_tag_update(ob);
return OPERATOR_FINISHED;
}
@@ -795,7 +847,6 @@ static bool pose_select_same_keyingset(bContext *C, ReportList *reports, Object
static int pose_select_grouped_exec(bContext *C, wmOperator *op)
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = (bArmature *)ob->data;
const ePose_SelectSame_Mode type = RNA_enum_get(op->ptr, "type");
const bool extend = RNA_boolean_get(op->ptr, "extend");
bool changed = false;
@@ -824,11 +875,8 @@ static int pose_select_grouped_exec(bContext *C, wmOperator *op)
}
/* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ if (changed) {
+ ED_pose_bone_select_tag_update(ob);
}
/* report done status */
@@ -873,59 +921,63 @@ void POSE_OT_select_grouped(wmOperatorType *ot)
static int pose_select_mirror_exec(bContext *C, wmOperator *op)
{
Object *ob_act = CTX_data_active_object(C);
- Object *ob = BKE_object_pose_armature_get(ob_act);
- bArmature *arm;
- bPoseChannel *pchan, *pchan_mirror_act = NULL;
- const bool active_only = RNA_boolean_get(op->ptr, "only_active");
- const bool extend = RNA_boolean_get(op->ptr, "extend");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- if ((ob && (ob->mode & OB_MODE_POSE)) == 0) {
- return OPERATOR_CANCELLED;
- }
+ FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, OB_MODE_POSE, ob)
+ {
+ bArmature *arm;
+ bPoseChannel *pchan, *pchan_mirror_act = NULL;
+ const bool active_only = RNA_boolean_get(op->ptr, "only_active");
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
- arm = ob->data;
+ arm = ob->data;
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- const int flag = (pchan->bone->flag & BONE_SELECTED);
- PBONE_PREV_FLAG_SET(pchan, flag);
- }
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (PBONE_SELECTABLE(arm, pchan->bone)) {
- bPoseChannel *pchan_mirror;
- int flag_new = extend ? PBONE_PREV_FLAG_GET(pchan) : 0;
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ const int flag = (pchan->bone->flag & BONE_SELECTED);
+ PBONE_PREV_FLAG_SET(pchan, flag);
+ }
- if ((pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) &&
- (PBONE_VISIBLE(arm, pchan_mirror->bone)))
- {
- const int flag_mirror = PBONE_PREV_FLAG_GET(pchan_mirror);
- flag_new |= flag_mirror;
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (PBONE_SELECTABLE(arm, pchan->bone)) {
+ bPoseChannel *pchan_mirror;
+ int flag_new = extend ? PBONE_PREV_FLAG_GET(pchan) : 0;
+
+ if ((pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) &&
+ (PBONE_VISIBLE(arm, pchan_mirror->bone)))
+ {
+ const int flag_mirror = PBONE_PREV_FLAG_GET(pchan_mirror);
+ flag_new |= flag_mirror;
+
+ if (pchan->bone == arm->act_bone) {
+ pchan_mirror_act = pchan_mirror;
+ }
- if (pchan->bone == arm->act_bone) {
- pchan_mirror_act = pchan_mirror;
+ /* skip all but the active or its mirror */
+ if (active_only && !ELEM(arm->act_bone, pchan->bone, pchan_mirror->bone)) {
+ continue;
+ }
}
- /* skip all but the active or its mirror */
- if (active_only && !ELEM(arm->act_bone, pchan->bone, pchan_mirror->bone)) {
- continue;
- }
+ pchan->bone->flag = (pchan->bone->flag & ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) | flag_new;
}
-
- pchan->bone->flag = (pchan->bone->flag & ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) | flag_new;
}
- }
- if (pchan_mirror_act) {
- arm->act_bone = pchan_mirror_act->bone;
+ if (pchan_mirror_act) {
+ arm->act_bone = pchan_mirror_act->bone;
- /* in weightpaint we select the associated vertex group too */
- if (ob_act->mode & OB_MODE_WEIGHT_PAINT) {
- ED_vgroup_select_by_name(ob_act, pchan_mirror_act->name);
- DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
+ /* in weightpaint we select the associated vertex group too */
+ if (ob_act->mode & OB_MODE_WEIGHT_PAINT) {
+ ED_vgroup_select_by_name(ob_act, pchan_mirror_act->name);
+ DEG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
+ }
}
- }
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ /* need to tag armature for cow updates, or else selection doesn't update */
+ DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
+ }
+ FOREACH_OBJECT_IN_MODE_END;
return OPERATOR_FINISHED;
}