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_select.c')
-rw-r--r--source/blender/editors/armature/armature_select.c221
1 files changed, 174 insertions, 47 deletions
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index 587cafa6d48..63864e75edc 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -29,6 +29,8 @@
* \ingroup edarmature
*/
+#include "MEM_guardedalloc.h"
+
#include "DNA_armature_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -40,6 +42,7 @@
#include "BKE_context.h"
#include "BKE_action.h"
#include "BKE_report.h"
+#include "BKE_layer.h"
#include "BIF_gl.h"
@@ -63,26 +66,84 @@
/* **************** PoseMode & EditMode Selection Buffer Queries *************************** */
-/* only for opengl selection indices */
-Bone *ED_armature_bone_find_index(Object *ob, int index)
+Base *ED_armature_base_and_ebone_from_select_buffer(
+ Base **bases, uint bases_len, int hit, EditBone **r_ebone)
{
- 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;
+ const uint hit_object = hit & 0xFFFF;
+ Base *base = NULL;
+ EditBone *ebone = NULL;
+ /* TODO(campbell): optimize, eg: sort & binary search. */
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ if (bases[base_index]->object->select_color == hit_object) {
+ base = bases[base_index];
+ break;
+ }
+ }
+ if (base != NULL) {
+ const uint hit_bone = (hit & ~BONESEL_ANY) >> 16;
+ bArmature *arm = base->object->data;
+ ebone = BLI_findlink(arm->edbo, hit_bone);
+ }
+ *r_ebone = ebone;
+ return base;
+}
+
+Object *ED_armature_object_and_ebone_from_select_buffer(
+ Object **objects, uint objects_len, int hit, EditBone **r_ebone)
+{
+ const uint hit_object = hit & 0xFFFF;
+ Object *ob = NULL;
+ EditBone *ebone = NULL;
+ /* TODO(campbell): optimize, eg: sort & binary search. */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ if (objects[ob_index]->select_color == hit_object) {
+ ob = objects[ob_index];
+ break;
+ }
+ }
+ if (ob != NULL) {
+ const uint hit_bone = (hit & ~BONESEL_ANY) >> 16;
+ bArmature *arm = ob->data;
+ ebone = BLI_findlink(arm->edbo, hit_bone);
+ }
+ *r_ebone = ebone;
+ return ob;
+}
+
+Base *ED_armature_base_and_bone_from_select_buffer(
+ Base **bases, uint bases_len, int hit, Bone **r_bone)
+{
+ const uint hit_object = hit & 0xFFFF;
+ Base *base = NULL;
+ Bone *bone = NULL;
+ /* TODO(campbell): optimize, eg: sort & binary search. */
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ if (bases[base_index]->object->select_color == hit_object) {
+ base = bases[base_index];
+ break;
+ }
+ }
+ if (base != NULL) {
+ if (base->object->pose != NULL) {
+ const uint hit_bone = (hit & ~BONESEL_ANY) >> 16;
+ bPoseChannel *pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone);;
+ bone = pchan ? pchan->bone : NULL;
+ }
+ }
+ *r_bone = bone;
+ return base;
}
/* See if there are any selected bones in this buffer */
/* only bones from base are checked on */
void *get_bone_from_selectbuffer(
- Base *base, Object *obedit, const unsigned int *buffer, short hits,
- bool findunsel, bool do_nearest)
+ Base **bases, uint bases_len, bool is_editmode, const unsigned int *buffer, short hits,
+ bool findunsel, bool do_nearest, Base **r_base)
{
Bone *bone;
EditBone *ebone;
void *firstunSel = NULL, *firstSel = NULL, *data;
+ Base *firstunSel_base = NULL, *firstSel_base = NULL;
unsigned int hitresult;
short i;
bool takeNext = false;
@@ -93,15 +154,14 @@ void *get_bone_from_selectbuffer(
if (!(hitresult & BONESEL_NOSEL)) {
if (hitresult & BONESEL_ANY) { /* to avoid including objects in selection */
+ Base *base = NULL;
bool sel;
-
+
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->object->select_color == (hitresult & 0xFFFF)) {
- bone = ED_armature_bone_find_index(base->object, hitresult);
-
+ if (is_editmode == false) {
+ base = ED_armature_base_and_bone_from_select_buffer(bases, bases_len, hitresult, &bone);
+ if (bone != NULL) {
if (findunsel)
sel = (bone->flag & BONE_SELECTED);
else
@@ -115,14 +175,12 @@ void *get_bone_from_selectbuffer(
}
}
else {
- bArmature *arm = obedit->data;
-
- ebone = BLI_findlink(arm->edbo, hitresult);
+ base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone);
if (findunsel)
sel = (ebone->flag & BONE_SELECTED);
else
sel = !(ebone->flag & BONE_SELECTED);
-
+
data = ebone;
}
@@ -131,11 +189,15 @@ void *get_bone_from_selectbuffer(
if (do_nearest) {
if (minsel > buffer[4 * i + 1]) {
firstSel = data;
+ firstSel_base = base;
minsel = buffer[4 * i + 1];
}
}
else {
- if (!firstSel) firstSel = data;
+ if (!firstSel) {
+ firstSel = data;
+ firstSel_base = base;
+ }
takeNext = 1;
}
}
@@ -143,12 +205,19 @@ void *get_bone_from_selectbuffer(
if (do_nearest) {
if (minunsel > buffer[4 * i + 1]) {
firstunSel = data;
+ firstunSel_base = base;
minunsel = buffer[4 * i + 1];
}
}
else {
- if (!firstunSel) firstunSel = data;
- if (takeNext) return data;
+ if (!firstunSel) {
+ firstunSel = data;
+ firstunSel_base = base;
+ }
+ if (takeNext) {
+ *r_base = base;
+ return data;
+ }
}
}
}
@@ -156,16 +225,22 @@ void *get_bone_from_selectbuffer(
}
}
- if (firstunSel)
+ if (firstunSel) {
+ *r_base = firstunSel_base;
return firstunSel;
- else
+ }
+ else {
+ *r_base = firstSel_base;
return firstSel;
+ }
}
/* used by posemode as well editmode */
/* only checks scene->basact! */
/* x and y are mouse coords (area space) */
-void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel)
+void *get_nearest_bone(
+ bContext *C, const int xy[2], bool findunsel,
+ Base **r_base)
{
EvaluationContext eval_ctx;
ViewContext vc;
@@ -182,8 +257,20 @@ void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel)
hits = view3d_opengl_select(&eval_ctx, &vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST);
+ *r_base = NULL;
+
if (hits > 0) {
- return get_bone_from_selectbuffer(vc.view_layer->basact, vc.obedit, buffer, hits, findunsel, true);
+ uint bases_len = 0;
+ Base **bases = BKE_view_layer_array_from_bases_in_mode(
+ eval_ctx.view_layer, &bases_len, {
+ .object_mode = vc.obedit ? OB_MODE_EDIT : OB_MODE_POSE,
+ .no_dup_data = true});
+
+ void *bone = get_bone_from_selectbuffer(
+ bases, bases_len, vc.obedit != NULL, buffer, hits, findunsel, true, r_base);
+
+ MEM_freeN(bases);
+ return bone;
}
return NULL;
}
@@ -197,16 +284,17 @@ static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEv
bArmature *arm;
EditBone *bone, *curBone, *next;
const bool extend = RNA_boolean_get(op->ptr, "extend");
- Object *obedit = CTX_data_edit_object(C);
- arm = obedit->data;
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;
+ arm = base->object->data;
+
/* Select parents */
for (curBone = bone; curBone; curBone = next) {
if ((curBone->flag & BONE_UNSELECTABLE) == 0) {
@@ -249,7 +337,7 @@ static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEv
ED_armature_edit_sync_selection(arm->edbo);
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object);
return OPERATOR_FINISHED;
}
@@ -295,7 +383,8 @@ static int selectbuffer_ret_hits_5(unsigned int *buffer, const int hits12, const
/* note that BONE ROOT only gets drawn for root bones (or without IK) */
static EditBone *get_nearest_editbonepoint(
const EvaluationContext *eval_ctx, ViewContext *vc,
- bool findunsel, bool use_cycle, int *r_selmask)
+ bool findunsel, bool use_cycle,
+ Base **r_base, int *r_selmask)
{
bArmature *arm = (bArmature *)vc->obedit->data;
EditBone *ebone_next_act = arm->act_edbone;
@@ -371,9 +460,11 @@ static EditBone *get_nearest_editbonepoint(
cache_end:
view3d_opengl_select_cache_end();
+ uint bases_len;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(eval_ctx->view_layer, &bases_len);
+
/* See if there are any selected bones in this group */
if (hits > 0) {
-
if (hits == 1) {
if (!(buffer[3] & BONESEL_NOSEL))
besthitresult = buffer[3];
@@ -382,10 +473,11 @@ cache_end:
for (i = 0; i < hits; i++) {
hitresult = buffer[3 + (i * 4)];
if (!(hitresult & BONESEL_NOSEL)) {
+ Base *base = NULL;
+ base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone);
+ arm = base->object->data;
+
int dep;
-
- ebone = BLI_findlink(arm->edbo, hitresult & ~BONESEL_ANY);
-
/* clicks on bone points get advantage */
if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) {
/* but also the unselected one */
@@ -425,11 +517,13 @@ cache_end:
}
}
}
-
+
if (!(besthitresult & BONESEL_NOSEL)) {
-
- ebone = BLI_findlink(arm->edbo, besthitresult & ~BONESEL_ANY);
-
+ Base *base = NULL;
+ base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone);
+ arm = base->object->data;
+ *r_base = base;
+
*r_selmask = 0;
if (besthitresult & BONESEL_ROOT)
*r_selmask |= BONE_ROOTSEL;
@@ -441,6 +535,7 @@ cache_end:
}
}
*r_selmask = 0;
+ *r_base = NULL;
return NULL;
}
@@ -469,6 +564,23 @@ void ED_armature_edit_deselect_all_visible(Object *obedit)
ED_armature_edit_sync_selection(arm->edbo);
}
+
+void ED_armature_edit_deselect_all_multi(struct Object **objects, uint objects_len)
+{
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ ED_armature_edit_deselect_all(obedit);
+ }
+}
+
+void ED_armature_edit_deselect_all_visible_multi(struct Object **objects, uint objects_len)
+{
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ ED_armature_edit_deselect_all_visible(obedit);
+ }
+}
+
/* accounts for connected parents */
static int ebone_select_flag(EditBone *ebone)
{
@@ -483,11 +595,11 @@ static int ebone_select_flag(EditBone *ebone)
/* context: editmode armature in view3d */
bool ED_armature_edit_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
- Object *obedit = CTX_data_edit_object(C);
EvaluationContext eval_ctx;
ViewContext vc;
EditBone *nearBone = NULL;
int selmask;
+ Base *basact = NULL;
CTX_data_eval_ctx(C, &eval_ctx);
ED_view3d_viewcontext_init(C, &vc);
@@ -498,12 +610,16 @@ bool ED_armature_edit_select_pick(bContext *C, const int mval[2], bool extend, b
return true;
}
- nearBone = get_nearest_editbonepoint(&eval_ctx, &vc, true, true, &selmask);
+ nearBone = get_nearest_editbonepoint(&eval_ctx, &vc, true, true, &basact, &selmask);
if (nearBone) {
- bArmature *arm = obedit->data;
+ ED_view3d_viewcontext_init_object(&vc, basact->object);
+ bArmature *arm = vc.obedit->data;
if (!extend && !deselect && !toggle) {
- ED_armature_edit_deselect_all(obedit);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(eval_ctx.view_layer, &objects_len);
+ ED_armature_edit_deselect_all_multi(objects, objects_len);
+ MEM_freeN(objects);
}
/* by definition the non-root connected bones have no root point drawn,
@@ -581,9 +697,14 @@ bool ED_armature_edit_select_pick(bContext *C, const int mval[2], bool extend, b
if (ebone_select_flag(nearBone)) {
arm->act_edbone = nearBone;
}
+
+ if (eval_ctx.view_layer->basact != basact) {
+ eval_ctx.view_layer->basact = basact;
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, vc.scene);
+ }
}
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object);
return true;
}
@@ -1296,17 +1417,23 @@ static int armature_shortest_path_pick_invoke(bContext *C, wmOperator *op, const
EditBone *ebone_isect_parent = NULL;
EditBone *ebone_isect_child[2];
bool changed;
+ Base *base_dst = NULL;
view3d_operator_needs_opengl(C);
ebone_src = arm->act_edbone;
- ebone_dst = get_nearest_bone(C, event->mval, false);
+ ebone_dst = get_nearest_bone(C, event->mval, false, &base_dst);
/* fallback to object selection */
if (ELEM(NULL, ebone_src, ebone_dst) || (ebone_src == ebone_dst)) {
return OPERATOR_PASS_THROUGH;
}
+ if (base_dst && base_dst->object != obedit) {
+ /* Disconnected, ignore. */
+ return OPERATOR_CANCELLED;
+ }
+
ebone_isect_child[0] = ebone_src;
ebone_isect_child[1] = ebone_dst;