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