diff options
author | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2018-08-31 17:14:20 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2018-09-03 17:29:59 +0300 |
commit | b812dfd1611e045a1446c70b81f830ae67fa3eab (patch) | |
tree | 3e092c70be295acfadc1516484a3725d54c98481 /source/blender/blenkernel | |
parent | 27c954386b279c480410b12e30ca5bd8e57629e7 (diff) |
Fix T56622: crash and other bugs deleting scenes.
Simplify library remapping code to handle special collection/object links
in postprocess. Previously base contained the actual object link which
needed special handling in preprocess, now objects are linked through
collection and the base cache can be updated in postprocess.
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r-- | source/blender/blenkernel/intern/collection.c | 56 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/layer.c | 10 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/library_remap.c | 72 |
3 files changed, 37 insertions, 101 deletions
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 1537743fff4..1f6ab06fb49 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -611,30 +611,37 @@ bool BKE_scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, } /* - * Remove all NULL objects from non-scene collections. + * Remove all NULL objects from collections. * This is used for library remapping, where these pointers have been set to NULL. * Otherwise this should never happen. */ -void BKE_collections_object_remove_nulls(Main *bmain) +static void collection_object_remove_nulls(Collection *collection) { - for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) { - if (!BKE_collection_is_in_scene(collection)) { - bool changed = false; - - for (CollectionObject *cob = collection->gobject.first, *cob_next = NULL; cob; cob = cob_next) { - cob_next = cob->next; + bool changed = false; - if (cob->ob == NULL) { - BLI_freelinkN(&collection->gobject, cob); - changed = true; - } - } + for (CollectionObject *cob = collection->gobject.first, *cob_next = NULL; cob; cob = cob_next) { + cob_next = cob->next; - if (changed) { - BKE_collection_object_cache_free(collection); - } + if (cob->ob == NULL) { + BLI_freelinkN(&collection->gobject, cob); + changed = true; } } + + if (changed) { + BKE_collection_object_cache_free(collection); + } +} + +void BKE_collections_object_remove_nulls(Main *bmain) +{ + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + collection_object_remove_nulls(scene->master_collection); + } + + for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) { + collection_object_remove_nulls(collection); + } } /* @@ -646,15 +653,9 @@ void BKE_collections_child_remove_nulls(Main *bmain, Collection *old_collection) { bool changed = false; - for (CollectionChild *child = old_collection->children.first; child; child = child->next) { - CollectionParent *cparent = collection_find_parent(child->collection, old_collection); - if (cparent) { - BLI_freelinkN(&child->collection->parents, cparent); - } - } - - for (CollectionParent *cparent = old_collection->parents.first; cparent; cparent = cparent->next) { + for (CollectionParent *cparent = old_collection->parents.first, *cnext; cparent; cparent = cnext) { Collection *parent = cparent->collection; + cnext = cparent->next; for (CollectionChild *child = parent->children.first, *child_next = NULL; child; child = child_next) { child_next = child->next; @@ -664,9 +665,12 @@ void BKE_collections_child_remove_nulls(Main *bmain, Collection *old_collection) changed = true; } } - } - BLI_freelistN(&old_collection->parents); + if (!collection_find_child(parent, old_collection)) { + BLI_freelinkN(&old_collection->parents, cparent); + changed = true; + } + } if (changed) { BKE_main_collection_sync(bmain); diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 4df1b72d02a..707e1738af9 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -80,7 +80,7 @@ static LayerCollection *layer_collection_add(ListBase *lb_parent, Collection *co static void layer_collection_free(ViewLayer *view_layer, LayerCollection *lc) { if (lc == view_layer->active_collection) { - view_layer->active_collection = view_layer->layer_collections.first; + view_layer->active_collection = NULL; } for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { @@ -311,7 +311,9 @@ static void view_layer_bases_hash_create(ViewLayer *view_layer) view_layer->object_bases_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); for (Base *base = view_layer->object_bases.first; base; base = base->next) { - BLI_ghash_insert(view_layer->object_bases_hash, base->object, base); + if (base->object) { + BLI_ghash_insert(view_layer->object_bases_hash, base->object, base); + } } BLI_mutex_unlock(&hash_lock); @@ -786,7 +788,9 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer) view_layer->basact = NULL; } - BLI_ghash_remove(view_layer->object_bases_hash, base->object, NULL, NULL); + if (base->object) { + BLI_ghash_remove(view_layer->object_bases_hash, base->object, NULL, NULL); + } } BLI_freelistN(&view_layer->object_bases); diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index 15be8231715..fc2e4cd4723 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -263,81 +263,9 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id return IDWALK_RET_NOP; } -/* Some remapping unfortunately require extra and/or specific handling, tackle those here. */ -static void libblock_remap_data_preprocess_scene_object_unlink( - IDRemap *r_id_remap_data, Scene *sce, Object *ob, const bool skip_indirect, const bool is_indirect) -{ - if (skip_indirect && is_indirect) { - r_id_remap_data->skipped_indirect++; - r_id_remap_data->skipped_refcounted++; - } - else { - /* Remove object from all collections in the scene. free_use is false - * to avoid recursively calling object free again. */ - BKE_scene_collections_object_remove(r_id_remap_data->bmain, sce, ob, false); - if (!is_indirect) { - r_id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT; - } - } -} - -static void libblock_remap_data_preprocess_collection_unlink( - IDRemap *r_id_remap_data, Object *ob, const bool skip_indirect, const bool is_indirect) -{ - Main *bmain = r_id_remap_data->bmain; - for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) { - if (!BKE_collection_is_in_scene(collection) && BKE_collection_has_object(collection, ob)) { - if (skip_indirect && is_indirect) { - r_id_remap_data->skipped_indirect++; - r_id_remap_data->skipped_refcounted++; - } - else { - BKE_collection_object_remove(bmain, collection, ob, false); - if (!is_indirect) { - r_id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT; - } - } - } - } -} - static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) { switch (GS(r_id_remap_data->id->name)) { - case ID_SCE: - { - Scene *sce = (Scene *)r_id_remap_data->id; - - if (!r_id_remap_data->new_id) { - const bool is_indirect = (sce->id.lib != NULL); - const bool skip_indirect = (r_id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0; - - /* In case we are unlinking... */ - if (!r_id_remap_data->old_id) { - /* TODO: how is it valid to iterator over a scene while - * removing objects from it? can't this crash? */ - /* ... everything from scene. */ - FOREACH_SCENE_OBJECT_BEGIN(sce, ob_iter) - { - libblock_remap_data_preprocess_scene_object_unlink( - r_id_remap_data, sce, ob_iter, skip_indirect, is_indirect); - libblock_remap_data_preprocess_collection_unlink( - r_id_remap_data, ob_iter, skip_indirect, is_indirect); - } - FOREACH_SCENE_OBJECT_END; - } - else if (GS(r_id_remap_data->old_id->name) == ID_OB) { - /* ... a specific object from scene. */ - Object *old_ob = (Object *)r_id_remap_data->old_id; - libblock_remap_data_preprocess_scene_object_unlink( - r_id_remap_data, sce, old_ob, skip_indirect, is_indirect); - libblock_remap_data_preprocess_collection_unlink( - r_id_remap_data, old_ob, skip_indirect, is_indirect); - } - - } - break; - } case ID_OB: { ID *old_id = r_id_remap_data->old_id; |