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