Discussion:
[Bf-blender-cvs] [9521d71] id-remap: Merge branch 'master' into id-remap
Bastien Montagne
10 years ago
Permalink
Commit: 9521d7173559e8a3980930893ce6e0ce05fcdaa8
Author: Bastien Montagne
Date: Mon Nov 2 19:22:14 2015 +0100
Branches: id-remap
https://developer.blender.org/rB9521d7173559e8a3980930893ce6e0ce05fcdaa8

Merge branch 'master' into id-remap

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



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

diff --cc source/blender/blenkernel/intern/brush.c
index e944c0b,95b65f5..f1a729d
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@@ -214,11 -219,25 +214,26 @@@ void BKE_brush_free(Brush *brush

curvemapping_free(brush->curve);

- if (brush->gradient)
- MEM_freeN(brush->gradient);
+ MEM_SAFE_FREE(brush->gradient);
+
+ BKE_previewimg_free(&(brush->preview));
}

+ /**
+ * \note Currently users don't remove brushes from the UI (as is done for scene, text... etc)
+ * This is only used by RNA, which can remove brushes.
+ */
+ void BKE_brush_unlink(Main *bmain, Brush *brush)
+ {
+ Brush *brush_iter;
+
+ for (brush_iter = bmain->brush.first; brush_iter; brush_iter = brush_iter->id.next) {
+ if (brush_iter->toggle_brush == brush) {
+ brush_iter->toggle_brush = NULL;
+ }
+ }
+ }
+
static void extern_local_brush(Brush *brush)
{
id_lib_extern((ID *)brush->mtex.tex);
diff --cc source/blender/editors/space_outliner/outliner_tools.c
index 7758f2f,253430a..b442f7c
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@@ -218,8 -215,9 +218,9 @@@ static void unlink_texture_cb(bContext
}
}

- static void unlink_group_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
+ static void unlink_group_cb(
+ bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *tsep, TreeStoreElem *tselem)
++ TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
Bastien Montagne
9 years ago
Permalink
Commit: 0c8b1a8c3721bd348e5b2b5c755b76b22bef1eb9
Author: Bastien Montagne
Date: Fri Nov 6 12:35:45 2015 +0100
Branches: id-remap
https://developer.blender.org/rB0c8b1a8c3721bd348e5b2b5c755b76b22bef1eb9

Merge branch 'master' into id-remap

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



===================================================================
Bastien Montagne
9 years ago
Permalink
Commit: f0c6c85788ac7ba9f8edef0b7d331c72965ab004
Author: Bastien Montagne
Date: Fri Nov 6 18:00:09 2015 +0100
Branches: id-remap
https://developer.blender.org/rBf0c6c85788ac7ba9f8edef0b7d331c72965ab004

Attempt to fix the 'user_one' mess...

Seems to work (though will need much more tests), but makes code more ugly. :|

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

M source/blender/blenkernel/BKE_library.h
M source/blender/blenkernel/BKE_screen.h
M source/blender/blenkernel/intern/library.c
M source/blender/blenkernel/intern/screen.c
M source/blender/editors/include/ED_util.h
M source/blender/editors/space_buttons/space_buttons.c
M source/blender/editors/space_clip/space_clip.c
M source/blender/editors/space_image/space_image.c
M source/blender/editors/space_logic/space_logic.c
M source/blender/editors/space_node/space_node.c
M source/blender/editors/space_outliner/space_outliner.c
M source/blender/editors/space_sequencer/space_sequencer.c
M source/blender/editors/space_text/space_text.c
M source/blender/editors/space_view3d/space_view3d.c
M source/blender/editors/util/ed_util.c
M source/blender/windowmanager/WM_api.h
M source/blender/windowmanager/intern/wm_event_system.c

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

diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 090145d..770010d 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -127,7 +127,7 @@ struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_

void BKE_library_callback_free_window_manager_set(void (*func)(struct bContext *, struct wmWindowManager *));
void BKE_library_callback_free_notifier_reference_set(void (*func)(const void *));
-void BKE_library_callback_remap_editor_id_reference_set(void (*func)(struct ID *, struct ID *));
+void BKE_library_callback_remap_editor_id_reference_set(bool (*func)(struct ID *, struct ID *));

/* use when "" is given to new_id() */
#define ID_FALLBACK_NAME N_("Untitled")
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index d74a61c..e89888c 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -99,7 +99,7 @@ typedef struct SpaceType {
int (*context)(const struct bContext *, const char *, struct bContextDataResult *);

/* Used when we want to replace an ID by another (or NULL). */
- void (*id_remap)(struct ScrArea *, struct SpaceLink *, struct ID *, struct ID *);
+ bool (*id_remap)(struct ScrArea *, struct SpaceLink *, struct ID *, struct ID *);

/* region type definitions */
ListBase regiontypes;
@@ -276,7 +276,7 @@ void BKE_spacedata_freelist(ListBase *lb);
void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2);
void BKE_spacedata_draw_locks(int set);

-void BKE_spacedata_callback_id_remap_set(void (*func)(struct ScrArea *, struct SpaceLink *, struct ID *, struct ID *));
+void BKE_spacedata_callback_id_remap_set(bool (*func)(struct ScrArea *, struct SpaceLink *, struct ID *, struct ID *));
void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID *id);

/* area/regions */
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 4de1909..e4b2459 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -982,9 +982,9 @@ void BKE_library_callback_free_notifier_reference_set(void (*func)(const void *)
free_notifier_reference_cb = func;
}

-static void (*remap_editor_id_reference_cb)(ID *, ID *) = NULL;
+static bool (*remap_editor_id_reference_cb)(ID *, ID *) = NULL;

-void BKE_library_callback_remap_editor_id_reference_set(void (*func)(ID *, ID *))
+void BKE_library_callback_remap_editor_id_reference_set(bool (*func)(ID *, ID *))
{
remap_editor_id_reference_cb = func;
}
@@ -994,10 +994,11 @@ typedef struct IDRemap {
ID *old_id;
ID *new_id;
ID *id; /* The ID in which we are replacing old_id by new_id usages. */
- /* XXX TODO: keeping this for now (also as debug data), in theory we can get rid of it. */
- int skipped_direct; /* Number of direct usecase that could not be remapped (e.g.: obdata when in edit mode). */
- int skipped_indirect; /* Number of indirect usecase that could not be remapped. */
int flag;
+
+ int skipped_direct; /* Number of direct usecases that could not be remapped (e.g.: obdata when in edit mode). */
+ int skipped_indirect; /* Number of indirect usecases that could not be remapped. */
+ int skipped_refcounted; /* Number of skipped usecases that refcount the datablock. */
} IDRemap;

