svn merge ^/trunk/blender -r47253:47272
[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  */
30
31
32 #include <math.h>
33 #include <stdio.h>
34 #include <string.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "DNA_node_types.h"
39 #include "DNA_lamp_types.h"
40 #include "DNA_material_types.h"
41 #include "DNA_object_types.h"
42 #include "DNA_scene_types.h"
43 #include "DNA_space_types.h"
44 #include "DNA_screen_types.h"
45 #include "DNA_world_types.h"
46
47 #include "BLI_math.h"
48 #include "BLI_blenlib.h"
49 #include "BLI_threads.h"
50 #include "BLI_utildefines.h"
51
52 #include "BLF_translation.h"
53
54 #include "BKE_context.h"
55 #include "BKE_depsgraph.h"
56 #include "BKE_main.h"
57 #include "BKE_node.h"
58
59 #include "BIF_gl.h"
60 #include "BIF_glutil.h"
61
62 #include "WM_api.h"
63 #include "WM_types.h"
64
65 #include "ED_node.h"
66 #include "ED_gpencil.h"
67
68 #include "UI_interface.h"
69 #include "UI_interface_icons.h"
70 #include "UI_resources.h"
71 #include "UI_view2d.h"
72
73 #include "RNA_access.h"
74
75 #include "NOD_composite.h"
76 #include "NOD_shader.h"
77
78 #include "intern/node_util.h"
79
80 #include "node_intern.h"
81
82 /* width of socket columns in group display */
83 #define NODE_GROUP_FRAME                120
84
85 // XXX interface.h
86 extern void ui_dropshadow(rctf *rct, float radius, float aspect, int select);
87
88 /* XXX update functions for node editor are a mess, needs a clear concept */
89 void ED_node_tree_update(SpaceNode *snode, Scene *scene)
90 {
91         snode_set_context(snode, scene);
92         
93         if (snode->nodetree && snode->nodetree->id.us==0)
94                 snode->nodetree->id.us= 1;
95 }
96
97 void ED_node_changed_update(ID *id, bNode *node)
98 {
99         bNodeTree *nodetree, *edittree;
100         int treetype;
101
102         node_tree_from_ID(id, &nodetree, &edittree, &treetype);
103
104         if (treetype==NTREE_SHADER) {
105                 DAG_id_tag_update(id, 0);
106
107                 if (GS(id->name) == ID_MA)
108                         WM_main_add_notifier(NC_MATERIAL|ND_SHADING_DRAW, id);
109                 else if (GS(id->name) == ID_LA)
110                         WM_main_add_notifier(NC_LAMP|ND_LIGHTING_DRAW, id);
111                 else if (GS(id->name) == ID_WO)
112                         WM_main_add_notifier(NC_WORLD|ND_WORLD_DRAW, id);
113         }
114         else if (treetype==NTREE_COMPOSIT) {
115                 if (node)
116                         nodeUpdate(edittree, node);
117                 /* don't use NodeTagIDChanged, it gives far too many recomposites for image, scene layers, ... */
118                         
119                 node= node_tree_get_editgroup(nodetree);
120                 if (node)
121                         nodeUpdateID(nodetree, node->id);
122
123                 WM_main_add_notifier(NC_SCENE|ND_NODES, id);
124         }                       
125         else if (treetype==NTREE_TEXTURE) {
126                 DAG_id_tag_update(id, 0);
127                 WM_main_add_notifier(NC_TEXTURE|ND_NODES, id);
128         }
129 }
130
131 static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup)
132 {
133         bNode *node;
134         
135         if (ntree == lookup)
136                 return 1;
137         
138         for (node=ntree->nodes.first; node; node=node->next)
139                 if (node->type == NODE_GROUP && node->id)
140                         if (has_nodetree((bNodeTree*)node->id, lookup))
141                                 return 1;
142         
143         return 0;
144 }
145
146 typedef struct NodeUpdateCalldata {
147         bNodeTree *ntree;
148         bNode *node;
149 } NodeUpdateCalldata;
150 static void node_generic_update_cb(void *calldata, ID *owner_id, bNodeTree *ntree)
151 {
152         NodeUpdateCalldata *cd= (NodeUpdateCalldata*)calldata;
153         /* check if nodetree uses the group stored in calldata */
154         if (has_nodetree(ntree, cd->ntree))
155                 ED_node_changed_update(owner_id, cd->node);
156 }
157 void ED_node_generic_update(Main *bmain, bNodeTree *ntree, bNode *node)
158 {
159         bNodeTreeType *tti= ntreeGetType(ntree->type);
160         NodeUpdateCalldata cd;
161         cd.ntree = ntree;
162         cd.node = node;
163         /* look through all datablocks, to support groups */
164         tti->foreach_nodetree(bmain, &cd, node_generic_update_cb);
165         
166         if (ntree->type == NTREE_TEXTURE)
167                 ntreeTexCheckCyclics(ntree);
168 }
169
170 static int compare_nodes(bNode *a, bNode *b)
171 {
172         bNode *parent;
173         /* These tell if either the node or any of the parent nodes is selected.
174          * A selected parent means an unselected node is also in foreground!
175          */
176         int a_select=(a->flag & NODE_SELECT), b_select=(b->flag & NODE_SELECT);
177         int a_active=(a->flag & NODE_ACTIVE), b_active=(b->flag & NODE_ACTIVE);
178         
179         /* if one is an ancestor of the other */
180         /* XXX there might be a better sorting algorithm for stable topological sort, this is O(n^2) worst case */
181         for (parent = a->parent; parent; parent=parent->parent) {
182                 /* if b is an ancestor, it is always behind a */
183                 if (parent==b)
184                         return 1;
185                 /* any selected ancestor moves the node forward */
186                 if (parent->flag & NODE_ACTIVE)
187                         a_active = 1;
188                 if (parent->flag & NODE_SELECT)
189                         a_select = 1;
190         }
191         for (parent = b->parent; parent; parent=parent->parent) {
192                 /* if a is an ancestor, it is always behind b */
193                 if (parent==a)
194                         return 0;
195                 /* any selected ancestor moves the node forward */
196                 if (parent->flag & NODE_ACTIVE)
197                         b_active = 1;
198                 if (parent->flag & NODE_SELECT)
199                         b_select = 1;
200         }
201
202         /* if one of the nodes is in the background and the other not */
203         if ((a->flag & NODE_BACKGROUND) && !(b->flag & NODE_BACKGROUND))
204                 return 0;
205         else if (!(a->flag & NODE_BACKGROUND) && (b->flag & NODE_BACKGROUND))
206                 return 1;
207         
208         /* if one has a higher selection state (active > selected > nothing) */
209         if (!b_active && a_active)
210                 return 1;
211         else if (!b_select && (a_active || a_select))
212                 return 1;
213         
214         return 0;
215 }
216
217 /* Sorts nodes by selection: unselected nodes first, then selected,
218  * then the active node at the very end. Relative order is kept intact!
219  */
220 void ED_node_sort(bNodeTree *ntree)
221 {
222         /* merge sort is the algorithm of choice here */
223         bNode *first_a, *first_b, *node_a, *node_b, *tmp;
224         int totnodes= BLI_countlist(&ntree->nodes);
225         int k, a, b;
226         
227         k = 1;
228         while (k < totnodes) {
229                 first_a = first_b = ntree->nodes.first;
230                 
231                 do {
232                         /* setup first_b pointer */
233                         for (b=0; b < k && first_b; ++b) {
234                                 first_b = first_b->next;
235                         }
236                         /* all batches merged? */
237                         if (first_b==NULL)
238                                 break;
239                         
240                         /* merge batches */
241                         node_a = first_a;
242                         node_b = first_b;
243                         a = b = 0;
244                         while (a < k && b < k && node_b) {
245                                 if (compare_nodes(node_a, node_b)==0) {
246                                         node_a = node_a->next;
247                                         ++a;
248                                 }
249                                 else {
250                                         tmp = node_b;
251                                         node_b = node_b->next;
252                                         ++b;
253                                         BLI_remlink(&ntree->nodes, tmp);
254                                         BLI_insertlinkbefore(&ntree->nodes, node_a, tmp);
255                                 }
256                         }
257
258                         /* setup first pointers for next batch */
259                         first_b = node_b;
260                         for (; b < k; ++b) {
261                                 /* all nodes sorted? */
262                                 if (first_b==NULL)
263                                         break;
264                                 first_b = first_b->next;
265                         }
266                         first_a = first_b;
267                 } while (first_b);
268                 
269                 k = k << 1;
270         }
271 }
272
273
274 static void do_node_internal_buttons(bContext *C, void *node_v, int event)
275 {
276         if (event==B_NODE_EXEC) {
277                 SpaceNode *snode= CTX_wm_space_node(C);
278                 if (snode && snode->id)
279                         ED_node_changed_update(snode->id, node_v);
280         }
281 }
282
283 static void node_uiblocks_init(const bContext *C, bNodeTree *ntree)
284 {
285         bNode *node;
286         char uiblockstr[32];
287         
288         /* add node uiBlocks in drawing order - prevents events going to overlapping nodes */
289         
290         for (node= ntree->nodes.first; node; node= node->next) {
291                 /* ui block */
292                 BLI_snprintf(uiblockstr, sizeof(uiblockstr), "node buttons %p", (void *)node);
293                 node->block= uiBeginBlock(C, CTX_wm_region(C), uiblockstr, UI_EMBOSS);
294                 uiBlockSetHandleFunc(node->block, do_node_internal_buttons, node);
295
296                 /* this cancels events for background nodes */
297                 uiBlockSetFlag(node->block, UI_BLOCK_CLIP_EVENTS);
298         }
299 }
300
301 /* based on settings in node, sets drawing rect info. each redraw! */
302 static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
303 {
304         uiLayout *layout;
305         PointerRNA ptr;
306         bNodeSocket *nsock;
307         float locx, locy;
308         float dy;
309         int buty;
310         
311         /* get "global" coords */
312         nodeToView(node, 0.0f, 0.0f, &locx, &locy);
313         dy= locy;
314         
315         /* header */
316         dy-= NODE_DY;
317         
318         /* little bit space in top */
319         if (node->outputs.first)
320                 dy-= NODE_DYS/2;
321
322         /* output sockets */
323         for (nsock= node->outputs.first; nsock; nsock= nsock->next) {
324                 if (!nodeSocketIsHidden(nsock)) {
325                         nsock->locx= locx + node->width;
326                         nsock->locy= dy - NODE_DYS;
327                         dy-= NODE_DY;
328                 }
329         }
330
331         node->prvr.xmin = locx + NODE_DYS;
332         node->prvr.xmax = locx + node->width- NODE_DYS;
333
334         /* preview rect? */
335         if (node->flag & NODE_PREVIEW) {
336                 /* only recalculate size when there's a preview actually, otherwise we use stored result */
337                 BLI_lock_thread(LOCK_PREVIEW);
338
339                 if (node->preview && node->preview->rect) {
340                         float aspect= 1.0f;
341                         
342                         if (node->preview && node->preview->xsize && node->preview->ysize) 
343                                 aspect= (float)node->preview->ysize/(float)node->preview->xsize;
344                         
345                         dy-= NODE_DYS/2;
346                         node->prvr.ymax = dy;
347                         
348                         if (aspect <= 1.0f)
349                                 node->prvr.ymin = dy - aspect*(node->width-NODE_DY);
350                         else {
351                                 float dx= (node->width - NODE_DYS) - (node->width- NODE_DYS)/aspect;    /* width correction of image */
352                                 
353                                 node->prvr.ymin = dy - (node->width-NODE_DY);
354                                 
355                                 node->prvr.xmin+= 0.5f*dx;
356                                 node->prvr.xmax-= 0.5f*dx;
357                         }
358
359                         dy= node->prvr.ymin - NODE_DYS/2;
360
361                         /* make sure that maximums are bigger or equal to minimums */
362                         if (node->prvr.xmax < node->prvr.xmin) SWAP(float, node->prvr.xmax, node->prvr.xmin);
363                         if (node->prvr.ymax < node->prvr.ymin) SWAP(float, node->prvr.ymax, node->prvr.ymin);
364                 }
365                 else {
366                         float oldh= node->prvr.ymax - node->prvr.ymin;
367                         if (oldh==0.0f)
368                                 oldh= 0.6f*node->width-NODE_DY;
369                         dy-= NODE_DYS/2;
370                         node->prvr.ymax = dy;
371                         node->prvr.ymin = dy - oldh;
372                         dy= node->prvr.ymin - NODE_DYS/2;
373                 }
374
375                 BLI_unlock_thread(LOCK_PREVIEW);
376         }
377
378         /* buttons rect? */
379         if ((node->flag & NODE_OPTIONS) && node->typeinfo->uifunc) {
380                 dy-= NODE_DYS/2;
381
382                 /* set this for uifunc() that don't use layout engine yet */
383                 node->butr.xmin = 0;
384                 node->butr.xmax = node->width - 2*NODE_DYS;
385                 node->butr.ymin = 0;
386                 node->butr.ymax = 0;
387                 
388                 RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr);
389                 
390                 layout= uiBlockLayout(node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL,
391                                                           locx+NODE_DYS, dy, node->butr.xmax, NODE_DY, UI_GetStyle());
392                 uiLayoutSetContextPointer(layout, "node", &ptr);
393                 
394                 node->typeinfo->uifunc(layout, (bContext *)C, &ptr);
395                 
396                 uiBlockEndAlign(node->block);
397                 uiBlockLayoutResolve(node->block, NULL, &buty);
398                 
399                 dy= buty - NODE_DYS/2;
400         }
401
402         /* input sockets */
403         for (nsock= node->inputs.first; nsock; nsock= nsock->next) {
404                 if (!nodeSocketIsHidden(nsock)) {
405                         nsock->locx= locx;
406                         nsock->locy= dy - NODE_DYS;
407                         dy-= NODE_DY;
408                 }
409         }
410         
411         /* little bit space in end */
412         if (node->inputs.first || (node->flag & (NODE_OPTIONS|NODE_PREVIEW))==0 )
413                 dy-= NODE_DYS/2;
414
415         node->totr.xmin = locx;
416         node->totr.xmax = locx + node->width;
417         node->totr.ymax = locy;
418         node->totr.ymin = MIN2(dy, locy-2*NODE_DY);
419         
420         /* Set the block bounds to clip mouse events from underlying nodes.
421          * Add a margin for sockets on each side.
422          */
423         uiExplicitBoundsBlock(node->block,
424                                                   node->totr.xmin - NODE_SOCKSIZE,
425                                                   node->totr.ymin,
426                                                   node->totr.xmax + NODE_SOCKSIZE,
427                                                   node->totr.ymax);
428 }
429
430 /* based on settings in node, sets drawing rect info. each redraw! */
431 static void node_update_hidden(bNode *node)
432 {
433         bNodeSocket *nsock;
434         float locx, locy;
435         float rad, drad, hiddenrad= HIDDEN_RAD;
436         int totin=0, totout=0, tot;
437         
438         /* get "global" coords */
439         nodeToView(node, 0.0f, 0.0f, &locx, &locy);
440
441         /* calculate minimal radius */
442         for (nsock= node->inputs.first; nsock; nsock= nsock->next)
443                 if (!nodeSocketIsHidden(nsock))
444                         totin++;
445         for (nsock= node->outputs.first; nsock; nsock= nsock->next)
446                 if (!nodeSocketIsHidden(nsock))
447                         totout++;
448         
449         tot= MAX2(totin, totout);
450         if (tot>4) {
451                 hiddenrad += 5.0f*(float)(tot-4);
452         }
453         
454         node->totr.xmin = locx;
455         node->totr.xmax = locx + 3*hiddenrad + node->miniwidth;
456         node->totr.ymax = locy + (hiddenrad - 0.5f*NODE_DY);
457         node->totr.ymin = node->totr.ymax - 2*hiddenrad;
458         
459         /* output sockets */
460         rad=drad= (float)M_PI/(1.0f + (float)totout);
461         
462         for (nsock= node->outputs.first; nsock; nsock= nsock->next) {
463                 if (!nodeSocketIsHidden(nsock)) {
464                         nsock->locx= node->totr.xmax - hiddenrad + (float)sin(rad)*hiddenrad;
465                         nsock->locy= node->totr.ymin + hiddenrad + (float)cos(rad)*hiddenrad;
466                         rad+= drad;
467                 }
468         }
469         
470         /* input sockets */
471         rad=drad= - (float)M_PI/(1.0f + (float)totin);
472         
473         for (nsock= node->inputs.first; nsock; nsock= nsock->next) {
474                 if (!nodeSocketIsHidden(nsock)) {
475                         nsock->locx= node->totr.xmin + hiddenrad + (float)sin(rad)*hiddenrad;
476                         nsock->locy= node->totr.ymin + hiddenrad + (float)cos(rad)*hiddenrad;
477                         rad+= drad;
478                 }
479         }
480
481         /* Set the block bounds to clip mouse events from underlying nodes.
482          * Add a margin for sockets on each side.
483          */
484         uiExplicitBoundsBlock(node->block,
485                                                   node->totr.xmin - NODE_SOCKSIZE,
486                                                   node->totr.ymin,
487                                                   node->totr.xmax + NODE_SOCKSIZE,
488                                                   node->totr.ymax);
489 }
490
491 void node_update_default(const bContext *C, bNodeTree *ntree, bNode *node)
492 {
493         if (node->flag & NODE_HIDDEN)
494                 node_update_hidden(node);
495         else
496                 node_update_basis(C, ntree, node);
497 }
498
499 int node_get_colorid(bNode *node)
500 {
501         if (node->typeinfo->nclass==NODE_CLASS_INPUT)
502                 return TH_NODE_IN_OUT;
503         if (node->typeinfo->nclass==NODE_CLASS_OUTPUT) {
504                 if (node->flag & NODE_DO_OUTPUT)
505                         return TH_NODE_IN_OUT;
506                 else
507                         return TH_NODE;
508         }
509         if (node->typeinfo->nclass==NODE_CLASS_CONVERTOR)
510                 return TH_NODE_CONVERTOR;
511         if (ELEM3(node->typeinfo->nclass, NODE_CLASS_OP_COLOR, NODE_CLASS_OP_VECTOR, NODE_CLASS_OP_FILTER))
512                 return TH_NODE_OPERATOR;
513         if (node->typeinfo->nclass==NODE_CLASS_GROUP)
514                 return TH_NODE_GROUP;
515         return TH_NODE;
516 }
517
518 /* note: in cmp_util.c is similar code, for node_compo_pass_on()
519  *       the same goes for shader and texture nodes. */
520 /* note: in node_edit.c is similar code, for untangle node */
521 static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node)
522 {
523         ListBase links;
524         bNodeLink *link;
525
526         if (node->typeinfo->internal_connect == NULL)
527                 return;
528
529         /* Get default muting links. */
530         links = node->typeinfo->internal_connect(snode->edittree, node);
531
532         glEnable(GL_BLEND);
533         glEnable(GL_LINE_SMOOTH);
534
535         for (link = links.first; link; link = link->next)
536                 node_draw_link_bezier(v2d, snode, link, TH_REDALERT, 0, TH_WIRE, 0, TH_WIRE);
537
538         glDisable(GL_BLEND);
539         glDisable(GL_LINE_SMOOTH);
540
541         BLI_freelistN(&links);
542 }
543
544 /* this might have some more generic use */
545 static void node_circle_draw(float x, float y, float size, char *col, int highlight)
546 {
547         /* 16 values of sin function */
548         static float si[16] = {
549                 0.00000000f, 0.39435585f, 0.72479278f, 0.93775213f,
550                 0.99871650f, 0.89780453f, 0.65137248f, 0.29936312f,
551                 -0.10116832f, -0.48530196f, -0.79077573f, -0.96807711f,
552                 -0.98846832f, -0.84864425f, -0.57126821f, -0.20129852f
553         };
554         /* 16 values of cos function */
555         static float co[16] ={
556                 1.00000000f, 0.91895781f, 0.68896691f, 0.34730525f,
557                 -0.05064916f, -0.44039415f, -0.75875812f, -0.95413925f,
558                 -0.99486932f, -0.87434661f, -0.61210598f, -0.25065253f,
559                 0.15142777f, 0.52896401f, 0.82076344f, 0.97952994f,
560         };
561         int a;
562         
563         glColor3ub(col[0], col[1], col[2]);
564         
565         glBegin(GL_POLYGON);
566         for (a=0; a<16; a++)
567                 glVertex2f(x+size*si[a], y+size*co[a]);
568         glEnd();
569         
570         if (highlight) {
571                 UI_ThemeColor(TH_TEXT_HI);
572                 glLineWidth(1.5f);
573         }
574         else {
575                 glColor4ub(0, 0, 0, 150);
576         }
577         glEnable(GL_BLEND);
578         glEnable(GL_LINE_SMOOTH);
579         glBegin(GL_LINE_LOOP);
580         for (a=0; a<16; a++)
581                 glVertex2f(x+size*si[a], y+size*co[a]);
582         glEnd();
583         glDisable(GL_LINE_SMOOTH);
584         glDisable(GL_BLEND);
585         glLineWidth(1.0f);
586 }
587
588 void node_socket_circle_draw(bNodeTree *UNUSED(ntree), bNodeSocket *sock, float size)
589 {
590         bNodeSocketType *stype = ntreeGetSocketType(sock->type);
591         node_circle_draw(sock->locx, sock->locy, size, stype->ui_color, (sock->flag & SELECT));
592 }
593
594 /* **************  Socket callbacks *********** */
595
596 /* not a callback */
597 static void node_draw_preview(bNodePreview *preview, rctf *prv)
598 {
599         float xscale= (prv->xmax-prv->xmin)/((float)preview->xsize);
600         float yscale= (prv->ymax-prv->ymin)/((float)preview->ysize);
601         float tile= (prv->xmax - prv->xmin) / 10.0f;
602         float x, y;
603         
604         /* draw checkerboard backdrop to show alpha */
605         glColor3ub(120, 120, 120);
606         glRectf(prv->xmin, prv->ymin, prv->xmax, prv->ymax);
607         glColor3ub(160, 160, 160);
608         
609         for (y=prv->ymin; y<prv->ymax; y+=tile*2) {
610                 for (x=prv->xmin; x<prv->xmax; x+=tile*2) {
611                         float tilex= tile, tiley= tile;
612
613                         if (x+tile > prv->xmax)
614                                 tilex= prv->xmax-x;
615                         if (y+tile > prv->ymax)
616                                 tiley= prv->ymax-y;
617
618                         glRectf(x, y, x + tilex, y + tiley);
619                 }
620         }
621         for (y=prv->ymin+tile; y<prv->ymax; y+=tile*2) {
622                 for (x=prv->xmin+tile; x<prv->xmax; x+=tile*2) {
623                         float tilex= tile, tiley= tile;
624
625                         if (x+tile > prv->xmax)
626                                 tilex= prv->xmax-x;
627                         if (y+tile > prv->ymax)
628                                 tiley= prv->ymax-y;
629
630                         glRectf(x, y, x + tilex, y + tiley);
631                 }
632         }
633         
634         glPixelZoom(xscale, yscale);
635
636         glEnable(GL_BLEND);
637         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  /* premul graphics */
638         
639         glColor4f(1.0, 1.0, 1.0, 1.0);
640         glaDrawPixelsTex(prv->xmin, prv->ymin, preview->xsize, preview->ysize, GL_UNSIGNED_BYTE, preview->rect);
641         
642         glDisable(GL_BLEND);
643         glPixelZoom(1.0f, 1.0f);
644
645         UI_ThemeColorShadeAlpha(TH_BACK, -15, +100);
646         fdrawbox(prv->xmin, prv->ymin, prv->xmax, prv->ymax);
647         
648 }
649
650 /* common handle function for operator buttons that need to select the node first */
651 static void node_toggle_button_cb(struct bContext *C, void *node_argv, void *op_argv)
652 {
653         bNode *node = (bNode*)node_argv;
654         const char *opname = (const char *)op_argv;
655         
656         /* select & activate only the button's node */
657         node_select_single(C, node);
658         
659         WM_operator_name_call(C, opname, WM_OP_INVOKE_DEFAULT, NULL);
660 }
661
662 void node_draw_shadow(SpaceNode *snode, bNode *node, float radius)
663 {
664         rctf *rct = &node->totr;
665         
666         uiSetRoundBox(UI_CNR_ALL);
667         if (node->parent==NULL)
668                 ui_dropshadow(rct, radius, snode->aspect, node->flag & SELECT);
669         else {
670                 const float margin = 3.0f;
671                 
672                 glColor4f(0.0f, 0.0f, 0.0f, 0.33f);
673                 glEnable(GL_BLEND);
674                 uiRoundBox(rct->xmin-margin, rct->ymin-margin,
675                            rct->xmax+margin, rct->ymax+margin, radius+margin);
676                 glDisable(GL_BLEND);
677         }
678 }
679
680 static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node)
681 {
682         bNodeSocket *sock;
683         rctf *rct= &node->totr;
684         float iconofs;
685         /* float socket_size= NODE_SOCKSIZE*U.dpi/72; */ /* UNUSED */
686         float iconbutw= 0.8f*UI_UNIT_X;
687         int color_id= node_get_colorid(node);
688         char showname[128]; /* 128 used below */
689         View2D *v2d = &ar->v2d;
690         
691         /* hurmf... another candidate for callback, have to see how this works first */
692         if (node->id && node->block && snode->treetype==NTREE_SHADER)
693                 nodeShaderSynchronizeID(node, 0);
694         
695         /* skip if out of view */
696         if (node->totr.xmax < ar->v2d.cur.xmin || node->totr.xmin > ar->v2d.cur.xmax ||
697                         node->totr.ymax < ar->v2d.cur.ymin || node->totr.ymin > ar->v2d.cur.ymax) {
698                 
699                 uiEndBlock(C, node->block);
700                 node->block= NULL;
701                 return;
702         }
703         
704         /* shadow */
705         node_draw_shadow(snode, node, BASIS_RAD);
706         
707         /* header */
708         if (color_id==TH_NODE)
709                 UI_ThemeColorShade(color_id, -20);
710         else
711                 UI_ThemeColor(color_id);
712         
713         if (node->flag & NODE_MUTED)
714                 UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);
715
716         uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
717         uiRoundBox(rct->xmin, rct->ymax-NODE_DY, rct->xmax, rct->ymax, BASIS_RAD);
718         
719         /* show/hide icons */
720         iconofs= rct->xmax - 7.0f;
721         
722         /* preview */
723         if (node->typeinfo->flag & NODE_PREVIEW) {
724                 uiBut *but;
725                 iconofs-=iconbutw;
726                 uiBlockSetEmboss(node->block, UI_EMBOSSN);
727                 but = uiDefIconBut(node->block, TOGBUT, B_REDR, ICON_MATERIAL,
728                                                    iconofs, rct->ymax-NODE_DY, iconbutw, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
729                 uiButSetFunc(but, node_toggle_button_cb, node, (void*)"NODE_OT_preview_toggle");
730                 /* XXX this does not work when node is activated and the operator called right afterwards,
731                  * since active ID is not updated yet (needs to process the notifier).
732                  * This can only work as visual indicator!
733                  */
734 //              if (!(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT)))
735 //                      uiButSetFlag(but, UI_BUT_DISABLED);
736                 uiBlockSetEmboss(node->block, UI_EMBOSS);
737         }
738         /* group edit */
739         if (node->type == NODE_GROUP) {
740                 uiBut *but;
741                 iconofs-=iconbutw;
742                 uiBlockSetEmboss(node->block, UI_EMBOSSN);
743                 but = uiDefIconBut(node->block, TOGBUT, B_REDR, ICON_NODETREE,
744                                                    iconofs, rct->ymax-NODE_DY, iconbutw, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
745                 uiButSetFunc(but, node_toggle_button_cb, node, (void*)"NODE_OT_group_edit");
746                 uiBlockSetEmboss(node->block, UI_EMBOSS);
747         }
748         
749         /* title */
750         if (node->flag & SELECT) 
751                 UI_ThemeColor(TH_SELECT);
752         else
753                 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
754         
755         /* open/close entirely? */
756         {
757                 uiBut *but;
758                 int but_size = UI_UNIT_X *0.6f;
759                 /* XXX button uses a custom triangle draw below, so make it invisible without icon */
760                 uiBlockSetEmboss(node->block, UI_EMBOSSN);
761                 but = uiDefBut(node->block, TOGBUT, B_REDR, "",
762                                            rct->xmin+10.0f-but_size/2, rct->ymax-NODE_DY/2.0f-but_size/2, but_size, but_size, NULL, 0, 0, 0, 0, "");
763                 uiButSetFunc(but, node_toggle_button_cb, node, (void*)"NODE_OT_hide_toggle");
764                 uiBlockSetEmboss(node->block, UI_EMBOSS);
765                 
766                 /* custom draw function for this button */
767                 UI_DrawTriIcon(rct->xmin+10.0f, rct->ymax-NODE_DY/2.0f, 'v');
768         }
769         
770         /* this isn't doing anything for the label, so commenting out */
771 #if 0
772         if (node->flag & SELECT) 
773                 UI_ThemeColor(TH_TEXT_HI);
774         else
775                 UI_ThemeColor(TH_TEXT);
776 #endif
777         
778         BLI_strncpy(showname, nodeLabel(node), sizeof(showname));
779         
780         //if (node->flag & NODE_MUTED)
781         //      BLI_snprintf(showname, sizeof(showname), "[%s]", showname); // XXX - don't print into self!
782         
783         uiDefBut(node->block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(rct->ymax-NODE_DY), 
784                          (int)(iconofs - rct->xmin-18.0f), NODE_DY,  NULL, 0, 0, 0, 0, "");
785
786         /* body */
787         if (node->flag & NODE_CUSTOM_COLOR)
788                 glColor3fv(node->color);
789         else
790                 UI_ThemeColor4(TH_NODE);
791         glEnable(GL_BLEND);
792         uiSetRoundBox(UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT);
793         uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax-NODE_DY, BASIS_RAD);
794         glDisable(GL_BLEND);
795
796         /* outline active and selected emphasis */
797         if ( node->flag & (NODE_ACTIVE|SELECT) ) {
798                 glEnable(GL_BLEND);
799                 glEnable(GL_LINE_SMOOTH);
800                 
801                 if (node->flag & NODE_ACTIVE)
802                         UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40);
803                 else
804                         UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40);
805                 uiSetRoundBox(UI_CNR_ALL);
806                 uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
807                 
808                 glDisable(GL_LINE_SMOOTH);
809                 glDisable(GL_BLEND);
810         }
811         
812         /* disable lines */
813         if (node->flag & NODE_MUTED)
814                 node_draw_mute_line(v2d, snode, node);
815
816         
817         /* socket inputs, buttons */
818         for (sock= node->inputs.first; sock; sock= sock->next) {
819                 if (nodeSocketIsHidden(sock))
820                         continue;
821                 
822                 node_socket_circle_draw(ntree, sock, NODE_SOCKSIZE);
823                 
824                 node->typeinfo->drawinputfunc(C, node->block, ntree, node, sock, IFACE_(sock->name),
825                                               sock->locx+NODE_DYS, sock->locy-NODE_DYS, node->width-NODE_DY);
826         }
827         
828         /* socket outputs */
829         for (sock= node->outputs.first; sock; sock= sock->next) {
830                 if (nodeSocketIsHidden(sock))
831                         continue;
832                 
833                 node_socket_circle_draw(ntree, sock, NODE_SOCKSIZE);
834                 
835                 node->typeinfo->drawoutputfunc(C, node->block, ntree, node, sock, IFACE_(sock->name),
836                                                sock->locx-node->width+NODE_DYS, sock->locy-NODE_DYS, node->width-NODE_DY);
837         }
838         
839         /* preview */
840         if (node->flag & NODE_PREVIEW) {
841                 BLI_lock_thread(LOCK_PREVIEW);
842                 if (node->preview && node->preview->rect && !BLI_rctf_is_empty(&node->prvr))
843                         node_draw_preview(node->preview, &node->prvr);
844                 BLI_unlock_thread(LOCK_PREVIEW);
845         }
846         
847         UI_ThemeClearColor(color_id);
848                 
849         uiEndBlock(C, node->block);
850         uiDrawBlock(C, node->block);
851         node->block= NULL;
852 }
853
854 static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, bNode *node)
855 {
856         bNodeSocket *sock;
857         rctf *rct= &node->totr;
858         float dx, centy= 0.5f*(rct->ymax+rct->ymin);
859         float hiddenrad= 0.5f*(rct->ymax-rct->ymin);
860         float socket_size= NODE_SOCKSIZE*U.dpi/72;
861         int color_id= node_get_colorid(node);
862         char showname[128];     /* 128 is used below */
863         
864         /* shadow */
865         node_draw_shadow(snode, node, hiddenrad);
866
867         /* body */
868         UI_ThemeColor(color_id);
869         if (node->flag & NODE_MUTED)
870                 UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);
871         uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
872         
873         /* outline active and selected emphasis */
874         if ( node->flag & (NODE_ACTIVE|SELECT) ) {
875                 glEnable(GL_BLEND);
876                 glEnable(GL_LINE_SMOOTH);
877                 
878                 if (node->flag & NODE_ACTIVE)
879                         UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40);
880                 else
881                         UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40);
882                 uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
883                 
884                 glDisable(GL_LINE_SMOOTH);
885                 glDisable(GL_BLEND);
886         }
887         
888         /* title */
889         if (node->flag & SELECT) 
890                 UI_ThemeColor(TH_SELECT);
891         else
892                 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
893         
894         /* open entirely icon */
895         {
896                 uiBut *but;
897                 int but_size = UI_UNIT_X *0.6f;
898                 /* XXX button uses a custom triangle draw below, so make it invisible without icon */
899                 uiBlockSetEmboss(node->block, UI_EMBOSSN);
900                 but = uiDefBut(node->block, TOGBUT, B_REDR, "",
901                                            rct->xmin+10.0f-but_size/2, centy-but_size/2, but_size, but_size, NULL, 0, 0, 0, 0, "");
902                 uiButSetFunc(but, node_toggle_button_cb, node, (void*)"NODE_OT_hide_toggle");
903                 uiBlockSetEmboss(node->block, UI_EMBOSS);
904                 
905                 /* custom draw function for this button */
906                 UI_DrawTriIcon(rct->xmin+10.0f, centy, 'h');
907         }
908         
909         /* disable lines */
910         if (node->flag & NODE_MUTED)
911                 node_draw_mute_line(&ar->v2d, snode, node);     
912         
913         if (node->flag & SELECT) 
914                 UI_ThemeColor(TH_SELECT);
915         else
916                 UI_ThemeColor(TH_TEXT);
917         
918         if (node->miniwidth>0.0f) {
919                 BLI_strncpy(showname, nodeLabel(node), sizeof(showname));
920                 
921                 //if (node->flag & NODE_MUTED)
922                 //      BLI_snprintf(showname, sizeof(showname), "[%s]", showname); // XXX - don't print into self!
923
924                 uiDefBut(node->block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(centy-10), 
925                                  (int)(rct->xmax - rct->xmin-18.0f -12.0f), NODE_DY,  NULL, 0, 0, 0, 0, "");
926         }       
927
928         /* scale widget thing */
929         UI_ThemeColorShade(color_id, -10);      
930         dx= 10.0f;
931         fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
932         fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
933         
934         UI_ThemeColorShade(color_id, +30);
935         dx-= snode->aspect;
936         fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
937         fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
938         
939         /* sockets */
940         for (sock= node->inputs.first; sock; sock= sock->next) {
941                 if (!nodeSocketIsHidden(sock))
942                         node_socket_circle_draw(snode->nodetree, sock, socket_size);
943         }
944         
945         for (sock= node->outputs.first; sock; sock= sock->next) {
946                 if (!nodeSocketIsHidden(sock))
947                         node_socket_circle_draw(snode->nodetree, sock, socket_size);
948         }
949         
950         uiEndBlock(C, node->block);
951         uiDrawBlock(C, node->block);
952         node->block= NULL;
953 }
954
955 int node_get_resize_cursor(int directions)
956 {
957         if (directions==0)
958                 return CURSOR_STD;
959         else if ((directions & ~(NODE_RESIZE_TOP|NODE_RESIZE_BOTTOM))==0)
960                 return CURSOR_Y_MOVE;
961         else if ((directions & ~(NODE_RESIZE_RIGHT|NODE_RESIZE_LEFT))==0)
962                 return CURSOR_X_MOVE;
963         else
964                 return CURSOR_EDIT;
965 }
966
967 void node_set_cursor(wmWindow *win, SpaceNode *snode)
968 {
969         bNodeTree *ntree = snode->edittree;
970         bNode *node;
971         bNodeSocket *sock;
972         int cursor = CURSOR_STD;
973         
974         if (ntree) {
975                 if (node_find_indicated_socket(snode, &node, &sock, SOCK_IN|SOCK_OUT)) {
976                         /* pass */
977                 }
978                 else {
979                         /* check nodes front to back */
980                         for (node=ntree->nodes.last; node; node=node->prev) {
981                                 if (BLI_in_rctf(&node->totr, snode->mx, snode->my))
982                                         break;  /* first hit on node stops */
983                         }
984                         if (node) {
985                                 int dir = node->typeinfo->resize_area_func(node, snode->mx, snode->my);
986                                 cursor = node_get_resize_cursor(dir);
987                         }
988                 }
989         }
990         
991         WM_cursor_set(win, cursor);
992 }
993
994 void node_draw_default(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node)
995 {
996         if (node->flag & NODE_HIDDEN)
997                 node_draw_hidden(C, ar, snode, node);
998         else
999                 node_draw_basis(C, ar, snode, ntree, node);
1000 }
1001
1002 static void node_update(const bContext *C, bNodeTree *ntree, bNode *node)
1003 {
1004         if (node->typeinfo->drawupdatefunc)
1005                 node->typeinfo->drawupdatefunc(C, ntree, node);
1006 }
1007
1008 void node_update_nodetree(const bContext *C, bNodeTree *ntree, float offsetx, float offsety)
1009 {
1010         bNode *node;
1011         
1012         /* update nodes front to back, so children sizes get updated before parents */
1013         for (node= ntree->nodes.last; node; node= node->prev) {
1014                 /* XXX little hack */
1015                 node->locx += offsetx;
1016                 node->locy += offsety;
1017                 
1018                 node_update(C, ntree, node);
1019                 
1020                 node->locx -= offsetx;
1021                 node->locy -= offsety;
1022         }
1023 }
1024
1025 static void node_draw(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node)
1026 {
1027         if (node->typeinfo->drawfunc)
1028                 node->typeinfo->drawfunc(C, ar, snode, ntree, node);
1029 }
1030
1031 void node_draw_nodetree(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree)
1032 {
1033         bNode *node;
1034         bNodeLink *link;
1035         int a;
1036         
1037         if (ntree==NULL) return;                /* groups... */
1038         
1039         /* draw background nodes, last nodes in front */
1040         for (a=0, node= ntree->nodes.first; node; node=node->next, a++) {
1041                 if (!(node->flag & NODE_BACKGROUND))
1042                         continue;
1043                 node->nr= a;            /* index of node in list, used for exec event code */
1044                 node_draw(C, ar, snode, ntree, node);
1045         }
1046         
1047         /* node lines */
1048         glEnable(GL_BLEND);
1049         glEnable(GL_LINE_SMOOTH);
1050         for (link= ntree->links.first; link; link= link->next)
1051                 node_draw_link(&ar->v2d, snode, link);
1052         glDisable(GL_LINE_SMOOTH);
1053         glDisable(GL_BLEND);
1054         
1055         /* draw foreground nodes, last nodes in front */
1056         for (a=0, node= ntree->nodes.first; node; node=node->next, a++) {
1057                 if (node->flag & NODE_BACKGROUND)
1058                         continue;
1059                 node->nr= a;            /* index of node in list, used for exec event code */
1060                 node_draw(C, ar, snode, ntree, node);
1061         }
1062 }
1063
1064 void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d)
1065 {
1066         View2DScrollers *scrollers;
1067         SpaceNode *snode= CTX_wm_space_node(C);
1068         Scene *scene= CTX_data_scene(C);
1069         int color_manage = scene->r.color_mgt_flag & R_COLOR_MANAGEMENT;
1070         bNodeLinkDrag *nldrag;
1071         LinkData *linkdata;
1072         
1073         UI_ThemeClearColor(TH_BACK);
1074         glClear(GL_COLOR_BUFFER_BIT);
1075
1076         UI_view2d_view_ortho(v2d);
1077         
1078         //uiFreeBlocksWin(&sa->uiblocks, sa->win);
1079
1080         /* only set once */
1081         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1082         glEnable(GL_MAP1_VERTEX_3);
1083
1084         /* aspect+font, set each time */
1085         snode->aspect= (v2d->cur.xmax - v2d->cur.xmin)/((float)ar->winx);
1086         // XXX snode->curfont= uiSetCurFont_ext(snode->aspect);
1087
1088         UI_view2d_constant_grid_draw(v2d);
1089         /* backdrop */
1090         draw_nodespace_back_pix(ar, snode, color_manage);
1091         
1092         /* nodes */
1093         snode_set_context(snode, CTX_data_scene(C));
1094         
1095         if (snode->nodetree) {
1096                 bNode *node;
1097                 
1098                 node_uiblocks_init(C, snode->nodetree);
1099                 
1100                 /* uiBlocks must be initialized in drawing order for correct event clipping.
1101                  * Node group internal blocks added after the main group block.
1102                  */
1103                 for (node= snode->nodetree->nodes.first; node; node= node->next) {
1104                         if (node->flag & NODE_GROUP_EDIT)
1105                                 node_uiblocks_init(C, (bNodeTree *)node->id);
1106                 }
1107                 
1108                 node_update_nodetree(C, snode->nodetree, 0.0f, 0.0f);
1109                 node_draw_nodetree(C, ar, snode, snode->nodetree);
1110                 
1111                 #if 0
1112                 /* active group */
1113                 for (node= snode->nodetree->nodes.first; node; node= node->next) {
1114                         if (node->flag & NODE_GROUP_EDIT)
1115                                 node_draw_group(C, ar, snode, snode->nodetree, node);
1116                 }
1117                 #endif
1118         }
1119         
1120         /* temporary links */
1121         glEnable(GL_BLEND);
1122         glEnable(GL_LINE_SMOOTH);
1123         for (nldrag= snode->linkdrag.first; nldrag; nldrag= nldrag->next) {
1124                 for (linkdata=nldrag->links.first; linkdata; linkdata=linkdata->next)
1125                         node_draw_link(&ar->v2d, snode, (bNodeLink *)linkdata->data);
1126         }
1127         glDisable(GL_LINE_SMOOTH);
1128         glDisable(GL_BLEND);
1129         
1130         /* draw grease-pencil ('canvas' strokes) */
1131         if (/*(snode->flag & SNODE_DISPGP) &&*/ (snode->nodetree))
1132                 draw_gpencil_view2d((bContext*)C, 1);
1133         
1134         /* reset view matrix */
1135         UI_view2d_view_restore(C);
1136         
1137         /* draw grease-pencil (screen strokes, and also paintbuffer) */
1138         if (/*(snode->flag & SNODE_DISPGP) && */(snode->nodetree))
1139                 draw_gpencil_view2d((bContext*)C, 0);
1140         
1141         /* scrollers */
1142         scrollers= UI_view2d_scrollers_calc(C, v2d, 10, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
1143         UI_view2d_scrollers_draw(C, v2d, scrollers);
1144         UI_view2d_scrollers_free(scrollers);
1145 }