Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/node.c
| Show First 20 Lines • Show All 896 Lines • ▼ Show 20 Lines | bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type) | ||||
| NODE_TYPES_END | NODE_TYPES_END | ||||
| if (!idname) { | if (!idname) { | ||||
| printf("Error: static node type %d undefined\n", type); | printf("Error: static node type %d undefined\n", type); | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| return nodeAddNode(C, ntree, idname); | return nodeAddNode(C, ntree, idname); | ||||
| } | } | ||||
| static void node_socket_copy(bNodeSocket *dst, bNodeSocket *src) | static void node_socket_copy(bNodeSocket *sock_dst, bNodeSocket *sock_src, const int flag) | ||||
| { | { | ||||
| src->new_sock = dst; | sock_src->new_sock = sock_dst; | ||||
| if (src->prop) | if (sock_src->prop) { | ||||
| dst->prop = IDP_CopyProperty(src->prop); | sock_dst->prop = IDP_CopyProperty_ex(sock_src->prop, flag); | ||||
| } | |||||
| if (src->default_value) | if (sock_src->default_value) { | ||||
| dst->default_value = MEM_dupallocN(src->default_value); | sock_dst->default_value = MEM_dupallocN(sock_src->default_value); | ||||
| } | |||||
| 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. | ||||
| */ | */ | ||||
| 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 *nodeCopyNode(bNodeTree *ntree, bNode *node) | bNode *BKE_node_copy_ex(bNodeTree *ntree, bNode *node_src, const int flag) | ||||
| { | { | ||||
| bNode *nnode = MEM_callocN(sizeof(bNode), "dupli node"); | bNode *node_dst = MEM_callocN(sizeof(bNode), "dupli node"); | ||||
| bNodeSocket *sock, *oldsock; | bNodeSocket *sock_dst, *sock_src; | ||||
| bNodeLink *link, *oldlink; | bNodeLink *link_dst, *link_src; | ||||
| *nnode = *node; | *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) { | ||||
| nodeUniqueName(ntree, nnode); | nodeUniqueName(ntree, node_dst); | ||||
| BLI_addtail(&ntree->nodes, nnode); | BLI_addtail(&ntree->nodes, node_dst); | ||||
| } | } | ||||
| BLI_duplicatelist(&nnode->inputs, &node->inputs); | BLI_duplicatelist(&node_dst->inputs, &node_src->inputs); | ||||
| oldsock = node->inputs.first; | for (sock_dst = node_dst->inputs.first, sock_src = node_src->inputs.first; | ||||
| for (sock = nnode->inputs.first; sock; sock = sock->next, oldsock = oldsock->next) | sock_dst != NULL; | ||||
| node_socket_copy(sock, oldsock); | sock_dst = sock_dst->next, sock_src = sock_src->next) | ||||
| { | |||||
| node_socket_copy(sock_dst, sock_src, flag); | |||||
| } | |||||
| BLI_duplicatelist(&nnode->outputs, &node->outputs); | BLI_duplicatelist(&node_dst->outputs, &node_src->outputs); | ||||
| oldsock = node->outputs.first; | for (sock_dst = node_dst->outputs.first, sock_src = node_src->outputs.first; | ||||
| for (sock = nnode->outputs.first; sock; sock = sock->next, oldsock = oldsock->next) | sock_dst != NULL; | ||||
| node_socket_copy(sock, oldsock); | sock_dst = sock_dst->next, sock_src = sock_src->next) | ||||
| { | |||||
| node_socket_copy(sock_dst, sock_src, flag); | |||||
| } | |||||
| if (node->prop) | if (node_src->prop) { | ||||
| nnode->prop = IDP_CopyProperty(node->prop); | node_dst->prop = IDP_CopyProperty_ex(node_src->prop, flag); | ||||
| } | |||||
| BLI_duplicatelist(&nnode->internal_links, &node->internal_links); | BLI_duplicatelist(&node_dst->internal_links, &node_src->internal_links); | ||||
| oldlink = node->internal_links.first; | for (link_dst = node_dst->internal_links.first, link_src = node_src->internal_links.first; | ||||
| for (link = nnode->internal_links.first; link; link = link->next, oldlink = oldlink->next) { | link_dst != NULL; | ||||
| link->fromnode = nnode; | link_dst = link_dst->next, link_src = link_src->next) | ||||
| link->tonode = nnode; | { | ||||
| link->fromsock = link->fromsock->new_sock; | link_dst->fromnode = node_dst; | ||||
| link->tosock = link->tosock->new_sock; | link_dst->tonode = node_dst; | ||||
| link_dst->fromsock = link_dst->fromsock->new_sock; | |||||
| link_dst->tosock = link_dst->tosock->new_sock; | |||||
| } | } | ||||
| /* don't increase node->id users, freenode doesn't decrement either */ | if ((flag & LIB_ID_COPY_NO_USER_REFCOUNT) == 0) { | ||||
| id_us_plus(node_dst->id); | |||||
| } | |||||
| if (node->typeinfo->copyfunc) | if (node_src->typeinfo->copyfunc) { | ||||
| node->typeinfo->copyfunc(ntree, nnode, node); | node_src->typeinfo->copyfunc(ntree, node_dst, node_src); | ||||
| } | |||||
| node->new_node = nnode; | node_src->new_node = node_dst; | ||||
| nnode->new_node = NULL; | node_dst->new_node = NULL; | ||||
| if (nnode->typeinfo->copyfunc_api) { | if (node_dst->typeinfo->copyfunc_api) { | ||||
| PointerRNA ptr; | PointerRNA ptr; | ||||
| RNA_pointer_create((ID *)ntree, &RNA_Node, nnode, &ptr); | RNA_pointer_create((ID *)ntree, &RNA_Node, node_dst, &ptr); | ||||
| nnode->typeinfo->copyfunc_api(&ptr, node); | node_dst->typeinfo->copyfunc_api(&ptr, node_src); | ||||
| } | } | ||||
| if (ntree) | if (ntree) { | ||||
| ntree->update |= NTREE_UPDATE_NODES; | ntree->update |= NTREE_UPDATE_NODES; | ||||
| } | |||||
| return nnode; | return node_dst; | ||||
| } | |||||
| bNode *nodeCopyNode(bNodeTree *ntree, bNode *node) | |||||
| { | |||||
| return BKE_node_copy_ex(ntree, node, LIB_ID_COPY_NO_USER_REFCOUNT); | |||||
| } | } | ||||
| /* 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(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock) | bNodeLink *nodeAddLink(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock) | ||||
| { | { | ||||
| bNodeLink *link = NULL; | bNodeLink *link = NULL; | ||||
| /* test valid input */ | /* test valid input */ | ||||
| ▲ Show 20 Lines • Show All 199 Lines • ▼ Show 20 Lines | bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname) | ||||
| ntree->init |= NTREE_TYPE_INIT; | ntree->init |= NTREE_TYPE_INIT; | ||||
| BLI_strncpy(ntree->idname, idname, sizeof(ntree->idname)); | BLI_strncpy(ntree->idname, idname, sizeof(ntree->idname)); | ||||
| ntree_set_typeinfo(ntree, ntreeTypeFind(idname)); | ntree_set_typeinfo(ntree, ntreeTypeFind(idname)); | ||||
| return ntree; | return ntree; | ||||
| } | } | ||||
| /* Warning: this function gets called during some rather unexpected times | /** | ||||
| * - this gets called when executing compositing updates (for threaded previews) | * Only copy internal data of NodeTree ID from source to already allocated/initialized destination. | ||||
| * - when the nodetree datablock needs to be copied (i.e. when users get copied) | * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. | ||||
| * - for scene duplication use ntreeSwapID() after so we don't have stale pointers. | |||||
| * | * | ||||
| * do_make_extern: keep enabled for general use, only reason _not_ to enable is when | * WARNING! This function will not handle ID user count! | ||||
| * copying for internal use (threads for eg), where you wont want it to modify the | * | ||||
| * scene data. | * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). | ||||
| */ | */ | ||||
| static bNodeTree *ntreeCopyTree_internal( | void BKE_node_tree_copy_data(Main *UNUSED(bmain), bNodeTree *ntree_dst, const bNodeTree *ntree_src, const int flag) | ||||
| const bNodeTree *ntree, Main *bmain, | { | ||||
| bool skip_database, bool do_id_user, bool do_make_extern, bool copy_previews) | bNode *node_src; | ||||
| { | bNodeSocket *sock_dst, *sock_src; | ||||
| bNodeTree *newtree; | bNodeLink *link_dst; | ||||
| bNode *node /*, *nnode */ /* UNUSED */, *last; | |||||
| bNodeSocket *sock, *oldsock; | |||||
| bNodeLink *link; | |||||
| if (ntree == NULL) return NULL; | /* We never handle usercount here for own data. */ | ||||
| const int flag_subdata = flag | LIB_ID_COPY_NO_USER_REFCOUNT; | |||||
| /* is ntree part of library? */ | if ((flag & LIB_ID_COPY_NO_USER_REFCOUNT) == 0) { | ||||
| if (bmain && !skip_database && BLI_findindex(&bmain->nodetree, ntree) >= 0) { | id_us_plus((ID *)ntree_dst->gpd); | ||||
| newtree = BKE_libblock_copy(bmain, &ntree->id); | |||||
| } | |||||
| else { | |||||
| newtree = BKE_libblock_copy_nolib(&ntree->id, true); | |||||
| } | } | ||||
| id_us_plus((ID *)newtree->gpd); | |||||
| /* in case a running nodetree is copied */ | /* in case a running nodetree is copied */ | ||||
| newtree->execdata = NULL; | ntree_dst->execdata = NULL; | ||||
| newtree->duplilock = NULL; | |||||
| BLI_listbase_clear(&newtree->nodes); | ntree_dst->duplilock = NULL; | ||||
| BLI_listbase_clear(&newtree->links); | |||||
| last = ntree->nodes.last; | BLI_listbase_clear(&ntree_dst->nodes); | ||||
| for (node = ntree->nodes.first; node; node = node->next) { | BLI_listbase_clear(&ntree_dst->links); | ||||
| /* ntreeUserDecrefID inline */ | for (node_src = ntree_src->nodes.first; node_src; node_src = node_src->next) { | ||||
| if (do_id_user) { | BKE_node_copy_ex(ntree_dst, node_src, flag_subdata); | ||||
| id_us_plus(node->id); | |||||
| } | |||||
| if (do_make_extern) { | |||||
| id_lib_extern(node->id); | |||||
| } | |||||
| node->new_node = NULL; | |||||
| /* nnode = */ nodeCopyNode(newtree, node); /* sets node->new */ | |||||
| /* make sure we don't copy new nodes again! */ | |||||
| if (node == last) | |||||
| break; | |||||
| } | } | ||||
| /* copy links */ | /* copy links */ | ||||
| BLI_duplicatelist(&newtree->links, &ntree->links); | BLI_duplicatelist(&ntree_dst->links, &ntree_src->links); | ||||
| for (link = newtree->links.first; link; link = link->next) { | for (link_dst = ntree_dst->links.first; link_dst; link_dst = link_dst->next) { | ||||
| link->fromnode = (link->fromnode ? link->fromnode->new_node : NULL); | link_dst->fromnode = (link_dst->fromnode ? link_dst->fromnode->new_node : NULL); | ||||
| link->fromsock = (link->fromsock ? link->fromsock->new_sock : NULL); | link_dst->fromsock = (link_dst->fromsock ? link_dst->fromsock->new_sock : NULL); | ||||
| link->tonode = (link->tonode ? link->tonode->new_node : NULL); | link_dst->tonode = (link_dst->tonode ? link_dst->tonode->new_node : NULL); | ||||
| link->tosock = (link->tosock ? link->tosock->new_sock : NULL); | link_dst->tosock = (link_dst->tosock ? link_dst->tosock->new_sock : NULL); | ||||
| /* update the link socket's pointer */ | /* update the link socket's pointer */ | ||||
| if (link->tosock) | if (link_dst->tosock) { | ||||
| link->tosock->link = link; | link_dst->tosock->link = link_dst; | ||||
| } | |||||
| } | } | ||||
| /* copy interface sockets */ | /* copy interface sockets */ | ||||
| BLI_duplicatelist(&newtree->inputs, &ntree->inputs); | BLI_duplicatelist(&ntree_dst->inputs, &ntree_src->inputs); | ||||
| oldsock = ntree->inputs.first; | for (sock_dst = ntree_dst->inputs.first, sock_src = ntree_src->inputs.first; | ||||
| for (sock = newtree->inputs.first; sock; sock = sock->next, oldsock = oldsock->next) | sock_dst != NULL; | ||||
| node_socket_copy(sock, oldsock); | sock_dst = sock_dst->next, sock_src = sock_src->next) | ||||
| { | |||||
| BLI_duplicatelist(&newtree->outputs, &ntree->outputs); | node_socket_copy(sock_dst, sock_src, flag_subdata); | ||||
| oldsock = ntree->outputs.first; | } | ||||
| for (sock = newtree->outputs.first; sock; sock = sock->next, oldsock = oldsock->next) | |||||
| node_socket_copy(sock, oldsock); | BLI_duplicatelist(&ntree_dst->outputs, &ntree_src->outputs); | ||||
| for (sock_dst = ntree_dst->outputs.first, sock_src = ntree_src->outputs.first; | |||||
| sock_dst != NULL; | |||||
| sock_dst = sock_dst->next, sock_src = sock_src->next) | |||||
| { | |||||
| node_socket_copy(sock_dst, sock_src, flag_subdata); | |||||
| } | |||||
| /* copy preview hash */ | /* copy preview hash */ | ||||
| if (ntree->previews && copy_previews) { | if (ntree_src->previews && (flag & LIB_ID_COPY_NO_PREVIEW) == 0) { | ||||
| bNodeInstanceHashIterator iter; | bNodeInstanceHashIterator iter; | ||||
| newtree->previews = BKE_node_instance_hash_new("node previews"); | ntree_dst->previews = BKE_node_instance_hash_new("node previews"); | ||||
| NODE_INSTANCE_HASH_ITER(iter, ntree->previews) { | NODE_INSTANCE_HASH_ITER(iter, ntree_src->previews) { | ||||
| bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter); | bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter); | ||||
| bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter); | bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter); | ||||
| BKE_node_instance_hash_insert(newtree->previews, key, BKE_node_preview_copy(preview)); | BKE_node_instance_hash_insert(ntree_dst->previews, key, BKE_node_preview_copy(preview)); | ||||
| } | } | ||||
| } | } | ||||
| else | else { | ||||
| newtree->previews = NULL; | ntree_dst->previews = NULL; | ||||
| } | |||||
| /* update node->parent pointers */ | /* update node->parent pointers */ | ||||
| for (node = newtree->nodes.first; node; node = node->next) { | for (node_src = ntree_dst->nodes.first; node_src; node_src = node_src->next) { | ||||
| if (node->parent) | if (node_src->parent) { | ||||
| node->parent = node->parent->new_node; | node_src->parent = node_src->parent->new_node; | ||||
| } | |||||
| } | } | ||||
| /* node tree will generate its own interface type */ | /* node tree will generate its own interface type */ | ||||
| newtree->interface_type = NULL; | ntree_dst->interface_type = NULL; | ||||
| BKE_id_copy_ensure_local(bmain, &ntree->id, &newtree->id); | |||||
| return newtree; | |||||
| } | } | ||||
| bNodeTree *ntreeCopyTree_ex(const bNodeTree *ntree, Main *bmain, const bool do_id_user) | bNodeTree *ntreeCopyTree_ex(const bNodeTree *ntree, Main *bmain, const bool do_id_user) | ||||
| { | { | ||||
| return ntreeCopyTree_internal(ntree, bmain, false, do_id_user, true, true); | bNodeTree *ntree_copy; | ||||
| BKE_id_copy_ex(bmain, (ID *)ntree, (ID **)&ntree_copy, do_id_user ? 0 : LIB_ID_COPY_NO_USER_REFCOUNT, false); | |||||
| return ntree_copy; | |||||
| } | } | ||||
| bNodeTree *ntreeCopyTree(Main *bmain, const bNodeTree *ntree) | bNodeTree *ntreeCopyTree(Main *bmain, const bNodeTree *ntree) | ||||
| { | { | ||||
| return ntreeCopyTree_ex(ntree, bmain, true); | return ntreeCopyTree_ex(ntree, bmain, true); | ||||
| } | } | ||||
| void ntreeUserIncrefID(bNodeTree *ntree) | void ntreeUserIncrefID(bNodeTree *ntree) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 674 Lines • ▼ Show 20 Lines | if (ntree) { | ||||
| if (adt) { | if (adt) { | ||||
| action_backup = adt->action; | action_backup = adt->action; | ||||
| tmpact_backup = adt->tmpact; | tmpact_backup = adt->tmpact; | ||||
| adt->action = NULL; | adt->action = NULL; | ||||
| adt->tmpact = NULL; | adt->tmpact = NULL; | ||||
| } | } | ||||
| /* Make full copy. | /* Make full copy outside of Main database. | ||||
| * Note: previews are not copied here. | * Note: previews are not copied here. | ||||
| */ | */ | ||||
| ltree = ntreeCopyTree_internal(ntree, G.main, true, false, false, false); | BKE_id_copy_ex(G.main, (ID *)ntree, (ID **)<ree, | ||||
| LIB_ID_COPY_NO_MAIN | LIB_ID_COPY_NO_USER_REFCOUNT | LIB_ID_COPY_NO_PREVIEW, false); | |||||
| ltree->flag |= NTREE_IS_LOCALIZED; | ltree->flag |= NTREE_IS_LOCALIZED; | ||||
| for (node = ltree->nodes.first; node; node = node->next) { | for (node = ltree->nodes.first; node; node = node->next) { | ||||
| if (node->type == NODE_GROUP && node->id) { | if (node->type == NODE_GROUP && node->id) { | ||||
| node->id = (ID *)ntreeLocalize((bNodeTree *)node->id); | node->id = (ID *)ntreeLocalize((bNodeTree *)node->id); | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 1,782 Lines • Show Last 20 Lines | |||||