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