4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * The Original Code is Copyright (C) 2008 Blender Foundation.
21 * All rights reserved.
23 * The Original Code is: all of this file.
24 * Contributor(s): Nathan Letwory
26 * ***** END GPL LICENSE BLOCK *****
29 /** \file blender/editors/space_node/node_draw.c
38 #include "MEM_guardedalloc.h"
40 #include "DNA_node_types.h"
41 #include "DNA_material_types.h"
42 #include "DNA_object_types.h"
43 #include "DNA_scene_types.h"
44 #include "DNA_space_types.h"
45 #include "DNA_screen_types.h"
48 #include "BLI_blenlib.h"
49 #include "BLI_threads.h"
50 #include "BLI_utildefines.h"
52 #include "BKE_context.h"
53 #include "BKE_depsgraph.h"
58 #include "BIF_glutil.h"
64 #include "ED_gpencil.h"
66 #include "UI_interface.h"
67 #include "UI_interface_icons.h"
68 #include "UI_resources.h"
69 #include "UI_view2d.h"
71 #include "RNA_access.h"
73 #include "NOD_composite.h"
74 #include "NOD_shader.h"
76 #include "node_intern.h"
78 /* width of socket columns in group display */
79 #define NODE_GROUP_FRAME 120
82 extern void ui_dropshadow(rctf *rct, float radius, float aspect, int select);
84 /* XXX update functions for node editor are a mess, needs a clear concept */
85 void ED_node_tree_update(SpaceNode *snode, Scene *scene)
87 snode_set_context(snode, scene);
89 if(snode->nodetree && snode->nodetree->id.us==0)
90 snode->nodetree->id.us= 1;
93 void ED_node_changed_update(ID *id, bNode *node)
95 bNodeTree *nodetree, *edittree;
98 node_tree_from_ID(id, &nodetree, &edittree, &treetype);
100 if(treetype==NTREE_SHADER) {
101 DAG_id_tag_update(id, 0);
102 WM_main_add_notifier(NC_MATERIAL|ND_SHADING_DRAW, id);
104 else if(treetype==NTREE_COMPOSIT) {
105 NodeTagChanged(edittree, node);
106 /* don't use NodeTagIDChanged, it gives far too many recomposites for image, scene layers, ... */
108 node= node_tree_get_editgroup(nodetree);
110 NodeTagIDChanged(nodetree, node->id);
112 WM_main_add_notifier(NC_SCENE|ND_NODES, id);
114 else if(treetype==NTREE_TEXTURE) {
115 DAG_id_tag_update(id, 0);
116 WM_main_add_notifier(NC_TEXTURE|ND_NODES, id);
120 static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup)
127 for(node=ntree->nodes.first; node; node=node->next)
128 if(node->type == NODE_GROUP && node->id)
129 if(has_nodetree((bNodeTree*)node->id, lookup))
135 typedef struct NodeUpdateCalldata {
138 } NodeUpdateCalldata;
139 static void node_generic_update_cb(void *calldata, ID *owner_id, bNodeTree *ntree)
141 NodeUpdateCalldata *cd= (NodeUpdateCalldata*)calldata;
142 /* check if nodetree uses the group stored in calldata */
143 if (has_nodetree(ntree, cd->ntree))
144 ED_node_changed_update(owner_id, cd->node);
146 void ED_node_generic_update(Main *bmain, bNodeTree *ntree, bNode *node)
148 bNodeTreeType *tti= ntreeGetType(ntree->type);
149 NodeUpdateCalldata cd;
152 /* look through all datablocks, to support groups */
153 tti->foreach_nodetree(bmain, &cd, node_generic_update_cb);
155 if(ntree->type == NTREE_TEXTURE)
156 ntreeTexCheckCyclics(ntree);
159 static void do_node_internal_buttons(bContext *C, void *node_v, int event)
161 if(event==B_NODE_EXEC) {
162 SpaceNode *snode= CTX_wm_space_node(C);
163 if(snode && snode->id)
164 ED_node_changed_update(snode->id, node_v);
169 static void node_scaling_widget(int color_id, float aspect, float xmin, float ymin, float xmax, float ymax)
174 dx= 0.5f*(xmax-xmin);
175 dy= 0.5f*(ymax-ymin);
177 UI_ThemeColorShade(color_id, +30);
178 fdrawline(xmin, ymin, xmax, ymax);
179 fdrawline(xmin+dx, ymin, xmax, ymax-dy);
181 UI_ThemeColorShade(color_id, -10);
182 fdrawline(xmin, ymin+aspect, xmax, ymax+aspect);
183 fdrawline(xmin+dx, ymin+aspect, xmax, ymax-dy+aspect);
186 static void node_uiblocks_init(const bContext *C, bNodeTree *ntree)
191 /* add node uiBlocks in reverse order - prevents events going to overlapping nodes */
193 /* process selected nodes first so they're at the start of the uiblocks list */
194 for(node= ntree->nodes.last; node; node= node->prev) {
196 if (node->flag & NODE_SELECT) {
198 sprintf(str, "node buttons %p", (void *)node);
199 node->block= uiBeginBlock(C, CTX_wm_region(C), str, UI_EMBOSS);
200 uiBlockSetHandleFunc(node->block, do_node_internal_buttons, node);
205 for(node= ntree->nodes.last; node; node= node->prev) {
207 if (!(node->flag & (NODE_GROUP_EDIT|NODE_SELECT))) {
209 sprintf(str, "node buttons %p", (void *)node);
210 node->block= uiBeginBlock(C, CTX_wm_region(C), str, UI_EMBOSS);
211 uiBlockSetHandleFunc(node->block, do_node_internal_buttons, node);
216 /* based on settings in node, sets drawing rect info. each redraw! */
217 static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
226 /* get "global" coords */
227 nodeSpaceCoords(node, &locx, &locy);
233 /* little bit space in top */
234 if(node->outputs.first)
238 for(nsock= node->outputs.first; nsock; nsock= nsock->next) {
239 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
240 nsock->locx= locx + node->width;
241 nsock->locy= dy - NODE_DYS;
246 node->prvr.xmin= locx + NODE_DYS;
247 node->prvr.xmax= locx + node->width- NODE_DYS;
250 if(node->flag & NODE_PREVIEW) {
251 /* only recalculate size when there's a preview actually, otherwise we use stored result */
252 BLI_lock_thread(LOCK_PREVIEW);
254 if(node->preview && node->preview->rect) {
257 if(node->preview && node->preview->xsize && node->preview->ysize)
258 aspect= (float)node->preview->ysize/(float)node->preview->xsize;
264 node->prvr.ymin= dy - aspect*(node->width-NODE_DY);
266 float dx= (node->width - NODE_DYS) - (node->width- NODE_DYS)/aspect; /* width correction of image */
268 node->prvr.ymin= dy - (node->width-NODE_DY);
270 node->prvr.xmin+= 0.5f*dx;
271 node->prvr.xmax-= 0.5f*dx;
274 dy= node->prvr.ymin - NODE_DYS/2;
276 /* make sure that maximums are bigger or equal to minimums */
277 if(node->prvr.xmax < node->prvr.xmin) SWAP(float, node->prvr.xmax, node->prvr.xmin);
278 if(node->prvr.ymax < node->prvr.ymin) SWAP(float, node->prvr.ymax, node->prvr.ymin);
281 float oldh= node->prvr.ymax - node->prvr.ymin;
283 oldh= 0.6f*node->width-NODE_DY;
286 node->prvr.ymin= dy - oldh;
287 dy= node->prvr.ymin - NODE_DYS/2;
290 BLI_unlock_thread(LOCK_PREVIEW);
294 if((node->flag & NODE_OPTIONS) && node->typeinfo->uifunc) {
297 /* set this for uifunc() that don't use layout engine yet */
299 node->butr.xmax= node->width - 2*NODE_DYS;
303 RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr);
305 layout= uiBlockLayout(node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL,
306 locx+NODE_DYS, dy, node->butr.xmax, NODE_DY, U.uistyles.first);
308 node->typeinfo->uifunc(layout, (bContext *)C, &ptr);
310 uiBlockEndAlign(node->block);
311 uiBlockLayoutResolve(node->block, NULL, &buty);
313 dy= buty - NODE_DYS/2;
317 for(nsock= node->inputs.first; nsock; nsock= nsock->next) {
318 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
320 nsock->locy= dy - NODE_DYS;
325 /* little bit space in end */
326 if(node->inputs.first || (node->flag & (NODE_OPTIONS|NODE_PREVIEW))==0 )
329 node->totr.xmin= locx;
330 node->totr.xmax= locx + node->width;
331 node->totr.ymax= locy;
332 node->totr.ymin= MIN2(dy, locy-2*NODE_DY);
335 /* based on settings in node, sets drawing rect info. each redraw! */
336 static void node_update_hidden(bNode *node)
340 float rad, drad, hiddenrad= HIDDEN_RAD;
341 int totin=0, totout=0, tot;
343 /* get "global" coords */
344 nodeSpaceCoords(node, &locx, &locy);
346 /* calculate minimal radius */
347 for(nsock= node->inputs.first; nsock; nsock= nsock->next)
348 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
350 for(nsock= node->outputs.first; nsock; nsock= nsock->next)
351 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
354 tot= MAX2(totin, totout);
356 hiddenrad += 5.0f*(float)(tot-4);
359 node->totr.xmin= locx;
360 node->totr.xmax= locx + 3*hiddenrad + node->miniwidth;
361 node->totr.ymax= locy + (hiddenrad - 0.5f*NODE_DY);
362 node->totr.ymin= node->totr.ymax - 2*hiddenrad;
365 rad=drad= (float)M_PI/(1.0f + (float)totout);
367 for(nsock= node->outputs.first; nsock; nsock= nsock->next) {
368 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
369 nsock->locx= node->totr.xmax - hiddenrad + (float)sin(rad)*hiddenrad;
370 nsock->locy= node->totr.ymin + hiddenrad + (float)cos(rad)*hiddenrad;
376 rad=drad= - (float)M_PI/(1.0f + (float)totin);
378 for(nsock= node->inputs.first; nsock; nsock= nsock->next) {
379 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
380 nsock->locx= node->totr.xmin + hiddenrad + (float)sin(rad)*hiddenrad;
381 nsock->locy= node->totr.ymin + hiddenrad + (float)cos(rad)*hiddenrad;
387 void node_update_default(const bContext *C, bNodeTree *ntree, bNode *node)
389 if(node->flag & NODE_HIDDEN)
390 node_update_hidden(node);
392 node_update_basis(C, ntree, node);
395 static int node_get_colorid(bNode *node)
397 if(node->typeinfo->nclass==NODE_CLASS_INPUT)
398 return TH_NODE_IN_OUT;
399 if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) {
400 if(node->flag & NODE_DO_OUTPUT)
401 return TH_NODE_IN_OUT;
405 if(node->typeinfo->nclass==NODE_CLASS_CONVERTOR)
406 return TH_NODE_CONVERTOR;
407 if(ELEM3(node->typeinfo->nclass, NODE_CLASS_OP_COLOR, NODE_CLASS_OP_VECTOR, NODE_CLASS_OP_FILTER))
408 return TH_NODE_OPERATOR;
409 if(node->typeinfo->nclass==NODE_CLASS_GROUP)
410 return TH_NODE_GROUP;
414 /* note: in cmp_util.c is similar code, for node_compo_pass_on() */
415 /* note: in node_edit.c is similar code, for untangle node */
416 static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node)
418 static int types[]= { SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA };
419 bNodeLink link= {NULL};
422 /* connect the first input of each type with first output of the same type */
425 glEnable( GL_LINE_SMOOTH );
427 link.fromnode = link.tonode = node;
428 for (i=0; i < 3; ++i) {
429 /* find input socket */
430 for (link.fromsock=node->inputs.first; link.fromsock; link.fromsock=link.fromsock->next)
431 if (link.fromsock->type==types[i] && nodeCountSocketLinks(snode->edittree, link.fromsock))
434 for (link.tosock=node->outputs.first; link.tosock; link.tosock=link.tosock->next)
435 if (link.tosock->type==types[i] && nodeCountSocketLinks(snode->edittree, link.tosock))
439 node_draw_link_bezier(v2d, snode, &link, TH_REDALERT, 0, TH_WIRE, 0, TH_WIRE);
445 glDisable( GL_LINE_SMOOTH );
448 /* this might have some more generic use */
449 static void node_circle_draw(float x, float y, float size, char *col)
451 /* 16 values of sin function */
452 static float si[16] = {
453 0.00000000f, 0.39435585f,0.72479278f,0.93775213f,
454 0.99871650f,0.89780453f,0.65137248f,0.29936312f,
455 -0.10116832f,-0.48530196f,-0.79077573f,-0.96807711f,
456 -0.98846832f,-0.84864425f,-0.57126821f,-0.20129852f
458 /* 16 values of cos function */
459 static float co[16] ={
460 1.00000000f,0.91895781f,0.68896691f,0.34730525f,
461 -0.05064916f,-0.44039415f,-0.75875812f,-0.95413925f,
462 -0.99486932f,-0.87434661f,-0.61210598f,-0.25065253f,
463 0.15142777f,0.52896401f,0.82076344f,0.97952994f,
467 glColor3ub(col[0], col[1], col[2]);
471 glVertex2f(x+size*si[a], y+size*co[a]);
474 glColor4ub(0, 0, 0, 150);
476 glEnable( GL_LINE_SMOOTH );
477 glBegin(GL_LINE_LOOP);
479 glVertex2f(x+size*si[a], y+size*co[a]);
481 glDisable( GL_LINE_SMOOTH );
485 void node_socket_circle_draw(bNodeTree *UNUSED(ntree), bNodeSocket *sock, float size)
487 bNodeSocketType *stype = ntreeGetSocketType(sock->type);
488 node_circle_draw(sock->locx, sock->locy, size, stype->ui_color);
491 /* ************** Socket callbacks *********** */
494 static void node_draw_preview(bNodePreview *preview, rctf *prv)
496 float xscale= (prv->xmax-prv->xmin)/((float)preview->xsize);
497 float yscale= (prv->ymax-prv->ymin)/((float)preview->ysize);
498 float tile= (prv->xmax - prv->xmin) / 10.0f;
501 /* draw checkerboard backdrop to show alpha */
502 glColor3ub(120, 120, 120);
503 glRectf(prv->xmin, prv->ymin, prv->xmax, prv->ymax);
504 glColor3ub(160, 160, 160);
506 for(y=prv->ymin; y<prv->ymax; y+=tile*2) {
507 for(x=prv->xmin; x<prv->xmax; x+=tile*2) {
508 float tilex= tile, tiley= tile;
510 if(x+tile > prv->xmax)
512 if(y+tile > prv->ymax)
515 glRectf(x, y, x + tilex, y + tiley);
518 for(y=prv->ymin+tile; y<prv->ymax; y+=tile*2) {
519 for(x=prv->xmin+tile; x<prv->xmax; x+=tile*2) {
520 float tilex= tile, tiley= tile;
522 if(x+tile > prv->xmax)
524 if(y+tile > prv->ymax)
527 glRectf(x, y, x + tilex, y + tiley);
531 glPixelZoom(xscale, yscale);
534 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); /* premul graphics */
536 glColor4f(1.0, 1.0, 1.0, 1.0);
537 glaDrawPixelsTex(prv->xmin, prv->ymin, preview->xsize, preview->ysize, GL_UNSIGNED_BYTE, preview->rect);
540 glPixelZoom(1.0f, 1.0f);
542 UI_ThemeColorShadeAlpha(TH_BACK, -15, +100);
543 fdrawbox(prv->xmin, prv->ymin, prv->xmax, prv->ymax);
547 static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node)
550 rctf *rct= &node->totr;
552 /* float socket_size= NODE_SOCKSIZE*U.dpi/72; */ /* UNUSED */
553 float iconbutw= 0.8f*UI_UNIT_X;
554 int color_id= node_get_colorid(node);
555 char showname[128]; /* 128 used below */
556 View2D *v2d = &ar->v2d;
558 /* hurmf... another candidate for callback, have to see how this works first */
559 if(node->id && node->block && snode->treetype==NTREE_SHADER)
560 nodeShaderSynchronizeID(node, 0);
562 /* skip if out of view */
563 if (node->totr.xmax < ar->v2d.cur.xmin || node->totr.xmin > ar->v2d.cur.xmax ||
564 node->totr.ymax < ar->v2d.cur.ymin || node->totr.ymin > ar->v2d.cur.ymax) {
566 uiEndBlock(C, node->block);
572 ui_dropshadow(rct, BASIS_RAD, snode->aspect, node->flag & SELECT);
575 if(color_id==TH_NODE)
576 UI_ThemeColorShade(color_id, -20);
578 UI_ThemeColor(color_id);
580 if(node->flag & NODE_MUTED)
581 UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);
584 uiRoundBox(rct->xmin, rct->ymax-NODE_DY, rct->xmax, rct->ymax, BASIS_RAD);
586 /* show/hide icons, note this sequence is copied in do_header_node() node_state.c */
587 iconofs= rct->xmax - 7.0f;
589 if(node->typeinfo->flag & NODE_PREVIEW) {
592 if(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT))
593 icon_id= ICON_MATERIAL;
595 icon_id= ICON_MATERIAL_DATA;
597 uiDefIconBut(node->block, LABEL, B_REDR, icon_id, iconofs, rct->ymax-NODE_DY,
598 iconbutw, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, 0.5, "");
600 if(node->type == NODE_GROUP) {
603 uiDefIconBut(node->block, LABEL, B_REDR, ICON_NODETREE, iconofs, rct->ymax-NODE_DY,
604 iconbutw, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, 0.5, "");
606 if(node->typeinfo->flag & NODE_OPTIONS) {
608 uiDefIconBut(node->block, LABEL, B_REDR, ICON_BUTS, iconofs, rct->ymax-NODE_DY,
609 iconbutw, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, 0.5, "");
611 { /* always hide/reveal unused sockets */
614 if(node_has_hidden_sockets(node))
621 uiDefIconBut(node->block, LABEL, B_REDR, ICON_PLUS, iconofs, rct->ymax-NODE_DY,
622 iconbutw, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, 0.5, "");
626 if(node->flag & SELECT)
627 UI_ThemeColor(TH_TEXT_HI);
629 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
631 /* open/close entirely? */
632 UI_DrawTriIcon(rct->xmin+10.0f, rct->ymax-NODE_DY/2.0f, 'v');
634 /* this isn't doing anything for the label, so commenting out
635 if(node->flag & SELECT)
636 UI_ThemeColor(TH_TEXT_HI);
638 UI_ThemeColor(TH_TEXT); */
640 BLI_strncpy(showname, nodeLabel(node), sizeof(showname));
642 //if(node->flag & NODE_MUTED)
643 // sprintf(showname, "[%s]", showname);
645 uiDefBut(node->block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(rct->ymax-NODE_DY),
646 (int)(iconofs - rct->xmin-18.0f), NODE_DY, NULL, 0, 0, 0, 0, "");
649 UI_ThemeColor4(TH_NODE);
652 uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax-NODE_DY, BASIS_RAD);
655 /* scaling indicator */
656 node_scaling_widget(TH_NODE, snode->aspect, rct->xmax-BASIS_RAD*snode->aspect, rct->ymin, rct->xmax, rct->ymin+BASIS_RAD*snode->aspect);
658 /* outline active and selected emphasis */
659 if( node->flag & (NODE_ACTIVE|SELECT) ) {
661 glEnable( GL_LINE_SMOOTH );
662 /* using different shades of TH_TEXT_HI for the empasis, like triangle */
663 if( node->flag & NODE_ACTIVE )
664 UI_ThemeColorShadeAlpha(TH_TEXT_HI, 0, -40);
666 UI_ThemeColorShadeAlpha(TH_TEXT_HI, -20, -120);
667 uiSetRoundBox(15-4); // round all corners except lower right
668 uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
670 glDisable( GL_LINE_SMOOTH );
675 if(node->flag & NODE_MUTED)
676 node_draw_mute_line(v2d, snode, node);
679 /* socket inputs, buttons */
680 for(sock= node->inputs.first; sock; sock= sock->next) {
681 bNodeSocketType *stype= ntreeGetSocketType(sock->type);
683 if(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))
686 node_socket_circle_draw(ntree, sock, NODE_SOCKSIZE);
689 uiDefBut(node->block, LABEL, 0, sock->name, sock->locx+NODE_DYS, sock->locy-NODE_DYS, node->width-NODE_DY, NODE_DY,
690 NULL, 0, 0, 0, 0, "");
693 if (stype->buttonfunc)
694 stype->buttonfunc(C, node->block, ntree, node, sock, sock->name, sock->locx+NODE_DYS, sock->locy-NODE_DYS, node->width-NODE_DY);
699 for(sock= node->outputs.first; sock; sock= sock->next) {
704 RNA_pointer_create((ID*)ntree, &RNA_NodeSocket, sock, &sockptr);
706 if(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))
709 node_socket_circle_draw(ntree, sock, NODE_SOCKSIZE);
712 UI_ThemeColor(TH_TEXT);
713 slen= snode->aspect*UI_GetStringWidth(sock->name);
714 while(slen > node->width) {
716 slen= snode->aspect*UI_GetStringWidth(sock->name+ofs);
718 uiDefBut(node->block, LABEL, 0, sock->name+ofs, (short)(sock->locx-15.0f-slen), (short)(sock->locy-9.0f),
719 (short)(node->width-NODE_DY), NODE_DY, NULL, 0, 0, 0, 0, "");
723 if(node->flag & NODE_PREVIEW) {
724 BLI_lock_thread(LOCK_PREVIEW);
725 if(node->preview && node->preview->rect && !BLI_rctf_is_empty(&node->prvr))
726 node_draw_preview(node->preview, &node->prvr);
727 BLI_unlock_thread(LOCK_PREVIEW);
730 UI_ThemeClearColor(color_id);
732 uiEndBlock(C, node->block);
733 uiDrawBlock(C, node->block);
737 static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, bNode *node)
740 rctf *rct= &node->totr;
741 float dx, centy= 0.5f*(rct->ymax+rct->ymin);
742 float hiddenrad= 0.5f*(rct->ymax-rct->ymin);
743 float socket_size= NODE_SOCKSIZE*U.dpi/72;
744 int color_id= node_get_colorid(node);
745 char showname[128]; /* 128 is used below */
749 ui_dropshadow(rct, hiddenrad, snode->aspect, node->flag & SELECT);
752 UI_ThemeColor(color_id);
753 if(node->flag & NODE_MUTED)
754 UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);
755 uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
757 /* outline active and selected emphasis */
758 if( node->flag & (NODE_ACTIVE|SELECT) ) {
760 glEnable( GL_LINE_SMOOTH );
761 /* using different shades of TH_TEXT_HI for the empasis, like triangle */
762 if( node->flag & NODE_ACTIVE )
763 UI_ThemeColorShadeAlpha(TH_TEXT_HI, 0, -40);
765 UI_ThemeColorShadeAlpha(TH_TEXT_HI, -20, -120);
766 uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
767 glDisable( GL_LINE_SMOOTH );
772 if(node->flag & SELECT)
773 UI_ThemeColor(TH_TEXT_HI);
775 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
777 /* open entirely icon */
778 UI_DrawTriIcon(rct->xmin+10.0f, centy, 'h');
781 if(node->flag & NODE_MUTED)
782 node_draw_mute_line(&ar->v2d, snode, node);
784 if(node->flag & SELECT)
785 UI_ThemeColor(TH_TEXT_HI);
787 UI_ThemeColor(TH_TEXT);
789 if(node->miniwidth>0.0f) {
790 BLI_strncpy(showname, nodeLabel(node), sizeof(showname));
792 //if(node->flag & NODE_MUTED)
793 // sprintf(showname, "[%s]", showname);
795 uiDefBut(node->block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(centy-10),
796 (int)(rct->xmax - rct->xmin-18.0f -12.0f), NODE_DY, NULL, 0, 0, 0, 0, "");
799 /* scale widget thing */
800 UI_ThemeColorShade(color_id, -10);
802 fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
803 fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
805 UI_ThemeColorShade(color_id, +30);
807 fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
808 fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
811 for(sock= node->inputs.first; sock; sock= sock->next) {
812 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
813 node_socket_circle_draw(snode->nodetree, sock, socket_size);
816 for(sock= node->outputs.first; sock; sock= sock->next) {
817 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
818 node_socket_circle_draw(snode->nodetree, sock, socket_size);
821 uiEndBlock(C, node->block);
822 uiDrawBlock(C, node->block);
826 void node_draw_default(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node)
828 if(node->flag & NODE_HIDDEN)
829 node_draw_hidden(C, ar, snode, node);
831 node_draw_basis(C, ar, snode, ntree, node);
834 static void node_update(const bContext *C, bNodeTree *ntree, bNode *node)
836 if (node->typeinfo->drawupdatefunc)
837 node->typeinfo->drawupdatefunc(C, ntree, node);
840 void node_update_nodetree(const bContext *C, bNodeTree *ntree, float offsetx, float offsety)
844 for(node= ntree->nodes.first; node; node= node->next) {
845 /* XXX little hack */
846 node->locx += offsetx;
847 node->locy += offsety;
849 node_update(C, ntree, node);
851 node->locx -= offsetx;
852 node->locy -= offsety;
856 static void node_draw(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node)
858 if (node->typeinfo->drawfunc)
859 node->typeinfo->drawfunc(C, ar, snode, ntree, node);
862 void node_draw_nodetree(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree)
868 if(ntree==NULL) return; /* groups... */
872 glEnable(GL_LINE_SMOOTH);
873 for(link= ntree->links.first; link; link= link->next)
874 node_draw_link(&ar->v2d, snode, link);
875 glDisable(GL_LINE_SMOOTH);
878 /* draw nodes, last nodes in front */
879 for(a=0, node= ntree->nodes.first; node; node=node->next, a++) {
880 node->nr= a; /* index of node in list, used for exec event code */
881 node_draw(C, ar, snode, ntree, node);
885 void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d)
887 View2DScrollers *scrollers;
888 SpaceNode *snode= CTX_wm_space_node(C);
889 Scene *scene= CTX_data_scene(C);
890 int color_manage = scene->r.color_mgt_flag & R_COLOR_MANAGEMENT;
891 bNodeLinkDrag *nldrag;
893 UI_ThemeClearColor(TH_BACK);
894 glClear(GL_COLOR_BUFFER_BIT);
896 UI_view2d_view_ortho(v2d);
898 //uiFreeBlocksWin(&sa->uiblocks, sa->win);
901 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
902 glEnable(GL_MAP1_VERTEX_3);
904 /* aspect+font, set each time */
905 snode->aspect= (v2d->cur.xmax - v2d->cur.xmin)/((float)ar->winx);
906 // XXX snode->curfont= uiSetCurFont_ext(snode->aspect);
908 UI_view2d_constant_grid_draw(v2d);
910 draw_nodespace_back_pix(ar, snode, color_manage);
913 snode_set_context(snode, CTX_data_scene(C));
915 if(snode->nodetree) {
918 /* init ui blocks for opened node group trees first
919 * so they're in the correct depth stack order */
920 for(node= snode->nodetree->nodes.first; node; node= node->next) {
921 if(node->flag & NODE_GROUP_EDIT)
922 node_uiblocks_init(C, (bNodeTree *)node->id);
925 node_uiblocks_init(C, snode->nodetree);
927 node_update_nodetree(C, snode->nodetree, 0.0f, 0.0f);
928 node_draw_nodetree(C, ar, snode, snode->nodetree);
932 for(node= snode->nodetree->nodes.first; node; node= node->next) {
933 if(node->flag & NODE_GROUP_EDIT)
934 node_draw_group(C, ar, snode, snode->nodetree, node);
939 /* temporary links */
941 glEnable(GL_LINE_SMOOTH);
942 for(nldrag= snode->linkdrag.first; nldrag; nldrag= nldrag->next)
943 node_draw_link(&ar->v2d, snode, nldrag->link);
944 glDisable(GL_LINE_SMOOTH);
947 /* draw grease-pencil ('canvas' strokes) */
948 if (/*(snode->flag & SNODE_DISPGP) &&*/ (snode->nodetree))
949 draw_gpencil_view2d((bContext*)C, 1);
951 /* reset view matrix */
952 UI_view2d_view_restore(C);
954 /* draw grease-pencil (screen strokes, and also paintbuffer) */
955 if (/*(snode->flag & SNODE_DISPGP) && */(snode->nodetree))
956 draw_gpencil_view2d((bContext*)C, 0);
959 scrollers= UI_view2d_scrollers_calc(C, v2d, 10, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
960 UI_view2d_scrollers_draw(C, v2d, scrollers);
961 UI_view2d_scrollers_free(scrollers);