Fix for #34739 and #35060, avoid ambiguity in compositor viewer 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  *  \brief higher level node drawing for the node editor.
30  */
31
32 #include "DNA_lamp_types.h"
33 #include "DNA_node_types.h"
34 #include "DNA_material_types.h"
35 #include "DNA_object_types.h"
36 #include "DNA_screen_types.h"
37 #include "DNA_space_types.h"
38 #include "DNA_texture_types.h"
39 #include "DNA_world_types.h"
40
41 #include "BLI_math.h"
42 #include "BLI_blenlib.h"
43
44 #include "BLF_translation.h"
45
46 #include "BKE_context.h"
47 #include "BKE_depsgraph.h"
48 #include "BKE_main.h"
49 #include "BKE_node.h"
50
51 #include "BLF_api.h"
52
53 #include "BIF_gl.h"
54 #include "BIF_glutil.h"
55
56 #include "WM_api.h"
57 #include "WM_types.h"
58
59 #include "ED_node.h"
60 #include "ED_gpencil.h"
61 #include "ED_screen.h"
62 #include "ED_space_api.h"
63
64 #include "UI_resources.h"
65 #include "UI_view2d.h"
66
67 #include "RNA_access.h"
68
69 #include "node_intern.h"  /* own include */
70 #include "COM_compositor.h"
71
72 /* XXX interface.h */
73 extern void ui_dropshadow(const rctf *rct, float radius, float aspect, float alpha, int select);
74
75 void ED_node_tree_update(const bContext *C)
76 {
77         SpaceNode *snode = CTX_wm_space_node(C);
78         snode_set_context(C);
79         
80         if (snode->nodetree && snode->nodetree->id.us == 0)
81                 snode->nodetree->id.us = 1;
82 }
83
84 /* id is supposed to contain a node tree */
85 static bNodeTree *node_tree_from_ID(ID *id)
86 {
87         if (id) {
88                 short idtype = GS(id->name);
89         
90                 switch (idtype) {
91                 case ID_NT:
92                         return (bNodeTree *)id;
93                 case ID_MA:
94                         return ((Material *)id)->nodetree;
95                 case ID_LA:
96                         return ((Lamp *)id)->nodetree;
97                 case ID_WO:
98                         return ((World *)id)->nodetree;
99                 case ID_SCE:
100                         return ((Scene *)id)->nodetree;
101                 case ID_TE:
102                         return ((Tex *)id)->nodetree;
103                 }
104         }
105         
106         return NULL;
107 }
108
109 void ED_node_tag_update_id(ID *id)
110 {
111         bNodeTree *ntree = node_tree_from_ID(id);
112         if (id == NULL || ntree == NULL)
113                 return;
114         
115         if (ntree->type == NTREE_SHADER) {
116                 DAG_id_tag_update(id, 0);
117                 
118                 if (GS(id->name) == ID_MA)
119                         WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, id);
120                 else if (GS(id->name) == ID_LA)
121                         WM_main_add_notifier(NC_LAMP | ND_LIGHTING_DRAW, id);
122                 else if (GS(id->name) == ID_WO)
123                         WM_main_add_notifier(NC_WORLD | ND_WORLD_DRAW, id);
124         }
125         else if (ntree->type == NTREE_COMPOSIT) {
126                 WM_main_add_notifier(NC_SCENE | ND_NODES, id);
127         }
128         else if (ntree->type == NTREE_TEXTURE) {
129                 DAG_id_tag_update(id, 0);
130                 WM_main_add_notifier(NC_TEXTURE | ND_NODES, id);
131         }
132 }
133
134 static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup)
135 {
136         bNode *node;
137         
138         if (ntree == lookup)
139                 return 1;
140         
141         for (node = ntree->nodes.first; node; node = node->next)
142                 if (node->type == NODE_GROUP && node->id)
143                         if (has_nodetree((bNodeTree *)node->id, lookup))
144                                 return 1;
145         
146         return 0;
147 }
148
149 void ED_node_tag_update_nodetree(Main *bmain, bNodeTree *ntree)
150 {
151         if (!ntree)
152                 return;
153         
154         /* look through all datablocks, to support groups */
155         FOREACH_NODETREE(bmain, tntree, id) {
156                 /* check if nodetree uses the group */
157                 if (has_nodetree(tntree, ntree))
158                         ED_node_tag_update_id(id);
159         } FOREACH_NODETREE_END
160         
161         if (ntree->type == NTREE_TEXTURE)
162                 ntreeTexCheckCyclics(ntree);
163 }
164
165 static int compare_nodes(bNode *a, bNode *b)
166 {
167         bNode *parent;
168         /* These tell if either the node or any of the parent nodes is selected.
169          * A selected parent means an unselected node is also in foreground!
170          */
171         int a_select = (a->flag & NODE_SELECT), b_select = (b->flag & NODE_SELECT);
172         int a_active = (a->flag & NODE_ACTIVE), b_active = (b->flag & NODE_ACTIVE);
173         
174         /* if one is an ancestor of the other */
175         /* XXX there might be a better sorting algorithm for stable topological sort, this is O(n^2) worst case */
176         for (parent = a->parent; parent; parent = parent->parent) {
177                 /* if b is an ancestor, it is always behind a */
178                 if (parent == b)
179                         return 1;
180                 /* any selected ancestor moves the node forward */
181                 if (parent->flag & NODE_ACTIVE)
182                         a_active = 1;
183                 if (parent->flag & NODE_SELECT)
184                         a_select = 1;
185         }
186         for (parent = b->parent; parent; parent = parent->parent) {
187                 /* if a is an ancestor, it is always behind b */
188                 if (parent == a)
189                         return 0;
190                 /* any selected ancestor moves the node forward */
191                 if (parent->flag & NODE_ACTIVE)
192                         b_active = 1;
193                 if (parent->flag & NODE_SELECT)
194                         b_select = 1;
195         }
196
197         /* if one of the nodes is in the background and the other not */
198         if ((a->flag & NODE_BACKGROUND) && !(b->flag & NODE_BACKGROUND))
199                 return 0;
200         else if (!(a->flag & NODE_BACKGROUND) && (b->flag & NODE_BACKGROUND))
201                 return 1;
202         
203         /* if one has a higher selection state (active > selected > nothing) */
204         if (!b_active && a_active)
205                 return 1;
206         else if (!b_select && (a_active || a_select))
207                 return 1;
208         
209         return 0;
210 }
211
212 /* Sorts nodes by selection: unselected nodes first, then selected,
213  * then the active node at the very end. Relative order is kept intact!
214  */
215 void ED_node_sort(bNodeTree *ntree)
216 {
217         /* merge sort is the algorithm of choice here */
218         bNode *first_a, *first_b, *node_a, *node_b, *tmp;
219         int totnodes = BLI_countlist(&ntree->nodes);
220         int k, a, b;
221         
222         k = 1;
223         while (k < totnodes) {
224                 first_a = first_b = ntree->nodes.first;
225                 
226                 do {
227                         /* setup first_b pointer */
228                         for (b = 0; b < k && first_b; ++b) {
229                                 first_b = first_b->next;
230                         }
231                         /* all batches merged? */
232                         if (first_b == NULL)
233                                 break;
234                         
235                         /* merge batches */
236                         node_a = first_a;
237                         node_b = first_b;
238                         a = b = 0;
239                         while (a < k && b < k && node_b) {
240                                 if (compare_nodes(node_a, node_b) == 0) {
241                                         node_a = node_a->next;
242                                         a++;
243                                 }
244                                 else {
245                                         tmp = node_b;
246                                         node_b = node_b->next;
247                                         b++;
248                                         BLI_remlink(&ntree->nodes, tmp);
249                                         BLI_insertlinkbefore(&ntree->nodes, node_a, tmp);
250                                 }
251                         }
252
253                         /* setup first pointers for next batch */
254                         first_b = node_b;
255                         for (; b < k; ++b) {
256                                 /* all nodes sorted? */
257                                 if (first_b == NULL)
258                                         break;
259                                 first_b = first_b->next;
260                         }
261                         first_a = first_b;
262                 } while (first_b);
263                 
264                 k = k << 1;
265         }
266 }
267
268
269 static void do_node_internal_buttons(bContext *C, void *UNUSED(node_v), int event)
270 {
271         if (event == B_NODE_EXEC) {
272                 SpaceNode *snode = CTX_wm_space_node(C);
273                 if (snode && snode->id)
274                         ED_node_tag_update_id(snode->id);
275         }
276 }
277
278 static void node_uiblocks_init(const bContext *C, bNodeTree *ntree)
279 {
280         bNode *node;
281         char uiblockstr[32];
282         
283         /* add node uiBlocks in drawing order - prevents events going to overlapping nodes */
284         
285         for (node = ntree->nodes.first; node; node = node->next) {
286                 /* ui block */
287                 BLI_snprintf(uiblockstr, sizeof(uiblockstr), "node buttons %p", (void *)node);
288                 node->block = uiBeginBlock(C, CTX_wm_region(C), uiblockstr, UI_EMBOSS);
289                 uiBlockSetHandleFunc(node->block, do_node_internal_buttons, node);
290
291                 /* this cancels events for background nodes */
292                 uiBlockSetFlag(node->block, UI_BLOCK_CLIP_EVENTS);
293         }
294 }
295
296 void node_to_view(struct bNode *node, float x, float y, float *rx, float *ry)
297 {
298         nodeToView(node, x, y, rx, ry);
299         *rx *= UI_DPI_FAC;
300         *ry *= UI_DPI_FAC;
301 }
302
303 void node_from_view(struct bNode *node, float x, float y, float *rx, float *ry)
304 {
305         x /= UI_DPI_FAC;
306         y /= UI_DPI_FAC;
307         nodeFromView(node, x, y, rx, ry);
308 }
309
310
311 /* based on settings in node, sets drawing rect info. each redraw! */
312 static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
313 {
314         uiLayout *layout, *row;
315         PointerRNA nodeptr, sockptr;
316         bNodeSocket *nsock;
317         float locx, locy;
318         float dy;
319         int buty;
320         
321         RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
322         
323         /* get "global" coords */
324         node_to_view(node, 0.0f, 0.0f, &locx, &locy);
325         dy = locy;
326         
327         /* header */
328         dy -= NODE_DY;
329         
330         /* little bit space in top */
331         if (node->outputs.first)
332                 dy -= NODE_DYS / 2;
333         
334         /* output sockets */
335         for (nsock = node->outputs.first; nsock; nsock = nsock->next) {
336                 if (nodeSocketIsHidden(nsock))
337                         continue;
338                 
339                 RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr);
340                 
341                 layout = uiBlockLayout(node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL,
342                                        locx + NODE_DYS, dy, NODE_WIDTH(node) - NODE_DY, NODE_DY, UI_GetStyle());
343                 /* context pointers for current node and socket */
344                 uiLayoutSetContextPointer(layout, "node", &nodeptr);
345                 uiLayoutSetContextPointer(layout, "socket", &sockptr);
346                 
347                 /* align output buttons to the right */
348                 row = uiLayoutRow(layout, 1);
349                 uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
350                 
351                 node->typeinfo->drawoutputfunc((bContext *)C, row, &sockptr, &nodeptr, (nsock->flag & SOCK_IN_USE));
352                 
353                 uiBlockEndAlign(node->block);
354                 uiBlockLayoutResolve(node->block, NULL, &buty);
355                 
356                 /* ensure minimum socket height in case layout is empty */
357                 buty = MIN2(buty, dy - NODE_DY);
358                 
359                 nsock->locx = locx + NODE_WIDTH(node);
360                 /* place the socket circle in the middle of the layout */
361                 nsock->locy = 0.5f * (dy + buty);
362                 
363                 dy = buty;
364                 if (nsock->next)
365                         dy -= NODE_SOCKDY;
366         }
367
368         node->prvr.xmin = locx + NODE_DYS;
369         node->prvr.xmax = locx + NODE_WIDTH(node) - NODE_DYS;
370
371         /* preview rect? */
372         if (node->flag & NODE_PREVIEW) {
373                 float aspect = 1.0f;
374                 
375                 if (node->preview_xsize && node->preview_ysize) 
376                         aspect = (float)node->preview_ysize / (float)node->preview_xsize;
377                 
378                 dy -= NODE_DYS / 2;
379                 node->prvr.ymax = dy;
380                 
381                 if (aspect <= 1.0f)
382                         node->prvr.ymin = dy - aspect * (NODE_WIDTH(node) - NODE_DY);
383                 else {
384                         /* width correction of image */
385                         /* XXX huh? (ton) */
386                         float dx = (NODE_WIDTH(node) - NODE_DYS) - (NODE_WIDTH(node) - NODE_DYS) / aspect;
387                         
388                         node->prvr.ymin = dy - (NODE_WIDTH(node) - NODE_DY);
389                         
390                         node->prvr.xmin += 0.5f * dx;
391                         node->prvr.xmax -= 0.5f * dx;
392                 }
393                 
394                 dy = node->prvr.ymin - NODE_DYS / 2;
395                 
396                 /* make sure that maximums are bigger or equal to minimums */
397                 if (node->prvr.xmax < node->prvr.xmin) SWAP(float, node->prvr.xmax, node->prvr.xmin);
398                 if (node->prvr.ymax < node->prvr.ymin) SWAP(float, node->prvr.ymax, node->prvr.ymin);
399         }
400
401         /* buttons rect? */
402         /* TODO: NODE_OPTION shall be cleaned up */
403         if (/*(node->flag & NODE_OPTIONS) && */node->typeinfo->uifunc) {
404                 dy -= NODE_DYS / 2;
405
406                 /* set this for uifunc() that don't use layout engine yet */
407                 node->butr.xmin = 0;
408                 node->butr.xmax = NODE_WIDTH(node) - 2 * NODE_DYS;
409                 node->butr.ymin = 0;
410                 node->butr.ymax = 0;
411                 
412                         
413                 layout = uiBlockLayout(node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL,
414                                        locx + NODE_DYS, dy, node->butr.xmax, 0, UI_GetStyle());
415                 uiLayoutSetContextPointer(layout, "node", &nodeptr);
416                 
417                 node->typeinfo->uifunc(layout, (bContext *)C, &nodeptr);
418                 
419                 uiBlockEndAlign(node->block);
420                 uiBlockLayoutResolve(node->block, NULL, &buty);
421                         
422                 dy = buty - NODE_DYS / 2;
423         }
424
425         /* input sockets */
426         for (nsock = node->inputs.first; nsock; nsock = nsock->next) {
427                 if (nodeSocketIsHidden(nsock))
428                         continue;
429                 
430                 RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr);
431                 
432                 layout = uiBlockLayout(node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL,
433                                        locx + NODE_DYS, dy, NODE_WIDTH(node) - NODE_DY, NODE_DY, UI_GetStyle());
434                 /* context pointers for current node and socket */
435                 uiLayoutSetContextPointer(layout, "node", &nodeptr);
436                 uiLayoutSetContextPointer(layout, "socket", &sockptr);
437                 
438                 node->typeinfo->drawinputfunc((bContext *)C, layout, &sockptr, &nodeptr, (nsock->flag & SOCK_IN_USE));
439                 
440                 uiBlockEndAlign(node->block);
441                 uiBlockLayoutResolve(node->block, NULL, &buty);
442                 
443                 /* ensure minimum socket height in case layout is empty */
444                 buty = MIN2(buty, dy - NODE_DY);
445                 
446                 nsock->locx = locx;
447                 /* place the socket circle in the middle of the layout */
448                 nsock->locy = 0.5f * (dy + buty);
449                 
450                 dy = buty;
451                 if (nsock->next)
452                         dy -= NODE_SOCKDY;
453         }
454         
455         /* little bit space in end */
456         if (node->inputs.first || (node->flag & (NODE_OPTIONS | NODE_PREVIEW)) == 0)
457                 dy -= NODE_DYS / 2;
458
459         node->totr.xmin = locx;
460         node->totr.xmax = locx + NODE_WIDTH(node);
461         node->totr.ymax = locy;
462         node->totr.ymin = min_ff(dy, locy - 2 * NODE_DY);
463         
464         /* Set the block bounds to clip mouse events from underlying nodes.
465          * Add a margin for sockets on each side.
466          */
467         uiExplicitBoundsBlock(node->block,
468                               node->totr.xmin - NODE_SOCKSIZE,
469                               node->totr.ymin,
470                               node->totr.xmax + NODE_SOCKSIZE,
471                               node->totr.ymax);
472 }
473
474 /* based on settings in node, sets drawing rect info. each redraw! */
475 static void node_update_hidden(bNode *node)
476 {
477         bNodeSocket *nsock;
478         float locx, locy;
479         float rad, drad, hiddenrad = HIDDEN_RAD;
480         int totin = 0, totout = 0, tot;
481         
482         /* get "global" coords */
483         node_to_view(node, 0.0f, 0.0f, &locx, &locy);
484
485         /* calculate minimal radius */
486         for (nsock = node->inputs.first; nsock; nsock = nsock->next)
487                 if (!nodeSocketIsHidden(nsock))
488                         totin++;
489         for (nsock = node->outputs.first; nsock; nsock = nsock->next)
490                 if (!nodeSocketIsHidden(nsock))
491                         totout++;
492         
493         tot = MAX2(totin, totout);
494         if (tot > 4) {
495                 hiddenrad += 5.0f * (float)(tot - 4);
496         }
497         
498         node->totr.xmin = locx;
499         node->totr.xmax = locx + 3 * hiddenrad + node->miniwidth;
500         node->totr.ymax = locy + (hiddenrad - 0.5f * NODE_DY);
501         node->totr.ymin = node->totr.ymax - 2 * hiddenrad;
502         
503         /* output sockets */
504         rad = drad = (float)M_PI / (1.0f + (float)totout);
505         
506         for (nsock = node->outputs.first; nsock; nsock = nsock->next) {
507                 if (!nodeSocketIsHidden(nsock)) {
508                         nsock->locx = node->totr.xmax - hiddenrad + sinf(rad) * hiddenrad;
509                         nsock->locy = node->totr.ymin + hiddenrad + cosf(rad) * hiddenrad;
510                         rad += drad;
511                 }
512         }
513         
514         /* input sockets */
515         rad = drad = -(float)M_PI / (1.0f + (float)totin);
516         
517         for (nsock = node->inputs.first; nsock; nsock = nsock->next) {
518                 if (!nodeSocketIsHidden(nsock)) {
519                         nsock->locx = node->totr.xmin + hiddenrad + sinf(rad) * hiddenrad;
520                         nsock->locy = node->totr.ymin + hiddenrad + cosf(rad) * hiddenrad;
521                         rad += drad;
522                 }
523         }
524
525         /* Set the block bounds to clip mouse events from underlying nodes.
526          * Add a margin for sockets on each side.
527          */
528         uiExplicitBoundsBlock(node->block,
529                               node->totr.xmin - NODE_SOCKSIZE,
530                               node->totr.ymin,
531                               node->totr.xmax + NODE_SOCKSIZE,
532                               node->totr.ymax);
533 }
534
535 void node_update_default(const bContext *C, bNodeTree *ntree, bNode *node)
536 {
537         if (node->flag & NODE_HIDDEN)
538                 node_update_hidden(node);
539         else
540                 node_update_basis(C, ntree, node);
541 }
542
543 int node_select_area_default(bNode *node, int x, int y)
544 {
545         return BLI_rctf_isect_pt(&node->totr, x, y);
546 }
547
548 int node_tweak_area_default(bNode *node, int x, int y)
549 {
550         return BLI_rctf_isect_pt(&node->totr, x, y);
551 }
552
553 int node_get_colorid(bNode *node)
554 {
555         switch (node->typeinfo->nclass) {
556                 case NODE_CLASS_INPUT:      return TH_NODE_IN_OUT;
557                 case NODE_CLASS_OUTPUT:     return (node->flag & NODE_DO_OUTPUT) ? TH_NODE_IN_OUT : TH_NODE;
558                 case NODE_CLASS_CONVERTOR:  return TH_NODE_CONVERTOR;
559                 case NODE_CLASS_OP_COLOR:
560                 case NODE_CLASS_OP_VECTOR:
561                 case NODE_CLASS_OP_FILTER:  return TH_NODE_OPERATOR;
562                 case NODE_CLASS_GROUP:      return TH_NODE_GROUP;
563                 case NODE_CLASS_INTERFACE:  return TH_NODE_INTERFACE;
564                 case NODE_CLASS_MATTE:      return TH_NODE_MATTE;
565                 case NODE_CLASS_DISTORT:    return TH_NODE_DISTORT;
566                 default:                    return TH_NODE;
567         }
568 }
569
570 /* note: in cmp_util.c is similar code, for node_compo_pass_on()
571  *       the same goes for shader and texture nodes. */
572 /* note: in node_edit.c is similar code, for untangle node */
573 static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node)
574 {
575         bNodeLink *link;
576
577         glEnable(GL_BLEND);
578         glEnable(GL_LINE_SMOOTH);
579
580         for (link = node->internal_links.first; link; link = link->next)
581                 node_draw_link_bezier(v2d, snode, link, TH_REDALERT, 0, TH_WIRE, 0, TH_WIRE);
582
583         glDisable(GL_BLEND);
584         glDisable(GL_LINE_SMOOTH);
585 }
586
587 /* this might have some more generic use */
588 static void node_circle_draw(float x, float y, float size, float *col, int highlight)
589 {
590         /* 16 values of sin function */
591         static float si[16] = {
592                 0.00000000f, 0.39435585f, 0.72479278f, 0.93775213f,
593                 0.99871650f, 0.89780453f, 0.65137248f, 0.29936312f,
594                 -0.10116832f, -0.48530196f, -0.79077573f, -0.96807711f,
595                 -0.98846832f, -0.84864425f, -0.57126821f, -0.20129852f
596         };
597         /* 16 values of cos function */
598         static float co[16] = {
599                 1.00000000f, 0.91895781f, 0.68896691f, 0.34730525f,
600                 -0.05064916f, -0.44039415f, -0.75875812f, -0.95413925f,
601                 -0.99486932f, -0.87434661f, -0.61210598f, -0.25065253f,
602                 0.15142777f, 0.52896401f, 0.82076344f, 0.97952994f,
603         };
604         int a;
605         
606         glColor4fv(col);
607         
608         glEnable(GL_BLEND);
609         glBegin(GL_POLYGON);
610         for (a = 0; a < 16; a++)
611                 glVertex2f(x + size * si[a], y + size * co[a]);
612         glEnd();
613         glDisable(GL_BLEND);
614         
615         if (highlight) {
616                 UI_ThemeColor(TH_TEXT_HI);
617                 glLineWidth(1.5f);
618         }
619         else {
620                 glColor4ub(0, 0, 0, 150);
621         }
622         glEnable(GL_BLEND);
623         glEnable(GL_LINE_SMOOTH);
624         glBegin(GL_LINE_LOOP);
625         for (a = 0; a < 16; a++)
626                 glVertex2f(x + size * si[a], y + size * co[a]);
627         glEnd();
628         glDisable(GL_LINE_SMOOTH);
629         glDisable(GL_BLEND);
630         glLineWidth(1.0f);
631 }
632
633 void node_socket_circle_draw(const bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *sock, float size, int highlight)
634 {
635         PointerRNA ptr, node_ptr;
636         float color[4];
637         
638         RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
639         RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
640         sock->typeinfo->draw_color((bContext *)C, &ptr, &node_ptr, color);
641         node_circle_draw(sock->locx, sock->locy, size, color, highlight);
642 }
643
644 /* **************  Socket callbacks *********** */
645
646 static void node_draw_preview_background(float tile, rctf *rect)
647 {
648         float x, y;
649         
650         /* draw checkerboard backdrop to show alpha */
651         glColor3ub(120, 120, 120);
652         glRectf(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
653         glColor3ub(160, 160, 160);
654         
655         for (y = rect->ymin; y < rect->ymax; y += tile * 2) {
656                 for (x = rect->xmin; x < rect->xmax; x += tile * 2) {
657                         float tilex = tile, tiley = tile;
658
659                         if (x + tile > rect->xmax)
660                                 tilex = rect->xmax - x;
661                         if (y + tile > rect->ymax)
662                                 tiley = rect->ymax - y;
663
664                         glRectf(x, y, x + tilex, y + tiley);
665                 }
666         }
667         for (y = rect->ymin + tile; y < rect->ymax; y += tile * 2) {
668                 for (x = rect->xmin + tile; x < rect->xmax; x += tile * 2) {
669                         float tilex = tile, tiley = tile;
670
671                         if (x + tile > rect->xmax)
672                                 tilex = rect->xmax - x;
673                         if (y + tile > rect->ymax)
674                                 tiley = rect->ymax - y;
675
676                         glRectf(x, y, x + tilex, y + tiley);
677                 }
678         }
679 }
680
681 /* not a callback */
682 static void node_draw_preview(bNodePreview *preview, rctf *prv)
683 {
684         float xrect = BLI_rctf_size_x(prv);
685         float yrect = BLI_rctf_size_y(prv);
686         float xscale = xrect / ((float)preview->xsize);
687         float yscale = yrect / ((float)preview->ysize);
688         float scale;
689         rctf draw_rect;
690         
691         /* uniform scale and offset */
692         draw_rect = *prv;
693         if (xscale < yscale) {
694                 float offset = 0.5f * (yrect - ((float)preview->ysize) * xscale);
695                 draw_rect.ymin += offset;
696                 draw_rect.ymax -= offset;
697                 scale = xscale;
698         }
699         else {
700                 float offset = 0.5f * (xrect - ((float)preview->xsize) * yscale);
701                 draw_rect.xmin += offset;
702                 draw_rect.xmax -= offset;
703                 scale = yscale;
704         }
705         
706         node_draw_preview_background(BLI_rctf_size_x(prv) / 10.0f, &draw_rect);
707         
708         glEnable(GL_BLEND);
709         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  /* premul graphics */
710         
711         glColor4f(1.0, 1.0, 1.0, 1.0);
712         glPixelZoom(scale, scale);
713         glaDrawPixelsTex(draw_rect.xmin, draw_rect.ymin, preview->xsize, preview->ysize, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, preview->rect);
714         glPixelZoom(1.0f, 1.0f);
715         
716         glDisable(GL_BLEND);
717
718         UI_ThemeColorShadeAlpha(TH_BACK, -15, +100);
719         fdrawbox(draw_rect.xmin, draw_rect.ymin, draw_rect.xmax, draw_rect.ymax);
720 }
721
722 /* common handle function for operator buttons that need to select the node first */
723 static void node_toggle_button_cb(struct bContext *C, void *node_argv, void *op_argv)
724 {
725         bNode *node = (bNode *)node_argv;
726         const char *opname = (const char *)op_argv;
727         
728         /* select & activate only the button's node */
729         node_select_single(C, node);
730         
731         WM_operator_name_call(C, opname, WM_OP_INVOKE_DEFAULT, NULL);
732 }
733
734 void node_draw_shadow(SpaceNode *snode, bNode *node, float radius, float alpha)
735 {
736         rctf *rct = &node->totr;
737         
738         uiSetRoundBox(UI_CNR_ALL);
739         if (node->parent == NULL)
740                 ui_dropshadow(rct, radius, snode->aspect, alpha, node->flag & SELECT);
741         else {
742                 const float margin = 3.0f;
743                 
744                 glColor4f(0.0f, 0.0f, 0.0f, 0.33f);
745                 glEnable(GL_BLEND);
746                 uiRoundBox(rct->xmin - margin, rct->ymin - margin,
747                            rct->xmax + margin, rct->ymax + margin, radius + margin);
748                 glDisable(GL_BLEND);
749         }
750 }
751
752 static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node, bNodeInstanceKey key)
753 {
754         bNodeInstanceHash *previews = CTX_data_pointer_get(C, "node_previews").data;
755         bNodeSocket *sock;
756         rctf *rct = &node->totr;
757         float iconofs;
758         /* float socket_size = NODE_SOCKSIZE*U.dpi/72; */ /* UNUSED */
759         float iconbutw = 0.8f * UI_UNIT_X;
760         int color_id = node_get_colorid(node);
761         char showname[128]; /* 128 used below */
762         View2D *v2d = &ar->v2d;
763         
764         /* XXX hack: copy values from linked ID data where displayed as sockets */
765         if (node->block)
766                 nodeSynchronizeID(node, false);
767         
768         /* skip if out of view */
769         if (BLI_rctf_isect(&node->totr, &ar->v2d.cur, NULL) == FALSE) {
770                 uiEndBlock(C, node->block);
771                 node->block = NULL;
772                 return;
773         }
774         
775         /* shadow */
776         node_draw_shadow(snode, node, BASIS_RAD, 1.0f);
777         
778         /* header uses color from backdrop, but we make it opaqie */
779         if (color_id == TH_NODE) {
780                 float col[3];
781                 UI_GetThemeColorShade3fv(color_id, -20, col);
782                 glColor4f(col[0], col[1], col[2], 1.0f);
783         }
784         else
785                 UI_ThemeColor(color_id);
786         
787         if (node->flag & NODE_MUTED)
788                 UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);
789         
790
791 #ifdef WITH_COMPOSITOR
792         if (ntree->type == NTREE_COMPOSIT && (snode->flag & SNODE_SHOW_HIGHLIGHT)) {
793                 if (COM_isHighlightedbNode(node)) {
794                         UI_ThemeColorBlend(color_id, TH_ACTIVE, 0.5f);
795                 }
796         }
797 #endif
798
799         uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
800         uiRoundBox(rct->xmin, rct->ymax - NODE_DY, rct->xmax, rct->ymax, BASIS_RAD);
801         
802         /* show/hide icons */
803         iconofs = rct->xmax - 0.35f * U.widget_unit;
804         
805         /* preview */
806         if (node->typeinfo->flag & NODE_PREVIEW) {
807                 uiBut *but;
808                 iconofs -= iconbutw;
809                 uiBlockSetEmboss(node->block, UI_EMBOSSN);
810                 but = uiDefIconBut(node->block, TOGBUT, B_REDR, ICON_MATERIAL,
811                                    iconofs, rct->ymax - NODE_DY, iconbutw, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
812                 uiButSetFunc(but, node_toggle_button_cb, node, (void *)"NODE_OT_preview_toggle");
813                 /* XXX this does not work when node is activated and the operator called right afterwards,
814                  * since active ID is not updated yet (needs to process the notifier).
815                  * This can only work as visual indicator!
816                  */
817 //              if (!(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT)))
818 //                      uiButSetFlag(but, UI_BUT_DISABLED);
819                 uiBlockSetEmboss(node->block, UI_EMBOSS);
820         }
821         /* group edit */
822         if (node->type == NODE_GROUP) {
823                 uiBut *but;
824                 iconofs -= iconbutw;
825                 uiBlockSetEmboss(node->block, UI_EMBOSSN);
826                 but = uiDefIconBut(node->block, TOGBUT, B_REDR, ICON_NODETREE,
827                                    iconofs, rct->ymax - NODE_DY, iconbutw, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
828                 uiButSetFunc(but, node_toggle_button_cb, node, (void *)"NODE_OT_group_edit");
829                 uiBlockSetEmboss(node->block, UI_EMBOSS);
830         }
831         
832         /* title */
833         if (node->flag & SELECT) 
834                 UI_ThemeColor(TH_SELECT);
835         else
836                 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
837         
838         /* open/close entirely? */
839         {
840                 uiBut *but;
841                 int but_size = UI_UNIT_X * 0.6f;
842                 /* XXX button uses a custom triangle draw below, so make it invisible without icon */
843                 uiBlockSetEmboss(node->block, UI_EMBOSSN);
844                 but = uiDefBut(node->block, TOGBUT, B_REDR, "",
845                                rct->xmin + 0.5f * U.widget_unit - but_size / 2, rct->ymax - NODE_DY / 2.0f - but_size / 2,
846                                but_size, but_size, NULL, 0, 0, 0, 0, "");
847                 uiButSetFunc(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle");
848                 uiBlockSetEmboss(node->block, UI_EMBOSS);
849                 
850                 /* custom draw function for this button */
851                 UI_DrawTriIcon(rct->xmin + 0.5f * U.widget_unit, rct->ymax - NODE_DY / 2.0f, 'v');
852         }
853         
854         /* this isn't doing anything for the label, so commenting out */
855 #if 0
856         if (node->flag & SELECT) 
857                 UI_ThemeColor(TH_TEXT_HI);
858         else
859                 UI_ThemeColor(TH_TEXT);
860 #endif
861         
862         BLI_strncpy(showname, nodeLabel(node), sizeof(showname));
863         
864         //if (node->flag & NODE_MUTED)
865         //      BLI_snprintf(showname, sizeof(showname), "[%s]", showname); /* XXX - don't print into self! */
866         
867         uiDefBut(node->block, LABEL, 0, showname,
868                  (int)(rct->xmin + (NODE_MARGIN_X)), (int)(rct->ymax - NODE_DY),
869                  (short)(iconofs - rct->xmin - 18.0f), (short)NODE_DY,
870                  NULL, 0, 0, 0, 0, "");
871
872         /* body */
873         if (!nodeIsRegistered(node))
874                 UI_ThemeColor4(TH_REDALERT);    /* use warning color to indicate undefined types */
875         else if (node->flag & NODE_CUSTOM_COLOR)
876                 glColor3fv(node->color);
877         else
878                 UI_ThemeColor4(TH_NODE);
879         glEnable(GL_BLEND);
880         uiSetRoundBox(UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT);
881         uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax - NODE_DY, BASIS_RAD);
882         glDisable(GL_BLEND);
883
884         /* outline active and selected emphasis */
885         if (node->flag & SELECT) {
886                 
887                 glEnable(GL_BLEND);
888                 glEnable(GL_LINE_SMOOTH);
889                 
890                 if (node->flag & NODE_ACTIVE)
891                         UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40);
892                 else
893                         UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40);
894                 
895                 uiSetRoundBox(UI_CNR_ALL);
896                 uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
897                 
898                 glDisable(GL_LINE_SMOOTH);
899                 glDisable(GL_BLEND);
900         }
901         
902         /* disable lines */
903         if (node->flag & NODE_MUTED)
904                 node_draw_mute_line(v2d, snode, node);
905
906         
907         /* socket inputs, buttons */
908         for (sock = node->inputs.first; sock; sock = sock->next) {
909                 if (nodeSocketIsHidden(sock))
910                         continue;
911                 
912                 node_socket_circle_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT);
913         }
914         
915         /* socket outputs */
916         for (sock = node->outputs.first; sock; sock = sock->next) {
917                 if (nodeSocketIsHidden(sock))
918                         continue;
919                 
920                 node_socket_circle_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT);
921         }
922         
923         /* preview */
924         if (node->flag & NODE_PREVIEW) {
925                 bNodePreview *preview = previews ? BKE_node_instance_hash_lookup(previews, key) : NULL;
926                 if (preview && preview->rect && !BLI_rctf_is_empty(&node->prvr))
927                         node_draw_preview(preview, &node->prvr);
928         }
929         
930         UI_ThemeClearColor(color_id);
931                 
932         uiEndBlock(C, node->block);
933         uiDrawBlock(C, node->block);
934         node->block = NULL;
935 }
936
937 static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node, bNodeInstanceKey UNUSED(key))
938 {
939         bNodeSocket *sock;
940         rctf *rct = &node->totr;
941         float dx, centy = BLI_rctf_cent_y(rct);
942         float hiddenrad = BLI_rctf_size_y(rct) / 2.0f;
943         float socket_size = NODE_SOCKSIZE;
944         int color_id = node_get_colorid(node);
945         char showname[128]; /* 128 is used below */
946         
947         /* shadow */
948         node_draw_shadow(snode, node, hiddenrad, 1.0f);
949
950         /* body */
951         UI_ThemeColor(color_id);
952         if (node->flag & NODE_MUTED)
953                 UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);
954
955 #ifdef WITH_COMPOSITOR
956         if (ntree->type == NTREE_COMPOSIT && (snode->flag & SNODE_SHOW_HIGHLIGHT)) {
957                 if (COM_isHighlightedbNode(node)) {
958                         UI_ThemeColorBlend(color_id, TH_ACTIVE, 0.5f);
959                 }
960         }
961 #else
962         (void)ntree;
963 #endif
964         
965         uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
966         
967         /* outline active and selected emphasis */
968         if (node->flag & SELECT) {
969                 glEnable(GL_BLEND);
970                 glEnable(GL_LINE_SMOOTH);
971                 
972                 if (node->flag & NODE_ACTIVE)
973                         UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40);
974                 else
975                         UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40);
976                 uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
977                 
978                 glDisable(GL_LINE_SMOOTH);
979                 glDisable(GL_BLEND);
980         }
981
982         /* custom color inline */
983         if (node->flag & NODE_CUSTOM_COLOR) {
984                 glEnable(GL_BLEND);
985                 glEnable(GL_LINE_SMOOTH);
986
987                 glColor3fv(node->color);
988                 uiDrawBox(GL_LINE_LOOP, rct->xmin + 1, rct->ymin + 1, rct->xmax -1, rct->ymax - 1, hiddenrad);
989
990                 glDisable(GL_LINE_SMOOTH);
991                 glDisable(GL_BLEND);
992         }
993
994         /* title */
995         if (node->flag & SELECT) 
996                 UI_ThemeColor(TH_SELECT);
997         else
998                 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
999         
1000         /* open entirely icon */
1001         {
1002                 uiBut *but;
1003                 int but_size = UI_UNIT_X * 0.6f;
1004                 /* XXX button uses a custom triangle draw below, so make it invisible without icon */
1005                 uiBlockSetEmboss(node->block, UI_EMBOSSN);
1006                 but = uiDefBut(node->block, TOGBUT, B_REDR, "",
1007                                rct->xmin + 10.0f - but_size / 2, centy - but_size / 2,
1008                                but_size, but_size, NULL, 0, 0, 0, 0, "");
1009                 uiButSetFunc(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle");
1010                 uiBlockSetEmboss(node->block, UI_EMBOSS);
1011                 
1012                 /* custom draw function for this button */
1013                 UI_DrawTriIcon(rct->xmin + 10.0f, centy, 'h');
1014         }
1015         
1016         /* disable lines */
1017         if (node->flag & NODE_MUTED)
1018                 node_draw_mute_line(&ar->v2d, snode, node);
1019         
1020         if (node->flag & SELECT) 
1021                 UI_ThemeColor(TH_SELECT);
1022         else
1023                 UI_ThemeColor(TH_TEXT);
1024         
1025         if (node->miniwidth > 0.0f) {
1026                 BLI_strncpy(showname, nodeLabel(node), sizeof(showname));
1027                 
1028                 //if (node->flag & NODE_MUTED)
1029                 //      BLI_snprintf(showname, sizeof(showname), "[%s]", showname); /* XXX - don't print into self! */
1030
1031                 uiDefBut(node->block, LABEL, 0, showname,
1032                          (int)(rct->xmin + (NODE_MARGIN_X)), (int)(centy - 10),
1033                          (short)(BLI_rctf_size_x(rct) - 18.0f - 12.0f), (short)NODE_DY,
1034                          NULL, 0, 0, 0, 0, "");
1035         }
1036
1037         /* scale widget thing */
1038         UI_ThemeColorShade(color_id, -10);
1039         dx = 10.0f;
1040         fdrawline(rct->xmax - dx, centy - 4.0f, rct->xmax - dx, centy + 4.0f);
1041         fdrawline(rct->xmax - dx - 3.0f * snode->aspect, centy - 4.0f, rct->xmax - dx - 3.0f * snode->aspect, centy + 4.0f);
1042         
1043         UI_ThemeColorShade(color_id, +30);
1044         dx -= snode->aspect;
1045         fdrawline(rct->xmax - dx, centy - 4.0f, rct->xmax - dx, centy + 4.0f);
1046         fdrawline(rct->xmax - dx - 3.0f * snode->aspect, centy - 4.0f, rct->xmax - dx - 3.0f * snode->aspect, centy + 4.0f);
1047
1048         /* sockets */
1049         for (sock = node->inputs.first; sock; sock = sock->next) {
1050                 if (!nodeSocketIsHidden(sock))
1051                         node_socket_circle_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT);
1052         }
1053         
1054         for (sock = node->outputs.first; sock; sock = sock->next) {
1055                 if (!nodeSocketIsHidden(sock))
1056                         node_socket_circle_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT);
1057         }
1058         
1059         uiEndBlock(C, node->block);
1060         uiDrawBlock(C, node->block);
1061         node->block = NULL;
1062 }
1063
1064 int node_get_resize_cursor(int directions)
1065 {
1066         if (directions == 0)
1067                 return CURSOR_STD;
1068         else if ((directions & ~(NODE_RESIZE_TOP | NODE_RESIZE_BOTTOM)) == 0)
1069                 return CURSOR_Y_MOVE;
1070         else if ((directions & ~(NODE_RESIZE_RIGHT | NODE_RESIZE_LEFT)) == 0)
1071                 return CURSOR_X_MOVE;
1072         else
1073                 return CURSOR_EDIT;
1074 }
1075
1076 void node_set_cursor(wmWindow *win, SpaceNode *snode)
1077 {
1078         bNodeTree *ntree = snode->edittree;
1079         bNode *node;
1080         bNodeSocket *sock;
1081         int cursor = CURSOR_STD;
1082         
1083         if (ntree) {
1084                 if (node_find_indicated_socket(snode, &node, &sock, SOCK_IN | SOCK_OUT)) {
1085                         /* pass */
1086                 }
1087                 else {
1088                         /* check nodes front to back */
1089                         for (node = ntree->nodes.last; node; node = node->prev) {
1090                                 if (BLI_rctf_isect_pt(&node->totr, snode->cursor[0], snode->cursor[1]))
1091                                         break;  /* first hit on node stops */
1092                         }
1093                         if (node) {
1094                                 int dir = node->typeinfo->resize_area_func(node, snode->cursor[0], snode->cursor[1]);
1095                                 cursor = node_get_resize_cursor(dir);
1096                         }
1097                 }
1098         }
1099         
1100         WM_cursor_set(win, cursor);
1101 }
1102
1103 void node_draw_default(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node, bNodeInstanceKey key)
1104 {
1105         if (node->flag & NODE_HIDDEN)
1106                 node_draw_hidden(C, ar, snode, ntree, node, key);
1107         else
1108                 node_draw_basis(C, ar, snode, ntree, node, key);
1109 }
1110
1111 static void node_update(const bContext *C, bNodeTree *ntree, bNode *node)
1112 {
1113         if (node->typeinfo->drawupdatefunc)
1114                 node->typeinfo->drawupdatefunc(C, ntree, node);
1115 }
1116
1117 void node_update_nodetree(const bContext *C, bNodeTree *ntree)
1118 {
1119         bNode *node;
1120         
1121         /* update nodes front to back, so children sizes get updated before parents */
1122         for (node = ntree->nodes.last; node; node = node->prev) {
1123                 node_update(C, ntree, node);
1124         }
1125 }
1126
1127 static void node_draw(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node, bNodeInstanceKey key)
1128 {
1129         if (node->typeinfo->drawfunc)
1130                 node->typeinfo->drawfunc(C, ar, snode, ntree, node, key);
1131 }
1132
1133 #define USE_DRAW_TOT_UPDATE
1134
1135 void node_draw_nodetree(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNodeInstanceKey parent_key)
1136 {
1137         bNode *node;
1138         bNodeLink *link;
1139         int a;
1140         
1141         if (ntree == NULL) return;      /* groups... */
1142
1143 #ifdef USE_DRAW_TOT_UPDATE
1144         if (ntree->nodes.first) {
1145                 BLI_rctf_init_minmax(&ar->v2d.tot);
1146         }
1147 #endif
1148
1149         /* draw background nodes, last nodes in front */
1150         for (a = 0, node = ntree->nodes.first; node; node = node->next, a++) {
1151                 bNodeInstanceKey key;
1152
1153 #ifdef USE_DRAW_TOT_UPDATE
1154                 /* unrelated to background nodes, update the v2d->tot,
1155                  * can be anywhere before we draw the scroll bars */
1156                 BLI_rctf_union(&ar->v2d.tot, &node->totr);
1157 #endif
1158
1159                 if (!(node->flag & NODE_BACKGROUND))
1160                         continue;
1161
1162                 key = BKE_node_instance_key(parent_key, ntree, node);
1163                 node->nr = a;        /* index of node in list, used for exec event code */
1164                 node_draw(C, ar, snode, ntree, node, key);
1165         }
1166         
1167         /* node lines */
1168         glEnable(GL_BLEND);
1169         glEnable(GL_LINE_SMOOTH);
1170         for (link = ntree->links.first; link; link = link->next) {
1171                 if (!nodeLinkIsHidden(link))
1172                         node_draw_link(&ar->v2d, snode, link);
1173         }
1174         glDisable(GL_LINE_SMOOTH);
1175         glDisable(GL_BLEND);
1176         
1177         /* draw foreground nodes, last nodes in front */
1178         for (a = 0, node = ntree->nodes.first; node; node = node->next, a++) {
1179                 bNodeInstanceKey key;
1180                 if (node->flag & NODE_BACKGROUND)
1181                         continue;
1182
1183                 key = BKE_node_instance_key(parent_key, ntree, node);
1184                 node->nr = a;        /* index of node in list, used for exec event code */
1185                 node_draw(C, ar, snode, ntree, node, key);
1186         }
1187 }
1188
1189 /* draw tree path info in lower left corner */
1190 static void draw_tree_path(SpaceNode *snode)
1191 {
1192         char info[256];
1193         
1194         ED_node_tree_path_get_fixedbuf(snode, info, sizeof(info));
1195         
1196         UI_ThemeColor(TH_TEXT_HI);
1197         BLF_draw_default(30, 30, 0.0f, info, sizeof(info));
1198 }
1199
1200 static void snode_setup_v2d(SpaceNode *snode, ARegion *ar, float center[2])
1201 {
1202         View2D *v2d = &ar->v2d;
1203         
1204         /* shift view to node tree center */
1205         UI_view2d_setcenter(v2d, center[0], center[1]);
1206         UI_view2d_view_ortho(v2d);
1207         
1208         /* aspect+font, set each time */
1209         snode->aspect = BLI_rctf_size_x(&v2d->cur) / (float)ar->winx;
1210         // XXX snode->curfont = uiSetCurFont_ext(snode->aspect);
1211 }
1212
1213 static void draw_nodetree(const bContext *C, ARegion *ar, bNodeTree *ntree, bNodeInstanceKey parent_key)
1214 {
1215         SpaceNode *snode = CTX_wm_space_node(C);
1216         
1217         node_uiblocks_init(C, ntree);
1218         
1219 #ifdef WITH_COMPOSITOR
1220         if (ntree->type == NTREE_COMPOSIT) {
1221                 COM_startReadHighlights();
1222         }
1223 #endif
1224         
1225         node_update_nodetree(C, ntree);
1226         node_draw_nodetree(C, ar, snode, ntree, parent_key);
1227 }
1228
1229 /* shade the parent node group and add a uiBlock to clip mouse events */
1230 static void draw_group_overlay(const bContext *C, ARegion *ar)
1231 {
1232         View2D *v2d = &ar->v2d;
1233         rctf rect = v2d->cur;
1234         uiBlock *block;
1235         
1236         /* shade node groups to separate them visually */
1237         UI_ThemeColorShadeAlpha(TH_NODE_GROUP, 0, -70);
1238         glEnable(GL_BLEND);
1239         uiSetRoundBox(0);
1240         uiDrawBox(GL_POLYGON, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 0);
1241         glDisable(GL_BLEND);
1242         
1243         /* set the block bounds to clip mouse events from underlying nodes */
1244         block = uiBeginBlock(C, ar, "node tree bounds block", UI_EMBOSS);
1245         uiExplicitBoundsBlock(block, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1246         uiBlockSetFlag(block, UI_BLOCK_CLIP_EVENTS);
1247         uiEndBlock(C, block);
1248 }
1249
1250 void drawnodespace(const bContext *C, ARegion *ar)
1251 {
1252         View2DScrollers *scrollers;
1253         SpaceNode *snode = CTX_wm_space_node(C);
1254         View2D *v2d = &ar->v2d;
1255
1256         UI_ThemeClearColor(TH_BACK);
1257         glClear(GL_COLOR_BUFFER_BIT);
1258
1259         UI_view2d_view_ortho(v2d);
1260
1261         ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
1262
1263         /* only set once */
1264         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1265         glEnable(GL_MAP1_VERTEX_3);
1266         
1267         /* nodes */
1268         snode_set_context(C);
1269         
1270         /* draw parent node trees */
1271         if (snode->treepath.last) {
1272                 static const int max_depth = 2;
1273                 bNodeTreePath *path;
1274                 int depth, curdepth;
1275                 float center[2];
1276                 bNodeTree *ntree;
1277                 bNodeLinkDrag *nldrag;
1278                 LinkData *linkdata;
1279                 
1280                 path = snode->treepath.last;
1281                 
1282                 /* current View2D center, will be set temporarily for parent node trees */
1283                 UI_view2d_getcenter(v2d, &center[0], &center[1]);
1284                 
1285                 /* store new view center in path and current edittree */
1286                 copy_v2_v2(path->view_center, center);
1287                 if (snode->edittree)
1288                         copy_v2_v2(snode->edittree->view_center, center);
1289                 
1290                 depth = 0;
1291                 while (path->prev && depth < max_depth) {
1292                         path = path->prev;
1293                         ++depth;
1294                 }
1295                 
1296                 /* parent node trees in the background */
1297                 for (curdepth = depth; curdepth > 0; path = path->next, --curdepth) {
1298                         ntree = path->nodetree;
1299                         if (ntree) {
1300                                 snode_setup_v2d(snode, ar, path->view_center);
1301                                 
1302                                 draw_nodetree(C, ar, ntree, path->parent_key);
1303                                 
1304                                 draw_group_overlay(C, ar);
1305                         }
1306                 }
1307                 
1308                 /* top-level edit tree */
1309                 ntree = path->nodetree;
1310                 if (ntree) {
1311                         snode_setup_v2d(snode, ar, center);
1312                         
1313                         /* grid, uses theme color based on node path depth */
1314                         UI_view2d_multi_grid_draw(v2d, (depth > 0 ? TH_NODE_GROUP : TH_BACK), U.widget_unit, 5, 2);
1315                         
1316                         /* backdrop */
1317                         draw_nodespace_back_pix(C, ar, snode, path->parent_key);
1318                         
1319                         draw_nodetree(C, ar, ntree, path->parent_key);
1320                 }
1321                 
1322                 /* temporary links */
1323                 glEnable(GL_BLEND);
1324                 glEnable(GL_LINE_SMOOTH);
1325                 for (nldrag = snode->linkdrag.first; nldrag; nldrag = nldrag->next) {
1326                         for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next)
1327                                 node_draw_link(v2d, snode, (bNodeLink *)linkdata->data);
1328                 }
1329                 glDisable(GL_LINE_SMOOTH);
1330                 glDisable(GL_BLEND);
1331                 
1332                 if (snode->flag & SNODE_SHOW_GPENCIL) {
1333                         /* draw grease-pencil ('canvas' strokes) */
1334                         draw_gpencil_view2d(C, TRUE);
1335                 }
1336         }
1337         else {
1338                 /* default grid */
1339                 UI_view2d_multi_grid_draw(v2d, TH_BACK, U.widget_unit, 5, 2);
1340                 
1341                 /* backdrop */
1342                 draw_nodespace_back_pix(C, ar, snode, NODE_INSTANCE_KEY_NONE);
1343         }
1344         
1345         ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
1346         
1347         /* reset view matrix */
1348         UI_view2d_view_restore(C);
1349         
1350         if (snode->treepath.last) {
1351                 if (snode->flag & SNODE_SHOW_GPENCIL) {
1352                         /* draw grease-pencil (screen strokes, and also paintbuffer) */
1353                         draw_gpencil_view2d(C, FALSE);
1354                 }
1355         }
1356
1357         /* tree path info */
1358         draw_tree_path(snode);
1359         
1360         /* scrollers */
1361         scrollers = UI_view2d_scrollers_calc(C, v2d, 10, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
1362         UI_view2d_scrollers_draw(C, v2d, scrollers);
1363         UI_view2d_scrollers_free(scrollers);
1364 }