IDManagement: Add option to clear asset data when making ID local.

When appending an asset from the asset browser, its asset data needs to
be cleared.

However, linking an asset (or regular append from the file browser)
should not clear such data. In linking case, it would be there again
after a blend file reload anyway.

So this commit introduces a new `BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR`
option.

NOTE: in case the appended ID needs to be copied from its linked data
(instead of making the later directly local), asset data is lost anyway
since it is never copied with the ID currently.

Ref. {T91749} and D11768.
This commit is contained in:
Bastien Montagne 2021-10-21 12:55:15 +02:00
parent 17a96051cf
commit 641a5be50e
7 changed files with 44 additions and 24 deletions

View File

@ -245,6 +245,10 @@ enum {
/** In case caller code already knows this ID should be made local using copying. */
LIB_ID_MAKELOCAL_FORCE_COPY = 1 << 2,
/** Clear asset data (in case the ID can actually be made local, in copy case asset data is never
* copied over). */
LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR = 1 << 3,
/* Special type-specific options. */
/** For Objects, do not clear the proxy pointers while making the data-block local. */
LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING = 1 << 16,
@ -271,13 +275,13 @@ void BKE_lib_id_swap(struct Main *bmain, struct ID *id_a, struct ID *id_b);
void BKE_lib_id_swap_full(struct Main *bmain, struct ID *id_a, struct ID *id_b);
void id_sort_by_name(struct ListBase *lb, struct ID *id, struct ID *id_sorting_hint);
void BKE_lib_id_expand_local(struct Main *bmain, struct ID *id);
void BKE_lib_id_expand_local(struct Main *bmain, struct ID *id, const int flags);
bool BKE_id_new_name_validate(struct ListBase *lb,
struct ID *id,
const char *name,
const bool do_linked_data) ATTR_NONNULL(1, 2);
void BKE_lib_id_clear_library_data(struct Main *bmain, struct ID *id);
void BKE_lib_id_clear_library_data(struct Main *bmain, struct ID *id, const int flags);
/* Affect whole Main database. */
void BKE_main_id_tag_idcode(struct Main *mainvar,

View File

@ -183,8 +183,8 @@ static void brush_make_local(Main *bmain, ID *id, const int flags)
}
if (force_local) {
BKE_lib_id_clear_library_data(bmain, &brush->id);
BKE_lib_id_expand_local(bmain, &brush->id);
BKE_lib_id_clear_library_data(bmain, &brush->id, flags);
BKE_lib_id_expand_local(bmain, &brush->id, flags);
/* enable fake user by default */
id_fake_user_set(&brush->id);

View File

@ -152,8 +152,10 @@ static int lib_id_clear_library_data_users_update_cb(LibraryIDLinkCallbackData *
/**
* Pull an ID out of a library (make it local). Only call this for IDs that
* don't have other library users.
*
* \param flags Same set of `LIB_ID_MAKELOCAL_` flags as passed to `BKE_lib_id_make_local`.
*/
void BKE_lib_id_clear_library_data(Main *bmain, ID *id)
void BKE_lib_id_clear_library_data(Main *bmain, ID *id, const int flags)
{
const bool id_in_mainlist = (id->tag & LIB_TAG_NO_MAIN) == 0 &&
(id->flag & LIB_EMBEDDED_DATA) == 0;
@ -177,6 +179,10 @@ void BKE_lib_id_clear_library_data(Main *bmain, ID *id)
BKE_lib_libblock_session_uuid_renew(id);
}
if ((flags & LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR) != 0 && id->asset_data != NULL) {
BKE_asset_metadata_free(&id->asset_data);
}
/* We need to tag this IDs and all of its users, conceptually new local ID and original linked
* ones are two completely different data-blocks that were virtually remapped, even though in
* reality they remain the same data. For undo this info is critical now. */
@ -193,7 +199,7 @@ void BKE_lib_id_clear_library_data(Main *bmain, ID *id)
* IDs here, this is down automatically in `lib_id_expand_local_cb()`. */
Key *key = BKE_key_from_id(id);
if (key != NULL) {
BKE_lib_id_clear_library_data(bmain, &key->id);
BKE_lib_id_clear_library_data(bmain, &key->id, flags);
}
DEG_relations_tag_update(bmain);
@ -372,6 +378,7 @@ static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data)
ID *id_self = cb_data->id_self;
ID **id_pointer = cb_data->id_pointer;
int const cb_flag = cb_data->cb_flag;
const int flags = POINTER_AS_INT(cb_data->user_data);
if (cb_flag & IDWALK_CB_LOOPBACK) {
/* We should never have anything to do with loop-back pointers here. */
@ -386,7 +393,7 @@ static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data)
if (*id_pointer != NULL && ID_IS_LINKED(*id_pointer)) {
BLI_assert(*id_pointer != id_self);
BKE_lib_id_clear_library_data(bmain, *id_pointer);
BKE_lib_id_clear_library_data(bmain, *id_pointer, flags);
}
return IDWALK_RET_NOP;
}
@ -407,18 +414,19 @@ static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data)
* Expand ID usages of given id as 'extern' (and no more indirect) linked data.
* Used by ID copy/make_local functions.
*/
void BKE_lib_id_expand_local(Main *bmain, ID *id)
void BKE_lib_id_expand_local(Main *bmain, ID *id, const int flags)
{
BKE_library_foreach_ID_link(bmain, id, lib_id_expand_local_cb, bmain, IDWALK_READONLY);
BKE_library_foreach_ID_link(
bmain, id, lib_id_expand_local_cb, POINTER_FROM_INT(flags), IDWALK_READONLY);
}
/**
* Ensure new (copied) ID is fully made local.
*/
static void lib_id_copy_ensure_local(Main *bmain, const ID *old_id, ID *new_id)
static void lib_id_copy_ensure_local(Main *bmain, const ID *old_id, ID *new_id, const int flags)
{
if (ID_IS_LINKED(old_id)) {
BKE_lib_id_expand_local(bmain, new_id);
BKE_lib_id_expand_local(bmain, new_id, flags);
lib_id_library_local_paths(bmain, old_id->lib, new_id);
}
}
@ -459,8 +467,8 @@ void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
}
if (force_local) {
BKE_lib_id_clear_library_data(bmain, id);
BKE_lib_id_expand_local(bmain, id);
BKE_lib_id_clear_library_data(bmain, id, flags);
BKE_lib_id_expand_local(bmain, id, flags);
}
else if (force_copy) {
ID *id_new = BKE_id_copy(bmain, id);
@ -648,7 +656,7 @@ ID *BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag)
* XXX TODO: is this behavior OK, or should we need own flag to control that? */
if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
BLI_assert((flag & LIB_ID_COPY_KEEP_LIB) == 0);
lib_id_copy_ensure_local(bmain, id, newid);
lib_id_copy_ensure_local(bmain, id, newid, 0);
}
else {
newid->lib = id->lib;
@ -2046,8 +2054,8 @@ void BKE_library_make_local(Main *bmain,
* currently there are some indirect usages. So instead of making a copy that we'll likely
* get rid of later, directly make that data block local.
* Saves a tremendous amount of time with complex scenes... */
BKE_lib_id_clear_library_data(bmain, id);
BKE_lib_id_expand_local(bmain, id);
BKE_lib_id_clear_library_data(bmain, id, 0);
BKE_lib_id_expand_local(bmain, id, 0);
id->tag &= ~LIB_TAG_DOIT;
if (GS(id->name) == ID_OB) {

View File

@ -357,8 +357,8 @@ static void object_make_local(Main *bmain, ID *id, const int flags)
}
if (force_local) {
BKE_lib_id_clear_library_data(bmain, &ob->id);
BKE_lib_id_expand_local(bmain, &ob->id);
BKE_lib_id_clear_library_data(bmain, &ob->id, flags);
BKE_lib_id_expand_local(bmain, &ob->id, flags);
if (clear_proxy) {
if (ob->proxy_from != NULL) {
ob->proxy_from->proxy = NULL;

View File

@ -228,6 +228,8 @@ typedef enum eBLOLibLinkFlags {
BLO_LIBLINK_APPEND_RECURSIVE = 1 << 20,
/** Try to re-use previously appended matching ID on new append. */
BLO_LIBLINK_APPEND_LOCAL_ID_REUSE = 1 << 21,
/** Clear the asset data. */
BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR = 1 << 22,
/** Instantiate object data IDs (i.e. create objects for them if needed). */
BLO_LIBLINK_OBDATA_INSTANCE = 1 << 24,
/** Instantiate collections as empties, instead of linking them into current view layer. */

View File

@ -466,7 +466,8 @@ static ID *wm_drag_asset_id_import(wmDragAsset *asset_drag)
asset_drag->path,
idtype,
name,
BLO_LIBLINK_APPEND_RECURSIVE | FILE_ACTIVE_COLLECTION);
BLO_LIBLINK_APPEND_RECURSIVE | FILE_ACTIVE_COLLECTION |
BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR);
case FILE_ASSET_IMPORT_APPEND_REUSE:
return WM_file_append_datablock(G_MAIN,
scene,
@ -476,6 +477,7 @@ static ID *wm_drag_asset_id_import(wmDragAsset *asset_drag)
idtype,
name,
BLO_LIBLINK_APPEND_RECURSIVE | FILE_ACTIVE_COLLECTION |
BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR |
BLO_LIBLINK_APPEND_LOCAL_ID_REUSE);
}

View File

@ -630,6 +630,12 @@ static void wm_append_do(WMLinkAppendData *lapp_data,
const bool set_fakeuser = (lapp_data->flag & BLO_LIBLINK_APPEND_SET_FAKEUSER) != 0;
const bool do_reuse_local_id = (lapp_data->flag & BLO_LIBLINK_APPEND_LOCAL_ID_REUSE) != 0;
const int make_local_common_flags = LIB_ID_MAKELOCAL_FULL_LIBRARY |
((lapp_data->flag & BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR) !=
0 ?
LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR :
0);
LinkNode *itemlink;
/* Generate a mapping between newly linked IDs and their items, and tag linked IDs used as
@ -731,16 +737,14 @@ static void wm_append_do(WMLinkAppendData *lapp_data,
BLI_strncpy(lib_id_name, id->name, sizeof(lib_id_name));
switch (item->append_action) {
case WM_APPEND_ACT_COPY_LOCAL: {
BKE_lib_id_make_local(
bmain, id, LIB_ID_MAKELOCAL_FULL_LIBRARY | LIB_ID_MAKELOCAL_FORCE_COPY);
case WM_APPEND_ACT_COPY_LOCAL:
BKE_lib_id_make_local(bmain, id, make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_COPY);
local_appended_new_id = id->newid;
break;
}
case WM_APPEND_ACT_MAKE_LOCAL:
BKE_lib_id_make_local(bmain,
id,
LIB_ID_MAKELOCAL_FULL_LIBRARY | LIB_ID_MAKELOCAL_FORCE_LOCAL |
make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_LOCAL |
LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING);
BLI_assert(id->newid == NULL);
local_appended_new_id = id;