diff options
Diffstat (limited to 'source/blender/blenkernel/intern')
-rw-r--r-- | source/blender/blenkernel/intern/image.c | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mask.c | 9 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/material.c | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/movieclip.c | 9 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/node.c | 2902 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/texture.c | 2 |
6 files changed, 1984 insertions, 944 deletions
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index c27f5e62520..355541557ea 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -2171,7 +2171,7 @@ void BKE_image_walk_all_users(const Main *mainp, void *customdata, } else if (sa->spacetype == SPACE_NODE) { SpaceNode *snode = sa->spacedata.first; - if ((snode->treetype == NTREE_COMPOSIT) && (snode->nodetree)) { + if (snode->nodetree && snode->nodetree->type==NTREE_COMPOSIT) { bNode *node; for (node = snode->nodetree->nodes.first; node; node = node->next) { if (node->id && node->type == CMP_NODE_IMAGE) { diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index 87802ab8ee6..a5241684e3a 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -57,6 +57,8 @@ #include "BKE_movieclip.h" #include "BKE_image.h" +#include "NOD_composite.h" + static MaskSplinePoint *mask_spline_point_next(MaskSpline *spline, MaskSplinePoint *points_array, MaskSplinePoint *point) { if (point == &points_array[spline->tot_point - 1]) { @@ -966,10 +968,9 @@ void BKE_mask_free(Main *bmain, Mask *mask) } } - { - bNodeTreeType *treetype = ntreeGetType(NTREE_COMPOSIT); - treetype->foreach_nodetree(bmain, (void *)mask, &BKE_node_tree_unlink_id_cb); - } + FOREACH_NODETREE(bmain, ntree, id) { + BKE_node_tree_unlink_id((ID *)mask, ntree); + } FOREACH_NODETREE_END /* free mask data */ BKE_mask_layer_free_list(&mask->masklayers); diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index ab425d8e5b9..c47eb7eac45 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -1012,7 +1012,7 @@ void init_render_material(Material *mat, int r_mode, float *amb) init_render_nodetree(mat->nodetree, mat, r_mode, amb); if (!mat->nodetree->execdata) - mat->nodetree->execdata = ntreeShaderBeginExecTree(mat->nodetree, 1); + mat->nodetree->execdata = ntreeShaderBeginExecTree(mat->nodetree); } } @@ -1046,7 +1046,7 @@ void end_render_material(Material *mat) { if (mat && mat->nodetree && mat->use_nodes) { if (mat->nodetree->execdata) - ntreeShaderEndExecTree(mat->nodetree->execdata, 1); + ntreeShaderEndExecTree(mat->nodetree->execdata); } } diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index e79754ca203..821c8fe3bda 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -86,6 +86,8 @@ #include "intern/openexr/openexr_multi.h" #endif +#include "NOD_composite.h" + /*********************** movieclip buffer loaders *************************/ static int sequence_guess_offset(const char *full_name, int head_len, unsigned short numlen) @@ -1401,10 +1403,9 @@ void BKE_movieclip_unlink(Main *bmain, MovieClip *clip) } } - { - bNodeTreeType *treetype = ntreeGetType(NTREE_COMPOSIT); - treetype->foreach_nodetree(bmain, (void *)clip, &BKE_node_tree_unlink_id_cb); - } + FOREACH_NODETREE(bmain, ntree, id) { + BKE_node_tree_unlink_id((ID *)clip, ntree); + } FOREACH_NODETREE_END clip->id.us = 0; } diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 974a564b9da..0b63c4d8842 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -58,133 +58,634 @@ #include "BKE_action.h" #include "BKE_fcurve.h" #include "BKE_global.h" +#include "BKE_idprop.h" #include "BKE_image.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BLI_ghash.h" #include "RNA_access.h" +#include "RNA_define.h" #include "NOD_socket.h" +#include "NOD_common.h" #include "NOD_composite.h" #include "NOD_shader.h" #include "NOD_texture.h" -bNodeTreeType *ntreeGetType(int type) +static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype) { - static bNodeTreeType *types[NUM_NTREE_TYPES]; - static int types_init = 1; - if (types_init) { - types[NTREE_SHADER] = &ntreeType_Shader; - types[NTREE_COMPOSIT] = &ntreeType_Composite; - types[NTREE_TEXTURE] = &ntreeType_Texture; - types_init = 0; + bNodeSocketTemplate *sockdef; + /* bNodeSocket *sock; */ /* UNUSED */ + + if (ntype->inputs) { + sockdef = ntype->inputs; + while (sockdef->type != -1) { + /* sock = */ node_add_socket_from_template(ntree, node, sockdef, SOCK_IN); + + sockdef++; + } + } + if (ntype->outputs) { + sockdef = ntype->outputs; + while (sockdef->type != -1) { + /* sock = */ node_add_socket_from_template(ntree, node, sockdef, SOCK_OUT); + + sockdef++; + } } +} + +/* Note: This function is called to initialize node data based on the type. + * The bNodeType may not be registered at creation time of the node, + * so this can be delayed until the node type gets registered. + * The node->typeinfo must not be used in that case until it is defined! + */ +static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node) +{ + bNodeType *ntype = node->typeinfo; + if (!ntype) + return; + + /* only do this once */ + if (node->flag & NODE_INIT) + return; + + node->flag = NODE_SELECT | ntype->flag; + node->width = ntype->width; + node->miniwidth = 42.0f; + node->height = ntype->height; + node->color[0] = node->color[1] = node->color[2] = 0.608; /* default theme color */ - if (type >= 0 && type < NUM_NTREE_TYPES) { - return types[type]; + /* initialize the node name with the node label. + * note: do this after the initfunc so nodes get their data set which may be used in naming + * (node groups for example) */ + /* XXX Do not use nodeLabel() here, it returns translated content, which should *only* be used + * in UI, *never* in data... + * This solution may be a bit rougher than nodeLabel()'s returned string, but it's simpler + * than adding a "no translate" flag to this func (and labelfunc() as well). */ + BLI_strncpy(node->name, ntype->ui_name, NODE_MAXSTR); + nodeUniqueName(ntree, node); + + node_add_sockets_from_type(ntree, node, ntype); + + if (ntype->initfunc != NULL) + ntype->initfunc(ntree, node); + + /* extra init callback */ + if (ntype->initfunc_api) { + PointerRNA ptr; + RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr); + + /* XXX Warning: context can be NULL in case nodes are added in do_versions. + * Delayed init is not supported for nodes with context-based initfunc_api atm. + */ + BLI_assert(C != NULL); + ntype->initfunc_api(C, &ptr); + } + + node->flag |= NODE_INIT; +} + +static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo) +{ + ntree->typeinfo = typeinfo; + + if (typeinfo) { + /* deprecated integer type */ + ntree->type = typeinfo->type; } else { - return NULL; + ntree->init &= ~NTREE_TYPE_INIT; } } -static bNodeType *node_get_type(bNodeTree *ntree, int type) +static void node_set_typeinfo(const struct bContext *C, bNodeTree *ntree, bNode *node, bNodeType *typeinfo) { - bNodeType *ntype = ntreeGetType(ntree->type)->node_types.first; - for (; ntype; ntype = ntype->next) - if (ntype->type == type) - return ntype; + node->typeinfo = typeinfo; + if (typeinfo) { + /* deprecated integer type */ + node->type = typeinfo->type; + + /* initialize the node if necessary */ + node_init(C, ntree, node); + } + else { + ntree->init &= ~NTREE_TYPE_INIT; + } +} + +static void node_socket_set_typeinfo(bNodeTree *ntree, bNodeSocket *sock, bNodeSocketType *typeinfo) +{ + sock->typeinfo = typeinfo; + + if (typeinfo) { + if (sock->default_value == NULL) { + /* initialize the default_value pointer used by standard socket types */ + node_socket_init_default_value(sock); + } + } + else { + ntree->init &= ~NTREE_TYPE_INIT; + } +} + +/* Set specific typeinfo pointers in all node trees on register/unregister */ +static void update_typeinfo(Main *bmain, const struct bContext *C, bNodeTreeType *treetype, bNodeType *nodetype, bNodeSocketType *socktype, bool unregister) +{ + if (!bmain) + return; + + FOREACH_NODETREE(bmain, ntree, id) { + bNode *node; + bNodeSocket *sock; + + ntree->init |= NTREE_TYPE_INIT; + + if (treetype && strcmp(ntree->idname, treetype->idname)==0) + ntree_set_typeinfo(ntree, unregister ? NULL : treetype); + + /* initialize nodes */ + for (node=ntree->nodes.first; node; node=node->next) { + if (nodetype && strcmp(node->idname, nodetype->idname)==0) + node_set_typeinfo(C, ntree, node, unregister ? NULL : nodetype); + + /* initialize node sockets */ + for (sock=node->inputs.first; sock; sock=sock->next) + if (socktype && strcmp(sock->idname, socktype->idname)==0) + node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype); + for (sock=node->outputs.first; sock; sock=sock->next) + if (socktype && strcmp(sock->idname, socktype->idname)==0) + node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype); + } + + /* initialize tree sockets */ + for (sock=ntree->inputs.first; sock; sock=sock->next) + if (socktype && strcmp(sock->idname, socktype->idname)==0) + node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype); + for (sock=ntree->outputs.first; sock; sock=sock->next) + if (socktype && strcmp(sock->idname, socktype->idname)==0) + node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype); + } + FOREACH_NODETREE_END +} + +/* Try to initialize all typeinfo in a node tree. + * NB: In general undefined typeinfo is a perfectly valid case, the type may just be registered later. + * In that case the update_typeinfo function will set typeinfo on registration + * and do necessary updates. + */ +void ntreeSetTypes(const struct bContext *C, bNodeTree *ntree) +{ + bNode *node; + bNodeSocket *sock; + + ntree->init |= NTREE_TYPE_INIT; + + ntree_set_typeinfo(ntree, ntreeTypeFind(ntree->idname)); + + for (node = ntree->nodes.first; node; node = node->next) { + node_set_typeinfo(C, ntree, node, nodeTypeFind(node->idname)); + + for (sock=node->inputs.first; sock; sock=sock->next) + node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname)); + for (sock=node->outputs.first; sock; sock=sock->next) + node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname)); + } + + for (sock=ntree->inputs.first; sock; sock=sock->next) + node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname)); + for (sock=ntree->outputs.first; sock; sock=sock->next) + node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname)); +} + + +static GHash *nodetreetypes_hash= NULL; +static GHash *nodetypes_hash= NULL; +static GHash *nodesockettypes_hash= NULL; + +bNodeTreeType *ntreeTypeFind(const char *idname) +{ + bNodeTreeType* nt; + + if (idname[0]) { + nt= BLI_ghash_lookup(nodetreetypes_hash, idname); + if(nt) + return nt; + } + return NULL; } -bNodeType *ntreeGetNodeType(bNodeTree *ntree) +void ntreeTypeAdd(bNodeTreeType* nt) { - return node_get_type(ntree, ntree->nodetype); + BLI_ghash_insert(nodetreetypes_hash, (void *)nt->idname, nt); + /* XXX pass Main to register function? */ + update_typeinfo(G.main, NULL, nt, NULL, NULL, false); } -bNodeSocketType *ntreeGetSocketType(int type) +/* callback for hash value free function */ +static void ntree_free_type(void *treetype_v) { - static bNodeSocketType *types[NUM_SOCKET_TYPES] = {NULL}; - static int types_init = 1; + bNodeTreeType *treetype = treetype_v; + /* XXX pass Main to unregister function? */ + update_typeinfo(G.main, NULL, treetype, NULL, NULL, true); + MEM_freeN(treetype); +} - if (types_init) { - node_socket_type_init(types); - types_init = 0; +void ntreeTypeFreeLink(bNodeTreeType* nt) +{ + BLI_ghash_remove(nodetreetypes_hash, nt->idname, NULL, ntree_free_type); +} + +GHashIterator *ntreeTypeGetIterator() +{ + return BLI_ghashIterator_new(nodetreetypes_hash); +} + +int ntreeIsValid(bNodeTree *ntree) +{ + return (ntree && (ntree->init & NTREE_TYPE_INIT)); +} + +bNodeType *nodeTypeFind(const char *idname) +{ + bNodeType* nt; + + if (idname[0]) { + nt= BLI_ghash_lookup(nodetypes_hash, idname); + if(nt) + return nt; } - if (type < NUM_SOCKET_TYPES) { - return types[type]; + return NULL; +} + +static void free_dynamic_typeinfo(bNodeType *ntype) +{ + if(ntype->type==NODE_DYNAMIC) { + if(ntype->inputs) { + MEM_freeN(ntype->inputs); + } + if(ntype->outputs) { + MEM_freeN(ntype->outputs); + } + if(ntype->ui_name) { + MEM_freeN((void *)ntype->ui_name); + } } - else { - return NULL; +} + +/* callback for hash value free function */ +static void node_free_type(void *nodetype_v) +{ + bNodeType *nodetype = nodetype_v; + /* XXX pass Main to unregister function? */ + update_typeinfo(G.main, NULL, NULL, nodetype, NULL, true); + + /* XXX deprecated */ + if (nodetype->type==NODE_DYNAMIC) + free_dynamic_typeinfo(nodetype); + + if (nodetype->needs_free) + MEM_freeN(nodetype); +} + +void nodeRegisterType(bNodeType *nt) +{ + /* debug only: basic verification of registered types */ + BLI_assert(nt->idname[0] != '\0'); + BLI_assert(nt->poll != NULL); + + BLI_ghash_insert(nodetypes_hash, (void *)nt->idname, nt); + /* XXX pass Main to register function? */ + update_typeinfo(G.main, NULL, NULL, nt, NULL, false); +} + +void nodeUnregisterType(bNodeType* nt) +{ + BLI_ghash_remove(nodetypes_hash, nt->idname, NULL, node_free_type); +} + +GHashIterator *nodeTypeGetIterator() +{ + return BLI_ghashIterator_new(nodetypes_hash); +} + +bNodeSocketType *nodeSocketTypeFind(const char *idname) +{ + bNodeSocketType* st; + + if (idname[0]) { + st= BLI_ghash_lookup(nodesockettypes_hash, idname); + if(st) + return st; } + + return NULL; } -void ntreeInitTypes(bNodeTree *ntree) +/* callback for hash value free function */ +static void node_free_socket_type(void *socktype_v) { - bNode *node, *next; + bNodeSocketType *socktype = socktype_v; + /* XXX pass Main to unregister function? */ + update_typeinfo(G.main, NULL, NULL, NULL, socktype, true); - for (node = ntree->nodes.first; node; node = next) { - next = node->next; - - node->typeinfo = node_get_type(ntree, node->type); + MEM_freeN(socktype); +} - if (node->typeinfo == NULL) { - printf("Error: Node type %s doesn't exist anymore, removed\n", node->name); - nodeFreeNode(ntree, node); - } +void nodeRegisterSocketType(bNodeSocketType* st) +{ + BLI_ghash_insert(nodesockettypes_hash, (void *)st->idname, st); + /* XXX pass Main to register function? */ + update_typeinfo(G.main, NULL, NULL, NULL, st, false); +} + +void nodeUnregisterSocketType(bNodeSocketType* st) +{ + BLI_ghash_remove(nodesockettypes_hash, st->idname, NULL, node_free_socket_type); +} + +GHashIterator *nodeSocketTypeGetIterator(void) +{ + return BLI_ghashIterator_new(nodesockettypes_hash); +} + +void nodeMakeDynamicType(bNode *UNUSED(node)) +{ + #if 0 /* XXX deprecated */ + /* find SH_DYNAMIC_NODE ntype */ + bNodeType *ntype= ntreeType_Shader->node_types.first; + while(ntype) { + if(ntype->type==NODE_DYNAMIC) + break; + ntype= ntype->next; } - - ntree->init |= NTREE_TYPE_INIT; + + /* make own type struct to fill */ + if(ntype) { + /*node->typeinfo= MEM_dupallocN(ntype);*/ + bNodeType *newtype= MEM_callocN(sizeof(bNodeType), "dynamic bNodeType"); + *newtype= *ntype; + BLI_strncpy(newtype->name, ntype->name, sizeof(newtype->name)); + node->typeinfo= newtype; + } + #endif } -static bNodeSocket *make_socket(bNodeTree *UNUSED(ntree), int in_out, const char *name, int type) +struct bNodeSocket *nodeFindSocket(bNode *node, int in_out, const char *identifier) +{ + bNodeSocket *sock = (in_out == SOCK_IN ? node->inputs.first : node->outputs.first); + for (; sock; sock=sock->next) { + if (strcmp(sock->identifier, identifier)==0) + return sock; + } + return NULL; +} + +/* find unique socket identifier */ +static bool unique_identifier_check(void *arg, const char *identifier) +{ + struct ListBase *lb = arg; + bNodeSocket *sock; + for (sock = lb->first; sock; sock = sock->next) { + if (strcmp(sock->identifier, identifier)==0) + return true; + } + return false; +} + +static bNodeSocket *make_socket(bNodeTree *ntree, bNode *UNUSED(node), int in_out, ListBase *lb, + const char *idname, const char *identifier, const char *name) { bNodeSocket *sock; + char auto_identifier[MAX_NAME]; + + if (identifier && identifier[0] != '\0') { + /* use explicit identifier */ + BLI_strncpy(auto_identifier, identifier, sizeof(auto_identifier)); + } + else { + /* if no explicit identifier is given, assign a unique identifier based on the name */ + BLI_strncpy(auto_identifier, name, sizeof(auto_identifier)); + } + /* make the identifier unique */ + BLI_uniquename_cb(unique_identifier_check, lb, NULL, '.', auto_identifier, sizeof(auto_identifier)); sock = MEM_callocN(sizeof(bNodeSocket), "sock"); + sock->in_out = in_out; - BLI_strncpy(sock->name, name, NODE_MAXSTR); + BLI_strncpy(sock->identifier, auto_identifier, NODE_MAXSTR); sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF); - sock->type = type; + + BLI_strncpy(sock->name, name, NODE_MAXSTR); sock->storage = NULL; sock->flag |= SOCK_COLLAPSED; + sock->type = SOCK_CUSTOM; /* int type undefined by default */ - sock->default_value = node_socket_make_default_value(type); - node_socket_init_default_value(type, sock->default_value); + BLI_strncpy(sock->idname, idname, sizeof(sock->idname)); + node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(idname)); return sock; } -bNodeSocket *nodeAddSocket(bNodeTree *ntree, bNode *node, int in_out, const char *name, int type) +bNodeSocket *nodeAddSocket(bNodeTree *ntree, bNode *node, int in_out, const char *idname, + const char *identifier, const char *name) { - bNodeSocket *sock = make_socket(ntree, in_out, name, type); - if (in_out == SOCK_IN) - BLI_addtail(&node->inputs, sock); - else if (in_out == SOCK_OUT) - BLI_addtail(&node->outputs, sock); + ListBase *lb = (in_out == SOCK_IN ? &node->inputs : &node->outputs); + bNodeSocket *sock = make_socket(ntree, node, in_out, lb, idname, identifier, name); + + BLI_remlink(lb, sock); /* does nothing for new socket */ + BLI_addtail(lb, sock); node->update |= NODE_UPDATE; return sock; } -bNodeSocket *nodeInsertSocket(bNodeTree *ntree, bNode *node, int in_out, bNodeSocket *next_sock, const char *name, int type) +bNodeSocket *nodeInsertSocket(bNodeTree *ntree, bNode *node, int in_out, const char *idname, + bNodeSocket *next_sock, const char *identifier, const char *name) { - bNodeSocket *sock = make_socket(ntree, in_out, name, type); - if (in_out == SOCK_IN) - BLI_insertlinkbefore(&node->inputs, next_sock, sock); - else if (in_out == SOCK_OUT) - BLI_insertlinkbefore(&node->outputs, next_sock, sock); + ListBase *lb = (in_out == SOCK_IN ? &node->inputs : &node->outputs); + bNodeSocket *sock = make_socket(ntree, node, in_out, lb, idname, identifier, name); + + BLI_remlink(lb, sock); /* does nothing for new socket */ + BLI_insertlinkbefore(lb, next_sock, sock); node->update |= NODE_UPDATE; return sock; } +const char *nodeStaticSocketType(int type, int subtype) +{ + switch (type) { + case SOCK_FLOAT: + switch (subtype) { + case PROP_UNSIGNED: + return "NodeSocketFloatUnsigned"; + case PROP_PERCENTAGE: + return "NodeSocketFloatPercentage"; + case PROP_FACTOR: + return "NodeSocketFloatFactor"; + case PROP_ANGLE: + return "NodeSocketFloatAngle"; + case PROP_TIME: + return "NodeSocketFloatTime"; + case PROP_NONE: + default: + return "NodeSocketFloat"; + } + case SOCK_INT: + switch (subtype) { + case PROP_UNSIGNED: + return "NodeSocketIntUnsigned"; + case PROP_PERCENTAGE: + return "NodeSocketIntPercentage"; + case PROP_FACTOR: + return "NodeSocketIntFactor"; + case PROP_NONE: + default: + return "NodeSocketInt"; + } + case SOCK_BOOLEAN: + return "NodeSocketBool"; + case SOCK_VECTOR: + switch (subtype) { + case PROP_TRANSLATION: + return "NodeSocketVectorTranslation"; + case PROP_DIRECTION: + return "NodeSocketVectorDirection"; + case PROP_VELOCITY: + return "NodeSocketVectorVelocity"; + case PROP_ACCELERATION: + return "NodeSocketVectorAcceleration"; + case PROP_EULER: + return "NodeSocketVectorEuler"; + case PROP_XYZ: + return "NodeSocketVectorXYZ"; + case PROP_NONE: + default: + return "NodeSocketVector"; + } + case SOCK_RGBA: + return "NodeSocketColor"; + case SOCK_STRING: + return "NodeSocketString"; + case SOCK_SHADER: + return "NodeSocketShader"; + } + return NULL; +} + +const char *nodeStaticSocketInterfaceType(int type, int subtype) +{ + switch (type) { + case SOCK_FLOAT: + switch (subtype) { + case PROP_UNSIGNED: + return "NodeSocketInterfaceFloatUnsigned"; + case PROP_PERCENTAGE: + return "NodeSocketInterfaceFloatPercentage"; + case PROP_FACTOR: + return "NodeSocketInterfaceFloatFactor"; + case PROP_ANGLE: + return "NodeSocketInterfaceFloatAngle"; + case PROP_TIME: + return "NodeSocketInterfaceFloatTime"; + case PROP_NONE: + default: + return "NodeSocketInterfaceFloat"; + } + case SOCK_INT: + switch (subtype) { + case PROP_UNSIGNED: + return "NodeSocketInterfaceIntUnsigned"; + case PROP_PERCENTAGE: + return "NodeSocketInterfaceIntPercentage"; + case PROP_FACTOR: + return "NodeSocketInterfaceIntFactor"; + case PROP_NONE: + default: + return "NodeSocketInterfaceInt"; + } + case SOCK_BOOLEAN: + return "NodeSocketInterfaceBool"; + case SOCK_VECTOR: + switch (subtype) { + case PROP_TRANSLATION: + return "NodeSocketInterfaceVectorTranslation"; + case PROP_DIRECTION: + return "NodeSocketInterfaceVectorDirection"; + case PROP_VELOCITY: + return "NodeSocketInterfaceVectorVelocity"; + case PROP_ACCELERATION: + return "NodeSocketInterfaceVectorAcceleration"; + case PROP_EULER: + return "NodeSocketInterfaceVectorEuler"; + case PROP_XYZ: + return "NodeSocketInterfaceVectorXYZ"; + case PROP_NONE: + default: + return "NodeSocketInterfaceVector"; + } + case SOCK_RGBA: + return "NodeSocketInterfaceColor"; + case SOCK_STRING: + return "NodeSocketInterfaceString"; + case SOCK_SHADER: + return "NodeSocketInterfaceShader"; + } + return NULL; +} + +bNodeSocket *nodeAddStaticSocket(bNodeTree *ntree, bNode *node, int in_out, int type, int subtype, + const char *identifier, const char *name) +{ + const char *idname = nodeStaticSocketType(type, subtype); + bNodeSocket *sock; + + if (!idname) { + printf("Error: static node socket type %d undefined\n", type); + return NULL; + } + + sock = nodeAddSocket(ntree, node, in_out, idname, identifier, name); + sock->type = type; + return sock; +} + +bNodeSocket *nodeInsertStaticSocket(bNodeTree *ntree, bNode *node, int in_out, int type, int subtype, + bNodeSocket *next_sock, const char *identifier, const char *name) +{ + const char *idname = nodeStaticSocketType(type, subtype); + bNodeSocket *sock; + + if (!idname) { + printf("Error: static node socket type %d undefined\n", type); + return NULL; + } + + sock = nodeInsertSocket(ntree, node, in_out, idname, next_sock, identifier, name); + sock->type = type; + return sock; +} + +static void node_socket_free(bNodeTree *UNUSED(ntree), bNodeSocket *sock, bNode *UNUSED(node)) +{ + if (sock->prop) { + IDP_FreeProperty(sock->prop); + MEM_freeN(sock->prop); + } + + if (sock->default_value) + MEM_freeN(sock->default_value); +} + void nodeRemoveSocket(bNodeTree *ntree, bNode *node, bNodeSocket *sock) { bNodeLink *link, *next; @@ -200,7 +701,7 @@ void nodeRemoveSocket(bNodeTree *ntree, bNode *node, bNodeSocket *sock) BLI_remlink(&node->inputs, sock); BLI_remlink(&node->outputs, sock); - node_socket_free_default_value(sock->type, sock->default_value); + node_socket_free(ntree, sock, node); MEM_freeN(sock); node->update |= NODE_UPDATE; @@ -208,7 +709,7 @@ void nodeRemoveSocket(bNodeTree *ntree, bNode *node, bNodeSocket *sock) void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node) { - bNodeSocket *sock; + bNodeSocket *sock, *sock_next; bNodeLink *link, *next; for (link = ntree->links.first; link; link = next) { @@ -218,12 +719,16 @@ void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node) } } - for (sock = node->inputs.first; sock; sock = sock->next) - node_socket_free_default_value(sock->type, sock->default_value); - BLI_freelistN(&node->inputs); - for (sock = node->outputs.first; sock; sock = sock->next) - node_socket_free_default_value(sock->type, sock->default_value); - BLI_freelistN(&node->outputs); + for (sock = node->inputs.first; sock; sock = sock_next) { + sock_next = sock->next; + node_socket_free(ntree, sock, node); + MEM_freeN(sock); + } + for (sock = node->outputs.first; sock; sock = sock_next) { + sock_next = sock->next; + node_socket_free(ntree, sock, node); + MEM_freeN(sock); + } node->update |= NODE_UPDATE; } @@ -235,26 +740,18 @@ bNode *nodeFindNodebyName(bNodeTree *ntree, const char *name) } /* finds a node based on given socket */ -int nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **nodep, int *sockindex, int *in_out) +int nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **nodep, int *sockindex) { + int in_out = sock->in_out; bNode *node; bNodeSocket *tsock; int index = 0; for (node = ntree->nodes.first; node; node = node->next) { - for (index = 0, tsock = node->inputs.first; tsock; tsock = tsock->next, index++) { - if (tsock == sock) { - if (in_out) *in_out = SOCK_IN; + tsock = (in_out == SOCK_IN ? node->inputs.first : node->outputs.first); + for (index = 0; tsock; tsock = tsock->next, index++) { + if (tsock == sock) break; - } - } - if (tsock) - break; - for (index = 0, tsock = node->outputs.first; tsock; tsock = tsock->next, index++) { - if (tsock == sock) { - if (in_out) *in_out = SOCK_OUT; - break; - } } if (tsock) break; @@ -271,28 +768,6 @@ int nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **nodep, int *sockin } /* ************** Add stuff ********** */ -static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype) -{ - bNodeSocketTemplate *sockdef; - /* bNodeSocket *sock; */ /* UNUSED */ - - if (ntype->inputs) { - sockdef = ntype->inputs; - while (sockdef->type != -1) { - /* sock = */ node_add_input_from_template(ntree, node, sockdef); - - sockdef++; - } - } - if (ntype->outputs) { - sockdef = ntype->outputs; - while (sockdef->type != -1) { - /* sock = */ node_add_output_from_template(ntree, node, sockdef); - - sockdef++; - } - } -} /* Find the first available, non-duplicate name for a given node */ void nodeUniqueName(bNodeTree *ntree, bNode *node) @@ -300,51 +775,55 @@ void nodeUniqueName(bNodeTree *ntree, bNode *node) BLI_uniquename(&ntree->nodes, node, "Node", '.', offsetof(bNode, name), sizeof(node->name)); } -bNode *nodeAddNode(bNodeTree *ntree, struct bNodeTemplate *ntemp) +bNode *nodeAddNode(const struct bContext *C, bNodeTree *ntree, const char *idname) { bNode *node; - bNodeType *ntype; - - ntype = node_get_type(ntree, ntemp->type); - if (ntype == NULL) { - printf("nodeAddNodeType() error: '%d' type invalid\n", ntemp->type); - return NULL; - } - /* validity check */ - if (!nodeValid(ntree, ntemp)) - return NULL; node = MEM_callocN(sizeof(bNode), "new node"); - node->type = ntype->type; - node->typeinfo = ntype; - node->flag = NODE_SELECT | ntype->flag; - node->width = ntype->width; - node->miniwidth = 42.0f; - node->height = ntype->height; - node->color[0] = node->color[1] = node->color[2] = 0.608; /* default theme color */ - - node_add_sockets_from_type(ntree, node, ntype); - BLI_addtail(&ntree->nodes, node); - if (ntype->initfunc != NULL) - ntype->initfunc(ntree, node, ntemp); - - /* initialize the node name with the node label. - * note: do this after the initfunc so nodes get their data set which may be used in naming - * (node groups for example) */ - /* XXX Do not use nodeLabel() here, it returns translated content, which should *only* be used - * in UI, *never* in data... - * This solution may be a bit rougher than nodeLabel()'s returned string, but it's simpler - * than adding a "no translate" flag to this func (and labelfunc() as well). */ - BLI_strncpy(node->name, node->typeinfo->name, NODE_MAXSTR); - nodeUniqueName(ntree, node); + BLI_strncpy(node->idname, idname, sizeof(node->idname)); + node_set_typeinfo(C, ntree, node, nodeTypeFind(idname)); ntree->update |= NTREE_UPDATE_NODES; return node; } +bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type) +{ + const char *idname=NULL; + + NODE_TYPES_BEGIN(ntype) + if(ntype->type==type) { + idname = ntype->idname; + break; + } + NODE_TYPES_END + if (!idname) { + printf("Error: static node type %d undefined\n", type); + return NULL; + } + return nodeAddNode(C, ntree, idname); +} + +static void node_socket_copy(bNodeSocket *dst, bNodeSocket *src) +{ + src->new_sock = dst; + + if (src->prop) + dst->prop = IDP_CopyProperty(src->prop); + + if (src->default_value) + dst->default_value = MEM_dupallocN(src->default_value); + + dst->stack_index = 0; + /* XXX some compositor node (e.g. image, render layers) still store + * some persistent buffer data here, need to clear this to avoid dangling pointers. + */ + dst->cache = NULL; +} + /* keep socket listorder identical, for copying links */ /* ntree is the target tree */ bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node) @@ -363,33 +842,16 @@ bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node) BLI_duplicatelist(&nnode->inputs, &node->inputs); oldsock = node->inputs.first; - for (sock = nnode->inputs.first; sock; sock = sock->next, oldsock = oldsock->next) { - oldsock->new_sock = sock; - sock->stack_index = 0; - - sock->default_value = node_socket_make_default_value(oldsock->type); - node_socket_copy_default_value(oldsock->type, sock->default_value, oldsock->default_value); - - /* XXX some compositor node (e.g. image, render layers) still store - * some persistent buffer data here, need to clear this to avoid dangling pointers. - */ - sock->cache = NULL; - } + for (sock = nnode->inputs.first; sock; sock = sock->next, oldsock = oldsock->next) + node_socket_copy(sock, oldsock); BLI_duplicatelist(&nnode->outputs, &node->outputs); oldsock = node->outputs.first; - for (sock = nnode->outputs.first; sock; sock = sock->next, oldsock = oldsock->next) { - oldsock->new_sock = sock; - sock->stack_index = 0; - - sock->default_value = node_socket_make_default_value(oldsock->type); - node_socket_copy_default_value(oldsock->type, sock->default_value, oldsock->default_value); - - /* XXX some compositor node (e.g. image, render layers) still store - * some persistent buffer data here, need to clear this to avoid dangling pointers. - */ - sock->cache = NULL; - } + for (sock = nnode->outputs.first; sock; sock = sock->next, oldsock = oldsock->next) + node_socket_copy(sock, oldsock); + + if (node->prop) + nnode->prop = IDP_CopyProperty(node->prop); BLI_duplicatelist(&nnode->internal_links, &node->internal_links); oldlink = node->internal_links.first; @@ -402,22 +864,17 @@ bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node) /* don't increase node->id users, freenode doesn't decrement either */ - if (node->typeinfo->copystoragefunc) - node->typeinfo->copystoragefunc(node, nnode); + if (node->typeinfo->copyfunc) + node->typeinfo->copyfunc(ntree, nnode, node); node->new_node = nnode; nnode->new_node = NULL; - /* only shader nodes get pleasant preview updating this way, compo uses own system */ - if (node->preview) { - if (ntree && (ntree->type == NTREE_SHADER)) { - nnode->preview = MEM_dupallocN(node->preview); - if (node->preview->rect) - nnode->preview->rect = MEM_dupallocN(node->preview->rect); - } - else { - nnode->preview = NULL; - } + if (nnode->typeinfo->copyfunc_api) { + PointerRNA ptr; + RNA_pointer_create((ID *)ntree, &RNA_Node, nnode, &ptr); + + nnode->typeinfo->copyfunc_api(&ptr, node); } if (ntree) @@ -429,71 +886,13 @@ bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node) /* also used via rna api, so we check for proper input output direction */ bNodeLink *nodeAddLink(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock) { - bNodeSocket *sock; bNodeLink *link = NULL; - int from = 0, to = 0; - if (fromnode) { - /* test valid input */ - for (sock = fromnode->outputs.first; sock; sock = sock->next) - if (sock == fromsock) - break; - if (sock) - from = 1; /* OK */ - else { - for (sock = fromnode->inputs.first; sock; sock = sock->next) - if (sock == fromsock) - break; - if (sock) - from = -1; /* OK but flip */ - } - } - else if (ntree) { - /* check tree sockets */ - for (sock = ntree->inputs.first; sock; sock = sock->next) - if (sock == fromsock) - break; - if (sock) - from = 1; /* OK */ - else { - for (sock = ntree->outputs.first; sock; sock = sock->next) - if (sock == fromsock) - break; - if (sock) - from = -1; /* OK but flip */ - } - } - if (tonode) { - for (sock = tonode->inputs.first; sock; sock = sock->next) - if (sock == tosock) - break; - if (sock) - to = 1; /* OK */ - else { - for (sock = tonode->outputs.first; sock; sock = sock->next) - if (sock == tosock) - break; - if (sock) - to = -1; /* OK but flip */ - } - } - else if (ntree) { - /* check tree sockets */ - for (sock = ntree->outputs.first; sock; sock = sock->next) - if (sock == tosock) - break; - if (sock) - to = 1; /* OK */ - else { - for (sock = ntree->inputs.first; sock; sock = sock->next) - if (sock == tosock) - break; - if (sock) - to = -1; /* OK but flip */ - } - } + /* test valid input */ + BLI_assert(fromnode); + BLI_assert(tonode); - if (from >= 0 && to >= 0) { + if (fromsock->in_out == SOCK_OUT && tosock->in_out == SOCK_IN) { link = MEM_callocN(sizeof(bNodeLink), "link"); if (ntree) BLI_addtail(&ntree->links, link); @@ -502,7 +901,8 @@ bNodeLink *nodeAddLink(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, link->tonode = tonode; link->tosock = tosock; } - else if (from <= 0 && to <= 0) { + else if (fromsock->in_out == SOCK_IN && tosock->in_out == SOCK_OUT) { + /* OK but flip */ link = MEM_callocN(sizeof(bNodeLink), "link"); if (ntree) BLI_addtail(&ntree->links, link); @@ -546,6 +946,11 @@ void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock) ntree->update |= NTREE_UPDATE_LINKS; } +int nodeLinkIsHidden(bNodeLink *link) +{ + return nodeSocketIsHidden(link->fromsock) || nodeSocketIsHidden(link->tosock); +} + void nodeInternalRelink(bNodeTree *ntree, bNode *node) { bNodeLink *link, *link_next; @@ -662,30 +1067,29 @@ void nodeDetachNode(struct bNode *node) } } -bNodeTree *ntreeAddTree(Main *bmain, const char *name, int type, int nodetype) +bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname) { bNodeTree *ntree; - bNodeType *ntype; - /* trees are created as local trees if they of compositor, material or texture type, + /* trees are created as local trees for compositor, material or texture nodes, * node groups and other tree types are created as library data. */ - if (ELEM3(type, NTREE_COMPOSIT, NTREE_SHADER, NTREE_TEXTURE) && nodetype == 0) { + if (bmain) { + ntree= BKE_libblock_alloc(&bmain->nodetree, ID_NT, name); + } + else { ntree = MEM_callocN(sizeof(bNodeTree), "new node tree"); - *( (short *)ntree->id.name) = ID_NT; /* not "type", as that is ntree->type */ + *( (short *)ntree->id.name ) = ID_NT; BLI_strncpy(ntree->id.name + 2, name, sizeof(ntree->id.name)); } - else - ntree = BKE_libblock_alloc(&bmain->nodetree, ID_NT, name); - ntree->type = type; - ntree->nodetype = nodetype; - - ntreeInitTypes(ntree); + /* Types are fully initialized at this point, + * if an undefined node is added later this will be reset. + */ + ntree->init |= NTREE_TYPE_INIT; - ntype = node_get_type(ntree, ntree->nodetype); - if (ntype && ntype->inittreefunc) - ntype->inittreefunc(ntree); + BLI_strncpy(ntree->idname, idname, sizeof(ntree->idname)); + ntree_set_typeinfo(ntree, ntreeTypeFind(idname)); return ntree; } @@ -699,12 +1103,12 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, int type, int nodetype) * copying for internal use (threads for eg), where you wont want it to modify the * scene data. */ -static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, const short do_id_user, const short do_make_extern) +static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, const short do_id_user, const short do_make_extern, const short copy_previews) { bNodeTree *newtree; bNode *node /*, *nnode */ /* UNUSED */, *last; + bNodeSocket *sock, *oldsock; bNodeLink *link; - bNodeSocket *gsock, *oldgsock; if (ntree == NULL) return NULL; @@ -747,22 +1151,6 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, const short do_id_use break; } - /* socket definition for group usage */ - BLI_duplicatelist(&newtree->inputs, &ntree->inputs); - for (gsock = newtree->inputs.first, oldgsock = ntree->inputs.first; gsock; gsock = gsock->next, oldgsock = oldgsock->next) { - oldgsock->new_sock = gsock; - gsock->groupsock = (oldgsock->groupsock ? oldgsock->groupsock->new_sock : NULL); - gsock->default_value = node_socket_make_default_value(oldgsock->type); - node_socket_copy_default_value(oldgsock->type, gsock->default_value, oldgsock->default_value); - } - BLI_duplicatelist(&newtree->outputs, &ntree->outputs); - for (gsock = newtree->outputs.first, oldgsock = ntree->outputs.first; gsock; gsock = gsock->next, oldgsock = oldgsock->next) { - oldgsock->new_sock = gsock; - gsock->groupsock = (oldgsock->groupsock ? oldgsock->groupsock->new_sock : NULL); - gsock->default_value = node_socket_make_default_value(oldgsock->type); - node_socket_copy_default_value(oldgsock->type, gsock->default_value, oldgsock->default_value); - } - /* copy links */ BLI_duplicatelist(&newtree->links, &ntree->links); for (link = newtree->links.first; link; link = link->next) { @@ -775,18 +1163,47 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, const short do_id_use link->tosock->link = link; } + /* copy interface sockets */ + BLI_duplicatelist(&newtree->inputs, &ntree->inputs); + oldsock = ntree->inputs.first; + for (sock = newtree->inputs.first; sock; sock = sock->next, oldsock = oldsock->next) + node_socket_copy(sock, oldsock); + + BLI_duplicatelist(&newtree->outputs, &ntree->outputs); + oldsock = ntree->outputs.first; + for (sock = newtree->outputs.first; sock; sock = sock->next, oldsock = oldsock->next) + node_socket_copy(sock, oldsock); + + /* copy preview hash */ + if (ntree->previews && copy_previews) { + bNodeInstanceHashIterator iter; + + newtree->previews = BKE_node_instance_hash_new("node previews"); + + NODE_INSTANCE_HASH_ITER(iter, ntree->previews) { + bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter); + bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter); + BKE_node_instance_hash_insert(newtree->previews, key, BKE_node_preview_copy(preview)); + } + } + else + newtree->previews = NULL; + /* update node->parent pointers */ for (node = newtree->nodes.first; node; node = node->next) { if (node->parent) node->parent = node->parent->new_node; } + /* node tree will generate its own interface type */ + ntree->interface_type = NULL; + return newtree; } bNodeTree *ntreeCopyTree_ex(bNodeTree *ntree, const short do_id_user) { - return ntreeCopyTree_internal(ntree, do_id_user, TRUE); + return ntreeCopyTree_internal(ntree, do_id_user, TRUE, TRUE); } bNodeTree *ntreeCopyTree(bNodeTree *ntree) { @@ -835,62 +1252,225 @@ void ntreeUserDecrefID(bNodeTree *ntree) } } -/* *************** preview *********** */ -/* if node->preview, then we assume the rect to exist */ +/* *************** Node Preview *********** */ -void nodeFreePreview(bNode *node) +/* XXX this should be removed eventually ... + * Currently BKE functions are modelled closely on previous code, + * using BKE_node_preview_init_tree to set up previews for a whole node tree in advance. + * This should be left more to the individual node tree implementations. + */ +int BKE_node_preview_used(bNode *node) { - if (node->preview) { - if (node->preview->rect) - MEM_freeN(node->preview->rect); - MEM_freeN(node->preview); - node->preview = NULL; - } + /* XXX check for closed nodes? */ + return (node->typeinfo->flag & NODE_PREVIEW) != 0; } -static void node_init_preview(bNode *node, int xsize, int ysize) +bNodePreview *BKE_node_preview_verify(bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, int create) { + bNodePreview *preview; - if (node->preview == NULL) { - node->preview = MEM_callocN(sizeof(bNodePreview), "node preview"); - // printf("added preview %s\n", node->name); + preview = BKE_node_instance_hash_lookup(previews, key); + if (!preview) { + if (create) { + preview = MEM_callocN(sizeof(bNodePreview), "node preview"); + BKE_node_instance_hash_insert(previews, key, preview); + } + else + return NULL; } /* node previews can get added with variable size this way */ if (xsize == 0 || ysize == 0) - return; + return preview; /* sanity checks & initialize */ - if (node->preview->rect) { - if (node->preview->xsize != xsize && node->preview->ysize != ysize) { - MEM_freeN(node->preview->rect); - node->preview->rect = NULL; + if (preview->rect) { + if (preview->xsize != xsize || preview->ysize != ysize) { + MEM_freeN(preview->rect); + preview->rect = NULL; } } - if (node->preview->rect == NULL) { - node->preview->rect = MEM_callocN(4 * xsize + xsize * ysize * sizeof(char) * 4, "node preview rect"); - node->preview->xsize = xsize; - node->preview->ysize = ysize; + if (preview->rect == NULL) { + preview->rect = MEM_callocN(4 * xsize + xsize * ysize * sizeof(char) * 4, "node preview rect"); + preview->xsize = xsize; + preview->ysize = ysize; } /* no clear, makes nicer previews */ + + return preview; } -void ntreeInitPreview(bNodeTree *ntree, int xsize, int ysize) +bNodePreview *BKE_node_preview_copy(bNodePreview *preview) +{ + bNodePreview *new_preview = MEM_dupallocN(preview); + if (preview->rect) + new_preview->rect = MEM_dupallocN(preview->rect); + return new_preview; +} + +void BKE_node_preview_free(bNodePreview *preview) +{ + if (preview->rect) + MEM_freeN(preview->rect); + MEM_freeN(preview); +} + +static void node_preview_init_tree_recursive(bNodeInstanceHash *previews, bNodeTree *ntree, bNodeInstanceKey parent_key, int xsize, int ysize, int create) { bNode *node; - - if (ntree == NULL) + for (node = ntree->nodes.first; node; node = node->next) { + bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node); + + if (BKE_node_preview_used(node)) { + node->preview_xsize = xsize; + node->preview_ysize = ysize; + + BKE_node_preview_verify(previews, key, xsize, ysize, create); + } + + if (node->type == NODE_GROUP) + node_preview_init_tree_recursive(previews, (bNodeTree *)node->id, key, xsize, ysize, create); + } +} + +void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize, int create_previews) +{ + if (!ntree) return; + if (!ntree->previews) + ntree->previews = BKE_node_instance_hash_new("node previews"); + + node_preview_init_tree_recursive(ntree->previews, ntree, NODE_INSTANCE_KEY_BASE, xsize, ysize, create_previews); +} + +static void node_preview_tag_used_recursive(bNodeInstanceHash *previews, bNodeTree *ntree, bNodeInstanceKey parent_key) +{ + bNode *node; for (node = ntree->nodes.first; node; node = node->next) { - if (node->typeinfo->flag & NODE_PREVIEW) /* hrms, check for closed nodes? */ - node_init_preview(node, xsize, ysize); - if (node->type == NODE_GROUP && (node->flag & NODE_GROUP_EDIT)) - ntreeInitPreview((bNodeTree *)node->id, xsize, ysize); + bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node); + + if (BKE_node_preview_used(node)) + BKE_node_instance_hash_tag_key(previews, key); + + if (node->type == NODE_GROUP) + node_preview_tag_used_recursive(previews, (bNodeTree *)node->id, key); + } +} + +void BKE_node_preview_remove_unused(bNodeTree *ntree) +{ + if (!ntree || !ntree->previews) + return; + + /* use the instance hash functions for tagging and removing unused previews */ + BKE_node_instance_hash_clear_tags(ntree->previews); + node_preview_tag_used_recursive(ntree->previews, ntree, NODE_INSTANCE_KEY_BASE); + + BKE_node_instance_hash_remove_untagged(ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free); +} + +void BKE_node_preview_free_tree(bNodeTree *ntree) +{ + if (!ntree) + return; + + if (ntree->previews) { + BKE_node_instance_hash_free(ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free); + ntree->previews = NULL; + } +} + +void BKE_node_preview_clear(bNodePreview *preview) +{ + if (preview && preview->rect) + memset(preview->rect, 0, MEM_allocN_len(preview->rect)); +} + +void BKE_node_preview_clear_tree(bNodeTree *ntree) +{ + bNodeInstanceHashIterator iter; + + if (!ntree || !ntree->previews) + return; + + NODE_INSTANCE_HASH_ITER(iter, ntree->previews) { + bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter); + BKE_node_preview_clear(preview); + } +} + +static void node_preview_sync(bNodePreview *to, bNodePreview *from) +{ + /* sizes should have been initialized by BKE_node_preview_init_tree */ + BLI_assert(to->xsize == from->xsize && to->ysize == from->ysize); + + /* copy over contents of previews */ + if (to->rect && from->rect) { + int xsize = to->xsize; + int ysize = to->ysize; + memcpy(to->rect, from->rect, 4 * xsize + xsize * ysize * sizeof(char) * 4); } } +void BKE_node_preview_sync_tree(bNodeTree *to_ntree, bNodeTree *from_ntree) +{ + bNodeInstanceHash *from_previews = from_ntree->previews; + bNodeInstanceHash *to_previews = to_ntree->previews; + bNodeInstanceHashIterator iter; + + if (!from_previews || !to_previews) + return; + + NODE_INSTANCE_HASH_ITER(iter, from_previews) { + bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter); + bNodePreview *from = BKE_node_instance_hash_iterator_get_value(&iter); + bNodePreview *to = BKE_node_instance_hash_lookup(to_previews, key); + + if (from && to) + node_preview_sync(to, from); + } +} + +void BKE_node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree) +{ + /* free old previews */ + if (to_ntree->previews) + BKE_node_instance_hash_free(to_ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free); + + /* transfer previews */ + to_ntree->previews = from_ntree->previews; + from_ntree->previews = NULL; + + /* clean up, in case any to_ntree nodes have been removed */ + BKE_node_preview_remove_unused(to_ntree); +} + +/* hack warning! this function is only used for shader previews, and + * since it gets called multiple times per pixel for Ztransp we only + * add the color once. Preview gets cleared before it starts render though */ +void BKE_node_preview_set_pixel(bNodePreview *preview, const float col[4], int x, int y, int do_manage) +{ + if (preview) { + if (x >= 0 && y >= 0) { + if (x < preview->xsize && y < preview->ysize) { + unsigned char *tar = preview->rect + 4 * ((preview->xsize * y) + x); + + if (do_manage) { + linearrgb_to_srgb_uchar4(tar, col); + } + else { + rgba_float_to_uchar(tar, col); + } + } + //else printf("prv out bound x y %d %d\n", x, y); + } + //else printf("prv out bound x y %d %d\n", x, y); + } +} + +#if 0 static void nodeClearPreview(bNode *node) { if (node->preview && node->preview->rect) @@ -908,7 +1488,7 @@ void ntreeClearPreview(bNodeTree *ntree) for (node = ntree->nodes.first; node; node = node->next) { if (node->typeinfo->flag & NODE_PREVIEW) nodeClearPreview(node); - if (node->type == NODE_GROUP && (node->flag & NODE_GROUP_EDIT)) + if (node->type == NODE_GROUP) ntreeClearPreview((bNodeTree *)node->id); } } @@ -936,6 +1516,7 @@ void nodeAddToPreview(bNode *node, const float col[4], int x, int y, int do_mana //else printf("prv out bound x y %d %d\n", x, y); } } +#endif /* ************** Free stuff ********** */ @@ -985,45 +1566,54 @@ void nodeFreeNode(bNodeTree *ntree, bNode *node) { bNodeSocket *sock, *nextsock; + /* extra free callback */ + if (node->typeinfo && node->typeinfo->freefunc_api) { + PointerRNA ptr; + RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr); + + node->typeinfo->freefunc_api(&ptr); + } + + /* since it is called while free database, node->id is undefined */ + /* can be called for nodes outside a node tree (e.g. clipboard) */ if (ntree) { - bNodeTreeType *treetype = ntreeGetType(ntree->type); - /* remove all references to this node */ nodeUnlinkNode(ntree, node); node_unlink_attached(ntree, node); - + BLI_remlink(&ntree->nodes, node); - - if (treetype->free_node_cache) - treetype->free_node_cache(ntree, node); + + if (ntree->typeinfo && ntree->typeinfo->free_node_cache) + ntree->typeinfo->free_node_cache(ntree, node); /* texture node has bad habit of keeping exec data around */ if (ntree->type == NTREE_TEXTURE && ntree->execdata) { - ntreeTexEndExecTree(ntree->execdata, 1); + ntreeTexEndExecTree(ntree->execdata); ntree->execdata = NULL; } + + if(node->typeinfo && node->typeinfo->freefunc) + node->typeinfo->freefunc(node); } - /* since it is called while free database, node->id is undefined */ - - if (node->typeinfo && node->typeinfo->freestoragefunc) - node->typeinfo->freestoragefunc(node); - for (sock = node->inputs.first; sock; sock = nextsock) { nextsock = sock->next; - node_socket_free_default_value(sock->type, sock->default_value); + node_socket_free(ntree, sock, node); MEM_freeN(sock); } for (sock = node->outputs.first; sock; sock = nextsock) { nextsock = sock->next; - node_socket_free_default_value(sock->type, sock->default_value); + node_socket_free(ntree, sock, node); MEM_freeN(sock); } BLI_freelistN(&node->internal_links); - nodeFreePreview(node); + if (node->prop) { + IDP_FreeProperty(node->prop); + MEM_freeN(node->prop); + } MEM_freeN(node); @@ -1031,12 +1621,24 @@ void nodeFreeNode(bNodeTree *ntree, bNode *node) ntree->update |= NTREE_UPDATE_NODES; } +static void node_socket_interface_free(bNodeTree *UNUSED(ntree), bNodeSocket *sock) +{ + if (sock->prop) { + IDP_FreeProperty(sock->prop); + MEM_freeN(sock->prop); + } + + /* can be left over from old files */ + if (sock->default_value) + MEM_freeN(sock->default_value); +} + /* do not free ntree itself here, BKE_libblock_free calls this function too */ void ntreeFreeTree_ex(bNodeTree *ntree, const short do_id_user) { bNodeTree *tntree; bNode *node, *next; - bNodeSocket *sock; + bNodeSocket *sock, *nextsock; if (ntree == NULL) return; @@ -1048,15 +1650,18 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const short do_id_user) if (ntree->execdata) { switch (ntree->type) { case NTREE_SHADER: - ntreeShaderEndExecTree(ntree->execdata, 1); + ntreeShaderEndExecTree(ntree->execdata); break; case NTREE_TEXTURE: - ntreeTexEndExecTree(ntree->execdata, 1); + ntreeTexEndExecTree(ntree->execdata); ntree->execdata = NULL; break; } } + /* unregister associated RNA types */ + ntreeInterfaceTypeFree(ntree); + BKE_free_animdata((ID *)ntree); id_us_min((ID *)ntree->gpd); @@ -1082,13 +1687,23 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const short do_id_user) nodeFreeNode(ntree, node); } + + /* free interface sockets */ + for (sock = ntree->inputs.first; sock; sock = nextsock) { + nextsock = sock->next; + node_socket_interface_free(ntree, sock); + MEM_freeN(sock); + } + for (sock = ntree->outputs.first; sock; sock = nextsock) { + nextsock = sock->next; + node_socket_interface_free(ntree, sock); + MEM_freeN(sock); + } - for (sock = ntree->inputs.first; sock; sock = sock->next) - node_socket_free_default_value(sock->type, sock->default_value); - BLI_freelistN(&ntree->inputs); - for (sock = ntree->outputs.first; sock; sock = sock->next) - node_socket_free_default_value(sock->type, sock->default_value); - BLI_freelistN(&ntree->outputs); + /* free preview hash */ + if (ntree->previews) { + BKE_node_instance_hash_free(ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free); + } /* if ntree is not part of library, free the libblock data explicitly */ for (tntree = G.main->nodetree.first; tntree; tntree = tntree->id.next) @@ -1106,13 +1721,10 @@ void ntreeFreeTree(bNodeTree *ntree) void ntreeFreeCache(bNodeTree *ntree) { - bNodeTreeType *treetype; - if (ntree == NULL) return; - treetype = ntreeGetType(ntree->type); - if (treetype->free_cache) - treetype->free_cache(ntree); + if (ntree->typeinfo->free_cache) + ntree->typeinfo->free_cache(ntree); } void ntreeSetOutput(bNodeTree *ntree) @@ -1162,6 +1774,24 @@ void ntreeSetOutput(bNodeTree *ntree) if (output == 0) node->flag |= NODE_DO_OUTPUT; } + + /* group node outputs use this flag too */ + if (node->type == NODE_GROUP_OUTPUT) { + bNode *tnode; + int output = 0; + + for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) { + if (tnode->type == NODE_GROUP_OUTPUT) { + if (tnode->flag & NODE_DO_OUTPUT) { + output++; + if (output > 1) + tnode->flag &= ~NODE_DO_OUTPUT; + } + } + } + if (output == 0) + node->flag |= NODE_DO_OUTPUT; + } } /* here we could recursively set which nodes have to be done, @@ -1180,52 +1810,10 @@ bNodeTree *ntreeFromID(ID *id) } } -typedef struct MakeLocalCallData { - ID *group_id; - ID *new_id; - int lib, local; -} MakeLocalCallData; - -static void ntreeMakeLocal_CheckLocal(void *calldata, ID *owner_id, bNodeTree *ntree) -{ - MakeLocalCallData *cd = (MakeLocalCallData *)calldata; - bNode *node; - - /* find if group is in tree */ - for (node = ntree->nodes.first; node; node = node->next) { - if (node->id == cd->group_id) { - if (owner_id->lib) { - cd->lib = TRUE; - } - else { - cd->local = TRUE; - } - } - } -} - -static void ntreeMakeLocal_LinkNew(void *calldata, ID *owner_id, bNodeTree *ntree) -{ - MakeLocalCallData *cd = (MakeLocalCallData *)calldata; - bNode *node; - - /* find if group is in tree */ - for (node = ntree->nodes.first; node; node = node->next) { - if (node->id == cd->group_id) { - if (owner_id->lib == NULL) { - node->id = cd->new_id; - cd->new_id->us++; - cd->group_id->us--; - } - } - } -} - void ntreeMakeLocal(bNodeTree *ntree) { Main *bmain = G.main; - bNodeTreeType *treetype = ntreeGetType(ntree->type); - MakeLocalCallData cd; + int lib = FALSE, local = FALSE; /* - only lib users: do nothing * - only local users: set flag @@ -1239,26 +1827,42 @@ void ntreeMakeLocal(bNodeTree *ntree) } /* now check users of groups... again typedepending, callback... */ - cd.group_id = &ntree->id; - cd.new_id = NULL; - cd.local = 0; - cd.lib = 0; - - treetype->foreach_nodetree(G.main, &cd, &ntreeMakeLocal_CheckLocal); + FOREACH_NODETREE(G.main, tntree, owner_id) { + bNode *node; + /* find if group is in tree */ + for (node = tntree->nodes.first; node; node = node->next) { + if (node->id == (ID *)ntree) { + if (owner_id->lib) + lib = TRUE; + else + local = TRUE; + } + } + } FOREACH_NODETREE_END /* if all users are local, we simply make tree local */ - if (cd.local && cd.lib == 0) { + if (local && !lib) { id_clear_lib_data(bmain, (ID *)ntree); } - else if (cd.local && cd.lib) { + else if (local && lib) { /* this is the mixed case, we copy the tree and assign it to local users */ bNodeTree *newtree = ntreeCopyTree(ntree); newtree->id.us = 0; - - cd.new_id = &newtree->id; - treetype->foreach_nodetree(G.main, &cd, &ntreeMakeLocal_LinkNew); + FOREACH_NODETREE(G.main, tntree, owner_id) { + bNode *node; + /* find if group is in tree */ + for (node = tntree->nodes.first; node; node = node->next) { + if (node->id == (ID *)ntree) { + if (owner_id->lib == NULL) { + node->id = (ID *)newtree; + newtree->id.us++; + ntree->id.us--; + } + } + } + } FOREACH_NODETREE_END } } @@ -1283,90 +1887,326 @@ int ntreeOutputExists(bNode *node, bNodeSocket *testsock) /* returns localized tree for execution in threads */ bNodeTree *ntreeLocalize(bNodeTree *ntree) { - bNodeTreeType *ntreetype = ntreeGetType(ntree->type); - - bNodeTree *ltree; - bNode *node; + if (ntreeIsValid(ntree)) { + bNodeTree *ltree; + bNode *node; + + bAction *action_backup = NULL, *tmpact_backup = NULL; + + /* Workaround for copying an action on each render! + * set action to NULL so animdata actions don't get copied */ + AnimData *adt = BKE_animdata_from_id(&ntree->id); + + if (adt) { + action_backup = adt->action; + tmpact_backup = adt->tmpact; + + adt->action = NULL; + adt->tmpact = NULL; + } - bAction *action_backup = NULL, *tmpact_backup = NULL; + /* Make full copy. + * Note: previews are not copied here. + */ + ltree = ntreeCopyTree_internal(ntree, FALSE, FALSE, FALSE); + + if (adt) { + AnimData *ladt = BKE_animdata_from_id(<ree->id); + + adt->action = ladt->action = action_backup; + adt->tmpact = ladt->tmpact = tmpact_backup; + + if (action_backup) action_backup->id.us++; + if (tmpact_backup) tmpact_backup->id.us++; + + } + /* end animdata uglyness */ - /* Workaround for copying an action on each render! - * set action to NULL so animdata actions don't get copied */ - AnimData *adt = BKE_animdata_from_id(&ntree->id); + /* ensures only a single output node is enabled */ + ntreeSetOutput(ntree); + + for (node = ntree->nodes.first; node; node = node->next) { + /* store new_node pointer to original */ + node->new_node->new_node = node; + } + + if (ntree->typeinfo->localize) + ntree->typeinfo->localize(ltree, ntree); + + return ltree; + } + else + return NULL; +} - if (adt) { - action_backup = adt->action; - tmpact_backup = adt->tmpact; +/* sync local composite with real tree */ +/* local tree is supposed to be running, be careful moving previews! */ +/* is called by jobs manager, outside threads, so it doesnt happen during draw */ +void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree) +{ + if (localtree && ntreeIsValid(ntree)) { + /* XXX syncing was disabled for compositor nodes. + * It has to be ensured that there is no concurrent read/write access! + * Possibly needs a mutex lock or a flag to disable for certain tree types ... + */ + BKE_node_preview_sync_tree(ntree, localtree); + + if (ntree->typeinfo->local_sync) + ntree->typeinfo->local_sync(localtree, ntree); + } +} - adt->action = NULL; - adt->tmpact = NULL; +/* merge local tree results back, and free local tree */ +/* we have to assume the editor already changed completely */ +void ntreeLocalMerge(bNodeTree *localtree, bNodeTree *ntree) +{ + if (localtree && ntreeIsValid(ntree)) { + BKE_node_preview_merge_tree(ntree, localtree); + + if (ntree->typeinfo->local_merge) + ntree->typeinfo->local_merge(localtree, ntree); + + ntreeFreeTree_ex(localtree, FALSE); + MEM_freeN(localtree); } +} - /* node copy func */ - ltree = ntreeCopyTree_internal(ntree, FALSE, FALSE); - if (adt) { - AnimData *ladt = BKE_animdata_from_id(<ree->id); +/* ************ NODE TREE INTERFACE *************** */ - adt->action = ladt->action = action_backup; - adt->tmpact = ladt->tmpact = tmpact_backup; +static bNodeSocket *make_socket_template(bNodeTree *ntree, int in_out, + const char *idname, const char *name) +{ + bNodeSocketType *stype = nodeSocketTypeFind(idname); + bNodeSocket *sock; + int own_index = ntree->cur_index++; + + if (stype == NULL) { + printf("Error: node socket type '%s' undefined\n", idname); + return NULL; + } + + sock = MEM_callocN(sizeof(bNodeSocket), "socket template"); + sock->typeinfo= stype; + BLI_strncpy(sock->idname, stype->idname, sizeof(sock->idname)); + sock->in_out = in_out; + sock->type = SOCK_CUSTOM; /* int type undefined by default */ + + /* assign new unique index */ + own_index = ntree->cur_index++; + /* use the own_index as socket identifier */ + if (in_out == SOCK_IN) + BLI_snprintf(sock->identifier, MAX_NAME, "Input_%d", own_index); + else + BLI_snprintf(sock->identifier, MAX_NAME, "Output_%d", own_index); +#ifdef USE_NODE_COMPAT_CUSTOMNODES + /* XXX forward compatibility: + * own_index is deprecated, but needs to be set here. + * Node sockets generally use the identifier string instead now, + * but reconstructing own_index in writefile.c would require parsing the identifier string. + */ + sock->own_index = own_index; +#endif + + sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF); + + BLI_strncpy(sock->name, name, NODE_MAXSTR); + sock->storage = NULL; + sock->flag |= SOCK_COLLAPSED; + + return sock; +} - if (action_backup) action_backup->id.us++; - if (tmpact_backup) tmpact_backup->id.us++; - +bNodeSocket *ntreeFindSocketInterface(bNodeTree *ntree, int in_out, const char *identifier) +{ + bNodeSocket *iosock = (in_out == SOCK_IN ? ntree->inputs.first : ntree->outputs.first); + for (; iosock; iosock = iosock->next) + if (strcmp(iosock->identifier, identifier)==0) + return iosock; + return NULL; +} + +bNodeSocket *ntreeAddSocketInterface(bNodeTree *ntree, int in_out, const char *idname, const char *name) +{ + bNodeSocket *iosock; + + iosock = make_socket_template(ntree, in_out, idname, name); + if (in_out == SOCK_IN) { + BLI_addtail(&ntree->inputs, iosock); + ntree->update |= NTREE_UPDATE_GROUP_IN; } - /* end animdata uglyness */ + else if (in_out == SOCK_OUT) { + BLI_addtail(&ntree->outputs, iosock); + ntree->update |= NTREE_UPDATE_GROUP_OUT; + } + + return iosock; +} - /* ensures only a single output node is enabled */ - ntreeSetOutput(ntree); +bNodeSocket *ntreeInsertSocketInterface(bNodeTree *ntree, int in_out, const char *idname, + bNodeSocket *next_sock, const char *name) +{ + bNodeSocket *iosock; + + iosock = make_socket_template(ntree, in_out, idname, name); + if (in_out == SOCK_IN) { + BLI_insertlinkbefore(&ntree->inputs, next_sock, iosock); + ntree->update |= NTREE_UPDATE_GROUP_IN; + } + else if (in_out == SOCK_OUT) { + BLI_insertlinkbefore(&ntree->outputs, next_sock, iosock); + ntree->update |= NTREE_UPDATE_GROUP_OUT; + } + + return iosock; +} - for (node = ntree->nodes.first; node; node = node->next) { - /* store new_node pointer to original */ - node->new_node->new_node = node; +struct bNodeSocket *ntreeAddSocketInterfaceFromSocket(bNodeTree *ntree, bNode *from_node, bNodeSocket *from_sock) +{ + bNodeSocket *iosock = ntreeAddSocketInterface(ntree, from_sock->in_out, from_sock->idname, from_sock->name); + if (iosock) { + if (iosock->typeinfo->interface_from_socket) + iosock->typeinfo->interface_from_socket(ntree, iosock, from_node, from_sock); } + return iosock; +} - if (ntreetype->localize) - ntreetype->localize(ltree, ntree); +struct bNodeSocket *ntreeInsertSocketInterfaceFromSocket(bNodeTree *ntree, bNodeSocket *next_sock, bNode *from_node, bNodeSocket *from_sock) +{ + bNodeSocket *iosock = ntreeInsertSocketInterface(ntree, from_sock->in_out, from_sock->idname, next_sock, from_sock->name); + if (iosock) { + if (iosock->typeinfo->interface_from_socket) + iosock->typeinfo->interface_from_socket(ntree, iosock, from_node, from_sock); + } + return iosock; +} - return ltree; +void ntreeRemoveSocketInterface(bNodeTree *ntree, bNodeSocket *sock) +{ + /* this is fast, this way we don't need an in_out argument */ + BLI_remlink(&ntree->inputs, sock); + BLI_remlink(&ntree->outputs, sock); + + node_socket_interface_free(ntree, sock); + MEM_freeN(sock); + + ntree->update |= NTREE_UPDATE_GROUP; } -/* sync local composite with real tree */ -/* local tree is supposed to be running, be careful moving previews! */ -/* is called by jobs manager, outside threads, so it doesnt happen during draw */ -void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree) +/* generates a valid RNA identifier from the node tree name */ +static void ntree_interface_identifier_base(bNodeTree *ntree, char *base) { - bNodeTreeType *ntreetype = ntreeGetType(ntree->type); + /* generate a valid RNA identifier */ + sprintf(base, "NodeTreeInterface_%s", ntree->id.name+2); + RNA_identifier_sanitize(base, FALSE); +} - if (ntreetype->local_sync) - ntreetype->local_sync(localtree, ntree); +/* check if the identifier is already in use */ +static bool ntree_interface_unique_identifier_check(void *UNUSED(data), const char *identifier) +{ + return (RNA_struct_find(identifier) != NULL); } -/* merge local tree results back, and free local tree */ -/* we have to assume the editor already changed completely */ -void ntreeLocalMerge(bNodeTree *localtree, bNodeTree *ntree) +/* generates the actual unique identifier and ui name and description */ +static void ntree_interface_identifier(bNodeTree *ntree, const char *base, char *identifier, int maxlen, char *name, char *description) { - bNodeTreeType *ntreetype = ntreeGetType(ntree->type); - bNode *lnode; + /* There is a possibility that different node tree names get mapped to the same identifier + * after sanitization (e.g. "SomeGroup_A", "SomeGroup.A" both get sanitized to "SomeGroup_A"). + * On top of the sanitized id string add a number suffix if necessary to avoid duplicates. + */ + identifier[0] = '\0'; + BLI_uniquename_cb(ntree_interface_unique_identifier_check, NULL, base, '_', identifier, maxlen); - /* move over the compbufs and previews */ - for (lnode = localtree->nodes.first; lnode; lnode = lnode->next) { - if (ntreeNodeExists(ntree, lnode->new_node)) { - if (lnode->preview && lnode->preview->rect) { - nodeFreePreview(lnode->new_node); - lnode->new_node->preview = lnode->preview; - lnode->preview = NULL; - } + sprintf(name, "Node Tree %s Interface", ntree->id.name+2); + sprintf(description, "Interface properties of node group %s", ntree->id.name+2); +} + +static void ntree_interface_type_create(bNodeTree *ntree) +{ + StructRNA *srna; + bNodeSocket *sock; + /* strings are generated from base string + ID name, sizes are sufficient */ + char base[MAX_ID_NAME+64], identifier[MAX_ID_NAME+64], name[MAX_ID_NAME+64], description[MAX_ID_NAME+64]; + + /* generate a valid RNA identifier */ + ntree_interface_identifier_base(ntree, base); + ntree_interface_identifier(ntree, base, identifier, sizeof(identifier), name, description); + + /* register a subtype of PropertyGroup */ + srna = RNA_def_struct_ptr(&BLENDER_RNA, identifier, &RNA_PropertyGroup); + RNA_def_struct_ui_text(srna, name, description); + RNA_def_struct_duplicate_pointers(srna); + + /* associate the RNA type with the node tree */ + ntree->interface_type = srna; + RNA_struct_blender_type_set(srna, ntree); + + /* add socket properties */ + for (sock = ntree->inputs.first; sock; sock = sock->next) { + bNodeSocketType *stype = sock->typeinfo; + if (stype && stype->interface_register_properties) + stype->interface_register_properties(ntree, sock, srna); + } + for (sock = ntree->outputs.first; sock; sock = sock->next) { + bNodeSocketType *stype = sock->typeinfo; + if (stype && stype->interface_register_properties) + stype->interface_register_properties(ntree, sock, srna); + } +} + +StructRNA *ntreeInterfaceTypeGet(bNodeTree *ntree, int create) +{ + if (ntree->interface_type) { + /* strings are generated from base string + ID name, sizes are sufficient */ + char base[MAX_ID_NAME+64], identifier[MAX_ID_NAME+64], name[MAX_ID_NAME+64], description[MAX_ID_NAME+64]; + + /* A bit of a hack: when changing the ID name, update the RNA type identifier too, + * so that the names match. This is not strictly necessary to keep it working, + * but better for identifying associated NodeTree blocks and RNA types. + */ + StructRNA *srna = ntree->interface_type; + + ntree_interface_identifier_base(ntree, base); + + /* RNA identifier may have a number suffix, but should start with the idbase string */ + if (strncmp(RNA_struct_identifier(srna), base, sizeof(base)) != 0) { + /* generate new unique RNA identifier from the ID name */ + ntree_interface_identifier(ntree, base, identifier, sizeof(identifier), name, description); + + /* rename the RNA type */ + RNA_def_struct_free_pointers(srna); + RNA_def_struct_identifier(srna, identifier); + RNA_def_struct_ui_text(srna, name, description); + RNA_def_struct_duplicate_pointers(srna); } } + else if (create) { + ntree_interface_type_create(ntree); + } + + return ntree->interface_type; +} - if (ntreetype->local_merge) - ntreetype->local_merge(localtree, ntree); +void ntreeInterfaceTypeFree(bNodeTree *ntree) +{ + if (ntree->interface_type) { + RNA_struct_free(&BLENDER_RNA, ntree->interface_type); + ntree->interface_type = NULL; + } +} - ntreeFreeTree_ex(localtree, FALSE); - MEM_freeN(localtree); +void ntreeInterfaceTypeUpdate(bNodeTree *ntree) +{ + /* XXX it would be sufficient to just recreate all properties + * instead of re-registering the whole struct type, + * but there is currently no good way to do this in the RNA functions. + * Overhead should be negligible. + */ + ntreeInterfaceTypeFree(ntree); + ntree_interface_type_create(ntree); } + /* ************ find stuff *************** */ int ntreeHasType(bNodeTree *ntree, int type) @@ -1420,25 +2260,25 @@ bNode *nodeGetActive(bNodeTree *ntree) /* two active flags, ID nodes have special flag for buttons display */ bNode *nodeGetActiveID(bNodeTree *ntree, short idtype) { - bNode *node; + bNode *node, *tnode; if (ntree == NULL) return NULL; - /* check for group edit */ - for (node = ntree->nodes.first; node; node = node->next) - if (node->flag & NODE_GROUP_EDIT) - break; - - if (node) - ntree = (bNodeTree *)node->id; - - /* now find active node with this id */ for (node = ntree->nodes.first; node; node = node->next) if (node->id && GS(node->id->name) == idtype) if (node->flag & NODE_ACTIVE_ID) - break; - - return node; + return node; + + /* no node with active ID in this tree, look inside groups */ + for(node= ntree->nodes.first; node; node= node->next) { + if(node->type==NODE_GROUP) { + tnode = nodeGetActiveID((bNodeTree*)node->id, idtype); + if (tnode) + return tnode; + } + } + + return NULL; } int nodeSetActiveID(bNodeTree *ntree, short idtype, ID *id) @@ -1448,15 +2288,6 @@ int nodeSetActiveID(bNodeTree *ntree, short idtype, ID *id) if (ntree == NULL) return ok; - /* check for group edit */ - for (node = ntree->nodes.first; node; node = node->next) - if (node->flag & NODE_GROUP_EDIT) - break; - - if (node) - ntree = (bNodeTree *)node->id; - - /* now find active node with this id */ for (node = ntree->nodes.first; node; node = node->next) { if (node->id && GS(node->id->name) == idtype) { if (id && ok == FALSE && node->id == id) { @@ -1469,6 +2300,15 @@ int nodeSetActiveID(bNodeTree *ntree, short idtype, ID *id) } } + /* update all groups linked from here + * if active ID node has been found already, + * just pass NULL so other matching nodes are deactivated. + */ + for(node= ntree->nodes.first; node; node= node->next) { + if(node->type==NODE_GROUP) + ok |= nodeSetActiveID((bNodeTree*)node->id, idtype, (ok==FALSE ? id : NULL)); + } + return ok; } @@ -1485,6 +2325,24 @@ void nodeClearActiveID(bNodeTree *ntree, short idtype) node->flag &= ~NODE_ACTIVE_ID; } +void nodeSetSelected(bNode *node, int select) +{ + if (select) { + node->flag |= NODE_SELECT; + } + else { + bNodeSocket *sock; + + node->flag &= ~NODE_SELECT; + + /* deselect sockets too */ + for (sock=node->inputs.first; sock; sock=sock->next) + sock->flag &= ~NODE_SELECT; + for (sock=node->outputs.first; sock; sock=sock->next) + sock->flag &= ~NODE_SELECT; + } +} + void nodeClearActive(bNodeTree *ntree) { bNode *node; @@ -1495,7 +2353,6 @@ void nodeClearActive(bNodeTree *ntree) node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_ID); } - /* two active flags, ID nodes have special flag for buttons display */ void nodeSetActive(bNodeTree *ntree, bNode *node) { @@ -1525,19 +2382,6 @@ int nodeSocketIsHidden(bNodeSocket *sock) return ((sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) != 0); } -void nodeSocketSetType(bNodeSocket *sock, int type) -{ - int old_type = sock->type; - void *old_default_value = sock->default_value; - - sock->type = type; - - sock->default_value = node_socket_make_default_value(sock->type); - node_socket_init_default_value(type, sock->default_value); - node_socket_convert_default_value(sock->type, sock->default_value, old_type, old_default_value); - node_socket_free_default_value(old_type, old_default_value); -} - /* ************** Node Clipboard *********** */ #define USE_NODE_CB_VALIDATE @@ -1692,6 +2536,163 @@ int BKE_node_clipboard_get_type(void) return node_clipboard.type; } + +/* Node Instance Hash */ + +/* magic number for initial hash key */ +const bNodeInstanceKey NODE_INSTANCE_KEY_BASE = {5381}; + +/* Generate a hash key from ntree and node names + * Uses the djb2 algorithm with xor by Bernstein: + * http://www.cse.yorku.ca/~oz/hash.html + */ +static bNodeInstanceKey node_hash_int_str(bNodeInstanceKey hash, const char *str) +{ + char c; + + while ((c = *str++)) + hash.value = ((hash.value << 5) + hash.value) ^ c; /* (hash * 33) ^ c */ + + /* separator '\0' character, to avoid ambiguity from concatenated strings */ + hash.value = (hash.value << 5) + hash.value; /* hash * 33 */ + + return hash; +} + +bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key, bNodeTree *ntree, bNode *node) +{ + bNodeInstanceKey key; + + key = node_hash_int_str(parent_key, ntree->id.name+2); + + if (node) + key = node_hash_int_str(key, node->name); + + return key; +} + +static unsigned int node_instance_hash_key(const void *key) +{ + return ((const bNodeInstanceKey *)key)->value; +} + +static int node_instance_hash_key_cmp(const void *a, const void *b) +{ + unsigned int value_a = ((const bNodeInstanceKey *)a)->value; + unsigned int value_b = ((const bNodeInstanceKey *)b)->value; + if (value_a == value_b) + return 0; + else if (value_a < value_b) + return -1; + else + return 1; +} + +bNodeInstanceHash *BKE_node_instance_hash_new(const char *info) +{ + bNodeInstanceHash *hash = MEM_mallocN(sizeof(bNodeInstanceHash), info); + hash->ghash = BLI_ghash_new(node_instance_hash_key, node_instance_hash_key_cmp, "node instance hash ghash"); + return hash; +} + +void BKE_node_instance_hash_free(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp) +{ + BLI_ghash_free(hash->ghash, NULL, (GHashValFreeFP)valfreefp); + MEM_freeN(hash); +} + +void BKE_node_instance_hash_insert(bNodeInstanceHash *hash, bNodeInstanceKey key, void *value) +{ + bNodeInstanceHashEntry *entry = value; + entry->key = key; + entry->tag = 0; + BLI_ghash_insert(hash->ghash, &entry->key, value); +} + +void *BKE_node_instance_hash_lookup(bNodeInstanceHash *hash, bNodeInstanceKey key) +{ + return BLI_ghash_lookup(hash->ghash, &key); +} + +int BKE_node_instance_hash_remove(bNodeInstanceHash *hash, bNodeInstanceKey key, bNodeInstanceValueFP valfreefp) +{ + return BLI_ghash_remove(hash->ghash, &key, NULL, (GHashValFreeFP)valfreefp); +} + +void BKE_node_instance_hash_clear(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp) +{ + BLI_ghash_clear(hash->ghash, NULL, (GHashValFreeFP)valfreefp); +} + +void *BKE_node_instance_hash_pop(bNodeInstanceHash *hash, bNodeInstanceKey key) +{ + return BLI_ghash_pop(hash->ghash, &key, NULL); +} + +int BKE_node_instance_hash_haskey(bNodeInstanceHash *hash, bNodeInstanceKey key) +{ + return BLI_ghash_haskey(hash->ghash, &key); +} + +int BKE_node_instance_hash_size(bNodeInstanceHash *hash) +{ + return BLI_ghash_size(hash->ghash); +} + +void BKE_node_instance_hash_clear_tags(bNodeInstanceHash *hash) +{ + bNodeInstanceHashIterator iter; + + NODE_INSTANCE_HASH_ITER(iter, hash) { + bNodeInstanceHashEntry *value = BKE_node_instance_hash_iterator_get_value(&iter); + + value->tag = 0; + } +} + +void BKE_node_instance_hash_tag(bNodeInstanceHash *UNUSED(hash), void *value) +{ + bNodeInstanceHashEntry *entry = value; + entry->tag = 1; +} + +int BKE_node_instance_hash_tag_key(bNodeInstanceHash *hash, bNodeInstanceKey key) +{ + bNodeInstanceHashEntry *entry = BKE_node_instance_hash_lookup(hash, key); + + if (entry) { + entry->tag = 1; + return TRUE; + } + else + return FALSE; +} + +void BKE_node_instance_hash_remove_untagged(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp) +{ + /* NOTE: Hash must not be mutated during iterating! + * Store tagged entries in a separate list and remove items afterward. + */ + bNodeInstanceKey *untagged = MEM_mallocN(sizeof(bNodeInstanceKey)*BKE_node_instance_hash_size(hash), "temporary node instance key list"); + bNodeInstanceHashIterator iter; + int num_untagged, i; + + num_untagged = 0; + NODE_INSTANCE_HASH_ITER(iter, hash) { + bNodeInstanceHashEntry *value = BKE_node_instance_hash_iterator_get_value(&iter); + + if (!value->tag) + untagged[num_untagged++] = BKE_node_instance_hash_iterator_get_key(&iter); + } + + for (i = 0; i < num_untagged; ++i) { + BKE_node_instance_hash_remove(hash, untagged[i], valfreefp); + } + + MEM_freeN(untagged); +} + + /* ************** dependency stuff *********** */ /* node is guaranteed to be not checked before */ @@ -1707,12 +2708,10 @@ static int node_get_deplist_recurs(bNodeTree *ntree, bNode *node, bNode ***nsort for (link = ntree->links.first; link; link = link->next) { if (link->tonode == node) { fromnode = link->fromnode; - if (fromnode) { - if (fromnode->done == 0) - fromnode->level = node_get_deplist_recurs(ntree, fromnode, nsort); - if (fromnode->level <= level) - level = fromnode->level - 1; - } + if (fromnode->done == 0) + fromnode->level = node_get_deplist_recurs(ntree, fromnode, nsort); + if (fromnode->level <= level) + level = fromnode->level - 1; } } @@ -1792,13 +2791,6 @@ static void ntree_update_link_pointers(bNodeTree *ntree) sock->flag &= ~SOCK_IN_USE; } } - for (sock = ntree->inputs.first; sock; sock = sock->next) { - sock->flag &= ~SOCK_IN_USE; - } - for (sock = ntree->outputs.first; sock; sock = sock->next) { - sock->link = NULL; - sock->flag &= ~SOCK_IN_USE; - } for (link = ntree->links.first; link; link = link->next) { link->tosock->link = link; @@ -1810,144 +2802,133 @@ static void ntree_update_link_pointers(bNodeTree *ntree) static void ntree_validate_links(bNodeTree *ntree) { - bNodeTreeType *ntreetype = ntreeGetType(ntree->type); bNodeLink *link; for (link = ntree->links.first; link; link = link->next) { link->flag |= NODE_LINK_VALID; if (link->fromnode && link->tonode && link->fromnode->level <= link->tonode->level) link->flag &= ~NODE_LINK_VALID; - else if (ntreetype->validate_link) { - if (!ntreetype->validate_link(ntree, link)) + else if (ntree->typeinfo->validate_link) { + if (!ntree->typeinfo->validate_link(ntree, link)) link->flag &= ~NODE_LINK_VALID; } } } -static void ntree_verify_nodes_cb(void *calldata, struct ID *UNUSED(owner_id), struct bNodeTree *ntree) -{ - ID *id = (ID *)calldata; - bNode *node; - - for (node = ntree->nodes.first; node; node = node->next) - if (node->typeinfo->verifyfunc) - node->typeinfo->verifyfunc(ntree, node, id); -} - void ntreeVerifyNodes(struct Main *main, struct ID *id) { - bNodeTreeType *ntreetype; - bNodeTree *ntree; - int n; - - for (n = 0; n < NUM_NTREE_TYPES; ++n) { - ntreetype = ntreeGetType(n); - if (ntreetype && ntreetype->foreach_nodetree) - ntreetype->foreach_nodetree(main, id, ntree_verify_nodes_cb); - } - for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) - ntree_verify_nodes_cb(id, NULL, ntree); + FOREACH_NODETREE(main, ntree, owner_id) { + bNode *node; + + if (!ntreeIsValid(ntree)) + return; + + for (node = ntree->nodes.first; node; node = node->next) + if (node->typeinfo && node->typeinfo->verifyfunc) + node->typeinfo->verifyfunc(ntree, node, id); + } FOREACH_NODETREE_END } void ntreeUpdateTree(bNodeTree *ntree) { - bNodeTreeType *ntreetype = ntreeGetType(ntree->type); bNode *node; + /* avoid reentrant updates, can be caused by RNA update callbacks */ + if (ntree->is_updating) + return; + ntree->is_updating = TRUE; + + /* only if types are initialized */ + if (!ntreeIsValid(ntree)) + return; + if (ntree->update & (NTREE_UPDATE_LINKS | NTREE_UPDATE_NODES)) { /* set the bNodeSocket->link pointers */ ntree_update_link_pointers(ntree); - - /* update the node level from link dependencies */ - ntree_update_node_level(ntree); } /* update individual nodes */ for (node = ntree->nodes.first; node; node = node->next) { /* node tree update tags override individual node update flags */ if ((node->update & NODE_UPDATE) || (ntree->update & NTREE_UPDATE)) { - if (ntreetype->update_node) - ntreetype->update_node(ntree, node); - else if (node->typeinfo->updatefunc) + if (node->typeinfo->updatefunc) node->typeinfo->updatefunc(ntree, node); nodeUpdateInternalLinks(ntree, node); } } - /* check link validity */ - if (ntree->update & (NTREE_UPDATE_LINKS | NTREE_UPDATE_NODES)) - ntree_validate_links(ntree); - /* generic tree update callback */ - if (ntreetype->update) - ntreetype->update(ntree); - else { - /* Trees can be associated with a specific node type (i.e. group nodes), - * in that case a tree update function may be defined by that node type. - */ - bNodeType *ntype = node_get_type(ntree, ntree->nodetype); - if (ntype && ntype->updatetreefunc) - ntype->updatetreefunc(ntree); - } + if (ntree->typeinfo->update) + ntree->typeinfo->update(ntree); + /* XXX this should be moved into the tree type update callback for tree supporting node groups. + * Currently the node tree interface is still a generic feature of the base NodeTree type. + */ + if (ntree->update & NTREE_UPDATE_GROUP) + ntreeInterfaceTypeUpdate(ntree); /* XXX hack, should be done by depsgraph!! */ ntreeVerifyNodes(G.main, &ntree->id); + if (ntree->update & (NTREE_UPDATE_LINKS | NTREE_UPDATE_NODES)) { + /* node updates can change sockets or links, repeat link pointer update afterward */ + ntree_update_link_pointers(ntree); + + /* update the node level from link dependencies */ + ntree_update_node_level(ntree); + + /* check link validity */ + ntree_validate_links(ntree); + } + /* clear update flags */ for (node = ntree->nodes.first; node; node = node->next) { node->update = 0; } ntree->update = 0; + + ntree->is_updating = FALSE; } void nodeUpdate(bNodeTree *ntree, bNode *node) { - bNodeTreeType *ntreetype = ntreeGetType(ntree->type); + /* avoid reentrant updates, can be caused by RNA update callbacks */ + if (ntree->is_updating) + return; + ntree->is_updating = TRUE; - if (ntreetype->update_node) - ntreetype->update_node(ntree, node); - else if (node->typeinfo->updatefunc) + if (node->typeinfo->updatefunc) node->typeinfo->updatefunc(ntree, node); nodeUpdateInternalLinks(ntree, node); /* clear update flag */ node->update = 0; + + ntree->is_updating = FALSE; } int nodeUpdateID(bNodeTree *ntree, ID *id) { - bNodeTreeType *ntreetype; bNode *node; int change = FALSE; if (ELEM(NULL, id, ntree)) return change; - ntreetype = ntreeGetType(ntree->type); + /* avoid reentrant updates, can be caused by RNA update callbacks */ + if (ntree->is_updating) + return change; + ntree->is_updating = TRUE; - if (ntreetype->update_node) { - for (node = ntree->nodes.first; node; node = node->next) { - if (node->id == id) { - change = TRUE; - node->update |= NODE_UPDATE_ID; - ntreetype->update_node(ntree, node); - /* clear update flag */ - node->update = 0; - } - } - } - else { - for (node = ntree->nodes.first; node; node = node->next) { - if (node->id == id) { - change = TRUE; - node->update |= NODE_UPDATE_ID; - if (node->typeinfo->updatefunc) - node->typeinfo->updatefunc(ntree, node); - /* clear update flag */ - node->update = 0; - } + for (node = ntree->nodes.first; node; node = node->next) { + if(node->id == id) { + change = TRUE; + node->update |= NODE_UPDATE_ID; + if (node->typeinfo->updatefunc) + node->typeinfo->updatefunc(ntree, node); + /* clear update flag */ + node->update = 0; } } @@ -1955,6 +2936,7 @@ int nodeUpdateID(bNodeTree *ntree, ID *id) nodeUpdateInternalLinks(ntree, node); } + ntree->is_updating = FALSE; return change; } @@ -1967,21 +2949,75 @@ void nodeUpdateInternalLinks(bNodeTree *ntree, bNode *node) } -/* ************* node type access ********** */ - -int nodeValid(bNodeTree *ntree, bNodeTemplate *ntemp) +/* nodes that use ID data get synced with local data */ +void nodeSynchronizeID(bNode *node, bool copy_to_id) { - bNodeType *ntype = node_get_type(ntree, ntemp->type); - if (ntype) { - if (ntype->validfunc) - return ntype->validfunc(ntree, ntemp); - else - return 1; + if (node->id==NULL) return; + + if (ELEM(node->type, SH_NODE_MATERIAL, SH_NODE_MATERIAL_EXT)) { + bNodeSocket *sock; + Material *ma= (Material *)node->id; + int a; + + /* hrmf, case in loop isn't super fast, but we don't edit 100s of material at same time either! */ + for (a=0, sock= node->inputs.first; sock; sock= sock->next, a++) { + if (!nodeSocketIsHidden(sock)) { + if (copy_to_id) { + switch (a) { + case MAT_IN_COLOR: + copy_v3_v3(&ma->r, ((bNodeSocketValueRGBA *)sock->default_value)->value); break; + case MAT_IN_SPEC: + copy_v3_v3(&ma->specr, ((bNodeSocketValueRGBA *)sock->default_value)->value); break; + case MAT_IN_REFL: + ma->ref= ((bNodeSocketValueFloat *)sock->default_value)->value; break; + case MAT_IN_MIR: + copy_v3_v3(&ma->mirr, ((bNodeSocketValueRGBA *)sock->default_value)->value); break; + case MAT_IN_AMB: + ma->amb = ((bNodeSocketValueFloat *)sock->default_value)->value; break; + case MAT_IN_EMIT: + ma->emit = ((bNodeSocketValueFloat *)sock->default_value)->value; break; + case MAT_IN_SPECTRA: + ma->spectra = ((bNodeSocketValueFloat *)sock->default_value)->value; break; + case MAT_IN_RAY_MIRROR: + ma->ray_mirror = ((bNodeSocketValueFloat *)sock->default_value)->value; break; + case MAT_IN_ALPHA: + ma->alpha = ((bNodeSocketValueFloat *)sock->default_value)->value; break; + case MAT_IN_TRANSLUCENCY: + ma->translucency = ((bNodeSocketValueFloat *)sock->default_value)->value; break; + } + } + else { + switch (a) { + case MAT_IN_COLOR: + copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->r); break; + case MAT_IN_SPEC: + copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->specr); break; + case MAT_IN_REFL: + ((bNodeSocketValueFloat *)sock->default_value)->value= ma->ref; break; + case MAT_IN_MIR: + copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->mirr); break; + case MAT_IN_AMB: + ((bNodeSocketValueFloat *)sock->default_value)->value = ma->amb; break; + case MAT_IN_EMIT: + ((bNodeSocketValueFloat *)sock->default_value)->value = ma->emit; break; + case MAT_IN_SPECTRA: + ((bNodeSocketValueFloat *)sock->default_value)->value = ma->spectra; break; + case MAT_IN_RAY_MIRROR: + ((bNodeSocketValueFloat *)sock->default_value)->value = ma->ray_mirror; break; + case MAT_IN_ALPHA: + ((bNodeSocketValueFloat *)sock->default_value)->value = ma->alpha; break; + case MAT_IN_TRANSLUCENCY: + ((bNodeSocketValueFloat *)sock->default_value)->value = ma->translucency; break; + } + } + } + } } - else - return 0; } + +/* ************* node type access ********** */ + const char *nodeLabel(bNode *node) { if (node->label[0] != '\0') @@ -1989,81 +3025,136 @@ const char *nodeLabel(bNode *node) else if (node->typeinfo->labelfunc) return node->typeinfo->labelfunc(node); else - return IFACE_(node->typeinfo->name); + return IFACE_(node->typeinfo->ui_name); } -struct bNodeTree *nodeGroupEditGet(struct bNode *node) +static void node_type_base_defaults(bNodeType *ntype) { - if (node->typeinfo->group_edit_get) - return node->typeinfo->group_edit_get(node); - else - return NULL; + /* default size values */ + node_type_size_preset(ntype, NODE_SIZE_DEFAULT); + ntype->height = 100; + ntype->minheight = 30; + ntype->maxheight = FLT_MAX; } -struct bNodeTree *nodeGroupEditSet(struct bNode *node, int edit) +/* allow this node for any tree type */ +static int node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *UNUSED(ntree)) { - if (node->typeinfo->group_edit_set) - return node->typeinfo->group_edit_set(node, edit); - else if (node->typeinfo->group_edit_get) - return node->typeinfo->group_edit_get(node); - else - return NULL; + return TRUE; } -void nodeGroupEditClear(struct bNode *node) +/* use the basic poll function */ +static int node_poll_instance_default(bNode *node, bNodeTree *ntree) { - if (node->typeinfo->group_edit_clear) - node->typeinfo->group_edit_clear(node); + return node->typeinfo->poll(node->typeinfo, ntree); } -struct bNodeTemplate nodeMakeTemplate(struct bNode *node) +void node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag) { - bNodeTemplate ntemp; - if (node->typeinfo->templatefunc) - return node->typeinfo->templatefunc(node); - else { - ntemp.type = node->type; - return ntemp; + /* Use static type info header to map static int type to identifier string and RNA struct type. + * Associate the RNA struct type with the bNodeType. + * Dynamically registered nodes will create an RNA type at runtime + * and call RNA_struct_blender_type_set, so this only needs to be done for old RNA types + * created in makesrna, which can not be associated to a bNodeType immediately, + * since bNodeTypes are registered afterward ... + */ + #define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \ + case ID: \ + BLI_strncpy(ntype->idname, #Category #StructName, sizeof(ntype->idname)); \ + ntype->ext.srna = RNA_struct_find(#Category #StructName); \ + BLI_assert(ntype->ext.srna != NULL); \ + RNA_struct_blender_type_set(ntype->ext.srna, ntype); \ + break; + + switch (type) { + #include "NOD_static_types.h" } + + /* make sure we have a valid type (everything registered) */ + BLI_assert(ntype->idname[0] != '\0'); + + ntype->type = type; + BLI_strncpy(ntype->ui_name, name, sizeof(ntype->ui_name)); + ntype->nclass = nclass; + ntype->flag = flag; + + node_type_base_defaults(ntype); + + ntype->poll = node_poll_default; + ntype->poll_instance = node_poll_instance_default; } -void node_type_base(bNodeTreeType *ttype, bNodeType *ntype, int type, const char *name, short nclass, short flag) +void node_type_base_custom(bNodeType *ntype, const char *idname, const char *name, short nclass, short flag) { - memset(ntype, 0, sizeof(bNodeType)); - - ntype->type = type; - BLI_strncpy(ntype->name, name, sizeof(ntype->name)); + BLI_strncpy(ntype->idname, idname, sizeof(ntype->idname)); + ntype->type = NODE_CUSTOM; + BLI_strncpy(ntype->ui_name, name, sizeof(ntype->ui_name)); ntype->nclass = nclass; ntype->flag = flag; - /* Default muting stuff. */ - if (ttype) - ntype->update_internal_links = ttype->update_internal_links; + node_type_base_defaults(ntype); +} - /* default size values */ - node_type_size_preset(ntype, NODE_SIZE_DEFAULT); +static bool unique_socket_template_identifier_check(void *arg, const char *name) +{ + bNodeSocketTemplate *ntemp; + struct {bNodeSocketTemplate *list; bNodeSocketTemplate *ntemp;} *data= arg; - ntype->height = 100; - ntype->minheight = 30; - ntype->maxheight = FLT_MAX; + for (ntemp = data->list; ntemp->type >= 0; ++ntemp) { + if (ntemp != data->ntemp) { + if (!strcmp(ntemp->identifier, name)) { + return true; + } + } + } + + return false; +} + +static void unique_socket_template_identifier(bNodeSocketTemplate *list, bNodeSocketTemplate *ntemp, const char defname[], char delim) +{ + struct {bNodeSocketTemplate *list; bNodeSocketTemplate *ntemp;} data; + data.list= list; + data.ntemp = ntemp; + + BLI_uniquename_cb(unique_socket_template_identifier_check, &data, defname, delim, ntemp->identifier, sizeof(ntemp->identifier)); } void node_type_socket_templates(struct bNodeType *ntype, struct bNodeSocketTemplate *inputs, struct bNodeSocketTemplate *outputs) { + bNodeSocketTemplate *ntemp; + ntype->inputs = inputs; ntype->outputs = outputs; + + /* automatically generate unique identifiers */ + if (inputs) { + /* clear identifier strings (uninitialized memory) */ + for (ntemp=inputs; ntemp->type >= 0; ++ntemp) + ntemp->identifier[0] = '\0'; + + for (ntemp=inputs; ntemp->type >= 0; ++ntemp) { + BLI_strncpy(ntemp->identifier, ntemp->name, sizeof(ntemp->identifier)); + unique_socket_template_identifier(inputs, ntemp, ntemp->identifier, '_'); + } + } + if (outputs) { + /* clear identifier strings (uninitialized memory) */ + for (ntemp=outputs; ntemp->type >= 0; ++ntemp) + ntemp->identifier[0] = '\0'; + + for (ntemp=outputs; ntemp->type >= 0; ++ntemp) { + BLI_strncpy(ntemp->identifier, ntemp->name, sizeof(ntemp->identifier)); + unique_socket_template_identifier(outputs, ntemp, ntemp->identifier, '_'); + } + } } -void node_type_init(struct bNodeType *ntype, void (*initfunc)(struct bNodeTree *ntree, struct bNode *node, struct bNodeTemplate *ntemp)) +void node_type_init(struct bNodeType *ntype, void (*initfunc)(struct bNodeTree *ntree, struct bNode *node)) { ntype->initfunc = initfunc; } -void node_type_valid(struct bNodeType *ntype, int (*validfunc)(struct bNodeTree *ntree, struct bNodeTemplate *ntemp)) -{ - ntype->validfunc = validfunc; -} - void node_type_size(struct bNodeType *ntype, int width, int minwidth, int maxwidth) { ntype->width = width; @@ -2089,14 +3180,17 @@ void node_type_size_preset(struct bNodeType *ntype, eNodeSizePreset size) } } -void node_type_storage(bNodeType *ntype, const char *storagename, void (*freestoragefunc)(struct bNode *), void (*copystoragefunc)(struct bNode *, struct bNode *)) +void node_type_storage(bNodeType *ntype, + const char *storagename, + void (*freefunc)(struct bNode *node), + void (*copyfunc)(struct bNodeTree *dest_ntree, struct bNode *dest_node, struct bNode *src_node)) { if (storagename) BLI_strncpy(ntype->storagename, storagename, sizeof(ntype->storagename)); else ntype->storagename[0] = '\0'; - ntype->copystoragefunc = copystoragefunc; - ntype->freestoragefunc = freestoragefunc; + ntype->copyfunc = copyfunc; + ntype->freefunc = freefunc; } void node_type_label(struct bNodeType *ntype, const char *(*labelfunc)(struct bNode *)) @@ -2104,11 +3198,6 @@ void node_type_label(struct bNodeType *ntype, const char *(*labelfunc)(struct bN ntype->labelfunc = labelfunc; } -void node_type_template(struct bNodeType *ntype, struct bNodeTemplate (*templatefunc)(struct bNode *)) -{ - ntype->templatefunc = templatefunc; -} - void node_type_update(struct bNodeType *ntype, void (*updatefunc)(struct bNodeTree *ntree, struct bNode *node), void (*verifyfunc)(struct bNodeTree *ntree, struct bNode *node, struct ID *id)) @@ -2117,50 +3206,21 @@ void node_type_update(struct bNodeType *ntype, ntype->verifyfunc = verifyfunc; } -void node_type_tree(struct bNodeType *ntype, void (*inittreefunc)(struct bNodeTree *), void (*updatetreefunc)(struct bNodeTree *)) -{ - ntype->inittreefunc = inittreefunc; - ntype->updatetreefunc = updatetreefunc; -} - -void node_type_group_edit(struct bNodeType *ntype, - struct bNodeTree *(*group_edit_get)(struct bNode *node), - struct bNodeTree *(*group_edit_set)(struct bNode *node, int edit), - void (*group_edit_clear)(struct bNode *node)) -{ - ntype->group_edit_get = group_edit_get; - ntype->group_edit_set = group_edit_set; - ntype->group_edit_clear = group_edit_clear; -} - -void node_type_exec(struct bNodeType *ntype, void (*execfunc)(void *data, struct bNode *, struct bNodeStack **, struct bNodeStack **)) -{ - ntype->execfunc = execfunc; -} - -void node_type_exec_new(struct bNodeType *ntype, - void *(*initexecfunc)(struct bNode *node), - void (*freeexecfunc)(struct bNode *node, void *nodedata), - void (*newexecfunc)(void *data, int thread, struct bNode *, void *nodedata, struct bNodeStack **, struct bNodeStack **)) +void node_type_exec(struct bNodeType *ntype, NodeInitExecFunction initexecfunc, NodeFreeExecFunction freeexecfunc, NodeExecFunction execfunc) { ntype->initexecfunc = initexecfunc; ntype->freeexecfunc = freeexecfunc; - ntype->newexecfunc = newexecfunc; -} - -void node_type_internal_links(bNodeType *ntype, void (*update_internal_links)(bNodeTree *, bNode *)) -{ - ntype->update_internal_links = update_internal_links; + ntype->execfunc = execfunc; } -void node_type_gpu(struct bNodeType *ntype, int (*gpufunc)(struct GPUMaterial *mat, struct bNode *node, struct GPUNodeStack *in, struct GPUNodeStack *out)) +void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpufunc) { ntype->gpufunc = gpufunc; } -void node_type_gpu_ext(struct bNodeType *ntype, int (*gpuextfunc)(struct GPUMaterial *mat, struct bNode *node, void *nodedata, struct GPUNodeStack *in, struct GPUNodeStack *out)) +void node_type_internal_links(bNodeType *ntype, void (*update_internal_links)(bNodeTree *, bNode *)) { - ntype->gpuextfunc = gpuextfunc; + ntype->update_internal_links = update_internal_links; } void node_type_compatibility(struct bNodeType *ntype, short compatibility) @@ -2168,298 +3228,276 @@ void node_type_compatibility(struct bNodeType *ntype, short compatibility) ntype->compatibility = compatibility; } -static bNodeType *is_nodetype_registered(ListBase *typelist, int type) -{ - bNodeType *ntype = typelist->first; - - for (; ntype; ntype = ntype->next) - if (ntype->type == type) - return ntype; - - return NULL; -} - -void nodeRegisterType(bNodeTreeType *ttype, bNodeType *ntype) -{ - ListBase *typelist = &(ttype->node_types); - bNodeType *found = is_nodetype_registered(typelist, ntype->type); - - if (found == NULL) - BLI_addtail(typelist, ntype); - - /* Associate the RNA struct type with the bNodeType. - * Dynamically registered nodes will create an RNA type at runtime - * and call RNA_struct_blender_type_set, so this only needs to be done for old RNA types - * created in makesrna, which can not be associated to a bNodeType immediately, - * since bNodeTypes are registered afterward ... - */ - #define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \ - if (ID == ntype->type) { \ - StructRNA *srna = RNA_struct_find(STRINGIFY_ARG(Category##StructName)); \ - BLI_assert(srna != NULL); \ - RNA_struct_blender_type_set(srna, ntype); \ - } - - /* XXX hack, this file will be moved to the nodes folder in customnodes branch, - * then this stupid include path is not needed any more. - */ - #include "intern/rna_nodetree_types.h" -} - -static void registerCompositNodes(bNodeTreeType *ttype) -{ - register_node_type_frame(ttype); - register_node_type_reroute(ttype); - - register_node_type_cmp_group(ttype); - - register_node_type_cmp_rlayers(ttype); - register_node_type_cmp_image(ttype); - register_node_type_cmp_texture(ttype); - register_node_type_cmp_value(ttype); - register_node_type_cmp_rgb(ttype); - register_node_type_cmp_curve_time(ttype); - register_node_type_cmp_movieclip(ttype); - - register_node_type_cmp_composite(ttype); - register_node_type_cmp_viewer(ttype); - register_node_type_cmp_splitviewer(ttype); - register_node_type_cmp_output_file(ttype); - register_node_type_cmp_view_levels(ttype); - - register_node_type_cmp_curve_rgb(ttype); - register_node_type_cmp_mix_rgb(ttype); - register_node_type_cmp_hue_sat(ttype); - register_node_type_cmp_brightcontrast(ttype); - register_node_type_cmp_gamma(ttype); - register_node_type_cmp_invert(ttype); - register_node_type_cmp_alphaover(ttype); - register_node_type_cmp_zcombine(ttype); - register_node_type_cmp_colorbalance(ttype); - register_node_type_cmp_huecorrect(ttype); - - register_node_type_cmp_normal(ttype); - register_node_type_cmp_curve_vec(ttype); - register_node_type_cmp_map_value(ttype); - register_node_type_cmp_map_range(ttype); - register_node_type_cmp_normalize(ttype); - - register_node_type_cmp_filter(ttype); - register_node_type_cmp_blur(ttype); - register_node_type_cmp_dblur(ttype); - register_node_type_cmp_bilateralblur(ttype); - register_node_type_cmp_vecblur(ttype); - register_node_type_cmp_dilateerode(ttype); - register_node_type_cmp_inpaint(ttype); - register_node_type_cmp_despeckle(ttype); - register_node_type_cmp_defocus(ttype); - - register_node_type_cmp_valtorgb(ttype); - register_node_type_cmp_rgbtobw(ttype); - register_node_type_cmp_setalpha(ttype); - register_node_type_cmp_idmask(ttype); - register_node_type_cmp_math(ttype); - register_node_type_cmp_seprgba(ttype); - register_node_type_cmp_combrgba(ttype); - register_node_type_cmp_sephsva(ttype); - register_node_type_cmp_combhsva(ttype); - register_node_type_cmp_sepyuva(ttype); - register_node_type_cmp_combyuva(ttype); - register_node_type_cmp_sepycca(ttype); - register_node_type_cmp_combycca(ttype); - register_node_type_cmp_premulkey(ttype); - - register_node_type_cmp_diff_matte(ttype); - register_node_type_cmp_distance_matte(ttype); - register_node_type_cmp_chroma_matte(ttype); - register_node_type_cmp_color_matte(ttype); - register_node_type_cmp_channel_matte(ttype); - register_node_type_cmp_color_spill(ttype); - register_node_type_cmp_luma_matte(ttype); - register_node_type_cmp_doubleedgemask(ttype); - register_node_type_cmp_keyingscreen(ttype); - register_node_type_cmp_keying(ttype); - - register_node_type_cmp_translate(ttype); - register_node_type_cmp_rotate(ttype); - register_node_type_cmp_scale(ttype); - register_node_type_cmp_flip(ttype); - register_node_type_cmp_crop(ttype); - register_node_type_cmp_displace(ttype); - register_node_type_cmp_mapuv(ttype); - register_node_type_cmp_glare(ttype); - register_node_type_cmp_tonemap(ttype); - register_node_type_cmp_lensdist(ttype); - register_node_type_cmp_transform(ttype); - register_node_type_cmp_stabilize2d(ttype); - register_node_type_cmp_moviedistortion(ttype); - - register_node_type_cmp_colorcorrection(ttype); - register_node_type_cmp_boxmask(ttype); - register_node_type_cmp_ellipsemask(ttype); - register_node_type_cmp_bokehimage(ttype); - register_node_type_cmp_bokehblur(ttype); - register_node_type_cmp_switch(ttype); - register_node_type_cmp_pixelate(ttype); - - register_node_type_cmp_mask(ttype); - register_node_type_cmp_trackpos(ttype); -} - -static void registerShaderNodes(bNodeTreeType *ttype) -{ - register_node_type_frame(ttype); - register_node_type_reroute(ttype); - - register_node_type_sh_group(ttype); - - register_node_type_sh_output(ttype); - register_node_type_sh_material(ttype); - register_node_type_sh_camera(ttype); - register_node_type_sh_gamma(ttype); - register_node_type_sh_brightcontrast(ttype); - register_node_type_sh_value(ttype); - register_node_type_sh_rgb(ttype); - register_node_type_sh_mix_rgb(ttype); - register_node_type_sh_valtorgb(ttype); - register_node_type_sh_rgbtobw(ttype); - register_node_type_sh_texture(ttype); - register_node_type_sh_normal(ttype); - register_node_type_sh_geom(ttype); - register_node_type_sh_mapping(ttype); - register_node_type_sh_curve_vec(ttype); - register_node_type_sh_curve_rgb(ttype); - register_node_type_sh_math(ttype); - register_node_type_sh_vect_math(ttype); - register_node_type_sh_squeeze(ttype); - register_node_type_sh_material_ext(ttype); - register_node_type_sh_invert(ttype); - register_node_type_sh_seprgb(ttype); - register_node_type_sh_combrgb(ttype); - register_node_type_sh_hue_sat(ttype); - - register_node_type_sh_attribute(ttype); - register_node_type_sh_geometry(ttype); - register_node_type_sh_light_path(ttype); - register_node_type_sh_light_falloff(ttype); - register_node_type_sh_object_info(ttype); - register_node_type_sh_fresnel(ttype); - register_node_type_sh_layer_weight(ttype); - register_node_type_sh_tex_coord(ttype); - register_node_type_sh_particle_info(ttype); - register_node_type_sh_hair_info(ttype); - register_node_type_sh_bump(ttype); - register_node_type_sh_script(ttype); - register_node_type_sh_tangent(ttype); - register_node_type_sh_normal_map(ttype); - - register_node_type_sh_background(ttype); - register_node_type_sh_bsdf_anisotropic(ttype); - register_node_type_sh_bsdf_diffuse(ttype); - register_node_type_sh_bsdf_glossy(ttype); - register_node_type_sh_bsdf_glass(ttype); - register_node_type_sh_bsdf_refraction(ttype); - register_node_type_sh_bsdf_translucent(ttype); - register_node_type_sh_bsdf_transparent(ttype); - register_node_type_sh_bsdf_velvet(ttype); - register_node_type_sh_emission(ttype); - register_node_type_sh_holdout(ttype); - register_node_type_sh_ambient_occlusion(ttype); - //register_node_type_sh_volume_transparent(ttype); - //register_node_type_sh_volume_isotropic(ttype); - register_node_type_sh_mix_shader(ttype); - register_node_type_sh_add_shader(ttype); - - register_node_type_sh_output_lamp(ttype); - register_node_type_sh_output_material(ttype); - register_node_type_sh_output_world(ttype); - - register_node_type_sh_tex_image(ttype); - register_node_type_sh_tex_environment(ttype); - register_node_type_sh_tex_sky(ttype); - register_node_type_sh_tex_noise(ttype); - register_node_type_sh_tex_wave(ttype); - register_node_type_sh_tex_voronoi(ttype); - register_node_type_sh_tex_musgrave(ttype); - register_node_type_sh_tex_gradient(ttype); - register_node_type_sh_tex_magic(ttype); - register_node_type_sh_tex_checker(ttype); - register_node_type_sh_tex_brick(ttype); -} - -static void registerTextureNodes(bNodeTreeType *ttype) -{ - register_node_type_frame(ttype); - register_node_type_reroute(ttype); - - register_node_type_tex_group(ttype); - - register_node_type_tex_math(ttype); - register_node_type_tex_mix_rgb(ttype); - register_node_type_tex_valtorgb(ttype); - register_node_type_tex_rgbtobw(ttype); - register_node_type_tex_valtonor(ttype); - register_node_type_tex_curve_rgb(ttype); - register_node_type_tex_curve_time(ttype); - register_node_type_tex_invert(ttype); - register_node_type_tex_hue_sat(ttype); - register_node_type_tex_coord(ttype); - register_node_type_tex_distance(ttype); - register_node_type_tex_compose(ttype); - register_node_type_tex_decompose(ttype); - - register_node_type_tex_output(ttype); - register_node_type_tex_viewer(ttype); - - register_node_type_tex_checker(ttype); - register_node_type_tex_texture(ttype); - register_node_type_tex_bricks(ttype); - register_node_type_tex_image(ttype); - - register_node_type_tex_rotate(ttype); - register_node_type_tex_translate(ttype); - register_node_type_tex_scale(ttype); - register_node_type_tex_at(ttype); - - register_node_type_tex_proc_voronoi(ttype); - register_node_type_tex_proc_blend(ttype); - register_node_type_tex_proc_magic(ttype); - register_node_type_tex_proc_marble(ttype); - register_node_type_tex_proc_clouds(ttype); - register_node_type_tex_proc_wood(ttype); - register_node_type_tex_proc_musgrave(ttype); - register_node_type_tex_proc_noise(ttype); - register_node_type_tex_proc_stucci(ttype); - register_node_type_tex_proc_distnoise(ttype); -} - -static void free_typeinfos(ListBase *list) -{ - bNodeType *ntype, *next; - for (ntype = list->first; ntype; ntype = next) { - next = ntype->next; - - if (ntype->needs_free) - MEM_freeN(ntype); - } +static void registerCompositNodes(void) +{ + register_node_type_cmp_group(); + + register_node_type_cmp_rlayers(); + register_node_type_cmp_image(); + register_node_type_cmp_texture(); + register_node_type_cmp_value(); + register_node_type_cmp_rgb(); + register_node_type_cmp_curve_time(); + register_node_type_cmp_movieclip(); + + register_node_type_cmp_composite(); + register_node_type_cmp_viewer(); + register_node_type_cmp_splitviewer(); + register_node_type_cmp_output_file(); + register_node_type_cmp_view_levels(); + + register_node_type_cmp_curve_rgb(); + register_node_type_cmp_mix_rgb(); + register_node_type_cmp_hue_sat(); + register_node_type_cmp_brightcontrast(); + register_node_type_cmp_gamma(); + register_node_type_cmp_invert(); + register_node_type_cmp_alphaover(); + register_node_type_cmp_zcombine(); + register_node_type_cmp_colorbalance(); + register_node_type_cmp_huecorrect(); + + register_node_type_cmp_normal(); + register_node_type_cmp_curve_vec(); + register_node_type_cmp_map_value(); + register_node_type_cmp_map_range(); + register_node_type_cmp_normalize(); + + register_node_type_cmp_filter(); + register_node_type_cmp_blur(); + register_node_type_cmp_dblur(); + register_node_type_cmp_bilateralblur(); + register_node_type_cmp_vecblur(); + register_node_type_cmp_dilateerode(); + register_node_type_cmp_inpaint(); + register_node_type_cmp_despeckle(); + register_node_type_cmp_defocus(); + + register_node_type_cmp_valtorgb(); + register_node_type_cmp_rgbtobw(); + register_node_type_cmp_setalpha(); + register_node_type_cmp_idmask(); + register_node_type_cmp_math(); + register_node_type_cmp_seprgba(); + register_node_type_cmp_combrgba(); + register_node_type_cmp_sephsva(); + register_node_type_cmp_combhsva(); + register_node_type_cmp_sepyuva(); + register_node_type_cmp_combyuva(); + register_node_type_cmp_sepycca(); + register_node_type_cmp_combycca(); + register_node_type_cmp_premulkey(); + + register_node_type_cmp_diff_matte(); + register_node_type_cmp_distance_matte(); + register_node_type_cmp_chroma_matte(); + register_node_type_cmp_color_matte(); + register_node_type_cmp_channel_matte(); + register_node_type_cmp_color_spill(); + register_node_type_cmp_luma_matte(); + register_node_type_cmp_doubleedgemask(); + register_node_type_cmp_keyingscreen(); + register_node_type_cmp_keying(); + + register_node_type_cmp_translate(); + register_node_type_cmp_rotate(); + register_node_type_cmp_scale(); + register_node_type_cmp_flip(); + register_node_type_cmp_crop(); + register_node_type_cmp_displace(); + register_node_type_cmp_mapuv(); + register_node_type_cmp_glare(); + register_node_type_cmp_tonemap(); + register_node_type_cmp_lensdist(); + register_node_type_cmp_transform(); + register_node_type_cmp_stabilize2d(); + register_node_type_cmp_moviedistortion(); + + register_node_type_cmp_colorcorrection(); + register_node_type_cmp_boxmask(); + register_node_type_cmp_ellipsemask(); + register_node_type_cmp_bokehimage(); + register_node_type_cmp_bokehblur(); + register_node_type_cmp_switch(); + register_node_type_cmp_pixelate(); + + register_node_type_cmp_mask(); + register_node_type_cmp_trackpos(); +} + +static void registerShaderNodes(void) +{ + register_node_type_sh_group(); + + register_node_type_sh_output(); + register_node_type_sh_material(); + register_node_type_sh_camera(); + register_node_type_sh_gamma(); + register_node_type_sh_brightcontrast(); + register_node_type_sh_value(); + register_node_type_sh_rgb(); + register_node_type_sh_mix_rgb(); + register_node_type_sh_valtorgb(); + register_node_type_sh_rgbtobw(); + register_node_type_sh_texture(); + register_node_type_sh_normal(); + register_node_type_sh_geom(); + register_node_type_sh_mapping(); + register_node_type_sh_curve_vec(); + register_node_type_sh_curve_rgb(); + register_node_type_sh_math(); + register_node_type_sh_vect_math(); + register_node_type_sh_squeeze(); + register_node_type_sh_material_ext(); + register_node_type_sh_invert(); + register_node_type_sh_seprgb(); + register_node_type_sh_combrgb(); + register_node_type_sh_hue_sat(); + + register_node_type_sh_attribute(); + register_node_type_sh_geometry(); + register_node_type_sh_light_path(); + register_node_type_sh_light_falloff(); + register_node_type_sh_object_info(); + register_node_type_sh_fresnel(); + register_node_type_sh_layer_weight(); + register_node_type_sh_tex_coord(); + register_node_type_sh_particle_info(); + register_node_type_sh_bump(); + + register_node_type_sh_background(); + register_node_type_sh_bsdf_anisotropic(); + register_node_type_sh_bsdf_diffuse(); + register_node_type_sh_bsdf_glossy(); + register_node_type_sh_bsdf_glass(); + register_node_type_sh_bsdf_translucent(); + register_node_type_sh_bsdf_transparent(); + register_node_type_sh_bsdf_velvet(); + register_node_type_sh_emission(); + register_node_type_sh_holdout(); + //register_node_type_sh_volume_transparent(); + //register_node_type_sh_volume_isotropic(); + register_node_type_sh_mix_shader(); + register_node_type_sh_add_shader(); + + register_node_type_sh_output_lamp(); + register_node_type_sh_output_material(); + register_node_type_sh_output_world(); + + register_node_type_sh_tex_image(); + register_node_type_sh_tex_environment(); + register_node_type_sh_tex_sky(); + register_node_type_sh_tex_noise(); + register_node_type_sh_tex_wave(); + register_node_type_sh_tex_voronoi(); + register_node_type_sh_tex_musgrave(); + register_node_type_sh_tex_gradient(); + register_node_type_sh_tex_magic(); + register_node_type_sh_tex_checker(); + register_node_type_sh_tex_brick(); +} + +static void registerTextureNodes(void) +{ + register_node_type_tex_group(); + + + register_node_type_tex_math(); + register_node_type_tex_mix_rgb(); + register_node_type_tex_valtorgb(); + register_node_type_tex_rgbtobw(); + register_node_type_tex_valtonor(); + register_node_type_tex_curve_rgb(); + register_node_type_tex_curve_time(); + register_node_type_tex_invert(); + register_node_type_tex_hue_sat(); + register_node_type_tex_coord(); + register_node_type_tex_distance(); + register_node_type_tex_compose(); + register_node_type_tex_decompose(); + + register_node_type_tex_output(); + register_node_type_tex_viewer(); + register_node_type_sh_script(); + register_node_type_sh_tangent(); + register_node_type_sh_normal_map(); + register_node_type_sh_hair_info(); + + register_node_type_tex_checker(); + register_node_type_tex_texture(); + register_node_type_tex_bricks(); + register_node_type_tex_image(); + register_node_type_sh_bsdf_refraction(); + register_node_type_sh_ambient_occlusion(); + + register_node_type_tex_rotate(); + register_node_type_tex_translate(); + register_node_type_tex_scale(); + register_node_type_tex_at(); + + register_node_type_tex_proc_voronoi(); + register_node_type_tex_proc_blend(); + register_node_type_tex_proc_magic(); + register_node_type_tex_proc_marble(); + register_node_type_tex_proc_clouds(); + register_node_type_tex_proc_wood(); + register_node_type_tex_proc_musgrave(); + register_node_type_tex_proc_noise(); + register_node_type_tex_proc_stucci(); + register_node_type_tex_proc_distnoise(); } void init_nodesystem(void) { - /* init clipboard */ - node_clipboard.nodes.first = node_clipboard.nodes.last = NULL; - node_clipboard.links.first = node_clipboard.links.last = NULL; + nodetreetypes_hash = BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "nodetreetypes_hash gh"); + nodetypes_hash = BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "nodetypes_hash gh"); + nodesockettypes_hash = BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "nodesockettypes_hash gh"); + + register_standard_node_socket_types(); + + register_node_tree_type_cmp(); + register_node_tree_type_sh(); + register_node_tree_type_tex(); + + register_node_type_frame(); + register_node_type_reroute(); + register_node_type_group_input(); + register_node_type_group_output(); - registerCompositNodes(ntreeGetType(NTREE_COMPOSIT)); - registerShaderNodes(ntreeGetType(NTREE_SHADER)); - registerTextureNodes(ntreeGetType(NTREE_TEXTURE)); + registerCompositNodes(); + registerShaderNodes(); + registerTextureNodes(); } void free_nodesystem(void) { - free_typeinfos(&ntreeGetType(NTREE_COMPOSIT)->node_types); - free_typeinfos(&ntreeGetType(NTREE_SHADER)->node_types); - free_typeinfos(&ntreeGetType(NTREE_TEXTURE)->node_types); + NODE_TYPES_BEGIN(nt) + if(nt->ext.free) { + nt->ext.free(nt->ext.data); + } + NODE_TYPES_END + + NODE_SOCKET_TYPES_BEGIN(st) + if(st->ext_socket.free) + st->ext_socket.free(st->ext_socket.data); + if(st->ext_interface.free) + st->ext_interface.free(st->ext_interface.data); + NODE_SOCKET_TYPES_END + + NODE_TREE_TYPES_BEGIN(nt) + if(nt->ext.free) { + nt->ext.free(nt->ext.data); + } + NODE_TREE_TYPES_END + + BLI_ghash_free(nodetypes_hash, NULL, node_free_type); + nodetypes_hash = NULL; + + BLI_ghash_free(nodesockettypes_hash, NULL, node_free_socket_type); + nodesockettypes_hash = NULL; + + BLI_ghash_free(nodetreetypes_hash, NULL, ntree_free_type); + nodetreetypes_hash = NULL; } /* called from BKE_scene_unlink, when deleting a scene goes over all scenes diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index bdf2ce622de..c6d4cf1412d 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -695,7 +695,7 @@ Tex *BKE_texture_copy(Tex *tex) if (tex->nodetree) { if (tex->nodetree->execdata) { - ntreeTexEndExecTree(tex->nodetree->execdata, 1); + ntreeTexEndExecTree(tex->nodetree->execdata); } texn->nodetree = ntreeCopyTree(tex->nodetree); } |