Changeset View
Changeset View
Standalone View
Standalone View
source/blender/windowmanager/intern/wm_files_link.c
| Show First 20 Lines • Show All 184 Lines • ▼ Show 20 Lines | typedef struct WMLinkAppendData { | ||||
| /** | /** | ||||
| * Combines #eFileSel_Params_Flag from DNA_space_types.h & #eBLOLibLinkFlags from BLO_readfile.h | * Combines #eFileSel_Params_Flag from DNA_space_types.h & #eBLOLibLinkFlags from BLO_readfile.h | ||||
| */ | */ | ||||
| int flag; | int flag; | ||||
| /** Allows to easily find an existing items from an ID pointer. Used by append code. */ | /** Allows to easily find an existing items from an ID pointer. Used by append code. */ | ||||
| GHash *new_id_to_item; | GHash *new_id_to_item; | ||||
| /** Runtime info used by append code to manage re-use of already appended matching IDs. */ | |||||
| GHash *library_weak_reference_mapping; | |||||
| /* Internal 'private' data */ | /* Internal 'private' data */ | ||||
| MemArena *memarena; | MemArena *memarena; | ||||
| } WMLinkAppendData; | } WMLinkAppendData; | ||||
| typedef struct WMLinkAppendDataCallBack { | typedef struct WMLinkAppendDataCallBack { | ||||
| WMLinkAppendData *lapp_data; | WMLinkAppendData *lapp_data; | ||||
| WMLinkAppendDataItem *item; | WMLinkAppendDataItem *item; | ||||
| ReportList *reports; | ReportList *reports; | ||||
| Show All 24 Lines | |||||
| } | } | ||||
| static void wm_link_append_data_free(WMLinkAppendData *lapp_data) | static void wm_link_append_data_free(WMLinkAppendData *lapp_data) | ||||
| { | { | ||||
| if (lapp_data->new_id_to_item != NULL) { | if (lapp_data->new_id_to_item != NULL) { | ||||
| BLI_ghash_free(lapp_data->new_id_to_item, NULL, NULL); | BLI_ghash_free(lapp_data->new_id_to_item, NULL, NULL); | ||||
| } | } | ||||
| BLI_assert(lapp_data->library_weak_reference_mapping == NULL); | |||||
| BLI_memarena_free(lapp_data->memarena); | BLI_memarena_free(lapp_data->memarena); | ||||
| } | } | ||||
| /* WARNING! *Never* call wm_link_append_data_library_add() after having added some items! */ | /* WARNING! *Never* call wm_link_append_data_library_add() after having added some items! */ | ||||
| static void wm_link_append_data_library_add(WMLinkAppendData *lapp_data, const char *libname) | static void wm_link_append_data_library_add(WMLinkAppendData *lapp_data, const char *libname) | ||||
| { | { | ||||
| size_t len = strlen(libname) + 1; | size_t len = strlen(libname) + 1; | ||||
| ▲ Show 20 Lines • Show All 391 Lines • ▼ Show 20 Lines | for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { | ||||
| WMLinkAppendDataItem *item = itemlink->link; | WMLinkAppendDataItem *item = itemlink->link; | ||||
| ID *id = item->new_id; | ID *id = item->new_id; | ||||
| if (id == NULL) { | if (id == NULL) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BLI_ghash_insert(lapp_data->new_id_to_item, id, item); | BLI_ghash_insert(lapp_data->new_id_to_item, id, item); | ||||
| } | } | ||||
| const bool do_reuse_existing_id = true; | |||||
mont29: This will be false in initial commit, and API to use it for asset browser will be added… | |||||
| lapp_data->library_weak_reference_mapping = BKE_main_library_weak_reference_create(bmain); | |||||
| /* NOTE: Since we append items for IDs not already listed (i.e. implicitly linked indirect | /* NOTE: Since we append items for IDs not already listed (i.e. implicitly linked indirect | ||||
| * dependencies), this list will grow and we will process those IDs later, leading to a flatten | * dependencies), this list will grow and we will process those IDs later, leading to a flatten | ||||
| * recursive processing of all the linked dependencies. */ | * recursive processing of all the linked dependencies. */ | ||||
| for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { | for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { | ||||
| WMLinkAppendDataItem *item = itemlink->link; | WMLinkAppendDataItem *item = itemlink->link; | ||||
| ID *id = item->new_id; | ID *id = item->new_id; | ||||
| if (id == NULL) { | if (id == NULL) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BLI_assert(item->customdata == NULL); | BLI_assert(item->customdata == NULL); | ||||
| /* Clear tag previously used to mark IDs needing post-processing (instantiation of loose | /* Clear tag previously used to mark IDs needing post-processing (instantiation of loose | ||||
| * objects etc.). */ | * objects etc.). */ | ||||
| id->tag &= ~LIB_TAG_DOIT; | BLI_assert((id->tag & LIB_TAG_DOIT) == 0); | ||||
| ID *existing_local_id = BKE_idtype_idcode_append_is_reusable(GS(id->name)) ? | |||||
| BKE_main_library_weak_reference_search_item( | |||||
| lapp_data->library_weak_reference_mapping, | |||||
| id->lib->filepath, | |||||
| id->name) : | |||||
| NULL; | |||||
| if (item->append_action != WM_APPEND_ACT_UNSET) { | if (item->append_action != WM_APPEND_ACT_UNSET) { | ||||
| /* Already set, pass. */ | /* Already set, pass. */ | ||||
| } | } | ||||
| if (GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) { | if (GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) { | ||||
| CLOG_INFO(&LOG, 3, "Appended ID '%s' is proxified, keeping it linked...", id->name); | CLOG_INFO(&LOG, 3, "Appended ID '%s' is proxified, keeping it linked...", id->name); | ||||
| item->append_action = WM_APPEND_ACT_KEEP_LINKED; | item->append_action = WM_APPEND_ACT_KEEP_LINKED; | ||||
| } | } | ||||
| /* Only re-use existing local ID for indirectly linked data, the ID explicitely selected by the | |||||
| * user we always fully append. */ | |||||
| else if (do_reuse_existing_id && existing_local_id != NULL && | |||||
| (item->append_tag & WM_APPEND_TAG_INDIRECT) != 0) { | |||||
| CLOG_INFO(&LOG, 3, "Appended ID '%s' as a matching local one, re-using it...", id->name); | |||||
| item->append_action = WM_APPEND_ACT_REUSE_LOCAL; | |||||
| item->customdata = existing_local_id; | |||||
| } | |||||
| else if (id->tag & LIB_TAG_PRE_EXISTING) { | else if (id->tag & LIB_TAG_PRE_EXISTING) { | ||||
| CLOG_INFO(&LOG, 3, "Appended ID '%s' was already linked, need to copy it...", id->name); | CLOG_INFO(&LOG, 3, "Appended ID '%s' was already linked, need to copy it...", id->name); | ||||
| item->append_action = WM_APPEND_ACT_COPY_LOCAL; | item->append_action = WM_APPEND_ACT_COPY_LOCAL; | ||||
| } | } | ||||
| else { | else { | ||||
| /* In future we could search for already existing matching local ID etc. */ | /* In future we could search for already existing matching local ID etc. */ | ||||
| CLOG_INFO(&LOG, 3, "Appended ID '%s' will be made local...", id->name); | CLOG_INFO(&LOG, 3, "Appended ID '%s' will be made local...", id->name); | ||||
| item->append_action = WM_APPEND_ACT_MAKE_LOCAL; | item->append_action = WM_APPEND_ACT_MAKE_LOCAL; | ||||
| } | } | ||||
| /* Only check dependencies if we are not keeping linked data, nor re-using existing local data. | /* Only check dependencies if we are not keeping linked data, nor re-using existing local data. | ||||
| */ | */ | ||||
| if (do_recursive && | if (do_recursive && | ||||
| !ELEM(item->append_action, WM_APPEND_ACT_KEEP_LINKED, WM_APPEND_ACT_REUSE_LOCAL)) { | !ELEM(item->append_action, WM_APPEND_ACT_KEEP_LINKED, WM_APPEND_ACT_REUSE_LOCAL)) { | ||||
| WMLinkAppendDataCallBack cb_data = { | WMLinkAppendDataCallBack cb_data = { | ||||
| .lapp_data = lapp_data, .item = item, .reports = reports}; | .lapp_data = lapp_data, .item = item, .reports = reports}; | ||||
| BKE_library_foreach_ID_link( | BKE_library_foreach_ID_link( | ||||
| bmain, id, foreach_libblock_append_callback, &cb_data, IDWALK_NOP); | bmain, id, foreach_libblock_append_callback, &cb_data, IDWALK_NOP); | ||||
| } | } | ||||
| /* If we found a matching existing local id but are not re-using it, we need to properly clear | |||||
| * its weak reference to linked data. */ | |||||
| if (existing_local_id != NULL && | |||||
| !ELEM(item->append_action, WM_APPEND_ACT_KEEP_LINKED, WM_APPEND_ACT_REUSE_LOCAL)) { | |||||
| BKE_main_library_weak_reference_remove_item(lapp_data->library_weak_reference_mapping, | |||||
| id->lib->filepath, | |||||
| id->name, | |||||
| existing_local_id); | |||||
| } | |||||
| } | } | ||||
| /* Effectively perform required operation on every linked ID. */ | /* Effectively perform required operation on every linked ID. */ | ||||
| for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { | for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { | ||||
| WMLinkAppendDataItem *item = itemlink->link; | WMLinkAppendDataItem *item = itemlink->link; | ||||
| ID *id = item->new_id; | ID *id = item->new_id; | ||||
| if (id == NULL) { | if (id == NULL) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| ID *local_appended_new_id = NULL; | ID *local_appended_new_id = NULL; | ||||
| char lib_filepath[FILE_MAX]; | |||||
| BLI_strncpy(lib_filepath, id->lib->filepath, sizeof(lib_filepath)); | |||||
| char lib_id_name[MAX_ID_NAME]; | |||||
| BLI_strncpy(lib_id_name, id->name, sizeof(lib_id_name)); | |||||
| switch (item->append_action) { | switch (item->append_action) { | ||||
| case WM_APPEND_ACT_COPY_LOCAL: { | case WM_APPEND_ACT_COPY_LOCAL: { | ||||
| BKE_lib_id_make_local( | BKE_lib_id_make_local( | ||||
| bmain, id, LIB_ID_MAKELOCAL_FULL_LIBRARY | LIB_ID_MAKELOCAL_FORCE_COPY); | bmain, id, LIB_ID_MAKELOCAL_FULL_LIBRARY | LIB_ID_MAKELOCAL_FORCE_COPY); | ||||
| local_appended_new_id = id->newid; | local_appended_new_id = id->newid; | ||||
| break; | break; | ||||
| } | } | ||||
| case WM_APPEND_ACT_MAKE_LOCAL: | case WM_APPEND_ACT_MAKE_LOCAL: | ||||
| Show All 16 Lines | switch (item->append_action) { | ||||
| CLOG_ERROR( | CLOG_ERROR( | ||||
| &LOG, "Unexpected unset append action for '%s' ID, assuming 'keep link'", id->name); | &LOG, "Unexpected unset append action for '%s' ID, assuming 'keep link'", id->name); | ||||
| break; | break; | ||||
| default: | default: | ||||
| BLI_assert(0); | BLI_assert(0); | ||||
| } | } | ||||
| if (local_appended_new_id != NULL) { | if (local_appended_new_id != NULL) { | ||||
| if (BKE_idtype_idcode_append_is_reusable(GS(local_appended_new_id->name))) { | |||||
| BKE_main_library_weak_reference_add_item(lapp_data->library_weak_reference_mapping, | |||||
| lib_filepath, | |||||
| lib_id_name, | |||||
| local_appended_new_id); | |||||
| } | |||||
| if (GS(local_appended_new_id->name) == ID_OB) { | if (GS(local_appended_new_id->name) == ID_OB) { | ||||
| BKE_rigidbody_ensure_local_object(bmain, (Object *)local_appended_new_id); | BKE_rigidbody_ensure_local_object(bmain, (Object *)local_appended_new_id); | ||||
| } | } | ||||
| if (set_fakeuser) { | if (set_fakeuser) { | ||||
| if (!ELEM(GS(local_appended_new_id->name), ID_OB, ID_GR)) { | if (!ELEM(GS(local_appended_new_id->name), ID_OB, ID_GR)) { | ||||
| /* Do not set fake user on objects nor collections (instancing). */ | /* Do not set fake user on objects nor collections (instancing). */ | ||||
| id_fake_user_set(local_appended_new_id); | id_fake_user_set(local_appended_new_id); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| BKE_main_library_weak_reference_destroy(lapp_data->library_weak_reference_mapping); | |||||
| lapp_data->library_weak_reference_mapping = NULL; | |||||
| /* Remap IDs as needed. */ | /* Remap IDs as needed. */ | ||||
| for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { | for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { | ||||
| WMLinkAppendDataItem *item = itemlink->link; | WMLinkAppendDataItem *item = itemlink->link; | ||||
| if (item->append_action == WM_APPEND_ACT_KEEP_LINKED) { | if (item->append_action == WM_APPEND_ACT_KEEP_LINKED) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| ID *id = item->new_id; | ID *id = item->new_id; | ||||
| if (id == NULL) { | if (id == NULL) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (item->append_action == WM_APPEND_ACT_COPY_LOCAL) { | if (ELEM(item->append_action, WM_APPEND_ACT_COPY_LOCAL, WM_APPEND_ACT_REUSE_LOCAL)) { | ||||
| BLI_assert(ID_IS_LINKED(id)); | BLI_assert(ID_IS_LINKED(id)); | ||||
| id = id->newid; | id = id->newid; | ||||
| if (id == NULL) { | if (id == NULL) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| } | } | ||||
| BLI_assert(!ID_IS_LINKED(id)); | BLI_assert(!ID_IS_LINKED(id)); | ||||
| ▲ Show 20 Lines • Show All 1,091 Lines • Show Last 20 Lines | |||||
This will be false in initial commit, and API to use it for asset browser will be added afterward.