diff options
Diffstat (limited to 'source/blender/blenkernel/intern')
21 files changed, 1338 insertions, 2192 deletions
diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c index b0c571bf159..7b149761952 100644 --- a/source/blender/blenkernel/intern/blender_copybuffer.c +++ b/source/blender/blenkernel/intern/blender_copybuffer.c @@ -98,7 +98,7 @@ bool BKE_copybuffer_read(Main *bmain_dst, const char *libname, ReportList *repor /* Here appending/linking starts. */ Main *mainl = BLO_library_link_begin(bmain_dst, &bh, libname); BLO_library_link_copypaste(mainl, bh); - BLO_library_link_end(mainl, &bh, 0, NULL, NULL); + BLO_library_link_end(mainl, &bh, 0, NULL, NULL, NULL); /* Mark all library linked objects to be updated. */ BKE_main_lib_objects_recalc_all(bmain_dst); IMB_colormanagement_check_file_config(bmain_dst); @@ -145,7 +145,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re BLO_library_link_copypaste(mainl, bh); - BLO_library_link_end(mainl, &bh, flag, scene, view_layer); + BLO_library_link_end(mainl, &bh, flag, bmain, scene, view_layer); /* mark all library linked objects to be updated */ BKE_main_lib_objects_recalc_all(bmain); diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 4303f7d9150..5ba4a1196b8 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -31,15 +31,17 @@ #include "BLI_iterator.h" #include "BLI_listbase.h" #include "BLI_math_base.h" +#include "BLI_threads.h" #include "BLT_translation.h" #include "BLI_string_utils.h" #include "BKE_collection.h" -#include "BKE_group.h" +#include "BKE_icons.h" #include "BKE_idprop.h" #include "BKE_layer.h" #include "BKE_library.h" #include "BKE_main.h" +#include "BKE_object.h" #include "BKE_scene.h" #include "DNA_group_types.h" @@ -48,412 +50,573 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + #include "MEM_guardedalloc.h" -/* Prototypes. */ -static SceneCollection *find_collection_parent(const struct SceneCollection *sc_child, struct SceneCollection *sc_parent); -static bool is_collection_in_tree(const struct SceneCollection *sc_reference, struct SceneCollection *sc_parent); +/******************************** Prototypes ********************************/ -static SceneCollection *collection_master_from_id(const ID *owner_id) -{ - switch (GS(owner_id->name)) { - case ID_SCE: - return ((Scene *)owner_id)->collection; - case ID_GR: - return ((Group *)owner_id)->collection; - default: - BLI_assert(!"ID doesn't support collections"); - return NULL; - } -} +static bool collection_child_add(Collection *parent, Collection *collection, int flag, const bool add_us); +static bool collection_child_remove(Collection *parent, Collection *collection); +static bool collection_object_add(Collection *collection, Object *ob, int flag, const bool add_us); +static bool collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us); -/** - * The automatic/fallback name of a new collection. - */ -void BKE_collection_new_name_get(ID *owner_id, SceneCollection *sc_parent, char *rname) -{ - SceneCollection *sc_master = collection_master_from_id(owner_id); - char *name; +static CollectionChild *collection_find_child(Collection *parent, Collection *collection); +static CollectionParent *collection_find_parent(Collection *child, Collection *collection); - if (sc_parent == sc_master) { - name = BLI_sprintfN("Collection %d", BLI_listbase_count(&sc_master->scene_collections) + 1); - } - else { - const int number = BLI_listbase_count(&sc_parent->scene_collections) + 1; - const int digits = integer_digits_i(number); - const int max_len = sizeof(sc_parent->name) - 1 /* NULL terminator */ - (1 + digits) /* " %d" */; - name = BLI_sprintfN("%.*s %d", max_len, sc_parent->name, number); - } +static bool collection_find_child_recursive(Collection *parent, Collection *collection); - BLI_strncpy(rname, name, MAX_NAME); - MEM_freeN(name); -} +/***************************** Add Collection *******************************/ -/** - * Add a new collection, but don't handle syncing with layer collections - */ -static SceneCollection *collection_add(ID *owner_id, SceneCollection *sc_parent, const int type, const char *name_custom) +/* Add new collection, without view layer syncing. */ +static Collection *collection_add(Main *bmain, Collection *collection_parent, const char *name_custom) { - SceneCollection *sc_master = collection_master_from_id(owner_id); - SceneCollection *sc = MEM_callocN(sizeof(SceneCollection), "New Collection"); - sc->type = type; + /* Determine new collection name. */ char name[MAX_NAME]; - if (!sc_parent) { - sc_parent = sc_master; - } - - if (name_custom != NULL) { - BLI_strncpy(name, name_custom, MAX_NAME); + if (name_custom) { + STRNCPY(name, name_custom); } else { - BKE_collection_new_name_get(owner_id, sc_parent, name); + BKE_collection_new_name_get(collection_parent, name); } - BLI_addtail(&sc_parent->scene_collections, sc); - BKE_collection_rename(owner_id, sc, name); + /* Create new collection. */ + Collection *collection = BKE_libblock_alloc(bmain, ID_GR, name, 0); + + /* We increase collection user count when linking to Collections. */ + id_us_min(&collection->id); + + /* Optionally add to parent collection. */ + if (collection_parent) { + collection_child_add(collection_parent, collection, 0, true); + } - return sc; + return collection; } /** * Add a collection to a collection ListBase and syncronize all render layers * The ListBase is NULL when the collection is to be added to the master collection */ -SceneCollection *BKE_collection_add(ID *owner_id, SceneCollection *sc_parent, const int type, const char *name_custom) +Collection *BKE_collection_add(Main *bmain, Collection *collection_parent, const char *name_custom) { - if (sc_parent == NULL) { - sc_parent = BKE_collection_master(owner_id); - } + Collection *collection = collection_add(bmain, collection_parent, name_custom); + BKE_main_collection_sync(bmain); + return collection; +} - SceneCollection *scene_collection = collection_add(owner_id, sc_parent, type, name_custom); - BKE_layer_sync_new_scene_collection(owner_id, sc_parent, scene_collection); - return scene_collection; +/*********************** Free and Delete Collection ****************************/ + +/** Free (or release) any data used by this collection (does not free the collection itself). */ +void BKE_collection_free(Collection *collection) +{ + /* No animdata here. */ + BKE_previewimg_free(&collection->preview); + + BLI_freelistN(&collection->gobject); + BLI_freelistN(&collection->children); + BLI_freelistN(&collection->parents); + + BKE_collection_object_cache_free(collection); } /** - * Free the collection items recursively + * Remove a collection, optionally removing its child objects or moving + * them to parent collections. */ -static void collection_free(SceneCollection *sc, const bool do_id_user) +bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy) { - if (do_id_user) { - for (LinkData *link = sc->objects.first; link; link = link->next) { - id_us_min(link->data); + /* Master collection is not real datablock, can't be removed. */ + if (collection->flag & COLLECTION_IS_MASTER) { + BLI_assert("!Scene master collection can't be deleted"); + return false; + } + + if (hierarchy) { + /* Remove child objects. */ + CollectionObject *cob = collection->gobject.first; + while (cob != NULL) { + collection_object_remove(bmain, collection, cob->ob, true); + cob = collection->gobject.first; + } + + /* Delete all child collections recursively. */ + CollectionChild *child = collection->children.first; + while (child != NULL) { + BKE_collection_delete(bmain, child->collection, hierarchy); + child = collection->children.first; } } + else { + /* Link child collections into parent collection. */ + for (CollectionChild *child = collection->children.first; child; child = child->next) { + for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) { + Collection *parent = cparent->collection; + collection_child_add(parent, child->collection, 0, true); + } + } - BLI_freelistN(&sc->objects); + CollectionObject *cob = collection->gobject.first; + while (cob != NULL) { + /* Link child object into parent collections. */ + for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) { + Collection *parent = cparent->collection; + collection_object_add(parent, cob->ob, 0, true); + } - for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { - collection_free(nsc, do_id_user); + /* Remove child object. */ + collection_object_remove(bmain, collection, cob->ob, true); + cob = collection->gobject.first; + } } - BLI_freelistN(&sc->scene_collections); + + BKE_libblock_delete(bmain, collection); + + BKE_main_collection_sync(bmain); + + return true; } +/***************************** Collection Copy *******************************/ + /** - * Unlink the collection recursively - * \return true if unlinked. + * Only copy internal data of Collection ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). */ -static bool collection_remlink(SceneCollection *sc_parent, SceneCollection *sc_gone) +void BKE_collection_copy_data(Main *UNUSED(bmain), Collection *collection_dst, const Collection *collection_src, const int flag) { - for (SceneCollection *sc = sc_parent->scene_collections.first; sc; sc = sc->next) { - if (sc == sc_gone) { - BLI_remlink(&sc_parent->scene_collections, sc_gone); - return true; - } + /* Do not copy collection's preview (same behavior as for objects). */ + if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */ + BKE_previewimg_id_copy(&collection_dst->id, &collection_src->id); + } + else { + collection_dst->preview = NULL; + } - if (collection_remlink(sc, sc_gone)) { - return true; - } + collection_dst->flag &= ~COLLECTION_HAS_OBJECT_CACHE; + BLI_listbase_clear(&collection_dst->object_cache); + + BLI_listbase_clear(&collection_dst->gobject); + BLI_listbase_clear(&collection_dst->children); + BLI_listbase_clear(&collection_dst->parents); + + for (CollectionChild *child = collection_src->children.first; child; child = child->next) { + collection_child_add(collection_dst, child->collection, flag, false); + } + for (CollectionObject *cob = collection_src->gobject.first; cob; cob = cob->next) { + collection_object_add(collection_dst, cob->ob, flag, false); } - return false; } /** - * Recursively remove any instance of this SceneCollection + * Makes a shallow copy of a Collection + * + * Add a new collection in the same level as the old one, copy any nested collections + * but link the objects to the new collection (as oppose to copy them). */ -static void layer_collection_remove(ViewLayer *view_layer, ListBase *lb, const SceneCollection *sc) -{ - LayerCollection *lc = lb->first; - while (lc) { - if (lc->scene_collection == sc) { - BKE_layer_collection_free(view_layer, lc); - BLI_remlink(lb, lc); - - LayerCollection *lc_next = lc->next; - MEM_freeN(lc); - lc = lc_next; - - /* only the "top-level" layer collections may have the - * same SceneCollection in a sibling tree. - */ - if (lb != &view_layer->layer_collections) { - return; - } - } +Collection *BKE_collection_copy(Main *bmain, Collection *parent, Collection *collection) +{ + /* It's not allowed to copy the master collection. */ + if (collection->flag & COLLECTION_IS_MASTER) { + BLI_assert("!Master collection can't be copied"); + return NULL; + } - else { - layer_collection_remove(view_layer, &lc->layer_collections, sc); - lc = lc->next; + Collection *collection_new; + BKE_id_copy_ex(bmain, &collection->id, (ID **)&collection_new, 0, false); + + /* Optionally add to parent. */ + if (parent) { + if (collection_child_add(parent, collection_new, 0, true)) { + /* Put collection right after existing one. */ + CollectionChild *child = collection_find_child(parent, collection); + CollectionChild *child_new = collection_find_child(parent, collection_new); + + if (child && child_new) { + BLI_remlink(&parent->children, child_new); + BLI_insertlinkafter(&parent->children, child, child_new); + } } } + + BKE_main_collection_sync(bmain); + + return collection_new; } +Collection *BKE_collection_copy_master(Main *bmain, Collection *collection, const int flag) +{ + BLI_assert(collection->flag & COLLECTION_IS_MASTER); + + Collection *collection_dst = MEM_dupallocN(collection); + BKE_collection_copy_data(bmain, collection_dst, collection, flag); + return collection_dst; +} + +void BKE_collection_copy_full(Main *UNUSED(bmain), Collection *UNUSED(collection)) +{ + // TODO: implement full scene copy +} + +void BKE_collection_make_local(Main *bmain, Collection *collection, const bool lib_local) +{ + BKE_id_make_local_generic(bmain, &collection->id, true, lib_local); +} + +/********************************* Naming *******************************/ + /** - * Remove a collection from the scene, and syncronize all render layers - * - * If an object is in any other collection, link the object to the master collection. + * The automatic/fallback name of a new collection. */ -bool BKE_collection_remove(ID *owner_id, SceneCollection *sc) +void BKE_collection_new_name_get(Collection *collection_parent, char *rname) { - SceneCollection *sc_master = collection_master_from_id(owner_id); + char *name; - /* The master collection cannot be removed. */ - if (sc == sc_master) { - return false; + if (!collection_parent) { + name = BLI_sprintfN("Collection"); } - - /* We need to do bottom up removal, otherwise we get a crash when we remove a collection that - * has one of its nested collections linked to a view layer. */ - SceneCollection *scene_collection_nested = sc->scene_collections.first; - while (scene_collection_nested != NULL) { - SceneCollection *scene_collection_next = scene_collection_nested->next; - BKE_collection_remove(owner_id, scene_collection_nested); - scene_collection_nested = scene_collection_next; + else if (collection_parent->flag & COLLECTION_IS_MASTER) { + name = BLI_sprintfN("Collection %d", BLI_listbase_count(&collection_parent->children) + 1); } - - /* Unlink from the respective collection tree. */ - if (!collection_remlink(sc_master, sc)) { - BLI_assert(false); + else { + const int number = BLI_listbase_count(&collection_parent->children) + 1; + const int digits = integer_digits_i(number); + const int max_len = sizeof(collection_parent->id.name) - 1 /* NULL terminator */ - (1 + digits) /* " %d" */ - 2 /* ID */; + name = BLI_sprintfN("%.*s %d", max_len, collection_parent->id.name + 2, number); } - /* If an object is no longer in any collection, we add it to the master collection. */ - ListBase collection_objects; - BLI_duplicatelist(&collection_objects, &sc->objects); + BLI_strncpy(rname, name, MAX_NAME); + MEM_freeN(name); +} - FOREACH_SCENE_COLLECTION_BEGIN(owner_id, scene_collection_iter) +/************************* Dependencies ****************************/ + +bool BKE_collection_is_animated(Collection *collection, Object *UNUSED(parent)) +{ + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, object) { - if (scene_collection_iter == sc) { - continue; + if (object->proxy) { + return true; } + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + return false; +} - LinkData *link_next, *link = collection_objects.first; - while (link) { - link_next = link->next; +/* puts all collection members in local timing system, after this call + * you can draw everything, leaves tags in objects to signal it needs further updating */ - if (BLI_findptr(&scene_collection_iter->objects, link->data, offsetof(LinkData, data))) { - BLI_remlink(&collection_objects, link); - MEM_freeN(link); - } - - link = link_next; +/* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */ +void BKE_collection_handle_recalc_and_update(struct Depsgraph *depsgraph, Scene *scene, Object *UNUSED(parent), Collection *collection) +{ + /* only do existing tags, as set by regular depsgraph */ + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, object) + { + if (object->id.recalc & ID_RECALC_ALL) { + BKE_object_handle_update(depsgraph, scene, object); } } - FOREACH_SCENE_COLLECTION_END; - - for (LinkData *link = collection_objects.first; link; link = link->next) { - BKE_collection_object_add(owner_id, sc_master, link->data); + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } - BLI_freelistN(&collection_objects); +/* **************** Object List Cache *******************/ + +static void collection_object_cache_fill(ListBase *lb, Collection *collection, int parent_restrict) +{ + int child_restrict = collection->flag | parent_restrict; + + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + Base *base = BLI_findptr(lb, cob->ob, offsetof(Base, object)); + + if (base == NULL) { + base = MEM_callocN(sizeof(Base), "Object Base"); + base->object = cob->ob; - /* Clear the collection items. */ - collection_free(sc, true); + if ((child_restrict & COLLECTION_RESTRICT_VIEW) == 0) { + base->flag |= BASE_VISIBLED | BASE_VISIBLE_VIEWPORT; - /* check all layers that use this collection and clear them */ - for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { - layer_collection_remove(view_layer, &view_layer->layer_collections, sc); - view_layer->active_collection = 0; + if ((child_restrict & COLLECTION_RESTRICT_SELECT) == 0) { + base->flag |= BASE_SELECTABLED; + } + } + + if ((child_restrict & COLLECTION_RESTRICT_RENDER) == 0) { + base->flag |= BASE_VISIBLE_RENDER; + } + + BLI_addtail(lb, base); + } } - MEM_freeN(sc); - return true; + for (CollectionChild *child = collection->children.first; child; child = child->next) { + collection_object_cache_fill(lb, child->collection, child_restrict); + } } -/** - * Copy SceneCollection tree but keep pointing to the same objects - * - * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). - */ -void BKE_collection_copy_data(SceneCollection *sc_dst, SceneCollection *sc_src, const int flag) +ListBase BKE_collection_object_cache_get(Collection *collection) { - BLI_duplicatelist(&sc_dst->objects, &sc_src->objects); - if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { - for (LinkData *link = sc_dst->objects.first; link; link = link->next) { - id_us_plus(link->data); + if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) { + static ThreadMutex cache_lock = BLI_MUTEX_INITIALIZER; + + if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) { + BLI_mutex_lock(&cache_lock); + collection_object_cache_fill(&collection->object_cache, collection, 0); + collection->flag |= COLLECTION_HAS_OBJECT_CACHE; + BLI_mutex_unlock(&cache_lock); } } - BLI_duplicatelist(&sc_dst->scene_collections, &sc_src->scene_collections); - for (SceneCollection *nsc_src = sc_src->scene_collections.first, *nsc_dst = sc_dst->scene_collections.first; - nsc_src; - nsc_src = nsc_src->next, nsc_dst = nsc_dst->next) - { - BKE_collection_copy_data(nsc_dst, nsc_src, flag); - } + return collection->object_cache; } -/** - * Makes a shallow copy of a SceneCollection - * - * Add a new collection in the same level as the old one, copy any nested collections - * but link the objects to the new collection (as oppose to copy them). - */ -SceneCollection *BKE_collection_duplicate(ID *owner_id, SceneCollection *scene_collection) +static void collection_object_cache_free(Collection *collection) { - SceneCollection *scene_collection_master = BKE_collection_master(owner_id); - SceneCollection *scene_collection_parent = find_collection_parent(scene_collection, scene_collection_master); + /* Clear own cache an for all parents, since those are affected by changes as well. */ + collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE; + BLI_freelistN(&collection->object_cache); - /* It's not allowed to copy the master collection. */ - if (scene_collection_master == scene_collection) { - return NULL; + for (CollectionParent *parent = collection->parents.first; parent; parent = parent->next) { + collection_object_cache_free(parent->collection); } +} + +void BKE_collection_object_cache_free(Collection *collection) +{ + collection_object_cache_free(collection); +} + +Base *BKE_collection_or_layer_objects(Depsgraph *depsgraph, + const Scene *scene, + const ViewLayer *view_layer, + Collection *collection) +{ + // TODO: this is used by physics to get objects from a collection, but the + // the physics systems are not all using the depsgraph correctly which means + // we try different things. Instead we should explicitly get evaluated or + // non-evaluated data and always have the depsgraph available when needed - SceneCollection *scene_collection_new = collection_add( - owner_id, - scene_collection_parent, - scene_collection->type, - scene_collection->name); + if (collection) { + return BKE_collection_object_cache_get(collection).first; + } + else if (depsgraph) { + view_layer = DEG_get_evaluated_view_layer(depsgraph); - if (scene_collection_new != scene_collection->next) { - BLI_remlink(&scene_collection_parent->scene_collections, scene_collection_new); - BLI_insertlinkafter(&scene_collection_parent->scene_collections, scene_collection, scene_collection_new); + if (view_layer) { + return FIRSTBASE(view_layer); + } + else { + view_layer = DEG_get_input_view_layer(depsgraph); + return FIRSTBASE(view_layer); + } + } + else if (view_layer) { + return FIRSTBASE(view_layer); + } + else { + /* depsgraph is NULL during deg build */ + return FIRSTBASE(BKE_view_layer_context_active_PLACEHOLDER(scene)); } +} - BKE_collection_copy_data(scene_collection_new, scene_collection, 0); - BKE_layer_sync_new_scene_collection(owner_id, scene_collection_parent, scene_collection_new); +/*********************** Scene Master Collection ***************/ - /* Make sure every linked instance of the new collection has the same values (flags, overrides, ...) as the - * corresponding original collection. */ - BKE_layer_collection_sync_flags(owner_id, scene_collection_new, scene_collection); +Collection *BKE_collection_master_add() +{ + /* Not an actual datablock, but owned by scene. */ + Collection *master_collection = MEM_callocN(sizeof(Collection), "Master Collection"); + STRNCPY(master_collection->id.name, "GRMaster Collection"); + master_collection->flag |= COLLECTION_IS_MASTER; + return master_collection; +} - return scene_collection_new; +Collection *BKE_collection_master(const Scene *scene) +{ + return scene->master_collection; } -static SceneCollection *master_collection_from_id(const ID *owner_id) +/*********************** Cyclic Checks ************************/ + +static bool collection_object_cyclic_check_internal(Object *object, Collection *collection) { - switch (GS(owner_id->name)) { - case ID_SCE: - return ((const Scene *)owner_id)->collection; - case ID_GR: - return ((const Group *)owner_id)->collection; - default: - BLI_assert(!"ID doesn't support scene collection"); - return NULL; + if (object->dup_group) { + Collection *dup_collection = object->dup_group; + if ((dup_collection->id.tag & LIB_TAG_DOIT) == 0) { + /* Cycle already exists in collections, let's prevent further crappyness */ + return true; + } + /* flag the object to identify cyclic dependencies in further dupli collections */ + dup_collection->id.tag &= ~LIB_TAG_DOIT; + + if (dup_collection == collection) { + return true; + } + else { + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(dup_collection, collection_object) + { + if (collection_object_cyclic_check_internal(collection_object, dup_collection)) { + return true; + } + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + } + + /* un-flag the object, it's allowed to have the same collection multiple times in parallel */ + dup_collection->id.tag |= LIB_TAG_DOIT; } + + return false; } -/** - * Returns the master collection of the scene or group - */ -SceneCollection *BKE_collection_master(const ID *owner_id) +bool BKE_collection_object_cyclic_check(Main *bmain, Object *object, Collection *collection) { - return master_collection_from_id(owner_id); + /* first flag all collections */ + BKE_main_id_tag_listbase(&bmain->collection, LIB_TAG_DOIT, true); + + return collection_object_cyclic_check_internal(object, collection); } -static void collection_rename(const ID *owner_id, SceneCollection *sc, const char *name) +/******************* Collection Object Membership *******************/ + +bool BKE_collection_has_object(Collection *collection, Object *ob) { - SceneCollection *sc_parent = find_collection_parent(sc, collection_master_from_id(owner_id)); - BLI_strncpy(sc->name, name, sizeof(sc->name)); - BLI_uniquename(&sc_parent->scene_collections, sc, DATA_("Collection"), '.', offsetof(SceneCollection, name), sizeof(sc->name)); + if (ELEM(NULL, collection, ob)) { + return false; + } + + return (BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob))); } -void BKE_collection_rename(const ID *owner_id, SceneCollection *sc, const char *name) +bool BKE_collection_has_object_recursive(Collection *collection, Object *ob) { - collection_rename(owner_id, sc, name); + if (ELEM(NULL, collection, ob)) { + return false; + } + + const ListBase objects = BKE_collection_object_cache_get(collection); + return (BLI_findptr(&objects, ob, offsetof(Base, object))); } -/** - * Make sure the collection name is still unique within its siblings. - */ -static void collection_name_check(const ID *owner_id, SceneCollection *sc) +Collection *BKE_collection_object_find(Main *bmain, Collection *collection, Object *ob) { - /* It's a bit of a hack, we simply try to make sure the collection name is valid. */ - collection_rename(owner_id, sc, sc->name); + if (collection) + collection = collection->id.next; + else + collection = bmain->collection.first; + + while (collection) { + if (BKE_collection_has_object(collection, ob)) + return collection; + collection = collection->id.next; + } + return NULL; } -/** - * Free (or release) any data used by the master collection (does not free the master collection itself). - * Used only to clear the entire scene or group data since it's not doing re-syncing of the LayerCollection tree - */ -void BKE_collection_master_free(ID *owner_id, const bool do_id_user) +/********************** Collection Objects *********************/ + +static bool collection_object_add(Collection *collection, Object *ob, int flag, const bool add_us) { - collection_free(BKE_collection_master(owner_id), do_id_user); + if (ob->dup_group) { + /* Cyclic dependency check. */ + if (collection_find_child_recursive(collection, ob->dup_group)) { + return false; + } + } + + CollectionObject *cob = BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob)); + if (cob) { + return false; + } + + cob = MEM_callocN(sizeof(CollectionObject), __func__); + cob->ob = ob; + BLI_addtail(&collection->gobject, cob); + BKE_collection_object_cache_free(collection); + + if (add_us && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus(&ob->id); + } + + return true; } -static void collection_object_add(const ID *owner_id, SceneCollection *sc, Object *ob) +static bool collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us) { - BLI_addtail(&sc->objects, BLI_genericNodeN(ob)); + CollectionObject *cob = BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob)); + if (cob == NULL) { + return false; + } + + BLI_freelinkN(&collection->gobject, cob); + BKE_collection_object_cache_free(collection); - if (GS(owner_id->name) == ID_SCE) { - id_us_plus((ID *)ob); + if (free_us) { + BKE_libblock_free_us(bmain, ob); } else { - BLI_assert(GS(owner_id->name) == ID_GR); - if ((ob->flag & OB_FROMGROUP) == 0) { - ob->flag |= OB_FROMGROUP; - } + id_us_min(&ob->id); } - BKE_layer_sync_object_link(owner_id, sc, ob); + return true; } /** * Add object to collection */ -bool BKE_collection_object_add(const ID *owner_id, SceneCollection *sc, Object *ob) +bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob) { - if (BKE_collection_object_exists(sc, ob)) { - /* don't add the same object twice */ + if (ELEM(NULL, collection, ob)) { return false; } - collection_object_add(owner_id, sc, ob); + if (!collection_object_add(collection, ob, 0, true)) { + return false; + } + + if (BKE_collection_is_in_scene(collection)) { + BKE_main_collection_sync(bmain); + } + return true; } /** - * Add object to all collections that reference objects is in + * Add object to all scene collections that reference objects is in * (used to copy objects) */ -void BKE_collection_object_add_from(Scene *scene, Object *ob_src, Object *ob_dst) +void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, Object *ob_dst) { - FOREACH_SCENE_COLLECTION_BEGIN(scene, sc) + FOREACH_SCENE_COLLECTION_BEGIN(scene, collection) { - if (BLI_findptr(&sc->objects, ob_src, offsetof(LinkData, data))) { - collection_object_add(&scene->id, sc, ob_dst); + if (BKE_collection_has_object(collection, ob_src)) { + collection_object_add(collection, ob_dst, 0, true); } } FOREACH_SCENE_COLLECTION_END; + + BKE_main_collection_sync(bmain); } /** * Remove object from collection. - * \param bmain: Can be NULL if free_us is false. */ -bool BKE_collection_object_remove(Main *bmain, ID *owner_id, SceneCollection *sc, Object *ob, const bool free_us) +bool BKE_collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us) { - LinkData *link = BLI_findptr(&sc->objects, ob, offsetof(LinkData, data)); - - if (link == NULL) { + if (ELEM(NULL, collection, ob)) { return false; } - BLI_remlink(&sc->objects, link); - MEM_freeN(link); - - BKE_layer_sync_object_unlink(owner_id, sc, ob); - - if (GS(owner_id->name) == ID_SCE) { - if (free_us) { - BKE_libblock_free_us(bmain, ob); - } - else { - id_us_min(&ob->id); - } + if (collection_object_remove(bmain, collection, ob, free_us)) { + return false; } - else { - BLI_assert(GS(owner_id->name) == ID_GR); + + if (BKE_collection_is_in_scene(collection)) { + BKE_main_collection_sync(bmain); } return true; @@ -463,408 +626,436 @@ bool BKE_collection_object_remove(Main *bmain, ID *owner_id, SceneCollection *sc * Remove object from all collections of scene * \param scene_collection_skip: Don't remove base from this collection. */ -static bool collections_object_remove_ex(Main *bmain, ID *owner_id, Object *ob, const bool free_us, - SceneCollection *scene_collection_skip) +static bool scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us, + Collection *collection_skip) { bool removed = false; - if (GS(owner_id->name) == ID_SCE) { - BKE_scene_remove_rigidbody_object((Scene *)owner_id, ob); - } - else { - BLI_assert(GS(owner_id->name) == ID_GR); - } - FOREACH_SCENE_COLLECTION_BEGIN(owner_id, sc) + BKE_scene_remove_rigidbody_object(scene, ob); + + FOREACH_SCENE_COLLECTION_BEGIN(scene, collection) { - if (sc != scene_collection_skip) { - removed |= BKE_collection_object_remove(bmain, owner_id, sc, ob, free_us); + if (collection != collection_skip) { + removed |= collection_object_remove(bmain, collection, ob, free_us); } } FOREACH_SCENE_COLLECTION_END; + + BKE_main_collection_sync(bmain); + return removed; } /** * Remove object from all collections of scene */ -bool BKE_collections_object_remove(Main *bmain, ID *owner_id, Object *ob, const bool free_us) +bool BKE_scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us) { - return collections_object_remove_ex(bmain, owner_id, ob, free_us, NULL); + return scene_collections_object_remove(bmain, scene, ob, free_us, NULL); } -/** - * Move object from a collection into another - * - * If source collection is NULL move it from all the existing collections. +/* + * Remove all NULL objects from non-scene collections. + * This is used for library remapping, where these pointers have been set to NULL. + * Otherwise this should never happen. */ -void BKE_collection_object_move(ID *owner_id, SceneCollection *sc_dst, SceneCollection *sc_src, Object *ob) +void BKE_collections_object_remove_nulls(Main *bmain) { - /* In both cases we first add the object, then remove it from the other collections. - * Otherwise we lose the original base and whether it was active and selected. */ - if (sc_src != NULL) { - if (BKE_collection_object_add(owner_id, sc_dst, ob)) { - BKE_collection_object_remove(NULL, owner_id, sc_src, ob, false); + 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; + + if (cob->ob == NULL) { + BLI_freelinkN(&collection->gobject, cob); + changed = true; + } + } + + if (changed) { + BKE_collection_object_cache_free(collection); + } } } - else { - /* Adding will fail if object is already in collection. - * However we still need to remove it from the other collections. */ - BKE_collection_object_add(owner_id, sc_dst, ob); - collections_object_remove_ex(NULL, owner_id, ob, false, sc_dst); - } } -/** - * Whether the object is directly inside the collection. +/* + * Remove all NULL children from parent objects of changed old_collection. + * This is used for library remapping, where these pointers have been set to NULL. + * Otherwise this should never happen. */ -bool BKE_collection_object_exists(struct SceneCollection *scene_collection, struct Object *ob) +void BKE_collections_child_remove_nulls(Main *bmain, Collection *old_collection) { - if (BLI_findptr(&scene_collection->objects, ob, offsetof(LinkData, data))) { - return true; - } - return false; -} + bool changed = false; -static SceneCollection *scene_collection_from_index_recursive(SceneCollection *scene_collection, const int index, int *index_current) -{ - if (index == (*index_current)) { - return scene_collection; + 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); + } } - (*index_current)++; + for (CollectionParent *cparent = old_collection->parents.first; cparent; cparent = cparent->next) { + Collection *parent = cparent->collection; - for (SceneCollection *scene_collection_iter = scene_collection->scene_collections.first; - scene_collection_iter != NULL; - scene_collection_iter = scene_collection_iter->next) - { - SceneCollection *nested = scene_collection_from_index_recursive(scene_collection_iter, index, index_current); - if (nested != NULL) { - return nested; + for (CollectionChild *child = parent->children.first, *child_next = NULL; child; child = child_next) { + child_next = child->next; + + if (child->collection == NULL) { + BLI_freelinkN(&parent->children, child); + changed = true; + } } } - return NULL; -} -/** - * Return Scene Collection for a given index. - * - * The index is calculated from top to bottom counting the children before the siblings. - */ -SceneCollection *BKE_collection_from_index(Scene *scene, const int index) -{ - int index_current = 0; - SceneCollection *master_collection = BKE_collection_master(&scene->id); - return scene_collection_from_index_recursive(master_collection, index, &index_current); -} + BLI_freelistN(&old_collection->parents); -static void layer_collection_sync(LayerCollection *lc_dst, LayerCollection *lc_src) -{ - lc_dst->flag = lc_src->flag; - - /* Continue recursively. */ - LayerCollection *lc_dst_nested, *lc_src_nested; - lc_src_nested = lc_src->layer_collections.first; - for (lc_dst_nested = lc_dst->layer_collections.first; - lc_dst_nested && lc_src_nested; - lc_dst_nested = lc_dst_nested->next, lc_src_nested = lc_src_nested->next) - { - layer_collection_sync(lc_dst_nested, lc_src_nested); + if (changed) { + BKE_main_collection_sync(bmain); } } /** - * Select all the objects in this SceneCollection (and its nested collections) for this ViewLayer. - * Return true if any object was selected. + * Move object from a collection into another + * + * If source collection is NULL move it from all the existing collections. */ -bool BKE_collection_objects_select(ViewLayer *view_layer, SceneCollection *scene_collection) +void BKE_collection_object_move(Main *bmain, Scene *scene, Collection *collection_dst, Collection *collection_src, Object *ob) { - LayerCollection *layer_collection = BKE_layer_collection_first_from_scene_collection(view_layer, scene_collection); - if (layer_collection != NULL) { - BKE_layer_collection_objects_select(layer_collection); - return true; + /* In both cases we first add the object, then remove it from the other collections. + * Otherwise we lose the original base and whether it was active and selected. */ + if (collection_src != NULL) { + if (BKE_collection_object_add(bmain, collection_dst, ob)) { + BKE_collection_object_remove(bmain, collection_src, ob, false); + } } else { - /* Slower approach, we need to iterate over all the objects and for each one we see if there is a base. */ - bool changed = false; - for (LinkData *link = scene_collection->objects.first; link; link = link->next) { - Base *base = BKE_view_layer_base_find(view_layer, link->data); - if (base != NULL) { - if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLED) != 0)) { - base->flag |= BASE_SELECTED; - changed = true; - } - } - } - return changed; + /* Adding will fail if object is already in collection. + * However we still need to remove it from the other collections. */ + BKE_collection_object_add(bmain, collection_dst, ob); + scene_collections_object_remove(bmain, scene, ob, false, collection_dst); } } -/** - * Leave only the master collection in, remove everything else. - * @param group - */ -static void collection_group_cleanup(Group *group) +/***************** Collection Scene Membership ****************/ + +bool BKE_collection_is_in_scene(Collection *collection) { - /* Unlink all the LayerCollections. */ - while (group->view_layer->layer_collections.last != NULL) { - BKE_collection_unlink(group->view_layer, group->view_layer->layer_collections.last); + if (collection->flag & COLLECTION_IS_MASTER) { + return true; + } + + for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) { + if (BKE_collection_is_in_scene(cparent->collection)) { + return true; + } } - /* Remove all the SceneCollections but the master. */ - collection_free(group->collection, false); + return false; } -/** - * Create a group from a collection - * - * Any ViewLayer that may have this the related SceneCollection linked is converted - * to a Group Collection. - */ -Group *BKE_collection_group_create(Main *bmain, Scene *scene, LayerCollection *lc_src) +void BKE_collections_after_lib_link(Main *bmain) { - SceneCollection *sc_dst, *sc_src = lc_src->scene_collection; - LayerCollection *lc_dst; + /* Update view layer collections to match any changes in linked + * collections after file load. */ + BKE_main_collection_sync(bmain); +} - /* The master collection can't be converted. */ - if (sc_src == BKE_collection_master(&scene->id)) { - return NULL; - } +/********************** Collection Children *******************/ - /* If a sub-collection of sc_dst is directly linked into a ViewLayer we can't convert. */ - for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { - for (LayerCollection *lc_child = view_layer->layer_collections.first; lc_child; lc_child = lc_child->next) { - if (is_collection_in_tree(lc_child->scene_collection, sc_src)) { - return NULL; - } - } +bool BKE_collection_find_cycle(Collection *new_ancestor, Collection *collection) +{ + if (collection == new_ancestor) { + return true; } - /* Create new group with the same data as the original collection. */ - Group *group = BKE_group_add(bmain, sc_src->name); - collection_group_cleanup(group); - - sc_dst = BKE_collection_add(&group->id, NULL, COLLECTION_TYPE_GROUP_INTERNAL, sc_src->name); - BKE_collection_copy_data(sc_dst, sc_src, 0); - FOREACH_SCENE_COLLECTION_BEGIN(&group->id, sc_group) - { - sc_group->type = COLLECTION_TYPE_GROUP_INTERNAL; + for (CollectionParent *parent = new_ancestor->parents.first; parent; parent = parent->next) { + if (BKE_collection_find_cycle(parent->collection, collection)) { + return true; + } } - FOREACH_SCENE_COLLECTION_END; - lc_dst = BKE_collection_link(group->view_layer, sc_dst); - layer_collection_sync(lc_dst, lc_src); - - return group; + return false; } -/* ---------------------------------------------------------------------- */ -/* Outliner drag and drop */ +static CollectionChild *collection_find_child(Collection *parent, Collection *collection) +{ + return BLI_findptr(&parent->children, collection, offsetof(CollectionChild, collection)); +} -/** - * Find and return the SceneCollection that has \a sc_child as one of its directly - * nested SceneCollection. - * - * \param sc_parent Initial SceneCollection to look into recursively, usually the master collection - */ -static SceneCollection *find_collection_parent(const SceneCollection *sc_child, SceneCollection *sc_parent) +static bool collection_find_child_recursive(Collection *parent, Collection *collection) { - for (SceneCollection *sc_nested = sc_parent->scene_collections.first; sc_nested; sc_nested = sc_nested->next) { - if (sc_nested == sc_child) { - return sc_parent; + for (CollectionChild *child = parent->children.first; child; child = child->next) { + if (child->collection == collection) { + return true; } - SceneCollection *found = find_collection_parent(sc_child, sc_nested); - if (found) { - return found; + if (collection_find_child_recursive(child->collection, collection)) { + return true; } } - return NULL; + return false; } -/** - * Check if \a sc_reference is nested to \a sc_parent SceneCollection - */ -static bool is_collection_in_tree(const SceneCollection *sc_reference, SceneCollection *sc_parent) +static CollectionParent *collection_find_parent(Collection *child, Collection *collection) { - return find_collection_parent(sc_reference, sc_parent) != NULL; + return BLI_findptr(&child->parents, collection, offsetof(CollectionParent, collection)); } -bool BKE_collection_move_above(const ID *owner_id, SceneCollection *sc_dst, SceneCollection *sc_src) +static bool collection_child_add(Collection *parent, Collection *collection, const int flag, const bool add_us) { - /* Find the SceneCollection the sc_src belongs to */ - SceneCollection *sc_master = master_collection_from_id(owner_id); - - /* Master Layer can't be moved around*/ - if (ELEM(sc_master, sc_src, sc_dst)) { + CollectionChild *child = collection_find_child(parent, collection); + if (child) { return false; } - - /* collection is already where we wanted it to be */ - if (sc_dst->prev == sc_src) { + if (BKE_collection_find_cycle(parent, collection)) { return false; } - /* We can't move a collection fs the destiny collection - * is nested to the source collection */ - if (is_collection_in_tree(sc_dst, sc_src)) { - return false; + child = MEM_callocN(sizeof(CollectionChild), "CollectionChild"); + child->collection = collection; + BLI_addtail(&parent->children, child); + + /* Don't add parent links for depsgraph datablocks, these are not kept in sync. */ + if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) { + CollectionParent *cparent = MEM_callocN(sizeof(CollectionParent), "CollectionParent"); + cparent->collection = parent; + BLI_addtail(&collection->parents, cparent); } - SceneCollection *sc_src_parent = find_collection_parent(sc_src, sc_master); - SceneCollection *sc_dst_parent = find_collection_parent(sc_dst, sc_master); - BLI_assert(sc_src_parent); - BLI_assert(sc_dst_parent); + if (add_us) { + id_us_plus(&collection->id); + } - /* Remove sc_src from its parent */ - BLI_remlink(&sc_src_parent->scene_collections, sc_src); + BKE_collection_object_cache_free(parent); - /* Re-insert it where it belongs */ - BLI_insertlinkbefore(&sc_dst_parent->scene_collections, sc_dst, sc_src); + return true; +} + +static bool collection_child_remove(Collection *parent, Collection *collection) +{ + CollectionChild *child = collection_find_child(parent, collection); + if (child == NULL) { + return false; + } - /* Update the tree */ - BKE_layer_collection_resync(owner_id, sc_src_parent); - BKE_layer_collection_resync(owner_id, sc_dst_parent); + CollectionParent *cparent = collection_find_parent(collection, parent); + BLI_freelinkN(&collection->parents, cparent); + BLI_freelinkN(&parent->children, child); - /* Keep names unique. */ - collection_name_check(owner_id, sc_src); + id_us_min(&collection->id); + + BKE_collection_object_cache_free(parent); return true; } -bool BKE_collection_move_below(const ID *owner_id, SceneCollection *sc_dst, SceneCollection *sc_src) +bool BKE_collection_child_add(Main *bmain, Collection *parent, Collection *child) { - /* Find the SceneCollection the sc_src belongs to */ - SceneCollection *sc_master = master_collection_from_id(owner_id); - - /* Master Layer can't be moved around*/ - if (ELEM(sc_master, sc_src, sc_dst)) { + if (!collection_child_add(parent, child, 0, true)) { return false; } - /* Collection is already where we wanted it to be */ - if (sc_dst->next == sc_src) { - return false; - } + BKE_main_collection_sync(bmain); + return true; +} - /* We can't move a collection if the destiny collection - * is nested to the source collection */ - if (is_collection_in_tree(sc_dst, sc_src)) { +bool BKE_collection_child_remove(Main *bmain, Collection *parent, Collection *child) +{ + if (!collection_child_remove(parent, child)) { return false; } - SceneCollection *sc_src_parent = find_collection_parent(sc_src, sc_master); - SceneCollection *sc_dst_parent = find_collection_parent(sc_dst, sc_master); - BLI_assert(sc_src_parent); - BLI_assert(sc_dst_parent); + BKE_main_collection_sync(bmain); + return true; +} - /* Remove sc_src from its parent */ - BLI_remlink(&sc_src_parent->scene_collections, sc_src); +/********************** Collection index *********************/ - /* Re-insert it where it belongs */ - BLI_insertlinkafter(&sc_dst_parent->scene_collections, sc_dst, sc_src); +static Collection *collection_from_index_recursive(Collection *collection, const int index, int *index_current) +{ + if (index == (*index_current)) { + return collection; + } - /* Update the tree */ - BKE_layer_collection_resync(owner_id, sc_src_parent); - BKE_layer_collection_resync(owner_id, sc_dst_parent); + (*index_current)++; - /* Keep names unique. */ - collection_name_check(owner_id, sc_src); + for (CollectionChild *child = collection->children.first; child; child = child->next) { + Collection *nested = collection_from_index_recursive(child->collection, index, index_current); + if (nested != NULL) { + return nested; + } + } + return NULL; +} - return true; +/** + * Return Scene Collection for a given index. + * + * The index is calculated from top to bottom counting the children before the siblings. + */ +Collection *BKE_collection_from_index(Scene *scene, const int index) +{ + int index_current = 0; + Collection *master_collection = BKE_collection_master(scene); + return collection_from_index_recursive(master_collection, index, &index_current); } -bool BKE_collection_move_into(const ID *owner_id, SceneCollection *sc_dst, SceneCollection *sc_src) +static bool collection_objects_select(ViewLayer *view_layer, Collection *collection, bool deselect) { - /* Find the SceneCollection the sc_src belongs to */ - SceneCollection *sc_master = master_collection_from_id(owner_id); - if (sc_src == sc_master) { + bool changed = false; + + if (collection->flag & COLLECTION_RESTRICT_SELECT) { return false; } - /* We can't move a collection if the destiny collection - * is nested to the source collection */ - if (is_collection_in_tree(sc_dst, sc_src)) { - return false; + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + Base *base = BKE_view_layer_base_find(view_layer, cob->ob); + + if (base) { + if (deselect) { + if (base->flag & BASE_SELECTED) { + base->flag &= ~BASE_SELECTED; + changed = true; + } + } + else { + if ((base->flag & BASE_SELECTABLED) && !(base->flag & BASE_SELECTED)) { + base->flag |= BASE_SELECTED; + changed = true; + } + } + } + } + + for (CollectionChild *child = collection->children.first; child; child = child->next) { + if (collection_objects_select(view_layer, collection, deselect)) { + changed = true; + } } - SceneCollection *sc_src_parent = find_collection_parent(sc_src, sc_master); - BLI_assert(sc_src_parent); + return changed; +} - /* collection is already where we wanted it to be */ - if (sc_dst->scene_collections.last == sc_src) { +/** + * Select all the objects in this Collection (and its nested collections) for this ViewLayer. + * Return true if any object was selected. + */ +bool BKE_collection_objects_select(ViewLayer *view_layer, Collection *collection, bool deselect) +{ + LayerCollection *layer_collection = BKE_layer_collection_first_from_scene_collection(view_layer, collection); + + if (layer_collection != NULL) { + return BKE_layer_collection_objects_select(view_layer, layer_collection, deselect); + } + else { + return collection_objects_select(view_layer, collection, deselect); + } +} + +/***************** Collection move (outliner drag & drop) *********************/ + +bool BKE_collection_move(Main *bmain, + Collection *to_parent, + Collection *from_parent, + Collection *relative, + bool relative_after, + Collection *collection) +{ + if (collection->flag & COLLECTION_IS_MASTER) { return false; } + if (BKE_collection_find_cycle(to_parent, collection)) { + return false; + } + + /* Move to new parent collection */ + if (from_parent) { + collection_child_remove(from_parent, collection); + } + + collection_child_add(to_parent, collection, 0, true); + + /* Move to specified location under parent. */ + if (relative) { + CollectionChild *child = collection_find_child(to_parent, collection); + CollectionChild *relative_child = collection_find_child(to_parent, relative); - /* Remove sc_src from it */ - BLI_remlink(&sc_src_parent->scene_collections, sc_src); + if (relative_child) { + BLI_remlink(&to_parent->children, child); - /* Insert sc_src into sc_dst */ - BLI_addtail(&sc_dst->scene_collections, sc_src); + if (relative_after) { + BLI_insertlinkafter(&to_parent->children, relative_child, child); + } + else { + BLI_insertlinkbefore(&to_parent->children, relative_child, child); + } - /* Update the tree */ - BKE_layer_collection_resync(owner_id, sc_src_parent); - BKE_layer_collection_resync(owner_id, sc_dst); + BKE_collection_object_cache_free(to_parent); + } + } - /* Keep names unique. */ - collection_name_check(owner_id, sc_src); + BKE_main_collection_sync(bmain); return true; } -/* ---------------------------------------------------------------------- */ -/* Iteractors */ +/**************************** Iterators ******************************/ + /* scene collection iteractor */ -typedef struct SceneCollectionsIteratorData { - ID *owner_id; +typedef struct CollectionsIteratorData { + Scene *scene; void **array; int tot, cur; -} SceneCollectionsIteratorData; +} CollectionsIteratorData; -static void scene_collection_callback(SceneCollection *sc, BKE_scene_collections_Cb callback, void *data) +static void scene_collection_callback(Collection *collection, BKE_scene_collections_Cb callback, void *data) { - callback(sc, data); + callback(collection, data); - for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { - scene_collection_callback(nsc, callback, data); + for (CollectionChild *child = collection->children.first; child; child = child->next) { + scene_collection_callback(child->collection, callback, data); } } -static void scene_collections_count(SceneCollection *UNUSED(sc), void *data) +static void scene_collections_count(Collection *UNUSED(collection), void *data) { int *tot = data; (*tot)++; } -static void scene_collections_build_array(SceneCollection *sc, void *data) +static void scene_collections_build_array(Collection *collection, void *data) { - SceneCollection ***array = data; - **array = sc; + Collection ***array = data; + **array = collection; (*array)++; } -static void scene_collections_array(ID *owner_id, SceneCollection ***collections_array, int *tot) +static void scene_collections_array(Scene *scene, Collection ***collections_array, int *tot) { - SceneCollection *sc; - SceneCollection **array; + Collection *collection; + Collection **array; *collections_array = NULL; *tot = 0; - if (owner_id == NULL) { + if (scene == NULL) { return; } - sc = master_collection_from_id(owner_id); - BLI_assert(sc != NULL); - scene_collection_callback(sc, scene_collections_count, tot); + collection = BKE_collection_master(scene); + BLI_assert(collection != NULL); + scene_collection_callback(collection, scene_collections_count, tot); if (*tot == 0) return; - *collections_array = array = MEM_mallocN(sizeof(SceneCollection *) * (*tot), "SceneCollectionArray"); - scene_collection_callback(sc, scene_collections_build_array, &array); + *collections_array = array = MEM_mallocN(sizeof(Collection *) * (*tot), "CollectionArray"); + scene_collection_callback(collection, scene_collections_build_array, &array); } /** @@ -873,14 +1064,14 @@ static void scene_collections_array(ID *owner_id, SceneCollection ***collections */ void BKE_scene_collections_iterator_begin(BLI_Iterator *iter, void *data_in) { - ID *owner_id = data_in; - SceneCollectionsIteratorData *data = MEM_callocN(sizeof(SceneCollectionsIteratorData), __func__); + Scene *scene = data_in; + CollectionsIteratorData *data = MEM_callocN(sizeof(CollectionsIteratorData), __func__); - data->owner_id = owner_id; + data->scene = scene; iter->data = data; iter->valid = true; - scene_collections_array(owner_id, (SceneCollection ***)&data->array, &data->tot); + scene_collections_array(scene, (Collection ***)&data->array, &data->tot); BLI_assert(data->tot != 0); data->cur = 0; @@ -889,7 +1080,7 @@ void BKE_scene_collections_iterator_begin(BLI_Iterator *iter, void *data_in) void BKE_scene_collections_iterator_next(struct BLI_Iterator *iter) { - SceneCollectionsIteratorData *data = iter->data; + CollectionsIteratorData *data = iter->data; if (++data->cur < data->tot) { iter->current = data->array[data->cur]; @@ -901,7 +1092,7 @@ void BKE_scene_collections_iterator_next(struct BLI_Iterator *iter) void BKE_scene_collections_iterator_end(struct BLI_Iterator *iter) { - SceneCollectionsIteratorData *data = iter->data; + CollectionsIteratorData *data = iter->data; if (data) { if (data->array) { @@ -917,7 +1108,7 @@ void BKE_scene_collections_iterator_end(struct BLI_Iterator *iter) typedef struct SceneObjectsIteratorData { GSet *visited; - LinkData *link_next; + CollectionObject *cob_next; BLI_Iterator scene_collection_iter; } SceneObjectsIteratorData; @@ -933,9 +1124,9 @@ void BKE_scene_objects_iterator_begin(BLI_Iterator *iter, void *data_in) /* we wrap the scenecollection iterator here to go over the scene collections */ BKE_scene_collections_iterator_begin(&data->scene_collection_iter, scene); - SceneCollection *sc = data->scene_collection_iter.current; - if (sc->objects.first != NULL) { - iter->current = ((LinkData *)sc->objects.first)->data; + Collection *collection = data->scene_collection_iter.current; + if (collection->gobject.first != NULL) { + iter->current = ((CollectionObject *)collection->gobject.first)->ob; } else { BKE_scene_objects_iterator_next(iter); @@ -945,14 +1136,14 @@ void BKE_scene_objects_iterator_begin(BLI_Iterator *iter, void *data_in) /** * Gets the first unique object in the sequence */ -static LinkData *object_base_unique(GSet *gs, LinkData *link) +static CollectionObject *object_base_unique(GSet *gs, CollectionObject *cob) { - for (; link != NULL; link = link->next) { - Object *ob = link->data; + for (; cob != NULL; cob = cob->next) { + Object *ob = cob->ob; void **ob_key_p; if (!BLI_gset_ensure_p_ex(gs, ob, &ob_key_p)) { *ob_key_p = ob; - return link; + return cob; } } return NULL; @@ -961,23 +1152,23 @@ static LinkData *object_base_unique(GSet *gs, LinkData *link) void BKE_scene_objects_iterator_next(BLI_Iterator *iter) { SceneObjectsIteratorData *data = iter->data; - LinkData *link = data->link_next ? object_base_unique(data->visited, data->link_next) : NULL; + CollectionObject *cob = data->cob_next ? object_base_unique(data->visited, data->cob_next) : NULL; - if (link) { - data->link_next = link->next; - iter->current = link->data; + if (cob) { + data->cob_next = cob->next; + iter->current = cob->ob; } else { - /* if this is the last object of this ListBase look at the next SceneCollection */ - SceneCollection *sc; + /* if this is the last object of this ListBase look at the next Collection */ + Collection *collection; BKE_scene_collections_iterator_next(&data->scene_collection_iter); do { - sc = data->scene_collection_iter.current; + collection = data->scene_collection_iter.current; /* get the first unique object of this collection */ - LinkData *new_link = object_base_unique(data->visited, sc->objects.first); - if (new_link) { - data->link_next = new_link->next; - iter->current = new_link->data; + CollectionObject *new_cob = object_base_unique(data->visited, collection->gobject.first); + if (new_cob) { + data->cob_next = new_cob->next; + iter->current = new_cob->ob; return; } BKE_scene_collections_iterator_next(&data->scene_collection_iter); diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index ee3c38b9282..b23b1b2dbed 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -46,8 +46,8 @@ #include "BLI_edgehash.h" #include "BKE_cloth.h" +#include "BKE_collection.h" #include "BKE_effect.h" -#include "BKE_group.h" #include "BKE_layer.h" #include "BKE_modifier.h" #include "BKE_scene.h" @@ -503,20 +503,20 @@ static void add_collision_object(Object ***objs, unsigned int *numobj, unsigned /* objects in dupli groups, one level only for now */ if (ob->dup_group && level == 0) { - Group *group= ob->dup_group; + Collection *collection= ob->dup_group; /* add objects */ - FOREACH_GROUP_OBJECT_BEGIN(group, object) + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, object) { add_collision_object(objs, numobj, maxobj, object, self, level+1, modifier_type); } - FOREACH_GROUP_OBJECT_END; + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } } // return all collision objects in scene // collision object will exclude self -Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, unsigned int *numcollobj, unsigned int modifier_type, bool dupli) +Object **get_collisionobjects_ext(Scene *scene, Object *self, Collection *collection, unsigned int *numcollobj, unsigned int modifier_type, bool dupli) { Object **objs; unsigned int numobj= 0, maxobj= 100; @@ -525,13 +525,13 @@ Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, unsi objs= MEM_callocN(sizeof(Object *)*maxobj, "CollisionObjectsArray"); /* gather all collision objects */ - if (group) { - /* use specified group */ - FOREACH_GROUP_OBJECT_BEGIN(group, object) + if (collection) { + /* use specified collection */ + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, object) { add_collision_object(&objs, &numobj, &maxobj, object, self, level, modifier_type); } - FOREACH_GROUP_OBJECT_END; + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } else { Scene *sce_iter; @@ -549,11 +549,11 @@ Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, unsi return objs; } -Object **get_collisionobjects(Scene *scene, Object *self, Group *group, unsigned int *numcollobj, unsigned int modifier_type) +Object **get_collisionobjects(Scene *scene, Object *self, Collection *collection, unsigned int *numcollobj, unsigned int modifier_type) { /* Need to check for active layers, too. Otherwise this check fails if the objects are not on the same layer - DG */ - return get_collisionobjects_ext(scene, self, group, numcollobj, modifier_type, true); + return get_collisionobjects_ext(scene, self, collection, numcollobj, modifier_type, true); } static void add_collider_cache_object(ListBase **objs, Object *ob, Object *self, int level) @@ -579,30 +579,30 @@ static void add_collider_cache_object(ListBase **objs, Object *ob, Object *self, BLI_addtail(*objs, col); } - /* objects in dupli groups, one level only for now */ + /* objects in dupli collection, one level only for now */ if (ob->dup_group && level == 0) { - Group *group= ob->dup_group; + Collection *collection= ob->dup_group; /* add objects */ - FOREACH_GROUP_OBJECT_BEGIN(group, object) + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, object) { add_collider_cache_object(objs, object, self, level+1); } - FOREACH_GROUP_OBJECT_END; + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } } -ListBase *get_collider_cache(Scene *scene, Object *self, Group *group) +ListBase *get_collider_cache(Scene *scene, Object *self, Collection *collection) { ListBase *objs= NULL; /* add object in same layer in scene */ - if (group) { - FOREACH_GROUP_OBJECT_BEGIN(group, object) + if (collection) { + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, object) { add_collider_cache_object(&objs, object, self, 0); } - FOREACH_GROUP_OBJECT_END; + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } else { Scene *sce_iter; diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index f420fd974cd..6314486d809 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -30,6 +30,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_group_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" @@ -949,7 +950,7 @@ LayerCollection *CTX_data_layer_collection(const bContext *C) LayerCollection *layer_collection; if (ctx_data_pointer_verify(C, "layer_collection", (void *)&layer_collection)) { - if (BKE_view_layer_has_collection(view_layer, layer_collection->scene_collection)) { + if (BKE_view_layer_has_collection(view_layer, layer_collection->collection)) { return layer_collection; } } @@ -958,21 +959,21 @@ LayerCollection *CTX_data_layer_collection(const bContext *C) return BKE_layer_collection_get_active(view_layer); } -SceneCollection *CTX_data_scene_collection(const bContext *C) +Collection *CTX_data_collection(const bContext *C) { - SceneCollection *scene_collection; - if (ctx_data_pointer_verify(C, "scene_collection", (void *)&scene_collection)) { - return scene_collection; + Collection *collection; + if (ctx_data_pointer_verify(C, "collection", (void *)&collection)) { + return collection; } LayerCollection *layer_collection = CTX_data_layer_collection(C); if (layer_collection) { - return layer_collection->scene_collection; + return layer_collection->collection; } /* fallback */ Scene *scene = CTX_data_scene(C); - return BKE_collection_master(&scene->id); + return BKE_collection_master(scene); } int CTX_data_mode_enum_ex(const Object *obedit, const Object *ob, const eObjectMode object_mode) diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 848e5fbe5f8..ee2ece48325 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -43,7 +43,7 @@ #include "DNA_armature_types.h" #include "DNA_constraint_types.h" #include "DNA_dynamicpaint_types.h" -#include "DNA_group_types.h" /*GroupObject*/ +#include "DNA_group_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -55,6 +55,7 @@ #include "BKE_animsys.h" #include "BKE_armature.h" #include "BKE_bvhutils.h" /* bvh tree */ +#include "BKE_collection.h" #include "BKE_colorband.h" #include "BKE_cdderivedmesh.h" #include "BKE_constraint.h" @@ -491,17 +492,12 @@ static void scene_setSubframe(Scene *scene, float subframe) static int surface_getBrushFlags(DynamicPaintSurface *surface, const ViewLayer *view_layer) { - Base *base = NULL; + Base *base = BKE_collection_or_layer_objects(NULL, NULL, view_layer, surface->brush_group); Object *brushObj = NULL; ModifierData *md = NULL; int flags = 0; - if (surface->brush_group) - base = FIRSTBASE(surface->brush_group->view_layer); - else - base = FIRSTBASE(view_layer); - while (base) { brushObj = NULL; @@ -5911,21 +5907,15 @@ static int dynamicPaint_doStep(struct Depsgraph *depsgraph, Scene *scene, Object * Loop through surface's target paint objects and do painting */ { - Base *base = NULL; Object *brushObj = NULL; ModifierData *md = NULL; ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); + Base *base = BKE_collection_or_layer_objects(NULL, NULL, view_layer, surface->brush_group); /* backup current scene frame */ int scene_frame = scene->r.cfra; float scene_subframe = scene->r.subframe; - /* either from group or from all objects */ - if (surface->brush_group) - base = FIRSTBASE(surface->brush_group->view_layer); - else - base = FIRSTBASE(view_layer); - while (base) { brushObj = NULL; /* select object */ diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 8bdc74edffd..00c1c82bae8 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -57,6 +57,7 @@ #include "PIL_time.h" #include "BKE_anim.h" /* needed for where_on_path */ +#include "BKE_collection.h" #include "BKE_collision.h" #include "BKE_curve.h" #include "BKE_displist.h" @@ -64,7 +65,6 @@ #include "BKE_cdderivedmesh.h" #include "BKE_effect.h" #include "BKE_global.h" -#include "BKE_group.h" #include "BKE_layer.h" #include "BKE_library.h" #include "BKE_modifier.h" @@ -86,7 +86,7 @@ #include <string.h> #endif // WITH_MOD_FLUID -EffectorWeights *BKE_add_effector_weights(Group *group) +EffectorWeights *BKE_add_effector_weights(Collection *collection) { EffectorWeights *weights = MEM_callocN(sizeof(EffectorWeights), "EffectorWeights"); int i; @@ -96,7 +96,7 @@ EffectorWeights *BKE_add_effector_weights(Group *group) weights->global_gravity = 1.0f; - weights->group = group; + weights->group = collection; return weights; } @@ -215,23 +215,10 @@ ListBase *pdInitEffectors( struct Depsgraph *depsgraph, Scene *scene, Object *ob_src, ParticleSystem *psys_src, EffectorWeights *weights, bool for_simulation) { - ViewLayer *view_layer; - Base *base; + Base *base = BKE_collection_or_layer_objects(depsgraph, scene, NULL, weights->group); ListBase *effectors = NULL; - if (weights->group) { - view_layer = weights->group->view_layer; - } - /* TODO(mai): the check for view_layer shouldnt be needed, remove when render engine api is updated for this */ - else if (depsgraph && DEG_get_evaluated_view_layer(depsgraph)) { - view_layer = DEG_get_evaluated_view_layer(depsgraph); - } - else { - /* depsgraph is NULL during deg build */ - view_layer = BKE_view_layer_context_active_PLACEHOLDER(scene); - } - - for (base = FIRSTBASE(view_layer); base; base = base->next) { + for (; base; base = base->next) { if ((base->flag & BASE_VISIBLED) == 0) { continue; } diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c index b656d2cf7c0..d439b5e7a6e 100644 --- a/source/blender/blenkernel/intern/freestyle.c +++ b/source/blender/blenkernel/intern/freestyle.c @@ -83,7 +83,7 @@ void BKE_freestyle_config_free(FreestyleConfig *config, const bool do_id_user) BLI_freelistN(&config->modules); } -void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config, const int flag) +void BKE_freestyle_config_copy(FreestyleConfig *new_config, const FreestyleConfig *config, const int flag) { FreestyleLineSet *lineset, *new_lineset; FreestyleModuleConfig *module, *new_module; diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c deleted file mode 100644 index f2c9bfdd974..00000000000 --- a/source/blender/blenkernel/intern/group.c +++ /dev/null @@ -1,389 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/blenkernel/intern/group.c - * \ingroup bke - */ - - -#include <stdio.h> -#include <string.h> -#include <math.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_group_types.h" -#include "DNA_material_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_particle_types.h" - -#include "BLI_blenlib.h" -#include "BLI_utildefines.h" - -#include "BKE_collection.h" -#include "BKE_global.h" -#include "BKE_group.h" -#include "BKE_icons.h" -#include "BKE_layer.h" -#include "BKE_library.h" -#include "BKE_main.h" -#include "BKE_object.h" -#include "BKE_scene.h" - -#include "DEG_depsgraph.h" - -/** Free (or release) any data used by this group (does not free the group itself). */ -void BKE_group_free(Group *group) -{ - /* No animdata here. */ - BKE_previewimg_free(&group->preview); - - if (group->view_layer != NULL) { - BKE_view_layer_free(group->view_layer); - group->view_layer = NULL; - } - - if (group->collection != NULL) { - BKE_collection_master_free(&group->id, false); - MEM_freeN(group->collection); - group->collection = NULL; - } -} - -/** - * Run when adding new groups or during doversion. - */ -void BKE_group_init(Group *group) -{ - group->collection = MEM_callocN(sizeof(SceneCollection), __func__); - BLI_strncpy(group->collection->name, "Master Collection", sizeof(group->collection->name)); - group->view_layer = BKE_view_layer_group_add(group); - - /* Unlink the master collection. */ - BKE_collection_unlink(group->view_layer, group->view_layer->layer_collections.first); - - /* Create and link a new default collection. */ - SceneCollection *defaut_collection = BKE_collection_add(&group->id, NULL, COLLECTION_TYPE_GROUP_INTERNAL, NULL); - BKE_collection_link(group->view_layer, defaut_collection); -} - -Group *BKE_group_add(Main *bmain, const char *name) -{ - Group *group; - - group = BKE_libblock_alloc(bmain, ID_GR, name, 0); - id_us_min(&group->id); - id_us_ensure_real(&group->id); - group->layer = (1 << 20) - 1; - - group->preview = NULL; - BKE_group_init(group); - return group; -} - -/** - * Only copy internal data of Group ID from source to already allocated/initialized destination. - * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. - * - * WARNING! This function will not handle ID user count! - * - * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). - */ -void BKE_group_copy_data(Main *UNUSED(bmain), Group *group_dst, const Group *group_src, const int flag) -{ - /* We never handle usercount here for own data. */ - const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; - - /* Do not copy group's preview (same behavior as for objects). */ - if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */ - BKE_previewimg_id_copy(&group_dst->id, &group_src->id); - } - else { - group_dst->preview = NULL; - } - - group_dst->collection = MEM_dupallocN(group_src->collection); - SceneCollection *master_collection_src = BKE_collection_master(&group_src->id); - SceneCollection *master_collection_dst = BKE_collection_master(&group_dst->id); - - /* Recursively creates a new SceneCollection tree. */ - BKE_collection_copy_data(master_collection_dst, master_collection_src, - flag_subdata); - - group_dst->view_layer = MEM_dupallocN(group_src->view_layer); - BKE_view_layer_copy_data(group_dst->view_layer, group_src->view_layer, - master_collection_dst, master_collection_src, - flag_subdata); -} - -Group *BKE_group_copy(Main *bmain, const Group *group) -{ - Group *group_copy; - BKE_id_copy_ex(bmain, &group->id, (ID **)&group_copy, 0, false); - return group_copy; -} - -void BKE_group_make_local(Main *bmain, Group *group, const bool lib_local) -{ - BKE_id_make_local_generic(bmain, &group->id, true, lib_local); -} - -/* external */ -static bool group_object_add_internal(Group *group, Object *ob) -{ - if (group == NULL || ob == NULL) { - return false; - } - - /* For now always add to master collection of the group. */ - SceneCollection *scene_collection = GROUP_MASTER_COLLECTION(group); - - /* If the object has been added already it returns false. */ - if (BKE_collection_object_add(&group->id, scene_collection, ob) == false) { - return false; - } - - id_us_ensure_real(&ob->id); - return true; -} - -bool BKE_group_object_add(Group *group, Object *object) -{ - if (group_object_add_internal(group, object)) { - if ((object->flag & OB_FROMGROUP) == 0) { - object->flag |= OB_FROMGROUP; - } - return true; - } - else { - return false; - } -} - -/* also used for (ob == NULL) */ -static bool group_object_unlink_internal(Group *group, Object *ob) -{ - if (group == NULL) { - return false; - } - - if (BKE_collections_object_remove(NULL, &group->id, ob, false)) { - return true; - } - - return false; -} - -static bool group_object_cyclic_check_internal(Object *object, Group *group) -{ - if (object->dup_group) { - Group *dup_group = object->dup_group; - if ((dup_group->id.tag & LIB_TAG_DOIT) == 0) { - /* Cycle already exists in groups, let's prevent further crappyness */ - return true; - } - /* flag the object to identify cyclic dependencies in further dupli groups */ - dup_group->id.tag &= ~LIB_TAG_DOIT; - - if (dup_group == group) - return true; - else { - FOREACH_GROUP_OBJECT_BEGIN(dup_group, group_object) - { - if (group_object_cyclic_check_internal(group_object, dup_group)) { - return true; - } - } - FOREACH_GROUP_OBJECT_END; - } - - /* un-flag the object, it's allowed to have the same group multiple times in parallel */ - dup_group->id.tag |= LIB_TAG_DOIT; - } - - return false; -} - -bool BKE_group_object_cyclic_check(Main *bmain, Object *object, Group *group) -{ - /* first flag all groups */ - BKE_main_id_tag_listbase(&bmain->group, LIB_TAG_DOIT, true); - - return group_object_cyclic_check_internal(object, group); -} - -bool BKE_group_object_unlink(Group *group, Object *object) -{ - if (group_object_unlink_internal(group, object)) { - /* object can be NULL */ - if (object && BKE_group_object_find(NULL, object) == NULL) { - object->flag &= ~OB_FROMGROUP; - } - return true; - } - else { - return false; - } -} - -bool BKE_group_object_exists(Group *group, Object *ob) -{ - if (group == NULL || ob == NULL) { - return false; - } - else { - return (BLI_findptr(&group->view_layer->object_bases, ob, offsetof(Base, object))); - } -} - -Group *BKE_group_object_find(Group *group, Object *ob) -{ - if (group) - group = group->id.next; - else - group = G.main->group.first; - - while (group) { - if (BKE_group_object_exists(group, ob)) - return group; - group = group->id.next; - } - return NULL; -} - -bool BKE_group_is_animated(Group *group, Object *UNUSED(parent)) -{ - FOREACH_GROUP_OBJECT_BEGIN(group, object) - { - if (object->proxy) { - return true; - } - } - FOREACH_GROUP_OBJECT_END; - return false; -} - -#if 0 // add back when timeoffset & animsys work again -/* only replaces object strips or action when parent nla instructs it */ -/* keep checking nla.c though, in case internal structure of strip changes */ -static void group_replaces_nla(Object *parent, Object *target, char mode) -{ - static ListBase nlastrips = {NULL, NULL}; - static bAction *action = NULL; - static bool done = false; - bActionStrip *strip, *nstrip; - - if (mode == 's') { - - for (strip = parent->nlastrips.first; strip; strip = strip->next) { - if (strip->object == target) { - if (done == 0) { - /* clear nla & action from object */ - nlastrips = target->nlastrips; - BLI_listbase_clear(&target->nlastrips); - action = target->action; - target->action = NULL; - target->nlaflag |= OB_NLA_OVERRIDE; - done = true; - } - nstrip = MEM_dupallocN(strip); - BLI_addtail(&target->nlastrips, nstrip); - } - } - } - else if (mode == 'e') { - if (done) { - BLI_freelistN(&target->nlastrips); - target->nlastrips = nlastrips; - target->action = action; - - BLI_listbase_clear(&nlastrips); /* not needed, but yah... :) */ - action = NULL; - done = false; - } - } -} -#endif - -/* puts all group members in local timing system, after this call - * you can draw everything, leaves tags in objects to signal it needs further updating */ - -/* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */ -void BKE_group_handle_recalc_and_update(struct Depsgraph *depsgraph, Scene *scene, Object *UNUSED(parent), Group *group) -{ -#if 0 /* warning, isn't clearing the recalc flag on the object which causes it to run all the time, - * not just on frame change. - * This isn't working because the animation data is only re-evaluated on frame change so commenting for now - * but when its enabled at some point it will need to be changed so as not to update so much - campbell */ - - /* if animated group... */ - if (parent->nlastrips.first) { - int cfrao; - - /* switch to local time */ - cfrao = scene->r.cfra; - - /* we need a DAG per group... */ - for (go = group->gobject.first; go; go = go->next) { - if (go->ob && go->recalc) { - go->ob->recalc = go->recalc; - - group_replaces_nla(parent, go->ob, 's'); - BKE_object_handle_update(depsgraph, scene, go->ob); - group_replaces_nla(parent, go->ob, 'e'); - - /* leave recalc tags in case group members are in normal scene */ - go->ob->recalc = go->recalc; - } - } - - /* restore */ - scene->r.cfra = cfrao; - } - else -#endif - { - /* only do existing tags, as set by regular depsgraph */ - FOREACH_GROUP_OBJECT_BEGIN(group, object) - { - if (object->id.recalc & ID_RECALC_ALL) { - BKE_object_handle_update(depsgraph, scene, object); - } - } - FOREACH_GROUP_OBJECT_END; - } -} - -/* ******** Dependency graph evaluation ******** */ - -void BKE_group_eval_view_layers(struct Depsgraph *depsgraph, - Group *group) -{ - DEG_debug_print_eval(depsgraph, __func__, group->id.name, group); - BKE_layer_eval_view_layer(depsgraph, &group->id, group->view_layer); -} diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index 61c05c2500d..8476bb6b66d 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -322,7 +322,7 @@ PreviewImage **BKE_previewimg_id_get_p(const ID *id) ID_PRV_CASE(ID_IM, Image); ID_PRV_CASE(ID_BR, Brush); ID_PRV_CASE(ID_OB, Object); - ID_PRV_CASE(ID_GR, Group); + ID_PRV_CASE(ID_GR, Collection); ID_PRV_CASE(ID_SCE, Scene); ID_PRV_CASE(ID_SCR, bScreen); #undef ID_PRV_CASE diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c index 487635f06ad..4860f5a896d 100644 --- a/source/blender/blenkernel/intern/idcode.c +++ b/source/blender/blenkernel/intern/idcode.c @@ -61,9 +61,9 @@ static IDType idtypes[] = { { ID_BR, "Brush", "brushes", BLT_I18NCONTEXT_ID_BRUSH, IDTYPE_FLAGS_ISLINKABLE }, { ID_CA, "Camera", "cameras", BLT_I18NCONTEXT_ID_CAMERA, IDTYPE_FLAGS_ISLINKABLE }, { ID_CF, "CacheFile", "cache_files", BLT_I18NCONTEXT_ID_CACHEFILE, IDTYPE_FLAGS_ISLINKABLE }, + { ID_GR, "Collection", "collections", BLT_I18NCONTEXT_ID_COLLECTION, IDTYPE_FLAGS_ISLINKABLE }, { ID_CU, "Curve", "curves", BLT_I18NCONTEXT_ID_CURVE, IDTYPE_FLAGS_ISLINKABLE }, { ID_GD, "GPencil", "grease_pencil", BLT_I18NCONTEXT_ID_GPENCIL, IDTYPE_FLAGS_ISLINKABLE }, /* rename gpencil */ - { ID_GR, "Group", "groups", BLT_I18NCONTEXT_ID_GROUP, IDTYPE_FLAGS_ISLINKABLE }, { ID_IM, "Image", "images", BLT_I18NCONTEXT_ID_IMAGE, IDTYPE_FLAGS_ISLINKABLE }, { ID_IP, "Ipo", "ipos", "", IDTYPE_FLAGS_ISLINKABLE }, /* deprecated */ { ID_KE, "Key", "shape_keys", BLT_I18NCONTEXT_ID_SHAPEKEY, 0 }, diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index da068802586..685c007da6b 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -31,12 +31,12 @@ #include "BLI_string.h" #include "BLI_string_utf8.h" #include "BLI_string_utils.h" +#include "BLI_threads.h" #include "BLT_translation.h" #include "BKE_collection.h" #include "BKE_freestyle.h" #include "BKE_global.h" -#include "BKE_group.h" #include "BKE_idprop.h" #include "BKE_layer.h" #include "BKE_main.h" @@ -61,24 +61,51 @@ #include "MEM_guardedalloc.h" + /* prototype */ -struct EngineSettingsCB_Type; -static void layer_collections_sync_flags(ListBase *layer_collections_dst, const ListBase *layer_collections_src); -static void layer_collection_free(ViewLayer *view_layer, LayerCollection *lc); -static void layer_collection_objects_populate(ViewLayer *view_layer, LayerCollection *lc, ListBase *objects); -static LayerCollection *layer_collection_add(ViewLayer *view_layer, LayerCollection *parent, SceneCollection *sc); -static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc, const SceneCollection *sc); static void object_bases_iterator_next(BLI_Iterator *iter, const int flag); + +/*********************** Layer Collections and bases *************************/ + +static LayerCollection *layer_collection_add(ListBase *lb_parent, Collection *collection) +{ + LayerCollection *lc = MEM_callocN(sizeof(LayerCollection), "Collection Base"); + lc->collection = collection; + BLI_addtail(lb_parent, lc); + + return lc; +} + +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; + } + + for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { + layer_collection_free(view_layer, nlc); + } + + BLI_freelistN(&lc->layer_collections); +} + +static Base *object_base_new(Object *ob) +{ + Base *base = MEM_callocN(sizeof(Base), "Object Base"); + base->object = ob; + return base; +} + +/********************************* View Layer ********************************/ + + /* RenderLayer */ /* Returns the default view layer to view in workspaces if there is * none linked to the workspace yet. */ ViewLayer *BKE_view_layer_default_view(const Scene *scene) { - /* TODO: it makes more sense to have the Viewport layer as the default, - * but this breaks view layer tests so change it later. */ -#if 0 for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { if (!(view_layer->flag & VIEW_LAYER_RENDER)) { return view_layer; @@ -87,9 +114,6 @@ ViewLayer *BKE_view_layer_default_view(const Scene *scene) BLI_assert(scene->view_layers.first); return scene->view_layers.first; -#else - return BKE_view_layer_default_render(scene); -#endif } /* Returns the default view layer to render if we need to render just one. */ @@ -123,7 +147,7 @@ ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const Scene *scene) return scene->view_layers.first; } -static ViewLayer *view_layer_add(const char *name, SceneCollection *master_scene_collection) +static ViewLayer *view_layer_add(const char *name) { if (!name) { name = DATA_("View Layer"); @@ -134,9 +158,6 @@ static ViewLayer *view_layer_add(const char *name, SceneCollection *master_scene BLI_strncpy_utf8(view_layer->name, name, sizeof(view_layer->name)); - /* Link the master collection by default. */ - layer_collection_add(view_layer, NULL, master_scene_collection); - /* Pure rendering pipeline settings. */ view_layer->layflag = 0x7FFF; /* solid ztra halo edge strand */ view_layer->passflag = SCE_PASS_COMBINED | SCE_PASS_Z; @@ -152,8 +173,7 @@ static ViewLayer *view_layer_add(const char *name, SceneCollection *master_scene */ ViewLayer *BKE_view_layer_add(Scene *scene, const char *name) { - SceneCollection *sc = BKE_collection_master(&scene->id); - ViewLayer *view_layer = view_layer_add(name, sc); + ViewLayer *view_layer = view_layer_add(name); BLI_addtail(&scene->view_layers, view_layer); @@ -162,18 +182,8 @@ ViewLayer *BKE_view_layer_add(Scene *scene, const char *name) &scene->view_layers, view_layer, DATA_("ViewLayer"), '.', offsetof(ViewLayer, name), sizeof(view_layer->name)); - return view_layer; -} + BKE_layer_collection_sync(scene, view_layer); -/** - * Add a ViewLayer for a Group - * It should be added only once - */ -ViewLayer *BKE_view_layer_group_add(Group *group) -{ - BLI_assert(group->view_layer == NULL); - SceneCollection *sc = BKE_collection_master(&group->id); - ViewLayer *view_layer = view_layer_add(group->id.name + 2, sc); return view_layer; } @@ -191,8 +201,12 @@ void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user) BLI_freelistN(&view_layer->object_bases); + if (view_layer->object_bases_hash) { + BLI_ghash_free(view_layer->object_bases_hash, NULL, NULL); + } + for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) { - layer_collection_free(NULL, lc); + layer_collection_free(view_layer, lc); } BLI_freelistN(&view_layer->layer_collections); @@ -235,22 +249,6 @@ void BKE_view_layer_selected_objects_tag(ViewLayer *view_layer, const int tag) } } -/** - * Return the first ViewLayer for a given id - */ -ViewLayer *BKE_view_layer_first_from_id(const ID *owner_id) -{ - switch (GS(owner_id->name)) { - case ID_SCE: - return ((Scene *)owner_id)->view_layers.first; - case ID_GR: - return ((Group *)owner_id)->view_layer; - default: - BLI_assert(!"ID doesn't support view layers"); - return NULL; - } -} - static bool find_scene_collection_in_scene_collections(ListBase *lb, const LayerCollection *lc) { for (LayerCollection *lcn = lb->first; lcn; lcn = lcn->next) { @@ -285,32 +283,43 @@ Object *BKE_view_layer_camera_find(ViewLayer *view_layer) /** * Find the ViewLayer a LayerCollection belongs to */ -ViewLayer *BKE_view_layer_find_from_collection(const ID *owner_id, LayerCollection *lc) +ViewLayer *BKE_view_layer_find_from_collection(const Scene *scene, LayerCollection *lc) { - switch (GS(owner_id->name)) { - case ID_GR: - return ((Group *)owner_id)->view_layer; - case ID_SCE: - { - Scene *scene = (Scene *)owner_id; - for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { - if (find_scene_collection_in_scene_collections(&view_layer->layer_collections, lc)) { - return view_layer; - } - } - return NULL; + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + if (find_scene_collection_in_scene_collections(&view_layer->layer_collections, lc)) { + return view_layer; } - default: - BLI_assert(!"ID doesn't support scene layers"); - return NULL; } + + return NULL; } /* Base */ +static void view_layer_bases_hash_create(ViewLayer *view_layer) +{ + static ThreadMutex hash_lock = BLI_MUTEX_INITIALIZER; + + if (!view_layer->object_bases_hash) { + BLI_mutex_lock(&hash_lock); + + 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); + } + + BLI_mutex_unlock(&hash_lock); + } +} + Base *BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob) { - return BLI_findptr(&view_layer->object_bases, ob, offsetof(Base, object)); + if (!view_layer->object_bases_hash) { + view_layer_bases_hash_create(view_layer); + } + + return BLI_ghash_lookup(view_layer->object_bases_hash, ob); } void BKE_view_layer_base_deselect_all(ViewLayer *view_layer) @@ -330,134 +339,32 @@ void BKE_view_layer_base_select(struct ViewLayer *view_layer, Base *selbase) } } -/****************************************************************************/ -/* Copying functions for datablocks that use ViewLayer/SceneCollection */ +/**************************** Copy View Layer and Layer Collections ***********************/ -/* Find the equivalent SceneCollection in the new tree */ -static SceneCollection *scene_collection_from_new_tree( - SceneCollection *sc_reference, SceneCollection *sc_dst, SceneCollection *sc_src) +static void layer_collections_copy_data(ListBase *layer_collections_dst, const ListBase *layer_collections_src) { - if (sc_src == sc_reference) { - return sc_dst; - } + BLI_duplicatelist(layer_collections_dst, layer_collections_src); - for (SceneCollection *nsc_src = sc_src->scene_collections.first, *nsc_dst = sc_dst->scene_collections.first; - nsc_src; - nsc_src = nsc_src->next, nsc_dst = nsc_dst->next) - { - SceneCollection *found = scene_collection_from_new_tree(sc_reference, nsc_dst, nsc_src); - if (found != NULL) { - return found; - } - } - return NULL; -} - -static void layer_collection_sync_flags( - LayerCollection *layer_collection_dst, - const LayerCollection *layer_collection_src) -{ - layer_collection_dst->flag = layer_collection_src->flag; - - layer_collections_sync_flags(&layer_collection_dst->layer_collections, - &layer_collection_src->layer_collections); -} + LayerCollection *layer_collection_dst = layer_collections_dst->first; + const LayerCollection *layer_collection_src = layer_collections_src->first; -static void layer_collections_sync_flags(ListBase *layer_collections_dst, const ListBase *layer_collections_src) -{ - BLI_assert(BLI_listbase_count(layer_collections_dst) == BLI_listbase_count(layer_collections_src)); - LayerCollection *layer_collection_dst = (LayerCollection *)layer_collections_dst->first; - const LayerCollection *layer_collection_src = (const LayerCollection *)layer_collections_src->first; while (layer_collection_dst != NULL) { - layer_collection_sync_flags(layer_collection_dst, layer_collection_src); + layer_collections_copy_data(&layer_collection_dst->layer_collections, + &layer_collection_src->layer_collections); + layer_collection_dst = layer_collection_dst->next; layer_collection_src = layer_collection_src->next; } } -static bool layer_collection_sync_if_match( - ListBase *lb, - const SceneCollection *scene_collection_dst, - const SceneCollection *scene_collection_src) -{ - for (LayerCollection *layer_collection = lb->first; - layer_collection; - layer_collection = layer_collection->next) - { - if (layer_collection->scene_collection == scene_collection_src) { - LayerCollection *layer_collection_dst = - BLI_findptr( - lb, - scene_collection_dst, - offsetof(LayerCollection, scene_collection)); - - if (layer_collection_dst != NULL) { - layer_collection_sync_flags(layer_collection_dst, layer_collection); - } - return true; - } - else { - if (layer_collection_sync_if_match( - &layer_collection->layer_collections, - scene_collection_dst, - scene_collection_src)) - { - return true; - } - } - } - return false; -} - -/** - * Sync sibling collections across all view layers - * - * Make sure every linked instance of \a scene_collection_dst has the same values - * (flags, overrides, ...) as the corresponding scene_collection_src. - * - * \note expect scene_collection_dst to be scene_collection_src->next, and it also - * expects both collections to have the same ammount of sub-collections. - */ -void BKE_layer_collection_sync_flags( - ID *owner_id, - SceneCollection *scene_collection_dst, - SceneCollection *scene_collection_src) -{ - for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { - for (LayerCollection *layer_collection = view_layer->layer_collections.first; - layer_collection; - layer_collection = layer_collection->next) - { - layer_collection_sync_if_match( - &layer_collection->layer_collections, - scene_collection_dst, - scene_collection_src); - } - } -} - -/* recreate the LayerCollection tree */ -static void layer_collections_recreate( - ViewLayer *view_layer_dst, ListBase *lb_src, SceneCollection *mc_dst, SceneCollection *mc_src) -{ - for (LayerCollection *lc_src = lb_src->first; lc_src; lc_src = lc_src->next) { - SceneCollection *sc_dst = scene_collection_from_new_tree(lc_src->scene_collection, mc_dst, mc_src); - BLI_assert(sc_dst); - - /* instead of synchronizing both trees we simply re-create it */ - BKE_collection_link(view_layer_dst, sc_dst); - } -} - /** * Only copy internal data of ViewLayer from source to already allocated/initialized destination. * - * \param mc_src Master Collection the source ViewLayer links in. - * \param mc_dst Master Collection the destination ViewLayer links in. * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). */ void BKE_view_layer_copy_data( - ViewLayer *view_layer_dst, ViewLayer *view_layer_src, SceneCollection *mc_dst, SceneCollection *mc_src, + Scene *UNUSED(scene_dst), const Scene *UNUSED(scene_src), + ViewLayer *view_layer_dst, const ViewLayer *view_layer_src, const int flag) { if (view_layer_dst->id_properties != NULL) { @@ -467,176 +374,16 @@ void BKE_view_layer_copy_data( view_layer_dst->stats = NULL; - /* we start fresh with no overrides and no visibility flags set - * instead of syncing both trees we simply unlink and relink the scene collection */ - BLI_listbase_clear(&view_layer_dst->layer_collections); - BLI_listbase_clear(&view_layer_dst->object_bases); + /* Clear temporary data. */ BLI_listbase_clear(&view_layer_dst->drawdata); - - layer_collections_recreate(view_layer_dst, &view_layer_src->layer_collections, mc_dst, mc_src); - - /* Now we handle the syncing for visibility, selectability, ... */ - layer_collections_sync_flags(&view_layer_dst->layer_collections, &view_layer_src->layer_collections); - - Object *active_ob = OBACT(view_layer_src); - for (Base *base_src = view_layer_src->object_bases.first, *base_dst = view_layer_dst->object_bases.first; - base_src; - base_src = base_src->next, base_dst = base_dst->next) - { - base_dst->flag = base_src->flag; - base_dst->flag_legacy = base_src->flag_legacy; - - if (base_dst->object == active_ob) { - view_layer_dst->basact = base_dst; - } - } - view_layer_dst->object_bases_array = NULL; -} - -/** - * Find and return the ListBase of LayerCollection that has \a lc_child as one of its directly - * nested LayerCollection. - * - * \param lb_parent Initial ListBase of LayerCollection to look into recursively - * usually the view layer's collection list - */ -static ListBase *find_layer_collection_parent_list_base(ListBase *lb_parent, const LayerCollection *lc_child) -{ - for (LayerCollection *lc_nested = lb_parent->first; lc_nested; lc_nested = lc_nested->next) { - if (lc_nested == lc_child) { - return lb_parent; - } + view_layer_dst->object_bases_hash = NULL; - ListBase *found = find_layer_collection_parent_list_base(&lc_nested->layer_collections, lc_child); - if (found != NULL) { - return found; - } - } + /* Copy layer collections and object bases. */ + BLI_duplicatelist(&view_layer_dst->object_bases, &view_layer_src->object_bases); + layer_collections_copy_data(&view_layer_dst->layer_collections, &view_layer_src->layer_collections); - return NULL; -} - -/** - * Makes a shallow copy of a LayerCollection - * - * Add a new collection in the same level as the old one (linking if necessary), - * and copy all the collection data across them. - */ -struct LayerCollection *BKE_layer_collection_duplicate(struct ID *owner_id, struct LayerCollection *layer_collection) -{ - SceneCollection *scene_collection, *scene_collection_new; - - scene_collection = layer_collection->scene_collection; - scene_collection_new = BKE_collection_duplicate(owner_id, scene_collection); - - LayerCollection *layer_collection_new = NULL; - - /* If the original layer_collection was directly linked to the view layer - we need to link the new scene collection here as well. */ - for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { - if (BLI_findindex(&view_layer->layer_collections, layer_collection) != -1) { - layer_collection_new = BKE_collection_link(view_layer, scene_collection_new); - layer_collection_sync_flags(layer_collection_new, layer_collection); - - if (layer_collection_new != layer_collection->next) { - BLI_remlink(&view_layer->layer_collections, layer_collection_new); - BLI_insertlinkafter(&view_layer->layer_collections, layer_collection, layer_collection_new); - } - break; - } - } - - /* Otherwise just try to find the corresponding layer collection to return it back. */ - if (layer_collection_new == NULL) { - for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { - ListBase *layer_collections_parent; - layer_collections_parent = find_layer_collection_parent_list_base( - &view_layer->layer_collections, - layer_collection); - if (layer_collections_parent != NULL) { - layer_collection_new = BLI_findptr( - layer_collections_parent, - scene_collection_new, - offsetof(LayerCollection, scene_collection)); - break; - } - } - } - return layer_collection_new; -} - -static void view_layer_object_base_unref(ViewLayer *view_layer, Base *base) -{ - base->refcount--; - - /* It only exists in the RenderLayer */ - if (base->refcount == 0) { - if (view_layer->basact == base) { - view_layer->basact = NULL; - } - - BLI_remlink(&view_layer->object_bases, base); - MEM_freeN(base); - } -} - -/** - * Return the base if existent, or create it if necessary - * Always bump the refcount - */ -static Base *object_base_add(ViewLayer *view_layer, Object *ob) -{ - Base *base; - base = BKE_view_layer_base_find(view_layer, ob); - - if (base == NULL) { - base = MEM_callocN(sizeof(Base), "Object Base"); - - /* Do not bump user count, leave it for SceneCollections. */ - base->object = ob; - BLI_addtail(&view_layer->object_bases, base); - } - - base->refcount++; - return base; -} - -/* LayerCollection */ - -static void layer_collection_objects_unpopulate(ViewLayer *view_layer, LayerCollection *lc) -{ - if (view_layer) { - for (LinkData *link = lc->object_bases.first; link; link = link->next) { - view_layer_object_base_unref(view_layer, link->data); - } - } - - BLI_freelistN(&lc->object_bases); -} - -/** - * When freeing the entire ViewLayer at once we don't bother with unref - * otherwise ViewLayer is passed to keep the syncing of the LayerCollection tree - */ -static void layer_collection_free(ViewLayer *view_layer, LayerCollection *lc) -{ - layer_collection_objects_unpopulate(view_layer, lc); - - for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { - layer_collection_free(view_layer, nlc); - } - - BLI_freelistN(&lc->layer_collections); -} - -/** - * Free (or release) LayerCollection from ViewLayer - * (does not free the LayerCollection itself). - */ -void BKE_layer_collection_free(ViewLayer *view_layer, LayerCollection *lc) -{ - layer_collection_free(view_layer, lc); + // TODO: not always safe to free BKE_layer_collection_sync(scene_dst, view_layer_dst); } /* LayerCollection */ @@ -675,28 +422,46 @@ LayerCollection *BKE_layer_collection_from_index(ViewLayer *view_layer, const in */ LayerCollection *BKE_layer_collection_get_active(ViewLayer *view_layer) { - int i = 0; - return collection_from_index(&view_layer->layer_collections, view_layer->active_collection, &i); + return view_layer->active_collection; } +/* + * Activate collection + */ +bool BKE_layer_collection_activate(ViewLayer *view_layer, LayerCollection *lc) +{ + if (lc->flag & LAYER_COLLECTION_EXCLUDE) { + return false; + } + + view_layer->active_collection = lc; + return true; +} /** - * Return layer collection to add new object(s). - * Create one if none exists. + * Activate first parent collection */ -LayerCollection *BKE_layer_collection_get_active_ensure(Scene *scene, ViewLayer *view_layer) +LayerCollection *BKE_layer_collection_activate_parent(ViewLayer *view_layer, LayerCollection *lc) { - LayerCollection *lc = BKE_layer_collection_get_active(view_layer); + CollectionParent *parent = lc->collection->parents.first; + + if (parent) { + lc = BKE_layer_collection_first_from_scene_collection(view_layer, parent->collection); + } + else { + lc = NULL; + } + + if (lc && (lc->flag & LAYER_COLLECTION_EXCLUDE)) { + /* Don't activate excluded collections. */ + return BKE_layer_collection_activate_parent(view_layer, lc); + } - if (lc == NULL) { - BLI_assert(BLI_listbase_is_empty(&view_layer->layer_collections)); - /* When there is no collection linked to this ViewLayer, create one. */ - SceneCollection *sc = BKE_collection_add(&scene->id, NULL, COLLECTION_TYPE_NONE, NULL); - lc = BKE_collection_link(view_layer, sc); - /* New collection has to be the active one. */ - BLI_assert(lc == BKE_layer_collection_get_active(view_layer)); + if (!lc) { + lc = view_layer->layer_collections.first; } + view_layer->active_collection = lc; return lc; } @@ -750,348 +515,208 @@ int BKE_layer_collection_findindex(ViewLayer *view_layer, const LayerCollection return index_from_collection(&view_layer->layer_collections, lc, &i); } -/** - * Lookup the listbase that contains \a lc. - */ -static ListBase *layer_collection_listbase_find(ListBase *lb, LayerCollection *lc) -{ - for (LayerCollection *lc_iter = lb->first; lc_iter; lc_iter = lc_iter->next) { - if (lc_iter == lc) { - return lb; +/*********************************** Syncing ********************************* + * + * The layer collection tree mirrors the scene collection tree. Whenever that + * changes we need to synchronize them so that there is a corresponding layer + * collection for each collection. Note that the scene collection tree can + * contain link or override collections, and so this is also called on .blend + * file load to ensure any new or removed collections are synced. + * + * The view layer also contains a list of bases for each object that exists + * in at least one layer collection. That list is also synchronized here, and + * stores state like selection. */ + +static void layer_collection_sync(ViewLayer *view_layer, + const ListBase *lb_scene, + ListBase *lb_layer, + ListBase *new_object_bases, + int parent_exclude, + int parent_restrict) +{ + /* TODO: support recovery after removal of intermediate collections, reordering, .. + * For local edits we can make editing operating do the appropriate thing, but for + * linking we can only sync after the fact. */ + + /* Remove layer collections that no longer have a corresponding scene collection. */ + for (LayerCollection *lc = lb_layer->first; lc;) { + /* Note ID remap can set lc->collection to NULL when deleting collections. */ + LayerCollection *lc_next = lc->next; + Collection *collection = (lc->collection) ? BLI_findptr(lb_scene, lc->collection, offsetof(CollectionChild, collection)) : NULL; + + if (!collection) { + /* Free recursively. */ + layer_collection_free(view_layer, lc); + BLI_freelinkN(lb_layer, lc); } - ListBase *lb_child_result; - if ((lb_child_result = layer_collection_listbase_find(&lc_iter->layer_collections, lc))) { - return lb_child_result; - } + lc = lc_next; } - return NULL; -} + /* Add layer collections for any new scene collections, and ensure order is the same. */ + ListBase new_lb_layer = {NULL, NULL}; -#if 0 -/** - * Lookup the listbase that contains \a sc. - */ -static ListBase *scene_collection_listbase_find(ListBase *lb, SceneCollection *sc) -{ - for (SceneCollection *sc_iter = lb->first; sc_iter; sc_iter = sc_iter->next) { - if (sc_iter == sc) { - return lb; + for (const CollectionChild *child = lb_scene->first; child; child = child->next) { + Collection *collection = child->collection; + LayerCollection *lc = BLI_findptr(lb_layer, collection, offsetof(LayerCollection, collection)); + + if (lc) { + BLI_remlink(lb_layer, lc); + BLI_addtail(&new_lb_layer, lc); + } + else { + lc = layer_collection_add(&new_lb_layer, collection); + lc->flag = parent_exclude; } - ListBase *lb_child_result; - if ((lb_child_result = scene_collection_listbase_find(&sc_iter->scene_collections, sc))) { - return lb_child_result; + /* Collection restrict is inherited. */ + int child_restrict = parent_restrict; + if (!(collection->flag & COLLECTION_IS_MASTER)) { + child_restrict |= collection->flag; } - } - return NULL; -} -#endif + /* Sync child collections. */ + layer_collection_sync(view_layer, &collection->children, &lc->layer_collections, new_object_bases, lc->flag, child_restrict); -/* ---------------------------------------------------------------------- */ -/* Outliner drag and drop */ + /* Layer collection exclude is not inherited. */ + if (lc->flag & LAYER_COLLECTION_EXCLUDE) { + continue; + } -/** - * Nest a LayerCollection into another one - * Both collections must be from the same ViewLayer, return true if succeded. - * - * The LayerCollection will effectively be moved into the - * new (nested) position. So all the settings, overrides, ... go with it, and - * if the collection was directly linked to the ViewLayer it's then unlinked. - * - * For the other ViewLayers we simply resync the tree, without changing directly - * linked collections (even if they link to the same SceneCollection) - * - * \param lc_src LayerCollection to nest into \a lc_dst - * \param lc_dst LayerCollection to have \a lc_src inserted into - */ + /* Sync objects, except if collection was excluded. */ + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + Base *base = BLI_ghash_lookup(view_layer->object_bases_hash, cob->ob); + + if (base) { + /* Move from old base list to new base list. Base might have already + * been moved to the new base list and the first/last test ensure that + * case also works. */ + if (!ELEM(base, new_object_bases->first, new_object_bases->last)) { + BLI_remlink(&view_layer->object_bases, base); + BLI_addtail(new_object_bases, base); + } + } + else { + /* Create new base. */ + base = object_base_new(cob->ob); + BLI_addtail(new_object_bases, base); + BLI_ghash_insert(view_layer->object_bases_hash, base->object, base); + } -static void layer_collection_swap( - ViewLayer *view_layer, ListBase *lb_a, ListBase *lb_b, - LayerCollection *lc_a, LayerCollection *lc_b) -{ - if (lb_a == NULL) { - lb_a = layer_collection_listbase_find(&view_layer->layer_collections, lc_a); - } + if ((child_restrict & COLLECTION_RESTRICT_VIEW) == 0) { + base->flag |= BASE_VISIBLED | BASE_VISIBLE_VIEWPORT; - if (lb_b == NULL) { - lb_b = layer_collection_listbase_find(&view_layer->layer_collections, lc_b); + if ((child_restrict & COLLECTION_RESTRICT_SELECT) == 0) { + base->flag |= BASE_SELECTABLED; + } + } + if ((child_restrict & COLLECTION_RESTRICT_RENDER) == 0) { + base->flag |= BASE_VISIBLE_RENDER; + } + } } - BLI_assert(lb_a); - BLI_assert(lb_b); - - BLI_listbases_swaplinks(lb_a, lb_b, lc_a, lc_b); + /* Replace layer collection list with new one. */ + *lb_layer = new_lb_layer; + BLI_assert(BLI_listbase_count(lb_scene) == BLI_listbase_count(lb_layer)); } /** - * Move \a lc_src into \a lc_dst. Both have to be stored in \a view_layer. - * If \a lc_src is directly linked to the ViewLayer it's unlinked + * Update view layer collection tree from collections used in the scene. + * This is used when collections are removed or added, both while editing + * and on file loaded in case linked data changed or went missing. */ -bool BKE_layer_collection_move_into(const ID *owner_id, LayerCollection *lc_dst, LayerCollection *lc_src) +void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer) { - ViewLayer *view_layer = BKE_view_layer_find_from_collection(owner_id, lc_src); - bool is_directly_linked = false; - - if ((!view_layer) || (view_layer != BKE_view_layer_find_from_collection(owner_id, lc_dst))) { - return false; - } - - /* We can't nest the collection into itself */ - if (lc_src->scene_collection == lc_dst->scene_collection) { - return false; - } - - /* Collection is already where we wanted it to be */ - if (lc_dst->layer_collections.last == lc_src) { - return false; + if (!scene->master_collection) { + /* Happens for old files that don't have versioning applied yet. */ + return; } - /* Collection is already where we want it to be in the scene tree - * but we want to swap it in the layer tree still */ - if (lc_dst->scene_collection->scene_collections.last == lc_src->scene_collection) { - LayerCollection *lc_swap = lc_dst->layer_collections.last; - layer_collection_swap(view_layer, &lc_dst->layer_collections, NULL, lc_dst->layer_collections.last, lc_src); - - if (BLI_findindex(&view_layer->layer_collections, lc_swap) != -1) { - BKE_collection_unlink(view_layer, lc_swap); - } - return true; - } - else { - LayerCollection *lc_temp; - is_directly_linked = BLI_findindex(&view_layer->layer_collections, lc_src) != -1; - - if (!is_directly_linked) { - /* lc_src will be invalid after BKE_collection_move_into! - * so we swap it with lc_temp to preserve its settings */ - lc_temp = BKE_collection_link(view_layer, lc_src->scene_collection); - layer_collection_swap(view_layer, &view_layer->layer_collections, NULL, lc_temp, lc_src); - } + /* Free cache. */ + MEM_SAFE_FREE(view_layer->object_bases_array); - if (!BKE_collection_move_into(owner_id, lc_dst->scene_collection, lc_src->scene_collection)) { - if (!is_directly_linked) { - /* Swap back and remove */ - layer_collection_swap(view_layer, NULL, NULL, lc_temp, lc_src); - BKE_collection_unlink(view_layer, lc_temp); - } - return false; - } + /* Create object to base hash if it does not exist yet. */ + if (!view_layer->object_bases_hash) { + view_layer_bases_hash_create(view_layer); } - LayerCollection *lc_new = BLI_findptr( - &lc_dst->layer_collections, lc_src->scene_collection, offsetof(LayerCollection, scene_collection)); - BLI_assert(lc_new); - layer_collection_swap(view_layer, &lc_dst->layer_collections, NULL, lc_new, lc_src); - - /* If it's directly linked, unlink it after the swap */ - if (BLI_findindex(&view_layer->layer_collections, lc_new) != -1) { - BKE_collection_unlink(view_layer, lc_new); + /* Clear visible and selectable flags to be reset. */ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + base->flag &= ~(BASE_VISIBLED | BASE_SELECTABLED | BASE_VISIBLE_VIEWPORT | BASE_VISIBLE_RENDER); } - return true; -} + /* Generate new layer connections and object bases when collections changed. */ + CollectionChild child = {NULL, NULL, scene->master_collection}; + const ListBase collections = {&child, &child}; + ListBase new_object_bases = {NULL, NULL}; -/** - * Move \a lc_src above \a lc_dst. Both have to be stored in \a view_layer. - * If \a lc_src is directly linked to the ViewLayer it's unlinked - */ -bool BKE_layer_collection_move_above(const ID *owner_id, LayerCollection *lc_dst, LayerCollection *lc_src) -{ - ViewLayer *view_layer = BKE_view_layer_find_from_collection(owner_id, lc_src); - const bool is_directly_linked_src = BLI_findindex(&view_layer->layer_collections, lc_src) != -1; - const bool is_directly_linked_dst = BLI_findindex(&view_layer->layer_collections, lc_dst) != -1; + const int parent_exclude = 0, parent_restrict = 0; + layer_collection_sync(view_layer, &collections, &view_layer->layer_collections, &new_object_bases, parent_exclude, parent_restrict); - if ((!view_layer) || (view_layer != BKE_view_layer_find_from_collection(owner_id, lc_dst))) { - return false; - } + /* Any remaning object bases are to be removed. */ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if (view_layer->basact == base) { + view_layer->basact = NULL; + } - /* Collection is already where we wanted it to be */ - if (lc_dst->prev == lc_src) { - return false; + BLI_ghash_remove(view_layer->object_bases_hash, base->object, NULL, NULL); } - /* Collection is already where we want it to be in the scene tree - * but we want to swap it in the layer tree still */ - if (lc_dst->prev && lc_dst->prev->scene_collection == lc_src->scene_collection) { - LayerCollection *lc_swap = lc_dst->prev; - layer_collection_swap(view_layer, NULL, NULL, lc_dst->prev, lc_src); - - if (BLI_findindex(&view_layer->layer_collections, lc_swap) != -1) { - BKE_collection_unlink(view_layer, lc_swap); - } - return true; - } - /* We don't allow to move above/below a directly linked collection - * unless the source collection is also directly linked */ - else if (is_directly_linked_dst) { - /* Both directly linked to the ViewLayer, just need to swap */ - if (is_directly_linked_src) { - BLI_remlink(&view_layer->layer_collections, lc_src); - BLI_insertlinkbefore(&view_layer->layer_collections, lc_dst, lc_src); - return true; - } - else { - return false; - } - } - else { - LayerCollection *lc_temp; + BLI_freelistN(&view_layer->object_bases); + view_layer->object_bases = new_object_bases; - if (!is_directly_linked_src) { - /* lc_src will be invalid after BKE_collection_move_into! - * so we swap it with lc_temp to preserve its settings */ - lc_temp = BKE_collection_link(view_layer, lc_src->scene_collection); - layer_collection_swap(view_layer, &view_layer->layer_collections, NULL, lc_temp, lc_src); - } + /* Always set a valid active collection. */ + LayerCollection *active = view_layer->active_collection; - if (!BKE_collection_move_above(owner_id, lc_dst->scene_collection, lc_src->scene_collection)) { - if (!is_directly_linked_src) { - /* Swap back and remove */ - layer_collection_swap(view_layer, NULL, NULL, lc_temp, lc_src); - BKE_collection_unlink(view_layer, lc_temp); - } - return false; - } + if (active && (active->flag & LAYER_COLLECTION_EXCLUDE)) { + BKE_layer_collection_activate_parent(view_layer, active); } - - LayerCollection *lc_new = lc_dst->prev; - BLI_assert(lc_new); - layer_collection_swap(view_layer, NULL, NULL, lc_new, lc_src); - - /* If it's directly linked, unlink it after the swap */ - if (BLI_findindex(&view_layer->layer_collections, lc_new) != -1) { - BKE_collection_unlink(view_layer, lc_new); + else if (active == NULL) { + view_layer->active_collection = view_layer->layer_collections.first; } - - return true; } -/** - * Move \a lc_src below \a lc_dst. Both have to be stored in \a view_layer. - * If \a lc_src is directly linked to the ViewLayer it's unlinked - */ -bool BKE_layer_collection_move_below(const ID *owner_id, LayerCollection *lc_dst, LayerCollection *lc_src) +void BKE_scene_collection_sync(const Scene *scene) { - ViewLayer *view_layer = BKE_view_layer_find_from_collection(owner_id, lc_src); - const bool is_directly_linked_src = BLI_findindex(&view_layer->layer_collections, lc_src) != -1; - const bool is_directly_linked_dst = BLI_findindex(&view_layer->layer_collections, lc_dst) != -1; - - if ((!view_layer) || (view_layer != BKE_view_layer_find_from_collection(owner_id, lc_dst))) { - return false; - } - - /* Collection is already where we wanted it to be */ - if (lc_dst->next == lc_src) { - return false; - } - - /* Collection is already where we want it to be in the scene tree - * but we want to swap it in the layer tree still */ - if (lc_dst->next && lc_dst->next->scene_collection == lc_src->scene_collection) { - LayerCollection *lc_swap = lc_dst->next; - layer_collection_swap(view_layer, NULL, NULL, lc_dst->next, lc_src); - - if (BLI_findindex(&view_layer->layer_collections, lc_swap) != -1) { - BKE_collection_unlink(view_layer, lc_swap); - } - return true; - } - /* We don't allow to move above/below a directly linked collection - * unless the source collection is also directly linked */ - else if (is_directly_linked_dst) { - /* Both directly linked to the ViewLayer, just need to swap */ - if (is_directly_linked_src) { - BLI_remlink(&view_layer->layer_collections, lc_src); - BLI_insertlinkafter(&view_layer->layer_collections, lc_dst, lc_src); - return true; - } - else { - return false; - } + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + BKE_layer_collection_sync(scene, view_layer); } - else { - LayerCollection *lc_temp; - - if (!is_directly_linked_src) { - /* lc_src will be invalid after BKE_collection_move_into! - * so we swap it with lc_temp to preserve its settings */ - lc_temp = BKE_collection_link(view_layer, lc_src->scene_collection); - layer_collection_swap(view_layer, &view_layer->layer_collections, NULL, lc_temp, lc_src); - } +} - if (!BKE_collection_move_below(owner_id, lc_dst->scene_collection, lc_src->scene_collection)) { - if (!is_directly_linked_src) { - /* Swap back and remove */ - layer_collection_swap(view_layer, NULL, NULL, lc_temp, lc_src); - BKE_collection_unlink(view_layer, lc_temp); - } - return false; - } - } +void BKE_main_collection_sync(const Main *bmain) +{ + /* TODO: if a single collection changed, figure out which + * scenes it belongs to and only update those. */ - LayerCollection *lc_new = lc_dst->next; - BLI_assert(lc_new); - layer_collection_swap(view_layer, NULL, NULL, lc_new, lc_src); + /* TODO: optimize for file load so only linked collections get checked? */ - /* If it's directly linked, unlink it after the swap */ - if (BLI_findindex(&view_layer->layer_collections, lc_new) != -1) { - BKE_collection_unlink(view_layer, lc_new); + for (const Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + BKE_scene_collection_sync(scene); } - - return true; } -static bool layer_collection_resync(ViewLayer *view_layer, LayerCollection *lc, const SceneCollection *sc) +void BKE_main_collection_sync_remap(const Main *bmain) { - if (lc->scene_collection == sc) { - ListBase collections = {NULL}; - BLI_movelisttolist(&collections, &lc->layer_collections); + /* On remapping of object or collection pointers free caches. */ + /* TODO: try to make this faster */ - for (SceneCollection *sc_nested = sc->scene_collections.first; sc_nested; sc_nested = sc_nested->next) { - LayerCollection *lc_nested = BLI_findptr(&collections, sc_nested, offsetof(LayerCollection, scene_collection)); - if (lc_nested) { - BLI_remlink(&collections, lc_nested); - BLI_addtail(&lc->layer_collections, lc_nested); - } - else { - layer_collection_add(view_layer, lc, sc_nested); - } - } + for (const Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + MEM_SAFE_FREE(view_layer->object_bases_array); - for (LayerCollection *lc_nested = collections.first; lc_nested; lc_nested = lc_nested->next) { - layer_collection_free(view_layer, lc_nested); + if (view_layer->object_bases_hash) { + BLI_ghash_free(view_layer->object_bases_hash, NULL, NULL); + view_layer->object_bases_hash = NULL; + } } - BLI_freelistN(&collections); - - BLI_assert(BLI_listbase_count(&lc->layer_collections) == - BLI_listbase_count(&sc->scene_collections)); - - return true; } - for (LayerCollection *lc_nested = lc->layer_collections.first; lc_nested; lc_nested = lc_nested->next) { - if (layer_collection_resync(view_layer, lc_nested, sc)) { - return true; - } + for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) { + BKE_collection_object_cache_free(collection); } - return false; -} - -/** - * Update the scene layers so that any LayerCollection that points - * to \a sc is re-synced again - */ -void BKE_layer_collection_resync(const ID *owner_id, const SceneCollection *sc) -{ - for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { - for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) { - layer_collection_resync(view_layer, lc, sc); - } - } + BKE_main_collection_sync(bmain); } /* ---------------------------------------------------------------------- */ @@ -1102,161 +727,69 @@ void BKE_layer_collection_resync(const ID *owner_id, const SceneCollection *sc) * It also select the objects that are in nested collections. * \note Recursive */ -void BKE_layer_collection_objects_select(struct LayerCollection *layer_collection) +bool BKE_layer_collection_objects_select(ViewLayer *view_layer, LayerCollection *lc, bool deselect) { - if ((layer_collection->flag & COLLECTION_DISABLED) || - ((layer_collection->flag & COLLECTION_SELECTABLE) == 0)) - { - return; - } - - for (LinkData *link = layer_collection->object_bases.first; link; link = link->next) { - Base *base = link->data; - if (base->flag & BASE_SELECTABLED) { - base->flag |= BASE_SELECTED; - } - } - - for (LayerCollection *iter = layer_collection->layer_collections.first; iter; iter = iter->next) { - BKE_layer_collection_objects_select(iter); - } -} - -/* ---------------------------------------------------------------------- */ - -/** - * Link a collection to a renderlayer - * The collection needs to be created separately - */ -LayerCollection *BKE_collection_link(ViewLayer *view_layer, SceneCollection *sc) -{ - LayerCollection *lc = layer_collection_add(view_layer, NULL, sc); - view_layer->active_collection = BKE_layer_collection_findindex(view_layer, lc); - return lc; -} - -/** - * Unlink a collection base from a renderlayer - * The corresponding collection is not removed from the master collection - */ -void BKE_collection_unlink(ViewLayer *view_layer, LayerCollection *lc) -{ - BKE_layer_collection_free(view_layer, lc); - BLI_remlink(&view_layer->layer_collections, lc); - MEM_freeN(lc); - view_layer->active_collection = 0; -} - -/** - * Recursively enable nested collections - */ -static void layer_collection_enable(ViewLayer *view_layer, LayerCollection *lc) -{ - layer_collection_objects_populate(view_layer, lc, &lc->scene_collection->objects); - - for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { - layer_collection_enable(view_layer, nlc); - } -} - -/** - * Enable collection - * Add its objects bases to ViewLayer - * - * Only around for doversion. - */ -void BKE_collection_enable(ViewLayer *view_layer, LayerCollection *lc) -{ - if ((lc->flag & COLLECTION_DISABLED) == 0) { - return; + if (lc->collection->flag & COLLECTION_RESTRICT_SELECT) { + return false; } - lc->flag &= ~COLLECTION_DISABLED; - layer_collection_enable(view_layer, lc); -} - -static void layer_collection_object_add(ViewLayer *view_layer, LayerCollection *lc, Object *ob) -{ - Base *base = object_base_add(view_layer, ob); - - /* Only add an object once. */ - if (BLI_findptr(&lc->object_bases, base, offsetof(LinkData, data))) { - return; - } + bool changed = false; - bool is_visible = ((lc->flag & COLLECTION_VIEWPORT) != 0) && ((lc->flag & COLLECTION_DISABLED) == 0); - bool is_selectable = is_visible && ((lc->flag & COLLECTION_SELECTABLE) != 0); + if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) { + for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) { + Base *base = BKE_view_layer_base_find(view_layer, cob->ob); - if (is_visible) { - base->flag |= BASE_VISIBLED; + if (base) { + if (deselect) { + if (base->flag & BASE_SELECTED) { + base->flag &= ~BASE_SELECTED; + changed = true; + } + } + else { + if ((base->flag & BASE_SELECTABLED) && !(base->flag & BASE_SELECTED)) { + base->flag |= BASE_SELECTED; + changed = true; + } + } + } + } } - if (is_selectable) { - base->flag |= BASE_SELECTABLED; + for (LayerCollection *iter = lc->layer_collections.first; iter; iter = iter->next) { + changed |= BKE_layer_collection_objects_select(view_layer, iter, deselect); } - BLI_addtail(&lc->object_bases, BLI_genericNodeN(base)); + return changed; } -static void layer_collection_object_remove(ViewLayer *view_layer, LayerCollection *lc, Object *ob) -{ - Base *base; - base = BKE_view_layer_base_find(view_layer, ob); - - LinkData *link = BLI_findptr(&lc->object_bases, base, offsetof(LinkData, data)); - BLI_remlink(&lc->object_bases, link); - MEM_freeN(link); - - view_layer_object_base_unref(view_layer, base); -} +/* ---------------------------------------------------------------------- */ -static void layer_collection_objects_populate(ViewLayer *view_layer, LayerCollection *lc, ListBase *objects) +static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc, const Collection *collection) { - for (LinkData *link = objects->first; link; link = link->next) { - layer_collection_object_add(view_layer, lc, link->data); + if (lc->collection == collection) { + return lc; } -} -static void layer_collection_populate(ViewLayer *view_layer, LayerCollection *lc, SceneCollection *sc) -{ - layer_collection_objects_populate(view_layer, lc, &sc->objects); - - for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { - layer_collection_add(view_layer, lc, nsc); - } -} - -static LayerCollection *layer_collection_add(ViewLayer *view_layer, LayerCollection *parent, SceneCollection *sc) -{ - LayerCollection *lc = MEM_callocN(sizeof(LayerCollection), "Collection Base"); - - lc->scene_collection = sc; - lc->flag = COLLECTION_SELECTABLE | COLLECTION_VIEWPORT | COLLECTION_RENDER; - - if (parent != NULL) { - BLI_addtail(&parent->layer_collections, lc); - } - else { - BLI_addtail(&view_layer->layer_collections, lc); + for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { + LayerCollection *found = find_layer_collection_by_scene_collection(nlc, collection); + if (found) { + return found; + } } - - layer_collection_populate(view_layer, lc, sc); - - return lc; + return NULL; } -/* ---------------------------------------------------------------------- */ - /** - * Return the first matching LayerCollection in the ViewLayer for the SceneCollection. + * Return the first matching LayerCollection in the ViewLayer for the Collection. */ -LayerCollection *BKE_layer_collection_first_from_scene_collection(ViewLayer *view_layer, const SceneCollection *scene_collection) +LayerCollection *BKE_layer_collection_first_from_scene_collection(ViewLayer *view_layer, const Collection *collection) { for (LayerCollection *layer_collection = view_layer->layer_collections.first; layer_collection != NULL; layer_collection = layer_collection->next) { - LayerCollection *found = find_layer_collection_by_scene_collection(layer_collection, scene_collection); + LayerCollection *found = find_layer_collection_by_scene_collection(layer_collection, collection); if (found != NULL) { return found; @@ -1268,9 +801,9 @@ LayerCollection *BKE_layer_collection_first_from_scene_collection(ViewLayer *vie /** * See if view layer has the scene collection linked directly, or indirectly (nested) */ -bool BKE_view_layer_has_collection(ViewLayer *view_layer, const SceneCollection *scene_collection) +bool BKE_view_layer_has_collection(ViewLayer *view_layer, const Collection *collection) { - return BKE_layer_collection_first_from_scene_collection(view_layer, scene_collection) != NULL; + return BKE_layer_collection_first_from_scene_collection(view_layer, collection) != NULL; } /** @@ -1287,70 +820,6 @@ bool BKE_scene_has_object(Scene *scene, Object *ob) return false; } - -/* ---------------------------------------------------------------------- */ -/* Syncing */ - -static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc, const SceneCollection *sc) -{ - if (lc->scene_collection == sc) { - return lc; - } - - for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { - LayerCollection *found = find_layer_collection_by_scene_collection(nlc, sc); - if (found) { - return found; - } - } - return NULL; -} - -/** - * Add a new LayerCollection for all the ViewLayers that have sc_parent - */ -void BKE_layer_sync_new_scene_collection(ID *owner_id, const SceneCollection *sc_parent, SceneCollection *sc) -{ - for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { - for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) { - LayerCollection *lc_parent = find_layer_collection_by_scene_collection(lc, sc_parent); - if (lc_parent) { - layer_collection_add(view_layer, lc_parent, sc); - } - } - } -} - -/** - * Add a corresponding ObjectBase to all the equivalent LayerCollection - */ -void BKE_layer_sync_object_link(const ID *owner_id, SceneCollection *sc, Object *ob) -{ - for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { - for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) { - LayerCollection *found = find_layer_collection_by_scene_collection(lc, sc); - if (found) { - layer_collection_object_add(view_layer, found, ob); - } - } - } -} - -/** - * Remove the equivalent object base to all layers that have this collection - */ -void BKE_layer_sync_object_unlink(const ID *owner_id, SceneCollection *sc, Object *ob) -{ - for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) { - for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) { - LayerCollection *found = find_layer_collection_by_scene_collection(lc, sc); - if (found) { - layer_collection_object_remove(view_layer, found, ob); - } - } - } -} - /* ---------------------------------------------------------------------- */ /* Override */ @@ -1677,93 +1146,28 @@ void BKE_view_layer_bases_in_mode_iterator_end(BLI_Iterator *UNUSED(iter)) /* Evaluation */ -static void layer_eval_layer_collection_pre(Depsgraph *depsgraph, ID *UNUSED(owner_id), ViewLayer *view_layer) +void BKE_layer_eval_view_layer(struct Depsgraph *depsgraph, + struct Scene *UNUSED(scene), + ViewLayer *view_layer) { DEG_debug_print_eval(depsgraph, __func__, view_layer->name, view_layer); - //Scene *scene = (GS(owner_id->name) == ID_SCE) ? (Scene *)owner_id : NULL; - for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) { - base->flag &= ~(BASE_VISIBLED | BASE_SELECTABLED); - } + /* Set visibility based on depsgraph mode. */ + const eEvaluationMode mode = DEG_get_mode(depsgraph); + const int base_flag = (mode == DAG_EVAL_VIEWPORT) ? BASE_VISIBLE_VIEWPORT : BASE_VISIBLE_RENDER; - /* TODO(sergey): Is it always required? */ - view_layer->flag |= VIEW_LAYER_ENGINE_DIRTY; -} - -static const char *collection_type_lookup[] = -{ - "None", /* COLLECTION_TYPE_NONE */ - "Group Internal", /* COLLECTION_TYPE_GROUP_INTERNAL */ -}; - -/** - * \note We can't use layer_collection->flag because of 3 level nesting (where parent is visible, but not grand-parent) - * So layer_collection->flag_evaluated is expected to be up to date with layer_collection->flag. - */ -static bool layer_collection_visible_get(Depsgraph *depsgraph, LayerCollection *layer_collection) -{ - if (layer_collection->flag_evaluated & COLLECTION_DISABLED) { - return false; - } - - if (DEG_get_mode(depsgraph) == DAG_EVAL_VIEWPORT) { - return (layer_collection->flag_evaluated & COLLECTION_VIEWPORT) != 0; - } - else { - return (layer_collection->flag_evaluated & COLLECTION_RENDER) != 0; - } -} - -static void layer_eval_layer_collection(Depsgraph *depsgraph, - LayerCollection *layer_collection, - LayerCollection *parent_layer_collection) -{ - DEG_debug_print_eval_parent_typed( - depsgraph, - __func__, - layer_collection->scene_collection->name, - layer_collection->scene_collection, - collection_type_lookup[layer_collection->scene_collection->type], - "parent", - (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection->name : "NONE", - (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection : NULL, - (parent_layer_collection != NULL) ? collection_type_lookup[parent_layer_collection->scene_collection->type] : ""); - BLI_assert(layer_collection != parent_layer_collection); - - /* visibility */ - layer_collection->flag_evaluated = layer_collection->flag; - - if (parent_layer_collection != NULL) { - if (layer_collection_visible_get(depsgraph, parent_layer_collection) == false) { - layer_collection->flag_evaluated |= COLLECTION_DISABLED; - } - - if ((parent_layer_collection->flag_evaluated & COLLECTION_DISABLED) || - (parent_layer_collection->flag_evaluated & COLLECTION_SELECTABLE) == 0) - { - layer_collection->flag_evaluated &= ~COLLECTION_SELECTABLE; - } - } - - const bool is_visible = layer_collection_visible_get(depsgraph, layer_collection); - const bool is_selectable = is_visible && ((layer_collection->flag_evaluated & COLLECTION_SELECTABLE) != 0); - - for (LinkData *link = layer_collection->object_bases.first; link != NULL; link = link->next) { - Base *base = link->data; - - if (is_visible) { + for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) { + if (base->flag & base_flag) { base->flag |= BASE_VISIBLED; } - - if (is_selectable) { - base->flag |= BASE_SELECTABLED; + else { + base->flag &= ~BASE_VISIBLED; } } -} -static void layer_eval_layer_collection_post(Depsgraph *depsgraph, ViewLayer *view_layer) -{ - DEG_debug_print_eval(depsgraph, __func__, view_layer->name, view_layer); + /* TODO(sergey): Is it always required? */ + view_layer->flag |= VIEW_LAYER_ENGINE_DIRTY; + /* Create array of bases, for fast index-based lookup. */ const int num_object_bases = BLI_listbase_count(&view_layer->object_bases); MEM_SAFE_FREE(view_layer->object_bases_array); @@ -1780,42 +1184,12 @@ static void layer_eval_layer_collection_post(Depsgraph *depsgraph, ViewLayer *vi } } -static void layer_eval_collections_recurse(Depsgraph *depsgraph, - ListBase *layer_collections, - LayerCollection *parent_layer_collection) -{ - for (LayerCollection *layer_collection = layer_collections->first; - layer_collection != NULL; - layer_collection = layer_collection->next) - { - layer_eval_layer_collection(depsgraph, - layer_collection, - parent_layer_collection); - layer_eval_collections_recurse(depsgraph, - &layer_collection->layer_collections, - layer_collection); - } -} - -void BKE_layer_eval_view_layer(struct Depsgraph *depsgraph, - struct ID *owner_id, - ViewLayer *view_layer) -{ - layer_eval_layer_collection_pre(depsgraph, owner_id, view_layer); - layer_eval_collections_recurse(depsgraph, - &view_layer->layer_collections, - NULL); - layer_eval_layer_collection_post(depsgraph, view_layer); -} - void BKE_layer_eval_view_layer_indexed(struct Depsgraph *depsgraph, - struct ID *owner_id, + struct Scene *scene, int view_layer_index) { - BLI_assert(GS(owner_id->name) == ID_SCE); BLI_assert(view_layer_index >= 0); - Scene *scene = (Scene *)owner_id; ViewLayer *view_layer = BLI_findlink(&scene->view_layers, view_layer_index); BLI_assert(view_layer != NULL); - BKE_layer_eval_view_layer(depsgraph, owner_id, view_layer); + BKE_layer_eval_view_layer(depsgraph, scene, view_layer); } diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 883f0342159..3926d2055f0 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -91,11 +91,11 @@ #include "BKE_brush.h" #include "BKE_camera.h" #include "BKE_cachefile.h" +#include "BKE_collection.h" #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_font.h" #include "BKE_global.h" -#include "BKE_group.h" #include "BKE_gpencil.h" #include "BKE_idcode.h" #include "BKE_idprop.h" @@ -437,7 +437,7 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local) if (!test) BKE_sound_make_local(bmain, (bSound *)id, lib_local); return true; case ID_GR: - if (!test) BKE_group_make_local(bmain, (Group *)id, lib_local); + if (!test) BKE_collection_make_local(bmain, (Collection *)id, lib_local); return true; case ID_AR: if (!test) BKE_armature_make_local(bmain, (bArmature *)id, lib_local); @@ -615,7 +615,7 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, con BKE_text_copy_data(bmain, (Text *)*r_newid, (Text *)id, flag); break; case ID_GR: - BKE_group_copy_data(bmain, (Group *)*r_newid, (Group *)id, flag); + BKE_collection_copy_data(bmain, (Collection *)*r_newid, (Collection *)id, flag); break; case ID_AR: BKE_armature_copy_data(bmain, (bArmature *)*r_newid, (bArmature *)id, flag); @@ -729,7 +729,7 @@ void BKE_id_swap(Main *bmain, ID *id_a, ID *id_b) CASE_SWAP(ID_TXT, Text); CASE_SWAP(ID_SPK, Speaker); CASE_SWAP(ID_SO, bSound); - CASE_SWAP(ID_GR, Group); + CASE_SWAP(ID_GR, Collection); CASE_SWAP(ID_AR, bArmature); CASE_SWAP(ID_AC, bAction); CASE_SWAP(ID_NT, bNodeTree); @@ -935,7 +935,7 @@ ListBase *which_libbase(Main *mainlib, short type) case ID_SO: return &(mainlib->sound); case ID_GR: - return &(mainlib->group); + return &(mainlib->collection); case ID_AR: return &(mainlib->armature); case ID_AC: @@ -1096,7 +1096,7 @@ int set_listbasepointers(Main *main, ListBase **lb) lb[INDEX_ID_TXT] = &(main->text); lb[INDEX_ID_SO] = &(main->sound); - lb[INDEX_ID_GR] = &(main->group); + lb[INDEX_ID_GR] = &(main->collection); lb[INDEX_ID_PAL] = &(main->palettes); lb[INDEX_ID_PC] = &(main->paintcurves); lb[INDEX_ID_BR] = &(main->brush); @@ -1165,7 +1165,7 @@ size_t BKE_libblock_get_alloc_info(short type, const char **name) CASE_RETURN(ID_SPK, Speaker); CASE_RETURN(ID_LP, LightProbe); CASE_RETURN(ID_SO, bSound); - CASE_RETURN(ID_GR, Group); + CASE_RETURN(ID_GR, Collection); CASE_RETURN(ID_AR, bArmature); CASE_RETURN(ID_AC, bAction); CASE_RETURN(ID_NT, bNodeTree); diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index efc550ac64c..dbfe619153d 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -72,7 +72,6 @@ #include "BKE_collection.h" #include "BKE_constraint.h" #include "BKE_fcurve.h" -#include "BKE_group.h" #include "BKE_idprop.h" #include "BKE_library.h" #include "BKE_library_query.h" @@ -287,6 +286,16 @@ static void library_foreach_bone(LibraryForeachIDData *data, Bone *bone) FOREACH_FINALIZE_VOID; } +static void library_foreach_layer_collection(LibraryForeachIDData *data, ListBase *lb) +{ + for (LayerCollection *lc = lb->first; lc; lc = lc->next) { + FOREACH_CALLBACK_INVOKE(data, lc->collection, IDWALK_CB_NOP); + library_foreach_layer_collection(data, &lc->layer_collections); + } + + FOREACH_FINALIZE_VOID; +} + static void library_foreach_ID_as_subdata_link( ID **id_pp, LibraryIDLinkCallback callback, void *user_data, int flag, LibraryForeachIDData *data) { @@ -409,20 +418,21 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call CALLBACK_INVOKE(scene->gpd, IDWALK_CB_USER); - FOREACH_SCENE_COLLECTION_BEGIN(scene, sc) - { - for (LinkData *link = sc->objects.first; link; link = link->next) { - CALLBACK_INVOKE_ID(link->data, IDWALK_CB_USER); - } + for (CollectionObject *cob = scene->master_collection->gobject.first; cob; cob = cob->next) { + CALLBACK_INVOKE(cob->ob, IDWALK_CB_USER); + } + for (CollectionChild *child = scene->master_collection->children.first; child; child = child->next) { + CALLBACK_INVOKE(child->collection, IDWALK_CB_USER); } - FOREACH_SCENE_COLLECTION_END; ViewLayer *view_layer; for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { for (Base *base = view_layer->object_bases.first; base; base = base->next) { - CALLBACK_INVOKE(base->object, IDWALK_NOP); + CALLBACK_INVOKE(base->object, IDWALK_CB_NOP); } + library_foreach_layer_collection(&data, &view_layer->layer_collections); + for (FreestyleModuleConfig *fmc = view_layer->freestyle_config.modules.first; fmc; fmc = fmc->next) { if (fmc->script) { CALLBACK_INVOKE(fmc->script, IDWALK_CB_NOP); @@ -702,12 +712,13 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call case ID_GR: { - Group *group = (Group *) id; - FOREACH_GROUP_BASE_BEGIN(group, base) - { - CALLBACK_INVOKE(base->object, IDWALK_CB_USER_ONE); + Collection *collection = (Collection *) id; + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + CALLBACK_INVOKE(cob->ob, IDWALK_CB_USER); + } + for (CollectionChild *child = collection->children.first; child; child = child->next) { + CALLBACK_INVOKE(child->collection, IDWALK_CB_USER); } - FOREACH_GROUP_BASE_END break; } @@ -1048,7 +1059,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used) case ID_SPK: return ELEM(id_type_used, ID_SO); case ID_GR: - return ELEM(id_type_used, ID_OB); + return ELEM(id_type_used, ID_OB, ID_GR); case ID_NT: /* Could be the following, but node.id has no type restriction... */ #if 0 diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index 983f6781572..cf2a001daaa 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -77,7 +77,6 @@ #include "BKE_curve.h" #include "BKE_fcurve.h" #include "BKE_font.h" -#include "BKE_group.h" #include "BKE_gpencil.h" #include "BKE_idprop.h" #include "BKE_image.h" @@ -271,25 +270,27 @@ static void libblock_remap_data_preprocess_scene_object_unlink( r_id_remap_data->skipped_refcounted++; } else { - BKE_collections_object_remove(r_id_remap_data->bmain, &sce->id, ob, false); + /* 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_group_unlink( +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 (Group *group = bmain->group.first; group; group = group->id.next) { - if (BKE_group_object_exists(group, ob)) { + 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_collections_object_remove(bmain, &group->id, ob, false); + BKE_collection_object_remove(bmain, collection, ob, false); if (!is_indirect) { r_id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT; } @@ -311,12 +312,14 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) /* 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_group_unlink( + libblock_remap_data_preprocess_collection_unlink( r_id_remap_data, ob_iter, skip_indirect, is_indirect); } FOREACH_SCENE_OBJECT_END; @@ -326,7 +329,7 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) 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_group_unlink( + libblock_remap_data_preprocess_collection_unlink( r_id_remap_data, old_ob, skip_indirect, is_indirect); } @@ -360,23 +363,16 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) static void libblock_remap_data_postprocess_object_update(Main *bmain, Object *old_ob, Object *new_ob) { - if (old_ob->flag & OB_FROMGROUP) { - /* Note that for Scene's BaseObject->flag, either we: - * - unlinked old_ob (i.e. new_ob is NULL), in which case scenes' bases have been removed already. - * - remapped old_ob by new_ob, in which case scenes' bases are still valid as is. - * So in any case, no need to update them here. */ - if (BKE_group_object_find(NULL, old_ob) == NULL) { - old_ob->flag &= ~OB_FROMGROUP; - } - if (new_ob == NULL) { /* We need to remove NULL-ified groupobjects... */ - for (Group *group = bmain->group.first; group; group = group->id.next) { - BKE_group_object_unlink(group, NULL); - } - } - else { - new_ob->flag |= OB_FROMGROUP; - } + if (new_ob == NULL) { + /* In case we unlinked old_ob (new_ob is NULL), the object has already + * been removed from the scenes and their collections. We still have + * to remove the NULL children from collections not used in any scene. */ + BKE_collections_object_remove_nulls(bmain); } + else { + BKE_main_collection_sync_remap(bmain); + } + if (old_ob->type == OB_MBALL) { for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->type == OB_MBALL && BKE_mball_is_basis_for(ob, old_ob)) { @@ -386,27 +382,20 @@ static void libblock_remap_data_postprocess_object_update(Main *bmain, Object *o } } -static void libblock_remap_data_postprocess_group_scene_unlink(Main *UNUSED(bmain), Scene *sce, ID *old_id) +static void libblock_remap_data_postprocess_collection_update(Main *bmain, Collection *old_collection, Collection *new_collection) { - /* Note that here we assume no object has no base (i.e. all objects are assumed instanced - * in one scene...). */ - FOREACH_SCENE_OBJECT_BEGIN(sce, ob) - { - if (ob->flag & OB_FROMGROUP) { - Group *grp = BKE_group_object_find(NULL, ob); - - /* Unlinked group (old_id) is still in bmain... */ - if (grp && (&grp->id == old_id || grp->id.us == 0)) { - grp = BKE_group_object_find(grp, ob); - } - if (!grp) { - ob->flag &= ~OB_FROMGROUP; - } - } + if (new_collection == NULL) { + /* In case we unlinked old_collection (new_collection is NULL), we need + * to remove any collection children that have been set to NULL in the + * because of pointer replacement. */ + BKE_collections_child_remove_nulls(bmain, old_collection); + } + else { + BKE_main_collection_sync_remap(bmain); } - FOREACH_SCENE_OBJECT_END; } + static void libblock_remap_data_postprocess_obdata_relink(Main *UNUSED(bmain), Object *ob, ID *new_id) { if (ob->data == new_id) { @@ -588,11 +577,7 @@ void BKE_libblock_remap_locked( libblock_remap_data_postprocess_object_update(bmain, (Object *)old_id, (Object *)new_id); break; case ID_GR: - if (!new_id) { /* Only affects us in case group was unlinked. */ - for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) { - libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id); - } - } + libblock_remap_data_postprocess_collection_update(bmain, (Collection *)old_id, (Collection *)new_id); break; case ID_ME: case ID_CU: @@ -689,8 +674,6 @@ void BKE_libblock_relink_ex( switch (GS(id->name)) { case ID_SCE: { - Scene *sce = (Scene *)id; - if (old_id) { switch (GS(old_id->name)) { case ID_OB: @@ -699,21 +682,19 @@ void BKE_libblock_relink_ex( break; } case ID_GR: - if (!new_id) { /* Only affects us in case group was unlinked. */ - libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id); - } + libblock_remap_data_postprocess_collection_update(bmain, (Collection *)old_id, (Collection *)new_id); break; default: break; } } else { - /* No choice but to check whole objects/groups. */ + /* No choice but to check whole objects/collections. */ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { libblock_remap_data_postprocess_object_update(bmain, ob, NULL); } - for (Group *grp = bmain->group.first; grp; grp = grp->id.next) { - libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, NULL); + for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) { + libblock_remap_data_postprocess_collection_update(bmain, collection, NULL); } } break; @@ -843,7 +824,7 @@ void BKE_libblock_free_datablock(ID *id, const int UNUSED(flag)) BKE_sound_free((bSound *)id); break; case ID_GR: - BKE_group_free((Group *)id); + BKE_collection_free((Collection *)id); break; case ID_AR: BKE_armature_free((bArmature *)id); @@ -1038,8 +1019,8 @@ void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */ id_us_min(id); - /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding groups when deleting an object. - * Since only 'user_one' usage of objects is groups, and only 'real user' usage of objects is scenes, + /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding collections when deleting an object. + * Since only 'user_one' usage of objects is collections, and only 'real user' usage of objects is scenes, * removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets * fully unlinked. * But only for local objects, not linked ones! diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index bced9a1e019..1e6d3041f3f 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -80,12 +80,12 @@ #include "BKE_DerivedMesh.h" #include "BKE_animsys.h" #include "BKE_anim.h" +#include "BKE_collection.h" #include "BKE_constraint.h" #include "BKE_curve.h" #include "BKE_displist.h" #include "BKE_effect.h" #include "BKE_fcurve.h" -#include "BKE_group.h" #include "BKE_icons.h" #include "BKE_key.h" #include "BKE_lamp.h" @@ -719,7 +719,7 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name) ob = BKE_libblock_alloc(bmain, ID_OB, name, 0); - /* We increase object user count when linking to SceneCollections. */ + /* We increase object user count when linking to Collections. */ id_us_min(&ob->id); /* default object vars */ @@ -746,12 +746,12 @@ static Object *object_add_common(Main *bmain, ViewLayer *view_layer, int type, c /** * General add: to scene, with layer from area and default name * - * Object is added to the active SceneCollection. + * Object is added to the active Collection. * If there is no linked collection to the active ViewLayer we create a new one. */ /* creates minimum required data, but without vertices etc. */ Object *BKE_object_add( - Main *bmain, Scene *scene, ViewLayer *view_layer, + Main *bmain, Scene *UNUSED(scene), ViewLayer *view_layer, int type, const char *name) { Object *ob; @@ -760,8 +760,8 @@ Object *BKE_object_add( ob = object_add_common(bmain, view_layer, type, name); - layer_collection = BKE_layer_collection_get_active_ensure(scene, view_layer); - BKE_collection_object_add(&scene->id, layer_collection->scene_collection, ob); + layer_collection = BKE_layer_collection_get_active(view_layer); + BKE_collection_object_add(bmain, layer_collection->collection, ob); base = BKE_view_layer_base_find(view_layer, ob); BKE_view_layer_base_select(view_layer, base); @@ -782,7 +782,7 @@ Object *BKE_object_add_from( Base *base; ob = object_add_common(bmain, view_layer, type, name); - BKE_collection_object_add_from(scene, ob_src, ob); + BKE_collection_object_add_from(bmain, scene, ob_src, ob); base = BKE_view_layer_base_find(view_layer, ob); BKE_view_layer_base_select(view_layer, base); @@ -1157,7 +1157,6 @@ void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_ if (ob_src->iuser) ob_dst->iuser = MEM_dupallocN(ob_src->iuser); if (ob_src->bb) ob_dst->bb = MEM_dupallocN(ob_src->bb); - ob_dst->flag &= ~OB_FROMGROUP; BLI_listbase_clear(&ob_dst->modifiers); @@ -1344,9 +1343,9 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target) /* proxy rule: lib_object->proxy_from == the one we borrow from, set temporally while object_update */ /* local_object->proxy == pointer to library object, saved in files and read */ -/* local_object->proxy_group == pointer to group dupli-object, saved in files and read */ +/* local_object->proxy_group == pointer to collection dupli-object, saved in files and read */ -void BKE_object_make_proxy(Object *ob, Object *target, Object *gob) +void BKE_object_make_proxy(Object *ob, Object *target, Object *cob) { /* paranoia checks */ if (ID_IS_LINKED(ob) || !ID_IS_LINKED(target)) { @@ -1355,24 +1354,24 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob) } ob->proxy = target; - ob->proxy_group = gob; + ob->proxy_group = cob; id_lib_extern(&target->id); DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); DEG_id_tag_update(&target->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* copy transform - * - gob means this proxy comes from a group, just apply the matrix + * - cob means this proxy comes from a collection, just apply the matrix * so the object wont move from its dupli-transform. * - * - no gob means this is being made from a linked object, + * - no cob means this is being made from a linked object, * this is closer to making a copy of the object - in-place. */ - if (gob) { + if (cob) { ob->rotmode = target->rotmode; - mul_m4_m4m4(ob->obmat, gob->obmat, target->obmat); - if (gob->dup_group) { /* should always be true */ + mul_m4_m4m4(ob->obmat, cob->obmat, target->obmat); + if (cob->dup_group) { /* should always be true */ float tvec[3]; - mul_v3_mat3_m4v3(tvec, ob->obmat, gob->dup_group->dupli_ofs); + mul_v3_mat3_m4v3(tvec, ob->obmat, cob->dup_group->dupli_ofs); sub_v3_v3(ob->obmat[3], tvec); } BKE_object_apply_mat4(ob, ob->obmat, false, true); @@ -2624,13 +2623,13 @@ static void object_handle_update_proxy(Depsgraph *depsgraph, Object *object, const bool do_proxy_update) { - /* The case when this is a group proxy, object_update is called in group.c */ + /* The case when this is a collection proxy, object_update is called in collection.c */ if (object->proxy == NULL) { return; } /* set pointer in library proxy target, for copying, but restore it */ object->proxy->proxy_from = object; - // printf("set proxy pointer for later group stuff %s\n", ob->id.name); + // printf("set proxy pointer for later collection stuff %s\n", ob->id.name); /* the no-group proxy case, we call update */ if (object->proxy_group == NULL) { @@ -3410,22 +3409,22 @@ LinkNode *BKE_object_relational_superset(struct ViewLayer *view_layer, eObjectSe /** * return all groups this object is apart of, caller must free. */ -struct LinkNode *BKE_object_groups(Object *ob) +struct LinkNode *BKE_object_groups(Main *bmain, Object *ob) { - LinkNode *group_linknode = NULL; - Group *group = NULL; - while ((group = BKE_group_object_find(group, ob))) { - BLI_linklist_prepend(&group_linknode, group); + LinkNode *collection_linknode = NULL; + Collection *collection = NULL; + while ((collection = BKE_collection_object_find(bmain, collection, ob))) { + BLI_linklist_prepend(&collection_linknode, collection); } - return group_linknode; + return collection_linknode; } -void BKE_object_groups_clear(Object *ob) +void BKE_object_groups_clear(Main *bmain, Object *ob) { - Group *group = NULL; - while ((group = BKE_group_object_find(group, ob))) { - BKE_group_object_unlink(group, ob); + Collection *collection = NULL; + while ((collection = BKE_collection_object_find(bmain, collection, ob))) { + BKE_collection_object_remove(bmain, collection, ob, false); } } diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index d99a1ba8c0b..5e42cdb6b14 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -48,10 +48,10 @@ #include "DNA_vfont_types.h" #include "BKE_animsys.h" +#include "BKE_collection.h" #include "BKE_DerivedMesh.h" #include "BKE_font.h" #include "BKE_global.h" -#include "BKE_group.h" #include "BKE_idprop.h" #include "BKE_lattice.h" #include "BKE_main.h" @@ -74,7 +74,7 @@ typedef struct DupliContext { Depsgraph *depsgraph; bool do_update; bool animated; - Group *group; /* XXX child objects are selected from this group if set, could be nicer */ + Collection *collection; /* XXX child objects are selected from this group if set, could be nicer */ Object *obedit; /* Only to check if the object is in edit-mode. */ Scene *scene; @@ -107,7 +107,7 @@ static void init_context(DupliContext *r_ctx, Depsgraph *depsgraph, Scene *scene /* don't allow BKE_object_handle_update for viewport during render, can crash */ r_ctx->do_update = update && !(G.is_rendering && DEG_get_mode(depsgraph) != DAG_EVAL_RENDER); r_ctx->animated = false; - r_ctx->group = NULL; + r_ctx->collection = NULL; r_ctx->object = ob; r_ctx->obedit = OBEDIT_FROM_OBACT(ob); @@ -130,8 +130,8 @@ static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Obj r_ctx->animated |= animated; /* object animation makes all children animated */ /* XXX annoying, previously was done by passing an ID* argument, this at least is more explicit */ - if (ctx->gen->type == OB_DUPLIGROUP) - r_ctx->group = ctx->object->dup_group; + if (ctx->gen->type == OB_DUPLICOLLECTION) + r_ctx->collection = ctx->object->dup_group; r_ctx->object = ob; if (mat) @@ -210,7 +210,7 @@ static DupliObject *make_dupli(const DupliContext *ctx, */ static void make_recursive_duplis(const DupliContext *ctx, Object *ob, float space_mat[4][4], int index, bool animated) { - /* simple preventing of too deep nested groups with MAX_DUPLI_RECUR */ + /* simple preventing of too deep nested collections with MAX_DUPLI_RECUR */ if (ctx->level < MAX_DUPLI_RECUR) { DupliContext rctx; copy_dupli_context(&rctx, ctx, ob, space_mat, index, animated); @@ -235,19 +235,19 @@ static bool is_child(const Object *ob, const Object *parent) return false; } -/* create duplis from every child in scene or group */ +/* create duplis from every child in scene or collection */ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChildDuplisFunc make_child_duplis_cb) { Object *parent = ctx->object; - if (ctx->group) { - int groupid = 0; - FOREACH_GROUP_BASE_BEGIN(ctx->group, base) + if (ctx->collection) { + int collectionid = 0; + FOREACH_COLLECTION_BASE_RECURSIVE_BEGIN(ctx->collection, base) { Object *ob = base->object; if ((base->flag & BASE_VISIBLED) && ob != ctx->obedit && is_child(ob, parent)) { DupliContext pctx; - copy_dupli_context(&pctx, ctx, ctx->object, NULL, groupid, false); + copy_dupli_context(&pctx, ctx, ctx->object, NULL, collectionid, false); /* mballs have a different dupli handling */ if (ob->type != OB_MBALL) { @@ -255,9 +255,9 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild } make_child_duplis_cb(&pctx, userdata, ob); } - groupid++; + collectionid++; } - FOREACH_GROUP_BASE_END + FOREACH_COLLECTION_BASE_RECURSIVE_END } else { int baseid = 0; @@ -281,54 +281,55 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild /*---- Implementations ----*/ -/* OB_DUPLIGROUP */ -static void make_duplis_group(const DupliContext *ctx) +/* OB_DUPLICOLLECTION */ +static void make_duplis_collection(const DupliContext *ctx) { Object *ob = ctx->object; - Group *group; + Collection *collection; Base *base; - float group_mat[4][4]; + float collection_mat[4][4]; int id; bool animated; if (ob->dup_group == NULL) return; - group = ob->dup_group; + collection = ob->dup_group; - /* combine group offset and obmat */ - unit_m4(group_mat); - sub_v3_v3(group_mat[3], group->dupli_ofs); - mul_m4_m4m4(group_mat, ob->obmat, group_mat); + /* combine collection offset and obmat */ + unit_m4(collection_mat); + sub_v3_v3(collection_mat[3], collection->dupli_ofs); + mul_m4_m4m4(collection_mat, ob->obmat, collection_mat); /* don't access 'ob->obmat' from now on. */ - /* handles animated groups */ + /* handles animated collections */ /* we need to check update for objects that are not in scene... */ if (ctx->do_update) { /* note: update is optional because we don't always need object * transformations to be correct. Also fixes bug [#29616]. */ - BKE_group_handle_recalc_and_update(ctx->depsgraph, ctx->scene, ob, group); + BKE_collection_handle_recalc_and_update(ctx->depsgraph, ctx->scene, ob, collection); } - animated = BKE_group_is_animated(group, ob); + animated = BKE_collection_is_animated(collection, ob); - for (base = group->view_layer->object_bases.first, id = 0; base; base = base->next, id++) { + const ListBase dup_collection_objects = BKE_collection_object_cache_get(collection); + for (base = dup_collection_objects.first, id = 0; base; base = base->next, id++) { if (base->object != ob && (base->flag & BASE_VISIBLED)) { float mat[4][4]; - /* group dupli offset, should apply after everything else */ - mul_m4_m4m4(mat, group_mat, base->object->obmat); + /* collection dupli offset, should apply after everything else */ + mul_m4_m4m4(mat, collection_mat, base->object->obmat); make_dupli(ctx, base->object, mat, id, animated, false); /* recursion */ - make_recursive_duplis(ctx, base->object, group_mat, id, animated); + make_recursive_duplis(ctx, base->object, collection_mat, id, animated); } } } -static const DupliGenerator gen_dupli_group = { - OB_DUPLIGROUP, /* type */ - make_duplis_group /* make_duplis */ +static const DupliGenerator gen_dupli_collection = { + OB_DUPLICOLLECTION, /* type */ + make_duplis_collection /* make_duplis */ }; /* OB_DUPLIFRAMES */ @@ -341,8 +342,8 @@ static void make_duplis_frames(const DupliContext *ctx) int cfrao = scene->r.cfra; int dupend = ob->dupend; - /* dupliframes not supported inside groups */ - if (ctx->group) + /* dupliframes not supported inside collections */ + if (ctx->collection) return; /* if we don't have any data/settings which will lead to object movement, * don't waste time trying, as it will all look the same... @@ -601,8 +602,8 @@ static void make_duplis_font(const DupliContext *ctx) const wchar_t *text = NULL; bool text_free = false; - /* font dupliverts not supported inside groups */ - if (ctx->group) + /* font dupliverts not supported inside collections */ + if (ctx->collection) return; copy_m4_m4(pmat, par->obmat); @@ -851,7 +852,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size = 0.0; float (*obmat)[4]; int a, b, hair = 0; - int totpart, totchild, totgroup = 0 /*, pa_num */; + int totpart, totchild, totcollection = 0 /*, pa_num */; int no_draw_flag = PARS_UNEXIST; @@ -891,10 +892,14 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem return; } else { /*PART_DRAW_GR */ - if (part->dup_group == NULL || BLI_listbase_is_empty(&part->dup_group->view_layer->object_bases)) + if (part->dup_group == NULL) return; - if (BLI_findptr(&part->dup_group->view_layer->object_bases, par, offsetof(Base, object))) { + const ListBase dup_collection_objects = BKE_collection_object_cache_get(part->dup_group); + if (BLI_listbase_is_empty(&dup_collection_objects)) + return; + + if (BLI_findptr(&dup_collection_objects, par, offsetof(Base, object))) { return; } } @@ -918,31 +923,31 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem /* gather list of objects or single object */ if (part->ren_as == PART_DRAW_GR) { if (ctx->do_update) { - BKE_group_handle_recalc_and_update(ctx->depsgraph, scene, par, part->dup_group); + BKE_collection_handle_recalc_and_update(ctx->depsgraph, scene, par, part->dup_group); } if (part->draw & PART_DRAW_COUNT_GR) { for (dw = part->dupliweights.first; dw; dw = dw->next) - totgroup += dw->count; + totcollection += dw->count; } else { - FOREACH_GROUP_OBJECT_BEGIN(part->dup_group, object) + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(part->dup_group, object) { (void) object; - totgroup++; + totcollection++; } - FOREACH_GROUP_OBJECT_END; + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } /* we also copy the actual objects to restore afterwards, since * BKE_object_where_is_calc_time will change the object which breaks transform */ - oblist = MEM_callocN((size_t)totgroup * sizeof(Object *), "dupgroup object list"); - obcopylist = MEM_callocN((size_t)totgroup * sizeof(Object), "dupgroup copy list"); + oblist = MEM_callocN((size_t)totcollection * sizeof(Object *), "dupcollection object list"); + obcopylist = MEM_callocN((size_t)totcollection * sizeof(Object), "dupcollection copy list"); - if (part->draw & PART_DRAW_COUNT_GR && totgroup) { + if (part->draw & PART_DRAW_COUNT_GR && totcollection) { dw = part->dupliweights.first; - for (a = 0; a < totgroup; dw = dw->next) { + for (a = 0; a < totcollection; dw = dw->next) { for (b = 0; b < dw->count; b++, a++) { oblist[a] = dw->ob; obcopylist[a] = *dw->ob; @@ -951,17 +956,17 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem } else { a = 0; - FOREACH_GROUP_OBJECT_BEGIN(part->dup_group, object) + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(part->dup_group, object) { oblist[a] = object; obcopylist[a] = *object; a++; - if (a >= totgroup) { + if (a >= totcollection) { continue; } } - FOREACH_GROUP_OBJECT_END; + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } } else { @@ -1003,14 +1008,14 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem if (part->ren_as == PART_DRAW_GR) { /* prevent divide by zero below [#28336] */ - if (totgroup == 0) + if (totcollection == 0) continue; - /* for groups, pick the object based on settings */ + /* for collections, pick the object based on settings */ if (part->draw & PART_DRAW_RAND_GR) - b = BLI_rand() % totgroup; + b = BLI_rand() % totcollection; else - b = a % totgroup; + b = a % totcollection; ob = oblist[b]; obmat = oblist[b]->obmat; @@ -1051,7 +1056,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem if (part->ren_as == PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) { b = 0; - FOREACH_GROUP_OBJECT_BEGIN(part->dup_group, object) + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(part->dup_group, object) { copy_m4_m4(tmat, oblist[b]->obmat); @@ -1059,7 +1064,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem mul_mat3_m4_fl(tmat, size * scale); mul_v3_fl(tmat[3], size * scale); - /* group dupli offset, should apply after everything else */ + /* collection dupli offset, should apply after everything else */ if (!is_zero_v3(part->dup_group->dupli_ofs)) { sub_v3_v3(tmat[3], part->dup_group->dupli_ofs); } @@ -1076,7 +1081,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem b++; } - FOREACH_GROUP_OBJECT_END; + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } else { /* to give ipos in object correct offset */ @@ -1130,7 +1135,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem /* restore objects since they were changed in BKE_object_where_is_calc_time */ if (part->ren_as == PART_DRAW_GR) { - for (a = 0; a < totgroup; a++) + for (a = 0; a < totcollection; a++) *(oblist[a]) = obcopylist[a]; } else @@ -1201,8 +1206,8 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx) else if (transflag & OB_DUPLIFRAMES) { return &gen_dupli_frames; } - else if (transflag & OB_DUPLIGROUP) { - return &gen_dupli_group; + else if (transflag & OB_DUPLICOLLECTION) { + return &gen_dupli_collection; } return NULL; diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index dacd826084f..26c822f5fef 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -65,10 +65,10 @@ #include "BKE_boids.h" #include "BKE_cloth.h" +#include "BKE_collection.h" #include "BKE_colortools.h" #include "BKE_effect.h" #include "BKE_global.h" -#include "BKE_group.h" #include "BKE_main.h" #include "BKE_lattice.h" @@ -372,13 +372,19 @@ void psys_check_group_weights(ParticleSettings *part) ParticleDupliWeight *dw, *tdw; int current = 0; - if (part->ren_as == PART_DRAW_GR && part->dup_group && part->dup_group->view_layer->object_bases.first) { + if (part->ren_as != PART_DRAW_GR || !part->dup_group) { + BLI_freelistN(&part->dupliweights); + return; + } + + const ListBase dup_group_objects = BKE_collection_object_cache_get(part->dup_group); + if (dup_group_objects.first) { /* First try to find NULL objects from their index, * and remove all weights that don't have an object in the group. */ dw = part->dupliweights.first; while (dw) { - if (dw->ob == NULL || !BKE_group_object_exists(part->dup_group, dw->ob)) { - Base *base = BLI_findlink(&part->dup_group->view_layer->object_bases, dw->index); + if (dw->ob == NULL || !BKE_collection_has_object_recursive(part->dup_group, dw->ob)) { + Base *base = BLI_findlink(&dup_group_objects, dw->index); if (base != NULL) { dw->ob = base->object; } @@ -394,7 +400,7 @@ void psys_check_group_weights(ParticleSettings *part) } /* then add objects in the group to new list */ - FOREACH_GROUP_OBJECT_BEGIN(part->dup_group, object) + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(part->dup_group, object) { dw = part->dupliweights.first; while (dw && dw->ob != object) { @@ -408,7 +414,7 @@ void psys_check_group_weights(ParticleSettings *part) BLI_addtail(&part->dupliweights, dw); } } - FOREACH_GROUP_OBJECT_END; + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; dw = part->dupliweights.first; for (; dw; dw = dw->next) { diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 12b197070a2..7fd7b791a3f 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -59,6 +59,7 @@ #include "BKE_appdir.h" #include "BKE_anim.h" #include "BKE_cloth.h" +#include "BKE_collection.h" #include "BKE_dynamicpaint.h" #include "BKE_global.h" #include "BKE_main.h" @@ -1741,8 +1742,8 @@ void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int dup * for baking with linking dupligroups. Once we have better overrides * this can be revisited so users select the local objects directly. */ if (scene && (duplis-- > 0) && (ob->dup_group)) { - Group *group = ob->dup_group; - Base *base = group->view_layer->object_bases.first; + Collection *collection = ob->dup_group; + Base *base = BKE_collection_object_cache_get(collection).first; for (; base; base = base->next) { if (base->object != ob) { diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 1c16d57ab12..5a9b5585efd 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -55,9 +55,9 @@ #include "DNA_scene_types.h" #include "BKE_cdderivedmesh.h" +#include "BKE_collection.h" #include "BKE_effect.h" #include "BKE_global.h" -#include "BKE_group.h" #include "BKE_library.h" #include "BKE_library_query.h" #include "BKE_mesh.h" @@ -94,7 +94,7 @@ void BKE_rigidbody_free_world(RigidBodyWorld *rbw) if (rbw->physics_world) { /* free physics references, we assume that all physics objects in will have been added to the world */ if (rbw->constraints) { - FOREACH_GROUP_OBJECT_BEGIN(rbw->constraints, object) + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, object) { if (object->rigidbody_constraint) { RigidBodyCon *rbc = object->rigidbody_constraint; @@ -103,11 +103,11 @@ void BKE_rigidbody_free_world(RigidBodyWorld *rbw) } } } - FOREACH_GROUP_OBJECT_END; + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } if (rbw->group) { - FOREACH_GROUP_OBJECT_BEGIN(rbw->group, object) + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object) { if (object->rigidbody_object) { RigidBodyOb *rbo = object->rigidbody_object; @@ -116,7 +116,7 @@ void BKE_rigidbody_free_world(RigidBodyWorld *rbw) } } } - FOREACH_GROUP_OBJECT_END; + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } /* free dynamics world */ RB_dworld_delete(rbw->physics_world); @@ -1156,7 +1156,7 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob) /* remove object from rigid body constraints */ if (rbw->constraints) { - FOREACH_GROUP_OBJECT_BEGIN(rbw->constraints, obt) + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, obt) { if (obt && obt->rigidbody_constraint) { rbc = obt->rigidbody_constraint; @@ -1165,7 +1165,7 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob) } } } - FOREACH_GROUP_OBJECT_END; + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } } @@ -1199,9 +1199,10 @@ void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob) /* Update object array and rigid body count so they're in sync with the rigid body group */ static void rigidbody_update_ob_array(RigidBodyWorld *rbw) { + const ListBase objects = BKE_collection_object_cache_get(rbw->group); int i, n; - n = BLI_listbase_count(&rbw->group->view_layer->object_bases); + n = BLI_listbase_count(&objects); if (rbw->numbodies != n) { rbw->numbodies = n; @@ -1209,12 +1210,12 @@ static void rigidbody_update_ob_array(RigidBodyWorld *rbw) } i = 0; - FOREACH_GROUP_OBJECT_BEGIN(rbw->group, object) + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object) { rbw->objects[i] = object; i++; } - FOREACH_GROUP_OBJECT_END; + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } static void rigidbody_update_sim_world(Scene *scene, RigidBodyWorld *rbw) @@ -1340,7 +1341,7 @@ static void rigidbody_update_simulation(struct Depsgraph *depsgraph, Scene *scen * Memory management needs redesign here, this is just a dirty workaround. */ if (rebuild && rbw->constraints) { - FOREACH_GROUP_OBJECT_BEGIN(rbw->constraints, ob) + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, ob) { RigidBodyCon *rbc = ob->rigidbody_constraint; if (rbc && rbc->physics_constraint) { @@ -1349,11 +1350,11 @@ static void rigidbody_update_simulation(struct Depsgraph *depsgraph, Scene *scen rbc->physics_constraint = NULL; } } - FOREACH_GROUP_OBJECT_END; + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } /* update objects */ - FOREACH_GROUP_OBJECT_BEGIN(rbw->group, ob) + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, ob) { if (ob->type == OB_MESH) { /* validate that we've got valid object set up here... */ @@ -1396,13 +1397,13 @@ static void rigidbody_update_simulation(struct Depsgraph *depsgraph, Scene *scen rigidbody_update_sim_ob(depsgraph, scene, rbw, ob, rbo); } } - FOREACH_GROUP_OBJECT_END; + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; /* update constraints */ if (rbw->constraints == NULL) /* no constraints, move on */ return; - FOREACH_GROUP_OBJECT_BEGIN(rbw->constraints, ob) + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, ob) { /* validate that we've got valid object set up here... */ RigidBodyCon *rbc = ob->rigidbody_constraint; @@ -1430,12 +1431,12 @@ static void rigidbody_update_simulation(struct Depsgraph *depsgraph, Scene *scen rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE; } } - FOREACH_GROUP_OBJECT_END; + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } static void rigidbody_update_simulation_post_step(RigidBodyWorld *rbw) { - FOREACH_GROUP_BASE_BEGIN(rbw->group, base) + FOREACH_COLLECTION_BASE_RECURSIVE_BEGIN(rbw->group, base) { Object *ob = base->object; RigidBodyOb *rbo = ob->rigidbody_object; @@ -1448,7 +1449,7 @@ static void rigidbody_update_simulation_post_step(RigidBodyWorld *rbw) RB_body_deactivate(rbo->physics_object); } } - FOREACH_GROUP_BASE_END + FOREACH_COLLECTION_BASE_RECURSIVE_END } bool BKE_rigidbody_check_sim_running(RigidBodyWorld *rbw, float ctime) @@ -1575,7 +1576,8 @@ void BKE_rigidbody_rebuild_world(struct Depsgraph *depsgraph, Scene *scene, floa cache = rbw->pointcache; /* flag cache as outdated if we don't have a world or number of objects in the simulation has changed */ - if (rbw->physics_world == NULL || rbw->numbodies != BLI_listbase_count(&rbw->group->view_layer->object_bases)) { + const ListBase objects = BKE_collection_object_cache_get(rbw->group); + if (rbw->physics_world == NULL || rbw->numbodies != BLI_listbase_count(&objects)) { cache->flag |= PTCACHE_OUTDATED; } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 950db7d7453..ea0498930ff 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -75,7 +75,6 @@ #include "BKE_freestyle.h" #include "BKE_global.h" #include "BKE_gpencil.h" -#include "BKE_group.h" #include "BKE_icons.h" #include "BKE_idprop.h" #include "BKE_image.h" @@ -244,20 +243,18 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons sce_dst->depsgraph_hash = NULL; sce_dst->fps_info = NULL; - /* layers and collections */ - sce_dst->collection = MEM_dupallocN(sce_src->collection); - SceneCollection *mc_src = BKE_collection_master(&sce_src->id); - SceneCollection *mc_dst = BKE_collection_master(&sce_dst->id); - - /* Recursively creates a new SceneCollection tree. */ - BKE_collection_copy_data(mc_dst, mc_src, flag_subdata); + /* Master Collection */ + if (sce_src->master_collection) { + sce_dst->master_collection = BKE_collection_copy_master(bmain, sce_src->master_collection, flag); + } + /* View Layers */ BLI_duplicatelist(&sce_dst->view_layers, &sce_src->view_layers); for (ViewLayer *view_layer_src = sce_src->view_layers.first, *view_layer_dst = sce_dst->view_layers.first; view_layer_src; view_layer_src = view_layer_src->next, view_layer_dst = view_layer_dst->next) { - BKE_view_layer_copy_data(view_layer_dst, view_layer_src, mc_dst, mc_src, flag_subdata); + BKE_view_layer_copy_data(sce_dst, sce_src, view_layer_dst, view_layer_src, flag_subdata); } BLI_duplicatelist(&(sce_dst->markers), &(sce_src->markers)); @@ -407,6 +404,9 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) BKE_id_copy_ex(bmain, (ID *)sce_copy->world, (ID **)&sce_copy->world, LIB_ID_COPY_ACTIONS, false); } + /* Collections */ + BKE_collection_copy_full(bmain, sce_copy->master_collection); + /* Full copy of GreasePencil. */ /* XXX Not copying anim/actions here? */ if (sce_copy->gpd) { @@ -506,9 +506,15 @@ void BKE_scene_free_ex(Scene *sce, const bool do_id_user) } /* Master Collection */ - BKE_collection_master_free(&sce->id, do_id_user); - MEM_freeN(sce->collection); - sce->collection = NULL; + // TODO: what to do with do_id_user? it's also true when just + // closing the file which seems wrong? should decrement users + // for objects directly in the master collection? then other + // collections in the scene need to do it too? + if (sce->master_collection) { + BKE_collection_free(sce->master_collection); + MEM_freeN(sce->master_collection); + sce->master_collection = NULL; + } /* These are freed on doversion. */ BLI_assert(sce->layer_properties == NULL); @@ -789,8 +795,7 @@ void BKE_scene_init(Scene *sce) sce->orientation_index_custom = -1; /* Master Collection */ - sce->collection = MEM_callocN(sizeof(SceneCollection), "Master Collection"); - BLI_strncpy(sce->collection->name, "Master Collection", sizeof(sce->collection->name)); + sce->master_collection = BKE_collection_master_add(); BKE_view_layer_add(sce, "View Layer"); @@ -910,29 +915,19 @@ Object *BKE_scene_object_find_by_name(Scene *scene, const char *name) void BKE_scene_set_background(Main *bmain, Scene *scene) { Object *ob; - Group *group; /* check for cyclic sets, for reading old files but also for definite security (py?) */ BKE_scene_validate_setscene(bmain, scene); /* deselect objects (for dataselect) */ for (ob = bmain->object.first; ob; ob = ob->id.next) - ob->flag &= ~(SELECT | OB_FROMGROUP); - - /* group flags again */ - for (group = bmain->group.first; group; group = group->id.next) { - FOREACH_GROUP_OBJECT_BEGIN(group, object) - { - object->flag |= OB_FROMGROUP; - } - FOREACH_GROUP_OBJECT_END; - } + ob->flag &= ~SELECT; /* copy layers and flags from bases to objects */ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { for (Base *base = view_layer->object_bases.first; base; base = base->next) { ob = base->object; - /* group patch... */ + /* collection patch... */ BKE_scene_object_base_flag_sync_from_base(base); } } @@ -1025,9 +1020,9 @@ int BKE_scene_base_iter_next( else { if (iter->phase != F_DUPLI) { if (depsgraph && (*base)->object->transflag & OB_DUPLI) { - /* groups cannot be duplicated for mballs yet, + /* collections cannot be duplicated for mballs yet, * this enters eternal loop because of - * makeDispListMBall getting called inside of group_duplilist */ + * makeDispListMBall getting called inside of collection_duplilist */ if ((*base)->object->dup_group == NULL) { iter->duplilist = object_duplilist_ex(depsgraph, (*scene), (*base)->object, false); @@ -1087,11 +1082,11 @@ int BKE_scene_base_iter_next( return iter->phase; } -Scene *BKE_scene_find_from_collection(const Main *bmain, const SceneCollection *scene_collection) +Scene *BKE_scene_find_from_collection(const Main *bmain, const Collection *collection) { for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { for (ViewLayer *layer = scene->view_layers.first; layer; layer = layer->next) { - if (BKE_view_layer_has_collection(layer, scene_collection)) { + if (BKE_view_layer_has_collection(layer, collection)) { return scene; } } @@ -1555,11 +1550,7 @@ void BKE_scene_object_base_flag_sync_from_base(Base *base) { Object *ob = base->object; - /* keep the object only flags untouched */ - int flag = ob->flag & OB_FROMGROUP; - ob->flag = base->flag; - ob->flag |= flag; if ((base->flag & BASE_SELECTED) != 0) { ob->flag |= SELECT; diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 0af400796a4..9aa6c172a90 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -71,10 +71,10 @@ variables on the UI for now #include "BLI_ghash.h" #include "BLI_threads.h" +#include "BKE_collection.h" #include "BKE_curve.h" #include "BKE_effect.h" #include "BKE_global.h" -#include "BKE_group.h" #include "BKE_modifier.h" #include "BKE_softbody.h" #include "BKE_pointcache.h" @@ -514,20 +514,18 @@ static void ccd_build_deflector_hash_single(GHash *hash, Object *ob) } /** - * \note group overrides scene when not NULL. + * \note collection overrides scene when not NULL. */ -static void ccd_build_deflector_hash(ViewLayer *view_layer, Group *group, Object *vertexowner, GHash *hash) +static void ccd_build_deflector_hash(ViewLayer *view_layer, Collection *collection, Object *vertexowner, GHash *hash) { Object *ob; if (!hash) return; - /* Explicit collision group. */ - if (group) { - view_layer = group->view_layer; - } + /* Explicit collision collection. */ + Base *base = BKE_collection_or_layer_objects(NULL, NULL, view_layer, collection); - for (Base *base = FIRSTBASE(view_layer); base; base = base->next) { + for (; base; base = base->next) { /* Only proceed for mesh object in same layer. */ if (base->object->type == OB_MESH) { ob = base->object; @@ -551,20 +549,18 @@ static void ccd_update_deflector_hash_single(GHash *hash, Object *ob) } /** - * \note group overrides scene when not NULL. + * \note collection overrides scene when not NULL. */ -static void ccd_update_deflector_hash(ViewLayer *view_layer, Group *group, Object *vertexowner, GHash *hash) +static void ccd_update_deflector_hash(ViewLayer *view_layer, Collection *collection, Object *vertexowner, GHash *hash) { Object *ob; if ((!hash) || (!vertexowner)) return; - /* Explicit collision group. */ - if (group) { - view_layer = group->view_layer; - } + /* Explicit collision collection. */ + Base *base = BKE_collection_or_layer_objects(NULL, NULL, view_layer, collection); - for (Base *base = FIRSTBASE(view_layer); base; base = base->next) { + for (; base; base = base->next) { /* Only proceed for mesh object in same layer. */ if (base->object->type == OB_MESH) { ob = base->object; @@ -964,11 +960,11 @@ static void free_softbody_intern(SoftBody *sb) /* +++ dependency information functions*/ /** - * \note group overrides scene when not NULL. + * \note collection overrides scene when not NULL. */ -static bool are_there_deflectors(ViewLayer *view_layer) +static bool are_there_deflectors(Base *first_base) { - for (Base *base = FIRSTBASE(view_layer); base; base = base->next) { + for (Base *base = first_base; base; base = base->next) { if (base->object->pd) { if (base->object->pd->deflect) return 1; @@ -978,9 +974,9 @@ static bool are_there_deflectors(ViewLayer *view_layer) return 0; } -static int query_external_colliders(ViewLayer *view_layer, Group *group) +static int query_external_colliders(ViewLayer *view_layer, Collection *collection) { - return(are_there_deflectors(group != NULL ? group->view_layer : view_layer)); + return(are_there_deflectors(BKE_collection_or_layer_objects(NULL, NULL, view_layer, collection))); } /* --- dependency information functions*/ |