Fix T68971: Copy As New Driver from Material node creates a bad reference.
authorAlexander Gavrilov <angavrilov@gmail.com>
Thu, 22 Aug 2019 12:40:10 +0000 (15:40 +0300)
committerAlexander Gavrilov <angavrilov@gmail.com>
Thu, 22 Aug 2019 12:46:37 +0000 (15:46 +0300)
NodeTree structures of materials and some other data blocks are
effectively node group data block objects that are contained inside
the parent block. Thus, direct references to them are only valid
while blender is running, and are lost on save.

Fix Copy As New Driver to create a reference that goes through
the owner data block, by adding a new runtime field to bNodeTree.

source/blender/blenkernel/BKE_node.h
source/blender/blenkernel/intern/linestyle.c
source/blender/blenkernel/intern/node.c
source/blender/blenloader/intern/readfile.c
source/blender/editors/animation/drivers.c
source/blender/editors/include/ED_keyframing.h
source/blender/editors/interface/interface_ops.c
source/blender/editors/space_node/node_add.c
source/blender/editors/space_node/node_edit.c
source/blender/editors/space_node/node_group.c
source/blender/makesdna/DNA_node_types.h

index e3d0588b60770eff3b85d9b7a27178a073660872..b76e3777557da0f3bdfb9f8e6a243b7f2319e08d 100644 (file)
@@ -366,7 +366,7 @@ struct GHashIterator *ntreeTypeGetIterator(void);
 void ntreeSetTypes(const struct bContext *C, struct bNodeTree *ntree);
 
 void ntreeInitDefault(struct bNodeTree *ntree);
-struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char *idname);
+struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char *idname, struct ID *owner);
 
 /* copy/free funcs, need to manage ID users */
 void ntreeFreeTree(struct bNodeTree *ntree);
index 7bfe5a7c8ffafb751782bed297baa08a2f021af4..cdef24b07fbdc06f2a711119791c70079ef23a93 100644 (file)
@@ -1456,7 +1456,7 @@ void BKE_linestyle_default_shader(const bContext *C, FreestyleLineStyle *linesty
 
   BLI_assert(linestyle->nodetree == NULL);
 
-  ntree = ntreeAddTree(NULL, "stroke_shader", "ShaderNodeTree");
+  ntree = ntreeAddTree(NULL, "stroke_shader", "ShaderNodeTree", &linestyle->id);
 
   linestyle->nodetree = ntree;
 
index 206c59c110adaba97d66fabc6a42a3332c879b0d..59ffbbfea6f7ffce8414b3a40aca6f6f217738df 100644 (file)
@@ -1394,7 +1394,7 @@ void ntreeInitDefault(bNodeTree *ntree)
   ntree_set_typeinfo(ntree, NULL);
 }
 
-bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname)
+bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname, ID *owner)
 {
   bNodeTree *ntree;
 
@@ -1408,6 +1408,7 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname)
     ntree = MEM_callocN(sizeof(bNodeTree), "new node tree");
     *((short *)ntree->id.name) = ID_NT;
     BLI_strncpy(ntree->id.name + 2, name, sizeof(ntree->id.name));
+    ntree->owner = owner;
   }
 
   /* Types are fully initialized at this point,
index 1e3342cef0429db89ee89fd7223d92d25d1e6952..47fa8704df9f9328da8eb3e1d4ee4e85d5e7e339 100644 (file)
@@ -3477,13 +3477,15 @@ static void direct_link_node_socket(FileData *fd, bNodeSocket *sock)
 }
 
 /* ntree itself has been read! */
