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')
-rw-r--r--source/blender/editors/armature/CMakeLists.txt1
-rw-r--r--source/blender/editors/armature/armature_add.c3
-rw-r--r--source/blender/editors/armature/armature_edit.c86
-rw-r--r--source/blender/editors/armature/armature_intern.h11
-rw-r--r--source/blender/editors/armature/armature_select.c221
-rw-r--r--source/blender/editors/armature/editarmature_undo.c81
-rw-r--r--source/blender/editors/armature/pose_edit.c3
-rw-r--r--source/blender/editors/armature/pose_select.c108
8 files changed, 396 insertions, 118 deletions
diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt
index 4301fe6582f..8a40ea3b383 100644
--- a/source/blender/editors/armature/CMakeLists.txt
+++ b/source/blender/editors/armature/CMakeLists.txt
@@ -28,6 +28,7 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
+ ../../../../intern/clog
../../../../intern/guardedalloc
../../../../intern/eigen
../../../../intern/glew-mx
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index cb072bee345..36dded5ed5e 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -1074,7 +1074,6 @@ void ARMATURE_OT_bone_primitive_add(wmOperatorType *ot)
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;
@@ -1083,7 +1082,7 @@ static int armature_subdivide_exec(bContext *C, wmOperator *op)
/* loop over all editable bones */
// XXX the old code did this in reverse order though!
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
+ CTX_DATA_BEGIN_WITH_ID(C, EditBone *, ebone, selected_editable_bones, bArmature *, arm)
{
for (i = cuts + 1; i > 1; i--) {
/* compute cut ratio first */
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index 75b80627dff..2335e29aca8 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -48,6 +48,7 @@
#include "BKE_armature.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_global.h"
#include "BKE_report.h"
#include "BKE_object.h"
@@ -630,25 +631,39 @@ static void fill_add_joint(EditBone *ebo, short eb_tail, ListBase *points)
/* 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;
+ Object *obedit_active = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ListBase points = {NULL, NULL};
EditBone *newbone = NULL;
int count;
+ bool mixed_object_error = false;
/* sanity checks */
- if (ELEM(NULL, obedit, arm))
+ if (ELEM(NULL, obedit_active, obedit_active->data)) {
return OPERATOR_CANCELLED;
+ }
/* loop over all bones, and only consider if visible */
- CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones)
+ bArmature *arm = NULL;
+ CTX_DATA_BEGIN_WITH_ID(C, EditBone *, ebone, visible_bones, bArmature *, arm_iter)
{
- if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL))
+ bool check = false;
+ if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL)) {
fill_add_joint(ebone, 0, &points);
- if (ebone->flag & BONE_TIPSEL)
+ check = true;
+ }
+ if (ebone->flag & BONE_TIPSEL) {
fill_add_joint(ebone, 1, &points);
+ check = true;
+ }
+
+ if (check) {
+ if (arm && (arm != arm_iter)) {
+ mixed_object_error = true;
+ }
+ arm = arm_iter;
+ }
}
CTX_DATA_END;
@@ -658,12 +673,30 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op)
* 3+) error (a smarter method involving finding chains needs to be worked out
*/
count = BLI_listbase_count(&points);
-
+
if (count == 0) {
BKE_report(op->reports, RPT_ERROR, "No joints selected");
return OPERATOR_CANCELLED;
}
- else if (count == 1) {
+ else if (mixed_object_error) {
+ BKE_report(op->reports, RPT_ERROR, "Bones for different objects selected");
+ BLI_freelistN(&points);
+ return OPERATOR_CANCELLED;
+ }
+
+ Object *obedit = NULL;
+ {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, OB_MODE_EDIT, ob_iter) {
+ if (ob_iter->data == arm) {
+ obedit = ob_iter;
+ }
+ }
+ FOREACH_OBJECT_IN_MODE_END;
+ }
+ BLI_assert(obedit != NULL);
+
+ if (count == 1) {
EditBonePoint *ebp;
float curs[3];
@@ -1301,18 +1334,23 @@ static bool armature_delete_ebone_cb(const char *bone_name, void *arm_p)
/* only editmode! */
static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
{
- bArmature *arm;
EditBone *curBone, *ebone_next;
- Object *obedit = CTX_data_edit_object(C);
- bool changed = false;
- arm = obedit->data;
+ bool changed_multi = false;
/* cancel if nothing selected */
if (CTX_DATA_COUNT(C, selected_bones) == 0)
return OPERATOR_CANCELLED;
-
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
+ bool changed = false;
+
armature_select_mirrored(arm);
-
+
BKE_pose_channels_remove(obedit, armature_delete_ebone_cb, arm);
for (curBone = arm->edbo->first; curBone; curBone = ebone_next) {
@@ -1325,14 +1363,20 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
}
}
}
-
- if (!changed)
- return OPERATOR_CANCELLED;
-
- ED_armature_edit_sync_selection(arm->edbo);
- BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose);
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ if (changed) {
+ changed_multi = true;
+
+ ED_armature_edit_sync_selection(arm->edbo);
+ BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ }
+ }
+
+ if (!changed_multi) {
+ return OPERATOR_CANCELLED;
+ }
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index 0ba720a17d0..575d1597cc4 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -248,10 +248,15 @@ void armature_select_mirrored_ex(struct bArmature *arm, const int flag);
void armature_select_mirrored(struct bArmature *arm);
void armature_tag_unselect(struct bArmature *arm);
-void *get_nearest_bone(struct bContext *C, const int xy[2], bool findunsel);
+void *get_nearest_bone(
+ struct bContext *C, const int xy[2], bool findunsel,
+ struct Base **r_base);
+
void *get_bone_from_selectbuffer(
- struct Base *base, struct Object *obedit, const unsigned int *buffer, short hits,
- bool findunsel, bool do_nearest);
+ struct Base **bases, uint bases_len,
+ bool is_editmode, const unsigned int *buffer, short hits,
+ bool findunsel, bool do_nearest,
+ struct Base **r_base);
int bone_looper(struct Object *ob, struct Bone *bone, void *data,
int (*bone_func)(struct Object *, struct Bone *, void *));
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;
diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c
index 217de06d99b..f6f97af32b9 100644
--- a/source/blender/editors/armature/editarmature_undo.c
+++ b/source/blender/editors/armature/editarmature_undo.c
@@ -27,26 +27,34 @@
* \ingroup edarmature
*/
+#include "MEM_guardedalloc.h"
+
+
+#include "CLG_log.h"
+
#include "DNA_armature_types.h"
#include "DNA_object_types.h"
-#include "MEM_guardedalloc.h"
-
#include "BLI_math.h"
#include "BLI_array_utils.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_undo_system.h"
#include "DEG_depsgraph.h"
#include "ED_armature.h"
#include "ED_object.h"
+#include "ED_undo.h"
#include "ED_util.h"
#include "WM_types.h"
#include "WM_api.h"
+/** We only need this locally. */
+static CLG_LogRef LOG = {"ed.undo.armature"};
+
/* -------------------------------------------------------------------- */
/** \name Undo Conversion
* \{ */
@@ -121,13 +129,20 @@ static Object *editarm_object_from_context(bContext *C)
/* -------------------------------------------------------------------- */
/** \name Implements ED Undo System
+ *
+ * \note This is similar for all edit-mode types.
* \{ */
-typedef struct ArmatureUndoStep {
- UndoStep step;
- /* note: will split out into list for multi-object-editmode. */
+typedef struct ArmatureUndoStep_Elem {
+ struct ArmatureUndoStep_Elem *next, *prev;
UndoRefID_Object obedit_ref;
UndoArmature data;
+} ArmatureUndoStep_Elem;
+
+typedef struct ArmatureUndoStep {
+ UndoStep step;
+ ArmatureUndoStep_Elem *elems;
+ uint elems_len;
} ArmatureUndoStep;
static bool armature_undosys_poll(bContext *C)
@@ -138,10 +153,24 @@ static bool armature_undosys_poll(bContext *C)
static bool armature_undosys_step_encode(struct bContext *C, UndoStep *us_p)
{
ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
- us->obedit_ref.ptr = editarm_object_from_context(C);
- bArmature *arm = us->obedit_ref.ptr->data;
- undoarm_from_editarm(&us->data, arm);
- us->step.data_size = us->data.undo_size;
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
+
+ us->elems = MEM_callocN(sizeof(*us->elems) * objects_len, __func__);
+ us->elems_len = objects_len;
+
+ for (uint i = 0; i < objects_len; i++) {
+ Object *ob = objects[i];
+ ArmatureUndoStep_Elem *elem = &us->elems[i];
+
+ elem->obedit_ref.ptr = ob;
+ bArmature *arm = elem->obedit_ref.ptr->data;
+ undoarm_from_editarm(&elem->data, arm);
+ us->step.data_size += elem->data.undo_size;
+ }
+ MEM_freeN(objects);
return true;
}
@@ -152,24 +181,46 @@ static void armature_undosys_step_decode(struct bContext *C, UndoStep *us_p, int
BLI_assert(armature_undosys_poll(C));
ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
- Object *obedit = us->obedit_ref.ptr;
- bArmature *arm = obedit->data;
- undoarm_to_editarm(&us->data, arm);
- DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ ArmatureUndoStep_Elem *elem = &us->elems[i];
+ Object *obedit = elem->obedit_ref.ptr;
+ bArmature *arm = obedit->data;
+ if (arm->edbo == NULL) {
+ /* Should never fail, may not crash but can give odd behavior. */
+ CLOG_ERROR(&LOG, "name='%s', failed to enter edit-mode for object '%s', undo state invalid", us_p->name, obedit->id.name);
+ continue;
+ }
+ undoarm_to_editarm(&elem->data, arm);
+ DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ }
+
+ /* The first element is always active */
+ ED_undo_object_set_active_or_warn(CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG);
+
WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
}
static void armature_undosys_step_free(UndoStep *us_p)
{
ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
- undoarm_free_data(&us->data);
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ ArmatureUndoStep_Elem *elem = &us->elems[i];
+ undoarm_free_data(&elem->data);
+ }
+ MEM_freeN(us->elems);
}
static void armature_undosys_foreach_ID_ref(
UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
{
ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
- foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ ArmatureUndoStep_Elem *elem = &us->elems[i];
+ foreach_ID_ref_fn(user_data, ((UndoRefID *)&elem->obedit_ref));
+ }
}
/* Export for ED_undo_sys. */
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 520ecc797aa..ea93e024f8e 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -1015,7 +1015,6 @@ static int armature_bone_layers_invoke(bContext *C, wmOperator *op, const wmEven
static int armature_bone_layers_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_edit_object(C);
- bArmature *arm = (ob) ? ob->data : NULL;
PointerRNA ptr;
int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
@@ -1023,7 +1022,7 @@ static int armature_bone_layers_exec(bContext *C, wmOperator *op)
RNA_boolean_get_array(op->ptr, "layers", layers);
/* set layers of pchans based on the values set in the operator props */
- CTX_DATA_BEGIN (C, EditBone *, ebone, selected_editable_bones)
+ CTX_DATA_BEGIN_WITH_ID (C, EditBone *, ebone, selected_editable_bones, bArmature *, arm)
{
/* get pointer for pchan, and write flags this way */
RNA_pointer_create((ID *)arm, &RNA_EditBone, ebone, &ptr);
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index 1c23f71233d..b6f1e101291 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -45,6 +45,7 @@
#include "BKE_context.h"
#include "BKE_object.h"
#include "BKE_report.h"
+#include "BKE_layer.h"
#include "DEG_depsgraph.h"
@@ -145,7 +146,9 @@ bool ED_armature_pose_select_pick_with_buffer(
Object *ob_act = OBACT(view_layer);
Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
- nearBone = get_bone_from_selectbuffer(base, obedit, buffer, hits, 1, do_nearest);
+ /* 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)) {
@@ -166,7 +169,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_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
+ ED_pose_deselect_all_multi(objects, objects_len, SEL_DESELECT, true);
+ MEM_SAFE_FREE(objects);
+ }
nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
arm->act_bone = nearBone;
}
@@ -252,6 +260,43 @@ void ED_pose_deselect_all(Object *ob, int select_mode, const bool ignore_visibil
}
}
+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];
+ ED_pose_deselect_all(ob_iter, select_mode, ignore_visibility);
+ }
+}
+
/* ***************** Selections ********************** */
static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend)
@@ -278,17 +323,18 @@ 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;
+
+ bArmature *arm = base->object->data;
/* Select parents */
for (curBone = bone; curBone; curBone = next) {
@@ -310,14 +356,14 @@ 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);
+ selectconnected_posebonechildren(base->object, curBone, extend);
/* updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object);
if (arm->flag & ARM_HAS_VIZ_DEPS) {
/* mask modifier ('armature' mode), etc. */
- DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&base->object->id, OB_RECALC_DATA);
}
return OPERATOR_FINISHED;
@@ -354,27 +400,31 @@ 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);
+ }
+ 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)) {
- DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
return OPERATOR_FINISHED;
}
@@ -450,13 +500,13 @@ 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;
-
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ Object *ob_prev = NULL;
+
+ CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob)
{
+ bArmature *arm = ob->data;
if (pchan->bone->flag & BONE_SELECTED) {
for (con = pchan->constraints.first; con; con = con->next) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
@@ -472,6 +522,16 @@ 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) {
+ /* updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ if (arm->flag & ARM_HAS_VIZ_DEPS) {
+ /* mask modifier ('armature' mode), etc. */
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+ ob_prev = ob;
+ }
}
}
}
@@ -487,14 +547,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. */
- DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
return OPERATOR_FINISHED;
}