Blender V5.0
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_utf8.h"
23#include "BLI_string_utils.hh"
24
25#include "BLT_translation.hh"
26
27#include "BKE_anim_data.hh"
28#include "BKE_collection.hh"
29#include "BKE_file_handler.hh"
30#include "BKE_idprop.hh"
31#include "BKE_idtype.hh"
32#include "BKE_layer.hh"
33#include "BKE_lib_id.hh"
34#include "BKE_lib_query.hh"
35#include "BKE_lib_remap.hh"
36#include "BKE_library.hh"
37#include "BKE_main.hh"
38#include "BKE_object.hh"
39#include "BKE_preview_image.hh"
40#include "BKE_rigidbody.h"
41#include "BKE_scene.hh"
42
43#include "DNA_defaults.h"
44
45#include "DNA_ID.h"
47#include "DNA_layer_types.h"
48#include "DNA_object_types.h"
49#include "DNA_rigidbody_types.h"
50#include "DNA_scene_types.h"
51
52#include "DEG_depsgraph.hh"
54
55#include "MEM_guardedalloc.h"
56
57#include "BLO_read_write.hh"
58
59static CLG_LogRef LOG = {"object.collection"};
60
64// #define USE_DEBUG_EXTRA_GOBJECT_ASSERT
65
66/* -------------------------------------------------------------------- */
69
71static bool collection_child_add(Main *bmain,
72 Collection *parent,
73 Collection *collection,
74 const CollectionLightLinking *light_linking,
75 const int id_create_flag,
76 const bool add_us);
78static bool collection_child_remove(Main *bmain,
79 Collection *parent,
80 Collection *collection,
81 const int id_create_flag);
83static bool collection_object_add(Main *bmain,
84 Collection *collection,
85 Object *ob,
86 CollectionLightLinking *light_linking,
87 const int id_create_flag,
88 const bool add_us);
89
92 Collection *collection,
94 const int id_create_flag,
95 const bool free_us);
97static bool collection_object_remove(
98 Main *bmain, Collection *collection, Object *ob, const int id_create_flag, const bool free_us);
99
101
102static bool collection_find_child_recursive(const Collection *parent,
103 const Collection *collection);
104
106static void collection_object_cache_free(const Main *bmain,
107 Collection *collection,
108 const int id_create_flag,
109 const uint id_recalc_flag);
110
111static void collection_gobject_hash_ensure(Collection *collection);
113 Object *ob_old,
114 CollectionObject *cob);
116
118
119/* -------------------------------------------------------------------- */
122
123static void collection_init_data(ID *id)
124{
125 Collection *collection = (Collection *)id;
127
129 collection->runtime = MEM_new<blender::bke::CollectionRuntime>(__func__);
130}
131
142static void collection_copy_data(Main *bmain,
143 std::optional<Library *> /*owner_library*/,
144 ID *id_dst,
145 const ID *id_src,
146 const int flag)
147{
148 Collection *collection_dst = (Collection *)id_dst;
149 const Collection *collection_src = (const Collection *)id_src;
150
151 collection_dst->runtime = MEM_new<blender::bke::CollectionRuntime>(__func__);
152
153 BLI_assert(((collection_src->flag & COLLECTION_IS_MASTER) != 0) ==
154 ((collection_src->id.flag & ID_FLAG_EMBEDDED_DATA) != 0));
155
156 /* Do not copy collection's preview (same behavior as for objects). */
157 if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO: temp hack. */
158 BKE_previewimg_id_copy(&collection_dst->id, &collection_src->id);
159 }
160 else {
161 collection_dst->preview = nullptr;
162 }
163
165
166 BLI_listbase_clear(&collection_dst->gobject);
167 BLI_listbase_clear(&collection_dst->children);
168 BLI_listbase_clear(&collection_dst->exporters);
169
170 LISTBASE_FOREACH (CollectionChild *, child, &collection_src->children) {
172 bmain, collection_dst, child->collection, &child->light_linking, flag, false);
173 }
174 LISTBASE_FOREACH (CollectionObject *, cob, &collection_src->gobject) {
175 collection_object_add(bmain, collection_dst, cob->ob, &cob->light_linking, flag, false);
176 }
177 LISTBASE_FOREACH (CollectionExport *, data, &collection_src->exporters) {
178 collection_exporter_copy(collection_dst, data);
179 }
180}
181
182static void collection_free_data(ID *id)
183{
184 Collection *collection = (Collection *)id;
185
186 /* No animation-data here. */
187 BKE_previewimg_free(&collection->preview);
188
189 BLI_freelistN(&collection->gobject);
190 if (collection->runtime->gobject_hash) {
191 BLI_ghash_free(collection->runtime->gobject_hash, nullptr, nullptr);
192 collection->runtime->gobject_hash = nullptr;
193 }
194
195 BLI_freelistN(&collection->children);
196 BLI_freelistN(&collection->runtime->parents);
197
200 }
201 BLI_freelistN(&collection->exporters);
202
203 /* No need for depsgraph tagging here, since the data is being deleted. */
205
206 MEM_delete(collection->runtime);
207}
208
210{
211 Collection *collection = (Collection *)id;
212 const int data_flags = BKE_lib_query_foreachid_process_flags_get(data);
213
215 data,
216 collection->owner_id,
218
219 LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
220 Object *cob_ob_old = cob->ob;
221
224
225 if (collection->runtime->gobject_hash) {
226 /* If the remapping does not create inconsistent data (nullptr object pointer or duplicate
227 * CollectionObjects), keeping the ghash consistent is also possible. Otherwise, this call
228 * will take care of tagging the collection objects list as dirty. */
229 collection_gobject_hash_update_object(collection, cob_ob_old, cob);
230 }
231 else if (cob_ob_old != cob->ob || cob->ob == nullptr) {
232 /* If there is no reference GHash, duplicates cannot be reliably detected, so assume that any
233 * nullptr pointer or changed pointer may create an invalid collection object list. */
235 }
236 }
237 LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
239 child->collection,
242 }
243 LISTBASE_FOREACH (CollectionParent *, parent, &collection->runtime->parents) {
244 /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad
245 * anyway... */
246 const LibraryForeachIDCallbackFlag cb_flag =
247 ((parent->collection != nullptr && (data_flags & IDWALK_NO_ORIG_POINTERS_ACCESS) == 0 &&
248 (parent->collection->id.flag & ID_FLAG_EMBEDDED_DATA) != 0) ?
252 data, parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK | cb_flag);
253 }
254}
255
256static ID **collection_owner_pointer_get(ID *id, const bool debug_relationship_assert)
257{
258 if ((id->flag & ID_FLAG_EMBEDDED_DATA) == 0) {
259 return nullptr;
260 }
261
262 Collection *master_collection = (Collection *)id;
263 BLI_assert((master_collection->flag & COLLECTION_IS_MASTER) != 0);
264 if (debug_relationship_assert) {
265 BLI_assert(master_collection->owner_id != nullptr);
266 BLI_assert(GS(master_collection->owner_id->name) == ID_SCE);
267 BLI_assert(((Scene *)master_collection->owner_id)->master_collection == master_collection);
268 }
269
270 return &master_collection->owner_id;
271}
272
274{
275 collection->runtime = nullptr;
276 /* Clean up, important in undo case to reduce false detection of changed data-blocks. */
277 collection->flag &= ~COLLECTION_FLAG_ALL_RUNTIME;
278}
279
281{
282 BKE_id_blend_write(writer, &collection->id);
283
284 /* Shared function for collection data-blocks and scene master collection. */
285 BKE_previewimg_blend_write(writer, collection->preview);
286
287 LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
289 }
290
291 LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
292 BLO_write_struct(writer, CollectionChild, child);
293 }
294
297 if (data->export_properties) {
298 IDP_BlendWrite(writer, data->export_properties);
299 }
300 }
301}
302
303static void collection_blend_write(BlendWriter *writer, ID *id, const void *id_address)
304{
305 Collection *collection = (Collection *)id;
306
308
309 /* write LibData */
310 BLO_write_id_struct(writer, Collection, id_address, &collection->id);
311
312 BKE_collection_blend_write_nolib(writer, collection);
313}
314
315void BKE_collection_blend_read_data(BlendDataReader *reader, Collection *collection, ID *owner_id)
316{
317 /* Special case for this pointer, do not rely on regular `lib_link` process here. Avoids needs
318 * for do_versioning, and ensures coherence of data in any case.
319 *
320 * NOTE: Old versions are very often 'broken' here, just fix it silently in these cases.
321 */
322 if (BLO_read_fileversion_get(reader) > 300) {
323 BLI_assert((collection->id.flag & ID_FLAG_EMBEDDED_DATA) != 0 || owner_id == nullptr);
324 }
325 BLI_assert(owner_id == nullptr || owner_id->lib == collection->id.lib);
326 if (owner_id != nullptr && (collection->id.flag & ID_FLAG_EMBEDDED_DATA) == 0) {
327 /* This is unfortunate, but currently a lot of existing files (including startup ones) have
328 * missing `ID_FLAG_EMBEDDED_DATA` flag.
329 *
330 * NOTE: Using do_version is not a solution here, since this code will be called before any
331 * do_version takes place. Keeping it here also ensures future (or unknown existing) similar
332 * bugs won't go easily unnoticed. */
333 if (BLO_read_fileversion_get(reader) > 300) {
334 CLOG_WARN(&LOG,
335 "Fixing root node tree '%s' owned by '%s' missing EMBEDDED tag, please consider "
336 "re-saving your (startup) file",
337 collection->id.name,
338 owner_id->name);
339 }
340 collection->id.flag |= ID_FLAG_EMBEDDED_DATA;
341 }
342
343 collection->runtime = MEM_new<blender::bke::CollectionRuntime>(__func__);
344 collection->flag &= ~COLLECTION_FLAG_ALL_RUNTIME;
345
346 collection->owner_id = owner_id;
347
348 BLO_read_struct_list(reader, CollectionObject, &collection->gobject);
349 BLO_read_struct_list(reader, CollectionChild, &collection->children);
350
351 BLO_read_struct_list(reader, CollectionExport, &collection->exporters);
353 BLO_read_struct(reader, IDProperty, &data->export_properties);
354 IDP_BlendDataRead(reader, &data->export_properties);
355 }
356
357 BLO_read_struct(reader, PreviewImage, &collection->preview);
358 BKE_previewimg_blend_read(reader, collection->preview);
359}
360
362{
363 Collection *collection = (Collection *)id;
364 BKE_collection_blend_read_data(reader, collection, nullptr);
365}
366
368{
369 Collection *collection = reinterpret_cast<Collection *>(id);
370
371 /* Sanity check over Collection/Object data. */
372 BLI_assert(collection->runtime->gobject_hash == nullptr);
373 LISTBASE_FOREACH_MUTABLE (CollectionObject *, cob, &collection->gobject) {
374 if (cob->ob == nullptr) {
375 BLI_freelinkN(&collection->gobject, cob);
376 }
377 }
378
379 /* foreach_id code called by generic lib_link process has most likely set this flag, however it
380 * is not needed during readfile process since the runtime data is affects are not yet built, so
381 * just clear it here. */
382 BLI_assert(collection->runtime->gobject_hash == nullptr);
384}
385
387 /*id_code*/ Collection::id_type,
388 /*id_filter*/ FILTER_ID_GR,
389 /*dependencies_id_types*/ FILTER_ID_OB | FILTER_ID_GR,
390 /*main_listbase_index*/ INDEX_ID_GR,
391 /*struct_size*/ sizeof(Collection),
392 /*name*/ "Collection",
393 /*name_plural*/ N_("collections"),
394 /*translation_context*/ BLT_I18NCONTEXT_ID_COLLECTION,
396 /*asset_type_info*/ nullptr,
397
398 /*init_data*/ collection_init_data,
399 /*copy_data*/ collection_copy_data,
400 /*free_data*/ collection_free_data,
401 /*make_local*/ nullptr,
402 /*foreach_id*/ collection_foreach_id,
403 /*foreach_cache*/ nullptr,
404 /*foreach_path*/ nullptr,
405 /*foreach_working_space_color*/ nullptr,
406 /*owner_pointer_get*/ collection_owner_pointer_get,
407
408 /*blend_write*/ collection_blend_write,
409 /*blend_read_data*/ collection_blend_read_data,
410 /*blend_read_after_liblink*/ collection_blend_read_after_liblink,
411
412 /*blend_read_undo_preserve*/ nullptr,
413
414 /*lib_override_apply_post*/ nullptr,
415};
416
418
419/* -------------------------------------------------------------------- */
422
423/* Add new collection, without view layer syncing. */
425 Collection *collection_parent,
426 const char *name_custom)
427{
428 /* Determine new collection name. */
429 char name[MAX_ID_NAME - 2];
430
431 if (name_custom) {
432 STRNCPY_UTF8(name, name_custom);
433 }
434 else {
435 BKE_collection_new_name_get(collection_parent, name);
436 }
437
438 /* Create new collection. */
439 Collection *collection = BKE_id_new<Collection>(bmain, name);
440
441 /* We increase collection user count when linking to Collections. */
442 id_us_min(&collection->id);
443
444 /* Optionally add to parent collection. */
445 if (collection_parent) {
446 collection_child_add(bmain, collection_parent, collection, nullptr, 0, true);
447 }
448
449 return collection;
450}
451
452Collection *BKE_collection_add(Main *bmain, Collection *collection_parent, const char *name_custom)
453{
454 Collection *collection = collection_add(bmain, collection_parent, name_custom);
456 return collection;
457}
458
460 Scene *scene,
461 const Object *ob_src,
462 Collection *collection_dst)
463{
464 bool is_instantiated = false;
465
466 FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
467 if (!ID_IS_LINKED(collection) && !ID_IS_OVERRIDABLE_LIBRARY(collection) &&
468 BKE_collection_has_object(collection, ob_src))
469 {
470 collection_child_add(bmain, collection, collection_dst, nullptr, 0, true);
471 is_instantiated = true;
472 }
473 }
475
476 if (!is_instantiated) {
477 collection_child_add(bmain, scene->master_collection, collection_dst, nullptr, 0, true);
478 }
479
481}
482
484 Scene *scene,
485 Collection *collection_src,
486 Collection *collection_dst)
487{
488 bool is_instantiated = false;
489
490 FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
491 if (ID_IS_EDITABLE(collection) && !ID_IS_OVERRIDE_LIBRARY(collection) &&
492 BKE_collection_child_find(collection, collection_src))
493 {
494 collection_child_add(bmain, collection, collection_dst, nullptr, 0, true);
495 is_instantiated = true;
496 }
497 else if (!is_instantiated && BKE_collection_child_find(collection, collection_dst)) {
498 /* If given collection_dst is already instantiated in scene, even if its 'model'
499 * collection_src one is not, do not add it to master scene collection. */
500 is_instantiated = true;
501 }
502 }
504
505 if (!is_instantiated) {
506 collection_child_add(bmain, scene->master_collection, collection_dst, nullptr, 0, true);
507 }
508
510}
511
513
514/* -------------------------------------------------------------------- */
517
519{
520 BKE_libblock_free_data(&collection->id, false);
521 collection_free_data(&collection->id);
522}
523
526 const char *newname)
527{
528 /* Only use the new name if it's not empty. */
529 if (newname && newname[0] != '\0') {
530 const ListBase list = exporters ? *exporters : BLI_listbase_from_link((Link *)data);
531
532 STRNCPY(data->name, newname);
534 &list, data, newname, '.', offsetof(CollectionExport, name), sizeof(data->name));
535 }
536}
537
539{
540 if (data->export_properties) {
541 IDP_FreeProperty(data->export_properties);
542 }
543}
544
545bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
546{
547 /* Master collection is not real datablock, can't be removed. */
548 if (collection->flag & COLLECTION_IS_MASTER) {
549 BLI_assert_msg(0, "Scene master collection cannot be deleted");
550 return false;
551 }
552
553 /* This is being deleted, no need to handle each item.
554 * NOTE: While it might seem an advantage to use the hash instead of the list-lookup
555 * it is in fact slower because the items are removed in-order,
556 * so the list-lookup succeeds on the first test. */
557 if (collection->runtime->gobject_hash) {
558 BLI_ghash_free(collection->runtime->gobject_hash, nullptr, nullptr);
559 collection->runtime->gobject_hash = nullptr;
560 }
561
562 if (hierarchy) {
563 /* Remove child objects. */
564 CollectionObject *cob = static_cast<CollectionObject *>(collection->gobject.first);
565 while (cob != nullptr) {
567 bmain, collection, cob, LIB_ID_CREATE_NO_DEG_TAG, true);
568 cob = static_cast<CollectionObject *>(collection->gobject.first);
569 }
570
571 /* Delete all child collections recursively. */
572 CollectionChild *child = static_cast<CollectionChild *>(collection->children.first);
573 while (child != nullptr) {
574 BKE_collection_delete(bmain, child->collection, hierarchy);
575 child = static_cast<CollectionChild *>(collection->children.first);
576 }
577 }
578 else {
579 /* Link child collections into parent collection. */
580 LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
581 LISTBASE_FOREACH (CollectionParent *, cparent, &collection->runtime->parents) {
582 Collection *parent = cparent->collection;
583 collection_child_add(bmain, parent, child->collection, nullptr, 0, true);
584 }
585 }
586
587 CollectionObject *cob = static_cast<CollectionObject *>(collection->gobject.first);
588 while (cob != nullptr) {
589 /* Link child object into parent collections. */
590 LISTBASE_FOREACH (CollectionParent *, cparent, &collection->runtime->parents) {
591 Collection *parent = cparent->collection;
592 collection_object_add(bmain, parent, cob->ob, nullptr, 0, true);
593 }
594
595 /* Remove child object. */
597 bmain, collection, cob, LIB_ID_CREATE_NO_DEG_TAG, true);
598 cob = static_cast<CollectionObject *>(collection->gobject.first);
599 }
600 }
601
602 BKE_id_delete(bmain, collection);
603
605
606 return true;
607}
608
610
611/* -------------------------------------------------------------------- */
614
616 Collection *parent,
617 Collection *collection_old,
618 CollectionChild *child_old,
619 const int id_create_flag,
620 const eDupli_ID_Flags duplicate_flags,
621 const eLibIDDuplicateFlags duplicate_options)
622{
623 Collection *collection_new;
624 bool do_full_process = false;
625 const bool is_collection_master = (collection_old->flag & COLLECTION_IS_MASTER) != 0;
626
627 const bool do_objects = (duplicate_flags & USER_DUP_OBJECT) != 0;
628
629 if (is_collection_master) {
630 /* We never duplicate master collections here, but we can still deep-copy their objects and
631 * collections. */
632 BLI_assert(parent == nullptr);
633 collection_new = collection_old;
634 do_full_process = true;
635 }
636 else if (collection_old->id.newid == nullptr) {
637 collection_new = (Collection *)BKE_id_copy_for_duplicate(
638 bmain, (ID *)collection_old, duplicate_flags, id_create_flag);
639
640 if (collection_new == collection_old) {
641 return collection_new;
642 }
643
644 do_full_process = true;
645 }
646 else {
647 collection_new = (Collection *)collection_old->id.newid;
648 }
649
650 /* Optionally add to parent (we always want to do that,
651 * even if collection_old had already been duplicated). */
652 if (parent != nullptr) {
653 if (collection_child_add(bmain,
654 parent,
655 collection_new,
656 child_old ? &child_old->light_linking : nullptr,
657 id_create_flag,
658 true))
659 {
660 /* Put collection right after existing one.
661 * NOTE: Lookup child in the actual parent, as the parent might be different
662 * one when duplicating collection in a linked parent. */
663 CollectionChild *child = BKE_collection_child_find(parent, collection_old);
664 CollectionChild *child_new = BKE_collection_child_find(parent, collection_new);
665
666 if (child && child_new) {
667 BLI_remlink(&parent->children, child_new);
668 BLI_insertlinkafter(&parent->children, child, child_new);
669 }
670 }
671 }
672
673 /* If we are not doing any kind of deep-copy, we can return immediately.
674 * False do_full_process means collection_old had already been duplicated,
675 * no need to redo some deep-copy on it. */
676 if (!do_full_process) {
677 return collection_new;
678 }
679
680 if (do_objects) {
681 /* We need to first duplicate the objects in a separate loop, to support the master collection
682 * case, where both old and new collections are the same.
683 * Otherwise, depending on naming scheme and sorting, we may end up duplicating the new objects
684 * we just added, in some infinite loop. */
685 LISTBASE_FOREACH (CollectionObject *, cob, &collection_old->gobject) {
686 Object *ob_old = cob->ob;
687
688 if (ob_old->id.newid == nullptr) {
690 bmain, ob_old, duplicate_flags, duplicate_options | LIB_ID_DUPLICATE_IS_SUBPROCESS);
691 }
692 }
693
694 /* We can loop on collection_old's objects, but have to consider it mutable because with master
695 * collections collection_old and collection_new are the same data here. */
696 LISTBASE_FOREACH_MUTABLE (CollectionObject *, cob, &collection_old->gobject) {
697 Object *ob_old = cob->ob;
698 Object *ob_new = (Object *)ob_old->id.newid;
699
700 /* New object can be nullptr in master collection case, since new and old objects are in same
701 * collection. */
702 if (ELEM(ob_new, ob_old, nullptr)) {
703 continue;
704 }
705
707 bmain, collection_new, ob_new, &cob->light_linking, id_create_flag, true);
708 collection_object_remove(bmain, collection_new, ob_old, id_create_flag, false);
709 }
710 }
711
712 /* We can loop on collection_old's children,
713 * that list is currently identical the collection_new' children, and won't be changed here. */
714 LISTBASE_FOREACH_MUTABLE (CollectionChild *, child_iter, &collection_old->children) {
715 Collection *child_collection_old = child_iter->collection;
716
717 Collection *child_collection_new = collection_duplicate_recursive(bmain,
718 collection_new,
719 child_collection_old,
720 child_iter,
721 id_create_flag,
722 duplicate_flags,
723 duplicate_options);
724 if (child_collection_new != child_collection_old) {
725 collection_child_remove(bmain, collection_new, child_collection_old, id_create_flag);
726 }
727 }
728
729 return collection_new;
730}
731
733 Collection *parent,
734 CollectionChild *child_old,
735 Collection *collection,
736 eDupli_ID_Flags duplicate_flags,
737 /*eLibIDDuplicateFlags*/ uint duplicate_options)
738{
739 const bool is_subprocess = (duplicate_options & LIB_ID_DUPLICATE_IS_SUBPROCESS) != 0;
740 const bool is_root_id = (duplicate_options & LIB_ID_DUPLICATE_IS_ROOT_ID) != 0;
741 const int id_create_flag = (collection->id.tag & ID_TAG_NO_MAIN) ? LIB_ID_CREATE_NO_MAIN : 0;
742
743 if (!is_subprocess) {
745 }
746 if (is_root_id) {
747 /* In case root duplicated ID is linked, assume we want to get a local copy of it and duplicate
748 * all expected linked data. */
749 if (ID_IS_LINKED(collection)) {
750 duplicate_flags |= USER_DUP_LINKED_ID;
751 }
752 duplicate_options &= ~LIB_ID_DUPLICATE_IS_ROOT_ID;
753 }
754
756 bmain,
757 parent,
758 collection,
759 child_old,
760 id_create_flag,
761 duplicate_flags,
762 eLibIDDuplicateFlags(duplicate_options));
763
764 if (!is_subprocess) {
765 /* `collection_duplicate_recursive` will also tag our 'root' collection, which is not required
766 * unless its duplication is a sub-process of another one. */
767 collection_new->id.tag &= ~ID_TAG_NEW;
768
769 /* This code will follow into all ID links using an ID tagged with ID_TAG_NEW. */
770 /* Unfortunate, but with some types (e.g. meshes), an object is considered in Edit mode if its
771 * obdata contains edit mode runtime data. This can be the case of all newly duplicated
772 * objects, as even though duplicate code move the object back in Object mode, they are still
773 * using the original obdata ID, leading to them being falsely detected as being in Edit mode,
774 * and therefore not remapping their obdata to the newly duplicated one.
775 * See #139715. */
778
779#ifndef NDEBUG
780 /* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those flags. */
781 ID *id_iter;
782 FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
783 if (id_iter->tag & ID_TAG_NEW) {
784 BLI_assert((id_iter->tag & ID_TAG_NEW) == 0);
785 }
786 }
788#endif
789
790 /* Cleanup. */
792
794 }
795
796 return collection_new;
797}
798
800
801/* -------------------------------------------------------------------- */
804
805void BKE_collection_new_name_get(Collection *collection_parent, char r_name[MAX_ID_NAME - 2])
806{
807 const size_t name_maxncpy = MAX_ID_NAME - 2;
808 if (!collection_parent) {
809 BLI_strncpy_utf8(r_name, DATA_("Collection"), name_maxncpy);
810 }
811 else if (collection_parent->flag & COLLECTION_IS_MASTER) {
812 BLI_snprintf_utf8(r_name,
813 name_maxncpy,
814 DATA_("Collection %d"),
815 BLI_listbase_count(&collection_parent->children) + 1);
816 }
817 else {
818 const int number = BLI_listbase_count(&collection_parent->children) + 1;
819 const int digits = integer_digits_i(number);
820 const size_t name_part_maxncpy = name_maxncpy - (1 + digits);
821 const size_t name_part_len = BLI_strncpy_utf8_rlen(
822 r_name, collection_parent->id.name + 2, name_part_maxncpy);
823 BLI_snprintf(r_name + name_part_len, name_maxncpy - name_part_len, " %d", number);
824 }
825}
826
828{
829 if (collection->flag & COLLECTION_IS_MASTER) {
830 return IFACE_("Scene Collection");
831 }
832
833 return collection->id.name + 2;
834}
835
837
838/* -------------------------------------------------------------------- */
841
843 Collection *collection,
844 int parent_restrict,
845 bool with_instances)
846{
847 int child_restrict = collection->flag | parent_restrict;
848
849 LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
850 Base *base = static_cast<Base *>(BLI_findptr(lb, cob->ob, offsetof(Base, object)));
851
852 if (base == nullptr) {
853 base = MEM_callocN<Base>("Object Base");
854 base->object = cob->ob;
855 BLI_addtail(lb, base);
856 if (with_instances && cob->ob->instance_collection) {
858 lb, cob->ob->instance_collection, child_restrict, with_instances);
859 }
860 }
861
862 /* Only collection flags are checked here currently, object restrict flag is checked
863 * in FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN since it can be animated
864 * without updating the cache. */
865 if ((child_restrict & COLLECTION_HIDE_VIEWPORT) == 0) {
867 }
868 if ((child_restrict & COLLECTION_HIDE_RENDER) == 0) {
869 base->flag |= BASE_ENABLED_RENDER;
870 }
871 }
872
873 LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
874 collection_object_cache_fill(lb, child->collection, child_restrict, with_instances);
875 }
876}
877
879{
880 if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) {
881 static blender::Mutex cache_lock;
882
883 std::scoped_lock lock(cache_lock);
884 if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) {
885 collection_object_cache_fill(&collection->runtime->object_cache, collection, 0, false);
886 collection->flag |= COLLECTION_HAS_OBJECT_CACHE;
887 }
888 }
889
890 return collection->runtime->object_cache;
891}
892
894{
895 if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE_INSTANCED)) {
896 static blender::Mutex cache_lock;
897
898 std::scoped_lock lock(cache_lock);
899 if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE_INSTANCED)) {
901 &collection->runtime->object_cache_instanced, collection, 0, true);
903 }
904 }
905
906 return collection->runtime->object_cache_instanced;
907}
908
909static void collection_object_cache_free(const Main *bmain,
910 Collection *collection,
911 const int id_create_flag,
912 const uint id_recalc_flag)
913{
915 BLI_freelistN(&collection->runtime->object_cache);
916 BLI_freelistN(&collection->runtime->object_cache_instanced);
917
918 /* Although it may seem abusive to call depsgraph updates from this utility function,
919 * it is called from any code-path modifying the collections hierarchy and/or their objects.
920 * Including the reversed-hierarchy walked by #collection_object_cache_free_parent_recursive.
921 *
922 * Plus, the main reason to tag the hierarchy of parents for deg update is because their object
923 * caches are being freed.
924 *
925 * Having this code here avoids the need for another utility tagging function processing the
926 * parent hierarchy as well. */
927 if (id_recalc_flag && (id_create_flag & (LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_DEG_TAG)) == 0)
928 {
929 BLI_assert(bmain != nullptr);
930 DEG_id_tag_update_ex(const_cast<Main *>(bmain), &collection->id, id_recalc_flag);
931 }
932}
933
936 Collection *collection,
937 const int id_create_flag,
938 const uint id_recalc_flag)
939{
940 collection_object_cache_free(bmain, collection, id_create_flag, id_recalc_flag);
941
942 /* Clear cache in all parents recursively, since those are affected by changes as well. */
943 LISTBASE_FOREACH (CollectionParent *, parent, &collection->runtime->parents) {
944 /* In theory there should be no nullptr pointer here. However, this code can be called from
945 * non-valid temporary states (e.g. indirectly from #BKE_collections_object_remove_invalids
946 * as part of ID remapping process). */
947 if (parent->collection == nullptr) {
948 continue;
949 }
951 bmain, parent->collection, id_create_flag, id_recalc_flag);
952 }
953}
954
956 Collection *collection,
957 const int id_create_flag)
958{
959 BLI_assert(collection != nullptr);
961 bmain, collection, id_create_flag, ID_RECALC_HIERARCHY | ID_RECALC_GEOMETRY);
962}
963
965{
966 for (Scene *scene = static_cast<Scene *>(bmain->scenes.first); scene != nullptr;
967 scene = static_cast<Scene *>(scene->id.next))
968 {
970 bmain, scene->master_collection, 0, ID_RECALC_HIERARCHY | ID_RECALC_GEOMETRY);
971 }
972
973 for (Collection *collection = static_cast<Collection *>(bmain->collections.first);
974 collection != nullptr;
975 collection = static_cast<Collection *>(collection->id.next))
976 {
978 }
979}
980
982 ViewLayer *view_layer,
983 Collection *collection)
984{
985 if (collection) {
986 return static_cast<Base *>(BKE_collection_object_cache_get(collection).first);
987 }
988 BKE_view_layer_synced_ensure(scene, view_layer);
989 return static_cast<Base *>(BKE_view_layer_object_bases_get(view_layer)->first);
990}
991
993
994/* -------------------------------------------------------------------- */
997
999{
1000 BLI_assert(scene != nullptr && scene->master_collection == nullptr);
1001
1002 /* Not an actual datablock, but owned by scene. */
1003 Collection *master_collection = static_cast<Collection *>(BKE_libblock_alloc_in_lib(
1005 master_collection->id.flag |= ID_FLAG_EMBEDDED_DATA;
1006 master_collection->owner_id = &scene->id;
1007 master_collection->flag |= COLLECTION_IS_MASTER;
1008 master_collection->color_tag = COLLECTION_COLOR_NONE;
1009
1010 BLI_assert(scene->id.lib == master_collection->id.lib);
1011 master_collection->runtime = MEM_new<blender::bke::CollectionRuntime>(__func__);
1012
1013 return master_collection;
1014}
1015
1017
1018/* -------------------------------------------------------------------- */
1021
1023{
1024 if (object->instance_collection) {
1025 Collection *dup_collection = object->instance_collection;
1026 if ((dup_collection->id.tag & ID_TAG_DOIT) == 0) {
1027 /* Cycle already exists in collections, let's prevent further creepiness. */
1028 return true;
1029 }
1030 /* flag the object to identify cyclic dependencies in further dupli collections */
1031 dup_collection->id.tag &= ~ID_TAG_DOIT;
1032
1033 if (dup_collection == collection) {
1034 return true;
1035 }
1036
1037 FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (dup_collection, collection_object) {
1038 if (collection_object_cyclic_check_internal(collection_object, dup_collection)) {
1039 return true;
1040 }
1041 }
1043
1044 /* un-flag the object, it's allowed to have the same collection multiple times in parallel */
1045 dup_collection->id.tag |= ID_TAG_DOIT;
1046 }
1047
1048 return false;
1049}
1050
1052{
1053 /* first flag all collections */
1055
1056 return collection_object_cyclic_check_internal(object, collection);
1057}
1058
1060
1061/* -------------------------------------------------------------------- */
1064
1065bool BKE_collection_has_object(Collection *collection, const Object *ob)
1066{
1067 if (ELEM(nullptr, collection, ob)) {
1068 return false;
1069 }
1071 return BLI_ghash_lookup(collection->runtime->gobject_hash, ob);
1072}
1073
1075{
1076 if (ELEM(nullptr, collection, ob)) {
1077 return false;
1078 }
1079
1080 const ListBase objects = BKE_collection_object_cache_get(collection);
1081 return BLI_findptr(&objects, ob, offsetof(Base, object));
1082}
1083
1085{
1086 if (ELEM(nullptr, collection, ob)) {
1087 return false;
1088 }
1089
1090 const ListBase objects = BKE_collection_object_cache_instanced_get(collection);
1091 return BLI_findptr(&objects, ob, offsetof(Base, object));
1092}
1093
1095 Object *object_eval)
1096{
1097 BLI_assert(collection_eval->id.tag & ID_TAG_COPIED_ON_EVAL);
1098 const Object *ob_orig = DEG_get_original(object_eval);
1099 const ListBase objects = BKE_collection_object_cache_instanced_get(collection_eval);
1100 LISTBASE_FOREACH (Base *, base, &objects) {
1101 if (DEG_get_original(base->object) == ob_orig) {
1102 return true;
1103 }
1104 }
1105 return false;
1106}
1107
1109{
1110 LISTBASE_FOREACH (CollectionObject *, col_ob, &collection->gobject) {
1111 if (col_ob->ob->visibility_flag & OB_HIDE_RENDER) {
1112 continue;
1113 }
1114 if (OB_TYPE_IS_GEOMETRY(col_ob->ob->type)) {
1115 return true;
1116 }
1117 }
1118
1119 LISTBASE_FOREACH (CollectionChild *, child_col, &collection->children) {
1120 if (child_col->collection->flag & COLLECTION_HIDE_RENDER) {
1121 continue;
1122 }
1123 if (BKE_collection_contains_geometry_recursive(child_col->collection)) {
1124 return true;
1125 }
1126 }
1127
1128 return false;
1129}
1130
1131static Collection *collection_next_find(Main *bmain, Scene *scene, Collection *collection)
1132{
1133 if (scene && collection == scene->master_collection) {
1134 return static_cast<Collection *>(bmain->collections.first);
1135 }
1136
1137 return static_cast<Collection *>(collection->id.next);
1138}
1139
1141 Scene *scene,
1142 Collection *collection,
1143 Object *ob)
1144{
1145 if (collection) {
1146 collection = collection_next_find(bmain, scene, collection);
1147 }
1148 else if (scene) {
1149 collection = scene->master_collection;
1150 }
1151 else {
1152 collection = static_cast<Collection *>(bmain->collections.first);
1153 }
1154
1155 while (collection) {
1156 if (BKE_collection_has_object(collection, ob)) {
1157 return collection;
1158 }
1159 collection = collection_next_find(bmain, scene, collection);
1160 }
1161 return nullptr;
1162}
1163
1165{
1166 return BLI_listbase_is_empty(&collection->gobject) &&
1167 BLI_listbase_is_empty(&collection->children);
1168}
1169
1171
1172/* -------------------------------------------------------------------- */
1175
1177 const bool do_extensive_check);
1178
1180{
1181 return BLI_ghash_ptr_new_ex(__func__, uint(BLI_listbase_count(&collection->gobject)));
1182}
1183
1185{
1186 GHash *gobject_hash = collection_gobject_hash_alloc(collection);
1187 LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
1188 if (UNLIKELY(cob->ob == nullptr)) {
1190 continue;
1191 }
1192 CollectionObject **cob_p;
1193 /* Do not overwrite an already existing entry. */
1194 if (UNLIKELY(BLI_ghash_ensure_p(gobject_hash, cob->ob, (void ***)&cob_p))) {
1196 continue;
1197 }
1198 *cob_p = cob;
1199 }
1200 collection->runtime->gobject_hash = gobject_hash;
1201}
1202
1204{
1205 if (collection->runtime->gobject_hash) {
1206#ifdef USE_DEBUG_EXTRA_GOBJECT_ASSERT
1208#endif
1209 return;
1210 }
1211
1213
1215}
1216
1222{
1223 bool changed = false;
1224
1225 if ((collection->runtime->tag & COLLECTION_TAG_COLLECTION_OBJECT_DIRTY) == 0) {
1226#ifdef USE_DEBUG_EXTRA_GOBJECT_ASSERT
1228#endif
1229 return;
1230 }
1231
1232 GHash *gobject_hash = collection->runtime->gobject_hash;
1233 if (gobject_hash) {
1234 BLI_ghash_clear_ex(gobject_hash, nullptr, nullptr, BLI_ghash_len(gobject_hash));
1235 }
1236 else {
1237 collection->runtime->gobject_hash = gobject_hash = collection_gobject_hash_alloc(collection);
1238 }
1239
1240 LISTBASE_FOREACH_MUTABLE (CollectionObject *, cob, &collection->gobject) {
1241 if (cob->ob == nullptr) {
1242 BLI_freelinkN(&collection->gobject, cob);
1243 changed = true;
1244 continue;
1245 }
1246 CollectionObject **cob_p;
1247 if (BLI_ghash_ensure_p(gobject_hash, cob->ob, (void ***)&cob_p)) {
1248 BLI_freelinkN(&collection->gobject, cob);
1249 changed = true;
1250 continue;
1251 }
1252 *cob_p = cob;
1253 }
1254
1255 if (changed) {
1256 BKE_collection_object_cache_free(bmain, collection, 0);
1257 }
1258
1261}
1262
1278 Object *ob_old,
1279 CollectionObject *cob)
1280{
1281 if (ob_old == cob->ob) {
1282 return;
1283 }
1284
1285 if (ob_old) {
1286 CollectionObject *cob_old = static_cast<CollectionObject *>(
1287 BLI_ghash_popkey(collection->runtime->gobject_hash, ob_old, nullptr));
1288 if (cob_old != cob) {
1289 /* Old object already removed from the #GHash. */
1291 }
1292 }
1293
1294 if (cob->ob) {
1295 CollectionObject **cob_p;
1296 if (!BLI_ghash_ensure_p(collection->runtime->gobject_hash, cob->ob, (void ***)&cob_p)) {
1297 *cob_p = cob;
1298 }
1299 else {
1300 /* Duplicate #CollectionObject entries. */
1302 }
1303 }
1304 else {
1305 /* #CollectionObject with nullptr object pointer. */
1307 }
1308}
1309
1324 const bool do_extensive_check)
1325{
1327 if (!do_extensive_check) {
1328 return;
1329 }
1330
1331 if (collection->runtime->gobject_hash == nullptr) {
1332 /* NOTE: If the `ghash` does not exist yet, it's creation will assert on errors,
1333 * so in theory the second loop below could be skipped. */
1335 }
1336 GHash *gobject_hash = collection->runtime->gobject_hash;
1337 UNUSED_VARS_NDEBUG(gobject_hash);
1338 LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
1339 BLI_assert(cob->ob != nullptr);
1340 /* If there are more than one #CollectionObject for the same object,
1341 * at most one of them will pass this test. */
1342 BLI_assert(BLI_ghash_lookup(gobject_hash, cob->ob) == cob);
1343 }
1344}
1345
1355 Collection *collection,
1356 bool &r_is_in_viewlayer)
1357{
1358 LayerCollection *layer_collection = view_layer ?
1360 view_layer, collection) :
1361 nullptr;
1362 r_is_in_viewlayer = layer_collection != nullptr;
1363
1364 if (!ID_IS_EDITABLE(collection) || ID_IS_OVERRIDE_LIBRARY(collection)) {
1365 return false;
1366 }
1367 if (!view_layer) {
1368 return true;
1369 }
1370
1371 if (!layer_collection) {
1372 return false;
1373 }
1374 if (layer_collection->flag & LAYER_COLLECTION_EXCLUDE) {
1375 return false;
1376 }
1377 return true;
1378}
1379
1381 Collection *collection)
1382{
1383 bool is_in_viewlayer = false;
1384 if (collection_is_editable_in_viewlayer(view_layer, collection, is_in_viewlayer)) {
1385 return collection;
1386 }
1387 if (view_layer && !is_in_viewlayer) {
1388 /* In case the collection is not in given view_layer, there is no point in searching in its
1389 * ancestors either. */
1390 return nullptr;
1391 }
1392
1393 if (collection->flag & COLLECTION_IS_MASTER) {
1394 return nullptr;
1395 }
1396
1397 LISTBASE_FOREACH (CollectionParent *, collection_parent, &collection->runtime->parents) {
1399 view_layer, collection_parent->collection);
1400 if (editable_collection) {
1401 return editable_collection;
1402 }
1403 }
1404
1405 return nullptr;
1406}
1407
1408static bool collection_object_add(Main *bmain,
1409 Collection *collection,
1410 Object *ob,
1411 CollectionLightLinking *light_linking,
1412 const int id_create_flag,
1413 const bool add_us)
1414{
1415 /* Cyclic dependency check. */
1416 if (ob->instance_collection) {
1417 if ((ob->instance_collection == collection) ||
1419 {
1420 return false;
1421 }
1422 }
1423
1425 CollectionObject **cob_p;
1426 if (BLI_ghash_ensure_p(collection->runtime->gobject_hash, ob, (void ***)&cob_p)) {
1427 return false;
1428 }
1429
1431 cob->ob = ob;
1432 if (light_linking) {
1433 cob->light_linking = *light_linking;
1434 }
1435 *cob_p = cob;
1436 BLI_addtail(&collection->gobject, cob);
1437 BKE_collection_object_cache_free(bmain, collection, id_create_flag);
1438
1439 if (add_us && (id_create_flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
1440 id_us_plus(&ob->id);
1441 }
1442
1443 if ((id_create_flag & LIB_ID_CREATE_NO_MAIN) == 0) {
1444 BKE_rigidbody_main_collection_object_add(bmain, collection, ob);
1445 }
1446
1447 return true;
1448}
1449
1455 Collection *collection,
1456 CollectionObject *cob,
1457 const int id_create_flag,
1458 const bool free_us)
1459{
1460 Object *ob = cob->ob;
1461 BLI_freelinkN(&collection->gobject, cob);
1462 BKE_collection_object_cache_free(bmain, collection, id_create_flag);
1463
1464 if (free_us) {
1465 BKE_id_free_us(bmain, ob);
1466 }
1467 else {
1468 id_us_min(&ob->id);
1469 }
1470}
1471
1473 Main *bmain, Collection *collection, Object *ob, const int id_create_flag, const bool free_us)
1474{
1476 CollectionObject *cob = static_cast<CollectionObject *>(
1477 BLI_ghash_popkey(collection->runtime->gobject_hash, ob, nullptr));
1478 if (cob == nullptr) {
1479 return false;
1480 }
1481 collection_object_remove_no_gobject_hash(bmain, collection, cob, id_create_flag, free_us);
1482 return true;
1483}
1484
1485CollectionExport *BKE_collection_exporter_add(Collection *collection, char *idname, char *label)
1486{
1487 /* Add a new #CollectionExport item to our handler list and fill it with #FileHandlerType
1488 * information. Also load in the operator's properties now as well. */
1490 STRNCPY(data->fh_idname, idname);
1491
1492 BKE_collection_exporter_name_set(&collection->exporters, data, label);
1493
1494 IDPropertyTemplate val{};
1495 data->export_properties = IDP_New(IDP_GROUP, &val, "export_properties");
1496 data->flag |= IO_HANDLER_PANEL_OPEN;
1497
1498 BLI_addtail(&collection->exporters, data);
1499 collection->active_exporter_index = BLI_listbase_count(&collection->exporters) - 1;
1500
1501 return data;
1502}
1503
1505{
1506 ListBase *exporters = &collection->exporters;
1507 BLI_remlink(exporters, data);
1509
1510 MEM_freeN(data);
1511
1512 const int count = BLI_listbase_count(exporters);
1513 const int new_index = count == 0 ? 0 : std::min(collection->active_exporter_index, count - 1);
1514 collection->active_exporter_index = new_index;
1515}
1516
1517bool BKE_collection_exporter_move(Collection *collection, const int from, const int to)
1518{
1519 if (from == to) {
1520 return false;
1521 }
1522
1523 return BLI_listbase_move_index(&collection->exporters, from, to);
1524}
1525
1527{
1528 CollectionExport *new_data = MEM_callocN<CollectionExport>("CollectionExport");
1529 STRNCPY(new_data->fh_idname, data->fh_idname);
1530 new_data->export_properties = IDP_CopyProperty(data->export_properties);
1531 new_data->flag = data->flag;
1532
1533 /* Clear the `filepath` property. */
1534 IDProperty *filepath = IDP_GetPropertyFromGroup(new_data->export_properties, "filepath");
1535 if (filepath) {
1536 IDP_AssignString(filepath, "");
1537 }
1538
1539 BLI_addtail(&collection->exporters, new_data);
1540}
1541
1543{
1544 if (ob == nullptr) {
1545 return false;
1546 }
1547
1548 /* Only case where this pointer can be nullptr is when scene itself is linked, this case should
1549 * never be reached. */
1550 BLI_assert(collection != nullptr);
1551 if (collection == nullptr) {
1552 return false;
1553 }
1554
1555 const int id_create_flag = (collection->id.tag & ID_TAG_NO_MAIN) ? LIB_ID_CREATE_NO_MAIN : 0;
1556 if (!collection_object_add(bmain, collection, ob, nullptr, id_create_flag, true)) {
1557 return false;
1558 }
1559
1560 if (BKE_collection_is_in_scene(collection)) {
1562 }
1563
1564 return true;
1565}
1566
1567bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
1568{
1569 return BKE_collection_viewlayer_object_add(bmain, nullptr, collection, ob);
1570}
1571
1573 const ViewLayer *view_layer,
1574 Collection *collection,
1575 Object *ob)
1576{
1577 if (collection == nullptr) {
1578 return false;
1579 }
1580
1581 collection = BKE_collection_parent_editable_find_recursive(view_layer, collection);
1582
1583 if (collection == nullptr) {
1584 return false;
1585 }
1586
1587 return BKE_collection_object_add_notest(bmain, collection, ob);
1588}
1589
1590void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, Object *ob_dst)
1591{
1592 bool is_instantiated = false;
1593
1594 FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
1595 if (ID_IS_EDITABLE(collection) && !ID_IS_OVERRIDE_LIBRARY(collection) &&
1596 BKE_collection_has_object(collection, ob_src))
1597 {
1598 collection_object_add(bmain, collection, ob_dst, nullptr, 0, true);
1599 is_instantiated = true;
1600 }
1601 }
1603
1604 if (!is_instantiated) {
1605 /* In case we could not find any non-linked collections in which instantiate our ob_dst,
1606 * fall back to scene's master collection... */
1607 collection_object_add(bmain, scene->master_collection, ob_dst, nullptr, 0, true);
1608 }
1609
1611}
1612
1614 Collection *collection,
1615 Object *ob,
1616 const bool free_us)
1617{
1618 if (ELEM(nullptr, collection, ob)) {
1619 return false;
1620 }
1621
1622 const int id_create_flag = (collection->id.tag & ID_TAG_NO_MAIN) ? LIB_ID_CREATE_NO_MAIN : 0;
1623 if (!collection_object_remove(bmain, collection, ob, id_create_flag, free_us)) {
1624 return false;
1625 }
1626
1627 if (BKE_collection_is_in_scene(collection)) {
1629 }
1630
1631 return true;
1632}
1633
1635 Collection *collection,
1636 Object *ob_old,
1637 Object *ob_new)
1638{
1640 CollectionObject *cob;
1641 cob = static_cast<CollectionObject *>(
1642 BLI_ghash_popkey(collection->runtime->gobject_hash, ob_old, nullptr));
1643 if (cob == nullptr) {
1644 return false;
1645 }
1646
1647 if (!BLI_ghash_haskey(collection->runtime->gobject_hash, ob_new)) {
1648 id_us_min(&cob->ob->id);
1649 cob->ob = ob_new;
1650 id_us_plus(&cob->ob->id);
1651
1652 BLI_ghash_insert(collection->runtime->gobject_hash, cob->ob, cob);
1653 }
1654 else {
1655 collection_object_remove_no_gobject_hash(bmain, collection, cob, 0, false);
1656 }
1657
1658 if (BKE_collection_is_in_scene(collection)) {
1660 }
1661
1662 return true;
1663}
1664
1670 Main *bmain, Scene *scene, Object *ob, const bool free_us, Collection *collection_skip)
1671{
1672 bool removed = false;
1673 const int id_create_flag = (scene->id.tag & ID_TAG_NO_MAIN) ? LIB_ID_CREATE_NO_MAIN : 0;
1674
1675 /* If given object is removed from all collections in given scene, then it can also be safely
1676 * removed from rigidbody world for given scene. */
1677 if (collection_skip == nullptr) {
1678 BKE_scene_remove_rigidbody_object(bmain, scene, ob, free_us);
1679 }
1680
1681 FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
1682 if (!ID_IS_EDITABLE(collection) || ID_IS_OVERRIDE_LIBRARY(collection)) {
1683 continue;
1684 }
1685 if (collection == collection_skip) {
1686 continue;
1687 }
1688
1689 removed |= collection_object_remove(bmain, collection, ob, id_create_flag, free_us);
1690 }
1692
1694
1695 return removed;
1696}
1697
1698bool BKE_scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us)
1699{
1700 return scene_collections_object_remove(bmain, scene, ob, free_us, nullptr);
1701}
1702
1704{
1705 LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
1706 collection_gobject_hash_ensure_fix(bmain, scene->master_collection);
1707 }
1708
1709 LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
1710 collection_gobject_hash_ensure_fix(bmain, collection);
1711 }
1712}
1713
1715{
1716 LISTBASE_FOREACH_MUTABLE (CollectionChild *, child, &collection->children) {
1717 if (child->collection == nullptr) {
1718 BLI_freelinkN(&collection->children, child);
1719 }
1720 }
1721}
1722
1724{
1725 LISTBASE_FOREACH_MUTABLE (CollectionParent *, parent, &collection->runtime->parents) {
1726 if ((parent->collection == nullptr) ||
1727 !BKE_collection_child_find(parent->collection, collection))
1728 {
1729 BLI_freelinkN(&collection->runtime->parents, parent);
1730 }
1731 }
1732}
1733
1735 Collection *parent_collection,
1736 Collection *child_collection)
1737{
1738 if (child_collection == nullptr) {
1739 if (parent_collection != nullptr) {
1740 collection_null_children_remove(parent_collection);
1741 }
1742 else {
1743 /* We need to do the checks in two steps when more than one collection may be involved,
1744 * otherwise we can miss some cases...
1745 * Also, master collections are not in bmain, so we also need to loop over scenes.
1746 */
1747 LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
1749 }
1750 LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
1751 collection_null_children_remove(scene->master_collection);
1752 }
1753 }
1754
1755 LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
1757 }
1758 LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
1759 collection_missing_parents_remove(scene->master_collection);
1760 }
1761 }
1762 else {
1763 LISTBASE_FOREACH_MUTABLE (CollectionParent *, parent, &child_collection->runtime->parents) {
1764 collection_null_children_remove(parent->collection);
1765
1766 if (!BKE_collection_child_find(parent->collection, child_collection)) {
1767 BLI_freelinkN(&child_collection->runtime->parents, parent);
1768 }
1769 }
1770 }
1771}
1772
1774 Main *bmain, Scene *scene, Collection *collection_dst, Collection *collection_src, Object *ob)
1775{
1776 /* In both cases we first add the object, then remove it from the other collections.
1777 * Otherwise we lose the original base and whether it was active and selected. */
1778 if (collection_src != nullptr) {
1779 if (BKE_collection_object_add(bmain, collection_dst, ob)) {
1780 BKE_collection_object_remove(bmain, collection_src, ob, false);
1781 }
1782 }
1783 else {
1784 /* Adding will fail if object is already in collection.
1785 * However we still need to remove it from the other collections. */
1786 BKE_collection_object_add(bmain, collection_dst, ob);
1787 scene_collections_object_remove(bmain, scene, ob, false, collection_dst);
1788 }
1789}
1790
1792
1793/* -------------------------------------------------------------------- */
1796
1798{
1799 if (collection->flag & COLLECTION_IS_MASTER) {
1800 return true;
1801 }
1802
1803 LISTBASE_FOREACH (CollectionParent *, cparent, &collection->runtime->parents) {
1804 if (BKE_collection_is_in_scene(cparent->collection)) {
1805 return true;
1806 }
1807 }
1808
1809 return false;
1810}
1811
1813{
1814 /* Need to update layer collections because objects might have changed
1815 * in linked files, and because undo push does not include updated base
1816 * flags since those are refreshed after the operator completes. */
1818}
1819
1821
1822/* -------------------------------------------------------------------- */
1825
1827 Collection *instance_collection)
1828{
1829 LISTBASE_FOREACH (CollectionObject *, collection_object, &collection->gobject) {
1830 if (collection_object->ob != nullptr &&
1831 /* Object from a given collection should never instantiate that collection either. */
1832 ELEM(collection_object->ob->instance_collection, instance_collection, collection))
1833 {
1834 return true;
1835 }
1836 }
1837
1838 LISTBASE_FOREACH (CollectionChild *, collection_child, &collection->children) {
1839 if (collection_child->collection != nullptr &&
1840 collection_instance_find_recursive(collection_child->collection, instance_collection))
1841 {
1842 return true;
1843 }
1844 }
1845
1846 return false;
1847}
1848
1849bool BKE_collection_cycle_find(Collection *new_ancestor, Collection *collection)
1850{
1851 if (collection == new_ancestor) {
1852 return true;
1853 }
1854
1855 if (collection == nullptr) {
1856 collection = new_ancestor;
1857 }
1858
1859 LISTBASE_FOREACH (CollectionParent *, parent, &new_ancestor->runtime->parents) {
1860 if (BKE_collection_cycle_find(parent->collection, collection)) {
1861 return true;
1862 }
1863 }
1864
1865 /* Find possible objects in collection or its children, that would instantiate the given ancestor
1866 * collection (that would also make a fully invalid cycle of dependencies). */
1867 return collection_instance_find_recursive(collection, new_ancestor);
1868}
1869
1870static bool collection_instance_fix_recursive(Collection *parent_collection,
1871 Collection *collection)
1872{
1873 bool cycles_found = false;
1874
1875 LISTBASE_FOREACH (CollectionObject *, collection_object, &parent_collection->gobject) {
1876 if (collection_object->ob != nullptr &&
1877 collection_object->ob->instance_collection == collection)
1878 {
1879 id_us_min(&collection->id);
1880 collection_object->ob->instance_collection = nullptr;
1881 cycles_found = true;
1882 }
1883 }
1884
1885 LISTBASE_FOREACH (CollectionChild *, collection_child, &parent_collection->children) {
1886 if (collection_instance_fix_recursive(collection_child->collection, collection)) {
1887 cycles_found = true;
1888 }
1889 }
1890
1891 return cycles_found;
1892}
1893
1895 Collection *parent_collection,
1896 Collection *collection)
1897{
1898 bool cycles_found = false;
1899
1900 LISTBASE_FOREACH_MUTABLE (CollectionParent *, parent, &parent_collection->runtime->parents) {
1901 if (BKE_collection_cycle_find(parent->collection, collection)) {
1902 BKE_collection_child_remove(bmain, parent->collection, parent_collection);
1903 cycles_found = true;
1904 }
1905 else if (collection_cycle_fix_recursive(bmain, parent->collection, collection)) {
1906 cycles_found = true;
1907 }
1908 }
1909
1910 return cycles_found;
1911}
1912
1914{
1915 return collection_cycle_fix_recursive(bmain, collection, collection) ||
1916 collection_instance_fix_recursive(collection, collection);
1917}
1918
1920{
1921 return static_cast<CollectionChild *>(
1922 BLI_findptr(&parent->children, collection, offsetof(CollectionChild, collection)));
1923}
1924
1925static bool collection_find_child_recursive(const Collection *parent, const Collection *collection)
1926{
1927 LISTBASE_FOREACH (const CollectionChild *, child, &parent->children) {
1928 if (child->collection == collection) {
1929 return true;
1930 }
1931
1932 if (collection_find_child_recursive(child->collection, collection)) {
1933 return true;
1934 }
1935 }
1936
1937 return false;
1938}
1939
1940bool BKE_collection_has_collection(const Collection *parent, const Collection *collection)
1941{
1942 return collection_find_child_recursive(parent, collection);
1943}
1944
1946{
1947 return static_cast<CollectionParent *>(
1948 BLI_findptr(&child->runtime->parents, collection, offsetof(CollectionParent, collection)));
1949}
1950
1951static bool collection_child_add(Main *bmain,
1952 Collection *parent,
1953 Collection *collection,
1954 const CollectionLightLinking *light_linking,
1955 const int id_create_flag,
1956 const bool add_us)
1957{
1958 CollectionChild *child = BKE_collection_child_find(parent, collection);
1959 if (child) {
1960 return false;
1961 }
1962 if (BKE_collection_cycle_find(parent, collection)) {
1963 return false;
1964 }
1965
1966 child = MEM_callocN<CollectionChild>("CollectionChild");
1967 child->collection = collection;
1968 if (light_linking) {
1969 child->light_linking = *light_linking;
1970 }
1971 BLI_addtail(&parent->children, child);
1972
1973 /* Don't add parent links for depsgraph datablocks, these are not kept in sync. */
1974 if ((id_create_flag & LIB_ID_CREATE_NO_MAIN) == 0) {
1975 CollectionParent *cparent = MEM_callocN<CollectionParent>("CollectionParent");
1976 cparent->collection = parent;
1977 BLI_addtail(&collection->runtime->parents, cparent);
1978 }
1979
1980 if (add_us) {
1981 id_us_plus(&collection->id);
1982 }
1983
1984 BKE_collection_object_cache_free(bmain, parent, id_create_flag);
1985
1986 return true;
1987}
1988
1990 Collection *parent,
1991 Collection *collection,
1992 const int id_create_flag)
1993{
1994 CollectionChild *child = BKE_collection_child_find(parent, collection);
1995 if (child == nullptr) {
1996 return false;
1997 }
1998
1999 CollectionParent *cparent = collection_find_parent(collection, parent);
2000 BLI_freelinkN(&collection->runtime->parents, cparent);
2001 BLI_freelinkN(&parent->children, child);
2002
2003 id_us_min(&collection->id);
2004
2005 BKE_collection_object_cache_free(bmain, parent, id_create_flag);
2006
2007 return true;
2008}
2009
2011{
2012 if (!collection_child_add(bmain, parent, child, nullptr, 0, true)) {
2013 return false;
2014 }
2015
2017 return true;
2018}
2019
2021{
2022 return collection_child_add(bmain, parent, child, nullptr, 0, true);
2023}
2024
2026{
2027 if (!collection_child_remove(bmain, parent, child, 0)) {
2028 return false;
2029 }
2030
2032 return true;
2033}
2034
2036{
2037 LISTBASE_FOREACH_MUTABLE (CollectionChild *, child, &collection->children) {
2038 /* Check for duplicated children (can happen with remapping e.g.). */
2039 CollectionChild *other_child = BKE_collection_child_find(collection, child->collection);
2040 if (other_child != child) {
2041 BLI_freelinkN(&collection->children, child);
2042 continue;
2043 }
2044
2045 /* Invalid child, either without a collection, or because it creates a dependency cycle. */
2046 if (child->collection == nullptr || BKE_collection_cycle_find(collection, child->collection)) {
2047 BLI_freelinkN(&collection->children, child);
2048 continue;
2049 }
2050
2051 /* Can happen when remapping data partially out-of-Main (during advanced ID management
2052 * operations like lib-override resync e.g.). */
2053 if ((child->collection->id.tag & (ID_TAG_NO_MAIN | ID_TAG_COPIED_ON_EVAL)) != 0) {
2054 continue;
2055 }
2056
2057 BLI_assert(collection_find_parent(child->collection, collection) == nullptr);
2059 cparent->collection = collection;
2060 BLI_addtail(&child->collection->runtime->parents, cparent);
2061 }
2062}
2063
2065{
2066 /* A same collection may be child of several others, no need to process it more than once. */
2067 if ((collection->runtime->tag & COLLECTION_TAG_RELATION_REBUILD) == 0) {
2068 return;
2069 }
2070
2072 collection->runtime->tag &= ~COLLECTION_TAG_RELATION_REBUILD;
2073
2074 LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
2075 /* See comment above in `BKE_collection_parent_relations_rebuild`. */
2076 if ((child->collection->id.tag & (ID_TAG_NO_MAIN | ID_TAG_COPIED_ON_EVAL)) != 0) {
2077 continue;
2078 }
2079 collection_parents_rebuild_recursive(child->collection);
2080 }
2081}
2082
2084{
2085 /* Only collections not in bmain (master ones in scenes) have no parent... */
2086 LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
2087 BLI_freelistN(&collection->runtime->parents);
2088
2089 collection->runtime->tag |= COLLECTION_TAG_RELATION_REBUILD;
2090 }
2091
2092 /* Scene's master collections will be 'root' parent of most of our collections, so start with
2093 * them. */
2094 LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
2095 /* This function can be called from `readfile.cc`, when this pointer is not guaranteed to be
2096 * nullptr.
2097 */
2098 if (scene->master_collection != nullptr) {
2099 BLI_assert(BLI_listbase_is_empty(&scene->master_collection->runtime->parents));
2100 scene->master_collection->runtime->tag |= COLLECTION_TAG_RELATION_REBUILD;
2101 collection_parents_rebuild_recursive(scene->master_collection);
2102 }
2103 }
2104
2105 /* We may have parent chains outside of scene's master_collection context? At least, readfile's
2106 * #collection_blend_read_after_liblink() seems to assume that, so do the same here. */
2107 LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
2108 if (collection->runtime->tag & COLLECTION_TAG_RELATION_REBUILD) {
2109 /* NOTE: we do not have easy access to 'which collections is root' info in that case, which
2110 * means test for cycles in collection relationships may fail here. I don't think that is an
2111 * issue in practice here, but worth keeping in mind... */
2113 }
2114 }
2115}
2116
2118{
2119 if (!BLI_listbase_validate(&collection->children)) {
2120 return false;
2121 }
2122 if (!BLI_listbase_validate(&collection->runtime->parents)) {
2123 return false;
2124 }
2125 if (BKE_collection_cycle_find(collection, nullptr)) {
2126 return false;
2127 }
2128
2129 bool is_ok = true;
2130
2131 /* Check that children have each collection used/referenced only once. */
2132 GSet *processed_collections = BLI_gset_ptr_new(__func__);
2133 LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
2134 void **r_key;
2135 if (BLI_gset_ensure_p_ex(processed_collections, child->collection, &r_key)) {
2136 is_ok = false;
2137 }
2138 else {
2139 *r_key = child->collection;
2140 }
2141 }
2142
2143 /* Check that parents have each collection used/referenced only once. */
2144 BLI_gset_clear(processed_collections, nullptr);
2145 LISTBASE_FOREACH (CollectionParent *, parent, &collection->runtime->parents) {
2146 void **r_key;
2147 if (BLI_gset_ensure_p_ex(processed_collections, parent->collection, &r_key)) {
2148 is_ok = false;
2149 }
2150 else {
2151 *r_key = parent->collection;
2152 }
2153 }
2154
2155 BLI_gset_free(processed_collections, nullptr);
2156 return is_ok;
2157}
2158
2160
2161/* -------------------------------------------------------------------- */
2164
2166 uint64_t session_uid)
2167{
2168
2169 LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
2170 if (child->collection->id.session_uid == session_uid) {
2171 return child->collection;
2172 }
2173 Collection *nested = collection_from_session_uid_recursive(child->collection, session_uid);
2174 if (nested != nullptr) {
2175 return nested;
2176 }
2177 }
2178 return nullptr;
2179}
2180
2182{
2183 Collection *master_collection = scene->master_collection;
2184 if (master_collection->id.session_uid == session_uid) {
2185 return scene->master_collection;
2186 }
2187 return collection_from_session_uid_recursive(master_collection, session_uid);
2188}
2189
2191{
2192 LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
2193 Collection *collection = BKE_collection_from_session_uid(scene, session_uid);
2194 if (collection) {
2195 if (r_scene) {
2196 *r_scene = scene;
2197 }
2198 return collection;
2199 }
2200 }
2201 return nullptr;
2202}
2203
2204static bool collection_objects_select(const Scene *scene,
2205 ViewLayer *view_layer,
2206 Collection *collection,
2207 bool deselect)
2208{
2209 bool changed = false;
2210
2211 if (collection->flag & COLLECTION_HIDE_SELECT) {
2212 return false;
2213 }
2214
2215 BKE_view_layer_synced_ensure(scene, view_layer);
2216 LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
2217 Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
2218
2219 if (base) {
2220 if (deselect) {
2221 if (base->flag & BASE_SELECTED) {
2222 base->flag &= ~BASE_SELECTED;
2223 changed = true;
2224 }
2225 }
2226 else {
2227 if ((base->flag & BASE_SELECTABLE) && !(base->flag & BASE_SELECTED)) {
2228 base->flag |= BASE_SELECTED;
2229 changed = true;
2230 }
2231 }
2232 }
2233 }
2234
2235 LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
2236 if (collection_objects_select(scene, view_layer, collection, deselect)) {
2237 changed = true;
2238 }
2239 }
2240
2241 return changed;
2242}
2243
2245 ViewLayer *view_layer,
2246 Collection *collection,
2247 bool deselect)
2248{
2250 collection);
2251
2252 if (layer_collection != nullptr) {
2253 return BKE_layer_collection_objects_select(scene, view_layer, layer_collection, deselect);
2254 }
2255
2256 return collection_objects_select(scene, view_layer, collection, deselect);
2257}
2258
2260
2261/* -------------------------------------------------------------------- */
2264
2266 Collection *to_parent,
2267 Collection *from_parent,
2268 Collection *relative,
2269 bool relative_after,
2270 Collection *collection)
2271{
2272 if (collection->flag & COLLECTION_IS_MASTER) {
2273 return false;
2274 }
2275 if (BKE_collection_cycle_find(to_parent, collection)) {
2276 return false;
2277 }
2278
2279 /* Move to new parent collection */
2280 if (from_parent) {
2281 collection_child_remove(bmain, from_parent, collection, 0);
2282 }
2283
2284 collection_child_add(bmain, to_parent, collection, nullptr, 0, true);
2285
2286 /* Move to specified location under parent. */
2287 if (relative) {
2288 CollectionChild *child = BKE_collection_child_find(to_parent, collection);
2289 CollectionChild *relative_child = BKE_collection_child_find(to_parent, relative);
2290
2291 if (relative_child) {
2292 BLI_remlink(&to_parent->children, child);
2293
2294 if (relative_after) {
2295 BLI_insertlinkafter(&to_parent->children, relative_child, child);
2296 }
2297 else {
2298 BLI_insertlinkbefore(&to_parent->children, relative_child, child);
2299 }
2300
2301 BKE_collection_object_cache_free(bmain, to_parent, 0);
2302 }
2303 }
2304
2305 /* Update layer collections. */
2307
2308 return true;
2309}
2310
2312
2313/* -------------------------------------------------------------------- */
2316
2317/* Scene collection iterator. */
2318
2324
2326 BKE_scene_collections_Cb callback,
2327 void *data)
2328{
2329 callback(collection, data);
2330
2331 LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
2332 scene_collection_callback(child->collection, callback, data);
2333 }
2334}
2335
2336static void scene_collections_count(Collection * /*collection*/, void *data)
2337{
2338 int *tot = static_cast<int *>(data);
2339 (*tot)++;
2340}
2341
2342static void scene_collections_build_array(Collection *collection, void *data)
2343{
2344 Collection ***array = static_cast<Collection ***>(data);
2345 **array = collection;
2346 (*array)++;
2347}
2348
2350 Collection ***r_collections_array,
2351 int *r_collections_array_len)
2352{
2353 *r_collections_array = nullptr;
2354 *r_collections_array_len = 0;
2355
2356 if (scene == nullptr) {
2357 return;
2358 }
2359
2360 Collection *collection = scene->master_collection;
2361 BLI_assert(collection != nullptr);
2362 scene_collection_callback(collection, scene_collections_count, r_collections_array_len);
2363
2364 BLI_assert(*r_collections_array_len > 0);
2365
2366 Collection **array = MEM_malloc_arrayN<Collection *>(size_t(*r_collections_array_len),
2367 "CollectionArray");
2368 *r_collections_array = array;
2370}
2371
2373{
2374 Scene *scene = static_cast<Scene *>(data_in);
2376
2377 data->scene = scene;
2378
2379 BLI_ITERATOR_INIT(iter);
2380 iter->data = data;
2381
2382 scene_collections_array(scene, (Collection ***)&data->array, &data->tot);
2383 BLI_assert(data->tot != 0);
2384
2385 data->cur = 0;
2386 iter->current = data->array[data->cur];
2387}
2388
2390{
2392
2393 if (++data->cur < data->tot) {
2394 iter->current = data->array[data->cur];
2395 }
2396 else {
2397 iter->valid = false;
2398 }
2399}
2400
2402{
2404
2405 if (data) {
2406 if (data->array) {
2407 MEM_freeN(data->array);
2408 }
2409 MEM_freeN(data);
2410 }
2411 iter->valid = false;
2412}
2413
2414/* scene objects iterator */
2415
2421
2422static void scene_objects_iterator_begin(BLI_Iterator *iter, Scene *scene, GSet *visited_objects)
2423{
2425
2426 BLI_ITERATOR_INIT(iter);
2427 iter->data = data;
2428
2429 /* Lookup list to make sure that each object is only processed once. */
2430 if (visited_objects != nullptr) {
2431 data->visited = visited_objects;
2432 }
2433 else {
2434 data->visited = BLI_gset_ptr_new(__func__);
2435 }
2436
2437 /* We wrap the scene-collection iterator here to go over the scene collections. */
2438 BKE_scene_collections_iterator_begin(&data->scene_collection_iter, scene);
2439
2440 Collection *collection = static_cast<Collection *>(data->scene_collection_iter.current);
2441 data->cob_next = static_cast<CollectionObject *>(collection->gobject.first);
2442
2444}
2445
2447{
2448 Scene *scene = static_cast<Scene *>(data_in);
2449
2450 scene_objects_iterator_begin(iter, scene, nullptr);
2451}
2452
2454{
2455 if (!iter->valid) {
2456 return;
2457 }
2458
2459 /* Unpack the data. */
2461 iter->data = data->iter_data;
2462
2463 Object *ob = static_cast<Object *>(iter->current);
2464 if (ob && (ob->flag & data->flag) == 0) {
2465 iter->skip = true;
2466 }
2467
2468 /* Pack the data. */
2469 data->iter_data = iter->data;
2470 iter->data = data;
2471}
2472
2474{
2476
2478
2479 /* Pack the data. */
2480 data->iter_data = iter->data;
2481 iter->data = data_in;
2482
2484}
2485
2487{
2488 /* Unpack the data. */
2490 iter->data = data->iter_data;
2491
2493
2494 /* Pack the data. */
2495 data->iter_data = iter->data;
2496 iter->data = data;
2497
2499}
2500
2502{
2503 /* Unpack the data. */
2505 iter->data = data->iter_data;
2506
2508
2509 /* Pack the data. */
2510 data->iter_data = iter->data;
2511 iter->data = data;
2512}
2513
2518{
2519 for (; cob != nullptr; cob = cob->next) {
2520 Object *ob = cob->ob;
2521 void **ob_key_p;
2522 if (!BLI_gset_ensure_p_ex(gs, ob, &ob_key_p)) {
2523 *ob_key_p = ob;
2524 return cob;
2525 }
2526 }
2527 return nullptr;
2528}
2529
2531{
2533 CollectionObject *cob = data->cob_next ? object_base_unique(data->visited, data->cob_next) :
2534 nullptr;
2535
2536 if (cob) {
2537 data->cob_next = cob->next;
2538 iter->current = cob->ob;
2539 }
2540 else {
2541 /* if this is the last object of this ListBase look at the next Collection */
2542 Collection *collection;
2543 BKE_scene_collections_iterator_next(&data->scene_collection_iter);
2544 do {
2545 collection = static_cast<Collection *>(data->scene_collection_iter.current);
2546 /* get the first unique object of this collection */
2548 data->visited, static_cast<CollectionObject *>(collection->gobject.first));
2549 if (new_cob) {
2550 data->cob_next = new_cob->next;
2551 iter->current = new_cob->ob;
2552 return;
2553 }
2554 BKE_scene_collections_iterator_next(&data->scene_collection_iter);
2555 } while (data->scene_collection_iter.valid);
2556
2557 if (!data->scene_collection_iter.valid) {
2558 iter->valid = false;
2559 }
2560 }
2561}
2562
2564{
2566 if (data) {
2567 BKE_scene_collections_iterator_end(&data->scene_collection_iter);
2568 if (data->visited != nullptr) {
2569 BLI_gset_free(data->visited, nullptr);
2570 }
2571 MEM_freeN(data);
2572 }
2573}
2574
2576{
2577 BLI_Iterator iter;
2578 scene_objects_iterator_begin(&iter, scene, objects_gset);
2579 while (iter.valid) {
2581 }
2582
2583 /* `return_gset` is either given `objects_gset` (if non-nullptr), or the GSet allocated by the
2584 * iterator. Either way, we want to get it back, and prevent `BKE_scene_objects_iterator_end`
2585 * from freeing it. */
2586 GSet *return_gset = ((SceneObjectsIteratorData *)iter.data)->visited;
2587 ((SceneObjectsIteratorData *)iter.data)->visited = nullptr;
2589
2590 return return_gset;
2591}
2592
#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
@ COLLECTION_TAG_COLLECTION_OBJECT_DIRTY
@ COLLECTION_TAG_RELATION_REBUILD
IDProperty * IDP_GetPropertyFromGroup(const IDProperty *prop, blender::StringRef name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:747
void IDP_AssignString(IDProperty *prop, const char *st) ATTR_NONNULL()
Definition idprop.cc:439
#define IDP_BlendDataRead(reader, prop)
void IDP_FreeProperty(IDProperty *prop)
Definition idprop.cc:1251
IDProperty * IDP_New(char type, const IDPropertyTemplate *val, blender::StringRef name, eIDPropertyFlag flags={}) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:1009
IDProperty * IDP_CopyProperty(const IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:863
void IDP_BlendWrite(BlendWriter *writer, const IDProperty *prop)
Definition idprop.cc:1461
@ IDTYPE_FLAGS_APPEND_IS_REUSABLE
Definition BKE_idtype.hh:47
@ IDTYPE_FLAGS_NO_ANIMDATA
Definition BKE_idtype.hh:49
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:787
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:358
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:2001
void * BKE_id_new(Main *bmain, short type, const char *name)
Definition lib_id.cc:1514
@ 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_min(ID *id)
Definition lib_id.cc:366
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:1352
void BKE_main_id_tag_listbase(ListBase *lb, int tag, bool value)
Definition lib_id.cc:1201
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:2631
#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:931
@ ID_REMAP_SKIP_USER_CLEAR
@ ID_REMAP_FORCE_OBDATA_IN_EDITMODE
#define FOREACH_MAIN_ID_END
Definition BKE_main.hh:583
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition BKE_main.hh:577
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:2336
#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)
bool BLI_listbase_move_index(ListBase *listbase, int from, int to) ATTR_NONNULL()
Definition listbase.cc:467
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 * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
size_t size_t size_t BLI_snprintf_utf8(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
char size_t BLI_strncpy_utf8_rlen(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
#define STRNCPY_UTF8(dst, src)
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:5744
#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:189
T * DEG_get_original(T *id)
ID and Library types, which are fundamental for SDNA.
#define FILTER_ID_OB
Definition DNA_ID.h:1214
@ ID_TAG_NEW
Definition DNA_ID.h:919
@ ID_TAG_COPIED_ON_EVAL
Definition DNA_ID.h:997
@ ID_TAG_DOIT
Definition DNA_ID.h:1036
@ ID_TAG_NO_MAIN
Definition DNA_ID.h:978
@ ID_RECALC_HIERARCHY
Definition DNA_ID.h:1158
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
#define ID_IS_OVERRIDABLE_LIBRARY(_id)
Definition DNA_ID.h:716
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:694
#define MAX_ID_NAME
Definition DNA_ID.h:373
#define FILTER_ID_GR
Definition DNA_ID.h:1203
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:705
@ INDEX_ID_GR
Definition DNA_ID.h:1340
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:730
@ ID_FLAG_EMBEDDED_DATA
Definition DNA_ID.h:774
@ ID_SCE
@ ID_GR
@ IDP_GROUP
Object groups, one object can be in many groups at once.
#define COLLECTION_FLAG_ALL_RUNTIME
@ COLLECTION_HIDE_RENDER
@ COLLECTION_HAS_OBJECT_CACHE_INSTANCED
@ COLLECTION_HIDE_SELECT
@ COLLECTION_IS_MASTER
@ COLLECTION_HAS_OBJECT_CACHE
@ COLLECTION_HIDE_VIEWPORT
@ IO_HANDLER_PANEL_OPEN
@ COLLECTION_COLOR_NONE
#define DNA_struct_default_get(struct_name)
@ LAYER_COLLECTION_EXCLUDE
@ BASE_ENABLED_RENDER
@ BASE_ENABLED_VIEWPORT
Object is a sort of wrapper for general info.
@ OB_HIDE_RENDER
#define OB_TYPE_IS_GEOMETRY(_type)
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
unsigned long long int uint64_t
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 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_exporter_remove(Collection *collection, CollectionExport *data)
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 Collection * collection_from_session_uid_recursive(Collection *collection, uint64_t session_uid)
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)
Collection * BKE_collection_from_session_uid(Scene *scene, uint64_t session_uid)
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_collection_exporter_move(Collection *collection, const int from, const int to)
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)
CollectionExport * BKE_collection_exporter_add(Collection *collection, char *idname, char *label)
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_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)
bool BKE_collection_contains_geometry_recursive(const Collection *collection)
void BKE_main_collections_object_cache_free(const Main *bmain)
Collection * BKE_collection_object_find(Main *bmain, Scene *scene, Collection *collection, Object *ob)
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)
void BKE_collection_new_name_get(Collection *collection_parent, char r_name[MAX_ID_NAME - 2])
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 GS(x)
int count
DEG_id_tag_update_ex(cb_data->bmain, cb_data->owner_id, ID_RECALC_TAG_FOR_UNDO|ID_RECALC_SYNC_TO_EVAL)
#define LOG(level)
Definition log.h:97
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
const char * name
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
CollectionRuntimeHandle * runtime
Definition DNA_ID.h:414
int tag
Definition DNA_ID.h:442
struct Library * lib
Definition DNA_ID.h:420
char name[258]
Definition DNA_ID.h:432
struct ID * newid
Definition DNA_ID.h:418
short flag
Definition DNA_ID.h:438
void * next
Definition DNA_ID.h:417
unsigned int session_uid
Definition DNA_ID.h:462
void * first
ListBase scenes
Definition BKE_main.hh:278
ListBase collections
Definition BKE_main.hh:298
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:145