static int node_animation_properties(bNodeTree *ntree, bNode *node) { bNodeSocket *sock; const ListBase *lb; Link *link; PointerRNA ptr; PropertyRNA *prop; /* check to see if any of the node's properties have fcurves */ RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr); lb = RNA_struct_type_properties(ptr.type); for (link = lb->first; link; link = link->next) { prop = (PropertyRNA *)link; if (RNA_property_animated(&ptr, prop)) { nodeUpdate(ntree, node); return 1; } } /* now check node sockets */ for (sock = node->inputs.first; sock; sock = sock->next) { RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr); prop = RNA_struct_find_property(&ptr, "default_value"); if (RNA_property_animated(&ptr, prop)) { nodeUpdate(ntree, node); return 1; } } return 0; }
static int node_animation_properties(bNodeTree *ntree, bNode *node) { bNodeSocket *sock; const ListBase *lb; Link *link; PointerRNA ptr; PropertyRNA *prop; /* check to see if any of the node's properties have fcurves */ RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr); lb = RNA_struct_type_properties(ptr.type); for (link = lb->first; link; link = link->next) { int driven, len = 1, index; prop = (PropertyRNA *)link; if (RNA_property_array_check(prop)) len = RNA_property_array_length(&ptr, prop); for (index = 0; index < len; index++) { if (rna_get_fcurve(&ptr, prop, index, NULL, &driven)) { nodeUpdate(ntree, node); return 1; } } } /* now check node sockets */ for (sock = node->inputs.first; sock; sock = sock->next) { int driven, len = 1, index; RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr); prop = RNA_struct_find_property(&ptr, "default_value"); if (prop) { if (RNA_property_array_check(prop)) len = RNA_property_array_length(&ptr, prop); for (index = 0; index < len; index++) { if (rna_get_fcurve(&ptr, prop, index, NULL, &driven)) { nodeUpdate(ntree, node); return 1; } } } } return 0; }
void ED_node_changed_update(ID *id, bNode *node) { bNodeTree *nodetree, *edittree; int treetype; node_tree_from_ID(id, &nodetree, &edittree, &treetype); if(treetype==NTREE_SHADER) { DAG_id_tag_update(id, 0); if(GS(id->name) == ID_MA) WM_main_add_notifier(NC_MATERIAL|ND_SHADING_DRAW, id); else if(GS(id->name) == ID_LA) WM_main_add_notifier(NC_LAMP|ND_LIGHTING_DRAW, id); else if(GS(id->name) == ID_WO) WM_main_add_notifier(NC_WORLD|ND_WORLD_DRAW, id); } else if(treetype==NTREE_COMPOSIT) { if(node) nodeUpdate(edittree, node); /* don't use NodeTagIDChanged, it gives far too many recomposites for image, scene layers, ... */ node= node_tree_get_editgroup(nodetree); if(node) nodeUpdateID(nodetree, node->id); WM_main_add_notifier(NC_SCENE|ND_NODES, id); } else if(treetype==NTREE_TEXTURE) { DAG_id_tag_update(id, 0); WM_main_add_notifier(NC_TEXTURE|ND_NODES, id); } }
/* need to do all scenes, to prevent errors when you re-render 1 scene */ void ntreeCompositTagRender(Scene *curscene) { Scene *sce; for (sce = G.main->scene.first; sce; sce = sce->id.next) { if (sce->nodetree) { bNode *node; for (node = sce->nodetree->nodes.first; node; node = node->next) { if (node->id == (ID *)curscene || node->type == CMP_NODE_COMPOSITE) nodeUpdate(sce->nodetree, node); else if (node->type == CMP_NODE_TEXTURE) /* uses scene sizex/sizey */ nodeUpdate(sce->nodetree, node); } } } }
/* called from image window preview */ void ntreeCompositTagGenerators(bNodeTree *ntree) { bNode *node; if (ntree == NULL) return; for (node = ntree->nodes.first; node; node = node->next) { if (ELEM(node->type, CMP_NODE_R_LAYERS, CMP_NODE_IMAGE)) nodeUpdate(ntree, node); } }
/* tags nodes that have animation capabilities */ int ntreeCompositTagAnimated(bNodeTree *ntree) { bNode *node; int tagged = 0; if (ntree == NULL) return 0; for (node = ntree->nodes.first; node; node = node->next) { tagged = node_animation_properties(ntree, node); /* otherwise always tag these node types */ if (node->type == CMP_NODE_IMAGE) { Image *ima = (Image *)node->id; if (ima && ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) { nodeUpdate(ntree, node); tagged = 1; } } else if (node->type == CMP_NODE_TIME) { nodeUpdate(ntree, node); tagged = 1; } /* here was tag render layer, but this is called after a render, so re-composites fail */ else if (node->type == NODE_GROUP) { if (ntreeCompositTagAnimated((bNodeTree *)node->id) ) { nodeUpdate(ntree, node); } } else if (ELEM(node->type, CMP_NODE_MOVIECLIP, CMP_NODE_TRANSFORM)) { nodeUpdate(ntree, node); tagged = 1; } else if (node->type == CMP_NODE_MASK) { nodeUpdate(ntree, node); tagged = 1; } } return tagged; }
/* remove all nodes connected to this socket, if they aren't connected to other nodes */ static void node_socket_remove(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to) { if (!sock_to->link) return; node_remove_linked(ntree, sock_to->link->fromnode); nodeUpdate(ntree, node_to); ntreeUpdateTree(ntree); ED_node_generic_update(bmain, ntree, node_to); }
/* disconnect socket from the node it is connected to */ static void node_socket_disconnect(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to) { if (!sock_to->link) return; nodeRemLink(ntree, sock_to->link); nodeUpdate(ntree, node_to); ntreeUpdateTree(ntree); ED_node_generic_update(bmain, ntree, node_to); }
/* remove all nodes connected to this socket, if they aren't connected to other nodes */ static void node_socket_remove(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to) { if (!sock_to->link) return; node_remove_linked(ntree, sock_to->link->fromnode); sock_to->flag |= SOCK_COLLAPSED; nodeUpdate(ntree, node_to); ntreeUpdateTree(bmain, ntree); ED_node_tag_update_nodetree(bmain, ntree); }
/* disconnect socket from the node it is connected to */ static void node_socket_disconnect(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to) { if (!sock_to->link) return; nodeRemLink(ntree, sock_to->link); sock_to->flag |= SOCK_COLLAPSED; nodeUpdate(ntree, node_to); ntreeUpdateTree(bmain, ntree); ED_node_tag_update_nodetree(bmain, ntree); }
int ntreeTexTagAnimated(bNodeTree *ntree) { bNode *node; if (ntree == NULL) return 0; for (node = ntree->nodes.first; node; node = node->next) { if (node->type == TEX_NODE_CURVE_TIME) { nodeUpdate(ntree, node); return 1; } else if (node->type == NODE_GROUP) { if (ntreeTexTagAnimated((bNodeTree *)node->id) ) { return 1; } } } return 0; }
/* based on rules, force sockets hidden always */ void ntreeCompositForceHidden(bNodeTree *ntree) { bNode *node; if (ntree == NULL) return; for (node = ntree->nodes.first; node; node = node->next) { if (node->type == CMP_NODE_R_LAYERS) node_cmp_rlayers_force_hidden_passes(node); /* XXX this stuff is called all the time, don't want that. * Updates should only happen when actually necessary. */ #if 0 else if (node->type == CMP_NODE_IMAGE) { nodeUpdate(ntree, node); } #endif } }
/* based on rules, force sockets hidden always */ void ntreeCompositForceHidden(bNodeTree *ntree, Scene *curscene) { bNode *node; if (ntree == NULL) return; for (node = ntree->nodes.first; node; node = node->next) { if (node->type == CMP_NODE_R_LAYERS) { Scene *sce = node->id ? (Scene *)node->id : curscene; SceneRenderLayer *srl = BLI_findlink(&sce->r.layers, node->custom1); if (srl) force_hidden_passes(node, srl->passflag); } /* XXX this stuff is called all the time, don't want that. * Updates should only happen when actually necessary. */ #if 0 else if (node->type == CMP_NODE_IMAGE) { nodeUpdate(ntree, node); } #endif } }
/* add new node connected to this socket, or replace an existing one */ static void node_socket_add_replace(const bContext *C, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to, int type, NodeLinkItem *item) { bNode *node_from; bNodeSocket *sock_from_tmp; bNode *node_prev = NULL; /* unlink existing node */ if (sock_to->link) { node_prev = sock_to->link->fromnode; nodeRemLink(ntree, sock_to->link); } /* find existing node that we can use */ for (node_from = ntree->nodes.first; node_from; node_from = node_from->next) if (node_from->type == type) break; if (node_from) if (node_from->inputs.first || node_from->typeinfo->draw_buttons || node_from->typeinfo->draw_buttons_ex) node_from = NULL; if (node_prev && node_prev->type == type && node_link_item_compare(node_prev, item)) { /* keep the previous node if it's the same type */ node_from = node_prev; } else if (!node_from) { node_from = nodeAddStaticNode(C, ntree, type); if (node_prev != NULL) { /* If we're replacing existing node, use it's location. */ node_from->locx = node_prev->locx; node_from->locy = node_prev->locy; node_from->offsetx = node_prev->offsetx; node_from->offsety = node_prev->offsety; } else { /* Avoid exact intersection of nodes. * TODO(sergey): Still not ideal, but better than nothing. */ int index = BLI_findindex(&node_to->inputs, sock_to); BLI_assert(index != -1); node_from->locx = node_to->locx - (node_from->typeinfo->width + 50); node_from->locy = node_to->locy - (node_from->typeinfo->height * index); } node_link_item_apply(node_from, item); } nodeSetActive(ntree, node_from); /* add link */ sock_from_tmp = BLI_findlink(&node_from->outputs, item->socket_index); nodeAddLink(ntree, node_from, sock_from_tmp, node_to, sock_to); sock_to->flag &= ~SOCK_COLLAPSED; /* copy input sockets from previous node */ if (node_prev && node_from != node_prev) { bNodeSocket *sock_prev, *sock_from; for (sock_prev = node_prev->inputs.first; sock_prev; sock_prev = sock_prev->next) { for (sock_from = node_from->inputs.first; sock_from; sock_from = sock_from->next) { if (nodeCountSocketLinks(ntree, sock_from) >= sock_from->limit) continue; if (STREQ(sock_prev->name, sock_from->name) && sock_prev->type == sock_from->type) { bNodeLink *link = sock_prev->link; if (link && link->fromnode) { nodeAddLink(ntree, link->fromnode, link->fromsock, node_from, sock_from); nodeRemLink(ntree, link); } node_socket_copy_default_value(sock_from, sock_prev); } } } /* also preserve mapping for texture nodes */ if (node_from->typeinfo->nclass == NODE_CLASS_TEXTURE && node_prev->typeinfo->nclass == NODE_CLASS_TEXTURE) { memcpy(node_from->storage, node_prev->storage, sizeof(NodeTexBase)); } /* remove node */ node_remove_linked(ntree, node_prev); } nodeUpdate(ntree, node_from); nodeUpdate(ntree, node_to); ntreeUpdateTree(CTX_data_main(C), ntree); ED_node_tag_update_nodetree(CTX_data_main(C), ntree); }
/* add new node connected to this socket, or replace an existing one */ static void node_socket_add_replace(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to, bNodeTemplate *ntemp, int sock_num) { bNode *node_from; bNodeSocket *sock_from; bNode *node_prev = NULL; /* unlink existing node */ if (sock_to->link) { node_prev = sock_to->link->fromnode; nodeRemLink(ntree, sock_to->link); } /* find existing node that we can use */ for (node_from=ntree->nodes.first; node_from; node_from=node_from->next) if (node_from->type == ntemp->type) break; if (node_from) if (!(node_from->inputs.first == NULL && !(node_from->typeinfo->flag & NODE_OPTIONS))) node_from = NULL; if (node_prev && node_prev->type == ntemp->type && (ntemp->type != NODE_GROUP || node_prev->id == &ntemp->ngroup->id)) { /* keep the previous node if it's the same type */ node_from = node_prev; } else if (!node_from) { node_from= nodeAddNode(ntree, ntemp); node_from->locx = node_to->locx - (node_from->typeinfo->width + 50); node_from->locy = node_to->locy; if (node_from->id) id_us_plus(node_from->id); } nodeSetActive(ntree, node_from); /* add link */ sock_from = BLI_findlink(&node_from->outputs, sock_num); nodeAddLink(ntree, node_from, sock_from, node_to, sock_to); /* copy input sockets from previous node */ if (node_prev && node_from != node_prev) { bNodeSocket *sock_prev, *sock_from; for (sock_prev=node_prev->inputs.first; sock_prev; sock_prev=sock_prev->next) { for (sock_from=node_from->inputs.first; sock_from; sock_from=sock_from->next) { if (nodeCountSocketLinks(ntree, sock_from) >= sock_from->limit) continue; if (strcmp(sock_prev->name, sock_from->name) == 0 && sock_prev->type == sock_from->type) { bNodeLink *link = sock_prev->link; if (link && link->fromnode) { nodeAddLink(ntree, link->fromnode, link->fromsock, node_from, sock_from); nodeRemLink(ntree, link); } node_socket_free_default_value(sock_from->type, sock_from->default_value); sock_from->default_value = node_socket_make_default_value(sock_from->type); node_socket_copy_default_value(sock_from->type, sock_from->default_value, sock_prev->default_value); } } } /* also preserve mapping for texture nodes */ if (node_from->typeinfo->nclass == NODE_CLASS_TEXTURE && node_prev->typeinfo->nclass == NODE_CLASS_TEXTURE) { memcpy(node_from->storage, node_prev->storage, sizeof(NodeTexBase)); } /* remove node */ node_remove_linked(ntree, node_prev); } nodeUpdate(ntree, node_from); nodeUpdate(ntree, node_to); ntreeUpdateTree(ntree); ED_node_generic_update(bmain, ntree, node_to); }