Cycles: add location/rotate/scale and XYZ mapping options for all texture nodes,
[blender.git] / source / blender / editors / space_node / node_draw.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  * Contributor(s): Nathan Letwory
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_node/node_draw.c
28  *  \ingroup spnode
29  */
30
31
32 #include <math.h>
33 #include <stdio.h>
34 #include <string.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "DNA_node_types.h"
39 #include "DNA_lamp_types.h"
40 #include "DNA_material_types.h"
41 #include "DNA_object_types.h"
42 #include "DNA_scene_types.h"
43 #include "DNA_space_types.h"
44 #include "DNA_screen_types.h"
45 #include "DNA_world_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
103                 if(GS(id->name) == ID_MA)
104                         WM_main_add_notifier(NC_MATERIAL|ND_SHADING_DRAW, id);
105                 else if(GS(id->name) == ID_LA)
106                         WM_main_add_notifier(NC_LAMP|ND_LIGHTING_DRAW, id);
107                 else if(GS(id->name) == ID_WO)
108                         WM_main_add_notifier(NC_WORLD|ND_WORLD_DRAW, id);
109         }
110         else if(treetype==NTREE_COMPOSIT) {
111                 if(node)
112                         nodeUpdate(edittree, node);
113                 /* don't use NodeTagIDChanged, it gives far too many recomposites for image, scene layers, ... */
114                         
115                 node= node_tree_get_editgroup(nodetree);
116                 if(node)
117                         nodeUpdateID(nodetree, node->id);
118
119                 WM_main_add_notifier(NC_SCENE|ND_NODES, id);
120         }                       
121         else if(treetype==NTREE_TEXTURE) {
122                 DAG_id_tag_update(id, 0);
123                 WM_main_add_notifier(NC_TEXTURE|ND_NODES, id);
124         }
125 }
126
127 static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup)
128 {
129         bNode *node;
130         
131         if(ntree == lookup)
132                 return 1;
133         
134         for(node=ntree->nodes.first; node; node=node->next)
135                 if(node->type == NODE_GROUP && node->id)
136                         if(has_nodetree((bNodeTree*)node->id, lookup))
137                                 return 1;
138         
139         return 0;
140 }
141
142 typedef struct NodeUpdateCalldata {
143         bNodeTree *ntree;
144         bNode *node;
145 } NodeUpdateCalldata;
146 static void node_generic_update_cb(void *calldata, ID *owner_id, bNodeTree *ntree)
147 {
148         NodeUpdateCalldata *cd= (NodeUpdateCalldata*)calldata;
149         /* check if nodetree uses the group stored in calldata */
150         if (has_nodetree(ntree, cd->ntree))
151                 ED_node_changed_update(owner_id, cd->node);
152 }
153 void ED_node_generic_update(Main *bmain, bNodeTree *ntree, bNode *node)
154 {
155         bNodeTreeType *tti= ntreeGetType(ntree->type);
156         NodeUpdateCalldata cd;
157         cd.ntree = ntree;
158         cd.node = node;
159         /* look through all datablocks, to support groups */
160         tti->foreach_nodetree(bmain, &cd, node_generic_update_cb);
161         
162         if(ntree->type == NTREE_TEXTURE)
163                 ntreeTexCheckCyclics(ntree);
164 }
165
166 static void do_node_internal_buttons(bContext *C, void *node_v, int event)
167 {
168         if(event==B_NODE_EXEC) {
169                 SpaceNode *snode= CTX_wm_space_node(C);
170                 if(snode && snode->id)
171                         ED_node_changed_update(snode->id, node_v);
172         }
173 }
174
175
176 static void node_scaling_widget(int color_id, float aspect, float xmin, float ymin, float xmax, float ymax)
177 {
178         float dx;
179         float dy;
180         
181         dx= 0.5f*(xmax-xmin);
182         dy= 0.5f*(ymax-ymin);
183         
184         UI_ThemeColorShade(color_id, +30);      
185         fdrawline(xmin, ymin, xmax, ymax);
186         fdrawline(xmin+dx, ymin, xmax, ymax-dy);
187         
188         UI_ThemeColorShade(color_id, -10);
189         fdrawline(xmin, ymin+aspect, xmax, ymax+aspect);
190         fdrawline(xmin+dx, ymin+aspect, xmax, ymax-dy+aspect);
191 }
192
193 static void node_uiblocks_init(const bContext *C, bNodeTree *ntree)
194 {
195         bNode *node;
196         char str[32];
197         
198         /* add node uiBlocks in reverse order - prevents events going to overlapping nodes */
199         
200         /* process selected nodes first so they're at the start of the uiblocks list */
201         for(node= ntree->nodes.last; node; node= node->prev) {
202                 
203                 if (node->flag & NODE_SELECT) {
204                         /* ui block */
205                         sprintf(str, "node buttons %p", (void *)node);
206                         node->block= uiBeginBlock(C, CTX_wm_region(C), str, UI_EMBOSS);
207                         uiBlockSetHandleFunc(node->block, do_node_internal_buttons, node);
208                 }
209         }
210         
211         /* then the rest */
212         for(node= ntree->nodes.last; node; node= node->prev) {
213                 
214                 if (!(node->flag & (NODE_GROUP_EDIT|NODE_SELECT))) {
215                         /* ui block */
216                         sprintf(str, "node buttons %p", (void *)node);
217                         node->block= uiBeginBlock(C, CTX_wm_region(C), str, UI_EMBOSS);
218                         uiBlockSetHandleFunc(node->block, do_node_internal_buttons, node);
219                 }
220         }
221 }
222
223 /* based on settings in node, sets drawing rect info. each redraw! */
224 static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
225 {
226         uiLayout *layout;
227         PointerRNA ptr;
228         bNodeSocket *nsock;
229         float locx, locy;
230         float dy;
231         int buty;
232         
233         /* get "global" coords */
234         nodeSpaceCoords(node, &locx, &locy);
235         dy= locy;
236         
237         /* header */
238         dy-= NODE_DY;
239         
240         /* little bit space in top */
241         if(node->outputs.first)
242                 dy-= NODE_DYS/2;
243
244         /* output sockets */
245         for(nsock= node->outputs.first; nsock; nsock= nsock->next) {
246                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
247                         nsock->locx= locx + node->width;
248                         nsock->locy= dy - NODE_DYS;
249                         dy-= NODE_DY;
250                 }
251         }
252
253         node->prvr.xmin= locx + NODE_DYS;
254         node->prvr.xmax= locx + node->width- NODE_DYS;
255
256         /* preview rect? */
257         if(node->flag & NODE_PREVIEW) {
258                 /* only recalculate size when there's a preview actually, otherwise we use stored result */
259                 BLI_lock_thread(LOCK_PREVIEW);
260
261                 if(node->preview && node->preview->rect) {
262                         float aspect= 1.0f;
263                         
264                         if(node->preview && node->preview->xsize && node->preview->ysize) 
265                                 aspect= (float)node->preview->ysize/(float)node->preview->xsize;
266                         
267                         dy-= NODE_DYS/2;
268                         node->prvr.ymax= dy;
269                         
270                         if(aspect <= 1.0f)
271                                 node->prvr.ymin= dy - aspect*(node->width-NODE_DY);
272                         else {
273                                 float dx= (node->width - NODE_DYS) - (node->width- NODE_DYS)/aspect;    /* width correction of image */
274                                 
275                                 node->prvr.ymin= dy - (node->width-NODE_DY);
276                                 
277                                 node->prvr.xmin+= 0.5f*dx;
278                                 node->prvr.xmax-= 0.5f*dx;
279                         }
280
281                         dy= node->prvr.ymin - NODE_DYS/2;
282
283                         /* make sure that maximums are bigger or equal to minimums */
284                         if(node->prvr.xmax < node->prvr.xmin) SWAP(float, node->prvr.xmax, node->prvr.xmin);
285                         if(node->prvr.ymax < node->prvr.ymin) SWAP(float, node->prvr.ymax, node->prvr.ymin);
286                 }
287                 else {
288                         float oldh= node->prvr.ymax - node->prvr.ymin;
289                         if(oldh==0.0f)
290                                 oldh= 0.6f*node->width-NODE_DY;
291                         dy-= NODE_DYS/2;
292                         node->prvr.ymax= dy;
293                         node->prvr.ymin= dy - oldh;
294                         dy= node->prvr.ymin - NODE_DYS/2;
295                 }
296
297                 BLI_unlock_thread(LOCK_PREVIEW);
298         }
299
300         /* buttons rect? */
301         if((node->flag & NODE_OPTIONS) && node->typeinfo->uifunc) {
302                 dy-= NODE_DYS/2;
303
304                 /* set this for uifunc() that don't use layout engine yet */
305                 node->butr.xmin= 0;
306                 node->butr.xmax= node->width - 2*NODE_DYS;
307                 node->butr.ymin= 0;
308                 node->butr.ymax= 0;
309                 
310                 RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr);
311                 
312                 layout= uiBlockLayout(node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL,
313                                                           locx+NODE_DYS, dy, node->butr.xmax, NODE_DY, UI_GetStyle());
314                 
315                 node->typeinfo->uifunc(layout, (bContext *)C, &ptr);
316                 
317                 uiBlockEndAlign(node->block);
318                 uiBlockLayoutResolve(node->block, NULL, &buty);
319                 
320                 dy= buty - NODE_DYS/2;
321         }
322
323         /* input sockets */
324         for(nsock= node->inputs.first; nsock; nsock= nsock->next) {
325                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
326                         nsock->locx= locx;
327                         nsock->locy= dy - NODE_DYS;
328                         dy-= NODE_DY;
329                 }
330         }
331         
332         /* little bit space in end */
333         if(node->inputs.first || (node->flag & (NODE_OPTIONS|NODE_PREVIEW))==0 )
334                 dy-= NODE_DYS/2;
335
336         node->totr.xmin= locx;
337         node->totr.xmax= locx + node->width;
338         node->totr.ymax= locy;
339         node->totr.ymin= MIN2(dy, locy-2*NODE_DY);
340 }
341
342 /* based on settings in node, sets drawing rect info. each redraw! */
343 static void node_update_hidden(bNode *node)
344 {
345         bNodeSocket *nsock;
346         float locx, locy;
347         float rad, drad, hiddenrad= HIDDEN_RAD;
348         int totin=0, totout=0, tot;
349         
350         /* get "global" coords */
351         nodeSpaceCoords(node, &locx, &locy);
352
353         /* calculate minimal radius */
354         for(nsock= node->inputs.first; nsock; nsock= nsock->next)
355                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
356                         totin++;
357         for(nsock= node->outputs.first; nsock; nsock= nsock->next)
358                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
359                         totout++;
360         
361         tot= MAX2(totin, totout);
362         if(tot>4) {
363                 hiddenrad += 5.0f*(float)(tot-4);
364         }
365         
366         node->totr.xmin= locx;
367         node->totr.xmax= locx + 3*hiddenrad + node->miniwidth;
368         node->totr.ymax= locy + (hiddenrad - 0.5f*NODE_DY);
369         node->totr.ymin= node->totr.ymax - 2*hiddenrad;
370         
371         /* output sockets */
372         rad=drad= (float)M_PI/(1.0f + (float)totout);
373         
374         for(nsock= node->outputs.first; nsock; nsock= nsock->next) {
375                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
376                         nsock->locx= node->totr.xmax - hiddenrad + (float)sin(rad)*hiddenrad;
377                         nsock->locy= node->totr.ymin + hiddenrad + (float)cos(rad)*hiddenrad;
378                         rad+= drad;
379                 }
380         }
381         
382         /* input sockets */
383         rad=drad= - (float)M_PI/(1.0f + (float)totin);
384         
385         for(nsock= node->inputs.first; nsock; nsock= nsock->next) {
386                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
387                         nsock->locx= node->totr.xmin + hiddenrad + (float)sin(rad)*hiddenrad;
388                         nsock->locy= node->totr.ymin + hiddenrad + (float)cos(rad)*hiddenrad;
389                         rad+= drad;
390                 }
391         }
392 }
393
394 void node_update_default(const bContext *C, bNodeTree *ntree, bNode *node)
395 {
396         if(node->flag & NODE_HIDDEN)
397                 node_update_hidden(node);
398         else
399                 node_update_basis(C, ntree, node);
400 }
401
402 static int node_get_colorid(bNode *node)
403 {
404         if(node->typeinfo->nclass==NODE_CLASS_INPUT)
405                 return TH_NODE_IN_OUT;
406         if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) {
407                 if(node->flag & NODE_DO_OUTPUT)
408                         return TH_NODE_IN_OUT;
409                 else
410                         return TH_NODE;
411         }
412         if(node->typeinfo->nclass==NODE_CLASS_CONVERTOR)
413                 return TH_NODE_CONVERTOR;
414         if(ELEM3(node->typeinfo->nclass, NODE_CLASS_OP_COLOR, NODE_CLASS_OP_VECTOR, NODE_CLASS_OP_FILTER))
415                 return TH_NODE_OPERATOR;
416         if(node->typeinfo->nclass==NODE_CLASS_GROUP)
417                 return TH_NODE_GROUP;
418         return TH_NODE;
419 }
420
421 /* note: in cmp_util.c is similar code, for node_compo_pass_on() */
422 /* note: in node_edit.c is similar code, for untangle node */
423 static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node)
424 {
425         static int types[]= { SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA };
426         bNodeLink link= {NULL};
427         int i;
428         
429         /* connect the first input of each type with first output of the same type */
430         
431         glEnable(GL_BLEND);
432         glEnable( GL_LINE_SMOOTH );
433         
434         link.fromnode = link.tonode = node;
435         for (i=0; i < 3; ++i) {
436                 /* find input socket */
437                 for (link.fromsock=node->inputs.first; link.fromsock; link.fromsock=link.fromsock->next)
438                         if (link.fromsock->type==types[i] && nodeCountSocketLinks(snode->edittree, link.fromsock))
439                                 break;
440                 if (link.fromsock) {
441                         for (link.tosock=node->outputs.first; link.tosock; link.tosock=link.tosock->next)
442                                 if (link.tosock->type==types[i] && nodeCountSocketLinks(snode->edittree, link.tosock))
443                                         break;
444                         
445                         if (link.tosock) {
446                                 node_draw_link_bezier(v2d, snode, &link, TH_REDALERT, 0, TH_WIRE, 0, TH_WIRE);
447                         }
448                 }
449         }
450         
451         glDisable(GL_BLEND);
452         glDisable( GL_LINE_SMOOTH );
453 }
454
455 /* this might have some more generic use */
456 static void node_circle_draw(float x, float y, float size, char *col)
457 {
458         /* 16 values of sin function */
459         static float si[16] = {
460                 0.00000000f, 0.39435585f,0.72479278f,0.93775213f,
461                 0.99871650f,0.89780453f,0.65137248f,0.29936312f,
462                 -0.10116832f,-0.48530196f,-0.79077573f,-0.96807711f,
463                 -0.98846832f,-0.84864425f,-0.57126821f,-0.20129852f
464         };
465         /* 16 values of cos function */
466         static float co[16] ={
467                 1.00000000f,0.91895781f,0.68896691f,0.34730525f,
468                 -0.05064916f,-0.44039415f,-0.75875812f,-0.95413925f,
469                 -0.99486932f,-0.87434661f,-0.61210598f,-0.25065253f,
470                 0.15142777f,0.52896401f,0.82076344f,0.97952994f,
471         };
472         int a;
473         
474         glColor3ub(col[0], col[1], col[2]);
475         
476         glBegin(GL_POLYGON);
477         for(a=0; a<16; a++)
478                 glVertex2f(x+size*si[a], y+size*co[a]);
479         glEnd();
480         
481         glColor4ub(0, 0, 0, 150);
482         glEnable(GL_BLEND);
483         glEnable( GL_LINE_SMOOTH );
484         glBegin(GL_LINE_LOOP);
485         for(a=0; a<16; a++)
486                 glVertex2f(x+size*si[a], y+size*co[a]);
487         glEnd();
488         glDisable( GL_LINE_SMOOTH );
489         glDisable(GL_BLEND);
490 }
491
492 void node_socket_circle_draw(bNodeTree *UNUSED(ntree), bNodeSocket *sock, float size)
493 {
494         bNodeSocketType *stype = ntreeGetSocketType(sock->type);
495         node_circle_draw(sock->locx, sock->locy, size, stype->ui_color);
496 }
497
498 /* **************  Socket callbacks *********** */
499
500 /* not a callback */
501 static void node_draw_preview(bNodePreview *preview, rctf *prv)
502 {
503         float xscale= (prv->xmax-prv->xmin)/((float)preview->xsize);
504         float yscale= (prv->ymax-prv->ymin)/((float)preview->ysize);
505         float tile= (prv->xmax - prv->xmin) / 10.0f;
506         float x, y;
507         
508         /* draw checkerboard backdrop to show alpha */
509         glColor3ub(120, 120, 120);
510         glRectf(prv->xmin, prv->ymin, prv->xmax, prv->ymax);
511         glColor3ub(160, 160, 160);
512         
513         for(y=prv->ymin; y<prv->ymax; y+=tile*2) {
514                 for(x=prv->xmin; x<prv->xmax; x+=tile*2) {
515                         float tilex= tile, tiley= tile;
516
517                         if(x+tile > prv->xmax)
518                                 tilex= prv->xmax-x;
519                         if(y+tile > prv->ymax)
520                                 tiley= prv->ymax-y;
521
522                         glRectf(x, y, x + tilex, y + tiley);
523                 }
524         }
525         for(y=prv->ymin+tile; y<prv->ymax; y+=tile*2) {
526                 for(x=prv->xmin+tile; x<prv->xmax; x+=tile*2) {
527                         float tilex= tile, tiley= tile;
528
529                         if(x+tile > prv->xmax)
530                                 tilex= prv->xmax-x;
531                         if(y+tile > prv->ymax)
532                                 tiley= prv->ymax-y;
533
534                         glRectf(x, y, x + tilex, y + tiley);
535                 }
536         }
537         
538         glPixelZoom(xscale, yscale);
539
540         glEnable(GL_BLEND);
541         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );    /* premul graphics */
542         
543         glColor4f(1.0, 1.0, 1.0, 1.0);
544         glaDrawPixelsTex(prv->xmin, prv->ymin, preview->xsize, preview->ysize, GL_UNSIGNED_BYTE, preview->rect);
545         
546         glDisable(GL_BLEND);
547         glPixelZoom(1.0f, 1.0f);
548
549         UI_ThemeColorShadeAlpha(TH_BACK, -15, +100);
550         fdrawbox(prv->xmin, prv->ymin, prv->xmax, prv->ymax);
551         
552 }
553
554 static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node)
555 {
556         bNodeSocket *sock;
557         rctf *rct= &node->totr;
558         float iconofs;
559         /* float socket_size= NODE_SOCKSIZE*U.dpi/72; */ /* UNUSED */
560         float iconbutw= 0.8f*UI_UNIT_X;
561         int color_id= node_get_colorid(node);
562         char showname[128]; /* 128 used below */
563         View2D *v2d = &ar->v2d;
564         
565         /* hurmf... another candidate for callback, have to see how this works first */
566         if(node->id && node->block && snode->treetype==NTREE_SHADER)
567                 nodeShaderSynchronizeID(node, 0);
568         
569         /* skip if out of view */
570         if (node->totr.xmax < ar->v2d.cur.xmin || node->totr.xmin > ar->v2d.cur.xmax ||
571                         node->totr.ymax < ar->v2d.cur.ymin || node->totr.ymin > ar->v2d.cur.ymax) {
572                 
573                 uiEndBlock(C, node->block);
574                 node->block= NULL;
575                 return;
576         }
577         
578         uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_LEFT);
579         ui_dropshadow(rct, BASIS_RAD, snode->aspect, node->flag & SELECT);
580         
581         /* header */
582         if(color_id==TH_NODE)
583                 UI_ThemeColorShade(color_id, -20);
584         else
585                 UI_ThemeColor(color_id);
586         
587         if(node->flag & NODE_MUTED)
588            UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);
589                 
590         uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
591         uiRoundBox(rct->xmin, rct->ymax-NODE_DY, rct->xmax, rct->ymax, BASIS_RAD);
592         
593         /* show/hide icons, note this sequence is copied in do_header_node() node_state.c */
594         iconofs= rct->xmax - 7.0f;
595         
596         if(node->typeinfo->flag & NODE_PREVIEW) {
597                 int icon_id;
598                 
599                 if(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT))
600                         icon_id= ICON_MATERIAL;
601                 else
602                         icon_id= ICON_MATERIAL_DATA;
603                 iconofs-=iconbutw;
604                 uiDefIconBut(node->block, LABEL, B_REDR, icon_id, iconofs, rct->ymax-NODE_DY,
605                                          iconbutw, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, 0.5, "");
606         }
607         if(node->type == NODE_GROUP) {
608                 
609                 iconofs-=iconbutw;
610                 uiDefIconBut(node->block, LABEL, B_REDR, ICON_NODETREE, iconofs, rct->ymax-NODE_DY,
611                                          iconbutw, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, 0.5, "");
612         }
613         if(node->typeinfo->flag & NODE_OPTIONS) {
614                 iconofs-=iconbutw;
615                 uiDefIconBut(node->block, LABEL, B_REDR, ICON_BUTS, iconofs, rct->ymax-NODE_DY,
616                                          iconbutw, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, 0.5, "");
617         }
618         {       /* always hide/reveal unused sockets */ 
619                 // XXX re-enable
620                 /* int shade;
621                 if(node_has_hidden_sockets(node))
622                         shade= -40;
623                 else
624                         shade= -90; */
625
626                 iconofs-=iconbutw;
627
628                 uiDefIconBut(node->block, LABEL, B_REDR, ICON_PLUS, iconofs, rct->ymax-NODE_DY,
629                                                   iconbutw, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, 0.5, "");
630         }
631         
632         /* title */
633         if(node->flag & SELECT) 
634                 UI_ThemeColor(TH_TEXT_HI);
635         else
636                 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
637         
638         /* open/close entirely? */
639         UI_DrawTriIcon(rct->xmin+10.0f, rct->ymax-NODE_DY/2.0f, 'v');
640         
641         /* this isn't doing anything for the label, so commenting out
642         if(node->flag & SELECT) 
643                 UI_ThemeColor(TH_TEXT_HI);
644         else
645                 UI_ThemeColor(TH_TEXT); */
646         
647         BLI_strncpy(showname, nodeLabel(node), sizeof(showname));
648         
649         //if(node->flag & NODE_MUTED)
650         //      sprintf(showname, "[%s]", showname);
651         
652         uiDefBut(node->block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(rct->ymax-NODE_DY), 
653                          (int)(iconofs - rct->xmin-18.0f), NODE_DY,  NULL, 0, 0, 0, 0, "");
654
655         /* body */
656         UI_ThemeColor4(TH_NODE);
657         glEnable(GL_BLEND);
658         uiSetRoundBox(UI_CNR_BOTTOM_LEFT);
659         uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax-NODE_DY, BASIS_RAD);
660         glDisable(GL_BLEND);
661
662         /* scaling indicator */
663         node_scaling_widget(TH_NODE, snode->aspect, rct->xmax-BASIS_RAD*snode->aspect, rct->ymin, rct->xmax, rct->ymin+BASIS_RAD*snode->aspect);
664
665         /* outline active and selected emphasis */
666         if( node->flag & (NODE_ACTIVE|SELECT) ) {
667                 glEnable(GL_BLEND);
668                 glEnable( GL_LINE_SMOOTH );
669                         /* using different shades of TH_TEXT_HI for the empasis, like triangle */
670                         if( node->flag & NODE_ACTIVE ) 
671                                 UI_ThemeColorShadeAlpha(TH_TEXT_HI, 0, -40);
672                         else
673                                 UI_ThemeColorShadeAlpha(TH_TEXT_HI, -20, -120);
674                         uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_LEFT); // round all corners except lower right
675                         uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
676                         
677                 glDisable( GL_LINE_SMOOTH );
678                 glDisable(GL_BLEND);
679         }
680         
681         /* disable lines */
682         if(node->flag & NODE_MUTED)
683                 node_draw_mute_line(v2d, snode, node);
684
685         
686         /* socket inputs, buttons */
687         for(sock= node->inputs.first; sock; sock= sock->next) {
688                 bNodeSocketType *stype= ntreeGetSocketType(sock->type);
689                 
690                 if(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))
691                         continue;
692                 
693                 node_socket_circle_draw(ntree, sock, NODE_SOCKSIZE);
694                 
695                 if (sock->link || (sock->flag & SOCK_HIDE_VALUE)) {
696                         uiDefBut(node->block, LABEL, 0, sock->name, sock->locx+NODE_DYS, sock->locy-NODE_DYS, node->width-NODE_DY, NODE_DY,
697                                          NULL, 0, 0, 0, 0, "");
698                 }
699                 else {
700                         if (stype->buttonfunc)
701                                 stype->buttonfunc(C, node->block, ntree, node, sock, sock->name, sock->locx+NODE_DYS, sock->locy-NODE_DYS, node->width-NODE_DY);
702                 }
703         }
704         
705         /* socket outputs */
706         for(sock= node->outputs.first; sock; sock= sock->next) {
707                 PointerRNA sockptr;
708                 float slen;
709                 int ofs;
710                 
711                 RNA_pointer_create((ID*)ntree, &RNA_NodeSocket, sock, &sockptr);
712                 
713                 if(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))
714                         continue;
715                 
716                 node_socket_circle_draw(ntree, sock, NODE_SOCKSIZE);
717                 
718                 ofs= 0;
719                 UI_ThemeColor(TH_TEXT);
720                 slen= snode->aspect*UI_GetStringWidth(sock->name);
721                 while(slen > node->width) {
722                         ofs++;
723                         slen= snode->aspect*UI_GetStringWidth(sock->name+ofs);
724                 }
725                 uiDefBut(node->block, LABEL, 0, sock->name+ofs, (short)(sock->locx-15.0f-slen), (short)(sock->locy-9.0f), 
726                                  (short)(node->width-NODE_DY), NODE_DY,  NULL, 0, 0, 0, 0, "");
727         }
728         
729         /* preview */
730         if(node->flag & NODE_PREVIEW) {
731                 BLI_lock_thread(LOCK_PREVIEW);
732                 if(node->preview && node->preview->rect && !BLI_rctf_is_empty(&node->prvr))
733                         node_draw_preview(node->preview, &node->prvr);
734                 BLI_unlock_thread(LOCK_PREVIEW);
735         }
736         
737         UI_ThemeClearColor(color_id);
738                 
739         uiEndBlock(C, node->block);
740         uiDrawBlock(C, node->block);
741         node->block= NULL;
742 }
743
744 static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, bNode *node)
745 {
746         bNodeSocket *sock;
747         rctf *rct= &node->totr;
748         float dx, centy= 0.5f*(rct->ymax+rct->ymin);
749         float hiddenrad= 0.5f*(rct->ymax-rct->ymin);
750         float socket_size= NODE_SOCKSIZE*U.dpi/72;
751         int color_id= node_get_colorid(node);
752         char showname[128];     /* 128 is used below */
753         
754         /* shadow */
755         uiSetRoundBox(UI_CNR_ALL);
756         ui_dropshadow(rct, hiddenrad, snode->aspect, node->flag & SELECT);
757
758         /* body */
759         UI_ThemeColor(color_id);
760         if(node->flag & NODE_MUTED)
761            UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);     
762         uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
763         
764         /* outline active and selected emphasis */
765         if( node->flag & (NODE_ACTIVE|SELECT) ) {
766                 glEnable(GL_BLEND);
767                 glEnable( GL_LINE_SMOOTH );
768                         /* using different shades of TH_TEXT_HI for the empasis, like triangle */
769                         if( node->flag & NODE_ACTIVE ) 
770                                 UI_ThemeColorShadeAlpha(TH_TEXT_HI, 0, -40);
771                         else
772                                 UI_ThemeColorShadeAlpha(TH_TEXT_HI, -20, -120);
773                         uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
774                 glDisable( GL_LINE_SMOOTH );
775                 glDisable(GL_BLEND);
776         }
777         
778         /* title */
779         if(node->flag & SELECT) 
780                 UI_ThemeColor(TH_TEXT_HI);
781         else
782                 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
783         
784         /* open entirely icon */
785         UI_DrawTriIcon(rct->xmin+10.0f, centy, 'h');    
786         
787         /* disable lines */
788         if(node->flag & NODE_MUTED)
789                 node_draw_mute_line(&ar->v2d, snode, node);     
790         
791         if(node->flag & SELECT) 
792                 UI_ThemeColor(TH_TEXT_HI);
793         else
794                 UI_ThemeColor(TH_TEXT);
795         
796         if(node->miniwidth>0.0f) {
797                 BLI_strncpy(showname, nodeLabel(node), sizeof(showname));
798                 
799                 //if(node->flag & NODE_MUTED)
800                 //      sprintf(showname, "[%s]", showname);
801
802                 uiDefBut(node->block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(centy-10), 
803                                  (int)(rct->xmax - rct->xmin-18.0f -12.0f), NODE_DY,  NULL, 0, 0, 0, 0, "");
804         }       
805
806         /* scale widget thing */
807         UI_ThemeColorShade(color_id, -10);      
808         dx= 10.0f;
809         fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
810         fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
811         
812         UI_ThemeColorShade(color_id, +30);
813         dx-= snode->aspect;
814         fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
815         fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
816         
817         /* sockets */
818         for(sock= node->inputs.first; sock; sock= sock->next) {
819                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
820                         node_socket_circle_draw(snode->nodetree, sock, socket_size);
821         }
822         
823         for(sock= node->outputs.first; sock; sock= sock->next) {
824                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
825                         node_socket_circle_draw(snode->nodetree, sock, socket_size);
826         }
827         
828         uiEndBlock(C, node->block);
829         uiDrawBlock(C, node->block);
830         node->block= NULL;
831 }
832
833 void node_draw_default(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node)
834 {
835         if(node->flag & NODE_HIDDEN)
836                 node_draw_hidden(C, ar, snode, node);
837         else
838                 node_draw_basis(C, ar, snode, ntree, node);
839 }
840
841 static void node_update(const bContext *C, bNodeTree *ntree, bNode *node)
842 {
843         if (node->typeinfo->drawupdatefunc)
844                 node->typeinfo->drawupdatefunc(C, ntree, node);
845 }
846
847 void node_update_nodetree(const bContext *C, bNodeTree *ntree, float offsetx, float offsety)
848 {
849         bNode *node;
850         
851         for(node= ntree->nodes.first; node; node= node->next) {
852                 /* XXX little hack */
853                 node->locx += offsetx;
854                 node->locy += offsety;
855                 
856                 node_update(C, ntree, node);
857                 
858                 node->locx -= offsetx;
859                 node->locy -= offsety;
860         }
861 }
862
863 static void node_draw(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node)
864 {
865         if (node->typeinfo->drawfunc)
866                 node->typeinfo->drawfunc(C, ar, snode, ntree, node);
867 }
868
869 void node_draw_nodetree(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree)
870 {
871         bNode *node;
872         bNodeLink *link;
873         int a;
874         
875         if(ntree==NULL) return;         /* groups... */
876         
877         /* node lines */
878         glEnable(GL_BLEND);
879         glEnable(GL_LINE_SMOOTH);
880         for(link= ntree->links.first; link; link= link->next)
881                 node_draw_link(&ar->v2d, snode, link);
882         glDisable(GL_LINE_SMOOTH);
883         glDisable(GL_BLEND);
884         
885         /* draw nodes, last nodes in front */
886         for(a=0, node= ntree->nodes.first; node; node=node->next, a++) {
887                 node->nr= a;            /* index of node in list, used for exec event code */
888                 node_draw(C, ar, snode, ntree, node);
889         }
890 }
891
892 void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d)
893 {
894         View2DScrollers *scrollers;
895         SpaceNode *snode= CTX_wm_space_node(C);
896         Scene *scene= CTX_data_scene(C);
897         int color_manage = scene->r.color_mgt_flag & R_COLOR_MANAGEMENT;
898         bNodeLinkDrag *nldrag;
899         
900         UI_ThemeClearColor(TH_BACK);
901         glClear(GL_COLOR_BUFFER_BIT);
902
903         UI_view2d_view_ortho(v2d);
904         
905         //uiFreeBlocksWin(&sa->uiblocks, sa->win);
906
907         /* only set once */
908         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
909         glEnable(GL_MAP1_VERTEX_3);
910
911         /* aspect+font, set each time */
912         snode->aspect= (v2d->cur.xmax - v2d->cur.xmin)/((float)ar->winx);
913         // XXX snode->curfont= uiSetCurFont_ext(snode->aspect);
914
915         UI_view2d_constant_grid_draw(v2d);
916         /* backdrop */
917         draw_nodespace_back_pix(ar, snode, color_manage);
918         
919         /* nodes */
920         snode_set_context(snode, CTX_data_scene(C));
921         
922         if(snode->nodetree) {
923                 bNode *node;
924                 
925                 /* init ui blocks for opened node group trees first 
926                  * so they're in the correct depth stack order */
927                 for(node= snode->nodetree->nodes.first; node; node= node->next) {
928                         if(node->flag & NODE_GROUP_EDIT)
929                                 node_uiblocks_init(C, (bNodeTree *)node->id);
930                 }
931                 
932                 node_uiblocks_init(C, snode->nodetree);
933                 
934                 node_update_nodetree(C, snode->nodetree, 0.0f, 0.0f);
935                 node_draw_nodetree(C, ar, snode, snode->nodetree);
936                 
937                 #if 0
938                 /* active group */
939                 for(node= snode->nodetree->nodes.first; node; node= node->next) {
940                         if(node->flag & NODE_GROUP_EDIT)
941                                 node_draw_group(C, ar, snode, snode->nodetree, node);
942                 }
943                 #endif
944         }
945         
946         /* temporary links */
947         glEnable(GL_BLEND);
948         glEnable(GL_LINE_SMOOTH);
949         for(nldrag= snode->linkdrag.first; nldrag; nldrag= nldrag->next)
950                 node_draw_link(&ar->v2d, snode, nldrag->link);
951         glDisable(GL_LINE_SMOOTH);
952         glDisable(GL_BLEND);
953         
954         /* draw grease-pencil ('canvas' strokes) */
955         if (/*(snode->flag & SNODE_DISPGP) &&*/ (snode->nodetree))
956                 draw_gpencil_view2d((bContext*)C, 1);
957         
958         /* reset view matrix */
959         UI_view2d_view_restore(C);
960         
961         /* draw grease-pencil (screen strokes, and also paintbuffer) */
962         if (/*(snode->flag & SNODE_DISPGP) && */(snode->nodetree))
963                 draw_gpencil_view2d((bContext*)C, 0);
964         
965         /* scrollers */
966         scrollers= UI_view2d_scrollers_calc(C, v2d, 10, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
967         UI_view2d_scrollers_draw(C, v2d, scrollers);
968         UI_view2d_scrollers_free(scrollers);
969 }