-static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
+static void direct_link_nodetree(FileData *fd, bNodeTree *ntree, ID *owner)
 {
   /* note: writing and reading goes in sync, for speed */
   bNode *node;
   bNodeSocket *sock;
   bNodeLink *link;
 
+  ntree->owner = owner;
+
   ntree->init = 0; /* to set callbacks and force setting types */
   ntree->is_updating = false;
   ntree->typeinfo = NULL;
@@ -3958,7 +3960,7 @@ static void direct_link_light(FileData *fd, Light *la)
   la->nodetree = newdataadr(fd, la->nodetree);
   if (la->nodetree) {
     direct_link_id(fd, &la->nodetree->id);
-    direct_link_nodetree(fd, la->nodetree);
+    direct_link_nodetree(fd, la->nodetree, &la->id);
   }
 
   la->preview = direct_link_preview_image(fd, la->preview);
@@ -4121,7 +4123,7 @@ static void direct_link_world(FileData *fd, World *wrld)
   wrld->nodetree = newdataadr(fd, wrld->nodetree);
   if (wrld->nodetree) {
     direct_link_id(fd, &wrld->nodetree->id);
-    direct_link_nodetree(fd, wrld->nodetree);
+    direct_link_nodetree(fd, wrld->nodetree, &wrld->id);
   }
 
   wrld->preview = direct_link_preview_image(fd, wrld->preview);
@@ -4421,7 +4423,7 @@ static void direct_link_texture(FileData *fd, Tex *tex)
   tex->nodetree = newdataadr(fd, tex->nodetree);
   if (tex->nodetree) {
     direct_link_id(fd, &tex->nodetree->id);
-    direct_link_nodetree(fd, tex->nodetree);
+    direct_link_nodetree(fd, tex->nodetree, &tex->id);
   }
 
   tex->preview = direct_link_preview_image(fd, tex->preview);
@@ -4476,7 +4478,7 @@ static void direct_link_material(FileData *fd, Material *ma)
   ma->nodetree = newdataadr(fd, ma->nodetree);
   if (ma->nodetree) {
     direct_link_id(fd, &ma->nodetree->id);
-    direct_link_nodetree(fd, ma->nodetree);
+    direct_link_nodetree(fd, ma->nodetree, &ma->id);
   }
 
   ma->preview = direct_link_preview_image(fd, ma->preview);
@@ -6907,7 +6909,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
   sce->nodetree = newdataadr(fd, sce->nodetree);
   if (sce->nodetree) {
     direct_link_id(fd, &sce->nodetree->id);
-    direct_link_nodetree(fd, sce->nodetree);
+    direct_link_nodetree(fd, sce->nodetree, &sce->id);
   }
 
   direct_link_view_settings(fd, &sce->view_settings);
@@ -8931,7 +8933,7 @@ static void direct_link_linestyle(FileData *fd, FreestyleLineStyle *linestyle)
   linestyle->nodetree = newdataadr(fd, linestyle->nodetree);
   if (linestyle->nodetree) {
     direct_link_id(fd, &linestyle->nodetree->id);
-    direct_link_nodetree(fd, linestyle->nodetree);
+    direct_link_nodetree(fd, linestyle->nodetree, &linestyle->id);
   }
 }
 
@@ -9293,7 +9295,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const int ta
       direct_link_action(fd, (bAction *)id);
       break;
     case ID_NT:
-      direct_link_nodetree(fd, (bNodeTree *)id);
+      direct_link_nodetree(fd, (bNodeTree *)id, NULL);
       break;
     case ID_BR:
       direct_link_brush(fd, (Brush *)id);
index e341a16378c9be0358bbc0efc5640947fc4adab2..bf2056a7ec67db23d5e22563b6a7281db657e2c5 100644 (file)
@@ -846,6 +846,36 @@ bool ANIM_driver_vars_paste(ReportList *reports, FCurve *fcu, bool replace)
 
 /* -------------------------------------------------- */
 
+/** Compute an ID pointer and path to property valid for use in a driver.
+ *  Corrects for ID references that are not independent (e.g. material NodeTree). */
+bool ANIM_get_target_ID_and_path_to_property(
+    PointerRNA *ptr, PropertyRNA *prop, int index, ID **r_id, char **r_path)
+{
+  int dim = RNA_property_array_dimension(ptr, prop, NULL);
+  char *path = RNA_path_from_ID_to_property_index(ptr, prop, dim, index);
+  ID *id = ptr->id.data;
+
+  if (!path) {
+    return false;
+  }
+
+  if (GS(id->name) == ID_NT) {
+    bNodeTree *node_tree = (bNodeTree *)id;
+
+    if (node_tree->owner) {
+      id = node_tree->owner;
+
+      char *new_path = BLI_sprintfN("node_tree%s%s", path[0] == '[' ? "" : ".", path);
+      MEM_freeN(path);
+      path = new_path;
+    }
+  }
+
+  *r_id = id;
+  *r_path = path;
+  return true;
+}
+
 /* Create a driver & variable that reads the specified property,
  * and store it in the buffers for Paste Driver and Paste Variables. */
 void ANIM_copy_as_driver(struct ID *target_id, const char *target_path, const char *var_name)
