svn merge ^/trunk/blender -r48409:48411
[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_rect.h"
50 #include "BLI_threads.h"
51 #include "BLI_utildefines.h"
52
53 #include "BLF_translation.h"
54
55 #include "BKE_context.h"
56 #include "BKE_depsgraph.h"
57 #include "BKE_main.h"
58 #include "BKE_node.h"
59
60 #include "BIF_gl.h"
61 #include "BIF_glutil.h"
62
63 #include "WM_api.h"
64 #include "WM_types.h"
65
66 #include "ED_node.h"
67 #include "ED_gpencil.h"
68 #include "ED_space_api.h"
69
70 #include "UI_interface.h"
71 #include "UI_interface_icons.h"
72 #include "UI_resources.h"
73 #include "UI_view2d.h"
74
75 #include "RNA_access.h"
76
77 #include "NOD_composite.h"
78 #include "NOD_shader.h"
79
80 #include "intern/node_util.h"
81
82 #include "node_intern.h"
83
84 /* width of socket columns in group display */
85 #define NODE_GROUP_FRAME                120
86 // XXX interface.h
87 extern void ui_dropshadow(rctf *rct, float radius, float aspect, float alpha, int select);
88
89 /* XXX update functions for node editor are a mess, needs a clear concept */
90 void ED_node_tree_update(SpaceNode *snode, Scene *scene)
91 {
92         snode_set_context(snode, scene);
93         
94         if (snode->nodetree && snode->nodetree->id.us==0)
95                 snode->nodetree->id.us= 1;
96 }
97
98 void ED_node_changed_update(ID *id, bNode *node)
99 {
100         bNodeTree *nodetree, *edittree;
101         int treetype;
102
103         node_tree_from_ID(id, &nodetree, &edittree, &treetype);
104
105         if (treetype==NTREE_SHADER) {
106                 DAG_id_tag_update(id, 0);
107
108                 if (GS(id->name) == ID_MA)
109                         WM_main_add_notifier(NC_MATERIAL|ND_SHADING_DRAW, id);
110                 else if (GS(id->name) == ID_LA)
111                         WM_main_add_notifier(NC_LAMP|ND_LIGHTING_DRAW, id);
112                 else if (GS(id->name) == ID_WO)
113                         WM_main_add_notifier(NC_WORLD|ND_WORLD_DRAW, id);
114         }
115         else if (treetype==NTREE_COMPOSIT) {
116                 if (node)
117                         nodeUpdate(edittree, node);
118                 /* don't use NodeTagIDChanged, it gives far too many recomposites for image, scene layers, ... */
119                         
120                 node= node_tree_get_editgroup(nodetree);
121                 if (node)
122                         nodeUpdateID(nodetree, node->id);
123
124                 WM_main_add_notifier(NC_SCENE|ND_NODES, id);
125         }                       
126         else if (treetype==NTREE_TEXTURE) {
127                 DAG_id_tag_update(id, 0);
128                 WM_main_add_notifier(NC_TEXTURE|ND_NODES, id);
129         }
130 }
131
132 static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup)
133 {
134         bNode *node;
135         
136         if (ntree == lookup)
137                 return 1;
138         
139         for (node=ntree->nodes.first; node; node=node->next)
140                 if (node->type == NODE_GROUP && node->id)
141                         if (has_nodetree((bNodeTree*)node->id, lookup))
142                                 return 1;
143         
144         return 0;
145 }
146
147 typedef struct NodeUpdateCalldata {
148         bNodeTree *ntree;
149         bNode *node;
150 } NodeUpdateCalldata;
151 static void node_generic_update_cb(void *calldata, ID *owner_id, bNodeTree *ntree)
152 {
153         NodeUpdateCalldata *cd= (NodeUpdateCalldata*)calldata;
154         /* check if nodetree uses the group stored in calldata */
155         if (has_nodetree(ntree, cd->ntree))
156                 ED_node_changed_update(owner_id, cd->node);
157 }
158 void ED_node_generic_update(Main *bmain, bNodeTree *ntree, bNode *node)
159 {
160         bNodeTreeType *tti= ntreeGetType(ntree->type);
161         NodeUpdateCalldata cd;
162         cd.ntree = ntree;
163         cd.node = node;
164         /* look through all datablocks, to support groups */
165         tti->foreach_nodetree(bmain, &cd, node_generic_update_cb);
166         
167         if (ntree->type == NTREE_TEXTURE)
168                 ntreeTexCheckCyclics(ntree);
169 }
170
171 static int compare_nodes(bNode *a, bNode *b)
172 {
173         bNode *parent;
174         /* These tell if either the node or any of the parent nodes is selected.
175          * A selected parent means an unselected node is also in foreground!
176          */
177         int a_select=(a->flag & NODE_SELECT), b_select=(b->flag & NODE_SELECT);
178         int a_active=(a->flag & NODE_ACTIVE), b_active=(b->flag & NODE_ACTIVE);
179         
180         /* if one is an ancestor of the other */
181         /* XXX there might be a better sorting algorithm for stable topological sort, this is O(n^2) worst case */
182         for (parent = a->parent; parent; parent=parent->parent) {
183                 /* if b is an ancestor, it is always behind a */
184                 if (parent==b)
185                         return 1;
186                 /* any selected ancestor moves the node forward */
187                 if (parent->flag & NODE_ACTIVE)
188                         a_active = 1;
189                 if (parent->flag & NODE_SELECT)
190                         a_select = 1;
191         }
192         for (parent = b->parent; parent; parent=parent->parent) {
193                 /* if a is an ancestor, it is always behind b */
194                 if (parent==a)
195                         return 0;
196                 /* any selected ancestor moves the node forward */
197                 if (parent->flag & NODE_ACTIVE)
198                         b_active = 1;
199                 if (parent->flag & NODE_SELECT)
200                         b_select = 1;
201         }
202
203         /* if one of the nodes is in the background and the other not */
204         if ((a->flag & NODE_BACKGROUND) && !(b->flag & NODE_BACKGROUND))
205                 return 0;
206         else if (!(a->flag & NODE_BACKGROUND) && (b->flag & NODE_BACKGROUND))
207                 return 1;
208         
209         /* if one has a higher selection state (active > selected > nothing) */
210         if (!b_active && a_active)
211                 return 1;
212         else if (!b_select && (a_active || a_select))
213                 return 1;
214         
215         return 0;
216 }
217
218 /* Sorts nodes by selection: unselected nodes first, then selected,
219  * then the active node at the very end. Relative order is kept intact!
220  */
221 void ED_node_sort(bNodeTree *ntree)
222 {
223         /* merge sort is the algorithm of choice here */
224         bNode *first_a, *first_b, *node_a, *node_b, *tmp;
225         int totnodes= BLI_countlist(&ntree->nodes);
226         int k, a, b;
227         
228         k = 1;
229         while (k < totnodes) {
230                 first_a = first_b = ntree->nodes.first;
231                 
232                 do {
233                         /* setup first_b pointer */
234                         for (b=0; b < k && first_b; ++b) {
235                                 first_b = first_b->next;
236                         }
237                         /* all batches merged? */
238                         if (first_b==NULL)
239                                 break;
240                         
241                         /* merge batches */
242                         node_a = first_a;
243                         node_b = first_b;
244                         a = b = 0;
245                         while (a < k && b < k && node_b) {
246                                 if (compare_nodes(node_a, node_b)==0) {
247                                         node_a = node_a->next;
248                                         ++a;
249                                 }
250                                 else {
251                                         tmp = node_b;
252                                         node_b = node_b->next;
253                                         ++b;
254                                         BLI_remlink(&ntree->nodes, tmp);
255                                         BLI_insertlinkbefore(&ntree->nodes, node_a, tmp);
256                                 }
257                         }
258
259                         /* setup first pointers for next batch */
260                         first_b = node_b;
261                         for (; b < k; ++b) {
262                                 /* all nodes sorted? */
263                                 if (first_b==NULL)
264                                         break;
265                                 first_b = first_b->next;
266                         }
267                         first_a = first_b;
268                 } while (first_b);
269                 
270                 k = k << 1;
271         }
272 }
273
274
275 static void do_node_internal_buttons(bContext *C, void *node_v, int event)
276 {
277         if (event==B_NODE_EXEC) {
278                 SpaceNode *snode= CTX_wm_space_node(C);
279                 if (snode && snode->id)
280                         ED_node_changed_update(snode->id, node_v);
281         }
282 }
283
284 static void node_uiblocks_init(const bContext *C, bNodeTree *ntree)
285 {
286         bNode *node;
287         char uiblockstr[32];
288         
289         /* add node uiBlocks in drawing order - prevents events going to overlapping nodes */
290         
291         for (node= ntree->nodes.first; node; node= node->next) {
292                 /* ui block */
293                 BLI_snprintf(uiblockstr, sizeof(uiblockstr), "node buttons %p", (void *)node);
294                 node->block= uiBeginBlock(C, CTX_wm_region(C), uiblockstr, UI_EMBOSS);
295                 uiBlockSetHandleFunc(node->block, do_node_internal_buttons, node);
296
297                 /* this cancels events for background nodes */
298                 uiBlockSetFlag(node->block, UI_BLOCK_CLIP_EVENTS);
299         }
300 }
301
302 /* based on settings in node, sets drawing rect info. each redraw! */
303 static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
304 {
305         uiLayout *layout;
306         PointerRNA ptr;
307         bNodeSocket *nsock;
308         float locx, locy;
309         float dy;
310         int buty;
311         
312         /* get "global" coords */
313         nodeToView(node, 0.0f, 0.0f, &locx, &locy);
314         dy= locy;
315         
316         /* header */
317         dy-= NODE_DY;
318         
319         /* little bit space in top */
320         if (node->outputs.first)
321                 dy-= NODE_DYS/2;
322
323         /* output sockets */
324         for (nsock= node->outputs.first; nsock; nsock= nsock->next) {
325                 if (!nodeSocketIsHidden(nsock)) {
326                         nsock->locx= locx + node->width;
327                         nsock->locy= dy - NODE_DYS;
328                         dy-= NODE_DY;
329                 }
330         }
331
332         node->prvr.xmin = locx + NODE_DYS;
333         node->prvr.xmax = locx + node->width- NODE_DYS;
334
335         /* preview rect? */
336         if (node->flag & NODE_PREVIEW) {
337                 /* only recalculate size when there's a preview actually, otherwise we use stored result */
338                 BLI_lock_thread(LOCK_PREVIEW);
339
340                 if (node->preview && node->preview->rect) {
341                         float aspect= 1.0f;
342                         
343                         if (node->preview && node->preview->xsize && node->preview->ysize) 
344                                 aspect= (float)node->preview->ysize/(float)node->preview->xsize;
345                         
346                         dy-= NODE_DYS/2;
347                         node->prvr.ymax = dy;
348                         
349                         if (aspect <= 1.0f)
350                                 node->prvr.ymin = dy - aspect*(node->width-NODE_DY);
351                         else {
352                                 float dx= (node->width - NODE_DYS) - (node->width- NODE_DYS)/aspect;    /* width correction of image */
353                                 
354                                 node->prvr.ymin = dy - (node->width-NODE_DY);
355                                 
356                                 node->prvr.xmin+= 0.5f*dx;
357                                 node->prvr.xmax-= 0.5f*dx;
358                         }
359
360                         dy= node->prvr.ymin - NODE_DYS/2;
361
362                         /* make sure that maximums are bigger or equal to minimums */
363                         if (node->prvr.xmax < node->prvr.xmin) SWAP(float, node->prvr.xmax, node->prvr.xmin);
364                         if (node->prvr.ymax < node->prvr.ymin) SWAP(float, node->prvr.ymax, node->prvr.ymin);
365                 }
366                 else {
367                         float oldh= node->prvr.ymax - node->prvr.ymin;
368                         if (oldh==0.0f)
369                                 oldh= 0.6f*node->width-NODE_DY;
370                         dy-= NODE_DYS/2;
371                         node->prvr.ymax = dy;
372                         node->prvr.ymin = dy - oldh;
373                         dy= node->prvr.ymin - NODE_DYS/2;
374                 }
375
376                 BLI_unlock_thread(LOCK_PREVIEW);
377         }
378
379         /* buttons rect? */
380         if ((node->flag & NODE_OPTIONS) && node->typeinfo->uifunc) {
381                 dy-= NODE_DYS/2;
382
383                 /* set this for uifunc() that don't use layout engine yet */
384                 node->butr.xmin = 0;
385                 node->butr.xmax = node->width - 2*NODE_DYS;
386                 node->butr.ymin = 0;
387                 node->butr.ymax = 0;
388                 
389                 RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr);
390                 
391                 layout= uiBlockLayout(node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL,
392                                                           locx+NODE_DYS, dy, node->butr.xmax, NODE_DY, UI_GetStyle());
393                 uiLayoutSetContextPointer(layout, "node", &ptr);
394                 
395                 node->typeinfo->uifunc(layout, (bContext *)C, &ptr);
396                 
397                 uiBlockEndAlign(node->block);
398                 uiBlockLayoutResolve(node->block, NULL, &buty);
399                 
400                 dy= buty - NODE_DYS/2;
401         }
402
403         /* input sockets */
404         for (nsock= node->inputs.first; nsock; nsock= nsock->next) {
405                 if (!nodeSocketIsHidden(nsock)) {
406                         nsock->locx= locx;
407                         nsock->locy= dy - NODE_DYS;
408                         dy-= NODE_DY;
409                 }
410         }
411         
412         /* little bit space in end */
413         if (node->inputs.first || (node->flag & (NODE_OPTIONS|NODE_PREVIEW))==0 )
414                 dy-= NODE_DYS/2;
415
416         node->totr.xmin = locx;
417         node->totr.xmax = locx + node->width;
418         node->totr.ymax = locy;
419         node->totr.ymin = MIN2(dy, locy-2*NODE_DY);
420         
421         /* Set the block bounds to clip mouse events from underlying nodes.
422          * Add a margin for sockets on each side.
423          */
424         uiExplicitBoundsBlock(node->block,
425                                                   node->totr.xmin - NODE_SOCKSIZE,
426                                                   node->totr.ymin,
427                                                   node->totr.xmax + NODE_SOCKSIZE,
428                                                   node->totr.ymax);
429 }
430
431 /* based on settings in node, sets drawing rect info. each redraw! */
432 static void node_update_hidden(bNode *node)
433 {
434         bNodeSocket *nsock;
435         float locx, locy;
436         float rad, drad, hiddenrad= HIDDEN_RAD;
437         int totin=0, totout=0, tot;
438         
439         /* get "global" coords */
440         nodeToView(node, 0.0f, 0.0f, &locx, &locy);
441
442         /* calculate minimal radius */
443         for (nsock= node->inputs.first; nsock; nsock= nsock->next)
444                 if (!nodeSocketIsHidden(nsock))
445                         totin++;
446         for (nsock= node->outputs.first; nsock; nsock= nsock->next)
447                 if (!nodeSocketIsHidden(nsock))
448                         totout++;
449         
450         tot= MAX2(totin, totout);
451         if (tot>4) {
452                 hiddenrad += 5.0f*(float)(tot-4);
453         }
454         
455         node->totr.xmin = locx;
456         node->totr.xmax = locx + 3*hiddenrad + node->miniwidth;
457         node->totr.ymax = locy + (hiddenrad - 0.5f*NODE_DY);
458         node->totr.ymin = node->totr.ymax - 2*hiddenrad;
459         
460         /* output sockets */
461         rad=drad= (float)M_PI/(1.0f + (float)totout);
462         
463         for (nsock= node->outputs.first; nsock; nsock= nsock->next) {
464                 if (!nodeSocketIsHidden(nsock)) {
465                         nsock->locx= node->totr.xmax - hiddenrad + (float)sin(rad)*hiddenrad;
466                         nsock->locy= node->totr.ymin + hiddenrad + (float)cos(rad)*hiddenrad;
467                         rad+= drad;
468                 }
469         }
470         
471         /* input sockets */
472         rad=drad= - (float)M_PI/(1.0f + (float)totin);
473         
474         for (nsock= node->inputs.first; nsock; nsock= nsock->next) {
475                 if (!nodeSocketIsHidden(nsock)) {
476                         nsock->locx= node->totr.xmin + hiddenrad + (float)sin(rad)*hiddenrad;
477                         nsock->locy= node->totr.ymin + hiddenrad + (float)cos(rad)*hiddenrad;
478                         rad+= drad;
479                 }
480         }
481
482         /* Set the block bounds to clip mouse events from underlying nodes.
483          * Add a margin for sockets on each side.
484          */
485         uiExplicitBoundsBlock(node->block,
486                                                   node->totr.xmin - NODE_SOCKSIZE,
487                                                   node->totr.ymin,
488                                                   node->totr.xmax + NODE_SOCKSIZE,
489                                                   node->totr.ymax);
490 }
491
492 void node_update_default(const bContext *C, bNodeTree *ntree, bNode *node)
493 {
494         if (node->flag & NODE_HIDDEN)
495                 node_update_hidden(node);
496         else
497                 node_update_basis(C, ntree, node);
498 }
499
500 int node_select_area_default(bNode *node, int x, int y)
501 {
502         return BLI_in_rctf(&node->totr, x, y);
503 }
504
505 int node_tweak_area_default(bNode *node, int x, int y)
506 {
507         return BLI_in_rctf(&node->totr, x, y);
508 }
509
510 int node_get_colorid(bNode *node)
511 {
512         if (node->typeinfo->nclass==NODE_CLASS_INPUT)
513                 return TH_NODE_IN_OUT;
514         if (node->typeinfo->nclass==NODE_CLASS_OUTPUT) {
515                 if (node->flag & NODE_DO_OUTPUT)
516                         return TH_NODE_IN_OUT;
517                 else
518                         return TH_NODE;
519         }
520         if (node->typeinfo->nclass==NODE_CLASS_CONVERTOR)
521                 return TH_NODE_CONVERTOR;
522         if (ELEM3(node->typeinfo->nclass, NODE_CLASS_OP_COLOR, NODE_CLASS_OP_VECTOR, NODE_CLASS_OP_FILTER))
523                 return TH_NODE_OPERATOR;
524         if (node->typeinfo->nclass==NODE_CLASS_GROUP)
525                 return TH_NODE_GROUP;
526         return TH_NODE;
527 }
528
529 /* note: in cmp_util.c is similar code, for node_compo_pass_on()
530  *       the same goes for shader and texture nodes. */
531 /* note: in node_edit.c is similar code, for untangle node */
532 static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node)
533 {
534         ListBase links;
535         bNodeLink *link;
536
537         if (node->typeinfo->internal_connect == NULL)
538                 return;
539
540         /* Get default muting links. */
541         links = node->typeinfo->internal_connect(snode->edittree, node);
542
543         glEnable(GL_BLEND);
544         glEnable(GL_LINE_SMOOTH);
545
546         for (link = links.first; link; link = link->next)
547                 node_draw_link_bezier(v2d, snode, link, TH_REDALERT, 0, TH_WIRE, 0, TH_WIRE);
548
549         glDisable(GL_BLEND);
550         glDisable(GL_LINE_SMOOTH);
551
552         BLI_freelistN(&links);
553 }
554
555 /* this might have some more generic use */
556 static void node_circle_draw(float x, float y, float size, char *col, int highlight)
557 {
558         /* 16 values of sin function */
559         static float si[16] = {
560                 0.00000000f, 0.39435585f, 0.72479278f, 0.93775213f,
561                 0.99871650f, 0.89780453f, 0.65137248f, 0.29936312f,
562                 -0.10116832f, -0.48530196f, -0.79077573f, -0.96807711f,
563                 -0.98846832f, -0.84864425f, -0.57126821f, -0.20129852f
564         };
565         /* 16 values of cos function */
566         static float co[16] ={
567                 1.00000000f, 0.91895781f, 0.68896691f, 0.34730525f,
568                 -0.05064916f, -0.44039415f, -0.75875812f, -0.95413925f,
569                 -0.99486932f, -0.87434661f, -0.61210598f, -0.25065253f,
570                 0.15142777f, 0.52896401f, 0.82076344f, 0.97952994f,
571         };
572         int a;
573         
574         glColor3ub(col[0], col[1], col[2]);
575         
576         glBegin(GL_POLYGON);
577         for (a=0; a<16; a++)
578                 glVertex2f(x+size*si[a], y+size*co[a]);
579         glEnd();
580         
581         if (highlight) {
582                 UI_ThemeColor(TH_TEXT_HI);
583                 glLineWidth(1.5f);
584         }
585         else {
586                 glColor4ub(0, 0, 0, 150);
587         }
588         glEnable(GL_BLEND);
589         glEnable(GL_LINE_SMOOTH);
590         glBegin(GL_LINE_LOOP);
591         for (a=0; a<16; a++)
592                 glVertex2f(x+size*si[a], y+size*co[a]);
593         glEnd();
594         glDisable(GL_LINE_SMOOTH);
595         glDisable(GL_BLEND);
596         glLineWidth(1.0f);
597 }
598
599 void node_socket_circle_draw(bNodeTree *UNUSED(ntree), bNodeSocket *sock, float size, int highlight)
600 {
601         bNodeSocketType *stype = ntreeGetSocketType(sock->type);
602         node_circle_draw(sock->locx, sock->locy, size, stype->ui_color, highlight);
603 }
604
605 /* **************  Socket callbacks *********** */
606
607 /* not a callback */
608 static void node_draw_preview(bNodePreview *preview, rctf *prv)
609 {
610         float xscale= (prv->xmax-prv->xmin)/((float)preview->xsize);
611         float yscale= (prv->ymax-prv->ymin)/((float)preview->ysize);
612         float tile= (prv->xmax - prv->xmin) / 10.0f;
613         float x, y;
614         
615         /* draw checkerboard backdrop to show alpha */
616         glColor3ub(120, 120, 120);
617         glRectf(prv->xmin, prv->ymin, prv->xmax, prv->ymax);
618         glColor3ub(160, 160, 160);
619         
620         for (y=prv->ymin; y<prv->ymax; y+=tile*2) {
621                 for (x=prv->xmin; x<prv->xmax; x+=tile*2) {
622                         float tilex= tile, tiley= tile;
623
624                         if (x+tile > prv->xmax)
625                                 tilex= prv->xmax-x;
626                         if (y+tile > prv->ymax)
627                                 tiley= prv->ymax-y;
628
629                         glRectf(x, y, x + tilex, y + tiley);
630                 }
631         }
632         for (y=prv->ymin+tile; y<prv->ymax; y+=tile*2) {
633                 for (x=prv->xmin+tile; x<prv->xmax; x+=tile*2) {
634                         float tilex= tile, tiley= tile;
635
636                         if (x+tile > prv->xmax)
637                                 tilex= prv->xmax-x;
638                         if (y+tile > prv->ymax)
639                                 tiley= prv->ymax-y;
640
641                         glRectf(x, y, x + tilex, y + tiley);
642                 }
643         }
644         
645         glPixelZoom(xscale, yscale);
646
647         glEnable(GL_BLEND);
648         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  /* premul graphics */
649         
650         glColor4f(1.0, 1.0, 1.0, 1.0);
651         glaDrawPixelsTex(prv->xmin, prv->ymin, preview->xsize, preview->ysize, GL_UNSIGNED_BYTE, preview->rect);
652         
653         glDisable(GL_BLEND);
654         glPixelZoom(1.0f, 1.0f);
655
656         UI_ThemeColorShadeAlpha(TH_BACK, -15, +100);
657         fdrawbox(prv->xmin, prv->ymin, prv->xmax, prv->ymax);
658         
659 }
660
661 /* common handle function for operator buttons that need to select the node first */
662 static void node_toggle_button_cb(struct bContext *C, void *node_argv, void *op_argv)
663 {
664         bNode *node = (bNode*)node_argv;
665         const char *opname = (const char *)op_argv;
666         
667         /* select & activate only the button's node */
668         node_select_single(C, node);
669         
670         WM_operator_name_call(C, opname, WM_OP_INVOKE_DEFAULT, NULL);
671 }
672
673 void node_draw_shadow(SpaceNode *snode, bNode *node, float radius, float alpha)
674 {
675         rctf *rct = &node->totr;
676         
677         uiSetRoundBox(UI_CNR_ALL);
678         if (node->parent==NULL)
679                 ui_dropshadow(rct, radius, snode->aspect, alpha, node->flag & SELECT);
680         else {
681                 const float margin = 3.0f;
682                 
683                 glColor4f(0.0f, 0.0f, 0.0f, 0.33f);
684                 glEnable(GL_BLEND);
685                 uiRoundBox(rct->xmin-margin, rct->ymin-margin,
686                            rct->xmax+margin, rct->ymax+margin, radius+margin);
687                 glDisable(GL_BLEND);
688         }
689 }
690
691 static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node)
692 {
693         bNodeSocket *sock;
694         rctf *rct= &node->totr;
695         float iconofs;
696         /* float socket_size= NODE_SOCKSIZE*U.dpi/72; */ /* UNUSED */
697         float iconbutw= 0.8f*UI_UNIT_X;
698         int color_id= node_get_colorid(node);
699         char showname[128]; /* 128 used below */
700         View2D *v2d = &ar->v2d;
701         
702         /* hurmf... another candidate for callback, have to see how this works first */
703         if (node->id && node->block && snode->treetype==NTREE_SHADER)
704                 nodeShaderSynchronizeID(node, 0);
705         
706         /* skip if out of view */
707         if (node->totr.xmax < ar->v2d.cur.xmin || node->totr.xmin > ar->v2d.cur.xmax ||
708                         node->totr.ymax < ar->v2d.cur.ymin || node->totr.ymin > ar->v2d.cur.ymax) {
709                 
710                 uiEndBlock(C, node->block);
711                 node->block= NULL;
712                 return;
713         }
714         
715         /* shadow */
716         node_draw_shadow(snode, node, BASIS_RAD, 1.0f);
717         
718         /* header */
719         if (color_id==TH_NODE)
720                 UI_ThemeColorShade(color_id, -20);
721         else
722                 UI_ThemeColor(color_id);
723         
724         if (node->flag & NODE_MUTED)
725                 UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);
726
727         uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
728         uiRoundBox(rct->xmin, rct->ymax-NODE_DY, rct->xmax, rct->ymax, BASIS_RAD);
729         
730         /* show/hide icons */
731         iconofs= rct->xmax - 7.0f;
732         
733         /* preview */
734         if (node->typeinfo->flag & NODE_PREVIEW) {
735                 uiBut *but;
736                 iconofs-=iconbutw;
737                 uiBlockSetEmboss(node->block, UI_EMBOSSN);
738                 but = uiDefIconBut(node->block, TOGBUT, B_REDR, ICON_MATERIAL,
739                                                    iconofs, rct->ymax-NODE_DY, iconbutw, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
740                 uiButSetFunc(but, node_toggle_button_cb, node, (void*)"NODE_OT_preview_toggle");
741                 /* XXX this does not work when node is activated and the operator called right afterwards,
742                  * since active ID is not updated yet (needs to process the notifier).
743                  * This can only work as visual indicator!
744                  */
745 //              if (!(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT)))
746 //                      uiButSetFlag(but, UI_BUT_DISABLED);
747                 uiBlockSetEmboss(node->block, UI_EMBOSS);
748         }
749         /* group edit */
750         if (node->type == NODE_GROUP) {
751                 uiBut *but;
752                 iconofs-=iconbutw;
753                 uiBlockSetEmboss(node->block, UI_EMBOSSN);
754                 but = uiDefIconBut(node->block, TOGBUT, B_REDR, ICON_NODETREE,
755                                                    iconofs, rct->ymax-NODE_DY, iconbutw, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
756                 uiButSetFunc(but, node_toggle_button_cb, node, (void*)"NODE_OT_group_edit");
757                 uiBlockSetEmboss(node->block, UI_EMBOSS);
758         }
759         
760         /* title */
761         if (node->flag & SELECT) 
762                 UI_ThemeColor(TH_SELECT);
763         else
764                 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
765         
766         /* open/close entirely? */
767         {
768                 uiBut *but;
769                 int but_size = UI_UNIT_X *0.6f;
770                 /* XXX button uses a custom triangle draw below, so make it invisible without icon */
771                 uiBlockSetEmboss(node->block, UI_EMBOSSN);
772                 but = uiDefBut(node->block, TOGBUT, B_REDR, "",
773                                            rct->xmin+10.0f-but_size/2, rct->ymax-NODE_DY/2.0f-but_size/2, but_size, but_size, NULL, 0, 0, 0, 0, "");
774                 uiButSetFunc(but, node_toggle_button_cb, node, (void*)"NODE_OT_hide_toggle");
775                 uiBlockSetEmboss(node->block, UI_EMBOSS);
776                 
777                 /* custom draw function for this button */
778                 UI_DrawTriIcon(rct->xmin+10.0f, rct->ymax-NODE_DY/2.0f, 'v');
779         }
780         
781         /* this isn't doing anything for the label, so commenting out */
782 #if 0
783         if (node->flag & SELECT) 
784                 UI_ThemeColor(TH_TEXT_HI);
785         else
786                 UI_ThemeColor(TH_TEXT);
787 #endif
788         
789         BLI_strncpy(showname, nodeLabel(node), sizeof(showname));
790         
791         //if (node->flag & NODE_MUTED)
792         //      BLI_snprintf(showname, sizeof(showname), "[%s]", showname); // XXX - don't print into self!
793         
794         uiDefBut(node->block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(rct->ymax-NODE_DY), 
795                          (int)(iconofs - rct->xmin-18.0f), NODE_DY,  NULL, 0, 0, 0, 0, "");
796
797         /* body */
798         if (node->flag & NODE_CUSTOM_COLOR)
799                 glColor3fv(node->color);
800         else
801                 UI_ThemeColor4(TH_NODE);
802         glEnable(GL_BLEND);
803         uiSetRoundBox(UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT);
804         uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax-NODE_DY, BASIS_RAD);
805         glDisable(GL_BLEND);
806
807         /* outline active and selected emphasis */
808         if ( node->flag & (NODE_ACTIVE|SELECT) ) {
809                 glEnable(GL_BLEND);
810                 glEnable(GL_LINE_SMOOTH);
811                 
812                 if (node->flag & NODE_ACTIVE)
813                         UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40);
814                 else
815                         UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40);
816                 uiSetRoundBox(UI_CNR_ALL);
817                 uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
818                 
819                 glDisable(GL_LINE_SMOOTH);
820                 glDisable(GL_BLEND);
821         }
822         
823         /* disable lines */
824         if (node->flag & NODE_MUTED)
825                 node_draw_mute_line(v2d, snode, node);
826
827         
828         /* socket inputs, buttons */
829         for (sock= node->inputs.first; sock; sock= sock->next) {
830                 if (nodeSocketIsHidden(sock))
831                         continue;
832                 
833                 node_socket_circle_draw(ntree, sock, NODE_SOCKSIZE, sock->flag & SELECT);
834                 
835                 node->typeinfo->drawinputfunc(C, node->block, ntree, node, sock, IFACE_(sock->name),
836                                               sock->locx+NODE_DYS, sock->locy-NODE_DYS, node->width-NODE_DY);
837         }
838         
839         /* socket outputs */
840         for (sock= node->outputs.first; sock; sock= sock->next) {
841                 if (nodeSocketIsHidden(sock))
842                         continue;
843                 
844                 node_socket_circle_draw(ntree, sock, NODE_SOCKSIZE, sock->flag & SELECT);
845                 
846                 node->typeinfo->drawoutputfunc(C, node->block, ntree, node, sock, IFACE_(sock->name),
847                                                sock->locx-node->width+NODE_DYS, sock->locy-NODE_DYS, node->width-NODE_DY);
848         }
849         
850         /* preview */
851         if (node->flag & NODE_PREVIEW) {
852                 BLI_lock_thread(LOCK_PREVIEW);
853                 if (node->preview && node->preview->rect && !BLI_rctf_is_empty(&node->prvr))
854                         node_draw_preview(node->preview, &node->prvr);
855                 BLI_unlock_thread(LOCK_PREVIEW);
856         }
857         
858         UI_ThemeClearColor(color_id);
859                 
860         uiEndBlock(C, node->block);
861         uiDrawBlock(C, node->block);
862         node->block= NULL;
863 }
864
865 static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, bNode *node)
866 {
867         bNodeSocket *sock;
868         rctf *rct= &node->totr;
869         float dx, centy= 0.5f*(rct->ymax+rct->ymin);
870         float hiddenrad= 0.5f*(rct->ymax-rct->ymin);
871         float socket_size= NODE_SOCKSIZE*U.dpi/72;
872         int color_id= node_get_colorid(node);
873         char showname[128];     /* 128 is used below */
874         
875         /* shadow */
876         node_draw_shadow(snode, node, hiddenrad, 1.0f);
877
878         /* body */
879         UI_ThemeColor(color_id);
880         if (node->flag & NODE_MUTED)
881                 UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);
882         uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
883         
884         /* outline active and selected emphasis */
885         if ( node->flag & (NODE_ACTIVE|SELECT) ) {
886                 glEnable(GL_BLEND);
887                 glEnable(GL_LINE_SMOOTH);
888                 
889                 if (node->flag & NODE_ACTIVE)
890                         UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40);
891                 else
892                         UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40);
893                 uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
894                 
895                 glDisable(GL_LINE_SMOOTH);
896                 glDisable(GL_BLEND);
897         }
898         
899         /* title */
900         if (node->flag & SELECT) 
901                 UI_ThemeColor(TH_SELECT);
902         else
903                 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
904         
905         /* open entirely icon */
906         {
907                 uiBut *but;
908                 int but_size = UI_UNIT_X *0.6f;
909                 /* XXX button uses a custom triangle draw below, so make it invisible without icon */
910                 uiBlockSetEmboss(node->block, UI_EMBOSSN);
911                 but = uiDefBut(node->block, TOGBUT, B_REDR, "",
912                                            rct->xmin+10.0f-but_size/2, centy-but_size/2, but_size, but_size, NULL, 0, 0, 0, 0, "");
913                 uiButSetFunc(but, node_toggle_button_cb, node, (void*)"NODE_OT_hide_toggle");
914                 uiBlockSetEmboss(node->block, UI_EMBOSS);
915                 
916                 /* custom draw function for this button */
917                 UI_DrawTriIcon(rct->xmin+10.0f, centy, 'h');
918         }
919         
920         /* disable lines */
921         if (node->flag & NODE_MUTED)
922                 node_draw_mute_line(&ar->v2d, snode, node);     
923         
924         if (node->flag & SELECT) 
925                 UI_ThemeColor(TH_SELECT);
926         else
927                 UI_ThemeColor(TH_TEXT);
928         
929         if (node->miniwidth>0.0f) {
930                 BLI_strncpy(showname, nodeLabel(node), sizeof(showname));
931                 
932                 //if (node->flag & NODE_MUTED)
933                 //      BLI_snprintf(showname, sizeof(showname), "[%s]", showname); // XXX - don't print into self!
934
935                 uiDefBut(node->block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(centy-10), 
936                                  (int)(rct->xmax - rct->xmin-18.0f -12.0f), NODE_DY,  NULL, 0, 0, 0, 0, "");
937         }       
938
939         /* scale widget thing */
940         UI_ThemeColorShade(color_id, -10);      
941         dx= 10.0f;
942         fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
943         fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
944         
945         UI_ThemeColorShade(color_id, +30);
946         dx-= snode->aspect;
947         fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
948         fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
949
950         /* sockets */
951         for (sock= node->inputs.first; sock; sock= sock->next) {
952                 if (!nodeSocketIsHidden(sock))
953                         node_socket_circle_draw(snode->nodetree, sock, socket_size, sock->flag & SELECT);
954         }
955         
956         for (sock= node->outputs.first; sock; sock= sock->next) {
957                 if (!nodeSocketIsHidden(sock))
958                         node_socket_circle_draw(snode->nodetree, sock, socket_size, sock->flag & SELECT);
959         }
960         
961         uiEndBlock(C, node->block);
962         uiDrawBlock(C, node->block);
963         node->block= NULL;
964 }
965
966 int node_get_resize_cursor(int directions)
967 {
968         if (directions==0)
969                 return CURSOR_STD;
970         else if ((directions & ~(NODE_RESIZE_TOP|NODE_RESIZE_BOTTOM))==0)
971                 return CURSOR_Y_MOVE;
972         else if ((directions & ~(NODE_RESIZE_RIGHT|NODE_RESIZE_LEFT))==0)
973                 return CURSOR_X_MOVE;
974         else
975                 return CURSOR_EDIT;
976 }
977
978 void node_set_cursor(wmWindow *win, SpaceNode *snode)
979 {
980         bNodeTree *ntree = snode->edittree;
981         bNode *node;
982         bNodeSocket *sock;
983         int cursor = CURSOR_STD;
984         
985         if (ntree) {
986                 if (node_find_indicated_socket(snode, &node, &sock, SOCK_IN|SOCK_OUT)) {
987                         /* pass */
988                 }
989                 else {
990                         /* check nodes front to back */
991                         for (node=ntree->nodes.last; node; node=node->prev) {
992                                 if (BLI_in_rctf(&node->totr, snode->mx, snode->my))
993                                         break;  /* first hit on node stops */
994                         }
995                         if (node) {
996                                 int dir = node->typeinfo->resize_area_func(node, snode->mx, snode->my);
997                                 cursor = node_get_resize_cursor(dir);
998                         }
999                 }
1000         }
1001         
1002         WM_cursor_set(win, cursor);
1003 }
1004
1005 void node_draw_default(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node)
1006 {
1007         if (node->flag & NODE_HIDDEN)
1008                 node_draw_hidden(C, ar, snode, node);
1009         else
1010                 node_draw_basis(C, ar, snode, ntree, node);
1011 }
1012
1013 static void node_update(const bContext *C, bNodeTree *ntree, bNode *node)
1014 {
1015         if (node->typeinfo->drawupdatefunc)
1016                 node->typeinfo->drawupdatefunc(C, ntree, node);
1017 }
1018
1019 void node_update_nodetree(const bContext *C, bNodeTree *ntree, float offsetx, float offsety)
1020 {
1021         bNode *node;
1022         
1023         /* update nodes front to back, so children sizes get updated before parents */
1024         for (node= ntree->nodes.last; node; node= node->prev) {
1025                 /* XXX little hack */
1026                 node->locx += offsetx;
1027                 node->locy += offsety;
1028                 
1029                 node_update(C, ntree, node);
1030                 
1031                 node->locx -= offsetx;
1032                 node->locy -= offsety;
1033         }
1034 }
1035
1036 static void node_draw(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node)
1037 {
1038         if (node->typeinfo->drawfunc)
1039                 node->typeinfo->drawfunc(C, ar, snode, ntree, node);
1040 }
1041
1042 void node_draw_nodetree(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree)
1043 {
1044         bNode *node;
1045         bNodeLink *link;
1046         int a;
1047         
1048         if (ntree==NULL) return;                /* groups... */
1049         
1050         /* draw background nodes, last nodes in front */
1051         for (a=0, node= ntree->nodes.first; node; node=node->next, a++) {
1052                 if (!(node->flag & NODE_BACKGROUND))
1053                         continue;
1054                 node->nr= a;            /* index of node in list, used for exec event code */
1055                 node_draw(C, ar, snode, ntree, node);
1056         }
1057         
1058         /* node lines */
1059         glEnable(GL_BLEND);
1060         glEnable(GL_LINE_SMOOTH);
1061         for (link= ntree->links.first; link; link= link->next)
1062                 node_draw_link(&ar->v2d, snode, link);
1063         glDisable(GL_LINE_SMOOTH);
1064         glDisable(GL_BLEND);
1065         
1066         /* draw foreground nodes, last nodes in front */
1067         for (a=0, node= ntree->nodes.first; node; node=node->next, a++) {
1068                 if (node->flag & NODE_BACKGROUND)
1069                         continue;
1070                 node->nr= a;            /* index of node in list, used for exec event code */
1071                 node_draw(C, ar, snode, ntree, node);
1072         }
1073 }
1074
1075 void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d)
1076 {
1077         View2DScrollers *scrollers;
1078         SpaceNode *snode= CTX_wm_space_node(C);
1079         Scene *scene= CTX_data_scene(C);
1080         int color_manage = scene->r.color_mgt_flag & R_COLOR_MANAGEMENT;
1081         bNodeLinkDrag *nldrag;
1082         LinkData *linkdata;
1083         
1084         UI_ThemeClearColor(TH_BACK);
1085         glClear(GL_COLOR_BUFFER_BIT);
1086
1087         UI_view2d_view_ortho(v2d);
1088         
1089         //uiFreeBlocksWin(&sa->uiblocks, sa->win);
1090
1091         ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
1092
1093         /* only set once */
1094         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1095         glEnable(GL_MAP1_VERTEX_3);
1096
1097         /* aspect+font, set each time */
1098         snode->aspect= (v2d->cur.xmax - v2d->cur.xmin)/((float)ar->winx);
1099         // XXX snode->curfont= uiSetCurFont_ext(snode->aspect);
1100
1101         /* grid */
1102         UI_view2d_multi_grid_draw(v2d, 25.0f, 5, 2);
1103
1104         /* backdrop */
1105         draw_nodespace_back_pix(ar, snode, color_manage);
1106         
1107         /* nodes */
1108         snode_set_context(snode, CTX_data_scene(C));
1109         
1110         if (snode->nodetree) {
1111                 bNode *node;
1112                 
1113                 node_uiblocks_init(C, snode->nodetree);
1114                 
1115                 /* uiBlocks must be initialized in drawing order for correct event clipping.
1116                  * Node group internal blocks added after the main group block.
1117                  */
1118                 for (node= snode->nodetree->nodes.first; node; node= node->next) {
1119                         if (node->flag & NODE_GROUP_EDIT)
1120                                 node_uiblocks_init(C, (bNodeTree *)node->id);
1121                 }
1122                 
1123                 node_update_nodetree(C, snode->nodetree, 0.0f, 0.0f);
1124                 node_draw_nodetree(C, ar, snode, snode->nodetree);
1125                 
1126                 #if 0
1127                 /* active group */
1128                 for (node= snode->nodetree->nodes.first; node; node= node->next) {
1129                         if (node->flag & NODE_GROUP_EDIT)
1130                                 node_draw_group(C, ar, snode, snode->nodetree, node);
1131                 }
1132                 #endif
1133         }
1134         
1135         /* temporary links */
1136         glEnable(GL_BLEND);
1137         glEnable(GL_LINE_SMOOTH);
1138         for (nldrag= snode->linkdrag.first; nldrag; nldrag= nldrag->next) {
1139                 for (linkdata=nldrag->links.first; linkdata; linkdata=linkdata->next)
1140                         node_draw_link(&ar->v2d, snode, (bNodeLink *)linkdata->data);
1141         }
1142         glDisable(GL_LINE_SMOOTH);
1143         glDisable(GL_BLEND);
1144         
1145         ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
1146         
1147         /* draw grease-pencil ('canvas' strokes) */
1148         if (snode->nodetree)
1149                 draw_gpencil_view2d(C, 1);
1150         
1151         /* reset view matrix */
1152         UI_view2d_view_restore(C);
1153         
1154         /* draw grease-pencil (screen strokes, and also paintbuffer) */
1155         if (snode->nodetree)
1156                 draw_gpencil_view2d(C, 0);
1157         
1158         /* scrollers */
1159         scrollers= UI_view2d_scrollers_calc(C, v2d, 10, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
1160         UI_view2d_scrollers_draw(C, v2d, scrollers);
1161         UI_view2d_scrollers_free(scrollers);
1162 }