/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2008 Blender Foundation. * All rights reserved. * * The Original Code is: all of this file. * Contributor(s): Nathan Letwory * * ***** END GPL LICENSE BLOCK ***** */ /** \file blender/editors/space_node/node_draw.c * \ingroup spnode */ #include #include #include #include "MEM_guardedalloc.h" #include "DNA_node_types.h" #include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_space_types.h" #include "DNA_screen_types.h" #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_threads.h" #include "BLI_utildefines.h" #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_main.h" #include "BKE_node.h" #include "BIF_gl.h" #include "BIF_glutil.h" #include "WM_api.h" #include "WM_types.h" #include "ED_node.h" #include "ED_gpencil.h" #include "UI_interface.h" #include "UI_interface_icons.h" #include "UI_resources.h" #include "UI_view2d.h" #include "RNA_access.h" #include "NOD_composite.h" #include "NOD_shader.h" #include "node_intern.h" /* width of socket columns in group display */ #define NODE_GROUP_FRAME 120 // 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; int treetype; node_tree_from_ID(id, &nodetree, &edittree, &treetype); if(treetype==NTREE_SHADER) { DAG_id_tag_update(id, 0); WM_main_add_notifier(NC_MATERIAL|ND_SHADING_DRAW, id); } else if(treetype==NTREE_COMPOSIT) { NodeTagChanged(edittree, node); /* don't use NodeTagIDChanged, it gives far too many recomposites for image, scene layers, ... */ node= node_tree_get_editgroup(nodetree); if(node) NodeTagIDChanged(nodetree, node->id); WM_main_add_notifier(NC_SCENE|ND_NODES, id); } else if(treetype==NTREE_TEXTURE) { DAG_id_tag_update(id, 0); WM_main_add_notifier(NC_TEXTURE|ND_NODES, id); } } static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup) { bNode *node; if(ntree == lookup) return 1; for(node=ntree->nodes.first; node; node=node->next) if(node->type == NODE_GROUP && node->id) if(has_nodetree((bNodeTree*)node->id, lookup)) return 1; 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) { bNodeTreeType *tti= ntreeGetType(ntree->type); NodeUpdateCalldata cd; cd.ntree = ntree; cd.node = node; /* look through all datablocks, to support groups */ tti->foreach_nodetree(bmain, &cd, node_generic_update_cb); if(ntree->type == NTREE_TEXTURE) ntreeTexCheckCyclics(ntree); } static void do_node_internal_buttons(bContext *C, void *node_v, int event) { if(event==B_NODE_EXEC) { SpaceNode *snode= CTX_wm_space_node(C); if(snode && snode->id) ED_node_changed_update(snode->id, node_v); } } static void node_scaling_widget(int color_id, float aspect, float xmin, float ymin, float xmax, float ymax) { float dx; float dy; dx= 0.5f*(xmax-xmin); dy= 0.5f*(ymax-ymin); UI_ThemeColorShade(color_id, +30); fdrawline(xmin, ymin, xmax, ymax); fdrawline(xmin+dx, ymin, xmax, ymax-dy); UI_ThemeColorShade(color_id, -10); fdrawline(xmin, ymin+aspect, xmax, ymax+aspect); fdrawline(xmin+dx, ymin+aspect, xmax, ymax-dy+aspect); } static void node_uiblocks_init(const bContext *C, bNodeTree *ntree) { bNode *node; char str[32]; /* add node uiBlocks in reverse order - prevents events going to overlapping nodes */ /* process selected nodes first so they're at the start of the uiblocks list */ for(node= ntree->nodes.last; node; node= node->prev) { if (node->flag & NODE_SELECT) { /* ui block */ sprintf(str, "node buttons %p", (void *)node); node->block= uiBeginBlock(C, CTX_wm_region(C), str, UI_EMBOSS); uiBlockSetHandleFunc(node->block, do_node_internal_buttons, node); } } /* then the rest */ for(node= ntree->nodes.last; node; node= node->prev) { if (!(node->flag & (NODE_GROUP_EDIT|NODE_SELECT))) { /* ui block */ sprintf(str, "node buttons %p", (void *)node); node->block= uiBeginBlock(C, CTX_wm_region(C), str, UI_EMBOSS); uiBlockSetHandleFunc(node->block, do_node_internal_buttons, node); } } } /* based on settings in node, sets drawing rect info. each redraw! */ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) { uiLayout *layout; PointerRNA ptr; bNodeSocket *nsock; float locx, locy; float dy; int buty; /* get "global" coords */ nodeSpaceCoords(node, &locx, &locy); dy= locy; /* header */ dy-= NODE_DY; /* little bit space in top */ if(node->outputs.first) dy-= NODE_DYS/2; /* output sockets */ for(nsock= node->outputs.first; nsock; nsock= nsock->next) { if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) { nsock->locx= locx + node->width; nsock->locy= dy - NODE_DYS; dy-= NODE_DY; } } node->prvr.xmin= locx + NODE_DYS; node->prvr.xmax= locx + node->width- NODE_DYS; /* preview rect? */ if(node->flag & NODE_PREVIEW) { /* only recalculate size when there's a preview actually, otherwise we use stored result */ BLI_lock_thread(LOCK_PREVIEW); if(node->preview && node->preview->rect) { float aspect= 1.0f; if(node->preview && node->preview->xsize && node->preview->ysize) aspect= (float)node->preview->ysize/(float)node->preview->xsize; dy-= NODE_DYS/2; node->prvr.ymax= dy; if(aspect <= 1.0f) node->prvr.ymin= dy - aspect*(node->width-NODE_DY); else { float dx= (node->width - NODE_DYS) - (node->width- NODE_DYS)/aspect; /* width correction of image */ node->prvr.ymin= dy - (node->width-NODE_DY); node->prvr.xmin+= 0.5f*dx; node->prvr.xmax-= 0.5f*dx; } dy= node->prvr.ymin - NODE_DYS/2; /* make sure that maximums are bigger or equal to minimums */ if(node->prvr.xmax < node->prvr.xmin) SWAP(float, node->prvr.xmax, node->prvr.xmin); if(node->prvr.ymax < node->prvr.ymin) SWAP(float, node->prvr.ymax, node->prvr.ymin); } else { float oldh= node->prvr.ymax - node->prvr.ymin; if(oldh==0.0f) oldh= 0.6f*node->width-NODE_DY; dy-= NODE_DYS/2; node->prvr.ymax= dy; node->prvr.ymin= dy - oldh; dy= node->prvr.ymin - NODE_DYS/2; } BLI_unlock_thread(LOCK_PREVIEW); } /* buttons rect? */ if((node->flag & NODE_OPTIONS) && node->typeinfo->uifunc) { dy-= NODE_DYS/2; /* set this for uifunc() that don't use layout engine yet */ node->butr.xmin= 0; node->butr.xmax= node->width - 2*NODE_DYS; node->butr.ymin= 0; node->butr.ymax= 0; RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr); layout= uiBlockLayout(node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, locx+NODE_DYS, dy, node->butr.xmax, NODE_DY, UI_GetStyle()); 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= locx; nsock->locy= dy - NODE_DYS; dy-= NODE_DY; } } /* little bit space in end */ if(node->inputs.first || (node->flag & (NODE_OPTIONS|NODE_PREVIEW))==0 ) dy-= NODE_DYS/2; 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))) totin++; for(nsock= node->outputs.first; nsock; nsock= nsock->next) if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) totout++; tot= MAX2(totin, totout); if(tot>4) { hiddenrad += 5.0f*(float)(tot-4); } 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 */ rad=drad= (float)M_PI/(1.0f + (float)totout); for(nsock= node->outputs.first; nsock; nsock= nsock->next) { if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) { nsock->locx= node->totr.xmax - hiddenrad + (float)sin(rad)*hiddenrad; nsock->locy= node->totr.ymin + hiddenrad + (float)cos(rad)*hiddenrad; rad+= drad; } } /* input sockets */ rad=drad= - (float)M_PI/(1.0f + (float)totin); for(nsock= node->inputs.first; nsock; nsock= nsock->next) { if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) { nsock->locx= node->totr.xmin + hiddenrad + (float)sin(rad)*hiddenrad; nsock->locy= node->totr.ymin + hiddenrad + (float)cos(rad)*hiddenrad; rad+= drad; } } } 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) return TH_NODE_IN_OUT; if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) { if(node->flag & NODE_DO_OUTPUT) return TH_NODE_IN_OUT; else return TH_NODE; } if(node->typeinfo->nclass==NODE_CLASS_CONVERTOR) return TH_NODE_CONVERTOR; if(ELEM3(node->typeinfo->nclass, NODE_CLASS_OP_COLOR, NODE_CLASS_OP_VECTOR, NODE_CLASS_OP_FILTER)) return TH_NODE_OPERATOR; if(node->typeinfo->nclass==NODE_CLASS_GROUP) return TH_NODE_GROUP; return TH_NODE; } /* 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) { static int types[]= { SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA }; bNodeLink link= {NULL}; int i; /* connect the first input of each type with first output of the same type */ glEnable(GL_BLEND); glEnable( GL_LINE_SMOOTH ); 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 ); } /* this might have some more generic use */ static void node_circle_draw(float x, float y, float size, char *col) { /* 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(col[0], col[1], col[2]); 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); } void node_socket_circle_draw(bNodeTree *UNUSED(ntree), bNodeSocket *sock, float size) { bNodeSocketType *stype = ntreeGetSocketType(sock->type); node_circle_draw(sock->locx, sock->locy, size, stype->ui_color); } /* ************** Socket callbacks *********** */ /* not a callback */ static void node_draw_preview(bNodePreview *preview, rctf *prv) { float xscale= (prv->xmax-prv->xmin)/((float)preview->xsize); float yscale= (prv->ymax-prv->ymin)/((float)preview->ysize); float tile= (prv->xmax - prv->xmin) / 10.0f; float x, y; /* draw checkerboard backdrop to show alpha */ glColor3ub(120, 120, 120); glRectf(prv->xmin, prv->ymin, prv->xmax, prv->ymax); glColor3ub(160, 160, 160); for(y=prv->ymin; yymax; y+=tile*2) { for(x=prv->xmin; xxmax; x+=tile*2) { float tilex= tile, tiley= tile; if(x+tile > prv->xmax) tilex= prv->xmax-x; if(y+tile > prv->ymax) tiley= prv->ymax-y; glRectf(x, y, x + tilex, y + tiley); } } for(y=prv->ymin+tile; yymax; y+=tile*2) { for(x=prv->xmin+tile; xxmax; x+=tile*2) { float tilex= tile, tiley= tile; if(x+tile > prv->xmax) tilex= prv->xmax-x; if(y+tile > prv->ymax) tiley= prv->ymax-y; glRectf(x, y, x + tilex, y + tiley); } } glPixelZoom(xscale, yscale); glEnable(GL_BLEND); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); /* premul graphics */ glColor4f(1.0, 1.0, 1.0, 1.0); glaDrawPixelsTex(prv->xmin, prv->ymin, preview->xsize, preview->ysize, GL_UNSIGNED_BYTE, preview->rect); glDisable(GL_BLEND); glPixelZoom(1.0f, 1.0f); UI_ThemeColorShadeAlpha(TH_BACK, -15, +100); fdrawbox(prv->xmin, prv->ymin, prv->xmax, prv->ymax); } static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node) { bNodeSocket *sock; rctf *rct= &node->totr; float iconofs; /* float socket_size= NODE_SOCKSIZE*U.dpi/72; */ /* UNUSED */ float iconbutw= 0.8f*UI_UNIT_X; int color_id= node_get_colorid(node); char showname[128]; /* 128 used below */ View2D *v2d = &ar->v2d; /* hurmf... another candidate for callback, have to see how this works first */ if(node->id && node->block && snode->treetype==NTREE_SHADER) nodeShaderSynchronizeID(node, 0); /* skip if out of view */ if (node->totr.xmax < ar->v2d.cur.xmin || node->totr.xmin > ar->v2d.cur.xmax || node->totr.ymax < ar->v2d.cur.ymin || node->totr.ymin > ar->v2d.cur.ymax) { uiEndBlock(C, node->block); node->block= NULL; return; } uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_LEFT); ui_dropshadow(rct, BASIS_RAD, snode->aspect, node->flag & SELECT); /* header */ if(color_id==TH_NODE) UI_ThemeColorShade(color_id, -20); else UI_ThemeColor(color_id); if(node->flag & NODE_MUTED) UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f); uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT); uiRoundBox(rct->xmin, rct->ymax-NODE_DY, rct->xmax, rct->ymax, BASIS_RAD); /* show/hide icons, note this sequence is copied in do_header_node() node_state.c */ iconofs= rct->xmax - 7.0f; if(node->typeinfo->flag & NODE_PREVIEW) { int icon_id; if(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT)) icon_id= ICON_MATERIAL; else icon_id= ICON_MATERIAL_DATA; iconofs-=iconbutw; uiDefIconBut(node->block, LABEL, B_REDR, icon_id, iconofs, rct->ymax-NODE_DY, iconbutw, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, 0.5, ""); } if(node->type == NODE_GROUP) { iconofs-=iconbutw; uiDefIconBut(node->block, LABEL, B_REDR, ICON_NODETREE, iconofs, rct->ymax-NODE_DY, iconbutw, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, 0.5, ""); } if(node->typeinfo->flag & NODE_OPTIONS) { iconofs-=iconbutw; uiDefIconBut(node->block, LABEL, B_REDR, ICON_BUTS, iconofs, rct->ymax-NODE_DY, iconbutw, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, 0.5, ""); } { /* always hide/reveal unused sockets */ // XXX re-enable /* int shade; if(node_has_hidden_sockets(node)) shade= -40; else shade= -90; */ iconofs-=iconbutw; uiDefIconBut(node->block, LABEL, B_REDR, ICON_PLUS, iconofs, rct->ymax-NODE_DY, iconbutw, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, 0.5, ""); } /* title */ if(node->flag & SELECT) UI_ThemeColor(TH_TEXT_HI); else UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10); /* open/close entirely? */ UI_DrawTriIcon(rct->xmin+10.0f, rct->ymax-NODE_DY/2.0f, 'v'); /* this isn't doing anything for the label, so commenting out if(node->flag & SELECT) UI_ThemeColor(TH_TEXT_HI); else UI_ThemeColor(TH_TEXT); */ BLI_strncpy(showname, nodeLabel(node), sizeof(showname)); //if(node->flag & NODE_MUTED) // sprintf(showname, "[%s]", showname); uiDefBut(node->block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(rct->ymax-NODE_DY), (int)(iconofs - rct->xmin-18.0f), NODE_DY, NULL, 0, 0, 0, 0, ""); /* body */ UI_ThemeColor4(TH_NODE); glEnable(GL_BLEND); uiSetRoundBox(UI_CNR_BOTTOM_LEFT); uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax-NODE_DY, BASIS_RAD); glDisable(GL_BLEND); /* scaling indicator */ node_scaling_widget(TH_NODE, snode->aspect, rct->xmax-BASIS_RAD*snode->aspect, rct->ymin, rct->xmax, rct->ymin+BASIS_RAD*snode->aspect); /* outline active and selected emphasis */ if( node->flag & (NODE_ACTIVE|SELECT) ) { glEnable(GL_BLEND); glEnable( GL_LINE_SMOOTH ); /* using different shades of TH_TEXT_HI for the empasis, like triangle */ if( node->flag & NODE_ACTIVE ) UI_ThemeColorShadeAlpha(TH_TEXT_HI, 0, -40); else UI_ThemeColorShadeAlpha(TH_TEXT_HI, -20, -120); uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_LEFT); // round all corners except lower right uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD); glDisable( GL_LINE_SMOOTH ); glDisable(GL_BLEND); } /* disable lines */ if(node->flag & NODE_MUTED) node_draw_mute_line(v2d, snode, node); /* socket inputs, buttons */ for(sock= node->inputs.first; sock; sock= sock->next) { 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) { 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 */ if(node->flag & NODE_PREVIEW) { BLI_lock_thread(LOCK_PREVIEW); if(node->preview && node->preview->rect && !BLI_rctf_is_empty(&node->prvr)) node_draw_preview(node->preview, &node->prvr); BLI_unlock_thread(LOCK_PREVIEW); } UI_ThemeClearColor(color_id); uiEndBlock(C, node->block); uiDrawBlock(C, node->block); node->block= NULL; } static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, bNode *node) { bNodeSocket *sock; rctf *rct= &node->totr; float dx, centy= 0.5f*(rct->ymax+rct->ymin); float hiddenrad= 0.5f*(rct->ymax-rct->ymin); float socket_size= NODE_SOCKSIZE*U.dpi/72; int color_id= node_get_colorid(node); char showname[128]; /* 128 is used below */ /* shadow */ uiSetRoundBox(UI_CNR_ALL); ui_dropshadow(rct, hiddenrad, snode->aspect, node->flag & SELECT); /* body */ UI_ThemeColor(color_id); if(node->flag & NODE_MUTED) UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f); uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad); /* outline active and selected emphasis */ if( node->flag & (NODE_ACTIVE|SELECT) ) { glEnable(GL_BLEND); glEnable( GL_LINE_SMOOTH ); /* using different shades of TH_TEXT_HI for the empasis, like triangle */ if( node->flag & NODE_ACTIVE ) UI_ThemeColorShadeAlpha(TH_TEXT_HI, 0, -40); else UI_ThemeColorShadeAlpha(TH_TEXT_HI, -20, -120); uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad); glDisable( GL_LINE_SMOOTH ); glDisable(GL_BLEND); } /* title */ if(node->flag & SELECT) UI_ThemeColor(TH_TEXT_HI); else UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10); /* open entirely icon */ UI_DrawTriIcon(rct->xmin+10.0f, centy, 'h'); /* disable lines */ if(node->flag & NODE_MUTED) node_draw_mute_line(&ar->v2d, snode, node); if(node->flag & SELECT) UI_ThemeColor(TH_TEXT_HI); else UI_ThemeColor(TH_TEXT); if(node->miniwidth>0.0f) { BLI_strncpy(showname, nodeLabel(node), sizeof(showname)); //if(node->flag & NODE_MUTED) // sprintf(showname, "[%s]", showname); uiDefBut(node->block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(centy-10), (int)(rct->xmax - rct->xmin-18.0f -12.0f), NODE_DY, NULL, 0, 0, 0, 0, ""); } /* scale widget thing */ UI_ThemeColorShade(color_id, -10); dx= 10.0f; fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f); fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f); UI_ThemeColorShade(color_id, +30); dx-= snode->aspect; fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f); fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f); /* sockets */ for(sock= node->inputs.first; sock; sock= sock->next) { if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) 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))) node_socket_circle_draw(snode->nodetree, sock, socket_size); } uiEndBlock(C, node->block); uiDrawBlock(C, node->block); node->block= NULL; } 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; int a; if(ntree==NULL) return; /* groups... */ /* node lines */ glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); for(link= ntree->links.first; link; link= link->next) node_draw_link(&ar->v2d, snode, link); glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); /* 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 */ node_draw(C, ar, snode, ntree, node); } } void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d) { View2DScrollers *scrollers; SpaceNode *snode= CTX_wm_space_node(C); Scene *scene= CTX_data_scene(C); int color_manage = scene->r.color_mgt_flag & R_COLOR_MANAGEMENT; bNodeLinkDrag *nldrag; UI_ThemeClearColor(TH_BACK); glClear(GL_COLOR_BUFFER_BIT); UI_view2d_view_ortho(v2d); //uiFreeBlocksWin(&sa->uiblocks, sa->win); /* only set once */ glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glEnable(GL_MAP1_VERTEX_3); /* aspect+font, set each time */ snode->aspect= (v2d->cur.xmax - v2d->cur.xmin)/((float)ar->winx); // XXX snode->curfont= uiSetCurFont_ext(snode->aspect); UI_view2d_constant_grid_draw(v2d); /* backdrop */ draw_nodespace_back_pix(ar, snode, color_manage); /* nodes */ snode_set_context(snode, CTX_data_scene(C)); if(snode->nodetree) { bNode *node; /* init ui blocks for opened node group trees first * so they're in the correct depth stack order */ for(node= snode->nodetree->nodes.first; node; node= node->next) { if(node->flag & NODE_GROUP_EDIT) node_uiblocks_init(C, (bNodeTree *)node->id); } node_uiblocks_init(C, snode->nodetree); 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 */ glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); for(nldrag= snode->linkdrag.first; nldrag; nldrag= nldrag->next) node_draw_link(&ar->v2d, snode, nldrag->link); glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); /* draw grease-pencil ('canvas' strokes) */ if (/*(snode->flag & SNODE_DISPGP) &&*/ (snode->nodetree)) draw_gpencil_view2d((bContext*)C, 1); /* reset view matrix */ UI_view2d_view_restore(C); /* draw grease-pencil (screen strokes, and also paintbuffer) */ if (/*(snode->flag & SNODE_DISPGP) && */(snode->nodetree)) draw_gpencil_view2d((bContext*)C, 0); /* scrollers */ scrollers= UI_view2d_scrollers_calc(C, v2d, 10, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY); UI_view2d_scrollers_draw(C, v2d, scrollers); UI_view2d_scrollers_free(scrollers); }