Blender  V2.59
space_node.c
Go to the documentation of this file.
00001 /*
00002  * $Id: space_node.c 38442 2011-07-17 08:38:04Z nazgul $
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  * 
00024  * Contributor(s): Blender Foundation
00025  *
00026  * ***** END GPL LICENSE BLOCK *****
00027  */
00028 
00034 #include <string.h>
00035 #include <stdio.h>
00036 
00037 #include "DNA_node_types.h"
00038 #include "DNA_object_types.h"
00039 #include "DNA_material_types.h"
00040 #include "DNA_scene_types.h"
00041 
00042 #include "MEM_guardedalloc.h"
00043 
00044 #include "BLI_blenlib.h"
00045 #include "BLI_math.h"
00046 #include "BLI_rand.h"
00047 #include "BLI_utildefines.h"
00048 
00049 #include "BKE_context.h"
00050 #include "BKE_screen.h"
00051 #include "BKE_node.h"
00052 
00053 #include "ED_space_api.h"
00054 #include "ED_render.h"
00055 #include "ED_screen.h"
00056 
00057 
00058 #include "WM_api.h"
00059 #include "WM_types.h"
00060 
00061 #include "UI_resources.h"
00062 #include "UI_view2d.h"
00063 
00064 #include "RNA_access.h"
00065 
00066 #include "node_intern.h"        // own include
00067 
00068 /* ******************** manage regions ********************* */
00069 
00070 ARegion *node_has_buttons_region(ScrArea *sa)
00071 {
00072         ARegion *ar, *arnew;
00073 
00074         ar= BKE_area_find_region_type(sa, RGN_TYPE_UI);
00075         if(ar) return ar;
00076         
00077         /* add subdiv level; after header */
00078         ar= BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
00079 
00080         /* is error! */
00081         if(ar==NULL) return NULL;
00082         
00083         arnew= MEM_callocN(sizeof(ARegion), "buttons for node");
00084         
00085         BLI_insertlinkafter(&sa->regionbase, ar, arnew);
00086         arnew->regiontype= RGN_TYPE_UI;
00087         arnew->alignment= RGN_ALIGN_RIGHT;
00088         
00089         arnew->flag = RGN_FLAG_HIDDEN;
00090         
00091         return arnew;
00092 }
00093 
00094 /* ******************** default callbacks for node space ***************** */
00095 
00096 static SpaceLink *node_new(const bContext *UNUSED(C))
00097 {
00098         ARegion *ar;
00099         SpaceNode *snode;
00100         
00101         snode= MEM_callocN(sizeof(SpaceNode), "initnode");
00102         snode->spacetype= SPACE_NODE;   
00103         
00104         /* backdrop */
00105         snode->zoom = 1.0f;
00106         
00107         /* header */
00108         ar= MEM_callocN(sizeof(ARegion), "header for node");
00109         
00110         BLI_addtail(&snode->regionbase, ar);
00111         ar->regiontype= RGN_TYPE_HEADER;
00112         ar->alignment= RGN_ALIGN_BOTTOM;
00113         
00114         /* buttons/list view */
00115         ar= MEM_callocN(sizeof(ARegion), "buttons for node");
00116         
00117         BLI_addtail(&snode->regionbase, ar);
00118         ar->regiontype= RGN_TYPE_UI;
00119         ar->alignment= RGN_ALIGN_RIGHT;
00120         ar->flag = RGN_FLAG_HIDDEN;
00121         
00122         /* main area */
00123         ar= MEM_callocN(sizeof(ARegion), "main area for node");
00124         
00125         BLI_addtail(&snode->regionbase, ar);
00126         ar->regiontype= RGN_TYPE_WINDOW;
00127         
00128         ar->v2d.tot.xmin=  -256.0f;
00129         ar->v2d.tot.ymin=  -256.0f;
00130         ar->v2d.tot.xmax= 768.0f;
00131         ar->v2d.tot.ymax= 768.0f;
00132         
00133         ar->v2d.cur.xmin=  -256.0f;
00134         ar->v2d.cur.ymin=  -256.0f;
00135         ar->v2d.cur.xmax= 768.0f;
00136         ar->v2d.cur.ymax= 768.0f;
00137         
00138         ar->v2d.min[0]= 1.0f;
00139         ar->v2d.min[1]= 1.0f;
00140         
00141         ar->v2d.max[0]= 32000.0f;
00142         ar->v2d.max[1]= 32000.0f;
00143         
00144         ar->v2d.minzoom= 0.09f;
00145         ar->v2d.maxzoom= 2.31f;
00146         
00147         ar->v2d.scroll= (V2D_SCROLL_RIGHT|V2D_SCROLL_BOTTOM);
00148         ar->v2d.keepzoom= V2D_LIMITZOOM|V2D_KEEPASPECT;
00149         ar->v2d.keeptot= 0;
00150         
00151         return (SpaceLink *)snode;
00152 }
00153 
00154 /* not spacelink itself */
00155 static void node_free(SpaceLink *UNUSED(sl))
00156 {       
00157         
00158 }
00159 
00160 
00161 /* spacetype; init callback */
00162 static void node_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
00163 {
00164 
00165 }
00166 
00167 static void node_area_listener(ScrArea *sa, wmNotifier *wmn)
00168 {
00169         /* note, ED_area_tag_refresh will re-execute compositor */
00170         SpaceNode *snode= sa->spacedata.first;
00171         int type= snode->treetype;
00172         
00173         /* preview renders */
00174         switch(wmn->category) {
00175                 case NC_SCENE:
00176                         switch (wmn->data) {
00177                                 case ND_NODES:
00178                                 case ND_FRAME:
00179                                         ED_area_tag_refresh(sa);
00180                                         break;
00181                                 case ND_TRANSFORM_DONE:
00182                                         if(type==NTREE_COMPOSIT) {
00183                                                 if(snode->flag & SNODE_AUTO_RENDER) {
00184                                                         snode->recalc= 1;
00185                                                         ED_area_tag_refresh(sa);
00186                                                 }
00187                                         }
00188                                         break;
00189                         }
00190                         break;
00191                 case NC_WM:
00192                         if(wmn->data==ND_FILEREAD)
00193                                 ED_area_tag_refresh(sa);
00194                         break;
00195                 
00196                 /* future: add ID checks? */
00197                 case NC_MATERIAL:
00198                         if(type==NTREE_SHADER) {
00199                                 if(wmn->data==ND_SHADING)
00200                                         ED_area_tag_refresh(sa);
00201                                 else if(wmn->data==ND_SHADING_DRAW)
00202                                         ED_area_tag_refresh(sa);
00203                                 else if(wmn->action==NA_ADDED && snode->edittree)
00204                                         nodeSetActiveID(snode->edittree, ID_MA, wmn->reference);
00205                                         
00206                         }
00207                         break;
00208                 case NC_TEXTURE:
00209                         if(type==NTREE_SHADER || type==NTREE_TEXTURE) {
00210                                 if(wmn->data==ND_NODES)
00211                                         ED_area_tag_refresh(sa);
00212                         }
00213                         break;
00214                 case NC_TEXT:
00215                         /* pynodes */
00216                         if(wmn->data==ND_SHADING)
00217                                 ED_area_tag_refresh(sa);
00218                         break;
00219                 case NC_SPACE:
00220                         if(wmn->data==ND_SPACE_NODE)
00221                                 ED_area_tag_refresh(sa);
00222                         else if(wmn->data==ND_SPACE_NODE_VIEW)
00223                                 ED_area_tag_redraw(sa);
00224                         break;
00225                 case NC_NODE:
00226                         if (wmn->action == NA_EDITED)
00227                                 ED_area_tag_refresh(sa);
00228                         else if (wmn->action == NA_SELECTED)
00229                                 ED_area_tag_redraw(sa);
00230                         break;
00231                 case NC_SCREEN:
00232                         switch(wmn->data) {
00233                                 case ND_ANIMPLAY:
00234                                         ED_area_tag_refresh(sa);
00235                                         break;
00236                         }
00237                         break;
00238 
00239                 case NC_IMAGE:
00240                         if (wmn->action == NA_EDITED) {
00241                                 if(type==NTREE_COMPOSIT) {
00242                                         Scene *scene= wmn->window->screen->scene;
00243                                         
00244                                         /* note that NodeTagIDChanged is already called by BKE_image_signal() on all
00245                                          * scenes so really this is just to know if the images is used in the compo else
00246                                          * painting on images could become very slow when the compositor is open. */
00247                                         if(NodeTagIDChanged(scene->nodetree, wmn->reference))
00248                                                 ED_area_tag_refresh(sa);
00249                                 }
00250                         }
00251                         break;
00252         }
00253 }
00254 
00255 static void node_area_refresh(const struct bContext *C, struct ScrArea *sa)
00256 {
00257         /* default now: refresh node is starting preview */
00258         SpaceNode *snode= sa->spacedata.first;
00259 
00260         snode_set_context(snode, CTX_data_scene(C));
00261         
00262         if(snode->nodetree) {
00263                 if(snode->treetype==NTREE_SHADER) {
00264                         Material *ma= (Material *)snode->id;
00265                         if(ma->use_nodes)
00266                                 ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
00267                 }
00268                 else if(snode->treetype==NTREE_COMPOSIT) {
00269                         Scene *scene= (Scene *)snode->id;
00270                         if(scene->use_nodes) {
00271                                 /* recalc is set on 3d view changes for auto compo */
00272                                 if(snode->recalc) {
00273                                         snode->recalc= 0;
00274                                         node_render_changed_exec((struct bContext*)C, NULL);
00275                                 }
00276                                 else 
00277                                         snode_composite_job(C, sa);
00278                         }
00279                 }
00280                 else if(snode->treetype==NTREE_TEXTURE) {
00281                         Tex *tex= (Tex *)snode->id;
00282                         if(tex->use_nodes) {
00283                                 ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
00284                         }
00285                 }
00286         }
00287 }
00288 
00289 static SpaceLink *node_duplicate(SpaceLink *sl)
00290 {
00291         SpaceNode *snoden= MEM_dupallocN(sl);
00292         
00293         /* clear or remove stuff from old */
00294         snoden->nodetree= NULL;
00295         snoden->linkdrag.first= snoden->linkdrag.last= NULL;
00296         
00297         return (SpaceLink *)snoden;
00298 }
00299 
00300 
00301 /* add handlers, stuff you only do once or on area/region changes */
00302 static void node_buttons_area_init(wmWindowManager *wm, ARegion *ar)
00303 {
00304         wmKeyMap *keymap;
00305 
00306         ED_region_panels_init(wm, ar);
00307         
00308         keymap= WM_keymap_find(wm->defaultconf, "Node Generic", SPACE_NODE, 0);
00309         WM_event_add_keymap_handler(&ar->handlers, keymap);
00310 }
00311 
00312 static void node_buttons_area_draw(const bContext *C, ARegion *ar)
00313 {
00314         ED_region_panels(C, ar, 1, NULL, -1);
00315 }
00316 
00317 /* Initialise main area, setting handlers. */
00318 static void node_main_area_init(wmWindowManager *wm, ARegion *ar)
00319 {
00320         wmKeyMap *keymap;
00321         ListBase *lb;
00322         
00323         UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
00324         
00325         /* own keymaps */
00326         keymap= WM_keymap_find(wm->defaultconf, "Node Generic", SPACE_NODE, 0);
00327         WM_event_add_keymap_handler(&ar->handlers, keymap);
00328         
00329         keymap= WM_keymap_find(wm->defaultconf, "Node Editor", SPACE_NODE, 0);
00330         WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
00331         
00332         /* add drop boxes */
00333         lb = WM_dropboxmap_find("Node Editor", SPACE_NODE, RGN_TYPE_WINDOW);
00334         
00335         WM_event_add_dropbox_handler(&ar->handlers, lb);
00336 }
00337 
00338 static void node_main_area_draw(const bContext *C, ARegion *ar)
00339 {
00340         View2D *v2d= &ar->v2d;
00341         
00342         drawnodespace(C, ar, v2d);
00343 }
00344 
00345 
00346 /* ************* dropboxes ************* */
00347 
00348 static int node_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
00349 {
00350         if(drag->type==WM_DRAG_ID) {
00351                 ID *id= (ID *)drag->poin;
00352                 if( GS(id->name)==ID_IM )
00353                         return 1;
00354         }
00355         else if(drag->type==WM_DRAG_PATH){
00356                 if(ELEM(drag->icon, 0, ICON_FILE_IMAGE))        /* rule might not work? */
00357                         return 1;
00358         }
00359         return 0;
00360 }
00361 
00362 static void node_id_path_drop_copy(wmDrag *drag, wmDropBox *drop)
00363 {
00364         ID *id= (ID *)drag->poin;
00365         
00366         if(id) {
00367                 RNA_string_set(drop->ptr, "name", id->name+2);
00368         }
00369         if (drag->path[0]) {
00370                 RNA_string_set(drop->ptr, "filepath", drag->path);
00371         }
00372 }
00373 
00374 /* this region dropbox definition */
00375 static void node_dropboxes(void)
00376 {
00377         ListBase *lb= WM_dropboxmap_find("Node Editor", SPACE_NODE, RGN_TYPE_WINDOW);
00378         
00379         WM_dropbox_add(lb, "NODE_OT_add_file", node_drop_poll, node_id_path_drop_copy);
00380         
00381 }
00382 
00383 /* ************* end drop *********** */
00384 
00385 
00386 /* add handlers, stuff you only do once or on area/region changes */
00387 static void node_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
00388 {
00389         ED_region_header_init(ar);
00390 }
00391 
00392 static void node_header_area_draw(const bContext *C, ARegion *ar)
00393 {
00394         SpaceNode *snode= CTX_wm_space_node(C);
00395         Scene *scene= CTX_data_scene(C);
00396 
00397         /* find and set the context */
00398         snode_set_context(snode, scene);
00399 
00400         ED_region_header(C, ar);
00401 }
00402 
00403 /* used for header + main area */
00404 static void node_region_listener(ARegion *ar, wmNotifier *wmn)
00405 {
00406         /* context changes */
00407         switch(wmn->category) {
00408                 case NC_SPACE:
00409                         if(wmn->data==ND_SPACE_NODE)
00410                                 ED_region_tag_redraw(ar);
00411                         break;
00412                 case NC_SCREEN:
00413                         if(wmn->data == ND_GPENCIL)     
00414                                 ED_region_tag_redraw(ar);
00415                         break;
00416                 case NC_SCENE:
00417                 case NC_MATERIAL:
00418                 case NC_TEXTURE:
00419                 case NC_NODE:
00420                         ED_region_tag_redraw(ar);
00421                         break;
00422                 case NC_ID:
00423                         if(wmn->action == NA_RENAME)
00424                                 ED_region_tag_redraw(ar);
00425                         break;
00426         }
00427 }
00428 
00429 const char *node_context_dir[] = {"selected_nodes", NULL};
00430 
00431 static int node_context(const bContext *C, const char *member, bContextDataResult *result)
00432 {
00433         SpaceNode *snode= CTX_wm_space_node(C);
00434         
00435         if(CTX_data_dir(member)) {
00436                 CTX_data_dir_set(result, node_context_dir);
00437                 return 1;
00438         }
00439         else if(CTX_data_equals(member, "selected_nodes")) {
00440                 bNode *node;
00441                 
00442                 for(next_node(snode->edittree); (node=next_node(NULL));) {
00443                         if(node->flag & NODE_SELECT) {
00444                                 CTX_data_list_add(result, &snode->edittree->id, &RNA_Node, node);
00445                         }
00446                 }
00447                 CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
00448                 return 1;
00449         }
00450         
00451         return 0;
00452 }
00453 
00454 /* only called once, from space/spacetypes.c */
00455 void ED_spacetype_node(void)
00456 {
00457         SpaceType *st= MEM_callocN(sizeof(SpaceType), "spacetype node");
00458         ARegionType *art;
00459         
00460         st->spaceid= SPACE_NODE;
00461         strncpy(st->name, "Node", BKE_ST_MAXNAME);
00462         
00463         st->new= node_new;
00464         st->free= node_free;
00465         st->init= node_init;
00466         st->duplicate= node_duplicate;
00467         st->operatortypes= node_operatortypes;
00468         st->keymap= node_keymap;
00469         st->listener= node_area_listener;
00470         st->refresh= node_area_refresh;
00471         st->context= node_context;
00472         st->dropboxes = node_dropboxes;
00473         
00474         /* regions: main window */
00475         art= MEM_callocN(sizeof(ARegionType), "spacetype node region");
00476         art->regionid = RGN_TYPE_WINDOW;
00477         art->init= node_main_area_init;
00478         art->draw= node_main_area_draw;
00479         art->listener= node_region_listener;
00480         art->keymapflag= ED_KEYMAP_UI|ED_KEYMAP_VIEW2D|ED_KEYMAP_FRAMES|ED_KEYMAP_GPENCIL;
00481 
00482         BLI_addhead(&st->regiontypes, art);
00483         
00484         /* regions: header */
00485         art= MEM_callocN(sizeof(ARegionType), "spacetype node region");
00486         art->regionid = RGN_TYPE_HEADER;
00487         art->prefsizey= HEADERY;
00488         art->keymapflag= ED_KEYMAP_UI|ED_KEYMAP_VIEW2D|ED_KEYMAP_FRAMES|ED_KEYMAP_HEADER;
00489         art->listener= node_region_listener;
00490         art->init= node_header_area_init;
00491         art->draw= node_header_area_draw;
00492         
00493         BLI_addhead(&st->regiontypes, art);
00494 
00495         node_menus_register();
00496         
00497         /* regions: listview/buttons */
00498         art= MEM_callocN(sizeof(ARegionType), "spacetype node region");
00499         art->regionid = RGN_TYPE_UI;
00500         art->prefsizex= 180; // XXX
00501         art->keymapflag= ED_KEYMAP_UI|ED_KEYMAP_FRAMES;
00502         art->listener= node_region_listener;
00503         art->init= node_buttons_area_init;
00504         art->draw= node_buttons_area_draw;
00505         BLI_addhead(&st->regiontypes, art);
00506         
00507         node_buttons_register(art);
00508         
00509         BKE_spacetype_register(st);
00510 }
00511