[Bf-blender-cvs] [665d3db3a40] master: Fix T99460: Allow creation new datablocks from evaluated

Sergey Sharybin noreply at git.blender.org
Thu Aug 4 16:02:47 CEST 2022


Commit: 665d3db3a40c1e1ec3c5c5371b29bddcf07a6f92
Author: Sergey Sharybin
Date:   Wed Aug 3 10:54:11 2022 +0200
Branches: master
https://developer.blender.org/rB665d3db3a40c1e1ec3c5c5371b29bddcf07a6f92

Fix T99460: Allow creation new datablocks from evaluated

This changes makes it possible to copy evaluated result and put it
to the original bmain.

Prior to this change from the API point of view there was false
perception that it is possible, while in practice it was very fragile:
it only worked if the ID did not reference any evaluated IDs.

This change makes it so `id.copy()` Python API call will make it so
the copied ID only references original data-blocks. This sounds a bit
implicit, so here is motivational aspect why it is considered better
approach to all other:

- There needs to be a way to support the described scenario, in the
  lest fragile way. Requiring to always use an explicit function call
  or an argument is too verbose and is easy to be missed.

- The `id.copy()` is already doing implicit thing: it always adds the
  result to the bmain. So it might as well ensure the copied result
  does not reference evaluated data-blocks.

- Added clarity in the documentation should address possible confusion.

The limitation of this change is that the copy() of evaluated geometry
will clear its reference to the shape key. This is because the key is
only referenced for validness of RNA paths for drivers and the key
itself might not match topology of evaluated geometry due to modifiers.

Differential Revision: https://developer.blender.org/D15611

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

M	source/blender/blenkernel/BKE_lib_id.h
M	source/blender/blenkernel/intern/lib_id.c
M	source/blender/makesrna/intern/rna_ID.c

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

diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h
index 94497d9a487..148e6ec2791 100644
--- a/source/blender/blenkernel/BKE_lib_id.h
+++ b/source/blender/blenkernel/BKE_lib_id.h
@@ -453,6 +453,11 @@ struct ID *BKE_id_copy_for_duplicate(struct Main *bmain,
                                      uint duplicate_flags,
                                      int copy_flags);
 
+/* Special version of BKE_id_copy which is safe from using evaluated id as source with a copy
+ * result appearing in the main database.
+ * Takes care of the referenced data-blocks consistency. */
+struct ID *BKE_id_copy_for_use_in_bmain(struct Main *bmain, const struct ID *id);
+
 /**
  * Does a mere memory swap over the whole IDs data (including type-specific memory).
  * \note Most internal ID data itself is not swapped (only IDProperties are).
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index 3778e308db6..5a394a05d86 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -59,6 +59,7 @@
 
 #include "DEG_depsgraph.h"
 #include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
 
 #include "RNA_access.h"
 
@@ -708,6 +709,58 @@ ID *BKE_id_copy_for_duplicate(Main *bmain,
   return id->newid;
 }
 
+static int foreach_assign_id_to_orig_callback(LibraryIDLinkCallbackData *cb_data)
+{
+  ID **id_p = cb_data->id_pointer;
+
+  if (*id_p) {
+    ID *id = *id_p;
+    *id_p = DEG_get_original_id(id);
+
+    /* If the ID changes increase the user count.
+     *
+     * This means that the reference to evaluated ID has been changed with a reference to the
+     * original ID which implies that the user count of the original ID is increased.
+     *
+     * The evaluated IDs do not maintain their user counter, so do not change it to avoid issues
+     * with the user counter going negative. */
+    if (*id_p != id) {
+      if ((cb_data->cb_flag & IDWALK_CB_USER) != 0) {
+        id_us_plus(*id_p);
+      }
+    }
+  }
+
+  return IDWALK_RET_NOP;
+}
+
+ID *BKE_id_copy_for_use_in_bmain(Main *bmain, const ID *id)
+{
+  ID *newid = BKE_id_copy(bmain, id);
+
+  if (newid == NULL) {
+    return newid;
+  }
+
+  /* Assign ID references directly used by the given ID to their original complementary parts.
+   *
+   * For example, when is called on an evaluated object will assign object->data to its original
+   * pointer, the evaluated object->data will be kept unchanged. */
+  BKE_library_foreach_ID_link(NULL, newid, foreach_assign_id_to_orig_callback, NULL, IDWALK_NOP);
+
+  /* Shape keys reference on evaluated ID is preserved to keep driver paths available, but the key
+   * data is likely to be invalid now due to modifiers, so clear the shape key reference avoiding
+   * any possible shape corruption. */
+  if (DEG_is_evaluated_id(id)) {
+    Key **key_p = BKE_key_from_id_p(newid);
+    if (key_p) {
+      *key_p = NULL;
+    }
+  }
+
+  return newid;
+}
+
 /**
  * Does a mere memory swap over the whole IDs data (including type-specific memory).
  * \note Most internal ID data itself is not swapped (only IDProperties are).
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index b4fa7088d38..4b8f8ca7b4b 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -650,7 +650,7 @@ static ID *rna_ID_evaluated_get(ID *id, struct Depsgraph *depsgraph)
 
 static ID *rna_ID_copy(ID *id, Main *bmain)
 {
-  ID *newid = BKE_id_copy(bmain, id);
+  ID *newid = BKE_id_copy_for_use_in_bmain(bmain, id);
 
   if (newid != NULL) {
     id_us_min(newid);
@@ -2045,7 +2045,10 @@ static void rna_def_ID(BlenderRNA *brna)
 
   func = RNA_def_function(srna, "copy", "rna_ID_copy");
   RNA_def_function_ui_description(
-      func, "Create a copy of this data-block (not supported for all data-blocks)");
+      func,
+      "Create a copy of this data-block (not supported for all data-blocks). "
+      "The result is added to the Blend-File Data (Main database), with all references to other "
+      "data-blocks ensured to be from within the same Blend-File Data");
   RNA_def_function_flag(func, FUNC_USE_MAIN);
   parm = RNA_def_pointer(func, "id", "ID", "", "New copy of the ID");
   RNA_def_function_return(func, parm);



More information about the Bf-blender-cvs mailing list