A couple of render improvements;
[blender.git] / source / blender / src / editnode.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 <stdio.h>
31 #include <stdlib.h>
32 #include <math.h>
33 #include <string.h>
34
35 #include "MEM_guardedalloc.h"
36
37 #include "DNA_action_types.h"
38 #include "DNA_image_types.h"
39 #include "DNA_ipo_types.h"
40 #include "DNA_object_types.h"
41 #include "DNA_material_types.h"
42 #include "DNA_node_types.h"
43 #include "DNA_space_types.h"
44 #include "DNA_screen_types.h"
45 #include "DNA_scene_types.h"
46 #include "DNA_userdef_types.h"
47
48 #include "BKE_global.h"
49 #include "BKE_image.h"
50 #include "BKE_library.h"
51 #include "BKE_main.h"
52 #include "BKE_node.h"
53 #include "BKE_material.h"
54 #include "BKE_scene.h"
55 #include "BKE_utildefines.h"
56
57 #include "BIF_editview.h"
58 #include "BIF_gl.h"
59 #include "BIF_graphics.h"
60 #include "BIF_interface.h"
61 #include "BIF_mywindow.h"
62 #include "BIF_previewrender.h"
63 #include "BIF_resources.h"
64 #include "BIF_renderwin.h"
65 #include "BIF_space.h"
66 #include "BIF_screen.h"
67 #include "BIF_toolbox.h"
68
69 #include "BSE_drawipo.h"
70 #include "BSE_edit.h"
71 #include "BSE_filesel.h"
72 #include "BSE_headerbuttons.h"
73 #include "BSE_node.h"
74
75 #include "BLI_blenlib.h"
76 #include "BLI_arithb.h"
77
78 #include "BDR_editobject.h"
79
80 #include "RE_pipeline.h"
81
82 #include "blendef.h"
83 #include "butspace.h"
84 #include "PIL_time.h"
85 #include "mydevice.h"
86
87
88 /* currently called from BIF_preview_changed */
89 void snode_tag_dirty(SpaceNode *snode)
90 {
91         bNode *node;
92         
93         if(snode->treetype==NTREE_SHADER) {
94                 if(snode->nodetree) {
95                         for(node= snode->nodetree->nodes.first; node; node= node->next) {
96                                 if(node->type==SH_NODE_OUTPUT)
97                                         node->lasty= 0;
98                         }
99                         snode->flag |= SNODE_DO_PREVIEW;        /* this adds an afterqueue on a redraw, to allow button previews to work first */
100                 }
101         }
102         allqueue(REDRAWNODE, 1);
103 }
104
105 static void shader_node_previewrender(ScrArea *sa, SpaceNode *snode)
106 {
107         bNode *node;
108         
109         if(snode->id==NULL) return;
110         if( ((Material *)snode->id )->use_nodes==0 ) return;
111
112         for(node= snode->nodetree->nodes.first; node; node= node->next) {
113                 if(node->type==SH_NODE_OUTPUT) {
114                         if(node->flag & NODE_DO_OUTPUT) {
115                                 if(node->lasty<PREVIEW_RENDERSIZE-2) {
116                                         RenderInfo ri;  
117 //                                      int test= node->lasty;
118                                         
119                                         ri.curtile = 0;
120                                         ri.tottile = 0;
121                                         ri.rect = NULL;
122                                         ri.pr_rectx = PREVIEW_RENDERSIZE;
123                                         ri.pr_recty = PREVIEW_RENDERSIZE;
124                                         
125                                         BIF_previewrender(snode->id, &ri, NULL, PR_DO_RENDER);  /* sends redraw event */
126                                         if(ri.rect) MEM_freeN(ri.rect);
127                                         
128                                         /* when not finished... */
129                                         if(ri.curtile<ri.tottile)
130                                                 addafterqueue(sa->win, RENDERPREVIEW, 1);
131 //                                      if(test!=node->lasty)
132 //                                              printf("node rendered to %d\n", node->lasty);
133
134                                         break;
135                                 }
136                         }
137                 }
138         }
139 }
140
141
142 static void snode_handle_recalc(SpaceNode *snode)
143 {
144         if(snode->treetype==NTREE_SHADER) {
145                 BIF_preview_changed(ID_MA);      /* signals buttons windows and node editors */
146         }
147         else if(snode->treetype==NTREE_COMPOSIT) {
148                 if(G.scene->use_nodes) {
149                         snode->nodetree->timecursor= set_timecursor;
150                         G.afbreek= 0;
151                         snode->nodetree->test_break= blender_test_break;
152
153                         ntreeCompositExecTree(snode->nodetree, &G.scene->r, 1); /* 1 is do_previews */
154                         
155                         snode->nodetree->timecursor= NULL;
156                         snode->nodetree->test_break= NULL;
157                         waitcursor(0);
158                         
159                         allqueue(REDRAWNODE, 1);
160                         allqueue(REDRAWIMAGE, 1);
161                         if(G.scene->r.scemode & R_DOCOMP) {
162                                 BIF_redraw_render_rect();       /* seems to screwup display? */
163                                 mywinset(curarea->win);
164                         }
165                 }
166         }
167 }
168
169 static void shader_node_event(SpaceNode *snode, short event)
170 {
171         switch(event) {
172                 case B_REDR:
173                         allqueue(REDRAWNODE, 1);
174                         break;
175                 default:
176                         /* B_NODE_EXEC */
177                         snode_handle_recalc(snode);
178                         break;
179                         
180         }
181 }
182
183 static void load_node_image(char *str)  /* called from fileselect */
184 {
185         SpaceNode *snode= curarea->spacedata.first;
186         bNode *node= nodeGetActive(snode->edittree);
187         Image *ima= NULL;
188         
189         ima= add_image(str);
190         if(ima) {
191                 if(node->id)
192                         node->id->us--;
193                 
194                 node->id= &ima->id;
195                 ima->id.us++;
196
197                 free_image_buffers(ima);        /* force read again */
198                 ima->ok= 1;
199                 
200                 NodeTagChanged(snode->edittree, node);
201                 snode_handle_recalc(snode);
202                 allqueue(REDRAWNODE, 0); 
203         }
204 }
205
206 static bNode *snode_get_editgroup(SpaceNode *snode)
207 {
208         bNode *gnode;
209         
210         /* get the groupnode */
211         for(gnode= snode->nodetree->nodes.first; gnode; gnode= gnode->next)
212                 if(gnode->flag & NODE_GROUP_EDIT)
213                         break;
214         return gnode;
215 }
216
217 /* node has to be of type render result */
218 /* is a bit clumsy copying renderdata here... scene nodes use render size of current render */
219 static void composite_node_render(SpaceNode *snode, bNode *node)
220 {
221         RenderData rd;
222         Scene *scene= NULL;
223         int scemode, actlay;
224         
225         /* the button press won't show up otherwise, button hilites disabled */
226         force_draw(0);
227         
228         if(node->id && node->id!=(ID *)G.scene) {
229                 scene= G.scene;
230                 set_scene_bg((Scene *)node->id);
231                 rd= G.scene->r;
232                 G.scene->r.xsch= scene->r.xsch;
233                 G.scene->r.ysch= scene->r.ysch;
234                 G.scene->r.size= scene->r.size;
235                 G.scene->r.mode &= ~(R_BORDER|R_DOCOMP);
236                 G.scene->r.mode |= scene->r.mode & R_BORDER;
237                 G.scene->r.border= scene->r.border;
238         }
239         
240         scemode= G.scene->r.scemode;
241         actlay= G.scene->r.actlay;
242         
243         G.scene->r.scemode |= R_SINGLE_LAYER;
244         G.scene->r.actlay= node->custom1;
245         
246         BIF_do_render(0);
247         
248         G.scene->r.scemode= scemode;
249         G.scene->r.actlay= actlay;
250
251         node->custom2= 0;
252         
253         if(scene) {
254                 G.scene->r= rd;
255                 set_scene_bg(scene);
256         }
257 }
258
259 static void composit_node_event(SpaceNode *snode, short event)
260 {
261         
262         switch(event) {
263                 case B_REDR:
264                         allqueue(REDRAWNODE, 1);
265                         break;
266                 case B_NODE_LOADIMAGE:
267                 {
268                         bNode *node= nodeGetActive(snode->edittree);
269                         char name[FILE_MAXDIR+FILE_MAXFILE];
270                         
271                         if(node->id)
272                                 strcpy(name, ((Image *)node->id)->name);
273                         else strcpy(name, U.textudir);
274                         
275                         activate_fileselect(FILE_SPECIAL, "SELECT IMAGE", name, load_node_image);
276                         break;
277                 }
278                 case B_NODE_TREE_EXEC:
279                         snode_handle_recalc(snode);
280                         break;          
281                 default:
282                         /* B_NODE_EXEC */
283                 {
284                         bNode *node= BLI_findlink(&snode->edittree->nodes, event-B_NODE_EXEC);
285                         if(node) {
286                                 NodeTagChanged(snode->edittree, node);
287                                 /* not the best implementation of the world... but we need it to work now :) */
288                                 if(node->type==CMP_NODE_R_RESULT && node->custom2)
289                                         composite_node_render(snode, node);
290                                 else {
291                                         node= snode_get_editgroup(snode);
292                                         if(node)
293                                                 NodeTagIDChanged(snode->nodetree, node->id);
294                                 }
295                                 snode_handle_recalc(snode);
296                         }
297                 }                       
298         }
299 }
300
301
302 /* assumes nothing being done in ntree yet, sets the default in/out node */
303 /* called from shading buttons or header */
304 void node_shader_default(Material *ma)
305 {
306         bNode *in, *out;
307         bNodeSocket *fromsock, *tosock;
308         
309         /* but lets check it anyway */
310         if(ma->nodetree) {
311                 printf("error in shader initialize\n");
312                 return;
313         }
314         
315         ma->nodetree= ntreeAddTree(NTREE_SHADER);
316         
317         out= nodeAddNodeType(ma->nodetree, SH_NODE_OUTPUT, NULL);
318         out->locx= 300.0f; out->locy= 300.0f;
319         
320         in= nodeAddNodeType(ma->nodetree, SH_NODE_MATERIAL, NULL);
321         in->locx= 10.0f; in->locy= 300.0f;
322         nodeSetActive(ma->nodetree, in);
323         
324         /* only a link from color to color */
325         fromsock= in->outputs.first;
326         tosock= out->inputs.first;
327         nodeAddLink(ma->nodetree, in, fromsock, out, tosock);
328         
329         ntreeSolveOrder(ma->nodetree);  /* needed for pointers */
330 }
331
332 /* assumes nothing being done in ntree yet, sets the default in/out node */
333 /* called from shading buttons or header */
334 void node_composit_default(Scene *sce)
335 {
336         bNode *in, *out1, *out2;
337         bNodeSocket *fromsock, *tosock;
338         
339         /* but lets check it anyway */
340         if(sce->nodetree) {
341                 printf("error in composit initialize\n");
342                 return;
343         }
344         
345         sce->nodetree= ntreeAddTree(NTREE_COMPOSIT);
346         
347         out1= nodeAddNodeType(sce->nodetree, CMP_NODE_VIEWER, NULL);
348         out1->locx= 300.0f; out1->locy= 200.0f;
349         out2= nodeAddNodeType(sce->nodetree, CMP_NODE_COMPOSITE, NULL);
350         out2->locx= 300.0f; out2->locy= 500.0f;
351         
352         in= nodeAddNodeType(sce->nodetree, CMP_NODE_R_RESULT, NULL);
353         in->locx= 10.0f; in->locy= 400.0f;
354         nodeSetActive(sce->nodetree, in);
355         
356         /* links from color to color */
357         fromsock= in->outputs.first;
358         tosock= out1->inputs.first;
359         nodeAddLink(sce->nodetree, in, fromsock, out1, tosock);
360         tosock= out2->inputs.first;
361         nodeAddLink(sce->nodetree, in, fromsock, out2, tosock);
362         
363         ntreeSolveOrder(sce->nodetree); /* needed for pointers */
364         
365         out1->id= find_id("IM", "Compositor");
366         if(out1->id==NULL) {
367                 Image *ima= alloc_libblock(&G.main->image, ID_IM, "Compositor");
368                 strcpy(ima->name, "Compositor");
369                 ima->ok= 1;
370                 ima->xrep= ima->yrep= 1;
371                 out1->id= &ima->id;
372         }
373 }
374
375 /* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */
376 void snode_set_context(SpaceNode *snode)
377 {
378         Object *ob= OBACT;
379         bNode *node= NULL;
380         
381         snode->nodetree= NULL;
382         snode->id= snode->from= NULL;
383         
384         if(snode->treetype==NTREE_SHADER) {
385                 /* need active object, or we allow pinning... */
386                 if(ob) {
387                         Material *ma= give_current_material(ob, ob->actcol);
388                         if(ma) {
389                                 snode->from= material_from(ob, ob->actcol);
390                                 snode->id= &ma->id;
391                                 snode->nodetree= ma->nodetree;
392                         }
393                 }
394         }
395         else if(snode->treetype==NTREE_COMPOSIT) {
396                 snode->from= NULL;
397                 snode->id= &G.scene->id;
398                 snode->nodetree= G.scene->nodetree;
399         }
400         
401         /* find editable group */
402         if(snode->nodetree)
403                 for(node= snode->nodetree->nodes.first; node; node= node->next)
404                         if(node->flag & NODE_GROUP_EDIT)
405                                 break;
406         
407         if(node && node->id)
408                 snode->edittree= (bNodeTree *)node->id;
409         else
410                 snode->edittree= snode->nodetree;
411 }
412
413 static void node_set_active(SpaceNode *snode, bNode *node)
414 {
415         
416         nodeSetActive(snode->edittree, node);
417         
418         if(node->type!=NODE_GROUP) {
419                 
420                 /* tree specific activate calls */
421                 if(snode->treetype==NTREE_SHADER) {
422                         
423                         /* when we select a material, active texture is cleared, for buttons */
424                         if(node->id && GS(node->id->name)==ID_MA)
425                                 nodeClearActiveID(snode->edittree, ID_TE);
426                         if(node->id)
427                                 BIF_preview_changed(-1);        /* temp hack to force texture preview to update */
428                         
429                         allqueue(REDRAWBUTSSHADING, 1);
430                 }
431                 else if(snode->treetype==NTREE_COMPOSIT) {
432                         /* make active viewer, currently only 1 supported... */
433                         if(node->type==CMP_NODE_VIEWER) {
434                                 bNode *tnode;
435                                 int was_output= node->flag & NODE_DO_OUTPUT;
436
437                                 for(tnode= snode->edittree->nodes.first; tnode; tnode= tnode->next)
438                                         if(tnode->type==CMP_NODE_VIEWER)
439                                                 tnode->flag &= ~NODE_DO_OUTPUT;
440                                 
441                                 node->flag |= NODE_DO_OUTPUT;
442                                 if(was_output==0) {
443                                         NodeTagChanged(snode->edittree, node);
444                                         snode_handle_recalc(snode);
445                                 }
446                                 
447                                 /* add node doesnt link this yet... */
448                                 if(node->id==NULL) {
449                                         node->id= find_id("IM", "Compositor");
450                                         if(node->id==NULL) {
451                                                 Image *ima= alloc_libblock(&G.main->image, ID_IM, "Compositor");
452                                                 strcpy(ima->name, "Compositor");
453                                                 ima->ok= 1;
454                                                 ima->xrep= ima->yrep= 1;
455                                                 node->id= &ima->id;
456                                         }
457                                         else 
458                                                 node->id->us++;
459                                 }
460                         }
461                 }
462         }
463 }
464
465 static void snode_make_group_editable(SpaceNode *snode, bNode *gnode)
466 {
467         bNode *node;
468         
469         /* make sure nothing has group editing on */
470         for(node= snode->nodetree->nodes.first; node; node= node->next)
471                 node->flag &= ~NODE_GROUP_EDIT;
472         
473         if(gnode==NULL) {
474                 /* with NULL argument we do a toggle */
475                 if(snode->edittree==snode->nodetree)
476                         gnode= nodeGetActive(snode->nodetree);
477         }
478         
479         if(gnode && gnode->type==NODE_GROUP && gnode->id) {
480                 if(gnode->id->lib) {
481                         if(okee("Make Group Local"))
482                                 ntreeMakeLocal((bNodeTree *)gnode->id);
483                         else
484                                 return;
485                 }
486                 gnode->flag |= NODE_GROUP_EDIT;
487                 snode->edittree= (bNodeTree *)gnode->id;
488                 
489                 /* deselect all other nodes, so we can also do grabbing of entire subtree */
490                 for(node= snode->nodetree->nodes.first; node; node= node->next)
491                         node->flag &= ~SELECT;
492                 gnode->flag |= SELECT;
493                 
494         }
495         else 
496                 snode->edittree= snode->nodetree;
497         
498         ntreeSolveOrder(snode->nodetree);
499         
500         /* finally send out events for new active node */
501         if(snode->treetype==NTREE_SHADER) {
502                 allqueue(REDRAWBUTSSHADING, 0);
503                 
504                 BIF_preview_changed(-1);        /* temp hack to force texture preview to update */
505         }
506         
507         allqueue(REDRAWNODE, 0);
508 }
509
510 static void node_ungroup(SpaceNode *snode)
511 {
512         bNode *gnode;
513         
514         gnode= nodeGetActive(snode->edittree);
515         if(gnode->type!=NODE_GROUP)
516                 error("Not a group");
517         else {
518                 if(nodeGroupUnGroup(snode->edittree, gnode)) {
519                         
520                         ntreeSolveOrder(snode->edittree);
521                         BIF_undo_push("Deselect all nodes");
522                         allqueue(REDRAWNODE, 0);
523                 }
524                 else
525                         error("Can't ungroup");
526         }
527 }
528
529 /* when links in groups change, inputs/outputs change, nodes added/deleted... */
530 static void snode_verify_groups(SpaceNode *snode)
531 {
532         bNode *gnode;
533         
534         gnode= snode_get_editgroup(snode);
535         
536         /* does all materials */
537         if(gnode)
538                 nodeVerifyGroup((bNodeTree *)gnode->id);
539         
540 }
541
542 static void node_addgroup(SpaceNode *snode)
543 {
544         bNodeTree *ngroup;
545         int tot= 0, offs, val;
546         char *strp;
547         
548         if(snode->edittree!=snode->nodetree) {
549                 error("Can not add a Group in a Group");
550                 return;
551         }
552         
553         /* construct menu with choices */
554         for(ngroup= G.main->nodetree.first; ngroup; ngroup= ngroup->id.next) {
555                 if(ngroup->type==snode->treetype)
556                         tot++;
557         }
558         if(tot==0) {
559                 error("No groups available in database");
560                 return;
561         }
562         strp= MEM_mallocN(32*tot+32, "menu");
563         strcpy(strp, "Add Group %t");
564         offs= strlen(strp);
565         
566         for(tot=0, ngroup= G.main->nodetree.first; ngroup; ngroup= ngroup->id.next, tot++) {
567                 if(ngroup->type==snode->treetype)
568                         offs+= sprintf(strp+offs, "|%s %%x%d", ngroup->id.name+2, tot);
569         }       
570         
571         val= pupmenu(strp);
572         if(val>=0) {
573                 ngroup= BLI_findlink(&G.main->nodetree, val);
574                 if(ngroup) {
575                         bNode *node= nodeAddNodeType(snode->edittree, NODE_GROUP, ngroup);
576                         
577                         /* generics */
578                         if(node) {
579                                 float locx, locy;
580                                 short mval[2];
581
582                                 node_deselectall(snode, 0);
583                                 
584                                 getmouseco_areawin(mval);
585                                 areamouseco_to_ipoco(G.v2d, mval, &locx, &locy);
586                                 
587                                 node->locx= locx;
588                                 node->locy= locy + 60.0f;               // arbitrary.. so its visible
589                                 node->flag |= SELECT;
590                                 
591                                 id_us_plus(node->id);
592                                 
593                                 node_set_active(snode, node);
594                                 BIF_undo_push("Add Node");
595                         }
596                 }                       
597         }
598         MEM_freeN(strp);
599 }
600
601
602 /* ************************** Node generic ************** */
603
604 /* allows to walk the list in order of visibility */
605 static bNode *next_node(bNodeTree *ntree)
606 {
607         static bNode *current=NULL, *last= NULL;
608         
609         if(ntree) {
610                 /* set current to the first selected node */
611                 for(current= ntree->nodes.last; current; current= current->prev)
612                         if(current->flag & NODE_SELECT)
613                                 break;
614                 
615                 /* set last to the first unselected node */
616                 for(last= ntree->nodes.last; last; last= last->prev)
617                         if((last->flag & NODE_SELECT)==0)
618                                 break;
619                 
620                 if(current==NULL)
621                         current= last;
622                 
623                 return NULL;
624         }
625         /* no nodes, or we are ready */
626         if(current==NULL)
627                 return NULL;
628         
629         /* now we walk the list backwards, but we always return current */
630         if(current->flag & NODE_SELECT) {
631                 bNode *node= current;
632                 
633                 /* find previous selected */
634                 current= current->prev;
635                 while(current && (current->flag & NODE_SELECT)==0)
636                         current= current->prev;
637                 
638                 /* find first unselected */
639                 if(current==NULL)
640                         current= last;
641                 
642                 return node;
643         }
644         else {
645                 bNode *node= current;
646                 
647                 /* find previous unselected */
648                 current= current->prev;
649                 while(current && (current->flag & NODE_SELECT))
650                         current= current->prev;
651                 
652                 return node;
653         }
654         
655         return NULL;
656 }
657
658 /* is rct in visible part of node? */
659 static bNode *visible_node(SpaceNode *snode, rctf *rct)
660 {
661         bNode *tnode;
662         
663         for(next_node(snode->edittree); (tnode=next_node(NULL));) {
664                 if(BLI_isect_rctf(&tnode->totr, rct, NULL))
665                         break;
666         }
667         return tnode;
668 }
669
670 static void snode_home(ScrArea *sa, SpaceNode *snode)
671 {
672         bNode *node;
673         int first= 1;
674         
675         snode->v2d.cur.xmin= snode->v2d.cur.ymin= 0.0f;
676         snode->v2d.cur.xmax= sa->winx;
677         snode->v2d.cur.xmax= sa->winy;
678         
679         for(node= snode->edittree->nodes.first; node; node= node->next) {
680                 if(first) {
681                         first= 0;
682                         snode->v2d.cur= node->totr;
683                 }
684                 else {
685                         BLI_union_rctf(&snode->v2d.cur, &node->totr);
686                 }
687         }
688         snode->v2d.tot= snode->v2d.cur;
689         test_view2d(G.v2d, sa->winx, sa->winy);
690         
691 }
692
693 /* checks mouse position, and returns found node/socket */
694 /* type is SOCK_IN and/or SOCK_OUT */
695 static int find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, int in_out)
696 {
697         bNode *node;
698         bNodeSocket *sock;
699         rctf rect;
700         short mval[2];
701         
702         getmouseco_areawin(mval);
703         areamouseco_to_ipoco(G.v2d, mval, &rect.xmin, &rect.ymin);
704         
705         rect.xmin -= NODE_SOCKSIZE+3;
706         rect.ymin -= NODE_SOCKSIZE+3;
707         rect.xmax = rect.xmin + 2*NODE_SOCKSIZE+6;
708         rect.ymax = rect.ymin + 2*NODE_SOCKSIZE+6;
709         
710         /* check if we click in a socket */
711         for(node= snode->edittree->nodes.first; node; node= node->next) {
712                 if(in_out & SOCK_IN) {
713                         for(sock= node->inputs.first; sock; sock= sock->next) {
714                                 if(!(sock->flag & SOCK_HIDDEN)) {
715                                         if(BLI_in_rctf(&rect, sock->locx, sock->locy)) {
716                                                 if(node == visible_node(snode, &rect)) {
717                                                         *nodep= node;
718                                                         *sockp= sock;
719                                                         return 1;
720                                                 }
721                                         }
722                                 }
723                         }
724                 }
725                 if(in_out & SOCK_OUT) {
726                         for(sock= node->outputs.first; sock; sock= sock->next) {
727                                 if(!(sock->flag & SOCK_HIDDEN)) {
728                                         if(BLI_in_rctf(&rect, sock->locx, sock->locy)) {
729                                                 if(node == visible_node(snode, &rect)) {
730                                                         *nodep= node;
731                                                         *sockp= sock;
732                                                         return 1;
733                                                 }
734                                         }
735                                 }
736                         }
737                 }
738         }
739         return 0;
740 }
741
742 /* ********************* transform ****************** */
743
744 /* releases on event, only intern (for extern see below) */
745 /* we need argument ntree to allow operations on edittree or nodetree */
746 static void transform_nodes(bNodeTree *ntree, char mode, char *undostr)
747 {
748         bNode *node;
749         float mxstart, mystart, mx, my, *oldlocs, *ol;
750         int cont=1, tot=0, cancel=0, firsttime=1;
751         short mval[2], mvalo[2];
752         
753         /* count total */
754         for(node= ntree->nodes.first; node; node= node->next)
755                 if(node->flag & SELECT) tot++;
756         
757         if(tot==0) return;
758         
759         /* store oldlocs */
760         ol= oldlocs= MEM_mallocN(sizeof(float)*2*tot, "oldlocs transform");
761         for(node= ntree->nodes.first; node; node= node->next) {
762                 if(node->flag & SELECT) {
763                         ol[0]= node->locx; ol[1]= node->locy;
764                         ol+= 2;
765                 }
766         }
767         
768         getmouseco_areawin(mvalo);
769         areamouseco_to_ipoco(G.v2d, mvalo, &mxstart, &mystart);
770         
771         while(cont) {
772                 
773                 getmouseco_areawin(mval);
774                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || firsttime) {
775
776                         firsttime= 0;
777                         
778                         areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
779                         mvalo[0]= mval[0];
780                         mvalo[1]= mval[1];
781                         
782                         for(ol= oldlocs, node= ntree->nodes.first; node; node= node->next) {
783                                 if(node->flag & SELECT) {
784                                         node->locx= ol[0] + mx-mxstart;
785                                         node->locy= ol[1] + my-mystart;
786                                         ol+= 2;
787                                 }
788                         }
789                         
790                         force_draw(0);
791                 }
792                 else
793                         PIL_sleep_ms(10);
794                 
795                 while (qtest()) {
796                         short val;
797                         unsigned short event= extern_qread(&val);
798                         
799                         switch (event) {
800                                 case LEFTMOUSE:
801                                 case SPACEKEY:
802                                 case RETKEY:
803                                         cont=0;
804                                         break;
805                                 case ESCKEY:
806                                 case RIGHTMOUSE:
807                                         if(val) {
808                                                 cancel=1;
809                                                 cont=0;
810                                         }
811                                         break;
812                                 default:
813                                         if(val) arrows_move_cursor(event);
814                                         break;
815                         }
816                 }
817                 
818         }
819         
820         if(cancel) {
821                 for(ol= oldlocs, node= ntree->nodes.first; node; node= node->next) {
822                         if(node->flag & SELECT) {
823                                 node->locx= ol[0];
824                                 node->locy= ol[1];
825                                 ol+= 2;
826                         }
827                 }
828                 
829         }
830         else
831                 BIF_undo_push(undostr);
832         
833         allqueue(REDRAWNODE, 1);
834         MEM_freeN(oldlocs);
835 }
836
837 /* external call, also for callback */
838 void node_transform_ext(int mode, int unused)
839 {
840         SpaceNode *snode= curarea->spacedata.first;
841         
842         transform_nodes(snode->edittree, 'g', "Translate node");
843 }
844
845
846 /* releases on event, only 1 node */
847 static void scale_node(SpaceNode *snode, bNode *node)
848 {
849         float mxstart, mystart, mx, my, oldwidth;
850         int cont=1, cancel=0;
851         short mval[2], mvalo[2];
852         
853         /* store old */
854         if(node->flag & NODE_HIDDEN)
855                 oldwidth= node->miniwidth;
856         else
857                 oldwidth= node->width;
858                 
859         getmouseco_areawin(mvalo);
860         areamouseco_to_ipoco(G.v2d, mvalo, &mxstart, &mystart);
861         
862         while(cont) {
863                 
864                 getmouseco_areawin(mval);
865                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {
866                         
867                         areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
868                         mvalo[0]= mval[0];
869                         mvalo[1]= mval[1];
870                         
871                         if(node->flag & NODE_HIDDEN) {
872                                 node->miniwidth= oldwidth + mx-mxstart;
873                                 CLAMP(node->miniwidth, 0.0f, 100.0f);
874                         }
875                         else {
876                                 node->width= oldwidth + mx-mxstart;
877                                 CLAMP(node->width, node->typeinfo->minwidth, node->typeinfo->maxwidth);
878                         }
879                         
880                         force_draw(0);
881                 }
882                 else
883                         PIL_sleep_ms(10);
884                 
885                 while (qtest()) {
886                         short val;
887                         unsigned short event= extern_qread(&val);
888                         
889                         switch (event) {
890                                 case LEFTMOUSE:
891                                 case SPACEKEY:
892                                 case RETKEY:
893                                         cont=0;
894                                         break;
895                                 case ESCKEY:
896                                 case RIGHTMOUSE:
897                                         if(val) {
898                                                 cancel=1;
899                                                 cont=0;
900                                         }
901                                         break;
902                         }
903                 }
904                 
905         }
906         
907         if(cancel) {
908                 node->width= oldwidth;
909         }
910         else
911                 BIF_undo_push("Scale Node");
912         
913         allqueue(REDRAWNODE, 1);
914 }
915
916
917
918 /* ********************** select ******************** */
919
920 /* used in buttons to check context, also checks for edited groups */
921 bNode *editnode_get_active_idnode(bNodeTree *ntree, short id_code)
922 {
923         bNode *node;
924         
925         /* check for edited group */
926         for(node= ntree->nodes.first; node; node= node->next)
927                 if(node->flag & NODE_GROUP_EDIT)
928                         break;
929         if(node)
930                 return nodeGetActiveID((bNodeTree *)node->id, id_code);
931         else
932                 return nodeGetActiveID(ntree, id_code);
933 }
934
935 /* used in buttons to check context, also checks for edited groups */
936 Material *editnode_get_active_material(Material *ma)
937 {
938         if(ma && ma->use_nodes && ma->nodetree) {
939                 bNode *node= editnode_get_active_idnode(ma->nodetree, ID_MA);
940                 if(node)
941                         return (Material *)node->id;
942                 else
943                         return NULL;
944         }
945         return ma;
946 }
947
948 /* used in buttons to check context, also checks for edited groups */
949 bNode *editnode_get_active(bNodeTree *ntree)
950 {
951         bNode *node;
952         
953         /* check for edited group */
954         for(node= ntree->nodes.first; node; node= node->next)
955                 if(node->flag & NODE_GROUP_EDIT)
956                         break;
957         if(node)
958                 return nodeGetActive((bNodeTree *)node->id);
959         else
960                 return nodeGetActive(ntree);
961 }
962
963
964 /* no undo here! */
965 void node_deselectall(SpaceNode *snode, int swap)
966 {
967         bNode *node;
968         
969         if(swap) {
970                 for(node= snode->edittree->nodes.first; node; node= node->next)
971                         if(node->flag & SELECT)
972                                 break;
973                 if(node==NULL) {
974                         for(node= snode->edittree->nodes.first; node; node= node->next)
975                                 node->flag |= SELECT;
976                         allqueue(REDRAWNODE, 0);
977                         return;
978                 }
979                 /* else pass on to deselect */
980         }
981         
982         for(node= snode->edittree->nodes.first; node; node= node->next)
983                 node->flag &= ~SELECT;
984         
985         allqueue(REDRAWNODE, 0);
986 }
987
988 int node_has_hidden_sockets(bNode *node)
989 {
990         bNodeSocket *sock;
991         
992         for(sock= node->inputs.first; sock; sock= sock->next)
993                 if(sock->flag & SOCK_HIDDEN)
994                         return 1;
995         for(sock= node->outputs.first; sock; sock= sock->next)
996                 if(sock->flag & SOCK_HIDDEN)
997                         return 1;
998         return 0;
999 }
1000
1001
1002 static void node_hide_unhide_sockets(SpaceNode *snode, bNode *node)
1003 {
1004         bNodeSocket *sock;
1005         
1006         /* unhide all */
1007         if( node_has_hidden_sockets(node) ) {
1008                 for(sock= node->inputs.first; sock; sock= sock->next)
1009                         sock->flag &= ~SOCK_HIDDEN;
1010                 for(sock= node->outputs.first; sock; sock= sock->next)
1011                         sock->flag &= ~SOCK_HIDDEN;
1012         }
1013         else {
1014                 bNode *gnode= snode_get_editgroup(snode);
1015                 
1016                 /* hiding inside group should not break links in other group users */
1017                 if(gnode) {
1018                         nodeGroupSocketUseFlags((bNodeTree *)gnode->id);
1019                         for(sock= node->inputs.first; sock; sock= sock->next)
1020                                 if(!(sock->flag & SOCK_IN_USE))
1021                                         if(sock->link==NULL)
1022                                                 sock->flag |= SOCK_HIDDEN;
1023                         for(sock= node->outputs.first; sock; sock= sock->next)
1024                                 if(!(sock->flag & SOCK_IN_USE))
1025                                         if(nodeCountSocketLinks(snode->edittree, sock)==0)
1026                                                 sock->flag |= SOCK_HIDDEN;
1027                 }
1028                 else {
1029                         /* hide unused sockets */
1030                         for(sock= node->inputs.first; sock; sock= sock->next) {
1031                                 if(sock->link==NULL)
1032                                         sock->flag |= SOCK_HIDDEN;
1033                         }
1034                         for(sock= node->outputs.first; sock; sock= sock->next) {
1035                                 if(nodeCountSocketLinks(snode->edittree, sock)==0)
1036                                         sock->flag |= SOCK_HIDDEN;
1037                         }
1038                 }
1039         }
1040
1041         allqueue(REDRAWNODE, 1);
1042         snode_verify_groups(snode);
1043         BIF_undo_push("Hide/Unhide sockets");
1044
1045 }
1046
1047 static int do_header_node(SpaceNode *snode, bNode *node, float mx, float my)
1048 {
1049         rctf totr= node->totr;
1050         
1051         totr.ymin= totr.ymax-20.0f;
1052         
1053         totr.xmax= totr.xmin+15.0f;
1054         if(BLI_in_rctf(&totr, mx, my)) {
1055                 node->flag |= NODE_HIDDEN;
1056                 allqueue(REDRAWNODE, 0);
1057                 return 1;
1058         }       
1059         
1060         totr.xmax= node->totr.xmax;
1061         totr.xmin= totr.xmax-18.0f;
1062         if(node->typeinfo->flag & NODE_PREVIEW) {
1063                 if(BLI_in_rctf(&totr, mx, my)) {
1064                         node->flag ^= NODE_PREVIEW;
1065                         allqueue(REDRAWNODE, 0);
1066                         return 1;
1067                 }
1068                 totr.xmin-=18.0f;
1069         }
1070         if(node->type == NODE_GROUP) {
1071                 if(BLI_in_rctf(&totr, mx, my)) {
1072                         snode_make_group_editable(snode, node);
1073                         return 1;
1074                 }
1075                 totr.xmin-=18.0f;
1076         }
1077         if(node->typeinfo->flag & NODE_OPTIONS) {
1078                 if(BLI_in_rctf(&totr, mx, my)) {
1079                         node->flag ^= NODE_OPTIONS;
1080                         allqueue(REDRAWNODE, 0);
1081                         return 1;
1082                 }
1083                 totr.xmin-=18.0f;
1084         }
1085         if(node->outputs.first) {
1086                 if(BLI_in_rctf(&totr, mx, my)) {
1087                         node_hide_unhide_sockets(snode, node);
1088                 }
1089         }
1090         
1091         
1092         totr= node->totr;
1093         totr.xmin= totr.xmax-10.0f;
1094         totr.ymax= totr.ymin+10.0f;
1095         if(BLI_in_rctf(&totr, mx, my)) {
1096                 scale_node(snode, node);
1097                 return 1;
1098         }
1099         return 0;
1100 }
1101
1102 static int do_header_hidden_node(SpaceNode *snode, bNode *node, float mx, float my)
1103 {
1104         rctf totr= node->totr;
1105         
1106         totr.xmax= totr.xmin+15.0f;
1107         if(BLI_in_rctf(&totr, mx, my)) {
1108                 node->flag &= ~NODE_HIDDEN;
1109                 allqueue(REDRAWNODE, 0);
1110                 return 1;
1111         }       
1112         
1113         totr.xmax= node->totr.xmax;
1114         totr.xmin= node->totr.xmax-15.0f;
1115         if(BLI_in_rctf(&totr, mx, my)) {
1116                 scale_node(snode, node);
1117                 return 1;
1118         }
1119         return 0;
1120 }
1121
1122
1123 /* return 0: nothing done */
1124 static int node_mouse_select(SpaceNode *snode, unsigned short event)
1125 {
1126         bNode *node;
1127         float mx, my;
1128         short mval[2];
1129         
1130         getmouseco_areawin(mval);
1131         areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
1132         
1133         for(next_node(snode->edittree); (node=next_node(NULL));) {
1134                 
1135                 /* first check for the headers or scaling widget */
1136                 if(node->flag & NODE_HIDDEN) {
1137                         if(do_header_hidden_node(snode, node, mx, my))
1138                                 return 1;
1139                 }
1140                 else {
1141                         if(do_header_node(snode, node, mx, my))
1142                                 return 1;
1143                 }
1144                 
1145                 /* node body */
1146                 if(BLI_in_rctf(&node->totr, mx, my))
1147                         break;
1148         }
1149         if(node) {
1150                 if((G.qual & LR_SHIFTKEY)==0)
1151                         node_deselectall(snode, 0);
1152                 
1153                 if(G.qual & LR_SHIFTKEY) {
1154                         if(node->flag & SELECT)
1155                                 node->flag &= ~SELECT;
1156                         else
1157                                 node->flag |= SELECT;
1158                 }
1159                 else 
1160                         node->flag |= SELECT;
1161                 
1162                 node_set_active(snode, node);
1163                 
1164                 /* not so nice (no event), but function below delays redraw otherwise */
1165                 force_draw(0);
1166                 
1167                 std_rmouse_transform(node_transform_ext);       /* does undo push for select */
1168                 
1169                 return 1;
1170         }
1171         return 0;
1172 }
1173
1174 /* return 0, nothing done */
1175 static int node_mouse_groupheader(SpaceNode *snode)
1176 {
1177         bNode *gnode;
1178         float mx, my;
1179         short mval[2];
1180         
1181         gnode= snode_get_editgroup(snode);
1182         if(gnode==NULL) return 0;
1183         
1184         getmouseco_areawin(mval);
1185         areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
1186         
1187         /* click in header or outside? */
1188         if(BLI_in_rctf(&gnode->totr, mx, my)==0) {
1189                 rctf rect= gnode->totr;
1190                 
1191                 rect.ymax += NODE_DY;
1192                 if(BLI_in_rctf(&rect, mx, my)==0)
1193                         snode_make_group_editable(snode, NULL); /* toggles, so exits editmode */
1194                 else
1195                         transform_nodes(snode->nodetree, 'g', "Move group");
1196                 
1197                 return 1;
1198         }
1199         return 0;
1200 }
1201
1202 static int node_socket_hilights(SpaceNode *snode, int in_out)
1203 {
1204         bNode *node;
1205         bNodeSocket *sock, *tsock, *socksel= NULL;
1206         float mx, my;
1207         short mval[2], redraw= 0;
1208         
1209         if(snode->edittree==NULL) return 0;
1210         
1211         getmouseco_areawin(mval);
1212         areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
1213         
1214         /* deselect socks */
1215         for(node= snode->edittree->nodes.first; node; node= node->next) {
1216                 for(sock= node->inputs.first; sock; sock= sock->next) {
1217                         if(sock->flag & SELECT) {
1218                                 sock->flag &= ~SELECT;
1219                                 redraw++;
1220                                 socksel= sock;
1221                         }
1222                 }
1223                 for(sock= node->outputs.first; sock; sock= sock->next) {
1224                         if(sock->flag & SELECT) {
1225                                 sock->flag &= ~SELECT;
1226                                 redraw++;
1227                                 socksel= sock;
1228                         }
1229                 }
1230         }
1231         
1232         if(find_indicated_socket(snode, &node, &tsock, in_out)) {
1233                 tsock->flag |= SELECT;
1234                 if(redraw==1 && tsock==socksel) redraw= 0;
1235                 else redraw= 1;
1236         }
1237         
1238         return redraw;
1239 }
1240
1241 void node_border_select(SpaceNode *snode)
1242 {
1243         bNode *node;
1244         rcti rect;
1245         rctf rectf;
1246         short val, mval[2];
1247         
1248         if ( (val = get_border(&rect, 3)) ) {
1249                 
1250                 mval[0]= rect.xmin;
1251                 mval[1]= rect.ymin;
1252                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1253                 mval[0]= rect.xmax;
1254                 mval[1]= rect.ymax;
1255                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1256                 
1257                 for(node= snode->edittree->nodes.first; node; node= node->next) {
1258                         if(BLI_isect_rctf(&rectf, &node->totr, NULL)) {
1259                                 if(val==LEFTMOUSE)
1260                                         node->flag |= SELECT;
1261                                 else
1262                                         node->flag &= ~SELECT;
1263                         }
1264                 }
1265                 allqueue(REDRAWNODE, 1);
1266                 BIF_undo_push("Border select nodes");
1267         }               
1268 }
1269
1270 /* ****************** Add *********************** */
1271
1272 /* can be called from menus too, but they should do own undopush and redraws */
1273 bNode *node_add_node(SpaceNode *snode, int type, float locx, float locy)
1274 {
1275         bNode *node= NULL, *gnode;
1276         
1277         node_deselectall(snode, 0);
1278         
1279         if(type>=NODE_GROUP_MENU) {
1280                 if(snode->edittree!=snode->nodetree) {
1281                         error("Can not add a Group in a Group");
1282                         return NULL;
1283                 }
1284                 else {
1285                         bNodeTree *ngroup= BLI_findlink(&G.main->nodetree, type-NODE_GROUP_MENU);
1286                         if(ngroup)
1287                                 node= nodeAddNodeType(snode->edittree, NODE_GROUP, ngroup);
1288                 }
1289         }
1290         else
1291                 node= nodeAddNodeType(snode->edittree, type, NULL);
1292         
1293         /* generics */
1294         if(node) {
1295                 node->locx= locx;
1296                 node->locy= locy + 60.0f;               // arbitrary.. so its visible
1297                 node->flag |= SELECT;
1298                 
1299                 gnode= snode_get_editgroup(snode);
1300                 if(gnode) {
1301                         node->locx -= gnode->locx;
1302                         node->locy -= gnode->locy;
1303                 }
1304
1305                 node_set_active(snode, node);
1306                 snode_verify_groups(snode);
1307                 
1308                 if(node->id)
1309                         id_us_plus(node->id);
1310         }
1311         return node;
1312 }
1313
1314 void node_adduplicate(SpaceNode *snode)
1315 {
1316         
1317         ntreeCopyTree(snode->edittree, 1);      /* 1 == internally selected nodes */
1318         
1319         ntreeSolveOrder(snode->edittree);
1320         snode_verify_groups(snode);
1321         snode_handle_recalc(snode);
1322
1323         transform_nodes(snode->edittree, 'g', "Duplicate");
1324 }
1325
1326 static void node_insert_convertor(SpaceNode *snode, bNodeLink *link)
1327 {
1328         bNode *newnode= NULL;
1329         
1330         if(link->fromsock->type==SOCK_RGBA && link->tosock->type==SOCK_VALUE) {
1331                 if(snode->edittree->type==NTREE_SHADER)
1332                         newnode= node_add_node(snode, SH_NODE_RGBTOBW, 0.0f, 0.0f);
1333                 else if(snode->edittree->type==NTREE_COMPOSIT)
1334                         newnode= node_add_node(snode, CMP_NODE_RGBTOBW, 0.0f, 0.0f);
1335                 else
1336                         newnode= NULL;
1337         }
1338         else if(link->fromsock->type==SOCK_VALUE && link->tosock->type==SOCK_RGBA) {
1339                 if(snode->edittree->type==NTREE_SHADER)
1340                         newnode= node_add_node(snode, SH_NODE_VALTORGB, 0.0f, 0.0f);
1341                 else if(snode->edittree->type==NTREE_COMPOSIT)
1342                         newnode= node_add_node(snode, CMP_NODE_VALTORGB, 0.0f, 0.0f);
1343                 else
1344                         newnode= NULL;
1345         }
1346         
1347         if(newnode) {
1348                 /* dangerous assumption to use first in/out socks, but thats fine for now */
1349                 newnode->flag |= NODE_HIDDEN;
1350                 newnode->locx= 0.5f*(link->fromsock->locx + link->tosock->locx);
1351                 newnode->locy= 0.5f*(link->fromsock->locy + link->tosock->locy) + HIDDEN_RAD;
1352                 
1353                 nodeAddLink(snode->edittree, newnode, newnode->outputs.first, link->tonode, link->tosock);
1354                 link->tonode= newnode;
1355                 link->tosock= newnode->inputs.first;
1356         }
1357 }
1358
1359
1360 /* loop that adds a nodelink, called by function below  */
1361 /* in_out = starting socket */
1362 static int node_add_link_drag(SpaceNode *snode, bNode *node, bNodeSocket *sock, int in_out)
1363 {
1364         bNode *tnode;
1365         bNodeSocket *tsock;
1366         bNodeLink *link= NULL;
1367         short mval[2], mvalo[2], firsttime=1;   /* firsttime reconnects a link broken by caller */
1368         
1369         /* we make a temporal link */
1370         if(in_out==SOCK_OUT)
1371                 link= nodeAddLink(snode->edittree, node, sock, NULL, NULL);
1372         else
1373                 link= nodeAddLink(snode->edittree, NULL, NULL, node, sock);
1374         
1375         getmouseco_areawin(mvalo);
1376         while (get_mbut() & L_MOUSE) {
1377                 
1378                 getmouseco_areawin(mval);
1379                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || firsttime) {
1380                         firsttime= 0;
1381                         
1382                         mvalo[0]= mval[0];
1383                         mvalo[1]= mval[1];
1384                         
1385                         if(in_out==SOCK_OUT) {
1386                                 if(find_indicated_socket(snode, &tnode, &tsock, SOCK_IN)) {
1387                                         if(nodeFindLink(snode->edittree, sock, tsock)==NULL) {
1388                                                 if(tnode!=node  && link->tonode!=tnode && link->tosock!= tsock) {
1389                                                         link->tonode= tnode;
1390                                                         link->tosock= tsock;
1391                                                         ntreeSolveOrder(snode->edittree);       /* for interactive red line warning */
1392                                                 }
1393                                         }
1394                                 }
1395                                 else {
1396                                         link->tonode= NULL;
1397                                         link->tosock= NULL;
1398                                 }
1399                         }
1400                         else {
1401                                 if(find_indicated_socket(snode, &tnode, &tsock, SOCK_OUT)) {
1402                                         if(nodeFindLink(snode->edittree, sock, tsock)==NULL) {
1403                                                 if(nodeCountSocketLinks(snode->edittree, tsock) < tsock->limit) {
1404                                                         if(tnode!=node && link->fromnode!=tnode && link->fromsock!= tsock) {
1405                                                                 link->fromnode= tnode;
1406                                                                 link->fromsock= tsock;
1407                                                                 ntreeSolveOrder(snode->edittree);       /* for interactive red line warning */
1408                                                         }
1409                                                 }
1410                                         }
1411                                 }
1412                                 else {
1413                                         link->fromnode= NULL;
1414                                         link->fromsock= NULL;
1415                                 }
1416                         }
1417                         /* hilight target sockets only */
1418                         node_socket_hilights(snode, in_out==SOCK_OUT?SOCK_IN:SOCK_OUT);
1419                         
1420                         force_draw(0);
1421                 }
1422                 else BIF_wait_for_statechange();                
1423         }
1424         
1425         /* remove link? */
1426         if(link->tonode==NULL || link->fromnode==NULL) {
1427                 nodeRemLink(snode->edittree, link);
1428         }
1429         else {
1430                 bNodeLink *tlink;
1431
1432                 /* send changed events for original tonode and new */
1433                 if(link->tonode) 
1434                         NodeTagChanged(snode->edittree, link->tonode);
1435                 
1436                 /* we might need to remove a link */
1437                 if(in_out==SOCK_OUT) {
1438                         if(nodeCountSocketLinks(snode->edittree, link->tosock) > tsock->limit) {
1439                                 
1440                                 for(tlink= snode->edittree->links.first; tlink; tlink= tlink->next) {
1441                                         if(link!=tlink && tlink->tosock==link->tosock)
1442                                                 break;
1443                                 }
1444                                 if(tlink) {
1445                                         /* is there a free input socket with same type? */
1446                                         for(tsock= tlink->tonode->inputs.first; tsock; tsock= tsock->next) {
1447                                                 if(tsock->type==tlink->fromsock->type)
1448                                                         if(nodeCountSocketLinks(snode->edittree, tsock) < tsock->limit)
1449                                                                 break;
1450                                         }
1451                                         if(tsock)
1452                                                 tlink->tosock= tsock;
1453                                         else {
1454                                                 nodeRemLink(snode->edittree, tlink);
1455                                         }
1456                                 }                                       
1457                         }
1458                 }
1459                 
1460                 /* and last trick: insert a convertor when types dont match */
1461                 if(snode->treetype==NTREE_SHADER) {
1462                         if(link->tosock->type!=link->fromsock->type) {
1463                                 node_insert_convertor(snode, link);
1464                                 /* so nice do it twice! well, the sort-order can only handle 1 added link at a time */
1465                                 ntreeSolveOrder(snode->edittree);
1466                         }
1467                 }
1468         }
1469         
1470         ntreeSolveOrder(snode->edittree);
1471         snode_verify_groups(snode);
1472         snode_handle_recalc(snode);
1473         
1474         allqueue(REDRAWNODE, 0);
1475         BIF_undo_push("Add link");
1476
1477         return 1;
1478 }
1479
1480 /* return 1 when socket clicked */
1481 static int node_add_link(SpaceNode *snode)
1482 {
1483         bNode *node;
1484         bNodeLink *link;
1485         bNodeSocket *sock;
1486         
1487         /* output indicated? */
1488         if(find_indicated_socket(snode, &node, &sock, SOCK_OUT)) {
1489                 if(nodeCountSocketLinks(snode->edittree, sock)<sock->limit)
1490                         return node_add_link_drag(snode, node, sock, SOCK_OUT);
1491                 else {
1492                         /* find if we break a link */
1493                         for(link= snode->edittree->links.first; link; link= link->next) {
1494                                 if(link->fromsock==sock)
1495                                         break;
1496                         }
1497                         if(link) {
1498                                 node= link->tonode;
1499                                 sock= link->tosock;
1500                                 nodeRemLink(snode->edittree, link);
1501                                 return node_add_link_drag(snode, node, sock, SOCK_IN);
1502                         }
1503                 }
1504         }
1505         /* or an input? */
1506         else if(find_indicated_socket(snode, &node, &sock, SOCK_IN)) {
1507                 if(nodeCountSocketLinks(snode->edittree, sock)<sock->limit)
1508                         return node_add_link_drag(snode, node, sock, SOCK_IN);
1509                 else {
1510                         /* find if we break a link */
1511                         for(link= snode->edittree->links.first; link; link= link->next) {
1512                                 if(link->tosock==sock)
1513                                         break;
1514                         }
1515                         if(link) {
1516                                 /* send changed event to original tonode */
1517                                 if(link->tonode) 
1518                                         NodeTagChanged(snode->edittree, link->tonode);
1519                                 
1520                                 node= link->fromnode;
1521                                 sock= link->fromsock;
1522                                 nodeRemLink(snode->edittree, link);
1523                                 return node_add_link_drag(snode, node, sock, SOCK_OUT);
1524                         }
1525                 }
1526         }
1527         
1528         return 0;
1529 }
1530
1531 static void node_delete(SpaceNode *snode)
1532 {
1533         bNode *node, *next;
1534         
1535         for(node= snode->edittree->nodes.first; node; node= next) {
1536                 next= node->next;
1537                 if(node->flag & SELECT)
1538                         nodeFreeNode(snode->edittree, node);
1539         }
1540         
1541         snode_verify_groups(snode);
1542         snode_handle_recalc(snode);
1543         BIF_undo_push("Delete nodes");
1544         allqueue(REDRAWNODE, 1);
1545 }
1546
1547 static void node_hide(SpaceNode *snode)
1548 {
1549         bNode *node;
1550         int nothidden=0, ishidden=0;
1551         
1552         for(node= snode->edittree->nodes.first; node; node= node->next) {
1553                 if(node->flag & SELECT) {
1554                         if(node->flag & NODE_HIDDEN)
1555                                 ishidden++;
1556                         else
1557                                 nothidden++;
1558                 }
1559         }
1560         for(node= snode->edittree->nodes.first; node; node= node->next) {
1561                 if(node->flag & SELECT) {
1562                         if( (ishidden && nothidden) || ishidden==0)
1563                                 node->flag |= NODE_HIDDEN;
1564                         else 
1565                                 node->flag &= ~NODE_HIDDEN;
1566                 }
1567         }
1568         BIF_undo_push("Hide nodes");
1569         allqueue(REDRAWNODE, 1);
1570 }
1571                         
1572
1573 static void node_border_link_delete(SpaceNode *snode)
1574 {
1575         rcti rect;
1576         short val, mval[2], mvalo[2];
1577
1578         /* to make this work more friendly, we first wait for a mouse move */
1579         getmouseco_areawin(mvalo);
1580         while (get_mbut() & L_MOUSE) {
1581                 getmouseco_areawin(mval);
1582                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1])
1583                         break;
1584                 else BIF_wait_for_statechange();
1585         }
1586         if((get_mbut() & L_MOUSE)==0)
1587                 return;
1588         
1589         /* now change cursor and draw border */
1590         setcursor_space(SPACE_NODE, CURSOR_VPAINT);
1591         
1592         if ( (val = get_border(&rect, 2)) ) {
1593                 if(rect.xmin<rect.xmax && rect.ymin<rect.ymax) {
1594                         //#define NODE_MAXPICKBUF       256
1595                         bNodeLink *link, *next;
1596                         GLuint buffer[256];
1597                         rctf rectf;
1598                         int code=0, hits;
1599                         
1600                         mval[0]= rect.xmin;
1601                         mval[1]= rect.ymin;
1602                         areamouseco_to_ipoco(&snode->v2d, mval, &rectf.xmin, &rectf.ymin);
1603                         mval[0]= rect.xmax;
1604                         mval[1]= rect.ymax;
1605                         areamouseco_to_ipoco(&snode->v2d, mval, &rectf.xmax, &rectf.ymax);
1606                         
1607                         myortho2(rectf.xmin, rectf.xmax, rectf.ymin, rectf.ymax);
1608                         
1609                         glSelectBuffer(256, buffer); 
1610                         glRenderMode(GL_SELECT);
1611                         glInitNames();
1612                         glPushName(-1);
1613                         
1614                         /* draw links */
1615                         for(link= snode->edittree->links.first; link; link= link->next) {
1616                                 glLoadName(code++);
1617                                 node_draw_link(snode, link);
1618                         }
1619                         
1620                         hits= glRenderMode(GL_RENDER);
1621                         glPopName();
1622                         if(hits>0) {
1623                                 int a;
1624                                 for(a=0; a<hits; a++) {
1625                                         bNodeLink *link= BLI_findlink(&snode->edittree->links, buffer[ (4 * a) + 3]);
1626                                         if(link)
1627                                                 link->fromnode= NULL;   /* first tag for delete, otherwise indices are wrong */
1628                                 }
1629                                 for(link= snode->edittree->links.first; link; link= next) {
1630                                         next= link->next;
1631                                         if(link->fromnode==NULL) {
1632                                                 NodeTagChanged(snode->edittree, link->tonode);
1633                                                 nodeRemLink(snode->edittree, link);
1634                                         }
1635                                 }
1636                                 ntreeSolveOrder(snode->edittree);
1637                                 snode_verify_groups(snode);
1638                                 snode_handle_recalc(snode);
1639                         }
1640                         allqueue(REDRAWNODE, 0);
1641                         BIF_undo_push("Erase links");
1642                 }
1643         }
1644         
1645         setcursor_space(SPACE_NODE, CURSOR_STD);
1646 }
1647
1648
1649 /* ********************** */
1650
1651 void node_make_group(SpaceNode *snode)
1652 {
1653         bNode *gnode;
1654         
1655         if(snode->edittree!=snode->nodetree) {
1656                 error("Can not add a new Group in a Group");
1657                 return;
1658         }
1659         
1660         /* for time being... is too complex to handle */
1661         if(snode->treetype==NTREE_COMPOSIT) {
1662                 for(gnode=snode->nodetree->nodes.first; gnode; gnode= gnode->next) {
1663                         if(gnode->flag & SELECT)
1664                                 if(gnode->type==CMP_NODE_R_RESULT)
1665                                         break;
1666                 }
1667                 if(gnode) {
1668                         error("Can not add RenderResult in a Group");
1669                         return;
1670                 }
1671         }
1672         
1673         gnode= nodeMakeGroupFromSelected(snode->nodetree);
1674         if(gnode==NULL) {
1675                 error("Can not make Group");
1676         }
1677         else {
1678                 nodeSetActive(snode->nodetree, gnode);
1679                 ntreeSolveOrder(snode->nodetree);
1680                 allqueue(REDRAWNODE, 0);
1681                 BIF_undo_push("Make Node Group");
1682         }
1683 }
1684
1685 /* ******************** main event loop ****************** */
1686
1687 /* special version to prevent overlapping buttons, has a bit of hack... */
1688 /* yes, check for example composit_node_event(), file window use... */
1689 static int node_uiDoBlocks(SpaceNode *snode, ListBase *lb, short event)
1690 {
1691         bNode *node;
1692         rctf rect;
1693         ListBase listb= *lb;
1694         void *prev;
1695         int retval= UI_NOTHING;
1696         short mval[2];
1697         
1698         getmouseco_areawin(mval);
1699         areamouseco_to_ipoco(G.v2d, mval, &rect.xmin, &rect.ymin);
1700
1701         /* this happens after filesel usage... */
1702         if(lb->first==NULL) {
1703                 return UI_NOTHING;
1704         }
1705         
1706         rect.xmin -= 2.0f;
1707         rect.ymin -= 2.0f;
1708         rect.xmax = rect.xmin + 4.0f;
1709         rect.ymax = rect.ymin + 4.0f;
1710         
1711         for(node= snode->edittree->nodes.first; node; node= node->next) {
1712                 if(node->block) {
1713                         if(node == visible_node(snode, &rect)) {
1714                                 
1715                                 /* when there's menus, the prev pointer becomes zero! */
1716                                 prev= ((struct Link *)node->block)->prev;
1717                                 
1718                                 lb->first= lb->last= node->block;
1719                                 retval= uiDoBlocks(lb, event);
1720                                 ((struct Link *)node->block)->prev= prev;
1721
1722                                 break;
1723                         }
1724                 }
1725         }
1726         
1727         *lb= listb;
1728         
1729         return retval;
1730 }
1731
1732 void winqreadnodespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
1733 {
1734         SpaceNode *snode= spacedata;
1735         float dx;
1736         unsigned short event= evt->event;
1737         short val= evt->val, doredraw=0, fromlib= 0;
1738         
1739         if(sa->win==0) return;
1740         if(snode->nodetree==NULL) return;
1741         
1742         if(val) {
1743
1744                 if( node_uiDoBlocks(snode, &sa->uiblocks, event)!=UI_NOTHING ) event= 0;        
1745
1746                 fromlib= (snode->id && snode->id->lib);
1747                 
1748                 switch(event) {
1749                 case LEFTMOUSE:
1750                         if(fromlib) {
1751                                 if(node_mouse_groupheader(snode)==0)
1752                                         node_mouse_select(snode, event);
1753                         }
1754                         else {
1755                                 if(node_add_link(snode)==0)
1756                                         if(node_mouse_groupheader(snode)==0)
1757                                                 if(node_mouse_select(snode, event)==0)
1758                                                         node_border_link_delete(snode);
1759                         }
1760                         break;
1761                         
1762                 case RIGHTMOUSE: 
1763                         node_mouse_select(snode, event);
1764
1765                         break;
1766                 case MIDDLEMOUSE:
1767                 case WHEELUPMOUSE:
1768                 case WHEELDOWNMOUSE:
1769                         view2dmove(event);      /* in drawipo.c */
1770                         break;
1771                         
1772                 case MOUSEY:
1773                         doredraw= node_socket_hilights(snode, SOCK_IN|SOCK_OUT);
1774                         break;
1775                 
1776                 case UI_BUT_EVENT:
1777                         /* future: handlerize this! */
1778                         if(snode->treetype==NTREE_SHADER)
1779                                 shader_node_event(snode, val);
1780                         else if(snode->treetype==NTREE_COMPOSIT)
1781                                 composit_node_event(snode, val);
1782                         break;
1783                         
1784                 case RENDERPREVIEW:
1785                         if(snode->treetype==NTREE_SHADER)
1786                                 shader_node_previewrender(sa, snode);
1787                         break;
1788                         
1789                 case PADPLUSKEY:
1790                         dx= (float)(0.1154*(G.v2d->cur.xmax-G.v2d->cur.xmin));
1791                         G.v2d->cur.xmin+= dx;
1792                         G.v2d->cur.xmax-= dx;
1793                         dx= (float)(0.1154*(G.v2d->cur.ymax-G.v2d->cur.ymin));
1794                         G.v2d->cur.ymin+= dx;
1795                         G.v2d->cur.ymax-= dx;
1796                         test_view2d(G.v2d, sa->winx, sa->winy);
1797                         doredraw= 1;
1798                         break;
1799                 case PADMINUS:
1800                         dx= (float)(0.15*(G.v2d->cur.xmax-G.v2d->cur.xmin));
1801                         G.v2d->cur.xmin-= dx;
1802                         G.v2d->cur.xmax+= dx;
1803                         dx= (float)(0.15*(G.v2d->cur.ymax-G.v2d->cur.ymin));
1804                         G.v2d->cur.ymin-= dx;
1805                         G.v2d->cur.ymax+= dx;
1806                         test_view2d(G.v2d, sa->winx, sa->winy);
1807                         doredraw= 1;
1808                         break;
1809                 case HOMEKEY:
1810                         snode_home(sa, snode);
1811                         doredraw= 1;
1812                         break;
1813                 case TABKEY:
1814                         if(fromlib) fromlib= -1;
1815                         else snode_make_group_editable(snode, NULL);
1816                         break;
1817                         
1818                 case AKEY:
1819                         if(G.qual==LR_SHIFTKEY) {
1820                                 if(fromlib) fromlib= -1;
1821                                 else toolbox_n_add();
1822                         }
1823                         else if(G.qual==0) {
1824                                 node_deselectall(snode, 1);
1825                                 BIF_undo_push("Deselect all nodes");
1826                         }
1827                         break;
1828                 case BKEY:
1829                         if(G.qual==0)
1830                                 node_border_select(snode);
1831                         break;
1832                 case CKEY:      /* sort again, showing cyclics */
1833                         ntreeSolveOrder(snode->edittree);
1834                         doredraw= 1;
1835                         break;
1836                 case DKEY:
1837                         if(G.qual==LR_SHIFTKEY) {
1838                                 if(fromlib) fromlib= -1;
1839                                 else node_adduplicate(snode);
1840                         }
1841                         break;
1842                 case GKEY:
1843                         if(fromlib) fromlib= -1;
1844                         else {
1845                                 if(G.qual==LR_CTRLKEY) {
1846                                         if(okee("Make Group"))
1847                                                 node_make_group(snode);
1848                                 }
1849                                 else if(G.qual==LR_ALTKEY) {
1850                                         if(okee("Ungroup"))
1851                                                 node_ungroup(snode);
1852                                 }
1853                                 else if(G.qual==LR_SHIFTKEY) {
1854                                         node_addgroup(snode);
1855                                 }
1856                                 else
1857                                         transform_nodes(snode->edittree, 'g', "Translate Node");
1858                         }
1859                         break;
1860                 case HKEY:
1861                         node_hide(snode);
1862                         break;
1863                         
1864                 case DELKEY:
1865                 case XKEY:
1866                         if(fromlib) fromlib= -1;
1867                         else node_delete(snode);
1868                         break;
1869                 }
1870         }
1871
1872         if(fromlib==-1)
1873                 error("Cannot edit Library Data");
1874         if(doredraw)
1875                 scrarea_queue_winredraw(sa);
1876         if(doredraw==2)
1877                 scrarea_queue_headredraw(sa);
1878 }
1879
1880