Commit: 71f5df9f44dd6dfd125d6ea7f7f6542e6f9e7faa
Author: Bastien Montagne
Date:   Fri Jul 8 13:22:54 2016 +0200
Branches: master
https://developer.blender.org/rB71f5df9f44dd6dfd125d6ea7f7f6542e6f9e7faa

Refactor remapping's pre/post process of special cases.

Main issue was that BKE_libblock_relink_ex was pretty much ignoring all those...
Also, unlinking of objects was not handling correctly indirect-related flags.

Refactored code into helper functions to avoid too much duplicated code.

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

M       source/blender/blenkernel/BKE_library_remap.h
M       source/blender/blenkernel/intern/library_remap.c
M       source/blender/editors/render/render_preview.c

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

diff --git a/source/blender/blenkernel/BKE_library_remap.h 
b/source/blender/blenkernel/BKE_library_remap.h
index 7540052..e974b79 100644
--- a/source/blender/blenkernel/BKE_library_remap.h
+++ b/source/blender/blenkernel/BKE_library_remap.h
@@ -60,7 +60,9 @@ void BKE_libblock_unlink(
         struct Main *bmain, void *idv,
         const bool do_flag_never_null, const bool do_skip_indirect) 
ATTR_NONNULL();
 
-void BKE_libblock_relink_ex(void *idv, void *old_idv, void *new_idv, const 
bool us_min_never_null) ATTR_NONNULL(1);
+void BKE_libblock_relink_ex(
+        struct Main *bmain, void *idv, void *old_idv, void *new_idv,
+        const bool us_min_never_null) ATTR_NONNULL(1, 2);
 
 
 typedef void (*BKE_library_free_window_manager_cb)(struct bContext *, struct 
wmWindowManager *);
diff --git a/source/blender/blenkernel/intern/library_remap.c 
b/source/blender/blenkernel/intern/library_remap.c
index 491994a..584db46 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -230,6 +230,127 @@ static int foreach_libblock_remap_callback(void 
*user_data, ID *UNUSED(id_self),
        return IDWALK_RET_NOP;
 }
 
