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