From 8e0fe8bff72e2dc2926618577eaffdd3417a8304 Mon Sep 17 00:00:00 2001 From: Lukas Toenne Date: Mon, 5 Sep 2011 21:01:50 +0000 Subject: Merged the particles-2010 branch with node improvements into trunk. This branch adds mostly organizational improvements to the node system by renaming the node folders and files. A couple of internal features have been added too. Detailed information can be found on the wiki page: http://wiki.blender.org/index.php/User:Phonybone/Particles2010 --- source/blender/editors/space_node/drawnode.c | 750 ++++++++++++++++++++++- source/blender/editors/space_node/node_buttons.c | 4 +- source/blender/editors/space_node/node_draw.c | 679 +++++--------------- source/blender/editors/space_node/node_edit.c | 672 +++++++++++++------- source/blender/editors/space_node/node_header.c | 192 +++--- source/blender/editors/space_node/node_intern.h | 15 +- source/blender/editors/space_node/node_ops.c | 3 +- source/blender/editors/space_node/node_select.c | 24 +- source/blender/editors/space_node/node_state.c | 34 +- source/blender/editors/space_node/space_node.c | 22 +- 10 files changed, 1526 insertions(+), 869 deletions(-) (limited to 'source/blender/editors/space_node') diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 0474d1f3bb1..890b04dce91 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -53,9 +53,10 @@ #include "BKE_image.h" #include "BKE_library.h" #include "BKE_main.h" +#include "BKE_node.h" -#include "CMP_node.h" -#include "SHD_node.h" +#include "NOD_composite.h" +#include "NOD_shader.h" #include "BIF_gl.h" #include "BIF_glutil.h" @@ -81,6 +82,141 @@ #include "node_intern.h" +// XXX interface.h +extern void ui_dropshadow(rctf *rct, float radius, float aspect, int select); + +/* ****************** SOCKET BUTTON DRAW FUNCTIONS ***************** */ + +static void node_sync_cb(bContext *UNUSED(C), void *snode_v, void *node_v) +{ + SpaceNode *snode= snode_v; + + if(snode->treetype==NTREE_SHADER) { + nodeShaderSynchronizeID(node_v, 1); + // allqueue(REDRAWBUTSSHADING, 0); + } +} + +void node_socket_button_default(const bContext *C, uiBlock *block, + bNodeTree *ntree, bNode *node, bNodeSocket *sock, + const char *name, int x, int y, int width) +{ + PointerRNA ptr; + uiBut *bt; + + RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr); + + bt = uiDefButR(block, NUM, B_NODE_EXEC, name, + x, y+1, width, NODE_DY-2, + &ptr, "default_value", 0, 0, 0, -1, -1, NULL); + if (node) + uiButSetFunc(bt, node_sync_cb, CTX_wm_space_node(C), node); +} + +typedef struct SocketComponentMenuArgs { + PointerRNA ptr; + int x, y, width; + uiButHandleFunc cb; + void *arg1, *arg2; +} SocketComponentMenuArgs; +/* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */ +static uiBlock *socket_component_menu(bContext *C, ARegion *ar, void *args_v) +{ + SocketComponentMenuArgs *args= (SocketComponentMenuArgs*)args_v; + uiBlock *block; + uiLayout *layout; + + block= uiBeginBlock(C, ar, "socket menu", UI_EMBOSS); + uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN); + + layout= uiLayoutColumn(uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, args->x, args->y+2, args->width, NODE_DY, U.uistyles.first), 0); + + uiItemR(layout, &args->ptr, "default_value", UI_ITEM_R_EXPAND, "", ICON_NONE); + + return block; +} +void node_socket_button_components(const bContext *C, uiBlock *block, + bNodeTree *ntree, bNode *node, bNodeSocket *sock, + const char *name, int x, int y, int width) +{ + PointerRNA ptr; + SocketComponentMenuArgs *args; + + RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr); + + args= MEM_callocN(sizeof(SocketComponentMenuArgs), "SocketComponentMenuArgs"); + + args->ptr = ptr; + args->x = x; + args->y = y; + args->width = width; + args->cb = node_sync_cb; + args->arg1 = CTX_wm_space_node(C); + args->arg2 = node; + + uiDefBlockButN(block, socket_component_menu, args, name, x, y+1, width, NODE_DY-2, ""); +} + +void node_socket_button_color(const bContext *C, uiBlock *block, + bNodeTree *ntree, bNode *node, bNodeSocket *sock, + const char *name, int x, int y, int width) +{ + PointerRNA ptr; + uiBut *bt; + int labelw= width - 40; + + RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr); + + bt=uiDefButR(block, COL, B_NODE_EXEC, "", + x, y+2, (labelw>0 ? 40 : width), NODE_DY-2, + &ptr, "default_value", 0, 0, 0, -1, -1, NULL); + if (node) + uiButSetFunc(bt, node_sync_cb, CTX_wm_space_node(C), node); + + if (name[0]!='\0' && labelw>0) + uiDefBut(block, LABEL, 0, name, x + 40, y+2, labelw, NODE_DY-2, NULL, 0, 0, 0, 0, ""); +} + +/* ****************** BASE DRAW FUNCTIONS FOR NEW OPERATOR NODES ***************** */ + +void node_draw_socket_new(bNodeSocket *sock, float size) +{ + float x=sock->locx, y=sock->locy; + + /* 16 values of sin function */ + static float si[16] = { + 0.00000000f, 0.39435585f,0.72479278f,0.93775213f, + 0.99871650f,0.89780453f,0.65137248f,0.29936312f, + -0.10116832f,-0.48530196f,-0.79077573f,-0.96807711f, + -0.98846832f,-0.84864425f,-0.57126821f,-0.20129852f + }; + /* 16 values of cos function */ + static float co[16] ={ + 1.00000000f,0.91895781f,0.68896691f,0.34730525f, + -0.05064916f,-0.44039415f,-0.75875812f,-0.95413925f, + -0.99486932f,-0.87434661f,-0.61210598f,-0.25065253f, + 0.15142777f,0.52896401f,0.82076344f,0.97952994f, + }; + int a; + + glColor3ub(180, 180, 180); + + glBegin(GL_POLYGON); + for(a=0; a<16; a++) + glVertex2f(x+size*si[a], y+size*co[a]); + glEnd(); + + glColor4ub(0, 0, 0, 150); + glEnable(GL_BLEND); + glEnable( GL_LINE_SMOOTH ); + glBegin(GL_LINE_LOOP); + for(a=0; a<16; a++) + glVertex2f(x+size*si[a], y+size*co[a]); + glEnd(); + glDisable( GL_LINE_SMOOTH ); + glDisable(GL_BLEND); +} + /* ****************** BUTTON CALLBACKS FOR ALL TREES ***************** */ static void node_buts_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -192,11 +328,12 @@ static void node_buts_normal(uiLayout *layout, bContext *UNUSED(C), PointerRNA * bNode *node= ptr->data; rctf *butr= &node->butr; bNodeSocket *sock= node->outputs.first; /* first socket stores normal */ + float *nor= ((bNodeSocketValueVector*)sock->default_value)->value; uiBut *bt; bt= uiDefButF(block, BUT_NORMAL, B_NODE_EXEC, "", (short)butr->xmin, (short)butr->xmin, butr->xmax-butr->xmin, butr->xmax-butr->xmin, - sock->ns.vec, 0.0f, 1.0f, 0, 0, ""); + nor, 0.0f, 1.0f, 0, 0, ""); uiButSetFunc(bt, node_normal_cb, ntree, node); } #if 0 // not used in 2.5x yet @@ -287,6 +424,470 @@ static void node_buts_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *pt uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); } +static int node_resize_area_default(bNode *node, int x, int y) +{ + if (node->flag & NODE_HIDDEN) { + rctf totr= node->totr; + /* right part of node */ + totr.xmin= node->totr.xmax-20.0f; + return BLI_in_rctf(&totr, x, y); + } + else { + /* rect we're interested in is just the bottom right corner */ + rctf totr= node->totr; + /* bottom right corner */ + totr.xmin= totr.xmax-10.0f; + totr.ymax= totr.ymin+10.0f; + return BLI_in_rctf(&totr, x, y); + } +} + +/* ****************** BUTTON CALLBACKS FOR COMMON NODES ***************** */ + +/* width of socket columns in group display */ +#define NODE_GROUP_FRAME 120 + +/* based on settings in node, sets drawing rect info. each redraw! */ +/* note: this assumes only 1 group at a time is drawn (linked data) */ +/* in node->totr the entire boundbox for the group is stored */ +static void node_update_group(const bContext *C, bNodeTree *ntree, bNode *gnode) +{ + if (!(gnode->flag & NODE_GROUP_EDIT)) { + node_update_default(C, ntree, gnode); + } + else { + bNodeTree *ngroup= (bNodeTree *)gnode->id; + bNode *node; + bNodeSocket *sock, *gsock; + float locx, locy; + rctf *rect= &gnode->totr; + float node_group_frame= U.dpi*NODE_GROUP_FRAME/72; + int counter; + int dy; + + /* get "global" coords */ + nodeSpaceCoords(gnode, &locx, &locy); + + /* center them, is a bit of abuse of locx and locy though */ + node_update_nodetree(C, ngroup, locx, locy); + + rect->xmin = rect->xmax = locx; + rect->ymin = rect->ymax = locy; + + counter= 1; + for(node= ngroup->nodes.first; node; node= node->next) { + if(counter) { + *rect= node->totr; + counter= 0; + } + else + BLI_union_rctf(rect, &node->totr); + } + + /* add some room for links to group sockets */ + rect->xmin -= 4*NODE_DY; + rect->xmax += 4*NODE_DY; + rect->ymin-= NODE_DY; + rect->ymax+= NODE_DY; + + /* input sockets */ + dy = 0.5f*(rect->ymin+rect->ymax) + NODE_DY*(BLI_countlist(&gnode->inputs)-1); + gsock=ngroup->inputs.first; + sock=gnode->inputs.first; + while (gsock || sock) { + while (sock && !sock->groupsock) { + sock->locx = rect->xmin - node_group_frame; + sock->locy = dy; + + /* prevent long socket lists from growing out of the group box */ + if (dy-3*NODE_DYS < rect->ymin) + rect->ymin = dy-3*NODE_DYS; + if (dy+3*NODE_DYS > rect->ymax) + rect->ymax = dy+3*NODE_DYS; + dy -= 2*NODE_DY; + + sock = sock->next; + } + while (gsock && (!sock || sock->groupsock!=gsock)) { + gsock->locx = rect->xmin; + gsock->locy = dy; + + /* prevent long socket lists from growing out of the group box */ + if (dy-3*NODE_DYS < rect->ymin) + rect->ymin = dy-3*NODE_DYS; + if (dy+3*NODE_DYS > rect->ymax) + rect->ymax = dy+3*NODE_DYS; + dy -= 2*NODE_DY; + + gsock = gsock->next; + } + while (sock && gsock && sock->groupsock==gsock) { + gsock->locx = rect->xmin; + sock->locx = rect->xmin - node_group_frame; + sock->locy = gsock->locy = dy; + + /* prevent long socket lists from growing out of the group box */ + if (dy-3*NODE_DYS < rect->ymin) + rect->ymin = dy-3*NODE_DYS; + if (dy+3*NODE_DYS > rect->ymax) + rect->ymax = dy+3*NODE_DYS; + dy -= 2*NODE_DY; + + sock = sock->next; + gsock = gsock->next; + } + } + + /* output sockets */ + dy = 0.5f*(rect->ymin+rect->ymax) + NODE_DY*(BLI_countlist(&gnode->outputs)-1); + gsock=ngroup->outputs.first; + sock=gnode->outputs.first; + while (gsock || sock) { + while (sock && !sock->groupsock) { + sock->locx = rect->xmax + node_group_frame; + sock->locy = dy - NODE_DYS; + + /* prevent long socket lists from growing out of the group box */ + if (dy-3*NODE_DYS < rect->ymin) + rect->ymin = dy-3*NODE_DYS; + if (dy+3*NODE_DYS > rect->ymax) + rect->ymax = dy+3*NODE_DYS; + dy -= 2*NODE_DY; + + sock = sock->next; + } + while (gsock && (!sock || sock->groupsock!=gsock)) { + gsock->locx = rect->xmax; + gsock->locy = dy - NODE_DYS; + + /* prevent long socket lists from growing out of the group box */ + if (dy-3*NODE_DYS < rect->ymin) + rect->ymin = dy-3*NODE_DYS; + if (dy+3*NODE_DYS > rect->ymax) + rect->ymax = dy+3*NODE_DYS; + dy -= 2*NODE_DY; + + gsock = gsock->next; + } + while (sock && gsock && sock->groupsock==gsock) { + gsock->locx = rect->xmax; + sock->locx = rect->xmax + node_group_frame; + sock->locy = gsock->locy = dy - NODE_DYS; + + /* prevent long socket lists from growing out of the group box */ + if (dy-3*NODE_DYS < rect->ymin) + rect->ymin = dy-3*NODE_DYS; + if (dy+3*NODE_DYS > rect->ymax) + rect->ymax = dy+3*NODE_DYS; + dy -= 2*NODE_DY; + + sock = sock->next; + gsock = gsock->next; + } + } + } +} + +static void update_group_input_cb(bContext *UNUSED(C), void *UNUSED(snode_v), void *ngroup_v) +{ + bNodeTree *ngroup= (bNodeTree*)ngroup_v; + + ngroup->update |= NTREE_UPDATE_GROUP_IN; + ntreeUpdateTree(ngroup); +} + +static void update_group_output_cb(bContext *UNUSED(C), void *UNUSED(snode_v), void *ngroup_v) +{ + bNodeTree *ngroup= (bNodeTree*)ngroup_v; + + ngroup->update |= NTREE_UPDATE_GROUP_OUT; + ntreeUpdateTree(ngroup); +} + +static void draw_group_socket_name(SpaceNode *snode, bNode *gnode, bNodeSocket *sock, int in_out, float xoffset, float yoffset) +{ + bNodeTree *ngroup= (bNodeTree*)gnode->id; + uiBut *bt; + + if (sock->flag & SOCK_DYNAMIC) { + bt = uiDefBut(gnode->block, TEX, 0, "", + sock->locx+xoffset, sock->locy+1+yoffset, 72, NODE_DY, + sock->name, 0, 31, 0, 0, ""); + if (in_out==SOCK_IN) + uiButSetFunc(bt, update_group_input_cb, snode, ngroup); + else + uiButSetFunc(bt, update_group_output_cb, snode, ngroup); + } + else { + uiDefBut(gnode->block, LABEL, 0, sock->name, + sock->locx+xoffset, sock->locy+1+yoffset, 72, NODE_DY, + NULL, 0, 31, 0, 0, ""); + } +} + +static void draw_group_socket(const bContext *C, SpaceNode *snode, bNodeTree *ntree, bNode *gnode, bNodeSocket *sock, bNodeSocket *gsock, int index, int in_out) +{ + bNodeTree *ngroup= (bNodeTree*)gnode->id; + bNodeSocketType *stype= ntreeGetSocketType(gsock ? gsock->type : sock->type); + uiBut *bt; + float offset; + int draw_value; + float node_group_frame= U.dpi*NODE_GROUP_FRAME/72; + float socket_size= NODE_SOCKSIZE*U.dpi/72; + float arrowbutw= 0.8f*UI_UNIT_X; + /* layout stuff for buttons on group left frame */ + float colw= 0.6f*node_group_frame; + float col1= 6; + float col2= col1 + colw+6; + float col3= node_group_frame - arrowbutw - 6; + /* layout stuff for buttons on group right frame */ + float cor1= 6; + float cor2= cor1 + arrowbutw + 6; + float cor3= cor2 + arrowbutw + 6; + + /* node and group socket circles */ + if (sock) + node_socket_circle_draw(ntree, sock, socket_size); + if (gsock) + node_socket_circle_draw(ngroup, gsock, socket_size); + + /* socket name */ + offset = (in_out==SOCK_IN ? col1 : cor3); + if (!gsock) + offset += (in_out==SOCK_IN ? node_group_frame : -node_group_frame); + + /* draw both name and value button if: + * 1) input: not internal + * 2) output: (node type uses const outputs) and (group output is unlinked) + */ + switch (in_out) { + case SOCK_IN: + draw_value = !(gsock && (gsock->flag & SOCK_INTERNAL)); + break; + case SOCK_OUT: + if (gnode->typeinfo->flag & NODE_CONST_OUTPUT) + draw_value = !(gsock && gsock->link); + else + draw_value = 0; + break; + } + if (draw_value) { + /* both name and value buttons */ + if (gsock) { + draw_group_socket_name(snode, gnode, gsock, in_out, offset, 0); + if (stype->buttonfunc) + stype->buttonfunc(C, gnode->block, ngroup, NULL, gsock, "", gsock->locx+offset, gsock->locy-NODE_DY, colw); + } + else { + draw_group_socket_name(snode, gnode, sock, in_out, offset, 0); + if (stype->buttonfunc) + stype->buttonfunc(C, gnode->block, ngroup, NULL, sock, "", sock->locx+offset, sock->locy-NODE_DY, colw); + } + } + else { + /* only name, no value button */ + if (gsock) + draw_group_socket_name(snode, gnode, gsock, in_out, offset, -NODE_DYS); + else + draw_group_socket_name(snode, gnode, sock, in_out, offset, -NODE_DYS); + } + + if (gsock && (gsock->flag & SOCK_DYNAMIC)) { + /* up/down buttons */ + offset = (in_out==SOCK_IN ? col2 : cor2); + uiBlockSetDirection(gnode->block, UI_TOP); + uiBlockBeginAlign(gnode->block); + bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_move_up", 0, ICON_TRIA_UP, + gsock->locx+offset, gsock->locy, arrowbutw, arrowbutw, ""); + if (!gsock->prev || !(gsock->prev->flag & SOCK_DYNAMIC)) + uiButSetFlag(bt, UI_BUT_DISABLED); + RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index); + RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", in_out); + bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_move_down", 0, ICON_TRIA_DOWN, + gsock->locx+offset, gsock->locy-arrowbutw, arrowbutw, arrowbutw, ""); + if (!gsock->next || !(gsock->next->flag & SOCK_DYNAMIC)) + uiButSetFlag(bt, UI_BUT_DISABLED); + RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index); + RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", in_out); + uiBlockEndAlign(gnode->block); + uiBlockSetDirection(gnode->block, 0); + + /* remove button */ + offset = (in_out==SOCK_IN ? col3 : col1); + uiBlockSetEmboss(gnode->block, UI_EMBOSSN); + bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_remove", 0, ICON_X, + gsock->locx+offset, gsock->locy-0.5f*arrowbutw, arrowbutw, arrowbutw, ""); + RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index); + RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", in_out); + uiBlockSetEmboss(gnode->block, UI_EMBOSS); + } +} + +/* groups are, on creation, centered around 0,0 */ +static void node_draw_group(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *gnode) +{ + if (!(gnode->flag & NODE_GROUP_EDIT)) { + node_draw_default(C, ar, snode, ntree, gnode); + } + else { + bNodeTree *ngroup= (bNodeTree *)gnode->id; + bNodeSocket *sock, *gsock; + uiLayout *layout; + PointerRNA ptr; + rctf rect= gnode->totr; + float node_group_frame= U.dpi*NODE_GROUP_FRAME/72; + float group_header= 26*U.dpi/72; + + int index; + + /* backdrop header */ + glEnable(GL_BLEND); + uiSetRoundBox(3); + UI_ThemeColorShadeAlpha(TH_NODE_GROUP, 0, -70); + uiDrawBox(GL_POLYGON, rect.xmin-node_group_frame, rect.ymax, rect.xmax+node_group_frame, rect.ymax+group_header, BASIS_RAD); + + /* backdrop body */ + UI_ThemeColorShadeAlpha(TH_BACK, -8, -70); + uiSetRoundBox(0); + uiDrawBox(GL_POLYGON, rect.xmin, rect.ymin, rect.xmax, rect.ymax, BASIS_RAD); + + /* input column */ + UI_ThemeColorShadeAlpha(TH_BACK, 10, -50); + uiSetRoundBox(8); + uiDrawBox(GL_POLYGON, rect.xmin-node_group_frame, rect.ymin, rect.xmin, rect.ymax, BASIS_RAD); + + /* output column */ + UI_ThemeColorShadeAlpha(TH_BACK, 10, -50); + uiSetRoundBox(4); + uiDrawBox(GL_POLYGON, rect.xmax, rect.ymin, rect.xmax+node_group_frame, rect.ymax, BASIS_RAD); + + /* input column separator */ + glColor4ub(200, 200, 200, 140); + glBegin(GL_LINES); + glVertex2f(rect.xmin, rect.ymin); + glVertex2f(rect.xmin, rect.ymax); + glEnd(); + + /* output column separator */ + glColor4ub(200, 200, 200, 140); + glBegin(GL_LINES); + glVertex2f(rect.xmax, rect.ymin); + glVertex2f(rect.xmax, rect.ymax); + glEnd(); + + /* group node outline */ + uiSetRoundBox(15); + glColor4ub(200, 200, 200, 140); + glEnable( GL_LINE_SMOOTH ); + uiDrawBox(GL_LINE_LOOP, rect.xmin-node_group_frame, rect.ymin, rect.xmax+node_group_frame, rect.ymax+group_header, BASIS_RAD); + glDisable( GL_LINE_SMOOTH ); + glDisable(GL_BLEND); + + /* backdrop title */ + UI_ThemeColor(TH_TEXT_HI); + + layout = uiBlockLayout(gnode->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, (short)(rect.xmin+15), (short)(rect.ymax+group_header), + MIN2((int)(rect.xmax - rect.xmin-18.0f), node_group_frame+20), group_header, U.uistyles.first); + RNA_pointer_create(&ntree->id, &RNA_Node, gnode, &ptr); + uiTemplateIDBrowse(layout, (bContext*)C, &ptr, "node_tree", NULL, NULL, NULL); + uiBlockLayoutResolve(gnode->block, NULL, NULL); + + /* draw the internal tree nodes and links */ + node_draw_nodetree(C, ar, snode, ngroup); + + /* group sockets */ + gsock=ngroup->inputs.first; + sock=gnode->inputs.first; + index = 0; + while (gsock || sock) { + while (sock && !sock->groupsock) { + draw_group_socket(C, snode, ntree, gnode, sock, NULL, index, SOCK_IN); + sock = sock->next; + } + while (gsock && (!sock || sock->groupsock!=gsock)) { + draw_group_socket(C, snode, ntree, gnode, NULL, gsock, index, SOCK_IN); + gsock = gsock->next; + ++index; + } + while (sock && gsock && sock->groupsock==gsock) { + draw_group_socket(C, snode, ntree, gnode, sock, gsock, index, SOCK_IN); + sock = sock->next; + gsock = gsock->next; + ++index; + } + } + gsock=ngroup->outputs.first; + sock=gnode->outputs.first; + index = 0; + while (gsock || sock) { + while (sock && !sock->groupsock) { + draw_group_socket(C, snode, ntree, gnode, sock, NULL, index, SOCK_OUT); + sock = sock->next; + } + while (gsock && (!sock || sock->groupsock!=gsock)) { + draw_group_socket(C, snode, ntree, gnode, NULL, gsock, index, SOCK_OUT); + gsock = gsock->next; + ++index; + } + while (sock && gsock && sock->groupsock==gsock) { + draw_group_socket(C, snode, ntree, gnode, sock, gsock, index, SOCK_OUT); + sock = sock->next; + gsock = gsock->next; + ++index; + } + } + + uiEndBlock(C, gnode->block); + uiDrawBlock(C, gnode->block); + gnode->block= NULL; + } +} + +static void node_common_buts_whileloop(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "max_iterations", 0, NULL, 0); +} + +static void node_update_frame(const bContext *UNUSED(C), bNodeTree *UNUSED(ntree), bNode *node) +{ + float locx, locy; + + /* get "global" coords */ + nodeSpaceCoords(node, &locx, &locy); + + node->prvr.xmin= locx + NODE_DYS; + node->prvr.xmax= locx + node->width- NODE_DYS; + + node->totr.xmin= locx; + node->totr.xmax= locx + node->width; + node->totr.ymax= locy; + node->totr.ymin= locy - node->height; +} + +static void node_common_set_butfunc(bNodeType *ntype) +{ + switch(ntype->type) { + case NODE_GROUP: +// ntype->uifunc= node_common_buts_group; + ntype->drawfunc= node_draw_group; + ntype->drawupdatefunc= node_update_group; + break; + case NODE_FORLOOP: +// ntype->uifunc= node_common_buts_group; + ntype->drawfunc= node_draw_group; + ntype->drawupdatefunc= node_update_group; + break; + case NODE_WHILELOOP: + ntype->uifunc= node_common_buts_whileloop; + ntype->drawfunc= node_draw_group; + ntype->drawupdatefunc= node_update_group; + break; + case NODE_FRAME: + ntype->drawupdatefunc= node_update_frame; + break; + } +} + /* ****************** BUTTON CALLBACKS FOR SHADER NODES ***************** */ static void node_browse_text_cb(bContext *C, void *ntree_v, void *node_v) @@ -470,8 +1071,6 @@ static void node_shader_set_butfunc(bNodeType *ntype) case NODE_DYNAMIC: ntype->uifunc= node_shader_buts_dynamic; break; - default: - ntype->uifunc= NULL; } if (ntype->uifuncbut == NULL) ntype->uifuncbut = ntype->uifunc; } @@ -1225,8 +1824,6 @@ static void node_composit_set_butfunc(bNodeType *ntype) case CMP_NODE_SEPYCCA: ntype->uifunc=node_composit_buts_ycc; break; - default: - ntype->uifunc= NULL; } if (ntype->uifuncbut == NULL) ntype->uifuncbut = ntype->uifunc; @@ -1381,9 +1978,6 @@ static void node_texture_set_butfunc(bNodeType *ntype) case TEX_NODE_OUTPUT: ntype->uifunc = node_texture_buts_output; break; - - default: - ntype->uifunc= NULL; } if (ntype->uifuncbut == NULL) ntype->uifuncbut = ntype->uifunc; } @@ -1392,24 +1986,60 @@ static void node_texture_set_butfunc(bNodeType *ntype) void ED_init_node_butfuncs(void) { + bNodeTreeType *treetype; bNodeType *ntype; - - /* shader nodes */ - ntype= node_all_shaders.first; - while(ntype) { - node_shader_set_butfunc(ntype); - ntype= ntype->next; - } - /* composit nodes */ - ntype= node_all_composit.first; - while(ntype) { - node_composit_set_butfunc(ntype); - ntype= ntype->next; + bNodeSocketType *stype; + int i; + + /* node type ui functions */ + for (i=0; i < NUM_NTREE_TYPES; ++i) { + treetype = ntreeGetType(i); + if (treetype) { + for (ntype= treetype->node_types.first; ntype; ntype= ntype->next) { + /* default ui functions */ + ntype->drawfunc = node_draw_default; + ntype->drawupdatefunc = node_update_default; + ntype->uifunc = NULL; + ntype->uifuncbut = NULL; + ntype->resize_area_func = node_resize_area_default; + + node_common_set_butfunc(ntype); + + switch (i) { + case NTREE_COMPOSIT: + node_composit_set_butfunc(ntype); + break; + case NTREE_SHADER: + node_shader_set_butfunc(ntype); + break; + case NTREE_TEXTURE: + node_texture_set_butfunc(ntype); + break; + } + } + } } - ntype = node_all_textures.first; - while(ntype) { - node_texture_set_butfunc(ntype); - ntype= ntype->next; + + /* socket type ui functions */ + for (i=0; i < NUM_SOCKET_TYPES; ++i) { + stype = ntreeGetSocketType(i); + if (stype) { + switch(stype->type) { + case SOCK_FLOAT: + case SOCK_INT: + case SOCK_BOOLEAN: + stype->buttonfunc = node_socket_button_default; + break; + case SOCK_VECTOR: + stype->buttonfunc = node_socket_button_components; + break; + case SOCK_RGBA: + stype->buttonfunc = node_socket_button_color; + break; + default: + stype->buttonfunc = NULL; + } + } } } @@ -1840,6 +2470,69 @@ void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link, int t } } +static void node_link_straight_points(View2D *UNUSED(v2d), SpaceNode *snode, bNodeLink *link, float coord_array[][2]) +{ + if(link->fromsock) { + coord_array[0][0]= link->fromsock->locx; + coord_array[0][1]= link->fromsock->locy; + } + else { + if(snode==NULL) return; + coord_array[0][0]= snode->mx; + coord_array[0][1]= snode->my; + } + if(link->tosock) { + coord_array[1][0]= link->tosock->locx; + coord_array[1][1]= link->tosock->locy; + } + else { + if(snode==NULL) return; + coord_array[1][0]= snode->mx; + coord_array[1][1]= snode->my; + } +} + +void node_draw_link_straight(View2D *v2d, SpaceNode *snode, bNodeLink *link, int th_col1, int do_shaded, int th_col2, int do_triple, int th_col3 ) +{ + float coord_array[2][2]; + float linew; + int i; + + node_link_straight_points(v2d, snode, link, coord_array); + + /* store current linewidth */ + glGetFloatv(GL_LINE_WIDTH, &linew); + + glEnable(GL_LINE_SMOOTH); + + if(do_triple) { + UI_ThemeColorShadeAlpha(th_col3, -80, -120); + glLineWidth(4.0f); + + glBegin(GL_LINES); + glVertex2fv(coord_array[0]); + glVertex2fv(coord_array[1]); + glEnd(); + } + + UI_ThemeColor(th_col1); + glLineWidth(1.5f); + + glBegin(GL_LINE_STRIP); + for (i=0; i < LINK_RESOL; ++i) { + float t= (float)i/(float)(LINK_RESOL-1); + if(do_shaded) + UI_ThemeColorBlend(th_col1, th_col2, t); + glVertex2f((1.0f-t)*coord_array[0][0]+t*coord_array[1][0], (1.0f-t)*coord_array[0][1]+t*coord_array[1][1]); + } + glEnd(); + + glDisable(GL_LINE_SMOOTH); + + /* restore previuos linewidth */ + glLineWidth(linew); +} + /* note; this is used for fake links in groups too */ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link) { @@ -1868,7 +2561,7 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link) } else { /* check cyclic */ - if(link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF) { + if((link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF) && (link->flag & NODE_LINK_VALID)) { /* special indicated link, on drop-node */ if(link->flag & NODE_LINKFLAG_HILITE) { th_col1= th_col2= TH_ACTIVE; @@ -1890,6 +2583,5 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link) } node_draw_link_bezier(v2d, snode, link, th_col1, do_shaded, th_col2, do_triple, th_col3); +// node_draw_link_straight(v2d, snode, link, th_col1, do_shaded, th_col2, do_triple, th_col3); } - - diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c index 4b989a78fab..7b14e35e8fe 100644 --- a/source/blender/editors/space_node/node_buttons.c +++ b/source/blender/editors/space_node/node_buttons.c @@ -116,10 +116,12 @@ static void active_node_panel(const bContext *C, Panel *pa) uiItemS(layout); uiItemR(layout, &ptr, "name", 0, NULL, ICON_NODE); uiItemS(layout); - + /* draw this node's settings */ if (node->typeinfo && node->typeinfo->uifuncbut) node->typeinfo->uifuncbut(layout, (bContext *)C, &ptr); + else if (node->typeinfo && node->typeinfo->uifunc) + node->typeinfo->uifunc(layout, (bContext *)C, &ptr); } /* ******************* node buttons registration ************** */ diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index 950b3c72fe7..ec118bb3ca2 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -70,8 +70,8 @@ #include "RNA_access.h" -#include "CMP_node.h" -#include "SHD_node.h" +#include "NOD_composite.h" +#include "NOD_shader.h" #include "node_intern.h" @@ -81,6 +81,15 @@ // XXX interface.h extern void ui_dropshadow(rctf *rct, float radius, float aspect, int select); +/* XXX update functions for node editor are a mess, needs a clear concept */ +void ED_node_tree_update(SpaceNode *snode, Scene *scene) +{ + snode_set_context(snode, scene); + + if(snode->nodetree && snode->nodetree->id.us==0) + snode->nodetree->id.us= 1; +} + void ED_node_changed_update(ID *id, bNode *node) { bNodeTree *nodetree, *edittree; @@ -123,24 +132,25 @@ static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup) return 0; } +typedef struct NodeUpdateCalldata { + bNodeTree *ntree; + bNode *node; +} NodeUpdateCalldata; +static void node_generic_update_cb(void *calldata, ID *owner_id, bNodeTree *ntree) +{ + NodeUpdateCalldata *cd= (NodeUpdateCalldata*)calldata; + /* check if nodetree uses the group stored in calldata */ + if (has_nodetree(ntree, cd->ntree)) + ED_node_changed_update(owner_id, cd->node); +} void ED_node_generic_update(Main *bmain, bNodeTree *ntree, bNode *node) { - Material *ma; - Tex *tex; - Scene *sce; - + bNodeTreeType *tti= ntreeGetType(ntree->type); + NodeUpdateCalldata cd; + cd.ntree = ntree; + cd.node = node; /* look through all datablocks, to support groups */ - for(ma=bmain->mat.first; ma; ma=ma->id.next) - if(ma->nodetree && ma->use_nodes && has_nodetree(ma->nodetree, ntree)) - ED_node_changed_update(&ma->id, node); - - for(tex=bmain->tex.first; tex; tex=tex->id.next) - if(tex->nodetree && tex->use_nodes && has_nodetree(tex->nodetree, ntree)) - ED_node_changed_update(&tex->id, node); - - for(sce=bmain->scene.first; sce; sce=sce->id.next) - if(sce->nodetree && sce->use_nodes && has_nodetree(sce->nodetree, ntree)) - ED_node_changed_update(&sce->id, node); + tti->foreach_nodetree(bmain, &cd, node_generic_update_cb); if(ntree->type == NTREE_TEXTURE) ntreeTexCheckCyclics(ntree); @@ -204,14 +214,19 @@ static void node_uiblocks_init(const bContext *C, bNodeTree *ntree) } /* based on settings in node, sets drawing rect info. each redraw! */ -static void node_update(const bContext *C, bNodeTree *ntree, bNode *node) +static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) { uiLayout *layout; PointerRNA ptr; bNodeSocket *nsock; - float dy= node->locy; + float locx, locy; + float dy= locy; int buty; + /* get "global" coords */ + nodeSpaceCoords(node, &locx, &locy); + dy= locy; + /* header */ dy-= NODE_DY; @@ -222,14 +237,14 @@ static void node_update(const bContext *C, bNodeTree *ntree, bNode *node) /* output sockets */ for(nsock= node->outputs.first; nsock; nsock= nsock->next) { if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) { - nsock->locx= node->locx + node->width; + nsock->locx= locx + node->width; nsock->locy= dy - NODE_DYS; dy-= NODE_DY; } } - node->prvr.xmin= node->locx + NODE_DYS; - node->prvr.xmax= node->locx + node->width- NODE_DYS; + node->prvr.xmin= locx + NODE_DYS; + node->prvr.xmax= locx + node->width- NODE_DYS; /* preview rect? */ if(node->flag & NODE_PREVIEW) { @@ -286,21 +301,22 @@ static void node_update(const bContext *C, bNodeTree *ntree, bNode *node) node->butr.ymax= 0; RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr); - + layout= uiBlockLayout(node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, - node->locx+NODE_DYS, dy, node->butr.xmax, NODE_DY, U.uistyles.first); - + locx+NODE_DYS, dy, node->butr.xmax, NODE_DY, U.uistyles.first); + node->typeinfo->uifunc(layout, (bContext *)C, &ptr); + uiBlockEndAlign(node->block); uiBlockLayoutResolve(node->block, NULL, &buty); - + dy= buty - NODE_DYS/2; } /* input sockets */ for(nsock= node->inputs.first; nsock; nsock= nsock->next) { if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) { - nsock->locx= node->locx; + nsock->locx= locx; nsock->locy= dy - NODE_DYS; dy-= NODE_DY; } @@ -310,19 +326,23 @@ static void node_update(const bContext *C, bNodeTree *ntree, bNode *node) if(node->inputs.first || (node->flag & (NODE_OPTIONS|NODE_PREVIEW))==0 ) dy-= NODE_DYS/2; - node->totr.xmin= node->locx; - node->totr.xmax= node->locx + node->width; - node->totr.ymax= node->locy; - node->totr.ymin= MIN2(dy, node->locy-2*NODE_DY); + node->totr.xmin= locx; + node->totr.xmax= locx + node->width; + node->totr.ymax= locy; + node->totr.ymin= MIN2(dy, locy-2*NODE_DY); } /* based on settings in node, sets drawing rect info. each redraw! */ static void node_update_hidden(bNode *node) { bNodeSocket *nsock; + float locx, locy; float rad, drad, hiddenrad= HIDDEN_RAD; int totin=0, totout=0, tot; + /* get "global" coords */ + nodeSpaceCoords(node, &locx, &locy); + /* calculate minimal radius */ for(nsock= node->inputs.first; nsock; nsock= nsock->next) if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) @@ -336,9 +356,9 @@ static void node_update_hidden(bNode *node) hiddenrad += 5.0f*(float)(tot-4); } - node->totr.xmin= node->locx; - node->totr.xmax= node->locx + 3*hiddenrad + node->miniwidth; - node->totr.ymax= node->locy + (hiddenrad - 0.5f*NODE_DY); + node->totr.xmin= locx; + node->totr.xmax= locx + 3*hiddenrad + node->miniwidth; + node->totr.ymax= locy + (hiddenrad - 0.5f*NODE_DY); node->totr.ymin= node->totr.ymax - 2*hiddenrad; /* output sockets */ @@ -364,6 +384,14 @@ static void node_update_hidden(bNode *node) } } +void node_update_default(const bContext *C, bNodeTree *ntree, bNode *node) +{ + if(node->flag & NODE_HIDDEN) + node_update_hidden(node); + else + node_update_basis(C, ntree, node); +} + static int node_get_colorid(bNode *node) { if(node->typeinfo->nclass==NODE_CLASS_INPUT) @@ -383,138 +411,42 @@ static int node_get_colorid(bNode *node) return TH_NODE; } -/* based on settings in node, sets drawing rect info. each redraw! */ -/* note: this assumes only 1 group at a time is drawn (linked data) */ -/* in node->totr the entire boundbox for the group is stored */ -static void node_update_group(const bContext *C, bNodeTree *UNUSED(ntree), bNode *gnode) -{ - bNodeTree *ngroup= (bNodeTree *)gnode->id; - bNode *node; - bNodeSocket *sock, *gsock; - rctf *rect= &gnode->totr; - float node_group_frame= U.dpi*NODE_GROUP_FRAME/72; - int counter; - int dy; - - rect->xmin = rect->xmax = gnode->locx; - rect->ymin = rect->ymax = gnode->locy; - - /* center them, is a bit of abuse of locx and locy though */ - for(node= ngroup->nodes.first; node; node= node->next) { - node->locx+= gnode->locx; - node->locy+= gnode->locy; - - if(node->flag & NODE_HIDDEN) - node_update_hidden(node); - else - node_update(C, ngroup, node); - node->locx-= gnode->locx; - node->locy-= gnode->locy; - } - counter= 1; - for(node= ngroup->nodes.first; node; node= node->next) { - if(counter) { - *rect= node->totr; - counter= 0; - } - else - BLI_union_rctf(rect, &node->totr); - } - - /* add some room for links to group sockets */ - rect->xmin -= 4*NODE_DY; - rect->xmax += 4*NODE_DY; - rect->ymin-= NODE_DY; - rect->ymax+= NODE_DY; - - /* input sockets */ - dy = 0.5f*(rect->ymin+rect->ymax) + NODE_DY*(BLI_countlist(&gnode->inputs)-1); - for(gsock=ngroup->inputs.first, sock=gnode->inputs.first; gsock; gsock=gsock->next, sock=sock->next) { - gsock->locx = rect->xmin; - sock->locx = rect->xmin - node_group_frame; - sock->locy = gsock->locy = dy; - - /* prevent long socket lists from growing out of the group box */ - if (dy-3*NODE_DYS < rect->ymin) - rect->ymin = dy-3*NODE_DYS; - if (dy+3*NODE_DYS > rect->ymax) - rect->ymax = dy+3*NODE_DYS; - - dy -= 2*NODE_DY; - } - - /* output sockets */ - dy = 0.5f*(rect->ymin+rect->ymax) + NODE_DY*(BLI_countlist(&gnode->outputs)-1); - for(gsock=ngroup->outputs.first, sock=gnode->outputs.first; gsock; gsock=gsock->next, sock=sock->next) { - gsock->locx = rect->xmax; - sock->locx = rect->xmax + node_group_frame; - sock->locy = gsock->locy = dy - NODE_DYS; - - /* prevent long socket lists from growing out of the group box */ - if (dy-3*NODE_DYS < rect->ymin) - rect->ymin = dy-3*NODE_DYS; - if (dy+3*NODE_DYS > rect->ymax) - rect->ymax = dy+3*NODE_DYS; - - dy -= 2*NODE_DY; - } -} - /* note: in cmp_util.c is similar code, for node_compo_pass_on() */ /* note: in node_edit.c is similar code, for untangle node */ static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node) { - bNodeSocket *valsock= NULL, *colsock= NULL, *vecsock= NULL; - bNodeSocket *sock; + static int types[]= { SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA }; bNodeLink link= {NULL}; - int a; + int i; - /* connect the first value buffer in with first value out */ - /* connect the first RGBA buffer in with first RGBA out */ + /* connect the first input of each type with first output of the same type */ - /* test the inputs */ - for(a=0, sock= node->inputs.first; sock; sock= sock->next, a++) { - if(nodeCountSocketLinks(snode->edittree, sock)) { - if(sock->type==SOCK_VALUE && valsock==NULL) valsock= sock; - if(sock->type==SOCK_VECTOR && vecsock==NULL) vecsock= sock; - if(sock->type==SOCK_RGBA && colsock==NULL) colsock= sock; - } - } - - /* outputs, draw lines */ glEnable(GL_BLEND); glEnable( GL_LINE_SMOOTH ); - if(valsock || colsock || vecsock) { - for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) { - if(nodeCountSocketLinks(snode->edittree, sock)) { - link.tosock= sock; - - if(sock->type==SOCK_VALUE && valsock) { - link.fromsock= valsock; - node_draw_link_bezier(v2d, snode, &link, TH_REDALERT, 0, TH_WIRE, 0, TH_WIRE); - valsock= NULL; - } - if(sock->type==SOCK_VECTOR && vecsock) { - link.fromsock= vecsock; - node_draw_link_bezier(v2d, snode, &link, TH_REDALERT, 0, TH_WIRE, 0, TH_WIRE); - vecsock= NULL; - } - if(sock->type==SOCK_RGBA && colsock) { - link.fromsock= colsock; - node_draw_link_bezier(v2d, snode, &link, TH_REDALERT, 0, TH_WIRE, 0, TH_WIRE); - colsock= NULL; - } + link.fromnode = link.tonode = node; + for (i=0; i < 3; ++i) { + /* find input socket */ + for (link.fromsock=node->inputs.first; link.fromsock; link.fromsock=link.fromsock->next) + if (link.fromsock->type==types[i] && nodeCountSocketLinks(snode->edittree, link.fromsock)) + break; + if (link.fromsock) { + for (link.tosock=node->outputs.first; link.tosock; link.tosock=link.tosock->next) + if (link.tosock->type==types[i] && nodeCountSocketLinks(snode->edittree, link.tosock)) + break; + + if (link.tosock) { + node_draw_link_bezier(v2d, snode, &link, TH_REDALERT, 0, TH_WIRE, 0, TH_WIRE); } } } + glDisable(GL_BLEND); glDisable( GL_LINE_SMOOTH ); } -/* nice AA filled circle */ /* this might have some more generic use */ -static void circle_draw(float x, float y, float size, int col[3]) +static void node_circle_draw(float x, float y, float size, char *col) { /* 16 values of sin function */ static float si[16] = { @@ -550,37 +482,10 @@ static void circle_draw(float x, float y, float size, int col[3]) glDisable(GL_BLEND); } -static void socket_circle_draw(bNodeSocket *sock, float size) -{ - int col[3]; - - if(sock->type==-1) { - col[0]= 0; col[1]= 0; col[2]= 0; - } - else if(sock->type==SOCK_VALUE) { - col[0]= 160; col[1]= 160; col[2]= 160; - } - else if(sock->type==SOCK_VECTOR) { - col[0]= 100; col[1]= 100; col[2]= 200; - } - else if(sock->type==SOCK_RGBA) { - col[0]= 200; col[1]= 200; col[2]= 40; - } - else { - col[0]= 100; col[1]= 200; col[2]= 100; - } - - circle_draw(sock->locx, sock->locy, size, col); -} - -static void node_sync_cb(bContext *UNUSED(C), void *snode_v, void *node_v) +void node_socket_circle_draw(bNodeTree *UNUSED(ntree), bNodeSocket *sock, float size) { - SpaceNode *snode= snode_v; - - if(snode->treetype==NTREE_SHADER) { - nodeShaderSynchronizeID(node_v, 1); - // allqueue(REDRAWBUTSSHADING, 0); - } + bNodeSocketType *stype = ntreeGetSocketType(sock->type); + node_circle_draw(sock->locx, sock->locy, size, stype->ui_color); } /* ************** Socket callbacks *********** */ @@ -639,83 +544,6 @@ static void node_draw_preview(bNodePreview *preview, rctf *prv) } -typedef struct SocketVectorMenuArgs { - PointerRNA ptr; - int x, y, width; - uiButHandleFunc cb; - void *arg1, *arg2; -} SocketVectorMenuArgs; - -/* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */ -static uiBlock *socket_vector_menu(bContext *C, ARegion *ar, void *args_v) -{ - SocketVectorMenuArgs *args= (SocketVectorMenuArgs*)args_v; - uiBlock *block; - uiLayout *layout; - - block= uiBeginBlock(C, ar, "socket menu", UI_EMBOSS); - uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN); - - layout= uiLayoutColumn(uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, args->x, args->y+2, args->width, NODE_DY, U.uistyles.first), 0); - - uiItemR(layout, &args->ptr, "default_value", UI_ITEM_R_EXPAND, "", ICON_NONE); - - return block; -} - -static void node_draw_socket_button(bNodeTree *ntree, bNodeSocket *sock, const char *name, - uiBlock *block, int x, int y, int width, - uiButHandleFunc cb, void *arg1, void *arg2) -{ - uiBut *bt= NULL; - PointerRNA ptr; - int labelw; - SocketVectorMenuArgs *args; - - RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr); - - switch (sock->type) { - case SOCK_VALUE: - bt=uiDefButR(block, NUM, B_NODE_EXEC, name, - x, y+1, width, NODE_DY-2, - &ptr, "default_value", 0, sock->ns.min, sock->ns.max, -1, -1, NULL); - if (cb) - uiButSetFunc(bt, cb, arg1, arg2); - break; - - case SOCK_VECTOR: - args= MEM_callocN(sizeof(SocketVectorMenuArgs), "SocketVectorMenuArgs"); - - args->ptr = ptr; - args->x = x; - args->y = y; - args->width = width; - args->cb = cb; - args->arg1 = arg1; - args->arg2 = arg2; - - uiDefBlockButN(block, socket_vector_menu, args, name, - x, y+1, width, NODE_DY-2, - ""); - break; - - case SOCK_RGBA: - labelw= width - 40; - - bt=uiDefButR(block, COL, B_NODE_EXEC, "", - x, y+2, (labelw>0 ? 40 : width), NODE_DY-2, - &ptr, "default_value", 0, sock->ns.min, sock->ns.max, -1, -1, NULL); - if (cb) - uiButSetFunc(bt, cb, arg1, arg2); - - if (name[0]!='\0' && labelw>0) - uiDefBut(block, LABEL, 0, name, - x + 40, y+2, labelw, NODE_DY-2, - NULL, 0, 0, 0, 0, ""); - break; - } -} - static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node) { bNodeSocket *sock; @@ -809,13 +637,8 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN else UI_ThemeColor(TH_TEXT); */ - if (node->label[0]!='\0') - BLI_strncpy(showname, node->label, sizeof(showname)); - else if (node->typeinfo->labelfunc) - BLI_strncpy(showname, node->typeinfo->labelfunc(node), sizeof(showname)); - else - BLI_strncpy(showname, node->typeinfo->name, sizeof(showname)); - + BLI_strncpy(showname, nodeLabel(node), sizeof(showname)); + //if(node->flag & NODE_MUTED) // sprintf(showname, "[%s]", showname); @@ -855,37 +678,45 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN /* socket inputs, buttons */ for(sock= node->inputs.first; sock; sock= sock->next) { - if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) { - socket_circle_draw(sock, socket_size); - - if(node->block && sock->link==NULL) { - node_draw_socket_button(ntree, sock, sock->name, node->block, sock->locx+NODE_DYS, sock->locy-NODE_DYS, node->width-NODE_DY, node_sync_cb, snode, node); - } - else { - uiDefBut(node->block, LABEL, 0, sock->name, (short)(sock->locx+7), (short)(sock->locy-9.0f), - (short)(node->width-NODE_DY), NODE_DY, NULL, 0, 0, 0, 0, ""); - } + bNodeSocketType *stype= ntreeGetSocketType(sock->type); + + if(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)) + continue; + + node_socket_circle_draw(ntree, sock, NODE_SOCKSIZE); + + if (sock->link) { + uiDefBut(node->block, LABEL, 0, sock->name, sock->locx+NODE_DYS, sock->locy-NODE_DYS, node->width-NODE_DY, NODE_DY, + NULL, 0, 0, 0, 0, ""); + } + else { + if (stype->buttonfunc) + stype->buttonfunc(C, node->block, ntree, node, sock, sock->name, sock->locx+NODE_DYS, sock->locy-NODE_DYS, node->width-NODE_DY); } } /* socket outputs */ for(sock= node->outputs.first; sock; sock= sock->next) { - if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) { - float slen; - int ofs= 0; - - socket_circle_draw(sock, socket_size); - - UI_ThemeColor(TH_TEXT); - slen= snode->aspect*UI_GetStringWidth(sock->name); - while(slen > node->width) { - ofs++; - slen= snode->aspect*UI_GetStringWidth(sock->name+ofs); - } - - uiDefBut(node->block, LABEL, 0, sock->name+ofs, (short)(sock->locx-15.0f-slen), (short)(sock->locy-9.0f), - (short)(node->width-NODE_DY), NODE_DY, NULL, 0, 0, 0, 0, ""); + PointerRNA sockptr; + float slen; + int ofs; + + RNA_pointer_create((ID*)ntree, &RNA_NodeSocket, sock, &sockptr); + + if(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)) + continue; + + node_socket_circle_draw(ntree, sock, NODE_SOCKSIZE); + + ofs= 0; + UI_ThemeColor(TH_TEXT); + slen= snode->aspect*UI_GetStringWidth(sock->name); + while(slen > node->width) { + ofs++; + slen= snode->aspect*UI_GetStringWidth(sock->name+ofs); } + uiDefBut(node->block, LABEL, 0, sock->name+ofs, (short)(sock->locx-15.0f-slen), (short)(sock->locy-9.0f), + (short)(node->width-NODE_DY), NODE_DY, NULL, 0, 0, 0, 0, ""); } /* preview */ @@ -956,12 +787,7 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b UI_ThemeColor(TH_TEXT); if(node->miniwidth>0.0f) { - if (node->label[0]!='\0') - BLI_strncpy(showname, node->label, sizeof(showname)); - else if (node->typeinfo->labelfunc) - BLI_strncpy(showname, node->typeinfo->labelfunc(node), sizeof(showname)); - else - BLI_strncpy(showname, node->typeinfo->name, sizeof(showname)); + BLI_strncpy(showname, nodeLabel(node), sizeof(showname)); //if(node->flag & NODE_MUTED) // sprintf(showname, "[%s]", showname); @@ -984,12 +810,12 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b /* sockets */ for(sock= node->inputs.first; sock; sock= sock->next) { if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) - socket_circle_draw(sock, socket_size); + node_socket_circle_draw(snode->nodetree, sock, socket_size); } for(sock= node->outputs.first; sock; sock= sock->next) { if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) - socket_circle_draw(sock, socket_size); + node_socket_circle_draw(snode->nodetree, sock, socket_size); } uiEndBlock(C, node->block); @@ -997,7 +823,43 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b node->block= NULL; } -static void node_draw_nodetree(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree) +void node_draw_default(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node) +{ + if(node->flag & NODE_HIDDEN) + node_draw_hidden(C, ar, snode, node); + else + node_draw_basis(C, ar, snode, ntree, node); +} + +static void node_update(const bContext *C, bNodeTree *ntree, bNode *node) +{ + if (node->typeinfo->drawupdatefunc) + node->typeinfo->drawupdatefunc(C, ntree, node); +} + +void node_update_nodetree(const bContext *C, bNodeTree *ntree, float offsetx, float offsety) +{ + bNode *node; + + for(node= ntree->nodes.first; node; node= node->next) { + /* XXX little hack */ + node->locx += offsetx; + node->locy += offsety; + + node_update(C, ntree, node); + + node->locx -= offsetx; + node->locy -= offsety; + } +} + +static void node_draw(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node) +{ + if (node->typeinfo->drawfunc) + node->typeinfo->drawfunc(C, ar, snode, ntree, node); +} + +void node_draw_nodetree(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree) { bNode *node; bNodeLink *link; @@ -1013,212 +875,11 @@ static void node_draw_nodetree(const bContext *C, ARegion *ar, SpaceNode *snode, glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); - /* not selected first */ - for(a=0, node= ntree->nodes.first; node; node= node->next, a++) { + /* draw nodes, last nodes in front */ + for(a=0, node= ntree->nodes.first; node; node=node->next, a++) { node->nr= a; /* index of node in list, used for exec event code */ - if(!(node->flag & SELECT)) { - if(node->flag & NODE_GROUP_EDIT); - else if(node->flag & NODE_HIDDEN) - node_draw_hidden(C, ar, snode, node); - else - node_draw_basis(C, ar, snode, ntree, node); - } - } - - /* selected */ - for(node= ntree->nodes.first; node; node= node->next) { - if(node->flag & SELECT) { - if(node->flag & NODE_GROUP_EDIT); - else if(node->flag & NODE_HIDDEN) - node_draw_hidden(C, ar, snode, node); - else - node_draw_basis(C, ar, snode, ntree, node); - } - } -} - -static void group_verify_cb(bContext *UNUSED(C), void *UNUSED(snode_v), void *ngroup_v) -{ - bNodeTree *ngroup= (bNodeTree*)ngroup_v; - - nodeGroupVerify(ngroup); -} - -/* groups are, on creation, centered around 0,0 */ -static void node_draw_group(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *gnode) -{ - bNodeTree *ngroup= (bNodeTree *)gnode->id; - bNodeSocket *sock; - uiLayout *layout; - PointerRNA ptr; - uiBut *bt; - rctf rect= gnode->totr; - float socket_size= NODE_SOCKSIZE*U.dpi/72; - float node_group_frame= U.dpi*NODE_GROUP_FRAME/72; - float group_header= 26*U.dpi/72; - float arrowbutw= 0.8f*UI_UNIT_X; - /* layout stuff for buttons on group left frame */ - float col1= 6, colw1= 0.6f*node_group_frame; - float col2= col1 + colw1+6; - float col3= node_group_frame - arrowbutw - 6; - /* layout stuff for buttons on group right frame */ - float cor1= 6; - float cor2= cor1 + arrowbutw + 6; - float cor3= cor2 + arrowbutw + 6, corw3= node_group_frame - cor3-6; - - int index; - - /* backdrop header */ - glEnable(GL_BLEND); - uiSetRoundBox(3); - UI_ThemeColorShadeAlpha(TH_NODE_GROUP, 0, -70); - uiDrawBox(GL_POLYGON, rect.xmin-node_group_frame, rect.ymax, rect.xmax+node_group_frame, rect.ymax+group_header, BASIS_RAD); - - /* backdrop body */ - UI_ThemeColorShadeAlpha(TH_BACK, -8, -70); - uiSetRoundBox(0); - uiDrawBox(GL_POLYGON, rect.xmin, rect.ymin, rect.xmax, rect.ymax, BASIS_RAD); - - /* input column */ - UI_ThemeColorShadeAlpha(TH_BACK, 10, -50); - uiSetRoundBox(8); - uiDrawBox(GL_POLYGON, rect.xmin-node_group_frame, rect.ymin, rect.xmin, rect.ymax, BASIS_RAD); - - /* output column */ - UI_ThemeColorShadeAlpha(TH_BACK, 10, -50); - uiSetRoundBox(4); - uiDrawBox(GL_POLYGON, rect.xmax, rect.ymin, rect.xmax+node_group_frame, rect.ymax, BASIS_RAD); - - /* input column separator */ - glColor4ub(200, 200, 200, 140); - glBegin(GL_LINES); - glVertex2f(rect.xmin, rect.ymin); - glVertex2f(rect.xmin, rect.ymax); - glEnd(); - - /* output column separator */ - glColor4ub(200, 200, 200, 140); - glBegin(GL_LINES); - glVertex2f(rect.xmax, rect.ymin); - glVertex2f(rect.xmax, rect.ymax); - glEnd(); - - /* group node outline */ - uiSetRoundBox(15); - glColor4ub(200, 200, 200, 140); - glEnable( GL_LINE_SMOOTH ); - uiDrawBox(GL_LINE_LOOP, rect.xmin-node_group_frame, rect.ymin, rect.xmax+node_group_frame, rect.ymax+group_header, BASIS_RAD); - glDisable( GL_LINE_SMOOTH ); - glDisable(GL_BLEND); - - /* backdrop title */ - UI_ThemeColor(TH_TEXT_HI); - - layout = uiBlockLayout(gnode->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, (short)(rect.xmin+15), (short)(rect.ymax+group_header), - MIN2((int)(rect.xmax - rect.xmin-18.0f), node_group_frame+20), group_header, U.uistyles.first); - RNA_pointer_create(&ntree->id, &RNA_Node, gnode, &ptr); - uiTemplateIDBrowse(layout, (bContext*)C, &ptr, "node_tree", NULL, NULL, NULL); - uiBlockLayoutResolve(gnode->block, NULL, NULL); - - /* draw the internal tree nodes and links */ - node_draw_nodetree(C, ar, snode, ngroup); - - /* group sockets */ - for(sock=ngroup->inputs.first, index=0; sock; sock=sock->next, ++index) { - float locx= sock->locx - node_group_frame; - - socket_circle_draw(sock, socket_size); - /* small hack to use socket_circle_draw function with offset */ - sock->locx -= node_group_frame; - socket_circle_draw(sock, socket_size); - sock->locx += node_group_frame; - - bt = uiDefBut(gnode->block, TEX, 0, "", - locx+col1, sock->locy+1, colw1, NODE_DY, - sock->name, 0, 31, 0, 0, ""); - uiButSetFunc(bt, group_verify_cb, snode, ngroup); - - node_draw_socket_button(ngroup, sock, "", gnode->block, - locx+col1, sock->locy-NODE_DY, colw1, - NULL, NULL, NULL); - - uiBlockSetDirection(gnode->block, UI_TOP); - uiBlockBeginAlign(gnode->block); - bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_move_up", 0, ICON_TRIA_UP, - locx+col2, sock->locy, arrowbutw, arrowbutw, ""); - if (!sock->prev) - uiButSetFlag(bt, UI_BUT_DISABLED); - RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index); - RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", SOCK_IN); - bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_move_down", 0, ICON_TRIA_DOWN, - locx+col2, sock->locy-arrowbutw, arrowbutw, arrowbutw, ""); - if (!sock->next) - uiButSetFlag(bt, UI_BUT_DISABLED); - RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index); - RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", SOCK_IN); - uiBlockEndAlign(gnode->block); - uiBlockSetDirection(gnode->block, 0); - - uiBlockSetEmboss(gnode->block, UI_EMBOSSN); - bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_remove", 0, ICON_X, - locx+col3, sock->locy-0.5f*arrowbutw, arrowbutw, arrowbutw, ""); - RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index); - RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", SOCK_IN); - uiBlockSetEmboss(gnode->block, UI_EMBOSS); - } - - for(sock=ngroup->outputs.first, index=0; sock; sock=sock->next, ++index) { - float locx= sock->locx; - - socket_circle_draw(sock, socket_size); - /* small hack to use socket_circle_draw function with offset */ - sock->locx += node_group_frame; - socket_circle_draw(sock, socket_size); - sock->locx -= node_group_frame; - - uiBlockSetEmboss(gnode->block, UI_EMBOSSN); - bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_remove", 0, ICON_X, - locx+col1, sock->locy-0.5f*arrowbutw, arrowbutw, arrowbutw, ""); - RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index); - RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", SOCK_OUT); - uiBlockSetEmboss(gnode->block, UI_EMBOSS); - - uiBlockSetDirection(gnode->block, UI_TOP); - uiBlockBeginAlign(gnode->block); - bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_move_up", 0, ICON_TRIA_UP, - locx+cor2, sock->locy, arrowbutw, arrowbutw, ""); - if (!sock->prev) - uiButSetFlag(bt, UI_BUT_DISABLED); - RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index); - RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", SOCK_OUT); - bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_move_down", 0, ICON_TRIA_DOWN, - locx+cor2, sock->locy-arrowbutw, arrowbutw, arrowbutw, ""); - if (!sock->next) - uiButSetFlag(bt, UI_BUT_DISABLED); - RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index); - RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", SOCK_OUT); - uiBlockEndAlign(gnode->block); - uiBlockSetDirection(gnode->block, 0); - - if (sock->link) { - bt = uiDefBut(gnode->block, TEX, 0, "", - locx+cor3, sock->locy-NODE_DYS+1, corw3, NODE_DY, - sock->name, 0, 31, 0, 0, ""); - uiButSetFunc(bt, group_verify_cb, snode, ngroup); - } - else { - bt = uiDefBut(gnode->block, TEX, 0, "", - locx+cor3, sock->locy+1, corw3, NODE_DY, - sock->name, 0, 31, 0, 0, ""); - uiButSetFunc(bt, group_verify_cb, snode, ngroup); - - node_draw_socket_button(ngroup, sock, "", gnode->block, locx+cor3, sock->locy-NODE_DY, corw3, NULL, NULL, NULL); - } + node_draw(C, ar, snode, ntree, node); } - - uiEndBlock(C, gnode->block); - uiDrawBlock(C, gnode->block); - gnode->block= NULL; } void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d) @@ -1260,27 +921,19 @@ void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d) if(node->flag & NODE_GROUP_EDIT) node_uiblocks_init(C, (bNodeTree *)node->id); } - - node_uiblocks_init(C, snode->nodetree); + node_uiblocks_init(C, snode->nodetree); - /* for now, we set drawing coordinates on each redraw */ - for(node= snode->nodetree->nodes.first; node; node= node->next) { - if(node->flag & NODE_GROUP_EDIT) - node_update_group(C, snode->nodetree, node); - else if(node->flag & NODE_HIDDEN) - node_update_hidden(node); - else - node_update(C, snode->nodetree, node); - } - + node_update_nodetree(C, snode->nodetree, 0.0f, 0.0f); node_draw_nodetree(C, ar, snode, snode->nodetree); - + + #if 0 /* active group */ for(node= snode->nodetree->nodes.first; node; node= node->next) { if(node->flag & NODE_GROUP_EDIT) node_draw_group(C, ar, snode, snode->nodetree, node); } + #endif } /* temporary links */ diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 508cb82ee1b..214f375855d 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -40,9 +40,11 @@ #include "MEM_guardedalloc.h" +#include "DNA_ID.h" #include "DNA_object_types.h" #include "DNA_material_types.h" #include "DNA_node_types.h" +#include "DNA_particle_types.h" #include "DNA_scene_types.h" #include "BLI_math.h" @@ -58,11 +60,17 @@ #include "BKE_main.h" #include "BKE_node.h" #include "BKE_material.h" +#include "BKE_modifier.h" #include "BKE_paint.h" #include "BKE_screen.h" #include "BKE_texture.h" #include "BKE_report.h" + +#include "BLI_math.h" +#include "BLI_blenlib.h" +#include "BLI_storage_types.h" + #include "RE_pipeline.h" #include "IMB_imbuf_types.h" @@ -74,11 +82,13 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_enum_types.h" #include "WM_api.h" #include "WM_types.h" #include "UI_interface.h" +#include "UI_resources.h" #include "UI_view2d.h" #include "IMB_imbuf.h" @@ -88,9 +98,9 @@ #include "node_intern.h" static EnumPropertyItem socket_in_out_items[] = { - { SOCK_IN, "IN", 0, "In", "" }, - { SOCK_OUT, "OUT", 0, "Out", "" }, - { 0, NULL, 0, NULL, NULL} + { SOCK_IN, "SOCK_IN", 0, "Input", "" }, + { SOCK_OUT, "SOCK_OUT", 0, "Output", "" }, + { 0, NULL, 0, NULL, NULL }, }; /* ***************** composite job manager ********************** */ @@ -227,7 +237,7 @@ static bNode *editnode_get_active(bNodeTree *ntree) /* check for edited group */ for(node= ntree->nodes.first; node; node= node->next) - if(node->flag & NODE_GROUP_EDIT) + if(nodeGroupEditGet(node)) break; if(node) return nodeGetActive((bNodeTree *)node->id); @@ -258,7 +268,7 @@ bNode *node_tree_get_editgroup(bNodeTree *nodetree) /* get the groupnode */ for(gnode= nodetree->nodes.first; gnode; gnode= gnode->next) - if(gnode->flag & NODE_GROUP_EDIT) + if(nodeGroupEditGet(gnode)) break; return gnode; } @@ -269,6 +279,7 @@ void ED_node_shader_default(Material *ma) { bNode *in, *out; bNodeSocket *fromsock, *tosock; + bNodeTemplate ntemp; /* but lets check it anyway */ if(ma->nodetree) { @@ -277,12 +288,14 @@ void ED_node_shader_default(Material *ma) return; } - ma->nodetree= ntreeAddTree("Shader Nodetree", NTREE_SHADER, FALSE); + ma->nodetree= ntreeAddTree("Shader Nodetree", NTREE_SHADER, 0); - out= nodeAddNodeType(ma->nodetree, SH_NODE_OUTPUT, NULL, NULL); + ntemp.type = SH_NODE_OUTPUT; + out= nodeAddNode(ma->nodetree, &ntemp); out->locx= 300.0f; out->locy= 300.0f; - in= nodeAddNodeType(ma->nodetree, SH_NODE_MATERIAL, NULL, NULL); + ntemp.type = SH_NODE_MATERIAL; + in= nodeAddNode(ma->nodetree, &ntemp); in->locx= 10.0f; in->locy= 300.0f; nodeSetActive(ma->nodetree, in); @@ -291,7 +304,7 @@ void ED_node_shader_default(Material *ma) tosock= out->inputs.first; nodeAddLink(ma->nodetree, in, fromsock, out, tosock); - ntreeSolveOrder(ma->nodetree); /* needed for pointers */ + ntreeUpdateTree(ma->nodetree); } /* assumes nothing being done in ntree yet, sets the default in/out node */ @@ -300,6 +313,7 @@ void ED_node_composit_default(Scene *sce) { bNode *in, *out; bNodeSocket *fromsock, *tosock; + bNodeTemplate ntemp; /* but lets check it anyway */ if(sce->nodetree) { @@ -308,14 +322,16 @@ void ED_node_composit_default(Scene *sce) return; } - sce->nodetree= ntreeAddTree("Compositing Nodetree", NTREE_COMPOSIT, FALSE); + sce->nodetree= ntreeAddTree("Compositing Nodetree", NTREE_COMPOSIT, 0); - out= nodeAddNodeType(sce->nodetree, CMP_NODE_COMPOSITE, NULL, NULL); + ntemp.type = CMP_NODE_COMPOSITE; + out= nodeAddNode(sce->nodetree, &ntemp); out->locx= 300.0f; out->locy= 400.0f; out->id= &sce->id; id_us_plus(out->id); - in= nodeAddNodeType(sce->nodetree, CMP_NODE_R_LAYERS, NULL, NULL); + ntemp.type = CMP_NODE_R_LAYERS; + in= nodeAddNode(sce->nodetree, &ntemp); in->locx= 10.0f; in->locy= 400.0f; in->id= &sce->id; id_us_plus(in->id); @@ -326,7 +342,7 @@ void ED_node_composit_default(Scene *sce) tosock= out->inputs.first; nodeAddLink(sce->nodetree, in, fromsock, out, tosock); - ntreeSolveOrder(sce->nodetree); /* needed for pointers */ + ntreeUpdateTree(sce->nodetree); // XXX ntreeCompositForceHidden(sce->nodetree); } @@ -337,6 +353,7 @@ void ED_node_texture_default(Tex *tx) { bNode *in, *out; bNodeSocket *fromsock, *tosock; + bNodeTemplate ntemp; /* but lets check it anyway */ if(tx->nodetree) { @@ -345,12 +362,14 @@ void ED_node_texture_default(Tex *tx) return; } - tx->nodetree= ntreeAddTree("Texture Nodetree", NTREE_TEXTURE, FALSE); + tx->nodetree= ntreeAddTree("Texture Nodetree", NTREE_TEXTURE, 0); - out= nodeAddNodeType(tx->nodetree, TEX_NODE_OUTPUT, NULL, NULL); + ntemp.type = TEX_NODE_OUTPUT; + out= nodeAddNode(tx->nodetree, &ntemp); out->locx= 300.0f; out->locy= 300.0f; - in= nodeAddNodeType(tx->nodetree, TEX_NODE_CHECKER, NULL, NULL); + ntemp.type = TEX_NODE_CHECKER; + in= nodeAddNode(tx->nodetree, &ntemp); in->locx= 10.0f; in->locy= 300.0f; nodeSetActive(tx->nodetree, in); @@ -358,43 +377,53 @@ void ED_node_texture_default(Tex *tx) tosock= out->inputs.first; nodeAddLink(tx->nodetree, in, fromsock, out, tosock); - ntreeSolveOrder(tx->nodetree); /* needed for pointers */ + ntreeUpdateTree(tx->nodetree); } /* id is supposed to contain a node tree */ void node_tree_from_ID(ID *id, bNodeTree **ntree, bNodeTree **edittree, int *treetype) { - bNode *node= NULL; - short idtype= GS(id->name); - - if(idtype == ID_MA) { - *ntree= ((Material*)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; + if (id) { + bNode *node= NULL; + short idtype= GS(id->name); + + 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_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; + } + + /* find editable group */ + if(edittree) { + if(*ntree) + for(node= (*ntree)->nodes.first; node; node= node->next) + if(nodeGroupEditGet(node)) + break; + + if(node && node->id) + *edittree= (bNodeTree *)node->id; + else + *edittree= *ntree; + } } else { + *ntree= NULL; if(treetype) *treetype= 0; - return; - } - - /* find editable group */ - if(edittree) { - if(*ntree) - for(node= (*ntree)->nodes.first; node; node= node->next) - if(node->flag & NODE_GROUP_EDIT) - break; - - if(node && node->id) - *edittree= (bNodeTree *)node->id; - else - *edittree= *ntree; } } @@ -403,8 +432,6 @@ void snode_set_context(SpaceNode *snode, Scene *scene) { Object *ob= OBACT; - snode->nodetree= NULL; - snode->edittree= NULL; snode->id= snode->from= NULL; if(snode->treetype==NTREE_SHADER) { @@ -418,7 +445,6 @@ void snode_set_context(SpaceNode *snode, Scene *scene) } } else if(snode->treetype==NTREE_COMPOSIT) { - snode->from= NULL; snode->id= &scene->id; /* bit clumsy but reliable way to see if we draw first time */ @@ -461,9 +487,14 @@ void snode_set_context(SpaceNode *snode, Scene *scene) } } } + else { + if (snode->nodetree && snode->nodetree->type == snode->treetype) + snode->id = &snode->nodetree->id; + else + snode->id = NULL; + } - if(snode->id) - node_tree_from_ID(snode->id, &snode->nodetree, &snode->edittree, NULL); + node_tree_from_ID(snode->id, &snode->nodetree, &snode->edittree, NULL); } static void snode_tag_changed(SpaceNode *snode, bNode *node) @@ -574,17 +605,199 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node) } } -/* when links in groups change, inputs/outputs change, nodes added/deleted... */ -void node_tree_verify_groups(bNodeTree *nodetree) +static int compare_nodes(bNode *a, bNode *b) { - bNode *gnode; + bNode *parent; - gnode= node_tree_get_editgroup(nodetree); + /* if one is an ancestor of the other */ + /* XXX there might be a better sorting algorithm for stable topological sort, this is O(n^2) worst case */ + for (parent = a->parent; parent; parent=parent->parent) { + if (parent==b) + return 1; + } + for (parent = b->parent; parent; parent=parent->parent) { + if (parent==a) + return 0; + } + + /* if one of the nodes is in the background and the other not */ + if ((a->flag & NODE_BACKGROUND) && !(b->typeinfo->flag & NODE_BACKGROUND)) + return 0; + else if (!(a->flag & NODE_BACKGROUND) && (b->typeinfo->flag & NODE_BACKGROUND)) + return 1; - /* does all materials */ - if(gnode) - nodeGroupVerify((bNodeTree *)gnode->id); + /* if one has a higher selection state (active > selected > nothing) */ + if (!(b->flag & NODE_ACTIVE) && (a->flag & NODE_ACTIVE)) + return 1; + else if (!(b->flag & NODE_SELECT) && ((a->flag & NODE_ACTIVE) || (a->flag & NODE_SELECT))) + return 1; + return 0; +} +/* Sorts nodes by selection: unselected nodes first, then selected, + * then the active node at the very end. Relative order is kept intact! + */ +void node_sort(bNodeTree *ntree) +{ + /* merge sort is the algorithm of choice here */ + bNode *first_a, *first_b, *node_a, *node_b, *tmp; + int totnodes= BLI_countlist(&ntree->nodes); + int k, a, b; + + k = 1; + while (k < totnodes) { + first_a = first_b = ntree->nodes.first; + + do { + /* setup first_b pointer */ + for (b=0; b < k && first_b; ++b) { + first_b = first_b->next; + } + /* all batches merged? */ + if (first_b==NULL) + break; + + /* merge batches */ + node_a = first_a; + node_b = first_b; + a = b = 0; + while (a < k && b < k && node_b) { + if (compare_nodes(node_a, node_b)==0) { + node_a = node_a->next; + ++a; + } + else { + tmp = node_b; + node_b = node_b->next; + ++b; + BLI_remlink(&ntree->nodes, tmp); + BLI_insertlinkbefore(&ntree->nodes, node_a, tmp); + } + } + + /* setup first pointers for next batch */ + first_b = node_b; + for (; b < k; ++b) { + /* all nodes sorted? */ + if (first_b==NULL) + break; + first_b = first_b->next; + } + first_a = first_b; + } while (first_b); + + k = k << 1; + } +} + +static int inside_rctf(rctf *bounds, rctf *rect) +{ + return (bounds->xmin <= rect->xmin && bounds->xmax >= rect->xmax + && bounds->ymin <= rect->ymin && bounds->ymax >= rect->ymax); +} + +static void node_frame_attach_nodes(bNodeTree *UNUSED(ntree), bNode *frame) +{ + bNode *node; + + /* only check nodes on top of the frame for attaching */ + for (node=frame->next; node; node=node->next) { + if (node->parent==frame) { + /* detach nodes that went outside the frame */ + if (!inside_rctf(&frame->totr, &node->totr)) + nodeDetachNode(node); + } + else if (node->flag & NODE_SELECT && node->parent==NULL) { + /* attach selected, still unparented nodes */ + if (inside_rctf(&frame->totr, &node->totr)) + nodeAttachNode(node, frame); + } + } +} + +void ED_node_update_hierarchy(bContext *UNUSED(C), bNodeTree *ntree) +{ + bNode *node; + + /* XXX This does not work due to layout functions relying on node->block, + * which only exists during actual drawing. Can we rely on valid totr rects? + */ + /* make sure nodes have correct bounding boxes after transform */ +// node_update_nodetree(C, ntree, 0.0f, 0.0f); + + /* all selected nodes are re-parented */ + for (node=ntree->nodes.last; node; node=node->prev) { + if (node->flag & NODE_SELECT && node->parent) + nodeDetachNode(node); + } + + /* update higher Z-level nodes first */ + for (node=ntree->nodes.last; node; node=node->prev) { + /* XXX callback? */ + if (node->type==NODE_FRAME) + node_frame_attach_nodes(ntree, node); + } +} + +/* ***************** generic operator functions for nodes ***************** */ + +static int edit_node_poll(bContext *C) +{ + return ED_operator_node_active(C); +} + +static void edit_node_properties(wmOperatorType *ot) +{ + /* XXX could node be a context pointer? */ + RNA_def_string(ot->srna, "node", "", 32, "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", ""); +} + +static int edit_node_invoke_properties(bContext *C, wmOperator *op) +{ + if (!RNA_property_is_set(op->ptr, "node")) { + bNode *node= CTX_data_pointer_get_type(C, "node", &RNA_Node).data; + if (!node) + return 0; + else + RNA_string_set(op->ptr, "node", node->name); + } + + if (!RNA_property_is_set(op->ptr, "in_out")) + RNA_enum_set(op->ptr, "in_out", SOCK_IN); + + if (!RNA_property_is_set(op->ptr, "socket")) + RNA_int_set(op->ptr, "socket", 0); + + return 1; +} + +static void edit_node_properties_get(wmOperator *op, bNodeTree *ntree, bNode **rnode, bNodeSocket **rsock, int *rin_out) +{ + bNode *node; + bNodeSocket *sock; + char nodename[32]; + int sockindex; + int in_out; + + RNA_string_get(op->ptr, "node", nodename); + node = nodeFindNodebyName(ntree, nodename); + + in_out = RNA_enum_get(op->ptr, "in_out"); + + sockindex = RNA_int_get(op->ptr, "socket"); + switch (in_out) { + case SOCK_IN: sock = BLI_findlink(&node->inputs, sockindex); break; + case SOCK_OUT: sock = BLI_findlink(&node->outputs, sockindex); break; + } + + if (rnode) + *rnode = node; + if (rsock) + *rsock = sock; + if (rin_out) + *rin_out = in_out; } /* ***************** Edit Group operator ************* */ @@ -594,8 +807,8 @@ void snode_make_group_editable(SpaceNode *snode, bNode *gnode) bNode *node; /* make sure nothing has group editing on */ - for(node= snode->nodetree->nodes.first; node; node= node->next) - node->flag &= ~NODE_GROUP_EDIT; + for(node=snode->nodetree->nodes.first; node; node=node->next) + nodeGroupEditClear(node); if(gnode==NULL) { /* with NULL argument we do a toggle */ @@ -603,34 +816,30 @@ void snode_make_group_editable(SpaceNode *snode, bNode *gnode) gnode= nodeGetActive(snode->nodetree); } - if(gnode && gnode->type==NODE_GROUP && gnode->id) { - if(gnode->id->lib) - ntreeMakeLocal((bNodeTree *)gnode->id); - - gnode->flag |= NODE_GROUP_EDIT; - snode->edittree= (bNodeTree *)gnode->id; + if (gnode) { + snode->edittree = nodeGroupEditSet(gnode, 1); /* deselect all other nodes, so we can also do grabbing of entire subtree */ for(node= snode->nodetree->nodes.first; node; node= node->next) node->flag &= ~SELECT; gnode->flag |= SELECT; - } else snode->edittree= snode->nodetree; - - ntreeSolveOrder(snode->nodetree); } static int node_group_edit_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceNode *snode = CTX_wm_space_node(C); - bNode *gnode; ED_preview_kill_jobs(C); - gnode= nodeGetActive(snode->edittree); - snode_make_group_editable(snode, gnode); + if (snode->nodetree==snode->edittree) { + bNode *gnode= nodeGetActive(snode->nodetree); + snode_make_group_editable(snode, gnode); + } + else + snode_make_group_editable(snode, NULL); WM_event_add_notifier(C, NC_SCENE|ND_NODES, NULL); @@ -643,7 +852,8 @@ static int node_group_edit_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(e bNode *gnode; gnode= nodeGetActive(snode->edittree); - if(gnode && gnode->type==NODE_GROUP && gnode->id && gnode->id->lib) { + /* XXX callback? */ + if(gnode && gnode->id && GS(gnode->id->name)==ID_NT && gnode->id->lib) { uiPupMenuOkee(C, op->type->idname, "Make group local?"); return OPERATOR_CANCELLED; } @@ -674,7 +884,7 @@ static int node_group_socket_add_exec(bContext *C, wmOperator *op) SpaceNode *snode = CTX_wm_space_node(C); int in_out= -1; char name[32]= ""; - int type= SOCK_VALUE; + int type= SOCK_FLOAT; bNodeTree *ngroup= snode->edittree; bNodeSocket *sock; @@ -691,9 +901,10 @@ static int node_group_socket_add_exec(bContext *C, wmOperator *op) else return OPERATOR_CANCELLED; - sock = nodeGroupAddSocket(ngroup, name, type, in_out); + /* using placeholder subtype first */ + sock = node_group_add_socket(ngroup, name, type, in_out); - node_tree_verify_groups(snode->nodetree); + ntreeUpdateTree(ngroup); snode_notify(C, snode); @@ -716,7 +927,7 @@ void NODE_OT_group_socket_add(wmOperatorType *ot) RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output"); RNA_def_string(ot->srna, "name", "", 32, "Name", "Group socket name"); - RNA_def_enum(ot->srna, "type", node_socket_type_items, SOCK_VALUE, "Type", "Type of the group socket"); + RNA_def_enum(ot->srna, "type", node_socket_type_items, SOCK_FLOAT, "Type", "Type of the group socket"); } /* ***************** Remove Group Socket operator ************* */ @@ -743,8 +954,8 @@ static int node_group_socket_remove_exec(bContext *C, wmOperator *op) sock = (bNodeSocket*)BLI_findlink(in_out==SOCK_IN ? &ngroup->inputs : &ngroup->outputs, index); if (sock) { - nodeGroupRemoveSocket(ngroup, sock, in_out); - node_tree_verify_groups(snode->nodetree); + node_group_remove_socket(ngroup, sock, in_out); + ntreeUpdateTree(ngroup); snode_notify(C, snode); } @@ -801,6 +1012,8 @@ static int node_group_socket_move_up_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; BLI_remlink(&ngroup->inputs, sock); BLI_insertlinkbefore(&ngroup->inputs, prev, sock); + + ngroup->update |= NTREE_UPDATE_GROUP_IN; } else if (in_out==SOCK_OUT) { sock = (bNodeSocket*)BLI_findlink(&ngroup->outputs, index); @@ -810,8 +1023,10 @@ static int node_group_socket_move_up_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; BLI_remlink(&ngroup->outputs, sock); BLI_insertlinkbefore(&ngroup->outputs, prev, sock); + + ngroup->update |= NTREE_UPDATE_GROUP_OUT; } - node_tree_verify_groups(snode->nodetree); + ntreeUpdateTree(ngroup); snode_notify(C, snode); @@ -867,6 +1082,8 @@ static int node_group_socket_move_down_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; BLI_remlink(&ngroup->inputs, sock); BLI_insertlinkafter(&ngroup->inputs, next, sock); + + ngroup->update |= NTREE_UPDATE_GROUP_IN; } else if (in_out==SOCK_OUT) { sock = (bNodeSocket*)BLI_findlink(&ngroup->outputs, index); @@ -876,8 +1093,10 @@ static int node_group_socket_move_down_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; BLI_remlink(&ngroup->outputs, sock); BLI_insertlinkafter(&ngroup->outputs, next, sock); + + ngroup->update |= NTREE_UPDATE_GROUP_OUT; } - node_tree_verify_groups(snode->nodetree); + ntreeUpdateTree(ngroup); snode_notify(C, snode); @@ -924,7 +1143,7 @@ static int node_group_ungroup_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_WARNING, "Not a group"); return OPERATOR_CANCELLED; } - else if(!nodeGroupUnGroup(snode->edittree, gnode)) { + else if(!node_group_ungroup(snode->edittree, gnode)) { BKE_report(op->reports, RPT_WARNING, "Can't ungroup"); return OPERATOR_CANCELLED; } @@ -952,70 +1171,16 @@ void NODE_OT_group_ungroup(wmOperatorType *ot) /* ************************** Node generic ************** */ -/* allows to walk the list in order of visibility */ -bNode *next_node(bNodeTree *ntree) -{ - static bNode *current=NULL, *last= NULL; - - if(ntree) { - /* set current to the first selected node */ - for(current= ntree->nodes.last; current; current= current->prev) - if(current->flag & NODE_SELECT) - break; - - /* set last to the first unselected node */ - for(last= ntree->nodes.last; last; last= last->prev) - if((last->flag & NODE_SELECT)==0) - break; - - if(current==NULL) - current= last; - - return NULL; - } - /* no nodes, or we are ready */ - if(current==NULL) - return NULL; - - /* now we walk the list backwards, but we always return current */ - if(current->flag & NODE_SELECT) { - bNode *node= current; - - /* find previous selected */ - current= current->prev; - while(current && (current->flag & NODE_SELECT)==0) - current= current->prev; - - /* find first unselected */ - if(current==NULL) - current= last; - - return node; - } - else { - bNode *node= current; - - /* find previous unselected */ - current= current->prev; - while(current && (current->flag & NODE_SELECT)) - current= current->prev; - - return node; - } - - return NULL; -} - /* is rct in visible part of node? */ static bNode *visible_node(SpaceNode *snode, rctf *rct) { - bNode *tnode; + bNode *node; - for(next_node(snode->edittree); (tnode=next_node(NULL));) { - if(BLI_isect_rctf(&tnode->totr, rct, NULL)) + for(node=snode->edittree->nodes.last; node; node=node->prev) { + if(BLI_isect_rctf(&node->totr, rct, NULL)) break; } - return tnode; + return node; } /* **************************** */ @@ -1318,8 +1483,9 @@ void NODE_OT_backimage_sample(wmOperatorType *ot) /* ********************** size widget operator ******************** */ typedef struct NodeSizeWidget { - float mxstart; - float oldwidth; + float mxstart, mystart; + float oldwidth, oldheight; + float oldminiwidth; } NodeSizeWidget; static int node_resize_modal(bContext *C, wmOperator *op, wmEvent *event) @@ -1338,13 +1504,16 @@ static int node_resize_modal(bContext *C, wmOperator *op, wmEvent *event) if (node) { if(node->flag & NODE_HIDDEN) { - node->miniwidth= nsw->oldwidth + mx - nsw->mxstart; + node->miniwidth= nsw->oldminiwidth + mx - nsw->mxstart; CLAMP(node->miniwidth, 0.0f, 100.0f); } else { node->width= nsw->oldwidth + mx - nsw->mxstart; CLAMP(node->width, UI_DPI_FAC*node->typeinfo->minwidth, UI_DPI_FAC*node->typeinfo->maxwidth); } + /* height works the other way round ... */ + node->height= nsw->oldheight - my + nsw->mystart; + CLAMP(node->height, node->typeinfo->minheight, node->typeinfo->maxheight); } ED_region_tag_redraw(ar); @@ -1358,6 +1527,8 @@ static int node_resize_modal(bContext *C, wmOperator *op, wmEvent *event) MEM_freeN(nsw); op->customdata= NULL; + ED_node_update_hierarchy(C, snode->edittree); + return OPERATOR_FINISHED; } @@ -1371,35 +1542,21 @@ static int node_resize_invoke(bContext *C, wmOperator *op, wmEvent *event) bNode *node= editnode_get_active(snode->edittree); if(node) { - rctf totr; - /* convert mouse coordinates to v2d space */ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &snode->mx, &snode->my); - totr= node->totr; - - if(node->flag & NODE_HIDDEN) { - /* right part of node */ - totr.xmin= node->totr.xmax-20.0f; - } - else { - /* bottom right corner */ - totr.xmin= totr.xmax-10.0f; - totr.ymax= totr.ymin+10.0f; - } - - if(BLI_in_rctf(&totr, snode->mx, snode->my)) { + if(node->typeinfo->resize_area_func(node, snode->mx, snode->my)) { NodeSizeWidget *nsw= MEM_callocN(sizeof(NodeSizeWidget), "size widget op data"); op->customdata= nsw; nsw->mxstart= snode->mx; + nsw->mystart= snode->my; /* store old */ - if(node->flag & NODE_HIDDEN) - nsw->oldwidth= node->miniwidth; - else - nsw->oldwidth= node->width; + nsw->oldwidth= node->width; + nsw->oldheight= node->height; + nsw->oldminiwidth= node->miniwidth; /* add modal handler */ WM_event_add_modal_handler(C, op); @@ -1598,7 +1755,7 @@ static void node_link_viewer(SpaceNode *snode, bNode *tonode) link->fromnode= tonode; link->fromsock= sock; } - ntreeSolveOrder(snode->edittree); + ntreeUpdateTree(snode->edittree); snode_tag_changed(snode, node); } } @@ -1905,6 +2062,7 @@ void snode_autoconnect(SpaceNode *snode, int allow_multiple, int replace) ListBase *nodelist = MEM_callocN(sizeof(ListBase), "items_list"); bNodeListItem *nli; bNode *node; + bNodeLink *link; int i, numlinks=0; for(node= snode->edittree->nodes.first; node; node= node->next) { @@ -1941,7 +2099,15 @@ void snode_autoconnect(SpaceNode *snode, int allow_multiple, int replace) /* then we can connect */ if (replace) nodeRemSocketLinks(snode->edittree, sock_to); - nodeAddLink(snode->edittree, node_fr, sock_fr, node_to, sock_to); + + link = nodeAddLink(snode->edittree, node_fr, sock_fr, node_to, sock_to); + /* validate the new link */ + ntreeUpdateTree(snode->edittree); + if (!(link->flag & NODE_LINK_VALID)) { + nodeRemLink(snode->edittree, link); + continue; + } + snode_tag_changed(snode, node_to); ++numlinks; break; @@ -1949,8 +2115,7 @@ void snode_autoconnect(SpaceNode *snode, int allow_multiple, int replace) } if (numlinks > 0) { - node_tree_verify_groups(snode->nodetree); - ntreeSolveOrder(snode->edittree); + ntreeUpdateTree(snode->edittree); } BLI_freelistN(nodelist); @@ -1958,28 +2123,13 @@ void snode_autoconnect(SpaceNode *snode, int allow_multiple, int replace) } /* can be called from menus too, but they should do own undopush and redraws */ -bNode *node_add_node(SpaceNode *snode, Main *bmain, Scene *scene, int type, float locx, float locy) +bNode *node_add_node(SpaceNode *snode, Main *bmain, Scene *scene, bNodeTemplate *ntemp, float locx, float locy) { bNode *node= NULL, *gnode; node_deselectall(snode); - if(type>=NODE_DYNAMIC_MENU) { - node= nodeAddNodeType(snode->edittree, type, NULL, NULL); - } - else if(type>=NODE_GROUP_MENU) { - if(snode->edittree!=snode->nodetree) { - // XXX error("Can not add a Group in a Group"); - return NULL; - } - else { - bNodeTree *ngroup= BLI_findlink(&bmain->nodetree, type-NODE_GROUP_MENU); - if(ngroup) - node= nodeAddNodeType(snode->edittree, NODE_GROUP, ngroup, NULL); - } - } - else - node= nodeAddNodeType(snode->edittree, type, NULL, NULL); + node = nodeAddNode(snode->edittree, ntemp); /* generics */ if(node) { @@ -1993,7 +2143,7 @@ bNode *node_add_node(SpaceNode *snode, Main *bmain, Scene *scene, int type, floa node->locy -= gnode->locy; } - node_tree_verify_groups(snode->nodetree); + ntreeUpdateTree(snode->edittree); ED_node_set_active(bmain, snode->edittree, node); if(snode->nodetree->type==NTREE_COMPOSIT) { @@ -2025,6 +2175,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) bNode *node, *newnode, *lastnode; bNodeLink *link, *newlink, *lastlink; int keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs"); + bNodeSocket *sock; ED_preview_kill_jobs(C); @@ -2094,9 +2245,8 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) break; } - ntreeSolveOrder(ntree); + ntreeUpdateTree(snode->edittree); - node_tree_verify_groups(snode->nodetree); snode_notify(C, snode); snode_dag_update(C, snode); @@ -2185,17 +2335,25 @@ static int node_link_modal(bContext *C, wmOperator *op, wmEvent *event) if( link->tosock!= tsock && (!tnode || (tnode!=node && link->tonode!=tnode)) ) { link->tonode= tnode; link->tosock= tsock; - if (link->prev==NULL && link->next==NULL) + if (link->prev==NULL && link->next==NULL) { BLI_addtail(&snode->edittree->links, link); - ntreeSolveOrder(snode->edittree); /* for interactive red line warning */ + } + + snode->edittree->update |= NTREE_UPDATE_LINKS; + ntreeUpdateTree(snode->edittree); } } } else { - BLI_remlink(&snode->edittree->links, link); - link->prev = link->next = NULL; - link->tonode= NULL; - link->tosock= NULL; + if (link->tonode || link->tosock) { + BLI_remlink(&snode->edittree->links, link); + link->prev = link->next = NULL; + link->tonode= NULL; + link->tosock= NULL; + + snode->edittree->update |= NTREE_UPDATE_LINKS; + ntreeUpdateTree(snode->edittree); + } } } else { @@ -2205,18 +2363,25 @@ static int node_link_modal(bContext *C, wmOperator *op, wmEvent *event) if( link->fromsock!= tsock && (!tnode || (tnode!=node && link->fromnode!=tnode)) ) { link->fromnode= tnode; link->fromsock= tsock; - if (link->prev==NULL && link->next==NULL) + if (link->prev==NULL && link->next==NULL) { BLI_addtail(&snode->edittree->links, link); - ntreeSolveOrder(snode->edittree); /* for interactive red line warning */ + } + + snode->edittree->update |= NTREE_UPDATE_LINKS; + ntreeUpdateTree(snode->edittree); } } } } else { - BLI_remlink(&snode->edittree->links, link); - link->prev = link->next = NULL; - link->fromnode= NULL; - link->fromsock= NULL; + if (link->tonode || link->tosock) { + BLI_remlink(&snode->edittree->links, link); + link->prev = link->next = NULL; + link->fromnode= NULL; + link->fromsock= NULL; + snode->edittree->update |= NTREE_UPDATE_LINKS; + ntreeUpdateTree(snode->edittree); + } } } /* hilight target sockets only */ @@ -2244,23 +2409,26 @@ static int node_link_modal(bContext *C, wmOperator *op, wmEvent *event) else if (outside_group_rect(snode) && (link->tonode || link->fromnode)) { /* automatically add new group socket */ if (link->tonode && link->tosock) { - link->fromsock = nodeGroupExposeSocket(snode->edittree, link->tosock, SOCK_IN); + link->fromsock = node_group_expose_socket(snode->edittree, link->tosock, SOCK_IN); link->fromnode = NULL; - if (link->prev==NULL && link->next==NULL) + if (link->prev==NULL && link->next==NULL) { BLI_addtail(&snode->edittree->links, link); + } + snode->edittree->update |= NTREE_UPDATE_GROUP_IN | NTREE_UPDATE_LINKS; } else if (link->fromnode && link->fromsock) { - link->tosock = nodeGroupExposeSocket(snode->edittree, link->fromsock, SOCK_OUT); + link->tosock = node_group_expose_socket(snode->edittree, link->fromsock, SOCK_OUT); link->tonode = NULL; - if (link->prev==NULL && link->next==NULL) + if (link->prev==NULL && link->next==NULL) { BLI_addtail(&snode->edittree->links, link); + } + snode->edittree->update |= NTREE_UPDATE_GROUP_OUT | NTREE_UPDATE_LINKS; } } else nodeRemLink(snode->edittree, link); - ntreeSolveOrder(snode->edittree); - node_tree_verify_groups(snode->nodetree); + ntreeUpdateTree(snode->edittree); snode_notify(C, snode); snode_dag_update(C, snode); @@ -2335,7 +2503,7 @@ static int node_link_invoke(bContext *C, wmOperator *op, wmEvent *event) ED_preview_kill_jobs(C); nldrag->in_out= node_link_init(snode, nldrag); - + if(nldrag->in_out) { op->customdata= nldrag; @@ -2408,7 +2576,7 @@ static int node_make_link_exec(bContext *C, wmOperator *op) snode_autoconnect(snode, 1, replace); - node_tree_verify_groups(snode->nodetree); + ntreeUpdateTree(snode->edittree); snode_notify(C, snode); snode_dag_update(C, snode); @@ -2482,8 +2650,7 @@ static int cut_links_exec(bContext *C, wmOperator *op) } } - ntreeSolveOrder(snode->edittree); - node_tree_verify_groups(snode->nodetree); + ntreeUpdateTree(snode->edittree); snode_notify(C, snode); snode_dag_update(C, snode); @@ -2608,7 +2775,7 @@ void ED_node_link_insert(ScrArea *sa) link->flag &= ~NODE_LINKFLAG_HILITE; nodeAddLink(snode->edittree, select, socket_best_match(&select->outputs, sockto->type), node, sockto); - ntreeSolveOrder(snode->edittree); /* needed for pointers */ + ntreeUpdateTree(snode->edittree); /* needed for pointers */ snode_tag_changed(snode, select); ED_node_changed_update(snode->id, select); } @@ -2819,14 +2986,14 @@ static int node_group_make_exec(bContext *C, wmOperator *op) ED_preview_kill_jobs(C); - gnode= nodeMakeGroupFromSelected(snode->nodetree); + gnode= node_group_make_from_selected(snode->nodetree); if(gnode==NULL) { BKE_report(op->reports, RPT_WARNING, "Can not make Group"); return OPERATOR_CANCELLED; } else { nodeSetActive(snode->nodetree, gnode); - ntreeSolveOrder(snode->nodetree); + ntreeUpdateTree(snode->nodetree); } snode_notify(C, snode); @@ -2972,7 +3139,7 @@ static int node_socket_toggle_exec(bContext *C, wmOperator *UNUSED(op)) } } - node_tree_verify_groups(snode->nodetree); + ntreeUpdateTree(snode->edittree); snode_notify(C, snode); @@ -3056,7 +3223,7 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op)) } } - node_tree_verify_groups(snode->nodetree); + ntreeUpdateTree(snode->edittree); snode_notify(C, snode); snode_dag_update(C, snode); @@ -3126,7 +3293,7 @@ static void node_delete_reconnect(bNodeTree* tree, bNode* node) deliveringvecsocket = link->fromsock; } break; - case SOCK_VALUE: + case SOCK_FLOAT: if (valsocket == NULL) { valsocket = link->tosock; deliveringvalnode = link->fromnode; @@ -3147,7 +3314,7 @@ static void node_delete_reconnect(bNodeTree* tree, bNode* node) numberOfConnectedOutputSockets ++; if (!first) first = link; switch(sock->type) { - case SOCK_VALUE: + case SOCK_FLOAT: if (deliveringvalsocket) { link->fromnode = deliveringvalnode; link->fromsock = deliveringvalsocket; @@ -3205,7 +3372,7 @@ static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op)) } } - node_tree_verify_groups(snode->nodetree); + ntreeUpdateTree(snode->edittree); snode_notify(C, snode); snode_dag_update(C, snode); @@ -3235,7 +3402,7 @@ static int node_show_cycles_exec(bContext *C, wmOperator *UNUSED(op)) SpaceNode *snode= CTX_wm_space_node(C); /* this is just a wrapper around this call... */ - ntreeSolveOrder(snode->edittree); + ntreeUpdateTree(snode->nodetree); snode_notify(C, snode); return OPERATOR_FINISHED; @@ -3265,7 +3432,9 @@ static int node_add_file_exec(bContext *C, wmOperator *op) SpaceNode *snode= CTX_wm_space_node(C); bNode *node; Image *ima= NULL; - int ntype=0; + bNodeTemplate ntemp; + + ntemp.type = -1; /* check input variables */ if (RNA_property_is_set(op->ptr, "filepath")) @@ -3297,11 +3466,14 @@ static int node_add_file_exec(bContext *C, wmOperator *op) node_deselectall(snode); if (snode->nodetree->type==NTREE_COMPOSIT) - ntype = CMP_NODE_IMAGE; + ntemp.type = CMP_NODE_IMAGE; + if (ntemp.type < 0) + return OPERATOR_CANCELLED; + ED_preview_kill_jobs(C); - node = node_add_node(snode, bmain, scene, ntype, snode->mx, snode->my); + node = node_add_node(snode, bmain, scene, &ntemp, snode->mx, snode->my); if (!node) { BKE_report(op->reports, RPT_WARNING, "Could not add an image node."); @@ -3350,5 +3522,67 @@ void NODE_OT_add_file(wmOperatorType *ot) RNA_def_string(ot->srna, "name", "Image", 24, "Name", "Datablock name to assign."); } +/********************** New node tree operator *********************/ +static int new_node_tree_exec(bContext *C, wmOperator *op) +{ + SpaceNode *snode; + bNodeTree *ntree; + PointerRNA ptr, idptr; + PropertyRNA *prop; + int treetype; + char treename[MAX_ID_NAME-2] = "NodeTree"; + + /* retrieve state */ + snode= CTX_wm_space_node(C); + + if (RNA_property_is_set(op->ptr, "type")) + treetype = RNA_enum_get(op->ptr, "type"); + else + treetype = snode->treetype; + + if (RNA_property_is_set(op->ptr, "name")) + RNA_string_get(op->ptr, "name", treename); + + ntree = ntreeAddTree(treename, treetype, 0); + if(!ntree) + return OPERATOR_CANCELLED; + + /* hook into UI */ + uiIDContextProperty(C, &ptr, &prop); + if(prop) { + RNA_id_pointer_create(&ntree->id, &idptr); + RNA_property_pointer_set(&ptr, prop, idptr); + /* RNA_property_pointer_set increases the user count, + * fixed here as the editor is the initial user. + */ + --ntree->id.us; + RNA_property_update(C, &ptr, prop); + } + else if(snode) { + Scene *scene= CTX_data_scene(C); + snode->nodetree = ntree; + + ED_node_tree_update(snode, scene); + } + + return OPERATOR_FINISHED; +} + +void NODE_OT_new_node_tree(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "New node tree"; + ot->idname= "NODE_OT_new_node_tree"; + + /* api callbacks */ + ot->exec= new_node_tree_exec; + ot->poll= ED_operator_node_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "type", nodetree_type_items, NTREE_COMPOSIT, "Tree Type", ""); + RNA_def_string(ot->srna, "name", "NodeTree", MAX_ID_NAME-2, "Name", ""); +} diff --git a/source/blender/editors/space_node/node_header.c b/source/blender/editors/space_node/node_header.c index 634e49dc515..5c921d40344 100644 --- a/source/blender/editors/space_node/node_header.c +++ b/source/blender/editors/space_node/node_header.c @@ -45,24 +45,26 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_global.h" #include "BKE_screen.h" #include "BKE_node.h" #include "BKE_main.h" +#include "RNA_access.h" + #include "WM_api.h" #include "WM_types.h" - #include "UI_interface.h" -#include "UI_resources.h" #include "UI_interface_icons.h" +#include "UI_resources.h" #include "UI_view2d.h" #include "node_intern.h" /* ************************ add menu *********************** */ -static void do_node_add(bContext *C, void *UNUSED(arg), int event) +static void do_node_add(bContext *C, bNodeTemplate *ntemp) { Main *bmain= CTX_data_main(C); Scene *scene= CTX_data_scene(C); @@ -89,7 +91,7 @@ static void do_node_add(bContext *C, void *UNUSED(arg), int event) else node->flag &= ~NODE_TEST; } - node= node_add_node(snode, bmain, scene, event, snode->mx, snode->my); + node= node_add_node(snode, bmain, scene, ntemp, snode->mx, snode->my); /* select previous selection before autoconnect */ for(node= snode->edittree->nodes.first; node; node= node->next) { @@ -105,69 +107,111 @@ static void do_node_add(bContext *C, void *UNUSED(arg), int event) snode_dag_update(C, snode); } -static void node_auto_add_menu(bContext *C, uiLayout *layout, void *arg_nodeclass) +static void do_node_add_static(bContext *C, void *UNUSED(arg), int event) +{ + bNodeTemplate ntemp; + ntemp.type = event; + do_node_add(C, &ntemp); +} + +static void do_node_add_group(bContext *C, void *UNUSED(arg), int event) +{ + SpaceNode *snode= CTX_wm_space_node(C); + bNodeTemplate ntemp; + + if (event>=0) { + ntemp.ngroup= BLI_findlink(&G.main->nodetree, event); + ntemp.type = ntemp.ngroup->nodetype; + } + else { + ntemp.type = -event; + switch (ntemp.type) { + case NODE_GROUP: + ntemp.ngroup = ntreeAddTree("Group", snode->treetype, ntemp.type); + break; + case NODE_FORLOOP: + ntemp.ngroup = ntreeAddTree("For Loop", snode->treetype, ntemp.type); + break; + case NODE_WHILELOOP: + ntemp.ngroup = ntreeAddTree("While Loop", snode->treetype, ntemp.type); + break; + default: + ntemp.ngroup = NULL; + } + } + if (!ntemp.ngroup) + return; + + do_node_add(C, &ntemp); +} + +#if 0 /* disabled */ +static void do_node_add_dynamic(bContext *C, void *UNUSED(arg), int event) +{ + bNodeTemplate ntemp; + ntemp.type = NODE_DYNAMIC; + do_node_add(C, &ntemp); +} +#endif + +static int node_tree_has_type(int treetype, int nodetype) +{ + bNodeTreeType *ttype= ntreeGetType(treetype); + bNodeType *ntype; + for (ntype=ttype->node_types.first; ntype; ntype=ntype->next) { + if (ntype->type==nodetype) + return 1; + } + return 0; +} + +static void node_add_menu(bContext *C, uiLayout *layout, void *arg_nodeclass) { Main *bmain= CTX_data_main(C); SpaceNode *snode= CTX_wm_space_node(C); bNodeTree *ntree; int nodeclass= GET_INT_FROM_POINTER(arg_nodeclass); - int tot= 0, a; + int event; ntree = snode->nodetree; - + if(!ntree) { uiItemS(layout); return; } - - /* mostly taken from toolbox.c, node_add_sublevel() */ - if(nodeclass==NODE_CLASS_GROUP) { - bNodeTree *ngroup= bmain->nodetree.first; - for(; ngroup; ngroup= ngroup->id.next) - if(ngroup->type==ntree->type) - tot++; - } - else { - bNodeType *type = ntree->alltypes.first; - while(type) { - if(type->nclass == nodeclass) - tot++; - type= type->next; - } - } - if(tot==0) { + if (nodeclass==NODE_CLASS_GROUP) { + bNodeTree *ngroup; + + uiLayoutSetFunc(layout, do_node_add_group, NULL); + + /* XXX hack: negative numbers used for empty group types */ + if (node_tree_has_type(ntree->type, NODE_GROUP)) + uiItemV(layout, "New Group", 0, -NODE_GROUP); + if (node_tree_has_type(ntree->type, NODE_FORLOOP)) + uiItemV(layout, "New For Loop", 0, -NODE_FORLOOP); + if (node_tree_has_type(ntree->type, NODE_WHILELOOP)) + uiItemV(layout, "New While Loop", 0, -NODE_WHILELOOP); uiItemS(layout); - return; - } - - uiLayoutSetFunc(layout, do_node_add, NULL); - - if(nodeclass==NODE_CLASS_GROUP) { - bNodeTree *ngroup= bmain->nodetree.first; - - for(tot=0, a=0; ngroup; ngroup= ngroup->id.next, tot++) { - if(ngroup->type==ntree->type) { - uiItemV(layout, ngroup->id.name+2, ICON_NONE, NODE_GROUP_MENU+tot); - a++; + + for(ngroup=bmain->nodetree.first, event=0; ngroup; ngroup= ngroup->id.next, ++event) { + /* only use group trees */ + if (ngroup->type==ntree->type && ELEM3(ngroup->nodetype, NODE_GROUP, NODE_FORLOOP, NODE_WHILELOOP)) { + uiItemV(layout, ngroup->id.name+2, 0, event); } } } + else if (nodeclass==NODE_DYNAMIC) { + /* disabled */ + } else { - bNodeType *type; - int script=0; - - for(a=0, type= ntree->alltypes.first; type; type=type->next) { - if(type->nclass == nodeclass && type->name) { - if(type->type == NODE_DYNAMIC) { - uiItemV(layout, type->name, ICON_NONE, NODE_DYNAMIC_MENU+script); - script++; - } - else - uiItemV(layout, type->name, ICON_NONE, type->type); - - a++; - } + bNodeType *ntype; + + uiLayoutSetFunc(layout, do_node_add_static, NULL); + + for (ntype=ntreeGetType(ntree->type)->node_types.first; ntype; ntype=ntype->next) { + if(ntype->nclass==nodeclass && ntype->name) + uiItemV(layout, ntype->name, 0, ntype->type); } } } @@ -181,34 +225,34 @@ static void node_menu_add(const bContext *C, Menu *menu) uiLayoutSetActive(layout, 0); if(snode->treetype==NTREE_SHADER) { - uiItemMenuF(layout, "Input", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_INPUT)); - uiItemMenuF(layout, "Output", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OUTPUT)); - uiItemMenuF(layout, "Color", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_COLOR)); - uiItemMenuF(layout, "Vector", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_VECTOR)); - uiItemMenuF(layout, "Convertor", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_CONVERTOR)); - uiItemMenuF(layout, "Group", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_GROUP)); - uiItemMenuF(layout, "Dynamic", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_DYNAMIC)); + uiItemMenuF(layout, "Input", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_INPUT)); + uiItemMenuF(layout, "Output", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OUTPUT)); + uiItemMenuF(layout, "Color", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_COLOR)); + uiItemMenuF(layout, "Vector", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_VECTOR)); + uiItemMenuF(layout, "Convertor", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_CONVERTOR)); + uiItemMenuF(layout, "Group", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_GROUP)); + uiItemMenuF(layout, "Dynamic", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_DYNAMIC)); } else if(snode->treetype==NTREE_COMPOSIT) { - uiItemMenuF(layout, "Input", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_INPUT)); - uiItemMenuF(layout, "Output", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OUTPUT)); - uiItemMenuF(layout, "Color", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_COLOR)); - uiItemMenuF(layout, "Vector", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_VECTOR)); - uiItemMenuF(layout, "Filter", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_FILTER)); - uiItemMenuF(layout, "Convertor", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_CONVERTOR)); - uiItemMenuF(layout, "Matte", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_MATTE)); - uiItemMenuF(layout, "Distort", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_DISTORT)); - uiItemMenuF(layout, "Group", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_GROUP)); + uiItemMenuF(layout, "Input", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_INPUT)); + uiItemMenuF(layout, "Output", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OUTPUT)); + uiItemMenuF(layout, "Color", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_COLOR)); + uiItemMenuF(layout, "Vector", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_VECTOR)); + uiItemMenuF(layout, "Filter", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_FILTER)); + uiItemMenuF(layout, "Convertor", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_CONVERTOR)); + uiItemMenuF(layout, "Matte", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_MATTE)); + uiItemMenuF(layout, "Distort", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_DISTORT)); + uiItemMenuF(layout, "Group", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_GROUP)); } else if(snode->treetype==NTREE_TEXTURE) { - uiItemMenuF(layout, "Input", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_INPUT)); - uiItemMenuF(layout, "Output", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OUTPUT)); - uiItemMenuF(layout, "Color", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_COLOR)); - uiItemMenuF(layout, "Patterns", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_PATTERN)); - uiItemMenuF(layout, "Textures", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_TEXTURE)); - uiItemMenuF(layout, "Convertor", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_CONVERTOR)); - uiItemMenuF(layout, "Distort", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_DISTORT)); - uiItemMenuF(layout, "Group", 0, node_auto_add_menu, SET_INT_IN_POINTER(NODE_CLASS_GROUP)); + uiItemMenuF(layout, "Input", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_INPUT)); + uiItemMenuF(layout, "Output", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OUTPUT)); + uiItemMenuF(layout, "Color", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_COLOR)); + uiItemMenuF(layout, "Patterns", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_PATTERN)); + uiItemMenuF(layout, "Textures", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_TEXTURE)); + uiItemMenuF(layout, "Convertor", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_CONVERTOR)); + uiItemMenuF(layout, "Distort", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_DISTORT)); + uiItemMenuF(layout, "Group", 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_GROUP)); } } diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index 4cfde22b8a0..3751d8efae8 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -33,6 +33,8 @@ #ifndef ED_NODE_INTERN_H #define ED_NODE_INTERN_H +#include "UI_interface.h" + /* internal exports only */ struct ARegion; @@ -40,6 +42,7 @@ struct ARegionType; struct View2D; struct bContext; struct wmWindowManager; +struct bNodeTemplate; struct bNode; struct bNodeSocket; struct bNodeLink; @@ -64,6 +67,11 @@ void node_header_buttons(const bContext *C, ARegion *ar); void node_menus_register(void); /* node_draw.c */ +void node_socket_circle_draw(struct bNodeTree *ntree, struct bNodeSocket *sock, float size); +void node_draw_default(const struct bContext *C, struct ARegion *ar, struct SpaceNode *snode, struct bNodeTree *ntree, struct bNode *node); +void node_update_default(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node); +void node_update_nodetree(const struct bContext *C, struct bNodeTree *ntree, float offsetx, float offsety); +void node_draw_nodetree(const struct bContext *C, struct ARegion *ar, struct SpaceNode *snode, struct bNodeTree *ntree); void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d); /* node_buttons.c */ @@ -90,6 +98,7 @@ void NODE_OT_select_same_type_prev(wmOperatorType *ot); void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link); void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link, int th_col1, int do_shaded, int th_col2, int do_triple, int th_col3 ); int node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, float coord_array[][2], int resol); +void node_draw_link_straight(View2D *v2d, SpaceNode *snode, bNodeLink *link, int th_col1, int do_shaded, int th_col2, int do_triple, int th_col3 ); void draw_nodespace_back_pix(ARegion *ar, SpaceNode *snode, int color_manage); void draw_nodespace_color_info(struct ARegion *ar, int color_manage, int channels, int x, int y, char *cp, float *fp); @@ -97,10 +106,10 @@ void draw_nodespace_color_info(struct ARegion *ar, int color_manage, int channel void node_tree_from_ID(ID *id, bNodeTree **ntree, bNodeTree **edittree, int *treetype); void snode_notify(bContext *C, SpaceNode *snode); void snode_dag_update(bContext *C, SpaceNode *snode); -bNode *next_node(bNodeTree *ntree); -bNode *node_add_node(SpaceNode *snode, struct Main *bmain, Scene *scene, int type, float locx, float locy); +bNode *node_add_node(struct SpaceNode *snode, struct Main *bmain, struct Scene *scene, struct bNodeTemplate *ntemp, float locx, float locy); void snode_set_context(SpaceNode *snode, Scene *scene); void snode_make_group_editable(SpaceNode *snode, bNode *gnode); +void node_sort(struct bNodeTree *ntree); void node_deselectall(SpaceNode *snode); int node_select_same_type(SpaceNode *snode); int node_select_same_type_np(SpaceNode *snode, int dir); @@ -146,6 +155,8 @@ void NODE_OT_backimage_sample(wmOperatorType *ot); void NODE_OT_add_file(struct wmOperatorType *ot); +void NODE_OT_new_node_tree(struct wmOperatorType *ot); + extern const char *node_context_dir[]; // XXXXXX diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c index 4bb0283690b..153d703ddf6 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -96,6 +96,8 @@ void node_operatortypes(void) WM_operatortype_append(NODE_OT_backimage_sample); WM_operatortype_append(NODE_OT_add_file); + + WM_operatortype_append(NODE_OT_new_node_tree); } void ED_operatormacros_node(void) @@ -193,6 +195,5 @@ void node_keymap(struct wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "NODE_OT_read_fullsamplelayers", RKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "NODE_OT_render_changed", ZKEY, KM_PRESS, 0, 0); - transform_keymap_for_space(keyconf, keymap, SPACE_NODE); } diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index ca673277739..3d8b1676ea5 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -62,7 +62,7 @@ static bNode *node_under_mouse(bNodeTree *ntree, int mx, int my) { bNode *node; - for(next_node(ntree); (node=next_node(NULL));) { + for(node=ntree->nodes.last; node; node=node->prev) { /* node body (header and scale are in other operators) */ if (BLI_in_rctf(&node->totr, mx, my)) return node; @@ -93,8 +93,10 @@ static bNode *node_mouse_select(Main *bmain, SpaceNode *snode, ARegion *ar, cons } else node->flag ^= SELECT; - + ED_node_set_active(bmain, snode->edittree, node); + + node_sort(snode->edittree); } return node; @@ -182,6 +184,8 @@ static int node_borderselect_exec(bContext *C, wmOperator *op) } } + node_sort(snode->edittree); + WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL); return OPERATOR_FINISHED; @@ -252,6 +256,8 @@ static int node_select_all_exec(bContext *C, wmOperator *UNUSED(op)) node->flag |= NODE_SELECT; } + node_sort(snode->edittree); + WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL); return OPERATOR_FINISHED; } @@ -292,6 +298,8 @@ static int node_select_linked_to_exec(bContext *C, wmOperator *UNUSED(op)) node->flag |= NODE_SELECT; } + node_sort(snode->edittree); + WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL); return OPERATOR_FINISHED; } @@ -332,6 +340,8 @@ static int node_select_linked_from_exec(bContext *C, wmOperator *UNUSED(op)) node->flag |= NODE_SELECT; } + node_sort(snode->edittree); + WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL); return OPERATOR_FINISHED; } @@ -358,6 +368,9 @@ static int node_select_same_type_exec(bContext *C, wmOperator *UNUSED(op)) SpaceNode *snode = CTX_wm_space_node(C); node_select_same_type(snode); + + node_sort(snode->edittree); + WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL); return OPERATOR_FINISHED; } @@ -384,7 +397,11 @@ static int node_select_same_type_next_exec(bContext *C, wmOperator *UNUSED(op)) SpaceNode *snode = CTX_wm_space_node(C); node_select_same_type_np(snode, 0); + + node_sort(snode->edittree); + WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL); + return OPERATOR_FINISHED; } @@ -408,6 +425,9 @@ static int node_select_same_type_prev_exec(bContext *C, wmOperator *UNUSED(op)) SpaceNode *snode = CTX_wm_space_node(C); node_select_same_type_np(snode, 1); + + node_sort(snode->edittree); + WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_node/node_state.c b/source/blender/editors/space_node/node_state.c index 601ffbd313d..c4567bea648 100644 --- a/source/blender/editors/space_node/node_state.c +++ b/source/blender/editors/space_node/node_state.c @@ -69,30 +69,14 @@ void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set) sock->flag &= ~SOCK_HIDDEN; } else { - bNode *gnode= node_tree_get_editgroup(snode->nodetree); - - /* hiding inside group should not break links in other group users */ - if(gnode) { - nodeGroupSocketUseFlags((bNodeTree *)gnode->id); - for(sock= node->inputs.first; sock; sock= sock->next) - if(!(sock->flag & SOCK_IN_USE)) - if(sock->link==NULL) - sock->flag |= SOCK_HIDDEN; - for(sock= node->outputs.first; sock; sock= sock->next) - if(!(sock->flag & SOCK_IN_USE)) - if(nodeCountSocketLinks(snode->edittree, sock)==0) - sock->flag |= SOCK_HIDDEN; + /* hide unused sockets */ + for(sock= node->inputs.first; sock; sock= sock->next) { + if(sock->link==NULL) + sock->flag |= SOCK_HIDDEN; } - else { - /* hide unused sockets */ - for(sock= node->inputs.first; sock; sock= sock->next) { - if(sock->link==NULL) - sock->flag |= SOCK_HIDDEN; - } - for(sock= node->outputs.first; sock; sock= sock->next) { - if(nodeCountSocketLinks(snode->edittree, sock)==0) - sock->flag |= SOCK_HIDDEN; - } + for(sock= node->outputs.first; sock; sock= sock->next) { + if(nodeCountSocketLinks(snode->edittree, sock)==0) + sock->flag |= SOCK_HIDDEN; } } } @@ -100,7 +84,7 @@ void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set) static void node_hide_unhide_sockets(SpaceNode *snode, bNode *node) { node_set_hidden_sockets(snode, node, !node_has_hidden_sockets(node)); - node_tree_verify_groups(snode->nodetree); + ntreeUpdateTree(snode->edittree); } static int do_header_node(SpaceNode *snode, bNode *node, float mx, float my) @@ -168,7 +152,7 @@ static int node_toggle_visibility(SpaceNode *snode, ARegion *ar, const int mval[ UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &mx, &my); - for(next_node(snode->edittree); (node=next_node(NULL));) { + for(node=snode->edittree->nodes.last; node; node=node->prev) { if(node->flag & NODE_HIDDEN) { if(do_header_hidden_node(node, mx, my)) { ED_region_tag_redraw(ar); diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index 3c5f4a163a2..0990afa4fe6 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -439,14 +439,30 @@ static int node_context(const bContext *C, const char *member, bContextDataResul else if(CTX_data_equals(member, "selected_nodes")) { bNode *node; - for(next_node(snode->edittree); (node=next_node(NULL));) { - if(node->flag & NODE_SELECT) { - CTX_data_list_add(result, &snode->edittree->id, &RNA_Node, node); + if(snode->edittree) { + for(node=snode->edittree->nodes.last; node; node=node->prev) { + if(node->flag & NODE_SELECT) { + CTX_data_list_add(result, &snode->edittree->id, &RNA_Node, node); + } } } CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); return 1; } + else if(CTX_data_equals(member, "active_node")) { + bNode *node; + + if(snode->edittree) { + for(node=snode->edittree->nodes.last; node; node=node->prev) { + if(node->flag & NODE_ACTIVE) { + CTX_data_pointer_set(result, &snode->edittree->id, &RNA_Node, node); + break; + } + } + } + CTX_data_type_set(result, CTX_DATA_TYPE_POINTER); + return 1; + } return 0; } -- cgit v1.2.3