Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Montagne <montagne29@wanadoo.fr>2016-10-19 15:29:43 +0300
committerBastien Montagne <montagne29@wanadoo.fr>2016-10-19 15:32:08 +0300
commit417847c161ee9fa461c4f354c6b779b566c23796 (patch)
treed8f06ce5f930a1a1ae7a5a5295703241e5e78f78 /source/blender/blenkernel/intern/library_query.c
parent82f842c27f4ff483be0fda6c02d3a4527cc20ff2 (diff)
Fix T49775: Appending data with internal dependency cycles prevents correct clearing of linked data-blocks.
This is not a simple fix, but imho still needs to be backported to 2.78a...
Diffstat (limited to 'source/blender/blenkernel/intern/library_query.c')
-rw-r--r--source/blender/blenkernel/intern/library_query.c112
1 files changed, 91 insertions, 21 deletions
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index 08f9c439a7a..cec7fbacd80 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -1029,30 +1029,32 @@ static int foreach_libblock_id_users_callback(void *user_data, ID *self_id, ID *
{
IDUsersIter *iter = user_data;
- /* XXX This is actually some kind of hack...
- * Issue is, shapekeys' 'from' ID pointer is not actually ID usage.
- * Maybe we should even nuke it from BKE_library_foreach_ID_link, not 100% sure yet...
- */
- if ((GS(self_id->name) == ID_KE) && (((Key *)self_id)->from == *id_p)) {
- return IDWALK_RET_NOP;
- }
- /* XXX another hack, for similar reasons as above one. */
- if ((GS(self_id->name) == ID_OB) && (((Object *)self_id)->proxy_from == (Object *)*id_p)) {
- return IDWALK_RET_NOP;
- }
+ if (*id_p) {
+ /* XXX This is actually some kind of hack...
+ * Issue is, shapekeys' 'from' ID pointer is not actually ID usage.
+ * Maybe we should even nuke it from BKE_library_foreach_ID_link, not 100% sure yet...
+ */
+ if ((GS(self_id->name) == ID_KE) && (((Key *)self_id)->from == *id_p)) {
+ return IDWALK_RET_NOP;
+ }
+ /* XXX another hack, for similar reasons as above one. */
+ if ((GS(self_id->name) == ID_OB) && (((Object *)self_id)->proxy_from == (Object *)*id_p)) {
+ return IDWALK_RET_NOP;
+ }
- if (*id_p && (*id_p == iter->id)) {
+ if (*id_p == iter->id) {
#if 0
- printf("%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d, indirect_usage: %d)\n",
- iter->curr_id->name, iter->id->name, (cb_flag & IDWALK_USER) ? 1 : 0, (cb_flag & IDWALK_USER_ONE) ? 1 : 0,
- (iter->id->tag & LIB_TAG_EXTRAUSER) ? 1 : 0, (iter->id->tag & LIB_TAG_EXTRAUSER_SET) ? 1 : 0,
- (cb_flag & IDWALK_INDIRECT_USAGE) ? 1 : 0);
+ printf("%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d, indirect_usage: %d)\n",
+ iter->curr_id->name, iter->id->name, (cb_flag & IDWALK_USER) ? 1 : 0, (cb_flag & IDWALK_USER_ONE) ? 1 : 0,
+ (iter->id->tag & LIB_TAG_EXTRAUSER) ? 1 : 0, (iter->id->tag & LIB_TAG_EXTRAUSER_SET) ? 1 : 0,
+ (cb_flag & IDWALK_INDIRECT_USAGE) ? 1 : 0);
#endif
- if (cb_flag & IDWALK_INDIRECT_USAGE) {
- iter->count_indirect++;
- }
- else {
- iter->count_direct++;
+ if (cb_flag & IDWALK_INDIRECT_USAGE) {
+ iter->count_indirect++;
+ }
+ else {
+ iter->count_direct++;
+ }
}
}
@@ -1167,3 +1169,71 @@ void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, boo
*is_used_local = (iter.count_direct != 0);
*is_used_linked = (iter.count_indirect != 0);
}
+
+
+static int foreach_libblock_tag_unused_linked_data_callback(void *user_data, ID *self_id, ID **id_p, int UNUSED(cb_flag))
+{
+ bool *is_changed = user_data;
+
+ if (*id_p) {
+ /* XXX This is actually some kind of hack...
+ * Issue is, shapekeys' 'from' ID pointer is not actually ID usage.
+ * Maybe we should even nuke it from BKE_library_foreach_ID_link, not 100% sure yet...
+ */
+ if ((GS(self_id->name) == ID_KE) && (((Key *)self_id)->from == *id_p)) {
+ return IDWALK_RET_NOP;
+ }
+ /* XXX another hack, for similar reasons as above one. */
+ if ((GS(self_id->name) == ID_OB) && (((Object *)self_id)->proxy_from == (Object *)*id_p)) {
+ return IDWALK_RET_NOP;
+ }
+
+ /* If checked id is used by an assumed used ID, then it is also used and not part of any linked archipelago. */
+ if (!(self_id->tag & LIB_TAG_DOIT) && ((*id_p)->tag & LIB_TAG_DOIT)) {
+ (*id_p)->tag &= ~LIB_TAG_DOIT;
+ *is_changed = true;
+ }
+ }
+
+ return IDWALK_RET_NOP;
+}
+
+/**
+ * Detect orphaned linked data blocks (i.e. linked data not used (directly or indirectly) in any way by any local data),
+ * including complex cases like 'linked archipelagoes', i.e. linked datablocks that use each other in loops,
+ * which prevents their deletion by 'basic' usage checks...
+ *
+ * \param do_init_tag if \a true, all linked data are checked, if \a false, only linked datablocks already tagged with
+ * LIB_TAG_DOIT are checked.
+ */
+void BKE_library_tag_unused_linked_data(Main *bmain, const bool do_init_tag)
+{
+ ListBase *lb_array[MAX_LIBARRAY];
+
+ if (do_init_tag) {
+ int i = set_listbasepointers(bmain, lb_array);
+
+ while (i--) {
+ for (ID *id = lb_array[i]->first; id; id = id->next) {
+ if (id->lib && (id->tag & LIB_TAG_INDIRECT) != 0) {
+ id->tag |= LIB_TAG_DOIT;
+ }
+ else {
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+ }
+ }
+ }
+
+ bool do_loop = true;
+ while (do_loop) {
+ int i = set_listbasepointers(bmain, lb_array);
+ do_loop = false;
+
+ while (i--) {
+ for (ID *id = lb_array[i]->first; id; id = id->next) {
+ BKE_library_foreach_ID_link(id, foreach_libblock_tag_unused_linked_data_callback, &do_loop, IDWALK_NOP);
+ }
+ }
+ }
+}