More work on render stuff!
[blender-staging.git] / source / blender / src / drawnode.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2005 Blender Foundation.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <math.h>
31 #include <stdio.h>
32 #include <string.h>
33
34 #include "BLI_blenlib.h"
35 #include "BLI_arithb.h"
36
37 #include "DNA_action_types.h"
38 #include "DNA_ipo_types.h"
39 #include "DNA_ID.h"
40 #include "DNA_material_types.h"
41 #include "DNA_node_types.h"
42 #include "DNA_object_types.h"
43 #include "DNA_scene_types.h"
44 #include "DNA_space_types.h"
45 #include "DNA_screen_types.h"
46 #include "DNA_texture_types.h"
47 #include "DNA_userdef_types.h"
48
49 #include "BKE_global.h"
50 #include "BKE_image.h"
51 #include "BKE_library.h"
52 #include "BKE_main.h"
53 #include "BKE_material.h"
54 #include "BKE_node.h"
55 #include "BKE_object.h"
56 #include "BKE_texture.h"
57 #include "BKE_utildefines.h"
58
59 #include "BIF_gl.h"
60 #include "BIF_glutil.h"
61 #include "BIF_interface.h"
62 #include "BIF_interface_icons.h"
63 #include "BIF_language.h"
64 #include "BIF_mywindow.h"
65 #include "BIF_previewrender.h"
66 #include "BIF_resources.h"
67 #include "BIF_screen.h"
68 #include "BIF_space.h"
69
70 #include "BSE_drawipo.h"
71 #include "BSE_node.h"
72 #include "BSE_view.h"
73
74 #include "BMF_Api.h"
75
76 #include "MEM_guardedalloc.h"
77
78 #include "RE_pipeline.h"
79
80 #include "blendef.h"
81 #include "butspace.h"
82 #include "interface.h"  /* urm...  for rasterpos_safe, roundbox */
83 #include "mydevice.h"
84
85
86
87 static void snode_drawstring(SpaceNode *snode, char *str, int okwidth)
88 {
89         char drawstr[NODE_MAXSTR];
90         int width;
91         
92         if(str[0]==0 || okwidth<4) return;
93         
94         BLI_strncpy(drawstr, str, NODE_MAXSTR);
95         width= snode->aspect*BIF_GetStringWidth(snode->curfont, drawstr, 0);
96
97         if(width > okwidth) {
98                 int len= strlen(drawstr)-1;
99                 
100                 while(width > okwidth && len>=0) {
101                         drawstr[len]= 0;
102                         
103                         width= snode->aspect*BIF_GetStringWidth(snode->curfont, drawstr, 0);
104                         len--;
105                 }
106                 if(len==0) return;
107         }
108         BIF_DrawString(snode->curfont, drawstr, 0);
109
110 }
111
112 /* **************  Socket callbacks *********** */
113
114 /* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
115 static uiBlock *socket_vector_menu(void *butpoin_v)
116 {
117         float *butpoin= butpoin_v;
118         uiBlock *block;
119         
120         block= uiNewBlock(&curarea->uiblocks, "socket menu", UI_EMBOSS, UI_HELV, curarea->win);
121         
122         /* use this for a fake extra empy space around the buttons */
123         uiDefBut(block, LABEL, 0, "",                   -4, -4, 188, 68, NULL, 0, 0, 0, 0, "");
124         
125         uiBlockBeginAlign(block);
126         uiDefButF(block, NUMSLI, 0, "X ",        0,40,180,20, butpoin, -1.0, 1.0, 10, 0, "");
127         uiDefButF(block, NUMSLI, 0, "Y ",        0,20,180,20, butpoin+1, -1.0, 1.0, 10, 0, "");
128         uiDefButF(block, NUMSLI, 0, "Z ",        0,0,180,20, butpoin+2, -1.0, 1.0, 10, 0, "");
129         
130         uiBlockSetDirection(block, UI_TOP);
131         
132         allqueue(REDRAWNODE, 0);
133         
134         return block;
135 }
136
137 static void node_sync_cb(void *snode_v, void *node_v)
138 {
139         SpaceNode *snode= snode_v;
140         
141         if(snode->treetype==NTREE_SHADER) {
142                 nodeShaderSynchronizeID(node_v, 1);
143                 allqueue(REDRAWBUTSSHADING, 0);
144         }
145 }
146
147 /* ****************** GENERAL CALLBACKS FOR NODES ***************** */
148
149 static void node_ID_title_cb(void *node_v, void *unused_v)
150 {
151         bNode *node= node_v;
152         
153         if(node->id) {
154                 test_idbutton(node->id->name+2);        /* library.c, verifies unique name */
155                 BLI_strncpy(node->name, node->id->name+2, 21);
156                 
157                 allqueue(REDRAWBUTSSHADING, 0);
158                 allqueue(REDRAWNODE, 0);
159                 allqueue(REDRAWOOPS, 0);
160         }
161 }
162
163
164 static void node_but_title_cb(void *node_v, void *but_v)
165 {
166         bNode *node= node_v;
167         uiBut *bt= but_v;
168         BLI_strncpy(node->name, bt->drawstr, NODE_MAXSTR);
169         
170         allqueue(REDRAWNODE, 0);
171 }
172
173
174 /* ****************** BUTTON CALLBACKS FOR ALL TREES ***************** */
175
176 static int node_buts_group(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
177 {
178         if(block && node->id) {
179                 uiBut *bt;
180                 short width;
181                 
182                 uiBlockBeginAlign(block);
183                 
184                 /* name button */
185                 width= (short)(butr->xmax-butr->xmin - (node->id->us>1?19.0f:0.0f));
186                 bt= uiDefBut(block, TEX, B_NOP, "NT:",
187                                          butr->xmin, butr->ymin, width, 19, 
188                                          node->id->name+2, 0.0, 19.0, 0, 0, "NodeTree name");
189                 uiButSetFunc(bt, node_ID_title_cb, node, NULL);
190                 
191                 /* user amount */
192                 if(node->id->us>1) {
193                         char str1[32];
194                         sprintf(str1, "%d", node->id->us);
195                         bt= uiDefBut(block, BUT, B_NOP, str1, 
196                                                  butr->xmax-19, butr->ymin, 19, 19, 
197                                                  NULL, 0, 0, 0, 0, "Displays number of users. Click to make a single-user copy.");
198                         //uiButSetFunc(bt, node_mat_alone_cb, node, NULL);
199                 }
200                 
201                 uiBlockEndAlign(block);
202         }       
203         return 19;
204 }
205
206 static int node_buts_value(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
207 {
208         if(block) {
209                 bNodeSocket *sock= node->outputs.first;         /* first socket stores value */
210                 
211                 uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", 
212                                   butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, 
213                                   sock->ns.vec, 0.0f, 1.0f, 10, 2, "");
214                 
215         }
216         return 20;
217 }
218
219 static int node_buts_rgb(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
220 {
221         if(block) {
222                 bNodeSocket *sock= node->outputs.first;         /* first socket stores value */
223                 if(sock) {
224                         /* enforce square box drawing */
225                         uiBlockSetEmboss(block, UI_EMBOSSP);
226                         
227                         uiDefButF(block, HSVCUBE, B_NODE_EXEC+node->nr, "", 
228                                           butr->xmin, butr->ymin, butr->xmax-butr->xmin, 12, 
229                                           sock->ns.vec, 0.0f, 1.0f, 3, 0, "");
230                         uiDefButF(block, HSVCUBE, B_NODE_EXEC+node->nr, "", 
231                                           butr->xmin, butr->ymin+15, butr->xmax-butr->xmin, butr->ymax-butr->ymin -15 -15, 
232                                           sock->ns.vec, 0.0f, 1.0f, 2, 0, "");
233                         uiDefButF(block, COL, B_NOP, "",                
234                                           butr->xmin, butr->ymax-12, butr->xmax-butr->xmin, 12, 
235                                           sock->ns.vec, 0.0, 0.0, -1, 0, "");
236                         /* the -1 above prevents col button to popup a color picker */
237                         
238                         uiBlockSetEmboss(block, UI_EMBOSS);
239                 }
240         }
241         return 30 + (int)(node->width-NODE_DY);
242 }
243
244 static int node_buts_mix_rgb(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
245 {
246         if(block) {
247                 uiBut *bt;
248                 
249                 /* blend type */
250                 bt=uiDefButS(block, MENU, B_NODE_EXEC+node->nr, "Mix %x0|Add %x1|Subtract %x3|Multiply %x2|Screen %x4|Divide %x5|Difference %x6|Darken %x7|Lighten %x8",
251                                          butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, 
252                                          &node->custom1, 0, 0, 0, 0, "");
253                 uiButSetFunc(bt, node_but_title_cb, node, bt);
254         }
255         return 20;
256 }
257
258 static int node_buts_valtorgb(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
259 {
260         if(block) {
261                 if(node->storage) {
262                         draw_colorband_buts_small(block, node->storage, butr, B_NODE_EXEC+node->nr);
263                 }
264         }
265         return 40;
266 }
267
268 static int node_buts_curvevec(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
269 {
270         if(block) {
271                 curvemap_buttons(block, node->storage, 'v', B_NODE_EXEC+node->nr, B_REDR, butr);
272         }       
273         return (int)(node->width-NODE_DY);
274 }
275
276 static int node_buts_curvecol(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
277 {
278         if(block) {
279                 curvemap_buttons(block, node->storage, 'c', B_NODE_EXEC+node->nr, B_REDR, butr);
280         }       
281         return (int)(node->width-NODE_DY);
282 }
283
284 static int node_buts_normal(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
285 {
286         if(block) {
287                 bNodeSocket *sock= node->outputs.first;         /* first socket stores normal */
288                 
289                 uiDefButF(block, BUT_NORMAL, B_NODE_EXEC+node->nr, "", 
290                                   butr->xmin, butr->ymin, butr->xmax-butr->xmin, butr->ymax-butr->ymin, 
291                                   sock->ns.vec, 0.0f, 1.0f, 0, 0, "");
292                 
293         }       
294         return (int)(node->width-NODE_DY);
295 }
296
297
298
299 /* ****************** BUTTON CALLBACKS FOR SHADER NODES ***************** */
300
301
302 static void node_mat_alone_cb(void *node_v, void *unused)
303 {
304         bNode *node= node_v;
305         
306         node->id= (ID *)copy_material((Material *)node->id);
307         
308         BIF_undo_push("Single user material");
309         allqueue(REDRAWBUTSSHADING, 0);
310         allqueue(REDRAWNODE, 0);
311         allqueue(REDRAWOOPS, 0);
312 }
313
314 static void node_browse_mat_cb(void *ntree_v, void *node_v)
315 {
316         bNodeTree *ntree= ntree_v;
317         bNode *node= node_v;
318         
319         if(node->menunr<1) return;
320         
321         if(node->menunr==32767) {       /* code for Add New */
322                 if(node->id) {
323                         /* make copy, but make sure it doesnt have the node tag nor nodes */
324                         Material *ma= (Material *)node->id;
325                         ma->id.us--;
326                         ma= copy_material(ma);
327                         ma->use_nodes= 0;
328                         if(ma->nodetree) {
329                                 ntreeFreeTree(ma->nodetree);
330                                 MEM_freeN(ma->nodetree);
331                         }
332                         ma->nodetree= NULL;
333                         node->id= (ID *)ma;
334                 }
335                 else node->id= (ID *)add_material("MatNode");
336         }
337         else {
338                 if(node->id) node->id->us--;
339                 node->id= BLI_findlink(&G.main->mat, node->menunr-1);
340                 id_us_plus(node->id);
341         }
342         BLI_strncpy(node->name, node->id->name+2, 21);
343         
344         nodeSetActive(ntree, node);
345
346         allqueue(REDRAWBUTSSHADING, 0);
347         allqueue(REDRAWNODE, 0);
348         BIF_preview_changed(ID_MA);
349
350         node->menunr= 0;
351 }
352
353 static void node_new_mat_cb(void *ntree_v, void *node_v)
354 {
355         bNodeTree *ntree= ntree_v;
356         bNode *node= node_v;
357         
358         node->id= (ID *)add_material("MatNode");
359         BLI_strncpy(node->name, node->id->name+2, 21);
360
361         nodeSetActive(ntree, node);
362
363         allqueue(REDRAWBUTSSHADING, 0);
364         allqueue(REDRAWNODE, 0);
365         BIF_preview_changed(ID_MA);
366
367 }
368
369 static void node_texmap_cb(void *texmap_v, void *unused_v)
370 {
371         init_mapping(texmap_v);
372 }
373
374 static int node_shader_buts_material(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
375 {
376         if(block) {
377                 uiBut *bt;
378                 short dx= (short)((butr->xmax-butr->xmin)/3.0f), has_us= (node->id && node->id->us>1);
379                 short dy= (short)butr->ymin;
380                 char *strp;
381                 
382                 /* WATCH IT: we use this callback in material buttons, but then only want first row */
383                 if(butr->ymax-butr->ymin > 21.0f) dy+= 19;
384                 
385                 uiBlockBeginAlign(block);
386                 if(node->id==NULL) uiBlockSetCol(block, TH_REDALERT);
387                 else if(has_us) uiBlockSetCol(block, TH_BUT_SETTING1);
388                 else uiBlockSetCol(block, TH_BUT_SETTING2);
389                 
390                 /* browse button */
391                 IDnames_to_pupstring(&strp, NULL, "ADD NEW %x32767", &(G.main->mat), NULL, NULL);
392                 node->menunr= 0;
393                 bt= uiDefButS(block, MENU, B_NOP, strp, 
394                                   butr->xmin, dy, 19, 19, 
395                                   &node->menunr, 0, 0, 0, 0, "Browses existing choices or adds NEW");
396                 uiButSetFunc(bt, node_browse_mat_cb, ntree, node);
397                 if(strp) MEM_freeN(strp);
398                 
399                 /* Add New button */
400                 if(node->id==NULL) {
401                         bt= uiDefBut(block, BUT, B_NOP, "Add New",
402                                                  butr->xmin+19, dy, (short)(butr->xmax-butr->xmin-19.0f), 19, 
403                                                  NULL, 0.0, 0.0, 0, 0, "Add new Material");
404                         uiButSetFunc(bt, node_new_mat_cb, ntree, node);
405                         uiBlockSetCol(block, TH_AUTO);
406                 }
407                 else {
408                         /* name button */
409                         short width= (short)(butr->xmax-butr->xmin-19.0f - (has_us?19.0f:0.0f));
410                         bt= uiDefBut(block, TEX, B_NOP, "MA:",
411                                                   butr->xmin+19, dy, width, 19, 
412                                                   node->id->name+2, 0.0, 19.0, 0, 0, "Material name");
413                         uiButSetFunc(bt, node_ID_title_cb, node, NULL);
414                         
415                         /* user amount */
416                         if(has_us) {
417                                 char str1[32];
418                                 sprintf(str1, "%d", node->id->us);
419                                 bt= uiDefBut(block, BUT, B_NOP, str1, 
420                                                           butr->xmax-19, dy, 19, 19, 
421                                                           NULL, 0, 0, 0, 0, "Displays number of users. Click to make a single-user copy.");
422                                 uiButSetFunc(bt, node_mat_alone_cb, node, NULL);
423                         }
424                         
425                         /* WATCH IT: we use this callback in material buttons, but then only want first row */
426                         if(butr->ymax-butr->ymin > 21.0f) {
427                                 /* node options */
428                                 uiBlockSetCol(block, TH_AUTO);
429                                 uiDefButBitS(block, TOG, SH_NODE_MAT_DIFF, B_NODE_EXEC+node->nr, "Diff",
430                                                          butr->xmin, butr->ymin, dx, 19, 
431                                                          &node->custom1, 0, 0, 0, 0, "Material Node outputs Diffuse");
432                                 uiDefButBitS(block, TOG, SH_NODE_MAT_SPEC, B_NODE_EXEC+node->nr, "Spec",
433                                                          butr->xmin+dx, butr->ymin, dx, 19, 
434                                                          &node->custom1, 0, 0, 0, 0, "Material Node outputs Specular");
435                                 uiDefButBitS(block, TOG, SH_NODE_MAT_NEG, B_NODE_EXEC+node->nr, "Neg Normal",
436                                                          butr->xmax-dx, butr->ymin, dx, 19,
437                                                          &node->custom1, 0, 0, 0, 0, "Material Node uses inverted Normal");
438                         }
439                 }
440                 uiBlockEndAlign(block);
441         }       
442         return 38;
443 }
444
445 static int node_shader_buts_texture(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
446 {
447         if(block) {
448                 uiBut *bt;
449                 
450                 bt= uiDefIDPoinBut(block, test_texpoin_but, ID_TE, B_NODE_EXEC+node->nr, "",
451                                                    butr->xmin, butr->ymin, butr->xmax-butr->xmin, 19, 
452                                                    &node->id,  ""); 
453                 uiButSetFunc(bt, node_ID_title_cb, node, NULL);
454                 
455         }       
456         return 19;
457 }
458
459
460 static int node_shader_buts_mapping(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
461 {
462         if(block) {
463                 TexMapping *texmap= node->storage;
464                 short dx= (short)((butr->xmax-butr->xmin)/7.0f);
465                 short dy= (short)(butr->ymax-19);
466                 
467                 uiBlockSetFunc(block, node_texmap_cb, texmap, NULL);    /* all buttons get this */
468                 
469                 uiBlockBeginAlign(block);
470                 uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+dx, dy, 2*dx, 19, texmap->loc, -1000.0f, 1000.0f, 10, 2, "");
471                 uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->loc+1, -1000.0f, 1000.0f, 10, 2, "");
472                 uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->loc+2, -1000.0f, 1000.0f, 10, 2, "");
473                 dy-= 19;
474                 uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+dx, dy, 2*dx, 19, texmap->rot, -1000.0f, 1000.0f, 1000, 1, "");
475                 uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->rot+1, -1000.0f, 1000.0f, 1000, 1, "");
476                 uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->rot+2, -1000.0f, 1000.0f, 1000, 1, "");
477                 dy-= 19;
478                 uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+dx, dy, 2*dx, 19, texmap->size, -1000.0f, 1000.0f, 10, 2, "");
479                 uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->size+1, -1000.0f, 1000.0f, 10, 2, "");
480                 uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->size+2, -1000.0f, 1000.0f, 10, 2, "");
481                 dy-= 25;
482                 uiBlockBeginAlign(block);
483                 uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+dx, dy, 2*dx, 19, texmap->min, -10.0f, 10.0f, 100, 2, "");
484                 uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->min+1, -10.0f, 10.0f, 100, 2, "");
485                 uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->min+2, -10.0f, 10.0f, 100, 2, "");
486                 dy-= 19;
487                 uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+dx, dy, 2*dx, 19, texmap->max, -10.0f, 10.0f, 10, 2, "");
488                 uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->max+1, -10.0f, 10.0f, 10, 2, "");
489                 uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->max+2, -10.0f, 10.0f, 10, 2, "");
490                 uiBlockEndAlign(block);
491                 
492                 /* labels/options */
493                 
494                 dy= (short)(butr->ymax-19);
495                 uiDefBut(block, LABEL, B_NOP, "Loc", butr->xmin, dy, dx, 19, NULL, 0.0f, 0.0f, 0, 0, "");
496                 dy-= 19;
497                 uiDefBut(block, LABEL, B_NOP, "Rot", butr->xmin, dy, dx, 19, NULL, 0.0f, 0.0f, 0, 0, "");
498                 dy-= 19;
499                 uiDefBut(block, LABEL, B_NOP, "Size", butr->xmin, dy, dx, 19, NULL, 0.0f, 0.0f, 0, 0, "");
500                 dy-= 25;
501                 uiDefButBitI(block, TOG, TEXMAP_CLIP_MIN, B_NODE_EXEC+node->nr, "Min", butr->xmin, dy, dx-4, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, "");
502                 dy-= 19;
503                 uiDefButBitI(block, TOG, TEXMAP_CLIP_MAX, B_NODE_EXEC+node->nr, "Max", butr->xmin, dy, dx-4, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, "");
504                 
505         }       
506         return 5*19 + 6;
507 }
508
509
510 /* only once called */
511 static void node_shader_set_butfunc(bNodeType *ntype)
512 {
513         switch(ntype->type) {
514                 case NODE_GROUP:        /* note, generic type, but put here because we call this function anyway */
515                         ntype->butfunc= node_buts_group;
516                         break;
517                 case SH_NODE_MATERIAL:
518                         ntype->butfunc= node_shader_buts_material;
519                         break;
520                 case SH_NODE_TEXTURE:
521                         ntype->butfunc= node_shader_buts_texture;
522                         break;
523                 case SH_NODE_NORMAL:
524                         ntype->butfunc= node_buts_normal;
525                         break;
526                 case SH_NODE_CURVE_VEC:
527                         ntype->butfunc= node_buts_curvevec;
528                         break;
529                 case SH_NODE_CURVE_RGB:
530                         ntype->butfunc= node_buts_curvecol;
531                         break;
532                 case SH_NODE_MAPPING:
533                         ntype->butfunc= node_shader_buts_mapping;
534                         break;
535                 case SH_NODE_VALUE:
536                         ntype->butfunc= node_buts_value;
537                         break;
538                 case SH_NODE_RGB:
539                         ntype->butfunc= node_buts_rgb;
540                         break;
541                 case SH_NODE_MIX_RGB:
542                         ntype->butfunc= node_buts_mix_rgb;
543                         break;
544                 case SH_NODE_VALTORGB:
545                         ntype->butfunc= node_buts_valtorgb;
546                         break;
547                 default:
548                         ntype->butfunc= NULL;
549         }
550 }
551
552 /* ****************** BUTTON CALLBACKS FOR COMPOSIT NODES ***************** */
553
554
555
556 static void node_browse_image_cb(void *ntree_v, void *node_v)
557 {
558         bNodeTree *ntree= ntree_v;
559         bNode *node= node_v;
560         
561         nodeSetActive(ntree, node);
562         
563         if(node->menunr<1) return;
564         if(node->menunr==32767) {       /* code for Load New */
565                 addqueue(curarea->win, UI_BUT_EVENT, B_NODE_LOADIMAGE);
566         }
567         else {
568                 if(node->id) node->id->us--;
569                 node->id= BLI_findlink(&G.main->image, node->menunr-1);
570                 id_us_plus(node->id);
571
572                 BLI_strncpy(node->name, node->id->name+2, 21);
573
574                 NodeTagChanged(ntree, node); 
575         }
576         node->menunr= 0;
577 }
578
579 static void node_active_cb(void *ntree_v, void *node_v)
580 {
581         nodeSetActive(ntree_v, node_v);
582 }
583 static void node_image_anim_cb(void *node_v, void *unused)
584 {
585         bNode *node= node_v;
586         NodeImageAnim *nia;
587         
588         if(node->storage) {
589                 MEM_freeN(node->storage);
590                 node->storage= NULL;
591         }
592         else {
593                 nia= node->storage= MEM_callocN(sizeof(NodeImageAnim), "node image anim");
594                 nia->sfra= nia->nr= 1;
595         }
596         allqueue(REDRAWNODE, 1);
597 }
598
599 static int node_composit_buts_image(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
600 {
601         if(block) {
602                 uiBut *bt;
603                 short dy= (short)butr->ymax-19;
604                 char *strp;
605                 
606                 uiBlockBeginAlign(block);
607                 uiBlockSetCol(block, TH_BUT_SETTING2);
608                 
609                 /* browse button */
610                 IDnames_to_pupstring(&strp, NULL, "LOAD NEW %x32767", &(G.main->image), NULL, NULL);
611                 node->menunr= 0;
612                 bt= uiDefButS(block, MENU, B_NOP, strp, 
613                                           butr->xmin, dy, 19, 19, 
614                                           &node->menunr, 0, 0, 0, 0, "Browses existing choices");
615                 uiButSetFunc(bt, node_browse_image_cb, ntree, node);
616                 if(strp) MEM_freeN(strp);
617                 
618                 /* Add New button */
619                 if(node->id==NULL) {
620                         bt= uiDefBut(block, BUT, B_NODE_LOADIMAGE, "Load New",
621                                                  butr->xmin+19, dy, (short)(butr->xmax-butr->xmin-19.0f), 19, 
622                                                  NULL, 0.0, 0.0, 0, 0, "Add new Image");
623                         uiButSetFunc(bt, node_active_cb, ntree, node);
624                         uiBlockSetCol(block, TH_AUTO);
625                 }
626                 else {
627                         /* name button */
628                         short width= (short)(butr->xmax-butr->xmin-38.0f);
629                         bt= uiDefBut(block, TEX, B_NOP, "IMA:",
630                                                  butr->xmin+19, dy, width, 19, 
631                                                  node->id->name+2, 0.0, 19.0, 0, 0, "Image name");
632                         uiButSetFunc(bt, node_ID_title_cb, node, NULL);
633                         bt= uiDefIconBut(block, BUT, B_NOP, ICON_SEQUENCE,
634                                                  butr->xmax-19, dy, 19, 19, 
635                                                  node->id->name+2, 0.0, 19.0, 0, 0, "Enable/Disable Image animation");
636                         uiButSetFunc(bt, node_image_anim_cb, node, NULL);
637                 }
638                 if(node->storage) {
639                         NodeImageAnim *nia= node->storage;
640                         short width= (short)(butr->xmax-butr->xmin)/2;
641                         
642                         dy-= 19;
643                         uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "Frs:",
644                                           butr->xmin, dy, width, 19, 
645                                           &nia->frames, 0.0, 10000.0, 0, 0, "Amount of images used in animation");
646                         uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "SFra:",
647                                           butr->xmin+width, dy, width, 19, 
648                                           &nia->sfra, 1.0, 1000.0, 0, 0, "Start frame of animation");
649                         dy-= 19;
650                         uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "First:",
651                                           butr->xmin, dy, width, 19, 
652                                           &nia->nr, 0.0, 10000.0, 0, 0, "Number in image name, used as first in animation");
653                         uiDefButC(block, TOG, B_NODE_EXEC+node->nr, "Cycl",
654                                           butr->xmin+width, dy, width, 19, 
655                                           &nia->cyclic, 0.0, 0.0, 0, 0, "Make animation go cyclic");
656                         
657                 }
658                 
659         }       
660         if(node->storage) 
661                 return 57;
662         else
663                 return 19;
664 }
665
666 /* if we use render result from other scene, we make a nice title */
667 static void set_render_result_title(void *node_v, void *unused)
668 {
669         bNode *node= node_v;
670         Scene *sce;
671         SceneRenderLayer *srl;
672         char str[64];
673         
674         if(node->id) {
675                 BLI_strncpy(str, node->id->name+2, 21);
676                 strcat(str, "|");
677                 sce= (Scene *)node->id;
678         }
679         else {
680                 str[0]= 0;
681                 sce= G.scene;
682         }
683         srl= BLI_findlink(&sce->r.layers, node->custom1);
684         if(srl==NULL) {
685                 node->custom1= 0;
686                 srl= sce->r.layers.first;
687         }
688         
689         strcat(str, srl->name);
690         BLI_strncpy(node->name, str, 32);
691 }
692
693 static char *scene_layer_menu(Scene *sce)
694 {
695         SceneRenderLayer *srl;
696         int len= 32 + 32*BLI_countlist(&sce->r.layers);
697         short a, nr;
698         char *str= MEM_callocN(len, "menu layers");
699         
700         strcpy(str, "Active Layer %t");
701         a= strlen(str);
702         for(nr=0, srl= sce->r.layers.first; srl; srl= srl->next, nr++) {
703                 a+= sprintf(str+a, "|%s %%x%d", srl->name, nr);
704         }
705         
706         return str;
707 }
708
709 static void node_browse_scene_cb(void *ntree_v, void *node_v)
710 {
711         bNodeTree *ntree= ntree_v;
712         bNode *node= node_v;
713         Scene *sce;
714         
715         if(node->menunr<1) return;
716         
717         if(node->id) {
718                 node->id->us--;
719                 node->id= NULL;
720         }
721         sce= BLI_findlink(&G.main->scene, node->menunr-1);
722         if(sce!=G.scene) {
723                 node->id= &sce->id;
724                 id_us_plus(node->id);
725         }
726         
727         set_render_result_title(node, NULL);
728         nodeSetActive(ntree, node);
729
730         allqueue(REDRAWBUTSSHADING, 0);
731         allqueue(REDRAWNODE, 0);
732         NodeTagChanged(ntree, node); 
733
734         node->menunr= 0;
735 }
736
737
738 static int node_composit_buts_renderresult(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
739 {
740         if(block) {
741                 uiBut *bt;
742                 char *strp;
743                 
744                 /* browse button scene */
745                 uiBlockBeginAlign(block);
746                 IDnames_to_pupstring(&strp, NULL, "", &(G.main->scene), NULL, NULL);
747                 node->menunr= 0;
748                 bt= uiDefButS(block, MENU, B_NOP, strp, 
749                                           butr->xmin, butr->ymin, 20, 19, 
750                                           &node->menunr, 0, 0, 0, 0, "Browse Scene to use RenderLayer from");
751                 uiButSetFunc(bt, node_browse_scene_cb, ntree, node);
752                 if(strp) MEM_freeN(strp);
753                 
754                 /* browse button layer */
755                 strp= scene_layer_menu(node->id?(Scene *)node->id:G.scene);
756                 bt= uiDefButS(block, MENU, B_NODE_EXEC+node->nr, strp, 
757                                   butr->xmin+20, butr->ymin, (butr->xmax-butr->xmin)-20, 19, 
758                                   &node->custom1, 0, 0, 0, 0, "Choose Render Layer");
759                 uiButSetFunc(bt, set_render_result_title, node, NULL);
760                 MEM_freeN(strp);
761         }
762         return 19;
763 }
764
765 static int node_composit_buts_blur(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
766 {
767         if(block) {
768                 NodeBlurData *nbd= node->storage;
769                 uiBut *bt;
770                 short dy= butr->ymin+19;
771                 short dx= (butr->xmax-butr->xmin)/2;
772                 short dx3=(butr->xmax-butr->xmin)/3;
773                 char str[256];
774                 
775                 uiBlockBeginAlign(block);
776                 sprintf(str, "Filter Type%%t|Flat %%x%d|Tent %%x%d|Quad %%x%d|Cubic %%x%d|Gauss %%x%d|CatRom %%x%d|Mitch %%x%d", R_FILTER_BOX, R_FILTER_TENT, R_FILTER_QUAD, R_FILTER_CUBIC, R_FILTER_GAUSS, R_FILTER_CATROM, R_FILTER_MITCH);
777                 uiDefButS(block, MENU, B_NODE_EXEC,str,         
778                                   butr->xmin, dy, dx3, 19, 
779                                   &nbd->filtertype, 0, 0, 0, 0, "Set sampling filter for blur");
780                 uiDefButC(block, TOG, B_NODE_EXEC, "Bokeh",             
781                                   butr->xmin+dx3, dy, dx3, 19, 
782                                   &nbd->bokeh, 0, 0, 0, 0, "Uses circular filter, warning it's slow!");
783                 uiDefButC(block, TOG, B_NODE_EXEC, "Gamma",             
784                                   butr->xmin+2*dx3, dy, dx3, 19, 
785                                   &nbd->gamma, 0, 0, 0, 0, "Applies filter on gamma corrected values");
786                 
787                 dy-=19;
788                 bt=uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "X:",
789                                          butr->xmin, dy, dx, 19, 
790                                          &nbd->sizex, 0, 256, 0, 0, "");
791                 bt=uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "Y:",
792                                          butr->xmin+dx, dy, dx, 19, 
793                                          &nbd->sizey, 0, 256, 0, 0, "");
794         }
795         return 38;
796 }
797
798 static int node_composit_buts_filter(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
799 {
800         if(block) {
801                 uiBut *bt;
802                 
803                 /* blend type */
804                 bt=uiDefButS(block, MENU, B_NODE_EXEC+node->nr, "Soften %x0|Sharpen %x1|Laplace %x2|Sobel %x3|Prewitt %x4|Kirsch %x5|Shadow %x6",
805                                          butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, 
806                                          &node->custom1, 0, 0, 0, 0, "");
807                 uiButSetFunc(bt, node_but_title_cb, node, bt);
808         }
809         return 20;
810 }
811
812 static int node_composit_buts_map_value(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
813 {
814         if(block) {
815                 TexMapping *texmap= node->storage;
816                 short xstart= (short)butr->xmin;
817                 short dy= (short)(butr->ymax-19.0f);
818                 short dx= (short)(butr->xmax-butr->xmin)/2;
819                 
820                 uiBlockBeginAlign(block);
821                 uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Offs:", xstart, dy, 2*dx, 19, texmap->loc, -1000.0f, 1000.0f, 10, 2, "");
822                 dy-= 19;
823                 uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Size:", xstart, dy, 2*dx, 19, texmap->size, -1000.0f, 1000.0f, 10, 3, "");
824                 dy-= 23;
825                 uiBlockBeginAlign(block);
826                 uiDefButBitI(block, TOG, TEXMAP_CLIP_MIN, B_NODE_EXEC+node->nr, "Min", xstart, dy, dx, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, "");
827                 uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", xstart+dx, dy, dx, 19, texmap->min, -1000.0f, 1000.0f, 10, 2, "");
828                 dy-= 19;
829                 uiDefButBitI(block, TOG, TEXMAP_CLIP_MAX, B_NODE_EXEC+node->nr, "Max", xstart, dy, dx, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, "");
830                 uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", xstart+dx, dy, dx, 19, texmap->max, -1000.0f, 1000.0f, 10, 2, "");
831         }
832         return 80;
833 }
834
835
836 /* only once called */
837 static void node_composit_set_butfunc(bNodeType *ntype)
838 {
839         switch(ntype->type) {
840                 case NODE_GROUP:        /* note, generic type, but put here because we call this function anyway */
841                         ntype->butfunc= node_buts_group;
842                         break;
843                 case CMP_NODE_IMAGE:
844                         ntype->butfunc= node_composit_buts_image;
845                         break;
846                 case CMP_NODE_R_RESULT:
847                         ntype->butfunc= node_composit_buts_renderresult;
848                         break;
849                 case CMP_NODE_NORMAL:
850                         ntype->butfunc= node_buts_normal;
851                         break;
852                 case CMP_NODE_CURVE_VEC:
853                         ntype->butfunc= node_buts_curvevec;
854                         break;
855                 case CMP_NODE_CURVE_RGB:
856                         ntype->butfunc= node_buts_curvecol;
857                         break;
858                 case CMP_NODE_VALUE:
859                         ntype->butfunc= node_buts_value;
860                         break;
861                 case CMP_NODE_RGB:
862                         ntype->butfunc= node_buts_rgb;
863                         break;
864                 case CMP_NODE_MIX_RGB:
865                         ntype->butfunc= node_buts_mix_rgb;
866                         break;
867                 case CMP_NODE_VALTORGB:
868                         ntype->butfunc= node_buts_valtorgb;
869                         break;
870                 case CMP_NODE_BLUR:
871                         ntype->butfunc= node_composit_buts_blur;
872                         break;
873                 case CMP_NODE_FILTER:
874                         ntype->butfunc= node_composit_buts_filter;
875                         break;
876                 case CMP_NODE_MAP_VALUE:
877                         ntype->butfunc= node_composit_buts_map_value;
878                         break;
879                 default:
880                         ntype->butfunc= NULL;
881         }
882 }
883
884
885 /* ******* init draw callbacks for all tree types, only called in usiblender.c, once ************* */
886
887 void init_node_butfuncs(void)
888 {
889         bNodeType **typedefs;
890         
891         /* shader nodes */
892         typedefs= node_all_shaders;             /* BKE_node.h */
893         while( *typedefs) {
894                 node_shader_set_butfunc(*typedefs);
895                 typedefs++;
896         }
897         /* composit nodes */
898         typedefs= node_all_composit;            /* BKE_node.h */
899         while( *typedefs) {
900                 node_composit_set_butfunc(*typedefs);
901                 typedefs++;
902         }
903 }
904
905 /* ************** Generic drawing ************** */
906
907 static void draw_nodespace_grid(SpaceNode *snode)
908 {
909         float start, step= 25.0f;
910
911         BIF_ThemeColorShade(TH_BACK, -10);
912         
913         start= snode->v2d.cur.xmin -fmod(snode->v2d.cur.xmin, step);
914         
915         glBegin(GL_LINES);
916         for(; start<snode->v2d.cur.xmax; start+=step) {
917                 glVertex2f(start, snode->v2d.cur.ymin);
918                 glVertex2f(start, snode->v2d.cur.ymax);
919         }
920
921         start= snode->v2d.cur.ymin -fmod(snode->v2d.cur.ymin, step);
922         for(; start<snode->v2d.cur.ymax; start+=step) {
923                 glVertex2f(snode->v2d.cur.xmin, start);
924                 glVertex2f(snode->v2d.cur.xmax, start);
925         }
926         
927         /* X and Y axis */
928         BIF_ThemeColorShade(TH_BACK, -18);
929         glVertex2f(0.0f, snode->v2d.cur.ymin);
930         glVertex2f(0.0f, snode->v2d.cur.ymax);
931         glVertex2f(snode->v2d.cur.xmin, 0.0f);
932         glVertex2f(snode->v2d.cur.xmax, 0.0f);
933         
934         glEnd();
935 }
936
937
938 static void nodeshadow(rctf *rct, float radius, float aspect, int select)
939 {
940         float rad;
941         float a;
942         char alpha= 2;
943         
944         glEnable(GL_BLEND);
945         
946         if(radius > (rct->ymax-rct->ymin-10.0f)/2.0f)
947                 rad= (rct->ymax-rct->ymin-10.0f)/2.0f;
948         else
949                 rad= radius;
950         
951         if(select) a= 10.0f*aspect; else a= 7.0f*aspect;
952         for(; a>0.0f; a-=aspect) {
953                 /* alpha ranges from 2 to 20 or so */
954                 glColor4ub(0, 0, 0, alpha);
955                 alpha+= 2;
956                 
957                 gl_round_box(GL_POLYGON, rct->xmin - a, rct->ymin - a, rct->xmax + a, rct->ymax-10.0f + a, rad+a);
958         }
959         
960         /* outline emphasis */
961         glEnable( GL_LINE_SMOOTH );
962         glColor4ub(0, 0, 0, 100);
963         gl_round_box(GL_LINE_LOOP, rct->xmin-0.5f, rct->ymin-0.5f, rct->xmax+0.5f, rct->ymax+0.5f, radius);
964         glDisable( GL_LINE_SMOOTH );
965         
966         glDisable(GL_BLEND);
967 }
968
969 /* nice AA filled circle */
970 static void socket_circle_draw(float x, float y, float size, int type, int select)
971 {
972         /* 16 values of sin function */
973         static float si[16] = {
974                 0.00000000, 0.39435585,0.72479278,0.93775213,
975                 0.99871650,0.89780453,0.65137248,0.29936312,
976                 -0.10116832,-0.48530196,-0.79077573,-0.96807711,
977                 -0.98846832,-0.84864425,-0.57126821,-0.20129852
978         };
979         /* 16 values of cos function */
980         static float co[16] ={
981                 1.00000000,0.91895781,0.68896691,0.34730525,
982                 -0.05064916,-0.44039415,-0.75875812,-0.95413925,
983                 -0.99486932,-0.87434661,-0.61210598,-0.25065253,
984                 0.15142777,0.52896401,0.82076344,0.97952994,
985         };
986         int a;
987         
988         if(select==0) {
989                 if(type==-1)
990                         glColor3ub(0, 0, 0);
991                 else if(type==SOCK_VALUE)
992                         glColor3ub(160, 160, 160);
993                 else if(type==SOCK_VECTOR)
994                         glColor3ub(100, 100, 200);
995                 else if(type==SOCK_RGBA)
996                         glColor3ub(200, 200, 40);
997                 else 
998                         glColor3ub(100, 200, 100);
999         }
1000         else {
1001                 if(type==SOCK_VALUE)
1002                         glColor3ub(200, 200, 200);
1003                 else if(type==SOCK_VECTOR)
1004                         glColor3ub(140, 140, 240);
1005                 else if(type==SOCK_RGBA)
1006                         glColor3ub(240, 240, 100);
1007                 else 
1008                         glColor3ub(140, 240, 140);
1009         }
1010         
1011         glBegin(GL_POLYGON);
1012         for(a=0; a<16; a++)
1013                 glVertex2f(x+size*si[a], y+size*co[a]);
1014         glEnd();
1015         
1016         glColor4ub(0, 0, 0, 150);
1017         glEnable(GL_BLEND);
1018         glEnable( GL_LINE_SMOOTH );
1019         glBegin(GL_LINE_LOOP);
1020         for(a=0; a<16; a++)
1021                 glVertex2f(x+size*si[a], y+size*co[a]);
1022         glEnd();
1023         glDisable( GL_LINE_SMOOTH );
1024         glDisable(GL_BLEND);
1025 }
1026
1027 /* not a callback */
1028 static void node_draw_preview(bNodePreview *preview, rctf *prv)
1029 {
1030         float scale= (prv->xmax-prv->xmin)/((float)preview->xsize);
1031         float centx= prv->xmin + 0.5*(prv->xmax-prv->xmin);
1032         float centy= prv->ymin + 0.5*(prv->ymax-prv->ymin);
1033         
1034         /* draw standard bacdrop to show alpha */
1035         glBegin(GL_TRIANGLES);
1036         glColor3f(0.625f, 0.625f, 0.625f);
1037         glVertex2f(prv->xmin, prv->ymin);
1038         glVertex2f(prv->xmax, prv->ymin);
1039         glVertex2f(centx, centy);
1040         glVertex2f(prv->xmin, prv->ymax);
1041         glVertex2f(prv->xmax, prv->ymax);
1042         glVertex2f(centx, centy);
1043         
1044         glColor3f(0.25f, 0.25f, 0.25f);
1045         glVertex2f(prv->xmin, prv->ymin);
1046         glVertex2f(prv->xmin, prv->ymax);
1047         glVertex2f(centx, centy);
1048         glVertex2f(prv->xmax, prv->ymin);
1049         glVertex2f(prv->xmax, prv->ymax);
1050         glVertex2f(centx, centy);
1051         glEnd();
1052         
1053         glPixelZoom(scale, scale);
1054         glEnable(GL_BLEND);
1055         
1056         glaDrawPixelsTex(prv->xmin, prv->ymin, preview->xsize, preview->ysize, GL_FLOAT, preview->rect);
1057         
1058         glDisable(GL_BLEND);
1059         glPixelZoom(1.0f, 1.0f);
1060         
1061 }
1062
1063 /* based on settings in node, sets drawing rect info. each redraw! */
1064 static void node_update_hidden(bNode *node)
1065 {
1066         bNodeSocket *nsock;
1067         float rad, drad, hiddenrad= HIDDEN_RAD;
1068         int totin=0, totout=0, tot;
1069         
1070         /* calculate minimal radius */
1071         for(nsock= node->inputs.first; nsock; nsock= nsock->next)
1072                 if(!(nsock->flag & SOCK_HIDDEN))
1073                         totin++;
1074         for(nsock= node->outputs.first; nsock; nsock= nsock->next)
1075                 if(!(nsock->flag & SOCK_HIDDEN))
1076                         totout++;
1077         
1078         tot= MAX2(totin, totout);
1079         if(tot>4) {
1080                 hiddenrad += 5.0*(float)(tot-4);
1081         }
1082         
1083         node->totr.xmin= node->locx;
1084         node->totr.xmax= node->locx + 3*hiddenrad + node->miniwidth;
1085         node->totr.ymax= node->locy + (hiddenrad - 0.5f*NODE_DY);
1086         node->totr.ymin= node->totr.ymax - 2*hiddenrad;
1087         
1088         /* output sockets */
1089         rad=drad= M_PI/(1.0f + (float)totout);
1090         
1091         for(nsock= node->outputs.first; nsock; nsock= nsock->next) {
1092                 if(!(nsock->flag & SOCK_HIDDEN)) {
1093                         nsock->locx= node->totr.xmax - hiddenrad + sin(rad)*hiddenrad;
1094                         nsock->locy= node->totr.ymin + hiddenrad + cos(rad)*hiddenrad;
1095                         rad+= drad;
1096                 }
1097         }
1098         
1099         /* input sockets */
1100         rad=drad= - M_PI/(1.0f + (float)totin);
1101         
1102         for(nsock= node->inputs.first; nsock; nsock= nsock->next) {
1103                 if(!(nsock->flag & SOCK_HIDDEN)) {
1104                         nsock->locx= node->totr.xmin + hiddenrad + sin(rad)*hiddenrad;
1105                         nsock->locy= node->totr.ymin + hiddenrad + cos(rad)*hiddenrad;
1106                         rad+= drad;
1107                 }
1108         }
1109 }
1110
1111 /* based on settings in node, sets drawing rect info. each redraw! */
1112 static void node_update(bNode *node)
1113 {
1114         bNodeSocket *nsock;
1115         float dy= node->locy;
1116         
1117         /* header */
1118         dy-= NODE_DY;
1119         
1120         /* little bit space in top */
1121         if(node->outputs.first)
1122                 dy-= NODE_DYS/2;
1123         
1124         /* output sockets */
1125         for(nsock= node->outputs.first; nsock; nsock= nsock->next) {
1126                 if(!(nsock->flag & SOCK_HIDDEN)) {
1127                         nsock->locx= node->locx + node->width;
1128                         nsock->locy= dy - NODE_DYS;
1129                         dy-= NODE_DY;
1130                 }
1131         }
1132         
1133         node->prvr.xmin= node->butr.xmin= node->locx + NODE_DYS;
1134         node->prvr.xmax= node->butr.xmax= node->locx + node->width- NODE_DYS;
1135         
1136         /* preview rect? */
1137         if(node->flag & NODE_PREVIEW) {
1138                 /* only recalculate size when there's a preview actually, otherwise we use stored result */
1139                 if(node->preview && node->preview->rect) {
1140                         float aspect= 1.0f;
1141                         
1142                         if(node->preview && node->preview->xsize && node->preview->ysize) 
1143                                 aspect= (float)node->preview->ysize/(float)node->preview->xsize;
1144                         
1145                         dy-= NODE_DYS/2;
1146                         node->prvr.ymax= dy;
1147                         node->prvr.ymin= dy - aspect*(node->width-NODE_DY);
1148                         dy= node->prvr.ymin - NODE_DYS/2;
1149                 }
1150                 else {
1151                         float oldh= node->prvr.ymax - node->prvr.ymin;
1152                         if(oldh==0.0f)
1153                                 oldh= node->width-NODE_DY;
1154                         dy-= NODE_DYS/2;
1155                         node->prvr.ymax= dy;
1156                         node->prvr.ymin= dy - oldh;
1157                         dy= node->prvr.ymin - NODE_DYS/2;
1158                 }
1159         }
1160         
1161         /* buttons rect? */
1162         if((node->flag & NODE_OPTIONS) && node->typeinfo->butfunc) {
1163                 dy-= NODE_DYS/2;
1164                 node->butr.ymax= dy;
1165                 node->butr.ymin= dy - (float)node->typeinfo->butfunc(NULL, NULL, node, NULL);
1166                 dy= node->butr.ymin - NODE_DYS/2;
1167         }
1168         
1169         /* input sockets */
1170         for(nsock= node->inputs.first; nsock; nsock= nsock->next) {
1171                 if(!(nsock->flag & SOCK_HIDDEN)) {
1172                         nsock->locx= node->locx;
1173                         nsock->locy= dy - NODE_DYS;
1174                         dy-= NODE_DY;
1175                 }
1176         }
1177         
1178         /* little bit space in end */
1179         if(node->inputs.first || (node->flag & (NODE_OPTIONS|NODE_PREVIEW))==0 )
1180                 dy-= NODE_DYS/2;
1181         
1182         node->totr.xmin= node->locx;
1183         node->totr.xmax= node->locx + node->width;
1184         node->totr.ymax= node->locy;
1185         node->totr.ymin= dy;
1186 }
1187
1188 /* based on settings in node, sets drawing rect info. each redraw! */
1189 /* note: this assumes only 1 group at a time is drawn (linked data) */
1190 /* in node->totr the entire boundbox for the group is stored */
1191 static void node_update_group(bNode *gnode)
1192 {
1193         bNodeTree *ngroup= (bNodeTree *)gnode->id;
1194         bNode *node;
1195         bNodeSocket *nsock;
1196         rctf *rect= &gnode->totr;
1197         int counter;
1198         
1199         /* center them, is a bit of abuse of locx and locy though */
1200         for(node= ngroup->nodes.first; node; node= node->next) {
1201                 node->locx+= gnode->locx;
1202                 node->locy+= gnode->locy;
1203                 if(node->flag & NODE_HIDDEN)
1204                         node_update_hidden(node);
1205                 else
1206                         node_update(node);
1207                 node->locx-= gnode->locx;
1208                 node->locy-= gnode->locy;
1209         }
1210         counter= 1;
1211         for(node= ngroup->nodes.first; node; node= node->next) {
1212                 if(counter) {
1213                         *rect= node->totr;
1214                         counter= 0;
1215                 }
1216                 else
1217                         BLI_union_rctf(rect, &node->totr);
1218         }
1219         if(counter==1) return;  /* should be prevented? */
1220         
1221         rect->xmin-= NODE_DY;
1222         rect->ymin-= NODE_DY;
1223         rect->xmax+= NODE_DY;
1224         rect->ymax+= NODE_DY;
1225         
1226         /* output sockets */
1227         for(nsock= gnode->outputs.first; nsock; nsock= nsock->next) {
1228                 nsock->locx= rect->xmax;
1229                 nsock->locy= nsock->tosock->locy;
1230         }
1231         
1232         /* input sockets */
1233         for(nsock= gnode->inputs.first; nsock; nsock= nsock->next) {
1234                 nsock->locx= rect->xmin;
1235                 nsock->locy= nsock->tosock->locy;
1236         }
1237 }
1238
1239 static void node_scaling_widget(int color_id, float aspect, float xmin, float ymin, float xmax, float ymax)
1240 {
1241         float dx;
1242         float dy;
1243         
1244         dx= 0.5f*(xmax-xmin);
1245         dy= 0.5f*(ymax-ymin);
1246         
1247         BIF_ThemeColorShade(color_id, +30);     
1248         fdrawline(xmin, ymin, xmax, ymax);
1249         fdrawline(xmin+dx, ymin, xmax, ymax-dy);
1250         
1251         BIF_ThemeColorShade(color_id, -10);
1252         fdrawline(xmin, ymin+aspect, xmax, ymax+aspect);
1253         fdrawline(xmin+dx, ymin+aspect, xmax, ymax-dy+aspect);
1254 }
1255
1256 static int node_get_colorid(bNode *node)
1257 {
1258         if(node->typeinfo->nclass==NODE_CLASS_INPUT)
1259                 return TH_NODE_IN_OUT;
1260         if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) {
1261                 if(node->flag & NODE_DO_OUTPUT)
1262                         return TH_NODE_IN_OUT;
1263                 else
1264                         return TH_NODE;
1265         }
1266         if(node->typeinfo->nclass==NODE_CLASS_GENERATOR)
1267                 return TH_NODE_GENERATOR;
1268         if(node->typeinfo->nclass==NODE_CLASS_OPERATOR)
1269                 return TH_NODE_OPERATOR;
1270         if(node->typeinfo->nclass==NODE_CLASS_GROUP)
1271                 return TH_NODE_GROUP;
1272         return TH_NODE;
1273 }
1274
1275 static void node_draw_basis(ScrArea *sa, SpaceNode *snode, bNode *node)
1276 {
1277         bNodeSocket *sock;
1278         uiBut *bt;
1279         rctf *rct= &node->totr;
1280         float slen, iconofs;
1281         int ofs, color_id= node_get_colorid(node);
1282         
1283         uiSetRoundBox(15-4);
1284         nodeshadow(rct, BASIS_RAD, snode->aspect, node->flag & SELECT);
1285         
1286         /* header */
1287         if(color_id==TH_NODE)
1288                 BIF_ThemeColorShade(color_id, -20);
1289         else
1290                 BIF_ThemeColor(color_id);
1291                 
1292         uiSetRoundBox(3);
1293         uiRoundBox(rct->xmin, rct->ymax-NODE_DY, rct->xmax, rct->ymax, BASIS_RAD);
1294         
1295         /* show/hide icons, note this sequence is copied in editnode.c */
1296         iconofs= rct->xmax;
1297         
1298         if(node->typeinfo->flag & NODE_PREVIEW) {
1299                 int icon_id;
1300                 
1301                 if(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT))
1302                         icon_id= ICON_MATERIAL;
1303                 else
1304                         icon_id= ICON_MATERIAL_DEHLT;
1305                 iconofs-= 18.0f;
1306                 glEnable(GL_BLEND);
1307                 BIF_icon_set_aspect(icon_id, snode->aspect);
1308                 BIF_icon_draw_blended(iconofs, rct->ymax-NODE_DY+2, icon_id, 0, -60);
1309                 glDisable(GL_BLEND);
1310         }
1311         if(node->type == NODE_GROUP) {
1312                 iconofs-= 18.0f;
1313                 glEnable(GL_BLEND);
1314                 BIF_icon_set_aspect(ICON_NODE, snode->aspect);
1315                 BIF_icon_draw_blended(iconofs, rct->ymax-NODE_DY+2, ICON_NODE, 0, -60);
1316                 glDisable(GL_BLEND);
1317         }
1318         if(node->typeinfo->flag & NODE_OPTIONS) {
1319                 iconofs-= 18.0f;
1320                 glEnable(GL_BLEND);
1321                 BIF_icon_set_aspect(ICON_BUTS, snode->aspect);
1322                 BIF_icon_draw_blended(iconofs, rct->ymax-NODE_DY+2, ICON_BUTS, 0, -60);
1323                 glDisable(GL_BLEND);
1324         }
1325         if(node->outputs.first) {
1326                 int shade;
1327                 /* socket selector */
1328                 iconofs-= 18.0f;
1329                 if(node_has_hidden_sockets(node))
1330                         shade= -40;
1331                 else
1332                         shade= -90;
1333                 glEnable(GL_BLEND);
1334                 BIF_icon_set_aspect(ICON_PLUS, snode->aspect);
1335                 BIF_icon_draw_blended(iconofs, rct->ymax-NODE_DY+2, ICON_PLUS, 0, shade);
1336                 glDisable(GL_BLEND);
1337         }
1338         
1339         /* title */
1340         if(node->flag & SELECT) 
1341                 BIF_ThemeColor(TH_TEXT_HI);
1342         else
1343                 BIF_ThemeColorBlendShade(TH_TEXT, color_id, 0.4, 10);
1344         
1345         /* open/close entirely? */
1346         ui_draw_tria_icon(rct->xmin+8.0f, rct->ymax-NODE_DY+4.0f, snode->aspect, 'v');
1347
1348         if(node->flag & SELECT) 
1349                 BIF_ThemeColor(TH_TEXT_HI);
1350         else
1351                 BIF_ThemeColor(TH_TEXT);
1352         
1353         ui_rasterpos_safe(rct->xmin+19.0f, rct->ymax-NODE_DY+5.0f, snode->aspect);
1354         snode_drawstring(snode, node->name, (int)(iconofs - rct->xmin-18.0f));
1355                                          
1356         /* body */
1357         BIF_ThemeColor(TH_NODE);        
1358         uiSetRoundBox(8);
1359         uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax-NODE_DY, BASIS_RAD);
1360         
1361         /* scaling indicator */
1362         node_scaling_widget(TH_NODE, snode->aspect, rct->xmax-BASIS_RAD*snode->aspect, rct->ymin, rct->xmax, rct->ymin+BASIS_RAD*snode->aspect);
1363
1364         /* outline active emphasis */
1365         if(node->flag & NODE_ACTIVE) {
1366                 glEnable(GL_BLEND);
1367                 glColor4ub(200, 200, 200, 140);
1368                 uiSetRoundBox(15-4);
1369                 gl_round_box(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
1370                 glDisable(GL_BLEND);
1371         }
1372         
1373         /* we make buttons for input sockets, if... */
1374         if(node->flag & NODE_OPTIONS) {
1375                 if(node->inputs.first || node->typeinfo->butfunc) {
1376                         uiBlock *block= uiNewBlock(NULL, "node buttons", UI_EMBOSS, UI_HELV, sa->win);
1377                         BLI_addtail(&sa->uiblocks, block);
1378                         uiBlockSetFlag(block, UI_BLOCK_NO_HILITE);
1379                         if(snode->id)
1380                                 uiSetButLock(snode->id->lib!=NULL, "Can't edit library data");
1381                         node->block= block;
1382                 }
1383         }
1384         
1385         /* hurmf... another candidate for callback, have to see how this works first */
1386         if(node->id && node->block && snode->treetype==NTREE_SHADER)
1387                 nodeShaderSynchronizeID(node, 0);
1388         
1389         /* socket inputs, buttons */
1390         for(sock= node->inputs.first; sock; sock= sock->next) {
1391                 if(!(sock->flag & SOCK_HIDDEN)) {
1392                         socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT);
1393                         
1394                         if(node->block && sock->link==NULL) {
1395                                 float *butpoin= sock->ns.vec;
1396                                 
1397                                 if(node->type==NODE_GROUP && sock->tosock)
1398                                         butpoin= sock->tosock->ns.vec;
1399                                 
1400                                 if(sock->type==SOCK_VALUE) {
1401                                         bt= uiDefButF(node->block, NUM, B_NODE_EXEC+node->nr, sock->name, 
1402                                                   (short)sock->locx+NODE_DYS, (short)(sock->locy)-9, (short)node->width-NODE_DY, 17, 
1403                                                   butpoin, 0.0f, 1.0f, 10, 2, "");
1404                                         uiButSetFunc(bt, node_sync_cb, snode, node);
1405                                 }
1406                                 else if(sock->type==SOCK_VECTOR) {
1407                                         uiDefBlockBut(node->block, socket_vector_menu, butpoin, sock->name, 
1408                                                   (short)sock->locx+NODE_DYS, (short)sock->locy-9, (short)node->width-NODE_DY, 17, 
1409                                                   "");
1410                                 }
1411                                 else if(node->block && sock->type==SOCK_RGBA) {
1412                                         short labelw= node->width-NODE_DY-40, width;
1413                                         
1414                                         if(labelw>0) width= 40; else width= node->width-NODE_DY;
1415                                         
1416                                         bt= uiDefButF(node->block, COL, B_NODE_EXEC+node->nr, "", 
1417                                                 (short)(sock->locx+NODE_DYS), (short)sock->locy-8, width, 15, 
1418                                                    butpoin, 0, 0, 0, 0, "");
1419                                         uiButSetFunc(bt, node_sync_cb, snode, node);
1420                                         
1421                                         if(labelw>0) uiDefBut(node->block, LABEL, 0, sock->name, 
1422                                                                                    (short)(sock->locx+NODE_DYS) + 40, (short)sock->locy-8, labelw, 15, 
1423                                                                                    NULL, 0, 0, 0, 0, "");
1424                                 }
1425                         }
1426                         else {
1427                                 BIF_ThemeColor(TH_TEXT);
1428                                 ui_rasterpos_safe(sock->locx+8.0f, sock->locy-5.0f, snode->aspect);
1429                                 BIF_DrawString(snode->curfont, sock->name, 0);
1430                         }
1431                 }
1432         }
1433         
1434         /* socket outputs */
1435         for(sock= node->outputs.first; sock; sock= sock->next) {
1436                 if(!(sock->flag & SOCK_HIDDEN)) {
1437                         socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT);
1438                         
1439                         BIF_ThemeColor(TH_TEXT);
1440                         ofs= 0;
1441                         slen= snode->aspect*BIF_GetStringWidth(snode->curfont, sock->name, 0);
1442                         while(slen > node->width) {
1443                                 ofs++;
1444                                 slen= snode->aspect*BIF_GetStringWidth(snode->curfont, sock->name+ofs, 0);
1445                         }
1446                         ui_rasterpos_safe(sock->locx-8.0f-slen, sock->locy-5.0f, snode->aspect);
1447                         BIF_DrawString(snode->curfont, sock->name+ofs, 0);
1448                 }
1449         }
1450         
1451         /* preview */
1452         if(node->flag & NODE_PREVIEW)
1453                 if(node->preview && node->preview->rect)
1454                         node_draw_preview(node->preview, &node->prvr);
1455                 
1456         /* buttons */
1457         if(node->flag & NODE_OPTIONS) {
1458                 if(node->typeinfo->butfunc) {
1459                         node->typeinfo->butfunc(node->block, snode->nodetree, node, &node->butr);
1460                 }
1461                 uiDrawBlock(node->block);
1462         }
1463
1464 }
1465
1466 void node_draw_hidden(SpaceNode *snode, bNode *node)
1467 {
1468         bNodeSocket *sock;
1469         rctf *rct= &node->totr;
1470         float dx, centy= 0.5f*(rct->ymax+rct->ymin);
1471         float hiddenrad= 0.5f*(rct->ymax-rct->ymin);
1472         int color_id= node_get_colorid(node);
1473         
1474         /* shadow */
1475         uiSetRoundBox(15);
1476         nodeshadow(rct, hiddenrad, snode->aspect, node->flag & SELECT);
1477
1478         /* body */
1479         BIF_ThemeColor(color_id);       
1480         uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
1481         
1482         /* outline active emphasis */
1483         if(node->flag & NODE_ACTIVE) {
1484                 glEnable(GL_BLEND);
1485                 glColor4ub(200, 200, 200, 140);
1486                 gl_round_box(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
1487                 glDisable(GL_BLEND);
1488         }
1489         
1490         /* title */
1491         if(node->flag & SELECT) 
1492                 BIF_ThemeColor(TH_TEXT_HI);
1493         else
1494                 BIF_ThemeColorBlendShade(TH_TEXT, color_id, 0.4, 10);
1495         
1496         /* open entirely icon */
1497         ui_draw_tria_icon(rct->xmin+9.0f, centy-6.0f, snode->aspect, 'h');      
1498         
1499         if(node->flag & SELECT) 
1500                 BIF_ThemeColor(TH_TEXT_HI);
1501         else
1502                 BIF_ThemeColor(TH_TEXT);
1503         
1504         if(node->miniwidth>0.0f) {
1505                 ui_rasterpos_safe(rct->xmin+21.0f, centy-4.0f, snode->aspect);
1506                 snode_drawstring(snode, node->name, (int)(rct->xmax - rct->xmin-18.0f -12.0f));
1507         }       
1508
1509         /* scale widget thing */
1510         BIF_ThemeColorShade(color_id, -10);     
1511         dx= 10.0f;
1512         fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
1513         fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
1514         
1515         BIF_ThemeColorShade(color_id, +30);
1516         dx-= snode->aspect;
1517         fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
1518         fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
1519         
1520         /* sockets */
1521         for(sock= node->inputs.first; sock; sock= sock->next) {
1522                 if(!(sock->flag & SOCK_HIDDEN))
1523                         socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT);
1524         }
1525         
1526         for(sock= node->outputs.first; sock; sock= sock->next) {
1527                 if(!(sock->flag & SOCK_HIDDEN))
1528                         socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT);
1529         }
1530 }
1531
1532 /* note; this is used for fake links in groups too */
1533 void node_draw_link(SpaceNode *snode, bNodeLink *link)
1534 {
1535         float vec[4][3];
1536         float dist, spline_step, mx=0.0f, my=0.0f;
1537         int curve_res, do_shaded= 1, th_col1= TH_WIRE, th_col2= TH_WIRE;
1538         
1539         if(link->fromnode==NULL && link->tonode==NULL)
1540                 return;
1541         
1542         /* this is dragging link */
1543         if(link->fromnode==NULL || link->tonode==NULL) {
1544                 short mval[2];
1545                 getmouseco_areawin(mval);
1546                 areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
1547                 BIF_ThemeColor(TH_WIRE);
1548                 do_shaded= 0;
1549         }
1550         else {
1551                 /* a bit ugly... but thats how we detect the internal group links */
1552                 if(link->fromnode==link->tonode) {
1553                         BIF_ThemeColorBlend(TH_BACK, TH_WIRE, 0.25f);
1554                         do_shaded= 0;
1555                 }
1556                 else {
1557                         /* check cyclic */
1558                         if(link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF) {
1559                                 if(link->fromnode->flag & SELECT)
1560                                         th_col1= TH_EDGE_SELECT;
1561                                 if(link->tonode->flag & SELECT)
1562                                         th_col2= TH_EDGE_SELECT;
1563                         }                               
1564                         else {
1565                                 BIF_ThemeColor(TH_REDALERT);
1566                                 do_shaded= 0;
1567                         }
1568                 }
1569         }
1570         
1571         vec[0][2]= vec[1][2]= vec[2][2]= vec[3][2]= 0.0; /* only 2d spline, set the Z to 0*/
1572         
1573         /* in v0 and v3 we put begin/end points */
1574         if(link->fromnode) {
1575                 vec[0][0]= link->fromsock->locx;
1576                 vec[0][1]= link->fromsock->locy;
1577         }
1578         else {
1579                 vec[0][0]= mx;
1580                 vec[0][1]= my;
1581         }
1582         if(link->tonode) {
1583                 vec[3][0]= link->tosock->locx;
1584                 vec[3][1]= link->tosock->locy;
1585         }
1586         else {
1587                 vec[3][0]= mx;
1588                 vec[3][1]= my;
1589         }
1590         
1591         dist= 0.5f*ABS(vec[0][0] - vec[3][0]);
1592         
1593         /* check direction later, for top sockets */
1594         vec[1][0]= vec[0][0]+dist;
1595         vec[1][1]= vec[0][1];
1596         
1597         vec[2][0]= vec[3][0]-dist;
1598         vec[2][1]= vec[3][1];
1599         
1600         if( MIN4(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) > G.v2d->cur.xmax); /* clipped */  
1601         else if ( MAX4(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) < G.v2d->cur.xmin); /* clipped */
1602         else {
1603                 curve_res = 24;
1604                 
1605                 /* we can reuse the dist variable here to increment the GL curve eval amount*/
1606                 dist = 1.0f/curve_res;
1607                 spline_step = 0.0f;
1608                 
1609                 glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, vec[0]);
1610                 glBegin(GL_LINE_STRIP);
1611                 while (spline_step < 1.000001f) {
1612                         if(do_shaded)
1613                                 BIF_ThemeColorBlend(th_col1, th_col2, spline_step);
1614                         glEvalCoord1f(spline_step);
1615                         spline_step += dist;
1616                 }
1617                 glEnd();
1618         }
1619 }
1620
1621 static void node_draw_nodetree(ScrArea *sa, SpaceNode *snode, bNodeTree *ntree)
1622 {
1623         bNode *node;
1624         bNodeLink *link;
1625         int a;
1626         
1627         if(ntree==NULL) return;         /* groups... */
1628         
1629         /* node lines */
1630         glEnable(GL_BLEND);
1631         glEnable( GL_LINE_SMOOTH );
1632         for(link= ntree->links.first; link; link= link->next)
1633                 node_draw_link(snode, link);
1634         glDisable(GL_BLEND);
1635         glDisable( GL_LINE_SMOOTH );
1636         
1637         /* not selected first */
1638         for(a=0, node= ntree->nodes.first; node; node= node->next, a++) {
1639                 node->block= NULL;      /* were freed */
1640                 node->nr= a;            /* index of node in list, used for exec event code */
1641                 if(!(node->flag & SELECT)) {
1642                         if(node->flag & NODE_GROUP_EDIT);
1643                         else if(node->flag & NODE_HIDDEN)
1644                                 node_draw_hidden(snode, node);
1645                         else
1646                                 node_draw_basis(sa, snode, node);
1647                 }
1648         }
1649         
1650         /* selected */
1651         for(node= ntree->nodes.first; node; node= node->next) {
1652                 if(node->flag & SELECT) {
1653                         if(node->flag & NODE_GROUP_EDIT);
1654                         else if(node->flag & NODE_HIDDEN)
1655                                 node_draw_hidden(snode, node);
1656                         else
1657                                 node_draw_basis(sa, snode, node);
1658                 }
1659         }       
1660 }
1661
1662 /* fake links from groupnode to internal nodes */
1663 static void node_draw_group_links(SpaceNode *snode, bNode *gnode)
1664 {
1665         bNodeLink fakelink;
1666         bNodeSocket *sock;
1667         
1668         glEnable(GL_BLEND);
1669         glEnable( GL_LINE_SMOOTH );
1670         
1671         fakelink.tonode= fakelink.fromnode= gnode;
1672         
1673         for(sock= gnode->inputs.first; sock; sock= sock->next) {
1674                 if(!(sock->flag & SOCK_HIDDEN)) {
1675                         if(sock->tosock) {
1676                                 fakelink.fromsock= sock;
1677                                 fakelink.tosock= sock->tosock;
1678                                 node_draw_link(snode, &fakelink);
1679                         }
1680                 }
1681         }
1682         
1683         for(sock= gnode->outputs.first; sock; sock= sock->next) {
1684                 if(!(sock->flag & SOCK_HIDDEN)) {
1685                         if(sock->tosock) {
1686                                 fakelink.tosock= sock;
1687                                 fakelink.fromsock= sock->tosock;
1688                                 node_draw_link(snode, &fakelink);
1689                         }
1690                 }
1691         }
1692         
1693         glDisable(GL_BLEND);
1694         glDisable( GL_LINE_SMOOTH );
1695 }
1696
1697 /* groups are, on creation, centered around 0,0 */
1698 static void node_draw_group(ScrArea *sa, SpaceNode *snode, bNode *gnode)
1699 {
1700         bNodeTree *ngroup= (bNodeTree *)gnode->id;
1701         bNodeSocket *sock;
1702         rctf rect= gnode->totr;
1703         
1704         /* backdrop header */
1705         glEnable(GL_BLEND);
1706         uiSetRoundBox(3);
1707         BIF_ThemeColorShadeAlpha(TH_NODE_GROUP, 0, -70);
1708         gl_round_box(GL_POLYGON, rect.xmin, rect.ymax, rect.xmax, rect.ymax+NODE_DY, BASIS_RAD);
1709         
1710         /* backdrop body */
1711         BIF_ThemeColorShadeAlpha(TH_BACK, -8, -70);
1712         uiSetRoundBox(12);
1713         gl_round_box(GL_POLYGON, rect.xmin, rect.ymin, rect.xmax, rect.ymax, BASIS_RAD);
1714         
1715         /* selection outline */
1716         uiSetRoundBox(15);
1717         glColor4ub(200, 200, 200, 140);
1718         glEnable( GL_LINE_SMOOTH );
1719         gl_round_box(GL_LINE_LOOP, rect.xmin, rect.ymin, rect.xmax, rect.ymax+NODE_DY, BASIS_RAD);
1720         glDisable( GL_LINE_SMOOTH );
1721         glDisable(GL_BLEND);
1722         
1723         /* backdrop title */
1724         BIF_ThemeColor(TH_TEXT_HI);
1725         ui_rasterpos_safe(rect.xmin+8.0f, rect.ymax+5.0f, snode->aspect);
1726         BIF_DrawString(snode->curfont, ngroup->id.name+2, 0);
1727         
1728         /* links from groupsockets to the internal nodes */
1729         node_draw_group_links(snode, gnode);
1730         
1731         /* group sockets */
1732         for(sock= gnode->inputs.first; sock; sock= sock->next)
1733                 if(!(sock->flag & SOCK_HIDDEN))
1734                         socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT);
1735         for(sock= gnode->outputs.first; sock; sock= sock->next)
1736                 if(!(sock->flag & SOCK_HIDDEN))
1737                         socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT);
1738
1739         /* and finally the whole tree */
1740         node_draw_nodetree(sa, snode, ngroup);
1741 }
1742
1743
1744 void drawnodespace(ScrArea *sa, void *spacedata)
1745 {
1746         SpaceNode *snode= sa->spacedata.first;
1747         float col[3];
1748         
1749         BIF_GetThemeColor3fv(TH_BACK, col);
1750         glClearColor(col[0], col[1], col[2], 0.0);
1751         glClear(GL_COLOR_BUFFER_BIT);
1752
1753         calc_scrollrcts(sa, &(snode->v2d), sa->winx, sa->winy);
1754         
1755         myortho2(snode->v2d.cur.xmin, snode->v2d.cur.xmax, snode->v2d.cur.ymin, snode->v2d.cur.ymax);
1756         bwin_clear_viewmat(sa->win);    /* clear buttons view */
1757         glLoadIdentity();
1758         
1759         /* always free, blocks here have no unique identifier (1 block per node) */
1760         uiFreeBlocksWin(&sa->uiblocks, sa->win);
1761
1762         /* only set once */
1763         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1764         glEnable(GL_MAP1_VERTEX_3);
1765
1766         /* aspect+font, set each time */
1767         snode->aspect= (snode->v2d.cur.xmax - snode->v2d.cur.xmin)/((float)sa->winx);
1768         snode->curfont= uiSetCurFont_ext(snode->aspect);
1769
1770         /* backdrop */
1771         draw_nodespace_grid(snode);
1772         
1773         /* nodes */
1774         snode_set_context(snode);
1775         
1776         if(snode->nodetree) {
1777                 bNode *node;
1778                 
1779                 /* for now, we set drawing coordinates on each redraw */
1780                 for(node= snode->nodetree->nodes.first; node; node= node->next) {
1781                         if(node->flag & NODE_GROUP_EDIT)
1782                                 node_update_group(node);
1783                         else if(node->flag & NODE_HIDDEN)
1784                                 node_update_hidden(node);
1785                         else
1786                                 node_update(node);
1787                 }
1788
1789                 node_draw_nodetree(sa, snode, snode->nodetree);
1790                         
1791                 /* active group */
1792                 for(node= snode->nodetree->nodes.first; node; node= node->next) {
1793                         if(node->flag & NODE_GROUP_EDIT)
1794                                 node_draw_group(sa, snode, node);
1795                 }
1796         }
1797         
1798         /* restore viewport (not needed yet) */
1799         mywinset(sa->win);
1800
1801         /* ortho at pixel level curarea */
1802         myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
1803
1804         draw_area_emboss(sa);
1805         curarea->win_swap= WIN_BACK_OK;
1806         
1807         /* in the end, this is a delayed previewrender test, to allow buttons to be first */
1808         if(snode->flag & SNODE_DO_PREVIEW) {
1809                 addafterqueue(sa->win, RENDERPREVIEW, 1);
1810                 snode->flag &= ~SNODE_DO_PREVIEW;
1811         }
1812 }