[Bf-blender-cvs] [952dbad] tmp-id-users: 'users of ID' API (from id-remap).

Bastien Montagne noreply at git.blender.org
Tue Jan 5 17:41:59 CET 2016


Commit: 952dbad5c3ee6622ebeb086c8939a70551880b86
Author: Bastien Montagne
Date:   Fri Dec 18 23:30:31 2015 +0100
Branches: tmp-id-users
https://developer.blender.org/rB952dbad5c3ee6622ebeb086c8939a70551880b86

'users of ID' API (from id-remap).

This adds iterator over all (ID) users of a given datablock.
Mostly handy through the associated RNA API.

Note that it also had to fix an issue with RNA using DNA's ListBase struct (this
works OK with py, but breaks with cpp due to missing include - and we do not want to have to
include a DNA header just for that ;) ).

Reviewers: campbellbarton, sergey

Differential Revision: https://developer.blender.org/D1678

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

M	source/blender/blenkernel/BKE_library_query.h
M	source/blender/blenkernel/intern/library_query.c
M	source/blender/makesrna/RNA_types.h
M	source/blender/makesrna/intern/makesrna.c
M	source/blender/makesrna/intern/rna_ID.c
M	source/blender/python/intern/bpy_rna.c

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

diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h
index 194b6f0..4e2142f 100644
--- a/source/blender/blenkernel/BKE_library_query.h
+++ b/source/blender/blenkernel/BKE_library_query.h
@@ -32,6 +32,7 @@
  */
 
 struct ID;
+struct Main;
 
 /* Tips for the callback for cases it's gonna to modify the pointer. */
 enum {
@@ -65,4 +66,13 @@ enum {
 void BKE_library_foreach_ID_link(struct ID *id, LibraryIDLinkCallback callback, void *user_data, int flag);
 void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, const int cd_flag);
 
+/* Iterator over all ID users of a given datablock. */
+struct IDUsersIter;
+
+int BKE_library_ID_use_ID(struct ID *id_user, struct ID *id_used);
+
+struct IDUsersIter *BKE_library_ID_users_iter_init(struct Main *bmain, struct ID *id);
+struct ID *BKE_library_ID_users_iter_next(struct IDUsersIter *iter, int *r_count);
+void BKE_library_ID_users_iter_end(struct IDUsersIter **iter);
+
 #endif  /* __BKE_LIBRARY_QUERY_H__ */
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index d54f382..b7c917e 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -29,6 +29,7 @@
 
 #include <stdlib.h>
 
+#include "MEM_guardedalloc.h"
 
 #include "DNA_actuator_types.h"
 #include "DNA_anim_types.h"
@@ -61,12 +62,14 @@
 #include "DNA_world_types.h"
 
 #include "BLI_utildefines.h"
+#include "BLI_listbase.h"
 
 #include "BKE_animsys.h"
 #include "BKE_constraint.h"
 #include "BKE_fcurve.h"
 #include "BKE_library.h"
 #include "BKE_library_query.h"
+#include "BKE_main.h"
 #include "BKE_modifier.h"
 #include "BKE_particle.h"
 #include "BKE_rigidbody.h"
@@ -665,3 +668,125 @@ void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cd_flag)
 		id_us_ensure_real(id_dst);
 	}
 }
+
+/* ***** ID users iterator. ***** */
+typedef struct IDUsersIter {
+	ID *id;
+
+	ListBase *lb_array[MAX_LIBARRAY];
+	int lb_idx;
+
+	ID *curr_id;
+	int count;  /* Set by callback. */
+} IDUsersIter;
+
+static bool foreach_libblock_id_users_callback(void *user_data, ID **id_p, int UNUSED(cb_flag))
+{
+	IDUsersIter *iter = user_data;
+
+	if (*id_p && (*id_p == iter->id)) {
+		iter->count++;
+	}
+
+	return true;
+}
+
+/**
+ * Return the number of times given \a id_user uses/references \a id_used.
+ *
+ * \note This only checks for pointer references of an ID, shallow usages (like e.g. by RNA paths, as done
+ *       for FCurves) are not detected at all.
+ *
+ * \param id_user the ID which is supposed to use (reference) \a id_used.
+ * \param id_used the ID which is supposed to be used (referenced) by \a id_user.
+ * \return the number of direct usages/references of \a id_used by \a id_user.
+ */
+int BKE_library_ID_use_ID(ID *id_user, ID *id_used)
+{
+	IDUsersIter iter;
+
+	/* We do not care about iter.lb_array/lb_idx here... */
+	iter.id = id_used;
+	iter.curr_id = id_user;
+	iter.count = 0;
+
+	BKE_library_foreach_ID_link(iter.curr_id, foreach_libblock_id_users_callback, (void *)&iter, IDWALK_NOP);
+
+	return iter.count;
+}
+
+/**
+ * Initialize an id user iterator.
+ *
+ * \param bmain the Main database in which to search for \a id users.
+ * \param id the datablock to find users of.
+ * \return an opaque pointer to the initialized iterator.
+ */
+IDUsersIter *BKE_library_ID_users_iter_init(Main *bmain, ID *id)
+{
+	IDUsersIter *iter = MEM_mallocN(sizeof(*iter), __func__);
+
+	iter->id = id;
+	iter->lb_idx = set_listbasepointers(bmain, iter->lb_array);
+	iter->curr_id = NULL;
+	iter->count = 0;
+
+	return iter;
+}
+
+/**
+ * Return the next ID using the datablock this \a iter was built from.
+ *
+ * \param iter the iterator pointer (as returned by \a BKE_library_ID_users_iter_init).
+ * \param r_count if non-null, will be set to the number of usages detected for returned ID.
+ * \return a pointer to the next ID using the searched datablock, or NULL if none found anymore.
+ */
+ID *BKE_library_ID_users_iter_next(IDUsersIter *iter, int *r_count)
+{
+	ID *ret = NULL;
+
+	if (iter == NULL) {
+		if (r_count) {
+			*r_count = 0;
+		}
+		return ret;
+	}
+
+	iter->count = 0;
+	while (ret == NULL) {
+		while (iter->curr_id == NULL) {
+			if (iter->lb_idx-- == 0) {
+				break;
+			}
+			iter->curr_id = iter->lb_array[iter->lb_idx]->first;
+		}
+		if (iter->curr_id == NULL) {
+			break;
+		}
+
+		iter->count = 0;
+		BKE_library_foreach_ID_link(iter->curr_id, foreach_libblock_id_users_callback, (void *)iter, IDWALK_NOP);
+
+		if (iter->count > 0) {
+			ret = iter->curr_id;
+		}
+
+		iter->curr_id = iter->curr_id->next;
+	}
+
+	if (r_count) {
+		*r_count = iter->count;
+	}
+	return ret;
+}
+
+/**
+ * Finalize (clean up) an IDUsers iterator.
+ *
+ * \param iter the address of the iterator pointer to finalize.
+ */
+void BKE_library_ID_users_iter_end(IDUsersIter **iter)
+{
+	MEM_SAFE_FREE(*iter);
+}
+
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index 04a2361..a302bc6 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -285,6 +285,11 @@ typedef struct CollectionPointerLink {
 	PointerRNA ptr;
 } CollectionPointerLink;
 
