[Bf-blender-cvs] [f4e7fec] id-remap: Merge branch 'master' into id-remap
Bastien Montagne
noreply at git.blender.org
Sun Dec 27 12:55:16 CET 2015
Commit: f4e7fec73c9349e5765f54a906aadb71f296c7ff
Author: Bastien Montagne
Date: Sun Dec 27 12:54:57 2015 +0100
Branches: id-remap
https://developer.blender.org/rBf4e7fec73c9349e5765f54a906aadb71f296c7ff
Merge branch 'master' into id-remap
Conflicts:
source/blender/blenloader/intern/readfile.c
source/blender/makesdna/DNA_ID.h
===================================================================
===================================================================
diff --cc source/blender/blenkernel/intern/library.c
index ba2a919,14e21a8..ca3da6a
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@@ -170,31 -166,16 +170,31 @@@ void id_us_ensure_real(ID *id
{
if (id) {
const int limit = ID_FAKE_USERS(id);
- id->flag2 |= LIB_EXTRAUSER;
++ id->tag |= LIB_TAG_EXTRAUSER;
if (id->us <= limit) {
- if (id->us < limit || ((id->us == limit) && (id->flag2 & LIB_EXTRAUSER_SET))) {
- if (id->us < limit) {
++ if (id->us < limit || ((id->us == limit) && (id->tag & LIB_TAG_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;
++ id->tag |= LIB_TAG_EXTRAUSER_SET;
}
}
}
+static void id_us_clear_real(ID *id)
+{
- if (id && (id->flag2 & LIB_EXTRAUSER)) {
- if (id->flag2 & LIB_EXTRAUSER_SET) {
++ if (id && (id->tag & LIB_TAG_EXTRAUSER)) {
++ if (id->tag & LIB_TAG_EXTRAUSER_SET) {
+ const int limit = ID_FAKE_USERS(id);
+ id->us--;
+ BLI_assert(id->us >= limit);
+ UNUSED_VARS_NDEBUG(limit);
+ }
- id->flag2 &= ~(LIB_EXTRAUSER | LIB_EXTRAUSER_SET);
++ id->tag &= ~(LIB_TAG_EXTRAUSER | LIB_TAG_EXTRAUSER_SET);
+ }
+}
+
void id_us_plus(ID *id)
{
if (id) {
@@@ -208,17 -189,12 +208,17 @@@
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)) {
++ if ((id->us == limit) && (id->tag & LIB_TAG_EXTRAUSER) && !(id->tag & LIB_TAG_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]");
- /* We cannot assert here, because of how we 'delete' datablocks currently (setting their usercount to zero),
- * this is weak but it's how it works for now. */
- /* BLI_assert(0); */
+ printf("ID user decrement error: %s (from '%s'): %d <= %d\n",
+ id->name, id->lib ? id->lib->filepath : "[Main]", id->us, limit);
+ BLI_assert(0);
id->us = limit;
}
else {
@@@ -1029,381 -1042,11 +1035,381 @@@ void BKE_library_callback_free_notifier
free_notifier_reference_cb = func;
}
-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(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. */
+ short flag;
+
+ /* 'Output' data. */
+ short status;
+ 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;
+
+/* IDRemap->flag enums defined in BKE_library.h */
+
+/* IDRemap->status */
+enum {
+ /* *** Set by callback. *** */
+ ID_REMAP_IS_LINKED_DIRECT = 1 << 0, /* new_id is directly linked in current .blend. */
+ ID_REMAP_IS_USER_ONE_SKIPPED = 1 << 1, /* 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,
++ /* Note: proxy usage implies LIB_TAG_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));
+ /* Note that indirect data from same file as processed ID is **not** considered indirect! */
+ const bool is_indirect = ((id->lib != NULL) && (id->lib != old_id->lib));
+ 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));
+ const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;
+
+ if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_NEVER_NULL)) {
- id->flag |= LIB_DOIT;
++ id->flag |= LIB_TAG_DOIT;
+ }
+
+// if (GS(old_id->name) == ID_TXT) {
+// printf("\t\t %s (from %s) (%d)\n", old_id->name, old_id->lib ? old_id->lib->filepath : "<MAIN>", old_id->us);
+// 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 : "<NONE>", new_id);
+// }
+
+ /* Special hack in case it's Object->data and we are in edit mode (skipped_direct too). */
+ if ((is_never_null && skip_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->status |= ID_REMAP_IS_USER_ONE_SKIPPED;
+ }
+ }
+ else {
+ if (!is_never_null) {
+ *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. */
++ /* We do not want to handle LIB_TAG_INDIRECT/LIB_TAG_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,
++ /* We cannot affect old_id->us directly, LIB_TAG_EXTRAUSER(_SET) are assumed to be set as needed,
+ * that extra user is processed in final handling... */
+ }
+ if (!is_indirect) {
+ id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
+ }
+ }
+ }
+
+ return true;
+}
-void BKE_library_callback_free_editor_id_reference_set(BKE_library_free_editor_id_reference_cb func)
+/**
+ * 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 short remap_flags, IDRemap *r_id_remap_data)
{
- free_editor_id_reference_cb = func;
+ 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 = remap_flags;
+ r_id_remap_data->status = 0;
+ r_id_remap_data->skipped_direct = 0;
+ r_id_remap_data->skipped_indirect = 0;
+ r_id_remap_data->skipped_refcounted = 0;
+
+// if (old_id && GS(old_id->name) == ID_AC)
+// 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_curr = lb_array[i]->first;
+
+ for (; id_curr; id_curr = id_curr->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
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list