diff options
author | Peter Klimenko <peterklimk@outlook.com> | 2020-07-31 11:45:15 +0300 |
---|---|---|
committer | Peter Klimenko <peterklimk@outlook.com> | 2020-07-31 11:45:15 +0300 |
commit | 97a4a8d0fb7fd9ac34f9f5d4d5a0689c01235e14 (patch) | |
tree | fc9746d2210eda08be9d44ae67d5e58d64b48b40 /source/blender/blenkernel/intern/lib_id.c | |
parent | 4a7c203e9ecc7c5b0370afc0fdd6bcc183dc00df (diff) | |
parent | f3e8326453ae856d7914e45e832a2ed80aa9a9b9 (diff) |
merge
Diffstat (limited to 'source/blender/blenkernel/intern/lib_id.c')
-rw-r--r-- | source/blender/blenkernel/intern/lib_id.c | 112 |
1 files changed, 97 insertions, 15 deletions
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index 3ad429c5f5a..a64e550579d 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -114,7 +114,7 @@ IDTypeInfo IDType_ID_LINK_PLACEHOLDER = { * Also note that the id _must_ have a library - campbell */ static void lib_id_library_local_paths(Main *bmain, Library *lib, ID *id) { - const char *bpath_user_data[2] = {BKE_main_blendfile_path(bmain), lib->filepath}; + const char *bpath_user_data[2] = {BKE_main_blendfile_path(bmain), lib->filepath_abs}; BKE_bpath_traverse_id(bmain, id, @@ -123,6 +123,16 @@ static void lib_id_library_local_paths(Main *bmain, Library *lib, ID *id) (void *)bpath_user_data); } +static int lib_id_clear_library_data_users_update_cb(LibraryIDLinkCallbackData *cb_data) +{ + ID *id = cb_data->user_data; + if (*cb_data->id_pointer == id) { + DEG_id_tag_update_ex(cb_data->bmain, cb_data->id_owner, ID_RECALC_TAG_FOR_UNDO); + return IDWALK_RET_STOP_ITER; + } + return IDWALK_RET_NOP; +} + /** * Pull an ID out of a library (make it local). Only call this for IDs that * don't have other library users. @@ -145,6 +155,21 @@ static void lib_id_clear_library_data_ex(Main *bmain, ID *id) } } + /* Conceptually, an ID made local is not the same as the linked one anymore. Reflect that by + * regenerating its session UUID. */ + BKE_lib_libblock_session_uuid_renew(id); + + /* 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. */ + DEG_id_tag_update_ex(bmain, id, ID_RECALC_COPY_ON_WRITE); + ID *id_iter; + FOREACH_MAIN_ID_BEGIN (bmain, id_iter) { + BKE_library_foreach_ID_link( + bmain, id_iter, lib_id_clear_library_data_users_update_cb, id, IDWALK_READONLY); + } + FOREACH_MAIN_ID_END; + /* Internal shape key blocks inside data-blocks also stores id->lib, * make sure this stays in sync (note that we do not need any explicit handling for real EMBEDDED * IDs here, this is down automatically in `lib_id_expand_local_cb()`. */ @@ -200,7 +225,7 @@ void id_us_ensure_real(ID *id) CLOG_ERROR(&LOG, "ID user count error: %s (from '%s')", id->name, - id->lib ? id->lib->filepath : "[Main]"); + id->lib ? id->lib->filepath_abs : "[Main]"); BLI_assert(0); } id->us = limit + 1; @@ -258,7 +283,7 @@ void id_us_min(ID *id) CLOG_ERROR(&LOG, "ID user decrement error: %s (from '%s'): %d <= %d", id->name, - id->lib ? id->lib->filepath : "[Main]", + id->lib ? id->lib->filepath_abs : "[Main]", id->us, limit); if (GS(id->name) != ID_IP) { @@ -421,9 +446,9 @@ void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags) /** * Calls the appropriate make_local method for the block, unless test is set. * - * \note Always set ID->newid pointer in case it gets duplicated... + * \note Always set #ID.newid pointer in case it gets duplicated. * - * \param lib_local: Special flag used when making a whole library's content local, + * \param flags: Special flag used when making a whole library's content local, * it needs specific handling. * * \return true if the block can be made local. @@ -583,6 +608,47 @@ bool BKE_id_copy(Main *bmain, const ID *id, ID **newid) } /** + * Invokes the appropriate copy method for the block and returns the result in + * newid, unless test. Returns true if the block can be copied. + */ +ID *BKE_id_copy_for_duplicate(Main *bmain, ID *id, const eDupli_ID_Flags duplicate_flags) +{ + if (id == NULL) { + return id; + } + if (id->newid == NULL) { + const bool do_linked_id = (duplicate_flags & USER_DUP_LINKED_ID) != 0; + if (!(do_linked_id || !ID_IS_LINKED(id))) { + return id; + } + + ID *id_new; + BKE_id_copy(bmain, id, &id_new); + /* Copying add one user by default, need to get rid of that one. */ + id_us_min(id_new); + ID_NEW_SET(id, id_new); + + /* Shape keys are always copied with their owner ID, by default. */ + ID *key_new = (ID *)BKE_key_from_id(id_new); + ID *key = (ID *)BKE_key_from_id(id); + if (key != NULL) { + ID_NEW_SET(key, key_new); + } + + /* Note: embedded data (root nodetrees and master collections) should never be referenced by + * anything else, so we do not need to set their newid pointer and flag. */ + + BKE_animdata_duplicate_id_action(bmain, id_new, duplicate_flags); + if (key_new != NULL) { + BKE_animdata_duplicate_id_action(bmain, id_new, duplicate_flags); + } + /* Note that actions of embedded data (root nodetrees and master collections) are handled + * by `BKE_animdata_duplicate_id_action` as well. */ + } + return id->newid; +} + +/** * Does a mere memory swap over the whole IDs data (including type-specific memory). * \note Most internal ID data itself is not swapped (only IDProperties are). */ @@ -611,6 +677,9 @@ static void id_swap(Main *bmain, ID *id_a, ID *id_b, const bool do_full_id) /* Exception: IDProperties. */ id_a->properties = id_b_back.properties; id_b->properties = id_a_back.properties; + /* Exception: recalc flags. */ + id_a->recalc = id_b_back.recalc; + id_b->recalc = id_a_back.recalc; } if (bmain != NULL) { @@ -1047,8 +1116,10 @@ void BKE_lib_libblock_session_uuid_ensure(ID *id) /** * Re-generate a new session-wise uuid for the given \a id. * - * \warning This has a very specific use-case (to handle UI-related data-blocks that are kept - * across new file reading, when we do keep existing UI). No other usage is expected currently. + * \warning This has a few very specific use-cases, no other usage is expected currently: + * - To handle UI-related data-blocks that are kept across new file reading, when we do keep + * existing UI. + * - For IDs that are made local without needing any copying. */ void BKE_lib_libblock_session_uuid_renew(ID *id) { @@ -1156,7 +1227,7 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int ori /* We may need our own flag to control that at some point, but for now 'no main' one should be * good enough. */ - if ((orig_flag & LIB_ID_CREATE_NO_MAIN) == 0 && id->override_library != NULL) { + if ((orig_flag & LIB_ID_CREATE_NO_MAIN) == 0 && ID_IS_OVERRIDE_LIBRARY(id)) { /* We do not want to copy existing override rules here, as they would break the proper * remapping between IDs. Proper overrides rules will be re-generated anyway. */ BKE_lib_override_library_copy(new_id, id, false); @@ -1694,7 +1765,7 @@ static void library_make_local_copying_check(ID *id, continue; } - /* Shapekeys are considered 'private' to their owner ID here, and never tagged + /* Shape-keys are considered 'private' to their owner ID here, and never tagged * (since they cannot be linked), so we have to switch effective parent to their owner. */ if (GS(par_id->name) == ID_KE) { @@ -2090,7 +2161,7 @@ void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const ID *id, char separa /** * Generate full name of the data-block (without ID code, but with library if any), - * with a 3-character prefix prepended indicating whether it comes from a library, + * with a 2 to 3 character prefix prepended indicating whether it comes from a library, * is overriding, has a fake or no user, etc. * * \note Result is unique to a given ID type in a given Main database. @@ -2099,16 +2170,27 @@ void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const ID *id, char separa * will be filled with generated string. * \param separator_char: Character to use for separating name and library name. Can be 0 to use * default (' '). + * \param r_prefix_len: The length of the prefix added. */ void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI], const ID *id, - char separator_char) + const bool add_lib_hint, + char separator_char, + int *r_prefix_len) { - name[0] = id->lib ? (ID_MISSING(id) ? 'M' : 'L') : ID_IS_OVERRIDE_LIBRARY(id) ? 'O' : ' '; - name[1] = (id->flag & LIB_FAKEUSER) ? 'F' : ((id->us == 0) ? '0' : ' '); - name[2] = ' '; + int i = 0; - BKE_id_full_name_get(name + 3, id, separator_char); + if (add_lib_hint) { + name[i++] = id->lib ? (ID_MISSING(id) ? 'M' : 'L') : ID_IS_OVERRIDE_LIBRARY(id) ? 'O' : ' '; + } + name[i++] = (id->flag & LIB_FAKEUSER) ? 'F' : ((id->us == 0) ? '0' : ' '); + name[i++] = ' '; + + BKE_id_full_name_get(name + i, id, separator_char); + + if (r_prefix_len) { + *r_prefix_len = i; + } } /** |