/** * Replace all references in given Main to \a old_id by \a new_id * (if \a new_id is NULL, it unlinks \a old_id). */ void BKE_libblock_remap_locked( Main *bmain, void *old_idv, void *new_idv, const short remap_flags) { IDRemap id_remap_data; ID *old_id = old_idv; ID *new_id = new_idv; int skipped_direct, skipped_refcounted; BLI_assert(old_id != NULL); BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name)); BLI_assert(old_id != new_id); libblock_remap_data(bmain, NULL, old_id, new_id, remap_flags, &id_remap_data); if (free_notifier_reference_cb) { free_notifier_reference_cb(old_id); } /* We assume editors do not hold references to their IDs... This is false in some cases * (Image is especially tricky here), editors' code is to handle refcount (id->us) itself then. */ if (remap_editor_id_reference_cb) { remap_editor_id_reference_cb(old_id, new_id); } skipped_direct = id_remap_data.skipped_direct; skipped_refcounted = id_remap_data.skipped_refcounted; /* If old_id was used by some ugly 'user_one' stuff (like Image or Clip editors...), and user count has actually * been incremented for that, we have to decrease once more its user count... unless we had to skip * some 'user_one' cases. */ if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) && !(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) { id_us_min(old_id); old_id->tag &= ~LIB_TAG_EXTRAUSER_SET; } BLI_assert(old_id->us - skipped_refcounted >= 0); UNUSED_VARS_NDEBUG(skipped_refcounted); if (skipped_direct == 0) { /* old_id is assumed to not be used directly anymore... */ if (old_id->lib && (old_id->tag & LIB_TAG_EXTERN)) { old_id->tag &= ~LIB_TAG_EXTERN; old_id->tag |= LIB_TAG_INDIRECT; } } /* Some after-process updates. * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead? */ switch (GS(old_id->name)) { case ID_OB: libblock_remap_data_postprocess_object_fromgroup_update(bmain, (Object *)old_id, (Object *)new_id); break; case ID_GR: if (!new_id) { /* Only affects us in case group was unlinked. */ for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) { libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id); } } break; case ID_ME: case ID_CU: case ID_MB: if (new_id) { /* Only affects us in case obdata was relinked (changed). */ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { libblock_remap_data_postprocess_obdata_relink(bmain, ob, new_id); } } break; default: break; } /* Full rebuild of DAG! */ DAG_relations_tag_update(bmain); }
/* XXX Arg! Naming... :( * _relink? avoids confusion with _remap, but is confusing with _unlink * _remap_used_ids? * _remap_datablocks? * BKE_id_remap maybe? * ... sigh */ void BKE_libblock_relink_ex( Main *bmain, void *idv, void *old_idv, void *new_idv, const bool us_min_never_null) { ID *id = idv; ID *old_id = old_idv; ID *new_id = new_idv; int remap_flags = us_min_never_null ? 0 : ID_REMAP_SKIP_NEVER_NULL_USAGE; /* No need to lock here, we are only affecting given ID, not bmain database. */ BLI_assert(id); if (old_id) { BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name)); BLI_assert(old_id != new_id); } else { BLI_assert(new_id == NULL); } libblock_remap_data(bmain, id, old_id, new_id, remap_flags, NULL); /* Some after-process updates. * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead? */ switch (GS(id->name)) { case ID_SCE: { Scene *sce = (Scene *)id; if (old_id) { switch (GS(old_id->name)) { case ID_OB: { libblock_remap_data_postprocess_object_fromgroup_update( bmain, (Object *)old_id, (Object *)new_id); break; } case ID_GR: if (!new_id) { /* Only affects us in case group was unlinked. */ libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id); } break; default: break; } } else { /* No choice but to check whole objects/groups. */ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { libblock_remap_data_postprocess_object_fromgroup_update(bmain, ob, NULL); } for (Group *grp = bmain->group.first; grp; grp = grp->id.next) { libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, NULL); } } break; } case ID_OB: if (new_id) { /* Only affects us in case obdata was relinked (changed). */ libblock_remap_data_postprocess_obdata_relink(bmain, (Object *)id, new_id); } break; default: break; } }
/** * Replace all references in given Main to \a old_id by \a new_id * (if \a new_id is NULL, it unlinks \a old_id). */ void BKE_libblock_remap_locked( Main *bmain, void *old_idv, void *new_idv, const short remap_flags) { IDRemap id_remap_data; ID *old_id = old_idv; ID *new_id = new_idv; int skipped_direct, skipped_refcounted; BLI_assert(old_id != NULL); BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name)); BLI_assert(old_id != new_id); libblock_remap_data(bmain, NULL, old_id, new_id, remap_flags, &id_remap_data); if (free_notifier_reference_cb) { free_notifier_reference_cb(old_id); } /* We assume editors do not hold references to their IDs... This is false in some cases * (Image is especially tricky here), editors' code is to handle refcount (id->us) itself then. */ if (remap_editor_id_reference_cb) { remap_editor_id_reference_cb(old_id, new_id); } skipped_direct = id_remap_data.skipped_direct; skipped_refcounted = id_remap_data.skipped_refcounted; /* If old_id was used by some ugly 'user_one' stuff (like Image or Clip editors...), and user count has actually * been incremented for that, we have to decrease once more its user count... unless we had to skip * some 'user_one' cases. */ if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) && !(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) { id_us_clear_real(old_id); } if (old_id->us - skipped_refcounted < 0) { printf("Error in remapping process from '%s' (%p) to '%s' (%p): " "wrong user count in old ID after process (summing up to %d)\n", old_id->name, old_id, new_id ? new_id->name : "<NULL>", new_id, old_id->us - skipped_refcounted); BLI_assert(0); } if (skipped_direct == 0) { /* old_id is assumed to not be used directly anymore... */ if (old_id->lib && (old_id->tag & LIB_TAG_EXTERN)) { old_id->tag &= ~LIB_TAG_EXTERN; old_id->tag |= LIB_TAG_INDIRECT; } } /* Some after-process updates. * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead? */ switch (GS(old_id->name)) { case ID_OB: libblock_remap_data_postprocess_object_update(bmain, (Object *)old_id, (Object *)new_id); break; case ID_GR: if (!new_id) { /* Only affects us in case group was unlinked. */ for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) { libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id); } } break; case ID_ME: case ID_CU: case ID_MB: if (new_id) { /* Only affects us in case obdata was relinked (changed). */ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { libblock_remap_data_postprocess_obdata_relink(bmain, ob, new_id); } } break; default: break; } /* Node trees may virtually use any kind of data-block... */ /* XXX Yuck!!!! nodetree update can do pretty much any thing when talking about py nodes, * including creating new data-blocks (see T50385), so we need to unlock main here. :( * Why can't we have re-entrent locks? */ BKE_main_unlock(bmain); libblock_remap_data_postprocess_nodetree_update(bmain, new_id); BKE_main_lock(bmain); /* Full rebuild of DAG! */ DAG_relations_tag_update(bmain); }