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_color_types.h"
39 #include "DNA_image_types.h"
40 #include "DNA_ipo_types.h"
41 #include "DNA_object_types.h"
42 #include "DNA_material_types.h"
43 #include "DNA_node_types.h"
44 #include "DNA_space_types.h"
45 #include "DNA_screen_types.h"
46 #include "DNA_scene_types.h"
47 #include "DNA_userdef_types.h"
49 #include "BKE_colortools.h"
50 #include "BKE_global.h"
51 #include "BKE_image.h"
52 #include "BKE_library.h"
55 #include "BKE_material.h"
56 #include "BKE_scene.h"
57 #include "BKE_utildefines.h"
59 #include "BIF_cursors.h"
60 #include "BIF_editview.h"
62 #include "BIF_graphics.h"
63 #include "BIF_interface.h"
64 #include "BIF_mywindow.h"
65 #include "BIF_previewrender.h"
66 #include "BIF_resources.h"
67 #include "BIF_renderwin.h"
68 #include "BIF_space.h"
69 #include "BIF_screen.h"
70 #include "BIF_toolbox.h"
72 #include "BSE_drawipo.h"
74 #include "BSE_filesel.h"
75 #include "BSE_headerbuttons.h"
78 #include "BLI_blenlib.h"
79 #include "BLI_arithb.h"
81 #include "BDR_editobject.h"
83 #include "RE_pipeline.h"
84 #include "IMB_imbuf_types.h"
93 /* currently called from BIF_preview_changed */
94 void snode_tag_dirty(SpaceNode
*snode
)
98 if(snode
->treetype
==NTREE_SHADER
) {
100 for(node
= snode
->nodetree
->nodes
.first
; node
; node
= node
->next
) {
101 if(node
->type
==SH_NODE_OUTPUT
)
104 snode
->flag
|= SNODE_DO_PREVIEW
; /* this adds an afterqueue on a redraw, to allow button previews to work first */
107 allqueue(REDRAWNODE
, 1);
110 static void shader_node_previewrender(ScrArea
*sa
, SpaceNode
*snode
)
114 if(snode
->id
==NULL
) return;
115 if( ((Material
*)snode
->id
)->use_nodes
==0 ) return;
117 for(node
= snode
->nodetree
->nodes
.first
; node
; node
= node
->next
) {
118 if(node
->type
==SH_NODE_OUTPUT
) {
119 if(node
->flag
& NODE_DO_OUTPUT
) {
120 if(node
->lasty
<PREVIEW_RENDERSIZE
-2) {
122 // int test= node->lasty;
127 ri
.pr_rectx
= PREVIEW_RENDERSIZE
;
128 ri
.pr_recty
= PREVIEW_RENDERSIZE
;
130 BIF_previewrender(snode
->id
, &ri
, NULL
, PR_DO_RENDER
); /* sends redraw event */
131 if(ri
.rect
) MEM_freeN(ri
.rect
);
133 /* when not finished... */
134 if(ri
.curtile
<ri
.tottile
)
135 addafterqueue(sa
->win
, RENDERPREVIEW
, 1);
136 // if(test!=node->lasty)
137 // printf("node rendered to %d\n", node->lasty);
147 static void snode_handle_recalc(SpaceNode
*snode
)
149 if(snode
->treetype
==NTREE_SHADER
) {
150 BIF_preview_changed(ID_MA
); /* signals buttons windows and node editors */
152 else if(snode
->treetype
==NTREE_COMPOSIT
) {
153 if(G
.scene
->use_nodes
) {
154 snode
->nodetree
->timecursor
= set_timecursor
;
156 snode
->nodetree
->test_break
= blender_test_break
;
160 ntreeCompositExecTree(snode
->nodetree
, &G
.scene
->r
, 1); /* 1 is do_previews */
162 snode
->nodetree
->timecursor
= NULL
;
163 snode
->nodetree
->test_break
= NULL
;
166 allqueue(REDRAWNODE
, 1);
167 allqueue(REDRAWIMAGE
, 1);
168 if(G
.scene
->r
.scemode
& R_DOCOMP
) {
169 BIF_redraw_render_rect(); /* seems to screwup display? */
170 mywinset(curarea
->win
);
176 static void shader_node_event(SpaceNode
*snode
, short event
)
180 allqueue(REDRAWNODE
, 1);
184 snode_handle_recalc(snode
);
190 static void load_node_image(char *str
) /* called from fileselect */
192 SpaceNode
*snode
= curarea
->spacedata
.first
;
193 bNode
*node
= nodeGetActive(snode
->edittree
);
196 ima
= BKE_add_image_file(str
);
202 id_us_plus(node
->id
);
204 BLI_strncpy(node
->name
, node
->id
->name
+2, 21);
206 BKE_image_signal(ima
, node
->storage
, IMA_SIGNAL_RELOAD
);
208 NodeTagChanged(snode
->edittree
, node
);
209 snode_handle_recalc(snode
);
210 allqueue(REDRAWNODE
, 0);
214 static bNode
*snode_get_editgroup(SpaceNode
*snode
)
218 /* get the groupnode */
219 for(gnode
= snode
->nodetree
->nodes
.first
; gnode
; gnode
= gnode
->next
)
220 if(gnode
->flag
& NODE_GROUP_EDIT
)
225 /* node has to be of type 'render layers' */
226 /* is a bit clumsy copying renderdata here... scene nodes use render size of current render */
227 static void composite_node_render(SpaceNode
*snode
, bNode
*node
)
233 /* the button press won't show up otherwise, button hilites disabled */
236 if(node
->id
&& node
->id
!=(ID
*)G
.scene
) {
238 set_scene_bg((Scene
*)node
->id
);
240 G
.scene
->r
.xsch
= scene
->r
.xsch
;
241 G
.scene
->r
.ysch
= scene
->r
.ysch
;
242 G
.scene
->r
.size
= scene
->r
.size
;
243 G
.scene
->r
.mode
&= ~(R_BORDER
|R_DOCOMP
);
244 G
.scene
->r
.mode
|= scene
->r
.mode
& R_BORDER
;
245 G
.scene
->r
.border
= scene
->r
.border
;
246 G
.scene
->r
.cfra
= scene
->r
.cfra
;
249 scemode
= G
.scene
->r
.scemode
;
250 actlay
= G
.scene
->r
.actlay
;
252 G
.scene
->r
.scemode
|= R_SINGLE_LAYER
;
253 G
.scene
->r
.actlay
= node
->custom1
;
257 G
.scene
->r
.scemode
= scemode
;
258 G
.scene
->r
.actlay
= actlay
;
268 static void composit_node_event(SpaceNode
*snode
, short event
)
273 allqueue(REDRAWNODE
, 1);
275 case B_NODE_LOADIMAGE
:
277 bNode
*node
= nodeGetActive(snode
->edittree
);
278 char name
[FILE_MAXDIR
+FILE_MAXFILE
];
281 strcpy(name
, ((Image
*)node
->id
)->name
);
282 else strcpy(name
, U
.textudir
);
284 activate_fileselect(FILE_SPECIAL
, "SELECT IMAGE", name
, load_node_image
);
287 case B_NODE_TREE_EXEC
:
288 snode_handle_recalc(snode
);
293 bNode
*node
= BLI_findlink(&snode
->edittree
->nodes
, event
-B_NODE_EXEC
);
295 NodeTagChanged(snode
->edittree
, node
);
296 /* don't use NodeTagIDChanged, it gives far too many recomposites for image, scene layers, ... */
298 /* not the best implementation of the world... but we need it to work now :) */
299 if(node
->type
==CMP_NODE_R_LAYERS
&& node
->custom2
) {
300 /* new event, a render can go fullscreen and open new window */
301 addqueue(curarea
->win
, UI_BUT_EVENT
, B_NODE_TREE_EXEC
);
302 composite_node_render(snode
, node
);
303 snode_handle_recalc(snode
);
306 node
= snode_get_editgroup(snode
);
308 NodeTagIDChanged(snode
->nodetree
, node
->id
);
310 snode_handle_recalc(snode
);
318 /* assumes nothing being done in ntree yet, sets the default in/out node */
319 /* called from shading buttons or header */
320 void node_shader_default(Material
*ma
)
323 bNodeSocket
*fromsock
, *tosock
;
325 /* but lets check it anyway */
327 printf("error in shader initialize\n");
331 ma
->nodetree
= ntreeAddTree(NTREE_SHADER
);
333 out
= nodeAddNodeType(ma
->nodetree
, SH_NODE_OUTPUT
, NULL
);
334 out
->locx
= 300.0f
; out
->locy
= 300.0f
;
336 in
= nodeAddNodeType(ma
->nodetree
, SH_NODE_MATERIAL
, NULL
);
337 in
->locx
= 10.0f
; in
->locy
= 300.0f
;
338 nodeSetActive(ma
->nodetree
, in
);
340 /* only a link from color to color */
341 fromsock
= in
->outputs
.first
;
342 tosock
= out
->inputs
.first
;
343 nodeAddLink(ma
->nodetree
, in
, fromsock
, out
, tosock
);
345 ntreeSolveOrder(ma
->nodetree
); /* needed for pointers */
348 /* assumes nothing being done in ntree yet, sets the default in/out node */
349 /* called from shading buttons or header */
350 void node_composit_default(Scene
*sce
)
353 bNodeSocket
*fromsock
, *tosock
;
355 /* but lets check it anyway */
357 printf("error in composit initialize\n");
361 sce
->nodetree
= ntreeAddTree(NTREE_COMPOSIT
);
363 out
= nodeAddNodeType(sce
->nodetree
, CMP_NODE_COMPOSITE
, NULL
);
364 out
->locx
= 300.0f
; out
->locy
= 400.0f
;
366 in
= nodeAddNodeType(sce
->nodetree
, CMP_NODE_R_LAYERS
, NULL
);
367 in
->locx
= 10.0f
; in
->locy
= 400.0f
;
368 nodeSetActive(sce
->nodetree
, in
);
370 /* links from color to color */
371 fromsock
= in
->outputs
.first
;
372 tosock
= out
->inputs
.first
;
373 nodeAddLink(sce
->nodetree
, in
, fromsock
, out
, tosock
);
375 ntreeSolveOrder(sce
->nodetree
); /* needed for pointers */
377 ntreeCompositForceHidden(sce
->nodetree
);
380 /* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */
381 void snode_set_context(SpaceNode
*snode
)
386 snode
->nodetree
= NULL
;
387 snode
->id
= snode
->from
= NULL
;
389 if(snode
->treetype
==NTREE_SHADER
) {
390 /* need active object, or we allow pinning... */
392 Material
*ma
= give_current_material(ob
, ob
->actcol
);
394 snode
->from
= material_from(ob
, ob
->actcol
);
396 snode
->nodetree
= ma
->nodetree
;
400 else if(snode
->treetype
==NTREE_COMPOSIT
) {
402 snode
->id
= &G
.scene
->id
;
404 /* bit clumsy but reliable way to see if we draw first time */
405 if(snode
->nodetree
==NULL
)
406 ntreeCompositForceHidden(G
.scene
->nodetree
);
408 snode
->nodetree
= G
.scene
->nodetree
;
411 /* find editable group */
413 for(node
= snode
->nodetree
->nodes
.first
; node
; node
= node
->next
)
414 if(node
->flag
& NODE_GROUP_EDIT
)
418 snode
->edittree
= (bNodeTree
*)node
->id
;
420 snode
->edittree
= snode
->nodetree
;
423 /* on activate image viewer, check if we show it */
424 static void node_active_image(Image
*ima
)
427 SpaceImage
*sima
= NULL
;
429 /* find an imagewindow showing render result */
430 for(sa
=G
.curscreen
->areabase
.first
; sa
; sa
= sa
->next
) {
431 if(sa
->spacetype
==SPACE_IMAGE
) {
432 sima
= sa
->spacedata
.first
;
433 if(sima
->image
&& sima
->image
->source
!=IMA_SRC_VIEWER
)
439 scrarea_queue_winredraw(sa
);
440 scrarea_queue_headredraw(sa
);
445 static void node_set_active(SpaceNode
*snode
, bNode
*node
)
448 nodeSetActive(snode
->edittree
, node
);
450 if(node
->type
!=NODE_GROUP
) {
452 /* tree specific activate calls */
453 if(snode
->treetype
==NTREE_SHADER
) {
455 /* when we select a material, active texture is cleared, for buttons */
456 if(node
->id
&& GS(node
->id
->name
)==ID_MA
)
457 nodeClearActiveID(snode
->edittree
, ID_TE
);
459 BIF_preview_changed(-1); /* temp hack to force texture preview to update */
461 allqueue(REDRAWBUTSSHADING
, 1);
462 allqueue(REDRAWIPO
, 0);
464 else if(snode
->treetype
==NTREE_COMPOSIT
) {
465 /* make active viewer, currently only 1 supported... */
466 if( ELEM(node
->type
, CMP_NODE_VIEWER
, CMP_NODE_SPLITVIEWER
)) {
468 int was_output
= node
->flag
& NODE_DO_OUTPUT
;
470 for(tnode
= snode
->edittree
->nodes
.first
; tnode
; tnode
= tnode
->next
)
471 if( ELEM(tnode
->type
, CMP_NODE_VIEWER
, CMP_NODE_SPLITVIEWER
))
472 tnode
->flag
&= ~NODE_DO_OUTPUT
;
474 node
->flag
|= NODE_DO_OUTPUT
;
478 NodeTagChanged(snode
->edittree
, node
);
480 /* if inside group, tag entire group */
481 gnode
= snode_get_editgroup(snode
);
483 NodeTagIDChanged(snode
->nodetree
, gnode
->id
);
485 snode_handle_recalc(snode
);
488 /* addnode() doesnt link this yet... */
489 node
->id
= (ID
*)BKE_image_verify_viewer(IMA_TYPE_COMPOSITE
, "Viewer Node");
491 else if(node
->type
==CMP_NODE_IMAGE
) {
493 node_active_image((Image
*)node
->id
);
495 else if(node
->type
==CMP_NODE_R_LAYERS
) {
496 if(node
->id
==NULL
|| node
->id
==(ID
*)G
.scene
) {
497 G
.scene
->r
.actlay
= node
->custom1
;
498 allqueue(REDRAWBUTSSCENE
, 0);
505 void snode_make_group_editable(SpaceNode
*snode
, bNode
*gnode
)
509 /* make sure nothing has group editing on */
510 for(node
= snode
->nodetree
->nodes
.first
; node
; node
= node
->next
)
511 node
->flag
&= ~NODE_GROUP_EDIT
;
514 /* with NULL argument we do a toggle */
515 if(snode
->edittree
==snode
->nodetree
)
516 gnode
= nodeGetActive(snode
->nodetree
);
519 if(gnode
&& gnode
->type
==NODE_GROUP
&& gnode
->id
) {
521 if(okee("Make Group Local"))
522 ntreeMakeLocal((bNodeTree
*)gnode
->id
);
526 gnode
->flag
|= NODE_GROUP_EDIT
;
527 snode
->edittree
= (bNodeTree
*)gnode
->id
;
529 /* deselect all other nodes, so we can also do grabbing of entire subtree */
530 for(node
= snode
->nodetree
->nodes
.first
; node
; node
= node
->next
)
531 node
->flag
&= ~SELECT
;
532 gnode
->flag
|= SELECT
;
536 snode
->edittree
= snode
->nodetree
;
538 ntreeSolveOrder(snode
->nodetree
);
540 /* finally send out events for new active node */
541 if(snode
->treetype
==NTREE_SHADER
) {
542 allqueue(REDRAWBUTSSHADING
, 0);
544 BIF_preview_changed(-1); /* temp hack to force texture preview to update */
547 allqueue(REDRAWNODE
, 0);
550 void node_ungroup(SpaceNode
*snode
)
554 /* are we inside of a group? */
555 gnode
= snode_get_editgroup(snode
);
557 snode_make_group_editable(snode
, NULL
);
559 gnode
= nodeGetActive(snode
->edittree
);
560 if(gnode
==NULL
) return;
562 if(gnode
->type
!=NODE_GROUP
)
563 error("Not a group");
565 if(nodeGroupUnGroup(snode
->edittree
, gnode
)) {
567 BIF_undo_push("Deselect all nodes");
568 allqueue(REDRAWNODE
, 0);
571 error("Can't ungroup");
575 /* when links in groups change, inputs/outputs change, nodes added/deleted... */
576 static void snode_verify_groups(SpaceNode
*snode
)
580 gnode
= snode_get_editgroup(snode
);
582 /* does all materials */
584 nodeVerifyGroup((bNodeTree
*)gnode
->id
);
588 static void node_addgroup(SpaceNode
*snode
)
591 int tot
= 0, offs
, val
;
594 if(snode
->edittree
!=snode
->nodetree
) {
595 error("Can not add a Group in a Group");
599 /* construct menu with choices */
600 for(ngroup
= G
.main
->nodetree
.first
; ngroup
; ngroup
= ngroup
->id
.next
) {
601 if(ngroup
->type
==snode
->treetype
)
605 error("No groups available in database");
608 strp
= MEM_mallocN(32*tot
+32, "menu");
609 strcpy(strp
, "Add Group %t");
612 for(tot
=0, ngroup
= G
.main
->nodetree
.first
; ngroup
; ngroup
= ngroup
->id
.next
, tot
++) {
613 if(ngroup
->type
==snode
->treetype
)
614 offs
+= sprintf(strp
+offs
, "|%s %%x%d", ngroup
->id
.name
+2, tot
);
619 ngroup
= BLI_findlink(&G
.main
->nodetree
, val
);
621 bNode
*node
= nodeAddNodeType(snode
->edittree
, NODE_GROUP
, ngroup
);
628 node_deselectall(snode
, 0);
630 getmouseco_areawin(mval
);
631 areamouseco_to_ipoco(G
.v2d
, mval
, &locx
, &locy
);
634 node
->locy
= locy
+ 60.0f
; // arbitrary.. so its visible
635 node
->flag
|= SELECT
;
637 id_us_plus(node
->id
);
639 node_set_active(snode
, node
);
640 BIF_undo_push("Add Node");
648 /* ************************** Node generic ************** */
650 /* allows to walk the list in order of visibility */
651 static bNode
*next_node(bNodeTree
*ntree
)
653 static bNode
*current
=NULL
, *last
= NULL
;
656 /* set current to the first selected node */
657 for(current
= ntree
->nodes
.last
; current
; current
= current
->prev
)
658 if(current
->flag
& NODE_SELECT
)
661 /* set last to the first unselected node */
662 for(last
= ntree
->nodes
.last
; last
; last
= last
->prev
)
663 if((last
->flag
& NODE_SELECT
)==0)
671 /* no nodes, or we are ready */
675 /* now we walk the list backwards, but we always return current */
676 if(current
->flag
& NODE_SELECT
) {
677 bNode
*node
= current
;
679 /* find previous selected */
680 current
= current
->prev
;
681 while(current
&& (current
->flag
& NODE_SELECT
)==0)
682 current
= current
->prev
;
684 /* find first unselected */
691 bNode
*node
= current
;
693 /* find previous unselected */
694 current
= current
->prev
;
695 while(current
&& (current
->flag
& NODE_SELECT
))
696 current
= current
->prev
;
704 /* is rct in visible part of node? */
705 static bNode
*visible_node(SpaceNode
*snode
, rctf
*rct
)
709 for(next_node(snode
->edittree
); (tnode
=next_node(NULL
));) {
710 if(BLI_isect_rctf(&tnode
->totr
, rct
, NULL
))
716 void snode_home(ScrArea
*sa
, SpaceNode
*snode
)
721 snode
->v2d
.cur
.xmin
= snode
->v2d
.cur
.ymin
= 0.0f
;
722 snode
->v2d
.cur
.xmax
= sa
->winx
;
723 snode
->v2d
.cur
.xmax
= sa
->winy
;
725 if(snode
->edittree
) {
726 for(node
= snode
->edittree
->nodes
.first
; node
; node
= node
->next
) {
729 snode
->v2d
.cur
= node
->totr
;
732 BLI_union_rctf(&snode
->v2d
.cur
, &node
->totr
);
736 snode
->v2d
.tot
= snode
->v2d
.cur
;
738 snode
->xof
= snode
->yof
= 0.0;
740 test_view2d(G
.v2d
, sa
->winx
, sa
->winy
);
744 void snode_zoom_out(ScrArea
*sa
)
748 dx
= (float)(0.15*(G
.v2d
->cur
.xmax
-G
.v2d
->cur
.xmin
));
749 G
.v2d
->cur
.xmin
-= dx
;
750 G
.v2d
->cur
.xmax
+= dx
;
751 dx
= (float)(0.15*(G
.v2d
->cur
.ymax
-G
.v2d
->cur
.ymin
));
752 G
.v2d
->cur
.ymin
-= dx
;
753 G
.v2d
->cur
.ymax
+= dx
;
754 test_view2d(G
.v2d
, sa
->winx
, sa
->winy
);
757 void snode_zoom_in(ScrArea
*sa
)
761 dx
= (float)(0.1154*(G
.v2d
->cur
.xmax
-G
.v2d
->cur
.xmin
));
762 G
.v2d
->cur
.xmin
+= dx
;
763 G
.v2d
->cur
.xmax
-= dx
;
764 dx
= (float)(0.1154*(G
.v2d
->cur
.ymax
-G
.v2d
->cur
.ymin
));
765 G
.v2d
->cur
.ymin
+= dx
;
766 G
.v2d
->cur
.ymax
-= dx
;
767 test_view2d(G
.v2d
, sa
->winx
, sa
->winy
);
770 static void snode_bg_viewmove(SpaceNode
*snode
)
776 short mval
[2], mvalo
[2];
777 short rectx
, recty
, xmin
, xmax
, ymin
, ymax
, pad
;
780 ima
= BKE_image_verify_viewer(IMA_TYPE_COMPOSITE
, "Viewer Node");
781 ibuf
= BKE_image_get_ibuf(ima
, NULL
);
793 xmin
= -(sa
->winx
/2) - rectx
/2 + pad
;
794 xmax
= sa
->winx
/2 + rectx
/2 - pad
;
795 ymin
= -(sa
->winy
/2) - recty
/2 + pad
;
796 ymax
= sa
->winy
/2 + recty
/2 - pad
;
798 getmouseco_sc(mvalo
);
800 /* store the old cursor to temporarily change it */
801 oldcursor
=get_cursor();
802 win
=winlay_get_active_window();
804 SetBlenderCursor(BC_NSEW_SCROLLCURSOR
);
806 while(get_mbut()&(L_MOUSE
|M_MOUSE
)) {
810 if(mvalo
[0]!=mval
[0] || mvalo
[1]!=mval
[1]) {
812 snode
->xof
-= (mvalo
[0]-mval
[0]);
813 snode
->yof
-= (mvalo
[1]-mval
[1]);
815 /* prevent dragging image outside of the window and losing it! */
816 CLAMP(snode
->xof
, xmin
, xmax
);
817 CLAMP(snode
->yof
, ymin
, ymax
);
822 scrarea_do_windraw(curarea
);
823 screen_swapbuffers();
825 else BIF_wait_for_statechange();
828 window_set_cursor(win
, oldcursor
);
831 static void reset_sel_socket(SpaceNode
*snode
, int in_out
)
836 for(node
= snode
->edittree
->nodes
.first
; node
; node
= node
->next
) {
837 if(in_out
& SOCK_IN
) {
838 for(sock
= node
->inputs
.first
; sock
; sock
= sock
->next
)
839 if(sock
->flag
& SOCK_SEL
) sock
->flag
&= ~SOCK_SEL
;
841 if(in_out
& SOCK_OUT
) {
842 for(sock
= node
->outputs
.first
; sock
; sock
= sock
->next
)
843 if(sock
->flag
& SOCK_SEL
) sock
->flag
&= ~SOCK_SEL
;
848 /* checks mouse position, and returns found node/socket */
849 /* type is SOCK_IN and/or SOCK_OUT */
850 static int find_indicated_socket(SpaceNode
*snode
, bNode
**nodep
, bNodeSocket
**sockp
, int in_out
)
857 getmouseco_areawin(mval
);
859 /* check if we click in a socket */
860 for(node
= snode
->edittree
->nodes
.first
; node
; node
= node
->next
) {
862 areamouseco_to_ipoco(G
.v2d
, mval
, &rect
.xmin
, &rect
.ymin
);
864 rect
.xmin
-= NODE_SOCKSIZE
+3;
865 rect
.ymin
-= NODE_SOCKSIZE
+3;
866 rect
.xmax
= rect
.xmin
+ 2*NODE_SOCKSIZE
+6;
867 rect
.ymax
= rect
.ymin
+ 2*NODE_SOCKSIZE
+6;
869 if (!(node
->flag
& NODE_HIDDEN
)) {
870 /* extra padding inside and out - allow dragging on the text areas too */
871 if (in_out
== SOCK_IN
) {
872 rect
.xmax
+= NODE_SOCKSIZE
;
873 rect
.xmin
-= NODE_SOCKSIZE
*4;
874 } else if (in_out
== SOCK_OUT
) {
875 rect
.xmax
+= NODE_SOCKSIZE
*4;
876 rect
.xmin
-= NODE_SOCKSIZE
;
880 if(in_out
& SOCK_IN
) {
881 for(sock
= node
->inputs
.first
; sock
; sock
= sock
->next
) {
882 if(!(sock
->flag
& (SOCK_HIDDEN
|SOCK_UNAVAIL
))) {
883 if(BLI_in_rctf(&rect
, sock
->locx
, sock
->locy
)) {
884 if(node
== visible_node(snode
, &rect
)) {
893 if(in_out
& SOCK_OUT
) {
894 for(sock
= node
->outputs
.first
; sock
; sock
= sock
->next
) {
895 if(!(sock
->flag
& (SOCK_HIDDEN
|SOCK_UNAVAIL
))) {
896 if(BLI_in_rctf(&rect
, sock
->locx
, sock
->locy
)) {
897 if(node
== visible_node(snode
, &rect
)) {
910 /* ********************* transform ****************** */
912 /* releases on event, only intern (for extern see below) */
913 /* we need argument ntree to allow operations on edittree or nodetree */
914 static void transform_nodes(bNodeTree
*ntree
, char mode
, char *undostr
)
917 float mxstart
, mystart
, mx
, my
, *oldlocs
, *ol
;
918 int cont
=1, tot
=0, cancel
=0, firsttime
=1;
919 short mval
[2], mvalo
[2];
922 for(node
= ntree
->nodes
.first
; node
; node
= node
->next
)
923 if(node
->flag
& SELECT
) tot
++;
928 ol
= oldlocs
= MEM_mallocN(sizeof(float)*2*tot
, "oldlocs transform");
929 for(node
= ntree
->nodes
.first
; node
; node
= node
->next
) {
930 if(node
->flag
& SELECT
) {
931 ol
[0]= node
->locx
; ol
[1]= node
->locy
;
936 getmouseco_areawin(mvalo
);
937 areamouseco_to_ipoco(G
.v2d
, mvalo
, &mxstart
, &mystart
);
941 getmouseco_areawin(mval
);
942 if(mval
[0]!=mvalo
[0] || mval
[1]!=mvalo
[1] || firsttime
) {
946 areamouseco_to_ipoco(G
.v2d
, mval
, &mx
, &my
);
950 for(ol
= oldlocs
, node
= ntree
->nodes
.first
; node
; node
= node
->next
) {
951 if(node
->flag
& SELECT
) {
952 node
->locx
= ol
[0] + mx
-mxstart
;
953 node
->locy
= ol
[1] + my
-mystart
;
965 unsigned short event
= extern_qread(&val
);
981 if(val
) arrows_move_cursor(event
);
989 for(ol
= oldlocs
, node
= ntree
->nodes
.first
; node
; node
= node
->next
) {
990 if(node
->flag
& SELECT
) {
999 BIF_undo_push(undostr
);
1001 allqueue(REDRAWNODE
, 1);
1005 /* external call, also for callback */
1006 void node_transform_ext(int mode
, int unused
)
1008 SpaceNode
*snode
= curarea
->spacedata
.first
;
1010 transform_nodes(snode
->edittree
, 'g', "Move Node");
1014 /* releases on event, only 1 node */
1015 static void scale_node(SpaceNode
*snode
, bNode
*node
)
1017 float mxstart
, mystart
, mx
, my
, oldwidth
;
1018 int cont
=1, cancel
=0;
1019 short mval
[2], mvalo
[2];
1022 if(node
->flag
& NODE_HIDDEN
)
1023 oldwidth
= node
->miniwidth
;
1025 oldwidth
= node
->width
;
1027 getmouseco_areawin(mvalo
);
1028 areamouseco_to_ipoco(G
.v2d
, mvalo
, &mxstart
, &mystart
);
1032 getmouseco_areawin(mval
);
1033 if(mval
[0]!=mvalo
[0] || mval
[1]!=mvalo
[1]) {
1035 areamouseco_to_ipoco(G
.v2d
, mval
, &mx
, &my
);
1039 if(node
->flag
& NODE_HIDDEN
) {
1040 node
->miniwidth
= oldwidth
+ mx
-mxstart
;
1041 CLAMP(node
->miniwidth
, 0.0f
, 100.0f
);
1044 node
->width
= oldwidth
+ mx
-mxstart
;
1045 CLAMP(node
->width
, node
->typeinfo
->minwidth
, node
->typeinfo
->maxwidth
);
1055 unsigned short event
= extern_qread(&val
);
1076 node
->width
= oldwidth
;
1079 BIF_undo_push("Scale Node");
1081 allqueue(REDRAWNODE
, 1);
1084 void node_rename_cb(SpaceNode
*snode
)
1088 for(node
= snode
->edittree
->nodes
.first
; node
; node
= node
->next
) {
1089 if(node
->flag
& SELECT
) {
1090 draw_node_rename_panel(node
->name
);
1091 allqueue(REDRAWNODE
, 1);
1097 /* ********************** select ******************** */
1099 /* used in buttons to check context, also checks for edited groups */
1100 bNode
*editnode_get_active_idnode(bNodeTree
*ntree
, short id_code
)
1102 return nodeGetActiveID(ntree
, id_code
);
1105 /* used in buttons to check context, also checks for edited groups */
1106 Material
*editnode_get_active_material(Material
*ma
)
1108 if(ma
&& ma
->use_nodes
&& ma
->nodetree
) {
1109 bNode
*node
= editnode_get_active_idnode(ma
->nodetree
, ID_MA
);
1111 return (Material
*)node
->id
;
1118 /* used in buttons to check context, also checks for edited groups */
1119 bNode
*editnode_get_active(bNodeTree
*ntree
)
1123 /* check for edited group */
1124 for(node
= ntree
->nodes
.first
; node
; node
= node
->next
)
1125 if(node
->flag
& NODE_GROUP_EDIT
)
1128 return nodeGetActive((bNodeTree
*)node
->id
);
1130 return nodeGetActive(ntree
);
1133 /* select the same type, no undo here!! */
1134 void node_select_same_type(SpaceNode
*snode
)
1139 for (ac
= snode
->edittree
->nodes
.first
; ac
; ac
= ac
->next
) {
1140 if (ac
->flag
& SELECT
)
1148 for (p
= snode
->edittree
->nodes
.first
; p
; p
= p
->next
) {
1149 if (p
->type
!= ac
->type
&& p
->flag
& SELECT
) {
1153 else if (p
->type
== ac
->type
&& (!(p
->flag
& SELECT
))) {
1160 allqueue(REDRAWNODE
, 0);
1164 void node_deselectall(SpaceNode
*snode
, int swap
)
1169 for(node
= snode
->edittree
->nodes
.first
; node
; node
= node
->next
)
1170 if(node
->flag
& SELECT
)
1173 for(node
= snode
->edittree
->nodes
.first
; node
; node
= node
->next
)
1174 node
->flag
|= SELECT
;
1175 allqueue(REDRAWNODE
, 0);
1178 /* else pass on to deselect */
1181 for(node
= snode
->edittree
->nodes
.first
; node
; node
= node
->next
)
1182 node
->flag
&= ~SELECT
;
1184 allqueue(REDRAWNODE
, 0);
1187 int node_has_hidden_sockets(bNode
*node
)
1191 for(sock
= node
->inputs
.first
; sock
; sock
= sock
->next
)
1192 if(sock
->flag
& SOCK_HIDDEN
)
1194 for(sock
= node
->outputs
.first
; sock
; sock
= sock
->next
)
1195 if(sock
->flag
& SOCK_HIDDEN
)
1201 static void node_hide_unhide_sockets(SpaceNode
*snode
, bNode
*node
)
1206 if( node_has_hidden_sockets(node
) ) {
1207 for(sock
= node
->inputs
.first
; sock
; sock
= sock
->next
)
1208 sock
->flag
&= ~SOCK_HIDDEN
;
1209 for(sock
= node
->outputs
.first
; sock
; sock
= sock
->next
)
1210 sock
->flag
&= ~SOCK_HIDDEN
;
1213 bNode
*gnode
= snode_get_editgroup(snode
);
1215 /* hiding inside group should not break links in other group users */
1217 nodeGroupSocketUseFlags((bNodeTree
*)gnode
->id
);
1218 for(sock
= node
->inputs
.first
; sock
; sock
= sock
->next
)
1219 if(!(sock
->flag
& SOCK_IN_USE
))
1220 if(sock
->link
==NULL
)
1221 sock
->flag
|= SOCK_HIDDEN
;
1222 for(sock
= node
->outputs
.first
; sock
; sock
= sock
->next
)
1223 if(!(sock
->flag
& SOCK_IN_USE
))
1224 if(nodeCountSocketLinks(snode
->edittree
, sock
)==0)
1225 sock
->flag
|= SOCK_HIDDEN
;
1228 /* hide unused sockets */
1229 for(sock
= node
->inputs
.first
; sock
; sock
= sock
->next
) {
1230 if(sock
->link
==NULL
)
1231 sock
->flag
|= SOCK_HIDDEN
;
1233 for(sock
= node
->outputs
.first
; sock
; sock
= sock
->next
) {
1234 if(nodeCountSocketLinks(snode
->edittree
, sock
)==0)
1235 sock
->flag
|= SOCK_HIDDEN
;
1240 allqueue(REDRAWNODE
, 1);
1241 snode_verify_groups(snode
);
1242 BIF_undo_push("Hide/Unhide sockets");
1246 static int do_header_node(SpaceNode
*snode
, bNode
*node
, float mx
, float my
)
1248 rctf totr
= node
->totr
;
1250 totr
.ymin
= totr
.ymax
-20.0f
;
1252 totr
.xmax
= totr
.xmin
+15.0f
;
1253 if(BLI_in_rctf(&totr
, mx
, my
)) {
1254 node
->flag
|= NODE_HIDDEN
;
1255 allqueue(REDRAWNODE
, 0);
1259 totr
.xmax
= node
->totr
.xmax
;
1260 totr
.xmin
= totr
.xmax
-18.0f
;
1261 if(node
->typeinfo
->flag
& NODE_PREVIEW
) {
1262 if(BLI_in_rctf(&totr
, mx
, my
)) {
1263 node
->flag
^= NODE_PREVIEW
;
1264 allqueue(REDRAWNODE
, 0);
1269 if(node
->type
== NODE_GROUP
) {
1270 if(BLI_in_rctf(&totr
, mx
, my
)) {
1271 snode_make_group_editable(snode
, node
);
1276 if(node
->typeinfo
->flag
& NODE_OPTIONS
) {
1277 if(BLI_in_rctf(&totr
, mx
, my
)) {
1278 node
->flag
^= NODE_OPTIONS
;
1279 allqueue(REDRAWNODE
, 0);
1284 /* hide unused sockets */
1285 if(BLI_in_rctf(&totr
, mx
, my
)) {
1286 node_hide_unhide_sockets(snode
, node
);
1291 totr
.xmin
= totr
.xmax
-10.0f
;
1292 totr
.ymax
= totr
.ymin
+10.0f
;
1293 if(BLI_in_rctf(&totr
, mx
, my
)) {
1294 scale_node(snode
, node
);
1300 static int do_header_hidden_node(SpaceNode
*snode
, bNode
*node
, float mx
, float my
)
1302 rctf totr
= node
->totr
;
1304 totr
.xmax
= totr
.xmin
+15.0f
;
1305 if(BLI_in_rctf(&totr
, mx
, my
)) {
1306 node
->flag
&= ~NODE_HIDDEN
;
1307 allqueue(REDRAWNODE
, 0);
1311 totr
.xmax
= node
->totr
.xmax
;
1312 totr
.xmin
= node
->totr
.xmax
-15.0f
;
1313 if(BLI_in_rctf(&totr
, mx
, my
)) {
1314 scale_node(snode
, node
);
1320 static void node_link_viewer(SpaceNode
*snode
, bNode
*tonode
)
1325 if(tonode
==NULL
|| tonode
->outputs
.first
==NULL
)
1327 if( ELEM(tonode
->type
, CMP_NODE_VIEWER
, CMP_NODE_SPLITVIEWER
))
1331 for(node
= snode
->edittree
->nodes
.first
; node
; node
= node
->next
)
1332 if( ELEM(node
->type
, CMP_NODE_VIEWER
, CMP_NODE_SPLITVIEWER
))
1333 if(node
->flag
& NODE_DO_OUTPUT
)
1339 /* get link to viewer */
1340 for(link
= snode
->edittree
->links
.first
; link
; link
= link
->next
)
1341 if(link
->tonode
==node
)
1345 link
->fromnode
= tonode
;
1346 link
->fromsock
= tonode
->outputs
.first
;
1347 NodeTagChanged(snode
->edittree
, node
);
1349 snode_handle_recalc(snode
);
1355 void node_active_link_viewer(SpaceNode
*snode
)
1357 bNode
*node
= editnode_get_active(snode
->edittree
);
1359 node_link_viewer(snode
, node
);
1362 /* return 0: nothing done */
1363 static int node_mouse_select(SpaceNode
*snode
, unsigned short event
)
1369 getmouseco_areawin(mval
);
1370 areamouseco_to_ipoco(G
.v2d
, mval
, &mx
, &my
);
1372 for(next_node(snode
->edittree
); (node
=next_node(NULL
));) {
1374 /* first check for the headers or scaling widget */
1375 if(node
->flag
& NODE_HIDDEN
) {
1376 if(do_header_hidden_node(snode
, node
, mx
, my
))
1380 if(do_header_node(snode
, node
, mx
, my
))
1385 if(BLI_in_rctf(&node
->totr
, mx
, my
))
1389 if((G
.qual
& LR_SHIFTKEY
)==0)
1390 node_deselectall(snode
, 0);
1392 if(G
.qual
& LR_SHIFTKEY
) {
1393 if(node
->flag
& SELECT
)
1394 node
->flag
&= ~SELECT
;
1396 node
->flag
|= SELECT
;
1399 node
->flag
|= SELECT
;
1401 node_set_active(snode
, node
);
1403 /* viewer linking */
1404 if(G
.qual
& LR_CTRLKEY
)
1405 node_link_viewer(snode
, node
);
1407 /* not so nice (no event), but function below delays redraw otherwise */
1410 std_rmouse_transform(node_transform_ext
); /* does undo push for select */
1417 /* return 0, nothing done */
1418 static int node_mouse_groupheader(SpaceNode
*snode
)
1424 gnode
= snode_get_editgroup(snode
);
1425 if(gnode
==NULL
) return 0;
1427 getmouseco_areawin(mval
);
1428 areamouseco_to_ipoco(G
.v2d
, mval
, &mx
, &my
);
1430 /* click in header or outside? */
1431 if(BLI_in_rctf(&gnode
->totr
, mx
, my
)==0) {
1432 rctf rect
= gnode
->totr
;
1434 rect
.ymax
+= NODE_DY
;
1435 if(BLI_in_rctf(&rect
, mx
, my
)==0)
1436 snode_make_group_editable(snode
, NULL
); /* toggles, so exits editmode */
1438 transform_nodes(snode
->nodetree
, 'g', "Move group");
1445 static int node_socket_hilights(SpaceNode
*snode
, int in_out
)
1448 bNodeSocket
*sock
, *tsock
, *socksel
= NULL
;
1450 short mval
[2], redraw
= 0;
1452 if(snode
->edittree
==NULL
) return 0;
1454 getmouseco_areawin(mval
);
1455 areamouseco_to_ipoco(G
.v2d
, mval
, &mx
, &my
);
1457 /* deselect socks */
1458 for(node
= snode
->edittree
->nodes
.first
; node
; node
= node
->next
) {
1459 for(sock
= node
->inputs
.first
; sock
; sock
= sock
->next
) {
1460 if(sock
->flag
& SELECT
) {
1461 sock
->flag
&= ~SELECT
;
1466 for(sock
= node
->outputs
.first
; sock
; sock
= sock
->next
) {
1467 if(sock
->flag
& SELECT
) {
1468 sock
->flag
&= ~SELECT
;
1475 if(find_indicated_socket(snode
, &node
, &tsock
, in_out
)) {
1476 tsock
->flag
|= SELECT
;
1477 if(redraw
==1 && tsock
==socksel
) redraw
= 0;
1484 void node_border_select(SpaceNode
*snode
)
1491 if ( (val
= get_border(&rect
, 3)) ) {
1495 areamouseco_to_ipoco(G
.v2d
, mval
, &rectf
.xmin
, &rectf
.ymin
);
1498 areamouseco_to_ipoco(G
.v2d
, mval
, &rectf
.xmax
, &rectf
.ymax
);
1500 for(node
= snode
->edittree
->nodes
.first
; node
; node
= node
->next
) {
1501 if(BLI_isect_rctf(&rectf
, &node
->totr
, NULL
)) {
1503 node
->flag
|= SELECT
;
1505 node
->flag
&= ~SELECT
;
1508 allqueue(REDRAWNODE
, 1);
1509 BIF_undo_push("Border select nodes");
1513 /* ****************** Add *********************** */
1515 void snode_autoconnect(SpaceNode
*snode
, bNode
*node_to
, int flag
)
1517 bNodeSocket
*sock
, *sockfrom
[8];
1518 bNode
*node
, *nodefrom
[8];
1519 int totsock
= 0, socktype
=0;
1521 if(node_to
==NULL
|| node_to
->inputs
.first
==NULL
)
1524 /* no inputs for node allowed (code it) */
1526 /* connect first 1 socket type now */
1527 for(sock
= node_to
->inputs
.first
; sock
; sock
= sock
->next
)
1528 if(socktype
<sock
->type
)
1529 socktype
= sock
->type
;
1532 /* find potential sockets, max 8 should work */
1533 for(node
= snode
->edittree
->nodes
.first
; node
; node
= node
->next
) {
1534 if((node
->flag
& flag
) && node
!=node_to
) {
1535 for(sock
= node
->outputs
.first
; sock
; sock
= sock
->next
) {
1536 if(!(sock
->flag
& (SOCK_HIDDEN
|SOCK_UNAVAIL
))) {
1537 sockfrom
[totsock
]= sock
;
1538 nodefrom
[totsock
]= node
;
1549 /* now just get matching socket types and create links */
1550 for(sock
= node_to
->inputs
.first
; sock
; sock
= sock
->next
) {
1553 for(a
=0; a
<totsock
; a
++) {
1555 if(sock
->type
==sockfrom
[a
]->type
&& sock
->type
==socktype
) {
1556 nodeAddLink(snode
->edittree
, nodefrom
[a
], sockfrom
[a
], node_to
, sock
);
1564 ntreeSolveOrder(snode
->edittree
);
1567 /* can be called from menus too, but they should do own undopush and redraws */
1568 bNode
*node_add_node(SpaceNode
*snode
, int type
, float locx
, float locy
)
1570 bNode
*node
= NULL
, *gnode
;
1572 node_deselectall(snode
, 0);
1574 if(type
>=NODE_GROUP_MENU
) {
1575 if(snode
->edittree
!=snode
->nodetree
) {
1576 error("Can not add a Group in a Group");
1580 bNodeTree
*ngroup
= BLI_findlink(&G
.main
->nodetree
, type
-NODE_GROUP_MENU
);
1582 node
= nodeAddNodeType(snode
->edittree
, NODE_GROUP
, ngroup
);
1586 node
= nodeAddNodeType(snode
->edittree
, type
, NULL
);
1591 node
->locy
= locy
+ 60.0f
; // arbitrary.. so its visible
1592 node
->flag
|= SELECT
;
1594 gnode
= snode_get_editgroup(snode
);
1596 node
->locx
-= gnode
->locx
;
1597 node
->locy
-= gnode
->locy
;
1600 snode_verify_groups(snode
);
1601 node_set_active(snode
, node
);
1604 id_us_plus(node
->id
);
1606 if(snode
->nodetree
->type
==NTREE_COMPOSIT
)
1607 ntreeCompositForceHidden(snode
->edittree
);
1609 NodeTagChanged(snode
->edittree
, node
);
1614 void node_mute(SpaceNode
*snode
)
1619 /* no disabling inside of groups */
1620 if(snode_get_editgroup(snode
))
1624 for(node
= snode
->edittree
->nodes
.first
; node
; node
= node
->next
) {
1625 if(node
->flag
& SELECT
) {
1626 if(node
->inputs
.first
&& node
->outputs
.first
) {
1628 NodeTagChanged(snode
->edittree
, node
);
1632 if(node
->flag
& NODE_MUTED
)
1633 node
->flag
&= ~NODE_MUTED
;
1635 node
->flag
|= NODE_MUTED
;
1641 snode_handle_recalc(snode
);
1643 allqueue(REDRAWNODE
, 0);
1644 BIF_undo_push("Enable/Disable nodes");
1648 void node_adduplicate(SpaceNode
*snode
)
1651 ntreeCopyTree(snode
->edittree
, 1); /* 1 == internally selected nodes */
1653 ntreeSolveOrder(snode
->edittree
);
1654 snode_verify_groups(snode
);
1655 snode_handle_recalc(snode
);
1657 transform_nodes(snode
->edittree
, 'g', "Duplicate");
1661 static void node_insert_convertor(SpaceNode
*snode
, bNodeLink
*link
)
1663 bNode
*newnode
= NULL
;
1665 if(link
->fromsock
->type
==SOCK_RGBA
&& link
->tosock
->type
==SOCK_VALUE
) {
1666 if(snode
->edittree
->type
==NTREE_SHADER
)
1667 newnode
= node_add_node(snode
, SH_NODE_RGBTOBW
, 0.0f
, 0.0f
);
1668 else if(snode
->edittree
->type
==NTREE_COMPOSIT
)
1669 newnode
= node_add_node(snode
, CMP_NODE_RGBTOBW
, 0.0f
, 0.0f
);
1673 else if(link
->fromsock
->type
==SOCK_VALUE
&& link
->tosock
->type
==SOCK_RGBA
) {
1674 if(snode
->edittree
->type
==NTREE_SHADER
)
1675 newnode
= node_add_node(snode
, SH_NODE_VALTORGB
, 0.0f
, 0.0f
);
1676 else if(snode
->edittree
->type
==NTREE_COMPOSIT
)
1677 newnode
= node_add_node(snode
, CMP_NODE_VALTORGB
, 0.0f
, 0.0f
);
1683 /* dangerous assumption to use first in/out socks, but thats fine for now */
1684 newnode
->flag
|= NODE_HIDDEN
;
1685 newnode
->locx
= 0.5f
*(link
->fromsock
->locx
+ link
->tosock
->locx
);
1686 newnode
->locy
= 0.5f
*(link
->fromsock
->locy
+ link
->tosock
->locy
) + HIDDEN_RAD
;
1688 nodeAddLink(snode
->edittree
, newnode
, newnode
->outputs
.first
, link
->tonode
, link
->tosock
);
1689 link
->tonode
= newnode
;
1690 link
->tosock
= newnode
->inputs
.first
;
1696 static void node_remove_extra_links(SpaceNode
*snode
, bNodeSocket
*tsock
, bNodeLink
*link
)
1701 if(tsock
&& nodeCountSocketLinks(snode
->edittree
, link
->tosock
) > tsock
->limit
) {
1703 for(tlink
= snode
->edittree
->links
.first
; tlink
; tlink
= tlink
->next
) {
1704 if(link
!=tlink
&& tlink
->tosock
==link
->tosock
)
1708 /* is there a free input socket with same type? */
1709 for(sock
= tlink
->tonode
->inputs
.first
; sock
; sock
= sock
->next
) {
1710 if(sock
->type
==tlink
->fromsock
->type
)
1711 if(nodeCountSocketLinks(snode
->edittree
, sock
) < sock
->limit
)
1715 tlink
->tosock
= sock
;
1716 sock
->flag
&= ~SOCK_HIDDEN
;
1719 nodeRemLink(snode
->edittree
, tlink
);
1725 /* loop that adds a nodelink, called by function below */
1726 /* in_out = starting socket */
1727 static int node_add_link_drag(SpaceNode
*snode
, bNode
*node
, bNodeSocket
*sock
, int in_out
)
1730 bNodeSocket
*tsock
= NULL
;
1731 bNodeLink
*link
= NULL
;
1732 short mval
[2], mvalo
[2], firsttime
=1; /* firsttime reconnects a link broken by caller */
1734 /* we make a temporal link */
1735 if(in_out
==SOCK_OUT
)
1736 link
= nodeAddLink(snode
->edittree
, node
, sock
, NULL
, NULL
);
1738 link
= nodeAddLink(snode
->edittree
, NULL
, NULL
, node
, sock
);
1740 getmouseco_areawin(mvalo
);
1741 while (get_mbut() & L_MOUSE
) {
1743 getmouseco_areawin(mval
);
1744 if(mval
[0]!=mvalo
[0] || mval
[1]!=mvalo
[1] || firsttime
) {
1750 if(in_out
==SOCK_OUT
) {
1751 if(find_indicated_socket(snode
, &tnode
, &tsock
, SOCK_IN
)) {
1752 if(nodeFindLink(snode
->edittree
, sock
, tsock
)==NULL
) {
1753 if(tnode
!=node
&& link
->tonode
!=tnode
&& link
->tosock
!= tsock
) {
1754 link
->tonode
= tnode
;
1755 link
->tosock
= tsock
;
1756 ntreeSolveOrder(snode
->edittree
); /* for interactive red line warning */
1766 if(find_indicated_socket(snode
, &tnode
, &tsock
, SOCK_OUT
)) {
1767 if(nodeFindLink(snode
->edittree
, sock
, tsock
)==NULL
) {
1768 if(nodeCountSocketLinks(snode
->edittree
, tsock
) < tsock
->limit
) {
1769 if(tnode
!=node
&& link
->fromnode
!=tnode
&& link
->fromsock
!= tsock
) {
1770 link
->fromnode
= tnode
;
1771 link
->fromsock
= tsock
;
1772 ntreeSolveOrder(snode
->edittree
); /* for interactive red line warning */
1778 link
->fromnode
= NULL
;
1779 link
->fromsock
= NULL
;
1782 /* hilight target sockets only */
1783 node_socket_hilights(snode
, in_out
==SOCK_OUT
?SOCK_IN
:SOCK_OUT
);
1787 else BIF_wait_for_statechange();
1791 if(link
->tonode
==NULL
|| link
->fromnode
==NULL
) {
1792 nodeRemLink(snode
->edittree
, link
);
1795 /* send changed events for original tonode and new */
1797 NodeTagChanged(snode
->edittree
, link
->tonode
);
1799 /* we might need to remove a link */
1800 if(in_out
==SOCK_OUT
) node_remove_extra_links(snode
, tsock
, link
);
1803 ntreeSolveOrder(snode
->edittree
);
1804 snode_verify_groups(snode
);
1805 snode_handle_recalc(snode
);
1807 allqueue(REDRAWNODE
, 0);
1808 BIF_undo_push("Add link");
1813 /* return 1 when socket clicked */
1814 static int node_add_link(SpaceNode
*snode
)
1820 /* output indicated? */
1821 if(find_indicated_socket(snode
, &node
, &sock
, SOCK_OUT
)) {
1822 if(nodeCountSocketLinks(snode
->edittree
, sock
)<sock
->limit
)
1823 return node_add_link_drag(snode
, node
, sock
, SOCK_OUT
);
1825 /* find if we break a link */
1826 for(link
= snode
->edittree
->links
.first
; link
; link
= link
->next
) {
1827 if(link
->fromsock
==sock
)
1833 nodeRemLink(snode
->edittree
, link
);
1834 return node_add_link_drag(snode
, node
, sock
, SOCK_IN
);
1839 else if(find_indicated_socket(snode
, &node
, &sock
, SOCK_IN
)) {
1840 if(nodeCountSocketLinks(snode
->edittree
, sock
)<sock
->limit
)
1841 return node_add_link_drag(snode
, node
, sock
, SOCK_IN
);
1843 /* find if we break a link */
1844 for(link
= snode
->edittree
->links
.first
; link
; link
= link
->next
) {
1845 if(link
->tosock
==sock
)
1849 /* send changed event to original tonode */
1851 NodeTagChanged(snode
->edittree
, link
->tonode
);
1853 node
= link
->fromnode
;
1854 sock
= link
->fromsock
;
1855 nodeRemLink(snode
->edittree
, link
);
1856 return node_add_link_drag(snode
, node
, sock
, SOCK_OUT
);
1864 void node_delete(SpaceNode
*snode
)
1869 for(node
= snode
->edittree
->nodes
.first
; node
; node
= next
) {
1871 if(node
->flag
& SELECT
) {
1872 /* set selin and selout NULL if the sockets belong to a node to be deleted */
1873 for(sock
= node
->inputs
.first
; sock
; sock
= sock
->next
)
1874 if(snode
->edittree
->selin
== sock
) snode
->edittree
->selin
= NULL
;
1876 for(sock
= node
->outputs
.first
; sock
; sock
= sock
->next
)
1877 if(snode
->edittree
->selout
== sock
) snode
->edittree
->selout
= NULL
;
1879 /* check id user here, nodeFreeNode is called for free dbase too */
1882 nodeFreeNode(snode
->edittree
, node
);
1886 snode_verify_groups(snode
);
1887 snode_handle_recalc(snode
);
1888 BIF_undo_push("Delete nodes");
1889 allqueue(REDRAWNODE
, 1);
1892 void node_hide(SpaceNode
*snode
)
1895 int nothidden
=0, ishidden
=0;
1897 for(node
= snode
->edittree
->nodes
.first
; node
; node
= node
->next
) {
1898 if(node
->flag
& SELECT
) {
1899 if(node
->flag
& NODE_HIDDEN
)
1905 for(node
= snode
->edittree
->nodes
.first
; node
; node
= node
->next
) {
1906 if(node
->flag
& SELECT
) {
1907 if( (ishidden
&& nothidden
) || ishidden
==0)
1908 node
->flag
|= NODE_HIDDEN
;
1910 node
->flag
&= ~NODE_HIDDEN
;
1913 BIF_undo_push("Hide nodes");
1914 allqueue(REDRAWNODE
, 1);
1917 void node_insert_key(SpaceNode
*snode
)
1919 bNode
*node
= editnode_get_active(snode
->edittree
);
1921 if(node
->type
==CMP_NODE_TIME
) {
1922 if(node
->custom1
<node
->custom2
) {
1924 CurveMapping
*cumap
= node
->storage
;
1927 curval
= (float)(CFRA
- node
->custom1
)/(float)(node
->custom2
-node
->custom1
);
1928 fval
= curvemapping_evaluateF(cumap
, 0, curval
);
1930 if(fbutton(&fval
, 0.0f
, 1.0f
, 10, 10, "Insert Value")) {
1931 curvemap_insert(cumap
->cm
, curval
, fval
);
1933 BIF_undo_push("Insert key in Time node");
1934 allqueue(REDRAWNODE
, 1);
1940 void node_select_linked(SpaceNode
*snode
, int out
)
1945 /* NODE_TEST is the free flag */
1946 for(node
= snode
->edittree
->nodes
.first
; node
; node
= node
->next
)
1947 node
->flag
&= ~NODE_TEST
;
1949 for(link
= snode
->edittree
->links
.first
; link
; link
= link
->next
) {
1951 if(link
->fromnode
->flag
& NODE_SELECT
)
1952 link
->tonode
->flag
|= NODE_TEST
;
1955 if(link
->tonode
->flag
& NODE_SELECT
)
1956 link
->fromnode
->flag
|= NODE_TEST
;
1960 for(node
= snode
->edittree
->nodes
.first
; node
; node
= node
->next
)
1961 if(node
->flag
& NODE_TEST
)
1962 node
->flag
|= NODE_SELECT
;
1964 BIF_undo_push("Select Linked nodes");
1965 allqueue(REDRAWNODE
, 1);
1968 /* makes a link between selected output and input sockets */
1969 void node_make_link(SpaceNode
*snode
)
1971 bNode
*fromnode
, *tonode
;
1973 bNodeSocket
*outsock
= snode
->edittree
->selout
;
1974 bNodeSocket
*insock
= snode
->edittree
->selin
;
1976 if(!insock
|| !outsock
) return;
1977 if(nodeFindLink(snode
->edittree
, outsock
, insock
)) return;
1979 if(nodeFindNode(snode
->edittree
, outsock
, &fromnode
, NULL
) &&
1980 nodeFindNode(snode
->edittree
, insock
, &tonode
, NULL
)) {
1981 link
= nodeAddLink(snode
->edittree
, fromnode
, outsock
, tonode
, insock
);
1982 NodeTagChanged(snode
->edittree
, tonode
);
1983 node_remove_extra_links(snode
, insock
, link
);
1987 ntreeSolveOrder(snode
->edittree
);
1988 snode_verify_groups(snode
);
1989 snode_handle_recalc(snode
);
1991 allqueue(REDRAWNODE
, 0);
1992 BIF_undo_push("Make Link Between Sockets");
1995 static void node_border_link_delete(SpaceNode
*snode
)
1998 short val
, mval
[2], mvalo
[2];
2000 /* to make this work more friendly, we first wait for a mouse move */
2001 getmouseco_areawin(mvalo
);
2002 while (get_mbut() & L_MOUSE
) {
2003 getmouseco_areawin(mval
);
2004 if(mval
[0]!=mvalo
[0] || mval
[1]!=mvalo
[1])
2006 else BIF_wait_for_statechange();
2008 if((get_mbut() & L_MOUSE
)==0)
2011 /* now change cursor and draw border */
2012 setcursor_space(SPACE_NODE
, CURSOR_VPAINT
);
2014 if ( (val
= get_border(&rect
, 2)) ) {
2015 if(rect
.xmin
<rect
.xmax
&& rect
.ymin
<rect
.ymax
) {
2016 //#define NODE_MAXPICKBUF 256
2017 bNodeLink
*link
, *next
;
2024 areamouseco_to_ipoco(&snode
->v2d
, mval
, &rectf
.xmin
, &rectf
.ymin
);
2027 areamouseco_to_ipoco(&snode
->v2d
, mval
, &rectf
.xmax
, &rectf
.ymax
);
2029 myortho2(rectf
.xmin
, rectf
.xmax
, rectf
.ymin
, rectf
.ymax
);
2031 glSelectBuffer(256, buffer
);
2032 glRenderMode(GL_SELECT
);
2037 for(link
= snode
->edittree
->links
.first
; link
; link
= link
->next
) {
2039 node_draw_link(snode
, link
);
2042 hits
= glRenderMode(GL_RENDER
);
2046 for(a
=0; a
<hits
; a
++) {
2047 bNodeLink
*link
= BLI_findlink(&snode
->edittree
->links
, buffer
[ (4 * a
) + 3]);
2049 link
->fromnode
= NULL
; /* first tag for delete, otherwise indices are wrong */
2051 for(link
= snode
->edittree
->links
.first
; link
; link
= next
) {
2053 if(link
->fromnode
==NULL
) {
2054 NodeTagChanged(snode
->edittree
, link
->tonode
);
2055 nodeRemLink(snode
->edittree
, link
);
2058 ntreeSolveOrder(snode
->edittree
);
2059 snode_verify_groups(snode
);
2060 snode_handle_recalc(snode
);
2062 allqueue(REDRAWNODE
, 0);
2063 BIF_undo_push("Erase links");
2067 setcursor_space(SPACE_NODE
, CURSOR_STD
);
2070 /* goes over all scenes, reads render layerss */
2071 void node_read_renderlayers(SpaceNode
*snode
)
2076 /* first tag scenes unread */
2077 for(scene
= G
.main
->scene
.first
; scene
; scene
= scene
->id
.next
)
2078 scene
->id
.flag
|= LIB_DOIT
;
2080 for(node
= snode
->edittree
->nodes
.first
; node
; node
= node
->next
) {
2081 if(node
->type
==CMP_NODE_R_LAYERS
) {
2083 if(id
==NULL
) id
= (ID
*)G
.scene
;
2084 if(id
->flag
& LIB_DOIT
) {
2085 RE_ReadRenderResult(G
.scene
, (Scene
*)id
);
2086 ntreeCompositTagRender((Scene
*)id
);
2087 id
->flag
&= ~LIB_DOIT
;
2092 snode_handle_recalc(snode
);
2095 /* called from header_info, when deleting a scene
2096 * goes over all scenes other than the input, checks if they have
2097 * render layer nodes referencing the to-be-deleted scene, and
2098 * resets them to NULL. */
2099 void clear_scene_in_nodes(Scene
*sce
)
2104 sce1
= G
.main
->scene
.first
;
2107 if (sce1
->nodetree
) {
2108 for(node
= sce1
->nodetree
->nodes
.first
; node
; node
= node
->next
) {
2109 if(node
->type
==CMP_NODE_R_LAYERS
) {
2110 Scene
*nodesce
= (Scene
*)node
->id
;
2112 if (nodesce
==sce
) node
->id
= NULL
;
2117 sce1
= sce1
->id
.next
;
2122 /* gets active viewer user */
2123 struct ImageUser
*ntree_get_active_iuser(bNodeTree
*ntree
)
2128 for(node
= ntree
->nodes
.first
; node
; node
= node
->next
)
2129 if( ELEM(node
->type
, CMP_NODE_VIEWER
, CMP_NODE_SPLITVIEWER
))
2130 if(node
->flag
& NODE_DO_OUTPUT
)
2131 return node
->storage
;
2135 void imagepaint_composite_tags(bNodeTree
*ntree
, Image
*image
, ImageUser
*iuser
)
2142 /* search for renderresults */
2143 if(image
->type
==IMA_TYPE_R_RESULT
) {
2144 for(node
= ntree
->nodes
.first
; node
; node
= node
->next
) {
2145 if(node
->type
==CMP_NODE_R_LAYERS
&& node
->id
==NULL
) {
2146 /* imageuser comes from ImageWin, so indexes are offset 1 */
2147 if(node
->custom1
==iuser
->layer
-1)
2148 NodeTagChanged(ntree
, node
);
2153 for(node
= ntree
->nodes
.first
; node
; node
= node
->next
) {
2154 if(node
->id
== &image
->id
)
2155 NodeTagChanged(ntree
, node
);
2160 /* ********************** */
2162 void node_make_group(SpaceNode
*snode
)
2166 if(snode
->edittree
!=snode
->nodetree
) {
2167 error("Can not add a new Group in a Group");
2171 /* for time being... is too complex to handle */
2172 if(snode
->treetype
==NTREE_COMPOSIT
) {
2173 for(gnode
=snode
->nodetree
->nodes
.first
; gnode
; gnode
= gnode
->next
) {
2174 if(gnode
->flag
& SELECT
)
2175 if(gnode
->type
==CMP_NODE_R_LAYERS
)
2179 error("Can not add RenderLayer in a Group");
2184 gnode
= nodeMakeGroupFromSelected(snode
->nodetree
);
2186 error("Can not make Group");
2189 nodeSetActive(snode
->nodetree
, gnode
);
2190 ntreeSolveOrder(snode
->nodetree
);
2191 allqueue(REDRAWNODE
, 0);
2192 BIF_undo_push("Make Node Group");
2196 /* ******************** main event loop ****************** */
2198 /* special version to prevent overlapping buttons, has a bit of hack... */
2199 /* yes, check for example composit_node_event(), file window use... */
2200 static int node_uiDoBlocks(ScrArea
*sa
, short event
)
2202 SpaceNode
*snode
= sa
->spacedata
.first
;
2203 ListBase
*lb
= &sa
->uiblocks
;
2204 ListBase listb
= *lb
;
2208 int retval
= UI_NOTHING
;
2211 getmouseco_areawin(mval
);
2212 areamouseco_to_ipoco(G
.v2d
, mval
, &rect
.xmin
, &rect
.ymin
);
2214 /* this happens after filesel usage... */
2215 if(lb
->first
==NULL
) {
2221 rect
.xmax
= rect
.xmin
+ 4.0f
;
2222 rect
.ymax
= rect
.ymin
+ 4.0f
;
2224 for(node
= snode
->edittree
->nodes
.first
; node
; node
= node
->next
) {
2228 /* retreive unique block name, see also drawnode.c */
2229 sprintf(str
, "node buttons %p", node
);
2230 block
= uiGetBlock(str
, sa
);
2233 if(node
== visible_node(snode
, &rect
)) {
2235 /* when there's menus, the prev pointer becomes zero! */
2236 prev
= ((struct Link
*)block
)->prev
;
2237 next
= ((struct Link
*)block
)->next
;
2238 ((struct Link
*)block
)->prev
= NULL
;
2239 ((struct Link
*)block
)->next
= NULL
;
2241 lb
->first
= lb
->last
= block
;
2242 retval
= uiDoBlocks(lb
, event
);
2244 ((struct Link
*)block
)->prev
= prev
;
2245 ((struct Link
*)block
)->next
= next
;
2257 void winqreadnodespace(ScrArea
*sa
, void *spacedata
, BWinEvent
*evt
)
2259 SpaceNode
*snode
= spacedata
;
2261 bNodeSocket
*actsock
;
2262 unsigned short event
= evt
->event
;
2263 short val
= evt
->val
, doredraw
=0, fromlib
= 0;
2265 if(sa
->win
==0) return;
2266 if(snode
->nodetree
==NULL
) return;
2270 if( node_uiDoBlocks(sa
, event
)!=UI_NOTHING
) event
= 0;
2272 fromlib
= (snode
->id
&& snode
->id
->lib
);
2277 if(node_mouse_groupheader(snode
)==0)
2278 node_mouse_select(snode
, event
);
2282 if(G
.qual
& LR_CTRLKEY
) {
2285 if(node_add_link(snode
)==0)
2286 if(node_mouse_groupheader(snode
)==0)
2287 if(node_mouse_select(snode
, event
)==0)
2288 node_border_link_delete(snode
);
2294 if(find_indicated_socket(snode
, &actnode
, &actsock
, SOCK_IN
)) {
2295 if(actsock
->flag
& SOCK_SEL
) {
2296 snode
->edittree
->selin
= NULL
;
2297 actsock
->flag
&= ~SOCK_SEL
;
2300 snode
->edittree
->selin
= actsock
;
2301 reset_sel_socket(snode
, SOCK_IN
);
2302 actsock
->flag
|= SOCK_SEL
;
2305 else if(find_indicated_socket(snode
, &actnode
, &actsock
, SOCK_OUT
)) {
2306 if(actsock
->flag
& SOCK_SEL
) {
2307 snode
->edittree
->selout
= NULL
;
2308 actsock
->flag
&= ~SOCK_SEL
;
2311 snode
->edittree
->selout
= actsock
;
2312 reset_sel_socket(snode
, SOCK_OUT
);
2313 actsock
->flag
|= SOCK_SEL
;
2316 else if(!node_mouse_select(snode
, event
))
2321 if (G
.qual
==LR_SHIFTKEY
) {
2322 snode_bg_viewmove(snode
);
2327 case WHEELDOWNMOUSE
:
2328 view2dmove(event
); /* in drawipo.c */
2332 doredraw
= node_socket_hilights(snode
, SOCK_IN
|SOCK_OUT
);
2336 /* future: handlerize this! */
2337 if(snode
->treetype
==NTREE_SHADER
)
2338 shader_node_event(snode
, val
);
2339 else if(snode
->treetype
==NTREE_COMPOSIT
)
2340 composit_node_event(snode
, val
);
2344 if(snode
->treetype
==NTREE_SHADER
)
2345 shader_node_previewrender(sa
, snode
);
2357 snode_home(sa
, snode
);
2361 if(fromlib
) fromlib
= -1;
2362 else snode_make_group_editable(snode
, NULL
);
2366 if(G
.qual
==LR_SHIFTKEY
) {
2367 if(fromlib
) fromlib
= -1;
2368 else toolbox_n_add();
2370 else if(G
.qual
==0) {
2371 node_deselectall(snode
, 1);
2372 BIF_undo_push("Deselect all nodes");
2374 else if(G
.qual
& LR_CTRLKEY
) {
2375 node_select_same_type(snode
);
2376 BIF_undo_push("Select same nodes");
2381 node_border_select(snode
);
2383 case CKEY
: /* sort again, showing cyclics */
2384 ntreeSolveOrder(snode
->edittree
);
2388 if(G
.qual
==LR_SHIFTKEY
) {
2389 if(fromlib
) fromlib
= -1;
2390 else node_adduplicate(snode
);
2394 snode_handle_recalc(snode
);
2397 node_make_link(snode
);
2400 if(fromlib
) fromlib
= -1;
2402 if(G
.qual
==LR_CTRLKEY
) {
2403 if(okee("Make Group"))
2404 node_make_group(snode
);
2406 else if(G
.qual
==LR_ALTKEY
) {
2408 node_ungroup(snode
);
2410 else if(G
.qual
==LR_SHIFTKEY
) {
2411 node_addgroup(snode
);
2414 transform_nodes(snode
->edittree
, 'g', "Move Node");
2421 node_insert_key(snode
);
2424 node_select_linked(snode
, G
.qual
==LR_SHIFTKEY
);
2430 if(G
.qual
==LR_CTRLKEY
)
2431 node_rename_cb(snode
);
2432 else if(okee("Read saved Render Layers"))
2433 node_read_renderlayers(snode
);
2437 if(fromlib
) fromlib
= -1;
2438 else node_delete(snode
);
2446 scrarea_queue_winredraw(sa
);
2448 scrarea_queue_headredraw(sa
);