diff options
Diffstat (limited to 'source/blender/editors/space_node/node_edit.c')
-rw-r--r-- | source/blender/editors/space_node/node_edit.c | 865 |
1 files changed, 537 insertions, 328 deletions
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index f757345bdcb..c74c160080c 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -31,6 +31,8 @@ #include "MEM_guardedalloc.h" +#include "DNA_action_types.h" +#include "DNA_anim_types.h" #include "DNA_lamp_types.h" #include "DNA_material_types.h" #include "DNA_node_types.h" @@ -65,6 +67,7 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_enum_types.h" #include "WM_api.h" #include "WM_types.h" @@ -73,12 +76,25 @@ #include "GPU_material.h" +#include "IMB_imbuf_types.h" + #include "node_intern.h" /* own include */ +#include "NOD_common.h" +#include "NOD_socket.h" +#include "NOD_composite.h" +#include "NOD_shader.h" +#include "NOD_texture.h" + #define USE_ESC_COMPO /* ***************** composite job manager ********************** */ +enum { + COM_RECALC_COMPOSITE = 1, + COM_RECALC_VIEWER = 2 +}; + typedef struct CompoJob { Scene *scene; bNodeTree *ntree; @@ -87,8 +103,55 @@ typedef struct CompoJob { short *do_update; float *progress; short need_sync; + int recalc_flags; } CompoJob; +static void compo_tag_output_nodes(bNodeTree *nodetree, int recalc_flags) +{ + bNode *node; + + for (node = nodetree->nodes.first; node; node = node->next) { + if (node->type == CMP_NODE_COMPOSITE) { + if (recalc_flags & COM_RECALC_COMPOSITE) + node->flag |= NODE_DO_OUTPUT_RECALC; + } + else if (node->type == CMP_NODE_VIEWER) { + if (recalc_flags & COM_RECALC_VIEWER) + node->flag |= NODE_DO_OUTPUT_RECALC; + } + else if (node->type == NODE_GROUP) { + if (node->id) + compo_tag_output_nodes((bNodeTree *)node->id, recalc_flags); + } + } +} + +static int compo_get_recalc_flags(const bContext *C) +{ + bScreen *sc = CTX_wm_screen(C); + ScrArea *sa; + int recalc_flags = 0; + + for (sa = sc->areabase.first; sa; sa = sa->next) { + if (sa->spacetype == SPACE_IMAGE) { + SpaceImage *sima = sa->spacedata.first; + if (sima->image) { + if (sima->image->type == IMA_TYPE_R_RESULT) + recalc_flags |= COM_RECALC_COMPOSITE; + else if (sima->image->type == IMA_TYPE_COMPOSITE) + recalc_flags |= COM_RECALC_VIEWER; + } + } + else if (sa->spacetype == SPACE_NODE) { + SpaceNode *snode = sa->spacedata.first; + if (snode->flag & SNODE_BACKDRAW) + recalc_flags |= COM_RECALC_VIEWER; + } + } + + return recalc_flags; +} + /* called by compo, only to check job 'stop' value */ static int compo_breakjob(void *cjv) { @@ -137,6 +200,9 @@ static void compo_initjob(void *cjv) CompoJob *cj = cjv; cj->localtree = ntreeLocalize(cj->ntree); + + if (cj->recalc_flags) + compo_tag_output_nodes(cj->localtree, cj->recalc_flags); } /* called before redraw notifiers, it moves finished previews over */ @@ -223,6 +289,7 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene /* customdata for preview thread */ cj->scene = CTX_data_scene(C); cj->ntree = nodetree; + cj->recalc_flags = compo_get_recalc_flags(C); /* setup job */ WM_jobs_customdata_set(wm_job, cj, compo_freejob); @@ -239,27 +306,12 @@ int composite_node_active(bContext *C) { if (ED_operator_node_active(C)) { SpaceNode *snode = CTX_wm_space_node(C); - if (snode->treetype == NTREE_COMPOSIT) + if (ED_node_is_compositor(snode)) return 1; } return 0; } -/* also checks for edited groups */ -bNode *editnode_get_active(bNodeTree *ntree) -{ - bNode *node; - - /* check for edited group */ - for (node = ntree->nodes.first; node; node = node->next) - if (nodeGroupEditGet(node)) - break; - if (node) - return nodeGetActive((bNodeTree *)node->id); - else - return nodeGetActive(ntree); -} - static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup) { bNode *node; @@ -275,20 +327,16 @@ static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup) return 0; } -static void snode_dag_update_group(void *calldata, ID *owner_id, bNodeTree *ntree) -{ - if (has_nodetree(ntree, calldata)) - DAG_id_tag_update(owner_id, 0); -} - void snode_dag_update(bContext *C, SpaceNode *snode) { Main *bmain = CTX_data_main(C); /* for groups, update all ID's using this */ if (snode->edittree != snode->nodetree) { - bNodeTreeType *tti = ntreeGetType(snode->edittree->type); - tti->foreach_nodetree(bmain, snode->edittree, snode_dag_update_group); + FOREACH_NODETREE(bmain, tntree, id) { + if (has_nodetree(tntree, snode->edittree)) + DAG_id_tag_update(id, 0); + } FOREACH_NODETREE_END } DAG_id_tag_update(snode->id, 0); @@ -298,37 +346,49 @@ void snode_notify(bContext *C, SpaceNode *snode) { WM_event_add_notifier(C, NC_NODE | NA_EDITED, NULL); - if (snode->treetype == NTREE_SHADER) + if (ED_node_is_shader(snode)) WM_event_add_notifier(C, NC_MATERIAL | ND_NODES, snode->id); - else if (snode->treetype == NTREE_COMPOSIT) + else if (ED_node_is_compositor(snode)) WM_event_add_notifier(C, NC_SCENE | ND_NODES, snode->id); - else if (snode->treetype == NTREE_TEXTURE) + else if (ED_node_is_texture(snode)) WM_event_add_notifier(C, NC_TEXTURE | ND_NODES, snode->id); } -bNode *node_tree_get_editgroup(bNodeTree *nodetree) +void ED_node_set_tree_type(SpaceNode *snode, bNodeTreeType *typeinfo) { - bNode *gnode; - - /* get the groupnode */ - for (gnode = nodetree->nodes.first; gnode; gnode = gnode->next) - if (nodeGroupEditGet(gnode)) - break; - return gnode; + if (typeinfo) + BLI_strncpy(snode->tree_idname, typeinfo->idname, sizeof(snode->tree_idname)); + else + snode->tree_idname[0] = '\0'; +} + +int ED_node_is_compositor(struct SpaceNode *snode) +{ + return STREQ(snode->tree_idname, ntreeType_Composite->idname); +} + +int ED_node_is_shader(struct SpaceNode *snode) +{ + return STREQ(snode->tree_idname, ntreeType_Shader->idname); +} + +int ED_node_is_texture(struct SpaceNode *snode) +{ + return STREQ(snode->tree_idname, ntreeType_Texture->idname); } /* assumes nothing being done in ntree yet, sets the default in/out node */ /* called from shading buttons or header */ -void ED_node_shader_default(Scene *scene, ID *id) +void ED_node_shader_default(const bContext *C, ID *id) { + Scene *scene = CTX_data_scene(C); bNode *in, *out; bNodeSocket *fromsock, *tosock, *sock; bNodeTree *ntree; - bNodeTemplate ntemp; int output_type, shader_type; - float color[3], strength = 1.0f; + float color[4] = { 0.0f, 0.0f, 0.0f, 1.0f }, strength = 1.0f; - ntree = ntreeAddTree("Shader Nodetree", NTREE_SHADER, 0); + ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); switch (GS(id->name)) { case ID_MA: @@ -381,12 +441,10 @@ void ED_node_shader_default(Scene *scene, ID *id) return; } - ntemp.type = output_type; - out = nodeAddNode(ntree, &ntemp); + out = nodeAddStaticNode(C, ntree, output_type); out->locx = 300.0f; out->locy = 300.0f; - ntemp.type = shader_type; - in = nodeAddNode(ntree, &ntemp); + in = nodeAddStaticNode(C, ntree, shader_type); in->locx = 10.0f; in->locy = 300.0f; nodeSetActive(ntree, in); @@ -397,12 +455,16 @@ void ED_node_shader_default(Scene *scene, ID *id) /* default values */ if (BKE_scene_use_new_shading_nodes(scene)) { + PointerRNA sockptr; sock = in->inputs.first; - copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, color); + RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sockptr); + + RNA_float_set_array(&sockptr, "default_value", color); if (strength != 0.0f) { sock = in->inputs.last; - ((bNodeSocketValueFloat *)sock->default_value)->value = strength; + RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sockptr); + RNA_float_set(&sockptr, "default_value", strength); } } @@ -411,11 +473,10 @@ void ED_node_shader_default(Scene *scene, ID *id) /* assumes nothing being done in ntree yet, sets the default in/out node */ /* called from shading buttons or header */ -void ED_node_composit_default(Scene *sce) +void ED_node_composit_default(const bContext *C, struct Scene *sce) { bNode *in, *out; bNodeSocket *fromsock, *tosock; - bNodeTemplate ntemp; /* but lets check it anyway */ if (sce->nodetree) { @@ -424,20 +485,18 @@ void ED_node_composit_default(Scene *sce) return; } - sce->nodetree = ntreeAddTree("Compositing Nodetree", NTREE_COMPOSIT, 0); - + sce->nodetree = ntreeAddTree(NULL, "Compositing Nodetree", ntreeType_Composite->idname); + sce->nodetree->chunksize = 256; sce->nodetree->edit_quality = NTREE_QUALITY_HIGH; sce->nodetree->render_quality = NTREE_QUALITY_HIGH; - ntemp.type = CMP_NODE_COMPOSITE; - out = nodeAddNode(sce->nodetree, &ntemp); + out = nodeAddStaticNode(C, sce->nodetree, CMP_NODE_COMPOSITE); out->locx = 300.0f; out->locy = 400.0f; out->id = &sce->id; id_us_plus(out->id); - ntemp.type = CMP_NODE_R_LAYERS; - in = nodeAddNode(sce->nodetree, &ntemp); + in = nodeAddStaticNode(C, sce->nodetree, CMP_NODE_R_LAYERS); in->locx = 10.0f; in->locy = 400.0f; in->id = &sce->id; id_us_plus(in->id); @@ -455,11 +514,10 @@ void ED_node_composit_default(Scene *sce) /* assumes nothing being done in ntree yet, sets the default in/out node */ /* called from shading buttons or header */ -void ED_node_texture_default(Tex *tx) +void ED_node_texture_default(const bContext *C, Tex *tx) { bNode *in, *out; bNodeSocket *fromsock, *tosock; - bNodeTemplate ntemp; /* but lets check it anyway */ if (tx->nodetree) { @@ -468,14 +526,12 @@ void ED_node_texture_default(Tex *tx) return; } - tx->nodetree = ntreeAddTree("Texture Nodetree", NTREE_TEXTURE, 0); + tx->nodetree = ntreeAddTree(NULL, "Texture Nodetree", ntreeType_Texture->idname); - ntemp.type = TEX_NODE_OUTPUT; - out = nodeAddNode(tx->nodetree, &ntemp); + out = nodeAddStaticNode(C, tx->nodetree, TEX_NODE_OUTPUT); out->locx = 300.0f; out->locy = 300.0f; - ntemp.type = TEX_NODE_CHECKER; - in = nodeAddNode(tx->nodetree, &ntemp); + in = nodeAddStaticNode(C, tx->nodetree, TEX_NODE_CHECKER); in->locx = 10.0f; in->locy = 300.0f; nodeSetActive(tx->nodetree, in); @@ -486,156 +542,74 @@ void ED_node_texture_default(Tex *tx) ntreeUpdateTree(tx->nodetree); } -/* id is supposed to contain a node tree */ -void node_tree_from_ID(ID *id, bNodeTree **ntree, bNodeTree **edittree, int *treetype) +/* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */ +void snode_set_context(const bContext *C) { - if (id) { - bNode *node = NULL; - short idtype = GS(id->name); + SpaceNode *snode = CTX_wm_space_node(C); + bNodeTreeType *treetype = ntreeTypeFind(snode->tree_idname); + bNodeTree *ntree = snode->nodetree; + ID *id = snode->id, *from = snode->from; - if (idtype == ID_NT) { - *ntree = (bNodeTree *)id; - if (treetype) *treetype = (*ntree)->type; - } - else if (idtype == ID_MA) { - *ntree = ((Material *)id)->nodetree; - if (treetype) *treetype = NTREE_SHADER; - } - else if (idtype == ID_LA) { - *ntree = ((Lamp *)id)->nodetree; - if (treetype) *treetype = NTREE_SHADER; - } - else if (idtype == ID_WO) { - *ntree = ((World *)id)->nodetree; - if (treetype) *treetype = NTREE_SHADER; - } - else if (idtype == ID_SCE) { - *ntree = ((Scene *)id)->nodetree; - if (treetype) *treetype = NTREE_COMPOSIT; - } - else if (idtype == ID_TE) { - *ntree = ((Tex *)id)->nodetree; - if (treetype) *treetype = NTREE_TEXTURE; - } - else { - if (treetype) *treetype = 0; - return; - } + /* we use this to signal warnings, when node shaders are drawn in wrong render engine */ + if (BKE_scene_use_new_shading_nodes(CTX_data_scene(C))) + snode->flag |= SNODE_NEW_SHADERS; + else + snode->flag &= ~SNODE_NEW_SHADERS; + + /* check the tree type */ + if (!treetype || + (treetype->poll && !treetype->poll(C, treetype))) + { + /* invalid tree type, disable */ + snode->tree_idname[0] = '\0'; + ED_node_tree_start(snode, NULL, NULL, NULL); + return; + } + + if (snode->nodetree && strcmp(snode->nodetree->idname, snode->tree_idname) != 0) { + /* current tree does not match selected type, clear tree path */ + ntree = NULL; + id = NULL; + from = NULL; + } - /* find editable group */ - if (edittree) { - if (*ntree) - for (node = (*ntree)->nodes.first; node; node = node->next) - if (nodeGroupEditGet(node)) - break; + if (!(snode->flag & SNODE_PIN) || ntree == NULL) { + if (treetype->get_from_context) { + /* reset and update from context */ + ntree = NULL; + id = NULL; + from = NULL; - if (node && node->id) - *edittree = (bNodeTree *)node->id; - else - *edittree = *ntree; + treetype->get_from_context(C, treetype, &ntree, &id, &from); } } - else { - *ntree = NULL; - *edittree = NULL; - if (treetype) *treetype = 0; + + if (snode->nodetree != ntree || snode->id != id || snode->from != from) { + ED_node_tree_start(snode, ntree, id, from); } } -/* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */ -void snode_set_context(SpaceNode *snode, Scene *scene) +void snode_update(SpaceNode *snode, bNode *node) { - Object *ob = OBACT; + bNodeTreePath *path; - snode->id = snode->from = NULL; + /* XXX this only updates nodes in the current node space tree path. + * The function supposedly should update any potential group node linking to changed tree, + * this really requires a working depsgraph ... + */ - if (snode->treetype == NTREE_SHADER) { - /* need active object, or we allow pinning... */ - if (snode->shaderfrom == SNODE_SHADER_OBJECT) { - if (ob) { - if (ob->type == OB_LAMP) { - snode->from = &ob->id; - snode->id = ob->data; - } - else { - Material *ma = give_current_material(ob, ob->actcol); - if (ma) { - snode->from = &ob->id; - snode->id = &ma->id; - } - } - } - } - else { /* SNODE_SHADER_WORLD */ - if (scene->world) { - snode->from = NULL; - snode->id = &scene->world->id; - } + /* update all edited group nodes */ + path = snode->treepath.last; + if (path) { + bNodeTree *ngroup = path->nodetree; + for (path = path->prev; path; path = path->prev) { + nodeUpdateID(path->nodetree, (ID *)ngroup); + ngroup = path->nodetree; } } - else if (snode->treetype == NTREE_COMPOSIT) { - snode->id = &scene->id; - - /* update output sockets based on available layers */ - ntreeCompositForceHidden(scene->nodetree, scene); - } - else if (snode->treetype == NTREE_TEXTURE) { - Tex *tx = NULL; - - if (snode->texfrom == SNODE_TEX_OBJECT) { - if (ob) { - tx = give_current_object_texture(ob); - if (ob->type == OB_LAMP) - snode->from = (ID *)ob->data; - else - snode->from = (ID *)give_current_material(ob, ob->actcol); - - /* from is not set fully for material nodes, should be ID + Node then */ - snode->id = &tx->id; - } - } - else if (snode->texfrom == SNODE_TEX_WORLD) { - tx = give_current_world_texture(scene->world); - snode->from = (ID *)scene->world; - snode->id = &tx->id; - } - else { - struct Brush *brush = NULL; - - if (ob && (ob->mode & OB_MODE_SCULPT)) - brush = paint_brush(&scene->toolsettings->sculpt->paint); - else - brush = paint_brush(&scene->toolsettings->imapaint.paint); - - if (brush) { - snode->from = (ID *)brush; - tx = give_current_brush_texture(brush); - snode->id = &tx->id; - } - } - } - else { - if (snode->nodetree && snode->nodetree->type == snode->treetype) - snode->id = &snode->nodetree->id; - else - snode->id = NULL; - } - - node_tree_from_ID(snode->id, &snode->nodetree, &snode->edittree, NULL); -} - -void snode_update(SpaceNode *snode, bNode *node) -{ - bNode *gnode; - if (node) nodeUpdate(snode->edittree, node); - - /* if inside group, tag entire group */ - gnode = node_tree_get_editgroup(snode->nodetree); - if (gnode) - nodeUpdateID(snode->nodetree, gnode->id); } void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node) @@ -646,6 +620,19 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node) if (node->type != NODE_GROUP) { int was_output = (node->flag & NODE_DO_OUTPUT); + int do_update = 0; + + /* generic node group output: set node as active output */ + if (node->type == NODE_GROUP_OUTPUT) { + bNode *tnode; + for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) + if (tnode->type == NODE_GROUP_OUTPUT) + tnode->flag &= ~NODE_DO_OUTPUT; + + node->flag |= NODE_DO_OUTPUT; + if (!was_output) + do_update = 1; + } /* tree specific activate calls */ if (ntree->type == NTREE_SHADER) { @@ -662,8 +649,10 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node) node->flag |= NODE_DO_OUTPUT; if (was_output == 0) - ED_node_generic_update(bmain, ntree, node); + ED_node_tag_update_nodetree(bmain, ntree); } + else if (do_update) + ED_node_tag_update_nodetree(bmain, ntree); /* if active texture changed, free glsl materials */ if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) { @@ -690,7 +679,7 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node) node->flag |= NODE_DO_OUTPUT; if (was_output == 0) - ED_node_generic_update(bmain, ntree, node); + ED_node_tag_update_nodetree(bmain, ntree); /* addnode() doesnt link this yet... */ node->id = (ID *)BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node"); @@ -715,9 +704,11 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node) tnode->flag &= ~NODE_DO_OUTPUT; node->flag |= NODE_DO_OUTPUT; - ED_node_generic_update(bmain, ntree, node); + ED_node_tag_update_nodetree(bmain, ntree); } } + else if (do_update) + ED_node_tag_update_nodetree(bmain, ntree); } else if (ntree->type == NTREE_TEXTURE) { // XXX @@ -754,7 +745,7 @@ static void edit_node_properties(wmOperatorType *ot) /* XXX could node be a context pointer? */ RNA_def_string(ot->srna, "node", "", MAX_NAME, "Node", ""); RNA_def_int(ot->srna, "socket", 0, 0, MAX_SOCKET, "Socket", "", 0, MAX_SOCKET); - RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Side", ""); + RNA_def_enum(ot->srna, "in_out", node_socket_in_out_items, SOCK_IN, "Socket Side", ""); } static int edit_node_invoke_properties(bContext *C, wmOperator *op) @@ -829,7 +820,7 @@ typedef struct NodeSizeWidget { int directions; } NodeSizeWidget; -static void node_resize_init(bContext *C, wmOperator *op, wmEvent *UNUSED(event), bNode *node, int dir) +static void node_resize_init(bContext *C, wmOperator *op, const wmEvent *UNUSED(event), bNode *node, int dir) { SpaceNode *snode = CTX_wm_space_node(C); @@ -862,11 +853,11 @@ static void node_resize_exit(bContext *C, wmOperator *op, int UNUSED(cancel)) op->customdata = NULL; } -static int node_resize_modal(bContext *C, wmOperator *op, wmEvent *event) +static int node_resize_modal(bContext *C, wmOperator *op, const wmEvent *event) { SpaceNode *snode = CTX_wm_space_node(C); ARegion *ar = CTX_wm_region(C); - bNode *node = editnode_get_active(snode->edittree); + bNode *node = nodeGetActive(snode->edittree); NodeSizeWidget *nsw = op->customdata; float mx, my, dx, dy; @@ -874,8 +865,8 @@ static int node_resize_modal(bContext *C, wmOperator *op, wmEvent *event) case MOUSEMOVE: UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &mx, &my); - dx = mx - nsw->mxstart; - dy = my - nsw->mystart; + dx = (mx - nsw->mxstart) / UI_DPI_FAC; + dy = (my - nsw->mystart) / UI_DPI_FAC; if (node) { if (node->flag & NODE_HIDDEN) { @@ -894,8 +885,8 @@ static int node_resize_modal(bContext *C, wmOperator *op, wmEvent *event) } } else { - float widthmin = UI_DPI_FAC * node->typeinfo->minwidth; - float widthmax = UI_DPI_FAC * node->typeinfo->maxwidth; + float widthmin = node->typeinfo->minwidth; + float widthmax = node->typeinfo->maxwidth; if (nsw->directions & NODE_RESIZE_RIGHT) { node->width = nsw->oldwidth + dx; CLAMP(node->width, widthmin, widthmax); @@ -965,11 +956,11 @@ static int node_resize_modal(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } -static int node_resize_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int node_resize_invoke(bContext *C, wmOperator *op, const wmEvent *event) { SpaceNode *snode = CTX_wm_space_node(C); ARegion *ar = CTX_wm_region(C); - bNode *node = editnode_get_active(snode->edittree); + bNode *node = nodeGetActive(snode->edittree); int dir; if (node) { @@ -1048,33 +1039,6 @@ void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set) } } -/* return 0, nothing done */ -static int UNUSED_FUNCTION(node_mouse_groupheader) (SpaceNode * snode) -{ - bNode *gnode; - float mx = 0, my = 0; -// XXX int mval[2]; - - gnode = node_tree_get_editgroup(snode->nodetree); - if (gnode == NULL) return 0; - -// XXX getmouseco_areawin(mval); -// XXX areamouseco_to_ipoco(G.v2d, mval, &mx, &my); - - /* click in header or outside? */ - if (BLI_rctf_isect_pt(&gnode->totr, mx, my) == 0) { - rctf rect = gnode->totr; - - rect.ymax += NODE_DY; - if (BLI_rctf_isect_pt(&rect, mx, my) == 0) - snode_make_group_editable(snode, NULL); /* toggles, so exits editmode */ -// else -// XXX transform_nodes(snode->nodetree, 'g', "Move group"); - - return 1; - } - return 0; -} /* checks snode->mouse position, and returns found node/socket */ /* type is SOCK_IN and/or SOCK_OUT */ @@ -1135,32 +1099,6 @@ int node_find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **so } } - /* check group sockets - * NB: using ngroup->outputs as input sockets and vice versa here! - */ - if (in_out & SOCK_IN) { - for (sock = snode->edittree->outputs.first; sock; sock = sock->next) { - if (!nodeSocketIsHidden(sock)) { - if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) { - *nodep = NULL; /* NULL node pointer indicates group socket */ - *sockp = sock; - return 1; - } - } - } - } - if (in_out & SOCK_OUT) { - for (sock = snode->edittree->inputs.first; sock; sock = sock->next) { - if (!nodeSocketIsHidden(sock)) { - if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) { - *nodep = NULL; /* NULL node pointer indicates group socket */ - *sockp = sock; - return 1; - } - } - } - } - return 0; } @@ -1207,7 +1145,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) * but operators and readfile.c do. */ id_us_plus(newnode->id); /* to ensure redraws or rerenders happen */ - ED_node_changed_update(snode->id, newnode); + ED_node_tag_update_id(snode->id); } } @@ -1268,9 +1206,9 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) /* has been set during copy above */ newnode = node->new_node; - node_deselect(node); + nodeSetSelected(node, FALSE); node->flag &= ~NODE_ACTIVE; - node_select(newnode); + nodeSetSelected(newnode, TRUE); } /* make sure we don't copy new nodes again! */ @@ -1304,6 +1242,8 @@ void NODE_OT_duplicate(wmOperatorType *ot) } int ED_node_select_check(ListBase *lb) + + { bNode *node; @@ -1448,6 +1388,7 @@ void NODE_OT_render_changed(wmOperatorType *ot) ot->flag = 0; } + /* ****************** Hide operator *********************** */ static void node_flag_toggle_exec(SpaceNode *snode, int toggle_flag) @@ -1743,7 +1684,7 @@ static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op)) void NODE_OT_delete_reconnect(wmOperatorType *ot) { /* identifiers */ - ot->name = "Delete with reconnect"; + ot->name = "Delete with Reconnect"; ot->description = "Delete nodes; will reconnect nodes as if deletion was muted"; ot->idname = "NODE_OT_delete_reconnect"; @@ -1954,8 +1895,6 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; - bNode *gnode = node_tree_get_editgroup(snode->nodetree); - float gnode_x = 0.0f, gnode_y = 0.0f; bNode *node; bNodeLink *link, *newlink; @@ -1965,10 +1904,6 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op)) BKE_node_clipboard_clear(); BKE_node_clipboard_init(ntree); - /* get group node offset */ - if (gnode) - nodeToView(gnode, 0.0f, 0.0f, &gnode_x, &gnode_y); - for (node = ntree->nodes.first; node; node = node->next) { if (node->flag & SELECT) { bNode *new_node; @@ -1991,12 +1926,6 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op)) nodeDetachNode(new_node); } } - - /* transform to basic view space. child node location is relative to parent */ - if (!new_node->parent) { - new_node->locx += gnode_x; - new_node->locy += gnode_y; - } } } @@ -2025,7 +1954,7 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op)) void NODE_OT_clipboard_copy(wmOperatorType *ot) { /* identifiers */ - ot->name = "Copy to clipboard"; + ot->name = "Copy to Clipboard"; ot->description = "Copies selected nodes to the clipboard"; ot->idname = "NODE_OT_clipboard_copy"; @@ -2043,8 +1972,6 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) { SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; - bNode *gnode = node_tree_get_editgroup(snode->nodetree); - float gnode_center[2]; const ListBase *clipboard_nodes_lb; const ListBase *clipboard_links_lb; bNode *node; @@ -2078,14 +2005,6 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) /* deselect old nodes */ node_deselect_all(snode); - /* get group node offset */ - if (gnode) { - nodeToView(gnode, 0.0f, 0.0f, &gnode_center[0], &gnode_center[1]); - } - else { - zero_v2(gnode_center); - } - /* calculate "barycenter" for placing on mouse cursor */ zero_v2(center); for (node = clipboard_nodes_lb->first, num_nodes = 0; node; node = node->next, num_nodes++) { @@ -2102,7 +2021,7 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) id_us_plus(node->id); /* pasted nodes are selected */ - node_select(new_node); + nodeSetSelected(new_node, TRUE); } /* reparent copied nodes */ @@ -2110,13 +2029,6 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) bNode *new_node = node->new_node; if (new_node->parent) new_node->parent = new_node->parent->new_node; - - - /* place nodes around the mouse cursor. child nodes locations are relative to parent */ - if (!new_node->parent) { - new_node->locx += snode->cursor[0] - center[0] - gnode_center[0]; - new_node->locy += snode->cursor[1] - center[1] - gnode_center[1]; - } } for (link = clipboard_links_lb->first; link; link = link->next) { @@ -2132,7 +2044,7 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int node_clipboard_paste_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int node_clipboard_paste_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); SpaceNode *snode = CTX_wm_space_node(C); @@ -2146,7 +2058,7 @@ static int node_clipboard_paste_invoke(bContext *C, wmOperator *op, wmEvent *eve void NODE_OT_clipboard_paste(wmOperatorType *ot) { /* identifiers */ - ot->name = "Paste from clipboard"; + ot->name = "Paste from Clipboard"; ot->description = "Pastes nodes from the clipboard to the active node tree"; ot->idname = "NODE_OT_clipboard_paste"; @@ -2159,15 +2071,195 @@ void NODE_OT_clipboard_paste(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ********************** Shader Script Update ******************/ +/********************** Add interface socket operator *********************/ -typedef struct ScriptUpdateData { - RenderEngine *engine; - RenderEngineType *type; +static bNodeSocket *ntree_get_active_interface_socket(ListBase *lb) +{ + bNodeSocket *sock; + for (sock = lb->first; sock; sock = sock->next) + if (sock->flag & SELECT) + return sock; + return NULL; +} - Text *text; - int found; -} ScriptUpdateData; +static int ntree_socket_add_exec(bContext *C, wmOperator *op) +{ + SpaceNode *snode = CTX_wm_space_node(C); + bNodeTree *ntree = snode->edittree; + int in_out = RNA_enum_get(op->ptr, "in_out"); + PointerRNA ntree_ptr; + bNodeSocket *sock, *tsock, *active_sock; + const char *default_name; + + RNA_id_pointer_create((ID *)ntree, &ntree_ptr); + + if (in_out == SOCK_IN) { + active_sock = ntree_get_active_interface_socket(&ntree->inputs); + default_name = "Input"; + } + else { + active_sock = ntree_get_active_interface_socket(&ntree->outputs); + default_name = "Output"; + } + + if (active_sock) { + /* insert a copy of the active socket right after it */ + sock = ntreeInsertSocketInterface(ntree, in_out, active_sock->idname, active_sock->next, active_sock->name); + /* XXX this only works for actual sockets, not interface templates! */ + /*nodeSocketCopyValue(sock, &ntree_ptr, active_sock, &ntree_ptr);*/ + } + else { + /* XXX TODO define default socket type for a tree! */ + sock = ntreeAddSocketInterface(ntree, in_out, "NodeSocketFloat", default_name); + } + + /* deactivate sockets (has to check both lists) */ + for (tsock = ntree->inputs.first; tsock; tsock = tsock->next) + tsock->flag &= ~SELECT; + for (tsock = ntree->outputs.first; tsock; tsock = tsock->next) + tsock->flag &= ~SELECT; + /* make the new socket active */ + sock->flag |= SELECT; + + ntreeUpdateTree(ntree); + + WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL); + + return OPERATOR_FINISHED; +} + +void NODE_OT_tree_socket_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Node Tree Interface Socket"; + ot->description = "Add an input or output socket to the current node tree"; + ot->idname = "NODE_OT_tree_socket_add"; + + /* api callbacks */ + ot->exec = ntree_socket_add_exec; + ot->poll = ED_operator_node_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "in_out", node_socket_in_out_items, SOCK_IN, "Socket Type", ""); +} + +/********************** Remove interface socket operator *********************/ + +static int ntree_socket_remove_exec(bContext *C, wmOperator *UNUSED(op)) +{ + SpaceNode *snode = CTX_wm_space_node(C); + bNodeTree *ntree = snode->edittree; + bNodeSocket *iosock, *active_sock; + + iosock = ntree_get_active_interface_socket(&ntree->inputs); + if (!iosock) + iosock = ntree_get_active_interface_socket(&ntree->outputs); + if (!iosock) + return OPERATOR_CANCELLED; + + /* preferably next socket becomes active, otherwise try previous socket */ + active_sock = (iosock->next ? iosock->next : iosock->prev); + ntreeRemoveSocketInterface(ntree, iosock); + + /* set active socket */ + if (active_sock) + active_sock->flag |= SELECT; + + ntreeUpdateTree(ntree); + + WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL); + + return OPERATOR_FINISHED; +} + +void NODE_OT_tree_socket_remove(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Remove Node Tree Interface Socket"; + ot->description = "Remove an input or output socket to the current node tree"; + ot->idname = "NODE_OT_tree_socket_remove"; + + /* api callbacks */ + ot->exec = ntree_socket_remove_exec; + ot->poll = ED_operator_node_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/********************** Move interface socket operator *********************/ + +static EnumPropertyItem move_direction_items[] = { + { 1, "UP", 0, "Up", "" }, + { 2, "DOWN", 0, "Down", "" }, + { 0, NULL, 0, NULL, NULL }, +}; + +static int ntree_socket_move_exec(bContext *C, wmOperator *op) +{ + SpaceNode *snode = CTX_wm_space_node(C); + bNodeTree *ntree = snode->edittree; + int direction = RNA_enum_get(op->ptr, "direction"); + bNodeSocket *iosock; + ListBase *lb; + + lb = &ntree->inputs; + iosock = ntree_get_active_interface_socket(lb); + if (!iosock) { + lb = &ntree->outputs; + iosock = ntree_get_active_interface_socket(lb); + } + if (!iosock) + return OPERATOR_CANCELLED; + + switch (direction) { + case 1: { /* up */ + bNodeSocket *before = iosock->prev; + BLI_remlink(lb, iosock); + if (before) + BLI_insertlinkbefore(lb, before, iosock); + else + BLI_addhead(lb, iosock); + break; + } + case 2: { /* down */ + bNodeSocket *after = iosock->next; + BLI_remlink(lb, iosock); + if (after) + BLI_insertlinkafter(lb, after, iosock); + else + BLI_addtail(lb, iosock); + break; + } + } + + ntreeUpdateTree(ntree); + + WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL); + + return OPERATOR_FINISHED; +} + +void NODE_OT_tree_socket_move(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Move Node Tree Socket"; + ot->description = "Move a socket up or down in the current node tree's sockets stack"; + ot->idname = "NODE_OT_tree_socket_move"; + + /* api callbacks */ + ot->exec = ntree_socket_move_exec; + ot->poll = ED_operator_node_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "direction", move_direction_items, 1, "Direction", ""); +} + +/* ********************** Shader Script Update ******************/ static int node_shader_script_update_poll(bContext *C) { @@ -2200,64 +2292,79 @@ static int node_shader_script_update_poll(bContext *C) return 0; } -static void node_shader_script_update_text(void *data_, ID *UNUSED(id), bNodeTree *ntree) +/* recursively check for script nodes in groups using this text and update */ +static int node_shader_script_update_text_recursive(RenderEngine *engine, RenderEngineType *type, bNodeTree *ntree, Text *text) { - ScriptUpdateData *data = (ScriptUpdateData *)data_; + int found = FALSE; bNode *node; - + + ntree->done = TRUE; + /* update each script that is using this text datablock */ for (node = ntree->nodes.first; node; node = node->next) { if (node->type == NODE_GROUP) { - node_shader_script_update_text(data_, NULL, (bNodeTree *)node->id); + bNodeTree *ngroup = (bNodeTree *)node->id; + if (ngroup && !ngroup->done) + found |= node_shader_script_update_text_recursive(engine, type, ngroup, text); } - else if (node->type == SH_NODE_SCRIPT && node->id == &data->text->id) { - data->type->update_script_node(data->engine, ntree, node); - data->found = TRUE; + else if (node->type == SH_NODE_SCRIPT && node->id == &text->id) { + type->update_script_node(engine, ntree, node); + found = TRUE; } } + + return found; } static int node_shader_script_update_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - ScriptUpdateData data; PointerRNA nodeptr = CTX_data_pointer_get_type(C, "node", &RNA_ShaderNodeScript); + RenderEngine *engine; + RenderEngineType *type; + int found = FALSE; /* setup render engine */ - data.type = RE_engines_find(scene->r.engine); - data.engine = RE_engine_create(data.type); - data.engine->reports = op->reports; - data.text = NULL; - data.found = FALSE; + type = RE_engines_find(scene->r.engine); + engine = RE_engine_create(type); + engine->reports = op->reports; if (nodeptr.data) { /* update single node */ bNodeTree *ntree = nodeptr.id.data; bNode *node = nodeptr.data; - data.type->update_script_node(data.engine, ntree, node); + type->update_script_node(engine, ntree, node); - data.found = TRUE; + found = TRUE; } else { /* update all nodes using text datablock */ - data.text = CTX_data_pointer_get_type(C, "edit_text", &RNA_Text).data; - - if (data.text) { - bNodeTreeType *ntreetype = ntreeGetType(NTREE_SHADER); - - if (ntreetype && ntreetype->foreach_nodetree) - ntreetype->foreach_nodetree(bmain, &data, node_shader_script_update_text); + Text *text = CTX_data_pointer_get_type(C, "edit_text", &RNA_Text).data; + + if (text) { + /* clear flags for recursion check */ + FOREACH_NODETREE(bmain, ntree, id) { + if (ntree->type == NTREE_SHADER) + ntree->done = FALSE; + } FOREACH_NODETREE_END + + FOREACH_NODETREE(bmain, ntree, id) { + if (ntree->type == NTREE_SHADER) { + if (!ntree->done) + found |= node_shader_script_update_text_recursive(engine, type, ntree, text); + } + } FOREACH_NODETREE_END - if (!data.found) + if (!found) BKE_report(op->reports, RPT_INFO, "Text not used by any node, no update done"); } } - RE_engine_free(data.engine); + RE_engine_free(engine); - return (data.found)? OPERATOR_FINISHED: OPERATOR_CANCELLED; + return (found)? OPERATOR_FINISHED: OPERATOR_CANCELLED; } void NODE_OT_shader_script_update(wmOperatorType *ot) @@ -2275,3 +2382,105 @@ void NODE_OT_shader_script_update(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/* ********************** Viewer border ******************/ + +static void viewer_border_corner_to_backdrop(SpaceNode *snode, ARegion *ar, int x, int y, + int backdrop_width, int backdrop_height, + float *fx, float *fy) +{ + float bufx, bufy; + + bufx = backdrop_width * snode->zoom; + bufy = backdrop_height * snode->zoom; + + *fx = (bufx > 0.0f ? ((float) x - 0.5f * ar->winx - snode->xof) / bufx + 0.5f : 0.0f); + *fy = (bufy > 0.0f ? ((float) y - 0.5f * ar->winy - snode->yof) / bufy + 0.5f : 0.0f); +} + +static int viewer_border_exec(bContext *C, wmOperator *op) +{ + Image *ima; + void *lock; + ImBuf *ibuf; + + ED_preview_kill_jobs(C); + + ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node"); + ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + + if (ibuf) { + ARegion *ar = CTX_wm_region(C); + SpaceNode *snode = CTX_wm_space_node(C); + bNodeTree *btree = snode->edittree; + rcti rect; + rctf rectf; + + /* get border from operator */ + WM_operator_properties_border_to_rcti(op, &rect); + + /* convert border to unified space within backdrop image */ + viewer_border_corner_to_backdrop(snode, ar, rect.xmin, rect.ymin, ibuf->x, ibuf->y, + &rectf.xmin, &rectf.ymin); + + viewer_border_corner_to_backdrop(snode, ar, rect.xmax, rect.ymax, ibuf->x, ibuf->y, + &rectf.xmax, &rectf.ymax); + + /* clamp coordinates */ + rectf.xmin = max_ff(rectf.xmin, 0.0f); + rectf.ymin = max_ff(rectf.ymin, 0.0f); + rectf.xmax = min_ff(rectf.xmax, 1.0f); + rectf.ymax = min_ff(rectf.ymax, 1.0f); + + if (rectf.xmin < rectf.xmax && rectf.ymin < rectf.ymax) { + btree->viewer_border = rectf; + + if (rectf.xmin == 0.0f && rectf.ymin == 0.0f && + rectf.xmax == 1.0f && rectf.ymax == 1.0f) + { + btree->flag &= ~NTREE_VIEWER_BORDER; + } + else { + if (ibuf->rect) + memset(ibuf->rect, 0, 4 * ibuf->x * ibuf->y); + + if (ibuf->rect_float) + memset(ibuf->rect_float, 0, 4 * ibuf->x * ibuf->y * sizeof(float)); + + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; + + btree->flag |= NTREE_VIEWER_BORDER; + } + + snode_notify(C, snode); + WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL); + } + else { + btree->flag &= ~NTREE_VIEWER_BORDER; + } + } + + BKE_image_release_ibuf(ima, ibuf, lock); + + return OPERATOR_FINISHED; +} + +void NODE_OT_viewer_border(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Viewer Border"; + ot->description = "Set the boundaries for viewer operations"; + ot->idname = "NODE_OT_viewer_border"; + + /* api callbacks */ + ot->invoke = WM_border_select_invoke; + ot->exec = viewer_border_exec; + ot->modal = WM_border_select_modal; + ot->cancel = WM_border_select_cancel; + ot->poll = composite_node_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + WM_operator_properties_gesture_border(ot, TRUE); +} |