Fix T58412: in weight paint + pose mode certain armature operations crash.

The cause is that FOREACH_OBJECT_IN_MODE_BEGIN assumed that the active
object is in the correct mode, which is wrong in this case. It also
only considered objects of the same type as active, which had to be
replaced with an explicit type parameter.
This commit is contained in:
Alexander Gavrilov 2018-12-01 19:43:10 +03:00
parent 9ed522db73
commit 18f0618677
Notes: blender-bot 2023-02-14 04:56:36 +01:00
Referenced by issue #58412, Weight Paint mode crash
Referenced by issue #58265, Blender 2.8 Beta crashing in Sculpt Mode
13 changed files with 42 additions and 31 deletions

View File

@ -160,6 +160,7 @@ void BKE_view_layer_selected_editable_objects_iterator_end(BLI_Iterator *iter);
struct ObjectsInModeIteratorData {
int object_mode;
int object_type;
struct ViewLayer *view_layer;
struct View3D *v3d;
struct Base *base_active;
@ -226,10 +227,11 @@ void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter);
ITER_END; \
} ((void)0)
#define FOREACH_BASE_IN_MODE_BEGIN(_view_layer, _v3d, _object_mode, _instance) \
#define FOREACH_BASE_IN_MODE_BEGIN(_view_layer, _v3d, _object_type, _object_mode, _instance) \
{ \
struct ObjectsInModeIteratorData data_ = { \
.object_mode = _object_mode, \
.object_type = _object_type, \
.view_layer = _view_layer, \
.v3d = _v3d, \
.base_active = _view_layer->basact, \
@ -244,20 +246,20 @@ void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter);
} ((void)0)
#define FOREACH_BASE_IN_EDIT_MODE_BEGIN(_view_layer, _v3d, _instance) \
FOREACH_BASE_IN_MODE_BEGIN(_view_layer, _v3d, OB_MODE_EDIT, _instance)
FOREACH_BASE_IN_MODE_BEGIN(_view_layer, _v3d, -1, OB_MODE_EDIT, _instance)
#define FOREACH_BASE_IN_EDIT_MODE_END \
FOREACH_BASE_IN_MODE_END
#define FOREACH_OBJECT_IN_MODE_BEGIN(_view_layer, _v3d, _object_mode, _instance) \
FOREACH_BASE_IN_MODE_BEGIN(_view_layer, _v3d, _object_mode, _base) { \
#define FOREACH_OBJECT_IN_MODE_BEGIN(_view_layer, _v3d, _object_type, _object_mode, _instance) \
FOREACH_BASE_IN_MODE_BEGIN(_view_layer, _v3d, _object_type, _object_mode, _base) { \
Object *_instance = _base->object;
#define FOREACH_OBJECT_IN_MODE_END \
} FOREACH_BASE_IN_MODE_END
#define FOREACH_OBJECT_IN_EDIT_MODE_BEGIN(_view_layer, _instance) \
FOREACH_BASE_IN_EDIT_MODE_BEGIN(_view_layer, _base) { \
#define FOREACH_OBJECT_IN_EDIT_MODE_BEGIN(_view_layer, _v3d, _instance) \
FOREACH_BASE_IN_EDIT_MODE_BEGIN(_view_layer, _v3d, _base) { \
Object *_instance = _base->object;
#define FOREACH_OBJECT_IN_EDIT_MODE_END \

View File

@ -1414,6 +1414,11 @@ void BKE_view_layer_renderable_objects_iterator_end(BLI_Iterator *UNUSED(iter))
/** \name BKE_view_layer_bases_in_mode_iterator
* \{ */
static bool base_is_in_mode(struct ObjectsInModeIteratorData *data, Base *base)
{
return (base->object->type == data->object_type) && (base->object->mode & data->object_mode) != 0;
}
void BKE_view_layer_bases_in_mode_iterator_begin(BLI_Iterator *iter, void *data_in)
{
struct ObjectsInModeIteratorData *data = data_in;
@ -1427,7 +1432,12 @@ void BKE_view_layer_bases_in_mode_iterator_begin(BLI_Iterator *iter, void *data_
iter->data = data_in;
iter->current = base;
if (object_bases_iterator_is_valid(data->v3d, base) == false) {
/* default type is active object type */
if (data->object_type < 0) {
data->object_type = base->object->type;
}
if (object_bases_iterator_is_valid(data->v3d, base) == false || !base_is_in_mode(data, base)) {
BKE_view_layer_bases_in_mode_iterator_next(iter);
}
}
@ -1449,9 +1459,8 @@ void BKE_view_layer_bases_in_mode_iterator_next(BLI_Iterator *iter)
}
while (base) {
if ((base->object->type == data->base_active->object->type) &&
(base != data->base_active) &&
(base->object->mode & data->object_mode) &&
if ((base != data->base_active) &&
base_is_in_mode(data, base) &&
object_bases_iterator_is_valid(data->v3d, base))
{
iter->current = base;

View File

@ -44,7 +44,7 @@ Base **BKE_view_layer_array_from_bases_in_mode_params(
const struct ObjectsInModeParams *params)
{
if (params->no_dup_data) {
FOREACH_BASE_IN_MODE_BEGIN(view_layer, v3d, params->object_mode, base_iter) {
FOREACH_BASE_IN_MODE_BEGIN(view_layer, v3d, -1, params->object_mode, base_iter) {
ID *id = base_iter->object->data;
if (id) {
id->tag |= LIB_TAG_DOIT;
@ -55,7 +55,7 @@ Base **BKE_view_layer_array_from_bases_in_mode_params(
Base **base_array = NULL;
BLI_array_declare(base_array);
FOREACH_BASE_IN_MODE_BEGIN(view_layer, v3d, params->object_mode, base_iter) {
FOREACH_BASE_IN_MODE_BEGIN(view_layer, v3d, -1, params->object_mode, base_iter) {
if (params->filter_fn) {
if (!params->filter_fn(base_iter->object, params->filter_userdata)) {
continue;

View File

@ -2087,7 +2087,7 @@ void DRW_draw_select_loop(
#if 0
drw_engines_cache_populate(obact);
#else
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, obact->mode, ob_iter) {
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, obact->type, obact->mode, ob_iter) {
drw_engines_cache_populate(ob_iter);
}
FOREACH_OBJECT_IN_MODE_END;

View File

@ -709,7 +709,7 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op)
Object *obedit = NULL;
{
ViewLayer *view_layer = CTX_data_view_layer(C);
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_MODE_EDIT, ob_iter) {
FOREACH_OBJECT_IN_EDIT_MODE_BEGIN (view_layer, v3d, ob_iter) {
if (ob_iter->data == arm) {
obedit = ob_iter;
}

View File

@ -744,7 +744,7 @@ static int pose_flip_names_exec(bContext *C, wmOperator *op)
View3D *v3d = CTX_wm_view3d(C);
const bool do_strip_numbers = RNA_boolean_get(op->ptr, "do_strip_numbers");
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_MODE_POSE, ob)
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob)
{
bArmature *arm = ob->data;
ListBase bones_names = {NULL};
@ -1329,7 +1329,7 @@ static int pose_flip_quats_exec(bContext *C, wmOperator *UNUSED(op))
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C);
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_MODE_POSE, ob_iter) {
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob_iter) {
bool changed = false;
/* loop through all selected pchans, flipping and keying (as needed) */
FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob_iter, pchan) {

View File

@ -1621,7 +1621,7 @@ static int pose_propagate_exec(bContext *C, wmOperator *op)
BLI_freelistN(&modeData.sel_markers);
/* updates + notifiers */
FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, v3d, OB_MODE_POSE, ob) {
FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
poseAnim_mapping_refresh(C, scene, ob);
} FOREACH_OBJECT_IN_MODE_END;

View File

@ -235,7 +235,7 @@ static int pose_visual_transform_apply_exec(bContext *C, wmOperator *UNUSED(op))
View3D *v3d = CTX_wm_view3d(C);
Depsgraph *depsgraph = CTX_data_depsgraph(C);
FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, v3d, OB_MODE_POSE, ob)
FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob)
{
/* loop over all selected pchans
*
@ -781,7 +781,7 @@ static int pose_clear_transform_generic_exec(bContext *C, wmOperator *op,
/* only clear relevant transforms for selected bones */
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C);
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_MODE_POSE, ob_iter)
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob_iter)
{
Object *ob_eval = DEG_get_evaluated_object(CTX_data_depsgraph(C), ob_iter); // XXX: UGLY HACK (for autokey + clear transforms)
ListBase dsources = {NULL, NULL};
@ -942,7 +942,7 @@ static int pose_clear_user_transforms_exec(bContext *C, wmOperator *op)
float cframe = (float)CFRA;
const bool only_select = RNA_boolean_get(op->ptr, "only_selected");
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_MODE_POSE, ob)
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob)
{
if ((ob->adt) && (ob->adt->action)) {
/* XXX: this is just like this to avoid contaminating anything else;

View File

@ -290,7 +290,7 @@ void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks,
View3D *v3d = CTX_wm_view3d(C);
bool skip = true;
FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, v3d, OB_MODE_POSE, ob) {
FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
ob->id.tag &= ~LIB_TAG_DOIT;
ob = poseAnim_object_get(ob);
@ -342,7 +342,7 @@ void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks,
* - only do this if keyframes should have been added
* - do not calculate unless there are paths already to update...
*/
FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, v3d, OB_MODE_POSE, ob) {
FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
if (ob->id.tag & LIB_TAG_DOIT) {
if (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) {
//ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear

View File

@ -356,7 +356,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
} FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
}
else if (obact->mode & OB_MODE_POSE) {
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_MODE_POSE, ob_iter) {
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob_iter) {
FOREACH_PCHAN_VISIBLE_IN_OBJECT_BEGIN (ob_iter, pchan) {
CTX_data_list_add(result, &ob_iter->id, &RNA_PoseBone, pchan);
} FOREACH_PCHAN_VISIBLE_IN_OBJECT_END;
@ -375,7 +375,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
} FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
}
else if (obact->mode & OB_MODE_POSE) {
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_MODE_POSE, ob_iter) {
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob_iter) {
FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob_iter, pchan) {
CTX_data_list_add(result, &ob_iter->id, &RNA_PoseBone, pchan);
} FOREACH_PCHAN_SELECTED_IN_OBJECT_END;

View File

@ -412,7 +412,7 @@ static void stats_update(Depsgraph *depsgraph, ViewLayer *view_layer)
if (obedit) {
/* Edit Mode */
FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, ((View3D *)NULL), ob->mode, ob_iter)
FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, ((View3D *)NULL), ob->type, ob->mode, ob_iter)
{
stats_object_edit(ob_iter, &stats);
}

View File

@ -2853,13 +2853,13 @@ static int viewselected_exec(bContext *C, wmOperator *op)
}
else if (obedit) {
/* only selected */
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer_eval, v3d, obedit->mode, ob_eval_iter) {
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer_eval, v3d, obedit->type, obedit->mode, ob_eval_iter) {
ok |= ED_view3d_minmax_verts(ob_eval_iter, min, max);
}
FOREACH_OBJECT_IN_MODE_END;
}
else if (ob_eval && (ob_eval->mode & OB_MODE_POSE)) {
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer_eval, v3d, ob_eval->mode, ob_eval_iter) {
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer_eval, v3d, ob_eval->type, ob_eval->mode, ob_eval_iter) {
ok |= BKE_pose_minmax(ob_eval_iter, min, max, true, true);
}
FOREACH_OBJECT_IN_MODE_END;

View File

@ -456,7 +456,7 @@ static Base **do_pose_tag_select_op_prepare(ViewContext *vc, uint *r_bases_len)
{
Base **bases = NULL;
BLI_array_declare(bases);
FOREACH_BASE_IN_MODE_BEGIN (vc->view_layer, vc->v3d, OB_MODE_POSE, base_iter) {
FOREACH_BASE_IN_MODE_BEGIN (vc->view_layer, vc->v3d, OB_ARMATURE, OB_MODE_POSE, base_iter) {
Object *ob_iter = base_iter->object;
bArmature *arm = ob_iter->data;
for (bPoseChannel *pchan = ob_iter->pose->chanbase.first; pchan; pchan = pchan->next) {
@ -1000,7 +1000,7 @@ static void view3d_lasso_select(
}
else { /* Edit Mode */
FOREACH_OBJECT_IN_MODE_BEGIN (vc->view_layer, vc->v3d, ob->mode, ob_iter) {
FOREACH_OBJECT_IN_MODE_BEGIN (vc->view_layer, vc->v3d, ob->type, ob->mode, ob_iter) {
ED_view3d_viewcontext_init_object(vc, ob_iter);
switch (vc->obedit->type) {
@ -2531,7 +2531,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
if (vc.obedit) {
FOREACH_OBJECT_IN_MODE_BEGIN (vc.view_layer, vc.v3d, vc.obedit->mode, ob_iter) {
FOREACH_OBJECT_IN_MODE_BEGIN (vc.view_layer, vc.v3d, vc.obedit->type, vc.obedit->mode, ob_iter) {
ED_view3d_viewcontext_init_object(&vc, ob_iter);
switch (vc.obedit->type) {
@ -3263,7 +3263,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
{
view3d_operator_needs_opengl(C);
FOREACH_OBJECT_IN_MODE_BEGIN (vc.view_layer, vc.v3d, obact->mode, ob_iter) {
FOREACH_OBJECT_IN_MODE_BEGIN (vc.view_layer, vc.v3d, obact->type, obact->mode, ob_iter) {
ED_view3d_viewcontext_init_object(&vc, ob_iter);
obact = vc.obact;