Commit: ded1333f3cb711135de18ae7413b4d622e75a142
Author: Bastien Montagne
Date:   Wed Nov 11 16:52:15 2015 +0100
Branches: id-remap
https://developer.blender.org/rBded1333f3cb711135de18ae7413b4d622e75a142

Rework a bit IDRemap struct to separate input flags from output status, and fix
issues with unlinking ParticleSettings.

We now have the option to still decrement user count of old_id, even if we 
could not
replace it with NULL new_id (aka unlinking), needed to keep proper user count 
when
unlinking and ID from datablocks it uses, to delete it.

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

M       source/blender/blenkernel/BKE_library.h
M       source/blender/blenkernel/intern/library.c
M       source/blender/blenkernel/intern/particle.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 5b8f741..6384143 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(void *idv, void *old_idv, void *new_idv) 
ATTR_NONNULL(1);
+void BKE_libblock_relink_ex(void *idv, void *old_idv, void *new_idv, const 
bool us_min_never_null) 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 9f6f2d3..377cd03 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -1027,20 +1027,31 @@ 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;
+       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;
 
+/* IDRemp->flag */
 enum {
-       /* Set by caller. */
-       ID_REMAP_SKIP_INDIRECT_USAGE  = 1 << 0,
+       /* Do not remap indirect usages of IDs (that is, when user is some 
linked data). */
+       ID_REMAP_SKIP_INDIRECT_USAGE    = 1 << 0,
+       /* This flag should always be set, *except for 'unlink' scenarios* 
(only relevant when new_id == NULL).
+        * Basically, when unset, NEVER_NULL ID usages will keep pointing to 
old_id, but (if needed) old_id user count
+        * will still be decremented. This is mandatory for 'delete ID' case, 
but in all other situation this would lead
+        * to invalid user counts! */
+       ID_REMAP_SKIP_NEVER_NULL_USAGE  = 1 << 1,
+};
 
-       /* 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. */
+/* IDRemp->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)
@@ -1065,12 +1076,13 @@ static bool foreach_libblock_remap_callback(void 
*user_data, ID **id_p, int cb_f
                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));
+               const bool skip_never_null = (id_remap_data->flag & 
ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;
 
                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 ||
+               if ((is_never_null && skip_never_null) ||
                    (is_obj_editmode && (((Object *)id)->data == *id_p)) ||
                    (skip_indirect && (is_proxy || is_indirect)))
                {
@@ -1085,11 +1097,13 @@ static bool foreach_libblock_remap_callback(void 
*user_data, ID **id_p, int cb_f
                        }
                        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;
+                               id_remap_data->status |= 
ID_REMAP_IS_USER_ONE_SKIPPED;
                        }
                }
                else {
-                       *id_p = new_id;
+                       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. */
@@ -1102,7 +1116,7 @@ static bool foreach_libblock_remap_callback(void 
*user_data, ID **id_p, int cb_f
                                 * that extra user is processed in final 
handling... */
                        }
                        if (!is_indirect) {
-                               id_remap_data->flag |= 
ID_REMAP_IS_LINKED_DIRECT;
+                               id_remap_data->status |= 
ID_REMAP_IS_LINKED_DIRECT;
                        }
                }
        }
@@ -1131,7 +1145,7 @@ static bool foreach_libblock_remap_callback(void 
*user_data, ID **id_p, int cb_f
  * \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)
