Fix T86561: Edit-mode crash with multiple objects sharing a mesh
Use a for loop that always begins with the active object, instead of moving the active object in the array, which failed when it's data already being handled. While the existing logic could have been fixed, it's simpler to change the loop order.
This commit is contained in:
parent
d49e7b82da
commit
0a34fec56a
Notes:
blender-bot
2023-02-14 06:05:22 +01:00
Referenced by issue #86623, Blender crashes when going into edit mode Referenced by issue #86561, Crash when entering edit mode with multiple objects sharing the same mesh Referenced by issue #85958, Potential candidates for corrective releases
|
@ -911,9 +911,7 @@ void ED_undo_object_editmode_restore_helper(struct bContext *C,
|
|||
* and local collections may be used.
|
||||
* \{ */
|
||||
|
||||
static int undo_editmode_objects_from_view_layer_prepare(ViewLayer *view_layer,
|
||||
Object *obact,
|
||||
int *r_active_index)
|
||||
static int undo_editmode_objects_from_view_layer_prepare(ViewLayer *view_layer, Object *obact)
|
||||
{
|
||||
const short object_type = obact->type;
|
||||
|
||||
|
@ -929,9 +927,6 @@ static int undo_editmode_objects_from_view_layer_prepare(ViewLayer *view_layer,
|
|||
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
|
||||
Object *ob = base->object;
|
||||
if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
|
||||
if (ob == obact) {
|
||||
*r_active_index = len;
|
||||
}
|
||||
ID *id = ob->data;
|
||||
if ((id->tag & LIB_TAG_DOIT) == 0) {
|
||||
len += 1;
|
||||
|
@ -944,16 +939,18 @@ static int undo_editmode_objects_from_view_layer_prepare(ViewLayer *view_layer,
|
|||
|
||||
Object **ED_undo_editmode_objects_from_view_layer(ViewLayer *view_layer, uint *r_len)
|
||||
{
|
||||
Object *obact = OBACT(view_layer);
|
||||
if ((obact == NULL) || (obact->mode & OB_MODE_EDIT) == 0) {
|
||||
Base *baseact = BASACT(view_layer);
|
||||
if ((baseact == NULL) || (baseact->object->mode & OB_MODE_EDIT) == 0) {
|
||||
return MEM_mallocN(0, __func__);
|
||||
}
|
||||
int active_index = 0;
|
||||
const int len = undo_editmode_objects_from_view_layer_prepare(view_layer, obact, &active_index);
|
||||
const short object_type = obact->type;
|
||||
const int len = undo_editmode_objects_from_view_layer_prepare(view_layer, baseact->object);
|
||||
const short object_type = baseact->object->type;
|
||||
int i = 0;
|
||||
Object **objects = MEM_malloc_arrayN(len, sizeof(*objects), __func__);
|
||||
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
|
||||
/* Base iteration, starting with the active-base to ensure it's the first item in the array.
|
||||
* Looping over the active-base twice is OK as the tag check prevents it being handled twice. */
|
||||
for (Base *base = baseact, *base_next = FIRSTBASE(view_layer); base;
|
||||
base = base_next, base_next = base_next ? base_next->next : NULL) {
|
||||
Object *ob = base->object;
|
||||
if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
|
||||
ID *id = ob->data;
|
||||
|
@ -964,25 +961,25 @@ Object **ED_undo_editmode_objects_from_view_layer(ViewLayer *view_layer, uint *r
|
|||
}
|
||||
}
|
||||
BLI_assert(i == len);
|
||||
if (active_index > 0) {
|
||||
SWAP(Object *, objects[0], objects[active_index]);
|
||||
}
|
||||
BLI_assert(objects[0] == baseact->object);
|
||||
*r_len = len;
|
||||
return objects;
|
||||
}
|
||||
|
||||
Base **ED_undo_editmode_bases_from_view_layer(ViewLayer *view_layer, uint *r_len)
|
||||
{
|
||||
Object *obact = OBACT(view_layer);
|
||||
if ((obact == NULL) || (obact->mode & OB_MODE_EDIT) == 0) {
|
||||
Base *baseact = BASACT(view_layer);
|
||||
if ((baseact == NULL) || (baseact->object->mode & OB_MODE_EDIT) == 0) {
|
||||
return MEM_mallocN(0, __func__);
|
||||
}
|
||||
int active_index = 0;
|
||||
const int len = undo_editmode_objects_from_view_layer_prepare(view_layer, obact, &active_index);
|
||||
const short object_type = obact->type;
|
||||
const int len = undo_editmode_objects_from_view_layer_prepare(view_layer, baseact->object);
|
||||
const short object_type = baseact->object->type;
|
||||
int i = 0;
|
||||
Base **base_array = MEM_malloc_arrayN(len, sizeof(*base_array), __func__);
|
||||
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
|
||||
/* Base iteration, starting with the active-base to ensure it's the first item in the array.
|
||||
* Looping over the active-base twice is OK as the tag check prevents it being handled twice. */
|
||||
for (Base *base = BASACT(view_layer), *base_next = FIRSTBASE(view_layer); base;
|
||||
base = base_next, base_next = base_next ? base_next->next : NULL) {
|
||||
Object *ob = base->object;
|
||||
if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
|
||||
ID *id = ob->data;
|
||||
|
@ -992,10 +989,9 @@ Base **ED_undo_editmode_bases_from_view_layer(ViewLayer *view_layer, uint *r_len
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert(i == len);
|
||||
if (active_index > 0) {
|
||||
SWAP(Base *, base_array[0], base_array[active_index]);
|
||||
}
|
||||
BLI_assert(base_array[0] == baseact);
|
||||
*r_len = len;
|
||||
return base_array;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue