[Bf-blender-cvs] [1daa502] id-remap: Add BKE_libblock_relink(), which works as _libblock_remap(), but only over one given ID (instead of whole Main content).

Bastien Montagne noreply at git.blender.org
Wed Oct 7 23:17:48 CEST 2015


Commit: 1daa502f8753d3febd1122d83904e8e5dd57b31e
Author: Bastien Montagne
Date:   Wed Oct 7 21:56:27 2015 +0200
Branches: id-remap
https://developer.blender.org/rB1daa502f8753d3febd1122d83904e8e5dd57b31e

Add BKE_libblock_relink(), which works as _libblock_remap(), but only over one given ID
(instead of whole Main content).

Could replace maybe things like constraint, rigisbody world, etc. '_relink' func,
but for now it's only intended to replace custom 'id releasing' code in _free()
funcs of all IDs!

===================================================================

M	source/blender/blenkernel/BKE_library.h
M	source/blender/blenkernel/intern/library.c

===================================================================

diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 449358e..cbc0235 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -65,6 +65,8 @@ void BKE_libblock_remap(
 
 void BKE_libblock_unlink(struct Main *bmain, void *idv) ATTR_NONNULL();
 
+void BKE_libblock_relink(struct Main *bmain, void *idv, void *old_idv, void *new_idv) ATTR_NONNULL(1, 2);
+
 void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id);
 void id_lib_extern(struct ID *id);
 void BKE_library_filepath_set(struct Library *lib, const char *filepath);
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 872d159..0fc4af8 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -1005,7 +1005,12 @@ static bool foreach_libblock_remap_callback(void *user_data, ID **id_p, int cb_f
 	ID *new_id = id_remap_data->new_id;
 	ID *id = id_remap_data->id;
 
-	if (*id_p == old_id) {
+	if (!old_id) {  /* Used to cleanup all IDs used by a specific one. */
+		BLI_assert(!new_id);
+		old_id = *id_p;
+	}
+
+	if (*id_p && (*id_p == old_id)) {
 		/* Note: proxy usage implies LIB_EXTERN, so on this aspect it is direct,
 		 *       on the other hand since they get reset to lib data on file open/reload it is indirect too...
 		 *       Edit Mode is also a 'skip direct' case. */
@@ -1034,7 +1039,7 @@ static bool foreach_libblock_remap_callback(void *user_data, ID **id_p, int cb_f
 				if (new_id)
 					new_id->us++;
 			}
-			DAG_id_tag_update_ex(bmain, id, OB_RECALC_OB | OB_RECALC_DATA);
+			DAG_id_tag_update_ex(bmain, id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
 			if (!is_indirect) {
 				id_remap_data->flag |= ID_REMAP_IS_LINKED_DIRECT;
 			}
@@ -1044,15 +1049,72 @@ static bool foreach_libblock_remap_callback(void *user_data, ID **id_p, int cb_f
 	return true;
 }
 
+static void libblock_remap_do(
+        Main *bmain, ID *id, ID *old_id, ID *new_id, const bool skip_indirect_usage,
+        int *r_skipped_direct, int *r_skipped_indirect)
+{
+	IDRemap id_remap_data = {bmain, old_id, new_id, NULL};
+	ListBase *lb_array[MAX_LIBARRAY];
+	int i;
+
+	printf("%s: %s (%p) replaced by %s (%p)\n", __func__,
+	       old_id ? old_id->name : "", old_id, new_id ? new_id->name : "", new_id);
+
+	if (skip_indirect_usage) {
+		id_remap_data.flag |= ID_REMAP_SKIP_INDIRECT_USAGE;
+	}
+
+	if (id) {
+		printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib);
+		id_remap_data.id = id;
+		BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)&id_remap_data, IDWALK_NOP);
+	}
+	else {
+		i = set_listbasepointers(bmain, lb_array);
+
+		/* Note that this is a very 'bruteforce' approach, maybe we could use some depsgraph to only process
+		 * objects actually using given old_id... sounds rather unlikely currently, though, so this will do for now. */
+
+		while (i--) {
+			ID *id = lb_array[i]->first;
+
+			for (; id; id = id->next) {
+				/* Note that we cannot skip indirect usages of old_id here (if requested), we still need to check it for
+				 * the user count handling...
+				 * XXX No more true (except for debug usage of those skipping counters). */
+				printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib);
+				id_remap_data.id = id;
+				BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)&id_remap_data, IDWALK_NOP);
+			}
+		}
+	}
+
+	if (old_id->flag & LIB_FAKEUSER) {
+		id_remap_data.skipped_direct++;
+	}
+
+	if (new_id && (new_id->flag & LIB_INDIRECT) && (id_remap_data.flag & ID_REMAP_IS_LINKED_DIRECT)) {
+		new_id->flag &= ~LIB_INDIRECT;
+		new_id->flag |= LIB_EXTERN;
+	}
+
+	if (r_skipped_direct)
+		*r_skipped_direct = id_remap_data.skipped_direct;
+
+	if (r_skipped_indirect)
+		*r_skipped_indirect = id_remap_data.skipped_indirect;
+
+	printf("%s: %d occurences skipped (%d direct and %d indirect ones)\n", __func__,
+	       id_remap_data.skipped_direct + id_remap_data.skipped_indirect,
+	       id_remap_data.skipped_direct, id_remap_data.skipped_indirect);
+}
+
 /** Replace all references in .blend file to \a old_id by \a new_id (if \a new_id is NULL, it unlinks \a old_id). */
 void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const bool skip_indirect_usage)
 {
 	ID *old_id = old_idv;
 	ID *new_id = new_idv;
-	IDRemap id_remap_data = {(void *)bmain, (void *)old_id, (void *)new_id, NULL};
-	ListBase *lb_array[MAX_LIBARRAY];
-	int skipped;
-	int i;
+	int skipped_direct;
 
 	BLI_assert(old_id != NULL);
 	BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
@@ -1079,26 +1141,7 @@ void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const
 		}
 	}
 
-	if (skip_indirect_usage) {
-		id_remap_data.flag |= ID_REMAP_SKIP_INDIRECT_USAGE;
-	}
-
-	i = set_listbasepointers(bmain, lb_array);
-
-	/* Note that this is a very 'bruteforce' approach, maybe we could use some depsgraph to only process
-	 * objects actually using given old_id... But for now this will do. */
-
-	while (i--) {
-		ID *id = lb_array[i]->first;
-
-		for (; id; id = id->next) {
-			/* Note that we cannot skip indirect usages of old_id here (if requested), we still need to check it for
-			 * the user count handling... */
-			printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib);
-			id_remap_data.id = id;
-			BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)&id_remap_data, IDWALK_NOP);
-		}
-	}
+	libblock_remap_do(bmain, NULL, old_id, new_id, skip_indirect_usage, &skipped_direct, NULL);
 
 	if (free_notifier_reference_cb) {
 		free_notifier_reference_cb(old_id);
@@ -1110,11 +1153,6 @@ void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const
 		remap_editor_id_reference_cb(old_id, new_id);
 	}
 
-	if (old_id->flag & LIB_FAKEUSER) {
-		id_remap_data.skipped_direct++;
-	}
-	skipped = id_remap_data.skipped_direct + id_remap_data.skipped_indirect;
-
 	BLI_assert(old_id->us >= 0);
 
 #if 0
@@ -1125,12 +1163,7 @@ void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const
 	old_id->us = skipped;
 #endif
 
-	if (new_id && (new_id->flag & LIB_INDIRECT) && (id_remap_data.flag & ID_REMAP_IS_LINKED_DIRECT)) {
-		new_id->flag &= ~LIB_INDIRECT;
-		new_id->flag |= LIB_EXTERN;
-	}
-
-	if (id_remap_data.skipped_direct == 0) {
+	if (skipped_direct == 0) {
 		/* old_id is assumed to not be used directly anymore... */
 		if (old_id->lib && (old_id->flag & LIB_EXTERN)) {
 			old_id->flag &= ~LIB_EXTERN;
@@ -1188,6 +1221,38 @@ void BKE_libblock_unlink(Main *bmain, void *idv)
 	BKE_main_unlock(bmain);
 }
 
+/** Similar to libblock_remap, but only affects IDs used by given \a idv ID.
+ *
+ * \param old_id Unlike BKE_libblock_remap, can be NULL, in which case all ID usages by given \a idv will be cleared.
+ */
+/* Should be able to replace all _relink() funcs (constraints, rigidbody, etc.) ? */
+/* XXX Arg! Naming... :(
+ *     _relink? avoids confusion with _remap, but is confusing with _unlink
+ *     _remap_used_ids?
+ *     _remap_datablocks?
+ *     BKE_id_remap maybe?
+ *     ... sigh
+ */
+void BKE_libblock_relink(Main *bmain, void *idv, void *old_idv, void *new_idv)
+{
+	ID *id = idv;
+	ID *old_id = old_idv;
+	ID *new_id = new_idv;
+
+	/* No need to lock here, we are only affecting given ID. */
+
+	BLI_assert(id);
+	if (old_id) {
+		BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
+		BLI_assert(old_id != new_id);
+	}
+	else {
+		BLI_assert(new_id == NULL);
+	}
+
+	libblock_remap_do(bmain, id, old_id, new_id, false, NULL, NULL);
+}
+
 static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata)
 {
 	ChannelDriver *driver;




More information about the Bf-blender-cvs mailing list