diff options
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_library.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/blendfile.c | 10 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/library.c | 60 |
3 files changed, 72 insertions, 0 deletions
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 54b9fdac5b4..818fbce4f9a 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -218,6 +218,8 @@ void BKE_main_id_flag_all(struct Main *bmain, const int flag, const bool value); void BKE_main_id_clear_newpoins(struct Main *bmain); +void BLE_main_id_refcount_recompute(struct Main *bmain, const bool do_linked_only); + void BKE_main_lib_objects_recalc_all(struct Main *bmain); /* Only for repairing files via versioning, avoid for general use. */ diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index 570c1b9bd4c..c301588af0c 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -359,6 +359,16 @@ static void setup_app_data(bContext *C, /* TODO(sergey): Can this be also move above? */ RE_FreeAllPersistentData(); } + + if (mode == LOAD_UNDO) { + /* In undo/redo case, we do a whole lot of magic tricks to avoid having to re-read linked + * datablocks from libraries (since those are not supposed to change). Unfortunately, that + * means that we do not reset their user count, however we do increase that one when doing + * lib_link on local IDs using linked ones. + * There is no real way to predict amount of changes here, so we have to fully redo + * refcounting . */ + BLE_main_id_refcount_recompute(bmain, true); + } } static void setup_app_blend_file_data(bContext *C, diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 8b08c189270..8ca8dad8c0a 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -1788,6 +1788,66 @@ void BKE_main_id_clear_newpoins(Main *bmain) FOREACH_MAIN_ID_END; } +static int id_refcount_recompute_callback(void *user_data, + struct ID *UNUSED(id_self), + struct ID **id_pointer, + int cb_flag) +{ + const bool do_linked_only = (bool)POINTER_AS_INT(user_data); + + if (*id_pointer == NULL) { + return IDWALK_RET_NOP; + } + if (do_linked_only && !ID_IS_LINKED(*id_pointer)) { + return IDWALK_RET_NOP; + } + + if (cb_flag & IDWALK_CB_USER) { + /* Do not touch to direct/indirect linked status here... */ + id_us_plus_no_lib(*id_pointer); + } + if (cb_flag & IDWALK_CB_USER_ONE) { + id_us_ensure_real(*id_pointer); + } + + return IDWALK_RET_NOP; +} + +void BLE_main_id_refcount_recompute(struct Main *bmain, const bool do_linked_only) +{ + ListBase *lbarray[MAX_LIBARRAY]; + ID *id; + int a; + + /* Reset usercount of all affected IDs. */ + const int nbr_lb = a = set_listbasepointers(bmain, lbarray); + while (a--) { + for (id = lbarray[a]->first; id != NULL; id = id->next) { + if (!ID_IS_LINKED(id) && do_linked_only) { + continue; + } + id->us = ID_FAKE_USERS(id); + /* Note that we keep EXTRAUSER tag here, since some UI users may define it too... */ + if (id->tag & LIB_TAG_EXTRAUSER) { + id->tag &= ~(LIB_TAG_EXTRAUSER | LIB_TAG_EXTRAUSER_SET); + id_us_ensure_real(id); + } + } + } + + /* Go over whole Main database to re-generate proper usercounts... */ + a = nbr_lb; + while (a--) { + for (id = lbarray[a]->first; id != NULL; id = id->next) { + BKE_library_foreach_ID_link(bmain, + id, + id_refcount_recompute_callback, + POINTER_FROM_INT((int)do_linked_only), + IDWALK_READONLY); + } + } +} + static void library_make_local_copying_check(ID *id, GSet *loop_tags, MainIDRelations *id_relations, |