Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenloader')
-rw-r--r--source/blender/blenloader/intern/readfile.c1105
-rw-r--r--source/blender/blenloader/intern/readfile.h1
-rw-r--r--source/blender/blenloader/intern/versioning_250.c180
-rw-r--r--source/blender/blenloader/intern/writefile.c229
4 files changed, 999 insertions, 516 deletions
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index be2b45a3e12..ea5610af3b5 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -127,6 +127,7 @@
#include "BKE_lattice.h"
#include "BKE_library.h" // for which_libbase
#include "BKE_idcode.h"
+#include "BKE_idprop.h"
#include "BKE_material.h"
#include "BKE_main.h" // for Main
#include "BKE_mesh.h" // for ME_ defines (patching)
@@ -150,7 +151,11 @@
#include "IMB_imbuf.h" // for proxy / timecode versioning stuff
+#include "NOD_common.h"
#include "NOD_socket.h"
+#include "NOD_composite.h"
+#include "NOD_shader.h"
+#include "NOD_texture.h"
#include "BLO_readfile.h"
#include "BLO_undofile.h"
@@ -1313,10 +1318,12 @@ void blo_make_image_pointer_map(FileData *fd, Main *oldmain)
oldnewmap_insert(fd->imamap, ima->renders[a], ima->renders[a], 0);
}
for (; sce; sce = sce->id.next) {
- if (sce->nodetree) {
- bNode *node;
- for (node = sce->nodetree->nodes.first; node; node = node->next)
- oldnewmap_insert(fd->imamap, node->preview, node->preview, 0);
+ if (sce->nodetree && sce->nodetree->previews) {
+ bNodeInstanceHashIterator iter;
+ NODE_INSTANCE_HASH_ITER(iter, sce->nodetree->previews) {
+ bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter);
+ oldnewmap_insert(fd->imamap, preview, preview, 0);
+ }
}
}
}
@@ -1355,10 +1362,23 @@ void blo_end_image_pointer_map(FileData *fd, Main *oldmain)
ima->gputexture = newimaadr(fd, ima->gputexture);
}
for (; sce; sce = sce->id.next) {
- if (sce->nodetree) {
- bNode *node;
- for (node = sce->nodetree->nodes.first; node; node = node->next)
- node->preview = newimaadr(fd, node->preview);
+ if (sce->nodetree && sce->nodetree->previews) {
+ bNodeInstanceHash *new_previews = BKE_node_instance_hash_new("node previews");
+ bNodeInstanceHashIterator iter;
+
+ /* reconstruct the preview hash, only using remaining pointers */
+ NODE_INSTANCE_HASH_ITER(iter, sce->nodetree->previews) {
+ bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter);
+ if (preview) {
+ bNodePreview *new_preview = newimaadr(fd, preview);
+ if (new_preview) {
+ bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
+ BKE_node_instance_hash_insert(new_previews, key, new_preview);
+ }
+ }
+ }
+ BKE_node_instance_hash_free(sce->nodetree->previews, NULL);
+ sce->nodetree->previews = new_previews;
}
}
}
@@ -2286,17 +2306,42 @@ static void direct_link_motionpath(FileData *fd, bMotionPath *mpath)
/* ************ READ NODE TREE *************** */
+static void lib_link_node_socket(FileData *fd, ID *UNUSED(id), bNodeSocket *sock)
+{
+ /* Link ID Properties -- and copy this comment EXACTLY for easy finding
+ * of library blocks that implement this.*/
+ if (sock->prop)
+ IDP_LibLinkProperty(sock->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+}
+
/* singe node tree (also used for material/scene trees), ntree is not NULL */
static void lib_link_ntree(FileData *fd, ID *id, bNodeTree *ntree)
{
bNode *node;
+ bNodeSocket *sock;
if (ntree->adt) lib_link_animdata(fd, &ntree->id, ntree->adt);
ntree->gpd = newlibadr_us(fd, id->lib, ntree->gpd);
- for (node = ntree->nodes.first; node; node = node->next)
- node->id = newlibadr_us(fd, id->lib, node->id);
+ for (node = ntree->nodes.first; node; node = node->next) {
+ /* Link ID Properties -- and copy this comment EXACTLY for easy finding
+ * of library blocks that implement this.*/
+ if (node->prop)
+ IDP_LibLinkProperty(node->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+
+ node->id= newlibadr_us(fd, id->lib, node->id);
+
+ for (sock=node->inputs.first; sock; sock=sock->next)
+ lib_link_node_socket(fd, id, sock);
+ for (sock=node->outputs.first; sock; sock=sock->next)
+ lib_link_node_socket(fd, id, sock);
+ }
+
+ for (sock=ntree->inputs.first; sock; sock=sock->next)
+ lib_link_node_socket(fd, id, sock);
+ for (sock=ntree->outputs.first; sock; sock=sock->next)
+ lib_link_node_socket(fd, id, sock);
}
/* library ntree linking after fileread */
@@ -2313,131 +2358,49 @@ static void lib_link_nodetree(FileData *fd, Main *main)
}
}
-static void do_versions_socket_default_value(bNodeSocket *sock)
-{
- bNodeSocketValueFloat *valfloat;
- bNodeSocketValueVector *valvector;
- bNodeSocketValueRGBA *valrgba;
-
- if (sock->default_value)
- return;
-
- switch (sock->type) {
- case SOCK_FLOAT:
- valfloat = sock->default_value = MEM_callocN(sizeof(bNodeSocketValueFloat), "default socket value");
- valfloat->value = sock->ns.vec[0];
- valfloat->min = sock->ns.min;
- valfloat->max = sock->ns.max;
- valfloat->subtype = PROP_NONE;
- break;
- case SOCK_VECTOR:
- valvector = sock->default_value = MEM_callocN(sizeof(bNodeSocketValueVector), "default socket value");
- copy_v3_v3(valvector->value, sock->ns.vec);
- valvector->min = sock->ns.min;
- valvector->max = sock->ns.max;
- valvector->subtype = PROP_NONE;
- break;
- case SOCK_RGBA:
- valrgba = sock->default_value = MEM_callocN(sizeof(bNodeSocketValueRGBA), "default socket value");
- copy_v4_v4(valrgba->value, sock->ns.vec);
- break;
- }
-}
-
-void blo_do_versions_nodetree_default_value(bNodeTree *ntree)
-{
- bNode *node;
- bNodeSocket *sock;
- for (node=ntree->nodes.first; node; node=node->next) {
- for (sock=node->inputs.first; sock; sock=sock->next)
- do_versions_socket_default_value(sock);
- for (sock=node->outputs.first; sock; sock=sock->next)
- do_versions_socket_default_value(sock);
- }
- for (sock=ntree->inputs.first; sock; sock=sock->next)
- do_versions_socket_default_value(sock);
- for (sock=ntree->outputs.first; sock; sock=sock->next)
- do_versions_socket_default_value(sock);
-}
-
-static void lib_nodetree_init_types_cb(void *UNUSED(data), ID *UNUSED(id), bNodeTree *ntree)
-{
- bNode *node;
-
- ntreeInitTypes(ntree);
-
- /* need to do this here instead of in do_versions, otherwise next function can crash */
- blo_do_versions_nodetree_default_value(ntree);
-
- /* XXX could be replaced by do_versions for new nodes */
- for (node=ntree->nodes.first; node; node=node->next)
- node_verify_socket_templates(ntree, node);
-}
-
-/* updates group node socket own_index so that
+/* updates group node socket identifier so that
* external links to/from the group node are preserved.
*/
static void lib_node_do_versions_group_indices(bNode *gnode)
{
bNodeTree *ngroup = (bNodeTree*)gnode->id;
- bNode *intnode;
- bNodeSocket *sock, *gsock, *intsock;
- int found;
+ bNodeSocket *sock;
+ bNodeLink *link;
for (sock=gnode->outputs.first; sock; sock=sock->next) {
int old_index = sock->to_index;
- for (gsock=ngroup->outputs.first; gsock; gsock=gsock->next) {
- if (gsock->link && gsock->link->fromsock->own_index == old_index) {
- sock->own_index = gsock->own_index;
- break;
+
+ for (link = ngroup->links.first; link; link = link->next) {
+ if (link->tonode->type == NODE_GROUP_OUTPUT && link->fromsock->own_index == old_index) {
+ strcpy(sock->identifier, link->fromsock->identifier);
+ /* deprecated */
+ sock->own_index = link->fromsock->own_index;
+ sock->to_index = 0;
+ sock->groupsock = NULL;
}
}
}
for (sock=gnode->inputs.first; sock; sock=sock->next) {
int old_index = sock->to_index;
- /* can't use break in double loop */
- found = 0;
- for (intnode=ngroup->nodes.first; intnode && !found; intnode=intnode->next) {
- for (intsock=intnode->inputs.first; intsock; intsock=intsock->next) {
- if (intsock->own_index == old_index && intsock->link) {
- sock->own_index = intsock->link->fromsock->own_index;
- found = 1;
- break;
- }
+
+ for (link = ngroup->links.first; link; link = link->next) {
+ if (link->fromnode->type == NODE_GROUP_INPUT && link->tosock->own_index == old_index) {
+ strcpy(sock->identifier, link->tosock->identifier);
+ /* deprecated */
+ sock->own_index = link->tosock->own_index;
+ sock->to_index = 0;
+ sock->groupsock = NULL;
}
}
}
}
-/* updates external links for all group nodes in a tree */
-static void lib_nodetree_do_versions_group_indices_cb(void *UNUSED(data), ID *UNUSED(id), bNodeTree *ntree)
-{
- bNode *node;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == NODE_GROUP) {
- bNodeTree *ngroup = (bNodeTree*)node->id;
- if (ngroup && (ngroup->flag & NTREE_DO_VERSIONS_GROUP_EXPOSE))
- lib_node_do_versions_group_indices(node);
- }
- }
-}
-
-/* make an update call for the tree */
-static void lib_nodetree_do_versions_update_cb(void *UNUSED(data), ID *UNUSED(id), bNodeTree *ntree)
-{
- if (ntree->update)
- ntreeUpdateTree(ntree);
-}
-
/* verify types for nodes and groups, all data has to be read */
/* open = 0: appending/linking, open = 1: open new file (need to clean out dynamic
* typedefs */
static void lib_verify_nodetree(Main *main, int UNUSED(open))
{
bNodeTree *ntree;
- int i;
- bNodeTreeType *ntreetype;
/* this crashes blender on undo/redo */
#if 0
@@ -2447,41 +2410,138 @@ static void lib_verify_nodetree(Main *main, int UNUSED(open))
#endif
/* set node->typeinfo pointers */
- for (i = 0; i < NUM_NTREE_TYPES; ++i) {
- ntreetype = ntreeGetType(i);
- if (ntreetype && ntreetype->foreach_nodetree)
- ntreetype->foreach_nodetree(main, NULL, lib_nodetree_init_types_cb);
- }
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next)
- lib_nodetree_init_types_cb(NULL, NULL, ntree);
+ FOREACH_NODETREE(main, ntree, id) {
+ ntreeSetTypes(NULL, ntree);
+ } FOREACH_NODETREE_END
+
+ /* verify static socket templates */
+ FOREACH_NODETREE(main, ntree, id) {
+ bNode *node;
+ for (node=ntree->nodes.first; node; node=node->next)
+ node_verify_socket_templates(ntree, node);
+ } FOREACH_NODETREE_END
{
int has_old_groups = 0;
/* XXX this should actually be part of do_versions, but since we need
* finished library linking, it is not possible there. Instead in do_versions
- * we have set the NTREE_DO_VERSIONS flag, so at this point we can do the
+ * we have set the NTREE_DO_VERSIONS_GROUP_EXPOSE_2_56_2 flag, so at this point we can do the
* actual group node updates.
*/
for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
- if (ntree->flag & NTREE_DO_VERSIONS_GROUP_EXPOSE) {
- /* this adds copies and links from all unlinked internal sockets to group inputs/outputs. */
- node_group_expose_all_sockets(ntree);
+ if (ntree->flag & NTREE_DO_VERSIONS_GROUP_EXPOSE_2_56_2)
has_old_groups = 1;
- }
}
if (has_old_groups) {
- for (i = 0; i < NUM_NTREE_TYPES; ++i) {
- ntreetype = ntreeGetType(i);
- if (ntreetype && ntreetype->foreach_nodetree)
- ntreetype->foreach_nodetree(main, NULL, lib_nodetree_do_versions_group_indices_cb);
- }
+ FOREACH_NODETREE(main, ntree, id) {
+ /* updates external links for all group nodes in a tree */
+ bNode *node;
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == NODE_GROUP) {
+ bNodeTree *ngroup = (bNodeTree*)node->id;
+ if (ngroup && (ngroup->flag & NTREE_DO_VERSIONS_GROUP_EXPOSE_2_56_2))
+ lib_node_do_versions_group_indices(node);
+ }
+ }
+ } FOREACH_NODETREE_END
}
for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next)
- ntree->flag &= ~NTREE_DO_VERSIONS_GROUP_EXPOSE;
+ ntree->flag &= ~NTREE_DO_VERSIONS_GROUP_EXPOSE_2_56_2;
}
+
+ {
+ /* Convert the previously used ntree->inputs/ntree->outputs lists to interface nodes.
+ * Pre 2.56.2 node trees automatically have all unlinked sockets exposed already
+ * (see NTREE_DO_VERSIONS_GROUP_EXPOSE_2_56_2).
+ *
+ * XXX this should actually be part of do_versions,
+ * but needs valid typeinfo pointers to create interface nodes.
+ */
+ for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
+ if (ntree->flag & NTREE_DO_VERSIONS_CUSTOMNODES_GROUP) {
+ bNode *input_node = NULL, *output_node = NULL;
+ int num_inputs = 0, num_outputs = 0;
+ bNodeLink *link, *next_link;
+ /* Only create new interface nodes for actual older files.
+ * New file versions already have input/output nodes with duplicate links,
+ * in that case just remove the invalid links.
+ */
+ int create_io_nodes = (ntree->flag & NTREE_DO_VERSIONS_CUSTOMNODES_GROUP_CREATE_INTERFACE);
+
+ float input_locx = 1000000.0f, input_locy = 0.0f;
+ float output_locx = -1000000.0f, output_locy = 0.0f;
+ /* rough guess, not nice but we don't have access to UI constants here ... */
+ static const float offsetx = 42 + 3*20 + 20;
+ /*static const float offsety = 0.0f;*/
+
+ if (create_io_nodes) {
+ if (ntree->inputs.first)
+ input_node = nodeAddStaticNode(NULL, ntree, NODE_GROUP_INPUT);
+
+ if (ntree->outputs.first)
+ output_node = nodeAddStaticNode(NULL, ntree, NODE_GROUP_OUTPUT);
+ }
+
+ /* Redirect links from/to the node tree interface to input/output node.
+ * If the fromnode/tonode pointers are NULL, this means a link from/to
+ * the ntree interface sockets, which need to be redirected to new interface nodes.
+ */
+ for (link = ntree->links.first; link; link = next_link) {
+ int free_link = FALSE;
+ next_link = link->next;
+
+ if (link->fromnode == NULL) {
+ if (input_node) {
+ link->fromnode = input_node;
+ link->fromsock = node_group_input_find_socket(input_node, link->fromsock->identifier);
+ ++num_inputs;
+
+ if (input_locx > link->tonode->locx - offsetx)
+ input_locx = link->tonode->locx - offsetx;
+ input_locy += link->tonode->locy;
+ }
+ else
+ free_link = TRUE;
+ }
+
+ if (link->tonode == NULL) {
+ if (output_node) {
+ link->tonode = output_node;
+ link->tosock = node_group_output_find_socket(output_node, link->tosock->identifier);
+ ++num_outputs;
+
+ if (output_locx < link->fromnode->locx + offsetx)
+ output_locx = link->fromnode->locx + offsetx;
+ output_locy += link->fromnode->locy;
+ }
+ else
+ free_link = TRUE;
+ }
+
+ if (free_link)
+ nodeRemLink(ntree, link);
+ }
+
+ if (num_inputs > 0) {
+ input_locy /= num_inputs;
+ input_node->locx = input_locx;
+ input_node->locy = input_locy;
+ }
+ if (num_outputs > 0) {
+ output_locy /= num_outputs;
+ output_node->locx = output_locx;
+ output_node->locy = output_locy;
+ }
+
+ /* clear do_versions flags */
+ ntree->flag &= ~(NTREE_DO_VERSIONS_CUSTOMNODES_GROUP | NTREE_DO_VERSIONS_CUSTOMNODES_GROUP_CREATE_INTERFACE);
+ }
+ }
+ }
+
/* verify all group user nodes */
for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
ntreeVerifyNodes(main, &ntree->id);
@@ -2489,21 +2549,22 @@ static void lib_verify_nodetree(Main *main, int UNUSED(open))
/* make update calls where necessary */
{
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next)
+ FOREACH_NODETREE(main, ntree, id) {
+ /* make an update call for the tree */
if (ntree->update)
ntreeUpdateTree(ntree);
-
- for (i = 0; i < NUM_NTREE_TYPES; i++) {
- ntreetype = ntreeGetType(i);
- if (ntreetype && ntreetype->foreach_nodetree)
- ntreetype->foreach_nodetree(main, NULL, lib_nodetree_do_versions_update_cb);
- }
+ } FOREACH_NODETREE_END
}
}
static void direct_link_node_socket(FileData *fd, bNodeSocket *sock)
{
+ sock->prop = newdataadr(fd, sock->prop);
+ if (sock->prop)
+ IDP_DirectLinkProperty(sock->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+
sock->link = newdataadr(fd, sock->link);
+ sock->typeinfo = NULL;
sock->storage = newdataadr(fd, sock->storage);
sock->default_value = newdataadr(fd, sock->default_value);
sock->cache = NULL;
@@ -2518,6 +2579,10 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
bNodeLink *link;
ntree->init = 0; /* to set callbacks and force setting types */
+ ntree->is_updating = FALSE;
+ ntree->typeinfo= NULL;
+ ntree->interface_type = NULL;
+
ntree->progress = NULL;
ntree->execdata = NULL;
@@ -2533,6 +2598,10 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
link_list(fd, &node->inputs);
link_list(fd, &node->outputs);
+ node->prop = newdataadr(fd, node->prop);
+ if (node->prop)
+ IDP_DirectLinkProperty(node->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+
link_list(fd, &node->internal_links);
for (link = node->internal_links.first; link; link = link->next) {
link->fromnode = newdataadr(fd, link->fromnode);
@@ -2544,8 +2613,9 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
if (node->type == CMP_NODE_MOVIEDISTORTION) {
node->storage = newmclipadr(fd, node->storage);
}
- else
+ else {
node->storage = newdataadr(fd, node->storage);
+ }
if (node->storage) {
/* could be handlerized at some point */
@@ -2556,9 +2626,6 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
else if (node->type==SH_NODE_SCRIPT) {
NodeShaderScript *nss = (NodeShaderScript *) node->storage;
nss->bytecode = newdataadr(fd, nss->bytecode);
- nss->prop = newdataadr(fd, nss->prop);
- if (nss->prop)
- IDP_DirectLinkProperty(nss->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
}
else if (ntree->type==NTREE_COMPOSIT) {
@@ -2577,14 +2644,9 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
}
link_list(fd, &ntree->links);
- /* external sockets */
- link_list(fd, &ntree->inputs);
- link_list(fd, &ntree->outputs);
-
/* and we connect the rest */
for (node = ntree->nodes.first; node; node = node->next) {
node->parent = newdataadr(fd, node->parent);
- node->preview = newimaadr(fd, node->preview);
node->lasty = 0;
for (sock = node->inputs.first; sock; sock = sock->next)
@@ -2592,6 +2654,10 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
for (sock = node->outputs.first; sock; sock = sock->next)
direct_link_node_socket(fd, sock);
}
+
+ /* interface socket lists */
+ link_list(fd, &ntree->inputs);
+ link_list(fd, &ntree->outputs);
for (sock = ntree->inputs.first; sock; sock = sock->next)
direct_link_node_socket(fd, sock);
for (sock = ntree->outputs.first; sock; sock = sock->next)
@@ -2604,6 +2670,29 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
link->tosock = newdataadr(fd, link->tosock);
}
+#if 0
+ if (ntree->previews) {
+ bNodeInstanceHash *new_previews = BKE_node_instance_hash_new("node previews");
+ bNodeInstanceHashIterator iter;
+
+ NODE_INSTANCE_HASH_ITER(iter, ntree->previews) {
+ bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter);
+ if (preview) {
+ bNodePreview *new_preview = newimaadr(fd, preview);
+ if (new_preview) {
+ bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
+ BKE_node_instance_hash_insert(new_previews, key, new_preview);
+ }
+ }
+ }
+ BKE_node_instance_hash_free(ntree->previews, NULL);
+ ntree->previews = new_previews;
+ }
+#else
+ /* XXX TODO */
+ ntree->previews = NULL;
+#endif
+
/* type verification is in lib-link */
}
@@ -5543,28 +5632,34 @@ static void lib_link_screen(FileData *fd, Main *main)
}
else if (sl->spacetype == SPACE_NODE) {
SpaceNode *snode = (SpaceNode *)sl;
+ bNodeTreePath *path, *path_next;
- snode->id = newlibadr(fd, sc->id.lib, snode->id);
+ for (path=snode->treepath.first; path; path=path->next) {
+ path->nodetree = newlibadr(fd, sc->id.lib, path->nodetree);
+
+ if (!path->nodetree)
+ break;
+ }
- if (ELEM3(snode->treetype, NTREE_COMPOSIT, NTREE_SHADER, NTREE_TEXTURE)) {
- /* internal data, a bit patchy */
- snode->nodetree = NULL;
- if (snode->id) {
- if (GS(snode->id->name)==ID_MA)
- snode->nodetree = ((Material *)snode->id)->nodetree;
- else if (GS(snode->id->name)==ID_WO)
- snode->nodetree = ((World *)snode->id)->nodetree;
- else if (GS(snode->id->name)==ID_LA)
- snode->nodetree = ((Lamp *)snode->id)->nodetree;
- else if (GS(snode->id->name)==ID_SCE)
- snode->nodetree = ((Scene *)snode->id)->nodetree;
- else if (GS(snode->id->name)==ID_TE)
- snode->nodetree = ((Tex *)snode->id)->nodetree;
- }
+ /* remaining path entries are invalid, remove */
+ for (; path; path = path_next) {
+ path_next = path->next;
+
+ BLI_remlink(&snode->treepath, path);
+ MEM_freeN(path);
}
- else {
- snode->nodetree = newlibadr_us(fd, sc->id.lib, snode->nodetree);
+
+ snode->nodetree = newlibadr(fd, sc->id.lib, snode->nodetree);
+ /* edittree is just the last in the path,
+ * set this directly since the path may have been shortened above */
+ if (snode->treepath.last) {
+ path = snode->treepath.last;
+ snode->edittree = path->nodetree;
}
+ else
+ snode->edittree = NULL;
+ snode->id = newlibadr(fd, sc->id.lib, snode->id);
+ snode->from = newlibadr(fd, sc->id.lib, snode->from);
}
else if (sl->spacetype == SPACE_CLIP) {
SpaceClip *sclip = (SpaceClip *)sl;
@@ -5584,6 +5679,24 @@ static void lib_link_screen(FileData *fd, Main *main)
}
}
+static bool restore_pointer(ID *id, ID *newid, int user)
+{
+ if (strcmp(newid->name+2, id->name+2) == 0) {
+ if (newid->lib == id->lib) {
+ if (user == 1) {
+ if (newid->us == 0) {
+ newid->us++;
+ }
+ }
+ else if (user == 2) {
+ id_us_ensure_real(newid);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
/**
* Only for undo files, or to restore a screen after reading without UI...
*
@@ -5595,30 +5708,33 @@ static void lib_link_screen(FileData *fd, Main *main)
static void *restore_pointer_by_name(Main *mainp, ID *id, int user)
{
if (id) {
- ListBase *lb = which_libbase(mainp, GS(id->name));
-
- if (lb) { // there's still risk of checking corrupt mem (freed Ids in oops)
- ID *idn = lb->first;
- char *name = id->name + 2;
-
- for (; idn; idn = idn->next) {
- if (idn->name[2] == name[0] && strcmp(idn->name+2, name) == 0) {
- if (idn->lib == id->lib) {
- if (user == 1) {
- if (idn->us == 0) {
- idn->us++;
- }
- }
- else if (user == 2) {
- id_us_ensure_real(idn);
- }
- break;
- }
+ /* node trees can be stored locally in other IDs, needs special handling ... */
+ if (GS(id->name) == ID_NT) {
+ ID *idn = NULL;
+
+ FOREACH_NODETREE(mainp, ntree, owner_id) {
+ if (restore_pointer(id, &ntree->id, user)) {
+ idn = &ntree->id;
+ break;
}
}
+ FOREACH_NODETREE_END
return idn;
}
+ else {
+ ListBase *lb = which_libbase(mainp, GS(id->name));
+ if (lb) { // there's still risk of checking corrupt mem (freed Ids in oops)
+ ID *idn = lb->first;
+
+ for (; idn; idn = idn->next) {
+ if (restore_pointer(id, idn, user))
+ break;
+ }
+
+ return idn;
+ }
+ }
}
return NULL;
}
@@ -5848,24 +5964,34 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
}
else if (sl->spacetype == SPACE_NODE) {
SpaceNode *snode= (SpaceNode *)sl;
+ bNodeTreePath *path, *path_next;
- snode->id = restore_pointer_by_name(newmain, snode->id, 1);
- snode->edittree = NULL;
+ for (path=snode->treepath.first; path; path=path->next) {
+ path->nodetree= restore_pointer_by_name(newmain, (ID*)path->nodetree, 0);
+
+ if (!path->nodetree)
+ break;
+ }
- if (ELEM3(snode->treetype, NTREE_COMPOSIT, NTREE_SHADER, NTREE_TEXTURE)) {
- snode->nodetree = NULL;
- if (snode->id) {
- if (GS(snode->id->name)==ID_MA)
- snode->nodetree = ((Material *)snode->id)->nodetree;
- else if (GS(snode->id->name)==ID_SCE)
- snode->nodetree = ((Scene *)snode->id)->nodetree;
- else if (GS(snode->id->name)==ID_TE)
- snode->nodetree = ((Tex *)snode->id)->nodetree;
- }
+ /* remaining path entries are invalid, remove */
+ for (; path; path = path_next) {
+ path_next = path->next;
+
+ BLI_remlink(&snode->treepath, path);
+ MEM_freeN(path);
}
- else {
- snode->nodetree= restore_pointer_by_name(newmain, &snode->nodetree->id, 1);
+
+ snode->nodetree = restore_pointer_by_name(newmain, (ID*)snode->nodetree, 0);
+ /* edittree is just the last in the path,
+ * set this directly since the path may have been shortened above */
+ if (snode->treepath.last) {
+ path = snode->treepath.last;
+ snode->edittree = path->nodetree;
}
+ else
+ snode->edittree = NULL;
+ snode->id = restore_pointer_by_name(newmain, snode->id, 1);
+ snode->from = restore_pointer_by_name(newmain, snode->from, 0);
}
else if (sl->spacetype == SPACE_CLIP) {
SpaceClip *sclip = (SpaceClip *)sl;
@@ -6116,6 +6242,8 @@ static void direct_link_screen(FileData *fd, bScreen *sc)
snode->gpd = newdataadr(fd, snode->gpd);
direct_link_gpencil(fd, snode->gpd);
}
+
+ link_list(fd, &snode->treepath);
snode->edittree = NULL;
snode->linkdrag.first = snode->linkdrag.last = NULL;
}
@@ -6855,7 +6983,6 @@ static void link_global(FileData *fd, BlendFileData *bfd)
}
}
-/* deprecated, only keep this for readfile.c */
void convert_tface_mt(FileData *fd, Main *main)
{
Main *gmain;
@@ -6890,22 +7017,6 @@ static void do_versions_nodetree_image_default_alpha_output(bNodeTree *ntree)
}
}
-static void do_version_ntree_tex_mapping_260(void *UNUSED(data), ID *UNUSED(id), bNodeTree *ntree)
-{
- bNode *node;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == SH_NODE_MAPPING) {
- TexMapping *tex_mapping;
-
- tex_mapping= node->storage;
- tex_mapping->projx= PROJ_X;
- tex_mapping->projy= PROJ_Y;
- tex_mapping->projz= PROJ_Z;
- }
- }
-}
-
static void do_versions_nodetree_convert_angle(bNodeTree *ntree)
{
bNode *node;
@@ -7240,151 +7351,6 @@ static void do_versions_nodetree_frame_2_64_6(bNodeTree *ntree)
}
}
-static void do_version_ntree_image_user_264(void *UNUSED(data), ID *UNUSED(id), bNodeTree *ntree)
-{
- bNode *node;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT)) {
- NodeTexImage *tex = node->storage;
-
- tex->iuser.frames= 1;
- tex->iuser.sfra= 1;
- tex->iuser.fie_ima= 2;
- tex->iuser.ok= 1;
- }
- }
-}
-
-static void do_version_ntree_dilateerode_264(void *UNUSED(data), ID *UNUSED(id), bNodeTree *ntree)
-{
- bNode *node;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == CMP_NODE_DILATEERODE) {
- if (node->storage == NULL) {
- NodeDilateErode *data = MEM_callocN(sizeof(NodeDilateErode), __func__);
- data->falloff = PROP_SMOOTH;
- node->storage = data;
- }
- }
- }
-}
-
-static void do_version_ntree_defocus_264(void *UNUSED(data), ID *UNUSED(id), bNodeTree *ntree)
-{
- bNode *node;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == CMP_NODE_DEFOCUS) {
- NodeDefocus *data = node->storage;
- if (data->maxblur == 0.0f) {
- data->maxblur = 16.0f;
- }
- }
- }
-}
-
-static void do_version_ntree_mask_264(void *UNUSED(data), ID *UNUSED(id), bNodeTree *ntree)
-{
- bNode *node;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == CMP_NODE_MASK) {
- if (node->storage == NULL) {
- NodeMask *data = MEM_callocN(sizeof(NodeMask), __func__);
- /* move settings into own struct */
- data->size_x = (int)node->custom3;
- data->size_y = (int)node->custom4;
- node->custom3 = 0.5f; /* default shutter */
- node->storage = data;
- }
- }
- }
-}
-
-static void do_version_ntree_keying_despill_balance(void *UNUSED(data), ID *UNUSED(id), bNodeTree *ntree)
-{
- bNode *node;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == CMP_NODE_KEYING) {
- NodeKeyingData *data = node->storage;
-
- if (data->despill_balance == 0.0f) {
- data->despill_balance = 0.5f;
- }
- }
- }
-}
-
-static void do_version_ntree_tex_coord_from_dupli_264(void *UNUSED(data), ID *UNUSED(id), bNodeTree *ntree)
-{
- bNode *node;
-
- for (node = ntree->nodes.first; node; node = node->next)
- if (node->type == SH_NODE_TEX_COORD)
- node->flag |= NODE_OPTIONS;
-}
-
-static void do_version_node_cleanup_dynamic_sockets_264(void *UNUSED(data), ID *UNUSED(id), bNodeTree *ntree)
-{
- bNode *node;
- bNodeSocket *sock;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (!ELEM(node->type, NODE_GROUP, CMP_NODE_IMAGE)) {
- for (sock = node->inputs.first; sock; sock = sock->next)
- sock->flag &= ~SOCK_DYNAMIC;
- for (sock = node->outputs.first; sock; sock = sock->next)
- sock->flag &= ~SOCK_DYNAMIC;
- }
- }
-}
-
-static void do_version_node_fix_translate_wrapping(void *UNUSED(data), ID *UNUSED(id), bNodeTree *ntree)
-{
- bNode *node;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == CMP_NODE_TRANSLATE && node->storage == NULL) {
- node->storage = MEM_callocN(sizeof(NodeTranslateData), "node translate data");
- }
- }
-}
-
-static void do_version_node_straight_image_alpha_workaround(void *data, ID *UNUSED(id), bNodeTree *ntree)
-{
- FileData *fd = (FileData *) data;
- bNode *node;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == CMP_NODE_IMAGE) {
- Image *image = blo_do_versions_newlibadr(fd, ntree->id.lib, node->id);
-
- if (image) {
- if ((image->flag & IMA_DO_PREMUL) == 0 && image->alpha_mode == IMA_ALPHA_STRAIGHT)
- node->custom1 |= CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT;
- }
- }
- }
-}
-
-static void do_version_node_fix_internal_links_264(void *UNUSED(data), ID *UNUSED(id), bNodeTree *ntree)
-{
- bNode *node;
- bNodeLink *link, *nextlink;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- for (link = node->internal_links.first; link; link = nextlink) {
- nextlink = link->next;
- if (!link->fromnode || !link->fromsock || !link->tonode || !link->tosock) {
- BLI_remlink(&node->internal_links, link);
- }
- }
- }
-}
-
static void do_version_logic_264(ListBase *regionbase)
{
ARegion *ar;
@@ -7436,6 +7402,146 @@ static void do_versions_affine_tracker_track(MovieTrackingTrack *track)
}
}
+
+static const char *node_get_static_idname(int type, int treetype)
+{
+ /* use static type info header to map static int type to identifier string */
+ #define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \
+ case ID: return #Category #StructName;
+
+ /* XXX hack, group types share a single static integer identifier, but are registered as separate types */
+ if (type == NODE_GROUP) {
+ switch (treetype) {
+ case NTREE_COMPOSIT: return "CompositorNodeGroup";
+ case NTREE_SHADER: return "ShaderNodeGroup";
+ case NTREE_TEXTURE: return "TextureNodeGroup";
+ }
+ }
+ else {
+ switch (type) {
+ #include "NOD_static_types.h"
+ }
+ }
+ return "";
+}
+
+static const char *node_socket_get_static_idname(bNodeSocket *sock)
+{
+ switch (sock->type) {
+ case SOCK_FLOAT: {
+ bNodeSocketValueFloat *dval = sock->default_value;
+ return nodeStaticSocketType(SOCK_FLOAT, dval->subtype);
+ }
+ case SOCK_INT: {
+ bNodeSocketValueInt *dval = sock->default_value;
+ return nodeStaticSocketType(SOCK_INT, dval->subtype);
+ }
+ case SOCK_BOOLEAN: {
+ return nodeStaticSocketType(SOCK_BOOLEAN, PROP_NONE);
+ }
+ case SOCK_VECTOR: {
+ bNodeSocketValueVector *dval = sock->default_value;
+ return nodeStaticSocketType(SOCK_VECTOR, dval->subtype);
+ }
+ case SOCK_RGBA: {
+ return nodeStaticSocketType(SOCK_RGBA, PROP_NONE);
+ }
+ case SOCK_STRING: {
+ bNodeSocketValueString *dval = sock->default_value;
+ return nodeStaticSocketType(SOCK_STRING, dval->subtype);
+ }
+ case SOCK_SHADER: {
+ return nodeStaticSocketType(SOCK_SHADER, PROP_NONE);
+ }
+ }
+ return "";
+}
+
+static void do_versions_nodetree_customnodes(bNodeTree *ntree, int UNUSED(is_group))
+{
+ /* initialize node tree type idname */
+ {
+ bNode *node;
+ bNodeSocket *sock;
+
+ ntree->typeinfo = NULL;
+
+ /* tree type idname */
+ switch (ntree->type) {
+ case NTREE_COMPOSIT:
+ strcpy(ntree->idname, "CompositorNodeTree");
+ break;
+ case NTREE_SHADER:
+ strcpy(ntree->idname, "ShaderNodeTree");
+ break;
+ case NTREE_TEXTURE:
+ strcpy(ntree->idname, "TextureNodeTree");
+ break;
+ }
+
+ /* node type idname */
+ for (node=ntree->nodes.first; node; node=node->next) {
+ BLI_strncpy(node->idname, node_get_static_idname(node->type, ntree->type), sizeof(node->idname));
+
+ /* existing old nodes have been initialized already */
+ node->flag |= NODE_INIT;
+
+ /* sockets idname */
+ for (sock=node->inputs.first; sock; sock=sock->next)
+ BLI_strncpy(sock->idname, node_socket_get_static_idname(sock), sizeof(sock->idname));
+ for (sock=node->outputs.first; sock; sock=sock->next)
+ BLI_strncpy(sock->idname, node_socket_get_static_idname(sock), sizeof(sock->idname));
+ }
+ /* tree sockets idname */
+ for (sock=ntree->inputs.first; sock; sock=sock->next)
+ BLI_strncpy(sock->idname, node_socket_get_static_idname(sock), sizeof(sock->idname));
+ for (sock=ntree->outputs.first; sock; sock=sock->next)
+ BLI_strncpy(sock->idname, node_socket_get_static_idname(sock), sizeof(sock->idname));
+ }
+
+ /* initialize socket in_out values */
+ {
+ bNode *node;
+ bNodeSocket *sock;
+
+ for (node=ntree->nodes.first; node; node=node->next) {
+ for (sock=node->inputs.first; sock; sock=sock->next)
+ sock->in_out = SOCK_IN;
+ for (sock=node->outputs.first; sock; sock=sock->next)
+ sock->in_out = SOCK_OUT;
+ }
+ for (sock=ntree->inputs.first; sock; sock=sock->next)
+ sock->in_out = SOCK_IN;
+ for (sock=ntree->outputs.first; sock; sock=sock->next)
+ sock->in_out = SOCK_OUT;
+ }
+
+ /* initialize socket identifier strings */
+ {
+ bNode *node;
+ bNodeSocket *sock;
+
+ for (node=ntree->nodes.first; node; node=node->next) {
+ for (sock=node->inputs.first; sock; sock=sock->next) {
+ BLI_strncpy(sock->identifier, sock->name, sizeof(sock->identifier));
+ BLI_uniquename(&node->inputs, sock, sock->identifier, '.', offsetof(bNodeSocket, identifier), sizeof(sock->identifier));
+ }
+ for (sock=node->outputs.first; sock; sock=sock->next) {
+ BLI_strncpy(sock->identifier, sock->name, sizeof(sock->identifier));
+ BLI_uniquename(&node->outputs, sock, sock->identifier, '.', offsetof(bNodeSocket, identifier), sizeof(sock->identifier));
+ }
+ }
+ for (sock=ntree->inputs.first; sock; sock=sock->next) {
+ BLI_strncpy(sock->identifier, sock->name, sizeof(sock->identifier));
+ BLI_uniquename(&ntree->inputs, sock, sock->identifier, '.', offsetof(bNodeSocket, identifier), sizeof(sock->identifier));
+ }
+ for (sock=ntree->outputs.first; sock; sock=sock->next) {
+ BLI_strncpy(sock->identifier, sock->name, sizeof(sock->identifier));
+ BLI_uniquename(&ntree->outputs, sock, sock->identifier, '.', offsetof(bNodeSocket, identifier), sizeof(sock->identifier));
+ }
+ }
+}
+
/* initialize userdef with non-UI dependency stuff */
/* other initializers (such as theme color defaults) go to resources.c */
static void do_versions_userdef(FileData *fd, BlendFileData *bfd)
@@ -7451,7 +7557,6 @@ static void do_versions_userdef(FileData *fd, BlendFileData *bfd)
user->image_gpubuffer_limit = 10;
}
}
-
static void do_versions(FileData *fd, Library *lib, Main *main)
{
/* WATCH IT!!!: pointers from libdata have not been converted */
@@ -7517,10 +7622,21 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
if (main->versionfile < 260 || (main->versionfile == 260 && main->subversionfile < 2)) {
- bNodeTreeType *ntreetype = ntreeGetType(NTREE_SHADER);
-
- if (ntreetype && ntreetype->foreach_nodetree)
- ntreetype->foreach_nodetree(main, NULL, do_version_ntree_tex_mapping_260);
+ FOREACH_NODETREE(main, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ bNode *node;
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_MAPPING) {
+ TexMapping *tex_mapping;
+
+ tex_mapping= node->storage;
+ tex_mapping->projx= PROJ_X;
+ tex_mapping->projy= PROJ_Y;
+ tex_mapping->projz= PROJ_Z;
+ }
+ }
+ }
+ } FOREACH_NODETREE_END
}
if (main->versionfile < 260 || (main->versionfile == 260 && main->subversionfile < 4)) {
@@ -8156,16 +8272,26 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 9)) {
- bNodeTreeType *ntreetype = ntreeGetType(NTREE_SHADER);
-
- if (ntreetype && ntreetype->foreach_nodetree)
- ntreetype->foreach_nodetree(main, NULL, do_version_ntree_image_user_264);
+ FOREACH_NODETREE(main, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ bNode *node;
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT)) {
+ NodeTexImage *tex = node->storage;
+
+ tex->iuser.frames= 1;
+ tex->iuser.sfra= 1;
+ tex->iuser.fie_ima= 2;
+ tex->iuser.ok= 1;
+ }
+ }
+ }
+ } FOREACH_NODETREE_END
}
if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 10)) {
{
Scene *scene;
- bNodeTreeType *ntreetype;
// composite redesign
for (scene=main->scene.first; scene; scene=scene->id.next) {
if (scene->nodetree) {
@@ -8174,11 +8300,20 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
}
}
- ntreetype = ntreeGetType(NTREE_COMPOSIT);
-
- if (ntreetype && ntreetype->foreach_nodetree)
- ntreetype->foreach_nodetree(main, NULL, do_version_ntree_defocus_264);
+ FOREACH_NODETREE(main, ntree, id) {
+ if (ntree->type == NTREE_COMPOSIT) {
+ bNode *node;
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_DEFOCUS) {
+ NodeDefocus *data = node->storage;
+ if (data->maxblur == 0.0f) {
+ data->maxblur = 16.0f;
+ }
+ }
+ }
+ }
+ } FOREACH_NODETREE_END
}
{
@@ -8236,19 +8371,40 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 13)) {
- bNodeTreeType *ntreetype = ntreeGetType(NTREE_COMPOSIT);
-
- if (ntreetype && ntreetype->foreach_nodetree)
- ntreetype->foreach_nodetree(main, NULL, do_version_ntree_dilateerode_264);
+ FOREACH_NODETREE(main, ntree, id) {
+ if (ntree->type == NTREE_COMPOSIT) {
+ bNode *node;
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_DILATEERODE) {
+ if (node->storage == NULL) {
+ NodeDilateErode *data = MEM_callocN(sizeof(NodeDilateErode), __func__);
+ data->falloff = PROP_SMOOTH;
+ node->storage = data;
+ }
+ }
+ }
+ }
+ } FOREACH_NODETREE_END
}
if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 14)) {
ParticleSettings *part;
- bNodeTreeType *ntreetype = ntreeGetType(NTREE_COMPOSIT);
-
- if (ntreetype && ntreetype->foreach_nodetree)
- ntreetype->foreach_nodetree(main, NULL, do_version_ntree_keying_despill_balance);
-
+
+ FOREACH_NODETREE(main, ntree, id) {
+ if (ntree->type == NTREE_COMPOSIT) {
+ bNode *node;
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_KEYING) {
+ NodeKeyingData *data = node->storage;
+
+ if (data->despill_balance == 0.0f) {
+ data->despill_balance = 0.5f;
+ }
+ }
+ }
+ }
+ } FOREACH_NODETREE_END
+
/* keep compatibility for dupliobject particle size */
for (part=main->particle.first; part; part=part->id.next)
if (ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR))
@@ -8257,12 +8413,25 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 17)) {
- bNodeTreeType *ntreetype = ntreeGetType(NTREE_COMPOSIT);
-
- if (ntreetype && ntreetype->foreach_nodetree)
- ntreetype->foreach_nodetree(main, NULL, do_version_ntree_mask_264);
+ FOREACH_NODETREE(main, ntree, id) {
+ if (ntree->type == NTREE_COMPOSIT) {
+ bNode *node;
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_MASK) {
+ if (node->storage == NULL) {
+ NodeMask *data = MEM_callocN(sizeof(NodeMask), __func__);
+ /* move settings into own struct */
+ data->size_x = (int)node->custom3;
+ data->size_y = (int)node->custom4;
+ node->custom3 = 0.5f; /* default shutter */
+ node->storage = data;
+ }
+ }
+ }
+ }
+ } FOREACH_NODETREE_END
}
-
+
if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 18)) {
Scene *scene;
@@ -8387,15 +8556,14 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
if (main->versionfile < 264 || (main->versionfile == 264 && main->subversionfile < 1)) {
- bNodeTreeType *ntreetype = ntreeGetType(NTREE_SHADER);
- bNodeTree *ntree;
-
- if (ntreetype && ntreetype->foreach_nodetree)
- ntreetype->foreach_nodetree(main, NULL, do_version_ntree_tex_coord_from_dupli_264);
-
- for (ntree=main->nodetree.first; ntree; ntree=ntree->id.next)
- if (ntree->type==NTREE_SHADER)
- do_version_ntree_tex_coord_from_dupli_264(NULL, NULL, ntree);
+ FOREACH_NODETREE(main, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ bNode *node;
+ for (node = ntree->nodes.first; node; node = node->next)
+ if (node->type == SH_NODE_TEX_COORD)
+ node->flag |= NODE_OPTIONS;
+ }
+ } FOREACH_NODETREE_END
}
if (main->versionfile < 264 || (main->versionfile == 264 && main->subversionfile < 2)) {
@@ -8481,28 +8649,6 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 264 || (main->versionfile == 264 && main->subversionfile < 4)) {
- /* Fix for old node flags: Apparently the SOCK_DYNAMIC flag has been in use for other
- * purposes before and then removed and later reused for SOCK_DYNAMIC. This socket should
- * only be used by certain node types which don't use template lists, cleaning this up here.
- */
- bNodeTreeType *ntreetype;
- bNodeTree *ntree;
-
- ntreetype = ntreeGetType(NTREE_COMPOSIT);
- if (ntreetype && ntreetype->foreach_nodetree)
- ntreetype->foreach_nodetree(main, NULL, do_version_node_cleanup_dynamic_sockets_264);
- ntreetype = ntreeGetType(NTREE_SHADER);
- if (ntreetype && ntreetype->foreach_nodetree)
- ntreetype->foreach_nodetree(main, NULL, do_version_node_cleanup_dynamic_sockets_264);
- ntreetype = ntreeGetType(NTREE_TEXTURE);
- if (ntreetype && ntreetype->foreach_nodetree)
- ntreetype->foreach_nodetree(main, NULL, do_version_node_cleanup_dynamic_sockets_264);
-
- for (ntree=main->nodetree.first; ntree; ntree=ntree->id.next)
- do_version_node_cleanup_dynamic_sockets_264(NULL, NULL, ntree);
- }
-
if (main->versionfile < 264 || (main->versionfile == 264 && main->subversionfile < 5)) {
/* set a unwrapping margin and ABF by default */
Scene *scene;
@@ -8519,22 +8665,19 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
/* Fix for bug #32982, internal_links list could get corrupted from r51630 onward.
* Simply remove bad internal_links lists to avoid NULL pointers.
*/
- bNodeTreeType *ntreetype;
- bNodeTree *ntree;
-
- ntreetype = ntreeGetType(NTREE_COMPOSIT);
- if (ntreetype && ntreetype->foreach_nodetree)
- ntreetype->foreach_nodetree(main, NULL, do_version_node_fix_internal_links_264);
- ntreetype = ntreeGetType(NTREE_SHADER);
- if (ntreetype && ntreetype->foreach_nodetree)
- ntreetype->foreach_nodetree(main, NULL, do_version_node_fix_internal_links_264);
- ntreetype = ntreeGetType(NTREE_TEXTURE);
- if (ntreetype && ntreetype->foreach_nodetree)
- ntreetype->foreach_nodetree(main, NULL, do_version_node_fix_internal_links_264);
-
- for (ntree=main->nodetree.first; ntree; ntree=ntree->id.next)
- do_version_node_fix_internal_links_264(NULL, NULL, ntree);
-
+ FOREACH_NODETREE(main, ntree, id)
+ bNode *node;
+ bNodeLink *link, *nextlink;
+
+ for (node = ntree->nodes.first; node; node = node->next) {
+ for (link = node->internal_links.first; link; link = nextlink) {
+ nextlink = link->next;
+ if (!link->fromnode || !link->fromsock || !link->tonode || !link->tosock) {
+ BLI_remlink(&node->internal_links, link);
+ }
+ }
+ }
+ FOREACH_NODETREE_END
}
if (main->versionfile < 264 || (main->versionfile == 264 && main->subversionfile < 6)) {
@@ -8678,8 +8821,6 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
Scene *scene;
Image *image;
Tex *tex;
- bNodeTreeType *ntreetype;
- bNodeTree *ntree;
for (scene = main->scene.first; scene; scene = scene->id.next) {
Sequence *seq;
@@ -8735,12 +8876,21 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
}
- ntreetype = ntreeGetType(NTREE_COMPOSIT);
- if (ntreetype && ntreetype->foreach_nodetree)
- ntreetype->foreach_nodetree(main, fd, do_version_node_straight_image_alpha_workaround);
+ FOREACH_NODETREE(main, ntree, id) {
+ if (ntree->type == NTREE_COMPOSIT) {
+ bNode *node;
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_IMAGE) {
+ Image *image = blo_do_versions_newlibadr(fd, ntree->id.lib, node->id);
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next)
- do_version_node_straight_image_alpha_workaround(fd, NULL, ntree);
+ if (image) {
+ if ((image->flag & IMA_DO_PREMUL) == 0 && image->alpha_mode == IMA_ALPHA_STRAIGHT)
+ node->custom1 |= CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT;
+ }
+ }
+ }
+ }
+ } FOREACH_NODETREE_END
}
else if (main->versionfile < 266 || (main->versionfile == 266 && main->subversionfile < 1)) {
/* texture use alpha was removed for 2.66 but added back again for 2.66a,
@@ -8805,15 +8955,76 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
// add storage for compositor translate nodes when not existing
if (MAIN_VERSION_OLDER(main, 265, 11)) {
- bNodeTreeType *ntreetype;
- bNodeTree *ntree;
+ FOREACH_NODETREE(main, ntree, id) {
+ if (ntree->type == NTREE_COMPOSIT) {
+ bNode *node;
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_TRANSLATE && node->storage == NULL) {
+ node->storage = MEM_callocN(sizeof(NodeTranslateData), "node translate data");
+ }
+ }
+ }
+ } FOREACH_NODETREE_END
+ }
- ntreetype = ntreeGetType(NTREE_COMPOSIT);
- if (ntreetype && ntreetype->foreach_nodetree)
- ntreetype->foreach_nodetree(main, NULL, do_version_node_fix_translate_wrapping);
+ if (!MAIN_VERSION_ATLEAST(main, 266, 2)) {
+ FOREACH_NODETREE(main, ntree, id) {
+ do_versions_nodetree_customnodes(ntree, ((ID *)ntree == id));
+ } FOREACH_NODETREE_END
+ }
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next)
- do_version_node_fix_translate_wrapping(NULL, NULL, ntree);
+ if (!MAIN_VERSION_ATLEAST(main, 266, 2)) {
+ bScreen *sc;
+ for (sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_NODE) {
+ SpaceNode *snode = (SpaceNode *)sl;
+
+ /* reset pointers to force tree path update from context */
+ snode->nodetree = NULL;
+ snode->edittree = NULL;
+ snode->id = NULL;
+ snode->from = NULL;
+
+ /* convert deprecated treetype setting to tree_idname */
+ switch (snode->treetype) {
+ case NTREE_COMPOSIT:
+ strcpy(snode->tree_idname, "CompositorNodeTree");
+ break;
+ case NTREE_SHADER:
+ strcpy(snode->tree_idname, "ShaderNodeTree");
+ break;
+ case NTREE_TEXTURE:
+ strcpy(snode->tree_idname, "TextureNodeTree");
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Set flag for delayed do_versions in lib_verify_nodetree. It needs valid typeinfo pointers ... */
+ {
+ bNodeTree *ntree;
+ for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
+ /* XXX This should be kept without version check for now!
+ * As long as USE_NODE_COMPAT_CUSTOMNODES is active, files will write links
+ * to tree interface sockets for forward compatibility. These links need to be removed again
+ * on file load in new versions.
+ * Once forward compatibility is not required any longer, make a subversion bump
+ * and only execute this for older versions.
+ */
+ ntree->flag |= NTREE_DO_VERSIONS_CUSTOMNODES_GROUP;
+
+ /* Only add interface nodes once.
+ * In old Blender versions they will be removed automatically due to undefined type */
+ if (!MAIN_VERSION_ATLEAST(main, 266, 2))
+ ntree->flag |= NTREE_DO_VERSIONS_CUSTOMNODES_GROUP_CREATE_INTERFACE;
+ }
}
if (main->versionfile < 267) {
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index 46b95434e53..6d5fc056d89 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -152,7 +152,6 @@ void *blo_do_versions_newlibadr_us(struct FileData *fd, void *lib, void *adr);
struct PartEff *blo_do_version_give_parteff_245(struct Object *ob);
void blo_do_version_old_trackto_to_constraints(struct Object *ob);
void blo_do_versions_view3d_split_250(struct View3D *v3d, struct ListBase *regions);
-void blo_do_versions_nodetree_default_value(struct bNodeTree *ntree);
void blo_do_versions_pre250(struct FileData *fd, struct Library *lib, struct Main *main);
void blo_do_versions_250(struct FileData *fd, struct Library *lib, struct Main *main);
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 36f3ea3654c..f92a8678300 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -672,13 +672,90 @@ static void do_version_bone_roll_256(Bone *bone)
do_version_bone_roll_256(child);
}
-static void do_versions_nodetree_dynamic_sockets(bNodeTree *ntree)
+/* deprecated, only keep this for readfile.c */
+/* XXX Deprecated function to add a socket in ntree->inputs/ntree->outputs list
+ * (previously called node_group_add_socket). This function has been superseded
+ * by the implementation of proxy nodes. It is still necessary though
+ * for do_versions of pre-2.56.2 code (r35033), so later proxy nodes
+ * can be generated consistently from ntree socket lists.
+ */
+static bNodeSocket *do_versions_node_group_add_socket_2_56_2(bNodeTree *ngroup, const char *name, int type, int in_out)
+{
+// bNodeSocketType *stype = ntreeGetSocketType(type);
+ bNodeSocket *gsock = MEM_callocN(sizeof(bNodeSocket), "bNodeSocket");
+
+ BLI_strncpy(gsock->name, name, sizeof(gsock->name));
+ gsock->type = type;
+
+ gsock->next = gsock->prev = NULL;
+ gsock->new_sock = NULL;
+ gsock->link = NULL;
+ /* assign new unique index */
+ gsock->own_index = ngroup->cur_index++;
+ gsock->limit = (in_out==SOCK_IN ? 0xFFF : 1);
+
+// if (stype->value_structsize > 0)
+// gsock->default_value = MEM_callocN(stype->value_structsize, "default socket value");
+
+ BLI_addtail(in_out==SOCK_IN ? &ngroup->inputs : &ngroup->outputs, gsock);
+
+ ngroup->update |= (in_out==SOCK_IN ? NTREE_UPDATE_GROUP_IN : NTREE_UPDATE_GROUP_OUT);
+
+ return gsock;
+}
+
+/* Create default_value structs for node sockets from the internal bNodeStack value.
+ * These structs were used from 2.59.2 on, but are replaced in the subsequent do_versions for custom nodes
+ * by generic ID property values. This conversion happened _after_ do_versions originally due to messy type initialization
+ * for node sockets. Now created here intermediately for convenience and to keep do_versions consistent.
+ *
+ * Node compatibility code is gross ...
+ */
+static void do_versions_socket_default_value_259(bNodeSocket *sock)
+{
+ bNodeSocketValueFloat *valfloat;
+ bNodeSocketValueVector *valvector;
+ bNodeSocketValueRGBA *valrgba;
+
+ if (sock->default_value)
+ return;
+
+ switch (sock->type) {
+ case SOCK_FLOAT:
+ valfloat = sock->default_value = MEM_callocN(sizeof(bNodeSocketValueFloat), "default socket value");
+ valfloat->value = sock->ns.vec[0];
+ valfloat->min = sock->ns.min;
+ valfloat->max = sock->ns.max;
+ valfloat->subtype = PROP_NONE;
+ break;
+ case SOCK_VECTOR:
+ valvector = sock->default_value = MEM_callocN(sizeof(bNodeSocketValueVector), "default socket value");
+ copy_v3_v3(valvector->value, sock->ns.vec);
+ valvector->min = sock->ns.min;
+ valvector->max = sock->ns.max;
+ valvector->subtype = PROP_NONE;
+ break;
+ case SOCK_RGBA:
+ valrgba = sock->default_value = MEM_callocN(sizeof(bNodeSocketValueRGBA), "default socket value");
+ copy_v4_v4(valrgba->value, sock->ns.vec);
+ break;
+ }
+}
+
+static void do_versions_nodetree_default_value_259(bNodeTree *ntree)
{
+ bNode *node;
bNodeSocket *sock;
- for (sock = ntree->inputs.first; sock; sock = sock->next)
- sock->flag |= SOCK_DYNAMIC;
- for (sock = ntree->outputs.first; sock; sock = sock->next)
- sock->flag |= SOCK_DYNAMIC;
+ for (node=ntree->nodes.first; node; node=node->next) {
+ for (sock=node->inputs.first; sock; sock=sock->next)
+ do_versions_socket_default_value_259(sock);
+ for (sock=node->outputs.first; sock; sock=sock->next)
+ do_versions_socket_default_value_259(sock);
+ }
+ for (sock=ntree->inputs.first; sock; sock=sock->next)
+ do_versions_socket_default_value_259(sock);
+ for (sock=ntree->outputs.first; sock; sock=sock->next)
+ do_versions_socket_default_value_259(sock);
}
void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
@@ -2289,16 +2366,79 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 2)) {
bNodeTree *ntree;
-
+ bNode *node;
+ bNodeSocket *sock, *gsock;
+ bNodeLink *link;
+
/* node sockets are not exposed automatically any more,
* this mimics the old behavior by adding all unlinked sockets to groups.
*/
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
- /* XXX Only setting a flag here. Actual adding of group sockets
- * is done in lib_verify_nodetree, because at this point the internal
- * nodes may not be up-to-date! (missing lib-link)
+ for (ntree=main->nodetree.first; ntree; ntree=ntree->id.next) {
+ /* this adds copies and links from all unlinked internal sockets to group inputs/outputs. */
+
+ /* first make sure the own_index for new sockets is valid */
+ for (node=ntree->nodes.first; node; node=node->next) {
+ for (sock=node->inputs.first; sock; sock=sock->next)
+ if (sock->own_index >= ntree->cur_index)
+ ntree->cur_index = sock->own_index+1;
+ for (sock=node->outputs.first; sock; sock=sock->next)
+ if (sock->own_index >= ntree->cur_index)
+ ntree->cur_index = sock->own_index+1;
+ }
+
+ /* add ntree->inputs/ntree->outputs sockets for all unlinked sockets in the group tree. */
+ for (node=ntree->nodes.first; node; node=node->next) {
+ for (sock=node->inputs.first; sock; sock=sock->next) {
+ if (!sock->link && !nodeSocketIsHidden(sock)) {
+
+ gsock = do_versions_node_group_add_socket_2_56_2(ntree, sock->name, sock->type, SOCK_IN);
+
+ /* initialize the default socket value */
+ copy_v4_v4(gsock->ns.vec, sock->ns.vec);
+
+ /* XXX nodeAddLink does not work with incomplete (node==NULL) links any longer,
+ * have to create these directly here. These links are updated again in subsequent do_version!
+ */
+ link= MEM_callocN(sizeof(bNodeLink), "link");
+ BLI_addtail(&ntree->links, link);
+ link->fromnode= NULL;
+ link->fromsock= gsock;
+ link->tonode= node;
+ link->tosock= sock;
+ ntree->update |= NTREE_UPDATE_LINKS;
+
+ sock->link = link;
+ }
+ }
+ for (sock=node->outputs.first; sock; sock=sock->next) {
+ if (nodeCountSocketLinks(ntree, sock)==0 && !nodeSocketIsHidden(sock)) {
+ gsock = do_versions_node_group_add_socket_2_56_2(ntree, sock->name, sock->type, SOCK_OUT);
+
+ /* initialize the default socket value */
+ copy_v4_v4(gsock->ns.vec, sock->ns.vec);
+
+ /* XXX nodeAddLink does not work with incomplete (node==NULL) links any longer,
+ * have to create these directly here. These links are updated again in subsequent do_version!
+ */
+ link= MEM_callocN(sizeof(bNodeLink), "link");
+ BLI_addtail(&ntree->links, link);
+ link->fromnode= node;
+ link->fromsock= sock;
+ link->tonode= NULL;
+ link->tosock= gsock;
+ ntree->update |= NTREE_UPDATE_LINKS;
+
+ gsock->link = link;
+ }
+ }
+ }
+
+ /* XXX The external group node sockets needs to adjust their own_index to point at
+ * associated ntree inputs/outputs internal sockets. However, this can only happen
+ * after lib-linking (needs access to internal node group tree)!
+ * Setting a temporary flag here, actual do_versions happens in lib_verify_nodetree.
*/
- ntree->flag |= NTREE_DO_VERSIONS_GROUP_EXPOSE;
+ ntree->flag |= NTREE_DO_VERSIONS_GROUP_EXPOSE_2_56_2;
}
}
@@ -2601,39 +2741,29 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
bNodeTree *ntree;
for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
- blo_do_versions_nodetree_default_value(ntree);
+ do_versions_nodetree_default_value_259(ntree);
ntree->update |= NTREE_UPDATE;
}
for (sce = main->scene.first; sce; sce = sce->id.next)
if (sce->nodetree) {
- blo_do_versions_nodetree_default_value(sce->nodetree);
+ do_versions_nodetree_default_value_259(sce->nodetree);
sce->nodetree->update |= NTREE_UPDATE;
}
for (mat = main->mat.first; mat; mat = mat->id.next)
if (mat->nodetree) {
- blo_do_versions_nodetree_default_value(mat->nodetree);
+ do_versions_nodetree_default_value_259(mat->nodetree);
mat->nodetree->update |= NTREE_UPDATE;
}
for (tex = main->tex.first; tex; tex = tex->id.next)
if (tex->nodetree) {
- blo_do_versions_nodetree_default_value(tex->nodetree);
+ do_versions_nodetree_default_value_259(tex->nodetree);
tex->nodetree->update |= NTREE_UPDATE;
}
}
- /* add SOCK_DYNAMIC flag to existing group sockets */
- {
- bNodeTree *ntree;
- /* only need to do this for trees in main, local trees are not used as groups */
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
- do_versions_nodetree_dynamic_sockets(ntree);
- ntree->update |= NTREE_UPDATE;
- }
- }
-
{
/* Initialize group tree nodetypes.
* These are used to distinguish tree types and
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 4f7ec77a8e6..d78c6687e16 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -74,6 +74,7 @@
#include <math.h>
#include <fcntl.h>
+#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -151,6 +152,7 @@
#include "BKE_curve.h"
#include "BKE_constraint.h"
#include "BKE_global.h" // for G
+#include "BKE_idprop.h"
#include "BKE_library.h" // for set_listbasepointers
#include "BKE_main.h"
#include "BKE_node.h"
@@ -162,6 +164,13 @@
#include "BKE_pointcache.h"
#include "BKE_mesh.h"
+#ifdef USE_NODE_COMPAT_CUSTOMNODES
+#include "NOD_common.h"
+#include "NOD_socket.h" /* for sock->default_value data */
+#endif
+
+#include "RNA_access.h"
+
#include "BLO_writefile.h"
#include "BLO_readfile.h"
#include "BLO_undofile.h"
@@ -670,46 +679,54 @@ static void write_curvemapping(WriteData *wd, CurveMapping *cumap)
write_curvemapping_curves(wd, cumap);
}
-static void write_node_socket(WriteData *wd, bNodeSocket *sock)
+static void write_node_socket(WriteData *wd, bNodeTree *UNUSED(ntree), bNode *node, bNodeSocket *sock)
{
- bNodeSocketType *stype= ntreeGetSocketType(sock->type);
-
+#ifdef USE_NODE_COMPAT_CUSTOMNODES
/* forward compatibility code, so older blenders still open */
sock->stack_type = 1;
- if (sock->default_value) {
- bNodeSocketValueFloat *valfloat;
- bNodeSocketValueVector *valvector;
- bNodeSocketValueRGBA *valrgba;
-
- switch (sock->type) {
- case SOCK_FLOAT:
- valfloat = sock->default_value;
- sock->ns.vec[0] = valfloat->value;
- sock->ns.min = valfloat->min;
- sock->ns.max = valfloat->max;
- break;
- case SOCK_VECTOR:
- valvector = sock->default_value;
- copy_v3_v3(sock->ns.vec, valvector->value);
- sock->ns.min = valvector->min;
- sock->ns.max = valvector->max;
- break;
- case SOCK_RGBA:
- valrgba = sock->default_value;
- copy_v4_v4(sock->ns.vec, valrgba->value);
- sock->ns.min = 0.0f;
- sock->ns.max = 1.0f;
- break;
+ if (node->type == NODE_GROUP) {
+ bNodeTree *ngroup = (bNodeTree *)node->id;
+ if (ngroup) {
+ /* for node groups: look up the deprecated groupsock pointer */
+ sock->groupsock = ntreeFindSocketInterface(ngroup, sock->in_out, sock->identifier);
+ BLI_assert(sock->groupsock != NULL);
+
+ /* node group sockets now use the generic identifier string to verify group nodes,
+ * old blender uses the own_index.
+ */
+ sock->own_index = sock->groupsock->own_index;
}
}
+#endif
/* actual socket writing */
writestruct(wd, DATA, "bNodeSocket", 1, sock);
+
+ if (sock->prop)
+ IDP_WriteProperty(sock->prop, wd);
+
if (sock->default_value)
- writestruct(wd, DATA, stype->value_structname, 1, sock->default_value);
+ writedata(wd, DATA, MEM_allocN_len(sock->default_value), sock->default_value);
}
+static void write_node_socket_interface(WriteData *wd, bNodeTree *UNUSED(ntree), bNodeSocket *sock)
+{
+#ifdef USE_NODE_COMPAT_CUSTOMNODES
+ /* forward compatibility code, so older blenders still open */
+ sock->stack_type = 1;
+
+ /* Reconstruct the deprecated default_value structs in socket interface DNA. */
+ if (sock->default_value == NULL && sock->typeinfo) {
+ node_socket_init_default_value(sock);
+ }
+#endif
+ /* actual socket writing */
+ writestruct(wd, DATA, "bNodeSocket", 1, sock);
+
+ if (sock->prop)
+ IDP_WriteProperty(sock->prop, wd);
+}
/* this is only direct data, tree itself should have been written */
static void write_nodetree(WriteData *wd, bNodeTree *ntree)
{
@@ -721,18 +738,19 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree)
if (ntree->adt) write_animdata(wd, ntree->adt);
- for (node= ntree->nodes.first; node; node= node->next)
+ for (node= ntree->nodes.first; node; node= node->next) {
writestruct(wd, DATA, "bNode", 1, node);
- for (node= ntree->nodes.first; node; node= node->next) {
+ if (node->prop)
+ IDP_WriteProperty(node->prop, wd);
+
for (sock= node->inputs.first; sock; sock= sock->next)
- write_node_socket(wd, sock);
+ write_node_socket(wd, ntree, node, sock);
for (sock= node->outputs.first; sock; sock= sock->next)
- write_node_socket(wd, sock);
+ write_node_socket(wd, ntree, node, sock);
for (link = node->internal_links.first; link; link = link->next)
writestruct(wd, DATA, "bNodeLink", 1, link);
-
if (node->storage) {
/* could be handlerized at some point, now only 1 exception still */
if (ntree->type==NTREE_SHADER && (node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB))
@@ -741,10 +759,6 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree)
NodeShaderScript *nss = (NodeShaderScript *)node->storage;
if (nss->bytecode)
writedata(wd, DATA, strlen(nss->bytecode)+1, nss->bytecode);
- /* Write ID Properties -- and copy this comment EXACTLY for easy finding
- * of library blocks that implement this.*/
- if (nss->prop)
- IDP_WriteProperty(nss->prop, wd);
writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage);
}
else if (ntree->type==NTREE_COMPOSIT && ELEM4(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT))
@@ -773,11 +787,10 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree)
for (link= ntree->links.first; link; link= link->next)
writestruct(wd, DATA, "bNodeLink", 1, link);
- /* external sockets */
- for (sock= ntree->inputs.first; sock; sock= sock->next)
- write_node_socket(wd, sock);
- for (sock= ntree->outputs.first; sock; sock= sock->next)
- write_node_socket(wd, sock);
+ for (sock = ntree->inputs.first; sock; sock = sock->next)
+ write_node_socket_interface(wd, ntree, sock);
+ for (sock = ntree->outputs.first; sock; sock = sock->next)
+ write_node_socket_interface(wd, ntree, sock);
}
static void current_screen_compat(Main *mainvar, bScreen **screen)
@@ -2518,7 +2531,12 @@ static void write_screens(WriteData *wd, ListBase *scrbase)
writestruct(wd, DATA, "SpaceTime", 1, sl);
}
else if (sl->spacetype==SPACE_NODE) {
- writestruct(wd, DATA, "SpaceNode", 1, sl);
+ SpaceNode *snode = (SpaceNode *)sl;
+ bNodeTreePath *path;
+ writestruct(wd, DATA, "SpaceNode", 1, snode);
+
+ for (path=snode->treepath.first; path; path=path->next)
+ writestruct(wd, DATA, "bNodeTreePath", 1, path);
}
else if (sl->spacetype==SPACE_LOGIC) {
writestruct(wd, DATA, "SpaceLogic", 1, sl);
@@ -2770,6 +2788,118 @@ static void write_nodetrees(WriteData *wd, ListBase *idbase)
}
}
+#ifdef USE_NODE_COMPAT_CUSTOMNODES
+static void customnodes_add_deprecated_nodetree_data(bNodeTree *ntree)
+{
+ bNodeLink *link, *last_link = ntree->links.last;
+ /* Forward compatibility for group nodes: add links to node tree interface sockets.
+ * These links are invalid by new rules (missing node pointer)!
+ * They will be removed again in customnodes_free_deprecated_data,
+ * cannot do this directly lest bNodeLink pointer mapping becomes ambiguous.
+ * When loading files with such links in a new Blender version
+ * they will be removed as well.
+ */
+ for (link = ntree->links.first; link; link = link->next) {
+ bNode *fromnode = link->fromnode, *tonode = link->tonode;
+ bNodeSocket *fromsock = link->fromsock, *tosock = link->tosock;
+
+ /* check both sides of the link, to handle direct input-to-output links */
+ if (fromnode->type == NODE_GROUP_INPUT) {
+ fromnode = NULL;
+ fromsock = ntreeFindSocketInterface(ntree, SOCK_IN, fromsock->identifier);
+ }
+ /* only the active output node defines links */
+ if (tonode->type == NODE_GROUP_OUTPUT && (tonode->flag & NODE_DO_OUTPUT)) {
+ tonode = NULL;
+ tosock = ntreeFindSocketInterface(ntree, SOCK_OUT, tosock->identifier);
+ }
+
+ if (!fromnode || !tonode) {
+ /* Note: not using nodeAddLink here, it asserts existing node pointers */
+ bNodeLink *tlink = MEM_callocN(sizeof(bNodeLink), "group node link");
+ tlink->fromnode = fromnode;
+ tlink->fromsock = fromsock;
+ tlink->tonode = tonode;
+ tlink->tosock= tosock;
+ tosock->link = tlink;
+ tlink->flag |= NODE_LINK_VALID;
+ BLI_addtail(&ntree->links, tlink);
+ }
+
+ /* don't check newly created compatibility links */
+ if (link == last_link)
+ break;
+ }
+}
+
+static void customnodes_add_deprecated_data(Main *mainvar)
+{
+ bNodeTree *ntree;
+ Scene *scene;
+ Material *mat;
+ World *world;
+ Lamp *lamp;
+ Tex *tex;
+
+ for (ntree = mainvar->nodetree.first; ntree; ntree = ntree->id.next)
+ customnodes_add_deprecated_nodetree_data(ntree);
+ for (scene = mainvar->scene.first; scene; scene = scene->id.next)
+ if (scene->nodetree)
+ customnodes_add_deprecated_nodetree_data(scene->nodetree);
+ for (mat = mainvar->mat.first; mat; mat = mat->id.next)
+ if (mat->nodetree)
+ customnodes_add_deprecated_nodetree_data(mat->nodetree);
+ for (world = mainvar->world.first; world; world = world->id.next)
+ if (world->nodetree)
+ customnodes_add_deprecated_nodetree_data(world->nodetree);
+ for (lamp = mainvar->lamp.first; lamp; lamp = lamp->id.next)
+ if (lamp->nodetree)
+ customnodes_add_deprecated_nodetree_data(lamp->nodetree);
+ for (tex = mainvar->tex.first; tex; tex = tex->id.next)
+ if (tex->nodetree)
+ customnodes_add_deprecated_nodetree_data(tex->nodetree);
+}
+
+static void customnodes_free_deprecated_nodetree_data(bNodeTree *ntree)
+{
+ bNodeLink *link, *next_link;
+
+ for (link = ntree->links.first; link; link = next_link) {
+ next_link = link->next;
+ if (link->fromnode == NULL || link->tonode == NULL)
+ nodeRemLink(ntree, link);
+ }
+}
+
+static void customnodes_free_deprecated_data(Main *mainvar)
+{
+ bNodeTree *ntree;
+ Scene *scene;
+ Material *mat;
+ World *world;
+ Lamp *lamp;
+ Tex *tex;
+
+ for (ntree = mainvar->nodetree.first; ntree; ntree = ntree->id.next)
+ customnodes_free_deprecated_nodetree_data(ntree);
+ for (scene = mainvar->scene.first; scene; scene = scene->id.next)
+ if (scene->nodetree)
+ customnodes_free_deprecated_nodetree_data(scene->nodetree);
+ for (mat = mainvar->mat.first; mat; mat = mat->id.next)
+ if (mat->nodetree)
+ customnodes_free_deprecated_nodetree_data(mat->nodetree);
+ for (world = mainvar->world.first; world; world = world->id.next)
+ if (world->nodetree)
+ customnodes_free_deprecated_nodetree_data(world->nodetree);
+ for (lamp = mainvar->lamp.first; lamp; lamp = lamp->id.next)
+ if (lamp->nodetree)
+ customnodes_free_deprecated_nodetree_data(lamp->nodetree);
+ for (tex = mainvar->tex.first; tex; tex = tex->id.next)
+ if (tex->nodetree)
+ customnodes_free_deprecated_nodetree_data(tex->nodetree);
+}
+#endif
+
static void write_brushes(WriteData *wd, ListBase *idbase)
{
Brush *brush;
@@ -2981,6 +3111,11 @@ static int write_file_handle(Main *mainvar, int handle, MemFile *compare, MemFil
wd->use_mesh_compat = (write_flags & G_FILE_MESH_COMPAT) != 0;
#endif
+#ifdef USE_NODE_COMPAT_CUSTOMNODES
+ /* deprecated forward compat data is freed again below */
+ customnodes_add_deprecated_data(mainvar);
+#endif
+
sprintf(buf, "BLENDER%c%c%.3d", (sizeof(void*)==8)?'-':'_', (ENDIAN_ORDER==B_ENDIAN)?'V':'v', BLENDER_VERSION);
mywrite(wd, buf, 12);
@@ -3026,6 +3161,14 @@ static int write_file_handle(Main *mainvar, int handle, MemFile *compare, MemFil
/* dna as last, because (to be implemented) test for which structs are written */
writedata(wd, DNA1, wd->sdna->datalen, wd->sdna->data);
+#ifdef USE_NODE_COMPAT_CUSTOMNODES
+ /* Ugly, forward compatibility code generates deprecated data during writing,
+ * this has to be freed again. Can not be done directly after writing, otherwise
+ * the data pointers could be reused and not be mapped correctly.
+ */
+ customnodes_free_deprecated_data(mainvar);
+#endif
+
/* end of file */
memset(&bhead, 0, sizeof(BHead));
bhead.code= ENDB;