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