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