Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDalai Felinto <dfelinto@gmail.com>2018-02-02 02:11:59 +0300
committerDalai Felinto <dfelinto@gmail.com>2018-02-02 17:25:05 +0300
commitc7c070c2ece0f41772cbcfe3445f3e0be684dd1d (patch)
tree28f43537045a31a7a7b5c3d75d35035a73277de0 /source/blender/blenkernel
parenta4d2b102f313b8d427e6ff6066f38cc3a2394628 (diff)
Collections: Operator to duplicate a collection
When duplicating a layer collection directly linked to the view layer we copy the collection and link it. For all the not directly linked layer collectionns, we try to sync the layer collection flags, overrides, ... Also we make sure the new collection is right after the original collection. We also expose this in RNA, via collection.duplicate().
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_collection.h1
-rw-r--r--source/blender/blenkernel/BKE_layer.h7
-rw-r--r--source/blender/blenkernel/intern/collection.c55
-rw-r--r--source/blender/blenkernel/intern/layer.c164
4 files changed, 210 insertions, 17 deletions
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h
index 48b4ff881ae..618e60550b7 100644
--- a/source/blender/blenkernel/BKE_collection.h
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -49,6 +49,7 @@ struct SceneCollection *BKE_collection_add(
struct ID *owner_id, struct SceneCollection *sc_parent, const int type, const char *name);
bool BKE_collection_remove(struct ID *owner_id, struct SceneCollection *sc);
void BKE_collection_copy_data(struct SceneCollection *sc_dst, struct SceneCollection *sc_src, const int flag);
+struct SceneCollection *BKE_collection_duplicate(struct ID *owner_id, struct SceneCollection *scene_collection);
struct SceneCollection *BKE_collection_master(const struct ID *owner_id);
void BKE_collection_rename(const struct Scene *scene, struct SceneCollection *sc, const char *name);
void BKE_collection_master_free(struct ID *owner_id, const bool do_id_user);
diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h
index f098a7e7468..633cb2c6044 100644
--- a/source/blender/blenkernel/BKE_layer.h
+++ b/source/blender/blenkernel/BKE_layer.h
@@ -78,11 +78,18 @@ struct Base *BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Objec
void BKE_view_layer_base_deselect_all(struct ViewLayer *view_layer);
void BKE_view_layer_base_select(struct ViewLayer *view_layer, struct Base *selbase);
+void BKE_layer_collection_sync_flags(
+ struct ID *owner_id,
+ struct SceneCollection *scene_collection_dst,
+ struct SceneCollection *scene_collection_src);
+
void BKE_view_layer_copy_data(
struct ViewLayer *view_layer_dst, struct ViewLayer *view_layer_src,
struct SceneCollection *mc_dst, struct SceneCollection *mc_src,
const int flag);
+struct LayerCollection *BKE_layer_collection_duplicate(struct ID *owner_id, struct LayerCollection *layer_collection);
+
void BKE_layer_collection_free(struct ViewLayer *view_layer, struct LayerCollection *lc);
struct LayerCollection *BKE_layer_collection_get_active(struct ViewLayer *view_layer);
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index ca77969ccaa..729be02bfc7 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -68,10 +68,9 @@ static SceneCollection *collection_master_from_id(const ID *owner_id)
}
/**
- * 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
+ * Add a new collection, but don't handle syncing with layer collections
*/
-SceneCollection *BKE_collection_add(ID *owner_id, SceneCollection *sc_parent, const int type, const char *name_custom)
+static SceneCollection *collection_add(ID *owner_id, SceneCollection *sc_parent, const int type, const char *name_custom)
{
SceneCollection *sc_master = collection_master_from_id(owner_id);
SceneCollection *sc = MEM_callocN(sizeof(SceneCollection), "New Collection");
@@ -99,8 +98,6 @@ SceneCollection *BKE_collection_add(ID *owner_id, SceneCollection *sc_parent, co
BLI_addtail(&sc_parent->scene_collections, sc);
BKE_collection_rename((Scene *)owner_id, sc, name);
- BKE_layer_sync_new_scene_collection(owner_id, sc_parent, sc);
-
if (name != name_custom) {
MEM_freeN((char *)name);
}
@@ -109,6 +106,17 @@ SceneCollection *BKE_collection_add(ID *owner_id, SceneCollection *sc_parent, co
}
/**
+ * 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)
+{
+ 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 the collection items recursively
*/
static void collection_free(SceneCollection *sc, const bool do_id_user)
@@ -270,6 +278,43 @@ void BKE_collection_copy_data(SceneCollection *sc_dst, SceneCollection *sc_src,
}
}
+/**
+ * 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)
+{
+ SceneCollection *scene_collection_master = BKE_collection_master(owner_id);
+ SceneCollection *scene_collection_parent = find_collection_parent(scene_collection, scene_collection_master);
+
+ /* It's not allowed to copy the master collection. */
+ if (scene_collection_master == scene_collection) {
+ return NULL;
+ }
+
+ SceneCollection *scene_collection_new = collection_add(
+ owner_id,
+ scene_collection_parent,
+ scene_collection->type,
+ scene_collection->name);
+
+ 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);
+ }
+
+ BKE_collection_copy_data(scene_collection_new, scene_collection, 0);
+ BKE_layer_sync_new_scene_collection(owner_id, scene_collection_parent, scene_collection_new);
+
+ /* 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);
+
+ return scene_collection_new;
+}
+
static SceneCollection *master_collection_from_id(const ID *owner_id)
{
switch (GS(owner_id->name)) {
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index 4333faea863..9807c6e4f10 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -61,6 +61,7 @@
/* 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);
@@ -353,27 +354,94 @@ static SceneCollection *scene_collection_from_new_tree(
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;
+
+ if (layer_collection_dst->properties != NULL) {
+ IDP_FreeProperty(layer_collection_dst->properties);
+ MEM_SAFE_FREE(layer_collection_dst->properties);
+ }
+
+ if (layer_collection_src->properties != NULL) {
+ layer_collection_dst->properties = IDP_CopyProperty(layer_collection_src->properties);
+ }
+
+ layer_collections_sync_flags(&layer_collection_dst->layer_collections,
+ &layer_collection_src->layer_collections);
+}
+
static void layer_collections_sync_flags(ListBase *layer_collections_dst, const ListBase *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_dst->flag = layer_collection_src->flag;
+ layer_collection_sync_flags(layer_collection_dst, layer_collection_src);
+ layer_collection_dst = layer_collection_dst->next;
+ layer_collection_src = layer_collection_src->next;
+ }
+}
- if (layer_collection_dst->properties != NULL) {
- IDP_FreeProperty(layer_collection_dst->properties);
- MEM_SAFE_FREE(layer_collection_dst->properties);
+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;
}
-
- if (layer_collection_src->properties != NULL) {
- layer_collection_dst->properties = IDP_CopyProperty(layer_collection_src->properties);
+ else {
+ if (layer_collection_sync_if_match(
+ &layer_collection->layer_collections,
+ scene_collection_dst,
+ scene_collection_src))
+ {
+ return true;
+ }
}
+ }
+ return false;
+}
- layer_collections_sync_flags(&layer_collection_dst->layer_collections,
- &layer_collection_src->layer_collections);
-
- layer_collection_dst = layer_collection_dst->next;
- layer_collection_src = layer_collection_src->next;
+/**
+ * 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);
+ }
}
}
@@ -438,6 +506,78 @@ void BKE_view_layer_copy_data(
}
}
+/**
+ * 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;
+ }
+
+ ListBase *found = find_layer_collection_parent_list_base(&lc_nested->layer_collections, lc_child);
+ if (found != NULL) {
+ return found;
+ }
+ }
+
+ 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--;