[Bf-blender-cvs] [4c3d51326ef] master: LibOverride: Refactor 'make override' 3DView operator.

Bastien Montagne noreply at git.blender.org
Tue Jun 30 12:19:19 CEST 2020


Commit: 4c3d51326efaf1c6dcff3549da4a110b379e25b0
Author: Bastien Montagne
Date:   Tue Jun 30 12:04:44 2020 +0200
Branches: master
https://developer.blender.org/rB4c3d51326efaf1c6dcff3549da4a110b379e25b0

LibOverride: Refactor 'make override' 3DView operator.

This one now uses a generic 'dependency detection' process to decide
which IDs should be overridden.

This will e.g. allow to override mesh and shapekeys when those have some
values controlled by drivers using an armature bone...

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

M	source/blender/editors/object/object_relations.c

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

diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 7ec236de6f0..509b70f849e 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -33,6 +33,7 @@
 #include "DNA_collection_types.h"
 #include "DNA_constraint_types.h"
 #include "DNA_gpencil_types.h"
+#include "DNA_key_types.h"
 #include "DNA_lattice_types.h"
 #include "DNA_light_types.h"
 #include "DNA_material_types.h"
@@ -68,6 +69,7 @@
 #include "BKE_gpencil.h"
 #include "BKE_hair.h"
 #include "BKE_idprop.h"
+#include "BKE_idtype.h"
 #include "BKE_lattice.h"
 #include "BKE_layer.h"
 #include "BKE_lib_id.h"
@@ -2249,47 +2251,66 @@ void OBJECT_OT_make_local(wmOperatorType *ot)
 /** \name Make Library Override Operator
  * \{ */
 