+        Main *bmain, ID *id, ID *old_id, ID *new_id, const short remap_flags, 
IDRemap *r_id_remap_data)
 {
        IDRemap id_remap_data;
        ListBase *lb_array[MAX_LIBARRAY];
@@ -1143,7 +1157,8 @@ static void libblock_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->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;
@@ -1183,7 +1198,7 @@ static void libblock_remap_data(
                id_fake_user_set(new_id);
        }
 
-       if (new_id && (new_id->flag & LIB_INDIRECT) && (r_id_remap_data->flag & 
ID_REMAP_IS_LINKED_DIRECT)) {
+       if (new_id && (new_id->flag & LIB_INDIRECT) && (r_id_remap_data->status 
& ID_REMAP_IS_LINKED_DIRECT)) {
                new_id->flag &= ~LIB_INDIRECT;
                new_id->flag |= LIB_EXTERN;
        }
@@ -1199,6 +1214,7 @@ void BKE_libblock_remap_locked(Main *bmain, void 
*old_idv, void *new_idv, const
        IDRemap id_remap_data;
        ID *old_id = old_idv;
        ID *new_id = new_idv;
+       int remap_flags = skip_indirect_usage ? ID_REMAP_SKIP_INDIRECT_USAGE : 
0;
        int skipped_direct, skipped_refcounted;
 
        BLI_assert(old_id != NULL);
@@ -1207,7 +1223,7 @@ 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);
 
-       libblock_remap_data(bmain, NULL, old_id, new_id, skip_indirect_usage, 
&id_remap_data);
+       libblock_remap_data(bmain, NULL, old_id, new_id, remap_flags, 
&id_remap_data);
 
        if (free_notifier_reference_cb) {
                free_notifier_reference_cb(old_id);
@@ -1225,7 +1241,7 @@ void BKE_libblock_remap_locked(Main *bmain, void 
*old_idv, void *new_idv, const
        /* 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)) {
+       if ((old_id->flag2 & LIB_EXTRAUSER_SET) && !(id_remap_data.status & 
ID_REMAP_IS_USER_ONE_SKIPPED)) {
                id_us_min(old_id);
                old_id->flag2 &= ~LIB_EXTRAUSER_SET;
        }
@@ -1308,6 +1324,8 @@ void BKE_libblock_unlink(Main *bmain, void *idv)
 /** 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.
+ * \param us_min_never_null If true and new_id is NULL, 'NEVER_NULL' ID usages 
keep their old id, but this one still
+ *        gets its user count decremented (needed when given \a idv is going 
to be deleted right after being unlinked).
  */
 /* Should be able to replace all _relink() funcs (constraints, rigidbody, 
etc.) ? */
 /* XXX Arg! Naming... :(
@@ -1317,11 +1335,12 @@ void BKE_libblock_unlink(Main *bmain, void *idv)
  *     BKE_id_remap maybe?
  *     ... sigh
  */
-void BKE_libblock_relink_ex(void *idv, void *old_idv, void *new_idv)
+void BKE_libblock_relink_ex(void *idv, void *old_idv, void *new_idv, const 
bool us_min_never_null)
 {
        ID *id = idv;
        ID *old_id = old_idv;
        ID *new_id = new_idv;
+       int remap_flags = us_min_never_null ? 0 : 
ID_REMAP_SKIP_NEVER_NULL_USAGE;
 
        /* No need to lock here, we are only affecting given ID. */
 
@@ -1334,7 +1353,7 @@ void BKE_libblock_relink_ex(void *idv, void *old_idv, 
void *new_idv)
                BLI_assert(new_id == NULL);
        }
 
-       libblock_remap_data(NULL, id, old_id, new_id, false, NULL);
+       libblock_remap_data(NULL, id, old_id, new_id, remap_flags, NULL);
 }
 
 static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void 
*userdata)
@@ -1388,7 +1407,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, bool 
do_id_user)
 #endif
 
        if (do_id_user) {
-               BKE_libblock_relink_ex(id, NULL, NULL);
+               BKE_libblock_relink_ex(id, NULL, NULL, true);
        }
 
        switch (type) {
diff --git a/source/blender/blenkernel/intern/particle.c 
b/source/blender/blenkernel/intern/particle.c
index e76edf3..156fdd6 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -564,10 +564,7 @@ void psys_free(Object *ob, ParticleSystem *psys)
                if (!nr)
                        ob->transflag &= ~OB_DUPLIPARTS;
 
-               if (psys->part) {
-                       id_us_min(&psys->part->id);
-                       psys->part = NULL;
-               }
+               psys->part = NULL;
 
                BKE_ptcache_free_list(&psys->ptcaches);
                psys->pointcache = NULL;
diff --git a/source/blender/editors/render/render_preview.c 
b/source/blender/editors/render/render_preview.c
index a647f6a..1751712 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -863,7 +863,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(sp->worldcopy, NULL, NULL);
+               BKE_libblock_relink_ex(sp->worldcopy, NULL, NULL, true);
                BKE_world_free(sp->worldcopy);
                
                properties = IDP_GetProperties((ID *)sp->worldcopy, false);
@@ -880,7 +880,7 @@ static void shader_preview_free(void *customdata)
                
                /* get rid of copied lamp */
                BLI_remlink(&pr_main->lamp, sp->lampcopy);
-               BKE_libblock_relink_ex(sp->lampcop

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to