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