|
Blender
V2.59
|
00001 /* 00002 * $Id: node_edit.c 38813 2011-07-29 07:14:03Z lukastoenne $ 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 * 00020 * The Original Code is Copyright (C) 2005 Blender Foundation. 00021 * All rights reserved. 00022 * 00023 * The Original Code is: all of this file. 00024 * 00025 * Contributor(s): David Millan Escriva, Juho Vepsäläinen, Nathan Letwory 00026 * 00027 * ***** END GPL LICENSE BLOCK ***** 00028 */ 00029 00035 #include <stdio.h> 00036 #include <stdlib.h> 00037 #include <math.h> 00038 #include <string.h> 00039 #include <errno.h> 00040 00041 #include "MEM_guardedalloc.h" 00042 00043 #include "DNA_object_types.h" 00044 #include "DNA_material_types.h" 00045 #include "DNA_node_types.h" 00046 #include "DNA_scene_types.h" 00047 00048 #include "BLI_math.h" 00049 #include "BLI_blenlib.h" 00050 #include "BLI_storage_types.h" 00051 #include "BLI_utildefines.h" 00052 00053 #include "BKE_context.h" 00054 #include "BKE_depsgraph.h" 00055 #include "BKE_global.h" 00056 #include "BKE_image.h" 00057 #include "BKE_library.h" 00058 #include "BKE_main.h" 00059 #include "BKE_node.h" 00060 #include "BKE_material.h" 00061 #include "BKE_paint.h" 00062 #include "BKE_screen.h" 00063 #include "BKE_texture.h" 00064 #include "BKE_report.h" 00065 00066 #include "RE_pipeline.h" 00067 00068 #include "IMB_imbuf_types.h" 00069 00070 #include "ED_node.h" 00071 #include "ED_screen.h" 00072 #include "ED_space_api.h" 00073 #include "ED_render.h" 00074 00075 #include "RNA_access.h" 00076 #include "RNA_define.h" 00077 00078 #include "WM_api.h" 00079 #include "WM_types.h" 00080 00081 #include "UI_interface.h" 00082 #include "UI_view2d.h" 00083 00084 #include "IMB_imbuf.h" 00085 00086 #include "RNA_enum_types.h" 00087 00088 #include "node_intern.h" 00089 00090 static EnumPropertyItem socket_in_out_items[] = { 00091 { SOCK_IN, "IN", 0, "In", "" }, 00092 { SOCK_OUT, "OUT", 0, "Out", "" }, 00093 { 0, NULL, 0, NULL, NULL} 00094 }; 00095 00096 /* ***************** composite job manager ********************** */ 00097 00098 typedef struct CompoJob { 00099 Scene *scene; 00100 bNodeTree *ntree; 00101 bNodeTree *localtree; 00102 short *stop; 00103 short *do_update; 00104 float *progress; 00105 } CompoJob; 00106 00107 /* called by compo, only to check job 'stop' value */ 00108 static int compo_breakjob(void *cjv) 00109 { 00110 CompoJob *cj= cjv; 00111 00112 return *(cj->stop); 00113 } 00114 00115 /* called by compo, wmJob sends notifier */ 00116 static void compo_redrawjob(void *cjv, char *UNUSED(str)) 00117 { 00118 CompoJob *cj= cjv; 00119 00120 *(cj->do_update)= 1; 00121 } 00122 00123 static void compo_freejob(void *cjv) 00124 { 00125 CompoJob *cj= cjv; 00126 00127 if(cj->localtree) { 00128 ntreeLocalMerge(cj->localtree, cj->ntree); 00129 } 00130 MEM_freeN(cj); 00131 } 00132 00133 /* only now we copy the nodetree, so adding many jobs while 00134 sliding buttons doesn't frustrate */ 00135 static void compo_initjob(void *cjv) 00136 { 00137 CompoJob *cj= cjv; 00138 00139 cj->localtree= ntreeLocalize(cj->ntree); 00140 } 00141 00142 /* called before redraw notifiers, it moves finished previews over */ 00143 static void compo_updatejob(void *cjv) 00144 { 00145 CompoJob *cj= cjv; 00146 00147 ntreeLocalSync(cj->localtree, cj->ntree); 00148 } 00149 00150 static void compo_progressjob(void *cjv, float progress) 00151 { 00152 CompoJob *cj= cjv; 00153 00154 *(cj->progress) = progress; 00155 } 00156 00157 00158 /* only this runs inside thread */ 00159 static void compo_startjob(void *cjv, short *stop, short *do_update, float *progress) 00160 { 00161 CompoJob *cj= cjv; 00162 bNodeTree *ntree= cj->localtree; 00163 00164 if(cj->scene->use_nodes==0) 00165 return; 00166 00167 cj->stop= stop; 00168 cj->do_update= do_update; 00169 cj->progress= progress; 00170 00171 ntree->test_break= compo_breakjob; 00172 ntree->tbh= cj; 00173 ntree->stats_draw= compo_redrawjob; 00174 ntree->sdh= cj; 00175 ntree->progress= compo_progressjob; 00176 ntree->prh= cj; 00177 00178 // XXX BIF_store_spare(); 00179 00180 ntreeCompositExecTree(ntree, &cj->scene->r, 1); /* 1 is do_previews */ 00181 00182 ntree->test_break= NULL; 00183 ntree->stats_draw= NULL; 00184 ntree->progress= NULL; 00185 00186 } 00187 00188 void snode_composite_job(const bContext *C, ScrArea *sa) 00189 { 00190 SpaceNode *snode= sa->spacedata.first; 00191 wmJob *steve; 00192 CompoJob *cj; 00193 00194 steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Compositing", WM_JOB_EXCL_RENDER|WM_JOB_PROGRESS); 00195 cj= MEM_callocN(sizeof(CompoJob), "compo job"); 00196 00197 /* customdata for preview thread */ 00198 cj->scene= CTX_data_scene(C); 00199 cj->ntree= snode->nodetree; 00200 00201 /* setup job */ 00202 WM_jobs_customdata(steve, cj, compo_freejob); 00203 WM_jobs_timer(steve, 0.1, NC_SCENE, NC_SCENE|ND_COMPO_RESULT); 00204 WM_jobs_callbacks(steve, compo_startjob, compo_initjob, compo_updatejob, NULL); 00205 00206 WM_jobs_start(CTX_wm_manager(C), steve); 00207 00208 } 00209 00210 /* ***************************************** */ 00211 00212 /* operator poll callback */ 00213 static int composite_node_active(bContext *C) 00214 { 00215 if( ED_operator_node_active(C)) { 00216 SpaceNode *snode= CTX_wm_space_node(C); 00217 if(snode->treetype==NTREE_COMPOSIT) 00218 return 1; 00219 } 00220 return 0; 00221 } 00222 00223 /* also checks for edited groups */ 00224 static bNode *editnode_get_active(bNodeTree *ntree) 00225 { 00226 bNode *node; 00227 00228 /* check for edited group */ 00229 for(node= ntree->nodes.first; node; node= node->next) 00230 if(node->flag & NODE_GROUP_EDIT) 00231 break; 00232 if(node) 00233 return nodeGetActive((bNodeTree *)node->id); 00234 else 00235 return nodeGetActive(ntree); 00236 } 00237 00238 void snode_dag_update(bContext *UNUSED(C), SpaceNode *snode) 00239 { 00240 DAG_id_tag_update(snode->id, 0); 00241 } 00242 00243 void snode_notify(bContext *C, SpaceNode *snode) 00244 { 00245 WM_event_add_notifier(C, NC_NODE|NA_EDITED, NULL); 00246 00247 if(snode->treetype==NTREE_SHADER) 00248 WM_event_add_notifier(C, NC_MATERIAL|ND_NODES, snode->id); 00249 else if(snode->treetype==NTREE_COMPOSIT) 00250 WM_event_add_notifier(C, NC_SCENE|ND_NODES, snode->id); 00251 else if(snode->treetype==NTREE_TEXTURE) 00252 WM_event_add_notifier(C, NC_TEXTURE|ND_NODES, snode->id); 00253 } 00254 00255 bNode *node_tree_get_editgroup(bNodeTree *nodetree) 00256 { 00257 bNode *gnode; 00258 00259 /* get the groupnode */ 00260 for(gnode= nodetree->nodes.first; gnode; gnode= gnode->next) 00261 if(gnode->flag & NODE_GROUP_EDIT) 00262 break; 00263 return gnode; 00264 } 00265 00266 /* assumes nothing being done in ntree yet, sets the default in/out node */ 00267 /* called from shading buttons or header */ 00268 void ED_node_shader_default(Material *ma) 00269 { 00270 bNode *in, *out; 00271 bNodeSocket *fromsock, *tosock; 00272 00273 /* but lets check it anyway */ 00274 if(ma->nodetree) { 00275 if (G.f & G_DEBUG) 00276 printf("error in shader initialize\n"); 00277 return; 00278 } 00279 00280 ma->nodetree= ntreeAddTree("Shader Nodetree", NTREE_SHADER, FALSE); 00281 00282 out= nodeAddNodeType(ma->nodetree, SH_NODE_OUTPUT, NULL, NULL); 00283 out->locx= 300.0f; out->locy= 300.0f; 00284 00285 in= nodeAddNodeType(ma->nodetree, SH_NODE_MATERIAL, NULL, NULL); 00286 in->locx= 10.0f; in->locy= 300.0f; 00287 nodeSetActive(ma->nodetree, in); 00288 00289 /* only a link from color to color */ 00290 fromsock= in->outputs.first; 00291 tosock= out->inputs.first; 00292 nodeAddLink(ma->nodetree, in, fromsock, out, tosock); 00293 00294 ntreeSolveOrder(ma->nodetree); /* needed for pointers */ 00295 } 00296 00297 /* assumes nothing being done in ntree yet, sets the default in/out node */ 00298 /* called from shading buttons or header */ 00299 void ED_node_composit_default(Scene *sce) 00300 { 00301 bNode *in, *out; 00302 bNodeSocket *fromsock, *tosock; 00303 00304 /* but lets check it anyway */ 00305 if(sce->nodetree) { 00306 if (G.f & G_DEBUG) 00307 printf("error in composite initialize\n"); 00308 return; 00309 } 00310 00311 sce->nodetree= ntreeAddTree("Compositing Nodetree", NTREE_COMPOSIT, FALSE); 00312 00313 out= nodeAddNodeType(sce->nodetree, CMP_NODE_COMPOSITE, NULL, NULL); 00314 out->locx= 300.0f; out->locy= 400.0f; 00315 out->id= &sce->id; 00316 id_us_plus(out->id); 00317 00318 in= nodeAddNodeType(sce->nodetree, CMP_NODE_R_LAYERS, NULL, NULL); 00319 in->locx= 10.0f; in->locy= 400.0f; 00320 in->id= &sce->id; 00321 id_us_plus(in->id); 00322 nodeSetActive(sce->nodetree, in); 00323 00324 /* links from color to color */ 00325 fromsock= in->outputs.first; 00326 tosock= out->inputs.first; 00327 nodeAddLink(sce->nodetree, in, fromsock, out, tosock); 00328 00329 ntreeSolveOrder(sce->nodetree); /* needed for pointers */ 00330 00331 // XXX ntreeCompositForceHidden(sce->nodetree); 00332 } 00333 00334 /* assumes nothing being done in ntree yet, sets the default in/out node */ 00335 /* called from shading buttons or header */ 00336 void ED_node_texture_default(Tex *tx) 00337 { 00338 bNode *in, *out; 00339 bNodeSocket *fromsock, *tosock; 00340 00341 /* but lets check it anyway */ 00342 if(tx->nodetree) { 00343 if (G.f & G_DEBUG) 00344 printf("error in texture initialize\n"); 00345 return; 00346 } 00347 00348 tx->nodetree= ntreeAddTree("Texture Nodetree", NTREE_TEXTURE, FALSE); 00349 00350 out= nodeAddNodeType(tx->nodetree, TEX_NODE_OUTPUT, NULL, NULL); 00351 out->locx= 300.0f; out->locy= 300.0f; 00352 00353 in= nodeAddNodeType(tx->nodetree, TEX_NODE_CHECKER, NULL, NULL); 00354 in->locx= 10.0f; in->locy= 300.0f; 00355 nodeSetActive(tx->nodetree, in); 00356 00357 fromsock= in->outputs.first; 00358 tosock= out->inputs.first; 00359 nodeAddLink(tx->nodetree, in, fromsock, out, tosock); 00360 00361 ntreeSolveOrder(tx->nodetree); /* needed for pointers */ 00362 } 00363 00364 /* id is supposed to contain a node tree */ 00365 void node_tree_from_ID(ID *id, bNodeTree **ntree, bNodeTree **edittree, int *treetype) 00366 { 00367 bNode *node= NULL; 00368 short idtype= GS(id->name); 00369 00370 if(idtype == ID_MA) { 00371 *ntree= ((Material*)id)->nodetree; 00372 if(treetype) *treetype= NTREE_SHADER; 00373 } 00374 else if(idtype == ID_SCE) { 00375 *ntree= ((Scene*)id)->nodetree; 00376 if(treetype) *treetype= NTREE_COMPOSIT; 00377 } 00378 else if(idtype == ID_TE) { 00379 *ntree= ((Tex*)id)->nodetree; 00380 if(treetype) *treetype= NTREE_TEXTURE; 00381 } 00382 else { 00383 if(treetype) *treetype= 0; 00384 return; 00385 } 00386 00387 /* find editable group */ 00388 if(edittree) { 00389 if(*ntree) 00390 for(node= (*ntree)->nodes.first; node; node= node->next) 00391 if(node->flag & NODE_GROUP_EDIT) 00392 break; 00393 00394 if(node && node->id) 00395 *edittree= (bNodeTree *)node->id; 00396 else 00397 *edittree= *ntree; 00398 } 00399 } 00400 00401 /* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */ 00402 void snode_set_context(SpaceNode *snode, Scene *scene) 00403 { 00404 Object *ob= OBACT; 00405 00406 snode->nodetree= NULL; 00407 snode->edittree= NULL; 00408 snode->id= snode->from= NULL; 00409 00410 if(snode->treetype==NTREE_SHADER) { 00411 /* need active object, or we allow pinning... */ 00412 if(ob) { 00413 Material *ma= give_current_material(ob, ob->actcol); 00414 if(ma) { 00415 snode->from= &ob->id; 00416 snode->id= &ma->id; 00417 } 00418 } 00419 } 00420 else if(snode->treetype==NTREE_COMPOSIT) { 00421 snode->from= NULL; 00422 snode->id= &scene->id; 00423 00424 /* bit clumsy but reliable way to see if we draw first time */ 00425 if(snode->nodetree==NULL) 00426 ntreeCompositForceHidden(scene->nodetree, scene); 00427 } 00428 else if(snode->treetype==NTREE_TEXTURE) { 00429 Tex *tx= NULL; 00430 00431 if(snode->texfrom==SNODE_TEX_OBJECT) { 00432 if(ob) { 00433 tx= give_current_object_texture(ob); 00434 00435 if(ob->type == OB_LAMP) 00436 snode->from= (ID*)ob->data; 00437 else 00438 snode->from= (ID*)give_current_material(ob, ob->actcol); 00439 00440 /* from is not set fully for material nodes, should be ID + Node then */ 00441 snode->id= &tx->id; 00442 } 00443 } 00444 else if(snode->texfrom==SNODE_TEX_WORLD) { 00445 tx= give_current_world_texture(scene->world); 00446 snode->from= (ID *)scene->world; 00447 snode->id= &tx->id; 00448 } 00449 else { 00450 struct Brush *brush= NULL; 00451 00452 if(ob && (ob->mode & OB_MODE_SCULPT)) 00453 brush= paint_brush(&scene->toolsettings->sculpt->paint); 00454 else 00455 brush= paint_brush(&scene->toolsettings->imapaint.paint); 00456 00457 if (brush) { 00458 snode->from= (ID *)brush; 00459 tx= give_current_brush_texture(brush); 00460 snode->id= &tx->id; 00461 } 00462 } 00463 } 00464 00465 if(snode->id) 00466 node_tree_from_ID(snode->id, &snode->nodetree, &snode->edittree, NULL); 00467 } 00468 00469 static void snode_tag_changed(SpaceNode *snode, bNode *node) 00470 { 00471 bNode *gnode; 00472 00473 if (node) 00474 NodeTagChanged(snode->edittree, node); 00475 00476 /* if inside group, tag entire group */ 00477 gnode= node_tree_get_editgroup(snode->nodetree); 00478 if(gnode) 00479 NodeTagIDChanged(snode->nodetree, gnode->id); 00480 } 00481 00482 void node_set_active(SpaceNode *snode, bNode *node) 00483 { 00484 nodeSetActive(snode->edittree, node); 00485 00486 if(node->type!=NODE_GROUP) { 00487 int was_output= (node->flag & NODE_DO_OUTPUT); 00488 00489 /* tree specific activate calls */ 00490 if(snode->treetype==NTREE_SHADER) { 00491 /* when we select a material, active texture is cleared, for buttons */ 00492 if(node->id && GS(node->id->name)==ID_MA) 00493 nodeClearActiveID(snode->edittree, ID_TE); 00494 00495 if(node->type==SH_NODE_OUTPUT) { 00496 bNode *tnode; 00497 00498 for(tnode= snode->edittree->nodes.first; tnode; tnode= tnode->next) 00499 if( tnode->type==SH_NODE_OUTPUT) 00500 tnode->flag &= ~NODE_DO_OUTPUT; 00501 00502 node->flag |= NODE_DO_OUTPUT; 00503 if(was_output==0) 00504 ED_node_changed_update(snode->id, node); 00505 } 00506 00507 WM_main_add_notifier(NC_MATERIAL|ND_NODES, node->id); 00508 } 00509 else if(snode->treetype==NTREE_COMPOSIT) { 00510 Scene *scene= (Scene*)snode->id; 00511 00512 /* make active viewer, currently only 1 supported... */ 00513 if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { 00514 bNode *tnode; 00515 00516 00517 for(tnode= snode->edittree->nodes.first; tnode; tnode= tnode->next) 00518 if( ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) 00519 tnode->flag &= ~NODE_DO_OUTPUT; 00520 00521 node->flag |= NODE_DO_OUTPUT; 00522 if(was_output==0) { 00523 snode_tag_changed(snode, node); 00524 00525 ED_node_changed_update(snode->id, node); 00526 } 00527 00528 /* addnode() doesnt link this yet... */ 00529 node->id= (ID *)BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node"); 00530 } 00531 else if(node->type==CMP_NODE_R_LAYERS) { 00532 if(node->id==NULL || node->id==(ID *)scene) { 00533 scene->r.actlay= node->custom1; 00534 } 00535 } 00536 else if(node->type==CMP_NODE_COMPOSITE) { 00537 bNode *tnode; 00538 00539 for(tnode= snode->edittree->nodes.first; tnode; tnode= tnode->next) 00540 if( tnode->type==CMP_NODE_COMPOSITE) 00541 tnode->flag &= ~NODE_DO_OUTPUT; 00542 00543 node->flag |= NODE_DO_OUTPUT; 00544 ED_node_changed_update(snode->id, node); 00545 } 00546 } 00547 else if(snode->treetype==NTREE_TEXTURE) { 00548 // XXX 00549 #if 0 00550 if(node->id) 00551 ; // XXX BIF_preview_changed(-1); 00552 // allqueue(REDRAWBUTSSHADING, 1); 00553 // allqueue(REDRAWIPO, 0); 00554 #endif 00555 } 00556 } 00557 } 00558 00559 /* when links in groups change, inputs/outputs change, nodes added/deleted... */ 00560 void node_tree_verify_groups(bNodeTree *nodetree) 00561 { 00562 bNode *gnode; 00563 00564 gnode= node_tree_get_editgroup(nodetree); 00565 00566 /* does all materials */ 00567 if(gnode) 00568 nodeGroupVerify((bNodeTree *)gnode->id); 00569 00570 } 00571 00572 /* ***************** Edit Group operator ************* */ 00573 00574 void snode_make_group_editable(SpaceNode *snode, bNode *gnode) 00575 { 00576 bNode *node; 00577 00578 /* make sure nothing has group editing on */ 00579 for(node= snode->nodetree->nodes.first; node; node= node->next) 00580 node->flag &= ~NODE_GROUP_EDIT; 00581 00582 if(gnode==NULL) { 00583 /* with NULL argument we do a toggle */ 00584 if(snode->edittree==snode->nodetree) 00585 gnode= nodeGetActive(snode->nodetree); 00586 } 00587 00588 if(gnode && gnode->type==NODE_GROUP && gnode->id) { 00589 if(gnode->id->lib) 00590 ntreeMakeLocal((bNodeTree *)gnode->id); 00591 00592 gnode->flag |= NODE_GROUP_EDIT; 00593 snode->edittree= (bNodeTree *)gnode->id; 00594 00595 /* deselect all other nodes, so we can also do grabbing of entire subtree */ 00596 for(node= snode->nodetree->nodes.first; node; node= node->next) 00597 node->flag &= ~SELECT; 00598 gnode->flag |= SELECT; 00599 00600 } 00601 else 00602 snode->edittree= snode->nodetree; 00603 00604 ntreeSolveOrder(snode->nodetree); 00605 } 00606 00607 static int node_group_edit_exec(bContext *C, wmOperator *UNUSED(op)) 00608 { 00609 SpaceNode *snode = CTX_wm_space_node(C); 00610 bNode *gnode; 00611 00612 ED_preview_kill_jobs(C); 00613 00614 gnode= nodeGetActive(snode->edittree); 00615 snode_make_group_editable(snode, gnode); 00616 00617 WM_event_add_notifier(C, NC_SCENE|ND_NODES, NULL); 00618 00619 return OPERATOR_FINISHED; 00620 } 00621 00622 static int node_group_edit_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 00623 { 00624 SpaceNode *snode = CTX_wm_space_node(C); 00625 bNode *gnode; 00626 00627 gnode= nodeGetActive(snode->edittree); 00628 if(gnode && gnode->type==NODE_GROUP && gnode->id && gnode->id->lib) { 00629 uiPupMenuOkee(C, op->type->idname, "Make group local?"); 00630 return OPERATOR_CANCELLED; 00631 } 00632 00633 return node_group_edit_exec(C, op); 00634 } 00635 00636 void NODE_OT_group_edit(wmOperatorType *ot) 00637 { 00638 /* identifiers */ 00639 ot->name = "Edit Group"; 00640 ot->description = "Edit node group"; 00641 ot->idname = "NODE_OT_group_edit"; 00642 00643 /* api callbacks */ 00644 ot->invoke = node_group_edit_invoke; 00645 ot->exec = node_group_edit_exec; 00646 ot->poll = ED_operator_node_active; 00647 00648 /* flags */ 00649 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; 00650 } 00651 00652 /* ***************** Add Group Socket operator ************* */ 00653 00654 static int node_group_socket_add_exec(bContext *C, wmOperator *op) 00655 { 00656 SpaceNode *snode = CTX_wm_space_node(C); 00657 int in_out= -1; 00658 char name[32]= ""; 00659 int type= SOCK_VALUE; 00660 bNodeTree *ngroup= snode->edittree; 00661 bNodeSocket *sock; 00662 00663 ED_preview_kill_jobs(C); 00664 00665 if (RNA_property_is_set(op->ptr, "name")) 00666 RNA_string_get(op->ptr, "name", name); 00667 00668 if (RNA_property_is_set(op->ptr, "type")) 00669 type = RNA_enum_get(op->ptr, "type"); 00670 00671 if (RNA_property_is_set(op->ptr, "in_out")) 00672 in_out = RNA_enum_get(op->ptr, "in_out"); 00673 else 00674 return OPERATOR_CANCELLED; 00675 00676 sock = nodeGroupAddSocket(ngroup, name, type, in_out); 00677 00678 node_tree_verify_groups(snode->nodetree); 00679 00680 snode_notify(C, snode); 00681 00682 return OPERATOR_FINISHED; 00683 } 00684 00685 void NODE_OT_group_socket_add(wmOperatorType *ot) 00686 { 00687 /* identifiers */ 00688 ot->name = "Add Group Socket"; 00689 ot->description = "Add node group socket"; 00690 ot->idname = "NODE_OT_group_socket_add"; 00691 00692 /* api callbacks */ 00693 ot->exec = node_group_socket_add_exec; 00694 ot->poll = ED_operator_node_active; 00695 00696 /* flags */ 00697 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; 00698 00699 RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output"); 00700 RNA_def_string(ot->srna, "name", "", 32, "Name", "Group socket name"); 00701 RNA_def_enum(ot->srna, "type", node_socket_type_items, SOCK_VALUE, "Type", "Type of the group socket"); 00702 } 00703 00704 /* ***************** Remove Group Socket operator ************* */ 00705 00706 static int node_group_socket_remove_exec(bContext *C, wmOperator *op) 00707 { 00708 SpaceNode *snode = CTX_wm_space_node(C); 00709 int index= -1; 00710 int in_out= -1; 00711 bNodeTree *ngroup= snode->edittree; 00712 bNodeSocket *sock; 00713 00714 ED_preview_kill_jobs(C); 00715 00716 if (RNA_property_is_set(op->ptr, "index")) 00717 index = RNA_int_get(op->ptr, "index"); 00718 else 00719 return OPERATOR_CANCELLED; 00720 00721 if (RNA_property_is_set(op->ptr, "in_out")) 00722 in_out = RNA_enum_get(op->ptr, "in_out"); 00723 else 00724 return OPERATOR_CANCELLED; 00725 00726 sock = (bNodeSocket*)BLI_findlink(in_out==SOCK_IN ? &ngroup->inputs : &ngroup->outputs, index); 00727 if (sock) { 00728 nodeGroupRemoveSocket(ngroup, sock, in_out); 00729 node_tree_verify_groups(snode->nodetree); 00730 00731 snode_notify(C, snode); 00732 } 00733 00734 return OPERATOR_FINISHED; 00735 } 00736 00737 void NODE_OT_group_socket_remove(wmOperatorType *ot) 00738 { 00739 /* identifiers */ 00740 ot->name = "Remove Group Socket"; 00741 ot->description = "Removed node group socket"; 00742 ot->idname = "NODE_OT_group_socket_remove"; 00743 00744 /* api callbacks */ 00745 ot->exec = node_group_socket_remove_exec; 00746 ot->poll = ED_operator_node_active; 00747 00748 /* flags */ 00749 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; 00750 00751 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, INT_MAX); 00752 RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output"); 00753 } 00754 00755 /* ***************** Move Group Socket Up operator ************* */ 00756 00757 static int node_group_socket_move_up_exec(bContext *C, wmOperator *op) 00758 { 00759 SpaceNode *snode = CTX_wm_space_node(C); 00760 int index= -1; 00761 int in_out= -1; 00762 bNodeTree *ngroup= snode->edittree; 00763 bNodeSocket *sock, *prev; 00764 00765 ED_preview_kill_jobs(C); 00766 00767 if (RNA_property_is_set(op->ptr, "index")) 00768 index = RNA_int_get(op->ptr, "index"); 00769 else 00770 return OPERATOR_CANCELLED; 00771 00772 if (RNA_property_is_set(op->ptr, "in_out")) 00773 in_out = RNA_enum_get(op->ptr, "in_out"); 00774 else 00775 return OPERATOR_CANCELLED; 00776 00777 /* swap */ 00778 if (in_out==SOCK_IN) { 00779 sock = (bNodeSocket*)BLI_findlink(&ngroup->inputs, index); 00780 prev = sock->prev; 00781 /* can't move up the first socket */ 00782 if (!prev) 00783 return OPERATOR_CANCELLED; 00784 BLI_remlink(&ngroup->inputs, sock); 00785 BLI_insertlinkbefore(&ngroup->inputs, prev, sock); 00786 } 00787 else if (in_out==SOCK_OUT) { 00788 sock = (bNodeSocket*)BLI_findlink(&ngroup->outputs, index); 00789 prev = sock->prev; 00790 /* can't move up the first socket */ 00791 if (!prev) 00792 return OPERATOR_CANCELLED; 00793 BLI_remlink(&ngroup->outputs, sock); 00794 BLI_insertlinkbefore(&ngroup->outputs, prev, sock); 00795 } 00796 node_tree_verify_groups(snode->nodetree); 00797 00798 snode_notify(C, snode); 00799 00800 return OPERATOR_FINISHED; 00801 } 00802 00803 void NODE_OT_group_socket_move_up(wmOperatorType *ot) 00804 { 00805 /* identifiers */ 00806 ot->name = "Move Group Socket Up"; 00807 ot->description = "Move up node group socket"; 00808 ot->idname = "NODE_OT_group_socket_move_up"; 00809 00810 /* api callbacks */ 00811 ot->exec = node_group_socket_move_up_exec; 00812 ot->poll = ED_operator_node_active; 00813 00814 /* flags */ 00815 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; 00816 00817 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, INT_MAX); 00818 RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output"); 00819 } 00820 00821 /* ***************** Move Group Socket Up operator ************* */ 00822 00823 static int node_group_socket_move_down_exec(bContext *C, wmOperator *op) 00824 { 00825 SpaceNode *snode = CTX_wm_space_node(C); 00826 int index= -1; 00827 int in_out= -1; 00828 bNodeTree *ngroup= snode->edittree; 00829 bNodeSocket *sock, *next; 00830 00831 ED_preview_kill_jobs(C); 00832 00833 if (RNA_property_is_set(op->ptr, "index")) 00834 index = RNA_int_get(op->ptr, "index"); 00835 else 00836 return OPERATOR_CANCELLED; 00837 00838 if (RNA_property_is_set(op->ptr, "in_out")) 00839 in_out = RNA_enum_get(op->ptr, "in_out"); 00840 else 00841 return OPERATOR_CANCELLED; 00842 00843 /* swap */ 00844 if (in_out==SOCK_IN) { 00845 sock = (bNodeSocket*)BLI_findlink(&ngroup->inputs, index); 00846 next = sock->next; 00847 /* can't move down the last socket */ 00848 if (!next) 00849 return OPERATOR_CANCELLED; 00850 BLI_remlink(&ngroup->inputs, sock); 00851 BLI_insertlinkafter(&ngroup->inputs, next, sock); 00852 } 00853 else if (in_out==SOCK_OUT) { 00854 sock = (bNodeSocket*)BLI_findlink(&ngroup->outputs, index); 00855 next = sock->next; 00856 /* can't move down the last socket */ 00857 if (!next) 00858 return OPERATOR_CANCELLED; 00859 BLI_remlink(&ngroup->outputs, sock); 00860 BLI_insertlinkafter(&ngroup->outputs, next, sock); 00861 } 00862 node_tree_verify_groups(snode->nodetree); 00863 00864 snode_notify(C, snode); 00865 00866 return OPERATOR_FINISHED; 00867 } 00868 00869 void NODE_OT_group_socket_move_down(wmOperatorType *ot) 00870 { 00871 /* identifiers */ 00872 ot->name = "Move Group Socket Down"; 00873 ot->description = "Move down node group socket"; 00874 ot->idname = "NODE_OT_group_socket_move_down"; 00875 00876 /* api callbacks */ 00877 ot->exec = node_group_socket_move_down_exec; 00878 ot->poll = ED_operator_node_active; 00879 00880 /* flags */ 00881 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; 00882 00883 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, INT_MAX); 00884 RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output"); 00885 } 00886 00887 /* ******************** Ungroup operator ********************** */ 00888 00889 static int node_group_ungroup_exec(bContext *C, wmOperator *op) 00890 { 00891 SpaceNode *snode = CTX_wm_space_node(C); 00892 bNode *gnode; 00893 00894 ED_preview_kill_jobs(C); 00895 00896 /* are we inside of a group? */ 00897 gnode= node_tree_get_editgroup(snode->nodetree); 00898 if(gnode) 00899 snode_make_group_editable(snode, NULL); 00900 00901 gnode= nodeGetActive(snode->edittree); 00902 if(gnode==NULL) 00903 return OPERATOR_CANCELLED; 00904 00905 if(gnode->type!=NODE_GROUP) { 00906 BKE_report(op->reports, RPT_WARNING, "Not a group"); 00907 return OPERATOR_CANCELLED; 00908 } 00909 else if(!nodeGroupUnGroup(snode->edittree, gnode)) { 00910 BKE_report(op->reports, RPT_WARNING, "Can't ungroup"); 00911 return OPERATOR_CANCELLED; 00912 } 00913 00914 snode_notify(C, snode); 00915 snode_dag_update(C, snode); 00916 00917 return OPERATOR_FINISHED; 00918 } 00919 00920 void NODE_OT_group_ungroup(wmOperatorType *ot) 00921 { 00922 /* identifiers */ 00923 ot->name = "Ungroup"; 00924 ot->description = "Ungroup selected nodes"; 00925 ot->idname = "NODE_OT_group_ungroup"; 00926 00927 /* api callbacks */ 00928 ot->exec = node_group_ungroup_exec; 00929 ot->poll = ED_operator_node_active; 00930 00931 /* flags */ 00932 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; 00933 } 00934 00935 /* ************************** Node generic ************** */ 00936 00937 /* allows to walk the list in order of visibility */ 00938 bNode *next_node(bNodeTree *ntree) 00939 { 00940 static bNode *current=NULL, *last= NULL; 00941 00942 if(ntree) { 00943 /* set current to the first selected node */ 00944 for(current= ntree->nodes.last; current; current= current->prev) 00945 if(current->flag & NODE_SELECT) 00946 break; 00947 00948 /* set last to the first unselected node */ 00949 for(last= ntree->nodes.last; last; last= last->prev) 00950 if((last->flag & NODE_SELECT)==0) 00951 break; 00952 00953 if(current==NULL) 00954 current= last; 00955 00956 return NULL; 00957 } 00958 /* no nodes, or we are ready */ 00959 if(current==NULL) 00960 return NULL; 00961 00962 /* now we walk the list backwards, but we always return current */ 00963 if(current->flag & NODE_SELECT) { 00964 bNode *node= current; 00965 00966 /* find previous selected */ 00967 current= current->prev; 00968 while(current && (current->flag & NODE_SELECT)==0) 00969 current= current->prev; 00970 00971 /* find first unselected */ 00972 if(current==NULL) 00973 current= last; 00974 00975 return node; 00976 } 00977 else { 00978 bNode *node= current; 00979 00980 /* find previous unselected */ 00981 current= current->prev; 00982 while(current && (current->flag & NODE_SELECT)) 00983 current= current->prev; 00984 00985 return node; 00986 } 00987 00988 return NULL; 00989 } 00990 00991 /* is rct in visible part of node? */ 00992 static bNode *visible_node(SpaceNode *snode, rctf *rct) 00993 { 00994 bNode *tnode; 00995 00996 for(next_node(snode->edittree); (tnode=next_node(NULL));) { 00997 if(BLI_isect_rctf(&tnode->totr, rct, NULL)) 00998 break; 00999 } 01000 return tnode; 01001 } 01002 01003 /* **************************** */ 01004 01005 typedef struct NodeViewMove { 01006 int mvalo[2]; 01007 int xmin, ymin, xmax, ymax; 01008 } NodeViewMove; 01009 01010 static int snode_bg_viewmove_modal(bContext *C, wmOperator *op, wmEvent *event) 01011 { 01012 SpaceNode *snode= CTX_wm_space_node(C); 01013 ARegion *ar= CTX_wm_region(C); 01014 NodeViewMove *nvm= op->customdata; 01015 01016 switch (event->type) { 01017 case MOUSEMOVE: 01018 01019 snode->xof -= (nvm->mvalo[0]-event->mval[0]); 01020 snode->yof -= (nvm->mvalo[1]-event->mval[1]); 01021 nvm->mvalo[0]= event->mval[0]; 01022 nvm->mvalo[1]= event->mval[1]; 01023 01024 /* prevent dragging image outside of the window and losing it! */ 01025 CLAMP(snode->xof, nvm->xmin, nvm->xmax); 01026 CLAMP(snode->yof, nvm->ymin, nvm->ymax); 01027 01028 ED_region_tag_redraw(ar); 01029 01030 break; 01031 01032 case LEFTMOUSE: 01033 case MIDDLEMOUSE: 01034 case RIGHTMOUSE: 01035 01036 MEM_freeN(nvm); 01037 op->customdata= NULL; 01038 01039 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_NODE, NULL); 01040 01041 return OPERATOR_FINISHED; 01042 } 01043 01044 return OPERATOR_RUNNING_MODAL; 01045 } 01046 01047 static int snode_bg_viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event) 01048 { 01049 ARegion *ar= CTX_wm_region(C); 01050 NodeViewMove *nvm; 01051 Image *ima; 01052 ImBuf *ibuf; 01053 int pad= 10; 01054 void *lock; 01055 01056 ima= BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node"); 01057 ibuf= BKE_image_acquire_ibuf(ima, NULL, &lock); 01058 01059 if(ibuf == NULL) { 01060 BKE_image_release_ibuf(ima, lock); 01061 return OPERATOR_CANCELLED; 01062 } 01063 01064 nvm= MEM_callocN(sizeof(NodeViewMove), "NodeViewMove struct"); 01065 op->customdata= nvm; 01066 nvm->mvalo[0]= event->mval[0]; 01067 nvm->mvalo[1]= event->mval[1]; 01068 01069 nvm->xmin = -(ar->winx/2) - ibuf->x/2 + pad; 01070 nvm->xmax = ar->winx/2 + ibuf->x/2 - pad; 01071 nvm->ymin = -(ar->winy/2) - ibuf->y/2 + pad; 01072 nvm->ymax = ar->winy/2 + ibuf->y/2 - pad; 01073 01074 BKE_image_release_ibuf(ima, lock); 01075 01076 /* add modal handler */ 01077 WM_event_add_modal_handler(C, op); 01078 01079 return OPERATOR_RUNNING_MODAL; 01080 } 01081 01082 static int snode_bg_viewmove_cancel(bContext *UNUSED(C), wmOperator *op) 01083 { 01084 MEM_freeN(op->customdata); 01085 op->customdata= NULL; 01086 01087 return OPERATOR_CANCELLED; 01088 } 01089 01090 void NODE_OT_backimage_move(wmOperatorType *ot) 01091 { 01092 /* identifiers */ 01093 ot->name= "Background Image Move"; 01094 ot->description = "Move Node backdrop"; 01095 ot->idname= "NODE_OT_backimage_move"; 01096 01097 /* api callbacks */ 01098 ot->invoke= snode_bg_viewmove_invoke; 01099 ot->modal= snode_bg_viewmove_modal; 01100 ot->poll= composite_node_active; 01101 ot->cancel= snode_bg_viewmove_cancel; 01102 01103 /* flags */ 01104 ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER; 01105 } 01106 01107 static int backimage_zoom(bContext *C, wmOperator *op) 01108 { 01109 SpaceNode *snode= CTX_wm_space_node(C); 01110 ARegion *ar= CTX_wm_region(C); 01111 float fac= RNA_float_get(op->ptr, "factor"); 01112 01113 snode->zoom *= fac; 01114 ED_region_tag_redraw(ar); 01115 01116 return OPERATOR_FINISHED; 01117 } 01118 01119 01120 void NODE_OT_backimage_zoom(wmOperatorType *ot) 01121 { 01122 01123 /* identifiers */ 01124 ot->name= "Background Image Zoom"; 01125 ot->idname= "NODE_OT_backimage_zoom"; 01126 01127 /* api callbacks */ 01128 ot->exec= backimage_zoom; 01129 ot->poll= composite_node_active; 01130 01131 /* flags */ 01132 ot->flag= OPTYPE_BLOCKING; 01133 01134 /* internal */ 01135 RNA_def_float(ot->srna, "factor", 1.2f, 0.0f, 10.0f, "Factor", "", 0.0f, 10.0f); 01136 } 01137 01138 /******************** sample backdrop operator ********************/ 01139 01140 typedef struct ImageSampleInfo { 01141 ARegionType *art; 01142 void *draw_handle; 01143 int x, y; 01144 int channels; 01145 int color_manage; 01146 01147 char col[4]; 01148 float colf[4]; 01149 01150 int draw; 01151 } ImageSampleInfo; 01152 01153 static void sample_draw(const bContext *C, ARegion *ar, void *arg_info) 01154 { 01155 ImageSampleInfo *info= arg_info; 01156 01157 draw_nodespace_color_info(ar, (CTX_data_scene(C)->r.color_mgt_flag & R_COLOR_MANAGEMENT), info->channels, 01158 info->x, info->y, info->col, info->colf); 01159 } 01160 01161 static void sample_apply(bContext *C, wmOperator *op, wmEvent *event) 01162 { 01163 SpaceNode *snode= CTX_wm_space_node(C); 01164 ARegion *ar= CTX_wm_region(C); 01165 ImageSampleInfo *info= op->customdata; 01166 void *lock; 01167 Image *ima; 01168 ImBuf *ibuf; 01169 float fx, fy, bufx, bufy; 01170 01171 ima= BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node"); 01172 ibuf= BKE_image_acquire_ibuf(ima, NULL, &lock); 01173 if(!ibuf) 01174 return; 01175 01176 if(!ibuf->rect) { 01177 if(info->color_manage) 01178 ibuf->profile = IB_PROFILE_LINEAR_RGB; 01179 else 01180 ibuf->profile = IB_PROFILE_NONE; 01181 IMB_rect_from_float(ibuf); 01182 } 01183 01184 /* map the mouse coords to the backdrop image space */ 01185 bufx = ibuf->x * snode->zoom; 01186 bufy = ibuf->y * snode->zoom; 01187 fx = (bufx > 0.0f ? ((float)event->mval[0] - 0.5f*ar->winx - snode->xof) / bufx + 0.5f : 0.0f); 01188 fy = (bufy > 0.0f ? ((float)event->mval[1] - 0.5f*ar->winy - snode->yof) / bufy + 0.5f : 0.0f); 01189 01190 if(fx>=0.0f && fy>=0.0f && fx<1.0f && fy<1.0f) { 01191 float *fp; 01192 char *cp; 01193 int x= (int)(fx*ibuf->x), y= (int)(fy*ibuf->y); 01194 01195 CLAMP(x, 0, ibuf->x-1); 01196 CLAMP(y, 0, ibuf->y-1); 01197 01198 info->x= x; 01199 info->y= y; 01200 info->draw= 1; 01201 info->channels= ibuf->channels; 01202 01203 if(ibuf->rect) { 01204 cp= (char *)(ibuf->rect + y*ibuf->x + x); 01205 01206 info->col[0]= cp[0]; 01207 info->col[1]= cp[1]; 01208 info->col[2]= cp[2]; 01209 info->col[3]= cp[3]; 01210 01211 info->colf[0]= (float)cp[0]/255.0f; 01212 info->colf[1]= (float)cp[1]/255.0f; 01213 info->colf[2]= (float)cp[2]/255.0f; 01214 info->colf[3]= (float)cp[3]/255.0f; 01215 } 01216 if(ibuf->rect_float) { 01217 fp= (ibuf->rect_float + (ibuf->channels)*(y*ibuf->x + x)); 01218 01219 info->colf[0]= fp[0]; 01220 info->colf[1]= fp[1]; 01221 info->colf[2]= fp[2]; 01222 info->colf[3]= fp[3]; 01223 } 01224 } 01225 else 01226 info->draw= 0; 01227 01228 BKE_image_release_ibuf(ima, lock); 01229 01230 ED_area_tag_redraw(CTX_wm_area(C)); 01231 } 01232 01233 static void sample_exit(bContext *C, wmOperator *op) 01234 { 01235 ImageSampleInfo *info= op->customdata; 01236 01237 ED_region_draw_cb_exit(info->art, info->draw_handle); 01238 ED_area_tag_redraw(CTX_wm_area(C)); 01239 MEM_freeN(info); 01240 } 01241 01242 static int sample_invoke(bContext *C, wmOperator *op, wmEvent *event) 01243 { 01244 SpaceNode *snode= CTX_wm_space_node(C); 01245 ARegion *ar= CTX_wm_region(C); 01246 ImageSampleInfo *info; 01247 01248 if(snode->treetype!=NTREE_COMPOSIT || !(snode->flag & SNODE_BACKDRAW)) 01249 return OPERATOR_CANCELLED; 01250 01251 info= MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo"); 01252 info->art= ar->type; 01253 info->draw_handle = ED_region_draw_cb_activate(ar->type, sample_draw, info, REGION_DRAW_POST_PIXEL); 01254 op->customdata= info; 01255 01256 sample_apply(C, op, event); 01257 01258 WM_event_add_modal_handler(C, op); 01259 01260 return OPERATOR_RUNNING_MODAL; 01261 } 01262 01263 static int sample_modal(bContext *C, wmOperator *op, wmEvent *event) 01264 { 01265 switch(event->type) { 01266 case LEFTMOUSE: 01267 case RIGHTMOUSE: // XXX hardcoded 01268 sample_exit(C, op); 01269 return OPERATOR_CANCELLED; 01270 case MOUSEMOVE: 01271 sample_apply(C, op, event); 01272 break; 01273 } 01274 01275 return OPERATOR_RUNNING_MODAL; 01276 } 01277 01278 static int sample_cancel(bContext *C, wmOperator *op) 01279 { 01280 sample_exit(C, op); 01281 return OPERATOR_CANCELLED; 01282 } 01283 01284 void NODE_OT_backimage_sample(wmOperatorType *ot) 01285 { 01286 /* identifiers */ 01287 ot->name= "Backimage Sample"; 01288 ot->idname= "NODE_OT_backimage_sample"; 01289 01290 /* api callbacks */ 01291 ot->invoke= sample_invoke; 01292 ot->modal= sample_modal; 01293 ot->cancel= sample_cancel; 01294 ot->poll= ED_operator_node_active; 01295 01296 /* flags */ 01297 ot->flag= OPTYPE_BLOCKING; 01298 } 01299 01300 /* ********************** size widget operator ******************** */ 01301 01302 typedef struct NodeSizeWidget { 01303 float mxstart; 01304 float oldwidth; 01305 } NodeSizeWidget; 01306 01307 static int node_resize_modal(bContext *C, wmOperator *op, wmEvent *event) 01308 { 01309 SpaceNode *snode= CTX_wm_space_node(C); 01310 ARegion *ar= CTX_wm_region(C); 01311 bNode *node= editnode_get_active(snode->edittree); 01312 NodeSizeWidget *nsw= op->customdata; 01313 float mx, my; 01314 01315 switch (event->type) { 01316 case MOUSEMOVE: 01317 01318 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], 01319 &mx, &my); 01320 01321 if (node) { 01322 if(node->flag & NODE_HIDDEN) { 01323 node->miniwidth= nsw->oldwidth + mx - nsw->mxstart; 01324 CLAMP(node->miniwidth, 0.0f, 100.0f); 01325 } 01326 else { 01327 node->width= nsw->oldwidth + mx - nsw->mxstart; 01328 CLAMP(node->width, UI_DPI_FAC*node->typeinfo->minwidth, UI_DPI_FAC*node->typeinfo->maxwidth); 01329 } 01330 } 01331 01332 ED_region_tag_redraw(ar); 01333 01334 break; 01335 01336 case LEFTMOUSE: 01337 case MIDDLEMOUSE: 01338 case RIGHTMOUSE: 01339 01340 MEM_freeN(nsw); 01341 op->customdata= NULL; 01342 01343 return OPERATOR_FINISHED; 01344 } 01345 01346 return OPERATOR_RUNNING_MODAL; 01347 } 01348 01349 static int node_resize_invoke(bContext *C, wmOperator *op, wmEvent *event) 01350 { 01351 SpaceNode *snode= CTX_wm_space_node(C); 01352 ARegion *ar= CTX_wm_region(C); 01353 bNode *node= editnode_get_active(snode->edittree); 01354 01355 if(node) { 01356 rctf totr; 01357 01358 /* convert mouse coordinates to v2d space */ 01359 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], 01360 &snode->mx, &snode->my); 01361 01362 totr= node->totr; 01363 01364 if(node->flag & NODE_HIDDEN) { 01365 /* right part of node */ 01366 totr.xmin= node->totr.xmax-20.0f; 01367 } 01368 else { 01369 /* bottom right corner */ 01370 totr.xmin= totr.xmax-10.0f; 01371 totr.ymax= totr.ymin+10.0f; 01372 } 01373 01374 if(BLI_in_rctf(&totr, snode->mx, snode->my)) { 01375 NodeSizeWidget *nsw= MEM_callocN(sizeof(NodeSizeWidget), "size widget op data"); 01376 01377 op->customdata= nsw; 01378 nsw->mxstart= snode->mx; 01379 01380 /* store old */ 01381 if(node->flag & NODE_HIDDEN) 01382 nsw->oldwidth= node->miniwidth; 01383 else 01384 nsw->oldwidth= node->width; 01385 01386 /* add modal handler */ 01387 WM_event_add_modal_handler(C, op); 01388 01389 return OPERATOR_RUNNING_MODAL; 01390 } 01391 } 01392 return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH; 01393 } 01394 01395 static int node_resize_cancel(bContext *UNUSED(C), wmOperator *op) 01396 { 01397 MEM_freeN(op->customdata); 01398 op->customdata= NULL; 01399 01400 return OPERATOR_CANCELLED; 01401 } 01402 01403 void NODE_OT_resize(wmOperatorType *ot) 01404 { 01405 /* identifiers */ 01406 ot->name= "Resize Node"; 01407 ot->idname= "NODE_OT_resize"; 01408 01409 /* api callbacks */ 01410 ot->invoke= node_resize_invoke; 01411 ot->modal= node_resize_modal; 01412 ot->poll= ED_operator_node_active; 01413 ot->cancel= node_resize_cancel; 01414 01415 /* flags */ 01416 ot->flag= OPTYPE_BLOCKING; 01417 } 01418 01419 /* ********************** select ******************** */ 01420 01421 01422 /* no undo here! */ 01423 void node_deselectall(SpaceNode *snode) 01424 { 01425 bNode *node; 01426 01427 for(node= snode->edittree->nodes.first; node; node= node->next) 01428 node->flag &= ~SELECT; 01429 } 01430 01431 /* return 1 if we need redraw otherwise zero. */ 01432 int node_select_same_type(SpaceNode *snode) 01433 { 01434 bNode *nac, *p; 01435 int redraw; 01436 01437 /* search for the active node. */ 01438 for (nac= snode->edittree->nodes.first; nac; nac= nac->next) { 01439 if (nac->flag & SELECT) 01440 break; 01441 } 01442 01443 /* no active node, return. */ 01444 if (!nac) 01445 return(0); 01446 01447 redraw= 0; 01448 for (p= snode->edittree->nodes.first; p; p= p->next) { 01449 if (p->type != nac->type && p->flag & SELECT) { 01450 /* if it's selected but different type, unselect */ 01451 redraw= 1; 01452 p->flag &= ~SELECT; 01453 } 01454 else if (p->type == nac->type && (!(p->flag & SELECT))) { 01455 /* if it's the same type and is not selected, select! */ 01456 redraw= 1; 01457 p->flag |= SELECT; 01458 } 01459 } 01460 return(redraw); 01461 } 01462 01463 /* return 1 if we need redraw, otherwise zero. 01464 * dir can be 0 == next or 0 != prev. 01465 */ 01466 int node_select_same_type_np(SpaceNode *snode, int dir) 01467 { 01468 bNode *nac, *p; 01469 01470 /* search the active one. */ 01471 for (nac= snode->edittree->nodes.first; nac; nac= nac->next) { 01472 if (nac->flag & SELECT) 01473 break; 01474 } 01475 01476 /* no active node, return. */ 01477 if (!nac) 01478 return(0); 01479 01480 if (dir == 0) 01481 p= nac->next; 01482 else 01483 p= nac->prev; 01484 01485 while (p) { 01486 /* Now search the next with the same type. */ 01487 if (p->type == nac->type) 01488 break; 01489 01490 if (dir == 0) 01491 p= p->next; 01492 else 01493 p= p->prev; 01494 } 01495 01496 if (p) { 01497 node_deselectall(snode); 01498 p->flag |= SELECT; 01499 return(1); 01500 } 01501 return(0); 01502 } 01503 01504 int node_has_hidden_sockets(bNode *node) 01505 { 01506 bNodeSocket *sock; 01507 01508 for(sock= node->inputs.first; sock; sock= sock->next) 01509 if(sock->flag & SOCK_HIDDEN) 01510 return 1; 01511 for(sock= node->outputs.first; sock; sock= sock->next) 01512 if(sock->flag & SOCK_HIDDEN) 01513 return 1; 01514 return 0; 01515 } 01516 01517 static void node_link_viewer(SpaceNode *snode, bNode *tonode) 01518 { 01519 bNode *node; 01520 01521 /* context check */ 01522 if(tonode==NULL || tonode->outputs.first==NULL) 01523 return; 01524 if( ELEM(tonode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) 01525 return; 01526 01527 /* get viewer */ 01528 for(node= snode->edittree->nodes.first; node; node= node->next) 01529 if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) 01530 if(node->flag & NODE_DO_OUTPUT) 01531 break; 01532 /* no viewer, we make one active */ 01533 if(node==NULL) { 01534 for(node= snode->edittree->nodes.first; node; node= node->next) { 01535 if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { 01536 node->flag |= NODE_DO_OUTPUT; 01537 break; 01538 } 01539 } 01540 } 01541 01542 if(node) { 01543 bNodeLink *link; 01544 bNodeSocket *sock= NULL; 01545 01546 /* try to find an already connected socket to cycle to the next */ 01547 for(link= snode->edittree->links.first; link; link= link->next) 01548 if(link->tonode==node && link->fromnode==tonode) 01549 if(link->tosock==node->inputs.first) 01550 break; 01551 01552 if(link) { 01553 /* unlink existing connection */ 01554 sock= link->fromsock; 01555 nodeRemLink(snode->edittree, link); 01556 01557 /* find a socket after the previously connected socket */ 01558 for(sock=sock->next; sock; sock= sock->next) 01559 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) 01560 break; 01561 } 01562 01563 /* find a socket starting from the first socket */ 01564 if(!sock) { 01565 for(sock= tonode->outputs.first; sock; sock= sock->next) 01566 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) 01567 break; 01568 } 01569 01570 if(sock) { 01571 /* get link to viewer */ 01572 for(link= snode->edittree->links.first; link; link= link->next) 01573 if(link->tonode==node && link->tosock==node->inputs.first) 01574 break; 01575 01576 if(link==NULL) { 01577 nodeAddLink(snode->edittree, tonode, sock, node, node->inputs.first); 01578 } 01579 else { 01580 link->fromnode= tonode; 01581 link->fromsock= sock; 01582 } 01583 ntreeSolveOrder(snode->edittree); 01584 snode_tag_changed(snode, node); 01585 } 01586 } 01587 } 01588 01589 01590 static int node_active_link_viewer(bContext *C, wmOperator *UNUSED(op)) 01591 { 01592 SpaceNode *snode= CTX_wm_space_node(C); 01593 bNode *node; 01594 01595 node= editnode_get_active(snode->edittree); 01596 01597 if(!node) 01598 return OPERATOR_CANCELLED; 01599 01600 ED_preview_kill_jobs(C); 01601 01602 node_link_viewer(snode, node); 01603 snode_notify(C, snode); 01604 01605 return OPERATOR_FINISHED; 01606 } 01607 01608 01609 01610 void NODE_OT_link_viewer(wmOperatorType *ot) 01611 { 01612 /* identifiers */ 01613 ot->name= "Link to Viewer Node"; 01614 ot->description = "Link to Viewer Node"; 01615 ot->idname= "NODE_OT_link_viewer"; 01616 01617 /* api callbacks */ 01618 ot->exec= node_active_link_viewer; 01619 ot->poll= ED_operator_node_active; 01620 01621 /* flags */ 01622 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01623 } 01624 01625 01626 01627 /* return 0, nothing done */ 01628 static int node_mouse_groupheader(SpaceNode *snode) 01629 { 01630 bNode *gnode; 01631 float mx=0, my=0; 01632 // XXX int mval[2]; 01633 01634 gnode= node_tree_get_editgroup(snode->nodetree); 01635 if(gnode==NULL) return 0; 01636 01637 // XXX getmouseco_areawin(mval); 01638 // XXX areamouseco_to_ipoco(G.v2d, mval, &mx, &my); 01639 01640 /* click in header or outside? */ 01641 if(BLI_in_rctf(&gnode->totr, mx, my)==0) { 01642 rctf rect= gnode->totr; 01643 01644 rect.ymax += NODE_DY; 01645 if(BLI_in_rctf(&rect, mx, my)==0) 01646 snode_make_group_editable(snode, NULL); /* toggles, so exits editmode */ 01647 // else 01648 // XXX transform_nodes(snode->nodetree, 'g', "Move group"); 01649 01650 return 1; 01651 } 01652 return 0; 01653 } 01654 01655 /* checks snode->mouse position, and returns found node/socket */ 01656 /* type is SOCK_IN and/or SOCK_OUT */ 01657 static int find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, int in_out) 01658 { 01659 bNode *node; 01660 bNodeSocket *sock; 01661 rctf rect; 01662 01663 /* check if we click in a socket */ 01664 for(node= snode->edittree->nodes.first; node; node= node->next) { 01665 01666 rect.xmin = snode->mx - (NODE_SOCKSIZE+4); 01667 rect.ymin = snode->my - (NODE_SOCKSIZE+4); 01668 rect.xmax = snode->mx + (NODE_SOCKSIZE+4); 01669 rect.ymax = snode->my + (NODE_SOCKSIZE+4); 01670 01671 if (!(node->flag & NODE_HIDDEN)) { 01672 /* extra padding inside and out - allow dragging on the text areas too */ 01673 if (in_out == SOCK_IN) { 01674 rect.xmax += NODE_SOCKSIZE; 01675 rect.xmin -= NODE_SOCKSIZE*4; 01676 } else if (in_out == SOCK_OUT) { 01677 rect.xmax += NODE_SOCKSIZE*4; 01678 rect.xmin -= NODE_SOCKSIZE; 01679 } 01680 } 01681 01682 if(in_out & SOCK_IN) { 01683 for(sock= node->inputs.first; sock; sock= sock->next) { 01684 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) { 01685 if(BLI_in_rctf(&rect, sock->locx, sock->locy)) { 01686 if(node == visible_node(snode, &rect)) { 01687 *nodep= node; 01688 *sockp= sock; 01689 return 1; 01690 } 01691 } 01692 } 01693 } 01694 } 01695 if(in_out & SOCK_OUT) { 01696 for(sock= node->outputs.first; sock; sock= sock->next) { 01697 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) { 01698 if(BLI_in_rctf(&rect, sock->locx, sock->locy)) { 01699 if(node == visible_node(snode, &rect)) { 01700 *nodep= node; 01701 *sockp= sock; 01702 return 1; 01703 } 01704 } 01705 } 01706 } 01707 } 01708 } 01709 01710 /* check group sockets 01711 * NB: using ngroup->outputs as input sockets and vice versa here! 01712 */ 01713 if(in_out & SOCK_IN) { 01714 for(sock= snode->edittree->outputs.first; sock; sock= sock->next) { 01715 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) { 01716 if(BLI_in_rctf(&rect, sock->locx, sock->locy)) { 01717 *nodep= NULL; /* NULL node pointer indicates group socket */ 01718 *sockp= sock; 01719 return 1; 01720 } 01721 } 01722 } 01723 } 01724 if(in_out & SOCK_OUT) { 01725 for(sock= snode->edittree->inputs.first; sock; sock= sock->next) { 01726 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) { 01727 if(BLI_in_rctf(&rect, sock->locx, sock->locy)) { 01728 *nodep= NULL; /* NULL node pointer indicates group socket */ 01729 *sockp= sock; 01730 return 1; 01731 } 01732 } 01733 } 01734 } 01735 01736 return 0; 01737 } 01738 01739 static int node_socket_hilights(SpaceNode *snode, int in_out) 01740 { 01741 bNode *node; 01742 bNodeSocket *sock, *tsock, *socksel= NULL; 01743 short redraw= 0; 01744 01745 if(snode->edittree==NULL) return 0; 01746 01747 /* deselect sockets */ 01748 for(node= snode->edittree->nodes.first; node; node= node->next) { 01749 for(sock= node->inputs.first; sock; sock= sock->next) { 01750 if(sock->flag & SELECT) { 01751 sock->flag &= ~SELECT; 01752 redraw++; 01753 socksel= sock; 01754 } 01755 } 01756 for(sock= node->outputs.first; sock; sock= sock->next) { 01757 if(sock->flag & SELECT) { 01758 sock->flag &= ~SELECT; 01759 redraw++; 01760 socksel= sock; 01761 } 01762 } 01763 } 01764 01765 // XXX mousepos should be set here! 01766 01767 if(find_indicated_socket(snode, &node, &tsock, in_out)) { 01768 tsock->flag |= SELECT; 01769 if(redraw==1 && tsock==socksel) redraw= 0; 01770 else redraw= 1; 01771 } 01772 01773 return redraw; 01774 } 01775 01776 static int outside_group_rect(SpaceNode *snode) 01777 { 01778 bNode *gnode= node_tree_get_editgroup(snode->nodetree); 01779 if (gnode) { 01780 return (snode->mx < gnode->totr.xmin || snode->mx >= gnode->totr.xmax 01781 || snode->my < gnode->totr.ymin || snode->my >= gnode->totr.ymax); 01782 } 01783 return 0; 01784 } 01785 01786 /* ****************** Add *********************** */ 01787 01788 01789 typedef struct bNodeListItem { 01790 struct bNodeListItem *next, *prev; 01791 struct bNode *node; 01792 } bNodeListItem; 01793 01794 static int sort_nodes_locx(void *a, void *b) 01795 { 01796 bNodeListItem *nli1 = (bNodeListItem *)a; 01797 bNodeListItem *nli2 = (bNodeListItem *)b; 01798 bNode *node1 = nli1->node; 01799 bNode *node2 = nli2->node; 01800 01801 if (node1->locx > node2->locx) 01802 return 1; 01803 else 01804 return 0; 01805 } 01806 01807 static int socket_is_available(bNodeTree *ntree, bNodeSocket *sock, int allow_used) 01808 { 01809 if (sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)) 01810 return 0; 01811 01812 if (!allow_used) { 01813 if (nodeCountSocketLinks(ntree, sock) > 0) 01814 return 0; 01815 } 01816 return 1; 01817 } 01818 01819 static bNodeSocket *best_socket_output(bNodeTree *ntree, bNode *node, bNodeSocket *sock_target, int allow_multiple) 01820 { 01821 bNodeSocket *sock; 01822 01823 /* first try to find a socket with a matching name */ 01824 for (sock=node->outputs.first; sock; sock=sock->next) { 01825 01826 if (!socket_is_available(ntree, sock, allow_multiple)) 01827 continue; 01828 01829 /* check for same types */ 01830 if (sock->type == sock_target->type) { 01831 if (strcmp(sock->name, sock_target->name)==0) 01832 return sock; 01833 } 01834 } 01835 01836 /* otherwise settle for the first available socket of the right type */ 01837 for (sock=node->outputs.first; sock; sock=sock->next) { 01838 01839 if (!socket_is_available(ntree, sock, allow_multiple)) 01840 continue; 01841 01842 /* check for same types */ 01843 if (sock->type == sock_target->type) { 01844 return sock; 01845 } 01846 } 01847 01848 return NULL; 01849 } 01850 01851 /* this is a bit complicated, but designed to prioritise finding 01852 * sockets of higher types, such as image, first */ 01853 static bNodeSocket *best_socket_input(bNodeTree *ntree, bNode *node, int num, int replace) 01854 { 01855 bNodeSocket *sock; 01856 int socktype, maxtype=0; 01857 int a = 0; 01858 01859 for (sock=node->inputs.first; sock; sock=sock->next) { 01860 maxtype = MAX2(sock->type, maxtype); 01861 } 01862 01863 /* find sockets of higher 'types' first (i.e. image) */ 01864 for (socktype=maxtype; socktype >= 0; socktype--) { 01865 for (sock=node->inputs.first; sock; sock=sock->next) { 01866 01867 if (!socket_is_available(ntree, sock, replace)) { 01868 a++; 01869 continue; 01870 } 01871 01872 if (sock->type == socktype) { 01873 /* increment to make sure we don't keep finding 01874 * the same socket on every attempt running this function */ 01875 a++; 01876 if (a > num) 01877 return sock; 01878 } 01879 } 01880 } 01881 01882 return NULL; 01883 } 01884 01885 void snode_autoconnect(SpaceNode *snode, int allow_multiple, int replace) 01886 { 01887 ListBase *nodelist = MEM_callocN(sizeof(ListBase), "items_list"); 01888 bNodeListItem *nli; 01889 bNode *node; 01890 int i, numlinks=0; 01891 01892 for(node= snode->edittree->nodes.first; node; node= node->next) { 01893 if(node->flag & NODE_SELECT) { 01894 nli = MEM_mallocN(sizeof(bNodeListItem), "temporary node list item"); 01895 nli->node = node; 01896 BLI_addtail(nodelist, nli); 01897 } 01898 } 01899 01900 /* sort nodes left to right */ 01901 BLI_sortlist(nodelist, sort_nodes_locx); 01902 01903 for (nli=nodelist->first; nli; nli=nli->next) { 01904 bNode *node_fr, *node_to; 01905 bNodeSocket *sock_fr, *sock_to; 01906 01907 if (nli->next == NULL) break; 01908 01909 node_fr = nli->node; 01910 node_to = nli->next->node; 01911 01912 /* check over input sockets first */ 01913 for (i=0; i<BLI_countlist(&node_to->inputs); i++) { 01914 01915 /* find the best guess input socket */ 01916 sock_to = best_socket_input(snode->edittree, node_to, i, replace); 01917 if (!sock_to) continue; 01918 01919 /* check for an appropriate output socket to connect from */ 01920 sock_fr = best_socket_output(snode->edittree, node_fr, sock_to, allow_multiple); 01921 if (!sock_fr) continue; 01922 01923 /* then we can connect */ 01924 if (replace) 01925 nodeRemSocketLinks(snode->edittree, sock_to); 01926 nodeAddLink(snode->edittree, node_fr, sock_fr, node_to, sock_to); 01927 snode_tag_changed(snode, node_to); 01928 ++numlinks; 01929 break; 01930 } 01931 } 01932 01933 if (numlinks > 0) { 01934 node_tree_verify_groups(snode->nodetree); 01935 ntreeSolveOrder(snode->edittree); 01936 } 01937 01938 BLI_freelistN(nodelist); 01939 MEM_freeN(nodelist); 01940 } 01941 01942 /* can be called from menus too, but they should do own undopush and redraws */ 01943 bNode *node_add_node(SpaceNode *snode, Scene *scene, int type, float locx, float locy) 01944 { 01945 bNode *node= NULL, *gnode; 01946 01947 node_deselectall(snode); 01948 01949 if(type>=NODE_DYNAMIC_MENU) { 01950 node= nodeAddNodeType(snode->edittree, type, NULL, NULL); 01951 } 01952 else if(type>=NODE_GROUP_MENU) { 01953 if(snode->edittree!=snode->nodetree) { 01954 // XXX error("Can not add a Group in a Group"); 01955 return NULL; 01956 } 01957 else { 01958 bNodeTree *ngroup= BLI_findlink(&G.main->nodetree, type-NODE_GROUP_MENU); 01959 if(ngroup) 01960 node= nodeAddNodeType(snode->edittree, NODE_GROUP, ngroup, NULL); 01961 } 01962 } 01963 else 01964 node= nodeAddNodeType(snode->edittree, type, NULL, NULL); 01965 01966 /* generics */ 01967 if(node) { 01968 node->locx= locx; 01969 node->locy= locy + 60.0f; // arbitrary.. so its visible, (0,0) is top of node 01970 node->flag |= SELECT; 01971 01972 gnode= node_tree_get_editgroup(snode->nodetree); 01973 if(gnode) { 01974 node->locx -= gnode->locx; 01975 node->locy -= gnode->locy; 01976 } 01977 01978 node_tree_verify_groups(snode->nodetree); 01979 node_set_active(snode, node); 01980 01981 if(snode->nodetree->type==NTREE_COMPOSIT) { 01982 if(ELEM4(node->type, CMP_NODE_R_LAYERS, CMP_NODE_COMPOSITE, CMP_NODE_DEFOCUS, CMP_NODE_OUTPUT_FILE)) 01983 node->id = &scene->id; 01984 01985 ntreeCompositForceHidden(snode->edittree, scene); 01986 } 01987 01988 if(node->id) 01989 id_us_plus(node->id); 01990 01991 snode_tag_changed(snode, node); 01992 } 01993 01994 if(snode->nodetree->type==NTREE_TEXTURE) { 01995 ntreeTexCheckCyclics(snode->edittree); 01996 } 01997 01998 return node; 01999 } 02000 02001 /* ****************** Duplicate *********************** */ 02002 02003 static int node_duplicate_exec(bContext *C, wmOperator *op) 02004 { 02005 SpaceNode *snode= CTX_wm_space_node(C); 02006 bNodeTree *ntree= snode->edittree; 02007 bNode *node, *newnode, *lastnode; 02008 bNodeLink *link, *newlink, *lastlink; 02009 int keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs"); 02010 02011 ED_preview_kill_jobs(C); 02012 02013 lastnode = ntree->nodes.last; 02014 for(node= ntree->nodes.first; node; node= node->next) { 02015 if(node->flag & SELECT) { 02016 newnode = nodeCopyNode(ntree, node); 02017 02018 if(newnode->id) { 02019 /* simple id user adjustment, node internal functions dont touch this 02020 * but operators and readfile.c do. */ 02021 id_us_plus(newnode->id); 02022 /* to ensure redraws or rerenders happen */ 02023 ED_node_changed_update(snode->id, newnode); 02024 } 02025 } 02026 02027 /* make sure we don't copy new nodes again! */ 02028 if (node==lastnode) 02029 break; 02030 } 02031 02032 /* copy links between selected nodes 02033 * NB: this depends on correct node->new_node and sock->new_sock pointers from above copy! 02034 */ 02035 lastlink = ntree->links.last; 02036 for (link=ntree->links.first; link; link=link->next) { 02037 /* This creates new links between copied nodes. 02038 * If keep_inputs is set, also copies input links from unselected (when fromnode==NULL)! 02039 */ 02040 if (link->tonode && (link->tonode->flag & NODE_SELECT) 02041 && (keep_inputs || (link->fromnode && (link->fromnode->flag & NODE_SELECT)))) { 02042 newlink = MEM_callocN(sizeof(bNodeLink), "bNodeLink"); 02043 newlink->flag = link->flag; 02044 newlink->tonode = link->tonode->new_node; 02045 newlink->tosock = link->tosock->new_sock; 02046 if (link->fromnode && (link->fromnode->flag & NODE_SELECT)) { 02047 newlink->fromnode = link->fromnode->new_node; 02048 newlink->fromsock = link->fromsock->new_sock; 02049 } 02050 else { 02051 /* input node not copied, this keeps the original input linked */ 02052 newlink->fromnode = link->fromnode; 02053 newlink->fromsock = link->fromsock; 02054 } 02055 02056 BLI_addtail(&ntree->links, newlink); 02057 } 02058 02059 /* make sure we don't copy new links again! */ 02060 if (link==lastlink) 02061 break; 02062 } 02063 02064 /* deselect old nodes, select the copies instead */ 02065 for(node= ntree->nodes.first; node; node= node->next) { 02066 if(node->flag & SELECT) { 02067 /* has been set during copy above */ 02068 newnode = node->new_node; 02069 02070 node->flag &= ~(NODE_SELECT|NODE_ACTIVE); 02071 newnode->flag |= NODE_SELECT; 02072 } 02073 02074 /* make sure we don't copy new nodes again! */ 02075 if (node==lastnode) 02076 break; 02077 } 02078 02079 ntreeSolveOrder(ntree); 02080 02081 node_tree_verify_groups(snode->nodetree); 02082 snode_notify(C, snode); 02083 snode_dag_update(C, snode); 02084 02085 return OPERATOR_FINISHED; 02086 } 02087 02088 void NODE_OT_duplicate(wmOperatorType *ot) 02089 { 02090 /* identifiers */ 02091 ot->name= "Duplicate Nodes"; 02092 ot->description = "Duplicate the nodes"; 02093 ot->idname= "NODE_OT_duplicate"; 02094 02095 /* api callbacks */ 02096 ot->exec= node_duplicate_exec; 02097 ot->poll= ED_operator_node_active; 02098 02099 /* flags */ 02100 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02101 02102 RNA_def_boolean(ot->srna, "keep_inputs", 0, "Keep Inputs", "Keep the input links to duplicated nodes"); 02103 } 02104 02105 /* *************************** add link op ******************** */ 02106 02107 static void node_remove_extra_links(SpaceNode *snode, bNodeSocket *tsock, bNodeLink *link) 02108 { 02109 bNodeLink *tlink; 02110 bNodeSocket *sock; 02111 02112 if(tsock && nodeCountSocketLinks(snode->edittree, link->tosock) > tsock->limit) { 02113 02114 for(tlink= snode->edittree->links.first; tlink; tlink= tlink->next) { 02115 if(link!=tlink && tlink->tosock==link->tosock) 02116 break; 02117 } 02118 if(tlink) { 02119 /* try to move the existing link to the next available socket */ 02120 if (tlink->tonode) { 02121 /* is there a free input socket with the target type? */ 02122 for(sock= tlink->tonode->inputs.first; sock; sock= sock->next) { 02123 if(sock->type==tlink->tosock->type) 02124 if(nodeCountSocketLinks(snode->edittree, sock) < sock->limit) 02125 break; 02126 } 02127 if(sock) { 02128 tlink->tosock= sock; 02129 sock->flag &= ~SOCK_HIDDEN; 02130 } 02131 else { 02132 nodeRemLink(snode->edittree, tlink); 02133 } 02134 } 02135 else 02136 nodeRemLink(snode->edittree, tlink); 02137 } 02138 } 02139 } 02140 02141 /* loop that adds a nodelink, called by function below */ 02142 /* in_out = starting socket */ 02143 static int node_link_modal(bContext *C, wmOperator *op, wmEvent *event) 02144 { 02145 SpaceNode *snode= CTX_wm_space_node(C); 02146 ARegion *ar= CTX_wm_region(C); 02147 bNodeLinkDrag *nldrag= op->customdata; 02148 bNode *tnode, *node; 02149 bNodeSocket *tsock= NULL, *sock; 02150 bNodeLink *link; 02151 int in_out; 02152 02153 in_out= nldrag->in_out; 02154 node= nldrag->node; 02155 sock= nldrag->sock; 02156 link= nldrag->link; 02157 02158 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], 02159 &snode->mx, &snode->my); 02160 02161 switch (event->type) { 02162 case MOUSEMOVE: 02163 02164 if(in_out==SOCK_OUT) { 02165 if(find_indicated_socket(snode, &tnode, &tsock, SOCK_IN)) { 02166 if(nodeFindLink(snode->edittree, sock, tsock)==NULL) { 02167 if( link->tosock!= tsock && (!tnode || (tnode!=node && link->tonode!=tnode)) ) { 02168 link->tonode= tnode; 02169 link->tosock= tsock; 02170 if (link->prev==NULL && link->next==NULL) 02171 BLI_addtail(&snode->edittree->links, link); 02172 ntreeSolveOrder(snode->edittree); /* for interactive red line warning */ 02173 } 02174 } 02175 } 02176 else { 02177 BLI_remlink(&snode->edittree->links, link); 02178 link->prev = link->next = NULL; 02179 link->tonode= NULL; 02180 link->tosock= NULL; 02181 } 02182 } 02183 else { 02184 if(find_indicated_socket(snode, &tnode, &tsock, SOCK_OUT)) { 02185 if(nodeFindLink(snode->edittree, sock, tsock)==NULL) { 02186 if(nodeCountSocketLinks(snode->edittree, tsock) < tsock->limit) { 02187 if( link->fromsock!= tsock && (!tnode || (tnode!=node && link->fromnode!=tnode)) ) { 02188 link->fromnode= tnode; 02189 link->fromsock= tsock; 02190 if (link->prev==NULL && link->next==NULL) 02191 BLI_addtail(&snode->edittree->links, link); 02192 ntreeSolveOrder(snode->edittree); /* for interactive red line warning */ 02193 } 02194 } 02195 } 02196 } 02197 else { 02198 BLI_remlink(&snode->edittree->links, link); 02199 link->prev = link->next = NULL; 02200 link->fromnode= NULL; 02201 link->fromsock= NULL; 02202 } 02203 } 02204 /* hilight target sockets only */ 02205 node_socket_hilights(snode, in_out==SOCK_OUT?SOCK_IN:SOCK_OUT); 02206 ED_region_tag_redraw(ar); 02207 break; 02208 02209 case LEFTMOUSE: 02210 case RIGHTMOUSE: 02211 case MIDDLEMOUSE: 02212 if(link->tosock && link->fromsock) { 02213 /* send changed events for original tonode and new */ 02214 snode_tag_changed(snode, link->tonode); 02215 02216 /* we might need to remove a link */ 02217 if(in_out==SOCK_OUT) 02218 node_remove_extra_links(snode, link->tosock, link); 02219 02220 /* when linking to group outputs, update the socket type */ 02221 /* XXX this should all be part of a generic update system */ 02222 if (!link->tonode) { 02223 link->tosock->type = link->fromsock->type; 02224 } 02225 } 02226 else if (outside_group_rect(snode) && (link->tonode || link->fromnode)) { 02227 /* automatically add new group socket */ 02228 if (link->tonode && link->tosock) { 02229 link->fromsock = nodeGroupExposeSocket(snode->edittree, link->tosock, SOCK_IN); 02230 link->fromnode = NULL; 02231 if (link->prev==NULL && link->next==NULL) 02232 BLI_addtail(&snode->edittree->links, link); 02233 } 02234 else if (link->fromnode && link->fromsock) { 02235 link->tosock = nodeGroupExposeSocket(snode->edittree, link->fromsock, SOCK_OUT); 02236 link->tonode = NULL; 02237 if (link->prev==NULL && link->next==NULL) 02238 BLI_addtail(&snode->edittree->links, link); 02239 } 02240 } 02241 else 02242 nodeRemLink(snode->edittree, link); 02243 02244 ntreeSolveOrder(snode->edittree); 02245 node_tree_verify_groups(snode->nodetree); 02246 snode_notify(C, snode); 02247 snode_dag_update(C, snode); 02248 02249 BLI_remlink(&snode->linkdrag, nldrag); 02250 MEM_freeN(nldrag); 02251 02252 return OPERATOR_FINISHED; 02253 } 02254 02255 return OPERATOR_RUNNING_MODAL; 02256 } 02257 02258 /* return 1 when socket clicked */ 02259 static int node_link_init(SpaceNode *snode, bNodeLinkDrag *nldrag) 02260 { 02261 bNodeLink *link; 02262 02263 /* output indicated? */ 02264 if(find_indicated_socket(snode, &nldrag->node, &nldrag->sock, SOCK_OUT)) { 02265 if(nodeCountSocketLinks(snode->edittree, nldrag->sock) < nldrag->sock->limit) 02266 return SOCK_OUT; 02267 else { 02268 /* find if we break a link */ 02269 for(link= snode->edittree->links.first; link; link= link->next) { 02270 if(link->fromsock==nldrag->sock) 02271 break; 02272 } 02273 if(link) { 02274 nldrag->node= link->tonode; 02275 nldrag->sock= link->tosock; 02276 nodeRemLink(snode->edittree, link); 02277 return SOCK_IN; 02278 } 02279 } 02280 } 02281 /* or an input? */ 02282 else if(find_indicated_socket(snode, &nldrag->node, &nldrag->sock, SOCK_IN)) { 02283 if(nodeCountSocketLinks(snode->edittree, nldrag->sock) < nldrag->sock->limit) 02284 return SOCK_IN; 02285 else { 02286 /* find if we break a link */ 02287 for(link= snode->edittree->links.first; link; link= link->next) { 02288 if(link->tosock==nldrag->sock) 02289 break; 02290 } 02291 if(link) { 02292 /* send changed event to original tonode */ 02293 if(link->tonode) 02294 snode_tag_changed(snode, link->tonode); 02295 02296 nldrag->node= link->fromnode; 02297 nldrag->sock= link->fromsock; 02298 nodeRemLink(snode->edittree, link); 02299 return SOCK_OUT; 02300 } 02301 } 02302 } 02303 02304 return 0; 02305 } 02306 02307 static int node_link_invoke(bContext *C, wmOperator *op, wmEvent *event) 02308 { 02309 SpaceNode *snode= CTX_wm_space_node(C); 02310 ARegion *ar= CTX_wm_region(C); 02311 bNodeLinkDrag *nldrag= MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata"); 02312 02313 02314 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], 02315 &snode->mx, &snode->my); 02316 02317 ED_preview_kill_jobs(C); 02318 02319 nldrag->in_out= node_link_init(snode, nldrag); 02320 02321 if(nldrag->in_out) { 02322 op->customdata= nldrag; 02323 02324 /* we make a temporal link */ 02325 if(nldrag->in_out==SOCK_OUT) { 02326 nldrag->link= MEM_callocN(sizeof(bNodeLink), "link"); 02327 nldrag->link->fromnode= nldrag->node; 02328 nldrag->link->fromsock= nldrag->sock; 02329 nldrag->link->tonode= NULL; 02330 nldrag->link->tosock= NULL; 02331 } 02332 else { 02333 nldrag->link= MEM_callocN(sizeof(bNodeLink), "link"); 02334 nldrag->link->fromnode= NULL; 02335 nldrag->link->fromsock= NULL; 02336 nldrag->link->tonode= nldrag->node; 02337 nldrag->link->tosock= nldrag->sock; 02338 } 02339 BLI_addtail(&snode->linkdrag, nldrag); 02340 02341 /* add modal handler */ 02342 WM_event_add_modal_handler(C, op); 02343 02344 return OPERATOR_RUNNING_MODAL; 02345 } 02346 else { 02347 MEM_freeN(nldrag); 02348 return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH; 02349 } 02350 } 02351 02352 static int node_link_cancel(bContext *C, wmOperator *op) 02353 { 02354 SpaceNode *snode= CTX_wm_space_node(C); 02355 bNodeLinkDrag *nldrag= op->customdata; 02356 02357 nodeRemLink(snode->edittree, nldrag->link); 02358 BLI_remlink(&snode->linkdrag, nldrag); 02359 MEM_freeN(nldrag); 02360 02361 return OPERATOR_CANCELLED; 02362 } 02363 02364 void NODE_OT_link(wmOperatorType *ot) 02365 { 02366 /* identifiers */ 02367 ot->name= "Link Nodes"; 02368 ot->idname= "NODE_OT_link"; 02369 02370 /* api callbacks */ 02371 ot->invoke= node_link_invoke; 02372 ot->modal= node_link_modal; 02373 // ot->exec= node_link_exec; 02374 ot->poll= ED_operator_node_active; 02375 ot->cancel= node_link_cancel; 02376 02377 /* flags */ 02378 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; 02379 } 02380 02381 /* ********************** Make Link operator ***************** */ 02382 02383 /* makes a link between selected output and input sockets */ 02384 static int node_make_link_exec(bContext *C, wmOperator *op) 02385 { 02386 SpaceNode *snode= CTX_wm_space_node(C); 02387 int replace = RNA_boolean_get(op->ptr, "replace"); 02388 02389 ED_preview_kill_jobs(C); 02390 02391 snode_autoconnect(snode, 1, replace); 02392 02393 node_tree_verify_groups(snode->nodetree); 02394 snode_notify(C, snode); 02395 snode_dag_update(C, snode); 02396 02397 return OPERATOR_FINISHED; 02398 } 02399 02400 void NODE_OT_link_make(wmOperatorType *ot) 02401 { 02402 /* identifiers */ 02403 ot->name= "Make Links"; 02404 ot->description= "Makes a link between selected output in input sockets"; 02405 ot->idname= "NODE_OT_link_make"; 02406 02407 /* callbacks */ 02408 ot->exec= node_make_link_exec; 02409 ot->poll= ED_operator_node_active; // XXX we need a special poll which checks that there are selected input/output sockets 02410 02411 /* flags */ 02412 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02413 02414 RNA_def_boolean(ot->srna, "replace", 0, "Replace", "Replace socket connections with the new links"); 02415 } 02416 02417 /* ********************** Cut Link operator ***************** */ 02418 02419 #define LINK_RESOL 12 02420 static int cut_links_intersect(bNodeLink *link, float mcoords[][2], int tot) 02421 { 02422 float coord_array[LINK_RESOL+1][2]; 02423 int i, b; 02424 02425 if(node_link_bezier_points(NULL, NULL, link, coord_array, LINK_RESOL)) { 02426 02427 for(i=0; i<tot-1; i++) 02428 for(b=0; b<LINK_RESOL; b++) 02429 if(isect_line_line_v2(mcoords[i], mcoords[i+1], coord_array[b], coord_array[b+1]) > 0) 02430 return 1; 02431 } 02432 return 0; 02433 } 02434 02435 static int cut_links_exec(bContext *C, wmOperator *op) 02436 { 02437 SpaceNode *snode= CTX_wm_space_node(C); 02438 ARegion *ar= CTX_wm_region(C); 02439 float mcoords[256][2]; 02440 int i= 0; 02441 02442 RNA_BEGIN(op->ptr, itemptr, "path") { 02443 float loc[2]; 02444 02445 RNA_float_get_array(&itemptr, "loc", loc); 02446 UI_view2d_region_to_view(&ar->v2d, (short)loc[0], (short)loc[1], 02447 &mcoords[i][0], &mcoords[i][1]); 02448 i++; 02449 if(i>= 256) break; 02450 } 02451 RNA_END; 02452 02453 if(i>1) { 02454 bNodeLink *link, *next; 02455 02456 ED_preview_kill_jobs(C); 02457 02458 for(link= snode->edittree->links.first; link; link= next) { 02459 next= link->next; 02460 02461 if(cut_links_intersect(link, mcoords, i)) { 02462 snode_tag_changed(snode, link->tonode); 02463 nodeRemLink(snode->edittree, link); 02464 } 02465 } 02466 02467 ntreeSolveOrder(snode->edittree); 02468 node_tree_verify_groups(snode->nodetree); 02469 snode_notify(C, snode); 02470 snode_dag_update(C, snode); 02471 02472 return OPERATOR_FINISHED; 02473 } 02474 02475 return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH; 02476 } 02477 02478 void NODE_OT_links_cut(wmOperatorType *ot) 02479 { 02480 PropertyRNA *prop; 02481 02482 ot->name= "Cut links"; 02483 ot->idname= "NODE_OT_links_cut"; 02484 02485 ot->invoke= WM_gesture_lines_invoke; 02486 ot->modal= WM_gesture_lines_modal; 02487 ot->exec= cut_links_exec; 02488 ot->cancel= WM_gesture_lines_cancel; 02489 02490 ot->poll= ED_operator_node_active; 02491 02492 /* flags */ 02493 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02494 02495 prop= RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE); 02496 RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath); 02497 /* internal */ 02498 RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX); 02499 } 02500 02501 /* ********************* automatic node insert on dragging ******************* */ 02502 02503 /* assumes sockets in list */ 02504 static bNodeSocket *socket_best_match(ListBase *sockets, int type) 02505 { 02506 bNodeSocket *sock; 02507 02508 /* first, match type */ 02509 for(sock= sockets->first; sock; sock= sock->next) 02510 if(!(sock->flag & SOCK_HIDDEN)) 02511 if(type == sock->type) 02512 return sock; 02513 02514 /* then just use first unhidden socket */ 02515 for(sock= sockets->first; sock; sock= sock->next) 02516 if(!(sock->flag & SOCK_HIDDEN)) 02517 return sock; 02518 02519 /* OK, let's unhide proper one */ 02520 for(sock= sockets->first; sock; sock= sock->next) { 02521 if(type == sock->type) { 02522 sock->flag &= ~SOCK_HIDDEN; 02523 return sock; 02524 } 02525 } 02526 02527 /* just the first */ 02528 sock= sockets->first; 02529 sock->flag &= ~SOCK_HIDDEN; 02530 02531 return sockets->first; 02532 } 02533 02534 /* prevent duplicate testing code below */ 02535 static SpaceNode *ed_node_link_conditions(ScrArea *sa, bNode **select) 02536 { 02537 SpaceNode *snode= sa?sa->spacedata.first:NULL; 02538 bNode *node; 02539 bNodeLink *link; 02540 02541 /* no unlucky accidents */ 02542 if(sa==NULL || sa->spacetype!=SPACE_NODE) return NULL; 02543 02544 *select= NULL; 02545 02546 for(node= snode->edittree->nodes.first; node; node= node->next) { 02547 if(node->flag & SELECT) { 02548 if(*select) 02549 break; 02550 else 02551 *select= node; 02552 } 02553 } 02554 /* only one selected */ 02555 if(node || *select==NULL) return NULL; 02556 02557 /* correct node */ 02558 if((*select)->inputs.first==NULL || (*select)->outputs.first==NULL) return NULL; 02559 02560 /* test node for links */ 02561 for(link= snode->edittree->links.first; link; link=link->next) { 02562 if(link->tonode == *select || link->fromnode == *select) 02563 return NULL; 02564 } 02565 02566 return snode; 02567 } 02568 02569 /* assumes link with NODE_LINKFLAG_HILITE set */ 02570 void ED_node_link_insert(ScrArea *sa) 02571 { 02572 bNode *node, *select; 02573 SpaceNode *snode= ed_node_link_conditions(sa, &select); 02574 bNodeLink *link; 02575 bNodeSocket *sockto; 02576 02577 if(snode==NULL) return; 02578 02579 /* get the link */ 02580 for(link= snode->edittree->links.first; link; link=link->next) 02581 if(link->flag & NODE_LINKFLAG_HILITE) 02582 break; 02583 02584 if(link) { 02585 node= link->tonode; 02586 sockto= link->tosock; 02587 02588 link->tonode= select; 02589 link->tosock= socket_best_match(&select->inputs, link->fromsock->type); 02590 link->flag &= ~NODE_LINKFLAG_HILITE; 02591 02592 nodeAddLink(snode->edittree, select, socket_best_match(&select->outputs, sockto->type), node, sockto); 02593 ntreeSolveOrder(snode->edittree); /* needed for pointers */ 02594 snode_tag_changed(snode, select); 02595 ED_node_changed_update(snode->id, select); 02596 } 02597 } 02598 02599 02600 /* test == 0, clear all intersect flags */ 02601 void ED_node_link_intersect_test(ScrArea *sa, int test) 02602 { 02603 bNode *select; 02604 SpaceNode *snode= ed_node_link_conditions(sa, &select); 02605 bNodeLink *link, *selink=NULL; 02606 float mcoords[6][2]; 02607 02608 if(snode==NULL) return; 02609 02610 /* clear flags */ 02611 for(link= snode->edittree->links.first; link; link=link->next) 02612 link->flag &= ~NODE_LINKFLAG_HILITE; 02613 02614 if(test==0) return; 02615 02616 /* okay, there's 1 node, without links, now intersect */ 02617 mcoords[0][0]= select->totr.xmin; 02618 mcoords[0][1]= select->totr.ymin; 02619 mcoords[1][0]= select->totr.xmax; 02620 mcoords[1][1]= select->totr.ymin; 02621 mcoords[2][0]= select->totr.xmax; 02622 mcoords[2][1]= select->totr.ymax; 02623 mcoords[3][0]= select->totr.xmin; 02624 mcoords[3][1]= select->totr.ymax; 02625 mcoords[4][0]= select->totr.xmin; 02626 mcoords[4][1]= select->totr.ymin; 02627 mcoords[5][0]= select->totr.xmax; 02628 mcoords[5][1]= select->totr.ymax; 02629 02630 /* we only tag a single link for intersect now */ 02631 /* idea; use header dist when more? */ 02632 for(link= snode->edittree->links.first; link; link=link->next) { 02633 02634 if(cut_links_intersect(link, mcoords, 5)) { /* intersect code wants edges */ 02635 if(selink) 02636 break; 02637 selink= link; 02638 } 02639 } 02640 02641 if(link==NULL && selink) 02642 selink->flag |= NODE_LINKFLAG_HILITE; 02643 } 02644 02645 02646 /* ******************************** */ 02647 // XXX some code needing updating to operators... 02648 02649 02650 /* goes over all scenes, reads render layers */ 02651 static int node_read_renderlayers_exec(bContext *C, wmOperator *UNUSED(op)) 02652 { 02653 Main *bmain= CTX_data_main(C); 02654 SpaceNode *snode= CTX_wm_space_node(C); 02655 Scene *curscene= CTX_data_scene(C), *scene; 02656 bNode *node; 02657 02658 ED_preview_kill_jobs(C); 02659 02660 /* first tag scenes unread */ 02661 for(scene= bmain->scene.first; scene; scene= scene->id.next) 02662 scene->id.flag |= LIB_DOIT; 02663 02664 for(node= snode->edittree->nodes.first; node; node= node->next) { 02665 if(node->type==CMP_NODE_R_LAYERS) { 02666 ID *id= node->id; 02667 if(id->flag & LIB_DOIT) { 02668 RE_ReadRenderResult(curscene, (Scene *)id); 02669 ntreeCompositTagRender((Scene *)id); 02670 id->flag &= ~LIB_DOIT; 02671 } 02672 } 02673 } 02674 02675 snode_notify(C, snode); 02676 snode_dag_update(C, snode); 02677 02678 return OPERATOR_FINISHED; 02679 } 02680 02681 void NODE_OT_read_renderlayers(wmOperatorType *ot) 02682 { 02683 02684 ot->name= "Read Render Layers"; 02685 ot->idname= "NODE_OT_read_renderlayers"; 02686 02687 ot->exec= node_read_renderlayers_exec; 02688 02689 ot->poll= composite_node_active; 02690 02691 /* flags */ 02692 ot->flag= 0; 02693 } 02694 02695 static int node_read_fullsamplelayers_exec(bContext *C, wmOperator *UNUSED(op)) 02696 { 02697 Main *bmain= CTX_data_main(C); 02698 SpaceNode *snode= CTX_wm_space_node(C); 02699 Scene *curscene= CTX_data_scene(C); 02700 Render *re= RE_NewRender(curscene->id.name); 02701 02702 WM_cursor_wait(1); 02703 02704 RE_MergeFullSample(re, bmain, curscene, snode->nodetree); 02705 snode_notify(C, snode); 02706 snode_dag_update(C, snode); 02707 02708 WM_cursor_wait(0); 02709 return OPERATOR_FINISHED; 02710 } 02711 02712 02713 void NODE_OT_read_fullsamplelayers(wmOperatorType *ot) 02714 { 02715 02716 ot->name= "Read Full Sample Layers"; 02717 ot->idname= "NODE_OT_read_fullsamplelayers"; 02718 02719 ot->exec= node_read_fullsamplelayers_exec; 02720 02721 ot->poll= composite_node_active; 02722 02723 /* flags */ 02724 ot->flag= 0; 02725 } 02726 02727 int node_render_changed_exec(bContext *C, wmOperator *UNUSED(op)) 02728 { 02729 Scene *sce= CTX_data_scene(C); 02730 bNode *node; 02731 02732 for(node= sce->nodetree->nodes.first; node; node= node->next) { 02733 if(node->id==(ID *)sce && node->need_exec) { 02734 break; 02735 } 02736 } 02737 if(node) { 02738 SceneRenderLayer *srl= BLI_findlink(&sce->r.layers, node->custom1); 02739 02740 if(srl) { 02741 PointerRNA op_ptr; 02742 02743 WM_operator_properties_create(&op_ptr, "RENDER_OT_render"); 02744 RNA_string_set(&op_ptr, "layer", srl->name); 02745 RNA_string_set(&op_ptr, "scene", sce->id.name+2); 02746 02747 /* to keep keypositions */ 02748 sce->r.scemode |= R_NO_FRAME_UPDATE; 02749 02750 WM_operator_name_call(C, "RENDER_OT_render", WM_OP_INVOKE_DEFAULT, &op_ptr); 02751 02752 WM_operator_properties_free(&op_ptr); 02753 02754 return OPERATOR_FINISHED; 02755 } 02756 02757 } 02758 return OPERATOR_CANCELLED; 02759 } 02760 02761 void NODE_OT_render_changed(wmOperatorType *ot) 02762 { 02763 02764 ot->name= "Render Changed Layer"; 02765 ot->idname= "NODE_OT_render_changed"; 02766 02767 ot->exec= node_render_changed_exec; 02768 02769 ot->poll= composite_node_active; 02770 02771 /* flags */ 02772 ot->flag= 0; 02773 } 02774 02775 02776 /* ****************** Make Group operator ******************* */ 02777 02778 static int node_group_make_exec(bContext *C, wmOperator *op) 02779 { 02780 SpaceNode *snode = CTX_wm_space_node(C); 02781 bNode *gnode; 02782 02783 if(snode->edittree!=snode->nodetree) { 02784 BKE_report(op->reports, RPT_WARNING, "Can not add a new Group in a Group"); 02785 return OPERATOR_CANCELLED; 02786 } 02787 02788 /* for time being... is too complex to handle */ 02789 if(snode->treetype==NTREE_COMPOSIT) { 02790 for(gnode=snode->nodetree->nodes.first; gnode; gnode= gnode->next) { 02791 if(gnode->flag & SELECT) 02792 if(gnode->type==CMP_NODE_R_LAYERS) 02793 break; 02794 } 02795 02796 if(gnode) { 02797 BKE_report(op->reports, RPT_WARNING, "Can not add RenderLayer in a Group"); 02798 return OPERATOR_CANCELLED; 02799 } 02800 } 02801 02802 ED_preview_kill_jobs(C); 02803 02804 gnode= nodeMakeGroupFromSelected(snode->nodetree); 02805 if(gnode==NULL) { 02806 BKE_report(op->reports, RPT_WARNING, "Can not make Group"); 02807 return OPERATOR_CANCELLED; 02808 } 02809 else { 02810 nodeSetActive(snode->nodetree, gnode); 02811 ntreeSolveOrder(snode->nodetree); 02812 } 02813 02814 snode_notify(C, snode); 02815 snode_dag_update(C, snode); 02816 02817 return OPERATOR_FINISHED; 02818 } 02819 02820 void NODE_OT_group_make(wmOperatorType *ot) 02821 { 02822 /* identifiers */ 02823 ot->name = "Group"; 02824 ot->description = "Make group from selected nodes"; 02825 ot->idname = "NODE_OT_group_make"; 02826 02827 /* api callbacks */ 02828 ot->exec = node_group_make_exec; 02829 ot->poll = ED_operator_node_active; 02830 02831 /* flags */ 02832 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; 02833 } 02834 02835 /* ****************** Hide operator *********************** */ 02836 02837 static void node_flag_toggle_exec(SpaceNode *snode, int toggle_flag) 02838 { 02839 int tot_eq= 0, tot_neq= 0; 02840 bNode *node; 02841 02842 for(node= snode->edittree->nodes.first; node; node= node->next) { 02843 if(node->flag & SELECT) { 02844 02845 if(toggle_flag== NODE_PREVIEW && (node->typeinfo->flag & NODE_PREVIEW)==0) 02846 continue; 02847 02848 if(node->flag & toggle_flag) 02849 tot_eq++; 02850 else 02851 tot_neq++; 02852 } 02853 } 02854 for(node= snode->edittree->nodes.first; node; node= node->next) { 02855 if(node->flag & SELECT) { 02856 02857 if(toggle_flag== NODE_PREVIEW && (node->typeinfo->flag & NODE_PREVIEW)==0) 02858 continue; 02859 02860 if( (tot_eq && tot_neq) || tot_eq==0) 02861 node->flag |= toggle_flag; 02862 else 02863 node->flag &= ~toggle_flag; 02864 } 02865 } 02866 } 02867 02868 static int node_hide_exec(bContext *C, wmOperator *UNUSED(op)) 02869 { 02870 SpaceNode *snode= CTX_wm_space_node(C); 02871 02872 /* sanity checking (poll callback checks this already) */ 02873 if((snode == NULL) || (snode->edittree == NULL)) 02874 return OPERATOR_CANCELLED; 02875 02876 node_flag_toggle_exec(snode, NODE_HIDDEN); 02877 02878 snode_notify(C, snode); 02879 02880 return OPERATOR_FINISHED; 02881 } 02882 02883 void NODE_OT_hide_toggle(wmOperatorType *ot) 02884 { 02885 /* identifiers */ 02886 ot->name= "Hide"; 02887 ot->description= "Toggle hiding of selected nodes"; 02888 ot->idname= "NODE_OT_hide_toggle"; 02889 02890 /* callbacks */ 02891 ot->exec= node_hide_exec; 02892 ot->poll= ED_operator_node_active; 02893 02894 /* flags */ 02895 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02896 } 02897 02898 static int node_preview_exec(bContext *C, wmOperator *UNUSED(op)) 02899 { 02900 SpaceNode *snode= CTX_wm_space_node(C); 02901 02902 /* sanity checking (poll callback checks this already) */ 02903 if((snode == NULL) || (snode->edittree == NULL)) 02904 return OPERATOR_CANCELLED; 02905 02906 ED_preview_kill_jobs(C); 02907 02908 node_flag_toggle_exec(snode, NODE_PREVIEW); 02909 02910 snode_notify(C, snode); 02911 02912 return OPERATOR_FINISHED; 02913 } 02914 02915 void NODE_OT_preview_toggle(wmOperatorType *ot) 02916 { 02917 /* identifiers */ 02918 ot->name= "Toggle Node Preview"; 02919 ot->description= "Toggle preview display for selected nodes"; 02920 ot->idname= "NODE_OT_preview_toggle"; 02921 02922 /* callbacks */ 02923 ot->exec= node_preview_exec; 02924 ot->poll= ED_operator_node_active; 02925 02926 /* flags */ 02927 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02928 } 02929 02930 static int node_socket_toggle_exec(bContext *C, wmOperator *UNUSED(op)) 02931 { 02932 SpaceNode *snode= CTX_wm_space_node(C); 02933 bNode *node; 02934 int hidden= 0; 02935 02936 /* sanity checking (poll callback checks this already) */ 02937 if((snode == NULL) || (snode->edittree == NULL)) 02938 return OPERATOR_CANCELLED; 02939 02940 ED_preview_kill_jobs(C); 02941 02942 for(node= snode->edittree->nodes.first; node; node= node->next) { 02943 if(node->flag & SELECT) { 02944 if(node_has_hidden_sockets(node)) { 02945 hidden= 1; 02946 break; 02947 } 02948 } 02949 } 02950 02951 for(node= snode->edittree->nodes.first; node; node= node->next) { 02952 if(node->flag & SELECT) { 02953 node_set_hidden_sockets(snode, node, !hidden); 02954 } 02955 } 02956 02957 node_tree_verify_groups(snode->nodetree); 02958 02959 snode_notify(C, snode); 02960 02961 return OPERATOR_FINISHED; 02962 } 02963 02964 void NODE_OT_hide_socket_toggle(wmOperatorType *ot) 02965 { 02966 /* identifiers */ 02967 ot->name= "Toggle Hidden Node Sockets"; 02968 ot->description= "Toggle unused node socket display"; 02969 ot->idname= "NODE_OT_hide_socket_toggle"; 02970 02971 /* callbacks */ 02972 ot->exec= node_socket_toggle_exec; 02973 ot->poll= ED_operator_node_active; 02974 02975 /* flags */ 02976 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02977 } 02978 02979 /* ****************** Mute operator *********************** */ 02980 02981 static int node_mute_exec(bContext *C, wmOperator *UNUSED(op)) 02982 { 02983 SpaceNode *snode= CTX_wm_space_node(C); 02984 bNode *node; 02985 02986 /* no disabling inside of groups */ 02987 if(node_tree_get_editgroup(snode->nodetree)) 02988 return OPERATOR_CANCELLED; 02989 02990 ED_preview_kill_jobs(C); 02991 02992 for(node= snode->edittree->nodes.first; node; node= node->next) { 02993 if(node->flag & SELECT) { 02994 if(node->inputs.first && node->outputs.first) { 02995 node->flag ^= NODE_MUTED; 02996 snode_tag_changed(snode, node); 02997 } 02998 } 02999 } 03000 03001 snode_notify(C, snode); 03002 snode_dag_update(C, snode); 03003 03004 return OPERATOR_FINISHED; 03005 } 03006 03007 void NODE_OT_mute_toggle(wmOperatorType *ot) 03008 { 03009 /* identifiers */ 03010 ot->name= "Toggle Node Mute"; 03011 ot->description= "Toggle muting of the nodes"; 03012 ot->idname= "NODE_OT_mute_toggle"; 03013 03014 /* callbacks */ 03015 ot->exec= node_mute_exec; 03016 ot->poll= ED_operator_node_active; 03017 03018 /* flags */ 03019 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 03020 } 03021 03022 /* ****************** Delete operator ******************* */ 03023 03024 static int node_delete_exec(bContext *C, wmOperator *UNUSED(op)) 03025 { 03026 SpaceNode *snode= CTX_wm_space_node(C); 03027 bNode *node, *next; 03028 03029 ED_preview_kill_jobs(C); 03030 03031 for(node= snode->edittree->nodes.first; node; node= next) { 03032 next= node->next; 03033 if(node->flag & SELECT) { 03034 /* check id user here, nodeFreeNode is called for free dbase too */ 03035 if(node->id) 03036 node->id->us--; 03037 nodeFreeNode(snode->edittree, node); 03038 } 03039 } 03040 03041 node_tree_verify_groups(snode->nodetree); 03042 03043 snode_notify(C, snode); 03044 snode_dag_update(C, snode); 03045 03046 return OPERATOR_FINISHED; 03047 } 03048 03049 void NODE_OT_delete(wmOperatorType *ot) 03050 { 03051 /* identifiers */ 03052 ot->name= "Delete"; 03053 ot->description = "Delete selected nodes"; 03054 ot->idname= "NODE_OT_delete"; 03055 03056 /* api callbacks */ 03057 ot->exec= node_delete_exec; 03058 ot->poll= ED_operator_node_active; 03059 03060 /* flags */ 03061 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 03062 } 03063 03064 /* ****************** Delete with reconnect ******************* */ 03065 03066 /* note: in cmp_util.c is similar code, for node_compo_pass_on() */ 03067 /* used for disabling node (similar code in node_draw.c for disable line) */ 03068 static void node_delete_reconnect(bNodeTree* tree, bNode* node) 03069 { 03070 bNodeLink *link, *next; 03071 bNodeSocket *valsocket= NULL, *colsocket= NULL, *vecsocket= NULL; 03072 bNodeSocket *deliveringvalsocket= NULL, *deliveringcolsocket= NULL, *deliveringvecsocket= NULL; 03073 bNode *deliveringvalnode= NULL, *deliveringcolnode= NULL, *deliveringvecnode= NULL; 03074 bNodeSocket *sock; 03075 03076 /* test the inputs */ 03077 for(sock= node->inputs.first; sock; sock= sock->next) { 03078 int type = sock->type; 03079 if(type==SOCK_VALUE && valsocket==NULL) valsocket = sock; 03080 if(type==SOCK_VECTOR && vecsocket==NULL) vecsocket = sock; 03081 if(type==SOCK_RGBA && colsocket==NULL) colsocket = sock; 03082 } 03083 // we now have the input sockets for the 'data types' 03084 // now find the output sockets (and nodes) in the tree that delivers data to these input sockets 03085 for(link= tree->links.first; link; link=link->next) { 03086 if (valsocket != NULL) { 03087 if (link->tosock == valsocket) { 03088 deliveringvalnode = link->fromnode; 03089 deliveringvalsocket = link->fromsock; 03090 } 03091 } 03092 if (vecsocket != NULL) { 03093 if (link->tosock == vecsocket) { 03094 deliveringvecnode = link->fromnode; 03095 deliveringvecsocket = link->fromsock; 03096 } 03097 } 03098 if (colsocket != NULL) { 03099 if (link->tosock == colsocket) { 03100 deliveringcolnode = link->fromnode; 03101 deliveringcolsocket = link->fromsock; 03102 } 03103 } 03104 } 03105 // we now have the sockets+nodes that fill the inputsockets be aware for group nodes these can be NULL 03106 // now make the links for all outputlinks of the node to be reconnected 03107 for(link= tree->links.first; link; link=next) { 03108 next= link->next; 03109 if (link->fromnode == node) { 03110 sock = link->fromsock; 03111 switch(sock->type) { 03112 case SOCK_VALUE: 03113 if (deliveringvalsocket) { 03114 link->fromnode = deliveringvalnode; 03115 link->fromsock = deliveringvalsocket; 03116 } 03117 break; 03118 case SOCK_VECTOR: 03119 if (deliveringvecsocket) { 03120 link->fromnode = deliveringvecnode; 03121 link->fromsock = deliveringvecsocket; 03122 } 03123 break; 03124 case SOCK_RGBA: 03125 if (deliveringcolsocket) { 03126 link->fromnode = deliveringcolnode; 03127 link->fromsock = deliveringcolsocket; 03128 } 03129 break; 03130 } 03131 } 03132 } 03133 if(node->id) 03134 node->id->us--; 03135 nodeFreeNode(tree, node); 03136 03137 } 03138 03139 static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op)) 03140 { 03141 SpaceNode *snode= CTX_wm_space_node(C); 03142 bNode *node, *next; 03143 03144 ED_preview_kill_jobs(C); 03145 03146 for(node= snode->edittree->nodes.first; node; node= next) { 03147 next= node->next; 03148 if(node->flag & SELECT) { 03149 node_delete_reconnect(snode->edittree, node); 03150 } 03151 } 03152 03153 node_tree_verify_groups(snode->nodetree); 03154 03155 snode_notify(C, snode); 03156 snode_dag_update(C, snode); 03157 03158 return OPERATOR_FINISHED; 03159 } 03160 03161 void NODE_OT_delete_reconnect(wmOperatorType *ot) 03162 { 03163 /* identifiers */ 03164 ot->name= "Delete with reconnect"; 03165 ot->description = "Delete nodes; will reconnect nodes as if deletion was muted"; 03166 ot->idname= "NODE_OT_delete_reconnect"; 03167 03168 /* api callbacks */ 03169 ot->exec= node_delete_reconnect_exec; 03170 ot->poll= ED_operator_node_active; 03171 03172 /* flags */ 03173 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 03174 } 03175 03176 /* ****************** Show Cyclic Dependencies Operator ******************* */ 03177 03178 static int node_show_cycles_exec(bContext *C, wmOperator *UNUSED(op)) 03179 { 03180 SpaceNode *snode= CTX_wm_space_node(C); 03181 03182 /* this is just a wrapper around this call... */ 03183 ntreeSolveOrder(snode->edittree); 03184 snode_notify(C, snode); 03185 03186 return OPERATOR_FINISHED; 03187 } 03188 03189 void NODE_OT_show_cyclic_dependencies(wmOperatorType *ot) 03190 { 03191 /* identifiers */ 03192 ot->name= "Show Cyclic Dependencies"; 03193 ot->description= "Sort the nodes and show the cyclic dependencies between the nodes"; 03194 ot->idname= "NODE_OT_show_cyclic_dependencies"; 03195 03196 /* callbacks */ 03197 ot->exec= node_show_cycles_exec; 03198 ot->poll= ED_operator_node_active; 03199 03200 /* flags */ 03201 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 03202 } 03203 03204 /* ****************** Add File Node Operator ******************* */ 03205 03206 static int node_add_file_exec(bContext *C, wmOperator *op) 03207 { 03208 Scene *scene= CTX_data_scene(C); 03209 SpaceNode *snode= CTX_wm_space_node(C); 03210 bNode *node; 03211 Image *ima= NULL; 03212 int ntype=0; 03213 03214 /* check input variables */ 03215 if (RNA_property_is_set(op->ptr, "filepath")) 03216 { 03217 char path[FILE_MAX]; 03218 RNA_string_get(op->ptr, "filepath", path); 03219 03220 errno= 0; 03221 03222 ima= BKE_add_image_file(path); 03223 03224 if(!ima) { 03225 BKE_reportf(op->reports, RPT_ERROR, "Can't read: \"%s\", %s.", path, errno ? strerror(errno) : "Unsupported image format"); 03226 return OPERATOR_CANCELLED; 03227 } 03228 } 03229 else if(RNA_property_is_set(op->ptr, "name")) 03230 { 03231 char name[32]; 03232 RNA_string_get(op->ptr, "name", name); 03233 ima= (Image *)find_id("IM", name); 03234 03235 if(!ima) { 03236 BKE_reportf(op->reports, RPT_ERROR, "Image named \"%s\", not found.", name); 03237 return OPERATOR_CANCELLED; 03238 } 03239 } 03240 03241 node_deselectall(snode); 03242 03243 if (snode->nodetree->type==NTREE_COMPOSIT) 03244 ntype = CMP_NODE_IMAGE; 03245 03246 ED_preview_kill_jobs(C); 03247 03248 node = node_add_node(snode, scene, ntype, snode->mx, snode->my); 03249 03250 if (!node) { 03251 BKE_report(op->reports, RPT_WARNING, "Could not add an image node."); 03252 return OPERATOR_CANCELLED; 03253 } 03254 03255 node->id = (ID *)ima; 03256 03257 snode_notify(C, snode); 03258 snode_dag_update(C, snode); 03259 03260 return OPERATOR_FINISHED; 03261 } 03262 03263 static int node_add_file_invoke(bContext *C, wmOperator *op, wmEvent *event) 03264 { 03265 ARegion *ar= CTX_wm_region(C); 03266 SpaceNode *snode= CTX_wm_space_node(C); 03267 03268 /* convert mouse coordinates to v2d space */ 03269 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], 03270 &snode->mx, &snode->my); 03271 03272 if (RNA_property_is_set(op->ptr, "filepath") || RNA_property_is_set(op->ptr, "name")) 03273 return node_add_file_exec(C, op); 03274 else 03275 return WM_operator_filesel(C, op, event); 03276 } 03277 03278 void NODE_OT_add_file(wmOperatorType *ot) 03279 { 03280 /* identifiers */ 03281 ot->name= "Add File Node"; 03282 ot->description= "Add a file node to the current node editor"; 03283 ot->idname= "NODE_OT_add_file"; 03284 03285 /* callbacks */ 03286 ot->exec= node_add_file_exec; 03287 ot->invoke= node_add_file_invoke; 03288 ot->poll= composite_node_active; 03289 03290 /* flags */ 03291 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 03292 03293 WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH); //XXX TODO, relative_path 03294 RNA_def_string(ot->srna, "name", "Image", 24, "Name", "Datablock name to assign."); 03295 } 03296 03297 03298