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