+/* Some reamapping unfortunately require extra and/or specific handling, 
tackle those here. */
+static void libblock_remap_data_preprocess_scene_base_unlink(
+        IDRemap *r_id_remap_data, Scene *sce, Base *base, const bool 
skip_indirect, const bool is_indirect)
+{
+       if (skip_indirect && is_indirect) {
+               r_id_remap_data->skipped_indirect++;
+               r_id_remap_data->skipped_refcounted++;
+       }
+       else {
+               id_us_min((ID *)base->object);
+               BKE_scene_base_unlink(sce, base);
+               MEM_freeN(base);
+               if (!is_indirect) {
+                       r_id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
+               }
+       }
+}
+
+static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
+{
+       switch (GS(r_id_remap_data->id->name)) {
+               case ID_SCE:
+               {
+                       Scene *sce = (Scene *)r_id_remap_data->id;
+
+                       if (!r_id_remap_data->new_id) {
+                               const bool is_indirect = (sce->id.lib != NULL);
+                               const bool skip_indirect = 
(r_id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
+
+                               /* In case we are unlinking... */
+                               if (!r_id_remap_data->old_id) {
+                                       /* ... everything from scene. */
+                                       Base *base, *base_next;
+                                       for (base = sce->base.first; base; base 
= base_next) {
+                                               base_next = base->next;
+                                               
libblock_remap_data_preprocess_scene_base_unlink(
+                                                           r_id_remap_data, 
sce, base, skip_indirect, is_indirect);
+                                       }
+                               }
+                               else if (GS(r_id_remap_data->old_id->name) == 
ID_OB) {
+                                       /* ... a specific object from scene. */
+                                       Object *old_ob = (Object 
*)r_id_remap_data->old_id;
+                                       Base *base = BKE_scene_base_find(sce, 
old_ob);
+
+                                       if (base) {
+                                               
libblock_remap_data_preprocess_scene_base_unlink(
+                                                           r_id_remap_data, 
sce, base, skip_indirect, is_indirect);
+                                       }
+                               }
+                       }
+                       break;
+               }
+               case ID_OB:
+               {
+                       ID *old_id = r_id_remap_data->old_id;
+                       if (!old_id || GS(old_id->name) == ID_AR) {
+                               Object *ob = (Object *)r_id_remap_data->id;
+                               /* Object's pose holds reference to armature 
bones... sic */
+                               /* Note that in theory, we should have to 
bother about linked/non-linked/never-null/etc. flags/states.
+                                * Fortunately, this is just a tag, so we can 
accept to 'over-tag' a bit for pose recalc, and avoid
+                                * another complex and risky condition 
nightmare like the one we have in
+                                * foreach_libblock_remap_callback()... */
+                               if (ob->pose && (!old_id || ob->data == 
old_id)) {
+                                       BLI_assert(ob->type == OB_ARMATURE);
+                                       ob->pose->flag |= POSE_RECALC;
+                               }
+                       }
+                       break;
+               }
+               default:
+                       break;
+       }
+}
+
+static void libblock_remap_data_postprocess_object_fromgroup_update(Main 
*bmain, Object *old_ob, Object *new_ob)
+{
+       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.
+                *     - remapped old_ob by new_ob, in which case scenes' bases 
are still valid as is.
+                * So in any case, no need to update them here. */
+               if (BKE_group_object_find(NULL, old_ob) == NULL) {
+                       old_ob->flag &= ~OB_FROMGROUP;
+               }
+               if (new_ob == NULL) {  /* We need to remove NULL-ified 
groupobjects... */
+                       for (Group *group = bmain->group.first; group; group = 
group->id.next) {
+                               BKE_group_object_unlink(group, NULL, NULL, 
NULL);
+                       }
+               }
+               else {
+                       new_ob->flag |= OB_FROMGROUP;
+               }
+       }
+}
+
+static void libblock_remap_data_postprocess_group_scene_unlink(Main 
*UNUSED(bmain), Scene *sce, ID *old_id)
+{
+       /* Note that here we assume no object has no base (i.e. all objects are 
assumed instanced
+        * in one scene...). */
+       for (Base *base = sce->base.first; base; base = base->next) {
+               if (base->flag & OB_FROMGROUP) {
+                       Object *ob = base->object;
+
+                       if (ob->flag & OB_FROMGROUP) {
+                               Group *grp = BKE_group_object_find(NULL, ob);
+
+                               /* Unlinked group (old_id) is still in bmain... 
*/
+                               if (grp && (&grp->id == old_id || grp->id.us == 
0)) {
+                                       grp = BKE_group_object_find(grp, ob);
+                               }
+                               if (!grp) {
+                                       ob->flag &= ~OB_FROMGROUP;
+                               }
+                       }
+                       if (!(ob->flag & OB_FROMGROUP)) {
+                               base->flag &= ~OB_FROMGROUP;
+                       }
+               }
+       }
+}
+
 /**
  * Execute the 'data' part of the remapping (that is, all ID pointers from 
other ID datablocks).
  *
@@ -272,6 +393,7 @@ static void libblock_remap_data(
                printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib);
 #endif
                r_id_remap_data->id = id;
+               libblock_remap_data_preprocess(r_id_remap_data);
                BKE_library_foreach_ID_link(id, 
foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
        }
        else {
@@ -292,6 +414,7 @@ static void libblock_remap_data(
                                 * the user count handling...
                                 * XXX No more true (except for debug usage of 
those skipping counters). */
                                r_id_remap_data->id = id_curr;
+                               libblock_remap_data_preprocess(r_id_remap_data);
                                BKE_library_foreach_ID_link(
                                            id_curr, 
foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
                        }
