Cleanup: remove redundant preference check
[blender.git] / source / blender / editors / space_node / node_draw.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2008 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup spnode
22  * \brief higher level node drawing for the node editor.
23  */
24
25 #include "DNA_light_types.h"
26 #include "DNA_node_types.h"
27 #include "DNA_material_types.h"
28 #include "DNA_screen_types.h"
29 #include "DNA_space_types.h"
30 #include "DNA_texture_types.h"
31 #include "DNA_world_types.h"
32 #include "DNA_linestyle_types.h"
33
34 #include "BLI_math.h"
35 #include "BLI_blenlib.h"
36
37 #include "BLT_translation.h"
38
39 #include "BKE_context.h"
40 #include "BKE_library.h"
41 #include "BKE_main.h"
42 #include "BKE_node.h"
43
44 #include "DEG_depsgraph.h"
45
46 #include "BLF_api.h"
47
48 #include "BIF_glutil.h"
49
50 #include "GPU_draw.h"
51 #include "GPU_immediate.h"
52 #include "GPU_immediate_util.h"
53 #include "GPU_matrix.h"
54 #include "GPU_state.h"
55 #include "GPU_framebuffer.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(
77     const rctf *rct, float radius, float aspect, float alpha, int select);
78
79 float ED_node_grid_size(void)
80 {
81   return U.widget_unit;
82 }
83
84 void ED_node_tree_update(const bContext *C)
85 {
86   SpaceNode *snode = CTX_wm_space_node(C);
87   if (snode) {
88     snode_set_context(C);
89
90     id_us_ensure_real(&snode->nodetree->id);
91   }
92 }
93
94 /* id is supposed to contain a node tree */
95 static bNodeTree *node_tree_from_ID(ID *id)
96 {
97   if (id) {
98     short idtype = GS(id->name);
99
100     switch (idtype) {
101       case ID_NT:
102         return (bNodeTree *)id;
103       case ID_MA:
104         return ((Material *)id)->nodetree;
105       case ID_LA:
106         return ((Light *)id)->nodetree;
107       case ID_WO:
108         return ((World *)id)->nodetree;
109       case ID_SCE:
110         return ((Scene *)id)->nodetree;
111       case ID_TE:
112         return ((Tex *)id)->nodetree;
113       case ID_LS:
114         return ((FreestyleLineStyle *)id)->nodetree;
115     }
116   }
117
118   return NULL;
119 }
120
121 void ED_node_tag_update_id(ID *id)
122 {
123   bNodeTree *ntree = node_tree_from_ID(id);
124   if (id == NULL || ntree == NULL) {
125     return;
126   }
127
128   /* TODO(sergey): With the new dependency graph it
129    * should be just enough to only tag ntree itself,
130    * all the users of this tree will have update
131    * flushed from the tree,
132    */
133   DEG_id_tag_update(&ntree->id, 0);
134
135   if (ntree->type == NTREE_SHADER) {
136     DEG_id_tag_update(id, 0);
137
138     if (GS(id->name) == ID_MA) {
139       WM_main_add_notifier(NC_MATERIAL | ND_SHADING, id);
140     }
141     else if (GS(id->name) == ID_LA) {
142       WM_main_add_notifier(NC_LAMP | ND_LIGHTING, id);
143     }
144     else if (GS(id->name) == ID_WO) {
145       WM_main_add_notifier(NC_WORLD | ND_WORLD, id);
146     }
147   }
148   else if (ntree->type == NTREE_COMPOSIT) {
149     WM_main_add_notifier(NC_SCENE | ND_NODES, id);
150   }
151   else if (ntree->type == NTREE_TEXTURE) {
152     DEG_id_tag_update(id, 0);
153     WM_main_add_notifier(NC_TEXTURE | ND_NODES, id);
154   }
155   else if (id == &ntree->id) {
156     /* node groups */
157     DEG_id_tag_update(id, 0);
158   }
159 }
160
161 void ED_node_tag_update_nodetree(Main *bmain, bNodeTree *ntree, bNode *node)
162 {
163   if (!ntree) {
164     return;
165   }
166
167   bool do_tag_update = true;
168   if (node != NULL) {
169     if (!node_connected_to_output(bmain, ntree, node)) {
170       do_tag_update = false;
171     }
172   }
173
174   /* look through all datablocks, to support groups */
175   if (do_tag_update) {
176     FOREACH_NODETREE_BEGIN (bmain, tntree, id) {
177       /* check if nodetree uses the group */
178       if (ntreeHasTree(tntree, ntree)) {
179         ED_node_tag_update_id(id);
180       }
181     }
182     FOREACH_NODETREE_END;
183   }
184
185   if (ntree->type == NTREE_TEXTURE) {
186     ntreeTexCheckCyclics(ntree);
187   }
188 }
189
190 static bool compare_nodes(const bNode *a, const bNode *b)
191 {
192   bNode *parent;
193   /* These tell if either the node or any of the parent nodes is selected.
194    * A selected parent means an unselected node is also in foreground!
195    */
196   bool a_select = (a->flag & NODE_SELECT) != 0, b_select = (b->flag & NODE_SELECT) != 0;
197   bool a_active = (a->flag & NODE_ACTIVE) != 0, b_active = (b->flag & NODE_ACTIVE) != 0;
198
199   /* if one is an ancestor of the other */
200   /* XXX there might be a better sorting algorithm for stable topological sort,
201    * this is O(n^2) worst case */
202   for (parent = a->parent; parent; parent = parent->parent) {
203     /* if b is an ancestor, it is always behind a */
204     if (parent == b) {
205       return 1;
206     }
207     /* any selected ancestor moves the node forward */
208     if (parent->flag & NODE_ACTIVE) {
209       a_active = 1;
210     }
211     if (parent->flag & NODE_SELECT) {
212       a_select = 1;
213     }
214   }
215   for (parent = b->parent; parent; parent = parent->parent) {
216     /* if a is an ancestor, it is always behind b */
217     if (parent == a) {
218       return 0;
219     }
220     /* any selected ancestor moves the node forward */
221     if (parent->flag & NODE_ACTIVE) {
222       b_active = 1;
223     }
224     if (parent->flag & NODE_SELECT) {
225       b_select = 1;
226     }
227   }
228
229   /* if one of the nodes is in the background and the other not */
230   if ((a->flag & NODE_BACKGROUND) && !(b->flag & NODE_BACKGROUND)) {
231     return 0;
232   }
233   else if (!(a->flag & NODE_BACKGROUND) && (b->flag & NODE_BACKGROUND)) {
234     return 1;
235   }
236
237   /* if one has a higher selection state (active > selected > nothing) */
238   if (!b_active && a_active) {
239     return 1;
240   }
241   else if (!b_select && (a_active || a_select)) {
242     return 1;
243   }
244
245   return 0;
246 }
247
248 /* Sorts nodes by selection: unselected nodes first, then selected,
249  * then the active node at the very end. Relative order is kept intact!
250  */
251 void ED_node_sort(bNodeTree *ntree)
252 {
253   /* merge sort is the algorithm of choice here */
254   bNode *first_a, *first_b, *node_a, *node_b, *tmp;
255   int totnodes = BLI_listbase_count(&ntree->nodes);
256   int k, a, b;
257
258   k = 1;
259   while (k < totnodes) {
260     first_a = first_b = ntree->nodes.first;
261
262     do {
263       /* setup first_b pointer */
264       for (b = 0; b < k && first_b; ++b) {
265         first_b = first_b->next;
266       }
267       /* all batches merged? */
268       if (first_b == NULL) {
269         break;
270       }
271
272       /* merge batches */
273       node_a = first_a;
274       node_b = first_b;
275       a = b = 0;
276       while (a < k && b < k && node_b) {
277         if (compare_nodes(node_a, node_b) == 0) {
278           node_a = node_a->next;
279           a++;
280         }
281         else {
282           tmp = node_b;
283           node_b = node_b->next;
284           b++;
285           BLI_remlink(&ntree->nodes, tmp);
286           BLI_insertlinkbefore(&ntree->nodes, node_a, tmp);
287         }
288       }
289
290       /* setup first pointers for next batch */
291       first_b = node_b;
292       for (; b < k; ++b) {
293         /* all nodes sorted? */
294         if (first_b == NULL) {
295           break;
296         }
297         first_b = first_b->next;
298       }
299       first_a = first_b;
300     } while (first_b);
301
302     k = k << 1;
303   }
304 }
305
306 static void do_node_internal_buttons(bContext *C, void *UNUSED(node_v), int event)
307 {
308   if (event == B_NODE_EXEC) {
309     SpaceNode *snode = CTX_wm_space_node(C);
310     if (snode && snode->id) {
311       ED_node_tag_update_id(snode->id);
312     }
313   }
314 }
315
316 static void node_uiblocks_init(const bContext *C, bNodeTree *ntree)
317 {
318   bNode *node;
319   char uiblockstr[32];
320
321   /* add node uiBlocks in drawing order - prevents events going to overlapping nodes */
322
323   for (node = ntree->nodes.first; node; node = node->next) {
324     /* ui block */
325     BLI_snprintf(uiblockstr, sizeof(uiblockstr), "node buttons %p", (void *)node);
326     node->block = UI_block_begin(C, CTX_wm_region(C), uiblockstr, UI_EMBOSS);
327     UI_block_func_handle_set(node->block, do_node_internal_buttons, node);
328
329     /* this cancels events for background nodes */
330     UI_block_flag_enable(node->block, UI_BLOCK_CLIP_EVENTS);
331   }
332 }
333
334 void node_to_view(struct bNode *node, float x, float y, float *rx, float *ry)
335 {
336   nodeToView(node, x, y, rx, ry);
337   *rx *= UI_DPI_FAC;
338   *ry *= UI_DPI_FAC;
339 }
340
341 void node_to_updated_rect(struct bNode *node, rctf *r_rect)
342 {
343   node_to_view(node, node->offsetx, node->offsety, &r_rect->xmin, &r_rect->ymax);
344   node_to_view(node,
345                node->offsetx + node->width,
346                node->offsety - node->height,
347                &r_rect->xmax,
348                &r_rect->ymin);
349 }
350
351 void node_from_view(struct bNode *node, float x, float y, float *rx, float *ry)
352 {
353   x /= UI_DPI_FAC;
354   y /= UI_DPI_FAC;
355   nodeFromView(node, x, y, rx, ry);
356 }
357
358 /* based on settings in node, sets drawing rect info. each redraw! */
359 static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
360 {
361   uiLayout *layout, *row;
362   PointerRNA nodeptr, sockptr;
363   bNodeSocket *nsock;
364   float locx, locy;
365   float dy;
366   int buty;
367
368   RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
369
370   /* get "global" coords */
371   node_to_view(node, 0.0f, 0.0f, &locx, &locy);
372   dy = locy;
373
374   /* header */
375   dy -= NODE_DY;
376
377   /* little bit space in top */
378   if (node->outputs.first) {
379     dy -= NODE_DYS / 2;
380   }
381
382   /* output sockets */
383   bool add_output_space = false;
384
385   for (nsock = node->outputs.first; nsock; nsock = nsock->next) {
386     if (nodeSocketIsHidden(nsock)) {
387       continue;
388     }
389
390     RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr);
391
392     layout = UI_block_layout(node->block,
393                              UI_LAYOUT_VERTICAL,
394                              UI_LAYOUT_PANEL,
395                              locx + NODE_DYS,
396                              dy,
397                              NODE_WIDTH(node) - NODE_DY,
398                              NODE_DY,
399                              0,
400                              UI_style_get());
401
402     if (node->flag & NODE_MUTED) {
403       uiLayoutSetActive(layout, false);
404     }
405
406     /* context pointers for current node and socket */
407     uiLayoutSetContextPointer(layout, "node", &nodeptr);
408     uiLayoutSetContextPointer(layout, "socket", &sockptr);
409
410     /* align output buttons to the right */
411     row = uiLayoutRow(layout, 1);
412     uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
413
414     nsock->typeinfo->draw((bContext *)C, row, &sockptr, &nodeptr, IFACE_(nsock->name));
415
416     UI_block_align_end(node->block);
417     UI_block_layout_resolve(node->block, NULL, &buty);
418
419     /* ensure minimum socket height in case layout is empty */
420     buty = min_ii(buty, dy - NODE_DY);
421
422     nsock->locx = locx + NODE_WIDTH(node);
423     /* place the socket circle in the middle of the layout */
424     nsock->locy = 0.5f * (dy + buty);
425
426     dy = buty;
427     if (nsock->next) {
428       dy -= NODE_SOCKDY;
429     }
430
431     add_output_space = true;
432   }
433
434   if (add_output_space) {
435     dy -= NODE_DY / 4;
436   }
437
438   node->prvr.xmin = locx + NODE_DYS;
439   node->prvr.xmax = locx + NODE_WIDTH(node) - NODE_DYS;
440
441   /* preview rect? */
442   if (node->flag & NODE_PREVIEW) {
443     float aspect = 1.0f;
444
445     if (node->preview_xsize && node->preview_ysize) {
446       aspect = (float)node->preview_ysize / (float)node->preview_xsize;
447     }
448
449     dy -= NODE_DYS / 2;
450     node->prvr.ymax = dy;
451
452     if (aspect <= 1.0f) {
453       node->prvr.ymin = dy - aspect * (NODE_WIDTH(node) - NODE_DY);
454     }
455     else {
456       /* width correction of image */
457       /* XXX huh? (ton) */
458       float dx = (NODE_WIDTH(node) - NODE_DYS) - (NODE_WIDTH(node) - NODE_DYS) / aspect;
459
460       node->prvr.ymin = dy - (NODE_WIDTH(node) - NODE_DY);
461
462       node->prvr.xmin += 0.5f * dx;
463       node->prvr.xmax -= 0.5f * dx;
464     }
465
466     dy = node->prvr.ymin - NODE_DYS / 2;
467
468     /* make sure that maximums are bigger or equal to minimums */
469     if (node->prvr.xmax < node->prvr.xmin) {
470       SWAP(float, node->prvr.xmax, node->prvr.xmin);
471     }
472     if (node->prvr.ymax < node->prvr.ymin) {
473       SWAP(float, node->prvr.ymax, node->prvr.ymin);
474     }
475   }
476
477   /* buttons rect? */
478   if (node->typeinfo->draw_buttons && (node->flag & NODE_OPTIONS)) {
479     dy -= NODE_DYS / 2;
480
481     /* set this for uifunc() that don't use layout engine yet */
482     node->butr.xmin = 0;
483     node->butr.xmax = NODE_WIDTH(node) - 2 * NODE_DYS;
484     node->butr.ymin = 0;
485     node->butr.ymax = 0;
486
487     layout = UI_block_layout(node->block,
488                              UI_LAYOUT_VERTICAL,
489                              UI_LAYOUT_PANEL,
490                              locx + NODE_DYS,
491                              dy,
492                              node->butr.xmax,
493                              0,
494                              0,
495                              UI_style_get());
496
497     if (node->flag & NODE_MUTED) {
498       uiLayoutSetActive(layout, false);
499     }
500
501     uiLayoutSetContextPointer(layout, "node", &nodeptr);
502
503     node->typeinfo->draw_buttons(layout, (bContext *)C, &nodeptr);
504
505     UI_block_align_end(node->block);
506     UI_block_layout_resolve(node->block, NULL, &buty);
507
508     dy = buty - NODE_DYS / 2;
509   }
510
511   /* input sockets */
512   for (nsock = node->inputs.first; nsock; nsock = nsock->next) {
513     if (nodeSocketIsHidden(nsock)) {
514       continue;
515     }
516
517     RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr);
518
519     layout = UI_block_layout(node->block,
520                              UI_LAYOUT_VERTICAL,
521                              UI_LAYOUT_PANEL,
522                              locx + NODE_DYS,
523                              dy,
524                              NODE_WIDTH(node) - NODE_DY,
525                              NODE_DY,
526                              0,
527                              UI_style_get());
528
529     if (node->flag & NODE_MUTED) {
530       uiLayoutSetActive(layout, false);
531     }
532
533     /* context pointers for current node and socket */
534     uiLayoutSetContextPointer(layout, "node", &nodeptr);
535     uiLayoutSetContextPointer(layout, "socket", &sockptr);
536
537     row = uiLayoutRow(layout, 1);
538
539     nsock->typeinfo->draw((bContext *)C, row, &sockptr, &nodeptr, IFACE_(nsock->name));
540
541     UI_block_align_end(node->block);
542     UI_block_layout_resolve(node->block, NULL, &buty);
543
544     /* ensure minimum socket height in case layout is empty */
545     buty = min_ii(buty, dy - NODE_DY);
546
547     nsock->locx = locx;
548     /* place the socket circle in the middle of the layout */
549     nsock->locy = 0.5f * (dy + buty);
550
551     dy = buty;
552     if (nsock->next) {
553       dy -= NODE_SOCKDY;
554     }
555   }
556
557   /* little bit space in end */
558   if (node->inputs.first || (node->flag & (NODE_OPTIONS | NODE_PREVIEW)) == 0) {
559     dy -= NODE_DYS / 2;
560   }
561
562   node->totr.xmin = locx;
563   node->totr.xmax = locx + NODE_WIDTH(node);
564   node->totr.ymax = locy;
565   node->totr.ymin = min_ff(dy, locy - 2 * NODE_DY);
566
567   /* Set the block bounds to clip mouse events from underlying nodes.
568    * Add a margin for sockets on each side.
569    */
570   UI_block_bounds_set_explicit(node->block,
571                                node->totr.xmin - NODE_SOCKSIZE,
572                                node->totr.ymin,
573                                node->totr.xmax + NODE_SOCKSIZE,
574                                node->totr.ymax);
575 }
576
577 /* based on settings in node, sets drawing rect info. each redraw! */
578 static void node_update_hidden(bNode *node)
579 {
580   bNodeSocket *nsock;
581   float locx, locy;
582   float rad, drad, hiddenrad = HIDDEN_RAD;
583   int totin = 0, totout = 0, tot;
584
585   /* get "global" coords */
586   node_to_view(node, 0.0f, 0.0f, &locx, &locy);
587
588   /* calculate minimal radius */
589   for (nsock = node->inputs.first; nsock; nsock = nsock->next) {
590     if (!nodeSocketIsHidden(nsock)) {
591       totin++;
592     }
593   }
594   for (nsock = node->outputs.first; nsock; nsock = nsock->next) {
595     if (!nodeSocketIsHidden(nsock)) {
596       totout++;
597     }
598   }
599
600   tot = MAX2(totin, totout);
601   if (tot > 4) {
602     hiddenrad += 5.0f * (float)(tot - 4);
603   }
604
605   node->totr.xmin = locx;
606   node->totr.xmax = locx + max_ff(NODE_WIDTH(node), 2 * hiddenrad);
607   node->totr.ymax = locy + (hiddenrad - 0.5f * NODE_DY);
608   node->totr.ymin = node->totr.ymax - 2 * hiddenrad;
609
610   /* output sockets */
611   rad = drad = (float)M_PI / (1.0f + (float)totout);
612
613   for (nsock = node->outputs.first; nsock; nsock = nsock->next) {
614     if (!nodeSocketIsHidden(nsock)) {
615       nsock->locx = node->totr.xmax - hiddenrad + sinf(rad) * hiddenrad;
616       nsock->locy = node->totr.ymin + hiddenrad + cosf(rad) * hiddenrad;
617       rad += drad;
618     }
619   }
620
621   /* input sockets */
622   rad = drad = -(float)M_PI / (1.0f + (float)totin);
623
624   for (nsock = node->inputs.first; nsock; nsock = nsock->next) {
625     if (!nodeSocketIsHidden(nsock)) {
626       nsock->locx = node->totr.xmin + hiddenrad + sinf(rad) * hiddenrad;
627       nsock->locy = node->totr.ymin + hiddenrad + cosf(rad) * hiddenrad;
628       rad += drad;
629     }
630   }
631
632   /* Set the block bounds to clip mouse events from underlying nodes.
633    * Add a margin for sockets on each side.
634    */
635   UI_block_bounds_set_explicit(node->block,
636                                node->totr.xmin - NODE_SOCKSIZE,
637                                node->totr.ymin,
638                                node->totr.xmax + NODE_SOCKSIZE,
639                                node->totr.ymax);
640 }
641
642 void node_update_default(const bContext *C, bNodeTree *ntree, bNode *node)
643 {
644   if (node->flag & NODE_HIDDEN) {
645     node_update_hidden(node);
646   }
647   else {
648     node_update_basis(C, ntree, node);
649   }
650 }
651
652 int node_select_area_default(bNode *node, int x, int y)
653 {
654   return BLI_rctf_isect_pt(&node->totr, x, y);
655 }
656
657 int node_tweak_area_default(bNode *node, int x, int y)
658 {
659   return BLI_rctf_isect_pt(&node->totr, x, y);
660 }
661
662 int node_get_colorid(bNode *node)
663 {
664   switch (node->typeinfo->nclass) {
665     case NODE_CLASS_INPUT:
666       return TH_NODE_INPUT;
667     case NODE_CLASS_OUTPUT:
668       return (node->flag & NODE_DO_OUTPUT) ? TH_NODE_OUTPUT : TH_NODE;
669     case NODE_CLASS_CONVERTOR:
670       return TH_NODE_CONVERTOR;
671     case NODE_CLASS_OP_COLOR:
672       return TH_NODE_COLOR;
673     case NODE_CLASS_OP_VECTOR:
674       return TH_NODE_VECTOR;
675     case NODE_CLASS_OP_FILTER:
676       return TH_NODE_FILTER;
677     case NODE_CLASS_GROUP:
678       return TH_NODE_GROUP;
679     case NODE_CLASS_INTERFACE:
680       return TH_NODE_INTERFACE;
681     case NODE_CLASS_MATTE:
682       return TH_NODE_MATTE;
683     case NODE_CLASS_DISTORT:
684       return TH_NODE_DISTORT;
685     case NODE_CLASS_TEXTURE:
686       return TH_NODE_TEXTURE;
687     case NODE_CLASS_SHADER:
688       return TH_NODE_SHADER;
689     case NODE_CLASS_SCRIPT:
690       return TH_NODE_SCRIPT;
691     case NODE_CLASS_PATTERN:
692       return TH_NODE_PATTERN;
693     case NODE_CLASS_LAYOUT:
694       return TH_NODE_LAYOUT;
695     default:
696       return TH_NODE;
697   }
698 }
699
700 /* note: in cmp_util.c is similar code, for node_compo_pass_on()
701  *       the same goes for shader and texture nodes. */
702 /* note: in node_edit.c is similar code, for untangle node */
703 static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node)
704 {
705   bNodeLink *link;
706
707   GPU_blend(true);
708
709   for (link = node->internal_links.first; link; link = link->next) {
710     node_draw_link_bezier(v2d, snode, link, TH_REDALERT, TH_REDALERT, -1);
711   }
712
713   GPU_blend(false);
714 }
715
716 static void node_socket_circle_draw(const bContext *C,
717                                     bNodeTree *ntree,
718                                     PointerRNA node_ptr,
719                                     bNodeSocket *sock,
720                                     unsigned pos,
721                                     unsigned col)
722 {
723   PointerRNA ptr;
724   float color[4];
725
726   RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
727   sock->typeinfo->draw_color((bContext *)C, &ptr, &node_ptr, color);
728
729   bNode *node = node_ptr.data;
730   if (node->flag & NODE_MUTED) {
731     color[3] *= 0.25f;
732   }
733
734   immAttr4fv(col, color);
735   immVertex2f(pos, sock->locx, sock->locy);
736 }
737
738 /* **************  Socket callbacks *********** */
739
740 static void node_draw_preview_background(float tile, rctf *rect)
741 {
742   float x, y;
743
744   GPUVertFormat *format = immVertexFormat();
745   uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
746
747   immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
748
749   /* draw checkerboard backdrop to show alpha */
750   immUniformColor3ub(120, 120, 120);
751   immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
752   immUniformColor3ub(160, 160, 160);
753
754   for (y = rect->ymin; y < rect->ymax; y += tile * 2) {
755     for (x = rect->xmin; x < rect->xmax; x += tile * 2) {
756       float tilex = tile, tiley = tile;
757
758       if (x + tile > rect->xmax) {
759         tilex = rect->xmax - x;
760       }
761       if (y + tile > rect->ymax) {
762         tiley = rect->ymax - y;
763       }
764
765       immRectf(pos, x, y, x + tilex, y + tiley);
766     }
767   }
768   for (y = rect->ymin + tile; y < rect->ymax; y += tile * 2) {
769     for (x = rect->xmin + tile; x < rect->xmax; x += tile * 2) {
770       float tilex = tile, tiley = tile;
771
772       if (x + tile > rect->xmax) {
773         tilex = rect->xmax - x;
774       }
775       if (y + tile > rect->ymax) {
776         tiley = rect->ymax - y;
777       }
778
779       immRectf(pos, x, y, x + tilex, y + tiley);
780     }
781   }
782   immUnbindProgram();
783 }
784
785 /* not a callback */
786 static void node_draw_preview(bNodePreview *preview, rctf *prv)
787 {
788   float xrect = BLI_rctf_size_x(prv);
789   float yrect = BLI_rctf_size_y(prv);
790   float xscale = xrect / ((float)preview->xsize);
791   float yscale = yrect / ((float)preview->ysize);
792   float scale;
793   rctf draw_rect;
794
795   /* uniform scale and offset */
796   draw_rect = *prv;
797   if (xscale < yscale) {
798     float offset = 0.5f * (yrect - ((float)preview->ysize) * xscale);
799     draw_rect.ymin += offset;
800     draw_rect.ymax -= offset;
801     scale = xscale;
802   }
803   else {
804     float offset = 0.5f * (xrect - ((float)preview->xsize) * yscale);
805     draw_rect.xmin += offset;
806     draw_rect.xmax -= offset;
807     scale = yscale;
808   }
809
810   node_draw_preview_background(BLI_rctf_size_x(prv) / 10.0f, &draw_rect);
811
812   GPU_blend(true);
813   /* premul graphics */
814   GPU_blend_set_func_separate(
815       GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
816
817   IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
818   immDrawPixelsTex(&state,
819                    draw_rect.xmin,
820                    draw_rect.ymin,
821                    preview->xsize,
822                    preview->ysize,
823                    GL_RGBA,
824                    GL_UNSIGNED_BYTE,
825                    GL_LINEAR,
826                    preview->rect,
827                    scale,
828                    scale,
829                    NULL);
830
831   GPU_blend(false);
832
833   uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
834   immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
835   immUniformThemeColorShadeAlpha(TH_BACK, -15, +100);
836   imm_draw_box_wire_2d(pos, draw_rect.xmin, draw_rect.ymin, draw_rect.xmax, draw_rect.ymax);
837   immUnbindProgram();
838 }
839
840 /* common handle function for operator buttons that need to select the node first */
841 static void node_toggle_button_cb(struct bContext *C, void *node_argv, void *op_argv)
842 {
843   bNode *node = (bNode *)node_argv;
844   const char *opname = (const char *)op_argv;
845
846   /* select & activate only the button's node */
847   node_select_single(C, node);
848
849   WM_operator_name_call(C, opname, WM_OP_INVOKE_DEFAULT, NULL);
850 }
851
852 void node_draw_shadow(SpaceNode *snode, bNode *node, float radius, float alpha)
853 {
854   rctf *rct = &node->totr;
855
856   UI_draw_roundbox_corner_set(UI_CNR_ALL);
857   if (node->parent == NULL) {
858     ui_draw_dropshadow(rct, radius, snode->aspect, alpha, node->flag & SELECT);
859   }
860   else {
861     const float margin = 3.0f;
862
863     float color[4] = {0.0f, 0.0f, 0.0f, 0.33f};
864     UI_draw_roundbox_aa(true,
865                         rct->xmin - margin,
866                         rct->ymin - margin,
867                         rct->xmax + margin,
868                         rct->ymax + margin,
869                         radius + margin,
870                         color);
871   }
872 }
873
874 void node_draw_sockets(View2D *v2d,
875                        const bContext *C,
876                        bNodeTree *ntree,
877                        bNode *node,
878                        bool draw_outputs,
879                        bool select_all)
880 {
881   const uint total_input_len = BLI_listbase_count(&node->inputs);
882   const uint total_output_len = BLI_listbase_count(&node->outputs);
883
884   if (total_input_len + total_output_len == 0) {
885     return;
886   }
887
888   PointerRNA node_ptr;
889   RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
890
891   float scale;
892   UI_view2d_scale_get(v2d, &scale, NULL);
893
894   GPUVertFormat *format = immVertexFormat();
895   uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
896   uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
897
898   GPU_blend(true);
899   GPU_program_point_size(true);
900
901   immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_AA);
902
903   /* set handle size */
904   immUniform1f("size", 2.0f * NODE_SOCKSIZE * scale); /* 2 * size to have diameter */
905
906   if (!select_all) {
907     /* outline for unselected sockets */
908     immUniform1f("outlineWidth", 1.0f);
909     immUniform4f("outlineColor", 0.0f, 0.0f, 0.0f, 0.6f);
910
911     immBeginAtMost(GPU_PRIM_POINTS, total_input_len + total_output_len);
912   }
913
914   /* socket inputs */
915   short selected_input_len = 0;
916   bNodeSocket *sock;
917   for (sock = node->inputs.first; sock; sock = sock->next) {
918     if (nodeSocketIsHidden(sock)) {
919       continue;
920     }
921     if (select_all || (sock->flag & SELECT)) {
922       ++selected_input_len;
923       continue;
924     }
925
926     node_socket_circle_draw(C, ntree, node_ptr, sock, pos, col);
927   }
928
929   /* socket outputs */
930   short selected_output_len = 0;
931   if (draw_outputs) {
932     for (sock = node->outputs.first; sock; sock = sock->next) {
933       if (nodeSocketIsHidden(sock)) {
934         continue;
935       }
936       if (select_all || (sock->flag & SELECT)) {
937         ++selected_output_len;
938         continue;
939       }
940
941       node_socket_circle_draw(C, ntree, node_ptr, sock, pos, col);
942     }
943   }
944
945   if (!select_all) {
946     immEnd();
947   }
948
949   /* go back and draw selected sockets */
950   if (selected_input_len + selected_output_len > 0) {
951     /* outline for selected sockets */
952     float c[3];
953     UI_GetThemeColor3fv(TH_TEXT_HI, c);
954     immUniform4f("outlineColor", c[0], c[1], c[2], 1.0f);
955     immUniform1f("outlineWidth", 1.5f);
956
957     immBegin(GPU_PRIM_POINTS, selected_input_len + selected_output_len);
958
959     if (selected_input_len) {
960       /* socket inputs */
961       for (sock = node->inputs.first; sock; sock = sock->next) {
962         if (nodeSocketIsHidden(sock)) {
963           continue;
964         }
965         if (select_all || (sock->flag & SELECT)) {
966           node_socket_circle_draw(C, ntree, node_ptr, sock, pos, col);
967           if (--selected_input_len == 0) {
968             break; /* stop as soon as last one is drawn */
969           }
970         }
971       }
972     }
973
974     if (selected_output_len) {
975       /* socket outputs */
976       for (sock = node->outputs.first; sock; sock = sock->next) {
977         if (nodeSocketIsHidden(sock)) {
978           continue;
979         }
980         if (select_all || (sock->flag & SELECT)) {
981           node_socket_circle_draw(C, ntree, node_ptr, sock, pos, col);
982           if (--selected_output_len == 0) {
983             break; /* stop as soon as last one is drawn */
984           }
985         }
986       }
987     }
988
989     immEnd();
990   }
991
992   immUnbindProgram();
993
994   GPU_program_point_size(false);
995   GPU_blend(false);
996 }
997
998 static void node_draw_basis(const bContext *C,
999                             ARegion *ar,
1000                             SpaceNode *snode,
1001                             bNodeTree *ntree,
1002                             bNode *node,
1003                             bNodeInstanceKey key)
1004 {
1005   bNodeInstanceHash *previews = CTX_data_pointer_get(C, "node_previews").data;
1006   rctf *rct = &node->totr;
1007   float iconofs;
1008   /* float socket_size = NODE_SOCKSIZE*U.dpi/72; */ /* UNUSED */
1009   float iconbutw = 0.8f * UI_UNIT_X;
1010   int color_id = node_get_colorid(node);
1011   float color[4];
1012   char showname[128]; /* 128 used below */
1013   View2D *v2d = &ar->v2d;
1014
1015   /* skip if out of view */
1016   if (BLI_rctf_isect(&node->totr, &v2d->cur, NULL) == false) {
1017     UI_block_end(C, node->block);
1018     node->block = NULL;
1019     return;
1020   }
1021
1022   /* shadow */
1023   node_draw_shadow(snode, node, BASIS_RAD, 1.0f);
1024
1025   if (node->flag & NODE_MUTED) {
1026     /* Muted nodes are semi-transparent and colorless. */
1027     UI_GetThemeColor3fv(TH_NODE, color);
1028     color[3] = 0.25f;
1029   }
1030   else {
1031     /* Opaque headers for regular nodes. */
1032     UI_GetThemeColor3fv(color_id, color);
1033     color[3] = 1.0f;
1034   }
1035
1036   GPU_line_width(1.0f);
1037
1038   UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
1039   UI_draw_roundbox_aa(
1040       true, rct->xmin, rct->ymax - NODE_DY, rct->xmax, rct->ymax, BASIS_RAD, color);
1041
1042   /* show/hide icons */
1043   iconofs = rct->xmax - 0.35f * U.widget_unit;
1044
1045   /* preview */
1046   if (node->typeinfo->flag & NODE_PREVIEW) {
1047     uiBut *but;
1048     iconofs -= iconbutw;
1049     UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
1050     but = uiDefIconBut(node->block,
1051                        UI_BTYPE_BUT_TOGGLE,
1052                        B_REDR,
1053                        ICON_MATERIAL,
1054                        iconofs,
1055                        rct->ymax - NODE_DY,
1056                        iconbutw,
1057                        UI_UNIT_Y,
1058                        NULL,
1059                        0,
1060                        0,
1061                        0,
1062                        0,
1063                        "");
1064     UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_preview_toggle");
1065     /* XXX this does not work when node is activated and the operator called right afterwards,
1066      * since active ID is not updated yet (needs to process the notifier).
1067      * This can only work as visual indicator!
1068      */
1069     //      if (!(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT)))
1070     //          UI_but_flag_enable(but, UI_BUT_DISABLED);
1071     UI_block_emboss_set(node->block, UI_EMBOSS);
1072   }
1073   /* group edit */
1074   if (node->type == NODE_GROUP) {
1075     uiBut *but;
1076     iconofs -= iconbutw;
1077     UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
1078     but = uiDefIconBut(node->block,
1079                        UI_BTYPE_BUT_TOGGLE,
1080                        B_REDR,
1081                        ICON_NODETREE,
1082                        iconofs,
1083                        rct->ymax - NODE_DY,
1084                        iconbutw,
1085                        UI_UNIT_Y,
1086                        NULL,
1087                        0,
1088                        0,
1089                        0,
1090                        0,
1091                        "");
1092     UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_group_edit");
1093     UI_block_emboss_set(node->block, UI_EMBOSS);
1094   }
1095
1096   /* title */
1097   if (node->flag & SELECT) {
1098     UI_GetThemeColor4fv(TH_SELECT, color);
1099   }
1100   else {
1101     UI_GetThemeColorBlendShade4fv(TH_SELECT, color_id, 0.4f, 10, color);
1102   }
1103
1104   /* open/close entirely? */
1105   {
1106     uiBut *but;
1107     int but_size = U.widget_unit * 0.8f;
1108     /* XXX button uses a custom triangle draw below, so make it invisible without icon */
1109     UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
1110     but = uiDefBut(node->block,
1111                    UI_BTYPE_BUT_TOGGLE,
1112                    B_REDR,
1113                    "",
1114                    rct->xmin + 0.35f * U.widget_unit,
1115                    rct->ymax - NODE_DY / 2.2f - but_size / 2,
1116                    but_size,
1117                    but_size,
1118                    NULL,
1119                    0,
1120                    0,
1121                    0,
1122                    0,
1123                    "");
1124     UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle");
1125     UI_block_emboss_set(node->block, UI_EMBOSS);
1126
1127     UI_GetThemeColor4fv(TH_TEXT, color);
1128     /* custom draw function for this button */
1129     UI_draw_icon_tri(rct->xmin + 0.65f * U.widget_unit, rct->ymax - NODE_DY / 2.2f, 'v', color);
1130   }
1131
1132   nodeLabel(ntree, node, showname, sizeof(showname));
1133
1134   uiBut *but = uiDefBut(node->block,
1135                         UI_BTYPE_LABEL,
1136                         0,
1137                         showname,
1138                         (int)(rct->xmin + (NODE_MARGIN_X)),
1139                         (int)(rct->ymax - NODE_DY),
1140                         (short)(iconofs - rct->xmin - 18.0f),
1141                         (short)NODE_DY,
1142                         NULL,
1143                         0,
1144                         0,
1145                         0,
1146                         0,
1147                         "");
1148   if (node->flag & NODE_MUTED) {
1149     UI_but_flag_enable(but, UI_BUT_INACTIVE);
1150   }
1151
1152   /* body */
1153   if (!nodeIsRegistered(node)) {
1154     /* use warning color to indicate undefined types */
1155     UI_GetThemeColor4fv(TH_REDALERT, color);
1156   }
1157   else if (node->flag & NODE_MUTED) {
1158     /* Muted nodes are semi-transparent and colorless. */
1159     UI_GetThemeColor4fv(TH_NODE, color);
1160   }
1161   else if (node->flag & NODE_CUSTOM_COLOR) {
1162     rgba_float_args_set(color, node->color[0], node->color[1], node->color[2], 1.0f);
1163   }
1164   else {
1165     UI_GetThemeColor4fv(TH_NODE, color);
1166   }
1167
1168   if (node->flag & NODE_MUTED) {
1169     color[3] = 0.5f;
1170   }
1171
1172   UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT);
1173   UI_draw_roundbox_aa(
1174       true, rct->xmin, rct->ymin, rct->xmax, rct->ymax - NODE_DY, BASIS_RAD, color);
1175
1176   /* outline active and selected emphasis */
1177   if (node->flag & SELECT) {
1178     UI_GetThemeColorShadeAlpha4fv(
1179         (node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, 0, -40, color);
1180
1181     UI_draw_roundbox_corner_set(UI_CNR_ALL);
1182     UI_draw_roundbox_aa(false, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD, color);
1183   }
1184
1185   /* disable lines */
1186   if (node->flag & NODE_MUTED) {
1187     node_draw_mute_line(v2d, snode, node);
1188   }
1189
1190   node_draw_sockets(v2d, C, ntree, node, true, false);
1191
1192   /* preview */
1193   if (node->flag & NODE_PREVIEW && previews) {
1194     bNodePreview *preview = BKE_node_instance_hash_lookup(previews, key);
1195     if (preview && (preview->xsize && preview->ysize)) {
1196       if (preview->rect && !BLI_rctf_is_empty(&node->prvr)) {
1197         node_draw_preview(preview, &node->prvr);
1198       }
1199     }
1200   }
1201
1202   UI_ThemeClearColor(color_id);
1203
1204   UI_block_end(C, node->block);
1205   UI_block_draw(C, node->block);
1206   node->block = NULL;
1207 }
1208
1209 static void node_draw_hidden(const bContext *C,
1210                              ARegion *ar,
1211                              SpaceNode *snode,
1212                              bNodeTree *ntree,
1213                              bNode *node,
1214                              bNodeInstanceKey UNUSED(key))
1215 {
1216   rctf *rct = &node->totr;
1217   float dx, centy = BLI_rctf_cent_y(rct);
1218   float hiddenrad = BLI_rctf_size_y(rct) / 2.0f;
1219   int color_id = node_get_colorid(node);
1220   float color[4];
1221   char showname[128]; /* 128 is used below */
1222   View2D *v2d = &ar->v2d;
1223   float scale;
1224
1225   UI_view2d_scale_get(v2d, &scale, NULL);
1226
1227   /* shadow */
1228   node_draw_shadow(snode, node, hiddenrad, 1.0f);
1229
1230   /* body */
1231   if (node->flag & NODE_MUTED) {
1232     /* Muted nodes are semi-transparent and colorless. */
1233     UI_GetThemeColor4fv(TH_NODE, color);
1234     color[3] = 0.25f;
1235   }
1236   else {
1237     UI_GetThemeColor4fv(color_id, color);
1238   }
1239
1240   UI_draw_roundbox_aa(true, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad, color);
1241
1242   /* outline active and selected emphasis */
1243   if (node->flag & SELECT) {
1244     UI_GetThemeColorShadeAlpha4fv(
1245         (node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, 0, -40, color);
1246
1247     UI_draw_roundbox_aa(false, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad, color);
1248   }
1249
1250   /* custom color inline */
1251   if (node->flag & NODE_CUSTOM_COLOR) {
1252     GPU_blend(true);
1253     GPU_line_smooth(true);
1254
1255     UI_draw_roundbox_3fvAlpha(false,
1256                               rct->xmin + 1,
1257                               rct->ymin + 1,
1258                               rct->xmax - 1,
1259                               rct->ymax - 1,
1260                               hiddenrad,
1261                               node->color,
1262                               1.0f);
1263
1264     GPU_line_smooth(false);
1265     GPU_blend(false);
1266   }
1267
1268   /* title */
1269   if (node->flag & SELECT) {
1270     UI_GetThemeColor4fv(TH_SELECT, color);
1271   }
1272   else {
1273     UI_GetThemeColorBlendShade4fv(TH_SELECT, color_id, 0.4f, 10, color);
1274   }
1275
1276   /* open entirely icon */
1277   {
1278     uiBut *but;
1279     int but_size = U.widget_unit * 0.8f;
1280     /* XXX button uses a custom triangle draw below, so make it invisible without icon */
1281     UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
1282     but = uiDefBut(node->block,
1283                    UI_BTYPE_BUT_TOGGLE,
1284                    B_REDR,
1285                    "",
1286                    rct->xmin + 0.35f * U.widget_unit,
1287                    centy - but_size / 2,
1288                    but_size,
1289                    but_size,
1290                    NULL,
1291                    0,
1292                    0,
1293                    0,
1294                    0,
1295                    "");
1296     UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle");
1297     UI_block_emboss_set(node->block, UI_EMBOSS);
1298
1299     UI_GetThemeColor4fv(TH_TEXT, color);
1300     /* custom draw function for this button */
1301     UI_draw_icon_tri(rct->xmin + 0.65f * U.widget_unit, centy, 'h', color);
1302   }
1303
1304   /* disable lines */
1305   if (node->flag & NODE_MUTED) {
1306     node_draw_mute_line(&ar->v2d, snode, node);
1307   }
1308
1309   nodeLabel(ntree, node, showname, sizeof(showname));
1310
1311   /* XXX - don't print into self! */
1312   // if (node->flag & NODE_MUTED)
1313   //  BLI_snprintf(showname, sizeof(showname), "[%s]", showname);
1314
1315   uiBut *but = uiDefBut(node->block,
1316                         UI_BTYPE_LABEL,
1317                         0,
1318                         showname,
1319                         round_fl_to_int(rct->xmin + NODE_MARGIN_X),
1320                         round_fl_to_int(centy - NODE_DY * 0.5f),
1321                         (short)(BLI_rctf_size_x(rct) - 18.0f - 12.0f),
1322                         (short)NODE_DY,
1323                         NULL,
1324                         0,
1325                         0,
1326                         0,
1327                         0,
1328                         "");
1329   if (node->flag & NODE_MUTED) {
1330     UI_but_flag_enable(but, UI_BUT_INACTIVE);
1331   }
1332
1333   /* scale widget thing */
1334   uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1335   immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
1336
1337   immUniformThemeColorShade(color_id, -10);
1338   dx = 10.0f;
1339
1340   immBegin(GPU_PRIM_LINES, 4);
1341   immVertex2f(pos, rct->xmax - dx, centy - 4.0f);
1342   immVertex2f(pos, rct->xmax - dx, centy + 4.0f);
1343
1344   immVertex2f(pos, rct->xmax - dx - 3.0f * snode->aspect, centy - 4.0f);
1345   immVertex2f(pos, rct->xmax - dx - 3.0f * snode->aspect, centy + 4.0f);
1346   immEnd();
1347
1348   immUniformThemeColorShade(color_id, 30);
1349   dx -= snode->aspect;
1350
1351   immBegin(GPU_PRIM_LINES, 4);
1352   immVertex2f(pos, rct->xmax - dx, centy - 4.0f);
1353   immVertex2f(pos, rct->xmax - dx, centy + 4.0f);
1354
1355   immVertex2f(pos, rct->xmax - dx - 3.0f * snode->aspect, centy - 4.0f);
1356   immVertex2f(pos, rct->xmax - dx - 3.0f * snode->aspect, centy + 4.0f);
1357   immEnd();
1358
1359   immUnbindProgram();
1360
1361   node_draw_sockets(v2d, C, ntree, node, true, false);
1362
1363   UI_block_end(C, node->block);
1364   UI_block_draw(C, node->block);
1365   node->block = NULL;
1366 }
1367
1368 int node_get_resize_cursor(int directions)
1369 {
1370   if (directions == 0) {
1371     return CURSOR_STD;
1372   }
1373   else if ((directions & ~(NODE_RESIZE_TOP | NODE_RESIZE_BOTTOM)) == 0) {
1374     return CURSOR_Y_MOVE;
1375   }
1376   else if ((directions & ~(NODE_RESIZE_RIGHT | NODE_RESIZE_LEFT)) == 0) {
1377     return CURSOR_X_MOVE;
1378   }
1379   else {
1380     return CURSOR_EDIT;
1381   }
1382 }
1383
1384 void node_set_cursor(wmWindow *win, SpaceNode *snode, float cursor[2])
1385 {
1386   bNodeTree *ntree = snode->edittree;
1387   bNode *node;
1388   bNodeSocket *sock;
1389   int wmcursor = CURSOR_STD;
1390
1391   if (ntree) {
1392     if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN | SOCK_OUT)) {
1393       /* pass */
1394     }
1395     else {
1396       /* check nodes front to back */
1397       for (node = ntree->nodes.last; node; node = node->prev) {
1398         if (BLI_rctf_isect_pt(&node->totr, cursor[0], cursor[1])) {
1399           break; /* first hit on node stops */
1400         }
1401       }
1402       if (node) {
1403         int dir = node->typeinfo->resize_area_func(node, cursor[0], cursor[1]);
1404         wmcursor = node_get_resize_cursor(dir);
1405       }
1406     }
1407   }
1408
1409   WM_cursor_set(win, wmcursor);
1410 }
1411
1412 void node_draw_default(const bContext *C,
1413                        ARegion *ar,
1414                        SpaceNode *snode,
1415                        bNodeTree *ntree,
1416                        bNode *node,
1417                        bNodeInstanceKey key)
1418 {
1419   if (node->flag & NODE_HIDDEN) {
1420     node_draw_hidden(C, ar, snode, ntree, node, key);
1421   }
1422   else {
1423     node_draw_basis(C, ar, snode, ntree, node, key);
1424   }
1425 }
1426
1427 static void node_update(const bContext *C, bNodeTree *ntree, bNode *node)
1428 {
1429   if (node->typeinfo->draw_nodetype_prepare) {
1430     node->typeinfo->draw_nodetype_prepare(C, ntree, node);
1431   }
1432 }
1433
1434 void node_update_nodetree(const bContext *C, bNodeTree *ntree)
1435 {
1436   bNode *node;
1437
1438   /* make sure socket "used" tags are correct, for displaying value buttons */
1439   ntreeTagUsedSockets(ntree);
1440
1441   /* update nodes front to back, so children sizes get updated before parents */
1442   for (node = ntree->nodes.last; node; node = node->prev) {
1443     node_update(C, ntree, node);
1444   }
1445 }
1446
1447 static void node_draw(const bContext *C,
1448                       ARegion *ar,
1449                       SpaceNode *snode,
1450                       bNodeTree *ntree,
1451                       bNode *node,
1452                       bNodeInstanceKey key)
1453 {
1454   if (node->typeinfo->draw_nodetype) {
1455     node->typeinfo->draw_nodetype(C, ar, snode, ntree, node, key);
1456   }
1457 }
1458
1459 #define USE_DRAW_TOT_UPDATE
1460
1461 void node_draw_nodetree(const bContext *C,
1462                         ARegion *ar,
1463                         SpaceNode *snode,
1464                         bNodeTree *ntree,
1465                         bNodeInstanceKey parent_key)
1466 {
1467   bNode *node;
1468   bNodeLink *link;
1469   int a;
1470
1471   if (ntree == NULL) {
1472     return; /* groups... */
1473   }
1474
1475 #ifdef USE_DRAW_TOT_UPDATE
1476   if (ntree->nodes.first) {
1477     BLI_rctf_init_minmax(&ar->v2d.tot);
1478   }
1479 #endif
1480
1481   /* draw background nodes, last nodes in front */
1482   for (a = 0, node = ntree->nodes.first; node; node = node->next, a++) {
1483     bNodeInstanceKey key;
1484
1485 #ifdef USE_DRAW_TOT_UPDATE
1486     /* unrelated to background nodes, update the v2d->tot,
1487      * can be anywhere before we draw the scroll bars */
1488     BLI_rctf_union(&ar->v2d.tot, &node->totr);
1489 #endif
1490
1491     if (!(node->flag & NODE_BACKGROUND)) {
1492       continue;
1493     }
1494
1495     key = BKE_node_instance_key(parent_key, ntree, node);
1496     node->nr = a; /* index of node in list, used for exec event code */
1497     node_draw(C, ar, snode, ntree, node, key);
1498   }
1499
1500   /* node lines */
1501   GPU_blend(true);
1502   nodelink_batch_start(snode);
1503   for (link = ntree->links.first; link; link = link->next) {
1504     if (!nodeLinkIsHidden(link)) {
1505       node_draw_link(&ar->v2d, snode, link);
1506     }
1507   }
1508   nodelink_batch_end(snode);
1509   GPU_blend(false);
1510
1511   /* draw foreground nodes, last nodes in front */
1512   for (a = 0, node = ntree->nodes.first; node; node = node->next, a++) {
1513     bNodeInstanceKey key;
1514     if (node->flag & NODE_BACKGROUND) {
1515       continue;
1516     }
1517
1518     key = BKE_node_instance_key(parent_key, ntree, node);
1519     node->nr = a; /* index of node in list, used for exec event code */
1520     node_draw(C, ar, snode, ntree, node, key);
1521   }
1522 }
1523
1524 /* draw tree path info in lower left corner */
1525 static void draw_tree_path(SpaceNode *snode)
1526 {
1527   char info[256];
1528
1529   ED_node_tree_path_get_fixedbuf(snode, info, sizeof(info));
1530
1531   UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
1532   BLF_draw_default(1.5f * UI_UNIT_X, 1.5f * UI_UNIT_Y, 0.0f, info, sizeof(info));
1533 }
1534
1535 static void snode_setup_v2d(SpaceNode *snode, ARegion *ar, const float center[2])
1536 {
1537   View2D *v2d = &ar->v2d;
1538
1539   /* shift view to node tree center */
1540   UI_view2d_center_set(v2d, center[0], center[1]);
1541   UI_view2d_view_ortho(v2d);
1542
1543   /* aspect+font, set each time */
1544   snode->aspect = BLI_rctf_size_x(&v2d->cur) / (float)ar->winx;
1545   // XXX snode->curfont = uiSetCurFont_ext(snode->aspect);
1546 }
1547
1548 static void draw_nodetree(const bContext *C,
1549                           ARegion *ar,
1550                           bNodeTree *ntree,
1551                           bNodeInstanceKey parent_key)
1552 {
1553   SpaceNode *snode = CTX_wm_space_node(C);
1554
1555   node_uiblocks_init(C, ntree);
1556
1557   node_update_nodetree(C, ntree);
1558   node_draw_nodetree(C, ar, snode, ntree, parent_key);
1559 }
1560
1561 /* shade the parent node group and add a uiBlock to clip mouse events */
1562 static void draw_group_overlay(const bContext *C, ARegion *ar)
1563 {
1564   View2D *v2d = &ar->v2d;
1565   rctf rect = v2d->cur;
1566   uiBlock *block;
1567   float color[4];
1568
1569   /* shade node groups to separate them visually */
1570   GPU_blend(true);
1571
1572   UI_GetThemeColorShadeAlpha4fv(TH_NODE_GROUP, 0, 0, color);
1573   UI_draw_roundbox_corner_set(UI_CNR_NONE);
1574   UI_draw_roundbox_4fv(true, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 0, color);
1575   GPU_blend(false);
1576
1577   /* set the block bounds to clip mouse events from underlying nodes */
1578   block = UI_block_begin(C, ar, "node tree bounds block", UI_EMBOSS);
1579   UI_block_bounds_set_explicit(block, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1580   UI_block_flag_enable(block, UI_BLOCK_CLIP_EVENTS);
1581   UI_block_end(C, block);
1582 }
1583
1584 void drawnodespace(const bContext *C, ARegion *ar)
1585 {
1586   wmWindow *win = CTX_wm_window(C);
1587   View2DScrollers *scrollers;
1588   SpaceNode *snode = CTX_wm_space_node(C);
1589   View2D *v2d = &ar->v2d;
1590
1591   UI_ThemeClearColor(TH_BACK);
1592   GPU_clear(GPU_COLOR_BIT);
1593
1594   UI_view2d_view_ortho(v2d);
1595
1596   /* XXX snode->cursor set in coordspace for placing new nodes, used for drawing noodles too */
1597   UI_view2d_region_to_view(&ar->v2d,
1598                            win->eventstate->x - ar->winrct.xmin,
1599                            win->eventstate->y - ar->winrct.ymin,
1600                            &snode->cursor[0],
1601                            &snode->cursor[1]);
1602   snode->cursor[0] /= UI_DPI_FAC;
1603   snode->cursor[1] /= UI_DPI_FAC;
1604
1605   ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
1606
1607   /* only set once */
1608   GPU_blend_set_func_separate(
1609       GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
1610
1611   /* nodes */
1612   snode_set_context(C);
1613
1614   /* draw parent node trees */
1615   if (snode->treepath.last) {
1616     static const int max_depth = 2;
1617     bNodeTreePath *path;
1618     int depth, curdepth;
1619     float center[2];
1620     bNodeTree *ntree;
1621     bNodeLinkDrag *nldrag;
1622     LinkData *linkdata;
1623
1624     path = snode->treepath.last;
1625
1626     /* update tree path name (drawn in the bottom left) */
1627     ID *name_id = (path->nodetree && path->nodetree != snode->nodetree) ? &path->nodetree->id :
1628                                                                           snode->id;
1629
1630     if (name_id && UNLIKELY(!STREQ(path->node_name, name_id->name + 2))) {
1631       BLI_strncpy(path->node_name, name_id->name + 2, sizeof(path->node_name));
1632     }
1633
1634     /* current View2D center, will be set temporarily for parent node trees */
1635     UI_view2d_center_get(v2d, &center[0], &center[1]);
1636
1637     /* store new view center in path and current edittree */
1638     copy_v2_v2(path->view_center, center);
1639     if (snode->edittree) {
1640       copy_v2_v2(snode->edittree->view_center, center);
1641     }
1642
1643     depth = 0;
1644     while (path->prev && depth < max_depth) {
1645       path = path->prev;
1646       ++depth;
1647     }
1648
1649     /* parent node trees in the background */
1650     for (curdepth = depth; curdepth > 0; path = path->next, --curdepth) {
1651       ntree = path->nodetree;
1652       if (ntree) {
1653         snode_setup_v2d(snode, ar, path->view_center);
1654
1655         draw_nodetree(C, ar, ntree, path->parent_key);
1656
1657         draw_group_overlay(C, ar);
1658       }
1659     }
1660
1661     /* top-level edit tree */
1662     ntree = path->nodetree;
1663     if (ntree) {
1664       snode_setup_v2d(snode, ar, center);
1665
1666       /* grid, uses theme color based on node path depth */
1667       UI_view2d_multi_grid_draw(
1668           v2d, (depth > 0 ? TH_NODE_GROUP : TH_BACK), ED_node_grid_size(), NODE_GRID_STEPS, 2);
1669
1670       /* backdrop */
1671       draw_nodespace_back_pix(C, ar, snode, path->parent_key);
1672
1673       {
1674         float original_proj[4][4];
1675         GPU_matrix_projection_get(original_proj);
1676
1677         GPU_matrix_push();
1678         GPU_matrix_identity_set();
1679
1680         wmOrtho2_pixelspace(ar->winx, ar->winy);
1681
1682         WM_gizmomap_draw(ar->gizmo_map, C, WM_GIZMOMAP_DRAWSTEP_2D);
1683
1684         GPU_matrix_pop();
1685         GPU_matrix_projection_set(original_proj);
1686       }
1687
1688       draw_nodetree(C, ar, ntree, path->parent_key);
1689     }
1690
1691     /* temporary links */
1692     GPU_blend(true);
1693     GPU_line_smooth(true);
1694     for (nldrag = snode->linkdrag.first; nldrag; nldrag = nldrag->next) {
1695       for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) {
1696         node_draw_link(v2d, snode, (bNodeLink *)linkdata->data);
1697       }
1698     }
1699     GPU_line_smooth(false);
1700     GPU_blend(false);
1701
1702     if (snode->flag & SNODE_SHOW_GPENCIL) {
1703       /* draw grease-pencil ('canvas' strokes) */
1704       ED_annotation_draw_view2d(C, true);
1705     }
1706   }
1707   else {
1708     /* default grid */
1709     UI_view2d_multi_grid_draw(v2d, TH_BACK, ED_node_grid_size(), NODE_GRID_STEPS, 2);
1710
1711     /* backdrop */
1712     draw_nodespace_back_pix(C, ar, snode, NODE_INSTANCE_KEY_NONE);
1713   }
1714
1715   ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
1716
1717   /* reset view matrix */
1718   UI_view2d_view_restore(C);
1719
1720   if (snode->treepath.last) {
1721     if (snode->flag & SNODE_SHOW_GPENCIL) {
1722       /* draw grease-pencil (screen strokes, and also paintbuffer) */
1723       ED_annotation_draw_view2d(C, false);
1724     }
1725   }
1726
1727   /* tree path info */
1728   draw_tree_path(snode);
1729
1730   /* scrollers */
1731   scrollers = UI_view2d_scrollers_calc(v2d, NULL);
1732   UI_view2d_scrollers_draw(v2d, scrollers);
1733   UI_view2d_scrollers_free(scrollers);
1734 }