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