[Bf-blender-cvs] [827b145] libquery-recursive: Rework library_query foreach looper - add optional recursivity.
Bastien Montagne
noreply at git.blender.org
Thu Feb 18 17:56:43 CET 2016
Commit: 827b1457ca9e76f627e8c88cf883847fc3ae3267
Author: Bastien Montagne
Date: Wed Feb 17 18:31:01 2016 +0100
Branches: libquery-recursive
https://developer.blender.org/rB827b1457ca9e76f627e8c88cf883847fc3ae3267
Rework library_query foreach looper - add optional recursivity.
This commit:
* Fixes bad handling of 'stop iteration' (by adding a status flag, so that we can actually
stop in helper functions too, and jumping to a finalize label instead of raw return, to
allow propper clean up).
* Adds optional recursion into 'ID tree' - callback can also decide to exclude current id_pp
from recursion. Note that this implies 'readonly', modifying IDs while recursing is not
something we want to support!
* Changes callback signature/expected behavior: return behavior is now handled through flags,
and 'parent' ID of id_pp is also passed (since it may not always be root id anymore).
Used this new recursive behavior in ID preview generation as an example, still needs more testing!
===================================================================
M source/blender/blenkernel/BKE_library_query.h
M source/blender/blenkernel/intern/library.c
M source/blender/blenkernel/intern/library_query.c
M source/blender/editors/object/object_relations.c
M source/blender/python/intern/bpy_rna_id_collection.c
M source/blender/windowmanager/intern/wm_operators.c
===================================================================
diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h
index f07644d..86628ea 100644
--- a/source/blender/blenkernel/BKE_library_query.h
+++ b/source/blender/blenkernel/BKE_library_query.h
@@ -50,15 +50,23 @@ enum {
IDWALK_USER_ONE = (1 << 9),
};
-/* Call a callback for each ID link which the given ID uses.
+enum {
+ IDWALK_RET_NOP = 0,
+ IDWALK_RET_STOP_ITER = 1 << 0, /* Completly top iteration. */
+ IDWALK_RET_STOP_RECURSION = 1 << 1, /* Stop recursion, that is, do not loop over ID used by current one. */
+};
+
+/**
+ * Call a callback for each ID link which the given ID uses.
*
- * Return 'false' if you want to stop iteration.
+ * \return a set of flags to controll further iteration (0 to keep going).
*/
-typedef bool (*LibraryIDLinkCallback) (void *user_data, struct ID **id_pointer, int cd_flag);
+typedef int (*LibraryIDLinkCallback) (void *user_data, struct ID *id_self, struct ID **id_pointer, int cd_flag);
/* Flags for the foreach function itself. */
enum {
IDWALK_READONLY = (1 << 0),
+ IDWALK_RECURSE = (1 << 1), /* Also implies IDWALK_READONLY. */
};
/* Loop over all of the ID's this datablock links to. */
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 811fbf5..dfda527 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -1066,7 +1066,7 @@ void *BKE_libblock_copy(ID *id)
return BKE_libblock_copy_ex(G.main, id);
}
-static bool id_relink_looper(void *UNUSED(user_data), ID **id_pointer, const int cd_flag)
+static int id_relink_looper(void *UNUSED(user_data), ID *UNUSED(id_self), ID **id_pointer, const int cd_flag)
{
ID *id = *id_pointer;
if (id) {
@@ -1080,7 +1080,7 @@ static bool id_relink_looper(void *UNUSED(user_data), ID **id_pointer, const int
BKE_libblock_relink(id);
}
}
- return true;
+ return IDWALK_RET_NOP;
}
void BKE_libblock_relink(ID *id)
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index f5e17c0..2a9f449 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -61,6 +61,8 @@
#include "DNA_world_types.h"
#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist_stack.h"
#include "BKE_animsys.h"
#include "BKE_constraint.h"
@@ -74,52 +76,81 @@
#include "BKE_sequencer.h"
#include "BKE_tracking.h"
-#define FOREACH_CALLBACK_INVOKE_ID_PP(self_id, id_pp, flag, callback, user_data, cb_flag) \
- { \
+
+#define FOREACH_FINALIZE _finalize
+#define FOREACH_FINALIZE_VOID FOREACH_FINALIZE: (void)0
+
+#define FOREACH_CALLBACK_INVOKE_ID_PP(_data, id_pp, cb_flag) \
+ if (!((_data)->status & IDWALK_STOP)) { \
+ const int _flag = (_data)->flag; \
ID *old_id = *id_pp; \
- bool keep_working = callback(user_data, id_pp, cb_flag); \
- if (flag & IDWALK_READONLY) { \
+ const int callback_return = (_data)->callback((_data)->user_data, (_data)->id_self, id_pp, cb_flag); \
+ if (_flag & IDWALK_READONLY) { \
BLI_assert(*id_pp == old_id); \
- (void)old_id; /* quiet warning */ \
} \
- if (keep_working == false) { \
- /* REAL DANGER! Beware of this return! */ \
- /* TODO(sergey): Make it less creepy without too much duplicated code.. */ \
- return; \
+ if (_flag & IDWALK_RECURSE) { \
+ if (!BLI_gset_haskey((_data)->ids_handled, old_id)) { \
+ BLI_gset_add((_data)->ids_handled, old_id); \
+ if (!(callback_return & IDWALK_RET_STOP_RECURSION)) { \
+ BLI_LINKSTACK_PUSH((_data)->ids_todo, old_id); \
+ } \
+ } \
} \
+ if (callback_return & IDWALK_RET_STOP_ITER) { \
+ (_data)->status |= IDWALK_STOP; \
+ goto FOREACH_FINALIZE; \
+ } \
+ } \
+ else { \
+ goto FOREACH_FINALIZE; \
} ((void)0)
-#define FOREACH_CALLBACK_INVOKE_ID(self_id, id, flag, callback, user_data, cb_flag) \
+#define FOREACH_CALLBACK_INVOKE_ID(data, id, cb_flag) \
{ \
CHECK_TYPE_ANY(id, ID *, void *); \
- FOREACH_CALLBACK_INVOKE_ID_PP(self_id, (ID **)&(id), flag, callback, user_data, cb_flag); \
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, (ID **)&(id), cb_flag); \
} ((void)0)
-#define FOREACH_CALLBACK_INVOKE(self_id, id_super, flag, callback, user_data, cb_flag) \
+#define FOREACH_CALLBACK_INVOKE(data, id_super, cb_flag) \
{ \
CHECK_TYPE(&((id_super)->id), ID *); \
- FOREACH_CALLBACK_INVOKE_ID_PP(self_id, (ID **)&id_super, flag, callback, user_data, cb_flag); \
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, (ID **)&id_super, cb_flag); \
} ((void)0)
+/* status */
+enum {
+ IDWALK_STOP = 1 << 0,
+};
+
typedef struct LibraryForeachIDData {
- ID *self_id;
- int flag;
+ ID *id_self;
LibraryIDLinkCallback callback;
void *user_data;
+
+ int flag;
+ int status;
+
+ /* To handle recursion. */
+ GSet *ids_handled; /* All IDs that are either already done, or still in ids_todo stack. */
+ BLI_LINKSTACK_DECLARE(ids_todo, ID *);
} LibraryForeachIDData;
static void library_foreach_rigidbodyworldSceneLooper(
struct RigidBodyWorld *UNUSED(rbw), ID **id_pointer, void *user_data, int cd_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+
+ FOREACH_FINALIZE_VOID;
}
static void library_foreach_modifiersForeachIDLink(
void *user_data, Object *UNUSED(object), ID **id_pointer, int cd_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+
+ FOREACH_FINALIZE_VOID;
}
static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), ID **id_pointer,
@@ -127,35 +158,45 @@ static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), ID
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
const int cd_flag = is_reference ? IDWALK_USER : IDWALK_NOP;
- FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+
+ FOREACH_FINALIZE_VOID;
}
static void library_foreach_particlesystemsObjectLooper(
ParticleSystem *UNUSED(psys), ID **id_pointer, void *user_data, int cd_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+
+ FOREACH_FINALIZE_VOID;
}
static void library_foreach_sensorsObjectLooper(
bSensor *UNUSED(sensor), ID **id_pointer, void *user_data, int cd_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+
+ FOREACH_FINALIZE_VOID;
}
static void library_foreach_controllersObjectLooper(
bController *UNUSED(controller), ID **id_pointer, void *user_data, int cd_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+
+ FOREACH_FINALIZE_VOID;
}
static void library_foreach_actuatorsObjectLooper(
bActuator *UNUSED(actuator), ID **id_pointer, void *user_data, int cd_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, cd_flag);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+
+ FOREACH_FINALIZE_VOID;
}
static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *adt)
@@ -170,17 +211,21 @@ static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *
/* only used targets */
DRIVER_TARGETS_USED_LOOPER(dvar)
{
- FOREACH_CALLBACK_INVOKE_ID(data->self_id, dtar->id, data->flag, data->callback, data->user_data, IDWALK_NOP);
+ FOREACH_CALLBACK_INVOKE_ID(data, dtar->id, IDWALK_NOP);
}
DRIVER_TARGETS_LOOPER_END
}
}
+
+ FOREACH_FINALIZE_VOID;
}
static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex)
{
- FOREACH_CALLBACK_INVOKE(data->self_id, mtex->object, data->flag, data->callback, data->user_data, IDWALK_NOP);
- FOREACH_CALLBACK_INVOKE(data->self_id, mtex->tex, data->flag, data->callback, data->user_data, IDWALK_USER);
+ FOREACH_CALLBACK_INVOKE(data, mtex->object, IDWALK_NOP);
+ FOREACH_CALLBACK_INVOKE(data, mtex->tex, IDWALK_USER);
+
+ FOREACH_FINALIZE_VOID;
}
@@ -195,7 +240,17 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
LibraryForeachIDData data;
int i;
- data.self_id = id;
+ if (flag & IDWALK_RECURSE) {
+ /* For now, recusion implies read-only. */
+ flag |= IDWALK_READONLY;
+
+ data.ids_handled = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ BLI_LINKSTACK_INIT(data.ids_todo);
+ }
+ else {
+ data.ids_handled = NULL;
+ }
+
data.flag = flag;
data.callback = callback;
data.user_data = user_data;
@@ -206,445 +261,455 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
#define CALLBACK_INVOKE_ID(check_id, cb_flag) \
- FOREACH_CALLBACK_INVOKE_ID(id, check_id, flag, callback, user_data, cb_flag)
+ FOREACH_CALLBACK_INVOKE_ID(&data, check_id, cb_flag)
#define CALLBACK_INVOKE(check_id_super, cb_flag) \
- FOREACH_CALLBACK_INVOKE(id, check_id_super, flag, callback, user_data, cb_flag)
-
- switch (GS(id->name)) {
- case ID_SCE:
- {
- Scene *scene = (Scene *) id;
- ToolSettings *toolsett = scene->toolsettings;
- SceneRenderLayer *srl;
- Base *base;
-
- CALLBACK_INVOKE(scene->camera, IDWALK_NOP);
- CALLBACK_INVOKE(scene->world,
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list