/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2007 Blender Foundation. * All rights reserved. */ /** \file * \ingroup nodes */ #include #include "DNA_node_types.h" #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_string.h" #include "BLI_utildefines.h" #include "BKE_node.h" #include "RNA_access.h" #include "RNA_types.h" #include "MEM_guardedalloc.h" #include "NOD_socket.h" struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocketTemplate *stemp, int in_out) { bNodeSocket *sock = nodeAddStaticSocket( ntree, node, in_out, stemp->type, stemp->subtype, stemp->identifier, stemp->name); sock->flag |= stemp->flag; /* initialize default_value */ switch (stemp->type) { case SOCK_FLOAT: { bNodeSocketValueFloat *dval = sock->default_value; dval->value = stemp->val1; dval->min = stemp->min; dval->max = stemp->max; break; } case SOCK_INT: { bNodeSocketValueInt *dval = sock->default_value; dval->value = (int)stemp->val1; dval->min = (int)stemp->min; dval->max = (int)stemp->max; break; } case SOCK_BOOLEAN: { bNodeSocketValueBoolean *dval = sock->default_value; dval->value = (int)stemp->val1; break; } case SOCK_VECTOR: { bNodeSocketValueVector *dval = sock->default_value; dval->value[0] = stemp->val1; dval->value[1] = stemp->val2; dval->value[2] = stemp->val3; dval->min = stemp->min; dval->max = stemp->max; break; } case SOCK_RGBA: { bNodeSocketValueRGBA *dval = sock->default_value; dval->value[0] = stemp->val1; dval->value[1] = stemp->val2; dval->value[2] = stemp->val3; dval->value[3] = stemp->val4; break; } } return sock; } static bNodeSocket *verify_socket_template( bNodeTree *ntree, bNode *node, int in_out, ListBase *socklist, bNodeSocketTemplate *stemp) { bNodeSocket *sock; for (sock = socklist->first; sock; sock = sock->next) { if (STREQLEN(sock->name, stemp->name, NODE_MAXSTR)) { break; } } if (sock) { if (sock->type != stemp->type) { nodeModifySocketType(ntree, node, sock, stemp->type, stemp->subtype); } sock->flag |= stemp->flag; } else { /* no socket for this template found, make a new one */ sock = node_add_socket_from_template(ntree, node, stemp, in_out); } /* remove the new socket from the node socket list first, * will be added back after verification. */ BLI_remlink(socklist, sock); return sock; } static void verify_socket_template_list(bNodeTree *ntree, bNode *node, int in_out, ListBase *socklist, bNodeSocketTemplate *stemp_first) { bNodeSocket *sock, *nextsock; bNodeSocketTemplate *stemp; /* no inputs anymore? */ if (stemp_first == NULL) { for (sock = (bNodeSocket *)socklist->first; sock; sock = nextsock) { nextsock = sock->next; nodeRemoveSocket(ntree, node, sock); } } else { /* step by step compare */ stemp = stemp_first; while (stemp->type != -1) { stemp->sock = verify_socket_template(ntree, node, in_out, socklist, stemp); stemp++; } /* leftovers are removed */ for (sock = (bNodeSocket *)socklist->first; sock; sock = nextsock) { nextsock = sock->next; nodeRemoveSocket(ntree, node, sock); } /* and we put back the verified sockets */ stemp = stemp_first; if (socklist->first) { /* some dynamic sockets left, store the list start * so we can add static sockets infront of it. */ sock = socklist->first; while (stemp->type != -1) { /* put static sockets infront of dynamic */ BLI_insertlinkbefore(socklist, sock, stemp->sock); stemp++; } } else { while (stemp->type != -1) { BLI_addtail(socklist, stemp->sock); stemp++; } } } } void node_verify_socket_templates(bNodeTree *ntree, bNode *node) { bNodeType *ntype = node->typeinfo; /* Don't try to match socket lists when there are no templates. * This prevents dynamically generated sockets to be removed, like for * group, image or render layer nodes. We have an explicit check for the * render layer node since it still has fixed sockets too. */ if (ntype) { if (ntype->inputs && ntype->inputs[0].type >= 0) { verify_socket_template_list(ntree, node, SOCK_IN, &node->inputs, ntype->inputs); } if (ntype->outputs && ntype->outputs[0].type >= 0 && node->type != CMP_NODE_R_LAYERS) { verify_socket_template_list(ntree, node, SOCK_OUT, &node->outputs, ntype->outputs); } } } void node_socket_init_default_value(bNodeSocket *sock) { int type = sock->typeinfo->type; int subtype = sock->typeinfo->subtype; if (sock->default_value) { return; /* already initialized */ } switch (type) { case SOCK_FLOAT: { bNodeSocketValueFloat *dval = MEM_callocN(sizeof(bNodeSocketValueFloat), "node socket value float"); dval->subtype = subtype; dval->value = 0.0f; dval->min = -FLT_MAX; dval->max = FLT_MAX; sock->default_value = dval; break; } case SOCK_INT: { bNodeSocketValueInt *dval = MEM_callocN(sizeof(bNodeSocketValueInt), "node socket value int"); dval->subtype = subtype; dval->value = 0; dval->min = INT_MIN; dval->max = INT_MAX; sock->default_value = dval; break; } case SOCK_BOOLEAN: { bNodeSocketValueBoolean *dval = MEM_callocN(sizeof(bNodeSocketValueBoolean), "node socket value bool"); dval->value = false; sock->default_value = dval; break; } case SOCK_VECTOR: { static float default_value[] = {0.0f, 0.0f, 0.0f}; bNodeSocketValueVector *dval = MEM_callocN(sizeof(bNodeSocketValueVector), "node socket value vector"); dval->subtype = subtype; copy_v3_v3(dval->value, default_value); dval->min = -FLT_MAX; dval->max = FLT_MAX; sock->default_value = dval; break; } case SOCK_RGBA: { static float default_value[] = {0.0f, 0.0f, 0.0f, 1.0f}; bNodeSocketValueRGBA *dval = MEM_callocN(sizeof(bNodeSocketValueRGBA), "node socket value color"); copy_v4_v4(dval->value, default_value); sock->default_value = dval; break; } case SOCK_STRING: { bNodeSocketValueString *dval = MEM_callocN(sizeof(bNodeSocketValueString), "node socket value string"); dval->subtype = subtype; dval->value[0] = '\0'; sock->default_value = dval; break; } } } void node_socket_copy_default_value(bNodeSocket *to, const bNodeSocket *from) { /* sanity check */ if (to->type != from->type) { return; } /* make sure both exist */ if (!from->default_value) { return; } node_socket_init_default_value(to); /* use label instead of name if it has been set */ if (from->label[0] != '\0') { BLI_strncpy(to->name, from->label, NODE_MAXSTR); } switch (from->typeinfo->type) { case SOCK_FLOAT: { bNodeSocketValueFloat *toval = to->default_value; bNodeSocketValueFloat *fromval = from->default_value; *toval = *fromval; break; } case SOCK_INT: { bNodeSocketValueInt *toval = to->default_value; bNodeSocketValueInt *fromval = from->default_value; *toval = *fromval; break; } case SOCK_BOOLEAN: { bNodeSocketValueBoolean *toval = to->default_value; bNodeSocketValueBoolean *fromval = from->default_value; *toval = *fromval; break; } case SOCK_VECTOR: { bNodeSocketValueVector *toval = to->default_value; bNodeSocketValueVector *fromval = from->default_value; *toval = *fromval; break; } case SOCK_RGBA: { bNodeSocketValueRGBA *toval = to->default_value; bNodeSocketValueRGBA *fromval = from->default_value; *toval = *fromval; break; } case SOCK_STRING: { bNodeSocketValueString *toval = to->default_value; bNodeSocketValueString *fromval = from->default_value; *toval = *fromval; break; } } to->flag |= (from->flag & SOCK_HIDE_VALUE); } static void standard_node_socket_interface_init_socket(bNodeTree *UNUSED(ntree), bNodeSocket *stemp, bNode *UNUSED(node), bNodeSocket *sock, const char *UNUSED(data_path)) { /* initialize the type value */ sock->type = sock->typeinfo->type; /* XXX socket interface 'type' value is not used really, * but has to match or the copy function will bail out */ stemp->type = stemp->typeinfo->type; /* copy default_value settings */ node_socket_copy_default_value(sock, stemp); } /* copies settings that are not changed for each socket instance */ static void standard_node_socket_interface_verify_socket(bNodeTree *UNUSED(ntree), bNodeSocket *stemp, bNode *UNUSED(node), bNodeSocket *sock, const char *UNUSED(data_path)) { /* sanity check */ if (sock->type != stemp->typeinfo->type) { return; } /* make sure both exist */ if (!stemp->default_value) { return; } node_socket_init_default_value(sock); switch (stemp->typeinfo->type) { case SOCK_FLOAT: { bNodeSocketValueFloat *toval = sock->default_value; bNodeSocketValueFloat *fromval = stemp->default_value; toval->min = fromval->min; toval->max = fromval->max; break; } case SOCK_INT: { bNodeSocketValueInt *toval = sock->default_value; bNodeSocketValueInt *fromval = stemp->default_value; toval->min = fromval->min; toval->max = fromval->max; break; } case SOCK_VECTOR: { bNodeSocketValueVector *toval = sock->default_value; bNodeSocketValueVector *fromval = stemp->default_value; toval->min = fromval->min; toval->max = fromval->max; break; } } } static void standard_node_socket_interface_from_socket(bNodeTree *UNUSED(ntree), bNodeSocket *stemp, bNode *UNUSED(node), bNodeSocket *sock) { /* initialize settings */ stemp->type = stemp->typeinfo->type; node_socket_copy_default_value(stemp, sock); } static bNodeSocketType *make_standard_socket_type(int type, int subtype) { extern void ED_init_standard_node_socket_type(bNodeSocketType *); const char *socket_idname = nodeStaticSocketType(type, subtype); const char *interface_idname = nodeStaticSocketInterfaceType(type, subtype); bNodeSocketType *stype; StructRNA *srna; stype = MEM_callocN(sizeof(bNodeSocketType), "node socket C type"); stype->free_self = (void (*)(bNodeSocketType * stype)) MEM_freeN; BLI_strncpy(stype->idname, socket_idname, sizeof(stype->idname)); /* set the RNA type * uses the exact same identifier as the socket type idname */ srna = stype->ext_socket.srna = RNA_struct_find(socket_idname); BLI_assert(srna != NULL); /* associate the RNA type with the socket type */ RNA_struct_blender_type_set(srna, stype); /* set the interface RNA type */ srna = stype->ext_interface.srna = RNA_struct_find(interface_idname); BLI_assert(srna != NULL); /* associate the RNA type with the socket type */ RNA_struct_blender_type_set(srna, stype); /* extra type info for standard socket types */ stype->type = type; stype->subtype = subtype; /* XXX bad-level call! needed for setting draw callbacks */ ED_init_standard_node_socket_type(stype); stype->interface_init_socket = standard_node_socket_interface_init_socket; stype->interface_from_socket = standard_node_socket_interface_from_socket; stype->interface_verify_socket = standard_node_socket_interface_verify_socket; stype->use_link_limits_of_type = true; stype->input_link_limit = 1; stype->output_link_limit = 0xFFF; return stype; } static bNodeSocketType *make_socket_type_virtual(void) { extern void ED_init_node_socket_type_virtual(bNodeSocketType *); const char *socket_idname = "NodeSocketVirtual"; bNodeSocketType *stype; StructRNA *srna; stype = MEM_callocN(sizeof(bNodeSocketType), "node socket C type"); stype->free_self = (void (*)(bNodeSocketType * stype)) MEM_freeN; BLI_strncpy(stype->idname, socket_idname, sizeof(stype->idname)); /* set the RNA type * uses the exact same identifier as the socket type idname */ srna = stype->ext_socket.srna = RNA_struct_find(socket_idname); BLI_assert(srna != NULL); /* associate the RNA type with the socket type */ RNA_struct_blender_type_set(srna, stype); /* extra type info for standard socket types */ stype->type = SOCK_CUSTOM; ED_init_node_socket_type_virtual(stype); stype->use_link_limits_of_type = true; stype->input_link_limit = 1; stype->output_link_limit = 1; return stype; } void register_standard_node_socket_types(void) { /* draw callbacks are set in drawnode.c to avoid bad-level calls */ nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_NONE)); nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_UNSIGNED)); nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_PERCENTAGE)); nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_FACTOR)); nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_ANGLE)); nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_TIME)); nodeRegisterSocketType(make_standard_socket_type(SOCK_INT, PROP_NONE)); nodeRegisterSocketType(make_standard_socket_type(SOCK_INT, PROP_UNSIGNED)); nodeRegisterSocketType(make_standard_socket_type(SOCK_INT, PROP_PERCENTAGE)); nodeRegisterSocketType(make_standard_socket_type(SOCK_INT, PROP_FACTOR)); nodeRegisterSocketType(make_standard_socket_type(SOCK_BOOLEAN, PROP_NONE)); nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_NONE)); nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_TRANSLATION)); nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_DIRECTION)); nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_VELOCITY)); nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_ACCELERATION)); nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_EULER)); nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_XYZ)); nodeRegisterSocketType(make_standard_socket_type(SOCK_RGBA, PROP_NONE)); nodeRegisterSocketType(make_standard_socket_type(SOCK_STRING, PROP_NONE)); nodeRegisterSocketType(make_standard_socket_type(SOCK_SHADER, PROP_NONE)); nodeRegisterSocketType(make_socket_type_virtual()); }