Fix T68971: Copy As New Driver from Material node creates a bad reference.
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.
This commit is contained in:
parent
443586f34d
commit
8f578150ea
Notes:
blender-bot
2023-02-14 01:11:05 +01:00
Referenced by commit e6f3d8b3e1
, Revert "Fix T68971: Copy As New Driver from Material node creates a bad reference."
Referenced by issue #68971, problem saving/loading driver on shader node
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue