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:
authorMonique <mdewanchand@atmind.nl>2022-10-14 12:07:57 +0300
committerMonique <mdewanchand@atmind.nl>2022-10-14 12:07:57 +0300
commit61e7026e272b5627df97d17ba2941336a4b9b241 (patch)
treecc8d7fcb730645ca9752504804d9fa526bb455ed
parent057e99d6dfc3b2bed70be24ebe28724bc6dca7f2 (diff)
Added method to link multiple objects to a
collection. Refactored the findptr method to use a gset to check whether the object is already in the collection.
-rw-r--r--source/blender/blenkernel/BKE_collection.h15
-rw-r--r--source/blender/blenkernel/intern/collection.c119
-rw-r--r--source/blender/blenkernel/intern/object.cc2
-rw-r--r--source/blender/blenloader/intern/versioning_280.c6
-rw-r--r--source/blender/python/intern/bpy_rna_id_collection.c91
-rw-r--r--source/blender/python/intern/bpy_rna_id_collection.h1
-rw-r--r--source/blender/python/intern/bpy_rna_types_capi.c17
7 files changed, 206 insertions, 45 deletions
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h
index dd7866d83e5..0b2603cc240 100644
--- a/source/blender/blenkernel/BKE_collection.h
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -118,6 +118,15 @@ bool BKE_collection_object_add(struct Main *bmain,
struct Object *ob);
/**
+ * Add multiple objects to given collection, ensuring this collection is 'editable' (i.e. local and
+ * not a liboverride), and finding a suitable parent one otherwise.
+ */
+bool BKE_collection_object_add_multiple(struct Main *bmain,
+ struct Collection *collection,
+ struct Object **objects,
+ int ob_len);
+
+/**
* Add object to given collection, similar to #BKE_collection_object_add.
*
* However, it additionally ensures that the selected collection is also part of the given
@@ -126,7 +135,8 @@ bool BKE_collection_object_add(struct Main *bmain,
bool BKE_collection_viewlayer_object_add(struct Main *bmain,
const struct ViewLayer *view_layer,
struct Collection *collection,
- struct Object *ob);
+ struct Object **objects,
+ int objects_len);
/**
* Same as #BKE_collection_object_add, but unconditionally adds the object to the given collection.
@@ -135,7 +145,8 @@ bool BKE_collection_viewlayer_object_add(struct Main *bmain,
*/
bool BKE_collection_object_add_notest(struct Main *bmain,
struct Collection *collection,
- struct Object *ob);
+ struct Object **objects,
+ int objects_len);
/**
* Add \a ob_dst to all scene collections that reference object \a ob_src is in.
* Used for copying objects.
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 751b5185e39..42b709104f3 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -59,8 +59,12 @@ static bool collection_child_add(Collection *parent,
const int flag,
const bool add_us);
static bool collection_child_remove(Collection *parent, Collection *collection);
-static bool collection_object_add(
- Main *bmain, Collection *collection, Object *ob, int flag, const bool add_us);
+static bool collection_object_add(Main *bmain,
+ Collection *collection,
+ Object **objects,
+ int objects_len,
+ int flag,
+ const bool add_us);
static bool collection_object_remove(Main *bmain,
Collection *collection,
Object *ob,
@@ -125,7 +129,7 @@ static void collection_copy_data(Main *bmain, ID *id_dst, const ID *id_src, cons
collection_child_add(collection_dst, child->collection, flag, false);
}
LISTBASE_FOREACH (CollectionObject *, cob, &collection_src->gobject) {
- collection_object_add(bmain, collection_dst, cob->ob, flag, false);
+ collection_object_add(bmain, collection_dst, &cob->ob, 1, flag, false);
}
}
@@ -554,7 +558,7 @@ bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
/* Link child object into parent collections. */
LISTBASE_FOREACH (CollectionParent *, cparent, &collection->parents) {
Collection *parent = cparent->collection;
- collection_object_add(bmain, parent, cob->ob, 0, true);
+ collection_object_add(bmain, parent, &cob->ob, 1, 0, true);
}
/* Remove child object. */
@@ -657,7 +661,7 @@ static Collection *collection_duplicate_recursive(Main *bmain,
continue;
}
- collection_object_add(bmain, collection_new, ob_new, 0, true);
+ collection_object_add(bmain, collection_new, &ob_new, 1, 0, true);
collection_object_remove(bmain, collection_new, ob_old, false);
}
}
@@ -1066,40 +1070,65 @@ static Collection *collection_parent_editable_find_recursive(const ViewLayer *vi
return NULL;
}
-static bool collection_object_add(
- Main *bmain, Collection *collection, Object *ob, int flag, const bool add_us)
-{
- if (ob->instance_collection) {
- /* Cyclic dependency check. */
- if (collection_find_child_recursive(ob->instance_collection, collection) ||
- ob->instance_collection == collection) {
- return false;
+static bool collection_object_add(Main *bmain,
+ Collection *collection,
+ Object **objects,
+ int objects_len,
+ int flag,
+ const bool add_us)
+{
+ bool result = true;
+ GSet *collection_objects = NULL;
+
+ for (int i = 0; i < objects_len; i++) {
+ Object *ob = objects[i];
+ if (ob == NULL) {
+ result = false;
+ continue;
+ }
+ if (ob->instance_collection) {
+ /* Cyclic dependency check. */
+ if (collection_find_child_recursive(ob->instance_collection, collection) ||
+ ob->instance_collection == collection) {
+ result = false;
+ continue;
+ }
}
- }
- CollectionObject *cob = BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob));
- if (cob) {
- return false;
- }
+ if (collection_objects == NULL) {
+ collection_objects = BLI_gset_ptr_new(__func__);
+ LISTBASE_FOREACH (CollectionObject *, collection_object, &collection->gobject) {
+ BLI_gset_insert(collection_objects, collection_object->ob);
+ }
+ }
- cob = MEM_callocN(sizeof(CollectionObject), __func__);
- cob->ob = ob;
- BLI_addtail(&collection->gobject, cob);
- BKE_collection_object_cache_free(collection);
+ if (!BLI_gset_add(collection_objects, ob)) {
+ result = false;
+ continue;
+ }
- if (add_us && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus(&ob->id);
- }
+ CollectionObject *cob = MEM_callocN(sizeof(CollectionObject), __func__);
+ cob->ob = ob;
+ BLI_addtail(&collection->gobject, cob);
+ BKE_collection_object_cache_free(collection);
- if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
- collection_tag_update_parent_recursive(bmain, collection, ID_RECALC_COPY_ON_WRITE);
- }
+ if (add_us && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus(&ob->id);
+ }
- if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
- BKE_rigidbody_main_collection_object_add(bmain, collection, ob);
+ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ collection_tag_update_parent_recursive(bmain, collection, ID_RECALC_COPY_ON_WRITE);
+ }
+
+ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ BKE_rigidbody_main_collection_object_add(bmain, collection, ob);
+ }
}
- return true;
+ if (collection_objects) {
+ BLI_gset_free(collection_objects, NULL);
+ }
+ return result;
}
static bool collection_object_remove(Main *bmain,
@@ -1127,9 +1156,12 @@ static bool collection_object_remove(Main *bmain,
return true;
}
-bool BKE_collection_object_add_notest(Main *bmain, Collection *collection, Object *ob)
+bool BKE_collection_object_add_notest(Main *bmain,
+ Collection *collection,
+ Object **objects,
+ int objects_len)
{
- if (ob == NULL) {
+ if (objects == NULL) {
return false;
}
@@ -1140,7 +1172,7 @@ bool BKE_collection_object_add_notest(Main *bmain, Collection *collection, Objec
return false;
}
- if (!collection_object_add(bmain, collection, ob, 0, true)) {
+ if (!collection_object_add(bmain, collection, objects, objects_len, 0, true)) {
return false;
}
@@ -1155,13 +1187,22 @@ bool BKE_collection_object_add_notest(Main *bmain, Collection *collection, Objec
bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
{
- return BKE_collection_viewlayer_object_add(bmain, NULL, collection, ob);
+ return BKE_collection_object_add_multiple(bmain, collection, &ob, 1);
+}
+
+bool BKE_collection_object_add_multiple(Main *bmain,
+ Collection *collection,
+ Object **objects,
+ int objects_len)
+{
+ return BKE_collection_viewlayer_object_add(bmain, NULL, collection, objects, objects_len);
}
bool BKE_collection_viewlayer_object_add(Main *bmain,
const ViewLayer *view_layer,
Collection *collection,
- Object *ob)
+ Object **objects,
+ int objects_len)
{
if (collection == NULL) {
return false;
@@ -1173,7 +1214,7 @@ bool BKE_collection_viewlayer_object_add(Main *bmain,
return false;
}
- return BKE_collection_object_add_notest(bmain, collection, ob);
+ return BKE_collection_object_add_notest(bmain, collection, objects, objects_len);
}
void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, Object *ob_dst)
@@ -1183,7 +1224,7 @@ void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, O
FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
if (!ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY(collection) &&
BKE_collection_has_object(collection, ob_src)) {
- collection_object_add(bmain, collection, ob_dst, 0, true);
+ collection_object_add(bmain, collection, &ob_dst, 1, 0, true);
is_instantiated = true;
}
}
@@ -1192,7 +1233,7 @@ void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, O
if (!is_instantiated) {
/* In case we could not find any non-linked collections in which instantiate our ob_dst,
* fallback to scene's master collection... */
- collection_object_add(bmain, scene->master_collection, ob_dst, 0, true);
+ collection_object_add(bmain, scene->master_collection, &ob_dst, 1, 0, true);
}
BKE_main_collection_sync(bmain);
diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc
index 2d949fb5c65..42a1b869ce8 100644
--- a/source/blender/blenkernel/intern/object.cc
+++ b/source/blender/blenkernel/intern/object.cc
@@ -2276,7 +2276,7 @@ Object *BKE_object_add(
Object *ob = object_add_common(bmain, scene, view_layer, type, name);
LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer);
- BKE_collection_viewlayer_object_add(bmain, view_layer, layer_collection->collection, ob);
+ BKE_collection_viewlayer_object_add(bmain, view_layer, layer_collection->collection, &ob, 1);
/* NOTE: There is no way to be sure that #BKE_collection_viewlayer_object_add will actually
* manage to find a valid collection in given `view_layer` to add the new object to. */
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 1a8fec49516..98f5d508fd4 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -337,7 +337,7 @@ static void do_version_scene_collection_convert(
LISTBASE_FOREACH (LinkData *, link, &sc->objects) {
Object *ob = link->data;
if (ob) {
- BKE_collection_object_add_notest(bmain, collection, ob);
+ BKE_collection_object_add_notest(bmain, collection, &ob, 1);
id_us_min(&ob->id);
}
}
@@ -447,7 +447,7 @@ static void do_version_layers_to_collections(Main *bmain, Scene *scene)
/* Note usually this would do slow collection syncing for view layers,
* but since no view layers exists yet at this point it's fast. */
- BKE_collection_object_add_notest(bmain, collections[layer], base->object);
+ BKE_collection_object_add_notest(bmain, collections[layer], &base->object, 1);
}
if (base->flag & SELECT) {
@@ -1218,7 +1218,7 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
(*collection_hidden)->flag |= COLLECTION_HIDE_VIEWPORT | COLLECTION_HIDE_RENDER;
}
- BKE_collection_object_add_notest(bmain, *collection_hidden, ob);
+ BKE_collection_object_add_notest(bmain, *collection_hidden, &ob, 1);
BKE_collection_object_remove(bmain, collection, ob, true);
}
}
diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c
index 766c74c0bbc..10b7ba50988 100644
--- a/source/blender/python/intern/bpy_rna_id_collection.c
+++ b/source/blender/python/intern/bpy_rna_id_collection.c
@@ -14,14 +14,19 @@
#include "BLI_bitmap.h"
#include "BLI_utildefines.h"
+#include "BKE_collection.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "DNA_ID.h"
/* Those following are only to support hack of not listing some internal
* 'backward' pointers in generated user_map. */
+#include "DNA_collection_types.h"
#include "DNA_key_types.h"
#include "DNA_object_types.h"
@@ -413,6 +418,86 @@ static PyObject *bpy_orphans_purge(PyObject *UNUSED(self), PyObject *args, PyObj
return PyLong_FromSize_t(num_datablocks_deleted);
}
+PyDoc_STRVAR(bpy_link_multiple_doc,
+ ".. method:: link_multiple(objects)\n"
+ "\n"
+ " Link multiple objects at once.\n"
+ "\n"
+ " Note that this function is quicker than individual calls to :func:`link()` "
+ "(from :class:`bpy.types.CollectionObjects`)\n"
+ "\n"
+ " :arg objects: Iterables of Objects.\n"
+ " :type subset: sequence\n");
+static PyObject *bpy_link_multiple(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ BPy_StructRNA *pyrna = (BPy_StructRNA *)self;
+ Collection *collection = pyrna->ptr.data;
+ Main *bmain = G_MAIN; /* XXX Ugly, but should work! */
+
+ PyObject *objects = NULL;
+ PyObject *ret = NULL;
+
+ static const char *_keywords[] = {"objects", NULL};
+ static _PyArg_Parser _parser = {
+ "O" /* `objects` */
+ ":link_multiple",
+ _keywords,
+ 0,
+ };
+
+ if (!_PyArg_ParseTupleAndKeywordsFast(args, kwds, &_parser, &objects)) {
+ return ret;
+ }
+
+ if (objects) {
+ PyObject *objects_fast = PySequence_Fast(objects, "link_multiple");
+ if (objects_fast == NULL) {
+ goto error;
+ }
+
+ PyObject **objects_array = PySequence_Fast_ITEMS(objects_fast);
+ Py_ssize_t objects_len = PySequence_Fast_GET_SIZE(objects_fast);
+ Object **objs = MEM_malloc_arrayN(objects_len, sizeof(Object *), __func__);
+
+ for (int i = 0; i < objects_len; i++) {
+ ID *id;
+ if (!pyrna_id_FromPyObject(objects_array[i], &id)) {
+ PyErr_Format(PyExc_TypeError,
+ "Expected an ID type, not %.200s",
+ Py_TYPE(objects_array[i])->tp_name);
+ Py_DECREF(objects_fast);
+ MEM_freeN(objs);
+ goto error;
+ }
+ if (id == NULL || GS(id->name) != ID_OB) {
+ PyErr_Format(PyExc_TypeError, "Expected an Object type");
+ Py_DECREF(objects_fast);
+ MEM_freeN(objs);
+ goto error;
+ }
+ Object *obj = (Object *)id;
+ objs[i] = obj;
+ }
+ Py_DECREF(objects_fast);
+ for (int j = 0; j < objects_len; j++) {
+ BKE_collection_object_add(bmain, collection, objs[j]);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, &objs[j]->id);
+ }
+ MEM_freeN(objs);
+ }
+ else {
+ goto error;
+ }
+ Py_INCREF(Py_None);
+ ret = Py_None;
+
+ DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+
+error:
+ return ret;
+}
+
PyMethodDef BPY_rna_id_collection_user_map_method_def = {
"user_map",
(PyCFunction)bpy_user_map,
@@ -431,3 +516,9 @@ PyMethodDef BPY_rna_id_collection_orphans_purge_method_def = {
METH_STATIC | METH_VARARGS | METH_KEYWORDS,
bpy_orphans_purge_doc,
};
+PyMethodDef BPY_rna_id_collection_objects_link_multiple_method_def = {
+ "link_multiple",
+ (PyCFunction)bpy_link_multiple,
+ METH_VARARGS | METH_KEYWORDS,
+ bpy_link_multiple_doc,
+};
diff --git a/source/blender/python/intern/bpy_rna_id_collection.h b/source/blender/python/intern/bpy_rna_id_collection.h
index d06addc24e3..571d34c4dbb 100644
--- a/source/blender/python/intern/bpy_rna_id_collection.h
+++ b/source/blender/python/intern/bpy_rna_id_collection.h
@@ -13,6 +13,7 @@ extern "C" {
extern PyMethodDef BPY_rna_id_collection_user_map_method_def;
extern PyMethodDef BPY_rna_id_collection_batch_remove_method_def;
extern PyMethodDef BPY_rna_id_collection_orphans_purge_method_def;
+extern PyMethodDef BPY_rna_id_collection_objects_link_multiple_method_def;
#ifdef __cplusplus
}
diff --git a/source/blender/python/intern/bpy_rna_types_capi.c b/source/blender/python/intern/bpy_rna_types_capi.c
index 2b830eb9ffe..3481995a472 100644
--- a/source/blender/python/intern/bpy_rna_types_capi.c
+++ b/source/blender/python/intern/bpy_rna_types_capi.c
@@ -101,6 +101,17 @@ static struct PyMethodDef pyrna_text_methods[] = {
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Collection Objects
+ * \{ */
+
+static struct PyMethodDef pyrna_collection_objects_methods[] = {
+ {NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_objects_link_multiple_method_def */
+ {NULL, NULL, 0, NULL},
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Window Manager Clipboard Property
*
* Avoid using the RNA API because this value may change between checking its length
@@ -275,6 +286,12 @@ void BPY_rna_types_extend_capi(void)
ARRAY_SET_ITEMS(pyrna_context_methods, BPY_rna_context_temp_override_method_def);
pyrna_struct_type_extend_capi(&RNA_Context, pyrna_context_methods, NULL);
+
+ /* Collection Objects */
+ ARRAY_SET_ITEMS(pyrna_collection_objects_methods,
+ BPY_rna_id_collection_objects_link_multiple_method_def);
+ BLI_assert(ARRAY_SIZE(pyrna_collection_objects_methods) == 2);
+ pyrna_struct_type_extend_capi(&RNA_CollectionObjects, pyrna_collection_objects_methods, NULL);
}
/** \} */