+/* Copy of ListBase for RNA... */
+typedef struct CollectionListBase {
+	struct CollectionPointerLink *first, *last;
+} CollectionListBase;
+
 typedef enum RawPropertyType {
 	PROP_RAW_UNSET = -1,
 	PROP_RAW_INT, // XXX - abused for types that are not set, eg. MFace.verts, needs fixing.
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index ce977da..fa0acae 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -466,7 +466,7 @@ static const char *rna_parameter_type_name(PropertyRNA *parm)
 		}
 		case PROP_COLLECTION:
 		{
-			return "ListBase";
+			return "CollectionListBase";
 		}
 		default:
 			return "<error, no type specified>";
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 3a16330..ae8df64 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -87,9 +87,12 @@ EnumPropertyItem rna_enum_id_type_items[] = {
 
 #include "DNA_anim_types.h"
 
+#include "BLI_listbase.h"
+
 #include "BKE_font.h"
 #include "BKE_idprop.h"
 #include "BKE_library.h"
+#include "BKE_library_query.h"
 #include "BKE_animsys.h"
 #include "BKE_material.h"
 #include "BKE_depsgraph.h"
@@ -332,6 +335,28 @@ static void rna_ID_user_clear(ID *id)
 	id->us = 0; /* don't save */
 }
 
+static CollectionListBase rna_ID_used_by_ids(ID *id, Main *bmain)
+{
+	ListBase ret = {0};
+	struct IDUsersIter *iter = BKE_library_ID_users_iter_init(bmain, id);
+	ID *id_user;
+
+	do {
+		id_user = BKE_library_ID_users_iter_next(iter, NULL);
+
+		if (id_user) {
+			CollectionPointerLink *lnk = MEM_mallocN(sizeof(*lnk), __func__);
+			RNA_id_pointer_create(id_user, &lnk->ptr);
+			BLI_addtail(&ret, lnk);
+		}
+	} while (id_user != NULL);
+
+	BKE_library_ID_users_iter_end(&iter);
+
+	/* CollectionListBase is a mere RNA redefinition of ListBase. */
+	return *(CollectionListBase *)&ret;
+}
+
 static AnimData * rna_ID_animation_data_create(ID *id, Main *bmain)
 {
 	AnimData *adt = BKE_animdata_add_id(id);
@@ -976,6 +1001,20 @@ static void rna_def_ID(BlenderRNA *brna)
 	RNA_def_function_ui_description(func, "Clear the user count of a data-block so its not saved, "
 	                                "on reload the data will be removed");
 
+	func = RNA_def_function(srna, "user_of_id", "BKE_library_ID_use_ID");
+	RNA_def_function_ui_description(func, "Count the number of times that ID uses/references given one");
+	parm = RNA_def_pointer(func, "id", "ID", "", "ID to count usages");
+	RNA_def_property_flag(parm, PROP_NEVER_NULL);
+	parm = RNA_def_int(func, "count", 0, 0, INT_MAX,
+	                   "", "Number of usages/references of given id by current datablock", 0, INT_MAX);
+	RNA_def_function_return(func, parm);
+
+	func = RNA_def_function(srna, "used_by_ids", "rna_ID_used_by_ids");
+	RNA_def_function_ui_description(func, "Return a list of all datablocks using/referencing current one");
+	RNA_def_function_flag(func, FUNC_USE_MAIN);
+	parm = RNA_def_collection(func, "ids", "ID", "", "All datablocks using current ID");
+	RNA_def_function_return(func, parm);
+
 	func = RNA_def_function(srna, "animation_data_create", "rna_ID_animation_data_create");
 	RNA_def_function_flag(func, FUNC_USE_MAIN);
 	RNA_def_function_ui_description(func, "Create animation data to this ID, note that not all ID types support this");
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 45a5735..d7db89d 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -4993,7 +4993,7 @@ static PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *dat
 			}
 			case PROP_COLLECTION:
 			{
-				ListBase *lb = (ListBase *)data;
+				CollectionListBase *lb = (CollectionListBase *)data;
 				CollectionPointerLink *link;
 
 				ret = PyList_New(0);




More information about the Bf-blender-cvs mailing list