enum {
@@ -1006,6 +1007,8 @@ enum {

/* Set by callback. */
ID_REMAP_IS_LINKED_DIRECT = 1 << 16, /* new_id is directly linked in current .blend. */
+ ID_REMAP_IS_USER_ONE = 1 << 17, /* old_id was used by some nasty 'user_one' stuff (like image editor). */
+ ID_REMAP_IS_USER_ONE_SKIPPED = 1 << 18, /* there was some skipped 'user_one' usages of old_id. */
};

static bool foreach_libblock_remap_callback(void *user_data, ID **id_p, int cb_flag)
@@ -1030,18 +1033,29 @@ static bool foreach_libblock_remap_callback(void *user_data, ID **id_p, int cb_f
const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id));
const bool is_indirect = (id->lib != NULL);
const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
+ const bool is_never_null = ((cb_flag & IDWALK_NEVER_NULL) && (new_id == NULL));

printf("\t\tIn %s (%p): remapping %s (%p) to %s (%p)\n",
id->name, id, old_id->name, old_id, new_id ? new_id->name : "", new_id);

/* Special hack in case it's Object->data and we are in edit mode (skipped_direct too). */
- if ((is_obj_editmode && (((Object *)id)->data == *id_p)) || (skip_indirect && (is_proxy || is_indirect))) {
- if (is_proxy || is_obj_editmode) {
+ if (is_never_null ||
+ (is_obj_editmode && (((Object *)id)->data == *id_p)) ||
+ (skip_indirect && (is_proxy || is_indirect)))
+ {
+ if (is_never_null || is_proxy || is_obj_editmode) {
id_remap_data->skipped_direct++;
}
else {
id_remap_data->skipped_indirect++;
}
+ if (cb_flag & IDWALK_USER) {
+ id_remap_data->skipped_refcounted++;
+ }
+ else if (cb_flag & IDWALK_USER_ONE) {
+ /* We cannot affect old_id->us directly, flag it as such for final handling... */
+ id_remap_data->flag |= ID_REMAP_IS_USER_ONE_SKIPPED;
+ }
}
else {
*id_p = new_id;
@@ -1050,6 +1064,11 @@ static bool foreach_libblock_remap_callback(void *user_data, ID **id_p, int cb_f
if (new_id)
new_id->us++;
}
+ else if (cb_flag & IDWALK_USER_ONE) {
+ id_us_ensure_real(new_id);
+ /* We cannot affect old_id->us directly, flag it as such for final handling... */
+ id_remap_data->flag |= ID_REMAP_IS_USER_ONE;
+ }
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;
@@ -1060,25 +1079,54 @@ 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)
+/**
+ * Execute the 'data' part of the remapping (that is, all ID pointers from other ID datablocks).
+ *
+ * Behavior differs depending on whether given \a id is NULL or not:
+ * - \a id NULL: \a old_id must be non-NULL, \a new_id may be NULL (unlinking \a old_id) or not
+ * (remapping \a old_id to \a new_id). The whole \a bmain database is checked, and all pointers to \a old_id
+ * are remapped to \a new_id.
+ * - \a id is non-NULL:
+ * + If \a old_id is NULL, \a new_id must also be NULL, and all ID pointers from \a id are cleared (i.e. \a id
+ * does not references any other datablock anymore).
+ * + If \a old_id is non-NULL, behavior is as with a NULL \a id, but only for given \a id.
+ *
+ * \param bmain the Main data storage to operate on (if \a id is NULL).
+ * \param id the datablock to operate on (may be NULL).
+ * \param old_id the datablock to dereference (may be NULL if \a id is non-NULL).
+ * \param new_id the new datablock to replace \a old_id references with (may be NULL).
+ * \param skip_indirect_usage if true, do not remap/unlink indirect usages of \a old_id datablock.
+ * \param r_skipped_direct if non-NULL, the number of direct references that could not be replaced.
+ * \param r_skipped_indirect if non-NULL, the number of indirect references that could not be replaced.
+ * \param r_skipped_refcounted if non-NULL, the number of refcounted references that could not be replaced.
+ * \return true is there was some 'user_one' users of \a old_id (needed to handle correctly #old_id->us count).
+ */
+static bool libblock_remap_data(
+ Main *bmain, ID *id, ID *old_id, ID *new_id, const bool skip_indirect_usage, IDRemap *r_id_remap_data)
{
- IDRemap id_remap_data = {bmain, old_id, new_id, NULL};
+ IDRemap id_remap_data;
ListBase *lb_array[MAX_LIBARRAY];
int i;

+ if (r_id_remap_data == NULL) {
+ r_id_remap_data = &id_remap_data;
+ }
+ r_id_remap_data->bmain = bmain;
+ r_id_remap_data->old_id = old_id;
+ r_id_remap_data->new_id = new_id;
+ r_id_remap_data->id = NULL;
+ r_id_remap_data->flag = skip_indirect_usage ? ID_REMAP_SKIP_INDIRECT_USAGE : 0;
+ r_id_remap_data->skipped_direct = 0;
+ r_id_remap_data->skipped_indirect = 0;
+ r_id_remap_data->skipped_refcounted = 0;
+
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);
+ r_id_remap_data->id = id;
+ BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
}
else {
i = set_listbasepointers(bmain, lb_array);
@@ -1094,38 +1142,37 @@ static void libblock_remap_do(
* 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);
+ r_id_remap_data->id = id;
+ BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
}
}
}

if (old_id && (old_id->flag & LIB_FAKEUSER)) {
- id_remap_data.skipped_direct++;
+ r_id_remap_data->skipped_direct++;
+ r_id_remap_data->skipped_refcounted++;
}

