Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/node.c
| Show All 35 Lines | |||||
| #include "DNA_material_types.h" | #include "DNA_material_types.h" | ||||
| #include "DNA_node_types.h" | #include "DNA_node_types.h" | ||||
| #include "DNA_scene_types.h" | #include "DNA_scene_types.h" | ||||
| #include "DNA_texture_types.h" | #include "DNA_texture_types.h" | ||||
| #include "DNA_world_types.h" | #include "DNA_world_types.h" | ||||
| #include "DNA_linestyle_types.h" | #include "DNA_linestyle_types.h" | ||||
| #include "BLI_listbase.h" | #include "BLI_listbase.h" | ||||
| #include "BLI_ghash.h" | |||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BLI_path_util.h" | #include "BLI_path_util.h" | ||||
| #include "BLI_string.h" | #include "BLI_string.h" | ||||
| #include "BLI_string_utils.h" | #include "BLI_string_utils.h" | ||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "BLT_translation.h" | #include "BLT_translation.h" | ||||
| ▲ Show 20 Lines • Show All 951 Lines • ▼ Show 20 Lines | bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type) | ||||
| NODE_TYPES_END; | NODE_TYPES_END; | ||||
| if (!idname) { | if (!idname) { | ||||
| CLOG_ERROR(&LOG, "static node type %d undefined", type); | CLOG_ERROR(&LOG, "static node type %d undefined", type); | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| return nodeAddNode(C, ntree, idname); | return nodeAddNode(C, ntree, idname); | ||||
| } | } | ||||
| static void node_socket_copy(bNodeSocket *sock_dst, bNodeSocket *sock_src, const int flag) | static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src, const int flag) | ||||
| { | { | ||||
| sock_src->new_sock = sock_dst; | |||||
| if (sock_src->prop) { | if (sock_src->prop) { | ||||
| sock_dst->prop = IDP_CopyProperty_ex(sock_src->prop, flag); | sock_dst->prop = IDP_CopyProperty_ex(sock_src->prop, flag); | ||||
| } | } | ||||
| if (sock_src->default_value) { | if (sock_src->default_value) { | ||||
| sock_dst->default_value = MEM_dupallocN(sock_src->default_value); | sock_dst->default_value = MEM_dupallocN(sock_src->default_value); | ||||
| } | } | ||||
| sock_dst->stack_index = 0; | sock_dst->stack_index = 0; | ||||
| /* XXX some compositor node (e.g. image, render layers) still store | /* XXX some compositor node (e.g. image, render layers) still store | ||||
| * some persistent buffer data here, need to clear this to avoid dangling pointers. | * some persistent buffer data here, need to clear this to avoid dangling pointers. | ||||
| */ | */ | ||||
| sock_dst->cache = NULL; | sock_dst->cache = NULL; | ||||
| } | } | ||||
| /* keep socket listorder identical, for copying links */ | /* keep socket listorder identical, for copying links */ | ||||
| /* ntree is the target tree */ | /* ntree is the target tree */ | ||||
| bNode *BKE_node_copy_ex(bNodeTree *ntree, bNode *node_src, const int flag) | bNode *BKE_node_copy_ex(bNodeTree *ntree, const bNode *node_src, const int flag) | ||||
| { | { | ||||
| bNode *node_dst = MEM_callocN(sizeof(bNode), "dupli node"); | bNode *node_dst = MEM_callocN(sizeof(bNode), "dupli node"); | ||||
| bNodeSocket *sock_dst, *sock_src; | bNodeSocket *sock_dst, *sock_src; | ||||
| bNodeLink *link_dst, *link_src; | bNodeLink *link_dst, *link_src; | ||||
| *node_dst = *node_src; | *node_dst = *node_src; | ||||
| /* can be called for nodes outside a node tree (e.g. clipboard) */ | /* can be called for nodes outside a node tree (e.g. clipboard) */ | ||||
| if (ntree) { | if (ntree) { | ||||
| Show All 17 Lines | bNode *BKE_node_copy_ex(bNodeTree *ntree, const bNode *node_src, const int flag) | ||||
| if (node_src->prop) { | if (node_src->prop) { | ||||
| node_dst->prop = IDP_CopyProperty_ex(node_src->prop, flag); | node_dst->prop = IDP_CopyProperty_ex(node_src->prop, flag); | ||||
| } | } | ||||
| BLI_duplicatelist(&node_dst->internal_links, &node_src->internal_links); | BLI_duplicatelist(&node_dst->internal_links, &node_src->internal_links); | ||||
| for (link_dst = node_dst->internal_links.first, link_src = node_src->internal_links.first; | for (link_dst = node_dst->internal_links.first, link_src = node_src->internal_links.first; | ||||
| link_dst != NULL; | link_dst != NULL; | ||||
| link_dst = link_dst->next, link_src = link_src->next) { | link_dst = link_dst->next, link_src = link_src->next) { | ||||
| /* This is a bit annoying to do index lookups in a list, but is likely to be faster than | |||||
| * trying to create a hash-map. At least for usual nodes, which only have so much sockets | |||||
| * and internal links. */ | |||||
| const int from_sock_index = BLI_findindex(&node_src->inputs, link_src->fromsock); | |||||
| const int to_sock_index = BLI_findindex(&node_src->outputs, link_src->tosock); | |||||
| BLI_assert(from_sock_index != -1); | |||||
| BLI_assert(to_sock_index != -1); | |||||
| link_dst->fromnode = node_dst; | link_dst->fromnode = node_dst; | ||||
| link_dst->tonode = node_dst; | link_dst->tonode = node_dst; | ||||
| link_dst->fromsock = link_dst->fromsock->new_sock; | link_dst->fromsock = BLI_findlink(&node_dst->inputs, from_sock_index); | ||||
| link_dst->tosock = link_dst->tosock->new_sock; | link_dst->tosock = BLI_findlink(&node_dst->outputs, to_sock_index); | ||||
| } | } | ||||
| if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { | if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { | ||||
| id_us_plus(node_dst->id); | id_us_plus(node_dst->id); | ||||
| } | } | ||||
| if (node_src->typeinfo->copyfunc) { | if (node_src->typeinfo->copyfunc) { | ||||
| node_src->typeinfo->copyfunc(ntree, node_dst, node_src); | node_src->typeinfo->copyfunc(ntree, node_dst, node_src); | ||||
| } | } | ||||
| node_src->new_node = node_dst; | |||||
| node_dst->new_node = NULL; | node_dst->new_node = NULL; | ||||
| bool do_copy_api = !((flag & LIB_ID_CREATE_NO_MAIN) || (flag & LIB_ID_COPY_LOCALIZE)); | bool do_copy_api = !((flag & LIB_ID_CREATE_NO_MAIN) || (flag & LIB_ID_COPY_LOCALIZE)); | ||||
| if (node_dst->typeinfo->copyfunc_api && do_copy_api) { | if (node_dst->typeinfo->copyfunc_api && do_copy_api) { | ||||
| PointerRNA ptr; | PointerRNA ptr; | ||||
| RNA_pointer_create((ID *)ntree, &RNA_Node, node_dst, &ptr); | RNA_pointer_create((ID *)ntree, &RNA_Node, node_dst, &ptr); | ||||
| node_dst->typeinfo->copyfunc_api(&ptr, node_src); | node_dst->typeinfo->copyfunc_api(&ptr, node_src); | ||||
| } | } | ||||
| if (ntree) { | if (ntree) { | ||||
| ntree->update |= NTREE_UPDATE_NODES; | ntree->update |= NTREE_UPDATE_NODES; | ||||
| } | } | ||||
| return node_dst; | return node_dst; | ||||
| } | } | ||||
| bNode *BKE_node_copy_store_new_pointers(bNodeTree *ntree, bNode *node_src, const int flag) | |||||
| { | |||||
| bNode *new_node = BKE_node_copy_ex(ntree, node_src, flag); | |||||
| /* Store mapping to the node itself. */ | |||||
| node_src->new_node = new_node; | |||||
| /* Store mapping to inputs. */ | |||||
| bNodeSocket *new_input_sock = new_node->inputs.first; | |||||
| bNodeSocket *input_sock_src = node_src->inputs.first; | |||||
| while (new_input_sock != NULL) { | |||||
| input_sock_src->new_sock = new_input_sock; | |||||
| new_input_sock = new_input_sock->next; | |||||
| input_sock_src = input_sock_src->next; | |||||
| } | |||||
| /* Store mapping to outputs. */ | |||||
| bNodeSocket *new_output_sock = new_node->outputs.first; | |||||
| bNodeSocket *output_sock_src = node_src->outputs.first; | |||||
| while (new_output_sock != NULL) { | |||||
| output_sock_src->new_sock = new_output_sock; | |||||
| new_output_sock = new_output_sock->next; | |||||
| output_sock_src = output_sock_src->next; | |||||
| } | |||||
| return new_node; | |||||
| } | |||||
| /* also used via rna api, so we check for proper input output direction */ | /* also used via rna api, so we check for proper input output direction */ | ||||
| bNodeLink *nodeAddLink( | bNodeLink *nodeAddLink( | ||||
| bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock) | bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock) | ||||
| { | { | ||||
| bNodeLink *link = NULL; | bNodeLink *link = NULL; | ||||
| /* test valid input */ | /* test valid input */ | ||||
| BLI_assert(fromnode); | BLI_assert(fromnode); | ||||
| ▲ Show 20 Lines • Show All 291 Lines • ▼ Show 20 Lines | void BKE_node_tree_copy_data(Main *UNUSED(bmain), | ||||
| /* in case a running nodetree is copied */ | /* in case a running nodetree is copied */ | ||||
| ntree_dst->execdata = NULL; | ntree_dst->execdata = NULL; | ||||
| ntree_dst->duplilock = NULL; | ntree_dst->duplilock = NULL; | ||||
| BLI_listbase_clear(&ntree_dst->nodes); | BLI_listbase_clear(&ntree_dst->nodes); | ||||
| BLI_listbase_clear(&ntree_dst->links); | BLI_listbase_clear(&ntree_dst->links); | ||||
| for (bNode *node_src = ntree_src->nodes.first; node_src; node_src = node_src->next) { | /* Since source nodes and sockets are unique pointers we can put everything in a single map. */ | ||||
| BKE_node_copy_ex(ntree_dst, node_src, flag_subdata); | GHash *new_pointers = BLI_ghash_ptr_new("BKE_node_tree_copy_data"); | ||||
| for (const bNode *node_src = ntree_src->nodes.first; node_src; node_src = node_src->next) { | |||||
| bNode *new_node = BKE_node_copy_ex(ntree_dst, node_src, flag_subdata); | |||||
| BLI_ghash_insert(new_pointers, (void *)node_src, new_node); | |||||
| /* Store mapping to inputs. */ | |||||
| bNodeSocket *new_input_sock = new_node->inputs.first; | |||||
| const bNodeSocket *input_sock_src = node_src->inputs.first; | |||||
| while (new_input_sock != NULL) { | |||||
| BLI_ghash_insert(new_pointers, (void *)input_sock_src, new_input_sock); | |||||
| new_input_sock = new_input_sock->next; | |||||
| input_sock_src = input_sock_src->next; | |||||
| } | |||||
| /* Store mapping to outputs. */ | |||||
| bNodeSocket *new_output_sock = new_node->outputs.first; | |||||
| const bNodeSocket *output_sock_src = node_src->outputs.first; | |||||
| while (new_output_sock != NULL) { | |||||
| BLI_ghash_insert(new_pointers, (void *)output_sock_src, new_output_sock); | |||||
| new_output_sock = new_output_sock->next; | |||||
| output_sock_src = output_sock_src->next; | |||||
| } | |||||
| } | } | ||||
| /* copy links */ | /* copy links */ | ||||
| BLI_duplicatelist(&ntree_dst->links, &ntree_src->links); | BLI_duplicatelist(&ntree_dst->links, &ntree_src->links); | ||||
| for (link_dst = ntree_dst->links.first; link_dst; link_dst = link_dst->next) { | for (link_dst = ntree_dst->links.first; link_dst; link_dst = link_dst->next) { | ||||
| link_dst->fromnode = (link_dst->fromnode ? link_dst->fromnode->new_node : NULL); | link_dst->fromnode = BLI_ghash_lookup_default(new_pointers, link_dst->fromnode, NULL); | ||||
| link_dst->fromsock = (link_dst->fromsock ? link_dst->fromsock->new_sock : NULL); | link_dst->fromsock = BLI_ghash_lookup_default(new_pointers, link_dst->fromsock, NULL); | ||||
| link_dst->tonode = (link_dst->tonode ? link_dst->tonode->new_node : NULL); | link_dst->tonode = BLI_ghash_lookup_default(new_pointers, link_dst->tonode, NULL); | ||||
| link_dst->tosock = (link_dst->tosock ? link_dst->tosock->new_sock : NULL); | link_dst->tosock = BLI_ghash_lookup_default(new_pointers, link_dst->tosock, NULL); | ||||
| /* update the link socket's pointer */ | /* update the link socket's pointer */ | ||||
| if (link_dst->tosock) { | if (link_dst->tosock) { | ||||
| link_dst->tosock->link = link_dst; | link_dst->tosock->link = link_dst; | ||||
| } | } | ||||
| } | } | ||||
| BLI_ghash_free(new_pointers, NULL, NULL); | |||||
| /* copy interface sockets */ | /* copy interface sockets */ | ||||
| BLI_duplicatelist(&ntree_dst->inputs, &ntree_src->inputs); | BLI_duplicatelist(&ntree_dst->inputs, &ntree_src->inputs); | ||||
| for (sock_dst = ntree_dst->inputs.first, sock_src = ntree_src->inputs.first; sock_dst != NULL; | for (sock_dst = ntree_dst->inputs.first, sock_src = ntree_src->inputs.first; sock_dst != NULL; | ||||
| sock_dst = sock_dst->next, sock_src = sock_src->next) { | sock_dst = sock_dst->next, sock_src = sock_src->next) { | ||||
| node_socket_copy(sock_dst, sock_src, flag_subdata); | node_socket_copy(sock_dst, sock_src, flag_subdata); | ||||
| } | } | ||||
| BLI_duplicatelist(&ntree_dst->outputs, &ntree_src->outputs); | BLI_duplicatelist(&ntree_dst->outputs, &ntree_src->outputs); | ||||
| ▲ Show 20 Lines • Show All 766 Lines • ▼ Show 20 Lines | for (node = ltree->nodes.first; node; node = node->next) { | ||||
| if ((ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) && node->id) { | if ((ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) && node->id) { | ||||
| node->id = (ID *)ntreeLocalize((bNodeTree *)node->id); | node->id = (ID *)ntreeLocalize((bNodeTree *)node->id); | ||||
| } | } | ||||
| } | } | ||||
| /* ensures only a single output node is enabled */ | /* ensures only a single output node is enabled */ | ||||
| ntreeSetOutput(ntree); | ntreeSetOutput(ntree); | ||||
| for (node = ntree->nodes.first; node; node = node->next) { | bNode *node_src = ntree->nodes.first; | ||||
| /* store new_node pointer to original */ | bNode *node_local = ltree->nodes.first; | ||||
| node->new_node->original = node; | while (node_src != NULL) { | ||||
| node_local->original = node_src; | |||||
| node_src = node_src->next; | |||||
| node_local = node_local->next; | |||||
| } | } | ||||
| if (ntree->typeinfo->localize) { | if (ntree->typeinfo->localize) { | ||||
| ntree->typeinfo->localize(ltree, ntree); | ntree->typeinfo->localize(ltree, ntree); | ||||
| } | } | ||||
| BLI_mutex_unlock(ntree->duplilock); | BLI_mutex_unlock(ntree->duplilock); | ||||
| ▲ Show 20 Lines • Show All 1,375 Lines • ▼ Show 20 Lines | |||||
| * \warning Nodes defining a storage type _must_ allocate this for new nodes. | * \warning Nodes defining a storage type _must_ allocate this for new nodes. | ||||
| * Otherwise nodes will reload as undefined (T46619). | * Otherwise nodes will reload as undefined (T46619). | ||||
| */ | */ | ||||
| void node_type_storage(bNodeType *ntype, | void node_type_storage(bNodeType *ntype, | ||||
| const char *storagename, | const char *storagename, | ||||
| void (*freefunc)(struct bNode *node), | void (*freefunc)(struct bNode *node), | ||||
| void (*copyfunc)(struct bNodeTree *dest_ntree, | void (*copyfunc)(struct bNodeTree *dest_ntree, | ||||
| struct bNode *dest_node, | struct bNode *dest_node, | ||||
| struct bNode *src_node)) | const struct bNode *src_node)) | ||||
| { | { | ||||
| if (storagename) { | if (storagename) { | ||||
| BLI_strncpy(ntype->storagename, storagename, sizeof(ntype->storagename)); | BLI_strncpy(ntype->storagename, storagename, sizeof(ntype->storagename)); | ||||
| } | } | ||||
| else { | else { | ||||
| ntype->storagename[0] = '\0'; | ntype->storagename[0] = '\0'; | ||||
| } | } | ||||
| ntype->copyfunc = copyfunc; | ntype->copyfunc = copyfunc; | ||||
| ▲ Show 20 Lines • Show All 465 Lines • Show Last 20 Lines | |||||