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