Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/space_node')
-rw-r--r--source/blender/editors/space_node/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_node/SConscript2
-rw-r--r--source/blender/editors/space_node/drawnode.c106
-rw-r--r--source/blender/editors/space_node/node_buttons.c37
-rw-r--r--source/blender/editors/space_node/node_draw.c5
-rw-r--r--source/blender/editors/space_node/node_edit.c64
-rw-r--r--source/blender/editors/space_node/node_header.c48
-rw-r--r--source/blender/editors/space_node/node_templates.c647
8 files changed, 851 insertions, 60 deletions
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt
index 8a27bcca8af..f33b784c5d2 100644
--- a/source/blender/editors/space_node/CMakeLists.txt
+++ b/source/blender/editors/space_node/CMakeLists.txt
@@ -25,6 +25,7 @@ set(INC
../../blenlib
../../blenloader
../../imbuf
+ ../../gpu
../../makesdna
../../makesrna
../../nodes
@@ -47,6 +48,7 @@ set(SRC
node_ops.c
node_select.c
node_state.c
+ node_templates.c
space_node.c
node_intern.h
diff --git a/source/blender/editors/space_node/SConscript b/source/blender/editors/space_node/SConscript
index c4309dcfca3..6b72fd066e0 100644
--- a/source/blender/editors/space_node/SConscript
+++ b/source/blender/editors/space_node/SConscript
@@ -4,7 +4,7 @@ Import ('env')
sources = env.Glob('*.c')
incs = '../include ../../blenfont ../../blenlib ../../blenkernel ../../makesdna ../../makesrna ../../imbuf'
-incs += ' ../../nodes ../../render/extern/include ../../blenloader'
+incs += ' ../../nodes ../../render/extern/include ../../blenloader ../../gpu'
incs += ' ../../windowmanager #intern/guardedalloc #extern/glew/include'
defs = []
cf = []
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index b4d89e1365d..4394b4b1920 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -95,6 +95,14 @@ static void node_sync_cb(bContext *UNUSED(C), void *snode_v, void *node_v)
}
}
+static void node_socket_button_label(const bContext *UNUSED(C), uiBlock *block,
+ bNodeTree *UNUSED(ntree), bNode *UNUSED(node), bNodeSocket *sock,
+ const char *UNUSED(name), int x, int y, int width)
+{
+ uiDefBut(block, LABEL, 0, sock->name, x, y, width, NODE_DY, NULL, 0, 0, 0, 0, "");
+}
+
+
static void node_socket_button_default(const bContext *C, uiBlock *block,
bNodeTree *ntree, bNode *node, bNodeSocket *sock,
const char *name, int x, int y, int width)
@@ -938,28 +946,28 @@ static void node_shader_buts_material(uiLayout *layout, bContext *C, PointerRNA
static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ PointerRNA mappingptr = RNA_pointer_get(ptr, "mapping");
uiLayout *row;
uiItemL(layout, "Location:", ICON_NONE);
row= uiLayoutRow(layout, 1);
- uiItemR(row, ptr, "location", 0, "", ICON_NONE);
+ uiItemR(row, &mappingptr, "location", 0, "", ICON_NONE);
uiItemL(layout, "Rotation:", ICON_NONE);
row= uiLayoutRow(layout, 1);
- uiItemR(row, ptr, "rotation", 0, "", ICON_NONE);
+ uiItemR(row, &mappingptr, "rotation", 0, "", ICON_NONE);
uiItemL(layout, "Scale:", ICON_NONE);
row= uiLayoutRow(layout, 1);
- uiItemR(row, ptr, "scale", 0, "", ICON_NONE);
+ uiItemR(row, &mappingptr, "scale", 0, "", ICON_NONE);
row= uiLayoutRow(layout, 1);
- uiItemR(row, ptr, "use_min", 0, "Min", ICON_NONE);
- uiItemR(row, ptr, "min", 0, "", ICON_NONE);
+ uiItemR(row, &mappingptr, "use_min", 0, "Min", ICON_NONE);
+ uiItemR(row, &mappingptr, "min", 0, "", ICON_NONE);
row= uiLayoutRow(layout, 1);
- uiItemR(row, ptr, "use_max", 0, "Max", ICON_NONE);
- uiItemR(row, ptr, "max", 0, "", ICON_NONE);
-
+ uiItemR(row, &mappingptr, "use_max", 0, "Max", ICON_NONE);
+ uiItemR(row, &mappingptr, "max", 0, "", ICON_NONE);
}
static void node_shader_buts_vect_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -986,6 +994,54 @@ static void node_shader_buts_geometry(uiLayout *layout, bContext *C, PointerRNA
}
}
+static void node_shader_buts_attribute(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "attribute_name", 0, "Name", ICON_NONE);
+}
+
+static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ //uiItemR(layout, ptr, "image", 0, "", ICON_NONE);
+ uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
+ uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE);
+}
+
+static void node_shader_buts_tex_sky(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "sun_direction", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "turbidity", 0, NULL, ICON_NONE);
+}
+
+static void node_shader_buts_tex_gradient(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "gradient_type", 0, "", ICON_NONE);
+}
+
+static void node_shader_buts_tex_magic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "turbulence_depth", 0, NULL, ICON_NONE);
+}
+
+static void node_shader_buts_tex_wave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "wave_type", 0, "", ICON_NONE);
+}
+
+static void node_shader_buts_tex_musgrave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "musgrave_type", 0, "", ICON_NONE);
+}
+
+static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "coloring", 0, "", ICON_NONE);
+}
+
+static void node_shader_buts_glossy(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE);
+}
+
static void node_shader_buts_dynamic(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
Main *bmain= CTX_data_main(C);
@@ -1072,6 +1128,37 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_GEOMETRY:
ntype->uifunc= node_shader_buts_geometry;
break;
+ case SH_NODE_ATTRIBUTE:
+ ntype->uifunc= node_shader_buts_attribute;
+ break;
+ case SH_NODE_TEX_SKY:
+ ntype->uifunc= node_shader_buts_tex_sky;
+ break;
+ case SH_NODE_TEX_IMAGE:
+ ntype->uifunc= node_shader_buts_tex_image;
+ break;
+ case SH_NODE_TEX_ENVIRONMENT:
+ ntype->uifunc= node_shader_buts_tex_image;
+ break;
+ case SH_NODE_TEX_GRADIENT:
+ ntype->uifunc= node_shader_buts_tex_gradient;
+ break;
+ case SH_NODE_TEX_MAGIC:
+ ntype->uifunc= node_shader_buts_tex_magic;
+ break;
+ case SH_NODE_TEX_WAVE:
+ ntype->uifunc= node_shader_buts_tex_wave;
+ break;
+ case SH_NODE_TEX_MUSGRAVE:
+ ntype->uifunc= node_shader_buts_tex_musgrave;
+ break;
+ case SH_NODE_TEX_VORONOI:
+ ntype->uifunc= node_shader_buts_tex_voronoi;
+ break;
+ case SH_NODE_BSDF_GLOSSY:
+ case SH_NODE_BSDF_GLASS:
+ ntype->uifunc= node_shader_buts_glossy;
+ break;
case NODE_DYNAMIC:
ntype->uifunc= node_shader_buts_dynamic;
break;
@@ -2089,6 +2176,9 @@ void ED_init_node_butfuncs(void)
case SOCK_RGBA:
stype->buttonfunc = node_socket_button_color;
break;
+ case SOCK_SHADER:
+ stype->buttonfunc = node_socket_button_label;
+ break;
default:
stype->buttonfunc = NULL;
}
diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c
index 3886c709196..15e5719be37 100644
--- a/source/blender/editors/space_node/node_buttons.c
+++ b/source/blender/editors/space_node/node_buttons.c
@@ -45,6 +45,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_global.h"
#include "BKE_node.h"
#include "BKE_screen.h"
@@ -122,6 +123,34 @@ static void active_node_panel(const bContext *C, Panel *pa)
node->typeinfo->uifunc(layout, (bContext *)C, &ptr);
}
+static int node_sockets_poll(const bContext *C, PanelType *UNUSED(pt))
+{
+ SpaceNode *snode= CTX_wm_space_node(C);
+
+ return (snode && snode->nodetree && G.rt == 777);
+}
+
+static void node_sockets_panel(const bContext *C, Panel *pa)
+{
+ SpaceNode *snode= CTX_wm_space_node(C);
+ bNodeTree *ntree= (snode) ? snode->edittree : NULL;
+ bNode *node = (ntree) ? nodeGetActive(ntree) : NULL;
+ bNodeSocket *sock;
+ uiLayout *layout= pa->layout, *split;
+ char name[UI_MAX_NAME_STR];
+
+ if(ELEM(NULL, ntree, node))
+ return;
+
+ for(sock=node->inputs.first; sock; sock=sock->next) {
+ BLI_snprintf(name, sizeof(name), "%s:", sock->name);
+
+ split = uiLayoutSplit(layout, 0.35f, 0);
+ uiItemL(split, name, ICON_NONE);
+ uiTemplateNodeLink(split, ntree, node, sock);
+ }
+}
+
/* ******************* node buttons registration ************** */
void node_buttons_register(ARegionType *art)
@@ -134,6 +163,14 @@ void node_buttons_register(ARegionType *art)
pt->draw= active_node_panel;
pt->poll= active_node_poll;
BLI_addtail(&art->paneltypes, pt);
+
+ pt= MEM_callocN(sizeof(PanelType), "spacetype node panel node sockets");
+ strcpy(pt->idname, "NODE_PT_sockets");
+ strcpy(pt->label, "Sockets");
+ pt->draw= node_sockets_panel;
+ pt->poll= node_sockets_poll;
+ pt->flag |= PNL_DEFAULT_CLOSED;
+ BLI_addtail(&art->paneltypes, pt);
pt= MEM_callocN(sizeof(PanelType), "spacetype node panel gpencil");
strcpy(pt->idname, "NODE_PT_gpencil");
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index c2a2f319c28..a932f1b10d9 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -108,7 +108,8 @@ void ED_node_changed_update(ID *id, bNode *node)
WM_main_add_notifier(NC_WORLD|ND_WORLD_DRAW, id);
}
else if(treetype==NTREE_COMPOSIT) {
- nodeUpdate(edittree, node);
+ if(node)
+ nodeUpdate(edittree, node);
/* don't use NodeTagIDChanged, it gives far too many recomposites for image, scene layers, ... */
node= node_tree_get_editgroup(nodetree);
@@ -691,7 +692,7 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN
node_socket_circle_draw(ntree, sock, NODE_SOCKSIZE);
- if (sock->link) {
+ if (sock->link || (sock->flag & SOCK_HIDE_VALUE)) {
uiDefBut(node->block, LABEL, 0, sock->name, sock->locx+NODE_DYS, sock->locy-NODE_DYS, node->width-NODE_DY, NODE_DY,
NULL, 0, 0, 0, 0, "");
}
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index 745611c6251..23855ff24e1 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -61,6 +61,7 @@
#include "BKE_material.h"
#include "BKE_modifier.h"
#include "BKE_paint.h"
+#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_texture.h"
#include "BKE_report.h"
@@ -89,6 +90,8 @@
#include "RNA_enum_types.h"
+#include "GPU_material.h"
+
#include "node_intern.h"
static EnumPropertyItem socket_in_out_items[] = {
@@ -269,13 +272,14 @@ bNode *node_tree_get_editgroup(bNodeTree *nodetree)
/* assumes nothing being done in ntree yet, sets the default in/out node */
/* called from shading buttons or header */
-void ED_node_shader_default(Scene *UNUSED(scene), ID *id)
+void ED_node_shader_default(Scene *scene, ID *id)
{
bNode *in, *out;
- bNodeSocket *fromsock, *tosock;
+ bNodeSocket *fromsock, *tosock, *sock;
bNodeTree *ntree;
bNodeTemplate ntemp;
int output_type, shader_type;
+ float color[3], strength = 1.0f;
ntree= ntreeAddTree("Shader Nodetree", NTREE_SHADER, 0);
@@ -284,24 +288,42 @@ void ED_node_shader_default(Scene *UNUSED(scene), ID *id)
Material *ma= (Material*)id;
ma->nodetree = ntree;
- output_type = SH_NODE_OUTPUT;
- shader_type = SH_NODE_MATERIAL;
+ if(scene_use_new_shading_nodes(scene)) {
+ output_type = SH_NODE_OUTPUT_MATERIAL;
+ shader_type = SH_NODE_BSDF_DIFFUSE;
+ }
+ else {
+ output_type = SH_NODE_OUTPUT;
+ shader_type = SH_NODE_MATERIAL;
+ }
+
+ copy_v3_v3(color, &ma->r);
+ strength= 0.0f;
break;
}
case ID_WO: {
World *wo= (World*)id;
wo->nodetree = ntree;
- output_type = SH_NODE_OUTPUT;
- shader_type = SH_NODE_MATERIAL;
+ output_type = SH_NODE_OUTPUT_WORLD;
+ shader_type = SH_NODE_BACKGROUND;
+
+ copy_v3_v3(color, &wo->horr);
+ strength= 1.0f;
break;
}
case ID_LA: {
Lamp *la= (Lamp*)id;
la->nodetree = ntree;
- output_type = SH_NODE_OUTPUT;
- shader_type = SH_NODE_MATERIAL;
+ output_type = SH_NODE_OUTPUT_LAMP;
+ shader_type = SH_NODE_EMISSION;
+
+ copy_v3_v3(color, &la->r);
+ if(la->type == LA_LOCAL || la->type == LA_SPOT || la->type == LA_AREA)
+ strength= 100.0f;
+ else
+ strength= 1.0f;
break;
}
default:
@@ -322,6 +344,17 @@ void ED_node_shader_default(Scene *UNUSED(scene), ID *id)
fromsock= in->outputs.first;
tosock= out->inputs.first;
nodeAddLink(ntree, in, fromsock, out, tosock);
+
+ /* default values */
+ if(scene_use_new_shading_nodes(scene)) {
+ sock= in->inputs.first;
+ copy_v3_v3(((bNodeSocketValueRGBA*)sock->default_value)->value, color);
+
+ if(strength != 0.0f) {
+ sock= in->inputs.last;
+ ((bNodeSocketValueFloat*)sock->default_value)->value= strength;
+ }
+ }
ntreeUpdateTree(ntree);
}
@@ -567,6 +600,8 @@ static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup)
void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
{
+ int was_active_texture = (node->flag & NODE_ACTIVE_TEXTURE);
+
nodeSetActive(ntree, node);
if(node->type!=NODE_GROUP) {
@@ -590,6 +625,15 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
ED_node_generic_update(bmain, ntree, node);
}
+ /* if active texture changed, free glsl materials */
+ if((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) {
+ Material *ma;
+
+ for(ma=bmain->mat.first; ma; ma=ma->id.next)
+ if(ma->nodetree && ma->use_nodes && has_nodetree(ma->nodetree, ntree))
+ GPU_material_free(ma);
+ }
+
WM_main_add_notifier(NC_MATERIAL|ND_NODES, node->id);
}
else if(ntree->type==NTREE_COMPOSIT) {
@@ -2211,9 +2255,7 @@ bNode *node_add_node(SpaceNode *snode, Main *bmain, Scene *scene, bNodeTemplate
node->id = &scene->id;
}
else if(ELEM3(node->type, CMP_NODE_MOVIECLIP, CMP_NODE_MOVIEDISTORTION, CMP_NODE_STABILIZE2D)) {
- if(G.main->movieclip.first == G.main->movieclip.last) {
- node->id= G.main->movieclip.first;
- }
+ node->id = (ID *)scene->clip;
}
ntreeCompositForceHidden(snode->edittree, scene);
diff --git a/source/blender/editors/space_node/node_header.c b/source/blender/editors/space_node/node_header.c
index 42b5dafa3e1..6dd5eeba832 100644
--- a/source/blender/editors/space_node/node_header.c
+++ b/source/blender/editors/space_node/node_header.c
@@ -226,52 +226,24 @@ static void node_add_menu(bContext *C, uiLayout *layout, void *arg_nodeclass)
}
}
+static void node_menu_add_foreach_cb(void *calldata, int nclass, const char *name)
+{
+ uiLayout *layout= calldata;
+ uiItemMenuF(layout, name, 0, node_add_menu, SET_INT_IN_POINTER(nclass));
+}
+
static void node_menu_add(const bContext *C, Menu *menu)
{
Scene *scene= CTX_data_scene(C);
SpaceNode *snode= CTX_wm_space_node(C);
uiLayout *layout= menu->layout;
+ bNodeTreeType *ntreetype= ntreeGetType(snode->treetype);
if(!snode->nodetree)
uiLayoutSetActive(layout, 0);
-
- if(snode->treetype==NTREE_SHADER) {
- uiItemMenuF(layout, IFACE_("Input"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_INPUT));
- uiItemMenuF(layout, IFACE_("Output"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OUTPUT));
- if(scene_use_new_shading_nodes(scene)) {
- uiItemMenuF(layout, IFACE_("Shader"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_SHADER));
- uiItemMenuF(layout, IFACE_("Texture"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_TEXTURE));
- }
- uiItemMenuF(layout, IFACE_("Color"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_COLOR));
- uiItemMenuF(layout, IFACE_("Vector"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_VECTOR));
- uiItemMenuF(layout, IFACE_("Convertor"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_CONVERTOR));
- uiItemMenuF(layout, IFACE_("Group"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_GROUP));
- //uiItemMenuF(layout, IFACE_("Dynamic"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_DYNAMIC));
- uiItemMenuF(layout, IFACE_("Layout"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_LAYOUT));
- }
- else if(snode->treetype==NTREE_COMPOSIT) {
- uiItemMenuF(layout, IFACE_("Input"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_INPUT));
- uiItemMenuF(layout, IFACE_("Output"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OUTPUT));
- uiItemMenuF(layout, IFACE_("Color"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_COLOR));
- uiItemMenuF(layout, IFACE_("Vector"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_VECTOR));
- uiItemMenuF(layout, IFACE_("Filter"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_FILTER));
- uiItemMenuF(layout, IFACE_("Convertor"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_CONVERTOR));
- uiItemMenuF(layout, IFACE_("Matte"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_MATTE));
- uiItemMenuF(layout, IFACE_("Distort"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_DISTORT));
- uiItemMenuF(layout, IFACE_("Group"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_GROUP));
- uiItemMenuF(layout, IFACE_("Layout"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_LAYOUT));
- }
- else if(snode->treetype==NTREE_TEXTURE) {
- uiItemMenuF(layout, IFACE_("Input"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_INPUT));
- uiItemMenuF(layout, IFACE_("Output"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OUTPUT));
- uiItemMenuF(layout, IFACE_("Color"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_COLOR));
- uiItemMenuF(layout, IFACE_("Patterns"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_PATTERN));
- uiItemMenuF(layout, IFACE_("Textures"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_TEXTURE));
- uiItemMenuF(layout, IFACE_("Convertor"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_CONVERTOR));
- uiItemMenuF(layout, IFACE_("Distort"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_DISTORT));
- uiItemMenuF(layout, IFACE_("Group"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_GROUP));
- uiItemMenuF(layout, IFACE_("Layout"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_LAYOUT));
- }
+
+ if(ntreetype && ntreetype->foreach_nodeclass)
+ ntreetype->foreach_nodeclass(scene, layout, node_menu_add_foreach_cb);
}
void node_menus_register(void)
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
new file mode 100644
index 00000000000..fedb12f747c
--- /dev/null
+++ b/source/blender/editors/space_node/node_templates.c
@@ -0,0 +1,647 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Foundation 2009.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/interface/interface_node.c
+ * \ingroup edinterface
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_node_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BLF_translation.h"
+
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_scene.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+#include "../interface/interface_intern.h"
+
+#include "ED_node.h"
+
+/************************* Node Socket Manipulation **************************/
+
+static void node_tag_recursive(bNode *node)
+{
+ bNodeSocket *input;
+
+ if(!node || (node->flag & NODE_TEST))
+ return; /* in case of cycles */
+
+ node->flag |= NODE_TEST;
+
+ for(input=node->inputs.first; input; input=input->next)
+ if(input->link)
+ node_tag_recursive(input->link->fromnode);
+}
+
+static void node_clear_recursive(bNode *node)
+{
+ bNodeSocket *input;
+
+ if(!node || !(node->flag & NODE_TEST))
+ return; /* in case of cycles */
+
+ node->flag &= ~NODE_TEST;
+
+ for(input=node->inputs.first; input; input=input->next)
+ if(input->link)
+ node_clear_recursive(input->link->fromnode);
+}
+
+static void node_remove_linked(bNodeTree *ntree, bNode *rem_node)
+{
+ bNode *node, *next;
+ bNodeSocket *sock;
+
+ if(!rem_node)
+ return;
+
+ /* tag linked nodes to be removed */
+ for(node=ntree->nodes.first; node; node=node->next)
+ node->flag &= ~NODE_TEST;
+
+ node_tag_recursive(rem_node);
+
+ /* clear tags on nodes that are still used by other nodes */
+ for(node=ntree->nodes.first; node; node=node->next)
+ if(!(node->flag & NODE_TEST))
+ for(sock=node->inputs.first; sock; sock=sock->next)
+ if(sock->link && sock->link->fromnode != rem_node)
+ node_clear_recursive(sock->link->fromnode);
+
+ /* remove nodes */
+ for(node=ntree->nodes.first; node; node=next) {
+ next = node->next;
+
+ if(node->flag & NODE_TEST) {
+ if(node->id)
+ node->id->us--;
+ nodeFreeNode(ntree, node);
+ }
+ }
+}
+
+/* disconnect socket from the node it is connected to */
+static void node_socket_disconnect(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to)
+{
+ if(!sock_to->link)
+ return;
+
+ nodeRemLink(ntree, sock_to->link);
+
+ nodeUpdate(ntree, node_to);
+ ntreeUpdateTree(ntree);
+
+ ED_node_generic_update(bmain, ntree, node_to);
+}
+
+/* remove all nodes connected to this socket, if they aren't connected to other nodes */
+static void node_socket_remove(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to)
+{
+ if(!sock_to->link)
+ return;
+
+ node_remove_linked(ntree, sock_to->link->fromnode);
+
+ nodeUpdate(ntree, node_to);
+ ntreeUpdateTree(ntree);
+
+ ED_node_generic_update(bmain, ntree, node_to);
+}
+
+/* add new node connected to this socket, or replace an existing one */
+static void node_socket_add_replace(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to, bNodeTemplate *ntemp, int sock_num)
+{
+ bNode *node_from;
+ bNodeSocket *sock_from;
+ bNode *node_prev = NULL;
+
+ /* unlink existing node */
+ if(sock_to->link) {
+ node_prev = sock_to->link->fromnode;
+ nodeRemLink(ntree, sock_to->link);
+ }
+
+ /* find existing node that we can use */
+ for(node_from=ntree->nodes.first; node_from; node_from=node_from->next)
+ if(node_from->type == ntemp->type)
+ break;
+
+ if(node_from)
+ if(!(node_from->inputs.first == NULL && !(node_from->typeinfo->flag & NODE_OPTIONS)))
+ node_from = NULL;
+
+ if(node_prev && node_prev->type == ntemp->type &&
+ (ntemp->type != NODE_GROUP || node_prev->id == &ntemp->ngroup->id)) {
+ /* keep the previous node if it's the same type */
+ node_from = node_prev;
+ }
+ else if(!node_from) {
+ node_from= nodeAddNode(ntree, ntemp);
+ node_from->locx = node_to->locx - (node_from->typeinfo->width + 50);
+ node_from->locy = node_to->locy;
+
+ if(node_from->id)
+ id_us_plus(node_from->id);
+ }
+
+ nodeSetActive(ntree, node_from);
+
+ /* add link */
+ sock_from = BLI_findlink(&node_from->outputs, sock_num);
+ nodeAddLink(ntree, node_from, sock_from, node_to, sock_to);
+
+ /* copy input sockets from previous node */
+ if(node_prev && node_from != node_prev) {
+ bNodeSocket *sock_prev, *sock_from;
+
+ for(sock_prev=node_prev->inputs.first; sock_prev; sock_prev=sock_prev->next) {
+ for(sock_from=node_from->inputs.first; sock_from; sock_from=sock_from->next) {
+ if(strcmp(sock_prev->name, sock_from->name) == 0 && sock_prev->type == sock_from->type) {
+ bNodeLink *link = sock_prev->link;
+
+ if(link && link->fromnode) {
+ nodeAddLink(ntree, link->fromnode, link->fromsock, node_from, sock_from);
+ nodeRemLink(ntree, link);
+ }
+
+ if(sock_prev->default_value) {
+ if(sock_from->default_value)
+ MEM_freeN(sock_from->default_value);
+
+ sock_from->default_value = MEM_dupallocN(sock_prev->default_value);
+ }
+ }
+ }
+ }
+
+ /* also preserve mapping for texture nodes */
+ if(node_from->typeinfo->nclass == NODE_CLASS_TEXTURE &&
+ node_prev->typeinfo->nclass == NODE_CLASS_TEXTURE)
+ memcpy(node_from->storage, node_prev->storage, sizeof(NodeTexBase));
+
+ /* remove node */
+ node_remove_linked(ntree, node_prev);
+ }
+
+ nodeUpdate(ntree, node_from);
+ nodeUpdate(ntree, node_to);
+ ntreeUpdateTree(ntree);
+
+ ED_node_generic_update(bmain, ntree, node_to);
+}
+
+/****************************** Node Link Menu *******************************/
+
+#define UI_NODE_LINK_ADD 0
+#define UI_NODE_LINK_DISCONNECT -1
+#define UI_NODE_LINK_REMOVE -2
+
+typedef struct NodeLinkArg {
+ Main *bmain;
+ Scene *scene;
+ bNodeTree *ntree;
+ bNode *node;
+ bNodeSocket *sock;
+
+ bNodeTree *ngroup;
+ int type;
+ int output;
+
+ uiLayout *layout;
+} NodeLinkArg;
+
+static void ui_node_link(bContext *UNUSED(C), void *arg_p, void *event_p)
+{
+ NodeLinkArg *arg = (NodeLinkArg*)arg_p;
+ Main *bmain = arg->bmain;
+ bNode *node_to = arg->node;
+ bNodeSocket *sock_to = arg->sock;
+ bNodeTree *ntree = arg->ntree;
+ int event = GET_INT_FROM_POINTER(event_p);
+ bNodeTemplate ntemp;
+
+ ntemp.type = arg->type;
+ ntemp.ngroup = arg->ngroup;
+
+ if(event == UI_NODE_LINK_DISCONNECT)
+ node_socket_disconnect(bmain, ntree, node_to, sock_to);
+ else if(event == UI_NODE_LINK_REMOVE)
+ node_socket_remove(bmain, ntree, node_to, sock_to);
+ else
+ node_socket_add_replace(bmain, ntree, node_to, sock_to, &ntemp, arg->output);
+}
+
+static void ui_node_sock_name(bNodeSocket *sock, char name[UI_MAX_NAME_STR])
+{
+ if(sock->link && sock->link->fromnode) {
+ bNode *node = sock->link->fromnode;
+ char node_name[UI_MAX_NAME_STR];
+
+ if(node->type == NODE_GROUP)
+ BLI_strncpy(node_name, node->id->name+2, UI_MAX_NAME_STR);
+ else
+ BLI_strncpy(node_name, node->typeinfo->name, UI_MAX_NAME_STR);
+
+ if(node->inputs.first == NULL &&
+ node->outputs.first != node->outputs.last &&
+ !(node->typeinfo->flag & NODE_OPTIONS))
+ BLI_snprintf(name, UI_MAX_NAME_STR, "%s | %s", node_name, sock->link->fromsock->name);
+ else
+ BLI_strncpy(name, node_name, UI_MAX_NAME_STR);
+ }
+ else if(sock->type == SOCK_SHADER)
+ BLI_strncpy(name, "None", UI_MAX_NAME_STR);
+ else
+ BLI_strncpy(name, "Default", UI_MAX_NAME_STR);
+}
+
+static int ui_compatible_sockets(int typeA, int typeB)
+{
+ return (typeA == typeB);
+}
+
+static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
+{
+ Main *bmain = arg->bmain;
+ bNodeTree *ntree = arg->ntree;
+ bNodeSocket *sock = arg->sock;
+ uiLayout *layout = arg->layout;
+ uiLayout *column = NULL;
+ uiBlock *block = uiLayoutGetBlock(layout);
+ uiBut *but;
+ bNodeType *ntype;
+ bNodeTree *ngroup;
+ NodeLinkArg *argN;
+ int first = 1;
+ int compatibility= 0;
+
+ if(ntree->type == NTREE_SHADER) {
+ if(scene_use_new_shading_nodes(arg->scene))
+ compatibility= NODE_NEW_SHADING;
+ else
+ compatibility= NODE_OLD_SHADING;
+ }
+
+ if(nclass == NODE_CLASS_GROUP) {
+ for(ngroup=bmain->nodetree.first; ngroup; ngroup=ngroup->id.next) {
+ bNodeSocket *gsock;
+ char name[UI_MAX_NAME_STR];
+ int i, j, num = 0;
+
+ if(ngroup->type != ntree->type)
+ continue;
+
+ for(gsock=ngroup->inputs.first; gsock; gsock=gsock->next)
+ if(ui_compatible_sockets(gsock->type, sock->type))
+ num++;
+
+ for(i=0, j=0, gsock=ngroup->outputs.first; gsock; gsock=gsock->next, i++) {
+ if(!ui_compatible_sockets(gsock->type, sock->type))
+ continue;
+
+ if(first) {
+ column= uiLayoutColumn(layout, 0);
+ uiBlockSetCurLayout(block, column);
+
+ uiItemL(column, cname, ICON_NODE);
+ but= block->buttons.last;
+ but->flag= UI_TEXT_LEFT;
+
+ first = 0;
+ }
+
+ if(num > 1) {
+ if(j == 0) {
+ uiItemL(column, ngroup->id.name+2, ICON_NODE);
+ but= block->buttons.last;
+ but->flag= UI_TEXT_LEFT;
+ }
+
+ BLI_snprintf(name, UI_MAX_NAME_STR, " %s", gsock->name);
+ j++;
+ }
+ else
+ BLI_strncpy(name, ngroup->id.name+2, UI_MAX_NAME_STR);
+
+ but = uiDefBut(block, BUT, 0, ngroup->id.name+2, 0, 0, UI_UNIT_X*4, UI_UNIT_Y,
+ NULL, 0.0, 0.0, 0.0, 0.0, "Add node to input");
+
+ argN = MEM_dupallocN(arg);
+ argN->ngroup = ngroup;
+ argN->output = i;
+ uiButSetNFunc(but, ui_node_link, argN, NULL);
+ }
+ }
+ }
+ else {
+ bNodeTreeType *ttype= ntreeGetType(ntree->type);
+
+ for(ntype=ttype->node_types.first; ntype; ntype=ntype->next) {
+ bNodeSocketTemplate *stemp;
+ char name[UI_MAX_NAME_STR];
+ int i, j, num = 0;
+
+ if(compatibility && !(ntype->compatibility & compatibility))
+ continue;
+
+ if(ntype->nclass != nclass)
+ continue;
+
+ for(i=0, stemp=ntype->outputs; stemp && stemp->type != -1; stemp++, i++)
+ if(ui_compatible_sockets(stemp->type, sock->type))
+ num++;
+
+ for(i=0, j=0, stemp=ntype->outputs; stemp && stemp->type != -1; stemp++, i++) {
+ if(!ui_compatible_sockets(stemp->type, sock->type))
+ continue;
+
+ if(first) {
+ column= uiLayoutColumn(layout, 0);
+ uiBlockSetCurLayout(block, column);
+
+ uiItemL(column, cname, ICON_NODE);
+ but= block->buttons.last;
+ but->flag= UI_TEXT_LEFT;
+
+ first = 0;
+ }
+
+ if(num > 1) {
+ if(j == 0) {
+ uiItemL(column, ntype->name, ICON_NODE);
+ but= block->buttons.last;
+ but->flag= UI_TEXT_LEFT;
+ }
+
+ BLI_snprintf(name, UI_MAX_NAME_STR, " %s", stemp->name);
+ j++;
+ }
+ else
+ BLI_strncpy(name, ntype->name, UI_MAX_NAME_STR);
+
+ but = uiDefBut(block, BUT, 0, name, 0, 0, UI_UNIT_X*4, UI_UNIT_Y,
+ NULL, 0.0, 0.0, 0.0, 0.0, "Add node to input");
+
+ argN = MEM_dupallocN(arg);
+ argN->type = ntype->type;
+ argN->output = i;
+ uiButSetNFunc(but, ui_node_link, argN, NULL);
+ }
+ }
+ }
+}
+
+static void node_menu_column_foreach_cb(void *calldata, int nclass, const char *name)
+{
+ NodeLinkArg *arg = (NodeLinkArg*)calldata;
+
+ if(!ELEM(nclass, NODE_CLASS_GROUP, NODE_CLASS_LAYOUT))
+ ui_node_menu_column(arg, nclass, name);
+}
+
+static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_p)
+{
+ Main *bmain= CTX_data_main(C);
+ Scene *scene= CTX_data_scene(C);
+ uiBlock *block = uiLayoutGetBlock(layout);
+ uiBut *but = (uiBut*)but_p;
+ uiLayout *split, *column;
+ NodeLinkArg *arg = (NodeLinkArg*)but->func_argN;
+ bNodeSocket *sock = arg->sock;
+ bNodeTreeType *ntreetype= ntreeGetType(arg->ntree->type);
+
+ uiBlockSetCurLayout(block, layout);
+ split= uiLayoutSplit(layout, 0, 0);
+
+ arg->bmain= bmain;
+ arg->scene= scene;
+ arg->layout= split;
+
+ if(ntreetype && ntreetype->foreach_nodeclass)
+ ntreetype->foreach_nodeclass(scene, arg, node_menu_column_foreach_cb);
+
+ column= uiLayoutColumn(split, 0);
+ uiBlockSetCurLayout(block, column);
+
+ if(sock->link) {
+ uiItemL(column, "Link", ICON_NONE);
+ but= block->buttons.last;
+ but->flag= UI_TEXT_LEFT;
+
+ but = uiDefBut(block, BUT, 0, "Remove", 0, 0, UI_UNIT_X*4, UI_UNIT_Y,
+ NULL, 0.0, 0.0, 0.0, 0.0, "Remove nodes connected to the input");
+ uiButSetNFunc(but, ui_node_link, MEM_dupallocN(arg), SET_INT_IN_POINTER(UI_NODE_LINK_REMOVE));
+
+ but = uiDefBut(block, BUT, 0, "Disconnect", 0, 0, UI_UNIT_X*4, UI_UNIT_Y,
+ NULL, 0.0, 0.0, 0.0, 0.0, "Disconnect nodes connected to the input");
+ uiButSetNFunc(but, ui_node_link, MEM_dupallocN(arg), SET_INT_IN_POINTER(UI_NODE_LINK_DISCONNECT));
+ }
+
+ ui_node_menu_column(arg, NODE_CLASS_GROUP, IFACE_("Group"));
+}
+
+void uiTemplateNodeLink(uiLayout *layout, bNodeTree *ntree, bNode *node, bNodeSocket *sock)
+{
+ uiBlock *block = uiLayoutGetBlock(layout);
+ NodeLinkArg *arg;
+ uiBut *but;
+
+ arg = MEM_callocN(sizeof(NodeLinkArg), "NodeLinkArg");
+ arg->ntree = ntree;
+ arg->node = node;
+ arg->sock = sock;
+ arg->type = 0;
+ arg->output = 0;
+
+ uiBlockSetCurLayout(block, layout);
+
+ if(sock->link || sock->type == SOCK_SHADER || (sock->flag & SOCK_HIDE_VALUE)) {
+ char name[UI_MAX_NAME_STR];
+ ui_node_sock_name(sock, name);
+ but= uiDefMenuBut(block, ui_template_node_link_menu, NULL, name, 0, 0, UI_UNIT_X*4, UI_UNIT_Y, "");
+ }
+ else
+ but= uiDefIconMenuBut(block, ui_template_node_link_menu, NULL, ICON_NONE, 0, 0, UI_UNIT_X, UI_UNIT_Y, "");
+
+ but->type= MENU;
+ but->flag |= UI_TEXT_LEFT|UI_BUT_NODE_LINK;
+ but->poin= (char*)but;
+ but->func_argN = arg;
+
+ if(sock->link && sock->link->fromnode)
+ if(sock->link->fromnode->flag & NODE_ACTIVE_TEXTURE)
+ but->flag |= UI_BUT_NODE_ACTIVE;
+}
+
+/**************************** Node Tree Layout *******************************/
+
+static void ui_node_draw_input(uiLayout *layout, bContext *C,
+ bNodeTree *ntree, bNode *node, bNodeSocket *input, int depth);
+
+static void ui_node_draw_node(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, int depth)
+{
+ bNodeSocket *input;
+ uiLayout *col, *split;
+ PointerRNA nodeptr;
+
+ RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
+
+ if(node->typeinfo->uifunc) {
+ if(node->type != NODE_GROUP) {
+ split = uiLayoutSplit(layout, 0.35f, 0);
+ col = uiLayoutColumn(split, 0);
+ col = uiLayoutColumn(split, 0);
+
+ node->typeinfo->uifunc(col, C, &nodeptr);
+ }
+ }
+
+ for(input=node->inputs.first; input; input=input->next)
+ ui_node_draw_input(layout, C, ntree, node, input, depth+1);
+}
+
+static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input, int depth)
+{
+ PointerRNA inputptr;
+ uiBlock *block = uiLayoutGetBlock(layout);
+ uiBut *bt;
+ uiLayout *split, *row, *col;
+ bNode *lnode;
+ char label[UI_MAX_NAME_STR];
+ int indent = (depth > 1)? 2*(depth - 1): 0;
+
+ if(input->flag & SOCK_UNAVAIL)
+ return;
+
+ /* to avoid eternal loops on cyclic dependencies */
+ node->flag |= NODE_TEST;
+ lnode = (input->link)? input->link->fromnode: NULL;
+
+ /* socket RNA pointer */
+ RNA_pointer_create(&ntree->id, &RNA_NodeSocket, input, &inputptr);
+
+ /* indented label */
+ memset(label, ' ', indent);
+ label[indent] = '\0';
+ BLI_snprintf(label, UI_MAX_NAME_STR, "%s%s:", label, input->name);
+
+ /* split in label and value */
+ split = uiLayoutSplit(layout, 0.35f, 0);
+
+ row = uiLayoutRow(split, 1);
+
+ if(depth > 0) {
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+
+ if(lnode && (lnode->inputs.first || (lnode->typeinfo->uifunc && lnode->type != NODE_GROUP))) {
+ int icon = (input->flag & SOCK_COLLAPSED)? ICON_DISCLOSURE_TRI_RIGHT: ICON_DISCLOSURE_TRI_DOWN;
+ uiItemR(row, &inputptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", icon);
+ }
+ else
+ uiItemL(row, "", ICON_BLANK1);
+
+ bt = block->buttons.last;
+ bt->x2 = UI_UNIT_X/2;
+
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ }
+
+ uiItemL(row, label, ICON_NONE);
+ bt= block->buttons.last;
+ bt->flag= UI_TEXT_LEFT;
+
+ if(lnode) {
+ /* input linked to a node */
+ uiTemplateNodeLink(split, ntree, node, input);
+
+ if(!(input->flag & SOCK_COLLAPSED)) {
+ if(depth == 0)
+ uiItemS(layout);
+
+ ui_node_draw_node(layout, C, ntree, lnode, depth);
+ }
+ }
+ else {
+ /* input not linked, show value */
+ if(input->type != SOCK_SHADER && !(input->flag & SOCK_HIDE_VALUE)) {
+ if(input->type == SOCK_VECTOR) {
+ row = uiLayoutRow(split, 0);
+ col = uiLayoutColumn(row, 0);
+
+ uiItemR(col, &inputptr, "default_value", 0, "", 0);
+ }
+ else {
+ row = uiLayoutRow(split, 1);
+ uiItemR(row, &inputptr, "default_value", 0, "", 0);
+ }
+ }
+ else
+ row = uiLayoutRow(split, 0);
+
+ uiTemplateNodeLink(row, ntree, node, input);
+ }
+
+ /* clear */
+ node->flag &= ~NODE_TEST;
+}
+
+void uiTemplateNodeView(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input)
+{
+ bNode *tnode;
+
+ if(!ntree)
+ return;
+
+ /* clear for cycle check */
+ for(tnode=ntree->nodes.first; tnode; tnode=tnode->next)
+ tnode->flag &= ~NODE_TEST;
+
+ if(input)
+ ui_node_draw_input(layout, C, ntree, node, input, 0);
+ else
+ ui_node_draw_node(layout, C, ntree, node, 0);
+}
+