RenderEngine/Nodes: system to check for shading nodes compatibility
[blender.git] / source / blender / editors / space_node / node_header.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  * 
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_node/node_header.c
28  *  \ingroup spnode
29  */
30
31
32 #include <string.h>
33 #include <stdio.h>
34
35 #include "DNA_space_types.h"
36 #include "DNA_node_types.h"
37 #include "DNA_scene_types.h"
38 #include "DNA_screen_types.h"
39
40 #include "MEM_guardedalloc.h"
41
42 #include "BLI_blenlib.h"
43 #include "BLI_utildefines.h"
44
45 #include "BLF_translation.h"
46
47 #include "BKE_context.h"
48 #include "BKE_global.h"
49 #include "BKE_main.h"
50 #include "BKE_node.h"
51 #include "BKE_scene.h"
52 #include "BKE_screen.h"
53
54 #include "RNA_access.h"
55
56 #include "WM_api.h"
57 #include "WM_types.h"
58
59 #include "UI_interface.h"
60 #include "UI_interface_icons.h"
61 #include "UI_resources.h"
62 #include "UI_view2d.h"
63
64 #include "node_intern.h"
65
66 /* ************************ add menu *********************** */
67
68 static void do_node_add(bContext *C, bNodeTemplate *ntemp)
69 {
70         Main *bmain= CTX_data_main(C);
71         Scene *scene= CTX_data_scene(C);
72         SpaceNode *snode= CTX_wm_space_node(C);
73         ScrArea *sa= CTX_wm_area(C);
74         ARegion *ar;
75         bNode *node;
76         
77         /* get location to add node at mouse */
78         for(ar=sa->regionbase.first; ar; ar=ar->next) {
79                 if(ar->regiontype == RGN_TYPE_WINDOW) {
80                         wmWindow *win= CTX_wm_window(C);
81                         int x= win->eventstate->x - ar->winrct.xmin;
82                         int y= win->eventstate->y - ar->winrct.ymin;
83                         
84                         if(y < 60) y+= 60;
85                         UI_view2d_region_to_view(&ar->v2d, x, y, &snode->mx, &snode->my);
86                 }
87         }
88         
89         /* store selection in temp test flag */
90         for(node= snode->edittree->nodes.first; node; node= node->next) {
91                 if(node->flag & NODE_SELECT) node->flag |= NODE_TEST;
92                 else node->flag &= ~NODE_TEST;
93         }
94         
95         /* node= */ node_add_node(snode, bmain, scene, ntemp, snode->mx, snode->my);
96         
97         /* select previous selection before autoconnect */
98         for(node= snode->edittree->nodes.first; node; node= node->next) {
99                 if(node->flag & NODE_TEST) node->flag |= NODE_SELECT;
100         }
101         
102         /* deselect after autoconnection */
103         for(node= snode->edittree->nodes.first; node; node= node->next) {
104                 if(node->flag & NODE_TEST) node->flag &= ~NODE_SELECT;
105         }
106                 
107         snode_notify(C, snode);
108         snode_dag_update(C, snode);
109 }
110
111 static void do_node_add_static(bContext *C, void *UNUSED(arg), int event)
112 {
113         bNodeTemplate ntemp;
114         ntemp.type = event;
115         do_node_add(C, &ntemp);
116 }
117
118 static void do_node_add_group(bContext *C, void *UNUSED(arg), int event)
119 {
120         SpaceNode *snode= CTX_wm_space_node(C);
121         bNodeTemplate ntemp;
122         
123         if (event>=0) {
124                 ntemp.ngroup= BLI_findlink(&G.main->nodetree, event);
125                 ntemp.type = ntemp.ngroup->nodetype;
126         }
127         else {
128                 ntemp.type = -event;
129                 switch (ntemp.type) {
130                 case NODE_GROUP:
131                         ntemp.ngroup = ntreeAddTree("Group", snode->treetype, ntemp.type);
132                         break;
133                 case NODE_FORLOOP:
134                         ntemp.ngroup = ntreeAddTree("For Loop", snode->treetype, ntemp.type);
135                         break;
136                 case NODE_WHILELOOP:
137                         ntemp.ngroup = ntreeAddTree("While Loop", snode->treetype, ntemp.type);
138                         break;
139                 default:
140                         ntemp.ngroup = NULL;
141                 }
142         }
143         if (!ntemp.ngroup)
144                 return;
145         
146         do_node_add(C, &ntemp);
147 }
148
149 #if 0 /* disabled */
150 static void do_node_add_dynamic(bContext *C, void *UNUSED(arg), int event)
151 {
152         bNodeTemplate ntemp;
153         ntemp.type = NODE_DYNAMIC;
154         do_node_add(C, &ntemp);
155 }
156 #endif
157
158 static int node_tree_has_type(int treetype, int nodetype)
159 {
160         bNodeTreeType *ttype= ntreeGetType(treetype);
161         bNodeType *ntype;
162         for (ntype=ttype->node_types.first; ntype; ntype=ntype->next) {
163                 if (ntype->type==nodetype)
164                         return 1;
165         }
166         return 0;
167 }
168
169 static void node_add_menu(bContext *C, uiLayout *layout, void *arg_nodeclass)
170 {
171         Main *bmain= CTX_data_main(C);
172         Scene *scene= CTX_data_scene(C);
173         SpaceNode *snode= CTX_wm_space_node(C);
174         bNodeTree *ntree;
175         int nodeclass= GET_INT_FROM_POINTER(arg_nodeclass);
176         int event, compatibility= 0;
177         
178         ntree = snode->nodetree;
179         
180         if(!ntree) {
181                 uiItemS(layout);
182                 return;
183         }
184
185         if(ntree->type == NTREE_SHADER) {
186                 if(scene_use_new_shading_nodes(scene))
187                         compatibility= NODE_NEW_SHADING;
188                 else
189                         compatibility= NODE_OLD_SHADING;
190         }
191         
192         if (nodeclass==NODE_CLASS_GROUP) {
193                 bNodeTree *ngroup;
194                 
195                 uiLayoutSetFunc(layout, do_node_add_group, NULL);
196                 
197                 /* XXX hack: negative numbers used for empty group types */
198                 if (node_tree_has_type(ntree->type, NODE_GROUP))
199                         uiItemV(layout, "New Group", 0, -NODE_GROUP);
200                 if (node_tree_has_type(ntree->type, NODE_FORLOOP))
201                         uiItemV(layout, "New For Loop", 0, -NODE_FORLOOP);
202                 if (node_tree_has_type(ntree->type, NODE_WHILELOOP))
203                         uiItemV(layout, "New While Loop", 0, -NODE_WHILELOOP);
204                 uiItemS(layout);
205                 
206                 for(ngroup=bmain->nodetree.first, event=0; ngroup; ngroup= ngroup->id.next, ++event) {
207                         /* only use group trees */
208                         if (ngroup->type==ntree->type && ELEM3(ngroup->nodetype, NODE_GROUP, NODE_FORLOOP, NODE_WHILELOOP)) {
209                                 uiItemV(layout, ngroup->id.name+2, 0, event);
210                         }
211                 }
212         }
213         else if (nodeclass==NODE_DYNAMIC) {
214                 /* disabled */
215         }
216         else {
217                 bNodeType *ntype;
218                 
219                 uiLayoutSetFunc(layout, do_node_add_static, NULL);
220                 
221                 for (ntype=ntreeGetType(ntree->type)->node_types.first; ntype; ntype=ntype->next) {
222                         if (ntype->nclass==nodeclass && ntype->name)
223                                 if (!compatibility || (ntype->compatibility & compatibility))
224                                         uiItemV(layout, ntype->name, 0, ntype->type);
225                 }
226         }
227 }
228
229 static void node_menu_add(const bContext *C, Menu *menu)
230 {
231         Scene *scene= CTX_data_scene(C);
232         SpaceNode *snode= CTX_wm_space_node(C);
233         uiLayout *layout= menu->layout;
234
235         if(!snode->nodetree)
236                 uiLayoutSetActive(layout, 0);
237
238         if(snode->treetype==NTREE_SHADER) {
239                 uiItemMenuF(layout, IFACE_("Input"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_INPUT));
240                 uiItemMenuF(layout, IFACE_("Output"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OUTPUT));
241                 if(scene_use_new_shading_nodes(scene)) {
242                         uiItemMenuF(layout, IFACE_("Shader"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_SHADER));
243                         uiItemMenuF(layout, IFACE_("Texture"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_TEXTURE));
244                 }
245                 uiItemMenuF(layout, IFACE_("Color"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_COLOR));
246                 uiItemMenuF(layout, IFACE_("Vector"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_VECTOR));
247                 uiItemMenuF(layout, IFACE_("Convertor"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_CONVERTOR));
248                 uiItemMenuF(layout, IFACE_("Group"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_GROUP));
249                 //uiItemMenuF(layout, IFACE_("Dynamic"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_DYNAMIC));
250                 uiItemMenuF(layout, IFACE_("Layout"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_LAYOUT));
251         }
252         else if(snode->treetype==NTREE_COMPOSIT) {
253                 uiItemMenuF(layout, IFACE_("Input"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_INPUT));
254                 uiItemMenuF(layout, IFACE_("Output"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OUTPUT));
255                 uiItemMenuF(layout, IFACE_("Color"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_COLOR));
256                 uiItemMenuF(layout, IFACE_("Vector"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_VECTOR));
257                 uiItemMenuF(layout, IFACE_("Filter"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_FILTER));
258                 uiItemMenuF(layout, IFACE_("Convertor"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_CONVERTOR));
259                 uiItemMenuF(layout, IFACE_("Matte"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_MATTE));
260                 uiItemMenuF(layout, IFACE_("Distort"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_DISTORT));
261                 uiItemMenuF(layout, IFACE_("Group"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_GROUP));
262                 uiItemMenuF(layout, IFACE_("Layout"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_LAYOUT));
263         }
264         else if(snode->treetype==NTREE_TEXTURE) {
265                 uiItemMenuF(layout, IFACE_("Input"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_INPUT));
266                 uiItemMenuF(layout, IFACE_("Output"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OUTPUT));
267                 uiItemMenuF(layout, IFACE_("Color"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_COLOR));
268                 uiItemMenuF(layout, IFACE_("Patterns"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_PATTERN));
269                 uiItemMenuF(layout, IFACE_("Textures"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_TEXTURE));
270                 uiItemMenuF(layout, IFACE_("Convertor"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_CONVERTOR));
271                 uiItemMenuF(layout, IFACE_("Distort"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_DISTORT));
272                 uiItemMenuF(layout, IFACE_("Group"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_GROUP));
273                 uiItemMenuF(layout, IFACE_("Layout"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_LAYOUT));
274         }
275 }
276
277 void node_menus_register(void)
278 {
279         MenuType *mt;
280
281         mt= MEM_callocN(sizeof(MenuType), "spacetype node menu add");
282         strcpy(mt->idname, "NODE_MT_add");
283         strcpy(mt->label, "Add");
284         mt->draw= node_menu_add;
285         WM_menutype_add(mt);
286 }
287