Blender  V2.59
node_draw.c
Go to the documentation of this file.
00001 /*
00002  * $Id: node_draw.c 38751 2011-07-27 06:55:20Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version. 
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2008 Blender Foundation.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  * Contributor(s): Nathan Letwory
00025  *
00026  * ***** END GPL LICENSE BLOCK *****
00027  */
00028 
00034 #include <math.h>
00035 #include <stdio.h>
00036 #include <string.h>
00037 
00038 #include "MEM_guardedalloc.h"
00039 
00040 #include "DNA_node_types.h"
00041 #include "DNA_material_types.h"
00042 #include "DNA_object_types.h"
00043 #include "DNA_scene_types.h"
00044 #include "DNA_space_types.h"
00045 #include "DNA_screen_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 "CMP_node.h"
00074 #include "SHD_node.h"
00075 
00076 #include "node_intern.h"
00077 
00078 /* width of socket columns in group display */
00079 #define NODE_GROUP_FRAME                120
00080 
00081 // XXX interface.h
00082 extern void ui_dropshadow(rctf *rct, float radius, float aspect, int select);
00083 
00084 void ED_node_changed_update(ID *id, bNode *node)
00085 {
00086         bNodeTree *nodetree, *edittree;
00087         int treetype;
00088 
00089         node_tree_from_ID(id, &nodetree, &edittree, &treetype);
00090 
00091         if(treetype==NTREE_SHADER) {
00092                 DAG_id_tag_update(id, 0);
00093                 WM_main_add_notifier(NC_MATERIAL|ND_SHADING_DRAW, id);
00094         }
00095         else if(treetype==NTREE_COMPOSIT) {
00096                 NodeTagChanged(edittree, node);
00097                 /* don't use NodeTagIDChanged, it gives far too many recomposites for image, scene layers, ... */
00098                         
00099                 node= node_tree_get_editgroup(nodetree);
00100                 if(node)
00101                         NodeTagIDChanged(nodetree, node->id);
00102 
00103                 WM_main_add_notifier(NC_SCENE|ND_NODES, id);
00104         }                       
00105         else if(treetype==NTREE_TEXTURE) {
00106                 DAG_id_tag_update(id, 0);
00107                 WM_main_add_notifier(NC_TEXTURE|ND_NODES, id);
00108         }
00109 }
00110 
00111 static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup)
00112 {
00113         bNode *node;
00114         
00115         if(ntree == lookup)
00116                 return 1;
00117         
00118         for(node=ntree->nodes.first; node; node=node->next)
00119                 if(node->type == NODE_GROUP && node->id)
00120                         if(has_nodetree((bNodeTree*)node->id, lookup))
00121                                 return 1;
00122         
00123         return 0;
00124 }
00125 
00126 void ED_node_generic_update(Main *bmain, bNodeTree *ntree, bNode *node)
00127 {
00128         Material *ma;
00129         Tex *tex;
00130         Scene *sce;
00131         
00132         /* look through all datablocks, to support groups */
00133         for(ma=bmain->mat.first; ma; ma=ma->id.next)
00134                 if(ma->nodetree && ma->use_nodes && has_nodetree(ma->nodetree, ntree))
00135                         ED_node_changed_update(&ma->id, node);
00136         
00137         for(tex=bmain->tex.first; tex; tex=tex->id.next)
00138                 if(tex->nodetree && tex->use_nodes && has_nodetree(tex->nodetree, ntree))
00139                         ED_node_changed_update(&tex->id, node);
00140         
00141         for(sce=bmain->scene.first; sce; sce=sce->id.next)
00142                 if(sce->nodetree && sce->use_nodes && has_nodetree(sce->nodetree, ntree))
00143                         ED_node_changed_update(&sce->id, node);
00144         
00145         if(ntree->type == NTREE_TEXTURE)
00146                 ntreeTexCheckCyclics(ntree);
00147 }
00148 
00149 static void do_node_internal_buttons(bContext *C, void *node_v, int event)
00150 {
00151         if(event==B_NODE_EXEC) {
00152                 SpaceNode *snode= CTX_wm_space_node(C);
00153                 if(snode && snode->id)
00154                         ED_node_changed_update(snode->id, node_v);
00155         }
00156 }
00157 
00158 
00159 static void node_scaling_widget(int color_id, float aspect, float xmin, float ymin, float xmax, float ymax)
00160 {
00161         float dx;
00162         float dy;
00163         
00164         dx= 0.5f*(xmax-xmin);
00165         dy= 0.5f*(ymax-ymin);
00166         
00167         UI_ThemeColorShade(color_id, +30);      
00168         fdrawline(xmin, ymin, xmax, ymax);
00169         fdrawline(xmin+dx, ymin, xmax, ymax-dy);
00170         
00171         UI_ThemeColorShade(color_id, -10);
00172         fdrawline(xmin, ymin+aspect, xmax, ymax+aspect);
00173         fdrawline(xmin+dx, ymin+aspect, xmax, ymax-dy+aspect);
00174 }
00175 
00176 static void node_uiblocks_init(const bContext *C, bNodeTree *ntree)
00177 {
00178         bNode *node;
00179         char str[32];
00180         
00181         /* add node uiBlocks in reverse order - prevents events going to overlapping nodes */
00182         
00183         /* process selected nodes first so they're at the start of the uiblocks list */
00184         for(node= ntree->nodes.last; node; node= node->prev) {
00185                 
00186                 if (node->flag & NODE_SELECT) {
00187                         /* ui block */
00188                         sprintf(str, "node buttons %p", (void *)node);
00189                         node->block= uiBeginBlock(C, CTX_wm_region(C), str, UI_EMBOSS);
00190                         uiBlockSetHandleFunc(node->block, do_node_internal_buttons, node);
00191                 }
00192         }
00193         
00194         /* then the rest */
00195         for(node= ntree->nodes.last; node; node= node->prev) {
00196                 
00197                 if (!(node->flag & (NODE_GROUP_EDIT|NODE_SELECT))) {
00198                         /* ui block */
00199                         sprintf(str, "node buttons %p", (void *)node);
00200                         node->block= uiBeginBlock(C, CTX_wm_region(C), str, UI_EMBOSS);
00201                         uiBlockSetHandleFunc(node->block, do_node_internal_buttons, node);
00202                 }
00203         }
00204 }
00205 
00206 /* based on settings in node, sets drawing rect info. each redraw! */
00207 static void node_update(const bContext *C, bNodeTree *ntree, bNode *node)
00208 {
00209         uiLayout *layout;
00210         PointerRNA ptr;
00211         bNodeSocket *nsock;
00212         float dy= node->locy;
00213         int buty;
00214         
00215         /* header */
00216         dy-= NODE_DY;
00217         
00218         /* little bit space in top */
00219         if(node->outputs.first)
00220                 dy-= NODE_DYS/2;
00221 
00222         /* output sockets */
00223         for(nsock= node->outputs.first; nsock; nsock= nsock->next) {
00224                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
00225                         nsock->locx= node->locx + node->width;
00226                         nsock->locy= dy - NODE_DYS;
00227                         dy-= NODE_DY;
00228                 }
00229         }
00230 
00231         node->prvr.xmin= node->locx + NODE_DYS;
00232         node->prvr.xmax= node->locx + node->width- NODE_DYS;
00233 
00234         /* preview rect? */
00235         if(node->flag & NODE_PREVIEW) {
00236                 /* only recalculate size when there's a preview actually, otherwise we use stored result */
00237                 BLI_lock_thread(LOCK_PREVIEW);
00238 
00239                 if(node->preview && node->preview->rect) {
00240                         float aspect= 1.0f;
00241                         
00242                         if(node->preview && node->preview->xsize && node->preview->ysize) 
00243                                 aspect= (float)node->preview->ysize/(float)node->preview->xsize;
00244                         
00245                         dy-= NODE_DYS/2;
00246                         node->prvr.ymax= dy;
00247                         
00248                         if(aspect <= 1.0f)
00249                                 node->prvr.ymin= dy - aspect*(node->width-NODE_DY);
00250                         else {
00251                                 float dx= (node->width - NODE_DYS) - (node->width- NODE_DYS)/aspect;    /* width correction of image */
00252                                 
00253                                 node->prvr.ymin= dy - (node->width-NODE_DY);
00254                                 
00255                                 node->prvr.xmin+= 0.5f*dx;
00256                                 node->prvr.xmax-= 0.5f*dx;
00257                         }
00258 
00259                         dy= node->prvr.ymin - NODE_DYS/2;
00260 
00261                         /* make sure that maximums are bigger or equal to minimums */
00262                         if(node->prvr.xmax < node->prvr.xmin) SWAP(float, node->prvr.xmax, node->prvr.xmin);
00263                         if(node->prvr.ymax < node->prvr.ymin) SWAP(float, node->prvr.ymax, node->prvr.ymin);
00264                 }
00265                 else {
00266                         float oldh= node->prvr.ymax - node->prvr.ymin;
00267                         if(oldh==0.0f)
00268                                 oldh= 0.6f*node->width-NODE_DY;
00269                         dy-= NODE_DYS/2;
00270                         node->prvr.ymax= dy;
00271                         node->prvr.ymin= dy - oldh;
00272                         dy= node->prvr.ymin - NODE_DYS/2;
00273                 }
00274 
00275                 BLI_unlock_thread(LOCK_PREVIEW);
00276         }
00277 
00278         /* buttons rect? */
00279         if((node->flag & NODE_OPTIONS) && node->typeinfo->uifunc) {
00280                 dy-= NODE_DYS/2;
00281 
00282                 /* set this for uifunc() that don't use layout engine yet */
00283                 node->butr.xmin= 0;
00284                 node->butr.xmax= node->width - 2*NODE_DYS;
00285                 node->butr.ymin= 0;
00286                 node->butr.ymax= 0;
00287                 
00288                 RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr);
00289 
00290                 layout= uiBlockLayout(node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL,
00291                         node->locx+NODE_DYS, dy, node->butr.xmax, NODE_DY, U.uistyles.first);
00292 
00293                 node->typeinfo->uifunc(layout, (bContext *)C, &ptr);
00294                 uiBlockEndAlign(node->block);
00295                 uiBlockLayoutResolve(node->block, NULL, &buty);
00296 
00297                 dy= buty - NODE_DYS/2;
00298         }
00299 
00300         /* input sockets */
00301         for(nsock= node->inputs.first; nsock; nsock= nsock->next) {
00302                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
00303                         nsock->locx= node->locx;
00304                         nsock->locy= dy - NODE_DYS;
00305                         dy-= NODE_DY;
00306                 }
00307         }
00308         
00309         /* little bit space in end */
00310         if(node->inputs.first || (node->flag & (NODE_OPTIONS|NODE_PREVIEW))==0 )
00311                 dy-= NODE_DYS/2;
00312 
00313         node->totr.xmin= node->locx;
00314         node->totr.xmax= node->locx + node->width;
00315         node->totr.ymax= node->locy;
00316         node->totr.ymin= MIN2(dy, node->locy-2*NODE_DY);
00317 }
00318 
00319 /* based on settings in node, sets drawing rect info. each redraw! */
00320 static void node_update_hidden(bNode *node)
00321 {
00322         bNodeSocket *nsock;
00323         float rad, drad, hiddenrad= HIDDEN_RAD;
00324         int totin=0, totout=0, tot;
00325         
00326         /* calculate minimal radius */
00327         for(nsock= node->inputs.first; nsock; nsock= nsock->next)
00328                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
00329                         totin++;
00330         for(nsock= node->outputs.first; nsock; nsock= nsock->next)
00331                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
00332                         totout++;
00333         
00334         tot= MAX2(totin, totout);
00335         if(tot>4) {
00336                 hiddenrad += 5.0f*(float)(tot-4);
00337         }
00338         
00339         node->totr.xmin= node->locx;
00340         node->totr.xmax= node->locx + 3*hiddenrad + node->miniwidth;
00341         node->totr.ymax= node->locy + (hiddenrad - 0.5f*NODE_DY);
00342         node->totr.ymin= node->totr.ymax - 2*hiddenrad;
00343         
00344         /* output sockets */
00345         rad=drad= (float)M_PI/(1.0f + (float)totout);
00346         
00347         for(nsock= node->outputs.first; nsock; nsock= nsock->next) {
00348                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
00349                         nsock->locx= node->totr.xmax - hiddenrad + (float)sin(rad)*hiddenrad;
00350                         nsock->locy= node->totr.ymin + hiddenrad + (float)cos(rad)*hiddenrad;
00351                         rad+= drad;
00352                 }
00353         }
00354         
00355         /* input sockets */
00356         rad=drad= - (float)M_PI/(1.0f + (float)totin);
00357         
00358         for(nsock= node->inputs.first; nsock; nsock= nsock->next) {
00359                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
00360                         nsock->locx= node->totr.xmin + hiddenrad + (float)sin(rad)*hiddenrad;
00361                         nsock->locy= node->totr.ymin + hiddenrad + (float)cos(rad)*hiddenrad;
00362                         rad+= drad;
00363                 }
00364         }
00365 }
00366 
00367 static int node_get_colorid(bNode *node)
00368 {
00369         if(node->typeinfo->nclass==NODE_CLASS_INPUT)
00370                 return TH_NODE_IN_OUT;
00371         if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) {
00372                 if(node->flag & NODE_DO_OUTPUT)
00373                         return TH_NODE_IN_OUT;
00374                 else
00375                         return TH_NODE;
00376         }
00377         if(node->typeinfo->nclass==NODE_CLASS_CONVERTOR)
00378                 return TH_NODE_CONVERTOR;
00379         if(ELEM3(node->typeinfo->nclass, NODE_CLASS_OP_COLOR, NODE_CLASS_OP_VECTOR, NODE_CLASS_OP_FILTER))
00380                 return TH_NODE_OPERATOR;
00381         if(node->typeinfo->nclass==NODE_CLASS_GROUP)
00382                 return TH_NODE_GROUP;
00383         return TH_NODE;
00384 }
00385 
00386 /* based on settings in node, sets drawing rect info. each redraw! */
00387 /* note: this assumes only 1 group at a time is drawn (linked data) */
00388 /* in node->totr the entire boundbox for the group is stored */
00389 static void node_update_group(const bContext *C, bNodeTree *UNUSED(ntree), bNode *gnode)
00390 {
00391         bNodeTree *ngroup= (bNodeTree *)gnode->id;
00392         bNode *node;
00393         bNodeSocket *sock, *gsock;
00394         rctf *rect= &gnode->totr;
00395         float node_group_frame= U.dpi*NODE_GROUP_FRAME/72;
00396         int counter;
00397         int dy;
00398         
00399         rect->xmin = rect->xmax = gnode->locx;
00400         rect->ymin = rect->ymax = gnode->locy;
00401         
00402         /* center them, is a bit of abuse of locx and locy though */
00403         for(node= ngroup->nodes.first; node; node= node->next) {
00404                 node->locx+= gnode->locx;
00405                 node->locy+= gnode->locy;
00406                 
00407                 if(node->flag & NODE_HIDDEN)
00408                         node_update_hidden(node);
00409                 else
00410                         node_update(C, ngroup, node);
00411                 node->locx-= gnode->locx;
00412                 node->locy-= gnode->locy;
00413         }
00414         counter= 1;
00415         for(node= ngroup->nodes.first; node; node= node->next) {
00416                 if(counter) {
00417                         *rect= node->totr;
00418                         counter= 0;
00419                 }
00420                 else
00421                         BLI_union_rctf(rect, &node->totr);
00422         }
00423         
00424         /* add some room for links to group sockets */
00425         rect->xmin -= 4*NODE_DY;
00426         rect->xmax += 4*NODE_DY;
00427         rect->ymin-= NODE_DY;
00428         rect->ymax+= NODE_DY;
00429         
00430         /* input sockets */
00431         dy = 0.5f*(rect->ymin+rect->ymax) + NODE_DY*(BLI_countlist(&gnode->inputs)-1);
00432         for(gsock=ngroup->inputs.first, sock=gnode->inputs.first; gsock; gsock=gsock->next, sock=sock->next) {
00433                 gsock->locx = rect->xmin;
00434                 sock->locx = rect->xmin - node_group_frame;
00435                 sock->locy = gsock->locy = dy;
00436                 
00437                 /* prevent long socket lists from growing out of the group box */
00438                 if (dy-3*NODE_DYS < rect->ymin)
00439                         rect->ymin = dy-3*NODE_DYS;
00440                 if (dy+3*NODE_DYS > rect->ymax)
00441                         rect->ymax = dy+3*NODE_DYS;
00442                 
00443                 dy -= 2*NODE_DY;
00444         }
00445         
00446         /* output sockets */
00447         dy = 0.5f*(rect->ymin+rect->ymax) + NODE_DY*(BLI_countlist(&gnode->outputs)-1);
00448         for(gsock=ngroup->outputs.first, sock=gnode->outputs.first; gsock; gsock=gsock->next, sock=sock->next) {
00449                 gsock->locx = rect->xmax;
00450                 sock->locx = rect->xmax + node_group_frame;
00451                 sock->locy = gsock->locy = dy - NODE_DYS;
00452                 
00453                 /* prevent long socket lists from growing out of the group box */
00454                 if (dy-3*NODE_DYS < rect->ymin)
00455                         rect->ymin = dy-3*NODE_DYS;
00456                 if (dy+3*NODE_DYS > rect->ymax)
00457                         rect->ymax = dy+3*NODE_DYS;
00458                 
00459                 dy -= 2*NODE_DY;
00460         }
00461 }
00462 
00463 /* note: in cmp_util.c is similar code, for node_compo_pass_on() */
00464 /* note: in node_edit.c is similar code, for untangle node */
00465 static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node)
00466 {
00467         bNodeSocket *valsock= NULL, *colsock= NULL, *vecsock= NULL;
00468         bNodeSocket *sock;
00469         bNodeLink link= {NULL};
00470         int a;
00471         
00472         /* connect the first value buffer in with first value out */
00473         /* connect the first RGBA buffer in with first RGBA out */
00474         
00475         /* test the inputs */
00476         for(a=0, sock= node->inputs.first; sock; sock= sock->next, a++) {
00477                 if(nodeCountSocketLinks(snode->edittree, sock)) {
00478                         if(sock->type==SOCK_VALUE && valsock==NULL) valsock= sock;
00479                         if(sock->type==SOCK_VECTOR && vecsock==NULL) vecsock= sock;
00480                         if(sock->type==SOCK_RGBA && colsock==NULL) colsock= sock;
00481                 }
00482         }
00483         
00484         /* outputs, draw lines */
00485         glEnable(GL_BLEND);
00486         glEnable( GL_LINE_SMOOTH );
00487         
00488         if(valsock || colsock || vecsock) {
00489                 for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) {
00490                         if(nodeCountSocketLinks(snode->edittree, sock)) {
00491                                 link.tosock= sock;
00492                                 
00493                                 if(sock->type==SOCK_VALUE && valsock) {
00494                                         link.fromsock= valsock;
00495                                         node_draw_link_bezier(v2d, snode, &link, TH_REDALERT, 0, TH_WIRE, 0, TH_WIRE);
00496                                         valsock= NULL;
00497                                 }
00498                                 if(sock->type==SOCK_VECTOR && vecsock) {
00499                                         link.fromsock= vecsock;
00500                                         node_draw_link_bezier(v2d, snode, &link, TH_REDALERT, 0, TH_WIRE, 0, TH_WIRE);
00501                                         vecsock= NULL;
00502                                 }
00503                                 if(sock->type==SOCK_RGBA && colsock) {
00504                                         link.fromsock= colsock;
00505                                         node_draw_link_bezier(v2d, snode, &link, TH_REDALERT, 0, TH_WIRE, 0, TH_WIRE);
00506                                         colsock= NULL;
00507                                 }
00508                         }
00509                 }
00510         }
00511         glDisable(GL_BLEND);
00512         glDisable( GL_LINE_SMOOTH );
00513 }
00514 
00515 /* nice AA filled circle */
00516 /* this might have some more generic use */
00517 static void circle_draw(float x, float y, float size, int col[3])
00518 {
00519         /* 16 values of sin function */
00520         static float si[16] = {
00521                 0.00000000f, 0.39435585f,0.72479278f,0.93775213f,
00522                 0.99871650f,0.89780453f,0.65137248f,0.29936312f,
00523                 -0.10116832f,-0.48530196f,-0.79077573f,-0.96807711f,
00524                 -0.98846832f,-0.84864425f,-0.57126821f,-0.20129852f
00525         };
00526         /* 16 values of cos function */
00527         static float co[16] ={
00528                 1.00000000f,0.91895781f,0.68896691f,0.34730525f,
00529                 -0.05064916f,-0.44039415f,-0.75875812f,-0.95413925f,
00530                 -0.99486932f,-0.87434661f,-0.61210598f,-0.25065253f,
00531                 0.15142777f,0.52896401f,0.82076344f,0.97952994f,
00532         };
00533         int a;
00534         
00535         glColor3ub(col[0], col[1], col[2]);
00536         
00537         glBegin(GL_POLYGON);
00538         for(a=0; a<16; a++)
00539                 glVertex2f(x+size*si[a], y+size*co[a]);
00540         glEnd();
00541         
00542         glColor4ub(0, 0, 0, 150);
00543         glEnable(GL_BLEND);
00544         glEnable( GL_LINE_SMOOTH );
00545         glBegin(GL_LINE_LOOP);
00546         for(a=0; a<16; a++)
00547                 glVertex2f(x+size*si[a], y+size*co[a]);
00548         glEnd();
00549         glDisable( GL_LINE_SMOOTH );
00550         glDisable(GL_BLEND);
00551 }
00552 
00553 static void socket_circle_draw(bNodeSocket *sock, float size)
00554 {
00555         int col[3];
00556         
00557         if(sock->type==-1) {
00558                 col[0]= 0; col[1]= 0; col[2]= 0;
00559         }
00560         else if(sock->type==SOCK_VALUE) {
00561                 col[0]= 160; col[1]= 160; col[2]= 160;
00562         }
00563         else if(sock->type==SOCK_VECTOR) {
00564                 col[0]= 100; col[1]= 100; col[2]= 200;
00565         }
00566         else if(sock->type==SOCK_RGBA) {
00567                 col[0]= 200; col[1]= 200; col[2]= 40;
00568         }
00569         else { 
00570                 col[0]= 100; col[1]= 200; col[2]= 100;
00571         }
00572 
00573         circle_draw(sock->locx, sock->locy, size, col);
00574 }
00575 
00576 static void node_sync_cb(bContext *UNUSED(C), void *snode_v, void *node_v)
00577 {
00578         SpaceNode *snode= snode_v;
00579         
00580         if(snode->treetype==NTREE_SHADER) {
00581                 nodeShaderSynchronizeID(node_v, 1);
00582                 // allqueue(REDRAWBUTSSHADING, 0);
00583         }
00584 }
00585 
00586 /* **************  Socket callbacks *********** */
00587 
00588 /* not a callback */
00589 static void node_draw_preview(bNodePreview *preview, rctf *prv)
00590 {
00591         float xscale= (prv->xmax-prv->xmin)/((float)preview->xsize);
00592         float yscale= (prv->ymax-prv->ymin)/((float)preview->ysize);
00593         float tile= (prv->xmax - prv->xmin) / 10.0f;
00594         float x, y;
00595         
00596         /* draw checkerboard backdrop to show alpha */
00597         glColor3ub(120, 120, 120);
00598         glRectf(prv->xmin, prv->ymin, prv->xmax, prv->ymax);
00599         glColor3ub(160, 160, 160);
00600         
00601         for(y=prv->ymin; y<prv->ymax; y+=tile*2) {
00602                 for(x=prv->xmin; x<prv->xmax; x+=tile*2) {
00603                         float tilex= tile, tiley= tile;
00604 
00605                         if(x+tile > prv->xmax)
00606                                 tilex= prv->xmax-x;
00607                         if(y+tile > prv->ymax)
00608                                 tiley= prv->ymax-y;
00609 
00610                         glRectf(x, y, x + tilex, y + tiley);
00611                 }
00612         }
00613         for(y=prv->ymin+tile; y<prv->ymax; y+=tile*2) {
00614                 for(x=prv->xmin+tile; x<prv->xmax; x+=tile*2) {
00615                         float tilex= tile, tiley= tile;
00616 
00617                         if(x+tile > prv->xmax)
00618                                 tilex= prv->xmax-x;
00619                         if(y+tile > prv->ymax)
00620                                 tiley= prv->ymax-y;
00621 
00622                         glRectf(x, y, x + tilex, y + tiley);
00623                 }
00624         }
00625         
00626         glPixelZoom(xscale, yscale);
00627 
00628         glEnable(GL_BLEND);
00629         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );    /* premul graphics */
00630         
00631         glColor4f(1.0, 1.0, 1.0, 1.0);
00632         glaDrawPixelsTex(prv->xmin, prv->ymin, preview->xsize, preview->ysize, GL_UNSIGNED_BYTE, preview->rect);
00633         
00634         glDisable(GL_BLEND);
00635         glPixelZoom(1.0f, 1.0f);
00636 
00637         UI_ThemeColorShadeAlpha(TH_BACK, -15, +100);
00638         fdrawbox(prv->xmin, prv->ymin, prv->xmax, prv->ymax);
00639         
00640 }
00641 
00642 typedef struct SocketVectorMenuArgs {
00643         PointerRNA ptr;
00644         int x, y, width;
00645         uiButHandleFunc cb;
00646         void *arg1, *arg2;
00647 } SocketVectorMenuArgs;
00648 
00649 /* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
00650 static uiBlock *socket_vector_menu(bContext *C, ARegion *ar, void *args_v)
00651 {
00652         SocketVectorMenuArgs *args= (SocketVectorMenuArgs*)args_v;
00653         uiBlock *block;
00654         uiLayout *layout;
00655         
00656         block= uiBeginBlock(C, ar, "socket menu", UI_EMBOSS);
00657         uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN);
00658         
00659         layout= uiLayoutColumn(uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, args->x, args->y+2, args->width, NODE_DY, U.uistyles.first), 0);
00660         
00661         uiItemR(layout, &args->ptr, "default_value", UI_ITEM_R_EXPAND, "", ICON_NONE);
00662         
00663         return block;
00664 }
00665 
00666 static void node_draw_socket_button(bNodeTree *ntree, bNodeSocket *sock, const char *name,
00667                                                                         uiBlock *block, int x, int y, int width,
00668                                                                         uiButHandleFunc cb, void *arg1, void *arg2)
00669 {
00670         uiBut *bt= NULL;
00671         PointerRNA ptr;
00672         int labelw;
00673         SocketVectorMenuArgs *args;
00674         
00675         RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr);
00676         
00677         switch (sock->type) {
00678         case SOCK_VALUE:
00679                 bt=uiDefButR(block, NUM, B_NODE_EXEC, name,
00680                                          x, y+1, width, NODE_DY-2, 
00681                                          &ptr, "default_value", 0, sock->ns.min, sock->ns.max, -1, -1, NULL);
00682                 if (cb)
00683                         uiButSetFunc(bt, cb, arg1, arg2);
00684                 break;
00685                 
00686         case SOCK_VECTOR:
00687                 args= MEM_callocN(sizeof(SocketVectorMenuArgs), "SocketVectorMenuArgs");
00688         
00689                 args->ptr = ptr;
00690                 args->x = x;
00691                 args->y = y;
00692                 args->width = width;
00693                 args->cb = cb;
00694                 args->arg1 = arg1;
00695                 args->arg2 = arg2;
00696                 
00697                 uiDefBlockButN(block, socket_vector_menu, args, name, 
00698                                            x, y+1, width, NODE_DY-2, 
00699                                            "");
00700                 break;
00701                 
00702         case SOCK_RGBA:
00703                 labelw= width - 40;
00704                 
00705                 bt=uiDefButR(block, COL, B_NODE_EXEC, "",
00706                                          x, y+2, (labelw>0 ? 40 : width), NODE_DY-2, 
00707                                          &ptr, "default_value", 0, sock->ns.min, sock->ns.max, -1, -1, NULL);
00708                 if (cb)
00709                         uiButSetFunc(bt, cb, arg1, arg2);
00710                 
00711                 if (name[0]!='\0' && labelw>0)
00712                         uiDefBut(block, LABEL, 0, name, 
00713                                          x + 40, y+2, labelw, NODE_DY-2, 
00714                                          NULL, 0, 0, 0, 0, "");
00715                 break;
00716         }
00717 }
00718 
00719 static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node)
00720 {
00721         bNodeSocket *sock;
00722         rctf *rct= &node->totr;
00723         float iconofs;
00724         float socket_size= NODE_SOCKSIZE*U.dpi/72;
00725         float iconbutw= 0.8f*UI_UNIT_X;
00726         int color_id= node_get_colorid(node);
00727         char showname[128]; /* 128 used below */
00728         View2D *v2d = &ar->v2d;
00729         
00730         /* hurmf... another candidate for callback, have to see how this works first */
00731         if(node->id && node->block && snode->treetype==NTREE_SHADER)
00732                 nodeShaderSynchronizeID(node, 0);
00733         
00734         /* skip if out of view */
00735         if (node->totr.xmax < ar->v2d.cur.xmin || node->totr.xmin > ar->v2d.cur.xmax ||
00736                         node->totr.ymax < ar->v2d.cur.ymin || node->totr.ymin > ar->v2d.cur.ymax) {
00737                 
00738                 uiEndBlock(C, node->block);
00739                 node->block= NULL;
00740                 return;
00741         }
00742         
00743         uiSetRoundBox(15-4);
00744         ui_dropshadow(rct, BASIS_RAD, snode->aspect, node->flag & SELECT);
00745         
00746         /* header */
00747         if(color_id==TH_NODE)
00748                 UI_ThemeColorShade(color_id, -20);
00749         else
00750                 UI_ThemeColor(color_id);
00751         
00752         if(node->flag & NODE_MUTED)
00753            UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);
00754                 
00755         uiSetRoundBox(3);
00756         uiRoundBox(rct->xmin, rct->ymax-NODE_DY, rct->xmax, rct->ymax, BASIS_RAD);
00757         
00758         /* show/hide icons, note this sequence is copied in do_header_node() node_state.c */
00759         iconofs= rct->xmax - 7.0f;
00760         
00761         if(node->typeinfo->flag & NODE_PREVIEW) {
00762                 int icon_id;
00763                 
00764                 if(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT))
00765                         icon_id= ICON_MATERIAL;
00766                 else
00767                         icon_id= ICON_MATERIAL_DATA;
00768                 iconofs-=iconbutw;
00769                 uiDefIconBut(node->block, LABEL, B_REDR, icon_id, iconofs, rct->ymax-NODE_DY,
00770                                          iconbutw, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, 0.5, "");
00771         }
00772         if(node->type == NODE_GROUP) {
00773                 
00774                 iconofs-=iconbutw;
00775                 uiDefIconBut(node->block, LABEL, B_REDR, ICON_NODETREE, iconofs, rct->ymax-NODE_DY,
00776                                          iconbutw, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, 0.5, "");
00777         }
00778         if(node->typeinfo->flag & NODE_OPTIONS) {
00779                 iconofs-=iconbutw;
00780                 uiDefIconBut(node->block, LABEL, B_REDR, ICON_BUTS, iconofs, rct->ymax-NODE_DY,
00781                                          iconbutw, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, 0.5, "");
00782         }
00783         {       /* always hide/reveal unused sockets */ 
00784                 // XXX re-enable
00785                 /* int shade;
00786                 if(node_has_hidden_sockets(node))
00787                         shade= -40;
00788                 else
00789                         shade= -90; */
00790 
00791                 iconofs-=iconbutw;
00792 
00793                 uiDefIconBut(node->block, LABEL, B_REDR, ICON_PLUS, iconofs, rct->ymax-NODE_DY,
00794                                                   iconbutw, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, 0.5, "");
00795         }
00796         
00797         /* title */
00798         if(node->flag & SELECT) 
00799                 UI_ThemeColor(TH_TEXT_HI);
00800         else
00801                 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
00802         
00803         /* open/close entirely? */
00804         UI_DrawTriIcon(rct->xmin+10.0f, rct->ymax-NODE_DY/2.0f, 'v');
00805         
00806         /* this isn't doing anything for the label, so commenting out
00807         if(node->flag & SELECT) 
00808                 UI_ThemeColor(TH_TEXT_HI);
00809         else
00810                 UI_ThemeColor(TH_TEXT); */
00811         
00812         if (node->label[0]!='\0')
00813                 BLI_strncpy(showname, node->label, sizeof(showname));
00814         else if (node->typeinfo->labelfunc)
00815                 BLI_strncpy(showname, node->typeinfo->labelfunc(node), sizeof(showname));
00816         else
00817                 BLI_strncpy(showname, node->typeinfo->name, sizeof(showname));
00818 
00819         //if(node->flag & NODE_MUTED)
00820         //      sprintf(showname, "[%s]", showname);
00821         
00822         uiDefBut(node->block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(rct->ymax-NODE_DY), 
00823                          (int)(iconofs - rct->xmin-18.0f), NODE_DY,  NULL, 0, 0, 0, 0, "");
00824 
00825         /* body */
00826         UI_ThemeColor4(TH_NODE);
00827         glEnable(GL_BLEND);
00828         uiSetRoundBox(8);
00829         uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax-NODE_DY, BASIS_RAD);
00830         glDisable(GL_BLEND);
00831 
00832         /* scaling indicator */
00833         node_scaling_widget(TH_NODE, snode->aspect, rct->xmax-BASIS_RAD*snode->aspect, rct->ymin, rct->xmax, rct->ymin+BASIS_RAD*snode->aspect);
00834 
00835         /* outline active and selected emphasis */
00836         if( node->flag & (NODE_ACTIVE|SELECT) ) {
00837                 glEnable(GL_BLEND);
00838                 glEnable( GL_LINE_SMOOTH );
00839                         /* using different shades of TH_TEXT_HI for the empasis, like triangle */
00840                         if( node->flag & NODE_ACTIVE ) 
00841                                 UI_ThemeColorShadeAlpha(TH_TEXT_HI, 0, -40);
00842                         else
00843                                 UI_ThemeColorShadeAlpha(TH_TEXT_HI, -20, -120);
00844                         uiSetRoundBox(15-4); // round all corners except lower right
00845                         uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
00846                         
00847                 glDisable( GL_LINE_SMOOTH );
00848                 glDisable(GL_BLEND);
00849         }
00850         
00851         /* disable lines */
00852         if(node->flag & NODE_MUTED)
00853                 node_draw_mute_line(v2d, snode, node);
00854 
00855         
00856         /* socket inputs, buttons */
00857         for(sock= node->inputs.first; sock; sock= sock->next) {
00858                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
00859                         socket_circle_draw(sock, socket_size);
00860                         
00861                         if(node->block && sock->link==NULL) {
00862                                 node_draw_socket_button(ntree, sock, sock->name, node->block, sock->locx+NODE_DYS, sock->locy-NODE_DYS, node->width-NODE_DY, node_sync_cb, snode, node);
00863                         }
00864                         else {
00865                                 uiDefBut(node->block, LABEL, 0, sock->name, (short)(sock->locx+7), (short)(sock->locy-9.0f), 
00866                                                  (short)(node->width-NODE_DY), NODE_DY,  NULL, 0, 0, 0, 0, "");
00867                         }
00868                 }
00869         }
00870         
00871         /* socket outputs */
00872         for(sock= node->outputs.first; sock; sock= sock->next) {
00873                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
00874                         float slen;
00875                         int ofs= 0;
00876                         
00877                         socket_circle_draw(sock, socket_size);
00878                         
00879                         UI_ThemeColor(TH_TEXT);
00880                         slen= snode->aspect*UI_GetStringWidth(sock->name);
00881                         while(slen > node->width) {
00882                                 ofs++;
00883                                 slen= snode->aspect*UI_GetStringWidth(sock->name+ofs);
00884                         }
00885                         
00886                         uiDefBut(node->block, LABEL, 0, sock->name+ofs, (short)(sock->locx-15.0f-slen), (short)(sock->locy-9.0f), 
00887                                          (short)(node->width-NODE_DY), NODE_DY,  NULL, 0, 0, 0, 0, "");
00888                 }
00889         }
00890         
00891         /* preview */
00892         if(node->flag & NODE_PREVIEW) {
00893                 BLI_lock_thread(LOCK_PREVIEW);
00894                 if(node->preview && node->preview->rect && !BLI_rctf_is_empty(&node->prvr))
00895                         node_draw_preview(node->preview, &node->prvr);
00896                 BLI_unlock_thread(LOCK_PREVIEW);
00897         }
00898         
00899         UI_ThemeClearColor(color_id);
00900                 
00901         uiEndBlock(C, node->block);
00902         uiDrawBlock(C, node->block);
00903         node->block= NULL;
00904 }
00905 
00906 static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, bNode *node)
00907 {
00908         bNodeSocket *sock;
00909         rctf *rct= &node->totr;
00910         float dx, centy= 0.5f*(rct->ymax+rct->ymin);
00911         float hiddenrad= 0.5f*(rct->ymax-rct->ymin);
00912         float socket_size= NODE_SOCKSIZE*U.dpi/72;
00913         int color_id= node_get_colorid(node);
00914         char showname[128];     /* 128 is used below */
00915         
00916         /* shadow */
00917         uiSetRoundBox(15);
00918         ui_dropshadow(rct, hiddenrad, snode->aspect, node->flag & SELECT);
00919 
00920         /* body */
00921         UI_ThemeColor(color_id);
00922         if(node->flag & NODE_MUTED)
00923            UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);     
00924         uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
00925         
00926         /* outline active and selected emphasis */
00927         if( node->flag & (NODE_ACTIVE|SELECT) ) {
00928                 glEnable(GL_BLEND);
00929                 glEnable( GL_LINE_SMOOTH );
00930                         /* using different shades of TH_TEXT_HI for the empasis, like triangle */
00931                         if( node->flag & NODE_ACTIVE ) 
00932                                 UI_ThemeColorShadeAlpha(TH_TEXT_HI, 0, -40);
00933                         else
00934                                 UI_ThemeColorShadeAlpha(TH_TEXT_HI, -20, -120);
00935                         uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
00936                 glDisable( GL_LINE_SMOOTH );
00937                 glDisable(GL_BLEND);
00938         }
00939         
00940         /* title */
00941         if(node->flag & SELECT) 
00942                 UI_ThemeColor(TH_TEXT_HI);
00943         else
00944                 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
00945         
00946         /* open entirely icon */
00947         UI_DrawTriIcon(rct->xmin+10.0f, centy, 'h');    
00948         
00949         /* disable lines */
00950         if(node->flag & NODE_MUTED)
00951                 node_draw_mute_line(&ar->v2d, snode, node);     
00952         
00953         if(node->flag & SELECT) 
00954                 UI_ThemeColor(TH_TEXT_HI);
00955         else
00956                 UI_ThemeColor(TH_TEXT);
00957         
00958         if(node->miniwidth>0.0f) {
00959                 if (node->label[0]!='\0')
00960                         BLI_strncpy(showname, node->label, sizeof(showname));
00961                 else if (node->typeinfo->labelfunc)
00962                         BLI_strncpy(showname, node->typeinfo->labelfunc(node), sizeof(showname));
00963                 else
00964                         BLI_strncpy(showname, node->typeinfo->name, sizeof(showname));
00965                 
00966                 //if(node->flag & NODE_MUTED)
00967                 //      sprintf(showname, "[%s]", showname);
00968 
00969                 uiDefBut(node->block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(centy-10), 
00970                                  (int)(rct->xmax - rct->xmin-18.0f -12.0f), NODE_DY,  NULL, 0, 0, 0, 0, "");
00971         }       
00972 
00973         /* scale widget thing */
00974         UI_ThemeColorShade(color_id, -10);      
00975         dx= 10.0f;
00976         fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
00977         fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
00978         
00979         UI_ThemeColorShade(color_id, +30);
00980         dx-= snode->aspect;
00981         fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
00982         fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
00983         
00984         /* sockets */
00985         for(sock= node->inputs.first; sock; sock= sock->next) {
00986                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
00987                         socket_circle_draw(sock, socket_size);
00988         }
00989         
00990         for(sock= node->outputs.first; sock; sock= sock->next) {
00991                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
00992                         socket_circle_draw(sock, socket_size);
00993         }
00994         
00995         uiEndBlock(C, node->block);
00996         uiDrawBlock(C, node->block);
00997         node->block= NULL;
00998 }
00999 
01000 static void node_draw_nodetree(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree)
01001 {
01002         bNode *node;
01003         bNodeLink *link;
01004         int a;
01005         
01006         if(ntree==NULL) return;         /* groups... */
01007         
01008         /* node lines */
01009         glEnable(GL_BLEND);
01010         glEnable(GL_LINE_SMOOTH);
01011         for(link= ntree->links.first; link; link= link->next)
01012                 node_draw_link(&ar->v2d, snode, link);
01013         glDisable(GL_LINE_SMOOTH);
01014         glDisable(GL_BLEND);
01015         
01016         /* not selected first */
01017         for(a=0, node= ntree->nodes.first; node; node= node->next, a++) {
01018                 node->nr= a;            /* index of node in list, used for exec event code */
01019                 if(!(node->flag & SELECT)) {
01020                         if(node->flag & NODE_GROUP_EDIT);
01021                         else if(node->flag & NODE_HIDDEN)
01022                                 node_draw_hidden(C, ar, snode, node);
01023                         else
01024                                 node_draw_basis(C, ar, snode, ntree, node);
01025                 }
01026         }
01027         
01028         /* selected */
01029         for(node= ntree->nodes.first; node; node= node->next) {
01030                 if(node->flag & SELECT) {
01031                         if(node->flag & NODE_GROUP_EDIT);
01032                         else if(node->flag & NODE_HIDDEN)
01033                                 node_draw_hidden(C, ar, snode, node);
01034                         else
01035                                 node_draw_basis(C, ar, snode, ntree, node);
01036                 }
01037         }       
01038 }
01039 
01040 static void group_verify_cb(bContext *UNUSED(C), void *UNUSED(snode_v), void *ngroup_v)
01041 {
01042         bNodeTree *ngroup= (bNodeTree*)ngroup_v;
01043         
01044         nodeGroupVerify(ngroup);
01045 }
01046 
01047 /* groups are, on creation, centered around 0,0 */
01048 static void node_draw_group(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *gnode)
01049 {
01050         bNodeTree *ngroup= (bNodeTree *)gnode->id;
01051         bNodeSocket *sock;
01052         uiLayout *layout;
01053         PointerRNA ptr;
01054         uiBut *bt;
01055         rctf rect= gnode->totr;
01056         float socket_size= NODE_SOCKSIZE*U.dpi/72;
01057         float node_group_frame= U.dpi*NODE_GROUP_FRAME/72;
01058         float group_header= 26*U.dpi/72;
01059         float arrowbutw= 0.8f*UI_UNIT_X;
01060         /* layout stuff for buttons on group left frame */
01061         float col1= 6, colw1= 0.6f*node_group_frame;
01062         float col2= col1 + colw1+6;
01063         float col3= node_group_frame - arrowbutw - 6;
01064         /* layout stuff for buttons on group right frame */
01065         float cor1= 6;
01066         float cor2= cor1 + arrowbutw + 6;
01067         float cor3= cor2 + arrowbutw + 6, corw3= node_group_frame - cor3-6;
01068         
01069         int index;
01070         
01071         /* backdrop header */
01072         glEnable(GL_BLEND);
01073         uiSetRoundBox(3);
01074         UI_ThemeColorShadeAlpha(TH_NODE_GROUP, 0, -70);
01075         uiDrawBox(GL_POLYGON, rect.xmin-node_group_frame, rect.ymax, rect.xmax+node_group_frame, rect.ymax+group_header, BASIS_RAD);
01076         
01077         /* backdrop body */
01078         UI_ThemeColorShadeAlpha(TH_BACK, -8, -70);
01079         uiSetRoundBox(0);
01080         uiDrawBox(GL_POLYGON, rect.xmin, rect.ymin, rect.xmax, rect.ymax, BASIS_RAD);
01081 
01082         /* input column */
01083         UI_ThemeColorShadeAlpha(TH_BACK, 10, -50);
01084         uiSetRoundBox(8);
01085         uiDrawBox(GL_POLYGON, rect.xmin-node_group_frame, rect.ymin, rect.xmin, rect.ymax, BASIS_RAD);
01086 
01087         /* output column */
01088         UI_ThemeColorShadeAlpha(TH_BACK, 10, -50);
01089         uiSetRoundBox(4);
01090         uiDrawBox(GL_POLYGON, rect.xmax, rect.ymin, rect.xmax+node_group_frame, rect.ymax, BASIS_RAD);
01091 
01092         /* input column separator */
01093         glColor4ub(200, 200, 200, 140);
01094         glBegin(GL_LINES);
01095         glVertex2f(rect.xmin, rect.ymin);
01096         glVertex2f(rect.xmin, rect.ymax);
01097         glEnd();
01098 
01099         /* output column separator */
01100         glColor4ub(200, 200, 200, 140);
01101         glBegin(GL_LINES);
01102         glVertex2f(rect.xmax, rect.ymin);
01103         glVertex2f(rect.xmax, rect.ymax);
01104         glEnd();
01105 
01106         /* group node outline */
01107         uiSetRoundBox(15);
01108         glColor4ub(200, 200, 200, 140);
01109         glEnable( GL_LINE_SMOOTH );
01110         uiDrawBox(GL_LINE_LOOP, rect.xmin-node_group_frame, rect.ymin, rect.xmax+node_group_frame, rect.ymax+group_header, BASIS_RAD);
01111         glDisable( GL_LINE_SMOOTH );
01112         glDisable(GL_BLEND);
01113         
01114         /* backdrop title */
01115         UI_ThemeColor(TH_TEXT_HI);
01116 
01117         layout = uiBlockLayout(gnode->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, (short)(rect.xmin+15), (short)(rect.ymax+group_header),
01118                                                    MIN2((int)(rect.xmax - rect.xmin-18.0f), node_group_frame+20), group_header, U.uistyles.first);
01119         RNA_pointer_create(&ntree->id, &RNA_Node, gnode, &ptr);
01120         uiTemplateIDBrowse(layout, (bContext*)C, &ptr, "node_tree", NULL, NULL, NULL);
01121         uiBlockLayoutResolve(gnode->block, NULL, NULL);
01122 
01123         /* draw the internal tree nodes and links */
01124         node_draw_nodetree(C, ar, snode, ngroup);
01125 
01126         /* group sockets */
01127         for(sock=ngroup->inputs.first, index=0; sock; sock=sock->next, ++index) {
01128                 float locx= sock->locx - node_group_frame;
01129                 
01130                 socket_circle_draw(sock, socket_size);
01131                 /* small hack to use socket_circle_draw function with offset */
01132                 sock->locx -= node_group_frame;
01133                 socket_circle_draw(sock, socket_size);
01134                 sock->locx += node_group_frame;
01135 
01136                 bt = uiDefBut(gnode->block, TEX, 0, "", 
01137                                           locx+col1, sock->locy+1, colw1, NODE_DY,
01138                                           sock->name, 0, 31, 0, 0, "");
01139                 uiButSetFunc(bt, group_verify_cb, snode, ngroup);
01140                 
01141                 node_draw_socket_button(ngroup, sock, "", gnode->block,
01142                                                                 locx+col1, sock->locy-NODE_DY, colw1,
01143                                                                 NULL, NULL, NULL);
01144 
01145                 uiBlockSetDirection(gnode->block, UI_TOP);
01146                 uiBlockBeginAlign(gnode->block);
01147                 bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_move_up", 0, ICON_TRIA_UP,
01148                                                    locx+col2, sock->locy, arrowbutw, arrowbutw, "");
01149                 if (!sock->prev)
01150                         uiButSetFlag(bt, UI_BUT_DISABLED);
01151                 RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index);
01152                 RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", SOCK_IN);
01153                 bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_move_down", 0, ICON_TRIA_DOWN,
01154                                                    locx+col2, sock->locy-arrowbutw, arrowbutw, arrowbutw, "");
01155                 if (!sock->next)
01156                         uiButSetFlag(bt, UI_BUT_DISABLED);
01157                 RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index);
01158                 RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", SOCK_IN);
01159                 uiBlockEndAlign(gnode->block);
01160                 uiBlockSetDirection(gnode->block, 0);
01161                 
01162                 uiBlockSetEmboss(gnode->block, UI_EMBOSSN);
01163                 bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_remove", 0, ICON_X,
01164                                                    locx+col3, sock->locy-0.5f*arrowbutw, arrowbutw, arrowbutw, "");
01165                 RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index);
01166                 RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", SOCK_IN);
01167                 uiBlockSetEmboss(gnode->block, UI_EMBOSS);
01168         }
01169         
01170         for(sock=ngroup->outputs.first, index=0; sock; sock=sock->next, ++index) {
01171                 float locx= sock->locx;
01172                 
01173                 socket_circle_draw(sock, socket_size);
01174                 /* small hack to use socket_circle_draw function with offset */
01175                 sock->locx += node_group_frame;
01176                 socket_circle_draw(sock, socket_size);
01177                 sock->locx -= node_group_frame;
01178                 
01179                 uiBlockSetEmboss(gnode->block, UI_EMBOSSN);
01180                 bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_remove", 0, ICON_X,
01181                                                    locx+col1, sock->locy-0.5f*arrowbutw, arrowbutw, arrowbutw, "");
01182                 RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index);
01183                 RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", SOCK_OUT);
01184                 uiBlockSetEmboss(gnode->block, UI_EMBOSS);
01185                 
01186                 uiBlockSetDirection(gnode->block, UI_TOP);
01187                 uiBlockBeginAlign(gnode->block);
01188                 bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_move_up", 0, ICON_TRIA_UP,
01189                                                    locx+cor2, sock->locy, arrowbutw, arrowbutw, "");
01190                 if (!sock->prev)
01191                         uiButSetFlag(bt, UI_BUT_DISABLED);
01192                 RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index);
01193                 RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", SOCK_OUT);
01194                 bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_move_down", 0, ICON_TRIA_DOWN,
01195                                                    locx+cor2, sock->locy-arrowbutw, arrowbutw, arrowbutw, "");
01196                 if (!sock->next)
01197                         uiButSetFlag(bt, UI_BUT_DISABLED);
01198                 RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index);
01199                 RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", SOCK_OUT);
01200                 uiBlockEndAlign(gnode->block);
01201                 uiBlockSetDirection(gnode->block, 0);
01202                 
01203                 if (sock->link) {
01204                         bt = uiDefBut(gnode->block, TEX, 0, "", 
01205                                                   locx+cor3, sock->locy-NODE_DYS+1, corw3, NODE_DY,
01206                                                   sock->name, 0, 31, 0, 0, "");
01207                         uiButSetFunc(bt, group_verify_cb, snode, ngroup);
01208                 }
01209                 else {
01210                         bt = uiDefBut(gnode->block, TEX, 0, "", 
01211                                                   locx+cor3, sock->locy+1, corw3, NODE_DY,
01212                                                   sock->name, 0, 31, 0, 0, "");
01213                         uiButSetFunc(bt, group_verify_cb, snode, ngroup);
01214                         
01215                         node_draw_socket_button(ngroup, sock, "", gnode->block, locx+cor3, sock->locy-NODE_DY, corw3, NULL, NULL, NULL);
01216                 }
01217         }
01218         
01219         uiEndBlock(C, gnode->block);
01220         uiDrawBlock(C, gnode->block);
01221         gnode->block= NULL;
01222 }
01223 
01224 void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d)
01225 {
01226         View2DScrollers *scrollers;
01227         SpaceNode *snode= CTX_wm_space_node(C);
01228         Scene *scene= CTX_data_scene(C);
01229         int color_manage = scene->r.color_mgt_flag & R_COLOR_MANAGEMENT;
01230         bNodeLinkDrag *nldrag;
01231         
01232         UI_ThemeClearColor(TH_BACK);
01233         glClear(GL_COLOR_BUFFER_BIT);
01234 
01235         UI_view2d_view_ortho(v2d);
01236         
01237         //uiFreeBlocksWin(&sa->uiblocks, sa->win);
01238 
01239         /* only set once */
01240         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
01241         glEnable(GL_MAP1_VERTEX_3);
01242 
01243         /* aspect+font, set each time */
01244         snode->aspect= (v2d->cur.xmax - v2d->cur.xmin)/((float)ar->winx);
01245         // XXX snode->curfont= uiSetCurFont_ext(snode->aspect);
01246 
01247         UI_view2d_constant_grid_draw(v2d);
01248         /* backdrop */
01249         draw_nodespace_back_pix(ar, snode, color_manage);
01250         
01251         /* nodes */
01252         snode_set_context(snode, CTX_data_scene(C));
01253         
01254         if(snode->nodetree) {
01255                 bNode *node;
01256                 
01257                 /* init ui blocks for opened node group trees first 
01258                  * so they're in the correct depth stack order */
01259                 for(node= snode->nodetree->nodes.first; node; node= node->next) {
01260                         if(node->flag & NODE_GROUP_EDIT)
01261                                 node_uiblocks_init(C, (bNodeTree *)node->id);
01262                 }
01263 
01264                 node_uiblocks_init(C, snode->nodetree);
01265                 
01266                 
01267                 /* for now, we set drawing coordinates on each redraw */
01268                 for(node= snode->nodetree->nodes.first; node; node= node->next) {
01269                         if(node->flag & NODE_GROUP_EDIT)
01270                                 node_update_group(C, snode->nodetree, node);
01271                         else if(node->flag & NODE_HIDDEN)
01272                                 node_update_hidden(node);
01273                         else
01274                                 node_update(C, snode->nodetree, node);
01275                 }
01276 
01277                 node_draw_nodetree(C, ar, snode, snode->nodetree);
01278                         
01279                 /* active group */
01280                 for(node= snode->nodetree->nodes.first; node; node= node->next) {
01281                         if(node->flag & NODE_GROUP_EDIT)
01282                                 node_draw_group(C, ar, snode, snode->nodetree, node);
01283                 }
01284         }
01285         
01286         /* temporary links */
01287         glEnable(GL_BLEND);
01288         glEnable(GL_LINE_SMOOTH);
01289         for(nldrag= snode->linkdrag.first; nldrag; nldrag= nldrag->next)
01290                 node_draw_link(&ar->v2d, snode, nldrag->link);
01291         glDisable(GL_LINE_SMOOTH);
01292         glDisable(GL_BLEND);
01293         
01294         /* draw grease-pencil ('canvas' strokes) */
01295         if (/*(snode->flag & SNODE_DISPGP) &&*/ (snode->nodetree))
01296                 draw_gpencil_view2d((bContext*)C, 1);
01297         
01298         /* reset view matrix */
01299         UI_view2d_view_restore(C);
01300         
01301         /* draw grease-pencil (screen strokes, and also paintbuffer) */
01302         if (/*(snode->flag & SNODE_DISPGP) && */(snode->nodetree))
01303                 draw_gpencil_view2d((bContext*)C, 0);
01304         
01305         /* scrollers */
01306         scrollers= UI_view2d_scrollers_calc(C, v2d, 10, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
01307         UI_view2d_scrollers_draw(C, v2d, scrollers);
01308         UI_view2d_scrollers_free(scrollers);
01309 }