Blender V4.3
lib_remap.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
11#include "CLG_log.h"
12
13#include "BLI_array.hh"
14#include "BLI_linklist.h"
15#include "BLI_utildefines.h"
16
18#include "DNA_object_types.h"
19
20#include "BKE_armature.hh"
21#include "BKE_collection.hh"
22#include "BKE_curve.hh"
23#include "BKE_layer.hh"
24#include "BKE_lib_id.hh"
25#include "BKE_lib_query.hh"
26#include "BKE_lib_remap.hh"
27#include "BKE_main.hh"
28#include "BKE_material.h"
29#include "BKE_mball.hh"
30#include "BKE_modifier.hh"
31#include "BKE_multires.hh"
32#include "BKE_node.hh"
34#include "BKE_object.hh"
35
36#include "DEG_depsgraph.hh"
38
39#include "lib_intern.hh" /* own include */
40
41using namespace blender::bke::id;
42
43static CLG_LogRef LOG = {"bke.lib_remap"};
44
46
51
53
59
60struct IDRemap {
62 Main *bmain; /* Only used to trigger depsgraph updates in the right bmain. */
63
65
68 int flag;
69};
70
71/* IDRemap->flag enums defined in BKE_lib.h */
72
73static void foreach_libblock_remap_callback_skip(const ID * /*id_owner*/,
74 ID **id_ptr,
75 const int cb_flag,
76 const bool is_indirect,
77 const bool is_reference,
78 const bool violates_never_null,
79 const bool /*is_obj*/,
80 const bool is_obj_editmode)
81{
82 ID *id = *id_ptr;
83 BLI_assert(id != nullptr);
84
85 if (is_indirect) {
86 id->runtime.remap.skipped_indirect++;
87 }
88 else if (violates_never_null || is_obj_editmode || is_reference) {
89 id->runtime.remap.skipped_direct++;
90 }
91 else {
93 }
94
95 if (cb_flag & IDWALK_CB_USER) {
96 id->runtime.remap.skipped_refcounted++;
97 }
98 else if (cb_flag & IDWALK_CB_USER_ONE) {
99 /* No need to count number of times this happens, just a flag is enough. */
100 id->runtime.remap.status |= ID_REMAP_IS_USER_ONE_SKIPPED;
101 }
102}
103
105 ID *id_self,
106 ID **id_ptr,
107 IDRemap *id_remap_data,
108 const IDRemapper &mappings,
109 const IDRemapperApplyOptions id_remapper_options,
110 const int cb_flag,
111 const bool is_indirect,
112 const bool violates_never_null)
113{
114 const bool skip_update_tagging = (id_remap_data->flag & ID_REMAP_SKIP_UPDATE_TAGGING) != 0;
115 const bool skip_user_refcount = (id_remap_data->flag & ID_REMAP_SKIP_USER_REFCOUNT) != 0;
116 const bool force_user_refcount = (id_remap_data->flag & ID_REMAP_FORCE_USER_REFCOUNT) != 0;
117 BLI_assert(!skip_user_refcount || !force_user_refcount);
118
119 ID *old_id = *id_ptr;
120 if (!violates_never_null) {
121 mappings.apply(id_ptr, id_remapper_options, id_self);
122 if (!skip_update_tagging) {
123 if (id_remap_data->bmain != nullptr) {
124 DEG_id_tag_update_ex(id_remap_data->bmain,
125 id_self,
127 if (id_self != id_owner) {
128 DEG_id_tag_update_ex(id_remap_data->bmain,
129 id_owner,
131 }
132 }
133 if (GS(id_self->name) == ID_NT) {
134 /* Make sure that the node tree is updated after a property in it changed. Ideally, we
135 * would know which nodes property was changed so that only this node is tagged. */
137 }
138 }
139 }
140 /* Get the new_id pointer. When the mapping is violating never null we should use a nullptr
141 * pointer otherwise the incorrect users are decreased and increased on the same instance. */
142 ID *new_id = violates_never_null ? nullptr : *id_ptr;
143
144 if (!is_indirect && new_id) {
146 }
147
148 if (skip_user_refcount) {
149 return;
150 }
151
152 if (cb_flag & IDWALK_CB_USER) {
153 /* NOTE: by default we don't user-count IDs which are not in the main database.
154 * This is because in certain conditions we can have data-blocks in
155 * the main which are referencing data-blocks outside of it.
156 * For example, BKE_mesh_new_from_object() called on an evaluated
157 * object will cause such situation.
158 */
159 if (force_user_refcount || (old_id->tag & ID_TAG_NO_MAIN) == 0) {
160 id_us_min(old_id);
161 }
162 if (new_id != nullptr && (force_user_refcount || (new_id->tag & ID_TAG_NO_MAIN) == 0)) {
163 /* Do not handle ID_TAG_INDIRECT/ID_TAG_EXTERN here. */
164 id_us_plus_no_lib(new_id);
165 }
166 }
167 else if (cb_flag & IDWALK_CB_USER_ONE) {
168 id_us_ensure_real(new_id);
169 /* We cannot affect old_id->us directly, ID_TAG_EXTRAUSER(_SET)
170 * are assumed to be set as needed, that extra user is processed in final handling. */
171 }
172}
173
175{
176 const int cb_flag = cb_data->cb_flag;
177
178 /* NOTE: Support remapping of `IDWALK_CB_EMBEDDED_NON_OWNING` pointers, this is necessary in some
179 * complex low-level ID manipulation cases (e.g. in ID swapping, see #BKE_lib_id_swap & co).
180 */
181 if (cb_flag & IDWALK_CB_EMBEDDED) {
182 return IDWALK_RET_NOP;
183 }
184
185 ID *id_owner = cb_data->owner_id;
186 ID *id_self = cb_data->self_id;
187 ID **id_p = cb_data->id_pointer;
188 IDRemap *id_remap_data = static_cast<IDRemap *>(cb_data->user_data);
189
190 /* Those asserts ensure the general sanity of ID tags regarding 'embedded' ID data (root
191 * node-trees and co). */
192 BLI_assert(id_owner == id_remap_data->id_owner);
193 BLI_assert(id_self == id_owner || (id_self->flag & ID_FLAG_EMBEDDED_DATA) != 0);
194
195 /* Early exit when id pointer isn't set. */
196 if (*id_p == nullptr) {
197 return IDWALK_RET_NOP;
198 }
199
200 IDRemapper &id_remapper = id_remap_data->id_remapper;
202
203 /* Used to cleanup all IDs used by a specific one. */
204 if (id_remap_data->type == ID_REMAP_TYPE_CLEANUP) {
205 /* Clearing existing instance to reduce potential lookup times for IDs referencing many other
206 * IDs. This makes sure that there will only be a single rule in the id_remapper. */
207 id_remapper.clear();
208 id_remapper.add(*id_p, nullptr);
209 }
210
211 /* Better remap to nullptr than not remapping at all,
212 * then we can handle it as a regular remap-to-nullptr case. */
213 if (cb_flag & IDWALK_CB_NEVER_SELF) {
214 id_remapper_options |= ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF;
215 }
216
217 const IDRemapperApplyResult expected_mapping_result = id_remapper.get_mapping_result(
218 *id_p, id_remapper_options, id_self);
219 /* Exit when no modifications will be done, ensuring id->runtime counters won't changed. */
220 if (ELEM(expected_mapping_result,
223 {
224 BLI_assert_msg(id_remap_data->type == ID_REMAP_TYPE_REMAP,
225 "Cleanup should always do unassign.");
226 return IDWALK_RET_NOP;
227 }
228
229 const bool is_reference = (cb_flag & IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE) != 0;
230 const bool is_indirect = (cb_flag & IDWALK_CB_INDIRECT_USAGE) != 0;
231 const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
232 const bool is_obj = (GS(id_owner->name) == ID_OB);
233 /* NOTE: Edit Mode is a 'skip direct' case, unless specifically requested, obdata should not be
234 * remapped in this situation. */
235 const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id_owner) &&
236 (id_remap_data->flag & ID_REMAP_FORCE_OBDATA_IN_EDITMODE) == 0);
237 const bool violates_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) &&
238 (expected_mapping_result ==
240 (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0);
241 const bool skip_reference = (id_remap_data->flag & ID_REMAP_SKIP_OVERRIDE_LIBRARY) != 0;
242 const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;
243
244#ifdef DEBUG_PRINT
245 printf(
246 "In %s (lib %p): Remapping %s (%p) remap operation: %s "
247 "(is_indirect: %d, skip_indirect: %d, is_reference: %d, skip_reference: %d)\n",
248 id_owner->name,
249 id_owner->lib,
250 (*id_p)->name,
251 *id_p,
252 id_remapper.result_to_string(expected_mapping_result).c_str(),
253 is_indirect,
254 skip_indirect,
255 is_reference,
256 skip_reference);
257#endif
258
259 if ((id_remap_data->flag & ID_REMAP_STORE_NEVER_NULL_USAGE) &&
260 (cb_flag & IDWALK_CB_NEVER_NULL) &&
261 (expected_mapping_result == ID_REMAP_RESULT_SOURCE_UNASSIGNED))
262 {
263 id_remapper.never_null_users_add(id_owner);
264 }
265
266 /* Special hack in case it's Object->data and we are in edit mode, and new_id is not nullptr
267 * (otherwise, we follow common NEVER_NULL flags).
268 * (skipped_indirect too). */
269 if ((violates_never_null && skip_never_null) ||
270 (is_obj_editmode && (((Object *)id_owner)->data == *id_p) &&
271 (expected_mapping_result == ID_REMAP_RESULT_SOURCE_REMAPPED)) ||
272 (skip_indirect && is_indirect) || (is_reference && skip_reference))
273 {
275 id_p,
276 cb_flag,
277 is_indirect,
278 is_reference,
279 violates_never_null,
280 is_obj,
281 is_obj_editmode);
282 }
283 else {
285 id_self,
286 id_p,
287 id_remap_data,
288 id_remapper,
289 id_remapper_options,
290 cb_flag,
291 is_indirect,
292 violates_never_null);
293 }
294
295 return IDWALK_RET_NOP;
296}
297
299 eIDRemapType remap_type,
300 const IDRemapper &id_remapper)
301{
302 if (ob->type != OB_ARMATURE) {
303 return;
304 }
305 if (ob->pose == nullptr) {
306 return;
307 }
308
309 const bool is_cleanup_type = remap_type == ID_REMAP_TYPE_CLEANUP;
310 /* Early exit when mapping, but no armature mappings present. */
311 if (!is_cleanup_type && !id_remapper.contains_mappings_for_any(FILTER_ID_AR)) {
312 return;
313 }
314
315 /* Object's pose holds reference to armature bones. sic */
316 /* Note that in theory, we should have to bother about linked/non-linked/never-null/etc.
317 * flags/states.
318 * Fortunately, this is just a tag, so we can accept to 'over-tag' a bit for pose recalc,
319 * and avoid another complex and risky condition nightmare like the one we have in
320 * foreach_libblock_remap_callback(). */
321 const IDRemapperApplyResult expected_mapping_result = id_remapper.get_mapping_result(
322 static_cast<ID *>(ob->data), ID_REMAP_APPLY_DEFAULT, nullptr);
323 if (is_cleanup_type || expected_mapping_result == ID_REMAP_RESULT_SOURCE_REMAPPED) {
324 ob->pose->flag |= POSE_RECALC;
325 /* We need to clear pose bone pointers immediately, some code may access those before
326 * pose is actually recomputed, which can lead to segfault. */
328 }
329}
330
331static void libblock_remap_data_preprocess(ID *id_owner,
332 eIDRemapType remap_type,
333 const IDRemapper &id_remapper)
334{
335 switch (GS(id_owner->name)) {
336 case ID_OB: {
337 Object *ob = (Object *)id_owner;
338 libblock_remap_data_preprocess_ob(ob, remap_type, id_remapper);
339 break;
340 }
341 default:
342 break;
343 }
344}
345
351 Object *old_ob,
352 Object * /*new_ob*/,
353 const bool do_sync_collection)
354{
355 /* Will only effectively process collections that have been tagged with
356 * #COLLECTION_TAG_COLLECTION_OBJECT_DIRTY. See #collection_foreach_id callback. */
358
359 if (do_sync_collection) {
361 }
362
363 if (old_ob == nullptr) {
364 for (Object *ob = static_cast<Object *>(bmain->objects.first); ob != nullptr;
365 ob = static_cast<Object *>(ob->id.next))
366 {
367 if (ob->type == OB_MBALL && BKE_mball_is_basis(ob)) {
369 }
370 }
371 }
372 else {
373 for (Object *ob = static_cast<Object *>(bmain->objects.first); ob != nullptr;
374 ob = static_cast<Object *>(ob->id.next))
375 {
376 if (ob->type == OB_MBALL && BKE_mball_is_basis_for(ob, old_ob)) {
378 break; /* There is only one basis... */
379 }
380 }
381 }
382}
383
384/* Can be called with both old_collection and new_collection being nullptr,
385 * this means we have to check whole Main database then. */
387 Collection *owner_collection,
388 Collection * /*old_collection*/,
389 Collection *new_collection)
390{
391 if (new_collection == nullptr) {
392 /* XXX Complex cases can lead to nullptr pointers in other collections than old_collection,
393 * and BKE_main_collection_sync_remap() does not tolerate any of those, so for now always check
394 * whole existing collections for nullptr pointers.
395 * I'd consider optimizing that whole collection remapping process a TODO: for later. */
396 BKE_collections_child_remove_nulls(bmain, owner_collection, nullptr /*old_collection*/);
397 }
398 else {
399 /* Temp safe fix, but a "tad" brute force... We should probably be able to use parents from
400 * old_collection instead? */
401 /* NOTE: Also takes care of duplicated child collections that remapping may have created. */
403 }
404
406}
407
409{
410 if (ob->data == new_id) {
411 switch (GS(new_id->name)) {
412 case ID_ME:
414 break;
415 case ID_CU_LEGACY:
417 break;
418 default:
419 break;
420 }
422 BKE_object_materials_test(bmain, ob, new_id);
423 }
424}
425
427{
428 /* Update all group nodes using a node group. */
430}
431
432static void libblock_remap_data_update_tags(ID *old_id, ID *new_id, IDRemap *id_remap_data)
433{
434 const int remap_flags = id_remap_data->flag;
435 if ((remap_flags & ID_REMAP_SKIP_USER_CLEAR) == 0) {
436 /* XXX We may not want to always 'transfer' fake-user from old to new id...
437 * Think for now it's desired behavior though,
438 * we can always add an option (flag) to control this later if needed. */
439 if (old_id != nullptr && (old_id->flag & ID_FLAG_FAKEUSER) && new_id != nullptr) {
440 id_fake_user_clear(old_id);
441 id_fake_user_set(new_id);
442 }
443
444 id_us_clear_real(old_id);
445 }
446
447 if (new_id != nullptr && (new_id->tag & ID_TAG_INDIRECT) &&
449 {
450 new_id->tag &= ~ID_TAG_INDIRECT;
451 new_id->flag &= ~ID_FLAG_INDIRECT_WEAK_LINK;
452 new_id->tag |= ID_TAG_EXTERN;
453 }
454}
455
456static void libblock_remap_reset_remapping_status_fn(ID *old_id, ID *new_id)
457{
459 if (new_id != nullptr) {
461 }
462}
463
488 Main *bmain, ID *id, eIDRemapType remap_type, IDRemapper &id_remapper, const int remap_flags)
489{
490 IDRemap id_remap_data = {
491 /*type*/ remap_type,
492 /*bmain*/ bmain,
493 /*id_remapper*/ id_remapper,
494 /*id_owner*/ nullptr,
495 /*flag*/ remap_flags,
496 };
497
498 const bool include_ui = (remap_flags & ID_REMAP_FORCE_UI_POINTERS) != 0;
499 const int foreach_id_flags = (((remap_flags & ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS) != 0 ?
501 IDWALK_NOP) |
502 (include_ui ? IDWALK_INCLUDE_UI : IDWALK_NOP) |
503
504 ((remap_flags & ID_REMAP_NO_ORIG_POINTERS_ACCESS) != 0 ?
506 IDWALK_NOP) |
507 ((remap_flags & ID_REMAP_DO_LIBRARY_POINTERS) != 0 ?
509 IDWALK_NOP));
510
512
513 if (id) {
514#ifdef DEBUG_PRINT
515 printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib);
516#endif
517 id_remap_data.id_owner = (id->flag & ID_FLAG_EMBEDDED_DATA) ? BKE_id_owner_get(id) : id;
518 libblock_remap_data_preprocess(id_remap_data.id_owner, remap_type, id_remapper);
520 bmain, id, foreach_libblock_remap_callback, &id_remap_data, foreach_id_flags);
521 }
522 else {
523 /* Note that this is a very 'brute force' approach,
524 * maybe we could use some depsgraph to only process objects actually using given old_id...
525 * sounds rather unlikely currently, though, so this will do for now. */
526 ID *id_curr;
527
528 FOREACH_MAIN_ID_BEGIN (bmain, id_curr) {
529 const uint64_t can_use_filter_id = BKE_library_id_can_use_filter_id(id_curr, include_ui);
530 const bool has_mapping = id_remapper.contains_mappings_for_any(can_use_filter_id);
531
532 /* Continue when id_remapper doesn't have any mappings that can be used by id_curr. */
533 if (!has_mapping) {
534 continue;
535 }
536
537 /* Note that we cannot skip indirect usages of old_id
538 * here (if requested), we still need to check it for the
539 * user count handling...
540 * XXX No more true (except for debug usage of those
541 * skipping counters). */
542 id_remap_data.id_owner = id_curr;
543 libblock_remap_data_preprocess(id_remap_data.id_owner, remap_type, id_remapper);
545 bmain, id_curr, foreach_libblock_remap_callback, &id_remap_data, foreach_id_flags);
546 }
548 }
549
550 id_remapper.iter([&](ID *old_id, ID *new_id) {
551 libblock_remap_data_update_tags(old_id, new_id, &id_remap_data);
552 });
553}
554
555static void libblock_remap_foreach_idpair(ID *old_id, ID *new_id, Main *bmain, int remap_flags)
556{
557 if (old_id == new_id) {
558 return;
559 }
560
561 BLI_assert(old_id != nullptr);
562 BLI_assert((new_id == nullptr) || remap_flags & ID_REMAP_ALLOW_IDTYPE_MISMATCH ||
563 GS(old_id->name) == GS(new_id->name));
564
567 }
568
569 if ((remap_flags & ID_REMAP_SKIP_USER_CLEAR) == 0) {
570 /* If old_id was used by some ugly 'user_one' stuff (like Image or Clip editors...), and user
571 * count has actually been incremented for that, we have to decrease once more its user
572 * count... unless we had to skip some 'user_one' cases. */
573 if ((old_id->tag & ID_TAG_EXTRAUSER_SET) &&
575 {
576 id_us_clear_real(old_id);
577 }
578 }
579
580 const int skipped_refcounted = old_id->runtime.remap.skipped_refcounted;
581 if (old_id->us - skipped_refcounted < 0) {
583 "Error in remapping process from '%s' (%p) to '%s' (%p): "
584 "wrong user count in old ID after process (summing up to %d)",
585 old_id->name,
586 old_id,
587 new_id ? new_id->name : "<nullptr>",
588 new_id,
589 old_id->us - skipped_refcounted);
590 }
591
592 const int skipped_direct = old_id->runtime.remap.skipped_direct;
593 if (skipped_direct == 0) {
594 /* old_id is assumed to not be used directly anymore... */
595 if (old_id->lib && (old_id->tag & ID_TAG_EXTERN)) {
596 old_id->tag &= ~ID_TAG_EXTERN;
597 old_id->tag |= ID_TAG_INDIRECT;
598 }
599 }
600
601 /* Some after-process updates.
602 * This is a bit ugly, but cannot see a way to avoid it.
603 * Maybe we should do a per-ID callback for this instead? */
604 switch (GS(old_id->name)) {
605 case ID_OB:
607 bmain, (Object *)old_id, (Object *)new_id, true);
608 break;
609 case ID_GR:
611 bmain, nullptr, (Collection *)old_id, (Collection *)new_id);
612 break;
613 case ID_ME:
614 case ID_CU_LEGACY:
615 case ID_MB:
616 case ID_CV:
617 case ID_PT:
618 case ID_VO:
619 if (new_id) { /* Only affects us in case obdata was relinked (changed). */
620 for (Object *ob = static_cast<Object *>(bmain->objects.first); ob;
621 ob = static_cast<Object *>(ob->id.next))
622 {
624 }
625 }
626 break;
627 default:
628 break;
629 }
630
631 /* Node trees may virtually use any kind of data-block... */
632 /* XXX Yuck!!!! nodetree update can do pretty much any thing when talking about py nodes,
633 * including creating new data-blocks (see #50385), so we need to unlock main here. :(
634 * Why can't we have re-entrent locks? */
635 BKE_main_unlock(bmain);
637 BKE_main_lock(bmain);
638
639 /* Full rebuild of DEG! */
641
643}
644
645void BKE_libblock_remap_multiple_locked(Main *bmain, IDRemapper &mappings, const int remap_flags)
646{
647 if (mappings.is_empty()) {
648 /* Early exit nothing to do. */
649 return;
650 }
651
652 libblock_remap_data(bmain, nullptr, ID_REMAP_TYPE_REMAP, mappings, remap_flags);
653
654 mappings.iter([&](ID *old_id, ID *new_id) {
655 libblock_remap_foreach_idpair(old_id, new_id, bmain, remap_flags);
656 });
657
658 /* We assume editors do not hold references to their IDs... This is false in some cases
659 * (Image is especially tricky here),
660 * editors' code is to handle refcount (id->us) itself then. */
663 }
664
665 /* Full rebuild of DEG! */
667}
668
669void BKE_libblock_remap_multiple_raw(Main *bmain, IDRemapper &mappings, const int remap_flags)
670{
671 if (mappings.is_empty()) {
672 /* Early exit nothing to do. */
673 return;
674 }
675
677 nullptr,
679 mappings,
681}
682
683void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const int remap_flags)
684{
685 IDRemapper remapper;
686 ID *old_id = static_cast<ID *>(old_idv);
687 ID *new_id = static_cast<ID *>(new_idv);
688 remapper.add(old_id, new_id);
689 BKE_libblock_remap_multiple_locked(bmain, remapper, remap_flags);
690}
691
692void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const int remap_flags)
693{
694 BKE_main_lock(bmain);
695
696 BKE_libblock_remap_locked(bmain, old_idv, new_idv, remap_flags);
697
698 BKE_main_unlock(bmain);
699}
700
701void BKE_libblock_remap_multiple(Main *bmain, IDRemapper &mappings, const int remap_flags)
702{
703 BKE_main_lock(bmain);
704
705 BKE_libblock_remap_multiple_locked(bmain, mappings, remap_flags);
706
707 BKE_main_unlock(bmain);
708}
709
710void BKE_libblock_unlink(Main *bmain, void *idv, const bool do_skip_indirect)
711{
712 const int remap_flags = (do_skip_indirect ? ID_REMAP_SKIP_INDIRECT_USAGE : 0);
713
714 BKE_main_lock(bmain);
715
716 BKE_libblock_remap_locked(bmain, idv, nullptr, remap_flags);
717
718 BKE_main_unlock(bmain);
719}
720
721/* XXX Arg! Naming... :(
722 * _relink? avoids confusion with _remap, but is confusing with _unlink
723 * _remap_used_ids?
724 * _remap_datablocks?
725 * BKE_id_remap maybe?
726 * ... sigh
727 */
728
730 ID *new_id,
731 Main *bmain,
732 const blender::Span<ID *> ids)
733{
734 BLI_assert(old_id != nullptr);
735 BLI_assert((new_id == nullptr) || GS(old_id->name) == GS(new_id->name));
736 BLI_assert(old_id != new_id);
737
738 bool is_object_update_processed = false;
739 for (ID *id_iter : ids) {
740 /* Some after-process updates.
741 * This is a bit ugly, but cannot see a way to avoid it.
742 * Maybe we should do a per-ID callback for this instead?
743 */
744 switch (GS(id_iter->name)) {
745 case ID_SCE:
746 case ID_GR: {
747 /* NOTE: here we know which collection we have affected, so at lest for nullptr children
748 * detection we can only process that one.
749 * This is also a required fix in case `id` would not be in Main anymore, which can happen
750 * e.g. when called from `id_delete`. */
751 Collection *owner_collection = (GS(id_iter->name) == ID_GR) ?
752 (Collection *)id_iter :
753 ((Scene *)id_iter)->master_collection;
754 switch (GS(old_id->name)) {
755 case ID_OB:
756 if (!is_object_update_processed) {
758 bmain, (Object *)old_id, (Object *)new_id, true);
759 is_object_update_processed = true;
760 }
761 break;
762 case ID_GR:
764 bmain, owner_collection, (Collection *)old_id, (Collection *)new_id);
765 break;
766 default:
767 break;
768 }
769 break;
770 }
771 case ID_OB:
772 if (new_id != nullptr) { /* Only affects us in case obdata was relinked (changed). */
773 libblock_remap_data_postprocess_obdata_relink(bmain, (Object *)id_iter, new_id);
774 }
775 break;
776 default:
777 break;
778 }
779 }
780}
781
783 const blender::Span<ID *> ids,
784 const eIDRemapType remap_type,
785 IDRemapper &id_remapper,
786 const int remap_flags)
787{
788 BLI_assert(remap_type == ID_REMAP_TYPE_REMAP || id_remapper.is_empty());
789
790 for (ID *id_iter : ids) {
791 libblock_remap_data(bmain, id_iter, remap_type, id_remapper, remap_flags);
792 }
793
794 if (bmain == nullptr) {
795 return;
796 }
797
798 switch (remap_type) {
799 case ID_REMAP_TYPE_REMAP: {
800 id_remapper.iter([&](ID *old_id, ID *new_id) {
801 libblock_relink_foreach_idpair(old_id, new_id, bmain, ids);
802 });
803 break;
804 }
806 bool is_object_update_processed = false;
807 for (ID *id_iter : ids) {
808 switch (GS(id_iter->name)) {
809 case ID_SCE:
810 case ID_GR: {
811 /* NOTE: here we know which collection we have affected, so at lest for nullptr
812 * children detection we can only process that one. This is also a required fix in case
813 * `id` would not be in Main anymore, which can happen e.g. when called from
814 * `id_delete`. */
815 Collection *owner_collection = (GS(id_iter->name) == ID_GR) ?
816 (Collection *)id_iter :
817 ((Scene *)id_iter)->master_collection;
818 /* No choice but to check whole objects once, and all children collections. */
819 if (!is_object_update_processed) {
820 /* We only want to affect Object pointers here, not Collection ones, LayerCollections
821 * will be resynced as part of the call to
822 * `libblock_remap_data_postprocess_collection_update` below. */
823 libblock_remap_data_postprocess_object_update(bmain, nullptr, nullptr, false);
824 is_object_update_processed = true;
825 }
827 bmain, owner_collection, nullptr, nullptr);
828 break;
829 }
830 default:
831 break;
832 }
833 }
834
835 break;
836 }
837 default:
839 }
840
842}
843
845 Main *bmain, void *idv, void *old_idv, void *new_idv, const int remap_flags)
846{
847
848 /* Should be able to replace all _relink() functions (constraints, rigidbody, etc.) ? */
849
850 ID *id = static_cast<ID *>(idv);
851 ID *old_id = static_cast<ID *>(old_idv);
852 ID *new_id = static_cast<ID *>(new_idv);
853 blender::Array<ID *> ids = {id};
854
855 /* No need to lock here, we are only affecting given ID, not bmain database. */
856 IDRemapper id_remapper;
858
859 BLI_assert(id != nullptr);
861 if (old_id != nullptr) {
862 BLI_assert((new_id == nullptr) || GS(old_id->name) == GS(new_id->name));
863 BLI_assert(old_id != new_id);
864 id_remapper.add(old_id, new_id);
865 }
866 else {
867 BLI_assert(new_id == nullptr);
868 remap_type = ID_REMAP_TYPE_CLEANUP;
869 }
870
871 BKE_libblock_relink_multiple(bmain, ids, remap_type, id_remapper, remap_flags);
872}
873
878
880 ID *id,
881 RelinkToNewIDData *relink_data);
883{
884 const int cb_flag = cb_data->cb_flag;
885 /* NOTE: For now, support remapping `IDWALK_CB_EMBEDDED_NON_OWNING` pointers. */
887 return IDWALK_RET_NOP;
888 }
889
890 Main *bmain = cb_data->bmain;
891 ID **id_pointer = cb_data->id_pointer;
892 ID *id = *id_pointer;
893 RelinkToNewIDData *relink_data = static_cast<RelinkToNewIDData *>(cb_data->user_data);
894
895 if (id) {
896 /* See: NEW_ID macro */
897 if (id->newid != nullptr) {
898 relink_data->id_remapper.add(id, id->newid);
899 id = id->newid;
900 }
901 if (id->tag & ID_TAG_NEW) {
902 libblock_relink_to_newid_prepare_data(bmain, id, relink_data);
903 }
904 }
905 return IDWALK_RET_NOP;
906}
907
909 ID *id,
910 RelinkToNewIDData *relink_data)
911{
912 if (ID_IS_LINKED(id)) {
913 return;
914 }
915
916 id->tag &= ~ID_TAG_NEW;
917 relink_data->ids.append(id);
918 BKE_library_foreach_ID_link(bmain, id, id_relink_to_newid_looper, relink_data, 0);
919}
920
921void BKE_libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag)
922{
923 if (ID_IS_LINKED(id)) {
924 return;
925 }
926 /* We do not want to have those cached relationship data here. */
927 BLI_assert(bmain->relations == nullptr);
928
929 RelinkToNewIDData relink_data{};
930
931 libblock_relink_to_newid_prepare_data(bmain, id, &relink_data);
932
933 const int remap_flag_final = remap_flag | ID_REMAP_SKIP_INDIRECT_USAGE |
936 bmain, relink_data.ids, ID_REMAP_TYPE_REMAP, relink_data.id_remapper, remap_flag_final);
937}
void BKE_pose_clear_pointers(bPose *pose)
Definition armature.cc:2729
void BKE_collections_object_remove_invalids(Main *bmain)
void BKE_collections_child_remove_nulls(Main *bmain, Collection *parent_collection, Collection *child_collection)
void BKE_main_collections_parent_relations_rebuild(Main *bmain)
void BKE_curve_type_test(Object *ob)
Definition curve.cc:454
void BKE_main_collection_sync_remap(const Main *bmain)
void id_fake_user_set(ID *id)
Definition lib_id.cc:389
ID * BKE_id_owner_get(ID *id, const bool debug_relationship_assert=true)
Definition lib_id.cc:2444
void id_us_ensure_real(ID *id)
Definition lib_id.cc:306
void id_fake_user_clear(ID *id)
Definition lib_id.cc:397
void id_us_clear_real(ID *id)
Definition lib_id.cc:324
void id_us_plus_no_lib(ID *id)
Definition lib_id.cc:335
void BKE_libblock_runtime_reset_remapping_status(ID *id) ATTR_NONNULL(1)
Definition lib_id.cc:1434
void id_us_min(ID *id)
Definition lib_id.cc:359
@ IDWALK_RET_NOP
@ IDWALK_CB_NEVER_SELF
@ IDWALK_CB_USER_ONE
@ IDWALK_CB_USER
@ IDWALK_CB_EMBEDDED
@ IDWALK_CB_NEVER_NULL
@ IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE
@ IDWALK_CB_INDIRECT_USAGE
void BKE_library_foreach_ID_link(Main *bmain, ID *id, blender::FunctionRef< LibraryIDLinkCallback > callback, void *user_data, int flag)
Definition lib_query.cc:416
@ IDWALK_INCLUDE_UI
@ IDWALK_DO_LIBRARY_POINTER
@ IDWALK_NOP
@ IDWALK_DO_INTERNAL_RUNTIME_POINTERS
@ IDWALK_NO_ORIG_POINTERS_ACCESS
uint64_t BKE_library_id_can_use_filter_id(const ID *owner_id, const bool include_ui, const IDTypeInfo *owner_id_type=nullptr)
Definition lib_query.cc:461
void(*)(const blender::bke::id::IDRemapper &mappings) BKE_library_remap_editor_id_reference_cb
@ ID_REMAP_SKIP_USER_CLEAR
@ ID_REMAP_SKIP_USER_REFCOUNT
@ ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS
@ ID_REMAP_SKIP_OVERRIDE_LIBRARY
@ ID_REMAP_FORCE_USER_REFCOUNT
@ ID_REMAP_SKIP_NEVER_NULL_USAGE
@ ID_REMAP_DO_LIBRARY_POINTERS
@ ID_REMAP_FORCE_OBDATA_IN_EDITMODE
@ ID_REMAP_FORCE_UI_POINTERS
@ ID_REMAP_SKIP_INDIRECT_USAGE
@ ID_REMAP_FORCE_NEVER_NULL_USAGE
@ ID_REMAP_STORE_NEVER_NULL_USAGE
@ ID_REMAP_ALLOW_IDTYPE_MISMATCH
@ ID_REMAP_SKIP_UPDATE_TAGGING
@ ID_REMAP_NO_ORIG_POINTERS_ACCESS
IDRemapperApplyResult
@ ID_REMAP_RESULT_SOURCE_REMAPPED
@ ID_REMAP_RESULT_SOURCE_UNASSIGNED
@ ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE
@ ID_REMAP_RESULT_SOURCE_UNAVAILABLE
IDRemapperApplyOptions
@ ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF
@ ID_REMAP_APPLY_DEFAULT
eIDRemapType
@ ID_REMAP_TYPE_REMAP
@ ID_REMAP_TYPE_CLEANUP
void(*)(const void *) BKE_library_free_notifier_reference_cb
#define FOREACH_MAIN_ID_END
Definition BKE_main.hh:500
void BKE_main_lock(Main *bmain)
Definition main.cc:479
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition BKE_main.hh:494
void BKE_main_unlock(Main *bmain)
Definition main.cc:484
General operations, lookup, etc. for materials.
void BKE_object_materials_test(struct Main *bmain, struct Object *ob, struct ID *id)
bool BKE_mball_is_basis(const Object *ob)
Definition mball.cc:230
bool BKE_mball_is_basis_for(const Object *ob1, const Object *ob2)
Definition mball.cc:269
void BKE_modifiers_test_object(Object *ob)
void multires_force_sculpt_rebuild(Object *object)
Definition multires.cc:451
void BKE_ntree_update_tag_all(bNodeTree *ntree)
General operations, lookup, etc. for blender objects.
bool BKE_object_is_in_editmode(const Object *ob)
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
#define UNUSED_VARS_NDEBUG(...)
#define ELEM(...)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:182
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_id_tag_update_ex(Main *bmain, ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1021
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:654
@ ID_REMAP_IS_LINKED_DIRECT
Definition DNA_ID.h:382
@ ID_REMAP_IS_USER_ONE_SKIPPED
Definition DNA_ID.h:384
@ ID_FLAG_FAKEUSER
Definition DNA_ID.h:720
@ ID_FLAG_EMBEDDED_DATA
Definition DNA_ID.h:725
#define FILTER_ID_AR
Definition DNA_ID.h:1165
@ ID_TAG_NEW
Definition DNA_ID.h:865
@ ID_TAG_INDIRECT
Definition DNA_ID.h:794
@ ID_TAG_EXTERN
Definition DNA_ID.h:788
@ ID_TAG_EXTRAUSER_SET
Definition DNA_ID.h:830
@ ID_TAG_NO_MAIN
Definition DNA_ID.h:945
@ ID_VO
@ ID_NT
@ ID_SCE
@ ID_CV
@ ID_CU_LEGACY
@ ID_ME
@ ID_GR
@ ID_MB
@ ID_OB
@ ID_PT
@ POSE_RECALC
Object groups, one object can be in many groups at once.
Object is a sort of wrapper for general info.
@ OB_MBALL
@ OB_ARMATURE
constexpr const char * c_str() const
void append(const T &value)
IDRemapperApplyResult get_mapping_result(ID *id, IDRemapperApplyOptions options, const ID *id_self) const
IDRemapperApplyResult apply(ID **r_id_ptr, IDRemapperApplyOptions options, ID *id_self=nullptr) const
void iter(FunctionRef< void(ID *old_id, ID *new_id)> func) const
static const StringRefNull result_to_string(const IDRemapperApplyResult result)
void add(ID *old_id, ID *new_id)
bool contains_mappings_for_any(IDTypeFilter filter) const
#define printf
#define GS(x)
Definition iris.cc:202
static void libblock_remap_data_preprocess_ob(Object *ob, eIDRemapType remap_type, const IDRemapper &id_remapper)
Definition lib_remap.cc:298
void BKE_libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag)
Definition lib_remap.cc:921
BKE_library_remap_editor_id_reference_cb remap_editor_id_reference_cb
Definition lib_remap.cc:52
static int id_relink_to_newid_looper(LibraryIDLinkCallbackData *cb_data)
Definition lib_remap.cc:882
static void libblock_remap_data_postprocess_collection_update(Main *bmain, Collection *owner_collection, Collection *, Collection *new_collection)
Definition lib_remap.cc:386
void BKE_library_callback_remap_editor_id_reference_set(BKE_library_remap_editor_id_reference_cb func)
Definition lib_remap.cc:54
static void libblock_remap_data(Main *bmain, ID *id, eIDRemapType remap_type, IDRemapper &id_remapper, const int remap_flags)
Definition lib_remap.cc:487
void BKE_libblock_remap_multiple(Main *bmain, IDRemapper &mappings, const int remap_flags)
Definition lib_remap.cc:701
static void libblock_remap_data_preprocess(ID *id_owner, eIDRemapType remap_type, const IDRemapper &id_remapper)
Definition lib_remap.cc:331
static void libblock_relink_foreach_idpair(ID *old_id, ID *new_id, Main *bmain, const blender::Span< ID * > ids)
Definition lib_remap.cc:729
static void libblock_relink_to_newid_prepare_data(Main *bmain, ID *id, RelinkToNewIDData *relink_data)
Definition lib_remap.cc:908
static void foreach_libblock_remap_callback_skip(const ID *, ID **id_ptr, const int cb_flag, const bool is_indirect, const bool is_reference, const bool violates_never_null, const bool, const bool is_obj_editmode)
Definition lib_remap.cc:73
void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func)
Definition lib_remap.cc:47
void BKE_libblock_relink_ex(Main *bmain, void *idv, void *old_idv, void *new_idv, const int remap_flags)
Definition lib_remap.cc:844
static void foreach_libblock_remap_callback_apply(ID *id_owner, ID *id_self, ID **id_ptr, IDRemap *id_remap_data, const IDRemapper &mappings, const IDRemapperApplyOptions id_remapper_options, const int cb_flag, const bool is_indirect, const bool violates_never_null)
Definition lib_remap.cc:104
void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const int remap_flags)
Definition lib_remap.cc:692
void BKE_libblock_unlink(Main *bmain, void *idv, const bool do_skip_indirect)
Definition lib_remap.cc:710
static void libblock_remap_data_update_tags(ID *old_id, ID *new_id, IDRemap *id_remap_data)
Definition lib_remap.cc:432
void BKE_libblock_remap_multiple_raw(Main *bmain, IDRemapper &mappings, const int remap_flags)
Definition lib_remap.cc:669
static void libblock_remap_data_postprocess_obdata_relink(Main *bmain, Object *ob, ID *new_id)
Definition lib_remap.cc:408
static void libblock_remap_data_postprocess_object_update(Main *bmain, Object *old_ob, Object *, const bool do_sync_collection)
Definition lib_remap.cc:350
void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const int remap_flags)
Definition lib_remap.cc:683
void BKE_libblock_remap_multiple_locked(Main *bmain, IDRemapper &mappings, const int remap_flags)
Definition lib_remap.cc:645
void BKE_libblock_relink_multiple(Main *bmain, const blender::Span< ID * > ids, const eIDRemapType remap_type, IDRemapper &id_remapper, const int remap_flags)
Definition lib_remap.cc:782
static CLG_LogRef LOG
Definition lib_remap.cc:43
BKE_library_free_notifier_reference_cb free_notifier_reference_cb
Definition lib_remap.cc:45
static void libblock_remap_reset_remapping_status_fn(ID *old_id, ID *new_id)
Definition lib_remap.cc:456
static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data)
Definition lib_remap.cc:174
static void libblock_remap_data_postprocess_nodetree_update(Main *bmain, ID *new_id)
Definition lib_remap.cc:426
static void libblock_remap_foreach_idpair(ID *old_id, ID *new_id, Main *bmain, int remap_flags)
Definition lib_remap.cc:555
void node_tree_update_all_users(Main *main, ID *id)
Definition node.cc:4242
unsigned __int64 uint64_t
Definition stdint.h:90
eIDRemapType type
Definition lib_remap.cc:61
ID * id_owner
Definition lib_remap.cc:67
int flag
Definition lib_remap.cc:68
Main * bmain
Definition lib_remap.cc:62
IDRemapper & id_remapper
Definition lib_remap.cc:64
int skipped_refcounted
Definition DNA_ID.h:392
ID_Runtime_Remap remap
Definition DNA_ID.h:403
Definition DNA_ID.h:413
int tag
Definition DNA_ID.h:434
struct Library * lib
Definition DNA_ID.h:419
int us
Definition DNA_ID.h:435
short flag
Definition DNA_ID.h:430
char name[66]
Definition DNA_ID.h:425
struct ID_Runtime runtime
Definition DNA_ID.h:492
void * first
MainIDRelations * relations
Definition BKE_main.hh:260
ListBase objects
Definition BKE_main.hh:212
struct bPose * pose
IDRemapper id_remapper
Definition lib_remap.cc:876
blender::Vector< ID * > ids
Definition lib_remap.cc:875