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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Toenne <lukas.toenne@googlemail.com>2013-03-18 20:34:57 +0400
committerLukas Toenne <lukas.toenne@googlemail.com>2013-03-18 20:34:57 +0400
commit4638e5f99a9ba59ad0b8a1fd52b12e876480b9e8 (patch)
tree2444f12b4612440f44cf02835cdf5951b6564e92 /source/blender/blenkernel/intern/node.c
parent7bfef29f2f2a1b262d28abdc6e30fcd9c1f1caad (diff)
Merge of the PyNodes branch (aka "custom nodes") into trunk.
PyNodes opens up the node system in Blender to scripters and adds a number of UI-level improvements. === Dynamic node type registration === Node types can now be added at runtime, using the RNA registration mechanism from python. This enables addons such as render engines to create a complete user interface with nodes. Examples of how such nodes can be defined can be found in my personal wiki docs atm [1] and as a script template in release/scripts/templates_py/custom_nodes.py [2]. === Node group improvements === Each node editor now has a tree history of edited node groups, which allows opening and editing nested node groups. The node editor also supports pinning now, so that different spaces can be used to edit different node groups simultaneously. For more ramblings and rationale see (really old) blog post on code.blender.org [3]. The interface of node groups has been overhauled. Sockets of a node group are no longer displayed in columns on either side, but instead special input/output nodes are used to mirror group sockets inside a node tree. This solves the problem of long node lines in groups and allows more adaptable node layout. Internal sockets can be exposed from a group by either connecting to the extension sockets in input/output nodes (shown as empty circle) or by adding sockets from the node property bar in the "Interface" panel. Further details such as the socket name can also be changed there. [1] http://wiki.blender.org/index.php/User:Phonybone/Python_Nodes [2] http://projects.blender.org/scm/viewvc.php/trunk/blender/release/scripts/templates_py/custom_nodes.py?view=markup&root=bf-blender [3] http://code.blender.org/index.php/2012/01/improving-node-group-interface-editing/
Diffstat (limited to 'source/blender/blenkernel/intern/node.c')
-rw-r--r--source/blender/blenkernel/intern/node.c2902
1 files changed, 1970 insertions, 932 deletions
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(&ltree->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(&ltree->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