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