index bbeeeade8225c6129cb0a4772768a192f731a7cd..455337b9cc0c2c4d7d53c263681eaa3c48d5886e 100644 (file)
@@ -403,6 +403,11 @@ bool ANIM_driver_vars_paste(struct ReportList *reports, struct FCurve *fcu, bool
 
 /* -------- */
 
+/** Compute an ID pointer and path to property valid for use in a driver.
+ *  Corrects for ID references that are not independent (e.g. material NodeTree). */
+bool ANIM_get_target_ID_and_path_to_property(
+    struct PointerRNA *ptr, struct PropertyRNA *prop, int index, struct ID **r_id, char **r_path);
+
 /* Create a driver & variable that reads the specified property,
  * and store it in the buffers for Paste Driver and Paste Variables. */
 void ANIM_copy_as_driver(struct ID *target_id, const char *target_path, const char *var_name);
index c7ce66cfcf6aa37a3dd2289f35cae9a71e912a30..f8df8966297321a514e24c158f5d15c8f8b8093e 100644 (file)
@@ -195,11 +195,11 @@ static int copy_as_driver_button_exec(bContext *C, wmOperator *UNUSED(op))
   UI_context_active_but_prop_get(C, &ptr, &prop, &index);
 
   if (ptr.id.data && ptr.data && prop) {
-    int dim = RNA_property_array_dimension(&ptr, prop, NULL);
-    char *path = RNA_path_from_ID_to_property_index(&ptr, prop, dim, index);
+    ID *id;
+    char *path;
 
-    if (path) {
-      ANIM_copy_as_driver(ptr.id.data, path, RNA_property_identifier(prop));
+    if (ANIM_get_target_ID_and_path_to_property(&ptr, prop, index, &id, &path)) {
+      ANIM_copy_as_driver(id, path, RNA_property_identifier(prop));
       MEM_freeN(path);
       return OPERATOR_FINISHED;
     }
index 01a30f677a3ff93fd7edf81f482428c7cd0b9b1b..5ee1925fd55277bb0208db26f5bbf8d931873068 100644 (file)
@@ -509,7 +509,7 @@ static int new_node_tree_exec(bContext *C, wmOperator *op)
     return OPERATOR_CANCELLED;
   }
 
-  ntree = ntreeAddTree(bmain, treename, idname);
+  ntree = ntreeAddTree(bmain, treename, idname, NULL);
 
   /* hook into UI */
   UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
index d31256a1425187ed709d4d3b9da88e87b0aa9ce8..46dfa65e73cc8efcd082d8aa6a9ff2e13b0fd5f7 100644 (file)
@@ -448,7 +448,7 @@ void ED_node_shader_default(const bContext *C, ID *id)
   int output_type, shader_type;
   float color[4] = {0.0f, 0.0f, 0.0f, 1.0f}, strength = 1.0f;
 
-  ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname);
+  ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname, id);
 
   switch (GS(id->name)) {
     case ID_MA: {
@@ -534,7 +534,7 @@ void ED_node_composit_default(const bContext *C, struct Scene *sce)
     return;
   }
 
-  sce->nodetree = ntreeAddTree(NULL, "Compositing Nodetree", ntreeType_Composite->idname);
+  sce->nodetree = ntreeAddTree(NULL, "Compositing Nodetree", ntreeType_Composite->idname, &sce->id);
 
   sce->nodetree->chunksize = 256;
   sce->nodetree->edit_quality = NTREE_QUALITY_HIGH;
@@ -572,7 +572,7 @@ void ED_node_texture_default(const bContext *C, Tex *tx)
     return;
   }
 
-  tx->nodetree = ntreeAddTree(NULL, "Texture Nodetree", ntreeType_Texture->idname);
+  tx->nodetree = ntreeAddTree(NULL, "Texture Nodetree", ntreeType_Texture->idname, &tx->id);
 
   out = nodeAddStaticNode(C, tx->nodetree, TEX_NODE_OUTPUT);
   out->locx = 300.0f;
index 3fd03bac8740aa8dec79bd510e1836a48a1ee9c1..303cd39abbab4eee5d3f046cc4d5de07eaa882bc 100644 (file)
@@ -644,7 +644,7 @@ static bool node_group_make_test_selected(bNodeTree *ntree,
   int ok = true;
 
   /* make a local pseudo node tree to pass to the node poll functions */
-  ngroup = ntreeAddTree(NULL, "Pseudo Node Group", ntree_idname);
+  ngroup = ntreeAddTree(NULL, "Pseudo Node Group", ntree_idname, NULL);
 
   /* check poll functions for selected nodes */
   for (node = ntree->nodes.first; node; node = node->next) {
@@ -953,7 +953,7 @@ static bNode *node_group_make_from_selected(const bContext *C,
   }
 
   /* new nodetree */
-  ngroup = ntreeAddTree(bmain, "NodeGroup", ntreetype);
+  ngroup = ntreeAddTree(bmain, "NodeGroup", ntreetype, NULL);
 
   /* make group node */
   gnode = nodeAddNode(C, ntree, ntype);
index af66add01f3287d5144f3381de0bf8d1f2ee29db..d953237d1299178a23807c6a3670d3ee48f3c6bf 100644 (file)
@@ -477,6 +477,9 @@ typedef struct bNodeTree {
    */
   struct bNodeTreeExec *execdata;
 
+  /** Data block that owns this tree (Material, etc). Not saved. */
+  struct ID *owner;
+
   /* callbacks */
   void (*progress)(void *, float progress);
   /** \warning may be called by different threads */