Blender V2.61 - r43446

node_draw.c

Go to the documentation of this file.
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 }