Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/node.cc
- This file was moved from source/blender/blenkernel/intern/node.c.
| Show All 19 Lines | |||||
| /** \file | /** \file | ||||
| * \ingroup bke | * \ingroup bke | ||||
| */ | */ | ||||
| #include "CLG_log.h" | #include "CLG_log.h" | ||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include <limits.h> | #include <climits> | ||||
| #include <stddef.h> | #include <cstddef> | ||||
| #include <stdlib.h> | #include <cstdlib> | ||||
| #include <string.h> | #include <cstring> | ||||
| /* Allow using deprecated functionality for .blend file I/O. */ | /* Allow using deprecated functionality for .blend file I/O. */ | ||||
| #define DNA_DEPRECATED_ALLOW | #define DNA_DEPRECATED_ALLOW | ||||
| #include "DNA_action_types.h" | #include "DNA_action_types.h" | ||||
| #include "DNA_anim_types.h" | #include "DNA_anim_types.h" | ||||
| #include "DNA_collection_types.h" | #include "DNA_collection_types.h" | ||||
| #include "DNA_gpencil_types.h" | #include "DNA_gpencil_types.h" | ||||
| ▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | |||||
| static void node_free_node(bNodeTree *ntree, bNode *node); | static void node_free_node(bNodeTree *ntree, bNode *node); | ||||
| static void node_socket_interface_free(bNodeTree *UNUSED(ntree), | static void node_socket_interface_free(bNodeTree *UNUSED(ntree), | ||||
| bNodeSocket *sock, | bNodeSocket *sock, | ||||
| const bool do_id_user); | const bool do_id_user); | ||||
| static void ntree_init_data(ID *id) | static void ntree_init_data(ID *id) | ||||
| { | { | ||||
| bNodeTree *ntree = (bNodeTree *)id; | bNodeTree *ntree = (bNodeTree *)id; | ||||
| ntree_set_typeinfo(ntree, NULL); | ntree_set_typeinfo(ntree, nullptr); | ||||
| } | } | ||||
| static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int flag) | static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int flag) | ||||
| { | { | ||||
| bNodeTree *ntree_dst = (bNodeTree *)id_dst; | bNodeTree *ntree_dst = (bNodeTree *)id_dst; | ||||
| const bNodeTree *ntree_src = (const bNodeTree *)id_src; | const bNodeTree *ntree_src = (const bNodeTree *)id_src; | ||||
| /* We never handle usercount here for own data. */ | /* We never handle usercount here for own data. */ | ||||
| const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; | const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; | ||||
| /* in case a running nodetree is copied */ | /* in case a running nodetree is copied */ | ||||
| ntree_dst->execdata = NULL; | ntree_dst->execdata = nullptr; | ||||
| BLI_listbase_clear(&ntree_dst->nodes); | BLI_listbase_clear(&ntree_dst->nodes); | ||||
| BLI_listbase_clear(&ntree_dst->links); | BLI_listbase_clear(&ntree_dst->links); | ||||
| /* Since source nodes and sockets are unique pointers we can put everything in a single map. */ | /* Since source nodes and sockets are unique pointers we can put everything in a single map. */ | ||||
| GHash *new_pointers = BLI_ghash_ptr_new(__func__); | GHash *new_pointers = BLI_ghash_ptr_new(__func__); | ||||
| LISTBASE_FOREACH (const bNode *, node_src, &ntree_src->nodes) { | LISTBASE_FOREACH (const bNode *, node_src, &ntree_src->nodes) { | ||||
| bNode *new_node = BKE_node_copy_ex(ntree_dst, node_src, flag_subdata, true); | bNode *new_node = BKE_node_copy_ex(ntree_dst, node_src, flag_subdata, true); | ||||
| BLI_ghash_insert(new_pointers, (void *)node_src, new_node); | BLI_ghash_insert(new_pointers, (void *)node_src, new_node); | ||||
| /* Store mapping to inputs. */ | /* Store mapping to inputs. */ | ||||
| bNodeSocket *new_input_sock = new_node->inputs.first; | bNodeSocket *new_input_sock = (bNodeSocket *)new_node->inputs.first; | ||||
| const bNodeSocket *input_sock_src = node_src->inputs.first; | const bNodeSocket *input_sock_src = (const bNodeSocket *)node_src->inputs.first; | ||||
| while (new_input_sock != NULL) { | while (new_input_sock != nullptr) { | ||||
| BLI_ghash_insert(new_pointers, (void *)input_sock_src, new_input_sock); | BLI_ghash_insert(new_pointers, (void *)input_sock_src, new_input_sock); | ||||
| new_input_sock = new_input_sock->next; | new_input_sock = new_input_sock->next; | ||||
| input_sock_src = input_sock_src->next; | input_sock_src = input_sock_src->next; | ||||
| } | } | ||||
| /* Store mapping to outputs. */ | /* Store mapping to outputs. */ | ||||
| bNodeSocket *new_output_sock = new_node->outputs.first; | bNodeSocket *new_output_sock = (bNodeSocket *)new_node->outputs.first; | ||||
| const bNodeSocket *output_sock_src = node_src->outputs.first; | const bNodeSocket *output_sock_src = (const bNodeSocket *)node_src->outputs.first; | ||||
| while (new_output_sock != NULL) { | while (new_output_sock != nullptr) { | ||||
| BLI_ghash_insert(new_pointers, (void *)output_sock_src, new_output_sock); | BLI_ghash_insert(new_pointers, (void *)output_sock_src, new_output_sock); | ||||
| new_output_sock = new_output_sock->next; | new_output_sock = new_output_sock->next; | ||||
| output_sock_src = output_sock_src->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); | ||||
| LISTBASE_FOREACH (bNodeLink *, link_dst, &ntree_dst->links) { | LISTBASE_FOREACH (bNodeLink *, link_dst, &ntree_dst->links) { | ||||
| link_dst->fromnode = BLI_ghash_lookup_default(new_pointers, link_dst->fromnode, NULL); | link_dst->fromnode = (bNode *)BLI_ghash_lookup_default( | ||||
| link_dst->fromsock = BLI_ghash_lookup_default(new_pointers, link_dst->fromsock, NULL); | new_pointers, link_dst->fromnode, nullptr); | ||||
| link_dst->tonode = BLI_ghash_lookup_default(new_pointers, link_dst->tonode, NULL); | link_dst->fromsock = (bNodeSocket *)BLI_ghash_lookup_default( | ||||
| link_dst->tosock = BLI_ghash_lookup_default(new_pointers, link_dst->tosock, NULL); | new_pointers, link_dst->fromsock, nullptr); | ||||
| link_dst->tonode = (bNode *)BLI_ghash_lookup_default(new_pointers, link_dst->tonode, nullptr); | |||||
| link_dst->tosock = (bNodeSocket *)BLI_ghash_lookup_default( | |||||
| new_pointers, link_dst->tosock, nullptr); | |||||
| /* 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; | ||||
| } | } | ||||
| } | } | ||||
| /* copy interface sockets */ | /* copy interface sockets */ | ||||
| BLI_duplicatelist(&ntree_dst->inputs, &ntree_src->inputs); | BLI_duplicatelist(&ntree_dst->inputs, &ntree_src->inputs); | ||||
| bNodeSocket *sock_dst, *sock_src; | bNodeSocket *sock_dst, *sock_src; | ||||
| for (sock_dst = ntree_dst->inputs.first, sock_src = ntree_src->inputs.first; sock_dst != NULL; | for (sock_dst = (bNodeSocket *)ntree_dst->inputs.first, | ||||
| sock_dst = sock_dst->next, sock_src = sock_src->next) { | sock_src = (bNodeSocket *)ntree_src->inputs.first; | ||||
| sock_dst != nullptr; | |||||
| sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)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); | ||||
| for (sock_dst = ntree_dst->outputs.first, sock_src = ntree_src->outputs.first; sock_dst != NULL; | for (sock_dst = (bNodeSocket *)ntree_dst->outputs.first, | ||||
| sock_dst = sock_dst->next, sock_src = sock_src->next) { | sock_src = (bNodeSocket *)ntree_src->outputs.first; | ||||
| sock_dst != nullptr; | |||||
| sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) { | |||||
| node_socket_copy(sock_dst, sock_src, flag_subdata); | node_socket_copy(sock_dst, sock_src, flag_subdata); | ||||
| } | } | ||||
| /* copy preview hash */ | /* copy preview hash */ | ||||
| if (ntree_src->previews && (flag & LIB_ID_COPY_NO_PREVIEW) == 0) { | if (ntree_src->previews && (flag & LIB_ID_COPY_NO_PREVIEW) == 0) { | ||||
| bNodeInstanceHashIterator iter; | bNodeInstanceHashIterator iter; | ||||
| ntree_dst->previews = BKE_node_instance_hash_new("node previews"); | ntree_dst->previews = BKE_node_instance_hash_new("node previews"); | ||||
| NODE_INSTANCE_HASH_ITER (iter, ntree_src->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 = (bNodePreview *)BKE_node_instance_hash_iterator_get_value(&iter); | ||||
| BKE_node_instance_hash_insert(ntree_dst->previews, key, BKE_node_preview_copy(preview)); | BKE_node_instance_hash_insert(ntree_dst->previews, key, BKE_node_preview_copy(preview)); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| ntree_dst->previews = NULL; | ntree_dst->previews = nullptr; | ||||
| } | } | ||||
| /* update node->parent pointers */ | /* update node->parent pointers */ | ||||
| for (bNode *node_dst = ntree_dst->nodes.first, *node_src = ntree_src->nodes.first; node_dst; | for (bNode *node_dst = (bNode *)ntree_dst->nodes.first, | ||||
| node_dst = node_dst->next, node_src = node_src->next) { | *node_src = (bNode *)ntree_src->nodes.first; | ||||
| node_dst; | |||||
| node_dst = (bNode *)node_dst->next, node_src = (bNode *)node_src->next) { | |||||
| if (node_dst->parent) { | if (node_dst->parent) { | ||||
| node_dst->parent = BLI_ghash_lookup_default(new_pointers, node_dst->parent, NULL); | node_dst->parent = (bNode *)BLI_ghash_lookup_default( | ||||
| new_pointers, node_dst->parent, nullptr); | |||||
| } | } | ||||
| } | } | ||||
| BLI_ghash_free(new_pointers, NULL, NULL); | BLI_ghash_free(new_pointers, nullptr, nullptr); | ||||
| /* node tree will generate its own interface type */ | /* node tree will generate its own interface type */ | ||||
| ntree_dst->interface_type = NULL; | ntree_dst->interface_type = nullptr; | ||||
| } | } | ||||
| static void ntree_free_data(ID *id) | static void ntree_free_data(ID *id) | ||||
| { | { | ||||
| bNodeTree *ntree = (bNodeTree *)id; | bNodeTree *ntree = (bNodeTree *)id; | ||||
| /* XXX hack! node trees should not store execution graphs at all. | /* XXX hack! node trees should not store execution graphs at all. | ||||
| * This should be removed when old tree types no longer require it. | * This should be removed when old tree types no longer require it. | ||||
| * Currently the execution data for texture nodes remains in the tree | * Currently the execution data for texture nodes remains in the tree | ||||
| * after execution, until the node tree is updated or freed. | * after execution, until the node tree is updated or freed. | ||||
| */ | */ | ||||
| if (ntree->execdata) { | if (ntree->execdata) { | ||||
| switch (ntree->type) { | switch (ntree->type) { | ||||
| case NTREE_SHADER: | case NTREE_SHADER: | ||||
| ntreeShaderEndExecTree(ntree->execdata); | ntreeShaderEndExecTree(ntree->execdata); | ||||
| break; | break; | ||||
| case NTREE_TEXTURE: | case NTREE_TEXTURE: | ||||
| ntreeTexEndExecTree(ntree->execdata); | ntreeTexEndExecTree(ntree->execdata); | ||||
| ntree->execdata = NULL; | ntree->execdata = nullptr; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| /* XXX not nice, but needed to free localized node groups properly */ | /* XXX not nice, but needed to free localized node groups properly */ | ||||
| free_localized_node_groups(ntree); | free_localized_node_groups(ntree); | ||||
| /* unregister associated RNA types */ | /* unregister associated RNA types */ | ||||
| Show All 27 Lines | |||||
| static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket *sock) | static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket *sock) | ||||
| { | { | ||||
| IDP_foreach_property( | IDP_foreach_property( | ||||
| sock->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); | sock->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); | ||||
| switch ((eNodeSocketDatatype)sock->type) { | switch ((eNodeSocketDatatype)sock->type) { | ||||
| case SOCK_OBJECT: { | case SOCK_OBJECT: { | ||||
| bNodeSocketValueObject *default_value = sock->default_value; | bNodeSocketValueObject *default_value = (bNodeSocketValueObject *)sock->default_value; | ||||
| BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER); | BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER); | ||||
| break; | break; | ||||
| } | } | ||||
| case SOCK_IMAGE: { | case SOCK_IMAGE: { | ||||
| bNodeSocketValueImage *default_value = sock->default_value; | bNodeSocketValueImage *default_value = (bNodeSocketValueImage *)sock->default_value; | ||||
| BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER); | BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER); | ||||
| break; | break; | ||||
| } | } | ||||
| case SOCK_COLLECTION: { | case SOCK_COLLECTION: { | ||||
| bNodeSocketValueCollection *default_value = sock->default_value; | bNodeSocketValueCollection *default_value = (bNodeSocketValueCollection *) | ||||
| sock->default_value; | |||||
| BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER); | BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER); | ||||
| break; | break; | ||||
| } | } | ||||
| case SOCK_FLOAT: | case SOCK_FLOAT: | ||||
| case SOCK_VECTOR: | case SOCK_VECTOR: | ||||
| case SOCK_RGBA: | case SOCK_RGBA: | ||||
| case SOCK_BOOLEAN: | case SOCK_BOOLEAN: | ||||
| case SOCK_INT: | case SOCK_INT: | ||||
| Show All 33 Lines | static void node_foreach_id(ID *id, LibraryForeachIDData *data) | ||||
| } | } | ||||
| } | } | ||||
| static void node_foreach_cache(ID *id, | static void node_foreach_cache(ID *id, | ||||
| IDTypeForeachCacheFunctionCallback function_callback, | IDTypeForeachCacheFunctionCallback function_callback, | ||||
| void *user_data) | void *user_data) | ||||
| { | { | ||||
| bNodeTree *nodetree = (bNodeTree *)id; | bNodeTree *nodetree = (bNodeTree *)id; | ||||
| IDCacheKey key = { | IDCacheKey key = {0}; | ||||
| .id_session_uuid = id->session_uuid, | key.id_session_uuid = id->session_uuid; | ||||
| .offset_in_ID = offsetof(bNodeTree, previews), | key.offset_in_ID = offsetof(bNodeTree, previews); | ||||
| .cache_v = nodetree->previews, | key.cache_v = nodetree->previews; | ||||
| }; | |||||
| /* TODO, see also `direct_link_nodetree()` in readfile.c. */ | /* TODO, see also `direct_link_nodetree()` in readfile.c. */ | ||||
| #if 0 | #if 0 | ||||
| function_callback(id, &key, (void **)&nodetree->previews, 0, user_data); | function_callback(id, &key, (void **)&nodetree->previews, 0, user_data); | ||||
| #endif | #endif | ||||
| if (nodetree->type == NTREE_COMPOSIT) { | if (nodetree->type == NTREE_COMPOSIT) { | ||||
| LISTBASE_FOREACH (bNode *, node, &nodetree->nodes) { | LISTBASE_FOREACH (bNode *, node, &nodetree->nodes) { | ||||
| if (node->type == CMP_NODE_MOVIEDISTORTION) { | if (node->type == CMP_NODE_MOVIEDISTORTION) { | ||||
| key.offset_in_ID = (size_t)BLI_ghashutil_strhash_p(node->name); | key.offset_in_ID = (size_t)BLI_ghashutil_strhash_p(node->name); | ||||
| key.cache_v = node->storage; | key.cache_v = node->storage; | ||||
| function_callback(id, &key, (void **)&node->storage, 0, user_data); | function_callback(id, &key, (void **)&node->storage, 0, user_data); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *sock) | static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *sock) | ||||
| { | { | ||||
| if (sock->default_value == NULL) { | if (sock->default_value == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| switch ((eNodeSocketDatatype)sock->type) { | switch ((eNodeSocketDatatype)sock->type) { | ||||
| case SOCK_FLOAT: | case SOCK_FLOAT: | ||||
| BLO_write_struct(writer, bNodeSocketValueFloat, sock->default_value); | BLO_write_struct(writer, bNodeSocketValueFloat, sock->default_value); | ||||
| break; | break; | ||||
| case SOCK_VECTOR: | case SOCK_VECTOR: | ||||
| ▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) { | LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) { | ||||
| BLO_write_struct(writer, bNodeLink, link); | BLO_write_struct(writer, bNodeLink, link); | ||||
| } | } | ||||
| if (node->storage) { | if (node->storage) { | ||||
| /* could be handlerized at some point, now only 1 exception still */ | /* could be handlerized at some point, now only 1 exception still */ | ||||
| if ((ntree->type == NTREE_SHADER) && | if ((ntree->type == NTREE_SHADER) && | ||||
| ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB)) { | ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB)) { | ||||
| BKE_curvemapping_blend_write(writer, node->storage); | BKE_curvemapping_blend_write(writer, (const CurveMapping *)node->storage); | ||||
| } | } | ||||
| else if (ntree->type == NTREE_SHADER && (node->type == SH_NODE_SCRIPT)) { | else if (ntree->type == NTREE_SHADER && (node->type == SH_NODE_SCRIPT)) { | ||||
| NodeShaderScript *nss = (NodeShaderScript *)node->storage; | NodeShaderScript *nss = (NodeShaderScript *)node->storage; | ||||
| if (nss->bytecode) { | if (nss->bytecode) { | ||||
| BLO_write_string(writer, nss->bytecode); | BLO_write_string(writer, nss->bytecode); | ||||
| } | } | ||||
| BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage); | BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage); | ||||
| } | } | ||||
| else if ((ntree->type == NTREE_COMPOSIT) && ELEM(node->type, | else if ((ntree->type == NTREE_COMPOSIT) && ELEM(node->type, | ||||
| CMP_NODE_TIME, | CMP_NODE_TIME, | ||||
| CMP_NODE_CURVE_VEC, | CMP_NODE_CURVE_VEC, | ||||
| CMP_NODE_CURVE_RGB, | CMP_NODE_CURVE_RGB, | ||||
| CMP_NODE_HUECORRECT)) { | CMP_NODE_HUECORRECT)) { | ||||
| BKE_curvemapping_blend_write(writer, node->storage); | BKE_curvemapping_blend_write(writer, (const CurveMapping *)node->storage); | ||||
| } | } | ||||
| else if ((ntree->type == NTREE_TEXTURE) && | else if ((ntree->type == NTREE_TEXTURE) && | ||||
| (node->type == TEX_NODE_CURVE_RGB || node->type == TEX_NODE_CURVE_TIME)) { | (node->type == TEX_NODE_CURVE_RGB || node->type == TEX_NODE_CURVE_TIME)) { | ||||
| BKE_curvemapping_blend_write(writer, node->storage); | BKE_curvemapping_blend_write(writer, (const CurveMapping *)node->storage); | ||||
| } | } | ||||
| else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_MOVIEDISTORTION)) { | else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_MOVIEDISTORTION)) { | ||||
| /* pass */ | /* pass */ | ||||
| } | } | ||||
| else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_GLARE)) { | else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_GLARE)) { | ||||
| /* Simple forward compatibility for fix for T50736. | /* Simple forward compatibility for fix for T50736. | ||||
| * Not ideal (there is no ideal solution here), but should do for now. */ | * Not ideal (there is no ideal solution here), but should do for now. */ | ||||
| NodeGlare *ndg = node->storage; | NodeGlare *ndg = (NodeGlare *)node->storage; | ||||
| /* Not in undo case. */ | /* Not in undo case. */ | ||||
| if (!BLO_write_is_undo(writer)) { | if (!BLO_write_is_undo(writer)) { | ||||
| switch (ndg->type) { | switch (ndg->type) { | ||||
| case 2: /* Grrrr! magic numbers :( */ | case 2: /* Grrrr! magic numbers :( */ | ||||
| ndg->angle = ndg->streaks; | ndg->angle = ndg->streaks; | ||||
| break; | break; | ||||
| case 0: | case 0: | ||||
| ndg->angle = ndg->star_45; | ndg->angle = ndg->star_45; | ||||
| ▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | |||||
| static void ntree_blend_write(BlendWriter *writer, ID *id, const void *id_address) | static void ntree_blend_write(BlendWriter *writer, ID *id, const void *id_address) | ||||
| { | { | ||||
| bNodeTree *ntree = (bNodeTree *)id; | bNodeTree *ntree = (bNodeTree *)id; | ||||
| if (ntree->id.us > 0 || BLO_write_is_undo(writer)) { | if (ntree->id.us > 0 || BLO_write_is_undo(writer)) { | ||||
| /* Clean up, important in undo case to reduce false detection of changed datablocks. */ | /* Clean up, important in undo case to reduce false detection of changed datablocks. */ | ||||
| ntree->init = 0; /* to set callbacks and force setting types */ | ntree->init = 0; /* to set callbacks and force setting types */ | ||||
| ntree->is_updating = false; | ntree->is_updating = false; | ||||
| ntree->typeinfo = NULL; | ntree->typeinfo = nullptr; | ||||
| ntree->interface_type = NULL; | ntree->interface_type = nullptr; | ||||
| ntree->progress = NULL; | ntree->progress = nullptr; | ||||
| ntree->execdata = NULL; | ntree->execdata = nullptr; | ||||
| BLO_write_id_struct(writer, bNodeTree, id_address, &ntree->id); | BLO_write_id_struct(writer, bNodeTree, id_address, &ntree->id); | ||||
| ntreeBlendWrite(writer, ntree); | ntreeBlendWrite(writer, ntree); | ||||
| } | } | ||||
| } | } | ||||
| static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock) | static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock) | ||||
| { | { | ||||
| BLO_read_data_address(reader, &sock->prop); | BLO_read_data_address(reader, &sock->prop); | ||||
| IDP_BlendDataRead(reader, &sock->prop); | IDP_BlendDataRead(reader, &sock->prop); | ||||
| BLO_read_data_address(reader, &sock->link); | BLO_read_data_address(reader, &sock->link); | ||||
| sock->typeinfo = NULL; | sock->typeinfo = nullptr; | ||||
| BLO_read_data_address(reader, &sock->storage); | BLO_read_data_address(reader, &sock->storage); | ||||
| BLO_read_data_address(reader, &sock->default_value); | BLO_read_data_address(reader, &sock->default_value); | ||||
| sock->cache = NULL; | sock->cache = nullptr; | ||||
| } | } | ||||
| /* ntree itself has been read! */ | /* ntree itself has been read! */ | ||||
| void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) | void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) | ||||
| { | { | ||||
| /* note: writing and reading goes in sync, for speed */ | /* note: writing and reading goes in sync, for speed */ | ||||
| ntree->init = 0; /* to set callbacks and force setting types */ | ntree->init = 0; /* to set callbacks and force setting types */ | ||||
| ntree->is_updating = false; | ntree->is_updating = false; | ||||
| ntree->typeinfo = NULL; | ntree->typeinfo = nullptr; | ||||
| ntree->interface_type = NULL; | ntree->interface_type = nullptr; | ||||
| ntree->progress = NULL; | ntree->progress = nullptr; | ||||
| ntree->execdata = NULL; | ntree->execdata = nullptr; | ||||
| BLO_read_data_address(reader, &ntree->adt); | BLO_read_data_address(reader, &ntree->adt); | ||||
| BKE_animdata_blend_read_data(reader, ntree->adt); | BKE_animdata_blend_read_data(reader, ntree->adt); | ||||
| BLO_read_list(reader, &ntree->nodes); | BLO_read_list(reader, &ntree->nodes); | ||||
| LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| node->typeinfo = NULL; | node->typeinfo = nullptr; | ||||
| BLO_read_list(reader, &node->inputs); | BLO_read_list(reader, &node->inputs); | ||||
| BLO_read_list(reader, &node->outputs); | BLO_read_list(reader, &node->outputs); | ||||
| BLO_read_data_address(reader, &node->prop); | BLO_read_data_address(reader, &node->prop); | ||||
| IDP_BlendDataRead(reader, &node->prop); | IDP_BlendDataRead(reader, &node->prop); | ||||
| BLO_read_list(reader, &node->internal_links); | BLO_read_list(reader, &node->internal_links); | ||||
| Show All 18 Lines | if (node->storage) { | ||||
| case SH_NODE_CURVE_VEC: | case SH_NODE_CURVE_VEC: | ||||
| case SH_NODE_CURVE_RGB: | case SH_NODE_CURVE_RGB: | ||||
| case CMP_NODE_TIME: | case CMP_NODE_TIME: | ||||
| case CMP_NODE_CURVE_VEC: | case CMP_NODE_CURVE_VEC: | ||||
| case CMP_NODE_CURVE_RGB: | case CMP_NODE_CURVE_RGB: | ||||
| case CMP_NODE_HUECORRECT: | case CMP_NODE_HUECORRECT: | ||||
| case TEX_NODE_CURVE_RGB: | case TEX_NODE_CURVE_RGB: | ||||
| case TEX_NODE_CURVE_TIME: { | case TEX_NODE_CURVE_TIME: { | ||||
| BKE_curvemapping_blend_read(reader, node->storage); | BKE_curvemapping_blend_read(reader, (CurveMapping *)node->storage); | ||||
| break; | break; | ||||
| } | } | ||||
| case SH_NODE_SCRIPT: { | case SH_NODE_SCRIPT: { | ||||
| NodeShaderScript *nss = (NodeShaderScript *)node->storage; | NodeShaderScript *nss = (NodeShaderScript *)node->storage; | ||||
| BLO_read_data_address(reader, &nss->bytecode); | BLO_read_data_address(reader, &nss->bytecode); | ||||
| break; | break; | ||||
| } | } | ||||
| case SH_NODE_TEX_POINTDENSITY: { | case SH_NODE_TEX_POINTDENSITY: { | ||||
| NodeShaderTexPointDensity *npd = (NodeShaderTexPointDensity *)node->storage; | NodeShaderTexPointDensity *npd = (NodeShaderTexPointDensity *)node->storage; | ||||
| memset(&npd->pd, 0, sizeof(npd->pd)); | memset(&npd->pd, 0, sizeof(npd->pd)); | ||||
| break; | break; | ||||
| } | } | ||||
| case SH_NODE_TEX_IMAGE: { | case SH_NODE_TEX_IMAGE: { | ||||
| NodeTexImage *tex = (NodeTexImage *)node->storage; | NodeTexImage *tex = (NodeTexImage *)node->storage; | ||||
| tex->iuser.ok = 1; | tex->iuser.ok = 1; | ||||
| tex->iuser.scene = NULL; | tex->iuser.scene = nullptr; | ||||
| break; | break; | ||||
| } | } | ||||
| case SH_NODE_TEX_ENVIRONMENT: { | case SH_NODE_TEX_ENVIRONMENT: { | ||||
| NodeTexEnvironment *tex = (NodeTexEnvironment *)node->storage; | NodeTexEnvironment *tex = (NodeTexEnvironment *)node->storage; | ||||
| tex->iuser.ok = 1; | tex->iuser.ok = 1; | ||||
| tex->iuser.scene = NULL; | tex->iuser.scene = nullptr; | ||||
| break; | break; | ||||
| } | } | ||||
| case CMP_NODE_IMAGE: | case CMP_NODE_IMAGE: | ||||
| case CMP_NODE_R_LAYERS: | case CMP_NODE_R_LAYERS: | ||||
| case CMP_NODE_VIEWER: | case CMP_NODE_VIEWER: | ||||
| case CMP_NODE_SPLITVIEWER: { | case CMP_NODE_SPLITVIEWER: { | ||||
| ImageUser *iuser = node->storage; | ImageUser *iuser = (ImageUser *)node->storage; | ||||
| iuser->ok = 1; | iuser->ok = 1; | ||||
| iuser->scene = NULL; | iuser->scene = nullptr; | ||||
| break; | break; | ||||
| } | } | ||||
| case CMP_NODE_CRYPTOMATTE: { | case CMP_NODE_CRYPTOMATTE: { | ||||
| NodeCryptomatte *nc = (NodeCryptomatte *)node->storage; | NodeCryptomatte *nc = (NodeCryptomatte *)node->storage; | ||||
| BLO_read_data_address(reader, &nc->matte_id); | BLO_read_data_address(reader, &nc->matte_id); | ||||
| BLO_read_list(reader, &nc->entries); | BLO_read_list(reader, &nc->entries); | ||||
| break; | break; | ||||
| } | } | ||||
| case TEX_NODE_IMAGE: { | case TEX_NODE_IMAGE: { | ||||
| ImageUser *iuser = node->storage; | ImageUser *iuser = (ImageUser *)node->storage; | ||||
| iuser->ok = 1; | iuser->ok = 1; | ||||
| iuser->scene = NULL; | iuser->scene = nullptr; | ||||
| break; | break; | ||||
| } | } | ||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| BLO_read_list(reader, &ntree->links); | BLO_read_list(reader, &ntree->links); | ||||
| Show All 23 Lines | void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) | ||||
| LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { | LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { | ||||
| BLO_read_data_address(reader, &link->fromnode); | BLO_read_data_address(reader, &link->fromnode); | ||||
| BLO_read_data_address(reader, &link->tonode); | BLO_read_data_address(reader, &link->tonode); | ||||
| BLO_read_data_address(reader, &link->fromsock); | BLO_read_data_address(reader, &link->fromsock); | ||||
| BLO_read_data_address(reader, &link->tosock); | BLO_read_data_address(reader, &link->tosock); | ||||
| } | } | ||||
| /* TODO, should be dealt by new generic cache handling of IDs... */ | /* TODO, should be dealt by new generic cache handling of IDs... */ | ||||
| ntree->previews = NULL; | ntree->previews = nullptr; | ||||
| /* type verification is in lib-link */ | /* type verification is in lib-link */ | ||||
| } | } | ||||
| static void ntree_blend_read_data(BlendDataReader *reader, ID *id) | static void ntree_blend_read_data(BlendDataReader *reader, ID *id) | ||||
| { | { | ||||
| bNodeTree *ntree = (bNodeTree *)id; | bNodeTree *ntree = (bNodeTree *)id; | ||||
| ntreeBlendReadData(reader, ntree); | ntreeBlendReadData(reader, ntree); | ||||
| } | } | ||||
| static void lib_link_node_socket(BlendLibReader *reader, Library *lib, bNodeSocket *sock) | static void lib_link_node_socket(BlendLibReader *reader, Library *lib, bNodeSocket *sock) | ||||
| { | { | ||||
| IDP_BlendReadLib(reader, sock->prop); | IDP_BlendReadLib(reader, sock->prop); | ||||
| switch ((eNodeSocketDatatype)sock->type) { | switch ((eNodeSocketDatatype)sock->type) { | ||||
| case SOCK_OBJECT: { | case SOCK_OBJECT: { | ||||
| bNodeSocketValueObject *default_value = sock->default_value; | bNodeSocketValueObject *default_value = (bNodeSocketValueObject *)sock->default_value; | ||||
| BLO_read_id_address(reader, lib, &default_value->value); | BLO_read_id_address(reader, lib, &default_value->value); | ||||
| break; | break; | ||||
| } | } | ||||
| case SOCK_IMAGE: { | case SOCK_IMAGE: { | ||||
| bNodeSocketValueImage *default_value = sock->default_value; | bNodeSocketValueImage *default_value = (bNodeSocketValueImage *)sock->default_value; | ||||
| BLO_read_id_address(reader, lib, &default_value->value); | BLO_read_id_address(reader, lib, &default_value->value); | ||||
| break; | break; | ||||
| } | } | ||||
| case SOCK_COLLECTION: { | case SOCK_COLLECTION: { | ||||
| bNodeSocketValueImage *default_value = sock->default_value; | bNodeSocketValueCollection *default_value = (bNodeSocketValueCollection *) | ||||
| sock->default_value; | |||||
| BLO_read_id_address(reader, lib, &default_value->value); | BLO_read_id_address(reader, lib, &default_value->value); | ||||
| break; | break; | ||||
| } | } | ||||
| case SOCK_FLOAT: | case SOCK_FLOAT: | ||||
| case SOCK_VECTOR: | case SOCK_VECTOR: | ||||
| case SOCK_RGBA: | case SOCK_RGBA: | ||||
| case SOCK_BOOLEAN: | case SOCK_BOOLEAN: | ||||
| case SOCK_INT: | case SOCK_INT: | ||||
| Show All 32 Lines | void ntreeBlendReadLib(struct BlendLibReader *reader, struct bNodeTree *ntree) | ||||
| lib_link_node_sockets(reader, lib, &ntree->inputs); | lib_link_node_sockets(reader, lib, &ntree->inputs); | ||||
| lib_link_node_sockets(reader, lib, &ntree->outputs); | lib_link_node_sockets(reader, lib, &ntree->outputs); | ||||
| /* Set node->typeinfo pointers. This is done in lib linking, after the | /* Set node->typeinfo pointers. This is done in lib linking, after the | ||||
| * first versioning that can change types still without functions that | * first versioning that can change types still without functions that | ||||
| * update the typeinfo pointers. Versioning after lib linking needs | * update the typeinfo pointers. Versioning after lib linking needs | ||||
| * these top be valid. */ | * these top be valid. */ | ||||
| ntreeSetTypes(NULL, ntree); | ntreeSetTypes(nullptr, ntree); | ||||
| /* For nodes with static socket layout, add/remove sockets as needed | /* For nodes with static socket layout, add/remove sockets as needed | ||||
| * to match the static layout. */ | * to match the static layout. */ | ||||
| if (!BLO_read_lib_is_undo(reader)) { | if (!BLO_read_lib_is_undo(reader)) { | ||||
| LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| node_verify_socket_templates(ntree, node); | node_verify_socket_templates(ntree, node); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void ntree_blend_read_lib(BlendLibReader *reader, ID *id) | static void ntree_blend_read_lib(BlendLibReader *reader, ID *id) | ||||
| { | { | ||||
| bNodeTree *ntree = (bNodeTree *)id; | bNodeTree *ntree = (bNodeTree *)id; | ||||
| ntreeBlendReadLib(reader, ntree); | ntreeBlendReadLib(reader, ntree); | ||||
| } | } | ||||
| static void expand_node_socket(BlendExpander *expander, bNodeSocket *sock) | static void expand_node_socket(BlendExpander *expander, bNodeSocket *sock) | ||||
| { | { | ||||
| IDP_BlendReadExpand(expander, sock->prop); | IDP_BlendReadExpand(expander, sock->prop); | ||||
| if (sock->default_value != NULL) { | if (sock->default_value != nullptr) { | ||||
| switch ((eNodeSocketDatatype)sock->type) { | switch ((eNodeSocketDatatype)sock->type) { | ||||
| case SOCK_OBJECT: { | case SOCK_OBJECT: { | ||||
| bNodeSocketValueObject *default_value = sock->default_value; | bNodeSocketValueObject *default_value = (bNodeSocketValueObject *)sock->default_value; | ||||
| BLO_expand(expander, default_value->value); | BLO_expand(expander, default_value->value); | ||||
| break; | break; | ||||
| } | } | ||||
| case SOCK_IMAGE: { | case SOCK_IMAGE: { | ||||
| bNodeSocketValueImage *default_value = sock->default_value; | bNodeSocketValueImage *default_value = (bNodeSocketValueImage *)sock->default_value; | ||||
| BLO_expand(expander, default_value->value); | BLO_expand(expander, default_value->value); | ||||
| break; | break; | ||||
| } | } | ||||
| case SOCK_COLLECTION: { | case SOCK_COLLECTION: { | ||||
| bNodeSocketValueCollection *default_value = sock->default_value; | bNodeSocketValueCollection *default_value = (bNodeSocketValueCollection *) | ||||
| sock->default_value; | |||||
| BLO_expand(expander, default_value->value); | BLO_expand(expander, default_value->value); | ||||
| break; | break; | ||||
| } | } | ||||
| case SOCK_FLOAT: | case SOCK_FLOAT: | ||||
| case SOCK_VECTOR: | case SOCK_VECTOR: | ||||
| case SOCK_RGBA: | case SOCK_RGBA: | ||||
| case SOCK_BOOLEAN: | case SOCK_BOOLEAN: | ||||
| case SOCK_INT: | case SOCK_INT: | ||||
| Show All 37 Lines | |||||
| static void ntree_blend_read_expand(BlendExpander *expander, ID *id) | static void ntree_blend_read_expand(BlendExpander *expander, ID *id) | ||||
| { | { | ||||
| bNodeTree *ntree = (bNodeTree *)id; | bNodeTree *ntree = (bNodeTree *)id; | ||||
| ntreeBlendReadExpand(expander, ntree); | ntreeBlendReadExpand(expander, ntree); | ||||
| } | } | ||||
| IDTypeInfo IDType_ID_NT = { | IDTypeInfo IDType_ID_NT = { | ||||
| .id_code = ID_NT, | /* id_code */ ID_NT, | ||||
| .id_filter = FILTER_ID_NT, | /* id_filter */ FILTER_ID_NT, | ||||
| .main_listbase_index = INDEX_ID_NT, | /* main_listbase_index */ INDEX_ID_NT, | ||||
| .struct_size = sizeof(bNodeTree), | /* struct_size */ sizeof(bNodeTree), | ||||
| .name = "NodeTree", | /* name */ "NodeTree", | ||||
| .name_plural = "node_groups", | /* name_plural */ "node_groups", | ||||
| .translation_context = BLT_I18NCONTEXT_ID_NODETREE, | /* translation_context */ BLT_I18NCONTEXT_ID_NODETREE, | ||||
| .flags = 0, | /* flags */ 0, | ||||
| .init_data = ntree_init_data, | /* init_data */ ntree_init_data, | ||||
| .copy_data = ntree_copy_data, | /* copy_data */ ntree_copy_data, | ||||
| .free_data = ntree_free_data, | /* free_data */ ntree_free_data, | ||||
| .make_local = NULL, | /* make_local */ nullptr, | ||||
| .foreach_id = node_foreach_id, | /* foreach_id */ node_foreach_id, | ||||
| .foreach_cache = node_foreach_cache, | /* foreach_cache */ node_foreach_cache, | ||||
| .blend_write = ntree_blend_write, | /* blend_write */ ntree_blend_write, | ||||
| .blend_read_data = ntree_blend_read_data, | /* blend_read_data */ ntree_blend_read_data, | ||||
| .blend_read_lib = ntree_blend_read_lib, | /* blend_read_lib */ ntree_blend_read_lib, | ||||
| .blend_read_expand = ntree_blend_read_expand, | /* blend_read_expand */ ntree_blend_read_expand, | ||||
| /* blend_read_undo_preserve */ nullptr, | |||||
| .blend_read_undo_preserve = NULL, | /* lib_override_apply_post */ nullptr, | ||||
| }; | }; | ||||
| static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype) | static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype) | ||||
| { | { | ||||
| bNodeSocketTemplate *sockdef; | bNodeSocketTemplate *sockdef; | ||||
| /* bNodeSocket *sock; */ /* UNUSED */ | /* bNodeSocket *sock; */ /* UNUSED */ | ||||
| if (ntype->inputs) { | if (ntype->inputs) { | ||||
| ▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node) | ||||
| * Data have their own translation option! | * Data have their own translation option! | ||||
| * This solution may be a bit rougher than nodeLabel()'s returned string, but it's simpler | * This solution may be a bit rougher than nodeLabel()'s returned string, but it's simpler | ||||
| * than adding "do_translate" flags to this func (and labelfunc() as well). */ | * than adding "do_translate" flags to this func (and labelfunc() as well). */ | ||||
| BLI_strncpy(node->name, DATA_(ntype->ui_name), NODE_MAXSTR); | BLI_strncpy(node->name, DATA_(ntype->ui_name), NODE_MAXSTR); | ||||
| nodeUniqueName(ntree, node); | nodeUniqueName(ntree, node); | ||||
| node_add_sockets_from_type(ntree, node, ntype); | node_add_sockets_from_type(ntree, node, ntype); | ||||
| if (ntype->initfunc != NULL) { | if (ntype->initfunc != nullptr) { | ||||
| ntype->initfunc(ntree, node); | ntype->initfunc(ntree, node); | ||||
| } | } | ||||
| if (ntree->typeinfo->node_add_init != NULL) { | if (ntree->typeinfo->node_add_init != nullptr) { | ||||
| ntree->typeinfo->node_add_init(ntree, node); | ntree->typeinfo->node_add_init(ntree, node); | ||||
| } | } | ||||
| if (node->id) { | if (node->id) { | ||||
| id_us_plus(node->id); | id_us_plus(node->id); | ||||
| } | } | ||||
| /* extra init callback */ | /* extra init callback */ | ||||
| if (ntype->initfunc_api) { | if (ntype->initfunc_api) { | ||||
| PointerRNA ptr; | PointerRNA ptr; | ||||
| RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr); | RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr); | ||||
| /* XXX Warning: context can be NULL in case nodes are added in do_versions. | /* XXX Warning: context can be nullptr in case nodes are added in do_versions. | ||||
| * Delayed init is not supported for nodes with context-based initfunc_api atm. | * Delayed init is not supported for nodes with context-based initfunc_api atm. | ||||
| */ | */ | ||||
| BLI_assert(C != NULL); | BLI_assert(C != nullptr); | ||||
| ntype->initfunc_api(C, &ptr); | ntype->initfunc_api(C, &ptr); | ||||
| } | } | ||||
| node->flag |= NODE_INIT; | node->flag |= NODE_INIT; | ||||
| } | } | ||||
| static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo) | static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo) | ||||
| { | { | ||||
| Show All 13 Lines | |||||
| static void node_set_typeinfo(const struct bContext *C, | static void node_set_typeinfo(const struct bContext *C, | ||||
| bNodeTree *ntree, | bNodeTree *ntree, | ||||
| bNode *node, | bNode *node, | ||||
| bNodeType *typeinfo) | bNodeType *typeinfo) | ||||
| { | { | ||||
| /* for nodes saved in older versions storage can get lost, make undefined then */ | /* for nodes saved in older versions storage can get lost, make undefined then */ | ||||
| if (node->flag & NODE_INIT) { | if (node->flag & NODE_INIT) { | ||||
| if (typeinfo && typeinfo->storagename[0] && !node->storage) { | if (typeinfo && typeinfo->storagename[0] && !node->storage) { | ||||
| typeinfo = NULL; | typeinfo = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| if (typeinfo) { | if (typeinfo) { | ||||
| node->typeinfo = typeinfo; | node->typeinfo = typeinfo; | ||||
| /* deprecated integer type */ | /* deprecated integer type */ | ||||
| node->type = typeinfo->type; | node->type = typeinfo->type; | ||||
| Show All 13 Lines | static void node_socket_set_typeinfo(bNodeTree *ntree, | ||||
| bNodeSocketType *typeinfo) | bNodeSocketType *typeinfo) | ||||
| { | { | ||||
| if (typeinfo) { | if (typeinfo) { | ||||
| sock->typeinfo = typeinfo; | sock->typeinfo = typeinfo; | ||||
| /* deprecated integer type */ | /* deprecated integer type */ | ||||
| sock->type = typeinfo->type; | sock->type = typeinfo->type; | ||||
| if (sock->default_value == NULL) { | if (sock->default_value == nullptr) { | ||||
| /* initialize the default_value pointer used by standard socket types */ | /* initialize the default_value pointer used by standard socket types */ | ||||
| node_socket_init_default_value(sock); | node_socket_init_default_value(sock); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| sock->typeinfo = &NodeSocketTypeUndefined; | sock->typeinfo = &NodeSocketTypeUndefined; | ||||
| ntree->init &= ~NTREE_TYPE_INIT; | ntree->init &= ~NTREE_TYPE_INIT; | ||||
| Show All 11 Lines | static void update_typeinfo(Main *bmain, | ||||
| if (!bmain) { | if (!bmain) { | ||||
| return; | return; | ||||
| } | } | ||||
| FOREACH_NODETREE_BEGIN (bmain, ntree, id) { | FOREACH_NODETREE_BEGIN (bmain, ntree, id) { | ||||
| ntree->init |= NTREE_TYPE_INIT; | ntree->init |= NTREE_TYPE_INIT; | ||||
| if (treetype && STREQ(ntree->idname, treetype->idname)) { | if (treetype && STREQ(ntree->idname, treetype->idname)) { | ||||
| ntree_set_typeinfo(ntree, unregister ? NULL : treetype); | ntree_set_typeinfo(ntree, unregister ? nullptr : treetype); | ||||
| } | } | ||||
| /* initialize nodes */ | /* initialize nodes */ | ||||
| LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| if (nodetype && STREQ(node->idname, nodetype->idname)) { | if (nodetype && STREQ(node->idname, nodetype->idname)) { | ||||
| node_set_typeinfo(C, ntree, node, unregister ? NULL : nodetype); | node_set_typeinfo(C, ntree, node, unregister ? nullptr : nodetype); | ||||
| } | } | ||||
| /* initialize node sockets */ | /* initialize node sockets */ | ||||
| LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { | LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { | ||||
| if (socktype && STREQ(sock->idname, socktype->idname)) { | if (socktype && STREQ(sock->idname, socktype->idname)) { | ||||
| node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype); | node_socket_set_typeinfo(ntree, sock, unregister ? nullptr : socktype); | ||||
| } | } | ||||
| } | } | ||||
| LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { | LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { | ||||
| if (socktype && STREQ(sock->idname, socktype->idname)) { | if (socktype && STREQ(sock->idname, socktype->idname)) { | ||||
| node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype); | node_socket_set_typeinfo(ntree, sock, unregister ? nullptr : socktype); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* initialize tree sockets */ | /* initialize tree sockets */ | ||||
| LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) { | LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) { | ||||
| if (socktype && STREQ(sock->idname, socktype->idname)) { | if (socktype && STREQ(sock->idname, socktype->idname)) { | ||||
| node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype); | node_socket_set_typeinfo(ntree, sock, unregister ? nullptr : socktype); | ||||
| } | } | ||||
| } | } | ||||
| LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { | LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { | ||||
| if (socktype && STREQ(sock->idname, socktype->idname)) { | if (socktype && STREQ(sock->idname, socktype->idname)) { | ||||
| node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype); | node_socket_set_typeinfo(ntree, sock, unregister ? nullptr : socktype); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| FOREACH_NODETREE_END; | FOREACH_NODETREE_END; | ||||
| } | } | ||||
| /* Try to initialize all typeinfo in a node tree. | /* Try to initialize all typeinfo in a node tree. | ||||
| * NB: In general undefined typeinfo is a perfectly valid case, | * NB: In general undefined typeinfo is a perfectly valid case, | ||||
| Show All 21 Lines | void ntreeSetTypes(const struct bContext *C, bNodeTree *ntree) | ||||
| LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) { | LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) { | ||||
| node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname)); | node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname)); | ||||
| } | } | ||||
| LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { | LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { | ||||
| node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname)); | node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname)); | ||||
| } | } | ||||
| } | } | ||||
| static GHash *nodetreetypes_hash = NULL; | static GHash *nodetreetypes_hash = nullptr; | ||||
| static GHash *nodetypes_hash = NULL; | static GHash *nodetypes_hash = nullptr; | ||||
| static GHash *nodesockettypes_hash = NULL; | static GHash *nodesockettypes_hash = nullptr; | ||||
| bNodeTreeType *ntreeTypeFind(const char *idname) | bNodeTreeType *ntreeTypeFind(const char *idname) | ||||
| { | { | ||||
| bNodeTreeType *nt; | |||||
| if (idname[0]) { | if (idname[0]) { | ||||
| nt = BLI_ghash_lookup(nodetreetypes_hash, idname); | bNodeTreeType *nt = (bNodeTreeType *)BLI_ghash_lookup(nodetreetypes_hash, idname); | ||||
| if (nt) { | if (nt) { | ||||
| return nt; | return nt; | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| void ntreeTypeAdd(bNodeTreeType *nt) | void ntreeTypeAdd(bNodeTreeType *nt) | ||||
| { | { | ||||
| BLI_ghash_insert(nodetreetypes_hash, nt->idname, nt); | BLI_ghash_insert(nodetreetypes_hash, nt->idname, nt); | ||||
| /* XXX pass Main to register function? */ | /* XXX pass Main to register function? */ | ||||
| /* Probably not. It is pretty much expected we want to update G_MAIN here I think - | /* Probably not. It is pretty much expected we want to update G_MAIN here I think - | ||||
| * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ | * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ | ||||
| update_typeinfo(G_MAIN, NULL, nt, NULL, NULL, false); | update_typeinfo(G_MAIN, nullptr, nt, nullptr, nullptr, false); | ||||
| } | } | ||||
| /* callback for hash value free function */ | /* callback for hash value free function */ | ||||
| static void ntree_free_type(void *treetype_v) | static void ntree_free_type(void *treetype_v) | ||||
| { | { | ||||
| bNodeTreeType *treetype = treetype_v; | bNodeTreeType *treetype = (bNodeTreeType *)treetype_v; | ||||
| /* XXX pass Main to unregister function? */ | /* XXX pass Main to unregister function? */ | ||||
| /* Probably not. It is pretty much expected we want to update G_MAIN here I think - | /* Probably not. It is pretty much expected we want to update G_MAIN here I think - | ||||
| * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ | * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ | ||||
| update_typeinfo(G_MAIN, NULL, treetype, NULL, NULL, true); | update_typeinfo(G_MAIN, nullptr, treetype, nullptr, nullptr, true); | ||||
| MEM_freeN(treetype); | MEM_freeN(treetype); | ||||
| } | } | ||||
| void ntreeTypeFreeLink(const bNodeTreeType *nt) | void ntreeTypeFreeLink(const bNodeTreeType *nt) | ||||
| { | { | ||||
| BLI_ghash_remove(nodetreetypes_hash, nt->idname, NULL, ntree_free_type); | BLI_ghash_remove(nodetreetypes_hash, nt->idname, nullptr, ntree_free_type); | ||||
| } | } | ||||
| bool ntreeIsRegistered(bNodeTree *ntree) | bool ntreeIsRegistered(bNodeTree *ntree) | ||||
| { | { | ||||
| return (ntree->typeinfo != &NodeTreeTypeUndefined); | return (ntree->typeinfo != &NodeTreeTypeUndefined); | ||||
| } | } | ||||
| GHashIterator *ntreeTypeGetIterator(void) | GHashIterator *ntreeTypeGetIterator(void) | ||||
| { | { | ||||
| return BLI_ghashIterator_new(nodetreetypes_hash); | return BLI_ghashIterator_new(nodetreetypes_hash); | ||||
| } | } | ||||
| bNodeType *nodeTypeFind(const char *idname) | bNodeType *nodeTypeFind(const char *idname) | ||||
| { | { | ||||
| if (idname[0]) { | if (idname[0]) { | ||||
| bNodeType *nt = BLI_ghash_lookup(nodetypes_hash, idname); | bNodeType *nt = (bNodeType *)BLI_ghash_lookup(nodetypes_hash, idname); | ||||
| if (nt) { | if (nt) { | ||||
| return nt; | return nt; | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| static void free_dynamic_typeinfo(bNodeType *ntype) | static void free_dynamic_typeinfo(bNodeType *ntype) | ||||
| { | { | ||||
| if (ntype->type == NODE_DYNAMIC) { | if (ntype->type == NODE_DYNAMIC) { | ||||
| if (ntype->inputs) { | if (ntype->inputs) { | ||||
| MEM_freeN(ntype->inputs); | MEM_freeN(ntype->inputs); | ||||
| } | } | ||||
| if (ntype->outputs) { | if (ntype->outputs) { | ||||
| MEM_freeN(ntype->outputs); | MEM_freeN(ntype->outputs); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* callback for hash value free function */ | /* callback for hash value free function */ | ||||
| static void node_free_type(void *nodetype_v) | static void node_free_type(void *nodetype_v) | ||||
| { | { | ||||
| bNodeType *nodetype = nodetype_v; | bNodeType *nodetype = (bNodeType *)nodetype_v; | ||||
| /* XXX pass Main to unregister function? */ | /* XXX pass Main to unregister function? */ | ||||
| /* Probably not. It is pretty much expected we want to update G_MAIN here I think - | /* Probably not. It is pretty much expected we want to update G_MAIN here I think - | ||||
| * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ | * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ | ||||
| update_typeinfo(G_MAIN, NULL, NULL, nodetype, NULL, true); | update_typeinfo(G_MAIN, nullptr, nullptr, nodetype, nullptr, true); | ||||
| /* XXX deprecated */ | /* XXX deprecated */ | ||||
| if (nodetype->type == NODE_DYNAMIC) { | if (nodetype->type == NODE_DYNAMIC) { | ||||
| free_dynamic_typeinfo(nodetype); | free_dynamic_typeinfo(nodetype); | ||||
| } | } | ||||
| /* Can be NULL when the type is not dynamically allocated. */ | /* Can be null when the type is not dynamically allocated. */ | ||||
| if (nodetype->free_self) { | if (nodetype->free_self) { | ||||
| nodetype->free_self(nodetype); | nodetype->free_self(nodetype); | ||||
| } | } | ||||
| } | } | ||||
| void nodeRegisterType(bNodeType *nt) | void nodeRegisterType(bNodeType *nt) | ||||
| { | { | ||||
| /* debug only: basic verification of registered types */ | /* debug only: basic verification of registered types */ | ||||
| BLI_assert(nt->idname[0] != '\0'); | BLI_assert(nt->idname[0] != '\0'); | ||||
| BLI_assert(nt->poll != NULL); | BLI_assert(nt->poll != nullptr); | ||||
| BLI_ghash_insert(nodetypes_hash, nt->idname, nt); | BLI_ghash_insert(nodetypes_hash, nt->idname, nt); | ||||
| /* XXX pass Main to register function? */ | /* XXX pass Main to register function? */ | ||||
| /* Probably not. It is pretty much expected we want to update G_MAIN here I think - | /* Probably not. It is pretty much expected we want to update G_MAIN here I think - | ||||
| * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ | * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ | ||||
| update_typeinfo(G_MAIN, NULL, NULL, nt, NULL, false); | update_typeinfo(G_MAIN, nullptr, nullptr, nt, nullptr, false); | ||||
| } | } | ||||
| void nodeUnregisterType(bNodeType *nt) | void nodeUnregisterType(bNodeType *nt) | ||||
| { | { | ||||
| BLI_ghash_remove(nodetypes_hash, nt->idname, NULL, node_free_type); | BLI_ghash_remove(nodetypes_hash, nt->idname, nullptr, node_free_type); | ||||
| } | } | ||||
| bool nodeTypeUndefined(bNode *node) | bool nodeTypeUndefined(bNode *node) | ||||
| { | { | ||||
| return (node->typeinfo == &NodeTypeUndefined) || | return (node->typeinfo == &NodeTypeUndefined) || | ||||
| (node->type == NODE_GROUP && node->id && ID_IS_LINKED(node->id) && | (node->type == NODE_GROUP && node->id && ID_IS_LINKED(node->id) && | ||||
| (node->id->tag & LIB_TAG_MISSING)); | (node->id->tag & LIB_TAG_MISSING)); | ||||
| } | } | ||||
| GHashIterator *nodeTypeGetIterator(void) | GHashIterator *nodeTypeGetIterator(void) | ||||
| { | { | ||||
| return BLI_ghashIterator_new(nodetypes_hash); | return BLI_ghashIterator_new(nodetypes_hash); | ||||
| } | } | ||||
| bNodeSocketType *nodeSocketTypeFind(const char *idname) | bNodeSocketType *nodeSocketTypeFind(const char *idname) | ||||
| { | { | ||||
| if (idname[0]) { | if (idname[0]) { | ||||
| bNodeSocketType *st = BLI_ghash_lookup(nodesockettypes_hash, idname); | bNodeSocketType *st = (bNodeSocketType *)BLI_ghash_lookup(nodesockettypes_hash, idname); | ||||
| if (st) { | if (st) { | ||||
| return st; | return st; | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| /* callback for hash value free function */ | /* callback for hash value free function */ | ||||
| static void node_free_socket_type(void *socktype_v) | static void node_free_socket_type(void *socktype_v) | ||||
| { | { | ||||
| bNodeSocketType *socktype = socktype_v; | bNodeSocketType *socktype = (bNodeSocketType *)socktype_v; | ||||
| /* XXX pass Main to unregister function? */ | /* XXX pass Main to unregister function? */ | ||||
| /* Probably not. It is pretty much expected we want to update G_MAIN here I think - | /* Probably not. It is pretty much expected we want to update G_MAIN here I think - | ||||
| * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ | * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ | ||||
| update_typeinfo(G_MAIN, NULL, NULL, NULL, socktype, true); | update_typeinfo(G_MAIN, nullptr, nullptr, nullptr, socktype, true); | ||||
| socktype->free_self(socktype); | socktype->free_self(socktype); | ||||
| } | } | ||||
| void nodeRegisterSocketType(bNodeSocketType *st) | void nodeRegisterSocketType(bNodeSocketType *st) | ||||
| { | { | ||||
| BLI_ghash_insert(nodesockettypes_hash, (void *)st->idname, st); | BLI_ghash_insert(nodesockettypes_hash, (void *)st->idname, st); | ||||
| /* XXX pass Main to register function? */ | /* XXX pass Main to register function? */ | ||||
| /* Probably not. It is pretty much expected we want to update G_MAIN here I think - | /* Probably not. It is pretty much expected we want to update G_MAIN here I think - | ||||
| * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ | * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ | ||||
| update_typeinfo(G_MAIN, NULL, NULL, NULL, st, false); | update_typeinfo(G_MAIN, nullptr, nullptr, nullptr, st, false); | ||||
| } | } | ||||
| void nodeUnregisterSocketType(bNodeSocketType *st) | void nodeUnregisterSocketType(bNodeSocketType *st) | ||||
| { | { | ||||
| BLI_ghash_remove(nodesockettypes_hash, st->idname, NULL, node_free_socket_type); | BLI_ghash_remove(nodesockettypes_hash, st->idname, nullptr, node_free_socket_type); | ||||
| } | } | ||||
| bool nodeSocketIsRegistered(bNodeSocket *sock) | bool nodeSocketIsRegistered(bNodeSocket *sock) | ||||
| { | { | ||||
| return (sock->typeinfo != &NodeSocketTypeUndefined); | return (sock->typeinfo != &NodeSocketTypeUndefined); | ||||
| } | } | ||||
| GHashIterator *nodeSocketTypeGetIterator(void) | GHashIterator *nodeSocketTypeGetIterator(void) | ||||
| { | { | ||||
| return BLI_ghashIterator_new(nodesockettypes_hash); | return BLI_ghashIterator_new(nodesockettypes_hash); | ||||
| } | } | ||||
| struct bNodeSocket *nodeFindSocket(const bNode *node, int in_out, const char *identifier) | struct bNodeSocket *nodeFindSocket(const bNode *node, int in_out, const char *identifier) | ||||
| { | { | ||||
| const ListBase *sockets = (in_out == SOCK_IN) ? &node->inputs : &node->outputs; | const ListBase *sockets = (in_out == SOCK_IN) ? &node->inputs : &node->outputs; | ||||
| LISTBASE_FOREACH (bNodeSocket *, sock, sockets) { | LISTBASE_FOREACH (bNodeSocket *, sock, sockets) { | ||||
| if (STREQ(sock->identifier, identifier)) { | if (STREQ(sock->identifier, identifier)) { | ||||
| return sock; | return sock; | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| /* find unique socket identifier */ | /* find unique socket identifier */ | ||||
| static bool unique_identifier_check(void *arg, const char *identifier) | static bool unique_identifier_check(void *arg, const char *identifier) | ||||
| { | { | ||||
| struct ListBase *lb = arg; | const ListBase *lb = (const ListBase *)arg; | ||||
| LISTBASE_FOREACH (bNodeSocket *, sock, lb) { | LISTBASE_FOREACH (bNodeSocket *, sock, lb) { | ||||
| if (STREQ(sock->identifier, identifier)) { | if (STREQ(sock->identifier, identifier)) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| Show All 14 Lines | static bNodeSocket *make_socket(bNodeTree *ntree, | ||||
| else { | else { | ||||
| /* if no explicit identifier is given, assign a unique identifier based on the name */ | /* if no explicit identifier is given, assign a unique identifier based on the name */ | ||||
| BLI_strncpy(auto_identifier, name, sizeof(auto_identifier)); | BLI_strncpy(auto_identifier, name, sizeof(auto_identifier)); | ||||
| } | } | ||||
| /* make the identifier unique */ | /* make the identifier unique */ | ||||
| BLI_uniquename_cb( | BLI_uniquename_cb( | ||||
| unique_identifier_check, lb, "socket", '.', auto_identifier, sizeof(auto_identifier)); | unique_identifier_check, lb, "socket", '.', auto_identifier, sizeof(auto_identifier)); | ||||
| bNodeSocket *sock = MEM_callocN(sizeof(bNodeSocket), "sock"); | bNodeSocket *sock = (bNodeSocket *)MEM_callocN(sizeof(bNodeSocket), "sock"); | ||||
| sock->in_out = in_out; | sock->in_out = in_out; | ||||
| BLI_strncpy(sock->identifier, auto_identifier, NODE_MAXSTR); | BLI_strncpy(sock->identifier, auto_identifier, NODE_MAXSTR); | ||||
| sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF); | sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF); | ||||
| BLI_strncpy(sock->name, name, NODE_MAXSTR); | BLI_strncpy(sock->name, name, NODE_MAXSTR); | ||||
| sock->storage = NULL; | sock->storage = nullptr; | ||||
| sock->flag |= SOCK_COLLAPSED; | sock->flag |= SOCK_COLLAPSED; | ||||
| sock->type = SOCK_CUSTOM; /* int type undefined by default */ | sock->type = SOCK_CUSTOM; /* int type undefined by default */ | ||||
| BLI_strncpy(sock->idname, idname, sizeof(sock->idname)); | BLI_strncpy(sock->idname, idname, sizeof(sock->idname)); | ||||
| node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(idname)); | node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(idname)); | ||||
| return sock; | return sock; | ||||
| } | } | ||||
| static void socket_id_user_increment(bNodeSocket *sock) | static void socket_id_user_increment(bNodeSocket *sock) | ||||
| { | { | ||||
| switch ((eNodeSocketDatatype)sock->type) { | switch ((eNodeSocketDatatype)sock->type) { | ||||
| case SOCK_OBJECT: { | case SOCK_OBJECT: { | ||||
| bNodeSocketValueObject *default_value = sock->default_value; | bNodeSocketValueObject *default_value = (bNodeSocketValueObject *)sock->default_value; | ||||
| id_us_plus((ID *)default_value->value); | id_us_plus((ID *)default_value->value); | ||||
| break; | break; | ||||
| } | } | ||||
| case SOCK_IMAGE: { | case SOCK_IMAGE: { | ||||
| bNodeSocketValueImage *default_value = sock->default_value; | bNodeSocketValueImage *default_value = (bNodeSocketValueImage *)sock->default_value; | ||||
| id_us_plus((ID *)default_value->value); | id_us_plus((ID *)default_value->value); | ||||
| break; | break; | ||||
| } | } | ||||
| case SOCK_COLLECTION: { | case SOCK_COLLECTION: { | ||||
| bNodeSocketValueCollection *default_value = sock->default_value; | bNodeSocketValueCollection *default_value = (bNodeSocketValueCollection *) | ||||
| sock->default_value; | |||||
| id_us_plus((ID *)default_value->value); | id_us_plus((ID *)default_value->value); | ||||
| break; | break; | ||||
| } | } | ||||
| case SOCK_FLOAT: | case SOCK_FLOAT: | ||||
| case SOCK_VECTOR: | case SOCK_VECTOR: | ||||
| case SOCK_RGBA: | case SOCK_RGBA: | ||||
| case SOCK_BOOLEAN: | case SOCK_BOOLEAN: | ||||
| case SOCK_INT: | case SOCK_INT: | ||||
| case SOCK_STRING: | case SOCK_STRING: | ||||
| case __SOCK_MESH: | case __SOCK_MESH: | ||||
| case SOCK_CUSTOM: | case SOCK_CUSTOM: | ||||
| case SOCK_SHADER: | case SOCK_SHADER: | ||||
| case SOCK_GEOMETRY: | case SOCK_GEOMETRY: | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| static void socket_id_user_decrement(bNodeSocket *sock) | static void socket_id_user_decrement(bNodeSocket *sock) | ||||
| { | { | ||||
| switch ((eNodeSocketDatatype)sock->type) { | switch ((eNodeSocketDatatype)sock->type) { | ||||
| case SOCK_OBJECT: { | case SOCK_OBJECT: { | ||||
| bNodeSocketValueObject *default_value = sock->default_value; | bNodeSocketValueObject *default_value = (bNodeSocketValueObject *)sock->default_value; | ||||
| id_us_min(&default_value->value->id); | id_us_min(&default_value->value->id); | ||||
| break; | break; | ||||
| } | } | ||||
| case SOCK_IMAGE: { | case SOCK_IMAGE: { | ||||
| bNodeSocketValueImage *default_value = sock->default_value; | bNodeSocketValueImage *default_value = (bNodeSocketValueImage *)sock->default_value; | ||||
| id_us_min(&default_value->value->id); | id_us_min(&default_value->value->id); | ||||
| break; | break; | ||||
| } | } | ||||
| case SOCK_COLLECTION: { | case SOCK_COLLECTION: { | ||||
| bNodeSocketValueCollection *default_value = sock->default_value; | bNodeSocketValueCollection *default_value = (bNodeSocketValueCollection *) | ||||
| sock->default_value; | |||||
| id_us_min(&default_value->value->id); | id_us_min(&default_value->value->id); | ||||
| break; | break; | ||||
| } | } | ||||
| case SOCK_FLOAT: | case SOCK_FLOAT: | ||||
| case SOCK_VECTOR: | case SOCK_VECTOR: | ||||
| case SOCK_RGBA: | case SOCK_RGBA: | ||||
| case SOCK_BOOLEAN: | case SOCK_BOOLEAN: | ||||
| case SOCK_INT: | case SOCK_INT: | ||||
| Show All 14 Lines | void nodeModifySocketType( | ||||
| if (!idname) { | if (!idname) { | ||||
| CLOG_ERROR(&LOG, "static node socket type %d undefined", type); | CLOG_ERROR(&LOG, "static node socket type %d undefined", type); | ||||
| return; | return; | ||||
| } | } | ||||
| if (sock->default_value) { | if (sock->default_value) { | ||||
| socket_id_user_decrement(sock); | socket_id_user_decrement(sock); | ||||
| MEM_freeN(sock->default_value); | MEM_freeN(sock->default_value); | ||||
| sock->default_value = NULL; | sock->default_value = nullptr; | ||||
| } | } | ||||
| sock->type = type; | sock->type = type; | ||||
| BLI_strncpy(sock->idname, idname, sizeof(sock->idname)); | BLI_strncpy(sock->idname, idname, sizeof(sock->idname)); | ||||
| node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(idname)); | node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(idname)); | ||||
| } | } | ||||
| bNodeSocket *nodeAddSocket(bNodeTree *ntree, | bNodeSocket *nodeAddSocket(bNodeTree *ntree, | ||||
| ▲ Show 20 Lines • Show All 98 Lines • ▼ Show 20 Lines | case SOCK_OBJECT: | ||||
| return "NodeSocketObject"; | return "NodeSocketObject"; | ||||
| case SOCK_IMAGE: | case SOCK_IMAGE: | ||||
| return "NodeSocketImage"; | return "NodeSocketImage"; | ||||
| case SOCK_GEOMETRY: | case SOCK_GEOMETRY: | ||||
| return "NodeSocketGeometry"; | return "NodeSocketGeometry"; | ||||
| case SOCK_COLLECTION: | case SOCK_COLLECTION: | ||||
| return "NodeSocketCollection"; | return "NodeSocketCollection"; | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| const char *nodeStaticSocketInterfaceType(int type, int subtype) | const char *nodeStaticSocketInterfaceType(int type, int subtype) | ||||
| { | { | ||||
| switch (type) { | switch (type) { | ||||
| case SOCK_FLOAT: | case SOCK_FLOAT: | ||||
| switch (subtype) { | switch (subtype) { | ||||
| case PROP_UNSIGNED: | case PROP_UNSIGNED: | ||||
| ▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | case SOCK_OBJECT: | ||||
| return "NodeSocketInterfaceObject"; | return "NodeSocketInterfaceObject"; | ||||
| case SOCK_IMAGE: | case SOCK_IMAGE: | ||||
| return "NodeSocketInterfaceImage"; | return "NodeSocketInterfaceImage"; | ||||
| case SOCK_GEOMETRY: | case SOCK_GEOMETRY: | ||||
| return "NodeSocketInterfaceGeometry"; | return "NodeSocketInterfaceGeometry"; | ||||
| case SOCK_COLLECTION: | case SOCK_COLLECTION: | ||||
| return "NodeSocketInterfaceCollection"; | return "NodeSocketInterfaceCollection"; | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| bNodeSocket *nodeAddStaticSocket(bNodeTree *ntree, | bNodeSocket *nodeAddStaticSocket(bNodeTree *ntree, | ||||
| bNode *node, | bNode *node, | ||||
| int in_out, | int in_out, | ||||
| int type, | int type, | ||||
| int subtype, | int subtype, | ||||
| const char *identifier, | const char *identifier, | ||||
| const char *name) | const char *name) | ||||
| { | { | ||||
| const char *idname = nodeStaticSocketType(type, subtype); | const char *idname = nodeStaticSocketType(type, subtype); | ||||
| if (!idname) { | if (!idname) { | ||||
| CLOG_ERROR(&LOG, "static node socket type %d undefined", type); | CLOG_ERROR(&LOG, "static node socket type %d undefined", type); | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| bNodeSocket *sock = nodeAddSocket(ntree, node, in_out, idname, identifier, name); | bNodeSocket *sock = nodeAddSocket(ntree, node, in_out, idname, identifier, name); | ||||
| sock->type = type; | sock->type = type; | ||||
| return sock; | return sock; | ||||
| } | } | ||||
| bNodeSocket *nodeInsertStaticSocket(bNodeTree *ntree, | bNodeSocket *nodeInsertStaticSocket(bNodeTree *ntree, | ||||
| bNode *node, | bNode *node, | ||||
| int in_out, | int in_out, | ||||
| int type, | int type, | ||||
| int subtype, | int subtype, | ||||
| bNodeSocket *next_sock, | bNodeSocket *next_sock, | ||||
| const char *identifier, | const char *identifier, | ||||
| const char *name) | const char *name) | ||||
| { | { | ||||
| const char *idname = nodeStaticSocketType(type, subtype); | const char *idname = nodeStaticSocketType(type, subtype); | ||||
| if (!idname) { | if (!idname) { | ||||
| CLOG_ERROR(&LOG, "static node socket type %d undefined", type); | CLOG_ERROR(&LOG, "static node socket type %d undefined", type); | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| bNodeSocket *sock = nodeInsertSocket(ntree, node, in_out, idname, next_sock, identifier, name); | bNodeSocket *sock = nodeInsertSocket(ntree, node, in_out, idname, next_sock, identifier, name); | ||||
| sock->type = type; | sock->type = type; | ||||
| return sock; | return sock; | ||||
| } | } | ||||
| static void node_socket_free(bNodeTree *UNUSED(ntree), | static void node_socket_free(bNodeTree *UNUSED(ntree), | ||||
| ▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node) | ||||
| BLI_listbase_clear(&node->outputs); | BLI_listbase_clear(&node->outputs); | ||||
| node->update |= NODE_UPDATE; | node->update |= NODE_UPDATE; | ||||
| } | } | ||||
| /* finds a node based on its name */ | /* finds a node based on its name */ | ||||
| bNode *nodeFindNodebyName(bNodeTree *ntree, const char *name) | bNode *nodeFindNodebyName(bNodeTree *ntree, const char *name) | ||||
| { | { | ||||
| return BLI_findstring(&ntree->nodes, name, offsetof(bNode, name)); | return (bNode *)BLI_findstring(&ntree->nodes, name, offsetof(bNode, name)); | ||||
| } | } | ||||
| /* Finds a node based on given socket and returns true on success. */ | /* Finds a node based on given socket and returns true on success. */ | ||||
| bool nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_sockindex) | bool nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_sockindex) | ||||
| { | { | ||||
| *r_node = NULL; | *r_node = nullptr; | ||||
| LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| ListBase *sockets = (sock->in_out == SOCK_IN) ? &node->inputs : &node->outputs; | ListBase *sockets = (sock->in_out == SOCK_IN) ? &node->inputs : &node->outputs; | ||||
| int index = 0; | int index = 0; | ||||
| LISTBASE_FOREACH (bNodeSocket *, tsock, sockets) { | LISTBASE_FOREACH (bNodeSocket *, tsock, sockets) { | ||||
| if (sock == tsock) { | if (sock == tsock) { | ||||
| if (r_node != NULL) { | if (r_node != nullptr) { | ||||
| *r_node = node; | *r_node = node; | ||||
| } | } | ||||
| if (r_sockindex != NULL) { | if (r_sockindex != nullptr) { | ||||
| *r_sockindex = index; | *r_sockindex = index; | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| index++; | index++; | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| /** | /** | ||||
| * \note Recursive | * \note Recursive | ||||
| */ | */ | ||||
| bNode *nodeFindRootParent(bNode *node) | bNode *nodeFindRootParent(bNode *node) | ||||
| { | { | ||||
| if (node->parent) { | if (node->parent) { | ||||
| return nodeFindRootParent(node->parent); | return nodeFindRootParent(node->parent); | ||||
| } | } | ||||
| return node->type == NODE_FRAME ? node : NULL; | return node->type == NODE_FRAME ? node : nullptr; | ||||
| } | } | ||||
| /** | /** | ||||
| * \returns true if \a child has \a parent as a parent/grandparent/... | * \returns true if \a child has \a parent as a parent/grandparent/... | ||||
| * \note Recursive | * \note Recursive | ||||
| */ | */ | ||||
| bool nodeIsChildOf(const bNode *parent, const bNode *child) | bool nodeIsChildOf(const bNode *parent, const bNode *child) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | |||||
| static void iter_backwards_ex(const bNodeTree *ntree, | static void iter_backwards_ex(const bNodeTree *ntree, | ||||
| const bNode *node_start, | const bNode *node_start, | ||||
| bool (*callback)(bNode *, bNode *, void *), | bool (*callback)(bNode *, bNode *, void *), | ||||
| void *userdata, | void *userdata, | ||||
| char recursion_mask) | char recursion_mask) | ||||
| { | { | ||||
| LISTBASE_FOREACH (bNodeSocket *, sock, &node_start->inputs) { | LISTBASE_FOREACH (bNodeSocket *, sock, &node_start->inputs) { | ||||
| bNodeLink *link = sock->link; | bNodeLink *link = sock->link; | ||||
| if (link == NULL) { | if (link == nullptr) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if ((link->flag & NODE_LINK_VALID) == 0) { | if ((link->flag & NODE_LINK_VALID) == 0) { | ||||
| /* Skip links marked as cyclic. */ | /* Skip links marked as cyclic. */ | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (link->fromnode->iter_flag & recursion_mask) { | if (link->fromnode->iter_flag & recursion_mask) { | ||||
| continue; | continue; | ||||
| ▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | |||||
| void nodeUniqueName(bNodeTree *ntree, bNode *node) | void nodeUniqueName(bNodeTree *ntree, bNode *node) | ||||
| { | { | ||||
| BLI_uniquename( | BLI_uniquename( | ||||
| &ntree->nodes, node, DATA_("Node"), '.', offsetof(bNode, name), sizeof(node->name)); | &ntree->nodes, node, DATA_("Node"), '.', offsetof(bNode, name), sizeof(node->name)); | ||||
| } | } | ||||
| bNode *nodeAddNode(const struct bContext *C, bNodeTree *ntree, const char *idname) | bNode *nodeAddNode(const struct bContext *C, bNodeTree *ntree, const char *idname) | ||||
| { | { | ||||
| bNode *node = MEM_callocN(sizeof(bNode), "new node"); | bNode *node = (bNode *)MEM_callocN(sizeof(bNode), "new node"); | ||||
| BLI_addtail(&ntree->nodes, node); | BLI_addtail(&ntree->nodes, node); | ||||
| BLI_strncpy(node->idname, idname, sizeof(node->idname)); | BLI_strncpy(node->idname, idname, sizeof(node->idname)); | ||||
| node_set_typeinfo(C, ntree, node, nodeTypeFind(idname)); | node_set_typeinfo(C, ntree, node, nodeTypeFind(idname)); | ||||
| ntree->update |= NTREE_UPDATE_NODES; | ntree->update |= NTREE_UPDATE_NODES; | ||||
| return node; | return node; | ||||
| } | } | ||||
| bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type) | bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type) | ||||
| { | { | ||||
| const char *idname = NULL; | const char *idname = nullptr; | ||||
| NODE_TYPES_BEGIN (ntype) { | NODE_TYPES_BEGIN (ntype) { | ||||
| /* do an extra poll here, because some int types are used | /* do an extra poll here, because some int types are used | ||||
| * for multiple node types, this helps find the desired type | * for multiple node types, this helps find the desired type | ||||
| */ | */ | ||||
| if (ntype->type == type && (!ntype->poll || ntype->poll(ntype, ntree))) { | if (ntype->type == type && (!ntype->poll || ntype->poll(ntype, ntree))) { | ||||
| idname = ntype->idname; | idname = ntype->idname; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| 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 nullptr; | ||||
| } | } | ||||
| return nodeAddNode(C, ntree, idname); | return nodeAddNode(C, ntree, idname); | ||||
| } | } | ||||
| static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src, const int flag) | static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src, const int flag) | ||||
| { | { | ||||
| 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); | ||||
| if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { | if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { | ||||
| socket_id_user_increment(sock_dst); | socket_id_user_increment(sock_dst); | ||||
| } | } | ||||
| } | } | ||||
| 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 = nullptr; | ||||
| } | } | ||||
| /* keep socket listorder identical, for copying links */ | /* keep socket listorder identical, for copying links */ | ||||
| /* ntree is the target tree */ | /* ntree is the target tree */ | ||||
| /* unique_name needs to be true. It's only disabled for speed when doing GPUnodetrees. */ | /* unique_name needs to be true. It's only disabled for speed when doing GPUnodetrees. */ | ||||
| bNode *BKE_node_copy_ex(bNodeTree *ntree, | bNode *BKE_node_copy_ex(bNodeTree *ntree, | ||||
| const bNode *node_src, | const bNode *node_src, | ||||
| const int flag, | const int flag, | ||||
| const bool unique_name) | const bool unique_name) | ||||
| { | { | ||||
| bNode *node_dst = MEM_callocN(sizeof(bNode), "dupli node"); | bNode *node_dst = (bNode *)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) { | ||||
| if (unique_name) { | if (unique_name) { | ||||
| nodeUniqueName(ntree, node_dst); | nodeUniqueName(ntree, node_dst); | ||||
| } | } | ||||
| BLI_addtail(&ntree->nodes, node_dst); | BLI_addtail(&ntree->nodes, node_dst); | ||||
| } | } | ||||
| BLI_duplicatelist(&node_dst->inputs, &node_src->inputs); | BLI_duplicatelist(&node_dst->inputs, &node_src->inputs); | ||||
| for (sock_dst = node_dst->inputs.first, sock_src = node_src->inputs.first; sock_dst != NULL; | for (sock_dst = (bNodeSocket *)node_dst->inputs.first, | ||||
| sock_dst = sock_dst->next, sock_src = sock_src->next) { | sock_src = (bNodeSocket *)node_src->inputs.first; | ||||
| sock_dst != nullptr; | |||||
| sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) { | |||||
| node_socket_copy(sock_dst, sock_src, flag); | node_socket_copy(sock_dst, sock_src, flag); | ||||
| } | } | ||||
| BLI_duplicatelist(&node_dst->outputs, &node_src->outputs); | BLI_duplicatelist(&node_dst->outputs, &node_src->outputs); | ||||
| for (sock_dst = node_dst->outputs.first, sock_src = node_src->outputs.first; sock_dst != NULL; | for (sock_dst = (bNodeSocket *)node_dst->outputs.first, | ||||
| sock_dst = sock_dst->next, sock_src = sock_src->next) { | sock_src = (bNodeSocket *)node_src->outputs.first; | ||||
| sock_dst != nullptr; | |||||
| sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) { | |||||
| node_socket_copy(sock_dst, sock_src, flag); | node_socket_copy(sock_dst, sock_src, 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 = (bNodeLink *)node_dst->internal_links.first, | ||||
| link_dst != NULL; | link_src = (bNodeLink *)node_src->internal_links.first; | ||||
| link_dst = link_dst->next, link_src = link_src->next) { | link_dst != nullptr; | ||||
| link_dst = (bNodeLink *)link_dst->next, link_src = (bNodeLink *)link_src->next) { | |||||
| /* This is a bit annoying to do index lookups in a list, but is likely to be faster than | /* 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 | * trying to create a hash-map. At least for usual nodes, which only have so much sockets | ||||
| * and internal links. */ | * and internal links. */ | ||||
| const int from_sock_index = BLI_findindex(&node_src->inputs, link_src->fromsock); | 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); | const int to_sock_index = BLI_findindex(&node_src->outputs, link_src->tosock); | ||||
| BLI_assert(from_sock_index != -1); | BLI_assert(from_sock_index != -1); | ||||
| BLI_assert(to_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 = BLI_findlink(&node_dst->inputs, from_sock_index); | link_dst->fromsock = (bNodeSocket *)BLI_findlink(&node_dst->inputs, from_sock_index); | ||||
| link_dst->tosock = BLI_findlink(&node_dst->outputs, to_sock_index); | link_dst->tosock = (bNodeSocket *)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_dst->new_node = NULL; | node_dst->new_node = nullptr; | ||||
| /* Only call copy function when a copy is made for the main database, not | /* Only call copy function when a copy is made for the main database, not | ||||
| * for cases like the dependency graph and localization. */ | * for cases like the dependency graph and localization. */ | ||||
| if (node_dst->typeinfo->copyfunc_api && !(flag & LIB_ID_CREATE_NO_MAIN)) { | if (node_dst->typeinfo->copyfunc_api && !(flag & LIB_ID_CREATE_NO_MAIN)) { | ||||
| 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; | ||||
| } | } | ||||
| static void node_set_new_pointers(bNode *node_src, bNode *new_node) | static void node_set_new_pointers(bNode *node_src, bNode *new_node) | ||||
| { | { | ||||
| /* Store mapping to the node itself. */ | /* Store mapping to the node itself. */ | ||||
| node_src->new_node = new_node; | node_src->new_node = new_node; | ||||
| /* Store mapping to inputs. */ | /* Store mapping to inputs. */ | ||||
| bNodeSocket *new_input_sock = new_node->inputs.first; | bNodeSocket *new_input_sock = (bNodeSocket *)new_node->inputs.first; | ||||
| bNodeSocket *input_sock_src = node_src->inputs.first; | bNodeSocket *input_sock_src = (bNodeSocket *)node_src->inputs.first; | ||||
| while (new_input_sock != NULL) { | while (new_input_sock != nullptr) { | ||||
| input_sock_src->new_sock = new_input_sock; | input_sock_src->new_sock = new_input_sock; | ||||
| new_input_sock = new_input_sock->next; | new_input_sock = new_input_sock->next; | ||||
| input_sock_src = input_sock_src->next; | input_sock_src = input_sock_src->next; | ||||
| } | } | ||||
| /* Store mapping to outputs. */ | /* Store mapping to outputs. */ | ||||
| bNodeSocket *new_output_sock = new_node->outputs.first; | bNodeSocket *new_output_sock = (bNodeSocket *)new_node->outputs.first; | ||||
| bNodeSocket *output_sock_src = node_src->outputs.first; | bNodeSocket *output_sock_src = (bNodeSocket *)node_src->outputs.first; | ||||
| while (new_output_sock != NULL) { | while (new_output_sock != nullptr) { | ||||
| output_sock_src->new_sock = new_output_sock; | output_sock_src->new_sock = new_output_sock; | ||||
| new_output_sock = new_output_sock->next; | new_output_sock = new_output_sock->next; | ||||
| output_sock_src = output_sock_src->next; | output_sock_src = output_sock_src->next; | ||||
| } | } | ||||
| } | } | ||||
| bNode *BKE_node_copy_store_new_pointers(bNodeTree *ntree, bNode *node_src, const int flag) | 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, true); | bNode *new_node = BKE_node_copy_ex(ntree, node_src, flag, true); | ||||
| node_set_new_pointers(node_src, new_node); | node_set_new_pointers(node_src, new_node); | ||||
| return new_node; | return new_node; | ||||
| } | } | ||||
| bNodeTree *ntreeCopyTree_ex_new_pointers(const bNodeTree *ntree, | bNodeTree *ntreeCopyTree_ex_new_pointers(const bNodeTree *ntree, | ||||
| Main *bmain, | Main *bmain, | ||||
| const bool do_id_user) | const bool do_id_user) | ||||
| { | { | ||||
| bNodeTree *new_ntree = ntreeCopyTree_ex(ntree, bmain, do_id_user); | bNodeTree *new_ntree = ntreeCopyTree_ex(ntree, bmain, do_id_user); | ||||
| bNode *new_node = new_ntree->nodes.first; | bNode *new_node = (bNode *)new_ntree->nodes.first; | ||||
| bNode *node_src = ntree->nodes.first; | bNode *node_src = (bNode *)ntree->nodes.first; | ||||
| while (new_node != NULL) { | while (new_node != nullptr) { | ||||
| node_set_new_pointers(node_src, new_node); | node_set_new_pointers(node_src, new_node); | ||||
| new_node = new_node->next; | new_node = new_node->next; | ||||
| node_src = node_src->next; | node_src = node_src->next; | ||||
| } | } | ||||
| return new_ntree; | return new_ntree; | ||||
| } | } | ||||
| /* 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 = nullptr; | ||||
| /* test valid input */ | /* test valid input */ | ||||
| BLI_assert(fromnode); | BLI_assert(fromnode); | ||||
| BLI_assert(tonode); | BLI_assert(tonode); | ||||
| if (fromsock->in_out == SOCK_OUT && tosock->in_out == SOCK_IN) { | if (fromsock->in_out == SOCK_OUT && tosock->in_out == SOCK_IN) { | ||||
| link = MEM_callocN(sizeof(bNodeLink), "link"); | link = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "link"); | ||||
| if (ntree) { | if (ntree) { | ||||
| BLI_addtail(&ntree->links, link); | BLI_addtail(&ntree->links, link); | ||||
| } | } | ||||
| link->fromnode = fromnode; | link->fromnode = fromnode; | ||||
| link->fromsock = fromsock; | link->fromsock = fromsock; | ||||
| link->tonode = tonode; | link->tonode = tonode; | ||||
| link->tosock = tosock; | link->tosock = tosock; | ||||
| } | } | ||||
| else if (fromsock->in_out == SOCK_IN && tosock->in_out == SOCK_OUT) { | else if (fromsock->in_out == SOCK_IN && tosock->in_out == SOCK_OUT) { | ||||
| /* OK but flip */ | /* OK but flip */ | ||||
| link = MEM_callocN(sizeof(bNodeLink), "link"); | link = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "link"); | ||||
| if (ntree) { | if (ntree) { | ||||
| BLI_addtail(&ntree->links, link); | BLI_addtail(&ntree->links, link); | ||||
| } | } | ||||
| link->fromnode = tonode; | link->fromnode = tonode; | ||||
| link->fromsock = tosock; | link->fromsock = tosock; | ||||
| link->tonode = fromnode; | link->tonode = fromnode; | ||||
| link->tosock = fromsock; | link->tosock = fromsock; | ||||
| } | } | ||||
| if (ntree) { | if (ntree) { | ||||
| ntree->update |= NTREE_UPDATE_LINKS; | ntree->update |= NTREE_UPDATE_LINKS; | ||||
| } | } | ||||
| return link; | return link; | ||||
| } | } | ||||
| void nodeRemLink(bNodeTree *ntree, bNodeLink *link) | void nodeRemLink(bNodeTree *ntree, bNodeLink *link) | ||||
| { | { | ||||
| /* can be called for links outside a node tree (e.g. clipboard) */ | /* can be called for links outside a node tree (e.g. clipboard) */ | ||||
| if (ntree) { | if (ntree) { | ||||
| BLI_remlink(&ntree->links, link); | BLI_remlink(&ntree->links, link); | ||||
| } | } | ||||
| if (link->tosock) { | if (link->tosock) { | ||||
| link->tosock->link = NULL; | link->tosock->link = nullptr; | ||||
| } | } | ||||
| MEM_freeN(link); | MEM_freeN(link); | ||||
| if (ntree) { | if (ntree) { | ||||
| ntree->update |= NTREE_UPDATE_LINKS; | ntree->update |= NTREE_UPDATE_LINKS; | ||||
| } | } | ||||
| } | } | ||||
| void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock) | void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock) | ||||
| { | { | ||||
| bNodeLink *link, *next; | LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) { | ||||
| for (link = ntree->links.first; link; link = next) { | |||||
| next = link->next; | |||||
| if (link->fromsock == sock || link->tosock == sock) { | if (link->fromsock == sock || link->tosock == sock) { | ||||
| nodeRemLink(ntree, link); | nodeRemLink(ntree, link); | ||||
| } | } | ||||
| } | } | ||||
| ntree->update |= NTREE_UPDATE_LINKS; | ntree->update |= NTREE_UPDATE_LINKS; | ||||
| } | } | ||||
| bool nodeLinkIsHidden(bNodeLink *link) | bool nodeLinkIsHidden(const bNodeLink *link) | ||||
| { | { | ||||
| return nodeSocketIsHidden(link->fromsock) || nodeSocketIsHidden(link->tosock); | return nodeSocketIsHidden(link->fromsock) || nodeSocketIsHidden(link->tosock); | ||||
| } | } | ||||
| void nodeInternalRelink(bNodeTree *ntree, bNode *node) | void nodeInternalRelink(bNodeTree *ntree, bNode *node) | ||||
| { | { | ||||
| /* store link pointers in output sockets, for efficient lookup */ | /* store link pointers in output sockets, for efficient lookup */ | ||||
| LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) { | LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) { | ||||
| Show All 34 Lines | void nodeInternalRelink(bNodeTree *ntree, bNode *node) | ||||
| /* remove remaining upstream links */ | /* remove remaining upstream links */ | ||||
| LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) { | LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) { | ||||
| if (link->tonode == node) { | if (link->tonode == node) { | ||||
| nodeRemLink(ntree, link); | nodeRemLink(ntree, link); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void nodeToView(bNode *node, float x, float y, float *rx, float *ry) | void nodeToView(const bNode *node, float x, float y, float *rx, float *ry) | ||||
| { | { | ||||
| if (node->parent) { | if (node->parent) { | ||||
| nodeToView(node->parent, x + node->locx, y + node->locy, rx, ry); | nodeToView(node->parent, x + node->locx, y + node->locy, rx, ry); | ||||
| } | } | ||||
| else { | else { | ||||
| *rx = x + node->locx; | *rx = x + node->locx; | ||||
| *ry = y + node->locy; | *ry = y + node->locy; | ||||
| } | } | ||||
| } | } | ||||
| void nodeFromView(bNode *node, float x, float y, float *rx, float *ry) | void nodeFromView(const bNode *node, float x, float y, float *rx, float *ry) | ||||
| { | { | ||||
| if (node->parent) { | if (node->parent) { | ||||
| nodeFromView(node->parent, x, y, rx, ry); | nodeFromView(node->parent, x, y, rx, ry); | ||||
| *rx -= node->locx; | *rx -= node->locx; | ||||
| *ry -= node->locy; | *ry -= node->locy; | ||||
| } | } | ||||
| else { | else { | ||||
| *rx = x - node->locx; | *rx = x - node->locx; | ||||
| *ry = y - node->locy; | *ry = y - node->locy; | ||||
| } | } | ||||
| } | } | ||||
| bool nodeAttachNodeCheck(bNode *node, bNode *parent) | bool nodeAttachNodeCheck(const bNode *node, const bNode *parent) | ||||
| { | { | ||||
| for (bNode *parent_recurse = node; parent_recurse; parent_recurse = parent_recurse->parent) { | for (const bNode *parent_iter = node; parent_iter; parent_iter = parent_iter->parent) { | ||||
| if (parent_recurse == parent) { | if (parent_iter == parent) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void nodeAttachNode(bNode *node, bNode *parent) | void nodeAttachNode(bNode *node, bNode *parent) | ||||
| Show All 14 Lines | void nodeDetachNode(struct bNode *node) | ||||
| if (node->parent) { | if (node->parent) { | ||||
| BLI_assert(node->parent->type == NODE_FRAME); | BLI_assert(node->parent->type == NODE_FRAME); | ||||
| /* transform to view space */ | /* transform to view space */ | ||||
| float locx, locy; | float locx, locy; | ||||
| nodeToView(node, 0.0f, 0.0f, &locx, &locy); | nodeToView(node, 0.0f, 0.0f, &locx, &locy); | ||||
| node->locx = locx; | node->locx = locx; | ||||
| node->locy = locy; | node->locy = locy; | ||||
| node->parent = NULL; | node->parent = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| void nodePositionRelative(bNode *from_node, | void nodePositionRelative(bNode *from_node, | ||||
| bNode *to_node, | bNode *to_node, | ||||
| bNodeSocket *from_sock, | bNodeSocket *from_sock, | ||||
| bNodeSocket *to_sock) | bNodeSocket *to_sock) | ||||
| { | { | ||||
| Show All 32 Lines | void nodePositionRelative(bNode *from_node, | ||||
| from_node->locx = to_node->locx + offset_x; | from_node->locx = to_node->locx + offset_x; | ||||
| from_node->locy = to_node->locy - offset_y; | from_node->locy = to_node->locy - offset_y; | ||||
| } | } | ||||
| void nodePositionPropagate(bNode *node) | void nodePositionPropagate(bNode *node) | ||||
| { | { | ||||
| LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) { | LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) { | ||||
| if (nsock->link != NULL) { | if (nsock->link != nullptr) { | ||||
| bNodeLink *link = nsock->link; | bNodeLink *link = nsock->link; | ||||
| nodePositionRelative(link->fromnode, link->tonode, link->fromsock, link->tosock); | nodePositionRelative(link->fromnode, link->tonode, link->fromsock, link->tosock); | ||||
| nodePositionPropagate(link->fromnode); | nodePositionPropagate(link->fromnode); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname) | bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname) | ||||
| { | { | ||||
| bNodeTree *ntree; | |||||
| /* trees are created as local trees for compositor, material or texture nodes, | /* trees are created as local trees for compositor, material or texture nodes, | ||||
| * node groups and other tree types are created as library data. | * node groups and other tree types are created as library data. | ||||
| */ | */ | ||||
| const bool is_embedded = (bmain == NULL); | const bool is_embedded = (bmain == nullptr); | ||||
| int flag = 0; | int flag = 0; | ||||
| if (is_embedded) { | if (is_embedded) { | ||||
| flag |= LIB_ID_CREATE_NO_MAIN; | flag |= LIB_ID_CREATE_NO_MAIN; | ||||
| } | } | ||||
| ntree = BKE_libblock_alloc(bmain, ID_NT, name, flag); | bNodeTree *ntree = (bNodeTree *)BKE_libblock_alloc(bmain, ID_NT, name, flag); | ||||
| if (is_embedded) { | if (is_embedded) { | ||||
| ntree->id.flag |= LIB_EMBEDDED_DATA; | ntree->id.flag |= LIB_EMBEDDED_DATA; | ||||
| } | } | ||||
| /* Types are fully initialized at this point, | /* Types are fully initialized at this point, | ||||
| * if an undefined node is added later this will be reset. | * if an undefined node is added later this will be reset. | ||||
| */ | */ | ||||
| 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; | ||||
| } | } | ||||
| 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) | ||||
| { | { | ||||
| const int flag = do_id_user ? 0 : LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN; | const int flag = do_id_user ? 0 : LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN; | ||||
| bNodeTree *ntree_copy = (bNodeTree *)BKE_id_copy_ex(bmain, (ID *)ntree, NULL, flag); | bNodeTree *ntree_copy = (bNodeTree *)BKE_id_copy_ex(bmain, (ID *)ntree, nullptr, flag); | ||||
| return ntree_copy; | 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); | ||||
| } | } | ||||
| /* *************** Node Preview *********** */ | /* *************** Node Preview *********** */ | ||||
| /* XXX this should be removed eventually ... | /* XXX this should be removed eventually ... | ||||
| * Currently BKE functions are modeled closely on previous code, | * Currently BKE functions are modeled closely on previous code, | ||||
| * using BKE_node_preview_init_tree to set up previews for a whole node tree in advance. | * 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. | * This should be left more to the individual node tree implementations. | ||||
| */ | */ | ||||
| int BKE_node_preview_used(bNode *node) | bool BKE_node_preview_used(const bNode *node) | ||||
| { | { | ||||
| /* XXX check for closed nodes? */ | /* XXX check for closed nodes? */ | ||||
| return (node->typeinfo->flag & NODE_PREVIEW) != 0; | return (node->typeinfo->flag & NODE_PREVIEW) != 0; | ||||
| } | } | ||||
| bNodePreview *BKE_node_preview_verify( | bNodePreview *BKE_node_preview_verify( | ||||
| bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, bool create) | bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, bool create) | ||||
| { | { | ||||
| bNodePreview *preview = BKE_node_instance_hash_lookup(previews, key); | bNodePreview *preview = (bNodePreview *)BKE_node_instance_hash_lookup(previews, key); | ||||
| if (!preview) { | if (!preview) { | ||||
| if (create) { | if (create) { | ||||
| preview = MEM_callocN(sizeof(bNodePreview), "node preview"); | preview = (bNodePreview *)MEM_callocN(sizeof(bNodePreview), "node preview"); | ||||
| BKE_node_instance_hash_insert(previews, key, preview); | BKE_node_instance_hash_insert(previews, key, preview); | ||||
| } | } | ||||
| else { | else { | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| } | } | ||||
| /* node previews can get added with variable size this way */ | /* node previews can get added with variable size this way */ | ||||
| if (xsize == 0 || ysize == 0) { | if (xsize == 0 || ysize == 0) { | ||||
| return preview; | return preview; | ||||
| } | } | ||||
| /* sanity checks & initialize */ | /* sanity checks & initialize */ | ||||
| if (preview->rect) { | if (preview->rect) { | ||||
| if (preview->xsize != xsize || preview->ysize != ysize) { | if (preview->xsize != xsize || preview->ysize != ysize) { | ||||
| MEM_freeN(preview->rect); | MEM_freeN(preview->rect); | ||||
| preview->rect = NULL; | preview->rect = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| if (preview->rect == NULL) { | if (preview->rect == nullptr) { | ||||
| preview->rect = MEM_callocN(4 * xsize + xsize * ysize * sizeof(char[4]), "node preview rect"); | preview->rect = (unsigned char *)MEM_callocN(4 * xsize + xsize * ysize * sizeof(char[4]), | ||||
| "node preview rect"); | |||||
| preview->xsize = xsize; | preview->xsize = xsize; | ||||
| preview->ysize = ysize; | preview->ysize = ysize; | ||||
| } | } | ||||
| /* no clear, makes nicer previews */ | /* no clear, makes nicer previews */ | ||||
| return preview; | return preview; | ||||
| } | } | ||||
| bNodePreview *BKE_node_preview_copy(bNodePreview *preview) | bNodePreview *BKE_node_preview_copy(bNodePreview *preview) | ||||
| { | { | ||||
| bNodePreview *new_preview = MEM_dupallocN(preview); | bNodePreview *new_preview = (bNodePreview *)MEM_dupallocN(preview); | ||||
| if (preview->rect) { | if (preview->rect) { | ||||
| new_preview->rect = MEM_dupallocN(preview->rect); | new_preview->rect = (unsigned char *)MEM_dupallocN(preview->rect); | ||||
| } | } | ||||
| return new_preview; | return new_preview; | ||||
| } | } | ||||
| void BKE_node_preview_free(bNodePreview *preview) | void BKE_node_preview_free(bNodePreview *preview) | ||||
| { | { | ||||
| if (preview->rect) { | if (preview->rect) { | ||||
| MEM_freeN(preview->rect); | MEM_freeN(preview->rect); | ||||
| ▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | |||||
| void BKE_node_preview_free_tree(bNodeTree *ntree) | void BKE_node_preview_free_tree(bNodeTree *ntree) | ||||
| { | { | ||||
| if (!ntree) { | if (!ntree) { | ||||
| return; | return; | ||||
| } | } | ||||
| if (ntree->previews) { | if (ntree->previews) { | ||||
| BKE_node_instance_hash_free(ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free); | BKE_node_instance_hash_free(ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free); | ||||
| ntree->previews = NULL; | ntree->previews = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| void BKE_node_preview_clear(bNodePreview *preview) | void BKE_node_preview_clear(bNodePreview *preview) | ||||
| { | { | ||||
| if (preview && preview->rect) { | if (preview && preview->rect) { | ||||
| memset(preview->rect, 0, MEM_allocN_len(preview->rect)); | memset(preview->rect, 0, MEM_allocN_len(preview->rect)); | ||||
| } | } | ||||
| } | } | ||||
| void BKE_node_preview_clear_tree(bNodeTree *ntree) | void BKE_node_preview_clear_tree(bNodeTree *ntree) | ||||
| { | { | ||||
| if (!ntree || !ntree->previews) { | if (!ntree || !ntree->previews) { | ||||
| return; | return; | ||||
| } | } | ||||
| bNodeInstanceHashIterator iter; | bNodeInstanceHashIterator iter; | ||||
| NODE_INSTANCE_HASH_ITER (iter, ntree->previews) { | NODE_INSTANCE_HASH_ITER (iter, ntree->previews) { | ||||
| bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter); | bNodePreview *preview = (bNodePreview *)BKE_node_instance_hash_iterator_get_value(&iter); | ||||
| BKE_node_preview_clear(preview); | BKE_node_preview_clear(preview); | ||||
| } | } | ||||
| } | } | ||||
| static void node_preview_sync(bNodePreview *to, bNodePreview *from) | static void node_preview_sync(bNodePreview *to, bNodePreview *from) | ||||
| { | { | ||||
| /* sizes should have been initialized by BKE_node_preview_init_tree */ | /* sizes should have been initialized by BKE_node_preview_init_tree */ | ||||
| BLI_assert(to->xsize == from->xsize && to->ysize == from->ysize); | BLI_assert(to->xsize == from->xsize && to->ysize == from->ysize); | ||||
| Show All 13 Lines | void BKE_node_preview_sync_tree(bNodeTree *to_ntree, bNodeTree *from_ntree) | ||||
| if (!from_previews || !to_previews) { | if (!from_previews || !to_previews) { | ||||
| return; | return; | ||||
| } | } | ||||
| bNodeInstanceHashIterator iter; | bNodeInstanceHashIterator iter; | ||||
| NODE_INSTANCE_HASH_ITER (iter, from_previews) { | NODE_INSTANCE_HASH_ITER (iter, from_previews) { | ||||
| bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter); | bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter); | ||||
| bNodePreview *from = BKE_node_instance_hash_iterator_get_value(&iter); | bNodePreview *from = (bNodePreview *)BKE_node_instance_hash_iterator_get_value(&iter); | ||||
| bNodePreview *to = BKE_node_instance_hash_lookup(to_previews, key); | bNodePreview *to = (bNodePreview *)BKE_node_instance_hash_lookup(to_previews, key); | ||||
| if (from && to) { | if (from && to) { | ||||
| node_preview_sync(to, from); | node_preview_sync(to, from); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void BKE_node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree, bool remove_old) | void BKE_node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree, bool remove_old) | ||||
| { | { | ||||
| if (remove_old || !to_ntree->previews) { | if (remove_old || !to_ntree->previews) { | ||||
| /* free old previews */ | /* free old previews */ | ||||
| if (to_ntree->previews) { | if (to_ntree->previews) { | ||||
| BKE_node_instance_hash_free(to_ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free); | BKE_node_instance_hash_free(to_ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free); | ||||
| } | } | ||||
| /* transfer previews */ | /* transfer previews */ | ||||
| to_ntree->previews = from_ntree->previews; | to_ntree->previews = from_ntree->previews; | ||||
| from_ntree->previews = NULL; | from_ntree->previews = nullptr; | ||||
| /* clean up, in case any to_ntree nodes have been removed */ | /* clean up, in case any to_ntree nodes have been removed */ | ||||
| BKE_node_preview_remove_unused(to_ntree); | BKE_node_preview_remove_unused(to_ntree); | ||||
| } | } | ||||
| else { | else { | ||||
| if (from_ntree->previews) { | if (from_ntree->previews) { | ||||
| bNodeInstanceHashIterator iter; | bNodeInstanceHashIterator iter; | ||||
| NODE_INSTANCE_HASH_ITER (iter, from_ntree->previews) { | NODE_INSTANCE_HASH_ITER (iter, from_ntree->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 = (bNodePreview *)BKE_node_instance_hash_iterator_get_value(&iter); | ||||
| /* replace existing previews */ | /* replace existing previews */ | ||||
| BKE_node_instance_hash_remove( | BKE_node_instance_hash_remove( | ||||
| to_ntree->previews, key, (bNodeInstanceValueFP)BKE_node_preview_free); | to_ntree->previews, key, (bNodeInstanceValueFP)BKE_node_preview_free); | ||||
| BKE_node_instance_hash_insert(to_ntree->previews, key, preview); | BKE_node_instance_hash_insert(to_ntree->previews, key, preview); | ||||
| } | } | ||||
| /* Note: NULL free function here, | /* Note: null free function here, | ||||
| * because pointers have already been moved over to to_ntree->previews! */ | * because pointers have already been moved over to to_ntree->previews! */ | ||||
| BKE_node_instance_hash_free(from_ntree->previews, NULL); | BKE_node_instance_hash_free(from_ntree->previews, nullptr); | ||||
| from_ntree->previews = NULL; | from_ntree->previews = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* hack warning! this function is only used for shader previews, and | /* hack warning! this function is only used for shader previews, and | ||||
| * since it gets called multiple times per pixel for Ztransp we only | * since it gets called multiple times per pixel for Ztransp we only | ||||
| * add the color once. Preview gets cleared before it starts render though */ | * add the color once. Preview gets cleared before it starts render though */ | ||||
| void BKE_node_preview_set_pixel( | void BKE_node_preview_set_pixel( | ||||
| Show All 29 Lines | if (link->fromnode == node) { | ||||
| if (link->tonode) { | if (link->tonode) { | ||||
| link->tonode->update |= NODE_UPDATE; | link->tonode->update |= NODE_UPDATE; | ||||
| } | } | ||||
| } | } | ||||
| else if (link->tonode == node) { | else if (link->tonode == node) { | ||||
| lb = &node->inputs; | lb = &node->inputs; | ||||
| } | } | ||||
| else { | else { | ||||
| lb = NULL; | lb = nullptr; | ||||
| } | } | ||||
| if (lb) { | if (lb) { | ||||
| LISTBASE_FOREACH (bNodeSocket *, sock, lb) { | LISTBASE_FOREACH (bNodeSocket *, sock, lb) { | ||||
| if (link->fromsock == sock || link->tosock == sock) { | if (link->fromsock == sock || link->tosock == sock) { | ||||
| nodeRemLink(ntree, link); | nodeRemLink(ntree, link); | ||||
| break; | break; | ||||
| } | } | ||||
| Show All 27 Lines | if (ntree) { | ||||
| if (ntree->typeinfo->free_node_cache) { | if (ntree->typeinfo->free_node_cache) { | ||||
| ntree->typeinfo->free_node_cache(ntree, node); | ntree->typeinfo->free_node_cache(ntree, node); | ||||
| } | } | ||||
| /* texture node has bad habit of keeping exec data around */ | /* texture node has bad habit of keeping exec data around */ | ||||
| if (ntree->type == NTREE_TEXTURE && ntree->execdata) { | if (ntree->type == NTREE_TEXTURE && ntree->execdata) { | ||||
| ntreeTexEndExecTree(ntree->execdata); | ntreeTexEndExecTree(ntree->execdata); | ||||
| ntree->execdata = NULL; | ntree->execdata = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| if (node->typeinfo->freefunc) { | if (node->typeinfo->freefunc) { | ||||
| node->typeinfo->freefunc(node); | node->typeinfo->freefunc(node); | ||||
| } | } | ||||
| LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->inputs) { | LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->inputs) { | ||||
| ▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user) | ||||
| /* Remove animation data. */ | /* Remove animation data. */ | ||||
| char propname_esc[MAX_IDPROP_NAME * 2]; | char propname_esc[MAX_IDPROP_NAME * 2]; | ||||
| char prefix[MAX_IDPROP_NAME * 2]; | char prefix[MAX_IDPROP_NAME * 2]; | ||||
| BLI_str_escape(propname_esc, node->name, sizeof(propname_esc)); | BLI_str_escape(propname_esc, node->name, sizeof(propname_esc)); | ||||
| BLI_snprintf(prefix, sizeof(prefix), "nodes[\"%s\"]", propname_esc); | BLI_snprintf(prefix, sizeof(prefix), "nodes[\"%s\"]", propname_esc); | ||||
| if (BKE_animdata_fix_paths_remove((ID *)ntree, prefix)) { | if (BKE_animdata_fix_paths_remove((ID *)ntree, prefix)) { | ||||
| if (bmain != NULL) { | if (bmain != nullptr) { | ||||
| DEG_relations_tag_update(bmain); | DEG_relations_tag_update(bmain); | ||||
| } | } | ||||
| } | } | ||||
| /* Free node itself. */ | /* Free node itself. */ | ||||
| node_free_node(ntree, node); | node_free_node(ntree, node); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | void ntreeFreeLocalTree(bNodeTree *ntree) | ||||
| else { | else { | ||||
| ntreeFreeTree(ntree); | ntreeFreeTree(ntree); | ||||
| BKE_libblock_free_data(&ntree->id, true); | BKE_libblock_free_data(&ntree->id, true); | ||||
| } | } | ||||
| } | } | ||||
| void ntreeFreeCache(bNodeTree *ntree) | void ntreeFreeCache(bNodeTree *ntree) | ||||
| { | { | ||||
| if (ntree == NULL) { | if (ntree == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| if (ntree->typeinfo->free_cache) { | if (ntree->typeinfo->free_cache) { | ||||
| ntree->typeinfo->free_cache(ntree); | ntree->typeinfo->free_cache(ntree); | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | case ID_TE: | ||||
| return &((Tex *)id)->nodetree; | return &((Tex *)id)->nodetree; | ||||
| case ID_SCE: | case ID_SCE: | ||||
| return &((Scene *)id)->nodetree; | return &((Scene *)id)->nodetree; | ||||
| case ID_LS: | case ID_LS: | ||||
| return &((FreestyleLineStyle *)id)->nodetree; | return &((FreestyleLineStyle *)id)->nodetree; | ||||
| case ID_SIM: | case ID_SIM: | ||||
| return &((Simulation *)id)->nodetree; | return &((Simulation *)id)->nodetree; | ||||
| default: | default: | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| } | } | ||||
| /* Returns the private NodeTree object of the datablock, if it has one. */ | /* Returns the private NodeTree object of the datablock, if it has one. */ | ||||
| bNodeTree *ntreeFromID(ID *id) | bNodeTree *ntreeFromID(ID *id) | ||||
| { | { | ||||
| bNodeTree **nodetree = BKE_ntree_ptr_from_id(id); | bNodeTree **nodetree = BKE_ntree_ptr_from_id(id); | ||||
| return (nodetree != NULL) ? *nodetree : NULL; | return (nodetree != nullptr) ? *nodetree : nullptr; | ||||
| } | } | ||||
| /* Finds and returns the datablock that privately owns the given tree, or NULL. */ | /* Finds and returns the datablock that privately owns the given tree, or null. */ | ||||
| ID *BKE_node_tree_find_owner_ID(Main *bmain, struct bNodeTree *ntree) | ID *BKE_node_tree_find_owner_ID(Main *bmain, struct bNodeTree *ntree) | ||||
| { | { | ||||
| ListBase *lists[] = {&bmain->materials, | ListBase *lists[] = {&bmain->materials, | ||||
| &bmain->lights, | &bmain->lights, | ||||
| &bmain->worlds, | &bmain->worlds, | ||||
| &bmain->textures, | &bmain->textures, | ||||
| &bmain->scenes, | &bmain->scenes, | ||||
| &bmain->linestyles, | &bmain->linestyles, | ||||
| &bmain->simulations, | &bmain->simulations, | ||||
| NULL}; | nullptr}; | ||||
| for (int i = 0; lists[i] != NULL; i++) { | for (int i = 0; lists[i] != nullptr; i++) { | ||||
| LISTBASE_FOREACH (ID *, id, lists[i]) { | LISTBASE_FOREACH (ID *, id, lists[i]) { | ||||
| if (ntreeFromID(id) == ntree) { | if (ntreeFromID(id) == ntree) { | ||||
| return id; | return id; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| bool ntreeNodeExists(bNodeTree *ntree, bNode *testnode) | bool ntreeNodeExists(const bNodeTree *ntree, const bNode *testnode) | ||||
| { | { | ||||
| LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | LISTBASE_FOREACH (const bNode *, node, &ntree->nodes) { | ||||
| if (node == testnode) { | if (node == testnode) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| bool ntreeOutputExists(bNode *node, bNodeSocket *testsock) | bool ntreeOutputExists(const bNode *node, const bNodeSocket *testsock) | ||||
| { | { | ||||
| LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { | LISTBASE_FOREACH (const bNodeSocket *, sock, &node->outputs) { | ||||
| if (sock == testsock) { | if (sock == testsock) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void ntreeNodeFlagSet(const bNodeTree *ntree, const int flag, const bool enable) | void ntreeNodeFlagSet(const bNodeTree *ntree, const int flag, const bool enable) | ||||
| Show All 11 Lines | |||||
| /* returns localized tree for execution in threads */ | /* returns localized tree for execution in threads */ | ||||
| bNodeTree *ntreeLocalize(bNodeTree *ntree) | bNodeTree *ntreeLocalize(bNodeTree *ntree) | ||||
| { | { | ||||
| if (ntree) { | if (ntree) { | ||||
| /* Make full copy outside of Main database. | /* Make full copy outside of Main database. | ||||
| * Note: previews are not copied here. | * Note: previews are not copied here. | ||||
| */ | */ | ||||
| bNodeTree *ltree = (bNodeTree *)BKE_id_copy_ex( | bNodeTree *ltree = (bNodeTree *)BKE_id_copy_ex( | ||||
| NULL, &ntree->id, NULL, (LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA)); | nullptr, &ntree->id, nullptr, (LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA)); | ||||
| ltree->id.tag |= LIB_TAG_LOCALIZED; | ltree->id.tag |= LIB_TAG_LOCALIZED; | ||||
| LISTBASE_FOREACH (bNode *, node, <ree->nodes) { | LISTBASE_FOREACH (bNode *, node, <ree->nodes) { | ||||
| 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); | ||||
| bNode *node_src = ntree->nodes.first; | bNode *node_src = (bNode *)ntree->nodes.first; | ||||
| bNode *node_local = ltree->nodes.first; | bNode *node_local = (bNode *)ltree->nodes.first; | ||||
| while (node_src != NULL) { | while (node_src != nullptr) { | ||||
| node_local->original = node_src; | node_local->original = node_src; | ||||
| node_src = node_src->next; | node_src = node_src->next; | ||||
| node_local = node_local->next; | node_local = node_local->next; | ||||
| } | } | ||||
| if (ntree->typeinfo->localize) { | if (ntree->typeinfo->localize) { | ||||
| ntree->typeinfo->localize(ltree, ntree); | ntree->typeinfo->localize(ltree, ntree); | ||||
| } | } | ||||
| return ltree; | return ltree; | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| /* sync local composite with real tree */ | /* sync local composite with real tree */ | ||||
| /* local tree is supposed to be running, be careful moving previews! */ | /* local tree is supposed to be running, be careful moving previews! */ | ||||
| /* is called by jobs manager, outside threads, so it doesn't happen during draw */ | /* is called by jobs manager, outside threads, so it doesn't happen during draw */ | ||||
| void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree) | void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree) | ||||
| { | { | ||||
| if (localtree && ntree) { | if (localtree && ntree) { | ||||
| Show All 22 Lines | |||||
| static bNodeSocket *make_socket_interface(bNodeTree *ntree, | static bNodeSocket *make_socket_interface(bNodeTree *ntree, | ||||
| int in_out, | int in_out, | ||||
| const char *idname, | const char *idname, | ||||
| const char *name) | const char *name) | ||||
| { | { | ||||
| bNodeSocketType *stype = nodeSocketTypeFind(idname); | bNodeSocketType *stype = nodeSocketTypeFind(idname); | ||||
| int own_index = ntree->cur_index++; | int own_index = ntree->cur_index++; | ||||
| if (stype == NULL) { | if (stype == nullptr) { | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| bNodeSocket *sock = MEM_callocN(sizeof(bNodeSocket), "socket template"); | bNodeSocket *sock = (bNodeSocket *)MEM_callocN(sizeof(bNodeSocket), "socket template"); | ||||
| BLI_strncpy(sock->idname, stype->idname, sizeof(sock->idname)); | BLI_strncpy(sock->idname, stype->idname, sizeof(sock->idname)); | ||||
| node_socket_set_typeinfo(ntree, sock, stype); | node_socket_set_typeinfo(ntree, sock, stype); | ||||
| sock->in_out = in_out; | sock->in_out = in_out; | ||||
| sock->type = SOCK_CUSTOM; /* int type undefined by default */ | sock->type = SOCK_CUSTOM; /* int type undefined by default */ | ||||
| /* assign new unique index */ | /* assign new unique index */ | ||||
| own_index = ntree->cur_index++; | own_index = ntree->cur_index++; | ||||
| /* use the own_index as socket identifier */ | /* use the own_index as socket identifier */ | ||||
| if (in_out == SOCK_IN) { | if (in_out == SOCK_IN) { | ||||
| BLI_snprintf(sock->identifier, MAX_NAME, "Input_%d", own_index); | BLI_snprintf(sock->identifier, MAX_NAME, "Input_%d", own_index); | ||||
| } | } | ||||
| else { | else { | ||||
| BLI_snprintf(sock->identifier, MAX_NAME, "Output_%d", own_index); | BLI_snprintf(sock->identifier, MAX_NAME, "Output_%d", own_index); | ||||
| } | } | ||||
| sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF); | sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF); | ||||
| BLI_strncpy(sock->name, name, NODE_MAXSTR); | BLI_strncpy(sock->name, name, NODE_MAXSTR); | ||||
| sock->storage = NULL; | sock->storage = nullptr; | ||||
| sock->flag |= SOCK_COLLAPSED; | sock->flag |= SOCK_COLLAPSED; | ||||
| return sock; | return sock; | ||||
| } | } | ||||
| bNodeSocket *ntreeFindSocketInterface(bNodeTree *ntree, int in_out, const char *identifier) | bNodeSocket *ntreeFindSocketInterface(bNodeTree *ntree, int in_out, const char *identifier) | ||||
| { | { | ||||
| ListBase *sockets = (in_out == SOCK_IN) ? &ntree->inputs : &ntree->outputs; | ListBase *sockets = (in_out == SOCK_IN) ? &ntree->inputs : &ntree->outputs; | ||||
| LISTBASE_FOREACH (bNodeSocket *, iosock, sockets) { | LISTBASE_FOREACH (bNodeSocket *, iosock, sockets) { | ||||
| if (STREQ(iosock->identifier, identifier)) { | if (STREQ(iosock->identifier, identifier)) { | ||||
| return iosock; | return iosock; | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| bNodeSocket *ntreeAddSocketInterface(bNodeTree *ntree, | bNodeSocket *ntreeAddSocketInterface(bNodeTree *ntree, | ||||
| int in_out, | int in_out, | ||||
| const char *idname, | const char *idname, | ||||
| const char *name) | const char *name) | ||||
| { | { | ||||
| bNodeSocket *iosock = make_socket_interface(ntree, in_out, idname, name); | bNodeSocket *iosock = make_socket_interface(ntree, in_out, idname, name); | ||||
| ▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | static void ntree_interface_identifier_base(bNodeTree *ntree, char *base) | ||||
| /* generate a valid RNA identifier */ | /* generate a valid RNA identifier */ | ||||
| sprintf(base, "NodeTreeInterface_%s", ntree->id.name + 2); | sprintf(base, "NodeTreeInterface_%s", ntree->id.name + 2); | ||||
| RNA_identifier_sanitize(base, false); | RNA_identifier_sanitize(base, false); | ||||
| } | } | ||||
| /* check if the identifier is already in use */ | /* check if the identifier is already in use */ | ||||
| static bool ntree_interface_unique_identifier_check(void *UNUSED(data), const char *identifier) | static bool ntree_interface_unique_identifier_check(void *UNUSED(data), const char *identifier) | ||||
| { | { | ||||
| return (RNA_struct_find(identifier) != NULL); | return (RNA_struct_find(identifier) != nullptr); | ||||
| } | } | ||||
| /* generates the actual unique identifier and ui name and description */ | /* generates the actual unique identifier and ui name and description */ | ||||
| static void ntree_interface_identifier(bNodeTree *ntree, | static void ntree_interface_identifier(bNodeTree *ntree, | ||||
| const char *base, | const char *base, | ||||
| char *identifier, | char *identifier, | ||||
| int maxlen, | int maxlen, | ||||
| char *name, | char *name, | ||||
| char *description) | char *description) | ||||
| { | { | ||||
| /* There is a possibility that different node tree names get mapped to the same identifier | /* There is a possibility that different node tree names get mapped to the same identifier | ||||
| * after sanitation (e.g. "SomeGroup_A", "SomeGroup.A" both get sanitized to "SomeGroup_A"). | * after sanitation (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. | * On top of the sanitized id string add a number suffix if necessary to avoid duplicates. | ||||
| */ | */ | ||||
| identifier[0] = '\0'; | identifier[0] = '\0'; | ||||
| BLI_uniquename_cb(ntree_interface_unique_identifier_check, NULL, base, '_', identifier, maxlen); | BLI_uniquename_cb( | ||||
| ntree_interface_unique_identifier_check, nullptr, base, '_', identifier, maxlen); | |||||
| sprintf(name, "Node Tree %s Interface", ntree->id.name + 2); | sprintf(name, "Node Tree %s Interface", ntree->id.name + 2); | ||||
| sprintf(description, "Interface properties of node group %s", ntree->id.name + 2); | sprintf(description, "Interface properties of node group %s", ntree->id.name + 2); | ||||
| } | } | ||||
| static void ntree_interface_type_create(bNodeTree *ntree) | static void ntree_interface_type_create(bNodeTree *ntree) | ||||
| { | { | ||||
| /* strings are generated from base string + ID name, sizes are sufficient */ | /* strings are generated from base string + ID name, sizes are sufficient */ | ||||
| Show All 23 Lines | static void ntree_interface_type_create(bNodeTree *ntree) | ||||
| LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { | LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { | ||||
| bNodeSocketType *stype = sock->typeinfo; | bNodeSocketType *stype = sock->typeinfo; | ||||
| if (stype && stype->interface_register_properties) { | if (stype && stype->interface_register_properties) { | ||||
| stype->interface_register_properties(ntree, sock, srna); | stype->interface_register_properties(ntree, sock, srna); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| StructRNA *ntreeInterfaceTypeGet(bNodeTree *ntree, int create) | StructRNA *ntreeInterfaceTypeGet(bNodeTree *ntree, bool create) | ||||
| { | { | ||||
| if (ntree->interface_type) { | if (ntree->interface_type) { | ||||
| /* strings are generated from base string + ID name, sizes are sufficient */ | /* 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], | char base[MAX_ID_NAME + 64], identifier[MAX_ID_NAME + 64], name[MAX_ID_NAME + 64], | ||||
| description[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, | /* 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, | * so that the names match. This is not strictly necessary to keep it working, | ||||
| Show All 21 Lines | StructRNA *ntreeInterfaceTypeGet(bNodeTree *ntree, bool create) | ||||
| return ntree->interface_type; | return ntree->interface_type; | ||||
| } | } | ||||
| void ntreeInterfaceTypeFree(bNodeTree *ntree) | void ntreeInterfaceTypeFree(bNodeTree *ntree) | ||||
| { | { | ||||
| if (ntree->interface_type) { | if (ntree->interface_type) { | ||||
| RNA_struct_free(&BLENDER_RNA, ntree->interface_type); | RNA_struct_free(&BLENDER_RNA, ntree->interface_type); | ||||
| ntree->interface_type = NULL; | ntree->interface_type = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| void ntreeInterfaceTypeUpdate(bNodeTree *ntree) | void ntreeInterfaceTypeUpdate(bNodeTree *ntree) | ||||
| { | { | ||||
| /* XXX it would be sufficient to just recreate all properties | /* XXX it would be sufficient to just recreate all properties | ||||
| * instead of re-registering the whole struct type, | * instead of re-registering the whole struct type, | ||||
| * but there is currently no good way to do this in the RNA functions. | * but there is currently no good way to do this in the RNA functions. | ||||
| Show All 9 Lines | |||||
| { | { | ||||
| if (ntree) { | if (ntree) { | ||||
| LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| if (node->type == type) { | if (node->type == type) { | ||||
| return node; | return node; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| bool ntreeHasType(const bNodeTree *ntree, int type) | bool ntreeHasType(const bNodeTree *ntree, int type) | ||||
| { | { | ||||
| return ntreeFindType(ntree, type) != NULL; | return ntreeFindType(ntree, type) != nullptr; | ||||
| } | } | ||||
| bool ntreeHasTree(const bNodeTree *ntree, const bNodeTree *lookup) | bool ntreeHasTree(const bNodeTree *ntree, const bNodeTree *lookup) | ||||
| { | { | ||||
| if (ntree == lookup) { | if (ntree == lookup) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id) { | if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id) { | ||||
| if (ntreeHasTree((bNodeTree *)node->id, lookup)) { | if (ntreeHasTree((bNodeTree *)node->id, lookup)) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| bNodeLink *nodeFindLink(bNodeTree *ntree, bNodeSocket *from, bNodeSocket *to) | bNodeLink *nodeFindLink(bNodeTree *ntree, const bNodeSocket *from, const bNodeSocket *to) | ||||
| { | { | ||||
| LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { | LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { | ||||
| if (link->fromsock == from && link->tosock == to) { | if (link->fromsock == from && link->tosock == to) { | ||||
| return link; | return link; | ||||
| } | } | ||||
| if (link->fromsock == to && link->tosock == from) { /* hrms? */ | if (link->fromsock == to && link->tosock == from) { /* hrms? */ | ||||
| return link; | return link; | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| int nodeCountSocketLinks(bNodeTree *ntree, bNodeSocket *sock) | int nodeCountSocketLinks(const bNodeTree *ntree, const bNodeSocket *sock) | ||||
| { | { | ||||
| int tot = 0; | int tot = 0; | ||||
| LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { | LISTBASE_FOREACH (const bNodeLink *, link, &ntree->links) { | ||||
| if (link->fromsock == sock || link->tosock == sock) { | if (link->fromsock == sock || link->tosock == sock) { | ||||
| tot++; | tot++; | ||||
| } | } | ||||
| } | } | ||||
| return tot; | return tot; | ||||
| } | } | ||||
| bNode *nodeGetActive(bNodeTree *ntree) | bNode *nodeGetActive(bNodeTree *ntree) | ||||
| { | { | ||||
| if (ntree == NULL) { | if (ntree == nullptr) { | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| if (node->flag & NODE_ACTIVE) { | if (node->flag & NODE_ACTIVE) { | ||||
| return node; | return node; | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| static bNode *node_get_active_id_recursive(bNodeInstanceKey active_key, | static bNode *node_get_active_id_recursive(bNodeInstanceKey active_key, | ||||
| bNodeInstanceKey parent_key, | bNodeInstanceKey parent_key, | ||||
| bNodeTree *ntree, | bNodeTree *ntree, | ||||
| short idtype) | short idtype) | ||||
| { | { | ||||
| if (parent_key.value == active_key.value || active_key.value == 0) { | if (parent_key.value == active_key.value || active_key.value == 0) { | ||||
| Show All 15 Lines | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| bNode *tnode = node_get_active_id_recursive(active_key, group_key, group, idtype); | bNode *tnode = node_get_active_id_recursive(active_key, group_key, group, idtype); | ||||
| if (tnode) { | if (tnode) { | ||||
| return tnode; | return tnode; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| /* two active flags, ID nodes have special flag for buttons display */ | /* two active flags, ID nodes have special flag for buttons display */ | ||||
| bNode *nodeGetActiveID(bNodeTree *ntree, short idtype) | bNode *nodeGetActiveID(bNodeTree *ntree, short idtype) | ||||
| { | { | ||||
| if (ntree) { | if (ntree) { | ||||
| return node_get_active_id_recursive( | return node_get_active_id_recursive( | ||||
| ntree->active_viewer_key, NODE_INSTANCE_KEY_BASE, ntree, idtype); | ntree->active_viewer_key, NODE_INSTANCE_KEY_BASE, ntree, idtype); | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| bool nodeSetActiveID(bNodeTree *ntree, short idtype, ID *id) | bool nodeSetActiveID(bNodeTree *ntree, short idtype, ID *id) | ||||
| { | { | ||||
| bool ok = false; | bool ok = false; | ||||
| if (ntree == NULL) { | if (ntree == nullptr) { | ||||
| return ok; | return ok; | ||||
| } | } | ||||
| LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| if (node->id && GS(node->id->name) == idtype) { | if (node->id && GS(node->id->name) == idtype) { | ||||
| if (id && ok == false && node->id == id) { | if (id && ok == false && node->id == id) { | ||||
| node->flag |= NODE_ACTIVE_ID; | node->flag |= NODE_ACTIVE_ID; | ||||
| ok = true; | ok = true; | ||||
| } | } | ||||
| else { | else { | ||||
| node->flag &= ~NODE_ACTIVE_ID; | node->flag &= ~NODE_ACTIVE_ID; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* update all groups linked from here | /* update all groups linked from here | ||||
| * if active ID node has been found already, | * if active ID node has been found already, | ||||
| * just pass NULL so other matching nodes are deactivated. | * just pass null so other matching nodes are deactivated. | ||||
| */ | */ | ||||
| LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| if (node->type == NODE_GROUP) { | if (node->type == NODE_GROUP) { | ||||
| ok |= nodeSetActiveID((bNodeTree *)node->id, idtype, (ok == false ? id : NULL)); | ok |= nodeSetActiveID((bNodeTree *)node->id, idtype, (ok == false ? id : nullptr)); | ||||
| } | } | ||||
| } | } | ||||
| return ok; | return ok; | ||||
| } | } | ||||
| /* two active flags, ID nodes have special flag for buttons display */ | /* two active flags, ID nodes have special flag for buttons display */ | ||||
| void nodeClearActiveID(bNodeTree *ntree, short idtype) | void nodeClearActiveID(bNodeTree *ntree, short idtype) | ||||
| { | { | ||||
| if (ntree == NULL) { | if (ntree == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| if (node->id && GS(node->id->name) == idtype) { | if (node->id && GS(node->id->name) == idtype) { | ||||
| node->flag &= ~NODE_ACTIVE_ID; | node->flag &= ~NODE_ACTIVE_ID; | ||||
| } | } | ||||
| } | } | ||||
| Show All 14 Lines | else { | ||||
| LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { | LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { | ||||
| sock->flag &= ~NODE_SELECT; | sock->flag &= ~NODE_SELECT; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void nodeClearActive(bNodeTree *ntree) | void nodeClearActive(bNodeTree *ntree) | ||||
| { | { | ||||
| if (ntree == NULL) { | if (ntree == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_ID); | node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_ID); | ||||
| } | } | ||||
| } | } | ||||
| Show All 18 Lines | void nodeSetActive(bNodeTree *ntree, bNode *node) | ||||
| if (node->id) { | if (node->id) { | ||||
| node->flag |= NODE_ACTIVE_ID; | node->flag |= NODE_ACTIVE_ID; | ||||
| } | } | ||||
| if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) { | if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) { | ||||
| node->flag |= NODE_ACTIVE_TEXTURE; | node->flag |= NODE_ACTIVE_TEXTURE; | ||||
| } | } | ||||
| } | } | ||||
| int nodeSocketIsHidden(bNodeSocket *sock) | int nodeSocketIsHidden(const bNodeSocket *sock) | ||||
| { | { | ||||
| return ((sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) != 0); | return ((sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) != 0); | ||||
| } | } | ||||
| void nodeSetSocketAvailability(bNodeSocket *sock, bool is_available) | void nodeSetSocketAvailability(bNodeSocket *sock, bool is_available) | ||||
| { | { | ||||
| if (is_available) { | if (is_available) { | ||||
| sock->flag &= ~SOCK_UNAVAIL; | sock->flag &= ~SOCK_UNAVAIL; | ||||
| } | } | ||||
| else { | else { | ||||
| sock->flag |= SOCK_UNAVAIL; | sock->flag |= SOCK_UNAVAIL; | ||||
| } | } | ||||
| } | } | ||||
| int nodeSocketLinkLimit(struct bNodeSocket *sock) | int nodeSocketLinkLimit(const bNodeSocket *sock) | ||||
| { | { | ||||
| bNodeSocketType *stype = sock->typeinfo; | bNodeSocketType *stype = sock->typeinfo; | ||||
| if (stype != NULL && stype->use_link_limits_of_type) { | if (sock->flag & SOCK_MULTI_INPUT) { | ||||
| return 4095; | |||||
| } | |||||
| if (stype != nullptr && stype->use_link_limits_of_type) { | |||||
| int limit = (sock->in_out == SOCK_IN) ? stype->input_link_limit : stype->output_link_limit; | int limit = (sock->in_out == SOCK_IN) ? stype->input_link_limit : stype->output_link_limit; | ||||
| return limit; | return limit; | ||||
| } | } | ||||
| return sock->limit; | return sock->limit; | ||||
| } | } | ||||
| /* ************** Node Clipboard *********** */ | /* ************** Node Clipboard *********** */ | ||||
| #define USE_NODE_CB_VALIDATE | #define USE_NODE_CB_VALIDATE | ||||
| #ifdef USE_NODE_CB_VALIDATE | #ifdef USE_NODE_CB_VALIDATE | ||||
| /** | /** | ||||
| * This data structure is to validate the node on creation, | * This data structure is to validate the node on creation, | ||||
| * otherwise we may reference missing data. | * otherwise we may reference missing data. | ||||
| * | * | ||||
| * Currently its only used for ID's, but nodes may one day | * Currently its only used for ID's, but nodes may one day | ||||
| * reference other pointers which need validation. | * reference other pointers which need validation. | ||||
| */ | */ | ||||
| typedef struct bNodeClipboardExtraInfo { | struct bNodeClipboardExtraInfo { | ||||
| struct bNodeClipboardExtraInfo *next, *prev; | struct bNodeClipboardExtraInfo *next, *prev; | ||||
| ID *id; | ID *id; | ||||
| char id_name[MAX_ID_NAME]; | char id_name[MAX_ID_NAME]; | ||||
| char library_name[FILE_MAX]; | char library_name[FILE_MAX]; | ||||
| } bNodeClipboardExtraInfo; | }; | ||||
| #endif /* USE_NODE_CB_VALIDATE */ | #endif /* USE_NODE_CB_VALIDATE */ | ||||
| typedef struct bNodeClipboard { | struct bNodeClipboard { | ||||
| ListBase nodes; | ListBase nodes; | ||||
| #ifdef USE_NODE_CB_VALIDATE | #ifdef USE_NODE_CB_VALIDATE | ||||
| ListBase nodes_extra_info; | ListBase nodes_extra_info; | ||||
| #endif | #endif | ||||
| ListBase links; | ListBase links; | ||||
| int type; | int type; | ||||
| } bNodeClipboard; | }; | ||||
| static bNodeClipboard node_clipboard = {{NULL}}; | static bNodeClipboard node_clipboard = {{nullptr}}; | ||||
| void BKE_node_clipboard_init(struct bNodeTree *ntree) | void BKE_node_clipboard_init(const struct bNodeTree *ntree) | ||||
| { | { | ||||
| node_clipboard.type = ntree->type; | node_clipboard.type = ntree->type; | ||||
| } | } | ||||
| void BKE_node_clipboard_clear(void) | void BKE_node_clipboard_clear(void) | ||||
| { | { | ||||
| LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &node_clipboard.links) { | LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &node_clipboard.links) { | ||||
| nodeRemLink(NULL, link); | nodeRemLink(nullptr, link); | ||||
| } | } | ||||
| BLI_listbase_clear(&node_clipboard.links); | BLI_listbase_clear(&node_clipboard.links); | ||||
| LISTBASE_FOREACH_MUTABLE (bNode *, node, &node_clipboard.nodes) { | LISTBASE_FOREACH_MUTABLE (bNode *, node, &node_clipboard.nodes) { | ||||
| node_free_node(NULL, node); | node_free_node(nullptr, node); | ||||
| } | } | ||||
| BLI_listbase_clear(&node_clipboard.nodes); | BLI_listbase_clear(&node_clipboard.nodes); | ||||
| #ifdef USE_NODE_CB_VALIDATE | #ifdef USE_NODE_CB_VALIDATE | ||||
| BLI_freelistN(&node_clipboard.nodes_extra_info); | BLI_freelistN(&node_clipboard.nodes_extra_info); | ||||
| #endif | #endif | ||||
| } | } | ||||
| /* return false when one or more ID's are lost */ | /* return false when one or more ID's are lost */ | ||||
| bool BKE_node_clipboard_validate(void) | bool BKE_node_clipboard_validate(void) | ||||
| { | { | ||||
| bool ok = true; | bool ok = true; | ||||
| #ifdef USE_NODE_CB_VALIDATE | #ifdef USE_NODE_CB_VALIDATE | ||||
| bNodeClipboardExtraInfo *node_info; | bNodeClipboardExtraInfo *node_info; | ||||
| bNode *node; | bNode *node; | ||||
| /* lists must be aligned */ | /* lists must be aligned */ | ||||
| BLI_assert(BLI_listbase_count(&node_clipboard.nodes) == | BLI_assert(BLI_listbase_count(&node_clipboard.nodes) == | ||||
| BLI_listbase_count(&node_clipboard.nodes_extra_info)); | BLI_listbase_count(&node_clipboard.nodes_extra_info)); | ||||
| for (node = node_clipboard.nodes.first, node_info = node_clipboard.nodes_extra_info.first; node; | for (node = (bNode *)node_clipboard.nodes.first, | ||||
| node = node->next, node_info = node_info->next) { | node_info = (bNodeClipboardExtraInfo *)node_clipboard.nodes_extra_info.first; | ||||
| node; | |||||
| node = (bNode *)node->next, node_info = (bNodeClipboardExtraInfo *)node_info->next) { | |||||
| /* validate the node against the stored node info */ | /* validate the node against the stored node info */ | ||||
| /* re-assign each loop since we may clear, | /* re-assign each loop since we may clear, | ||||
| * open a new file where the ID is valid, and paste again */ | * open a new file where the ID is valid, and paste again */ | ||||
| node->id = node_info->id; | node->id = node_info->id; | ||||
| /* currently only validate the ID */ | /* currently only validate the ID */ | ||||
| if (node->id) { | if (node->id) { | ||||
| /* We want to search into current blend file, so using G_MAIN is valid here too. */ | /* We want to search into current blend file, so using G_MAIN is valid here too. */ | ||||
| ListBase *lb = which_libbase(G_MAIN, GS(node_info->id_name)); | ListBase *lb = which_libbase(G_MAIN, GS(node_info->id_name)); | ||||
| BLI_assert(lb != NULL); | BLI_assert(lb != nullptr); | ||||
| if (BLI_findindex(lb, node_info->id) == -1) { | if (BLI_findindex(lb, node_info->id) == -1) { | ||||
| /* may assign NULL */ | /* May assign null. */ | ||||
| node->id = BLI_findstring(lb, node_info->id_name + 2, offsetof(ID, name) + 2); | node->id = (ID *)BLI_findstring(lb, node_info->id_name + 2, offsetof(ID, name) + 2); | ||||
| if (node->id == NULL) { | if (node->id == nullptr) { | ||||
| ok = false; | ok = false; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| #endif /* USE_NODE_CB_VALIDATE */ | #endif /* USE_NODE_CB_VALIDATE */ | ||||
| return ok; | return ok; | ||||
| } | } | ||||
| void BKE_node_clipboard_add_node(bNode *node) | void BKE_node_clipboard_add_node(bNode *node) | ||||
| { | { | ||||
| #ifdef USE_NODE_CB_VALIDATE | #ifdef USE_NODE_CB_VALIDATE | ||||
| /* add extra info */ | /* add extra info */ | ||||
| bNodeClipboardExtraInfo *node_info = MEM_mallocN(sizeof(bNodeClipboardExtraInfo), | bNodeClipboardExtraInfo *node_info = (bNodeClipboardExtraInfo *)MEM_mallocN( | ||||
| "bNodeClipboardExtraInfo"); | sizeof(bNodeClipboardExtraInfo), __func__); | ||||
| node_info->id = node->id; | node_info->id = node->id; | ||||
| if (node->id) { | if (node->id) { | ||||
| BLI_strncpy(node_info->id_name, node->id->name, sizeof(node_info->id_name)); | BLI_strncpy(node_info->id_name, node->id->name, sizeof(node_info->id_name)); | ||||
| if (ID_IS_LINKED(node->id)) { | if (ID_IS_LINKED(node->id)) { | ||||
| BLI_strncpy( | BLI_strncpy( | ||||
| node_info->library_name, node->id->lib->filepath_abs, sizeof(node_info->library_name)); | node_info->library_name, node->id->lib->filepath_abs, sizeof(node_info->library_name)); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | static bNodeInstanceKey node_hash_int_str(bNodeInstanceKey hash, const char *str) | ||||
| } | } | ||||
| /* separator '\0' character, to avoid ambiguity from concatenated strings */ | /* separator '\0' character, to avoid ambiguity from concatenated strings */ | ||||
| hash.value = (hash.value << 5) + hash.value; /* hash * 33 */ | hash.value = (hash.value << 5) + hash.value; /* hash * 33 */ | ||||
| return hash; | return hash; | ||||
| } | } | ||||
| bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key, bNodeTree *ntree, bNode *node) | bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key, | ||||
| const bNodeTree *ntree, | |||||
| const bNode *node) | |||||
| { | { | ||||
| bNodeInstanceKey key; | bNodeInstanceKey key = node_hash_int_str(parent_key, ntree->id.name + 2); | ||||
| key = node_hash_int_str(parent_key, ntree->id.name + 2); | |||||
| if (node) { | if (node) { | ||||
| key = node_hash_int_str(key, node->name); | key = node_hash_int_str(key, node->name); | ||||
| } | } | ||||
| return key; | return key; | ||||
| } | } | ||||
| static unsigned int node_instance_hash_key(const void *key) | static unsigned int node_instance_hash_key(const void *key) | ||||
| { | { | ||||
| return ((const bNodeInstanceKey *)key)->value; | return ((const bNodeInstanceKey *)key)->value; | ||||
| } | } | ||||
| static bool node_instance_hash_key_cmp(const void *a, const void *b) | static bool node_instance_hash_key_cmp(const void *a, const void *b) | ||||
| { | { | ||||
| unsigned int value_a = ((const bNodeInstanceKey *)a)->value; | unsigned int value_a = ((const bNodeInstanceKey *)a)->value; | ||||
| unsigned int value_b = ((const bNodeInstanceKey *)b)->value; | unsigned int value_b = ((const bNodeInstanceKey *)b)->value; | ||||
| return (value_a != value_b); | return (value_a != value_b); | ||||
| } | } | ||||
| bNodeInstanceHash *BKE_node_instance_hash_new(const char *info) | bNodeInstanceHash *BKE_node_instance_hash_new(const char *info) | ||||
| { | { | ||||
| bNodeInstanceHash *hash = MEM_mallocN(sizeof(bNodeInstanceHash), info); | bNodeInstanceHash *hash = (bNodeInstanceHash *)MEM_mallocN(sizeof(bNodeInstanceHash), info); | ||||
| hash->ghash = BLI_ghash_new( | hash->ghash = BLI_ghash_new( | ||||
| node_instance_hash_key, node_instance_hash_key_cmp, "node instance hash ghash"); | node_instance_hash_key, node_instance_hash_key_cmp, "node instance hash ghash"); | ||||
| return hash; | return hash; | ||||
| } | } | ||||
| void BKE_node_instance_hash_free(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp) | void BKE_node_instance_hash_free(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp) | ||||
| { | { | ||||
| BLI_ghash_free(hash->ghash, NULL, (GHashValFreeFP)valfreefp); | BLI_ghash_free(hash->ghash, nullptr, (GHashValFreeFP)valfreefp); | ||||
| MEM_freeN(hash); | MEM_freeN(hash); | ||||
| } | } | ||||
| void BKE_node_instance_hash_insert(bNodeInstanceHash *hash, bNodeInstanceKey key, void *value) | void BKE_node_instance_hash_insert(bNodeInstanceHash *hash, bNodeInstanceKey key, void *value) | ||||
| { | { | ||||
| bNodeInstanceHashEntry *entry = value; | bNodeInstanceHashEntry *entry = (bNodeInstanceHashEntry *)value; | ||||
| entry->key = key; | entry->key = key; | ||||
| entry->tag = 0; | entry->tag = 0; | ||||
| BLI_ghash_insert(hash->ghash, &entry->key, value); | BLI_ghash_insert(hash->ghash, &entry->key, value); | ||||
| } | } | ||||
| void *BKE_node_instance_hash_lookup(bNodeInstanceHash *hash, bNodeInstanceKey key) | void *BKE_node_instance_hash_lookup(bNodeInstanceHash *hash, bNodeInstanceKey key) | ||||
| { | { | ||||
| return BLI_ghash_lookup(hash->ghash, &key); | return BLI_ghash_lookup(hash->ghash, &key); | ||||
| } | } | ||||
| int BKE_node_instance_hash_remove(bNodeInstanceHash *hash, | int BKE_node_instance_hash_remove(bNodeInstanceHash *hash, | ||||
| bNodeInstanceKey key, | bNodeInstanceKey key, | ||||
| bNodeInstanceValueFP valfreefp) | bNodeInstanceValueFP valfreefp) | ||||
| { | { | ||||
| return BLI_ghash_remove(hash->ghash, &key, NULL, (GHashValFreeFP)valfreefp); | return BLI_ghash_remove(hash->ghash, &key, nullptr, (GHashValFreeFP)valfreefp); | ||||
| } | } | ||||
| void BKE_node_instance_hash_clear(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp) | void BKE_node_instance_hash_clear(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp) | ||||
| { | { | ||||
| BLI_ghash_clear(hash->ghash, NULL, (GHashValFreeFP)valfreefp); | BLI_ghash_clear(hash->ghash, nullptr, (GHashValFreeFP)valfreefp); | ||||
| } | } | ||||
| void *BKE_node_instance_hash_pop(bNodeInstanceHash *hash, bNodeInstanceKey key) | void *BKE_node_instance_hash_pop(bNodeInstanceHash *hash, bNodeInstanceKey key) | ||||
| { | { | ||||
| return BLI_ghash_popkey(hash->ghash, &key, NULL); | return BLI_ghash_popkey(hash->ghash, &key, nullptr); | ||||
| } | } | ||||
| int BKE_node_instance_hash_haskey(bNodeInstanceHash *hash, bNodeInstanceKey key) | int BKE_node_instance_hash_haskey(bNodeInstanceHash *hash, bNodeInstanceKey key) | ||||
| { | { | ||||
| return BLI_ghash_haskey(hash->ghash, &key); | return BLI_ghash_haskey(hash->ghash, &key); | ||||
| } | } | ||||
| int BKE_node_instance_hash_size(bNodeInstanceHash *hash) | int BKE_node_instance_hash_size(bNodeInstanceHash *hash) | ||||
| { | { | ||||
| return BLI_ghash_len(hash->ghash); | return BLI_ghash_len(hash->ghash); | ||||
| } | } | ||||
| void BKE_node_instance_hash_clear_tags(bNodeInstanceHash *hash) | void BKE_node_instance_hash_clear_tags(bNodeInstanceHash *hash) | ||||
| { | { | ||||
| bNodeInstanceHashIterator iter; | bNodeInstanceHashIterator iter; | ||||
| NODE_INSTANCE_HASH_ITER (iter, hash) { | NODE_INSTANCE_HASH_ITER (iter, hash) { | ||||
| bNodeInstanceHashEntry *value = BKE_node_instance_hash_iterator_get_value(&iter); | bNodeInstanceHashEntry *value = (bNodeInstanceHashEntry *) | ||||
| BKE_node_instance_hash_iterator_get_value(&iter); | |||||
| value->tag = 0; | value->tag = 0; | ||||
| } | } | ||||
| } | } | ||||
| void BKE_node_instance_hash_tag(bNodeInstanceHash *UNUSED(hash), void *value) | void BKE_node_instance_hash_tag(bNodeInstanceHash *UNUSED(hash), void *value) | ||||
| { | { | ||||
| bNodeInstanceHashEntry *entry = value; | bNodeInstanceHashEntry *entry = (bNodeInstanceHashEntry *)value; | ||||
| entry->tag = 1; | entry->tag = 1; | ||||
| } | } | ||||
| bool BKE_node_instance_hash_tag_key(bNodeInstanceHash *hash, bNodeInstanceKey key) | bool BKE_node_instance_hash_tag_key(bNodeInstanceHash *hash, bNodeInstanceKey key) | ||||
| { | { | ||||
| bNodeInstanceHashEntry *entry = BKE_node_instance_hash_lookup(hash, key); | bNodeInstanceHashEntry *entry = (bNodeInstanceHashEntry *)BKE_node_instance_hash_lookup(hash, | ||||
| key); | |||||
| if (entry) { | if (entry) { | ||||
| entry->tag = 1; | entry->tag = 1; | ||||
| return true; | return true; | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void BKE_node_instance_hash_remove_untagged(bNodeInstanceHash *hash, | void BKE_node_instance_hash_remove_untagged(bNodeInstanceHash *hash, | ||||
| bNodeInstanceValueFP valfreefp) | bNodeInstanceValueFP valfreefp) | ||||
| { | { | ||||
| /* NOTE: Hash must not be mutated during iterating! | /* NOTE: Hash must not be mutated during iterating! | ||||
| * Store tagged entries in a separate list and remove items afterward. | * Store tagged entries in a separate list and remove items afterward. | ||||
| */ | */ | ||||
| bNodeInstanceKey *untagged = MEM_mallocN(sizeof(bNodeInstanceKey) * | bNodeInstanceKey *untagged = (bNodeInstanceKey *)MEM_mallocN( | ||||
| BKE_node_instance_hash_size(hash), | sizeof(bNodeInstanceKey) * BKE_node_instance_hash_size(hash), | ||||
| "temporary node instance key list"); | "temporary node instance key list"); | ||||
| bNodeInstanceHashIterator iter; | bNodeInstanceHashIterator iter; | ||||
| int num_untagged = 0; | int num_untagged = 0; | ||||
| NODE_INSTANCE_HASH_ITER (iter, hash) { | NODE_INSTANCE_HASH_ITER (iter, hash) { | ||||
| bNodeInstanceHashEntry *value = BKE_node_instance_hash_iterator_get_value(&iter); | bNodeInstanceHashEntry *value = (bNodeInstanceHashEntry *) | ||||
| BKE_node_instance_hash_iterator_get_value(&iter); | |||||
| if (!value->tag) { | if (!value->tag) { | ||||
| untagged[num_untagged++] = BKE_node_instance_hash_iterator_get_key(&iter); | untagged[num_untagged++] = BKE_node_instance_hash_iterator_get_key(&iter); | ||||
| } | } | ||||
| } | } | ||||
| for (int i = 0; i < num_untagged; i++) { | for (int i = 0; i < num_untagged; i++) { | ||||
| BKE_node_instance_hash_remove(hash, untagged[i], valfreefp); | BKE_node_instance_hash_remove(hash, untagged[i], valfreefp); | ||||
| ▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | void ntreeGetDependencyList(struct bNodeTree *ntree, struct bNode ***deplist, int *totnodes) | ||||
| *totnodes = 0; | *totnodes = 0; | ||||
| /* first clear data */ | /* first clear data */ | ||||
| LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| node->done = false; | node->done = false; | ||||
| (*totnodes)++; | (*totnodes)++; | ||||
| } | } | ||||
| if (*totnodes == 0) { | if (*totnodes == 0) { | ||||
| *deplist = NULL; | *deplist = nullptr; | ||||
| return; | return; | ||||
| } | } | ||||
| bNode **nsort; | bNode **nsort; | ||||
| nsort = *deplist = MEM_callocN((*totnodes) * sizeof(bNode *), "sorted node array"); | nsort = *deplist = (bNode **)MEM_callocN((*totnodes) * sizeof(bNode *), "sorted node array"); | ||||
| /* recursive check */ | /* recursive check */ | ||||
| LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| if (node->done == 0) { | if (node->done == 0) { | ||||
| node->level = node_get_deplist_recurs(ntree, node, &nsort); | node->level = node_get_deplist_recurs(ntree, node, &nsort); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* only updates node->level for detecting cycles links */ | /* only updates node->level for detecting cycles links */ | ||||
| static void ntree_update_node_level(bNodeTree *ntree) | static void ntree_update_node_level(bNodeTree *ntree) | ||||
| { | { | ||||
| /* first clear tag */ | /* first clear tag */ | ||||
| LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| node->done = false; | node->done = false; | ||||
| } | } | ||||
| /* recursive check */ | /* recursive check */ | ||||
| LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| if (node->done == 0) { | if (node->done == 0) { | ||||
| node->level = node_get_deplist_recurs(ntree, node, NULL); | node->level = node_get_deplist_recurs(ntree, node, nullptr); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void ntreeTagUsedSockets(bNodeTree *ntree) | void ntreeTagUsedSockets(bNodeTree *ntree) | ||||
| { | { | ||||
| /* first clear data */ | /* first clear data */ | ||||
| LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| Show All 11 Lines | void ntreeTagUsedSockets(bNodeTree *ntree) | ||||
| } | } | ||||
| } | } | ||||
| static void ntree_update_link_pointers(bNodeTree *ntree) | static void ntree_update_link_pointers(bNodeTree *ntree) | ||||
| { | { | ||||
| /* first clear data */ | /* first clear data */ | ||||
| LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { | LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { | ||||
| sock->link = NULL; | sock->link = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { | LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { | ||||
| link->tosock->link = link; | link->tosock->link = link; | ||||
| } | } | ||||
| ntreeTagUsedSockets(ntree); | ntreeTagUsedSockets(ntree); | ||||
| Show All 22 Lines | void ntreeUpdateAllNew(Main *main) | ||||
| FOREACH_NODETREE_BEGIN (main, ntree, owner_id) { | FOREACH_NODETREE_BEGIN (main, ntree, owner_id) { | ||||
| if (owner_id->tag & LIB_TAG_NEW) { | if (owner_id->tag & LIB_TAG_NEW) { | ||||
| LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| if (node->typeinfo->group_update_func) { | if (node->typeinfo->group_update_func) { | ||||
| node->typeinfo->group_update_func(ntree, node); | node->typeinfo->group_update_func(ntree, node); | ||||
| } | } | ||||
| } | } | ||||
| ntreeUpdateTree(NULL, ntree); | ntreeUpdateTree(nullptr, ntree); | ||||
| } | } | ||||
| } | } | ||||
| FOREACH_NODETREE_END; | FOREACH_NODETREE_END; | ||||
| } | } | ||||
| void ntreeUpdateAllUsers(Main *main, ID *id) | void ntreeUpdateAllUsers(Main *main, ID *id) | ||||
| { | { | ||||
| if (id == NULL) { | if (id == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Update all users of ngroup, to add/remove sockets as needed. */ | /* Update all users of ngroup, to add/remove sockets as needed. */ | ||||
| FOREACH_NODETREE_BEGIN (main, ntree, owner_id) { | FOREACH_NODETREE_BEGIN (main, ntree, owner_id) { | ||||
| bool need_update = false; | bool need_update = false; | ||||
| LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { | ||||
| if (node->id == id) { | if (node->id == id) { | ||||
| if (node->typeinfo->group_update_func) { | if (node->typeinfo->group_update_func) { | ||||
| node->typeinfo->group_update_func(ntree, node); | node->typeinfo->group_update_func(ntree, node); | ||||
| } | } | ||||
| need_update = true; | need_update = true; | ||||
| } | } | ||||
| } | } | ||||
| if (need_update) { | if (need_update) { | ||||
| ntreeUpdateTree(NULL, ntree); | ntreeUpdateTree(nullptr, ntree); | ||||
| } | } | ||||
| } | } | ||||
| FOREACH_NODETREE_END; | FOREACH_NODETREE_END; | ||||
| if (GS(id->name) == ID_NT) { | if (GS(id->name) == ID_NT) { | ||||
| bNodeTree *ngroup = (bNodeTree *)id; | bNodeTree *ngroup = (bNodeTree *)id; | ||||
| if (ngroup->type == NTREE_GEOMETRY) { | if (ngroup->type == NTREE_GEOMETRY) { | ||||
| LISTBASE_FOREACH (Object *, object, &main->objects) { | LISTBASE_FOREACH (Object *, object, &main->objects) { | ||||
| ▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | void nodeUpdate(bNodeTree *ntree, bNode *node) | ||||
| ntree->is_updating = false; | ntree->is_updating = false; | ||||
| } | } | ||||
| bool nodeUpdateID(bNodeTree *ntree, ID *id) | bool nodeUpdateID(bNodeTree *ntree, ID *id) | ||||
| { | { | ||||
| bool changed = false; | bool changed = false; | ||||
| if (ELEM(NULL, id, ntree)) { | if (ELEM(nullptr, id, ntree)) { | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| /* Avoid re-entrant updates, can be caused by RNA update callbacks. */ | /* Avoid re-entrant updates, can be caused by RNA update callbacks. */ | ||||
| if (ntree->is_updating) { | if (ntree->is_updating) { | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| ntree->is_updating = true; | ntree->is_updating = true; | ||||
| ▲ Show 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | void node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag) | ||||
| * and call RNA_struct_blender_type_set, so this only needs to be done for old RNA types | * 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, | * created in makesrna, which can not be associated to a bNodeType immediately, | ||||
| * since bNodeTypes are registered afterward ... | * since bNodeTypes are registered afterward ... | ||||
| */ | */ | ||||
| #define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \ | #define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \ | ||||
| case ID: \ | case ID: \ | ||||
| BLI_strncpy(ntype->idname, #Category #StructName, sizeof(ntype->idname)); \ | BLI_strncpy(ntype->idname, #Category #StructName, sizeof(ntype->idname)); \ | ||||
| ntype->rna_ext.srna = RNA_struct_find(#Category #StructName); \ | ntype->rna_ext.srna = RNA_struct_find(#Category #StructName); \ | ||||
| BLI_assert(ntype->rna_ext.srna != NULL); \ | BLI_assert(ntype->rna_ext.srna != nullptr); \ | ||||
| RNA_struct_blender_type_set(ntype->rna_ext.srna, ntype); \ | RNA_struct_blender_type_set(ntype->rna_ext.srna, ntype); \ | ||||
| break; | break; | ||||
| switch (type) { | switch (type) { | ||||
| #include "NOD_static_types.h" | #include "NOD_static_types.h" | ||||
| } | } | ||||
| /* make sure we have a valid type (everything registered) */ | /* make sure we have a valid type (everything registered) */ | ||||
| Show All 17 Lines | void node_type_base_custom( | ||||
| ntype->type = NODE_CUSTOM; | ntype->type = NODE_CUSTOM; | ||||
| BLI_strncpy(ntype->ui_name, name, sizeof(ntype->ui_name)); | BLI_strncpy(ntype->ui_name, name, sizeof(ntype->ui_name)); | ||||
| ntype->nclass = nclass; | ntype->nclass = nclass; | ||||
| ntype->flag = flag; | ntype->flag = flag; | ||||
| node_type_base_defaults(ntype); | node_type_base_defaults(ntype); | ||||
| } | } | ||||
| static bool unique_socket_template_identifier_check(void *arg, const char *name) | struct SocketTemplateIdentifierCallbackData { | ||||
| { | |||||
| bNodeSocketTemplate *ntemp; | |||||
| struct { | |||||
| bNodeSocketTemplate *list; | bNodeSocketTemplate *list; | ||||
| bNodeSocketTemplate *ntemp; | bNodeSocketTemplate *ntemp; | ||||
| } *data = arg; | }; | ||||
| for (ntemp = data->list; ntemp->type >= 0; ntemp++) { | static bool unique_socket_template_identifier_check(void *arg, const char *name) | ||||
| { | |||||
| SocketTemplateIdentifierCallbackData *data = (SocketTemplateIdentifierCallbackData *)arg; | |||||
| for (bNodeSocketTemplate *ntemp = data->list; ntemp->type >= 0; ntemp++) { | |||||
| if (ntemp != data->ntemp) { | if (ntemp != data->ntemp) { | ||||
| if (STREQ(ntemp->identifier, name)) { | if (STREQ(ntemp->identifier, name)) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| static void unique_socket_template_identifier(bNodeSocketTemplate *list, | static void unique_socket_template_identifier(bNodeSocketTemplate *list, | ||||
| bNodeSocketTemplate *ntemp, | bNodeSocketTemplate *ntemp, | ||||
| const char defname[], | const char defname[], | ||||
| char delim) | char delim) | ||||
| { | { | ||||
| struct { | SocketTemplateIdentifierCallbackData data; | ||||
| bNodeSocketTemplate *list; | |||||
| bNodeSocketTemplate *ntemp; | |||||
| } data; | |||||
| data.list = list; | data.list = list; | ||||
| data.ntemp = ntemp; | data.ntemp = ntemp; | ||||
| BLI_uniquename_cb(unique_socket_template_identifier_check, | BLI_uniquename_cb(unique_socket_template_identifier_check, | ||||
| &data, | &data, | ||||
| defname, | defname, | ||||
| delim, | delim, | ||||
| ntemp->identifier, | ntemp->identifier, | ||||
| ▲ Show 20 Lines • Show All 133 Lines • ▼ Show 20 Lines | |||||
| static bool node_undefined_poll(bNodeType *UNUSED(ntype), bNodeTree *UNUSED(nodetree)) | static bool node_undefined_poll(bNodeType *UNUSED(ntype), bNodeTree *UNUSED(nodetree)) | ||||
| { | { | ||||
| /* this type can not be added deliberately, it's just a placeholder */ | /* this type can not be added deliberately, it's just a placeholder */ | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* register fallback types used for undefined tree, nodes, sockets */ | /* register fallback types used for undefined tree, nodes, sockets */ | ||||
| static void register_undefined_types(void) | static void register_undefined_types() | ||||
| { | { | ||||
| /* Note: these types are not registered in the type hashes, | /* Note: these types are not registered in the type hashes, | ||||
| * they are just used as placeholders in case the actual types are not registered. | * they are just used as placeholders in case the actual types are not registered. | ||||
| */ | */ | ||||
| strcpy(NodeTreeTypeUndefined.idname, "NodeTreeUndefined"); | strcpy(NodeTreeTypeUndefined.idname, "NodeTreeUndefined"); | ||||
| strcpy(NodeTreeTypeUndefined.ui_name, N_("Undefined")); | strcpy(NodeTreeTypeUndefined.ui_name, N_("Undefined")); | ||||
| strcpy(NodeTreeTypeUndefined.ui_description, N_("Undefined Node Tree Type")); | strcpy(NodeTreeTypeUndefined.ui_description, N_("Undefined Node Tree Type")); | ||||
| node_type_base_custom(&NodeTypeUndefined, "NodeUndefined", "Undefined", 0, 0); | node_type_base_custom(&NodeTypeUndefined, "NodeUndefined", "Undefined", 0, 0); | ||||
| NodeTypeUndefined.poll = node_undefined_poll; | NodeTypeUndefined.poll = node_undefined_poll; | ||||
| BLI_strncpy(NodeSocketTypeUndefined.idname, | BLI_strncpy(NodeSocketTypeUndefined.idname, | ||||
| "NodeSocketUndefined", | "NodeSocketUndefined", | ||||
| sizeof(NodeSocketTypeUndefined.idname)); | sizeof(NodeSocketTypeUndefined.idname)); | ||||
| /* extra type info for standard socket types */ | /* extra type info for standard socket types */ | ||||
| NodeSocketTypeUndefined.type = SOCK_CUSTOM; | NodeSocketTypeUndefined.type = SOCK_CUSTOM; | ||||
| NodeSocketTypeUndefined.subtype = PROP_NONE; | NodeSocketTypeUndefined.subtype = PROP_NONE; | ||||
| NodeSocketTypeUndefined.use_link_limits_of_type = true; | NodeSocketTypeUndefined.use_link_limits_of_type = true; | ||||
| NodeSocketTypeUndefined.input_link_limit = 0xFFF; | NodeSocketTypeUndefined.input_link_limit = 0xFFF; | ||||
| NodeSocketTypeUndefined.output_link_limit = 0xFFF; | NodeSocketTypeUndefined.output_link_limit = 0xFFF; | ||||
| } | } | ||||
| static void registerCompositNodes(void) | static void registerCompositNodes() | ||||
| { | { | ||||
| register_node_type_cmp_group(); | register_node_type_cmp_group(); | ||||
| register_node_type_cmp_rlayers(); | register_node_type_cmp_rlayers(); | ||||
| register_node_type_cmp_image(); | register_node_type_cmp_image(); | ||||
| register_node_type_cmp_texture(); | register_node_type_cmp_texture(); | ||||
| register_node_type_cmp_value(); | register_node_type_cmp_value(); | ||||
| register_node_type_cmp_rgb(); | register_node_type_cmp_rgb(); | ||||
| ▲ Show 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | static void registerCompositNodes() | ||||
| register_node_type_cmp_pixelate(); | register_node_type_cmp_pixelate(); | ||||
| register_node_type_cmp_mask(); | register_node_type_cmp_mask(); | ||||
| register_node_type_cmp_trackpos(); | register_node_type_cmp_trackpos(); | ||||
| register_node_type_cmp_planetrackdeform(); | register_node_type_cmp_planetrackdeform(); | ||||
| register_node_type_cmp_cornerpin(); | register_node_type_cmp_cornerpin(); | ||||
| } | } | ||||
| static void registerShaderNodes(void) | static void registerShaderNodes() | ||||
| { | { | ||||
| register_node_type_sh_group(); | register_node_type_sh_group(); | ||||
| register_node_type_sh_camera(); | register_node_type_sh_camera(); | ||||
| register_node_type_sh_gamma(); | register_node_type_sh_gamma(); | ||||
| register_node_type_sh_brightcontrast(); | register_node_type_sh_brightcontrast(); | ||||
| register_node_type_sh_value(); | register_node_type_sh_value(); | ||||
| register_node_type_sh_rgb(); | register_node_type_sh_rgb(); | ||||
| ▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | static void registerShaderNodes() | ||||
| register_node_type_sh_tex_magic(); | register_node_type_sh_tex_magic(); | ||||
| register_node_type_sh_tex_checker(); | register_node_type_sh_tex_checker(); | ||||
| register_node_type_sh_tex_brick(); | register_node_type_sh_tex_brick(); | ||||
| register_node_type_sh_tex_pointdensity(); | register_node_type_sh_tex_pointdensity(); | ||||
| register_node_type_sh_tex_ies(); | register_node_type_sh_tex_ies(); | ||||
| register_node_type_sh_tex_white_noise(); | register_node_type_sh_tex_white_noise(); | ||||
| } | } | ||||
| static void registerTextureNodes(void) | static void registerTextureNodes() | ||||
| { | { | ||||
| register_node_type_tex_group(); | register_node_type_tex_group(); | ||||
| register_node_type_tex_math(); | register_node_type_tex_math(); | ||||
| register_node_type_tex_mix_rgb(); | register_node_type_tex_mix_rgb(); | ||||
| register_node_type_tex_valtorgb(); | register_node_type_tex_valtorgb(); | ||||
| register_node_type_tex_rgbtobw(); | register_node_type_tex_rgbtobw(); | ||||
| register_node_type_tex_valtonor(); | register_node_type_tex_valtonor(); | ||||
| Show All 33 Lines | static void registerTextureNodes() | ||||
| register_node_type_tex_proc_clouds(); | register_node_type_tex_proc_clouds(); | ||||
| register_node_type_tex_proc_wood(); | register_node_type_tex_proc_wood(); | ||||
| register_node_type_tex_proc_musgrave(); | register_node_type_tex_proc_musgrave(); | ||||
| register_node_type_tex_proc_noise(); | register_node_type_tex_proc_noise(); | ||||
| register_node_type_tex_proc_stucci(); | register_node_type_tex_proc_stucci(); | ||||
| register_node_type_tex_proc_distnoise(); | register_node_type_tex_proc_distnoise(); | ||||
| } | } | ||||
| static void registerGeometryNodes(void) | static void registerGeometryNodes() | ||||
| { | { | ||||
| register_node_type_geo_group(); | register_node_type_geo_group(); | ||||
| register_node_type_geo_attribute_compare(); | register_node_type_geo_attribute_compare(); | ||||
| register_node_type_geo_attribute_fill(); | register_node_type_geo_attribute_fill(); | ||||
| register_node_type_geo_attribute_vector_math(); | register_node_type_geo_attribute_vector_math(); | ||||
| register_node_type_geo_triangulate(); | register_node_type_geo_triangulate(); | ||||
| register_node_type_geo_edge_split(); | register_node_type_geo_edge_split(); | ||||
| register_node_type_geo_transform(); | register_node_type_geo_transform(); | ||||
| register_node_type_geo_subdivision_surface(); | register_node_type_geo_subdivision_surface(); | ||||
| register_node_type_geo_boolean(); | register_node_type_geo_boolean(); | ||||
| register_node_type_geo_point_distribute(); | register_node_type_geo_point_distribute(); | ||||
| register_node_type_geo_point_instance(); | register_node_type_geo_point_instance(); | ||||
| register_node_type_geo_point_separate(); | register_node_type_geo_point_separate(); | ||||
| register_node_type_geo_point_scale(); | register_node_type_geo_point_scale(); | ||||
| register_node_type_geo_point_translate(); | register_node_type_geo_point_translate(); | ||||
| register_node_type_geo_object_info(); | register_node_type_geo_object_info(); | ||||
| register_node_type_geo_attribute_randomize(); | register_node_type_geo_attribute_randomize(); | ||||
| register_node_type_geo_attribute_math(); | register_node_type_geo_attribute_math(); | ||||
| register_node_type_geo_join_geometry(); | register_node_type_geo_join_geometry(); | ||||
| register_node_type_geo_attribute_mix(); | register_node_type_geo_attribute_mix(); | ||||
| register_node_type_geo_attribute_color_ramp(); | register_node_type_geo_attribute_color_ramp(); | ||||
| register_node_type_geo_point_rotate(); | register_node_type_geo_point_rotate(); | ||||
| register_node_type_geo_align_rotation_to_vector(); | register_node_type_geo_align_rotation_to_vector(); | ||||
| register_node_type_geo_sample_texture(); | |||||
| register_node_type_geo_points_to_volume(); | |||||
| register_node_type_geo_collection_info(); | |||||
| } | } | ||||
| static void registerFunctionNodes(void) | static void registerFunctionNodes() | ||||
| { | { | ||||
| register_node_type_fn_boolean_math(); | register_node_type_fn_boolean_math(); | ||||
| register_node_type_fn_float_compare(); | register_node_type_fn_float_compare(); | ||||
| register_node_type_fn_switch(); | register_node_type_fn_switch(); | ||||
| register_node_type_fn_group_instance_id(); | register_node_type_fn_group_instance_id(); | ||||
| register_node_type_fn_combine_strings(); | register_node_type_fn_combine_strings(); | ||||
| register_node_type_fn_object_transforms(); | register_node_type_fn_object_transforms(); | ||||
| register_node_type_fn_random_float(); | register_node_type_fn_random_float(); | ||||
| Show All 32 Lines | void BKE_node_system_exit(void) | ||||
| if (nodetypes_hash) { | if (nodetypes_hash) { | ||||
| NODE_TYPES_BEGIN (nt) { | NODE_TYPES_BEGIN (nt) { | ||||
| if (nt->rna_ext.free) { | if (nt->rna_ext.free) { | ||||
| nt->rna_ext.free(nt->rna_ext.data); | nt->rna_ext.free(nt->rna_ext.data); | ||||
| } | } | ||||
| } | } | ||||
| NODE_TYPES_END; | NODE_TYPES_END; | ||||
| BLI_ghash_free(nodetypes_hash, NULL, node_free_type); | BLI_ghash_free(nodetypes_hash, nullptr, node_free_type); | ||||
| nodetypes_hash = NULL; | nodetypes_hash = nullptr; | ||||
| } | } | ||||
| if (nodesockettypes_hash) { | if (nodesockettypes_hash) { | ||||
| NODE_SOCKET_TYPES_BEGIN (st) { | NODE_SOCKET_TYPES_BEGIN (st) { | ||||
| if (st->ext_socket.free) { | if (st->ext_socket.free) { | ||||
| st->ext_socket.free(st->ext_socket.data); | st->ext_socket.free(st->ext_socket.data); | ||||
| } | } | ||||
| if (st->ext_interface.free) { | if (st->ext_interface.free) { | ||||
| st->ext_interface.free(st->ext_interface.data); | st->ext_interface.free(st->ext_interface.data); | ||||
| } | } | ||||
| } | } | ||||
| NODE_SOCKET_TYPES_END; | NODE_SOCKET_TYPES_END; | ||||
| BLI_ghash_free(nodesockettypes_hash, NULL, node_free_socket_type); | BLI_ghash_free(nodesockettypes_hash, nullptr, node_free_socket_type); | ||||
| nodesockettypes_hash = NULL; | nodesockettypes_hash = nullptr; | ||||
| } | } | ||||
| if (nodetreetypes_hash) { | if (nodetreetypes_hash) { | ||||
| NODE_TREE_TYPES_BEGIN (nt) { | NODE_TREE_TYPES_BEGIN (nt) { | ||||
| if (nt->rna_ext.free) { | if (nt->rna_ext.free) { | ||||
| nt->rna_ext.free(nt->rna_ext.data); | nt->rna_ext.free(nt->rna_ext.data); | ||||
| } | } | ||||
| } | } | ||||
| NODE_TREE_TYPES_END; | NODE_TREE_TYPES_END; | ||||
| BLI_ghash_free(nodetreetypes_hash, NULL, ntree_free_type); | BLI_ghash_free(nodetreetypes_hash, nullptr, ntree_free_type); | ||||
| nodetreetypes_hash = NULL; | nodetreetypes_hash = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /* NodeTree Iterator Helpers (FOREACH_NODETREE_BEGIN) */ | /* NodeTree Iterator Helpers (FOREACH_NODETREE_BEGIN) */ | ||||
| void BKE_node_tree_iter_init(struct NodeTreeIterStore *ntreeiter, struct Main *bmain) | void BKE_node_tree_iter_init(struct NodeTreeIterStore *ntreeiter, struct Main *bmain) | ||||
| { | { | ||||
| ntreeiter->ngroup = bmain->nodetrees.first; | ntreeiter->ngroup = (bNodeTree *)bmain->nodetrees.first; | ||||
| ntreeiter->scene = bmain->scenes.first; | ntreeiter->scene = (Scene *)bmain->scenes.first; | ||||
| ntreeiter->mat = bmain->materials.first; | ntreeiter->mat = (Material *)bmain->materials.first; | ||||
| ntreeiter->tex = bmain->textures.first; | ntreeiter->tex = (Tex *)bmain->textures.first; | ||||
| ntreeiter->light = bmain->lights.first; | ntreeiter->light = (Light *)bmain->lights.first; | ||||
| ntreeiter->world = bmain->worlds.first; | ntreeiter->world = (World *)bmain->worlds.first; | ||||
| ntreeiter->linestyle = bmain->linestyles.first; | ntreeiter->linestyle = (FreestyleLineStyle *)bmain->linestyles.first; | ||||
| ntreeiter->simulation = bmain->simulations.first; | ntreeiter->simulation = (Simulation *)bmain->simulations.first; | ||||
| } | } | ||||
| bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter, | bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter, | ||||
| bNodeTree **r_nodetree, | bNodeTree **r_nodetree, | ||||
| struct ID **r_id) | struct ID **r_id) | ||||
| { | { | ||||
| if (ntreeiter->ngroup) { | if (ntreeiter->ngroup) { | ||||
| *r_nodetree = ntreeiter->ngroup; | *r_nodetree = (bNodeTree *)ntreeiter->ngroup; | ||||
| *r_id = (ID *)ntreeiter->ngroup; | *r_id = (ID *)ntreeiter->ngroup; | ||||
| ntreeiter->ngroup = ntreeiter->ngroup->id.next; | ntreeiter->ngroup = (bNodeTree *)ntreeiter->ngroup->id.next; | ||||
| } | } | ||||
| else if (ntreeiter->scene) { | else if (ntreeiter->scene) { | ||||
| *r_nodetree = ntreeiter->scene->nodetree; | *r_nodetree = (bNodeTree *)ntreeiter->scene->nodetree; | ||||
| *r_id = (ID *)ntreeiter->scene; | *r_id = (ID *)ntreeiter->scene; | ||||
| ntreeiter->scene = ntreeiter->scene->id.next; | ntreeiter->scene = (Scene *)ntreeiter->scene->id.next; | ||||
| } | } | ||||
| else if (ntreeiter->mat) { | else if (ntreeiter->mat) { | ||||
| *r_nodetree = ntreeiter->mat->nodetree; | *r_nodetree = (bNodeTree *)ntreeiter->mat->nodetree; | ||||
| *r_id = (ID *)ntreeiter->mat; | *r_id = (ID *)ntreeiter->mat; | ||||
| ntreeiter->mat = ntreeiter->mat->id.next; | ntreeiter->mat = (Material *)ntreeiter->mat->id.next; | ||||
| } | } | ||||
| else if (ntreeiter->tex) { | else if (ntreeiter->tex) { | ||||
| *r_nodetree = ntreeiter->tex->nodetree; | *r_nodetree = (bNodeTree *)ntreeiter->tex->nodetree; | ||||
| *r_id = (ID *)ntreeiter->tex; | *r_id = (ID *)ntreeiter->tex; | ||||
| ntreeiter->tex = ntreeiter->tex->id.next; | ntreeiter->tex = (Tex *)ntreeiter->tex->id.next; | ||||
| } | } | ||||
| else if (ntreeiter->light) { | else if (ntreeiter->light) { | ||||
| *r_nodetree = ntreeiter->light->nodetree; | *r_nodetree = (bNodeTree *)ntreeiter->light->nodetree; | ||||
| *r_id = (ID *)ntreeiter->light; | *r_id = (ID *)ntreeiter->light; | ||||
| ntreeiter->light = ntreeiter->light->id.next; | ntreeiter->light = (Light *)ntreeiter->light->id.next; | ||||
| } | } | ||||
| else if (ntreeiter->world) { | else if (ntreeiter->world) { | ||||
| *r_nodetree = ntreeiter->world->nodetree; | *r_nodetree = (bNodeTree *)ntreeiter->world->nodetree; | ||||
| *r_id = (ID *)ntreeiter->world; | *r_id = (ID *)ntreeiter->world; | ||||
| ntreeiter->world = ntreeiter->world->id.next; | ntreeiter->world = (World *)ntreeiter->world->id.next; | ||||
| } | } | ||||
| else if (ntreeiter->linestyle) { | else if (ntreeiter->linestyle) { | ||||
| *r_nodetree = ntreeiter->linestyle->nodetree; | *r_nodetree = (bNodeTree *)ntreeiter->linestyle->nodetree; | ||||
| *r_id = (ID *)ntreeiter->linestyle; | *r_id = (ID *)ntreeiter->linestyle; | ||||
| ntreeiter->linestyle = ntreeiter->linestyle->id.next; | ntreeiter->linestyle = (FreestyleLineStyle *)ntreeiter->linestyle->id.next; | ||||
| } | } | ||||
| else if (ntreeiter->simulation) { | else if (ntreeiter->simulation) { | ||||
| *r_nodetree = ntreeiter->simulation->nodetree; | *r_nodetree = (bNodeTree *)ntreeiter->simulation->nodetree; | ||||
| *r_id = (ID *)ntreeiter->simulation; | *r_id = (ID *)ntreeiter->simulation; | ||||
| ntreeiter->simulation = ntreeiter->simulation->id.next; | ntreeiter->simulation = (Simulation *)ntreeiter->simulation->id.next; | ||||
| } | } | ||||
| else { | else { | ||||
| return false; | return false; | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| Show All 24 Lines | |||||