@@ -336,38 +459,6 @@ void BKE_libblock_remap_locked(
        BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
        BLI_assert(old_id != new_id);
 
-       /* Some pre-process updates.
-        * This is a bit ugly, but cannot see a way to avoid it. Maybe we 
should do a per-ID callback for this instead?
-        */
-       if (GS(old_id->name) == ID_OB) {
-               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) {
-                                       id_us_min((ID *)base->object);
-                                       BKE_scene_base_unlink(sce, base);
-                                       MEM_freeN(base);
-                               }
-                       }
-               }
-       }
-       else if (GS(old_id->name) == ID_AR) {
-               /* Object's pose holds reference to armature bones... sic */
-               for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
-                       if (ob->data == old_id && ob->pose) {
-                               BLI_assert(ob->type == OB_ARMATURE);
-                               ob->pose->flag |= POSE_RECALC;
-                       }
-               }
-       }
-
        libblock_remap_data(bmain, NULL, old_id, new_id, remap_flags, 
&id_remap_data);
 
        if (free_notifier_reference_cb) {
@@ -407,55 +498,12 @@ void BKE_libblock_remap_locked(
         */
        switch (GS(old_id->name)) {
                case ID_OB:
-               {
-                       Object *old_ob = (Object *)old_id;
-                       Object *new_ob = (Object *)new_id;
-
-                       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.
-                                *     - remapped old_ob by new_ob, in which 
case scenes' bases are still valid as is.
-                                * So in any case, no need to update them here. 
*/
-                               if (BKE_group_object_find(NULL, old_ob) == 
NULL) {
-                                       old_ob->flag &= ~OB_FROMGROUP;
-                               }
-                               if (new_ob == NULL) {  /* We need to remove 
NULL-ified groupobjects... */
-                                       Group *group;
-                                       for (group = bmain->group.first; group; 
group = group->id.next) {
-                                               BKE_group_object_unlink(group, 
NULL, NULL, NULL);
-                                       }
-                               }
-                               else {
-                                       new_ob->flag |= OB_FROMGROUP;
-                               }
-                       }
+                       
libblock_remap_data_postprocess_object_fromgroup_update(bmain, (Object 
*)old_id, (Object *)new_id);
                        break;
-               }
                case ID_GR:
                        if (new_id == NULL) {  /* Only affects us in case group 
was unlinked. */
                                for (Scene *sce = bmain->scene.first; sce; sce 
= sce->id.next) {
-                                       /* Note that here we assume no object 
has no base (i.e. all objects are assumed instanced
-                                        * in one scene...). */
-                                       for (Base *base = sce->base.first; 
base; base = base->next) {
-                                               if (base->flag & OB_FROMGROUP) {
-                                                       Object *ob = 
base->object;
-
-                                                       if (ob->flag & 
OB_FROMGROUP) {
-                                                               Group *grp = 
BKE_group_object_find(NULL, ob);
-
-                                                               /* Unlinked 
group (old_id) is still in bmain... */
-                                                               if (grp && 
(&grp->id == old_id)) {
-                                                                       grp = 
BKE_group_object_find(grp, ob);
-                                                               }
-                                                               if (!grp) {
-                                                                       
ob->flag &= ~OB_FROMGROUP;
-                                                               }
-                                                       }
-                                                       if (!(ob->flag & 
OB_FROMGROUP)) {
-                                                               base->flag &= 
~OB_FROMGROUP;
-                                                       }
-                                               }
-                                       }
+                                       
libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id);
                                }
                        }
                        break;
@@ -511,14 +559,14 @@ void BKE_libblock_unlink(Main *bmain, void *idv, const 
bool do_flag_never_null,
  *     ... sigh
  */
 void BKE_libblock_relink_ex(
-        void *idv, void *old_idv, void *new_idv, const bool us_min_never_null)
+        Main *bmain, 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. */
+       /* No need to lock here, we are only affecting given ID, not bmain 
database. */
 
        BLI_assert(id);
        if (old_id) {
@@ -529,16 +577,46 @@ void BKE_libblock_relink_ex(
                BLI_assert(new_id == NULL);
        }
 
-       if (GS(id->name) == ID_OB) {
-               Object *ob = (Object *)id;
-               /* Object's pose holds reference to armature bones... sic */
-               if (ob->data && ob->pose && (old_id == NULL 

@@ Diff output truncated at 10240 characters. @@

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

Reply via email to