-static void make_override_library_tag_object(Object *obact, Object *ob)
+static bool make_override_hierarchy_recursive_tag(Main *bmain, ID *id)
 {
-  if (ob == obact) {
-    return;
+  MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->id_user_to_used, id);
+
+  /* This way we won't process again that ID should we encounter it again through another
+   * relationship hierarchy.
+   * Note that this does not free any memory from relations, so we can still use the entries.
+   */
+  BKE_main_relations_ID_remove(bmain, id);
+
+  for (; entry != NULL; entry = entry->next) {
+    /* We only consider IDs from the same library. */
+    if (entry->id_pointer != NULL && (*entry->id_pointer)->lib == id->lib) {
+      if (make_override_hierarchy_recursive_tag(bmain, *entry->id_pointer)) {
+        id->tag |= LIB_TAG_DOIT;
+      }
+    }
   }
 
-  if (!ID_IS_LINKED(ob)) {
-    return;
+  return (id->tag & LIB_TAG_DOIT) != 0;
+}
+
+static int make_override_tag_ids_cb(LibraryIDLinkCallbackData *cb_data)
+{
+  if (cb_data->cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_LOOPBACK)) {
+    return IDWALK_RET_STOP_RECURSION;
   }
 
-  /* Note: all this is very case-by-case bad handling, ultimately we'll want a real full
-   * 'automatic', generic handling of all this,
-   * will probably require adding some override-aware stuff to library_query code... */
+  ID *id_root = cb_data->user_data;
+  Library *library_root = id_root->lib;
+  ID *id = *cb_data->id_pointer;
+  ID *id_owner = cb_data->id_owner;
 
-  if (obact->type == OB_ARMATURE && ob->modifiers.first != NULL) {
-    for (ModifierData *md = ob->modifiers.first; md != NULL; md = md->next) {
-      if (md->type == eModifierType_Armature) {
-        ArmatureModifierData *amd = (ArmatureModifierData *)md;
-        if (amd->object == obact) {
-          ob->id.tag |= LIB_TAG_DOIT;
-          break;
-        }
-      }
-    }
+  BLI_assert(id_owner == cb_data->id_self);
+
+  if (ELEM(id, NULL, id_owner)) {
+    return IDWALK_RET_NOP;
   }
-  else if (ob->parent == obact) {
-    ob->id.tag |= LIB_TAG_DOIT;
+
+  BLI_assert(id->lib != NULL);
+  BLI_assert(id_owner->lib == library_root);
+
+  if (id->tag & LIB_TAG_DOIT) {
+    /* Already processed, but maybe not with the same chain of dependency, so we need to check that
+     * one nonetheless. */
+    return IDWALK_RET_STOP_RECURSION;
   }
 
-  if (ob->id.tag & LIB_TAG_DOIT) {
-    printf("Indirectly overriding %s for %s\n", ob->id.name, obact->id.name);
+  if (id->lib != library_root) {
+    /* We do not override data-blocks from other libraries, nor do we process them. */
+    return IDWALK_RET_STOP_RECURSION;
   }
-}
 
-static void make_override_library_tag_collections(Collection *collection)
-{
-  collection->id.tag |= LIB_TAG_DOIT;
-  for (CollectionChild *coll_child = collection->children.first; coll_child != NULL;
-       coll_child = coll_child->next) {
-    make_override_library_tag_collections(coll_child->collection);
+  /* We tag all collections and objects for override. And we also tag all other data-blocks which
+   * would user one of those. */
+  if (ELEM(GS(id->name), ID_OB, ID_GR)) {
+    id->tag |= LIB_TAG_DOIT;
   }
+
+  return IDWALK_RET_NOP;
 }
 
 /* Set the object to override. */
@@ -2338,6 +2359,7 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
 {
   Main *bmain = CTX_data_main(C);
   Object *obact = CTX_data_active_object(C);
+  ID *id_root = NULL;
 
   bool success = false;
 
@@ -2351,111 +2373,156 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
       return OPERATOR_CANCELLED;
     }
 
-    BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+    id_root = &obact->instance_collection->id;
+  }
+  else if (!ID_IS_OVERRIDABLE_LIBRARY(obact)) {
+    BKE_reportf(op->reports,
+                RPT_ERROR_INVALID_INPUT,
+                "Active object '%s' is not overridable",
+                obact->id.name + 2);
+    return OPERATOR_CANCELLED;
+  }
+  /* Else, poll func ensures us that ID_IS_LINKED(obact) is true. */
+  else {
+    id_root = &obact->id;
+  }
 
-    Object *obcollection = obact;
-    Collection *collection = obcollection->instance_collection;
+  BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
 
-    const ListBase dup_collection_objects = BKE_collection_object_cache_get(collection);
-    Base *base = BLI_findlink(&dup_collection_objects, RNA_enum_get(op->ptr, "object"));
-    obact = base->object;
+  /* Tag all collections and objects, as well as other IDs using them. */
+  id_root->tag |= LIB_TAG_DOIT;
 
-    /* First, we make a library override of the linked collection itself, and all its children. */
-    make_override_library_tag_collections(collection);
+  BKE_main_relations_create(bmain, 0);
 
-    /* Then, we make library override of the whole set of objects in the Collection. */
-    FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, ob) {
-      ob->id.tag |= LIB_TAG_DOIT;
-    }
-    FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
-
-    /* Then, we remove (untag) bone shape objects, you shall never want to override those
-     * (hopefully)... */
-    FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, ob) {
-      if (ob->type == OB_ARMATURE && ob->pose != NULL) {
-        for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
-          if (pchan->custom != NULL) {
-            pchan->custom->id.tag &= ~LIB_TAG_DOIT;
-          }
+  BKE_library_foreach_ID_link(
+      bmain, id_root, make_override_tag_ids_cb, id_root, IDWALK_READONLY | IDWALK_RECURSE);
+
+  /* Then, we remove (untag) bone shape objects, you shall never want to override those
+   * (hopefully)... */
+  LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+    if (ob->type == OB_ARMATURE && ob->pose != NULL && (ob->id.tag & LIB_TAG_DOIT)) {
+      for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
+        if (pchan->custom != NULL) {
+          pchan->custom->id.tag &= ~LIB_TAG_DOIT;
         }
       }
     }
-    FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+  }
 
-    success = BKE_lib_override_library_create_from_tag(bmain);
+  /* The we tag all intermediary data-blocks in-between to overridden ones (e.g. if a shapekey has
+   * a driver using an armature object's bone, we need to override the shapekey/obdata, the objects
+   * using them, etc.) */
+  make_override_hierarchy_recursive_tag(bmain, id_root);
+
+  BKE_main_relations_free(bmain);
+
+  ID *id;
+  FOREACH_MAIN_ID_BEGIN (bmain, id) {
+    if (id->tag & LIB_TAG_DOIT && id->lib != NULL) {
+      printf("ID %s tagged for override\n", id->name);
+    }
+  }
+  FOREACH_MAIN_ID_END;
 
-    /* Instantiate our newly overridden objects in scene, if not yet done. */
+  success = BKE_lib_override_library_create_from_tag(bmain);
+
+  if (success) {
     Scene *scene = CTX_data_scene(C);
     ViewLayer *view_layer = CTX_data_view_layer(C);
-    Collection *new_collection = (Collection *)collection->id.newid;
 
-    BKE_collection_add_from_object(bmain, scene, obcollection, new_collection);
+    BKE_main_collection_sync(bmain);
+
+    switch (GS(id_root->name)) {
+      case ID_GR: {
+        Collection *collection_new = ((Collection *)id_root->newid);
+        BKE_collection_add_from_object(bmain, scene, obact, collection_new);
+
+        FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection_new, ob_new) {
+          if (ob_new != NULL && ob_new->id.override_library != NULL) {
+            Base *base;
+            if ((base = BKE_view_layer_base_find(view_layer, ob_new)) == NULL) {
+              BKE_collection_object_add_from(bmain, scene, obact, ob_new);
+              base = BKE_view_layer_base_find(view_layer, ob_new);
+              DEG_id_tag_update_ex(bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS);
+            }
 
-    FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (new_collection, new_ob) {
-      if (new_ob != NULL && new_ob->id.override_library != NULL) {
-        if ((base = BKE_view_layer_base_find(view_layer, new_ob)) == NULL) {
-          BKE_collection_object_add_from(bmain, scene, obcollection, new_ob);
-          base = BKE_view_layer_base_find(view_layer, new_ob);
-          DEG_id_tag_update_ex(bmain, &new_ob->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS);
+            if (ob_new == (Object *)obact->id.newid) {
+              /* TODO: is setting active needed? */
+              BKE_view_layer_base_select_and_set_active(view_layer, base);
+            }
+          }
         }
+        FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+        break;
+      }
+      case ID_OB: {
+        BKE_collection_object_add_from(bmain, scene, obact, ((Object *)id_root->newid));
+        break;
+      }
+      default:
+        BLI_assert(0);
+    }
 
-        if (new_ob == (Object *)obact->id.newid) {
-          /* TODO: is setting active needed? */
-          BKE_view_layer_base_select_and_set_active(view_layer, base);
+    /* We need to ensure all new overrides of objects are properly instantiated. */
+    LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+      Object *ob_new = (Object *)ob->id.newid;
+      if (ob_new != NULL) {
+        BLI_assert(ob_new->id.override_library != NULL &&
+                   ob_new->id.override_library->reference == &ob->id);
+
+        Collection *default_instantiating_collection = NULL;
+        Base *base;
+        if ((b

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list