- if (new_id && (new_id->flag & LIB_INDIRECT) && (id_remap_data.flag & ID_REMAP_IS_LINKED_DIRECT)) {
+ if (new_id && (new_id->flag & LIB_INDIRECT) && (r_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", __

@@ Diff output truncated at 10240 characters. @@
Bastien Montagne
9 years ago
Permalink
Commit: 8b6928b2fb40bec3f68ed59336c2174c22e25b95
Author: Bastien Montagne
Date: Sat Nov 7 10:54:48 2015 +0100
Branches: id-remap
https://developer.blender.org/rB8b6928b2fb40bec3f68ed59336c2174c22e25b95

Merge branch 'master' into id-remap

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



===================================================================
Bastien Montagne
9 years ago
Permalink
Commit: 7f53cbb556af8d1ee8cc521a5b2c2ce1bf98e5ad
Author: Bastien Montagne
Date: Sat Nov 7 11:31:28 2015 +0100
Branches: id-remap
https://developer.blender.org/rB7f53cbb556af8d1ee8cc521a5b2c2ce1bf98e5ad

Cleanup: get rid of bmain in foreach ID callback.

messing with depsgraph here is not a good idea I think... and makes things simpler!

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

M source/blender/blenkernel/BKE_library.h
M source/blender/blenkernel/intern/library.c
M source/blender/editors/render/render_preview.c

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

diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 770010d..c5b836f 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -66,7 +66,7 @@ void BKE_libblock_remap(

void BKE_libblock_unlink(struct Main *bmain, void *idv) ATTR_NONNULL();

-void BKE_libblock_relink_ex(struct Main *bmain, void *idv, void *old_idv, void *new_idv) ATTR_NONNULL(1, 2);
+void BKE_libblock_relink_ex(void *idv, void *old_idv, void *new_idv) ATTR_NONNULL(1);

void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id);
void id_lib_extern(struct ID *id);
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index e4b2459..203d92e 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -990,7 +990,6 @@ void BKE_library_callback_remap_editor_id_reference_set(bool (*func)(ID *, ID *)
}

typedef struct IDRemap {
- Main *bmain;
ID *old_id;
ID *new_id;
ID *id; /* The ID in which we are replacing old_id by new_id usages. */
@@ -1014,7 +1013,6 @@ enum {
static bool foreach_libblock_remap_callback(void *user_data, ID **id_p, int cb_flag)
{
IDRemap *id_remap_data = user_data;
- Main *bmain = id_remap_data->bmain;
ID *old_id = id_remap_data->old_id;
ID *new_id = id_remap_data->new_id;
ID *id = id_remap_data->id;
@@ -1069,7 +1067,6 @@ static bool foreach_libblock_remap_callback(void *user_data, ID **id_p, int cb_f
/* We cannot affect old_id->us directly, flag it as such for final handling... */
id_remap_data->flag |= ID_REMAP_IS_USER_ONE;
}
- 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;
}
@@ -1091,14 +1088,12 @@ static bool foreach_libblock_remap_callback(void *user_data, ID **id_p, int cb_f
* does not references any other datablock anymore).
* + If \a old_id is non-NULL, behavior is as with a NULL \a id, but only for given \a id.
*
- * \param bmain the Main data storage to operate on (if \a id is NULL).
- * \param id the datablock to operate on (may be NULL).
+ * \param bmain the Main data storage to operate on (can be NULL if \a id is non-NULL).
+ * \param id the datablock to operate on (can be NULL if \a bmain is non-NULL).
* \param old_id the datablock to dereference (may be NULL if \a id is non-NULL).
* \param new_id the new datablock to replace \a old_id references with (may be NULL).
* \param skip_indirect_usage if true, do not remap/unlink indirect usages of \a old_id datablock.
- * \param r_skipped_direct if non-NULL, the number of direct references that could not be replaced.
- * \param r_skipped_indirect if non-NULL, the number of indirect references that could not be replaced.
- * \param r_skipped_refcounted if non-NULL, the number of refcounted references that could not be replaced.
+ * \param r_id_remap_data if non-NULL, the IDRemap struct to use (uselful to retrieve info about remapping process).
* \return true is there was some 'user_one' users of \a old_id (needed to handle correctly #old_id->us count).
*/
static bool libblock_remap_data(
@@ -1111,7 +1106,6 @@ static bool libblock_remap_data(
if (r_id_remap_data == NULL) {
r_id_remap_data = &id_remap_data;
}
- r_id_remap_data->bmain = bmain;
r_id_remap_data->old_id = old_id;
r_id_remap_data->new_id = new_id;
r_id_remap_data->id = NULL;
@@ -1293,7 +1287,7 @@ void BKE_libblock_unlink(Main *bmain, void *idv)
* BKE_id_remap maybe?
* ... sigh
*/
-void BKE_libblock_relink_ex(Main *bmain, void *idv, void *old_idv, void *new_idv)
+void BKE_libblock_relink_ex(void *idv, void *old_idv, void *new_idv)
{
ID *id = idv;
ID *old_id = old_idv;
@@ -1310,7 +1304,7 @@ void BKE_libblock_relink_ex(Main *bmain, void *idv, void *old_idv, void *new_idv
BLI_assert(new_id == NULL);
}

- libblock_remap_data(bmain, id, old_id, new_id, false, NULL);
+ libblock_remap_data(NULL, id, old_id, new_id, false, NULL);
}

static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata)
@@ -1363,15 +1357,8 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, bool do_id_user)
BPY_id_release(id);
#endif

- /* XXX This breaks the nodetree case, which are supposed to be 'owned' by their material/texture/scene/whatever.
- * Quite odd, but...
- * One solution would be to call this **after** calling BKE_xxx_free(), but here again nodetree are a PITA,
- * since ntreeFreeTree() may free datablock itself. AAARRRRRRRRGGGGGGGG! >:(
- * Or maybe we should not take into account in foreach_id code? Since it's private data...
- * This has to be fixed one way or another!
- */
if (do_id_user) {
- BKE_libblock_relink_ex(bmain, id, NULL, NULL);
+ BKE_libblock_relink_ex(id, NULL, NULL);
}

switch (type) {
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 8931192..3d2fa70 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -861,7 +861,7 @@ static void shader_preview_free(void *customdata)
/* get rid of copied world */
BLI_remlink(&pr_main->world, sp->worldcopy);
/* T32865 - we need to unlink the texture copies, unlike for materials */
- BKE_libblock_relink_ex(pr_main, sp->worldcopy, NULL, NULL);
+ BKE_libblock_relink_ex(sp->worldcopy, NULL, NULL);
BKE_world_free(sp->worldcopy);

properties = IDP_GetProperties((ID *)sp->worldcopy, false);
@@ -878,7 +878,7 @@ static void shader_preview_free(void *customdata)

/* get rid of copied lamp */
BLI_remlink(&pr_main->lamp, sp->lampcopy);
- BKE_libblock_relink_ex(pr_main, sp->lampcopy, NULL, NULL);
+ BKE_libblock_relink_ex(sp->lampcopy, NULL, NULL);
BKE_lamp_free(sp->lampcopy);

properties = IDP_GetProperties((ID *)sp->lampcopy, false);
Bastien Montagne
9 years ago
Permalink
Commit: e43d70a60fdcf04d60b01a42c0e3984ad35eed8d
Author: Bastien Montagne
Date: Sun Nov 8 17:59:08 2015 +0100
Branches: id-remap
https://developer.blender.org/rBe43d70a60fdcf04d60b01a42c0e3984ad35eed8d

Merge branch 'master' into id-remap

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



===================================================================
Bastien Montagne
9 years ago
Permalink
Commit: 033a89957c60fe27791b02b4203225bb1aaabb3d
Author: Bastien Montagne
Date: Tue Nov 10 12:45:42 2015 +0100
Branches: id-remap
https://developer.blender.org/rB033a89957c60fe27791b02b4203225bb1aaabb3d

Merge branch 'master' into id-remap

Conflicts:
source/blender/blenkernel/intern/curve.c
source/blender/blenkernel/intern/linestyle.c
source/blender/blenkernel/intern/material.c
source/blender/blenkernel/intern/mball.c
source/blender/blenkernel/intern/mesh.c
source/blender/blenkernel/intern/object.c
source/blender/blenkernel/intern/particle.c
source/blender/blenkernel/intern/scene.c
source/blender/blenkernel/intern/world.c

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



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

diff --cc source/blender/blenkernel/intern/brush.c
index f1a729d,92ab4d7..225842e
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@@ -133,10 -133,10 +133,10 @@@ static void brush_defaults(Brush *brush

void BKE_brush_init(Brush *brush)
{
- BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(brush, id));
+ BLI_assert(MEMCMP_NULL_STRUCT_OFS(brush, id));

/* enable fake user by default */
- brush->id.flag |= LIB_FAKEUSER;
+ id_fake_user_set(&brush->id);

brush_defaults(brush);

diff --cc source/blender/makesrna/intern/rna_ID.c
index fdd957c,e1e892a..13feddf
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@@ -329,17 -327,10 +327,17 @@@ static void rna_ID_update_tag(ID *id, R

static void rna_ID_user_clear(ID *id)
{
+ id_fake_user_clear(id);
id->us = 0; /* don't save */
- id->flag &= ~LIB_FAKEUSER;
}

+static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id)
+{
+ if (GS(id->name) == GS(new_id->name)) {
+ BKE_libblock_remap(bmain, id, new_id, true); /* Now, do not allow remapping data in linked data from here... */
+ }
+}
+
static AnimData * rna_ID_animation_data_create(ID *id, Main *bmain)
{
AnimData *adt = BKE_animdata_add_id(id);
Bastien Montagne
9 years ago
Permalink
Commit: 959e2e8cfe0151610769cef3d648e40bcf113a29
Author: Bastien Montagne
Date: Tue Nov 10 14:51:42 2015 +0100
Branches: id-remap
https://developer.blender.org/rB959e2e8cfe0151610769cef3d648e40bcf113a29

Merge branch 'master' into id-remap

Conflicts:
source/blender/blenkernel/intern/library.c

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



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

diff --cc source/blender/blenkernel/intern/library.c
index 1a997a3,b76323b..f7a06ca
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@@ -1507,14 -1214,14 +1507,10 @@@ void BKE_libblock_free_us(Main *bmain,
{
ID *id = idv;

- id->us--;
+ id_us_min(id);

- if (id->us < 0) {
- printf("ERROR block %s (from %s lib): %d users\n", id->name, id->lib ? id->lib->name : "<MAIN>", id->us);
- id->us = 0;
- }
if (id->us == 0) {
- switch (GS(id->name)) {
- case ID_OB:
- BKE_object_unlink(bmain, (Object *)id);
- break;
- }
+ BKE_libblock_unlink(bmain, id);

BKE_libblock_free(bmain, id);
}
Bastien Montagne
9 years ago
Permalink
Commit: 9ddc60bc10c64ae8b36ab39dbe813e21df5960dc
Author: Bastien Montagne
Date: Tue Nov 10 16:21:37 2015 +0100
Branches: id-remap
https://developer.blender.org/rB9ddc60bc10c64ae8b36ab39dbe813e21df5960dc

Merge branch 'master' into id-remap

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



===================================================================
Bastien Montagne
9 years ago
Permalink
Commit: 5f0299898dd7556553bb5be0f2c2279b71cdef86
Author: Bastien Montagne
Date: Tue Nov 10 16:56:54 2015 +0100
Branches: id-remap
https://developer.blender.org/rB5f0299898dd7556553bb5be0f2c2279b71cdef86

Hopefully fix the 'real user' nightmare.

Idea is to add two new flags, one saying 'we need to ensure a real user exists',
the other 'we had to increment user count to ensure we have a real user'.

This allows us to easily control the extra user in release/delete/remap cases,
and also fixes the infamous 'add new image to texture, open image in ImageEditor,
delete image from texture, have a zero-user red image in Image Editor' issue.

There is still much to be done here, more places where we can use those flags,
also clear them when we force usercount to zero, etc.

All this allows us to fix unsolvable issues (like Group being ensure_user'ed
in loading code, but only if they do have objects in them), and to avoid returning
ugly bool from editors' callbacks (this is still to be cleaned up in the branch too).

Bad news - this means we cannot use short ID->flag anymore (not enough flags), for now
added a new int ID->flag2 (replacing pad int), not sure how to best manage change here,
maybe for 2.8 we can totally wipe ID->flag? But this would totally break forward compat.

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

M source/blender/blenkernel/intern/library.c
M source/blender/blenloader/intern/readfile.c
M source/blender/makesdna/DNA_ID.h

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

diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index ce78084..846add2 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -164,12 +164,14 @@ void id_us_ensure_real(ID *id)
{
if (id) {
const int limit = ID_FAKE_USERS(id);
+ id->flag2 |= LIB_EXTRAUSER;
if (id->us <= limit) {
- if (id->us < limit) {
+ if (id->us < limit || ((id->us == limit) && (id->flag2 & LIB_EXTRAUSER_SET))) {
printf("ID user count error: %s (from '%s')\n", id->name, id->lib ? id->lib->filepath : "[Main]");
BLI_assert(0);
}
id->us = limit + 1;
+ id->flag2 |= LIB_EXTRAUSER_SET;
}
}
}
@@ -190,7 +192,13 @@ void id_us_plus(ID *id)
void id_us_min(ID *id)
{
if (id) {
- const int limit = ID_FAKE_USERS(id);
+ const int limit = ID_FAKE_USERS(id);
+
+ if ((id->us == limit) && (id->flag2 & LIB_EXTRAUSER) && !(id->flag2 & LIB_EXTRAUSER_SET)) {
+ /* We need an extra user here, but never actually incremented user count for it so far, do it now. */
+ id_us_ensure_real(id);
+ }
+
if (id->us <= limit) {
printf("ID user decrement error: %s (from '%s')\n", id->name, id->lib ? id->lib->filepath : "[Main]");
BLI_assert(0);
@@ -1028,8 +1036,7 @@ enum {

/* Set by callback. */
ID_REMAP_IS_LINKED_DIRECT = 1 << 16, /* new_id is directly linked in current .blend. */
- ID_REMAP_IS_USER_ONE = 1 << 17, /* old_id was used by some nasty 'user_one' stuff (like image editor). */
- ID_REMAP_IS_USER_ONE_SKIPPED = 1 << 18, /* there was some skipped 'user_one' usages of old_id. */
+ ID_REMAP_IS_USER_ONE_SKIPPED = 1 << 17, /* there was some skipped 'user_one' usages of old_id. */
};

static bool foreach_libblock_remap_callback(void *user_data, ID **id_p, int cb_flag)
@@ -1081,12 +1088,14 @@ static bool foreach_libblock_remap_callback(void *user_data, ID **id_p, int cb_f
*id_p = new_id;
if (cb_flag & IDWALK_USER) {
id_us_min(old_id);
- id_us_plus(new_id); /* XXX Check, do we really want to handle LIB_INDIRECT/LIB_EXTERN here? */
+ /* We do not want to handle LIB_INDIRECT/LIB_EXTERN here. */
+ if (new_id)
+ new_id->us++;
}
else if (cb_flag & IDWALK_USER_ONE) {
id_us_ensure_real(new_id);
- /* We cannot affect old_id->us directly, flag it as such for final handling... */
- id_remap_data->flag |= ID_REMAP_IS_USER_ONE;
+ /* We cannot affect old_id->us directly, LIB_EXTRAUSER(_SET) are assumed to be set as needed,
+ * that extra user is processed in final handling... */
}
if (!is_indirect) {
id_remap_data->flag |= ID_REMAP_IS_LINKED_DIRECT;
@@ -1117,7 +1126,7 @@ static bool foreach_libblock_remap_callback(void *user_data, ID **id_p, int cb_f
* \param r_id_remap_data if non-NULL, the IDRemap struct to use (uselful to retrieve info about remapping process).
* \return true is there was some 'user_one' users of \a old_id (needed to handle correctly #old_id->us count).
*/
-static bool libblock_remap_data(
+static void libblock_remap_data(
Main *bmain, ID *id, ID *old_id, ID *new_id, const bool skip_indirect_usage, IDRemap *r_id_remap_data)
{
IDRemap id_remap_data;
@@ -1163,9 +1172,11 @@ static bool libblock_remap_data(
}
}

+ /* XXX We may not want to always 'transfer' fakeuser from old to new id... Think for now it's desired behavior
+ * though, we can always add an option (flag) to control this later if needed. */
if (old_id && (old_id->flag & LIB_FAKEUSER)) {
- r_id_remap_data->skipped_direct++;
- r_id_remap_data->skipped_refcounted++;
+ id_fake_user_clear(old_id);
+ id_fake_user_set(new_id);
}

if (new_id && (new_id->flag & LIB_INDIRECT) && (r_id_remap_data->flag & ID_REMAP_IS_LINKED_DIRECT)) {
@@ -1176,8 +1187,6 @@ static bool libblock_remap_data(
printf("%s: %d occurences skipped (%d direct and %d indirect ones)\n", __func__,
r_id_remap_data->skipped_direct + r_id_remap_data->skipped_indirect,
r_id_remap_data->skipped_direct, r_id_remap_data->skipped_indirect);
-
- return (r_id_remap_data->flag & ID_REMAP_IS_USER_ONE) != 0;
}

/** 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). */
@@ -1187,7 +1196,6 @@ void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const
ID *old_id = old_idv;
ID *new_id = new_idv;
int skipped_direct, skipped_refcounted;
- bool is_user_one;

BLI_assert(old_id != NULL);
BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
@@ -1214,7 +1222,7 @@ void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const
}
}

- is_user_one = libblock_remap_data(bmain, NULL, old_id, new_id, skip_indirect_usage, &id_remap_data);
+ libblock_remap_data(bmain, NULL, old_id, new_id, skip_indirect_usage, &id_remap_data);

if (free_notifier_reference_cb) {
free_notifier_reference_cb(old_id);
@@ -1223,21 +1231,23 @@ void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const
/* We assume editors do not hold references to their IDs... This is false in some cases
* (Image is especially tricky here), editors' code is to handle refcount (id->us) itself then. */
if (remap_editor_id_reference_cb) {
- is_user_one = is_user_one || remap_editor_id_reference_cb(old_id, new_id);
+ remap_editor_id_reference_cb(old_id, new_id);
}

skipped_direct = id_remap_data.skipped_direct;
skipped_refcounted = id_remap_data.skipped_refcounted;

- BLI_assert(old_id->us - skipped_refcounted >= 0);
-
- /* If old_id was used by some ugly 'user_one' stuff (like Image or Clip editors...), we have the right to
- * decrease once more its user count... unless we had to skip some 'user_one' cases. I hate that stuff!!! */
- if (is_user_one && !(id_remap_data.flag & ID_REMAP_IS_USER_ONE_SKIPPED) && (old_id->us - skipped_refcounted > 0)) {
- BLI_assert(old_id->us - skipped_refcounted == 1);
+ /* If old_id was used by some ugly 'user_one' stuff (like Image or Clip editors...), and user count has actually
+ * been incremented for that, we have to decrease once more its user count... unless we had to skip
+ * some 'user_one' cases. */
+ if ((old_id->flag2 & LIB_EXTRAUSER_SET) && !(id_remap_data.flag & ID_REMAP_IS_USER_ONE_SKIPPED)) {
id_us_min(old_id);
+ old_id->flag2 &= ~LIB_EXTRAUSER_SET;
}

+ BLI_assert(old_id->us - skipped_refcounted >= 0);
+ UNUSED_VARS_NDEBUG(skipped_refcounted);
+
if (skipped_direct == 0) {
/* old_id is assumed to not be used directly anymore... */
if (old_id->lib && (old_id->flag & LIB_EXTERN)) {
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 209159f..6996133 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -7927,6 +7927,8 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID

/* clear first 8 bits */
id->flag = (id->flag & 0xFF00) | flag | LIB_NEED_LINK;
+ /* clear first 16 bits */
+ id->flag2 = (id->flag2 & 0xFFFF0000);
id->lib = main->curlib;
id->us = (id->flag & LIB_FAKEUSER) ? 1 : 0;
id->icon_id = 0;
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 1d140f9..de15219 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -127,8 +127,9 @@ typedef struct ID {
* to.
*/
short flag;
+ int flag2;
int us;
- int icon_id, pad2;
+ int icon_id;
IDProperty *properties;
} ID;

@@ -299,6 +300,14 @@ enum {
LIB_ID_RECALC_ALL = (LIB_ID_RECALC | LIB_ID_RECALC_DATA),
};

+/* id->flag2: set first 16 bits always at zero while reading */
+enum {
+ /* tag datablock has having an extra user. */
+ LIB_EXTRAUSER = 1 << 0,
+ /* tag datablock has having actually increased usercount for the extra virtual user. */
+ LIB_EXTRAUSER_SET = 1 << 1,
+};
+
/* To filter ID types (filter_id) */
/* XXX We cannot put all needed IDs inside an enum...
* We'll have to see whether we can fit all needed ones inside 32 values,
Bastien Montagne
9 years ago
Permalink
Commit: d2913c14092525b889e02c02c9f329aa2a84f33e
Author: Bastien Montagne
Date: Tue Nov 10 19:59:44 2015 +0100
Branches: id-remap
https://developer.blender.org/rBd2913c14092525b889e02c02c9f329aa2a84f33e

Merge branch 'master' into id-remap

Conflicts:
source/blender/blenkernel/intern/object.c

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



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

diff --cc source/blender/blenkernel/intern/object.c
index cc081b1,b305387..b2b56e6
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@@ -383,30 -383,60 +383,29 @@@ void BKE_object_free_caches(Object *obj
}
}

-/* do not free object itself */
-void BKE_object_free_ex(Object *ob, bool do_id_user)
+/** Free (or release) any data used by this object (does not free the object itself). */
+void BKE_object_free(Object *ob)
{
- int a;
-
+ BKE_animdata_free((ID *)ob);
+
+ BKE_object_free_modifiers(ob);
-
- /* disconnect specific data, but not for lib data (might be indirect data, can get relinked) */
- if (ob->data) {
- ID *id = ob->data;
- id_us_min(id);
- if (id->us == 0 && id->lib == NULL) {
- switch (ob->type) {
- case OB_MESH:
- BKE_mesh_unlink((Mesh *)id);
- break;
- case OB_CURVE:
- BKE_curve_unlink((Curve *)id);
- break;
- case OB_MBALL:
- BKE_mball_unlink((MetaBall *)id);
- break;
- }
- }
- ob->data = NULL;
- }
+
- if (ob->mat) {
- for (a = 0; a < ob->totcol; a++) {
- if (ob->mat[a])
- id_us_min(&ob->mat[a]->id);
- }
- MEM_freeN(ob->mat);
+ MEM_SAFE_FREE(ob->mat);
+ MEM_SAFE_FREE(ob->matbits);
+ MEM_SAFE_FREE(ob->iuser);
+ MEM_SAFE_FREE(ob->bb);
+
+ BLI_freelistN(&ob->defbase);
+ if (ob->pose) {
+ BKE_pose_free_ex(ob->pose, false);
+ ob->pose = NULL;
}
- if (ob->matbits) MEM_freeN(ob->matbits);
- ob->mat = NULL;
- ob->matbits = NULL;
- if (ob->iuser) MEM_freeN(ob->iuser);
- ob->iuser = NULL;
- if (ob->bb) MEM_freeN(ob->bb);
- ob->bb = NULL;
- if (ob->adt) BKE_animdata_free((ID *)ob);
- if (ob->poselib)
- id_us_min(&ob->poselib->id);
- if (ob->gpd)
- id_us_min(&ob->gpd->id);
- if (ob->defbase.first)
- BLI_freelistN(&ob->defbase);
- if (ob->pose)
- BKE_pose_free_ex(ob->pose, do_id_user);
- if (ob->mpath)
+ if (ob->mpath) {
animviz_free_motionpath(ob->mpath);
+ ob->mpath = NULL;
+ }
BKE_bproperty_free_list(&ob->prop);
- BKE_object_free_modifiers(ob);
-
- BKE_object_free_derived_caches(ob);
-
+
free_sensors(&ob->sensors);
free_controllers(&ob->controllers);
free_actuators(&ob->actuators);
diff --cc source/blender/blenloader/intern/readfile.c
index 6996133,1108a75..77862e1
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@@ -7927,10 -7927,8 +7927,10 @@@ static BHead *read_libblock(FileData *f

/* clear first 8 bits */
id->flag = (id->flag & 0xFF00) | flag | LIB_NEED_LINK;
+ /* clear first 16 bits */
+ id->flag2 = (id->flag2 & 0xFFFF0000);
id->lib = main->curlib;
- id->us = (id->flag & LIB_FAKEUSER) ? 1 : 0;
+ id->us = ID_FAKE_USERS(id);
id->icon_id = 0;
id->flag &= ~(LIB_ID_RECALC | LIB_ID_RECALC_DATA | LIB_DOIT | LIB_MISSING);
Bastien Montagne
9 years ago
Permalink
Commit: 7a62ac4127ea88a4d89c21135d7ce0a67ff5cfc7
Author: Bastien Montagne
Date: Tue Nov 10 20:15:01 2015 +0100
Branches: id-remap
https://developer.blender.org/rB7a62ac4127ea88a4d89c21135d7ce0a67ff5cfc7

Some minor tweaks.

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

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

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

diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 846add2..8f3a6f7 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -160,6 +160,10 @@ void id_lib_extern(ID *id)
}

/* ensure we have a real user */
+/* Note: Now that we have flags, we could get rid of the 'fake_user' special case, flags are enough to ensure
+ * we always have a real user.
+ * However, ID_REAL_USERS is used in several places outside of core library.c, so think we can wait later
+ * to make this change... */
void id_us_ensure_real(ID *id)
{
if (id) {
@@ -1080,7 +1084,7 @@ static bool foreach_libblock_remap_callback(void *user_data, ID **id_p, int cb_f
id_remap_data->skipped_refcounted++;
}
else if (cb_flag & IDWALK_USER_ONE) {
- /* We cannot affect old_id->us directly, flag it as such for final handling... */
+ /* No need to count number of times this happens, just a flag is enough. */
id_remap_data->flag |= ID_REMAP_IS_USER_ONE_SKIPPED;
}
}
@@ -1203,25 +1207,6 @@ void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const

printf("%s: %s (%p) replaced by %s (%p)\n", __func__, old_id->name, old_id, new_id ? new_id->name : "", new_id);

- /* Some pre-processing.
- * This is a bit ugly, but cannot see a way to avoid it...
- */
- if ((GS(old_id->name) == ID_OB) && (new_id == NULL)) {
- Object *old_ob = (Object *)old_id;
- Scene *sce;
- Base *base;
-
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- base = BKE_scene_base_find(sce, old_ob);
-
- if (base) {
- BKE_scene_base_unlink(sce, base);
- id_us_min(&base->object->id);
- MEM_freeN(base);
- }
- }
- }
-
libblock_remap_data(bmain, NULL, old_id, new_id, skip_indirect_usage, &id_remap_data);

if (free_notifier_reference_cb) {
@@ -1263,6 +1248,20 @@ void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const
Object *old_ob = (Object *)old_id;
Object *new_ob = (Object *)new_id;

+ if (new_ob == NULL) {
+ Scene *sce;
+ Base *base;
+
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
+ base = BKE_scene_base_find(sce, old_ob);
+
+ if (base) {
+ BKE_scene_base_unlink(sce, base);
+ MEM_freeN(base);
+ }
+ }
+ }
+
if (old_ob->flag & OB_FROMGROUP) {
/* Note that for Scene's BaseObject->flag, either we:
* - unlinked old_ob (i.e. new_ob is NULL), in which case scenes' bases have been removed already.
Bastien Montagne
9 years ago
Permalink
Commit: 9e6cdd8e3a0e3c6df6b89b3a9ffff05c6f97234a
Author: Bastien Montagne
Date: Tue Nov 10 20:52:58 2015 +0100
Branches: id-remap
https://developer.blender.org/rB9e6cdd8e3a0e3c6df6b89b3a9ffff05c6f97234a

Merge branch 'master' into id-remap

Conflicts:
source/blender/blenkernel/BKE_library.h
source/blender/blenkernel/intern/library.c

Also clears now useless 'bool is_user_one' flag from editors' ID remap callback.

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



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

diff --cc source/blender/blenkernel/BKE_library.h
index e3764d3,9a961ba..5b8f741
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@@ -127,9 -118,13 +127,13 @@@ void BKE_library_make_local(struct Mai
struct ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();

- void BKE_library_callback_free_window_manager_set(void (*func)(struct bContext *, struct wmWindowManager *));
- void BKE_library_callback_free_notifier_reference_set(void (*func)(const void *));
- void BKE_library_callback_remap_editor_id_reference_set(bool (*func)(struct ID *, struct ID *));
+ typedef void (*BKE_library_free_window_manager_cb)(struct bContext *, struct wmWindowManager *);
+ typedef void (*BKE_library_free_notifier_reference_cb)(const void *);
-typedef void (*BKE_library_free_editor_id_reference_cb)(const struct ID *);
++typedef void (*BKE_library_remap_editor_id_reference_cb)(struct ID *, struct ID *);
+
+ void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func);
+ void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func);
-void BKE_library_callback_free_editor_id_reference_set(BKE_library_free_editor_id_reference_cb func);
++void BKE_library_callback_remap_editor_id_reference_set(BKE_library_remap_editor_id_reference_cb func);

/* use when "" is given to new_id() */
#define ID_FALLBACK_NAME N_("Untitled")
diff --cc source/blender/blenkernel/BKE_screen.h
index e89888c,4861641..d74a61c
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@@ -98,9 -98,6 +98,9 @@@ typedef struct SpaceType
/* return context data */
int (*context)(const struct bContext *, const char *, struct bContextDataResult *);

+ /* Used when we want to replace an ID by another (or NULL). */
- bool (*id_remap)(struct ScrArea *, struct SpaceLink *, struct ID *, struct ID *);
++ void (*id_remap)(struct ScrArea *, struct SpaceLink *, struct ID *, struct ID *);
+
/* region type definitions */
ListBase regiontypes;

@@@ -276,8 -273,8 +276,8 @@@ void BKE_spacedata_freelist(ListBase *l
void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2);
void BKE_spacedata_draw_locks(int set);

- void BKE_spacedata_callback_id_remap_set(bool (*func)(struct ScrArea *, struct SpaceLink *, struct ID *, struct ID *));
-void BKE_spacedata_callback_id_unref_set(void (*func)(struct SpaceLink *sl, const struct ID *));
-void BKE_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id);
++void BKE_spacedata_callback_id_remap_set(void (*func)(struct ScrArea *, struct SpaceLink *, struct ID *, struct ID *));
+void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID *id);

/* area/regions */
struct ARegion *BKE_area_region_copy(struct SpaceType *st, struct ARegion *ar);
diff --cc source/blender/blenkernel/intern/library.c
index 8f3a6f7,e8f02ee..8df8c16
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@@ -1016,325 -1035,11 +1016,325 @@@ void BKE_library_callback_free_notifier
free_notifier_reference_cb = func;
}

- static bool (*remap_editor_id_reference_cb)(ID *, ID *) = NULL;
-static BKE_library_free_editor_id_reference_cb free_editor_id_reference_cb = NULL;
++static BKE_library_remap_editor_id_reference_cb remap_editor_id_reference_cb = NULL;
+
- void BKE_library_callback_remap_editor_id_reference_set(bool (*func)(ID *, ID *))
++void BKE_library_callback_remap_editor_id_reference_set(BKE_library_remap_editor_id_reference_cb func)
+{
+ remap_editor_id_reference_cb = func;
+}
+
+typedef struct IDRemap {
+ ID *old_id;
+ ID *new_id;
+ ID *id; /* The ID in which we are replacing old_id by new_id usages. */
+ int flag;
+
+ int skipped_direct; /* Number of direct usecases that could not be remapped (e.g.: obdata when in edit mode). */
+ int skipped_indirect; /* Number of indirect usecases that could not be remapped. */
+ int skipped_refcounted; /* Number of skipped usecases that refcount the datablock. */
+} IDRemap;
+
+enum {
+ /* Set by caller. */
+ ID_REMAP_SKIP_INDIRECT_USAGE = 1 << 0,
+
+ /* Set by callback. */
+ ID_REMAP_IS_LINKED_DIRECT = 1 << 16, /* new_id is directly linked in current .blend. */
+ ID_REMAP_IS_USER_ONE_SKIPPED = 1 << 17, /* there was some skipped 'user_one' usages of old_id. */
+};
+
+static bool foreach_libblock_remap_callback(void *user_data, ID **id_p, int cb_flag)
+{
+ IDRemap *id_remap_data = user_data;
+ ID *old_id = id_remap_data->old_id;
+ ID *new_id = id_remap_data->new_id;
+ ID *id = id_remap_data->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. */
+ const bool is_obj = (GS(id->name) == ID_OB);
+ const bool is_proxy = (is_obj && (((Object *)id)->proxy || ((Object *)id)->proxy_group));
+ const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id));
+ const bool is_indirect = (id->lib != NULL);
+ const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
+ const bool is_never_null = ((cb_flag & IDWALK_NEVER_NULL) && (new_id == NULL));
+
+ printf("\t\tIn %s (%p): remapping %s (%p) to %s (%p)\n",
+ id->name, id, old_id->name, old_id, new_id ? new_id->name : "", new_id);
+
+ /* Special hack in case it's Object->data and we are in edit mode (skipped_direct too). */
+ if (is_never_null ||
+ (is_obj_editmode && (((Object *)id)->data == *id_p)) ||
+ (skip_indirect && (is_proxy || is_indirect)))
+ {
+ if (is_never_null || is_proxy || is_obj_editmode) {
+ id_remap_data->skipped_direct++;
+ }
+ else {
+ id_remap_data->skipped_indirect++;
+ }
+ if (cb_flag & IDWALK_USER) {
+ id_remap_data->skipped_refcounted++;
+ }
+ else if (cb_flag & IDWALK_USER_ONE) {
+ /* No need to count number of times this happens, just a flag is enough. */
+ id_remap_data->flag |= ID_REMAP_IS_USER_ONE_SKIPPED;
+ }
+ }
+ else {
+ *id_p = new_id;
+ if (cb_flag & IDWALK_USER) {
+ id_us_min(old_id);
+ /* We do not want to handle LIB_INDIRECT/LIB_EXTERN here. */
+ if (new_id)
+ new_id->us++;
+ }
+ else if (cb_flag & IDWALK_USER_ONE) {
+ id_us_ensure_real(new_id);
+ /* We cannot affect old_id->us directly, LIB_EXTRAUSER(_SET) are assumed to be set as needed,
+ * that extra user is processed in final handling... */
+ }
+ if (!is_indirect) {
+ id_remap_data->flag |= ID_REMAP_IS_LINKED_DIRECT;
+ }
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Execute the 'data' part of the remapping (that is, all ID pointers from other ID datablocks).
+ *
+ * Behavior differs depending on whether given \a id is NULL or not:
+ * - \a id NULL: \a old_id must be non-NULL, \a new_id may be NULL (unlinking \a old_id) or not
+ * (remapping \a old_id to \a new_id). The whole \a bmain database is checked, and all pointers to \a old_id
+ * are remapped to \a new_id.
+ * - \a id is non-NULL:
+ * + If \a old_id is NULL, \a new_id must also be NULL, and all ID pointers from \a id are cleared (i.e. \a id
+ * does not references any other datablock anymore).
+ * + If \a old_id is non-NULL, behavior is as with a NULL \a id, but only for given \a id.
+ *
+ * \param bmain the Main data storage to operate on (can be NULL if \a id is non-NULL).
+ * \param id the datablock to operate on (can be NULL if \a bmain is non-NULL).
+ * \param old_id the datablock to dereference (may be NULL if \a id is non-NULL).
+ * \param new_id the new datablock to replace \a old_id references with (may be NULL).
+ * \param skip_indirect_usage if true, do not remap/unlink indirect usages of \a old_id datablock.
+ * \param r_id_remap_data if non-NULL, the IDRemap struct to use (uselful to retrieve info about remapping process).
+ * \return true is there was some 'user_one' users of \a old_id (needed to handle correctly #old_id->us count).
+ */
+static void libblock_remap_data(
+ Main *bmain, ID *id, ID *old_id, ID *new_id, const bool skip_indirect_usage, IDRemap *r_id_remap_data)
+{
+ IDRemap id_remap_data;
+ ListBase *lb_array[MAX_LIBARRAY];
+ int i;
+
+ if (r_id_remap_data == NULL) {
+ r_id_remap_data = &id_remap_data;
+ }
+ r_id_remap_data->old_id = old_id;
+ r_id_remap_data->new_id = new_id;
+ r_id_remap_data->id = NULL;
+ r_id_remap_data->flag = skip_indirect_usage ? ID_REMAP_SKIP_INDIRECT_USAGE : 0;
+ r_id_remap_data->skipped_direct = 0;
+ r_id_remap_data->skipped_indirect = 0;
+ r_id_remap_data->skipped_refcounted = 0;
+
+ 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 (id) {
+ printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib);
+ r_id_remap_data->id = id;
+ BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)r_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);
+ r_id_remap_data->id = id;
+ BKE_librar

@@ Diff output truncated at 10240 characters. @@
Bastien Montagne
9 years ago
Permalink
Commit: 12292d441d8ce083853799311ecdd15c52a64b84
Author: Bastien Montagne
Date: Wed Nov 11 11:49:33 2015 +0100
Branches: id-remap
https://developer.blender.org/rB12292d441d8ce083853799311ecdd15c52a64b84

Merge branch 'master' into id-remap

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



===================================================================
Bastien Montagne
9 years ago
Permalink
Commit: 73c8d3abccde14b23112168cfb59970fa55803e9
Author: Bastien Montagne
Date: Wed Nov 11 12:43:51 2015 +0100
Branches: id-remap
https://developer.blender.org/rB73c8d3abccde14b23112168cfb59970fa55803e9

Merge branch 'master' into id-remap

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



===================================================================
Bastien Montagne
9 years ago
Permalink
Commit: 75c5f6135cba93c34a91efc76f0cbd450d223e47
Author: Bastien Montagne
Date: Wed Nov 11 12:44:47 2015 +0100
Branches: id-remap
https://developer.blender.org/rB75c5f6135cba93c34a91efc76f0cbd450d223e47

Silence a bit debug prints!

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

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

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

diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 04d3b24..9f6f2d3 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -1169,7 +1169,7 @@ static void libblock_remap_data(
/* 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);
+// printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib);
r_id_remap_data->id = id;
BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
}

Loading...