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) 2008 Blender Foundation. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * Contributor(s): Nathan Letwory 00023 * 00024 * ***** END GPL LICENSE BLOCK ***** 00025 */ 00026 00032 #include <math.h> 00033 #include <stdio.h> 00034 #include <string.h> 00035 00036 #include "MEM_guardedalloc.h" 00037 00038 #include "DNA_node_types.h" 00039 #include "DNA_lamp_types.h" 00040 #include "DNA_material_types.h" 00041 #include "DNA_object_types.h" 00042 #include "DNA_scene_types.h" 00043 #include "DNA_space_types.h" 00044 #include "DNA_screen_types.h" 00045 #include "DNA_world_types.h" 00046 00047 #include "BLI_math.h" 00048 #include "BLI_blenlib.h" 00049 #include "BLI_threads.h" 00050 #include "BLI_utildefines.h" 00051 00052 #include "BKE_context.h" 00053 #include "BKE_depsgraph.h" 00054 #include "BKE_main.h" 00055 #include "BKE_node.h" 00056 00057 #include "BIF_gl.h" 00058 #include "BIF_glutil.h" 00059 00060 #include "WM_api.h" 00061 #include "WM_types.h" 00062 00063 #include "ED_node.h" 00064 #include "ED_gpencil.h" 00065 00066 #include "UI_interface.h" 00067 #include "UI_interface_icons.h" 00068 #include "UI_resources.h" 00069 #include "UI_view2d.h" 00070 00071 #include "RNA_access.h" 00072 00073 #include "NOD_composite.h" 00074 #include "NOD_shader.h" 00075 00076 #include "intern/node_util.h" 00077 00078 #include "node_intern.h" 00079 00080 /* width of socket columns in group display */ 00081 #define NODE_GROUP_FRAME 120 00082 00083 // XXX interface.h 00084 extern void ui_dropshadow(rctf *rct, float radius, float aspect, int select); 00085 00086 /* XXX update functions for node editor are a mess, needs a clear concept */ 00087 void ED_node_tree_update(SpaceNode *snode, Scene *scene) 00088 { 00089 snode_set_context(snode, scene); 00090 00091 if(snode->nodetree && snode->nodetree->id.us==0) 00092 snode->nodetree->id.us= 1; 00093 } 00094 00095 void ED_node_changed_update(ID *id, bNode *node) 00096 { 00097 bNodeTree *nodetree, *edittree; 00098 int treetype; 00099 00100 node_tree_from_ID(id, &nodetree, &edittree, &treetype); 00101 00102 if(treetype==NTREE_SHADER) { 00103 DAG_id_tag_update(id, 0); 00104 00105 if(GS(id->name) == ID_MA) 00106 WM_main_add_notifier(NC_MATERIAL|ND_SHADING_DRAW, id); 00107 else if(GS(id->name) == ID_LA) 00108 WM_main_add_notifier(NC_LAMP|ND_LIGHTING_DRAW, id); 00109 else if(GS(id->name) == ID_WO) 00110 WM_main_add_notifier(NC_WORLD|ND_WORLD_DRAW, id); 00111 } 00112 else if(treetype==NTREE_COMPOSIT) { 00113 if(node) 00114 nodeUpdate(edittree, node); 00115 /* don't use NodeTagIDChanged, it gives far too many recomposites for image, scene layers, ... */ 00116 00117 node= node_tree_get_editgroup(nodetree); 00118 if(node) 00119 nodeUpdateID(nodetree, node->id); 00120 00121 WM_main_add_notifier(NC_SCENE|ND_NODES, id); 00122 } 00123 else if(treetype==NTREE_TEXTURE) { 00124 DAG_id_tag_update(id, 0); 00125 WM_main_add_notifier(NC_TEXTURE|ND_NODES, id); 00126 } 00127 } 00128 00129 static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup) 00130 { 00131 bNode *node; 00132 00133 if(ntree == lookup) 00134 return 1; 00135 00136 for(node=ntree->nodes.first; node; node=node->next) 00137 if(node->type == NODE_GROUP && node->id) 00138 if(has_nodetree((bNodeTree*)node->id, lookup)) 00139 return 1; 00140 00141 return 0; 00142 } 00143 00144 typedef struct NodeUpdateCalldata { 00145 bNodeTree *ntree; 00146 bNode *node; 00147 } NodeUpdateCalldata; 00148 static void node_generic_update_cb(void *calldata, ID *owner_id, bNodeTree *ntree) 00149 { 00150 NodeUpdateCalldata *cd= (NodeUpdateCalldata*)calldata; 00151 /* check if nodetree uses the group stored in calldata */ 00152 if (has_nodetree(ntree, cd->ntree)) 00153 ED_node_changed_update(owner_id, cd->node); 00154 } 00155 void ED_node_generic_update(Main *bmain, bNodeTree *ntree, bNode *node) 00156 { 00157 bNodeTreeType *tti= ntreeGetType(ntree->type); 00158 NodeUpdateCalldata cd; 00159 cd.ntree = ntree; 00160 cd.node = node; 00161 /* look through all datablocks, to support groups */ 00162 tti->foreach_nodetree(bmain, &cd, node_generic_update_cb); 00163 00164 if(ntree->type == NTREE_TEXTURE) 00165 ntreeTexCheckCyclics(ntree); 00166 } 00167 00168 static void do_node_internal_buttons(bContext *C, void *node_v, int event) 00169 { 00170 if(event==B_NODE_EXEC) { 00171 SpaceNode *snode= CTX_wm_space_node(C); 00172 if(snode && snode->id) 00173 ED_node_changed_update(snode->id, node_v); 00174 } 00175 } 00176 00177 00178 static void node_scaling_widget(int color_id, float aspect, float xmin, float ymin, float xmax, float ymax) 00179 { 00180 float dx; 00181 float dy; 00182 00183 dx= 0.5f*(xmax-xmin); 00184 dy= 0.5f*(ymax-ymin); 00185 00186 UI_ThemeColorShade(color_id, +30); 00187 fdrawline(xmin, ymin, xmax, ymax); 00188 fdrawline(xmin+dx, ymin, xmax, ymax-dy); 00189 00190 UI_ThemeColorShade(color_id, -10); 00191 fdrawline(xmin, ymin+aspect, xmax, ymax+aspect); 00192 fdrawline(xmin+dx, ymin+aspect, xmax, ymax-dy+aspect); 00193 } 00194 00195 static void node_uiblocks_init(const bContext *C, bNodeTree *ntree) 00196 { 00197 bNode *node; 00198 char uiblockstr[32]; 00199 00200 /* add node uiBlocks in drawing order - prevents events going to overlapping nodes */ 00201 00202 for (node= ntree->nodes.first; node; node= node->next) { 00203 /* ui block */ 00204 BLI_snprintf(uiblockstr, sizeof(uiblockstr), "node buttons %p", (void *)node); 00205 node->block= uiBeginBlock(C, CTX_wm_region(C), uiblockstr, UI_EMBOSS); 00206 uiBlockSetHandleFunc(node->block, do_node_internal_buttons, node); 00207 00208 /* this cancels events for background nodes */ 00209 uiBlockSetFlag(node->block, UI_BLOCK_CLIP_EVENTS); 00210 } 00211 } 00212 00213 /* based on settings in node, sets drawing rect info. each redraw! */ 00214 static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) 00215 { 00216 uiLayout *layout; 00217 PointerRNA ptr; 00218 bNodeSocket *nsock; 00219 float locx, locy; 00220 float dy; 00221 int buty; 00222 00223 /* get "global" coords */ 00224 nodeSpaceCoords(node, &locx, &locy); 00225 dy= locy; 00226 00227 /* header */ 00228 dy-= NODE_DY; 00229 00230 /* little bit space in top */ 00231 if(node->outputs.first) 00232 dy-= NODE_DYS/2; 00233 00234 /* output sockets */ 00235 for(nsock= node->outputs.first; nsock; nsock= nsock->next) { 00236 if(!nodeSocketIsHidden(nsock)) { 00237 nsock->locx= locx + node->width; 00238 nsock->locy= dy - NODE_DYS; 00239 dy-= NODE_DY; 00240 } 00241 } 00242 00243 node->prvr.xmin= locx + NODE_DYS; 00244 node->prvr.xmax= locx + node->width- NODE_DYS; 00245 00246 /* preview rect? */ 00247 if(node->flag & NODE_PREVIEW) { 00248 /* only recalculate size when there's a preview actually, otherwise we use stored result */ 00249 BLI_lock_thread(LOCK_PREVIEW); 00250 00251 if(node->preview && node->preview->rect) { 00252 float aspect= 1.0f; 00253 00254 if(node->preview && node->preview->xsize && node->preview->ysize) 00255 aspect= (float)node->preview->ysize/(float)node->preview->xsize; 00256 00257 dy-= NODE_DYS/2; 00258 node->prvr.ymax= dy; 00259 00260 if(aspect <= 1.0f) 00261 node->prvr.ymin= dy - aspect*(node->width-NODE_DY); 00262 else { 00263 float dx= (node->width - NODE_DYS) - (node->width- NODE_DYS)/aspect; /* width correction of image */ 00264 00265 node->prvr.ymin= dy - (node->width-NODE_DY); 00266 00267 node->prvr.xmin+= 0.5f*dx; 00268 node->prvr.xmax-= 0.5f*dx; 00269 } 00270 00271 dy= node->prvr.ymin - NODE_DYS/2; 00272 00273 /* make sure that maximums are bigger or equal to minimums */ 00274 if(node->prvr.xmax < node->prvr.xmin) SWAP(float, node->prvr.xmax, node->prvr.xmin); 00275 if(node->prvr.ymax < node->prvr.ymin) SWAP(float, node->prvr.ymax, node->prvr.ymin); 00276 } 00277 else { 00278 float oldh= node->prvr.ymax - node->prvr.ymin; 00279 if(oldh==0.0f) 00280 oldh= 0.6f*node->width-NODE_DY; 00281 dy-= NODE_DYS/2; 00282 node->prvr.ymax= dy; 00283 node->prvr.ymin= dy - oldh; 00284 dy= node->prvr.ymin - NODE_DYS/2; 00285 } 00286 00287 BLI_unlock_thread(LOCK_PREVIEW); 00288 } 00289 00290 /* buttons rect? */ 00291 if((node->flag & NODE_OPTIONS) && node->typeinfo->uifunc) { 00292 dy-= NODE_DYS/2; 00293 00294 /* set this for uifunc() that don't use layout engine yet */ 00295 node->butr.xmin= 0; 00296 node->butr.xmax= node->width - 2*NODE_DYS; 00297 node->butr.ymin= 0; 00298 node->butr.ymax= 0; 00299 00300 RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr); 00301 00302 layout= uiBlockLayout(node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 00303 locx+NODE_DYS, dy, node->butr.xmax, NODE_DY, UI_GetStyle()); 00304 00305 node->typeinfo->uifunc(layout, (bContext *)C, &ptr); 00306 00307 uiBlockEndAlign(node->block); 00308 uiBlockLayoutResolve(node->block, NULL, &buty); 00309 00310 dy= buty - NODE_DYS/2; 00311 } 00312 00313 /* input sockets */ 00314 for(nsock= node->inputs.first; nsock; nsock= nsock->next) { 00315 if(!nodeSocketIsHidden(nsock)) { 00316 nsock->locx= locx; 00317 nsock->locy= dy - NODE_DYS; 00318 dy-= NODE_DY; 00319 } 00320 } 00321 00322 /* little bit space in end */ 00323 if(node->inputs.first || (node->flag & (NODE_OPTIONS|NODE_PREVIEW))==0 ) 00324 dy-= NODE_DYS/2; 00325 00326 node->totr.xmin= locx; 00327 node->totr.xmax= locx + node->width; 00328 node->totr.ymax= locy; 00329 node->totr.ymin= MIN2(dy, locy-2*NODE_DY); 00330 00331 /* Set the block bounds to clip mouse events from underlying nodes. 00332 * Add a margin for sockets on each side. 00333 */ 00334 uiExplicitBoundsBlock(node->block, 00335 node->totr.xmin - NODE_SOCKSIZE, 00336 node->totr.ymin, 00337 node->totr.xmax + NODE_SOCKSIZE, 00338 node->totr.ymax); 00339 } 00340 00341 /* based on settings in node, sets drawing rect info. each redraw! */ 00342 static void node_update_hidden(bNode *node) 00343 { 00344 bNodeSocket *nsock; 00345 float locx, locy; 00346 float rad, drad, hiddenrad= HIDDEN_RAD; 00347 int totin=0, totout=0, tot; 00348 00349 /* get "global" coords */ 00350 nodeSpaceCoords(node, &locx, &locy); 00351 00352 /* calculate minimal radius */ 00353 for(nsock= node->inputs.first; nsock; nsock= nsock->next) 00354 if(!nodeSocketIsHidden(nsock)) 00355 totin++; 00356 for(nsock= node->outputs.first; nsock; nsock= nsock->next) 00357 if(!nodeSocketIsHidden(nsock)) 00358 totout++; 00359 00360 tot= MAX2(totin, totout); 00361 if(tot>4) { 00362 hiddenrad += 5.0f*(float)(tot-4); 00363 } 00364 00365 node->totr.xmin= locx; 00366 node->totr.xmax= locx + 3*hiddenrad + node->miniwidth; 00367 node->totr.ymax= locy + (hiddenrad - 0.5f*NODE_DY); 00368 node->totr.ymin= node->totr.ymax - 2*hiddenrad; 00369 00370 /* output sockets */ 00371 rad=drad= (float)M_PI/(1.0f + (float)totout); 00372 00373 for(nsock= node->outputs.first; nsock; nsock= nsock->next) { 00374 if(!nodeSocketIsHidden(nsock)) { 00375 nsock->locx= node->totr.xmax - hiddenrad + (float)sin(rad)*hiddenrad; 00376 nsock->locy= node->totr.ymin + hiddenrad + (float)cos(rad)*hiddenrad; 00377 rad+= drad; 00378 } 00379 } 00380 00381 /* input sockets */ 00382 rad=drad= - (float)M_PI/(1.0f + (float)totin); 00383 00384 for(nsock= node->inputs.first; nsock; nsock= nsock->next) { 00385 if(!nodeSocketIsHidden(nsock)) { 00386 nsock->locx= node->totr.xmin + hiddenrad + (float)sin(rad)*hiddenrad; 00387 nsock->locy= node->totr.ymin + hiddenrad + (float)cos(rad)*hiddenrad; 00388 rad+= drad; 00389 } 00390 } 00391 00392 /* Set the block bounds to clip mouse events from underlying nodes. 00393 * Add a margin for sockets on each side. 00394 */ 00395 uiExplicitBoundsBlock(node->block, 00396 node->totr.xmin - NODE_SOCKSIZE, 00397 node->totr.ymin, 00398 node->totr.xmax + NODE_SOCKSIZE, 00399 node->totr.ymax); 00400 } 00401 00402 void node_update_default(const bContext *C, bNodeTree *ntree, bNode *node) 00403 { 00404 if(node->flag & NODE_HIDDEN) 00405 node_update_hidden(node); 00406 else 00407 node_update_basis(C, ntree, node); 00408 } 00409 00410 static int node_get_colorid(bNode *node) 00411 { 00412 if(node->typeinfo->nclass==NODE_CLASS_INPUT) 00413 return TH_NODE_IN_OUT; 00414 if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) { 00415 if(node->flag & NODE_DO_OUTPUT) 00416 return TH_NODE_IN_OUT; 00417 else 00418 return TH_NODE; 00419 } 00420 if(node->typeinfo->nclass==NODE_CLASS_CONVERTOR) 00421 return TH_NODE_CONVERTOR; 00422 if(ELEM3(node->typeinfo->nclass, NODE_CLASS_OP_COLOR, NODE_CLASS_OP_VECTOR, NODE_CLASS_OP_FILTER)) 00423 return TH_NODE_OPERATOR; 00424 if(node->typeinfo->nclass==NODE_CLASS_GROUP) 00425 return TH_NODE_GROUP; 00426 return TH_NODE; 00427 } 00428 00429 /* note: in cmp_util.c is similar code, for node_compo_pass_on() 00430 * the same goes for shader and texture nodes. */ 00431 /* note: in node_edit.c is similar code, for untangle node */ 00432 static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node) 00433 { 00434 ListBase links; 00435 LinkInOutsMuteNode *lnk; 00436 bNodeLink link= {NULL}; 00437 int i; 00438 00439 if(node->typeinfo->mutelinksfunc == NULL) 00440 return; 00441 00442 /* Get default muting links (as bNodeSocket pointers). */ 00443 links = node->typeinfo->mutelinksfunc(snode->edittree, node, NULL, NULL, NULL, NULL); 00444 00445 glEnable(GL_BLEND); 00446 glEnable(GL_LINE_SMOOTH); 00447 00448 link.fromnode = link.tonode = node; 00449 for(lnk = links.first; lnk; lnk = lnk->next) { 00450 for(i = 0; i < lnk->num_outs; i++) { 00451 link.fromsock = (bNodeSocket*)(lnk->in); 00452 link.tosock = (bNodeSocket*)(lnk->outs)+i; 00453 node_draw_link_bezier(v2d, snode, &link, TH_REDALERT, 0, TH_WIRE, 0, TH_WIRE); 00454 } 00455 /* If num_outs > 1, lnk->outs was an allocated table of pointers... */ 00456 if(i > 1) 00457 MEM_freeN(lnk->outs); 00458 } 00459 00460 glDisable(GL_BLEND); 00461 glDisable(GL_LINE_SMOOTH); 00462 00463 BLI_freelistN(&links); 00464 } 00465 00466 /* this might have some more generic use */ 00467 static void node_circle_draw(float x, float y, float size, char *col) 00468 { 00469 /* 16 values of sin function */ 00470 static float si[16] = { 00471 0.00000000f, 0.39435585f,0.72479278f,0.93775213f, 00472 0.99871650f,0.89780453f,0.65137248f,0.29936312f, 00473 -0.10116832f,-0.48530196f,-0.79077573f,-0.96807711f, 00474 -0.98846832f,-0.84864425f,-0.57126821f,-0.20129852f 00475 }; 00476 /* 16 values of cos function */ 00477 static float co[16] ={ 00478 1.00000000f,0.91895781f,0.68896691f,0.34730525f, 00479 -0.05064916f,-0.44039415f,-0.75875812f,-0.95413925f, 00480 -0.99486932f,-0.87434661f,-0.61210598f,-0.25065253f, 00481 0.15142777f,0.52896401f,0.82076344f,0.97952994f, 00482 }; 00483 int a; 00484 00485 glColor3ub(col[0], col[1], col[2]); 00486 00487 glBegin(GL_POLYGON); 00488 for(a=0; a<16; a++) 00489 glVertex2f(x+size*si[a], y+size*co[a]); 00490 glEnd(); 00491 00492 glColor4ub(0, 0, 0, 150); 00493 glEnable(GL_BLEND); 00494 glEnable( GL_LINE_SMOOTH ); 00495 glBegin(GL_LINE_LOOP); 00496 for(a=0; a<16; a++) 00497 glVertex2f(x+size*si[a], y+size*co[a]); 00498 glEnd(); 00499 glDisable( GL_LINE_SMOOTH ); 00500 glDisable(GL_BLEND); 00501 } 00502 00503 void node_socket_circle_draw(bNodeTree *UNUSED(ntree), bNodeSocket *sock, float size) 00504 { 00505 bNodeSocketType *stype = ntreeGetSocketType(sock->type); 00506 node_circle_draw(sock->locx, sock->locy, size, stype->ui_color); 00507 } 00508 00509 /* ************** Socket callbacks *********** */ 00510 00511 /* not a callback */ 00512 static void node_draw_preview(bNodePreview *preview, rctf *prv) 00513 { 00514 float xscale= (prv->xmax-prv->xmin)/((float)preview->xsize); 00515 float yscale= (prv->ymax-prv->ymin)/((float)preview->ysize); 00516 float tile= (prv->xmax - prv->xmin) / 10.0f; 00517 float x, y; 00518 00519 /* draw checkerboard backdrop to show alpha */ 00520 glColor3ub(120, 120, 120); 00521 glRectf(prv->xmin, prv->ymin, prv->xmax, prv->ymax); 00522 glColor3ub(160, 160, 160); 00523 00524 for(y=prv->ymin; y<prv->ymax; y+=tile*2) { 00525 for(x=prv->xmin; x<prv->xmax; x+=tile*2) { 00526 float tilex= tile, tiley= tile; 00527 00528 if(x+tile > prv->xmax) 00529 tilex= prv->xmax-x; 00530 if(y+tile > prv->ymax) 00531 tiley= prv->ymax-y; 00532 00533 glRectf(x, y, x + tilex, y + tiley); 00534 } 00535 } 00536 for(y=prv->ymin+tile; y<prv->ymax; y+=tile*2) { 00537 for(x=prv->xmin+tile; x<prv->xmax; x+=tile*2) { 00538 float tilex= tile, tiley= tile; 00539 00540 if(x+tile > prv->xmax) 00541 tilex= prv->xmax-x; 00542 if(y+tile > prv->ymax) 00543 tiley= prv->ymax-y; 00544 00545 glRectf(x, y, x + tilex, y + tiley); 00546 } 00547 } 00548 00549 glPixelZoom(xscale, yscale); 00550 00551 glEnable(GL_BLEND); 00552 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); /* premul graphics */ 00553 00554 glColor4f(1.0, 1.0, 1.0, 1.0); 00555 glaDrawPixelsTex(prv->xmin, prv->ymin, preview->xsize, preview->ysize, GL_UNSIGNED_BYTE, preview->rect); 00556 00557 glDisable(GL_BLEND); 00558 glPixelZoom(1.0f, 1.0f); 00559 00560 UI_ThemeColorShadeAlpha(TH_BACK, -15, +100); 00561 fdrawbox(prv->xmin, prv->ymin, prv->xmax, prv->ymax); 00562 00563 } 00564 00565 /* common handle function for operator buttons that need to select the node first */ 00566 static void node_toggle_button_cb(struct bContext *C, void *node_argv, void *op_argv) 00567 { 00568 bNode *node = (bNode*)node_argv; 00569 const char *opname = (const char *)op_argv; 00570 00571 /* select & activate only the button's node */ 00572 node_select_single(C, node); 00573 00574 WM_operator_name_call(C, opname, WM_OP_INVOKE_DEFAULT, NULL); 00575 } 00576 00577 static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node) 00578 { 00579 bNodeSocket *sock; 00580 rctf *rct= &node->totr; 00581 float iconofs; 00582 /* float socket_size= NODE_SOCKSIZE*U.dpi/72; */ /* UNUSED */ 00583 float iconbutw= 0.8f*UI_UNIT_X; 00584 int color_id= node_get_colorid(node); 00585 char showname[128]; /* 128 used below */ 00586 View2D *v2d = &ar->v2d; 00587 00588 /* hurmf... another candidate for callback, have to see how this works first */ 00589 if(node->id && node->block && snode->treetype==NTREE_SHADER) 00590 nodeShaderSynchronizeID(node, 0); 00591 00592 /* skip if out of view */ 00593 if (node->totr.xmax < ar->v2d.cur.xmin || node->totr.xmin > ar->v2d.cur.xmax || 00594 node->totr.ymax < ar->v2d.cur.ymin || node->totr.ymin > ar->v2d.cur.ymax) { 00595 00596 uiEndBlock(C, node->block); 00597 node->block= NULL; 00598 return; 00599 } 00600 00601 uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_LEFT); 00602 ui_dropshadow(rct, BASIS_RAD, snode->aspect, node->flag & SELECT); 00603 00604 /* header */ 00605 if(color_id==TH_NODE) 00606 UI_ThemeColorShade(color_id, -20); 00607 else 00608 UI_ThemeColor(color_id); 00609 00610 if(node->flag & NODE_MUTED) 00611 UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f); 00612 00613 uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT); 00614 uiRoundBox(rct->xmin, rct->ymax-NODE_DY, rct->xmax, rct->ymax, BASIS_RAD); 00615 00616 /* show/hide icons */ 00617 iconofs= rct->xmax - 7.0f; 00618 00619 /* preview */ 00620 if(node->typeinfo->flag & NODE_PREVIEW) { 00621 uiBut *but; 00622 iconofs-=iconbutw; 00623 uiBlockSetEmboss(node->block, UI_EMBOSSN); 00624 but = uiDefIconBut(node->block, TOGBUT, B_REDR, ICON_MATERIAL, 00625 iconofs, rct->ymax-NODE_DY, iconbutw, UI_UNIT_Y, NULL, 0, 0, 0, 0, ""); 00626 uiButSetFunc(but, node_toggle_button_cb, node, (void*)"NODE_OT_preview_toggle"); 00627 /* XXX this does not work when node is activated and the operator called right afterwards, 00628 * since active ID is not updated yet (needs to process the notifier). 00629 * This can only work as visual indicator! 00630 */ 00631 // if (!(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT))) 00632 // uiButSetFlag(but, UI_BUT_DISABLED); 00633 uiBlockSetEmboss(node->block, UI_EMBOSS); 00634 } 00635 /* group edit */ 00636 if(node->type == NODE_GROUP) { 00637 uiBut *but; 00638 iconofs-=iconbutw; 00639 uiBlockSetEmboss(node->block, UI_EMBOSSN); 00640 but = uiDefIconBut(node->block, TOGBUT, B_REDR, ICON_NODETREE, 00641 iconofs, rct->ymax-NODE_DY, iconbutw, UI_UNIT_Y, NULL, 0, 0, 0, 0, ""); 00642 uiButSetFunc(but, node_toggle_button_cb, node, (void*)"NODE_OT_group_edit"); 00643 uiBlockSetEmboss(node->block, UI_EMBOSS); 00644 } 00645 00646 /* title */ 00647 if(node->flag & SELECT) 00648 UI_ThemeColor(TH_TEXT_HI); 00649 else 00650 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10); 00651 00652 /* open/close entirely? */ 00653 { 00654 uiBut *but; 00655 int but_size = UI_UNIT_X *0.6f; 00656 /* XXX button uses a custom triangle draw below, so make it invisible without icon */ 00657 uiBlockSetEmboss(node->block, UI_EMBOSSN); 00658 but = uiDefBut(node->block, TOGBUT, B_REDR, "", 00659 rct->xmin+10.0f-but_size/2, rct->ymax-NODE_DY/2.0f-but_size/2, but_size, but_size, NULL, 0, 0, 0, 0, ""); 00660 uiButSetFunc(but, node_toggle_button_cb, node, (void*)"NODE_OT_hide_toggle"); 00661 uiBlockSetEmboss(node->block, UI_EMBOSS); 00662 00663 /* custom draw function for this button */ 00664 UI_DrawTriIcon(rct->xmin+10.0f, rct->ymax-NODE_DY/2.0f, 'v'); 00665 } 00666 00667 /* this isn't doing anything for the label, so commenting out 00668 if(node->flag & SELECT) 00669 UI_ThemeColor(TH_TEXT_HI); 00670 else 00671 UI_ThemeColor(TH_TEXT); */ 00672 00673 BLI_strncpy(showname, nodeLabel(node), sizeof(showname)); 00674 00675 //if(node->flag & NODE_MUTED) 00676 // BLI_snprintf(showname, sizeof(showname), "[%s]", showname); // XXX - dont print into self! 00677 00678 uiDefBut(node->block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(rct->ymax-NODE_DY), 00679 (int)(iconofs - rct->xmin-18.0f), NODE_DY, NULL, 0, 0, 0, 0, ""); 00680 00681 /* body */ 00682 UI_ThemeColor4(TH_NODE); 00683 glEnable(GL_BLEND); 00684 uiSetRoundBox(UI_CNR_BOTTOM_LEFT); 00685 uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax-NODE_DY, BASIS_RAD); 00686 glDisable(GL_BLEND); 00687 00688 /* scaling indicator */ 00689 node_scaling_widget(TH_NODE, snode->aspect, rct->xmax-BASIS_RAD*snode->aspect, rct->ymin, rct->xmax, rct->ymin+BASIS_RAD*snode->aspect); 00690 00691 /* outline active and selected emphasis */ 00692 if( node->flag & (NODE_ACTIVE|SELECT) ) { 00693 glEnable(GL_BLEND); 00694 glEnable( GL_LINE_SMOOTH ); 00695 /* using different shades of TH_TEXT_HI for the empasis, like triangle */ 00696 if( node->flag & NODE_ACTIVE ) 00697 UI_ThemeColorShadeAlpha(TH_TEXT_HI, 0, -40); 00698 else 00699 UI_ThemeColorShadeAlpha(TH_TEXT_HI, -20, -120); 00700 uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_LEFT); // round all corners except lower right 00701 uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD); 00702 00703 glDisable( GL_LINE_SMOOTH ); 00704 glDisable(GL_BLEND); 00705 } 00706 00707 /* disable lines */ 00708 if(node->flag & NODE_MUTED) 00709 node_draw_mute_line(v2d, snode, node); 00710 00711 00712 /* socket inputs, buttons */ 00713 for(sock= node->inputs.first; sock; sock= sock->next) { 00714 bNodeSocketType *stype= ntreeGetSocketType(sock->type); 00715 00716 if(nodeSocketIsHidden(sock)) 00717 continue; 00718 00719 node_socket_circle_draw(ntree, sock, NODE_SOCKSIZE); 00720 00721 if (sock->link || (sock->flag & SOCK_HIDE_VALUE)) { 00722 uiDefBut(node->block, LABEL, 0, sock->name, sock->locx+NODE_DYS, sock->locy-NODE_DYS, node->width-NODE_DY, NODE_DY, 00723 NULL, 0, 0, 0, 0, ""); 00724 } 00725 else { 00726 if (stype->buttonfunc) 00727 stype->buttonfunc(C, node->block, ntree, node, sock, sock->name, sock->locx+NODE_DYS, sock->locy-NODE_DYS, node->width-NODE_DY); 00728 } 00729 } 00730 00731 /* socket outputs */ 00732 for(sock= node->outputs.first; sock; sock= sock->next) { 00733 PointerRNA sockptr; 00734 float slen; 00735 int ofs; 00736 00737 RNA_pointer_create((ID*)ntree, &RNA_NodeSocket, sock, &sockptr); 00738 00739 if(nodeSocketIsHidden(sock)) 00740 continue; 00741 00742 node_socket_circle_draw(ntree, sock, NODE_SOCKSIZE); 00743 00744 ofs= 0; 00745 UI_ThemeColor(TH_TEXT); 00746 slen= snode->aspect*UI_GetStringWidth(sock->name); 00747 while(slen > node->width) { 00748 ofs++; 00749 slen= snode->aspect*UI_GetStringWidth(sock->name+ofs); 00750 } 00751 uiDefBut(node->block, LABEL, 0, sock->name+ofs, (short)(sock->locx-15.0f-slen), (short)(sock->locy-9.0f), 00752 (short)(node->width-NODE_DY), NODE_DY, NULL, 0, 0, 0, 0, ""); 00753 } 00754 00755 /* preview */ 00756 if(node->flag & NODE_PREVIEW) { 00757 BLI_lock_thread(LOCK_PREVIEW); 00758 if(node->preview && node->preview->rect && !BLI_rctf_is_empty(&node->prvr)) 00759 node_draw_preview(node->preview, &node->prvr); 00760 BLI_unlock_thread(LOCK_PREVIEW); 00761 } 00762 00763 UI_ThemeClearColor(color_id); 00764 00765 uiEndBlock(C, node->block); 00766 uiDrawBlock(C, node->block); 00767 node->block= NULL; 00768 } 00769 00770 static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, bNode *node) 00771 { 00772 bNodeSocket *sock; 00773 rctf *rct= &node->totr; 00774 float dx, centy= 0.5f*(rct->ymax+rct->ymin); 00775 float hiddenrad= 0.5f*(rct->ymax-rct->ymin); 00776 float socket_size= NODE_SOCKSIZE*U.dpi/72; 00777 int color_id= node_get_colorid(node); 00778 char showname[128]; /* 128 is used below */ 00779 00780 /* shadow */ 00781 uiSetRoundBox(UI_CNR_ALL); 00782 ui_dropshadow(rct, hiddenrad, snode->aspect, node->flag & SELECT); 00783 00784 /* body */ 00785 UI_ThemeColor(color_id); 00786 if(node->flag & NODE_MUTED) 00787 UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f); 00788 uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad); 00789 00790 /* outline active and selected emphasis */ 00791 if( node->flag & (NODE_ACTIVE|SELECT) ) { 00792 glEnable(GL_BLEND); 00793 glEnable( GL_LINE_SMOOTH ); 00794 /* using different shades of TH_TEXT_HI for the empasis, like triangle */ 00795 if( node->flag & NODE_ACTIVE ) 00796 UI_ThemeColorShadeAlpha(TH_TEXT_HI, 0, -40); 00797 else 00798 UI_ThemeColorShadeAlpha(TH_TEXT_HI, -20, -120); 00799 uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad); 00800 glDisable( GL_LINE_SMOOTH ); 00801 glDisable(GL_BLEND); 00802 } 00803 00804 /* title */ 00805 if(node->flag & SELECT) 00806 UI_ThemeColor(TH_TEXT_HI); 00807 else 00808 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10); 00809 00810 /* open entirely icon */ 00811 { 00812 uiBut *but; 00813 int but_size = UI_UNIT_X *0.6f; 00814 /* XXX button uses a custom triangle draw below, so make it invisible without icon */ 00815 uiBlockSetEmboss(node->block, UI_EMBOSSN); 00816 but = uiDefBut(node->block, TOGBUT, B_REDR, "", 00817 rct->xmin+10.0f-but_size/2, centy-but_size/2, but_size, but_size, NULL, 0, 0, 0, 0, ""); 00818 uiButSetFunc(but, node_toggle_button_cb, node, (void*)"NODE_OT_hide_toggle"); 00819 uiBlockSetEmboss(node->block, UI_EMBOSS); 00820 00821 /* custom draw function for this button */ 00822 UI_DrawTriIcon(rct->xmin+10.0f, centy, 'h'); 00823 } 00824 00825 /* disable lines */ 00826 if(node->flag & NODE_MUTED) 00827 node_draw_mute_line(&ar->v2d, snode, node); 00828 00829 if(node->flag & SELECT) 00830 UI_ThemeColor(TH_TEXT_HI); 00831 else 00832 UI_ThemeColor(TH_TEXT); 00833 00834 if(node->miniwidth>0.0f) { 00835 BLI_strncpy(showname, nodeLabel(node), sizeof(showname)); 00836 00837 //if(node->flag & NODE_MUTED) 00838 // BLI_snprintf(showname, sizeof(showname), "[%s]", showname); // XXX - dont print into self! 00839 00840 uiDefBut(node->block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(centy-10), 00841 (int)(rct->xmax - rct->xmin-18.0f -12.0f), NODE_DY, NULL, 0, 0, 0, 0, ""); 00842 } 00843 00844 /* scale widget thing */ 00845 UI_ThemeColorShade(color_id, -10); 00846 dx= 10.0f; 00847 fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f); 00848 fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f); 00849 00850 UI_ThemeColorShade(color_id, +30); 00851 dx-= snode->aspect; 00852 fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f); 00853 fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f); 00854 00855 /* sockets */ 00856 for(sock= node->inputs.first; sock; sock= sock->next) { 00857 if(!nodeSocketIsHidden(sock)) 00858 node_socket_circle_draw(snode->nodetree, sock, socket_size); 00859 } 00860 00861 for(sock= node->outputs.first; sock; sock= sock->next) { 00862 if(!nodeSocketIsHidden(sock)) 00863 node_socket_circle_draw(snode->nodetree, sock, socket_size); 00864 } 00865 00866 uiEndBlock(C, node->block); 00867 uiDrawBlock(C, node->block); 00868 node->block= NULL; 00869 } 00870 00871 void node_draw_default(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node) 00872 { 00873 if(node->flag & NODE_HIDDEN) 00874 node_draw_hidden(C, ar, snode, node); 00875 else 00876 node_draw_basis(C, ar, snode, ntree, node); 00877 } 00878 00879 static void node_update(const bContext *C, bNodeTree *ntree, bNode *node) 00880 { 00881 if (node->typeinfo->drawupdatefunc) 00882 node->typeinfo->drawupdatefunc(C, ntree, node); 00883 } 00884 00885 void node_update_nodetree(const bContext *C, bNodeTree *ntree, float offsetx, float offsety) 00886 { 00887 bNode *node; 00888 00889 for(node= ntree->nodes.first; node; node= node->next) { 00890 /* XXX little hack */ 00891 node->locx += offsetx; 00892 node->locy += offsety; 00893 00894 node_update(C, ntree, node); 00895 00896 node->locx -= offsetx; 00897 node->locy -= offsety; 00898 } 00899 } 00900 00901 static void node_draw(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node) 00902 { 00903 if (node->typeinfo->drawfunc) 00904 node->typeinfo->drawfunc(C, ar, snode, ntree, node); 00905 } 00906 00907 void node_draw_nodetree(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree) 00908 { 00909 bNode *node; 00910 bNodeLink *link; 00911 int a; 00912 00913 if(ntree==NULL) return; /* groups... */ 00914 00915 /* node lines */ 00916 glEnable(GL_BLEND); 00917 glEnable(GL_LINE_SMOOTH); 00918 for(link= ntree->links.first; link; link= link->next) 00919 node_draw_link(&ar->v2d, snode, link); 00920 glDisable(GL_LINE_SMOOTH); 00921 glDisable(GL_BLEND); 00922 00923 /* draw nodes, last nodes in front */ 00924 for(a=0, node= ntree->nodes.first; node; node=node->next, a++) { 00925 node->nr= a; /* index of node in list, used for exec event code */ 00926 node_draw(C, ar, snode, ntree, node); 00927 } 00928 } 00929 00930 void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d) 00931 { 00932 View2DScrollers *scrollers; 00933 SpaceNode *snode= CTX_wm_space_node(C); 00934 Scene *scene= CTX_data_scene(C); 00935 int color_manage = scene->r.color_mgt_flag & R_COLOR_MANAGEMENT; 00936 bNodeLinkDrag *nldrag; 00937 00938 UI_ThemeClearColor(TH_BACK); 00939 glClear(GL_COLOR_BUFFER_BIT); 00940 00941 UI_view2d_view_ortho(v2d); 00942 00943 //uiFreeBlocksWin(&sa->uiblocks, sa->win); 00944 00945 /* only set once */ 00946 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); 00947 glEnable(GL_MAP1_VERTEX_3); 00948 00949 /* aspect+font, set each time */ 00950 snode->aspect= (v2d->cur.xmax - v2d->cur.xmin)/((float)ar->winx); 00951 // XXX snode->curfont= uiSetCurFont_ext(snode->aspect); 00952 00953 UI_view2d_constant_grid_draw(v2d); 00954 /* backdrop */ 00955 draw_nodespace_back_pix(ar, snode, color_manage); 00956 00957 /* nodes */ 00958 snode_set_context(snode, CTX_data_scene(C)); 00959 00960 if(snode->nodetree) { 00961 bNode *node; 00962 00963 node_uiblocks_init(C, snode->nodetree); 00964 00965 /* uiBlocks must be initialized in drawing order for correct event clipping. 00966 * Node group internal blocks added after the main group block. 00967 */ 00968 for(node= snode->nodetree->nodes.first; node; node= node->next) { 00969 if(node->flag & NODE_GROUP_EDIT) 00970 node_uiblocks_init(C, (bNodeTree *)node->id); 00971 } 00972 00973 node_update_nodetree(C, snode->nodetree, 0.0f, 0.0f); 00974 node_draw_nodetree(C, ar, snode, snode->nodetree); 00975 00976 #if 0 00977 /* active group */ 00978 for(node= snode->nodetree->nodes.first; node; node= node->next) { 00979 if(node->flag & NODE_GROUP_EDIT) 00980 node_draw_group(C, ar, snode, snode->nodetree, node); 00981 } 00982 #endif 00983 } 00984 00985 /* temporary links */ 00986 glEnable(GL_BLEND); 00987 glEnable(GL_LINE_SMOOTH); 00988 for(nldrag= snode->linkdrag.first; nldrag; nldrag= nldrag->next) 00989 node_draw_link(&ar->v2d, snode, nldrag->link); 00990 glDisable(GL_LINE_SMOOTH); 00991 glDisable(GL_BLEND); 00992 00993 /* draw grease-pencil ('canvas' strokes) */ 00994 if (/*(snode->flag & SNODE_DISPGP) &&*/ (snode->nodetree)) 00995 draw_gpencil_view2d((bContext*)C, 1); 00996 00997 /* reset view matrix */ 00998 UI_view2d_view_restore(C); 00999 01000 /* draw grease-pencil (screen strokes, and also paintbuffer) */ 01001 if (/*(snode->flag & SNODE_DISPGP) && */(snode->nodetree)) 01002 draw_gpencil_view2d((bContext*)C, 0); 01003 01004 /* scrollers */ 01005 scrollers= UI_view2d_scrollers_calc(C, v2d, 10, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY); 01006 UI_view2d_scrollers_draw(C, v2d, scrollers); 01007 UI_view2d_scrollers_free(scrollers); 01008 }