diff options
author | Bastien Montagne <montagne29@wanadoo.fr> | 2019-05-22 23:51:36 +0300 |
---|---|---|
committer | Bastien Montagne <montagne29@wanadoo.fr> | 2019-05-23 00:33:27 +0300 |
commit | d1f96f9b1194404ffafd2540cd2928048779656e (patch) | |
tree | 4137cd2f2ccc8cfbb5cbbd1d21762df49fa1b161 /source/blender/blenkernel | |
parent | 5a3c44937f64776099125577126766c67f96139a (diff) |
BKE Collection: Add new function to rebuild parent relationships.
It's not always possible to keep 'by hand' parent relationships valid in
collections hierarchy. Add functions to remake those
(re-using/factorizing code from `readfile.c` `lib_link_collection_data()`
function).
Can't stress again how painful it is to have those kind of backward
relationships in our data structures, those *always* end up being
serious issues to keep in sync... Should only be generated on the fly
when needed, period. :(
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r-- | source/blender/blenkernel/BKE_collection.h | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/collection.c | 66 |
2 files changed, 69 insertions, 0 deletions
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h index 0e093bb086b..502c949be9a 100644 --- a/source/blender/blenkernel/BKE_collection.h +++ b/source/blender/blenkernel/BKE_collection.h @@ -163,6 +163,9 @@ bool BKE_collection_find_cycle(struct Collection *new_ancestor, struct Collectio bool BKE_collection_has_collection(struct Collection *parent, struct Collection *collection); +void BKE_collection_parent_relations_rebuild(struct Collection *collection); +void BKE_main_collections_parent_relations_rebuild(struct Main *bmain); + /* Iteration callbacks. */ typedef void (*BKE_scene_objects_Cb)(struct Object *ob, void *data); diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index d2ca304e973..68392bf0d03 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -1056,6 +1056,72 @@ bool BKE_collection_child_remove(Main *bmain, Collection *parent, Collection *ch return true; } +/** + * Rebuild parent relationships from child ones, for all children of given \a collection. + * + * \note Given collection is assumed to already have valid parents. + */ +void BKE_collection_parent_relations_rebuild(Collection *collection) +{ + for (CollectionChild *child = collection->children.first, *child_next = NULL; child; + child = child_next) { + child_next = child->next; + + if (child->collection == NULL || BKE_collection_find_cycle(collection, child->collection)) { + BLI_freelinkN(&collection->children, child); + } + else { + CollectionParent *cparent = MEM_callocN(sizeof(CollectionParent), __func__); + cparent->collection = collection; + BLI_addtail(&child->collection->parents, cparent); + } + } +} + +static void collection_parents_rebuild_recursive(Collection *collection) +{ + BKE_collection_parent_relations_rebuild(collection); + collection->id.tag &= ~LIB_TAG_DOIT; + + for (CollectionChild *child = collection->children.first; child != NULL; child = child->next) { + collection_parents_rebuild_recursive(child->collection); + } +} + +/** + * Rebuild parent relationships from child ones, for all collections in given \a bmain. + * + * \note Uses LIB_TAG_DOIT internally... + */ +void BKE_main_collections_parent_relations_rebuild(Main *bmain) +{ + /* Only collections not in bmain (master ones in scenes) have no parent... */ + for (Collection *collection = bmain->collections.first; collection != NULL; + collection = collection->id.next) { + BLI_freelistN(&collection->parents); + + collection->id.tag |= LIB_TAG_DOIT; + } + + /* Scene's master collections will be 'root' parent of most of our collections, so start with + * them. */ + for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) { + collection_parents_rebuild_recursive(scene->master_collection); + } + + /* We may have parent chains outside of scene's master_collection context? At least, readfile's + * lib_link_collection_data() seems to assume that, so do the same here. */ + for (Collection *collection = bmain->collections.first; collection != NULL; + collection = collection->id.next) { + if (collection->id.tag & LIB_TAG_DOIT) { + /* Note: we do not have easy access to 'which collections is root' info in that case, which + * means test for cycles in collection relationships may fail here. I don't think that is an + * issue in practice here, but worth keeping in mind... */ + collection_parents_rebuild_recursive(collection); + } + } +} + /********************** Collection index *********************/ static Collection *collection_from_index_recursive(Collection *collection, |