4
* ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
20
* The Original Code is Copyright (C) 2005 Blender Foundation.
21
* All rights reserved.
23
* The Original Code is: all of this file.
25
* Contributor(s): none yet.
27
* ***** END GPL LICENSE BLOCK *****
35
#include "MEM_guardedalloc.h"
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"
48
#include "BKE_global.h"
49
#include "BKE_image.h"
50
#include "BKE_library.h"
53
#include "BKE_material.h"
54
#include "BKE_scene.h"
55
#include "BKE_utildefines.h"
57
#include "BIF_editview.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"
69
#include "BSE_drawipo.h"
71
#include "BSE_filesel.h"
72
#include "BSE_headerbuttons.h"
75
#include "BLI_blenlib.h"
76
#include "BLI_arithb.h"
78
#include "BDR_editobject.h"
80
#include "RE_pipeline.h"
88
/* currently called from BIF_preview_changed */
89
void snode_tag_dirty(SpaceNode *snode)
93
if(snode->treetype==NTREE_SHADER) {
95
for(node= snode->nodetree->nodes.first; node; node= node->next) {
96
if(node->type==SH_NODE_OUTPUT)
99
snode->flag |= SNODE_DO_PREVIEW; /* this adds an afterqueue on a redraw, to allow button previews to work first */
102
allqueue(REDRAWNODE, 1);
105
static void shader_node_previewrender(ScrArea *sa, SpaceNode *snode)
109
if(snode->id==NULL) return;
110
if( ((Material *)snode->id )->use_nodes==0 ) return;
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) {
117
// int test= node->lasty;
122
ri.pr_rectx = PREVIEW_RENDERSIZE;
123
ri.pr_recty = PREVIEW_RENDERSIZE;
125
BIF_previewrender(snode->id, &ri, NULL, PR_DO_RENDER); /* sends redraw event */
126
if(ri.rect) MEM_freeN(ri.rect);
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);
142
static void snode_handle_recalc(SpaceNode *snode)
144
if(snode->treetype==NTREE_SHADER) {
145
BIF_preview_changed(ID_MA); /* signals buttons windows and node editors */
147
else if(snode->treetype==NTREE_COMPOSIT) {
148
if(G.scene->use_nodes) {
149
snode->nodetree->timecursor= set_timecursor;
151
snode->nodetree->test_break= blender_test_break;
153
ntreeCompositExecTree(snode->nodetree, &G.scene->r, 1); /* 1 is do_previews */
155
snode->nodetree->timecursor= NULL;
156
snode->nodetree->test_break= NULL;
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);
169
static void shader_node_event(SpaceNode *snode, short event)
173
allqueue(REDRAWNODE, 1);
177
snode_handle_recalc(snode);
183
static void load_node_image(char *str) /* called from fileselect */
185
SpaceNode *snode= curarea->spacedata.first;
186
bNode *node= nodeGetActive(snode->edittree);
197
free_image_buffers(ima); /* force read again */
200
NodeTagChanged(snode->edittree, node);
201
snode_handle_recalc(snode);
202
allqueue(REDRAWNODE, 0);
206
static bNode *snode_get_editgroup(SpaceNode *snode)
210
/* get the groupnode */
211
for(gnode= snode->nodetree->nodes.first; gnode; gnode= gnode->next)
212
if(gnode->flag & NODE_GROUP_EDIT)
217
/* node has to be of type 'render layers' */
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)
225
/* the button press won't show up otherwise, button hilites disabled */
228
if(node->id && node->id!=(ID *)G.scene) {
230
set_scene_bg((Scene *)node->id);
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;
240
scemode= G.scene->r.scemode;
241
actlay= G.scene->r.actlay;
243
G.scene->r.scemode |= R_SINGLE_LAYER;
244
G.scene->r.actlay= node->custom1;
248
G.scene->r.scemode= scemode;
249
G.scene->r.actlay= actlay;
259
static void composit_node_event(SpaceNode *snode, short event)
264
allqueue(REDRAWNODE, 1);
266
case B_NODE_LOADIMAGE:
268
bNode *node= nodeGetActive(snode->edittree);
269
char name[FILE_MAXDIR+FILE_MAXFILE];
272
strcpy(name, ((Image *)node->id)->name);
273
else strcpy(name, U.textudir);
275
activate_fileselect(FILE_SPECIAL, "SELECT IMAGE", name, load_node_image);
278
case B_NODE_TREE_EXEC:
279
snode_handle_recalc(snode);
284
bNode *node= BLI_findlink(&snode->edittree->nodes, event-B_NODE_EXEC);
286
NodeTagChanged(snode->edittree, node);
287
NodeTagIDChanged(snode->nodetree, node->id); /* Scene-layer nodes, texture nodes, image nodes, all can be used many times */
289
/* not the best implementation of the world... but we need it to work now :) */
290
if(node->type==CMP_NODE_R_LAYERS && node->custom2) {
291
composite_node_render(snode, node);
292
/* new event, a render can go fullscreen and open new window */
293
addqueue(curarea->win, UI_BUT_EVENT, B_NODE_TREE_EXEC);
296
node= snode_get_editgroup(snode);
298
NodeTagIDChanged(snode->nodetree, node->id);
300
snode_handle_recalc(snode);
308
/* assumes nothing being done in ntree yet, sets the default in/out node */
309
/* called from shading buttons or header */
310
void node_shader_default(Material *ma)
313
bNodeSocket *fromsock, *tosock;
315
/* but lets check it anyway */
317
printf("error in shader initialize\n");
321
ma->nodetree= ntreeAddTree(NTREE_SHADER);
323
out= nodeAddNodeType(ma->nodetree, SH_NODE_OUTPUT, NULL);
324
out->locx= 300.0f; out->locy= 300.0f;
326
in= nodeAddNodeType(ma->nodetree, SH_NODE_MATERIAL, NULL);
327
in->locx= 10.0f; in->locy= 300.0f;
328
nodeSetActive(ma->nodetree, in);
330
/* only a link from color to color */
331
fromsock= in->outputs.first;
332
tosock= out->inputs.first;
333
nodeAddLink(ma->nodetree, in, fromsock, out, tosock);
335
ntreeSolveOrder(ma->nodetree); /* needed for pointers */
338
/* assumes nothing being done in ntree yet, sets the default in/out node */
339
/* called from shading buttons or header */
340
void node_composit_default(Scene *sce)
343
bNodeSocket *fromsock, *tosock;
345
/* but lets check it anyway */
347
printf("error in composit initialize\n");
351
sce->nodetree= ntreeAddTree(NTREE_COMPOSIT);
353
out= nodeAddNodeType(sce->nodetree, CMP_NODE_COMPOSITE, NULL);
354
out->locx= 300.0f; out->locy= 400.0f;
356
in= nodeAddNodeType(sce->nodetree, CMP_NODE_R_LAYERS, NULL);
357
in->locx= 10.0f; in->locy= 400.0f;
358
nodeSetActive(sce->nodetree, in);
360
/* links from color to color */
361
fromsock= in->outputs.first;
362
tosock= out->inputs.first;
363
nodeAddLink(sce->nodetree, in, fromsock, out, tosock);
365
ntreeSolveOrder(sce->nodetree); /* needed for pointers */
368
/* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */
369
void snode_set_context(SpaceNode *snode)
374
snode->nodetree= NULL;
375
snode->id= snode->from= NULL;
377
if(snode->treetype==NTREE_SHADER) {
378
/* need active object, or we allow pinning... */
380
Material *ma= give_current_material(ob, ob->actcol);
382
snode->from= material_from(ob, ob->actcol);
384
snode->nodetree= ma->nodetree;
388
else if(snode->treetype==NTREE_COMPOSIT) {
390
snode->id= &G.scene->id;
391
snode->nodetree= G.scene->nodetree;
394
/* find editable group */
396
for(node= snode->nodetree->nodes.first; node; node= node->next)
397
if(node->flag & NODE_GROUP_EDIT)
401
snode->edittree= (bNodeTree *)node->id;
403
snode->edittree= snode->nodetree;
406
static void node_set_active(SpaceNode *snode, bNode *node)
409
nodeSetActive(snode->edittree, node);
411
if(node->type!=NODE_GROUP) {
413
/* tree specific activate calls */
414
if(snode->treetype==NTREE_SHADER) {
416
/* when we select a material, active texture is cleared, for buttons */
417
if(node->id && GS(node->id->name)==ID_MA)
418
nodeClearActiveID(snode->edittree, ID_TE);
420
BIF_preview_changed(-1); /* temp hack to force texture preview to update */
422
allqueue(REDRAWBUTSSHADING, 1);
423
allqueue(REDRAWIPO, 0);
425
else if(snode->treetype==NTREE_COMPOSIT) {
426
/* make active viewer, currently only 1 supported... */
427
if(node->type==CMP_NODE_VIEWER) {
429
int was_output= node->flag & NODE_DO_OUTPUT;
431
for(tnode= snode->edittree->nodes.first; tnode; tnode= tnode->next)
432
if(tnode->type==CMP_NODE_VIEWER)
433
tnode->flag &= ~NODE_DO_OUTPUT;
435
node->flag |= NODE_DO_OUTPUT;
439
NodeTagChanged(snode->edittree, node);
441
/* if inside group, tag entire group */
442
gnode= snode_get_editgroup(snode);
444
NodeTagIDChanged(snode->nodetree, gnode->id);
446
snode_handle_recalc(snode);
449
/* add node doesnt link this yet... */
451
node->id= find_id("IM", "Viewer Node");
453
Image *ima= alloc_libblock(&G.main->image, ID_IM, "Viewer Node");
454
strcpy(ima->name, "Viewer Node");
456
ima->xrep= ima->yrep= 1;
467
void snode_make_group_editable(SpaceNode *snode, bNode *gnode)
471
/* make sure nothing has group editing on */
472
for(node= snode->nodetree->nodes.first; node; node= node->next)
473
node->flag &= ~NODE_GROUP_EDIT;
476
/* with NULL argument we do a toggle */
477
if(snode->edittree==snode->nodetree)
478
gnode= nodeGetActive(snode->nodetree);
481
if(gnode && gnode->type==NODE_GROUP && gnode->id) {
483
if(okee("Make Group Local"))
484
ntreeMakeLocal((bNodeTree *)gnode->id);
488
gnode->flag |= NODE_GROUP_EDIT;
489
snode->edittree= (bNodeTree *)gnode->id;
491
/* deselect all other nodes, so we can also do grabbing of entire subtree */
492
for(node= snode->nodetree->nodes.first; node; node= node->next)
493
node->flag &= ~SELECT;
494
gnode->flag |= SELECT;
498
snode->edittree= snode->nodetree;
500
ntreeSolveOrder(snode->nodetree);
502
/* finally send out events for new active node */
503
if(snode->treetype==NTREE_SHADER) {
504
allqueue(REDRAWBUTSSHADING, 0);
506
BIF_preview_changed(-1); /* temp hack to force texture preview to update */
509
allqueue(REDRAWNODE, 0);
512
void node_ungroup(SpaceNode *snode)
516
/* are we inside of a group? */
517
gnode= snode_get_editgroup(snode);
519
snode_make_group_editable(snode, NULL);
521
gnode= nodeGetActive(snode->edittree);
522
if(gnode==NULL) return;
524
if(gnode->type!=NODE_GROUP)
525
error("Not a group");
527
if(nodeGroupUnGroup(snode->edittree, gnode)) {
529
ntreeSolveOrder(snode->edittree);
530
BIF_undo_push("Deselect all nodes");
531
allqueue(REDRAWNODE, 0);
534
error("Can't ungroup");
538
/* when links in groups change, inputs/outputs change, nodes added/deleted... */
539
static void snode_verify_groups(SpaceNode *snode)
543
gnode= snode_get_editgroup(snode);
545
/* does all materials */
547
nodeVerifyGroup((bNodeTree *)gnode->id);
551
static void node_addgroup(SpaceNode *snode)
554
int tot= 0, offs, val;
557
if(snode->edittree!=snode->nodetree) {
558
error("Can not add a Group in a Group");
562
/* construct menu with choices */
563
for(ngroup= G.main->nodetree.first; ngroup; ngroup= ngroup->id.next) {
564
if(ngroup->type==snode->treetype)
568
error("No groups available in database");
571
strp= MEM_mallocN(32*tot+32, "menu");
572
strcpy(strp, "Add Group %t");
575
for(tot=0, ngroup= G.main->nodetree.first; ngroup; ngroup= ngroup->id.next, tot++) {
576
if(ngroup->type==snode->treetype)
577
offs+= sprintf(strp+offs, "|%s %%x%d", ngroup->id.name+2, tot);
582
ngroup= BLI_findlink(&G.main->nodetree, val);
584
bNode *node= nodeAddNodeType(snode->edittree, NODE_GROUP, ngroup);
591
node_deselectall(snode, 0);
593
getmouseco_areawin(mval);
594
areamouseco_to_ipoco(G.v2d, mval, &locx, &locy);
597
node->locy= locy + 60.0f; // arbitrary.. so its visible
598
node->flag |= SELECT;
600
id_us_plus(node->id);
602
node_set_active(snode, node);
603
BIF_undo_push("Add Node");
611
/* ************************** Node generic ************** */
613
/* allows to walk the list in order of visibility */
614
static bNode *next_node(bNodeTree *ntree)
616
static bNode *current=NULL, *last= NULL;
619
/* set current to the first selected node */
620
for(current= ntree->nodes.last; current; current= current->prev)
621
if(current->flag & NODE_SELECT)
624
/* set last to the first unselected node */
625
for(last= ntree->nodes.last; last; last= last->prev)
626
if((last->flag & NODE_SELECT)==0)
634
/* no nodes, or we are ready */
638
/* now we walk the list backwards, but we always return current */
639
if(current->flag & NODE_SELECT) {
640
bNode *node= current;
642
/* find previous selected */
643
current= current->prev;
644
while(current && (current->flag & NODE_SELECT)==0)
645
current= current->prev;
647
/* find first unselected */
654
bNode *node= current;
656
/* find previous unselected */
657
current= current->prev;
658
while(current && (current->flag & NODE_SELECT))
659
current= current->prev;
667
/* is rct in visible part of node? */
668
static bNode *visible_node(SpaceNode *snode, rctf *rct)
672
for(next_node(snode->edittree); (tnode=next_node(NULL));) {
673
if(BLI_isect_rctf(&tnode->totr, rct, NULL))
679
void snode_home(ScrArea *sa, SpaceNode *snode)
684
snode->v2d.cur.xmin= snode->v2d.cur.ymin= 0.0f;
685
snode->v2d.cur.xmax= sa->winx;
686
snode->v2d.cur.xmax= sa->winy;
688
if(snode->edittree) {
689
for(node= snode->edittree->nodes.first; node; node= node->next) {
692
snode->v2d.cur= node->totr;
695
BLI_union_rctf(&snode->v2d.cur, &node->totr);
699
snode->v2d.tot= snode->v2d.cur;
700
test_view2d(G.v2d, sa->winx, sa->winy);
704
void snode_zoom_out(ScrArea *sa)
708
dx= (float)(0.15*(G.v2d->cur.xmax-G.v2d->cur.xmin));
709
G.v2d->cur.xmin-= dx;
710
G.v2d->cur.xmax+= dx;
711
dx= (float)(0.15*(G.v2d->cur.ymax-G.v2d->cur.ymin));
712
G.v2d->cur.ymin-= dx;
713
G.v2d->cur.ymax+= dx;
714
test_view2d(G.v2d, sa->winx, sa->winy);
717
void snode_zoom_in(ScrArea *sa)
721
dx= (float)(0.1154*(G.v2d->cur.xmax-G.v2d->cur.xmin));
722
G.v2d->cur.xmin+= dx;
723
G.v2d->cur.xmax-= dx;
724
dx= (float)(0.1154*(G.v2d->cur.ymax-G.v2d->cur.ymin));
725
G.v2d->cur.ymin+= dx;
726
G.v2d->cur.ymax-= dx;
727
test_view2d(G.v2d, sa->winx, sa->winy);
730
/* checks mouse position, and returns found node/socket */
731
/* type is SOCK_IN and/or SOCK_OUT */
732
static int find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, int in_out)
739
getmouseco_areawin(mval);
740
areamouseco_to_ipoco(G.v2d, mval, &rect.xmin, &rect.ymin);
742
rect.xmin -= NODE_SOCKSIZE+3;
743
rect.ymin -= NODE_SOCKSIZE+3;
744
rect.xmax = rect.xmin + 2*NODE_SOCKSIZE+6;
745
rect.ymax = rect.ymin + 2*NODE_SOCKSIZE+6;
747
/* check if we click in a socket */
748
for(node= snode->edittree->nodes.first; node; node= node->next) {
749
if(in_out & SOCK_IN) {
750
for(sock= node->inputs.first; sock; sock= sock->next) {
751
if(!(sock->flag & SOCK_HIDDEN)) {
752
if(BLI_in_rctf(&rect, sock->locx, sock->locy)) {
753
if(node == visible_node(snode, &rect)) {
762
if(in_out & SOCK_OUT) {
763
for(sock= node->outputs.first; sock; sock= sock->next) {
764
if(!(sock->flag & SOCK_HIDDEN)) {
765
if(BLI_in_rctf(&rect, sock->locx, sock->locy)) {
766
if(node == visible_node(snode, &rect)) {
779
/* ********************* transform ****************** */
781
/* releases on event, only intern (for extern see below) */
782
/* we need argument ntree to allow operations on edittree or nodetree */
783
static void transform_nodes(bNodeTree *ntree, char mode, char *undostr)
786
float mxstart, mystart, mx, my, *oldlocs, *ol;
787
int cont=1, tot=0, cancel=0, firsttime=1;
788
short mval[2], mvalo[2];
791
for(node= ntree->nodes.first; node; node= node->next)
792
if(node->flag & SELECT) tot++;
797
ol= oldlocs= MEM_mallocN(sizeof(float)*2*tot, "oldlocs transform");
798
for(node= ntree->nodes.first; node; node= node->next) {
799
if(node->flag & SELECT) {
800
ol[0]= node->locx; ol[1]= node->locy;
805
getmouseco_areawin(mvalo);
806
areamouseco_to_ipoco(G.v2d, mvalo, &mxstart, &mystart);
810
getmouseco_areawin(mval);
811
if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || firsttime) {
815
areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
819
for(ol= oldlocs, node= ntree->nodes.first; node; node= node->next) {
820
if(node->flag & SELECT) {
821
node->locx= ol[0] + mx-mxstart;
822
node->locy= ol[1] + my-mystart;
834
unsigned short event= extern_qread(&val);
850
if(val) arrows_move_cursor(event);
858
for(ol= oldlocs, node= ntree->nodes.first; node; node= node->next) {
859
if(node->flag & SELECT) {
868
BIF_undo_push(undostr);
870
allqueue(REDRAWNODE, 1);
874
/* external call, also for callback */
875
void node_transform_ext(int mode, int unused)
877
SpaceNode *snode= curarea->spacedata.first;
879
transform_nodes(snode->edittree, 'g', "Move Node");
883
/* releases on event, only 1 node */
884
static void scale_node(SpaceNode *snode, bNode *node)
886
float mxstart, mystart, mx, my, oldwidth;
887
int cont=1, cancel=0;
888
short mval[2], mvalo[2];
891
if(node->flag & NODE_HIDDEN)
892
oldwidth= node->miniwidth;
894
oldwidth= node->width;
896
getmouseco_areawin(mvalo);
897
areamouseco_to_ipoco(G.v2d, mvalo, &mxstart, &mystart);
901
getmouseco_areawin(mval);
902
if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {
904
areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
908
if(node->flag & NODE_HIDDEN) {
909
node->miniwidth= oldwidth + mx-mxstart;
910
CLAMP(node->miniwidth, 0.0f, 100.0f);
913
node->width= oldwidth + mx-mxstart;
914
CLAMP(node->width, node->typeinfo->minwidth, node->typeinfo->maxwidth);
924
unsigned short event= extern_qread(&val);
945
node->width= oldwidth;
948
BIF_undo_push("Scale Node");
950
allqueue(REDRAWNODE, 1);
955
/* ********************** select ******************** */
957
/* used in buttons to check context, also checks for edited groups */
958
bNode *editnode_get_active_idnode(bNodeTree *ntree, short id_code)
962
/* check for edited group */
963
for(node= ntree->nodes.first; node; node= node->next)
964
if(node->flag & NODE_GROUP_EDIT)
967
return nodeGetActiveID((bNodeTree *)node->id, id_code);
969
return nodeGetActiveID(ntree, id_code);
972
/* used in buttons to check context, also checks for edited groups */
973
Material *editnode_get_active_material(Material *ma)
975
if(ma && ma->use_nodes && ma->nodetree) {
976
bNode *node= editnode_get_active_idnode(ma->nodetree, ID_MA);
978
return (Material *)node->id;
985
/* used in buttons to check context, also checks for edited groups */
986
bNode *editnode_get_active(bNodeTree *ntree)
990
/* check for edited group */
991
for(node= ntree->nodes.first; node; node= node->next)
992
if(node->flag & NODE_GROUP_EDIT)
995
return nodeGetActive((bNodeTree *)node->id);
997
return nodeGetActive(ntree);
1002
void node_deselectall(SpaceNode *snode, int swap)
1007
for(node= snode->edittree->nodes.first; node; node= node->next)
1008
if(node->flag & SELECT)
1011
for(node= snode->edittree->nodes.first; node; node= node->next)
1012
node->flag |= SELECT;
1013
allqueue(REDRAWNODE, 0);
1016
/* else pass on to deselect */
1019
for(node= snode->edittree->nodes.first; node; node= node->next)
1020
node->flag &= ~SELECT;
1022
allqueue(REDRAWNODE, 0);
1025
int node_has_hidden_sockets(bNode *node)
1029
for(sock= node->inputs.first; sock; sock= sock->next)
1030
if(sock->flag & SOCK_HIDDEN)
1032
for(sock= node->outputs.first; sock; sock= sock->next)
1033
if(sock->flag & SOCK_HIDDEN)
1039
static void node_hide_unhide_sockets(SpaceNode *snode, bNode *node)
1044
if( node_has_hidden_sockets(node) ) {
1045
for(sock= node->inputs.first; sock; sock= sock->next)
1046
sock->flag &= ~SOCK_HIDDEN;
1047
for(sock= node->outputs.first; sock; sock= sock->next)
1048
sock->flag &= ~SOCK_HIDDEN;
1051
bNode *gnode= snode_get_editgroup(snode);
1053
/* hiding inside group should not break links in other group users */
1055
nodeGroupSocketUseFlags((bNodeTree *)gnode->id);
1056
for(sock= node->inputs.first; sock; sock= sock->next)
1057
if(!(sock->flag & SOCK_IN_USE))
1058
if(sock->link==NULL)
1059
sock->flag |= SOCK_HIDDEN;
1060
for(sock= node->outputs.first; sock; sock= sock->next)
1061
if(!(sock->flag & SOCK_IN_USE))
1062
if(nodeCountSocketLinks(snode->edittree, sock)==0)
1063
sock->flag |= SOCK_HIDDEN;
1066
/* hide unused sockets */
1067
for(sock= node->inputs.first; sock; sock= sock->next) {
1068
if(sock->link==NULL)
1069
sock->flag |= SOCK_HIDDEN;
1071
for(sock= node->outputs.first; sock; sock= sock->next) {
1072
if(nodeCountSocketLinks(snode->edittree, sock)==0)
1073
sock->flag |= SOCK_HIDDEN;
1078
allqueue(REDRAWNODE, 1);
1079
snode_verify_groups(snode);
1080
BIF_undo_push("Hide/Unhide sockets");
1084
static int do_header_node(SpaceNode *snode, bNode *node, float mx, float my)
1086
rctf totr= node->totr;
1088
totr.ymin= totr.ymax-20.0f;
1090
totr.xmax= totr.xmin+15.0f;
1091
if(BLI_in_rctf(&totr, mx, my)) {
1092
node->flag |= NODE_HIDDEN;
1093
allqueue(REDRAWNODE, 0);
1097
totr.xmax= node->totr.xmax;
1098
totr.xmin= totr.xmax-18.0f;
1099
if(node->typeinfo->flag & NODE_PREVIEW) {
1100
if(BLI_in_rctf(&totr, mx, my)) {
1101
node->flag ^= NODE_PREVIEW;
1102
allqueue(REDRAWNODE, 0);
1107
if(node->type == NODE_GROUP) {
1108
if(BLI_in_rctf(&totr, mx, my)) {
1109
snode_make_group_editable(snode, node);
1114
if(node->typeinfo->flag & NODE_OPTIONS) {
1115
if(BLI_in_rctf(&totr, mx, my)) {
1116
node->flag ^= NODE_OPTIONS;
1117
allqueue(REDRAWNODE, 0);
1122
/* hide unused sockets */
1123
if(BLI_in_rctf(&totr, mx, my)) {
1124
node_hide_unhide_sockets(snode, node);
1129
totr.xmin= totr.xmax-10.0f;
1130
totr.ymax= totr.ymin+10.0f;
1131
if(BLI_in_rctf(&totr, mx, my)) {
1132
scale_node(snode, node);
1138
static int do_header_hidden_node(SpaceNode *snode, bNode *node, float mx, float my)
1140
rctf totr= node->totr;
1142
totr.xmax= totr.xmin+15.0f;
1143
if(BLI_in_rctf(&totr, mx, my)) {
1144
node->flag &= ~NODE_HIDDEN;
1145
allqueue(REDRAWNODE, 0);
1149
totr.xmax= node->totr.xmax;
1150
totr.xmin= node->totr.xmax-15.0f;
1151
if(BLI_in_rctf(&totr, mx, my)) {
1152
scale_node(snode, node);
1159
/* return 0: nothing done */
1160
static int node_mouse_select(SpaceNode *snode, unsigned short event)
1166
getmouseco_areawin(mval);
1167
areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
1169
for(next_node(snode->edittree); (node=next_node(NULL));) {
1171
/* first check for the headers or scaling widget */
1172
if(node->flag & NODE_HIDDEN) {
1173
if(do_header_hidden_node(snode, node, mx, my))
1177
if(do_header_node(snode, node, mx, my))
1182
if(BLI_in_rctf(&node->totr, mx, my))
1186
if((G.qual & LR_SHIFTKEY)==0)
1187
node_deselectall(snode, 0);
1189
if(G.qual & LR_SHIFTKEY) {
1190
if(node->flag & SELECT)
1191
node->flag &= ~SELECT;
1193
node->flag |= SELECT;
1196
node->flag |= SELECT;
1198
node_set_active(snode, node);
1200
/* not so nice (no event), but function below delays redraw otherwise */
1203
std_rmouse_transform(node_transform_ext); /* does undo push for select */
1210
/* return 0, nothing done */
1211
static int node_mouse_groupheader(SpaceNode *snode)
1217
gnode= snode_get_editgroup(snode);
1218
if(gnode==NULL) return 0;
1220
getmouseco_areawin(mval);
1221
areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
1223
/* click in header or outside? */
1224
if(BLI_in_rctf(&gnode->totr, mx, my)==0) {
1225
rctf rect= gnode->totr;
1227
rect.ymax += NODE_DY;
1228
if(BLI_in_rctf(&rect, mx, my)==0)
1229
snode_make_group_editable(snode, NULL); /* toggles, so exits editmode */
1231
transform_nodes(snode->nodetree, 'g', "Move group");
1238
static int node_socket_hilights(SpaceNode *snode, int in_out)
1241
bNodeSocket *sock, *tsock, *socksel= NULL;
1243
short mval[2], redraw= 0;
1245
if(snode->edittree==NULL) return 0;
1247
getmouseco_areawin(mval);
1248
areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
1250
/* deselect socks */
1251
for(node= snode->edittree->nodes.first; node; node= node->next) {
1252
for(sock= node->inputs.first; sock; sock= sock->next) {
1253
if(sock->flag & SELECT) {
1254
sock->flag &= ~SELECT;
1259
for(sock= node->outputs.first; sock; sock= sock->next) {
1260
if(sock->flag & SELECT) {
1261
sock->flag &= ~SELECT;
1268
if(find_indicated_socket(snode, &node, &tsock, in_out)) {
1269
tsock->flag |= SELECT;
1270
if(redraw==1 && tsock==socksel) redraw= 0;
1277
void node_border_select(SpaceNode *snode)
1284
if ( (val = get_border(&rect, 3)) ) {
1288
areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1291
areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1293
for(node= snode->edittree->nodes.first; node; node= node->next) {
1294
if(BLI_isect_rctf(&rectf, &node->totr, NULL)) {
1296
node->flag |= SELECT;
1298
node->flag &= ~SELECT;
1301
allqueue(REDRAWNODE, 1);
1302
BIF_undo_push("Border select nodes");
1306
/* ****************** Add *********************** */
1308
/* can be called from menus too, but they should do own undopush and redraws */
1309
bNode *node_add_node(SpaceNode *snode, int type, float locx, float locy)
1311
bNode *node= NULL, *gnode;
1313
node_deselectall(snode, 0);
1315
if(type>=NODE_GROUP_MENU) {
1316
if(snode->edittree!=snode->nodetree) {
1317
error("Can not add a Group in a Group");
1321
bNodeTree *ngroup= BLI_findlink(&G.main->nodetree, type-NODE_GROUP_MENU);
1323
node= nodeAddNodeType(snode->edittree, NODE_GROUP, ngroup);
1327
node= nodeAddNodeType(snode->edittree, type, NULL);
1332
node->locy= locy + 60.0f; // arbitrary.. so its visible
1333
node->flag |= SELECT;
1335
gnode= snode_get_editgroup(snode);
1337
node->locx -= gnode->locx;
1338
node->locy -= gnode->locy;
1341
snode_verify_groups(snode);
1342
node_set_active(snode, node);
1345
id_us_plus(node->id);
1350
void node_adduplicate(SpaceNode *snode)
1353
ntreeCopyTree(snode->edittree, 1); /* 1 == internally selected nodes */
1355
ntreeSolveOrder(snode->edittree);
1356
snode_verify_groups(snode);
1357
snode_handle_recalc(snode);
1359
transform_nodes(snode->edittree, 'g', "Duplicate");
1362
static void node_insert_convertor(SpaceNode *snode, bNodeLink *link)
1364
bNode *newnode= NULL;
1366
if(link->fromsock->type==SOCK_RGBA && link->tosock->type==SOCK_VALUE) {
1367
if(snode->edittree->type==NTREE_SHADER)
1368
newnode= node_add_node(snode, SH_NODE_RGBTOBW, 0.0f, 0.0f);
1369
else if(snode->edittree->type==NTREE_COMPOSIT)
1370
newnode= node_add_node(snode, CMP_NODE_RGBTOBW, 0.0f, 0.0f);
1374
else if(link->fromsock->type==SOCK_VALUE && link->tosock->type==SOCK_RGBA) {
1375
if(snode->edittree->type==NTREE_SHADER)
1376
newnode= node_add_node(snode, SH_NODE_VALTORGB, 0.0f, 0.0f);
1377
else if(snode->edittree->type==NTREE_COMPOSIT)
1378
newnode= node_add_node(snode, CMP_NODE_VALTORGB, 0.0f, 0.0f);
1384
/* dangerous assumption to use first in/out socks, but thats fine for now */
1385
newnode->flag |= NODE_HIDDEN;
1386
newnode->locx= 0.5f*(link->fromsock->locx + link->tosock->locx);
1387
newnode->locy= 0.5f*(link->fromsock->locy + link->tosock->locy) + HIDDEN_RAD;
1389
nodeAddLink(snode->edittree, newnode, newnode->outputs.first, link->tonode, link->tosock);
1390
link->tonode= newnode;
1391
link->tosock= newnode->inputs.first;
1396
/* loop that adds a nodelink, called by function below */
1397
/* in_out = starting socket */
1398
static int node_add_link_drag(SpaceNode *snode, bNode *node, bNodeSocket *sock, int in_out)
1402
bNodeLink *link= NULL;
1403
short mval[2], mvalo[2], firsttime=1; /* firsttime reconnects a link broken by caller */
1405
/* we make a temporal link */
1406
if(in_out==SOCK_OUT)
1407
link= nodeAddLink(snode->edittree, node, sock, NULL, NULL);
1409
link= nodeAddLink(snode->edittree, NULL, NULL, node, sock);
1411
getmouseco_areawin(mvalo);
1412
while (get_mbut() & L_MOUSE) {
1414
getmouseco_areawin(mval);
1415
if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || firsttime) {
1421
if(in_out==SOCK_OUT) {
1422
if(find_indicated_socket(snode, &tnode, &tsock, SOCK_IN)) {
1423
if(nodeFindLink(snode->edittree, sock, tsock)==NULL) {
1424
if(tnode!=node && link->tonode!=tnode && link->tosock!= tsock) {
1425
link->tonode= tnode;
1426
link->tosock= tsock;
1427
ntreeSolveOrder(snode->edittree); /* for interactive red line warning */
1437
if(find_indicated_socket(snode, &tnode, &tsock, SOCK_OUT)) {
1438
if(nodeFindLink(snode->edittree, sock, tsock)==NULL) {
1439
if(nodeCountSocketLinks(snode->edittree, tsock) < tsock->limit) {
1440
if(tnode!=node && link->fromnode!=tnode && link->fromsock!= tsock) {
1441
link->fromnode= tnode;
1442
link->fromsock= tsock;
1443
ntreeSolveOrder(snode->edittree); /* for interactive red line warning */
1449
link->fromnode= NULL;
1450
link->fromsock= NULL;
1453
/* hilight target sockets only */
1454
node_socket_hilights(snode, in_out==SOCK_OUT?SOCK_IN:SOCK_OUT);
1458
else BIF_wait_for_statechange();
1462
if(link->tonode==NULL || link->fromnode==NULL) {
1463
nodeRemLink(snode->edittree, link);
1468
/* send changed events for original tonode and new */
1470
NodeTagChanged(snode->edittree, link->tonode);
1472
/* we might need to remove a link */
1473
if(in_out==SOCK_OUT) {
1474
if(nodeCountSocketLinks(snode->edittree, link->tosock) > tsock->limit) {
1476
for(tlink= snode->edittree->links.first; tlink; tlink= tlink->next) {
1477
if(link!=tlink && tlink->tosock==link->tosock)
1481
/* is there a free input socket with same type? */
1482
for(tsock= tlink->tonode->inputs.first; tsock; tsock= tsock->next) {
1483
if(tsock->type==tlink->fromsock->type)
1484
if(nodeCountSocketLinks(snode->edittree, tsock) < tsock->limit)
1488
tlink->tosock= tsock;
1490
nodeRemLink(snode->edittree, tlink);
1496
/* and last trick: insert a convertor when types dont match */
1497
if(snode->treetype==NTREE_SHADER) {
1498
if(link->tosock->type!=link->fromsock->type) {
1499
node_insert_convertor(snode, link);
1500
/* so nice do it twice! well, the sort-order can only handle 1 added link at a time */
1501
ntreeSolveOrder(snode->edittree);
1506
ntreeSolveOrder(snode->edittree);
1507
snode_verify_groups(snode);
1508
snode_handle_recalc(snode);
1510
allqueue(REDRAWNODE, 0);
1511
BIF_undo_push("Add link");
1516
/* return 1 when socket clicked */
1517
static int node_add_link(SpaceNode *snode)
1523
/* output indicated? */
1524
if(find_indicated_socket(snode, &node, &sock, SOCK_OUT)) {
1525
if(nodeCountSocketLinks(snode->edittree, sock)<sock->limit)
1526
return node_add_link_drag(snode, node, sock, SOCK_OUT);
1528
/* find if we break a link */
1529
for(link= snode->edittree->links.first; link; link= link->next) {
1530
if(link->fromsock==sock)
1536
nodeRemLink(snode->edittree, link);
1537
return node_add_link_drag(snode, node, sock, SOCK_IN);
1542
else if(find_indicated_socket(snode, &node, &sock, SOCK_IN)) {
1543
if(nodeCountSocketLinks(snode->edittree, sock)<sock->limit)
1544
return node_add_link_drag(snode, node, sock, SOCK_IN);
1546
/* find if we break a link */
1547
for(link= snode->edittree->links.first; link; link= link->next) {
1548
if(link->tosock==sock)
1552
/* send changed event to original tonode */
1554
NodeTagChanged(snode->edittree, link->tonode);
1556
node= link->fromnode;
1557
sock= link->fromsock;
1558
nodeRemLink(snode->edittree, link);
1559
return node_add_link_drag(snode, node, sock, SOCK_OUT);
1567
void node_delete(SpaceNode *snode)
1571
for(node= snode->edittree->nodes.first; node; node= next) {
1573
if(node->flag & SELECT)
1574
nodeFreeNode(snode->edittree, node);
1577
snode_verify_groups(snode);
1578
snode_handle_recalc(snode);
1579
BIF_undo_push("Delete nodes");
1580
allqueue(REDRAWNODE, 1);
1583
void node_hide(SpaceNode *snode)
1586
int nothidden=0, ishidden=0;
1588
for(node= snode->edittree->nodes.first; node; node= node->next) {
1589
if(node->flag & SELECT) {
1590
if(node->flag & NODE_HIDDEN)
1596
for(node= snode->edittree->nodes.first; node; node= node->next) {
1597
if(node->flag & SELECT) {
1598
if( (ishidden && nothidden) || ishidden==0)
1599
node->flag |= NODE_HIDDEN;
1601
node->flag &= ~NODE_HIDDEN;
1604
BIF_undo_push("Hide nodes");
1605
allqueue(REDRAWNODE, 1);
1609
static void node_border_link_delete(SpaceNode *snode)
1612
short val, mval[2], mvalo[2];
1614
/* to make this work more friendly, we first wait for a mouse move */
1615
getmouseco_areawin(mvalo);
1616
while (get_mbut() & L_MOUSE) {
1617
getmouseco_areawin(mval);
1618
if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1])
1620
else BIF_wait_for_statechange();
1622
if((get_mbut() & L_MOUSE)==0)
1625
/* now change cursor and draw border */
1626
setcursor_space(SPACE_NODE, CURSOR_VPAINT);
1628
if ( (val = get_border(&rect, 2)) ) {
1629
if(rect.xmin<rect.xmax && rect.ymin<rect.ymax) {
1630
//#define NODE_MAXPICKBUF 256
1631
bNodeLink *link, *next;
1638
areamouseco_to_ipoco(&snode->v2d, mval, &rectf.xmin, &rectf.ymin);
1641
areamouseco_to_ipoco(&snode->v2d, mval, &rectf.xmax, &rectf.ymax);
1643
myortho2(rectf.xmin, rectf.xmax, rectf.ymin, rectf.ymax);
1645
glSelectBuffer(256, buffer);
1646
glRenderMode(GL_SELECT);
1651
for(link= snode->edittree->links.first; link; link= link->next) {
1653
node_draw_link(snode, link);
1656
hits= glRenderMode(GL_RENDER);
1660
for(a=0; a<hits; a++) {
1661
bNodeLink *link= BLI_findlink(&snode->edittree->links, buffer[ (4 * a) + 3]);
1663
link->fromnode= NULL; /* first tag for delete, otherwise indices are wrong */
1665
for(link= snode->edittree->links.first; link; link= next) {
1667
if(link->fromnode==NULL) {
1668
NodeTagChanged(snode->edittree, link->tonode);
1669
nodeRemLink(snode->edittree, link);
1672
ntreeSolveOrder(snode->edittree);
1673
snode_verify_groups(snode);
1674
snode_handle_recalc(snode);
1676
allqueue(REDRAWNODE, 0);
1677
BIF_undo_push("Erase links");
1681
setcursor_space(SPACE_NODE, CURSOR_STD);
1684
/* goes over all scenes, reads render layerss */
1685
void node_read_renderlayers(SpaceNode *snode)
1690
/* first tag scenes unread */
1691
for(scene= G.main->scene.first; scene; scene= scene->id.next)
1692
scene->id.flag |= LIB_DOIT;
1694
for(node= snode->edittree->nodes.first; node; node= node->next) {
1695
if(node->type==CMP_NODE_R_LAYERS) {
1697
if(id==NULL) id= (ID *)G.scene;
1698
if(id->flag & LIB_DOIT) {
1699
RE_ReadRenderResult(G.scene, (Scene *)id);
1700
id->flag &= ~LIB_DOIT;
1705
ntreeCompositTagRender(snode->edittree);
1706
snode_handle_recalc(snode);
1710
/* ********************** */
1712
void node_make_group(SpaceNode *snode)
1716
if(snode->edittree!=snode->nodetree) {
1717
error("Can not add a new Group in a Group");
1721
/* for time being... is too complex to handle */
1722
if(snode->treetype==NTREE_COMPOSIT) {
1723
for(gnode=snode->nodetree->nodes.first; gnode; gnode= gnode->next) {
1724
if(gnode->flag & SELECT)
1725
if(gnode->type==CMP_NODE_R_LAYERS)
1729
error("Can not add RenderLayer in a Group");
1734
gnode= nodeMakeGroupFromSelected(snode->nodetree);
1736
error("Can not make Group");
1739
nodeSetActive(snode->nodetree, gnode);
1740
ntreeSolveOrder(snode->nodetree);
1741
allqueue(REDRAWNODE, 0);
1742
BIF_undo_push("Make Node Group");
1746
/* ******************** main event loop ****************** */
1748
/* special version to prevent overlapping buttons, has a bit of hack... */
1749
/* yes, check for example composit_node_event(), file window use... */
1750
static int node_uiDoBlocks(ScrArea *sa, short event)
1752
SpaceNode *snode= sa->spacedata.first;
1753
ListBase *lb= &sa->uiblocks;
1754
ListBase listb= *lb;
1758
int retval= UI_NOTHING;
1761
getmouseco_areawin(mval);
1762
areamouseco_to_ipoco(G.v2d, mval, &rect.xmin, &rect.ymin);
1764
/* this happens after filesel usage... */
1765
if(lb->first==NULL) {
1771
rect.xmax = rect.xmin + 4.0f;
1772
rect.ymax = rect.ymin + 4.0f;
1774
for(node= snode->edittree->nodes.first; node; node= node->next) {
1778
/* retreive unique block name, see also drawnode.c */
1779
sprintf(str, "node buttons %p", node);
1780
block= uiGetBlock(str, sa);
1783
if(node == visible_node(snode, &rect)) {
1785
/* when there's menus, the prev pointer becomes zero! */
1786
prev= ((struct Link *)block)->prev;
1787
next= ((struct Link *)block)->next;
1788
((struct Link *)block)->prev= NULL;
1789
((struct Link *)block)->next= NULL;
1791
lb->first= lb->last= block;
1792
retval= uiDoBlocks(lb, event);
1794
((struct Link *)block)->prev= prev;
1795
((struct Link *)block)->next= next;
1807
void winqreadnodespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
1809
SpaceNode *snode= spacedata;
1810
unsigned short event= evt->event;
1811
short val= evt->val, doredraw=0, fromlib= 0;
1813
if(sa->win==0) return;
1814
if(snode->nodetree==NULL) return;
1818
if( node_uiDoBlocks(sa, event)!=UI_NOTHING ) event= 0;
1820
fromlib= (snode->id && snode->id->lib);
1825
if(node_mouse_groupheader(snode)==0)
1826
node_mouse_select(snode, event);
1829
if(node_add_link(snode)==0)
1830
if(node_mouse_groupheader(snode)==0)
1831
if(node_mouse_select(snode, event)==0)
1832
node_border_link_delete(snode);
1837
node_mouse_select(snode, event);
1842
case WHEELDOWNMOUSE:
1843
view2dmove(event); /* in drawipo.c */
1847
doredraw= node_socket_hilights(snode, SOCK_IN|SOCK_OUT);
1851
/* future: handlerize this! */
1852
if(snode->treetype==NTREE_SHADER)
1853
shader_node_event(snode, val);
1854
else if(snode->treetype==NTREE_COMPOSIT)
1855
composit_node_event(snode, val);
1859
if(snode->treetype==NTREE_SHADER)
1860
shader_node_previewrender(sa, snode);
1872
snode_home(sa, snode);
1876
if(fromlib) fromlib= -1;
1877
else snode_make_group_editable(snode, NULL);
1881
if(G.qual==LR_SHIFTKEY) {
1882
if(fromlib) fromlib= -1;
1883
else toolbox_n_add();
1885
else if(G.qual==0) {
1886
node_deselectall(snode, 1);
1887
BIF_undo_push("Deselect all nodes");
1892
node_border_select(snode);
1894
case CKEY: /* sort again, showing cyclics */
1895
ntreeSolveOrder(snode->edittree);
1899
if(G.qual==LR_SHIFTKEY) {
1900
if(fromlib) fromlib= -1;
1901
else node_adduplicate(snode);
1905
if(fromlib) fromlib= -1;
1907
if(G.qual==LR_CTRLKEY) {
1908
if(okee("Make Group"))
1909
node_make_group(snode);
1911
else if(G.qual==LR_ALTKEY) {
1913
node_ungroup(snode);
1915
else if(G.qual==LR_SHIFTKEY) {
1916
node_addgroup(snode);
1919
transform_nodes(snode->edittree, 'g', "Move Node");
1926
if(okee("Read saved Render Layers"))
1927
node_read_renderlayers(snode);
1931
if(fromlib) fromlib= -1;
1932
else node_delete(snode);
1938
error("Cannot edit Library Data");
1940
scrarea_queue_winredraw(sa);
1942
scrarea_queue_headredraw(sa);