Merging r48407 through r48409 from trunk into soc-2011-tomato
[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_rect.h"
50 #include "BLI_threads.h"
51 #include "BLI_utildefines.h"
52
53 #include "BLF_translation.h"
54
55 #include "BKE_context.h"
56 #include "BKE_depsgraph.h"
57 #include "BKE_main.h"
58 #include "BKE_node.h"
59
60 #include "BIF_gl.h"
61 #include "BIF_glutil.h"
62
63 #include "WM_api.h"
64 #include "WM_types.h"
65
66 #include "ED_node.h"
67 #include "ED_gpencil.h"
68
69 #include "UI_interface.h"
70 #include "UI_interface_icons.h"
71 #include "UI_resources.h"
72 #include "UI_view2d.h"
73
74 #include "RNA_access.h"
75
76 #include "NOD_composite.h"
77 #include "NOD_shader.h"
78
79 #include "intern/node_util.h"
80
81 #include "node_intern.h"
82
83 /* width of socket columns in group display */
84 #define NODE_GROUP_FRAME                120
85 // XXX interface.h
86 extern void ui_dropshadow(rctf *rct, float radius, float aspect, float alpha, 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_select_area_default(bNode *node, int x, int y)
500 {
501         return BLI_in_rctf(&node->totr, x, y);
502 }
503
504 int node_tweak_area_default(bNode *node, int x, int y)
505 {
506         return BLI_in_rctf(&node->totr, x, y);
507 }
508
509 int node_get_colorid(bNode *node)
510 {
511         if (node->typeinfo->nclass==NODE_CLASS_INPUT)
512                 return TH_NODE_IN_OUT;
513         if (node->typeinfo->nclass==NODE_CLASS_OUTPUT) {
514                 if (node->flag & NODE_DO_OUTPUT)
515                         return TH_NODE_IN_OUT;
516                 else
517                         return TH_NODE;
518         }
519         if (node->typeinfo->nclass==NODE_CLASS_CONVERTOR)
520                 return TH_NODE_CONVERTOR;
521         if (ELEM3(node->typeinfo->nclass, NODE_CLASS_OP_COLOR, NODE_CLASS_OP_VECTOR, NODE_CLASS_OP_FILTER))
522                 return TH_NODE_OPERATOR;
523         if (node->typeinfo->nclass==NODE_CLASS_GROUP)
524                 return TH_NODE_GROUP;
525         return TH_NODE;
526 }
527
528 /* note: in cmp_util.c is similar code, for node_compo_pass_on()
529  *       the same goes for shader and texture nodes. */
530 /* note: in node_edit.c is similar code, for untangle node */
531 static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node)
532 {
533         ListBase links;
534         bNodeLink *link;
535
536         if (node->typeinfo->internal_connect == NULL)
537                 return;
538
539         /* Get default muting links. */
540         links = node->typeinfo->internal_connect(snode->edittree, node);
541
542         glEnable(GL_BLEND);
543         glEnable(GL_LINE_SMOOTH);
544
545         for (link = links.first; link; link = link->next)
546                 node_draw_link_bezier(v2d, snode, link, TH_REDALERT, 0, TH_WIRE, 0, TH_WIRE);
547
548         glDisable(GL_BLEND);
549         glDisable(GL_LINE_SMOOTH);
550
551         BLI_freelistN(&links);
552 }
553
554 /* this might have some more generic use */
555 static void node_circle_draw(float x, float y, float size, char *col, int highlight)
556 {
557         /* 16 values of sin function */
558         static float si[16] = {
559                 0.00000000f, 0.39435585f, 0.72479278f, 0.93775213f,
560                 0.99871650f, 0.89780453f, 0.65137248f, 0.29936312f,
561                 -0.10116832f, -0.48530196f, -0.79077573f, -0.96807711f,
562                 -0.98846832f, -0.84864425f, -0.57126821f, -0.20129852f
563         };
564         /* 16 values of cos function */
565         static float co[16] ={
566                 1.00000000f, 0.91895781f, 0.68896691f, 0.34730525f,
567                 -0.05064916f, -0.44039415f, -0.75875812f, -0.95413925f,
568                 -0.99486932f, -0.87434661f, -0.61210598f, -0.25065253f,
569                 0.15142777f, 0.52896401f, 0.82076344f, 0.97952994f,
570         };
571         int a;
572         
573         glColor3ub(col[0], col[1], col[2]);
574         
575         glBegin(GL_POLYGON);
576         for (a=0; a<16; a++)
577                 glVertex2f(x+size*si[a], y+size*co[a]);
578         glEnd();
579         
580         if (highlight) {
581                 UI_ThemeColor(TH_TEXT_HI);
582                 glLineWidth(1.5f);
583         }
584         else {
585                 glColor4ub(0, 0, 0, 150);
586         }
587         glEnable(GL_BLEND);
588         glEnable(GL_LINE_SMOOTH);
589         glBegin(GL_LINE_LOOP);
590         for (a=0; a<16; a++)
591                 glVertex2f(x+size*si[a], y+size*co[a]);
592         glEnd();
593         glDisable(GL_LINE_SMOOTH);
594         glDisable(GL_BLEND);
595         glLineWidth(1.0f);
596 }
597
598 void node_socket_circle_draw(bNodeTree *UNUSED(ntree), bNodeSocket *sock, float size, int highlight)
599 {
600         bNodeSocketType *stype = ntreeGetSocketType(sock->type);
601         node_circle_draw(sock->locx, sock->locy, size, stype->ui_color, highlight);
602 }
603
604 /* **************  Socket callbacks *********** */
605
606 /* not a callback */
607 static void node_draw_preview(bNodePreview *preview, rctf *prv)
608 {
609         float xscale= (prv->xmax-prv->xmin)/((float)preview->xsize);
610         float yscale= (prv->ymax-prv->ymin)/((float)preview->ysize);
611         float tile= (prv->xmax - prv->xmin) / 10.0f;
612         float x, y;
613         
614         /* draw checkerboard backdrop to show alpha */
615         glColor3ub(120, 120, 120);
616         glRectf(prv->xmin, prv->ymin, prv->xmax, prv->ymax);
617         glColor3ub(160, 160, 160);
618         
619         for (y=prv->ymin; y<prv->ymax; y+=tile*2) {
620                 for (x=prv->xmin; x<prv->xmax; x+=tile*2) {
621                         float tilex= tile, tiley= tile;
622
623                         if (x+tile > prv->xmax)
624                                 tilex= prv->xmax-x;
625                         if (y+tile > prv->ymax)
626                                 tiley= prv->ymax-y;
627
628                         glRectf(x, y, x + tilex, y + tiley);
629                 }
630         }
631         for (y=prv->ymin+tile; y<prv->ymax; y+=tile*2) {
632                 for (x=prv->xmin+tile; x<prv->xmax; x+=tile*2) {
633                         float tilex= tile, tiley= tile;
634
635                         if (x+tile > prv->xmax)
636                                 tilex= prv->xmax-x;
637                         if (y+tile > prv->ymax)
638                                 tiley= prv->ymax-y;
639
640                         glRectf(x, y, x + tilex, y + tiley);
641                 }
642         }
643         
644         glPixelZoom(xscale, yscale);
645
646         glEnable(GL_BLEND);
647         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  /* premul graphics */
648         
649         glColor4f(1.0, 1.0, 1.0, 1.0);
650         glaDrawPixelsTex(prv->xmin, prv->ymin, preview->xsize, preview->ysize, GL_UNSIGNED_BYTE, preview->rect);
651         
652         glDisable(GL_BLEND);
653         glPixelZoom(1.0f, 1.0f);
654
655         UI_ThemeColorShadeAlpha(TH_BACK, -15, +100);
656         fdrawbox(prv->xmin, prv->ymin, prv->xmax, prv->ymax);
657         
658 }
659
660 /* common handle function for operator buttons that need to select the node first */
661 static void node_toggle_button_cb(struct bContext *C, void *node_argv, void *op_argv)
662 {
663         bNode *node = (bNode*)node_argv;
664         const char *opname = (const char *)op_argv;
665         
666         /* select & activate only the button's node */
667         node_select_single(C, node);
668         
669         WM_operator_name_call(C, opname, WM_OP_INVOKE_DEFAULT, NULL);
670 }
671
672 void node_draw_shadow(SpaceNode *snode, bNode *node, float radius, float alpha)
673 {
674         rctf *rct = &node->totr;
675         
676         uiSetRoundBox(UI_CNR_ALL);
677         if (node->parent==NULL)
678                 ui_dropshadow(rct, radius, snode->aspect, alpha, node->flag & SELECT);
679         else {
680                 const float margin = 3.0f;
681                 
682                 glColor4f(0.0f, 0.0f, 0.0f, 0.33f);
683                 glEnable(GL_BLEND);
684                 uiRoundBox(rct->xmin-margin, rct->ymin-margin,
685                            rct->xmax+margin, rct->ymax+margin, radius+margin);
686                 glDisable(GL_BLEND);
687         }
688 }
689
690 static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node)
691 {
692         bNodeSocket *sock;
693         rctf *rct= &node->totr;
694         float iconofs;
695         /* float socket_size= NODE_SOCKSIZE*U.dpi/72; */ /* UNUSED */
696         float iconbutw= 0.8f*UI_UNIT_X;
697         int color_id= node_get_colorid(node);
698         char showname[128]; /* 128 used below */
699         View2D *v2d = &ar->v2d;
700         
701         /* hurmf... another candidate for callback, have to see how this works first */
702         if (node->id && node->block && snode->treetype==NTREE_SHADER)
703                 nodeShaderSynchronizeID(node, 0);
704         
705         /* skip if out of view */
706         if (node->totr.xmax < ar->v2d.cur.xmin || node->totr.xmin > ar->v2d.cur.xmax ||
707                         node->totr.ymax < ar->v2d.cur.ymin || node->totr.ymin > ar->v2d.cur.ymax) {
708                 
709                 uiEndBlock(C, node->block);
710                 node->block= NULL;
711                 return;
712         }
713         
714         /* shadow */
715         node_draw_shadow(snode, node, BASIS_RAD, 1.0f);
716         
717         /* header */
718         if (color_id==TH_NODE)
719                 UI_ThemeColorShade(color_id, -20);
720         else
721                 UI_ThemeColor(color_id);
722         
723         if (node->flag & NODE_MUTED)
724                 UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);
725
726         uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
727         uiRoundBox(rct->xmin, rct->ymax-NODE_DY, rct->xmax, rct->ymax, BASIS_RAD);
728         
729         /* show/hide icons */
730         iconofs= rct->xmax - 7.0f;
731         
732         /* preview */
733         if (node->typeinfo->flag & NODE_PREVIEW) {
734                 uiBut *but;
735                 iconofs-=iconbutw;
736                 uiBlockSetEmboss(node->block, UI_EMBOSSN);
737                 but = uiDefIconBut(node->block, TOGBUT, B_REDR, ICON_MATERIAL,
738                                                    iconofs, rct->ymax-NODE_DY, iconbutw, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
739                 uiButSetFunc(but, node_toggle_button_cb, node, (void*)"NODE_OT_preview_toggle");
740                 /* XXX this does not work when node is activated and the operator called right afterwards,
741                  * since active ID is not updated yet (needs to process the notifier).
742                  * This can only work as visual indicator!
743                  */
744 //              if (!(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT)))
745 //                      uiButSetFlag(but, UI_BUT_DISABLED);
746                 uiBlockSetEmboss(node->block, UI_EMBOSS);
747         }
748         /* group edit */
749         if (node->type == NODE_GROUP) {
750                 uiBut *but;
751                 iconofs-=iconbutw;
752                 uiBlockSetEmboss(node->block, UI_EMBOSSN);
753                 but = uiDefIconBut(node->block, TOGBUT, B_REDR, ICON_NODETREE,
754                                                    iconofs, rct->ymax-NODE_DY, iconbutw, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
755                 uiButSetFunc(but, node_toggle_button_cb, node, (void*)"NODE_OT_group_edit");
756                 uiBlockSetEmboss(node->block, UI_EMBOSS);
757         }
758         
759         /* title */
760         if (node->flag & SELECT) 
761                 UI_ThemeColor(TH_SELECT);
762         else
763                 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
764         
765         /* open/close entirely? */
766         {
767                 uiBut *but;
768                 int but_size = UI_UNIT_X *0.6f;
769                 /* XXX button uses a custom triangle draw below, so make it invisible without icon */
770                 uiBlockSetEmboss(node->block, UI_EMBOSSN);
771                 but = uiDefBut(node->block, TOGBUT, B_REDR, "",
772                                            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, "");
773                 uiButSetFunc(but, node_toggle_button_cb, node, (void*)"NODE_OT_hide_toggle");
774                 uiBlockSetEmboss(node->block, UI_EMBOSS);
775                 
776                 /* custom draw function for this button */
777                 UI_DrawTriIcon(rct->xmin+10.0f, rct->ymax-NODE_DY/2.0f, 'v');
778         }
779         
780         /* this isn't doing anything for the label, so commenting out */
781 #if 0
782         if (node->flag & SELECT) 
783                 UI_ThemeColor(TH_TEXT_HI);
784         else
785                 UI_ThemeColor(TH_TEXT);
786 #endif
787         
788         BLI_strncpy(showname, nodeLabel(node), sizeof(showname));
789         
790         //if (node->flag & NODE_MUTED)
791         //      BLI_snprintf(showname, sizeof(showname), "[%s]", showname); // XXX - don't print into self!
792         
793         uiDefBut(node->block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(rct->ymax-NODE_DY), 
794                          (int)(iconofs - rct->xmin-18.0f), NODE_DY,  NULL, 0, 0, 0, 0, "");
795
796         /* body */
797         if (node->flag & NODE_CUSTOM_COLOR)
798                 glColor3fv(node->color);
799         else
800                 UI_ThemeColor4(TH_NODE);
801         glEnable(GL_BLEND);
802         uiSetRoundBox(UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT);
803         uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax-NODE_DY, BASIS_RAD);
804         glDisable(GL_BLEND);
805
806         /* outline active and selected emphasis */
807         if ( node->flag & (NODE_ACTIVE|SELECT) ) {
808                 glEnable(GL_BLEND);
809                 glEnable(GL_LINE_SMOOTH);
810                 
811                 if (node->flag & NODE_ACTIVE)
812                         UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40);
813                 else
814                         UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40);
815                 uiSetRoundBox(UI_CNR_ALL);
816                 uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
817                 
818                 glDisable(GL_LINE_SMOOTH);
819                 glDisable(GL_BLEND);
820         }
821         
822         /* disable lines */
823         if (node->flag & NODE_MUTED)
824                 node_draw_mute_line(v2d, snode, node);
825
826         
827         /* socket inputs, buttons */
828         for (sock= node->inputs.first; sock; sock= sock->next) {
829                 if (nodeSocketIsHidden(sock))
830                         continue;
831                 
832                 node_socket_circle_draw(ntree, sock, NODE_SOCKSIZE, sock->flag & SELECT);
833                 
834                 node->typeinfo->drawinputfunc(C, node->block, ntree, node, sock, IFACE_(sock->name),
835                                               sock->locx+NODE_DYS, sock->locy-NODE_DYS, node->width-NODE_DY);
836         }
837         
838         /* socket outputs */
839         for (sock= node->outputs.first; sock; sock= sock->next) {
840                 if (nodeSocketIsHidden(sock))
841                         continue;
842                 
843                 node_socket_circle_draw(ntree, sock, NODE_SOCKSIZE, sock->flag & SELECT);
844                 
845                 node->typeinfo->drawoutputfunc(C, node->block, ntree, node, sock, IFACE_(sock->name),
846                                                sock->locx-node->width+NODE_DYS, sock->locy-NODE_DYS, node->width-NODE_DY);
847         }
848         
849         /* preview */
850         if (node->flag & NODE_PREVIEW) {
851                 BLI_lock_thread(LOCK_PREVIEW);
852                 if (node->preview && node->preview->rect && !BLI_rctf_is_empty(&node->prvr))
853                         node_draw_preview(node->preview, &node->prvr);
854                 BLI_unlock_thread(LOCK_PREVIEW);
855         }
856         
857         UI_ThemeClearColor(color_id);
858                 
859         uiEndBlock(C, node->block);
860         uiDrawBlock(C, node->block);
861         node->block= NULL;
862 }
863
864 static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, bNode *node)
865 {
866         bNodeSocket *sock;
867         rctf *rct= &node->totr;
868         float dx, centy= 0.5f*(rct->ymax+rct->ymin);
869         float hiddenrad= 0.5f*(rct->ymax-rct->ymin);
870         float socket_size= NODE_SOCKSIZE*U.dpi/72;
871         int color_id= node_get_colorid(node);
872         char showname[128];     /* 128 is used below */
873         
874         /* shadow */
875         node_draw_shadow(snode, node, hiddenrad, 1.0f);
876
877         /* body */
878         UI_ThemeColor(color_id);
879         if (node->flag & NODE_MUTED)
880                 UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);
881         uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
882         
883         /* outline active and selected emphasis */
884         if ( node->flag & (NODE_ACTIVE|SELECT) ) {
885                 glEnable(GL_BLEND);
886                 glEnable(GL_LINE_SMOOTH);
887                 
888                 if (node->flag & NODE_ACTIVE)
889                         UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40);
890                 else
891                         UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40);
892                 uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
893                 
894                 glDisable(GL_LINE_SMOOTH);
895                 glDisable(GL_BLEND);
896         }
897         
898         /* title */
899         if (node->flag & SELECT) 
900                 UI_ThemeColor(TH_SELECT);
901         else
902                 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
903         
904         /* open entirely icon */
905         {
906                 uiBut *but;
907                 int but_size = UI_UNIT_X *0.6f;
908                 /* XXX button uses a custom triangle draw below, so make it invisible without icon */
909                 uiBlockSetEmboss(node->block, UI_EMBOSSN);
910                 but = uiDefBut(node->block, TOGBUT, B_REDR, "",
911                                            rct->xmin+10.0f-but_size/2, centy-but_size/2, but_size, but_size, NULL, 0, 0, 0, 0, "");
912                 uiButSetFunc(but, node_toggle_button_cb, node, (void*)"NODE_OT_hide_toggle");
913                 uiBlockSetEmboss(node->block, UI_EMBOSS);
914                 
915                 /* custom draw function for this button */
916                 UI_DrawTriIcon(rct->xmin+10.0f, centy, 'h');
917         }
918         
919         /* disable lines */
920         if (node->flag & NODE_MUTED)
921                 node_draw_mute_line(&ar->v2d, snode, node);     
922         
923         if (node->flag & SELECT) 
924                 UI_ThemeColor(TH_SELECT);
925         else
926                 UI_ThemeColor(TH_TEXT);
927         
928         if (node->miniwidth>0.0f) {
929                 BLI_strncpy(showname, nodeLabel(node), sizeof(showname));
930                 
931                 //if (node->flag & NODE_MUTED)
932                 //      BLI_snprintf(showname, sizeof(showname), "[%s]", showname); // XXX - don't print into self!
933
934                 uiDefBut(node->block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(centy-10), 
935                                  (int)(rct->xmax - rct->xmin-18.0f -12.0f), NODE_DY,  NULL, 0, 0, 0, 0, "");
936         }       
937
938         /* scale widget thing */
939         UI_ThemeColorShade(color_id, -10);      
940         dx= 10.0f;
941         fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
942         fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
943         
944         UI_ThemeColorShade(color_id, +30);
945         dx-= snode->aspect;
946         fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
947         fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
948
949         /* sockets */
950         for (sock= node->inputs.first; sock; sock= sock->next) {
951                 if (!nodeSocketIsHidden(sock))
952                         node_socket_circle_draw(snode->nodetree, sock, socket_size, sock->flag & SELECT);
953         }
954         
955         for (sock= node->outputs.first; sock; sock= sock->next) {
956                 if (!nodeSocketIsHidden(sock))
957                         node_socket_circle_draw(snode->nodetree, sock, socket_size, sock->flag & SELECT);
958         }
959         
960         uiEndBlock(C, node->block);
961         uiDrawBlock(C, node->block);
962         node->block= NULL;
963 }
964
965 int node_get_resize_cursor(int directions)
966 {
967         if (directions==0)
968                 return CURSOR_STD;
969         else if ((directions & ~(NODE_RESIZE_TOP|NODE_RESIZE_BOTTOM))==0)
970                 return CURSOR_Y_MOVE;
971         else if ((directions & ~(NODE_RESIZE_RIGHT|NODE_RESIZE_LEFT))==0)
972                 return CURSOR_X_MOVE;
973         else
974                 return CURSOR_EDIT;
975 }
976
977 void node_set_cursor(wmWindow *win, SpaceNode *snode)
978 {
979         bNodeTree *ntree = snode->edittree;
980         bNode *node;
981         bNodeSocket *sock;
982         int cursor = CURSOR_STD;
983         
984         if (ntree) {
985                 if (node_find_indicated_socket(snode, &node, &sock, SOCK_IN|SOCK_OUT)) {
986                         /* pass */
987                 }
988                 else {
989                         /* check nodes front to back */
990                         for (node=ntree->nodes.last; node; node=node->prev) {
991                                 if (BLI_in_rctf(&node->totr, snode->mx, snode->my))
992                                         break;  /* first hit on node stops */
993                         }
994                         if (node) {
995                                 int dir = node->typeinfo->resize_area_func(node, snode->mx, snode->my);
996                                 cursor = node_get_resize_cursor(dir);
997                         }
998                 }
999         }
1000         
1001         WM_cursor_set(win, cursor);
1002 }
1003
1004 void node_draw_default(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node)
1005 {
1006         if (node->flag & NODE_HIDDEN)
1007                 node_draw_hidden(C, ar, snode, node);
1008         else
1009                 node_draw_basis(C, ar, snode, ntree, node);
1010 }
1011
1012 static void node_update(const bContext *C, bNodeTree *ntree, bNode *node)
1013 {
1014         if (node->typeinfo->drawupdatefunc)
1015                 node->typeinfo->drawupdatefunc(C, ntree, node);
1016 }
1017
1018 void node_update_nodetree(const bContext *C, bNodeTree *ntree, float offsetx, float offsety)
1019 {
1020         bNode *node;
1021         
1022         /* update nodes front to back, so children sizes get updated before parents */
1023         for (node= ntree->nodes.last; node; node= node->prev) {
1024                 /* XXX little hack */
1025                 node->locx += offsetx;
1026                 node->locy += offsety;
1027                 
1028                 node_update(C, ntree, node);
1029                 
1030                 node->locx -= offsetx;
1031                 node->locy -= offsety;
1032         }
1033 }
1034
1035 static void node_draw(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node)
1036 {
1037         if (node->typeinfo->drawfunc)
1038                 node->typeinfo->drawfunc(C, ar, snode, ntree, node);
1039 }
1040
1041 void node_draw_nodetree(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree)
1042 {
1043         bNode *node;
1044         bNodeLink *link;
1045         int a;
1046         
1047         if (ntree==NULL) return;                /* groups... */
1048         
1049         /* draw background nodes, last nodes in front */
1050         for (a=0, node= ntree->nodes.first; node; node=node->next, a++) {
1051                 if (!(node->flag & NODE_BACKGROUND))
1052                         continue;
1053                 node->nr= a;            /* index of node in list, used for exec event code */
1054                 node_draw(C, ar, snode, ntree, node);
1055         }
1056         
1057         /* node lines */
1058         glEnable(GL_BLEND);
1059         glEnable(GL_LINE_SMOOTH);
1060         for (link= ntree->links.first; link; link= link->next)
1061                 node_draw_link(&ar->v2d, snode, link);
1062         glDisable(GL_LINE_SMOOTH);
1063         glDisable(GL_BLEND);
1064         
1065         /* draw foreground nodes, last nodes in front */
1066         for (a=0, node= ntree->nodes.first; node; node=node->next, a++) {
1067                 if (node->flag & NODE_BACKGROUND)
1068                         continue;
1069                 node->nr= a;            /* index of node in list, used for exec event code */
1070                 node_draw(C, ar, snode, ntree, node);
1071         }
1072 }
1073
1074 void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d)
1075 {
1076         View2DScrollers *scrollers;
1077         SpaceNode *snode= CTX_wm_space_node(C);
1078         Scene *scene= CTX_data_scene(C);
1079         int color_manage = scene->r.color_mgt_flag & R_COLOR_MANAGEMENT;
1080         bNodeLinkDrag *nldrag;
1081         LinkData *linkdata;
1082         
1083         UI_ThemeClearColor(TH_BACK);
1084         glClear(GL_COLOR_BUFFER_BIT);
1085
1086         UI_view2d_view_ortho(v2d);
1087         
1088         //uiFreeBlocksWin(&sa->uiblocks, sa->win);
1089
1090         /* only set once */
1091         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1092         glEnable(GL_MAP1_VERTEX_3);
1093
1094         /* aspect+font, set each time */
1095         snode->aspect= (v2d->cur.xmax - v2d->cur.xmin)/((float)ar->winx);
1096         // XXX snode->curfont= uiSetCurFont_ext(snode->aspect);
1097
1098         /* grid */
1099         UI_view2d_multi_grid_draw(v2d, 25.0f, 5, 2);
1100
1101         /* backdrop */
1102         draw_nodespace_back_pix(ar, snode, color_manage);
1103         
1104         /* nodes */
1105         snode_set_context(snode, CTX_data_scene(C));
1106         
1107         if (snode->nodetree) {
1108                 bNode *node;
1109                 
1110                 node_uiblocks_init(C, snode->nodetree);
1111                 
1112                 /* uiBlocks must be initialized in drawing order for correct event clipping.
1113                  * Node group internal blocks added after the main group block.
1114                  */
1115                 for (node= snode->nodetree->nodes.first; node; node= node->next) {
1116                         if (node->flag & NODE_GROUP_EDIT)
1117                                 node_uiblocks_init(C, (bNodeTree *)node->id);
1118                 }
1119                 
1120                 node_update_nodetree(C, snode->nodetree, 0.0f, 0.0f);
1121                 node_draw_nodetree(C, ar, snode, snode->nodetree);
1122                 
1123                 #if 0
1124                 /* active group */
1125                 for (node= snode->nodetree->nodes.first; node; node= node->next) {
1126                         if (node->flag & NODE_GROUP_EDIT)
1127                                 node_draw_group(C, ar, snode, snode->nodetree, node);
1128                 }
1129                 #endif
1130         }
1131         
1132         /* temporary links */
1133         glEnable(GL_BLEND);
1134         glEnable(GL_LINE_SMOOTH);
1135         for (nldrag= snode->linkdrag.first; nldrag; nldrag= nldrag->next) {
1136                 for (linkdata=nldrag->links.first; linkdata; linkdata=linkdata->next)
1137                         node_draw_link(&ar->v2d, snode, (bNodeLink *)linkdata->data);
1138         }
1139         glDisable(GL_LINE_SMOOTH);
1140         glDisable(GL_BLEND);
1141         
1142         /* draw grease-pencil ('canvas' strokes) */
1143         if (snode->nodetree)
1144                 draw_gpencil_view2d(C, 1);
1145         
1146         /* reset view matrix */
1147         UI_view2d_view_restore(C);
1148         
1149         /* draw grease-pencil (screen strokes, and also paintbuffer) */
1150         if (snode->nodetree)
1151                 draw_gpencil_view2d(C, 0);
1152         
1153         /* scrollers */
1154         scrollers= UI_view2d_scrollers_calc(C, v2d, 10, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
1155         UI_view2d_scrollers_draw(C, v2d, scrollers);
1156         UI_view2d_scrollers_free(scrollers);
1157 }