Blender V4.3
collection.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9/* Allow using deprecated functionality for .blend file I/O. */
10#define DNA_DEPRECATED_ALLOW
11
12#include "CLG_log.h"
13
14#include <cstring>
15#include <optional>
16
17#include "BLI_blenlib.h"
18#include "BLI_iterator.h"
19#include "BLI_listbase.h"
20#include "BLI_math_base.h"
21#include "BLI_string_utils.hh"
22#include "BLI_threads.h"
23#include "BLT_translation.hh"
24
25#include "BKE_anim_data.hh"
26#include "BKE_collection.hh"
27#include "BKE_idprop.hh"
28#include "BKE_idtype.hh"
29#include "BKE_layer.hh"
30#include "BKE_lib_id.hh"
31#include "BKE_lib_query.hh"
32#include "BKE_lib_remap.hh"
33#include "BKE_main.hh"
34#include "BKE_object.hh"
35#include "BKE_preview_image.hh"
36#include "BKE_report.hh"
37#include "BKE_rigidbody.h"
38#include "BKE_scene.hh"
39
40#include "DNA_defaults.h"
41
42#include "DNA_ID.h"
44#include "DNA_layer_types.h"
45#include "DNA_object_types.h"
46#include "DNA_rigidbody_types.h"
47#include "DNA_scene_types.h"
48
49#include "DEG_depsgraph.hh"
51
52#include "MEM_guardedalloc.h"
53
54#include "BLO_read_write.hh"
55
56static CLG_LogRef LOG = {"bke.collection"};
57
61// #define USE_DEBUG_EXTRA_GOBJECT_ASSERT
62
63/* -------------------------------------------------------------------- */
68static bool collection_child_add(Main *bmain,
69 Collection *parent,
70 Collection *collection,
71 const CollectionLightLinking *light_linking,
72 const int id_create_flag,
73 const bool add_us);
75static bool collection_child_remove(Main *bmain,
76 Collection *parent,
77 Collection *collection,
78 const int id_create_flag);
80static bool collection_object_add(Main *bmain,
81 Collection *collection,
82 Object *ob,
83 CollectionLightLinking *light_linking,
84 const int id_create_flag,
85 const bool add_us);
86
89 Collection *collection,
91 const int id_create_flag,
92 const bool free_us);
94static bool collection_object_remove(
95 Main *bmain, Collection *collection, Object *ob, const int id_create_flag, const bool free_us);
96
98
99static bool collection_find_child_recursive(const Collection *parent,
100 const Collection *collection);
101
103static void collection_object_cache_free(const Main *bmain,
104 Collection *collection,
105 const int id_create_flag,
106 const uint id_recalc_flag);
107
108static void collection_gobject_hash_ensure(Collection *collection);
110 Object *ob_old,
111 CollectionObject *cob);
112static void collection_exporter_copy(Collection *collection, CollectionExport *data);
113
116/* -------------------------------------------------------------------- */
120static void collection_init_data(ID *id)
121{
122 Collection *collection = (Collection *)id;
124
126}
127
138static void collection_copy_data(Main *bmain,
139 std::optional<Library *> /*owner_library*/,
140 ID *id_dst,
141 const ID *id_src,
142 const int flag)
143{
144 Collection *collection_dst = (Collection *)id_dst;
145 const Collection *collection_src = (const Collection *)id_src;
146
147 BLI_assert(((collection_src->flag & COLLECTION_IS_MASTER) != 0) ==
148 ((collection_src->id.flag & ID_FLAG_EMBEDDED_DATA) != 0));
149
150 /* Do not copy collection's preview (same behavior as for objects). */
151 if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO: temp hack. */
152 BKE_previewimg_id_copy(&collection_dst->id, &collection_src->id);
153 }
154 else {
155 collection_dst->preview = nullptr;
156 }
157
159 BLI_listbase_clear(&collection_dst->runtime.object_cache);
161
162 BLI_listbase_clear(&collection_dst->gobject);
163 BLI_listbase_clear(&collection_dst->children);
164 BLI_listbase_clear(&collection_dst->exporters);
165 BLI_listbase_clear(&collection_dst->runtime.parents);
166 collection_dst->runtime.gobject_hash = nullptr;
167
168 LISTBASE_FOREACH (CollectionChild *, child, &collection_src->children) {
170 bmain, collection_dst, child->collection, &child->light_linking, flag, false);
171 }
172 LISTBASE_FOREACH (CollectionObject *, cob, &collection_src->gobject) {
173 collection_object_add(bmain, collection_dst, cob->ob, &cob->light_linking, flag, false);
174 }
175 LISTBASE_FOREACH (CollectionExport *, data, &collection_src->exporters) {
176 collection_exporter_copy(collection_dst, data);
177 }
178}
179
180static void collection_free_data(ID *id)
181{
182 Collection *collection = (Collection *)id;
183
184 /* No animation-data here. */
185 BKE_previewimg_free(&collection->preview);
186
187 BLI_freelistN(&collection->gobject);
188 if (collection->runtime.gobject_hash) {
189 BLI_ghash_free(collection->runtime.gobject_hash, nullptr, nullptr);
190 collection->runtime.gobject_hash = nullptr;
191 }
192
193 BLI_freelistN(&collection->children);
194 BLI_freelistN(&collection->runtime.parents);
195
196 LISTBASE_FOREACH (CollectionExport *, data, &collection->exporters) {
198 }
199 BLI_freelistN(&collection->exporters);
200
201 /* No need for depsgraph tagging here, since the data is being deleted. */
203}
204
206{
207 Collection *collection = (Collection *)id;
208 const int data_flags = BKE_lib_query_foreachid_process_flags_get(data);
209
211 data,
212 collection->owner_id,
214
215 LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
216 Object *cob_ob_old = cob->ob;
217
220
221 if (collection->runtime.gobject_hash) {
222 /* If the remapping does not create inconsistent data (nullptr object pointer or duplicate
223 * CollectionObjects), keeping the ghash consistent is also possible. Otherwise, this call
224 * will take care of tagging the collection objects list as dirty. */
225 collection_gobject_hash_update_object(collection, cob_ob_old, cob);
226 }
227 else if (cob_ob_old != cob->ob || cob->ob == nullptr) {
228 /* If there is no reference GHash, duplicates cannot be reliably detected, so assume that any
229 * nullptr pointer or changed pointer may create an invalid collection object list. */
230 collection->runtime.tag |= COLLECTION_TAG_COLLECTION_OBJECT_DIRTY;
231 }
232 }
233 LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
235 child->collection,
238 }
239 LISTBASE_FOREACH (CollectionParent *, parent, &collection->runtime.parents) {
240 /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad
241 * anyway... */
242 const int cb_flag = ((parent->collection != nullptr &&
243 (data_flags & IDWALK_NO_ORIG_POINTERS_ACCESS) == 0 &&
244 (parent->collection->id.flag & ID_FLAG_EMBEDDED_DATA) != 0) ?
248 data, parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK | cb_flag);
249 }
250}
251
252static ID **collection_owner_pointer_get(ID *id, const bool debug_relationship_assert)
253{
254 if ((id->flag & ID_FLAG_EMBEDDED_DATA) == 0) {
255 return nullptr;
256 }
257
258 Collection *master_collection = (Collection *)id;
259 BLI_assert((master_collection->flag & COLLECTION_IS_MASTER) != 0);
260 if (debug_relationship_assert) {
261 BLI_assert(master_collection->owner_id != nullptr);
262 BLI_assert(GS(master_collection->owner_id->name) == ID_SCE);
263 BLI_assert(((Scene *)master_collection->owner_id)->master_collection == master_collection);
264 }
265
266 return &master_collection->owner_id;
267}
268
270{
271 memset(&collection->runtime, 0, sizeof(collection->runtime));
272 /* Clean up, important in undo case to reduce false detection of changed data-blocks. */
273 collection->flag &= ~COLLECTION_FLAG_ALL_RUNTIME;
274}
275
277{
278 BKE_id_blend_write(writer, &collection->id);
279
280 /* Shared function for collection data-blocks and scene master collection. */
281 BKE_previewimg_blend_write(writer, collection->preview);
282
283 LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
285 }
286
287 LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
288 BLO_write_struct(writer, CollectionChild, child);
289 }
290
291 LISTBASE_FOREACH (CollectionExport *, data, &collection->exporters) {
292 BLO_write_struct(writer, CollectionExport, data);
293 if (data->export_properties) {
294 IDP_BlendWrite(writer, data->export_properties);
295 }
296 }
297}
298
299static void collection_blend_write(BlendWriter *writer, ID *id, const void *id_address)
300{
301 Collection *collection = (Collection *)id;
302
304
305 /* write LibData */
306 BLO_write_id_struct(writer, Collection, id_address, &collection->id);
307
308 BKE_collection_blend_write_nolib(writer, collection);
309}
310
311void BKE_collection_blend_read_data(BlendDataReader *reader, Collection *collection, ID *owner_id)
312{
313 /* Special case for this pointer, do not rely on regular `lib_link` process here. Avoids needs
314 * for do_versioning, and ensures coherence of data in any case.
315 *
316 * NOTE: Old versions are very often 'broken' here, just fix it silently in these cases.
317 */
318 if (BLO_read_fileversion_get(reader) > 300) {
319 BLI_assert((collection->id.flag & ID_FLAG_EMBEDDED_DATA) != 0 || owner_id == nullptr);
320 }
321 BLI_assert(owner_id == nullptr || owner_id->lib == collection->id.lib);
322 if (owner_id != nullptr && (collection->id.flag & ID_FLAG_EMBEDDED_DATA) == 0) {
323 /* This is unfortunate, but currently a lot of existing files (including startup ones) have
324 * missing `ID_FLAG_EMBEDDED_DATA` flag.
325 *
326 * NOTE: Using do_version is not a solution here, since this code will be called before any
327 * do_version takes place. Keeping it here also ensures future (or unknown existing) similar
328 * bugs won't go easily unnoticed. */
329 if (BLO_read_fileversion_get(reader) > 300) {
330 CLOG_WARN(&LOG,
331 "Fixing root node tree '%s' owned by '%s' missing EMBEDDED tag, please consider "
332 "re-saving your (startup) file",
333 collection->id.name,
334 owner_id->name);
335 }
336 collection->id.flag |= ID_FLAG_EMBEDDED_DATA;
337 }
338
339 memset(&collection->runtime, 0, sizeof(collection->runtime));
340 collection->flag &= ~COLLECTION_FLAG_ALL_RUNTIME;
341
342 collection->owner_id = owner_id;
343
344 BLO_read_struct_list(reader, CollectionObject, &collection->gobject);
345 BLO_read_struct_list(reader, CollectionChild, &collection->children);
346
347 BLO_read_struct_list(reader, CollectionExport, &collection->exporters);
348 LISTBASE_FOREACH (CollectionExport *, data, &collection->exporters) {
349 BLO_read_struct(reader, IDProperty, &data->export_properties);
350 IDP_BlendDataRead(reader, &data->export_properties);
351 }
352
353 BLO_read_struct(reader, PreviewImage, &collection->preview);
354 BKE_previewimg_blend_read(reader, collection->preview);
355}
356
358{
359 Collection *collection = (Collection *)id;
360 BKE_collection_blend_read_data(reader, collection, nullptr);
361}
362
364{
365 Collection *collection = reinterpret_cast<Collection *>(id);
366
367 /* Sanity check over Collection/Object data. */
368 BLI_assert(collection->runtime.gobject_hash == nullptr);
369 LISTBASE_FOREACH_MUTABLE (CollectionObject *, cob, &collection->gobject) {
370 if (cob->ob == nullptr) {
371 BLI_freelinkN(&collection->gobject, cob);
372 }
373 }
374
375 /* foreach_id code called by generic lib_link process has most likely set this flag, however it
376 * is not needed during readfile process since the runtime data is affects are not yet built, so
377 * just clear it here. */
378 BLI_assert(collection->runtime.gobject_hash == nullptr);
379 collection->runtime.tag &= ~COLLECTION_TAG_COLLECTION_OBJECT_DIRTY;
380}
381
383 /*id_code*/ ID_GR,
384 /*id_filter*/ FILTER_ID_GR,
385 /*dependencies_id_types*/ FILTER_ID_OB | FILTER_ID_GR,
386 /*main_listbase_index*/ INDEX_ID_GR,
387 /*struct_size*/ sizeof(Collection),
388 /*name*/ "Collection",
389 /*name_plural*/ N_("collections"),
390 /*translation_context*/ BLT_I18NCONTEXT_ID_COLLECTION,
392 /*asset_type_info*/ nullptr,
393
394 /*init_data*/ collection_init_data,
395 /*copy_data*/ collection_copy_data,
396 /*free_data*/ collection_free_data,
397 /*make_local*/ nullptr,
398 /*foreach_id*/ collection_foreach_id,
399 /*foreach_cache*/ nullptr,
400 /*foreach_path*/ nullptr,
401 /*owner_pointer_get*/ collection_owner_pointer_get,
402
403 /*blend_write*/ collection_blend_write,
404 /*blend_read_data*/ collection_blend_read_data,
405 /*blend_read_after_liblink*/ collection_blend_read_after_liblink,
406
407 /*blend_read_undo_preserve*/ nullptr,
408
409 /*lib_override_apply_post*/ nullptr,
410};
411
414/* -------------------------------------------------------------------- */
418/* Add new collection, without view layer syncing. */
420 Collection *collection_parent,
421 const char *name_custom)
422{
423 /* Determine new collection name. */
424 char name[MAX_NAME];
425
426 if (name_custom) {
427 STRNCPY(name, name_custom);
428 }
429 else {
430 BKE_collection_new_name_get(collection_parent, name);
431 }
432
433 /* Create new collection. */
434 Collection *collection = static_cast<Collection *>(BKE_id_new(bmain, ID_GR, name));
435
436 /* We increase collection user count when linking to Collections. */
437 id_us_min(&collection->id);
438
439 /* Optionally add to parent collection. */
440 if (collection_parent) {
441 collection_child_add(bmain, collection_parent, collection, nullptr, 0, true);
442 }
443
444 return collection;
445}
446
447Collection *BKE_collection_add(Main *bmain, Collection *collection_parent, const char *name_custom)
448{
449 Collection *collection = collection_add(bmain, collection_parent, name_custom);
451 return collection;
452}
453
455 Scene *scene,
456 const Object *ob_src,
457 Collection *collection_dst)
458{
459 bool is_instantiated = false;
460
461 FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
462 if (!ID_IS_LINKED(collection) && !ID_IS_OVERRIDABLE_LIBRARY(collection) &&
463 BKE_collection_has_object(collection, ob_src))
464 {
465 collection_child_add(bmain, collection, collection_dst, nullptr, 0, true);
466 is_instantiated = true;
467 }
468 }
470
471 if (!is_instantiated) {
472 collection_child_add(bmain, scene->master_collection, collection_dst, nullptr, 0, true);
473 }
474
476}
477
479 Scene *scene,
480 Collection *collection_src,
481 Collection *collection_dst)
482{
483 bool is_instantiated = false;
484
485 FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
486 if (ID_IS_EDITABLE(collection) && !ID_IS_OVERRIDE_LIBRARY(collection) &&
487 BKE_collection_child_find(collection, collection_src))
488 {
489 collection_child_add(bmain, collection, collection_dst, nullptr, 0, true);
490 is_instantiated = true;
491 }
492 else if (!is_instantiated && BKE_collection_child_find(collection, collection_dst)) {
493 /* If given collection_dst is already instantiated in scene, even if its 'model'
494 * collection_src one is not, do not add it to master scene collection. */
495 is_instantiated = true;
496 }
497 }
499
500 if (!is_instantiated) {
501 collection_child_add(bmain, scene->master_collection, collection_dst, nullptr, 0, true);
502 }
503
505}
506
509/* -------------------------------------------------------------------- */
514{
515 BKE_libblock_free_data(&collection->id, false);
516 collection_free_data(&collection->id);
517}
518
520 CollectionExport *data,
521 const char *newname)
522{
523 /* Only use the new name if it's not empty. */
524 if (newname && newname[0] != '\0') {
525 const ListBase list = exporters ? *exporters : BLI_listbase_from_link((Link *)data);
526
527 STRNCPY(data->name, newname);
529 &list, data, newname, '.', offsetof(CollectionExport, name), sizeof(data->name));
530 }
531}
532
534{
535 if (data->export_properties) {
536 IDP_FreeProperty(data->export_properties);
537 }
538}
539
540bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
541{
542 /* Master collection is not real datablock, can't be removed. */
543 if (collection->flag & COLLECTION_IS_MASTER) {
544 BLI_assert_msg(0, "Scene master collection can't be deleted");
545 return false;
546 }
547
548 /* This is being deleted, no need to handle each item.
549 * NOTE: While it might seem an advantage to use the hash instead of the list-lookup
550 * it is in fact slower because the items are removed in-order,
551 * so the list-lookup succeeds on the first test. */
552 if (collection->runtime.gobject_hash) {
553 BLI_ghash_free(collection->runtime.gobject_hash, nullptr, nullptr);
554 collection->runtime.gobject_hash = nullptr;
555 }
556
557 if (hierarchy) {
558 /* Remove child objects. */
559 CollectionObject *cob = static_cast<CollectionObject *>(collection->gobject.first);
560 while (cob != nullptr) {
562 bmain, collection, cob, LIB_ID_CREATE_NO_DEG_TAG, true);
563 cob = static_cast<CollectionObject *>(collection->gobject.first);
564 }
565
566 /* Delete all child collections recursively. */
567 CollectionChild *child = static_cast<CollectionChild *>(collection->children.first);
568 while (child != nullptr) {
569 BKE_collection_delete(bmain, child->collection, hierarchy);
570 child = static_cast<CollectionChild *>(collection->children.first);
571 }
572 }
573 else {
574 /* Link child collections into parent collection. */
575 LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
576 LISTBASE_FOREACH (CollectionParent *, cparent, &collection->runtime.parents) {
577 Collection *parent = cparent->collection;
578 collection_child_add(bmain, parent, child->collection, nullptr, 0, true);
579 }
580 }
581
582 CollectionObject *cob = static_cast<CollectionObject *>(collection->gobject.first);
583 while (cob != nullptr) {
584 /* Link child object into parent collections. */
585 LISTBASE_FOREACH (CollectionParent *, cparent, &collection->runtime.parents) {
586 Collection *parent = cparent->collection;
587 collection_object_add(bmain, parent, cob->ob, nullptr, 0, true);
588 }
589
590 /* Remove child object. */
592 bmain, collection, cob, LIB_ID_CREATE_NO_DEG_TAG, true);
593 cob = static_cast<CollectionObject *>(collection->gobject.first);
594 }
595 }
596
597 BKE_id_delete(bmain, collection);
598
600
601 return true;
602}
603
606/* -------------------------------------------------------------------- */
611 Collection *parent,
612 Collection *collection_old,
613 CollectionChild *child_old,
614 const int id_create_flag,
615 const eDupli_ID_Flags duplicate_flags,
616 const eLibIDDuplicateFlags duplicate_options)
617{
618 Collection *collection_new;
619 bool do_full_process = false;
620 const bool is_collection_master = (collection_old->flag & COLLECTION_IS_MASTER) != 0;
621
622 const bool do_objects = (duplicate_flags & USER_DUP_OBJECT) != 0;
623
624 if (is_collection_master) {
625 /* We never duplicate master collections here, but we can still deep-copy their objects and
626 * collections. */
627 BLI_assert(parent == nullptr);
628 collection_new = collection_old;
629 do_full_process = true;
630 }
631 else if (collection_old->id.newid == nullptr) {
632 collection_new = (Collection *)BKE_id_copy_for_duplicate(
633 bmain, (ID *)collection_old, duplicate_flags, id_create_flag);
634
635 if (collection_new == collection_old) {
636 return collection_new;
637 }
638
639 do_full_process = true;
640 }
641 else {
642 collection_new = (Collection *)collection_old->id.newid;
643 }
644
645 /* Optionally add to parent (we always want to do that,
646 * even if collection_old had already been duplicated). */
647 if (parent != nullptr) {
648 if (collection_child_add(bmain,
649 parent,
650 collection_new,
651 child_old ? &child_old->light_linking : nullptr,
652 id_create_flag,
653 true))
654 {
655 /* Put collection right after existing one.
656 * NOTE: Lookup child in the actual parent, as the parent might be different
657 * one when duplicating collection in a linked parent. */
658 CollectionChild *child = BKE_collection_child_find(parent, collection_old);
659 CollectionChild *child_new = BKE_collection_child_find(parent, collection_new);
660
661 if (child && child_new) {
662 BLI_remlink(&parent->children, child_new);
663 BLI_insertlinkafter(&parent->children, child, child_new);
664 }
665 }
666 }
667
668 /* If we are not doing any kind of deep-copy, we can return immediately.
669 * False do_full_process means collection_old had already been duplicated,
670 * no need to redo some deep-copy on it. */
671 if (!do_full_process) {
672 return collection_new;
673 }
674
675 if (do_objects) {
676 /* We need to first duplicate the objects in a separate loop, to support the master collection
677 * case, where both old and new collections are the same.
678 * Otherwise, depending on naming scheme and sorting, we may end up duplicating the new objects
679 * we just added, in some infinite loop. */
680 LISTBASE_FOREACH (CollectionObject *, cob, &collection_old->gobject) {
681 Object *ob_old = cob->ob;
682
683 if (ob_old->id.newid == nullptr) {
685 bmain, ob_old, duplicate_flags, duplicate_options | LIB_ID_DUPLICATE_IS_SUBPROCESS);
686 }
687 }
688
689 /* We can loop on collection_old's objects, but have to consider it mutable because with master
690 * collections collection_old and collection_new are the same data here. */
691 LISTBASE_FOREACH_MUTABLE (CollectionObject *, cob, &collection_old->gobject) {
692 Object *ob_old = cob->ob;
693 Object *ob_new = (Object *)ob_old->id.newid;
694
695 /* New object can be nullptr in master collection case, since new and old objects are in same
696 * collection. */
697 if (ELEM(ob_new, ob_old, nullptr)) {
698 continue;
699 }
700
702 bmain, collection_new, ob_new, &cob->light_linking, id_create_flag, true);
703 collection_object_remove(bmain, collection_new, ob_old, id_create_flag, false);
704 }
705 }
706
707 /* We can loop on collection_old's children,
708 * that list is currently identical the collection_new' children, and won't be changed here. */
709 LISTBASE_FOREACH_MUTABLE (CollectionChild *, child_iter, &collection_old->children) {
710 Collection *child_collection_old = child_iter->collection;
711
712 Collection *child_collection_new = collection_duplicate_recursive(bmain,
713 collection_new,
714 child_collection_old,
715 child_iter,
716 id_create_flag,
717 duplicate_flags,
718 duplicate_options);
719 if (child_collection_new != child_collection_old) {
720 collection_child_remove(bmain, collection_new, child_collection_old, id_create_flag);
721 }
722 }
723
724 return collection_new;
725}
726
728 Collection *parent,
729 CollectionChild *child_old,
730 Collection *collection,
731 /*eDupli_ID_Flags*/ uint duplicate_flags,
732 /*eLibIDDuplicateFlags*/ uint duplicate_options)
733{
734 const bool is_subprocess = (duplicate_options & LIB_ID_DUPLICATE_IS_SUBPROCESS) != 0;
735 const bool is_root_id = (duplicate_options & LIB_ID_DUPLICATE_IS_ROOT_ID) != 0;
736 const int id_create_flag = (collection->id.tag & ID_TAG_NO_MAIN) ? LIB_ID_CREATE_NO_MAIN : 0;
737
738 if (!is_subprocess) {
740 }
741 if (is_root_id) {
742 /* In case root duplicated ID is linked, assume we want to get a local copy of it and duplicate
743 * all expected linked data. */
744 if (ID_IS_LINKED(collection)) {
745 duplicate_flags |= USER_DUP_LINKED_ID;
746 }
747 duplicate_options &= ~LIB_ID_DUPLICATE_IS_ROOT_ID;
748 }
749
751 bmain,
752 parent,
753 collection,
754 child_old,
755 id_create_flag,
756 eDupli_ID_Flags(duplicate_flags),
757 eLibIDDuplicateFlags(duplicate_options));
758
759 if (!is_subprocess) {
760 /* `collection_duplicate_recursive` will also tag our 'root' collection, which is not required
761 * unless its duplication is a sub-process of another one. */
762 collection_new->id.tag &= ~ID_TAG_NEW;
763
764 /* This code will follow into all ID links using an ID tagged with ID_TAG_NEW. */
765 BKE_libblock_relink_to_newid(bmain, &collection_new->id, 0);
766
767#ifndef NDEBUG
768 /* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those flags. */
769 ID *id_iter;
770 FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
771 if (id_iter->tag & ID_TAG_NEW) {
772 BLI_assert((id_iter->tag & ID_TAG_NEW) == 0);
773 }
774 }
776#endif
777
778 /* Cleanup. */
780
782 }
783
784 return collection_new;
785}
786
789/* -------------------------------------------------------------------- */
793void BKE_collection_new_name_get(Collection *collection_parent, char *rname)
794{
795 char *name;
796
797 if (!collection_parent) {
798 name = BLI_strdup(DATA_("Collection"));
799 }
800 else if (collection_parent->flag & COLLECTION_IS_MASTER) {
801 name = BLI_sprintfN(DATA_("Collection %d"),
802 BLI_listbase_count(&collection_parent->children) + 1);
803 }
804 else {
805 const int number = BLI_listbase_count(&collection_parent->children) + 1;
806 const int digits = integer_digits_i(number);
807 const int max_len = sizeof(collection_parent->id.name) - 1 /* nullptr terminator */ -
808 (1 + digits) /* " %d" */ - 2 /* ID */;
809 name = BLI_sprintfN("%.*s %d", max_len, collection_parent->id.name + 2, number);
810 }
811
812 BLI_strncpy(rname, name, MAX_NAME);
813 MEM_freeN(name);
814}
815
817{
818 if (collection->flag & COLLECTION_IS_MASTER) {
819 return IFACE_("Scene Collection");
820 }
821
822 return collection->id.name + 2;
823}
824
827/* -------------------------------------------------------------------- */
832 Collection *collection,
833 int parent_restrict,
834 bool with_instances)
835{
836 int child_restrict = collection->flag | parent_restrict;
837
838 LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
839 Base *base = static_cast<Base *>(BLI_findptr(lb, cob->ob, offsetof(Base, object)));
840
841 if (base == nullptr) {
842 base = static_cast<Base *>(MEM_callocN(sizeof(Base), "Object Base"));
843 base->object = cob->ob;
844 BLI_addtail(lb, base);
845 if (with_instances && cob->ob->instance_collection) {
847 lb, cob->ob->instance_collection, child_restrict, with_instances);
848 }
849 }
850
851 /* Only collection flags are checked here currently, object restrict flag is checked
852 * in FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN since it can be animated
853 * without updating the cache. */
854 if ((child_restrict & COLLECTION_HIDE_VIEWPORT) == 0) {
856 }
857 if ((child_restrict & COLLECTION_HIDE_RENDER) == 0) {
858 base->flag |= BASE_ENABLED_RENDER;
859 }
860 }
861
862 LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
863 collection_object_cache_fill(lb, child->collection, child_restrict, with_instances);
864 }
865}
866
868{
869 if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) {
870 static ThreadMutex cache_lock = BLI_MUTEX_INITIALIZER;
871
872 BLI_mutex_lock(&cache_lock);
873 if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) {
874 collection_object_cache_fill(&collection->runtime.object_cache, collection, 0, false);
875 collection->flag |= COLLECTION_HAS_OBJECT_CACHE;
876 }
877 BLI_mutex_unlock(&cache_lock);
878 }
879
880 return collection->runtime.object_cache;
881}
882
884{
885 if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE_INSTANCED)) {
886 static ThreadMutex cache_lock = BLI_MUTEX_INITIALIZER;
887
888 BLI_mutex_lock(&cache_lock);
889 if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE_INSTANCED)) {
891 &collection->runtime.object_cache_instanced, collection, 0, true);
892 collection->flag |= COLLECTION_HAS_OBJECT_CACHE_INSTANCED;
893 }
894 BLI_mutex_unlock(&cache_lock);
895 }
896
897 return collection->runtime.object_cache_instanced;
898}
899
900static void collection_object_cache_free(const Main *bmain,
901 Collection *collection,
902 const int id_create_flag,
903 const uint id_recalc_flag)
904{
906 BLI_freelistN(&collection->runtime.object_cache);
907 BLI_freelistN(&collection->runtime.object_cache_instanced);
908
909 /* Although it may seem abusive to call depsgraph updates from this utility function,
910 * it is called from any code-path modifying the collections hierarchy and/or their objects.
911 * Including the reversed-hierarchy walked by #collection_object_cache_free_parent_recursive.
912 *
913 * Plus, the main reason to tag the hierarchy of parents for deg update is because their object
914 * caches are being freed.
915 *
916 * Having this code here avoids the need for another utility tagging function processing the
917 * parent hierarchy as well. */
918 if (id_recalc_flag && (id_create_flag & (LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_DEG_TAG)) == 0)
919 {
920 BLI_assert(bmain != nullptr);
921 DEG_id_tag_update_ex(const_cast<Main *>(bmain), &collection->id, id_recalc_flag);
922 }
923}
924
927 Collection *collection,
928 const int id_create_flag,
929 const uint id_recalc_flag)
930{
931 collection_object_cache_free(bmain, collection, id_create_flag, id_recalc_flag);
932
933 /* Clear cache in all parents recursively, since those are affected by changes as well. */
934 LISTBASE_FOREACH (CollectionParent *, parent, &collection->runtime.parents) {
935 /* In theory there should be no nullptr pointer here. However, this code can be called from
936 * non-valid temporary states (e.g. indirectly from #BKE_collections_object_remove_invalids
937 * as part of ID remapping process). */
938 if (parent->collection == nullptr) {
939 continue;
940 }
942 bmain, parent->collection, id_create_flag, id_recalc_flag);
943 }
944}
945
947 Collection *collection,
948 const int id_create_flag)
949{
950 BLI_assert(collection != nullptr);
952 bmain, collection, id_create_flag, ID_RECALC_HIERARCHY | ID_RECALC_GEOMETRY);
953}
954
956{
957 for (Scene *scene = static_cast<Scene *>(bmain->scenes.first); scene != nullptr;
958 scene = static_cast<Scene *>(scene->id.next))
959 {
961 bmain, scene->master_collection, 0, ID_RECALC_HIERARCHY | ID_RECALC_GEOMETRY);
962 }
963
964 for (Collection *collection = static_cast<Collection *>(bmain->collections.first);
965 collection != nullptr;
966 collection = static_cast<Collection *>(collection->id.next))
967 {
969 }
970}
971
973 ViewLayer *view_layer,
974 Collection *collection)
975{
976 if (collection) {
977 return static_cast<Base *>(BKE_collection_object_cache_get(collection).first);
978 }
979 BKE_view_layer_synced_ensure(scene, view_layer);
980 return static_cast<Base *>(BKE_view_layer_object_bases_get(view_layer)->first);
981}
982
985/* -------------------------------------------------------------------- */
990{
991 BLI_assert(scene != nullptr && scene->master_collection == nullptr);
992
993 /* Not an actual datablock, but owned by scene. */
994 Collection *master_collection = static_cast<Collection *>(BKE_libblock_alloc_in_lib(
995 nullptr, scene->id.lib, ID_GR, BKE_SCENE_COLLECTION_NAME, LIB_ID_CREATE_NO_MAIN));
996 master_collection->id.flag |= ID_FLAG_EMBEDDED_DATA;
997 master_collection->owner_id = &scene->id;
998 master_collection->flag |= COLLECTION_IS_MASTER;
999 master_collection->color_tag = COLLECTION_COLOR_NONE;
1000
1001 BLI_assert(scene->id.lib == master_collection->id.lib);
1002
1003 return master_collection;
1004}
1005
1008/* -------------------------------------------------------------------- */
1013{
1014 if (object->instance_collection) {
1015 Collection *dup_collection = object->instance_collection;
1016 if ((dup_collection->id.tag & ID_TAG_DOIT) == 0) {
1017 /* Cycle already exists in collections, let's prevent further creepiness. */
1018 return true;
1019 }
1020 /* flag the object to identify cyclic dependencies in further dupli collections */
1021 dup_collection->id.tag &= ~ID_TAG_DOIT;
1022
1023 if (dup_collection == collection) {
1024 return true;
1025 }
1026
1027 FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (dup_collection, collection_object) {
1028 if (collection_object_cyclic_check_internal(collection_object, dup_collection)) {
1029 return true;
1030 }
1031 }
1033
1034 /* un-flag the object, it's allowed to have the same collection multiple times in parallel */
1035 dup_collection->id.tag |= ID_TAG_DOIT;
1036 }
1037
1038 return false;
1039}
1040
1042{
1043 /* first flag all collections */
1045
1046 return collection_object_cyclic_check_internal(object, collection);
1047}
1048
1051/* -------------------------------------------------------------------- */
1055bool BKE_collection_has_object(Collection *collection, const Object *ob)
1056{
1057 if (ELEM(nullptr, collection, ob)) {
1058 return false;
1059 }
1061 return BLI_ghash_lookup(collection->runtime.gobject_hash, ob);
1062}
1063
1065{
1066 if (ELEM(nullptr, collection, ob)) {
1067 return false;
1068 }
1069
1070 const ListBase objects = BKE_collection_object_cache_get(collection);
1071 return BLI_findptr(&objects, ob, offsetof(Base, object));
1072}
1073
1075{
1076 if (ELEM(nullptr, collection, ob)) {
1077 return false;
1078 }
1079
1080 const ListBase objects = BKE_collection_object_cache_instanced_get(collection);
1081 return BLI_findptr(&objects, ob, offsetof(Base, object));
1082}
1083
1085 Object *object_eval)
1086{
1087 BLI_assert(collection_eval->id.tag & ID_TAG_COPIED_ON_EVAL);
1088 const ID *ob_orig = DEG_get_original_id(&object_eval->id);
1089 const ListBase objects = BKE_collection_object_cache_instanced_get(collection_eval);
1090 LISTBASE_FOREACH (Base *, base, &objects) {
1091 if (DEG_get_original_id(&base->object->id) == ob_orig) {
1092 return true;
1093 }
1094 }
1095 return false;
1096}
1097
1098static Collection *collection_next_find(Main *bmain, Scene *scene, Collection *collection)
1099{
1100 if (scene && collection == scene->master_collection) {
1101 return static_cast<Collection *>(bmain->collections.first);
1102 }
1103
1104 return static_cast<Collection *>(collection->id.next);
1105}
1106
1108 Scene *scene,
1109 Collection *collection,
1110 Object *ob)
1111{
1112 if (collection) {
1113 collection = collection_next_find(bmain, scene, collection);
1114 }
1115 else if (scene) {
1116 collection = scene->master_collection;
1117 }
1118 else {
1119 collection = static_cast<Collection *>(bmain->collections.first);
1120 }
1121
1122 while (collection) {
1123 if (BKE_collection_has_object(collection, ob)) {
1124 return collection;
1125 }
1126 collection = collection_next_find(bmain, scene, collection);
1127 }
1128 return nullptr;
1129}
1130
1132{
1133 return BLI_listbase_is_empty(&collection->gobject) &&
1134 BLI_listbase_is_empty(&collection->children);
1135}
1136
1139/* -------------------------------------------------------------------- */
1144 const bool do_extensive_check);
1145
1147{
1148 return BLI_ghash_ptr_new_ex(__func__, uint(BLI_listbase_count(&collection->gobject)));
1149}
1150
1152{
1153 GHash *gobject_hash = collection_gobject_hash_alloc(collection);
1154 LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
1155 if (UNLIKELY(cob->ob == nullptr)) {
1156 BLI_assert(collection->runtime.tag & COLLECTION_TAG_COLLECTION_OBJECT_DIRTY);
1157 continue;
1158 }
1159 CollectionObject **cob_p;
1160 /* Do not overwrite an already existing entry. */
1161 if (UNLIKELY(BLI_ghash_ensure_p(gobject_hash, cob->ob, (void ***)&cob_p))) {
1162 BLI_assert(collection->runtime.tag & COLLECTION_TAG_COLLECTION_OBJECT_DIRTY);
1163 continue;
1164 }
1165 *cob_p = cob;
1166 }
1167 collection->runtime.gobject_hash = gobject_hash;
1168}
1169
1171{
1172 if (collection->runtime.gobject_hash) {
1173#ifdef USE_DEBUG_EXTRA_GOBJECT_ASSERT
1175#endif
1176 return;
1177 }
1178
1180
1182}
1183
1189{
1190 bool changed = false;
1191
1192 if ((collection->runtime.tag & COLLECTION_TAG_COLLECTION_OBJECT_DIRTY) == 0) {
1193#ifdef USE_DEBUG_EXTRA_GOBJECT_ASSERT
1195#endif
1196 return;
1197 }
1198
1199 GHash *gobject_hash = collection->runtime.gobject_hash;
1200 if (gobject_hash) {
1201 BLI_ghash_clear_ex(gobject_hash, nullptr, nullptr, BLI_ghash_len(gobject_hash));
1202 }
1203 else {
1204 collection->runtime.gobject_hash = gobject_hash = collection_gobject_hash_alloc(collection);
1205 }
1206
1207 LISTBASE_FOREACH_MUTABLE (CollectionObject *, cob, &collection->gobject) {
1208 if (cob->ob == nullptr) {
1209 BLI_freelinkN(&collection->gobject, cob);
1210 changed = true;
1211 continue;
1212 }
1213 CollectionObject **cob_p;
1214 if (BLI_ghash_ensure_p(gobject_hash, cob->ob, (void ***)&cob_p)) {
1215 BLI_freelinkN(&collection->gobject, cob);
1216 changed = true;
1217 continue;
1218 }
1219 *cob_p = cob;
1220 }
1221
1222 if (changed) {
1223 BKE_collection_object_cache_free(bmain, collection, 0);
1224 }
1225
1226 collection->runtime.tag &= ~COLLECTION_TAG_COLLECTION_OBJECT_DIRTY;
1228}
1229
1245 Object *ob_old,
1246 CollectionObject *cob)
1247{
1248 if (ob_old == cob->ob) {
1249 return;
1250 }
1251
1252 if (ob_old) {
1253 CollectionObject *cob_old = static_cast<CollectionObject *>(
1254 BLI_ghash_popkey(collection->runtime.gobject_hash, ob_old, nullptr));
1255 if (cob_old != cob) {
1256 /* Old object already removed from the #GHash. */
1257 collection->runtime.tag |= COLLECTION_TAG_COLLECTION_OBJECT_DIRTY;
1258 }
1259 }
1260
1261 if (cob->ob) {
1262 CollectionObject **cob_p;
1263 if (!BLI_ghash_ensure_p(collection->runtime.gobject_hash, cob->ob, (void ***)&cob_p)) {
1264 *cob_p = cob;
1265 }
1266 else {
1267 /* Duplicate #CollectionObject entries. */
1268 collection->runtime.tag |= COLLECTION_TAG_COLLECTION_OBJECT_DIRTY;
1269 }
1270 }
1271 else {
1272 /* #CollectionObject with nullptr object pointer. */
1273 collection->runtime.tag |= COLLECTION_TAG_COLLECTION_OBJECT_DIRTY;
1274 }
1275}
1276
1291 const bool do_extensive_check)
1292{
1293 BLI_assert((collection->runtime.tag & COLLECTION_TAG_COLLECTION_OBJECT_DIRTY) == 0);
1294 if (!do_extensive_check) {
1295 return;
1296 }
1297
1298 if (collection->runtime.gobject_hash == nullptr) {
1299 /* NOTE: If the `ghash` does not exist yet, it's creation will assert on errors,
1300 * so in theory the second loop below could be skipped. */
1302 }
1303 GHash *gobject_hash = collection->runtime.gobject_hash;
1304 UNUSED_VARS_NDEBUG(gobject_hash);
1305 LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
1306 BLI_assert(cob->ob != nullptr);
1307 /* If there are more than one #CollectionObject for the same object,
1308 * at most one of them will pass this test. */
1309 BLI_assert(BLI_ghash_lookup(gobject_hash, cob->ob) == cob);
1310 }
1311}
1312
1314 Collection *collection)
1315{
1316 if (ID_IS_EDITABLE(collection) && !ID_IS_OVERRIDE_LIBRARY(collection) &&
1317 (view_layer == nullptr || BKE_view_layer_has_collection(view_layer, collection)))
1318 {
1319 return collection;
1320 }
1321
1322 if (collection->flag & COLLECTION_IS_MASTER) {
1323 return nullptr;
1324 }
1325
1326 LISTBASE_FOREACH (CollectionParent *, collection_parent, &collection->runtime.parents) {
1327 if (!ID_IS_LINKED(collection_parent->collection) &&
1328 !ID_IS_OVERRIDE_LIBRARY(collection_parent->collection))
1329 {
1330 if (view_layer != nullptr &&
1331 !BKE_view_layer_has_collection(view_layer, collection_parent->collection))
1332 {
1333 /* In case this parent collection is not in given view_layer, there is no point in
1334 * searching in its ancestors either, we can skip that whole parenting branch. */
1335 continue;
1336 }
1337 return collection_parent->collection;
1338 }
1340 view_layer, collection_parent->collection);
1341 if (editable_collection != nullptr) {
1342 return editable_collection;
1343 }
1344 }
1345
1346 return nullptr;
1347}
1348
1349static bool collection_object_add(Main *bmain,
1350 Collection *collection,
1351 Object *ob,
1352 CollectionLightLinking *light_linking,
1353 const int id_create_flag,
1354 const bool add_us)
1355{
1356 /* Cyclic dependency check. */
1357 if (ob->instance_collection) {
1358 if ((ob->instance_collection == collection) ||
1360 {
1361 return false;
1362 }
1363 }
1364
1366 CollectionObject **cob_p;
1367 if (BLI_ghash_ensure_p(collection->runtime.gobject_hash, ob, (void ***)&cob_p)) {
1368 return false;
1369 }
1370
1371 CollectionObject *cob = static_cast<CollectionObject *>(
1372 MEM_callocN(sizeof(CollectionObject), __func__));
1373 cob->ob = ob;
1374 if (light_linking) {
1375 cob->light_linking = *light_linking;
1376 }
1377 *cob_p = cob;
1378 BLI_addtail(&collection->gobject, cob);
1379 BKE_collection_object_cache_free(bmain, collection, id_create_flag);
1380
1381 if (add_us && (id_create_flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
1382 id_us_plus(&ob->id);
1383 }
1384
1385 if ((id_create_flag & LIB_ID_CREATE_NO_MAIN) == 0) {
1386 BKE_rigidbody_main_collection_object_add(bmain, collection, ob);
1387 }
1388
1389 return true;
1390}
1391
1397 Collection *collection,
1398 CollectionObject *cob,
1399 const int id_create_flag,
1400 const bool free_us)
1401{
1402 Object *ob = cob->ob;
1403 BLI_freelinkN(&collection->gobject, cob);
1404 BKE_collection_object_cache_free(bmain, collection, id_create_flag);
1405
1406 if (free_us) {
1407 BKE_id_free_us(bmain, ob);
1408 }
1409 else {
1410 id_us_min(&ob->id);
1411 }
1412}
1413
1415 Main *bmain, Collection *collection, Object *ob, const int id_create_flag, const bool free_us)
1416{
1418 CollectionObject *cob = static_cast<CollectionObject *>(
1419 BLI_ghash_popkey(collection->runtime.gobject_hash, ob, nullptr));
1420 if (cob == nullptr) {
1421 return false;
1422 }
1423 collection_object_remove_no_gobject_hash(bmain, collection, cob, id_create_flag, free_us);
1424 return true;
1425}
1426
1428{
1429 CollectionExport *new_data = MEM_cnew<CollectionExport>("CollectionExport");
1430 STRNCPY(new_data->fh_idname, data->fh_idname);
1431 new_data->export_properties = IDP_CopyProperty(data->export_properties);
1432 new_data->flag = data->flag;
1433
1434 /* Clear the `filepath` property. */
1435 IDProperty *filepath = IDP_GetPropertyFromGroup(new_data->export_properties, "filepath");
1436 if (filepath) {
1437 IDP_AssignString(filepath, "");
1438 }
1439
1440 BLI_addtail(&collection->exporters, new_data);
1441}
1442
1444{
1445 if (ob == nullptr) {
1446 return false;
1447 }
1448
1449 /* Only case where this pointer can be nullptr is when scene itself is linked, this case should
1450 * never be reached. */
1451 BLI_assert(collection != nullptr);
1452 if (collection == nullptr) {
1453 return false;
1454 }
1455
1456 const int id_create_flag = (collection->id.tag & ID_TAG_NO_MAIN) ? LIB_ID_CREATE_NO_MAIN : 0;
1457 if (!collection_object_add(bmain, collection, ob, nullptr, id_create_flag, true)) {
1458 return false;
1459 }
1460
1461 if (BKE_collection_is_in_scene(collection)) {
1463 }
1464
1465 return true;
1466}
1467
1468bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
1469{
1470 return BKE_collection_viewlayer_object_add(bmain, nullptr, collection, ob);
1471}
1472
1474 const ViewLayer *view_layer,
1475 Collection *collection,
1476 Object *ob)
1477{
1478 if (collection == nullptr) {
1479 return false;
1480 }
1481
1482 collection = BKE_collection_parent_editable_find_recursive(view_layer, collection);
1483
1484 if (collection == nullptr) {
1485 return false;
1486 }
1487
1488 return BKE_collection_object_add_notest(bmain, collection, ob);
1489}
1490
1491void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, Object *ob_dst)
1492{
1493 bool is_instantiated = false;
1494
1495 FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
1496 if (ID_IS_EDITABLE(collection) && !ID_IS_OVERRIDE_LIBRARY(collection) &&
1497 BKE_collection_has_object(collection, ob_src))
1498 {
1499 collection_object_add(bmain, collection, ob_dst, nullptr, 0, true);
1500 is_instantiated = true;
1501 }
1502 }
1504
1505 if (!is_instantiated) {
1506 /* In case we could not find any non-linked collections in which instantiate our ob_dst,
1507 * fallback to scene's master collection... */
1508 collection_object_add(bmain, scene->master_collection, ob_dst, nullptr, 0, true);
1509 }
1510
1512}
1513
1515 Collection *collection,
1516 Object *ob,
1517 const bool free_us)
1518{
1519 if (ELEM(nullptr, collection, ob)) {
1520 return false;
1521 }
1522
1523 const int id_create_flag = (collection->id.tag & ID_TAG_NO_MAIN) ? LIB_ID_CREATE_NO_MAIN : 0;
1524 if (!collection_object_remove(bmain, collection, ob, id_create_flag, free_us)) {
1525 return false;
1526 }
1527
1528 if (BKE_collection_is_in_scene(collection)) {
1530 }
1531
1532 return true;
1533}
1534
1536 Collection *collection,
1537 Object *ob_old,
1538 Object *ob_new)
1539{
1541 CollectionObject *cob;
1542 cob = static_cast<CollectionObject *>(
1543 BLI_ghash_popkey(collection->runtime.gobject_hash, ob_old, nullptr));
1544 if (cob == nullptr) {
1545 return false;
1546 }
1547
1548 if (!BLI_ghash_haskey(collection->runtime.gobject_hash, ob_new)) {
1549 id_us_min(&cob->ob->id);
1550 cob->ob = ob_new;
1551 id_us_plus(&cob->ob->id);
1552
1553 BLI_ghash_insert(collection->runtime.gobject_hash, cob->ob, cob);
1554 }
1555 else {
1556 collection_object_remove_no_gobject_hash(bmain, collection, cob, 0, false);
1557 }
1558
1559 if (BKE_collection_is_in_scene(collection)) {
1561 }
1562
1563 return true;
1564}
1565
1571 Main *bmain, Scene *scene, Object *ob, const bool free_us, Collection *collection_skip)
1572{
1573 bool removed = false;
1574 const int id_create_flag = (scene->id.tag & ID_TAG_NO_MAIN) ? LIB_ID_CREATE_NO_MAIN : 0;
1575
1576 /* If given object is removed from all collections in given scene, then it can also be safely
1577 * removed from rigidbody world for given scene. */
1578 if (collection_skip == nullptr) {
1579 BKE_scene_remove_rigidbody_object(bmain, scene, ob, free_us);
1580 }
1581
1582 FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
1583 if (!ID_IS_EDITABLE(collection) || ID_IS_OVERRIDE_LIBRARY(collection)) {
1584 continue;
1585 }
1586 if (collection == collection_skip) {
1587 continue;
1588 }
1589
1590 removed |= collection_object_remove(bmain, collection, ob, id_create_flag, free_us);
1591 }
1593
1595
1596 return removed;
1597}
1598
1599bool BKE_scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us)
1600{
1601 return scene_collections_object_remove(bmain, scene, ob, free_us, nullptr);
1602}
1603
1605{
1606 LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
1607 collection_gobject_hash_ensure_fix(bmain, scene->master_collection);
1608 }
1609
1610 LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
1611 collection_gobject_hash_ensure_fix(bmain, collection);
1612 }
1613}
1614
1616{
1617 LISTBASE_FOREACH_MUTABLE (CollectionChild *, child, &collection->children) {
1618 if (child->collection == nullptr) {
1619 BLI_freelinkN(&collection->children, child);
1620 }
1621 }
1622}
1623
1625{
1626 LISTBASE_FOREACH_MUTABLE (CollectionParent *, parent, &collection->runtime.parents) {
1627 if ((parent->collection == nullptr) ||
1628 !BKE_collection_child_find(parent->collection, collection))
1629 {
1630 BLI_freelinkN(&collection->runtime.parents, parent);
1631 }
1632 }
1633}
1634
1636 Collection *parent_collection,
1637 Collection *child_collection)
1638{
1639 if (child_collection == nullptr) {
1640 if (parent_collection != nullptr) {
1641 collection_null_children_remove(parent_collection);
1642 }
1643 else {
1644 /* We need to do the checks in two steps when more than one collection may be involved,
1645 * otherwise we can miss some cases...
1646 * Also, master collections are not in bmain, so we also need to loop over scenes.
1647 */
1648 LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
1650 }
1651 LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
1652 collection_null_children_remove(scene->master_collection);
1653 }
1654 }
1655
1656 LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
1658 }
1659 LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
1660 collection_missing_parents_remove(scene->master_collection);
1661 }
1662 }
1663 else {
1664 LISTBASE_FOREACH_MUTABLE (CollectionParent *, parent, &child_collection->runtime.parents) {
1665 collection_null_children_remove(parent->collection);
1666
1667 if (!BKE_collection_child_find(parent->collection, child_collection)) {
1668 BLI_freelinkN(&child_collection->runtime.parents, parent);
1669 }
1670 }
1671 }
1672}
1673
1675 Main *bmain, Scene *scene, Collection *collection_dst, Collection *collection_src, Object *ob)
1676{
1677 /* In both cases we first add the object, then remove it from the other collections.
1678 * Otherwise we lose the original base and whether it was active and selected. */
1679 if (collection_src != nullptr) {
1680 if (BKE_collection_object_add(bmain, collection_dst, ob)) {
1681 BKE_collection_object_remove(bmain, collection_src, ob, false);
1682 }
1683 }
1684 else {
1685 /* Adding will fail if object is already in collection.
1686 * However we still need to remove it from the other collections. */
1687 BKE_collection_object_add(bmain, collection_dst, ob);
1688 scene_collections_object_remove(bmain, scene, ob, false, collection_dst);
1689 }
1690}
1691
1694/* -------------------------------------------------------------------- */
1699{
1700 if (collection->flag & COLLECTION_IS_MASTER) {
1701 return true;
1702 }
1703
1704 LISTBASE_FOREACH (CollectionParent *, cparent, &collection->runtime.parents) {
1705 if (BKE_collection_is_in_scene(cparent->collection)) {
1706 return true;
1707 }
1708 }
1709
1710 return false;
1711}
1712
1714{
1715 /* Need to update layer collections because objects might have changed
1716 * in linked files, and because undo push does not include updated base
1717 * flags since those are refreshed after the operator completes. */
1719}
1720
1723/* -------------------------------------------------------------------- */
1728 Collection *instance_collection)
1729{
1730 LISTBASE_FOREACH (CollectionObject *, collection_object, &collection->gobject) {
1731 if (collection_object->ob != nullptr &&
1732 /* Object from a given collection should never instantiate that collection either. */
1733 ELEM(collection_object->ob->instance_collection, instance_collection, collection))
1734 {
1735 return true;
1736 }
1737 }
1738
1739 LISTBASE_FOREACH (CollectionChild *, collection_child, &collection->children) {
1740 if (collection_child->collection != nullptr &&
1741 collection_instance_find_recursive(collection_child->collection, instance_collection))
1742 {
1743 return true;
1744 }
1745 }
1746
1747 return false;
1748}
1749
1750bool BKE_collection_cycle_find(Collection *new_ancestor, Collection *collection)
1751{
1752 if (collection == new_ancestor) {
1753 return true;
1754 }
1755
1756 if (collection == nullptr) {
1757 collection = new_ancestor;
1758 }
1759
1760 LISTBASE_FOREACH (CollectionParent *, parent, &new_ancestor->runtime.parents) {
1761 if (BKE_collection_cycle_find(parent->collection, collection)) {
1762 return true;
1763 }
1764 }
1765
1766 /* Find possible objects in collection or its children, that would instantiate the given ancestor
1767 * collection (that would also make a fully invalid cycle of dependencies). */
1768 return collection_instance_find_recursive(collection, new_ancestor);
1769}
1770
1771static bool collection_instance_fix_recursive(Collection *parent_collection,
1772 Collection *collection)
1773{
1774 bool cycles_found = false;
1775
1776 LISTBASE_FOREACH (CollectionObject *, collection_object, &parent_collection->gobject) {
1777 if (collection_object->ob != nullptr &&
1778 collection_object->ob->instance_collection == collection)
1779 {
1780 id_us_min(&collection->id);
1781 collection_object->ob->instance_collection = nullptr;
1782 cycles_found = true;
1783 }
1784 }
1785
1786 LISTBASE_FOREACH (CollectionChild *, collection_child, &parent_collection->children) {
1787 if (collection_instance_fix_recursive(collection_child->collection, collection)) {
1788 cycles_found = true;
1789 }
1790 }
1791
1792 return cycles_found;
1793}
1794
1796 Collection *parent_collection,
1797 Collection *collection)
1798{
1799 bool cycles_found = false;
1800
1801 LISTBASE_FOREACH_MUTABLE (CollectionParent *, parent, &parent_collection->runtime.parents) {
1802 if (BKE_collection_cycle_find(parent->collection, collection)) {
1803 BKE_collection_child_remove(bmain, parent->collection, parent_collection);
1804 cycles_found = true;
1805 }
1806 else if (collection_cycle_fix_recursive(bmain, parent->collection, collection)) {
1807 cycles_found = true;
1808 }
1809 }
1810
1811 return cycles_found;
1812}
1813
1815{
1816 return collection_cycle_fix_recursive(bmain, collection, collection) ||
1817 collection_instance_fix_recursive(collection, collection);
1818}
1819
1821{
1822 return static_cast<CollectionChild *>(
1823 BLI_findptr(&parent->children, collection, offsetof(CollectionChild, collection)));
1824}
1825
1826static bool collection_find_child_recursive(const Collection *parent, const Collection *collection)
1827{
1828 LISTBASE_FOREACH (const CollectionChild *, child, &parent->children) {
1829 if (child->collection == collection) {
1830 return true;
1831 }
1832
1833 if (collection_find_child_recursive(child->collection, collection)) {
1834 return true;
1835 }
1836 }
1837
1838 return false;
1839}
1840
1841bool BKE_collection_has_collection(const Collection *parent, const Collection *collection)
1842{
1843 return collection_find_child_recursive(parent, collection);
1844}
1845
1847{
1848 return static_cast<CollectionParent *>(
1849 BLI_findptr(&child->runtime.parents, collection, offsetof(CollectionParent, collection)));
1850}
1851
1852static bool collection_child_add(Main *bmain,
1853 Collection *parent,
1854 Collection *collection,
1855 const CollectionLightLinking *light_linking,
1856 const int id_create_flag,
1857 const bool add_us)
1858{
1859 CollectionChild *child = BKE_collection_child_find(parent, collection);
1860 if (child) {
1861 return false;
1862 }
1863 if (BKE_collection_cycle_find(parent, collection)) {
1864 return false;
1865 }
1866
1867 child = static_cast<CollectionChild *>(MEM_callocN(sizeof(CollectionChild), "CollectionChild"));
1868 child->collection = collection;
1869 if (light_linking) {
1870 child->light_linking = *light_linking;
1871 }
1872 BLI_addtail(&parent->children, child);
1873
1874 /* Don't add parent links for depsgraph datablocks, these are not kept in sync. */
1875 if ((id_create_flag & LIB_ID_CREATE_NO_MAIN) == 0) {
1876 CollectionParent *cparent = static_cast<CollectionParent *>(
1877 MEM_callocN(sizeof(CollectionParent), "CollectionParent"));
1878 cparent->collection = parent;
1879 BLI_addtail(&collection->runtime.parents, cparent);
1880 }
1881
1882 if (add_us) {
1883 id_us_plus(&collection->id);
1884 }
1885
1886 BKE_collection_object_cache_free(bmain, parent, id_create_flag);
1887
1888 return true;
1889}
1890
1892 Collection *parent,
1893 Collection *collection,
1894 const int id_create_flag)
1895{
1896 CollectionChild *child = BKE_collection_child_find(parent, collection);
1897 if (child == nullptr) {
1898 return false;
1899 }
1900
1901 CollectionParent *cparent = collection_find_parent(collection, parent);
1902 BLI_freelinkN(&collection->runtime.parents, cparent);
1903 BLI_freelinkN(&parent->children, child);
1904
1905 id_us_min(&collection->id);
1906
1907 BKE_collection_object_cache_free(bmain, parent, id_create_flag);
1908
1909 return true;
1910}
1911
1913{
1914 if (!collection_child_add(bmain, parent, child, nullptr, 0, true)) {
1915 return false;
1916 }
1917
1919 return true;
1920}
1921
1923{
1924 return collection_child_add(bmain, parent, child, nullptr, 0, true);
1925}
1926
1928{
1929 if (!collection_child_remove(bmain, parent, child, 0)) {
1930 return false;
1931 }
1932
1934 return true;
1935}
1936
1938{
1939 LISTBASE_FOREACH_MUTABLE (CollectionChild *, child, &collection->children) {
1940 /* Check for duplicated children (can happen with remapping e.g.). */
1941 CollectionChild *other_child = BKE_collection_child_find(collection, child->collection);
1942 if (other_child != child) {
1943 BLI_freelinkN(&collection->children, child);
1944 continue;
1945 }
1946
1947 /* Invalid child, either without a collection, or because it creates a dependency cycle. */
1948 if (child->collection == nullptr || BKE_collection_cycle_find(collection, child->collection)) {
1949 BLI_freelinkN(&collection->children, child);
1950 continue;
1951 }
1952
1953 /* Can happen when remapping data partially out-of-Main (during advanced ID management
1954 * operations like lib-override resync e.g.). */
1955 if ((child->collection->id.tag & (ID_TAG_NO_MAIN | ID_TAG_COPIED_ON_EVAL)) != 0) {
1956 continue;
1957 }
1958
1959 BLI_assert(collection_find_parent(child->collection, collection) == nullptr);
1960 CollectionParent *cparent = static_cast<CollectionParent *>(
1961 MEM_callocN(sizeof(CollectionParent), __func__));
1962 cparent->collection = collection;
1963 BLI_addtail(&child->collection->runtime.parents, cparent);
1964 }
1965}
1966
1968{
1969 /* A same collection may be child of several others, no need to process it more than once. */
1970 if ((collection->runtime.tag & COLLECTION_TAG_RELATION_REBUILD) == 0) {
1971 return;
1972 }
1973
1975 collection->runtime.tag &= ~COLLECTION_TAG_RELATION_REBUILD;
1976
1977 LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
1978 /* See comment above in `BKE_collection_parent_relations_rebuild`. */
1979 if ((child->collection->id.tag & (ID_TAG_NO_MAIN | ID_TAG_COPIED_ON_EVAL)) != 0) {
1980 continue;
1981 }
1982 collection_parents_rebuild_recursive(child->collection);
1983 }
1984}
1985
1987{
1988 /* Only collections not in bmain (master ones in scenes) have no parent... */
1989 LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
1990 BLI_freelistN(&collection->runtime.parents);
1991
1992 collection->runtime.tag |= COLLECTION_TAG_RELATION_REBUILD;
1993 }
1994
1995 /* Scene's master collections will be 'root' parent of most of our collections, so start with
1996 * them. */
1997 LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
1998 /* This function can be called from `readfile.cc`, when this pointer is not guaranteed to be
1999 * nullptr.
2000 */
2001 if (scene->master_collection != nullptr) {
2002 BLI_assert(BLI_listbase_is_empty(&scene->master_collection->runtime.parents));
2003 scene->master_collection->runtime.tag |= COLLECTION_TAG_RELATION_REBUILD;
2004 collection_parents_rebuild_recursive(scene->master_collection);
2005 }
2006 }
2007
2008 /* We may have parent chains outside of scene's master_collection context? At least, readfile's
2009 * #collection_blend_read_after_liblink() seems to assume that, so do the same here. */
2010 LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
2011 if (collection->runtime.tag & COLLECTION_TAG_RELATION_REBUILD) {
2012 /* NOTE: we do not have easy access to 'which collections is root' info in that case, which
2013 * means test for cycles in collection relationships may fail here. I don't think that is an
2014 * issue in practice here, but worth keeping in mind... */
2016 }
2017 }
2018}
2019
2021{
2022 if (!BLI_listbase_validate(&collection->children)) {
2023 return false;
2024 }
2025 if (!BLI_listbase_validate(&collection->runtime.parents)) {
2026 return false;
2027 }
2028 if (BKE_collection_cycle_find(collection, nullptr)) {
2029 return false;
2030 }
2031
2032 bool is_ok = true;
2033
2034 /* Check that children have each collection used/referenced only once. */
2035 GSet *processed_collections = BLI_gset_ptr_new(__func__);
2036 LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
2037 void **r_key;
2038 if (BLI_gset_ensure_p_ex(processed_collections, child->collection, &r_key)) {
2039 is_ok = false;
2040 }
2041 else {
2042 *r_key = child->collection;
2043 }
2044 }
2045
2046 /* Check that parents have each collection used/referenced only once. */
2047 BLI_gset_clear(processed_collections, nullptr);
2048 LISTBASE_FOREACH (CollectionParent *, parent, &collection->runtime.parents) {
2049 void **r_key;
2050 if (BLI_gset_ensure_p_ex(processed_collections, parent->collection, &r_key)) {
2051 is_ok = false;
2052 }
2053 else {
2054 *r_key = parent->collection;
2055 }
2056 }
2057
2058 BLI_gset_free(processed_collections, nullptr);
2059 return is_ok;
2060}
2061
2064/* -------------------------------------------------------------------- */
2069 const int index,
2070 int *index_current)
2071{
2072 if (index == (*index_current)) {
2073 return collection;
2074 }
2075
2076 (*index_current)++;
2077
2078 LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
2079 Collection *nested = collection_from_index_recursive(child->collection, index, index_current);
2080 if (nested != nullptr) {
2081 return nested;
2082 }
2083 }
2084 return nullptr;
2085}
2086
2088{
2089 int index_current = 0;
2090 Collection *master_collection = scene->master_collection;
2091 return collection_from_index_recursive(master_collection, index, &index_current);
2092}
2093
2094static bool collection_objects_select(const Scene *scene,
2095 ViewLayer *view_layer,
2096 Collection *collection,
2097 bool deselect)
2098{
2099 bool changed = false;
2100
2101 if (collection->flag & COLLECTION_HIDE_SELECT) {
2102 return false;
2103 }
2104
2105 BKE_view_layer_synced_ensure(scene, view_layer);
2106 LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
2107 Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
2108
2109 if (base) {
2110 if (deselect) {
2111 if (base->flag & BASE_SELECTED) {
2112 base->flag &= ~BASE_SELECTED;
2113 changed = true;
2114 }
2115 }
2116 else {
2117 if ((base->flag & BASE_SELECTABLE) && !(base->flag & BASE_SELECTED)) {
2118 base->flag |= BASE_SELECTED;
2119 changed = true;
2120 }
2121 }
2122 }
2123 }
2124
2125 LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
2126 if (collection_objects_select(scene, view_layer, collection, deselect)) {
2127 changed = true;
2128 }
2129 }
2130
2131 return changed;
2132}
2133
2135 ViewLayer *view_layer,
2136 Collection *collection,
2137 bool deselect)
2138{
2140 collection);
2141
2142 if (layer_collection != nullptr) {
2143 return BKE_layer_collection_objects_select(scene, view_layer, layer_collection, deselect);
2144 }
2145
2146 return collection_objects_select(scene, view_layer, collection, deselect);
2147}
2148
2151/* -------------------------------------------------------------------- */
2156 Collection *to_parent,
2157 Collection *from_parent,
2158 Collection *relative,
2159 bool relative_after,
2160 Collection *collection)
2161{
2162 if (collection->flag & COLLECTION_IS_MASTER) {
2163 return false;
2164 }
2165 if (BKE_collection_cycle_find(to_parent, collection)) {
2166 return false;
2167 }
2168
2169 /* Move to new parent collection */
2170 if (from_parent) {
2171 collection_child_remove(bmain, from_parent, collection, 0);
2172 }
2173
2174 collection_child_add(bmain, to_parent, collection, nullptr, 0, true);
2175
2176 /* Move to specified location under parent. */
2177 if (relative) {
2178 CollectionChild *child = BKE_collection_child_find(to_parent, collection);
2179 CollectionChild *relative_child = BKE_collection_child_find(to_parent, relative);
2180
2181 if (relative_child) {
2182 BLI_remlink(&to_parent->children, child);
2183
2184 if (relative_after) {
2185 BLI_insertlinkafter(&to_parent->children, relative_child, child);
2186 }
2187 else {
2188 BLI_insertlinkbefore(&to_parent->children, relative_child, child);
2189 }
2190
2191 BKE_collection_object_cache_free(bmain, to_parent, 0);
2192 }
2193 }
2194
2195 /* Update layer collections. */
2197
2198 return true;
2199}
2200
2203/* -------------------------------------------------------------------- */
2207/* Scene collection iterator. */
2208
2214
2217 void *data)
2218{
2219 callback(collection, data);
2220
2221 LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
2222 scene_collection_callback(child->collection, callback, data);
2223 }
2224}
2225
2226static void scene_collections_count(Collection * /*collection*/, void *data)
2227{
2228 int *tot = static_cast<int *>(data);
2229 (*tot)++;
2230}
2231
2232static void scene_collections_build_array(Collection *collection, void *data)
2233{
2234 Collection ***array = static_cast<Collection ***>(data);
2235 **array = collection;
2236 (*array)++;
2237}
2238
2240 Collection ***r_collections_array,
2241 int *r_collections_array_len)
2242{
2243 *r_collections_array = nullptr;
2244 *r_collections_array_len = 0;
2245
2246 if (scene == nullptr) {
2247 return;
2248 }
2249
2250 Collection *collection = scene->master_collection;
2251 BLI_assert(collection != nullptr);
2252 scene_collection_callback(collection, scene_collections_count, r_collections_array_len);
2253
2254 BLI_assert(*r_collections_array_len > 0);
2255
2256 Collection **array = static_cast<Collection **>(
2257 MEM_malloc_arrayN(*r_collections_array_len, sizeof(Collection *), "CollectionArray"));
2258 *r_collections_array = array;
2260}
2261
2263{
2264 Scene *scene = static_cast<Scene *>(data_in);
2265 CollectionsIteratorData *data = static_cast<CollectionsIteratorData *>(
2266 MEM_callocN(sizeof(CollectionsIteratorData), __func__));
2267
2268 data->scene = scene;
2269
2270 BLI_ITERATOR_INIT(iter);
2271 iter->data = data;
2272
2273 scene_collections_array(scene, (Collection ***)&data->array, &data->tot);
2274 BLI_assert(data->tot != 0);
2275
2276 data->cur = 0;
2277 iter->current = data->array[data->cur];
2278}
2279
2281{
2282 CollectionsIteratorData *data = static_cast<CollectionsIteratorData *>(iter->data);
2283
2284 if (++data->cur < data->tot) {
2285 iter->current = data->array[data->cur];
2286 }
2287 else {
2288 iter->valid = false;
2289 }
2290}
2291
2293{
2294 CollectionsIteratorData *data = static_cast<CollectionsIteratorData *>(iter->data);
2295
2296 if (data) {
2297 if (data->array) {
2298 MEM_freeN(data->array);
2299 }
2300 MEM_freeN(data);
2301 }
2302 iter->valid = false;
2303}
2304
2305/* scene objects iterator */
2306
2312
2313static void scene_objects_iterator_begin(BLI_Iterator *iter, Scene *scene, GSet *visited_objects)
2314{
2316 MEM_callocN(sizeof(SceneObjectsIteratorData), __func__));
2317
2318 BLI_ITERATOR_INIT(iter);
2319 iter->data = data;
2320
2321 /* Lookup list to make sure that each object is only processed once. */
2322 if (visited_objects != nullptr) {
2323 data->visited = visited_objects;
2324 }
2325 else {
2326 data->visited = BLI_gset_ptr_new(__func__);
2327 }
2328
2329 /* We wrap the scene-collection iterator here to go over the scene collections. */
2330 BKE_scene_collections_iterator_begin(&data->scene_collection_iter, scene);
2331
2332 Collection *collection = static_cast<Collection *>(data->scene_collection_iter.current);
2333 data->cob_next = static_cast<CollectionObject *>(collection->gobject.first);
2334
2336}
2337
2339{
2340 Scene *scene = static_cast<Scene *>(data_in);
2341
2342 scene_objects_iterator_begin(iter, scene, nullptr);
2343}
2344
2346{
2347 if (!iter->valid) {
2348 return;
2349 }
2350
2351 /* Unpack the data. */
2352 SceneObjectsIteratorExData *data = static_cast<SceneObjectsIteratorExData *>(iter->data);
2353 iter->data = data->iter_data;
2354
2355 Object *ob = static_cast<Object *>(iter->current);
2356 if (ob && (ob->flag & data->flag) == 0) {
2357 iter->skip = true;
2358 }
2359
2360 /* Pack the data. */
2361 data->iter_data = iter->data;
2362 iter->data = data;
2363}
2364
2366{
2367 SceneObjectsIteratorExData *data = static_cast<SceneObjectsIteratorExData *>(data_in);
2368
2369 BKE_scene_objects_iterator_begin(iter, data->scene);
2370
2371 /* Pack the data. */
2372 data->iter_data = iter->data;
2373 iter->data = data_in;
2374
2376}
2377
2379{
2380 /* Unpack the data. */
2381 SceneObjectsIteratorExData *data = static_cast<SceneObjectsIteratorExData *>(iter->data);
2382 iter->data = data->iter_data;
2383
2385
2386 /* Pack the data. */
2387 data->iter_data = iter->data;
2388 iter->data = data;
2389
2391}
2392
2394{
2395 /* Unpack the data. */
2396 SceneObjectsIteratorExData *data = static_cast<SceneObjectsIteratorExData *>(iter->data);
2397 iter->data = data->iter_data;
2398
2400
2401 /* Pack the data. */
2402 data->iter_data = iter->data;
2403 iter->data = data;
2404}
2405
2410{
2411 for (; cob != nullptr; cob = cob->next) {
2412 Object *ob = cob->ob;
2413 void **ob_key_p;
2414 if (!BLI_gset_ensure_p_ex(gs, ob, &ob_key_p)) {
2415 *ob_key_p = ob;
2416 return cob;
2417 }
2418 }
2419 return nullptr;
2420}
2421
2423{
2424 SceneObjectsIteratorData *data = static_cast<SceneObjectsIteratorData *>(iter->data);
2425 CollectionObject *cob = data->cob_next ? object_base_unique(data->visited, data->cob_next) :
2426 nullptr;
2427
2428 if (cob) {
2429 data->cob_next = cob->next;
2430 iter->current = cob->ob;
2431 }
2432 else {
2433 /* if this is the last object of this ListBase look at the next Collection */
2434 Collection *collection;
2435 BKE_scene_collections_iterator_next(&data->scene_collection_iter);
2436 do {
2437 collection = static_cast<Collection *>(data->scene_collection_iter.current);
2438 /* get the first unique object of this collection */
2440 data->visited, static_cast<CollectionObject *>(collection->gobject.first));
2441 if (new_cob) {
2442 data->cob_next = new_cob->next;
2443 iter->current = new_cob->ob;
2444 return;
2445 }
2446 BKE_scene_collections_iterator_next(&data->scene_collection_iter);
2447 } while (data->scene_collection_iter.valid);
2448
2449 if (!data->scene_collection_iter.valid) {
2450 iter->valid = false;
2451 }
2452 }
2453}
2454
2456{
2457 SceneObjectsIteratorData *data = static_cast<SceneObjectsIteratorData *>(iter->data);
2458 if (data) {
2459 BKE_scene_collections_iterator_end(&data->scene_collection_iter);
2460 if (data->visited != nullptr) {
2461 BLI_gset_free(data->visited, nullptr);
2462 }
2463 MEM_freeN(data);
2464 }
2465}
2466
2468{
2469 BLI_Iterator iter;
2470 scene_objects_iterator_begin(&iter, scene, objects_gset);
2471 while (iter.valid) {
2473 }
2474
2475 /* `return_gset` is either given `objects_gset` (if non-nullptr), or the GSet allocated by the
2476 * iterator. Either way, we want to get it back, and prevent `BKE_scene_objects_iterator_end`
2477 * from freeing it. */
2478 GSet *return_gset = ((SceneObjectsIteratorData *)iter.data)->visited;
2479 ((SceneObjectsIteratorData *)iter.data)->visited = nullptr;
2481
2482 return return_gset;
2483}
2484
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_END
void(*)(Collection *ob, void *data) BKE_scene_collections_Cb
#define FOREACH_SCENE_COLLECTION_END
#define FOREACH_SCENE_COLLECTION_BEGIN(scene, _instance)
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(_collection, _object)
#define BKE_SCENE_COLLECTION_NAME
void IDP_AssignString(IDProperty *prop, const char *st) ATTR_NONNULL()
Definition idprop.cc:431
IDProperty * IDP_GetPropertyFromGroup(const IDProperty *prop, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:763
#define IDP_BlendDataRead(reader, prop)
void IDP_FreeProperty(IDProperty *prop)
Definition idprop.cc:1227
IDProperty * IDP_CopyProperty(const IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:861
void IDP_BlendWrite(BlendWriter *writer, const IDProperty *prop)
Definition idprop.cc:1437
@ IDTYPE_FLAGS_APPEND_IS_REUSABLE
Definition BKE_idtype.hh:39
@ IDTYPE_FLAGS_NO_ANIMDATA
Definition BKE_idtype.hh:41
LayerCollection * BKE_layer_collection_first_from_scene_collection(const ViewLayer *view_layer, const Collection *collection)
bool BKE_view_layer_has_collection(const ViewLayer *view_layer, const Collection *collection)
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
bool BKE_layer_collection_objects_select(const Scene *scene, ViewLayer *view_layer, LayerCollection *lc, bool deselect)
void BKE_main_collection_sync(const Main *bmain)
Base * BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
ListBase * BKE_view_layer_object_bases_get(ViewLayer *view_layer)
ID * BKE_id_copy_for_duplicate(Main *bmain, ID *id, eDupli_ID_Flags duplicate_flags, int copy_flags)
Definition lib_id.cc:770
void BKE_id_delete(Main *bmain, void *idv) ATTR_NONNULL()
void BKE_id_free_us(Main *bmain, void *idv) ATTR_NONNULL()
@ LIB_ID_COPY_NO_PREVIEW
@ LIB_ID_CREATE_NO_USER_REFCOUNT
@ LIB_ID_CREATE_NO_MAIN
@ LIB_ID_CREATE_NO_DEG_TAG
void id_us_plus(ID *id)
Definition lib_id.cc:351
void BKE_libblock_free_data(ID *id, bool do_id_user) ATTR_NONNULL()
void BKE_main_id_newptr_and_tag_clear(Main *bmain)
Definition lib_id.cc:1947
void * BKE_id_new(Main *bmain, short type, const char *name)
Definition lib_id.cc:1482
void id_us_min(ID *id)
Definition lib_id.cc:359
void * BKE_libblock_alloc_in_lib(Main *bmain, std::optional< Library * > owner_library, short type, const char *name, int flag) ATTR_WARN_UNUSED_RESULT
Definition lib_id.cc:1321
void BKE_main_id_tag_listbase(ListBase *lb, int tag, bool value)
Definition lib_id.cc:1175
eLibIDDuplicateFlags
@ LIB_ID_DUPLICATE_IS_ROOT_ID
@ LIB_ID_DUPLICATE_IS_SUBPROCESS
void BKE_id_blend_write(BlendWriter *writer, ID *id)
Definition lib_id.cc:2560
#define BKE_LIB_FOREACHID_PROCESS_IDSUPER(data_, id_super_, cb_flag_)
@ IDWALK_CB_LOOPBACK
@ IDWALK_CB_NEVER_SELF
@ IDWALK_CB_USER
@ IDWALK_CB_EMBEDDED_NOT_OWNING
@ IDWALK_CB_OVERRIDE_LIBRARY_HIERARCHY_DEFAULT
@ IDWALK_CB_READFILE_IGNORE
@ IDWALK_CB_NOP
int BKE_lib_query_foreachid_process_flags_get(const LibraryForeachIDData *data)
Definition lib_query.cc:120
@ IDWALK_NO_ORIG_POINTERS_ACCESS
#define BKE_LIB_FOREACHID_PROCESS_ID(data_, id_, cb_flag_)
void BKE_libblock_relink_to_newid(Main *bmain, ID *id, int remap_flag) ATTR_NONNULL()
Definition lib_remap.cc:921
#define FOREACH_MAIN_ID_END
Definition BKE_main.hh:500
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition BKE_main.hh:494
General operations, lookup, etc. for blender objects.
Object * BKE_object_duplicate(Main *bmain, Object *ob, eDupli_ID_Flags dupflag, uint duplicate_options)
void BKE_previewimg_blend_write(BlendWriter *writer, const PreviewImage *prv)
void BKE_previewimg_free(PreviewImage **prv)
void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv)
void BKE_previewimg_id_copy(ID *new_id, const ID *old_id)
API for Blender-side Rigid Body stuff.
void BKE_rigidbody_main_collection_object_add(struct Main *bmain, struct Collection *collection, struct Object *object)
void BKE_scene_remove_rigidbody_object(Main *bmain, Scene *scene, Object *ob, bool free_us)
Definition scene.cc:2283
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
struct GSet GSet
Definition BLI_ghash.h:341
GSet * BLI_gset_ptr_new(const char *info)
bool BLI_ghash_haskey(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:819
bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key)
Definition BLI_ghash.c:971
void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.c:1029
void * BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:802
GHash * BLI_ghash_ptr_new_ex(const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
unsigned int BLI_ghash_len(const GHash *gh) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:702
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.c:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:860
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.c:1034
void BLI_ghash_clear_ex(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp, unsigned int nentries_reserve)
Definition BLI_ghash.c:842
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:752
#define BLI_ITERATOR_INIT(iter)
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
bool BLI_listbase_validate(struct ListBase *lb)
Definition listbase.cc:868
#define LISTBASE_FOREACH(type, var, list)
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:269
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:331
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
void * BLI_findptr(const struct ListBase *listbase, const void *ptr, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:370
ListBase BLI_listbase_from_link(struct Link *some_link)
Definition listbase.cc:787
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE int integer_digits_i(int i)
char * BLI_sprintfN(const char *__restrict format,...) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.c:40
#define STRNCPY(dst, src)
Definition BLI_string.h:593
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
void BLI_uniquename(const struct ListBase *list, void *vlink, const char *defname, char delim, int name_offset, size_t name_maxncpy) ATTR_NONNULL(1
unsigned int uint
#define BLI_MUTEX_INITIALIZER
Definition BLI_threads.h:84
void BLI_mutex_lock(ThreadMutex *mutex)
Definition threads.cc:345
void BLI_mutex_unlock(ThreadMutex *mutex)
Definition threads.cc:350
pthread_mutex_t ThreadMutex
Definition BLI_threads.h:83
#define UNUSED_VARS_NDEBUG(...)
#define UNLIKELY(x)
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
int BLO_read_fileversion_get(BlendDataReader *reader)
Definition readfile.cc:4898
#define BLO_write_id_struct(writer, struct_name, id_address, id)
#define BLO_write_struct(writer, struct_name, data_ptr)
#define BLO_read_struct_list(reader, struct_name, list)
#define BLO_read_struct(reader, struct_name, ptr_p)
#define IFACE_(msgid)
#define BLT_I18NCONTEXT_ID_COLLECTION
#define DATA_(msgid)
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
void DEG_id_tag_update_ex(Main *bmain, ID *id, unsigned int flags)
ID * DEG_get_original_id(ID *id)
ID and Library types, which are fundamental for SDNA.
#define FILTER_ID_OB
Definition DNA_ID.h:1181
@ ID_RECALC_HIERARCHY
Definition DNA_ID.h:1125
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
#define ID_IS_OVERRIDABLE_LIBRARY(_id)
Definition DNA_ID.h:669
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:654
#define FILTER_ID_GR
Definition DNA_ID.h:1170
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:658
@ ID_FLAG_EMBEDDED_DATA
Definition DNA_ID.h:725
@ ID_TAG_NEW
Definition DNA_ID.h:865
@ ID_TAG_COPIED_ON_EVAL
Definition DNA_ID.h:964
@ ID_TAG_DOIT
Definition DNA_ID.h:1003
@ ID_TAG_NO_MAIN
Definition DNA_ID.h:945
@ INDEX_ID_GR
Definition DNA_ID.h:1308
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:683
@ ID_SCE
@ ID_GR
Object groups, one object can be in many groups at once.
@ COLLECTION_TAG_COLLECTION_OBJECT_DIRTY
@ COLLECTION_TAG_RELATION_REBUILD
@ COLLECTION_HIDE_RENDER
@ COLLECTION_HAS_OBJECT_CACHE_INSTANCED
@ COLLECTION_HIDE_SELECT
@ COLLECTION_IS_MASTER
@ COLLECTION_HAS_OBJECT_CACHE
@ COLLECTION_HIDE_VIEWPORT
struct Collection Collection
@ COLLECTION_COLOR_NONE
#define DNA_struct_default_get(struct_name)
#define MAX_NAME
Definition DNA_defs.h:50
@ BASE_ENABLED_RENDER
@ BASE_ENABLED_VIEWPORT
Object is a sort of wrapper for general info.
Types and defines for representing Rigid Body entities.
#define BASE_SELECTED(v3d, base)
#define BASE_SELECTABLE(v3d, base)
eDupli_ID_Flags
@ USER_DUP_LINKED_ID
@ USER_DUP_OBJECT
Read Guarded memory(de)allocation.
static void collection_object_cache_fill(ListBase *lb, Collection *collection, int parent_restrict, bool with_instances)
static bool collection_object_add(Main *bmain, Collection *collection, Object *ob, CollectionLightLinking *light_linking, const int id_create_flag, const bool add_us)
static bool collection_cycle_fix_recursive(Main *bmain, Collection *parent_collection, Collection *collection)
static Collection * collection_from_index_recursive(Collection *collection, const int index, int *index_current)
static bool collection_child_remove(Main *bmain, Collection *parent, Collection *collection, const int id_create_flag)
bool BKE_collection_has_object_recursive_instanced(Collection *collection, Object *ob)
static Collection * collection_duplicate_recursive(Main *bmain, Collection *parent, Collection *collection_old, CollectionChild *child_old, const int id_create_flag, const eDupli_ID_Flags duplicate_flags, const eLibIDDuplicateFlags duplicate_options)
static CollectionObject * object_base_unique(GSet *gs, CollectionObject *cob)
void BKE_scene_objects_iterator_begin_ex(BLI_Iterator *iter, void *data_in)
void BKE_scene_objects_iterator_next_ex(BLI_Iterator *iter)
Collection * BKE_collection_master_add(Scene *scene)
static CollectionParent * collection_find_parent(Collection *child, Collection *collection)
void BKE_collection_object_cache_free(const Main *bmain, Collection *collection, const int id_create_flag)
bool BKE_collection_has_object_recursive(Collection *collection, Object *ob)
static void collection_exporter_copy(Collection *collection, CollectionExport *data)
static void collection_gobject_assert_internal_consistency(Collection *collection, const bool do_extensive_check)
CollectionChild * BKE_collection_child_find(Collection *parent, Collection *collection)
void BKE_collection_add_from_collection(Main *bmain, Scene *scene, Collection *collection_src, Collection *collection_dst)
const char * BKE_collection_ui_name_get(Collection *collection)
static Collection * collection_add(Main *bmain, Collection *collection_parent, const char *name_custom)
void BKE_collection_exporter_free_data(CollectionExport *data)
bool BKE_collection_has_object_recursive_instanced_orig_id(Collection *collection_eval, Object *object_eval)
static ID ** collection_owner_pointer_get(ID *id, const bool debug_relationship_assert)
void BKE_collection_blend_write_nolib(BlendWriter *writer, Collection *collection)
bool BKE_collection_child_remove(Main *bmain, Collection *parent, Collection *child)
bool BKE_collection_viewlayer_object_add(Main *bmain, const ViewLayer *view_layer, Collection *collection, Object *ob)
void BKE_scene_collections_iterator_next(BLI_Iterator *iter)
static GHash * collection_gobject_hash_alloc(const Collection *collection)
static bool collection_instance_find_recursive(Collection *collection, Collection *instance_collection)
Collection * BKE_collection_add(Main *bmain, Collection *collection_parent, const char *name_custom)
bool BKE_collection_has_object(Collection *collection, const Object *ob)
static void collection_copy_data(Main *bmain, std::optional< Library * >, ID *id_dst, const ID *id_src, const int flag)
ListBase BKE_collection_object_cache_instanced_get(Collection *collection)
void BKE_collections_object_remove_invalids(Main *bmain)
Base * BKE_collection_or_layer_objects(const Scene *scene, ViewLayer *view_layer, Collection *collection)
void BKE_scene_objects_iterator_end(BLI_Iterator *iter)
bool BKE_collection_object_replace(Main *bmain, Collection *collection, Object *ob_old, Object *ob_new)
bool BKE_collection_is_empty(const Collection *collection)
static void collection_parents_rebuild_recursive(Collection *collection)
static void collection_gobject_hash_ensure_fix(Main *bmain, Collection *collection)
bool BKE_collection_move(Main *bmain, Collection *to_parent, Collection *from_parent, Collection *relative, bool relative_after, Collection *collection)
bool BKE_collection_is_in_scene(Collection *collection)
static void scene_collection_callback(Collection *collection, BKE_scene_collections_Cb callback, void *data)
bool BKE_collection_child_add(Main *bmain, Collection *parent, Collection *child)
void BKE_collection_object_move(Main *bmain, Scene *scene, Collection *collection_dst, Collection *collection_src, Object *ob)
void BKE_collection_add_from_object(Main *bmain, Scene *scene, const Object *ob_src, Collection *collection_dst)
static Collection * collection_next_find(Main *bmain, Scene *scene, Collection *collection)
static bool collection_child_add(Main *bmain, Collection *parent, Collection *collection, const CollectionLightLinking *light_linking, const int id_create_flag, const bool add_us)
static bool collection_object_cyclic_check_internal(Object *object, Collection *collection)
bool BKE_scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us)
void BKE_collections_child_remove_nulls(Main *bmain, Collection *parent_collection, Collection *child_collection)
void BKE_collection_exporter_name_set(const ListBase *exporters, CollectionExport *data, const char *newname)
GSet * BKE_scene_objects_as_gset(Scene *scene, GSet *objects_gset)
bool BKE_collection_validate(Collection *collection)
bool BKE_collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us)
bool BKE_collection_child_add_no_sync(Main *bmain, Collection *parent, Collection *child)
void BKE_collection_blend_write_prepare_nolib(BlendWriter *, Collection *collection)
static void collection_gobject_hash_create(Collection *collection)
void BKE_scene_collections_iterator_begin(BLI_Iterator *iter, void *data_in)
void BKE_collection_new_name_get(Collection *collection_parent, char *rname)
void BKE_collection_free_data(Collection *collection)
static bool collection_objects_select(const Scene *scene, ViewLayer *view_layer, Collection *collection, bool deselect)
static bool collection_find_child_recursive(const Collection *parent, const Collection *collection)
static void collection_gobject_hash_ensure(Collection *collection)
static void scene_collections_count(Collection *, void *data)
void BKE_main_collections_object_cache_free(const Main *bmain)
Collection * BKE_collection_object_find(Main *bmain, Scene *scene, Collection *collection, Object *ob)
Collection * BKE_collection_from_index(Scene *scene, const int index)
static void collection_gobject_hash_update_object(Collection *collection, Object *ob_old, CollectionObject *cob)
void BKE_scene_collections_iterator_end(BLI_Iterator *iter)
bool BKE_collection_cycles_fix(Main *bmain, Collection *collection)
static bool collection_object_remove(Main *bmain, Collection *collection, Object *ob, const int id_create_flag, const bool free_us)
bool BKE_collection_object_add_notest(Main *bmain, Collection *collection, Object *ob)
void BKE_scene_objects_iterator_end_ex(BLI_Iterator *iter)
static void collection_free_data(ID *id)
static bool collection_instance_fix_recursive(Collection *parent_collection, Collection *collection)
void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, Object *ob_dst)
static void collection_blend_read_data(BlendDataReader *reader, ID *id)
Collection * BKE_collection_parent_editable_find_recursive(const ViewLayer *view_layer, Collection *collection)
static void scene_collections_array(Scene *scene, Collection ***r_collections_array, int *r_collections_array_len)
static void collection_object_cache_free(const Main *bmain, Collection *collection, const int id_create_flag, const uint id_recalc_flag)
bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
bool BKE_collection_cycle_find(Collection *new_ancestor, Collection *collection)
static void scene_objects_iterator_begin(BLI_Iterator *iter, Scene *scene, GSet *visited_objects)
static void collection_null_children_remove(Collection *collection)
Collection * BKE_collection_duplicate(Main *bmain, Collection *parent, CollectionChild *child_old, Collection *collection, uint duplicate_flags, uint duplicate_options)
static void collection_blend_write(BlendWriter *writer, ID *id, const void *id_address)
static CLG_LogRef LOG
Definition collection.cc:56
bool BKE_collection_object_cyclic_check(Main *bmain, Object *object, Collection *collection)
static void collection_missing_parents_remove(Collection *collection)
void BKE_collections_after_lib_link(Main *bmain)
bool BKE_collection_has_collection(const Collection *parent, const Collection *collection)
static void scene_collections_build_array(Collection *collection, void *data)
static void collection_object_remove_no_gobject_hash(Main *bmain, Collection *collection, CollectionObject *cob, const int id_create_flag, const bool free_us)
static bool scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us, Collection *collection_skip)
static void collection_init_data(ID *id)
static void collection_object_cache_free_parent_recursive(const Main *bmain, Collection *collection, const int id_create_flag, const uint id_recalc_flag)
ListBase BKE_collection_object_cache_get(Collection *collection)
void BKE_collection_blend_read_data(BlendDataReader *reader, Collection *collection, ID *owner_id)
void BKE_scene_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
void BKE_collection_parent_relations_rebuild(Collection *collection)
bool BKE_collection_objects_select(const Scene *scene, ViewLayer *view_layer, Collection *collection, bool deselect)
static void scene_objects_iterator_skip_invalid_flag(BLI_Iterator *iter)
static void collection_blend_read_after_liblink(BlendLibReader *, ID *id)
void BKE_scene_objects_iterator_next(BLI_Iterator *iter)
static void collection_foreach_id(ID *id, LibraryForeachIDData *data)
void BKE_main_collections_parent_relations_rebuild(Main *bmain)
IDTypeInfo IDType_ID_GR
bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
DEGForeachIDComponentCallback callback
#define offsetof(t, d)
#define GS(x)
Definition iris.cc:202
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
short flag
struct Object * object
struct Collection * collection
CollectionLightLinking light_linking
IDProperty * export_properties
struct CollectionObject * next
CollectionLightLinking light_linking
struct Collection * collection
struct PreviewImage * preview
Collection_Runtime runtime
Definition DNA_ID.h:413
int tag
Definition DNA_ID.h:434
struct Library * lib
Definition DNA_ID.h:419
struct ID * newid
Definition DNA_ID.h:417
short flag
Definition DNA_ID.h:430
char name[66]
Definition DNA_ID.h:425
ID id
Definition DNA_ID.h:529
void * first
ListBase scenes
Definition BKE_main.hh:210
ListBase collections
Definition BKE_main.hh:231
struct Collection * instance_collection
LightLinking * light_linking
BLI_Iterator scene_collection_iter
CollectionObject * cob_next
#define N_(msgid)
uint8_t flag
Definition wm_window.cc:138