fix some complier warnings and add -Wundef to CMake's default GCC warnings.
[blender.git] / source / blender / editors / space_node / node_draw.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
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. 
10  *
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.
15  *
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.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  * Contributor(s): Nathan Letwory
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 /** \file blender/editors/space_node/node_draw.c
30  *  \ingroup spnode
31  */
32
33
34 #include <math.h>
35 #include <stdio.h>
36 #include <string.h>
37
38 #include "MEM_guardedalloc.h"
39
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"
46
47 #include "BLI_math.h"
48 #include "BLI_blenlib.h"
49 #include "BLI_threads.h"
50 #include "BLI_utildefines.h"
51
52 #include "BKE_context.h"
53 #include "BKE_depsgraph.h"
54 #include "BKE_main.h"
55 #include "BKE_node.h"
56
57 #include "BIF_gl.h"
58 #include "BIF_glutil.h"
59
60 #include "WM_api.h"
61 #include "WM_types.h"
62
63 #include "ED_node.h"
64 #include "ED_gpencil.h"
65
66 #include "UI_interface.h"
67 #include "UI_interface_icons.h"
68 #include "UI_resources.h"
69 #include "UI_view2d.h"
70
71 #include "RNA_access.h"
72
73 #include "NOD_composite.h"
74 #include "NOD_shader.h"
75
76 #include "node_intern.h"
77
78 /* width of socket columns in group display */
79 #define NODE_GROUP_FRAME                120
80
81 // XXX interface.h
82 extern void ui_dropshadow(rctf *rct, float radius, float aspect, int select);
83
84 /* XXX update functions for node editor are a mess, needs a clear concept */
85 void ED_node_tree_update(SpaceNode *snode, Scene *scene)
86 {
87         snode_set_context(snode, scene);
88         
89         if(snode->nodetree && snode->nodetree->id.us==0)
90                 snode->nodetree->id.us= 1;
91 }
92
93 void ED_node_changed_update(ID *id, bNode *node)
94 {
95         bNodeTree *nodetree, *edittree;
96         int treetype;
97
98         node_tree_from_ID(id, &nodetree, &edittree, &treetype);
99
100         if(treetype==NTREE_SHADER) {
101                 DAG_id_tag_update(id, 0);
102                 WM_main_add_notifier(NC_MATERIAL|ND_SHADING_DRAW, id);
103         }
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, ... */
107                         
108                 node= node_tree_get_editgroup(nodetree);
109                 if(node)
110                         NodeTagIDChanged(nodetree, node->id);
111
112                 WM_main_add_notifier(NC_SCENE|ND_NODES, id);
113         }                       
114         else if(treetype==NTREE_TEXTURE) {
115                 DAG_id_tag_update(id, 0);
116                 WM_main_add_notifier(NC_TEXTURE|ND_NODES, id);
117         }
118 }
119
120 static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup)
121 {
122         bNode *node;
123         
124         if(ntree == lookup)
125                 return 1;
126         
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))
130                                 return 1;
131         
132         return 0;
133 }
134
135 typedef struct NodeUpdateCalldata {
136         bNodeTree *ntree;
137         bNode *node;
138 } NodeUpdateCalldata;
139 static void node_generic_update_cb(void *calldata, ID *owner_id, bNodeTree *ntree)
140 {
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);
145 }
146 void ED_node_generic_update(Main *bmain, bNodeTree *ntree, bNode *node)
147 {
148         bNodeTreeType *tti= ntreeGetType(ntree->type);
149         NodeUpdateCalldata cd;
150         cd.ntree = ntree;
151         cd.node = node;
152         /* look through all datablocks, to support groups */
153         tti->foreach_nodetree(bmain, &cd, node_generic_update_cb);
154         
155         if(ntree->type == NTREE_TEXTURE)
156                 ntreeTexCheckCyclics(ntree);
157 }
158
159 static void do_node_internal_buttons(bContext *C, void *node_v, int event)
160 {
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);
165         }
166 }
167
168
169 static void node_scaling_widget(int color_id, float aspect, float xmin, float ymin, float xmax, float ymax)
170 {
171         float dx;
172         float dy;
173         
174         dx= 0.5f*(xmax-xmin);
175         dy= 0.5f*(ymax-ymin);
176         
177         UI_ThemeColorShade(color_id, +30);      
178         fdrawline(xmin, ymin, xmax, ymax);
179         fdrawline(xmin+dx, ymin, xmax, ymax-dy);
180         
181         UI_ThemeColorShade(color_id, -10);
182         fdrawline(xmin, ymin+aspect, xmax, ymax+aspect);
183         fdrawline(xmin+dx, ymin+aspect, xmax, ymax-dy+aspect);
184 }
185
186 static void node_uiblocks_init(const bContext *C, bNodeTree *ntree)
187 {
188         bNode *node;
189         char str[32];
190         
191         /* add node uiBlocks in reverse order - prevents events going to overlapping nodes */
192         
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) {
195                 
196                 if (node->flag & NODE_SELECT) {
197                         /* ui block */
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);
201                 }
202         }
203         
204         /* then the rest */
205         for(node= ntree->nodes.last; node; node= node->prev) {
206                 
207                 if (!(node->flag & (NODE_GROUP_EDIT|NODE_SELECT))) {
208                         /* ui block */
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);
212                 }
213         }
214 }
215
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)
218 {
219         uiLayout *layout;
220         PointerRNA ptr;
221         bNodeSocket *nsock;
222         float locx, locy;
223         float dy= locy;
224         int buty;
225         
226         /* get "global" coords */
227         nodeSpaceCoords(node, &locx, &locy);
228         dy= locy;
229         
230         /* header */
231         dy-= NODE_DY;
232         
233         /* little bit space in top */
234         if(node->outputs.first)
235                 dy-= NODE_DYS/2;
236
237         /* output sockets */
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;
242                         dy-= NODE_DY;
243                 }
244         }
245
246         node->prvr.xmin= locx + NODE_DYS;
247         node->prvr.xmax= locx + node->width- NODE_DYS;
248
249         /* preview rect? */
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);
253
254                 if(node->preview && node->preview->rect) {
255                         float aspect= 1.0f;
256                         
257                         if(node->preview && node->preview->xsize && node->preview->ysize) 
258                                 aspect= (float)node->preview->ysize/(float)node->preview->xsize;
259                         
260                         dy-= NODE_DYS/2;
261                         node->prvr.ymax= dy;
262                         
263                         if(aspect <= 1.0f)
264                                 node->prvr.ymin= dy - aspect*(node->width-NODE_DY);
265                         else {
266                                 float dx= (node->width - NODE_DYS) - (node->width- NODE_DYS)/aspect;    /* width correction of image */
267                                 
268                                 node->prvr.ymin= dy - (node->width-NODE_DY);
269                                 
270                                 node->prvr.xmin+= 0.5f*dx;
271                                 node->prvr.xmax-= 0.5f*dx;
272                         }
273
274                         dy= node->prvr.ymin - NODE_DYS/2;
275
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);
279                 }
280                 else {
281                         float oldh= node->prvr.ymax - node->prvr.ymin;
282                         if(oldh==0.0f)
283                                 oldh= 0.6f*node->width-NODE_DY;
284                         dy-= NODE_DYS/2;
285                         node->prvr.ymax= dy;
286                         node->prvr.ymin= dy - oldh;
287                         dy= node->prvr.ymin - NODE_DYS/2;
288                 }
289
290                 BLI_unlock_thread(LOCK_PREVIEW);
291         }
292
293         /* buttons rect? */
294         if((node->flag & NODE_OPTIONS) && node->typeinfo->uifunc) {
295                 dy-= NODE_DYS/2;
296
297                 /* set this for uifunc() that don't use layout engine yet */
298                 node->butr.xmin= 0;
299                 node->butr.xmax= node->width - 2*NODE_DYS;
300                 node->butr.ymin= 0;
301                 node->butr.ymax= 0;
302                 
303                 RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr);
304                 
305                 layout= uiBlockLayout(node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL,
306                                                           locx+NODE_DYS, dy, node->butr.xmax, NODE_DY, U.uistyles.first);
307                 
308                 node->typeinfo->uifunc(layout, (bContext *)C, &ptr);
309                 
310                 uiBlockEndAlign(node->block);
311                 uiBlockLayoutResolve(node->block, NULL, &buty);
312                 
313                 dy= buty - NODE_DYS/2;
314         }
315
316         /* input sockets */
317         for(nsock= node->inputs.first; nsock; nsock= nsock->next) {
318                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
319                         nsock->locx= locx;
320                         nsock->locy= dy - NODE_DYS;
321                         dy-= NODE_DY;
322                 }
323         }
324         
325         /* little bit space in end */
326         if(node->inputs.first || (node->flag & (NODE_OPTIONS|NODE_PREVIEW))==0 )
327                 dy-= NODE_DYS/2;
328
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);
333 }
334
335 /* based on settings in node, sets drawing rect info. each redraw! */
336 static void node_update_hidden(bNode *node)
337 {
338         bNodeSocket *nsock;
339         float locx, locy;
340         float rad, drad, hiddenrad= HIDDEN_RAD;
341         int totin=0, totout=0, tot;
342         
343         /* get "global" coords */
344         nodeSpaceCoords(node, &locx, &locy);
345
346         /* calculate minimal radius */
347         for(nsock= node->inputs.first; nsock; nsock= nsock->next)
348                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
349                         totin++;
350         for(nsock= node->outputs.first; nsock; nsock= nsock->next)
351                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
352                         totout++;
353         
354         tot= MAX2(totin, totout);
355         if(tot>4) {
356                 hiddenrad += 5.0f*(float)(tot-4);
357         }
358         
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;
363         
364         /* output sockets */
365         rad=drad= (float)M_PI/(1.0f + (float)totout);
366         
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;
371                         rad+= drad;
372                 }
373         }
374         
375         /* input sockets */
376         rad=drad= - (float)M_PI/(1.0f + (float)totin);
377         
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;
382                         rad+= drad;
383                 }
384         }
385 }
386
387 void node_update_default(const bContext *C, bNodeTree *ntree, bNode *node)
388 {
389         if(node->flag & NODE_HIDDEN)
390                 node_update_hidden(node);
391         else
392                 node_update_basis(C, ntree, node);
393 }
394
395 static int node_get_colorid(bNode *node)
396 {
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;
402                 else
403                         return TH_NODE;
404         }
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;
411         return TH_NODE;
412 }
413
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)
417 {
418         static int types[]= { SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA };
419         bNodeLink link= {NULL};
420         int i;
421         
422         /* connect the first input of each type with first output of the same type */
423         
424         glEnable(GL_BLEND);
425         glEnable( GL_LINE_SMOOTH );
426         
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))
432                                 break;
433                 if (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))
436                                         break;
437                         
438                         if (link.tosock) {
439                                 node_draw_link_bezier(v2d, snode, &link, TH_REDALERT, 0, TH_WIRE, 0, TH_WIRE);
440                         }
441                 }
442         }
443         
444         glDisable(GL_BLEND);
445         glDisable( GL_LINE_SMOOTH );
446 }
447
448 /* this might have some more generic use */
449 static void node_circle_draw(float x, float y, float size, char *col)
450 {
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
457         };
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,
464         };
465         int a;
466         
467         glColor3ub(col[0], col[1], col[2]);
468         
469         glBegin(GL_POLYGON);
470         for(a=0; a<16; a++)
471                 glVertex2f(x+size*si[a], y+size*co[a]);
472         glEnd();
473         
474         glColor4ub(0, 0, 0, 150);
475         glEnable(GL_BLEND);
476         glEnable( GL_LINE_SMOOTH );
477         glBegin(GL_LINE_LOOP);
478         for(a=0; a<16; a++)
479                 glVertex2f(x+size*si[a], y+size*co[a]);
480         glEnd();
481         glDisable( GL_LINE_SMOOTH );
482         glDisable(GL_BLEND);
483 }
484
485 void node_socket_circle_draw(bNodeTree *UNUSED(ntree), bNodeSocket *sock, float size)
486 {
487         bNodeSocketType *stype = ntreeGetSocketType(sock->type);
488         node_circle_draw(sock->locx, sock->locy, size, stype->ui_color);
489 }
490
491 /* **************  Socket callbacks *********** */
492
493 /* not a callback */
494 static void node_draw_preview(bNodePreview *preview, rctf *prv)
495 {
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;
499         float x, y;
500         
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);
505         
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;
509
510                         if(x+tile > prv->xmax)
511                                 tilex= prv->xmax-x;
512                         if(y+tile > prv->ymax)
513                                 tiley= prv->ymax-y;
514
515                         glRectf(x, y, x + tilex, y + tiley);
516                 }
517         }
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;
521
522                         if(x+tile > prv->xmax)
523                                 tilex= prv->xmax-x;
524                         if(y+tile > prv->ymax)
525                                 tiley= prv->ymax-y;
526
527                         glRectf(x, y, x + tilex, y + tiley);
528                 }
529         }
530         
531         glPixelZoom(xscale, yscale);
532
533         glEnable(GL_BLEND);
534         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );    /* premul graphics */
535         
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);
538         
539         glDisable(GL_BLEND);
540         glPixelZoom(1.0f, 1.0f);
541
542         UI_ThemeColorShadeAlpha(TH_BACK, -15, +100);
543         fdrawbox(prv->xmin, prv->ymin, prv->xmax, prv->ymax);
544         
545 }
546
547 static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node)
548 {
549         bNodeSocket *sock;
550         rctf *rct= &node->totr;
551         float iconofs;
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;
557         
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);
561         
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) {
565                 
566                 uiEndBlock(C, node->block);
567                 node->block= NULL;
568                 return;
569         }
570         
571         uiSetRoundBox(15-4);
572         ui_dropshadow(rct, BASIS_RAD, snode->aspect, node->flag & SELECT);
573         
574         /* header */
575         if(color_id==TH_NODE)
576                 UI_ThemeColorShade(color_id, -20);
577         else
578                 UI_ThemeColor(color_id);
579         
580         if(node->flag & NODE_MUTED)
581            UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);
582                 
583         uiSetRoundBox(3);
584         uiRoundBox(rct->xmin, rct->ymax-NODE_DY, rct->xmax, rct->ymax, BASIS_RAD);
585         
586         /* show/hide icons, note this sequence is copied in do_header_node() node_state.c */
587         iconofs= rct->xmax - 7.0f;
588         
589         if(node->typeinfo->flag & NODE_PREVIEW) {
590                 int icon_id;
591                 
592                 if(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT))
593                         icon_id= ICON_MATERIAL;
594                 else
595                         icon_id= ICON_MATERIAL_DATA;
596                 iconofs-=iconbutw;
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, "");
599         }
600         if(node->type == NODE_GROUP) {
601                 
602                 iconofs-=iconbutw;
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, "");
605         }
606         if(node->typeinfo->flag & NODE_OPTIONS) {
607                 iconofs-=iconbutw;
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, "");
610         }
611         {       /* always hide/reveal unused sockets */ 
612                 // XXX re-enable
613                 /* int shade;
614                 if(node_has_hidden_sockets(node))
615                         shade= -40;
616                 else
617                         shade= -90; */
618
619                 iconofs-=iconbutw;
620
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, "");
623         }
624         
625         /* title */
626         if(node->flag & SELECT) 
627                 UI_ThemeColor(TH_TEXT_HI);
628         else
629                 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
630         
631         /* open/close entirely? */
632         UI_DrawTriIcon(rct->xmin+10.0f, rct->ymax-NODE_DY/2.0f, 'v');
633         
634         /* this isn't doing anything for the label, so commenting out
635         if(node->flag & SELECT) 
636                 UI_ThemeColor(TH_TEXT_HI);
637         else
638                 UI_ThemeColor(TH_TEXT); */
639         
640         BLI_strncpy(showname, nodeLabel(node), sizeof(showname));
641         
642         //if(node->flag & NODE_MUTED)
643         //      sprintf(showname, "[%s]", showname);
644         
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, "");
647
648         /* body */
649         UI_ThemeColor4(TH_NODE);
650         glEnable(GL_BLEND);
651         uiSetRoundBox(8);
652         uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax-NODE_DY, BASIS_RAD);
653         glDisable(GL_BLEND);
654
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);
657
658         /* outline active and selected emphasis */
659         if( node->flag & (NODE_ACTIVE|SELECT) ) {
660                 glEnable(GL_BLEND);
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);
665                         else
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);
669                         
670                 glDisable( GL_LINE_SMOOTH );
671                 glDisable(GL_BLEND);
672         }
673         
674         /* disable lines */
675         if(node->flag & NODE_MUTED)
676                 node_draw_mute_line(v2d, snode, node);
677
678         
679         /* socket inputs, buttons */
680         for(sock= node->inputs.first; sock; sock= sock->next) {
681                 bNodeSocketType *stype= ntreeGetSocketType(sock->type);
682                 
683                 if(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))
684                         continue;
685                 
686                 node_socket_circle_draw(ntree, sock, NODE_SOCKSIZE);
687                 
688                 if (sock->link) {
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, "");
691                 }
692                 else {
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);
695                 }
696         }
697         
698         /* socket outputs */
699         for(sock= node->outputs.first; sock; sock= sock->next) {
700                 PointerRNA sockptr;
701                 float slen;
702                 int ofs;
703                 
704                 RNA_pointer_create((ID*)ntree, &RNA_NodeSocket, sock, &sockptr);
705                 
706                 if(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))
707                         continue;
708                 
709                 node_socket_circle_draw(ntree, sock, NODE_SOCKSIZE);
710                 
711                 ofs= 0;
712                 UI_ThemeColor(TH_TEXT);
713                 slen= snode->aspect*UI_GetStringWidth(sock->name);
714                 while(slen > node->width) {
715                         ofs++;
716                         slen= snode->aspect*UI_GetStringWidth(sock->name+ofs);
717                 }
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, "");
720         }
721         
722         /* preview */
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);
728         }
729         
730         UI_ThemeClearColor(color_id);
731                 
732         uiEndBlock(C, node->block);
733         uiDrawBlock(C, node->block);
734         node->block= NULL;
735 }
736
737 static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, bNode *node)
738 {
739         bNodeSocket *sock;
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 */
746         
747         /* shadow */
748         uiSetRoundBox(15);
749         ui_dropshadow(rct, hiddenrad, snode->aspect, node->flag & SELECT);
750
751         /* body */
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);
756         
757         /* outline active and selected emphasis */
758         if( node->flag & (NODE_ACTIVE|SELECT) ) {
759                 glEnable(GL_BLEND);
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);
764                         else
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 );
768                 glDisable(GL_BLEND);
769         }
770         
771         /* title */
772         if(node->flag & SELECT) 
773                 UI_ThemeColor(TH_TEXT_HI);
774         else
775                 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
776         
777         /* open entirely icon */
778         UI_DrawTriIcon(rct->xmin+10.0f, centy, 'h');    
779         
780         /* disable lines */
781         if(node->flag & NODE_MUTED)
782                 node_draw_mute_line(&ar->v2d, snode, node);     
783         
784         if(node->flag & SELECT) 
785                 UI_ThemeColor(TH_TEXT_HI);
786         else
787                 UI_ThemeColor(TH_TEXT);
788         
789         if(node->miniwidth>0.0f) {
790                 BLI_strncpy(showname, nodeLabel(node), sizeof(showname));
791                 
792                 //if(node->flag & NODE_MUTED)
793                 //      sprintf(showname, "[%s]", showname);
794
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, "");
797         }       
798
799         /* scale widget thing */
800         UI_ThemeColorShade(color_id, -10);      
801         dx= 10.0f;
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);
804         
805         UI_ThemeColorShade(color_id, +30);
806         dx-= snode->aspect;
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);
809         
810         /* sockets */
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);
814         }
815         
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);
819         }
820         
821         uiEndBlock(C, node->block);
822         uiDrawBlock(C, node->block);
823         node->block= NULL;
824 }
825
826 void node_draw_default(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node)
827 {
828         if(node->flag & NODE_HIDDEN)
829                 node_draw_hidden(C, ar, snode, node);
830         else
831                 node_draw_basis(C, ar, snode, ntree, node);
832 }
833
834 static void node_update(const bContext *C, bNodeTree *ntree, bNode *node)
835 {
836         if (node->typeinfo->drawupdatefunc)
837                 node->typeinfo->drawupdatefunc(C, ntree, node);
838 }
839
840 void node_update_nodetree(const bContext *C, bNodeTree *ntree, float offsetx, float offsety)
841 {
842         bNode *node;
843         
844         for(node= ntree->nodes.first; node; node= node->next) {
845                 /* XXX little hack */
846                 node->locx += offsetx;
847                 node->locy += offsety;
848                 
849                 node_update(C, ntree, node);
850                 
851                 node->locx -= offsetx;
852                 node->locy -= offsety;
853         }
854 }
855
856 static void node_draw(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node)
857 {
858         if (node->typeinfo->drawfunc)
859                 node->typeinfo->drawfunc(C, ar, snode, ntree, node);
860 }
861
862 void node_draw_nodetree(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree)
863 {
864         bNode *node;
865         bNodeLink *link;
866         int a;
867         
868         if(ntree==NULL) return;         /* groups... */
869         
870         /* node lines */
871         glEnable(GL_BLEND);
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);
876         glDisable(GL_BLEND);
877         
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);
882         }
883 }
884
885 void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d)
886 {
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;
892         
893         UI_ThemeClearColor(TH_BACK);
894         glClear(GL_COLOR_BUFFER_BIT);
895
896         UI_view2d_view_ortho(v2d);
897         
898         //uiFreeBlocksWin(&sa->uiblocks, sa->win);
899
900         /* only set once */
901         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
902         glEnable(GL_MAP1_VERTEX_3);
903
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);
907
908         UI_view2d_constant_grid_draw(v2d);
909         /* backdrop */
910         draw_nodespace_back_pix(ar, snode, color_manage);
911         
912         /* nodes */
913         snode_set_context(snode, CTX_data_scene(C));
914         
915         if(snode->nodetree) {
916                 bNode *node;
917                 
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);
923                 }
924                 
925                 node_uiblocks_init(C, snode->nodetree);
926                 
927                 node_update_nodetree(C, snode->nodetree, 0.0f, 0.0f);
928                 node_draw_nodetree(C, ar, snode, snode->nodetree);
929                 
930                 #if 0
931                 /* active group */
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);
935                 }
936                 #endif
937         }
938         
939         /* temporary links */
940         glEnable(GL_BLEND);
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);
945         glDisable(GL_BLEND);
946         
947         /* draw grease-pencil ('canvas' strokes) */
948         if (/*(snode->flag & SNODE_DISPGP) &&*/ (snode->nodetree))
949                 draw_gpencil_view2d((bContext*)C, 1);
950         
951         /* reset view matrix */
952         UI_view2d_view_restore(C);
953         
954         /* draw grease-pencil (screen strokes, and also paintbuffer) */
955         if (/*(snode->flag & SNODE_DISPGP) && */(snode->nodetree))
956                 draw_gpencil_view2d((bContext*)C, 0);
957         
958         /* scrollers */
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);
962 }