diff options
Diffstat (limited to 'source/blender/editors')
34 files changed, 2539 insertions, 2591 deletions
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h index 32baa8883e1..448a15334c7 100644 --- a/source/blender/editors/include/ED_node.h +++ b/source/blender/editors/include/ED_node.h @@ -39,7 +39,10 @@ struct Tex; struct bContext; struct bNodeTree; struct bNode; +struct bNodeType; +struct bNodeSocketType; struct bNodeTree; +struct bNodeTreeType; struct ScrArea; struct Scene; struct View2D; @@ -51,15 +54,30 @@ typedef enum { NODE_RIGHT = 8 } NodeBorder; +/* space_node.c */ +int ED_node_tree_path_length(struct SpaceNode *snode); +void ED_node_tree_path_get(struct SpaceNode *snode, char *value); +void ED_node_tree_path_get_fixedbuf(struct SpaceNode *snode, char *value, int max_length); + +void ED_node_tree_start(struct SpaceNode *snode, struct bNodeTree *ntree, struct ID *id, struct ID *from); +void ED_node_tree_push(struct SpaceNode *snode, struct bNodeTree *ntree, struct bNode *gnode); +void ED_node_tree_pop(struct SpaceNode *snode); +int ED_node_tree_depth(struct SpaceNode *snode); +struct bNodeTree *ED_node_tree_get(struct SpaceNode *snode, int level); + /* drawnode.c */ void ED_node_init_butfuncs(void); +void ED_init_custom_node_type(struct bNodeType *ntype); +void ED_init_custom_node_socket_type(struct bNodeSocketType *stype); +void ED_init_standard_node_socket_type(struct bNodeSocketType *stype); +void ED_init_node_socket_type_virtual(struct bNodeSocketType *stype); void ED_node_sample_set(const float col[4]); void ED_node_draw_snap(struct View2D *v2d, const float cent[2], float size, NodeBorder border); /* node_draw.c */ -void ED_node_tree_update(struct SpaceNode *snode, struct Scene *scene); -void ED_node_changed_update(struct ID *id, struct bNode *node); -void ED_node_generic_update(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node); +void ED_node_tree_update(const struct bContext *C); +void ED_node_tag_update_id(struct ID *id); +void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree); void ED_node_sort(struct bNodeTree *ntree); /* node_relationships.c */ @@ -67,9 +85,14 @@ void ED_node_link_intersect_test(struct ScrArea *sa, int test); void ED_node_link_insert(struct ScrArea *sa); /* node_edit.c */ -void ED_node_shader_default(struct Scene *scene, struct ID *id); -void ED_node_composit_default(struct Scene *sce); -void ED_node_texture_default(struct Tex *tex); +void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typeinfo); +int ED_node_is_compositor(struct SpaceNode *snode); +int ED_node_is_shader(struct SpaceNode *snode); +int ED_node_is_texture(struct SpaceNode *snode); + +void ED_node_shader_default(const struct bContext *C, struct ID *id); +void ED_node_composit_default(const struct bContext *C, struct Scene *scene); +void ED_node_texture_default(const struct bContext *C, struct Tex *tex); int ED_node_select_check(ListBase *lb); void ED_node_post_apply_transform(struct bContext *C, struct bNodeTree *ntree); void ED_node_set_active(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node); diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 3c8a9a87fbe..f805b199280 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -259,7 +259,8 @@ typedef enum { WAVEFORM = (49 << 9), VECTORSCOPE = (50 << 9), PROGRESSBAR = (51 << 9), - SEARCH_MENU_UNLINK = (52 << 9) + SEARCH_MENU_UNLINK = (52 << 9), + NODESOCKET = (53 << 9) } eButType; #define BUTTYPE (63 << 9) @@ -835,6 +836,8 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C); void uiTemplateTextureImage(uiLayout *layout, struct bContext *C, struct Tex *tex); void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C); void uiTemplateKeymapItemProperties(uiLayout *layout, struct PointerRNA *ptr); +void uiTemplateComponentMenu(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name); +void uiTemplateNodeSocket(uiLayout *layout, struct bContext *C, float *color); /* Default UIList class name, keep in sync with its declaration in bl_ui/__init__.py */ #define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list" diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index 0086ef03b65..0cb3b2ce6d1 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -144,6 +144,7 @@ enum { TH_NODE, TH_NODE_IN_OUT, + TH_NODE_INTERFACE, TH_NODE_OPERATOR, TH_NODE_CONVERTOR, TH_NODE_GROUP, diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index 81a0f526049..3743539a9bd 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -167,7 +167,7 @@ View2DGrid *UI_view2d_grid_calc(struct Scene *scene, struct View2D *v2d, short xunits, short xclamp, short yunits, short yclamp, int winx, int winy); void UI_view2d_grid_draw(struct View2D *v2d, View2DGrid *grid, int flag); void UI_view2d_constant_grid_draw(struct View2D *v2d); -void UI_view2d_multi_grid_draw(struct View2D *v2d, float step, int level_size, int totlevels); +void UI_view2d_multi_grid_draw(struct View2D *v2d, int colorid, float step, int level_size, int totlevels); void UI_view2d_grid_size(View2DGrid *grid, float *r_dx, float *r_dy); void UI_view2d_grid_free(View2DGrid *grid); @@ -200,6 +200,9 @@ struct View2D *UI_view2d_fromcontext_rwin(const struct bContext *C); void UI_view2d_getscale(struct View2D *v2d, float *x, float *y); void UI_view2d_getscale_inverse(struct View2D *v2d, float *x, float *y); +void UI_view2d_getcenter(struct View2D *v2d, float *x, float *y); +void UI_view2d_setcenter(struct View2D *v2d, float x, float y); + short UI_view2d_mouse_in_scrollers(const struct bContext *C, struct View2D *v2d, int x, int y); /* cached text drawing in v2d, to allow pixel-aligned draw as post process */ diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index 5486e12c6bf..7fc5c21f052 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -42,6 +42,7 @@ #include "BLI_utildefines.h" #include "BKE_colortools.h" +#include "BKE_node.h" #include "BKE_texture.h" #include "BKE_tracking.h" @@ -1685,6 +1686,71 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc glDisable(GL_BLEND); } +void ui_draw_but_NODESOCKET(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), rcti *recti) +{ + static const float size = 5.0f; + + /* 16 values of sin function */ + static float si[16] = { + 0.00000000f, 0.39435585f, 0.72479278f, 0.93775213f, + 0.99871650f, 0.89780453f, 0.65137248f, 0.29936312f, + -0.10116832f, -0.48530196f, -0.79077573f, -0.96807711f, + -0.98846832f, -0.84864425f, -0.57126821f, -0.20129852f + }; + /* 16 values of cos function */ + static float co[16] = { + 1.00000000f, 0.91895781f, 0.68896691f, 0.34730525f, + -0.05064916f, -0.44039415f, -0.75875812f, -0.95413925f, + -0.99486932f, -0.87434661f, -0.61210598f, -0.25065253f, + 0.15142777f, 0.52896401f, 0.82076344f, 0.97952994f, + }; + + unsigned char *col = but->col; + int a; + GLint scissor[4]; + rcti scissor_new; + float x, y; + + x = 0.5f * (recti->xmin + recti->xmax); + y = 0.5f * (recti->ymin + recti->ymax); + + /* need scissor test, can draw outside of boundary */ + glGetIntegerv(GL_VIEWPORT, scissor); + scissor_new.xmin = ar->winrct.xmin + recti->xmin; + scissor_new.ymin = ar->winrct.ymin + recti->ymin; + scissor_new.xmax = ar->winrct.xmin + recti->xmax; + scissor_new.ymax = ar->winrct.ymin + recti->ymax; + BLI_rcti_isect(&scissor_new, &ar->winrct, &scissor_new); + glScissor(scissor_new.xmin, + scissor_new.ymin, + BLI_rcti_size_x(&scissor_new), + BLI_rcti_size_y(&scissor_new)); + + glColor4ubv(col); + + glEnable(GL_BLEND); + glBegin(GL_POLYGON); + for (a = 0; a < 16; a++) + glVertex2f(x + size * si[a], y + size * co[a]); + glEnd(); + glDisable(GL_BLEND); + + glColor4ub(0, 0, 0, 150); + + glEnable(GL_BLEND); + glEnable(GL_LINE_SMOOTH); + glBegin(GL_LINE_LOOP); + for (a = 0; a < 16; a++) + glVertex2f(x + size * si[a], y + size * co[a]); + glEnd(); + glDisable(GL_LINE_SMOOTH); + glDisable(GL_BLEND); + glLineWidth(1.0f); + + /* restore scissortest */ + glScissor(scissor[0], scissor[1], scissor[2], scissor[3]); +} + /* ****************************************************** */ diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 39aef38fadb..54a173af603 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -5434,6 +5434,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * case LISTROW: case BUT_IMAGE: case PROGRESSBAR: + case NODESOCKET: retval = ui_do_but_EXIT(C, but, data, event); break; case HISTOGRAM: diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 6065fcfe574..19b863dd6fa 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -510,6 +510,7 @@ void ui_draw_but_NORMAL(uiBut *but, struct uiWidgetColors *wcol, rcti *rect); void ui_draw_but_CURVE(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, rcti *rect); void ui_draw_but_IMAGE(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, rcti *rect); void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, rcti *rect); +void ui_draw_but_NODESOCKET(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, rcti *rect); /* interface_handlers.c */ extern void ui_pan_to_scroll(const struct wmEvent *event, int *type, int *val); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index eeddd8c7a9a..ee2625cf94b 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -32,6 +32,7 @@ #include "MEM_guardedalloc.h" #include "DNA_dynamicpaint_types.h" +#include "DNA_node_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" #include "DNA_object_force.h" @@ -57,6 +58,7 @@ #include "BKE_main.h" #include "BKE_material.h" #include "BKE_modifier.h" +#include "BKE_node.h" #include "BKE_object.h" #include "BKE_packedFile.h" #include "BKE_particle.h" @@ -3064,3 +3066,65 @@ void uiTemplateColormanagedViewSettings(uiLayout *layout, bContext *UNUSED(C), P if (view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) uiTemplateCurveMapping(col, &view_transform_ptr, "curve_mapping", 'c', TRUE, 0); } + +/********************************* Component Menu *************************************/ + +typedef struct ComponentMenuArgs { + PointerRNA ptr; + char propname[64]; /* XXX arbitrary */ +} ComponentMenuArgs; +/* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */ +static uiBlock *component_menu(bContext *C, ARegion *ar, void *args_v) +{ + ComponentMenuArgs *args = (ComponentMenuArgs*)args_v; + uiBlock *block; + uiLayout *layout; + + block = uiBeginBlock(C, ar, __func__, UI_EMBOSS); + uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN); + + layout = uiLayoutColumn(uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, UI_GetStyle()), 0); + + uiItemR(layout, &args->ptr, args->propname, UI_ITEM_R_EXPAND, "", ICON_NONE); + + uiBoundsBlock(block, 6); + uiBlockSetDirection(block, UI_DOWN); + uiEndBlock(C, block); + + return block; +} +void uiTemplateComponentMenu(uiLayout *layout, PointerRNA *ptr, const char *propname, const char *name) +{ + ComponentMenuArgs *args = MEM_callocN(sizeof(ComponentMenuArgs), "component menu template args"); + uiBlock *block; + + args->ptr = *ptr; + BLI_strncpy(args->propname, propname, sizeof(args->propname)); + + block = uiLayoutGetBlock(layout); + uiBlockBeginAlign(block); + + uiDefBlockButN(block, component_menu, args, name, 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, ""); + + uiBlockEndAlign(block); +} + +/************************* Node Socket Icon **************************/ + +void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float *color) +{ + uiBlock *block; + uiBut *but; + + block = uiLayoutGetBlock(layout); + uiBlockBeginAlign(block); + + /* XXX using explicit socket colors is not quite ideal. + * Eventually it should be possible to use theme colors for this purpose, + * but this requires a better design for extendable color palettes in user prefs. + */ + but = uiDefBut(block, NODESOCKET, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, ""); + rgba_float_to_uchar(but->col, color); + + uiBlockEndAlign(block); +} diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 78b6d2541fd..fc379468c6b 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -3367,6 +3367,10 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct ui_draw_but_TRACKPREVIEW(ar, but, &tui->wcol_regular, rect); break; + case NODESOCKET: + ui_draw_but_NODESOCKET(ar, but, &tui->wcol_regular, rect); + break; + default: wt = widget_type(UI_WTYPE_REGULAR); } diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 7ff5677259e..6b278358db9 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -389,6 +389,8 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo cp = ts->syntaxv; break; case TH_NODE_GROUP: cp = ts->syntaxc; break; + case TH_NODE_INTERFACE: + cp= ts->console_output; break; case TH_NODE_FRAME: cp = ts->movie; break; case TH_NODE_MATTE: @@ -951,7 +953,7 @@ void ui_theme_init_default(void) rgba_char_args_set_fl(btheme->ttime.grid, 0.36, 0.36, 0.36, 1.0); rgba_char_args_set(btheme->ttime.shade1, 173, 173, 173, 255); /* sliders */ - /* space node, re-uses syntax color storage */ + /* space node, re-uses syntax and console color storage */ btheme->tnode = btheme->tv3d; rgba_char_args_set(btheme->tnode.edge_select, 255, 255, 255, 255); /* wire selected */ rgba_char_args_set(btheme->tnode.syntaxl, 155, 155, 155, 160); /* TH_NODE, backdrop */ @@ -960,6 +962,7 @@ void ui_theme_init_default(void) rgba_char_args_set(btheme->tnode.syntaxv, 104, 106, 117, 255); /* generator */ rgba_char_args_set(btheme->tnode.syntaxc, 105, 117, 110, 255); /* group */ rgba_char_args_set(btheme->tnode.movie, 155, 155, 155, 160); /* frame */ + rgba_char_args_set(btheme->tnode.console_output, 190, 190, 80, 255); /* group input/output */ btheme->tnode.noodle_curving = 5; /* space logic */ @@ -2149,6 +2152,13 @@ void init_userdef_do_versions(void) } } + if (U.versionfile < 266 || (U.versionfile == 266 && U.subversionfile < 2)) { + bTheme *btheme; + for (btheme = U.themes.first; btheme; btheme = btheme->next) { + rgba_char_args_test_set(btheme->tnode.console_output, 223, 202, 53, 255); /* interface nodes */ + } + } + /* NOTE!! from now on use U.versionfile and U.subversionfile */ diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index 8a6de9a549b..fe7e6d01955 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -1368,7 +1368,7 @@ void UI_view2d_constant_grid_draw(View2D *v2d) } /* Draw a multi-level grid in given 2d-region */ -void UI_view2d_multi_grid_draw(View2D *v2d, float step, int level_size, int totlevels) +void UI_view2d_multi_grid_draw(View2D *v2d, int colorid, float step, int level_size, int totlevels) { int offset = -10; float lstep = step; @@ -1378,7 +1378,7 @@ void UI_view2d_multi_grid_draw(View2D *v2d, float step, int level_size, int totl int i; float start; - UI_ThemeColorShade(TH_BACK, offset); + UI_ThemeColorShade(colorid, offset); i = (v2d->cur.xmin >= 0.0f ? -(int)(-v2d->cur.xmin / lstep) : (int)(v2d->cur.xmin / lstep)); start = i * lstep; @@ -1402,7 +1402,7 @@ void UI_view2d_multi_grid_draw(View2D *v2d, float step, int level_size, int totl } /* X and Y axis */ - UI_ThemeColorShade(TH_BACK, offset - 8); + UI_ThemeColorShade(colorid, offset - 8); glVertex2f(0.0f, v2d->cur.ymin); glVertex2f(0.0f, v2d->cur.ymax); glVertex2f(v2d->cur.xmin, 0.0f); @@ -2075,6 +2075,31 @@ void UI_view2d_getscale_inverse(View2D *v2d, float *x, float *y) if (y) *y = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask); } +/* Simple functions for consistent center offset access. + * Used by node editor to shift view center for each individual node tree. + */ +void UI_view2d_getcenter(struct View2D *v2d, float *x, float *y) +{ + /* get center */ + if (x) *x = 0.5f*(v2d->cur.xmin + v2d->cur.xmax); + if (y) *y = 0.5f*(v2d->cur.ymin + v2d->cur.ymax); +} +void UI_view2d_setcenter(struct View2D *v2d, float x, float y) +{ + /* get delta from current center */ + float dx = x - 0.5f*(v2d->cur.xmin + v2d->cur.xmax); + float dy = y - 0.5f*(v2d->cur.ymin + v2d->cur.ymax); + + /* add to cur */ + v2d->cur.xmin += dx; + v2d->cur.xmax += dx; + v2d->cur.ymin += dy; + v2d->cur.ymax += dy; + + /* make sure that 'cur' rect is in a valid state as a result of these changes */ + UI_view2d_curRect_validate(v2d); +} + /* Check if mouse is within scrollers * - Returns appropriate code for match * 'h' = in horizontal scroller diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index dbb0d55a2b1..312cceac77d 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -852,7 +852,7 @@ static int object_lamp_add_exec(bContext *C, wmOperator *op) rename_id(&la->id, get_lamp_defname(type)); if (BKE_scene_use_new_shading_nodes(scene)) { - ED_node_shader_default(scene, &la->id); + ED_node_shader_default(C, &la->id); la->use_nodes = TRUE; } diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index dd5b97a68ed..948e272eca0 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -378,8 +378,8 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre sce->lay = 1 << mat->pr_type; if (mat->nodetree && sp->pr_method == PR_NODE_RENDER) { /* two previews, they get copied by wmJob */ - ntreeInitPreview(mat->nodetree, sp->sizex, sp->sizey); - ntreeInitPreview(origmat->nodetree, sp->sizex, sp->sizey); + BKE_node_preview_init_tree(mat->nodetree, sp->sizex, sp->sizey, TRUE); + BKE_node_preview_init_tree(origmat->nodetree, sp->sizex, sp->sizey, TRUE); } } } @@ -442,8 +442,8 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre if (tex && tex->nodetree && sp->pr_method == PR_NODE_RENDER) { /* two previews, they get copied by wmJob */ - ntreeInitPreview(origtex->nodetree, sp->sizex, sp->sizey); - ntreeInitPreview(tex->nodetree, sp->sizex, sp->sizey); + BKE_node_preview_init_tree(origtex->nodetree, sp->sizex, sp->sizey, TRUE); + BKE_node_preview_init_tree(tex->nodetree, sp->sizex, sp->sizey, TRUE); } } else if (id_type == ID_LA) { @@ -479,8 +479,8 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre if (la && la->nodetree && sp->pr_method == PR_NODE_RENDER) { /* two previews, they get copied by wmJob */ - ntreeInitPreview(origla->nodetree, sp->sizex, sp->sizey); - ntreeInitPreview(la->nodetree, sp->sizex, sp->sizey); + BKE_node_preview_init_tree(origla->nodetree, sp->sizex, sp->sizey, TRUE); + BKE_node_preview_init_tree(la->nodetree, sp->sizex, sp->sizey, TRUE); } } else if (id_type == ID_WO) { @@ -497,8 +497,8 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre if (wrld && wrld->nodetree && sp->pr_method == PR_NODE_RENDER) { /* two previews, they get copied by wmJob */ - ntreeInitPreview(wrld->nodetree, sp->sizex, sp->sizey); - ntreeInitPreview(origwrld->nodetree, sp->sizex, sp->sizey); + BKE_node_preview_init_tree(wrld->nodetree, sp->sizex, sp->sizey, TRUE); + BKE_node_preview_init_tree(origwrld->nodetree, sp->sizex, sp->sizey, TRUE); } } diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index c33b7442e41..54f59a82adc 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -379,7 +379,7 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op)) ma = BKE_material_add(bmain, "Material"); if (BKE_scene_use_new_shading_nodes(scene)) { - ED_node_shader_default(scene, &ma->id); + ED_node_shader_default(C, &ma->id); ma->use_nodes = TRUE; } } @@ -481,7 +481,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op)) wo = add_world(bmain, "World"); if (BKE_scene_use_new_shading_nodes(scene)) { - ED_node_shader_default(scene, &wo->id); + ED_node_shader_default(C, &wo->id); wo->use_nodes = TRUE; } } diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index a467b053443..d29c711cad0 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -377,7 +377,7 @@ static void texture_changed(Main *bmain, Tex *tex) if (scene->use_nodes && scene->nodetree) { for (node = scene->nodetree->nodes.first; node; node = node->next) { if (node->id == &tex->id) - ED_node_changed_update(&scene->id, node); + ED_node_tag_update_id(&scene->id); } } diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 1906a3259a9..8b69e6e831d 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -47,6 +47,7 @@ #include "DNA_meta_types.h" #include "DNA_mesh_types.h" #include "DNA_mask_types.h" +#include "DNA_node_types.h" #include "DNA_userdef_types.h" #include "BKE_context.h" @@ -54,6 +55,7 @@ #include "BKE_global.h" #include "BKE_main.h" #include "BKE_mesh.h" +#include "BKE_node.h" #include "BKE_object.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -252,7 +254,7 @@ int ED_operator_node_active(bContext *C) { SpaceNode *snode = CTX_wm_space_node(C); - if (snode && snode->edittree) + if (snode && ntreeIsValid(snode->edittree)) return 1; return 0; diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index d94b9372560..92a55151b66 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -407,7 +407,7 @@ void paint_brush_init_tex(Brush *brush) if (brush) { MTex *mtex = &brush->mtex; if (mtex->tex && mtex->tex->nodetree) - ntreeTexBeginExecTree(mtex->tex->nodetree, 1); /* has internal flag to detect it only does it once */ + ntreeTexBeginExecTree(mtex->tex->nodetree); /* has internal flag to detect it only does it once */ } } @@ -416,7 +416,7 @@ void paint_brush_exit_tex(Brush *brush) if (brush) { MTex *mtex = &brush->mtex; if (mtex->tex && mtex->tex->nodetree) - ntreeTexEndExecTree(mtex->tex->nodetree->execdata, 1); + ntreeTexEndExecTree(mtex->tex->nodetree->execdata); } } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 156be008a96..51500ab8e1c 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -4073,7 +4073,7 @@ static void sculpt_brush_init_tex(const Scene *scene, Sculpt *sd, SculptSession /* init mtex nodes */ if (mtex->tex && mtex->tex->nodetree) - ntreeTexBeginExecTree(mtex->tex->nodetree, 1); /* has internal flag to detect it only does it once */ + ntreeTexBeginExecTree(mtex->tex->nodetree); /* has internal flag to detect it only does it once */ /* TODO: Shouldn't really have to do this at the start of every * stroke, but sculpt would need some sort of notification when @@ -4249,7 +4249,7 @@ static void sculpt_brush_exit_tex(Sculpt *sd) MTex *mtex = &brush->mtex; if (mtex->tex && mtex->tex->nodetree) - ntreeTexEndExecTree(mtex->tex->nodetree->execdata, 1); + ntreeTexEndExecTree(mtex->tex->nodetree->execdata); } static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(stroke)) diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c index 1643921e4dd..bb1310d486a 100644 --- a/source/blender/editors/space_buttons/buttons_texture.c +++ b/source/blender/editors/space_buttons/buttons_texture.c @@ -113,7 +113,7 @@ static void buttons_texture_users_find_nodetree(ListBase *users, ID *id, { bNode *node; - if (ntree) { + if (ntreeIsValid(ntree)) { for (node = ntree->nodes.first; node; node = node->next) { if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) { PointerRNA ptr; diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 4a14d6ba6fd..fddecf267a9 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -43,18 +43,23 @@ #include "BKE_image.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_scene.h" #include "BKE_tracking.h" #include "BLF_api.h" #include "BLF_translation.h" +#include "NOD_texture.h" #include "BIF_gl.h" #include "BIF_glutil.h" +#include "BLF_translation.h" #include "MEM_guardedalloc.h" #include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" #include "ED_node.h" @@ -68,189 +73,137 @@ #include "IMB_imbuf_types.h" #include "node_intern.h" /* own include */ +#include "NOD_composite.h" +#include "NOD_shader.h" +#include "NOD_texture.h" -/* ****************** SOCKET BUTTON DRAW FUNCTIONS ***************** */ +/* ****************** MENU FUNCTIONS ***************** */ -static void node_sync_cb(bContext *UNUSED(C), void *snode_v, void *node_v) +static void node_add_menu_class(bContext *C, uiLayout *layout, void *arg_nodeclass) { - SpaceNode *snode = snode_v; + Scene *scene= CTX_data_scene(C); + SpaceNode *snode= CTX_wm_space_node(C); + bNodeTree *ntree; + int nodeclass= GET_INT_FROM_POINTER(arg_nodeclass); + int event, compatibility= 0; - if (snode->treetype == NTREE_SHADER) { - nodeShaderSynchronizeID(node_v, 1); - // allqueue(REDRAWBUTSSHADING, 0); + ntree = snode->nodetree; + + if(!ntree) { + uiItemS(layout); + return; } -} - -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, IFACE_(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) -{ - if (sock->link || (sock->flag & SOCK_HIDE_VALUE)) - node_socket_button_label(C, block, ntree, node, sock, name, x, y, width); - else { + if(ntree->type == NTREE_SHADER) { + if(BKE_scene_use_new_shading_nodes(scene)) + compatibility= NODE_NEW_SHADING; + else + compatibility= NODE_OLD_SHADING; + } + + if (nodeclass==NODE_CLASS_GROUP) { + Main *bmain= CTX_data_main(C); + bNodeTree *ngroup; + const char *ngroup_type, *node_type; PointerRNA ptr; - uiBut *bt; - - RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr); - bt = uiDefButR(block, NUM, B_NODE_EXEC, IFACE_(name), - x, y + 1, width, NODE_DY - 2, - &ptr, "default_value", 0, 0, 0, -1, -1, NULL); - if (node) - uiButSetFunc(bt, node_sync_cb, CTX_wm_space_node(C), node); + NODE_TYPES_BEGIN(ntype) + if (ntype->nclass!=nodeclass || !ntype->ui_name) + continue; + if (!ntype->poll(ntype, ntree)) + continue; + + switch (ntree->type) { + case NTREE_COMPOSIT: + ngroup_type = "CompositorNodeTree"; + node_type = "CompositorNodeGroup"; + break; + case NTREE_SHADER: + ngroup_type = "ShaderNodeTree"; + node_type = "ShaderNodeGroup"; + break; + case NTREE_TEXTURE: + ngroup_type = "TextureNodeTree"; + node_type = "TextureNodeGroup"; + break; + } + + ptr = uiItemFullO(layout, "NODE_OT_group_make", "New Group", ntype->ui_icon, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); + RNA_string_set(&ptr, "node_type", node_type); + + uiItemS(layout); + + for(ngroup=bmain->nodetree.first, event=0; ngroup; ngroup= ngroup->id.next, ++event) { + /* only use group trees of the right type */ + if (strcmp(ngroup->idname, ngroup_type)!=0) + continue; + if (!nodeGroupPoll(ntree, ngroup)) + continue; + + ptr = uiItemFullO(layout, "NODE_OT_add_group_node", ngroup->id.name+2, ntype->ui_icon, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); + RNA_string_set(&ptr, "type", ntype->idname); + RNA_string_set(&ptr, "grouptree", ngroup->id.name+2); + } + NODE_TYPES_END } -} - -static void node_socket_button_string(const bContext *C, uiBlock *block, - bNodeTree *ntree, bNode *node, bNodeSocket *sock, - const char *name, int x, int y, int width) -{ - if (sock->link || (sock->flag & SOCK_HIDE_VALUE)) - node_socket_button_label(C, block, ntree, node, sock, name, x, y, width); - else { + else if (nodeclass==NODE_DYNAMIC) { + /* disabled */ + } + else + { PointerRNA ptr; - uiBut *bt; - - SpaceNode *snode = CTX_wm_space_node(C); - const char *ui_name = IFACE_(name); - float slen; - - UI_ThemeColor(TH_TEXT); - slen = (UI_GetStringWidth(ui_name) + NODE_MARGIN_X) * snode->aspect; /* XXX, check for dpis */ - while (slen > (width * 0.5f) && *ui_name) { - ui_name = BLI_str_find_next_char_utf8(ui_name, NULL); - slen = (UI_GetStringWidth(ui_name) + NODE_MARGIN_X) * snode->aspect; - } - - RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr); - - if (name[0] == '\0') - slen = 0.0; - - bt = uiDefButR(block, TEX, B_NODE_EXEC, "", - x, y + 1, width - slen, NODE_DY - 2, - &ptr, "default_value", 0, 0, 0, -1, -1, ""); - if (node) - uiButSetFunc(bt, node_sync_cb, CTX_wm_space_node(C), node); - if (slen > 0.0f) - uiDefBut(block, LABEL, 0, IFACE_(name), x + (width - slen), y + 2, slen, NODE_DY - 2, NULL, 0, 0, 0, 0, ""); + NODE_TYPES_BEGIN(ntype) + if (ntype->nclass!=nodeclass || !ntype->ui_name) + continue; + if (!ntype->poll(ntype, ntree)) + continue; + if (compatibility && (ntype->compatibility & compatibility)==0) + continue; + + ptr = uiItemFullO(layout, "NODE_OT_add_node", IFACE_(ntype->ui_name), ntype->ui_icon, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); + RNA_string_set(&ptr, "type", ntype->idname); + NODE_TYPES_END } } -typedef struct SocketComponentMenuArgs { - PointerRNA ptr; - int x, y, width; - uiButHandleFunc cb; - void *arg1, *arg2; -} SocketComponentMenuArgs; -/* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */ -static uiBlock *socket_component_menu(bContext *C, ARegion *ar, void *args_v) +static void node_add_menu_foreach_class_cb(void *calldata, int nclass, const char *name) { - SocketComponentMenuArgs *args = (SocketComponentMenuArgs *)args_v; - uiBlock *block; - uiLayout *layout; - - block = uiBeginBlock(C, ar, __func__, UI_EMBOSS); - uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN); - - layout = uiLayoutColumn(uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, - args->x, args->y + 2, args->width, NODE_DY, UI_GetStyle()), FALSE); - - uiItemR(layout, &args->ptr, "default_value", UI_ITEM_R_EXPAND, "", ICON_NONE); - - return block; + uiLayout *layout= calldata; + uiItemMenuF(layout, IFACE_(name), 0, node_add_menu_class, SET_INT_IN_POINTER(nclass)); } -static void node_socket_button_components(const bContext *C, uiBlock *block, - bNodeTree *ntree, bNode *node, bNodeSocket *sock, - const char *name, int x, int y, int width) + +static void node_add_menu_default(const bContext *C, uiLayout *layout, bNodeTree *ntree) { - if (sock->link || (sock->flag & SOCK_HIDE_VALUE)) - node_socket_button_label(C, block, ntree, node, sock, name, x, y, width); - else { - PointerRNA ptr; - SocketComponentMenuArgs *args; - - RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr); - - args = MEM_callocN(sizeof(SocketComponentMenuArgs), "SocketComponentMenuArgs"); - - args->ptr = ptr; - args->x = x; - args->y = y; - args->width = width; - args->cb = node_sync_cb; - args->arg1 = CTX_wm_space_node(C); - args->arg2 = node; - - uiDefBlockButN(block, socket_component_menu, args, IFACE_(name), x, y + 1, width, NODE_DY - 2, ""); - } + Scene *scene= CTX_data_scene(C); + + if(ntree->typeinfo->foreach_nodeclass) + ntree->typeinfo->foreach_nodeclass(scene, layout, node_add_menu_foreach_class_cb); } -static void node_socket_button_color(const bContext *C, uiBlock *block, - bNodeTree *ntree, bNode *node, bNodeSocket *sock, - const char *name, int x, int y, int width) +/* ****************** SOCKET BUTTON DRAW FUNCTIONS ***************** */ + +static void node_socket_button_label(bContext *UNUSED(C), uiLayout *layout, PointerRNA *ptr, PointerRNA *UNUSED(node_ptr)) { - if (sock->link || (sock->flag & SOCK_HIDE_VALUE)) - node_socket_button_label(C, block, ntree, node, sock, IFACE_(name), x, y, width); - else { - PointerRNA ptr; - uiBut *bt; - int labelw = width - 40; - RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr); - - bt = uiDefButR(block, COLOR, B_NODE_EXEC, "", - x, y + 2, (labelw > 0 ? 40 : width), NODE_DY - 2, - &ptr, "default_value", -1, 0, 0, -1, -1, NULL); - if (node) - uiButSetFunc(bt, node_sync_cb, CTX_wm_space_node(C), node); - - if (name[0] != '\0' && labelw > 0) - uiDefBut(block, LABEL, 0, IFACE_(name), x + 40, y + 2, labelw, NODE_DY - 2, NULL, 0, 0, 0, 0, ""); - } + bNodeSocket *sock = (bNodeSocket *)ptr->data; + uiItemL(layout, sock->name, 0); } -/* standard draw function, display the default input value */ -static void node_draw_input_default(const bContext *C, uiBlock *block, - bNodeTree *ntree, bNode *node, bNodeSocket *sock, - const char *name, int x, int y, int width) +static void node_draw_input_default(bContext *C, uiLayout *layout, PointerRNA *ptr, PointerRNA *node_ptr, int linked) { - bNodeSocketType *stype = ntreeGetSocketType(sock->type); - if (stype->buttonfunc) - stype->buttonfunc(C, block, ntree, node, sock, name, x, y, width); + bNodeSocket *sock = (bNodeSocket *)ptr->data; + if (linked || (sock->flag & SOCK_HIDE_VALUE)) + node_socket_button_label(C, layout, ptr, node_ptr); else - node_socket_button_label(C, block, ntree, node, sock, IFACE_(name), x, y, width); + sock->typeinfo->draw(C, layout, ptr, node_ptr); } -static void node_draw_output_default(const bContext *UNUSED(C), uiBlock *block, - bNodeTree *UNUSED(ntree), bNode *node, bNodeSocket *sock, - const char *name, int UNUSED(x), int UNUSED(y), int UNUSED(width)) +static void node_draw_output_default(bContext *C, uiLayout *layout, PointerRNA *ptr, PointerRNA *node_ptr, int UNUSED(linked)) { - const char *ui_name = IFACE_(name); - float slen; - - UI_ThemeColor(TH_TEXT); - slen = (UI_GetStringWidth(ui_name) + NODE_MARGIN_X) ; - while (slen > NODE_WIDTH(node) && *ui_name) { - ui_name = BLI_str_find_next_char_utf8(ui_name, NULL); - slen = (UI_GetStringWidth(ui_name) + NODE_MARGIN_X); - } - - if (*ui_name) { - uiDefBut(block, LABEL, 0, ui_name, - (int)(sock->locx - slen), (int)(sock->locy - 9.0f), - (short)slen, (short)NODE_DY, - NULL, 0, 0, 0, 0, ""); - } + node_socket_button_label(C, layout, ptr, node_ptr); } + /* ****************** BASE DRAW FUNCTIONS FOR NEW OPERATOR NODES ***************** */ #if 0 /* UNUSED */ @@ -297,25 +250,23 @@ static void node_draw_socket_new(bNodeSocket *sock, float size) static void node_buts_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { + bNode *node = ptr->data; + /* first output stores value */ + bNodeSocket *output = node->outputs.first; PointerRNA sockptr; - PropertyRNA *prop; - - /* first socket stores value */ - prop = RNA_struct_find_property(ptr, "outputs"); - RNA_property_collection_lookup_int(ptr, prop, 0, &sockptr); + RNA_pointer_create(ptr->id.data, &RNA_NodeSocket, output, &sockptr); uiItemR(layout, &sockptr, "default_value", 0, "", ICON_NONE); } static void node_buts_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiLayout *col; + bNode *node = ptr->data; + /* first output stores value */ + bNodeSocket *output = node->outputs.first; PointerRNA sockptr; - PropertyRNA *prop; - - /* first socket stores value */ - prop = RNA_struct_find_property(ptr, "outputs"); - RNA_property_collection_lookup_int(ptr, prop, 0, &sockptr); + uiLayout *col; + RNA_pointer_create(ptr->id.data, &RNA_NodeSocket, output, &sockptr); col = uiLayoutColumn(layout, FALSE); uiTemplateColorPicker(col, &sockptr, "default_value", 1, 0, 0, 0); @@ -399,14 +350,15 @@ static void node_buts_curvecol(uiLayout *layout, bContext *UNUSED(C), PointerRNA static void node_buts_normal(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - bNodeTree *ntree = (bNodeTree *)ptr->id.data; - bNode *node = (bNode *)ptr->data; - bNodeSocket *sock = node->outputs.first; /* first socket stores normal */ + bNode *node = ptr->data; + /* first output stores normal */ + bNodeSocket *output = node->outputs.first; PointerRNA sockptr; - - RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &sockptr); + RNA_pointer_create(ptr->id.data, &RNA_NodeSocket, output, &sockptr); + uiItemR(layout, &sockptr, "default_value", 0, "", ICON_NONE); } + #if 0 /* not used in 2.5x yet */ static void node_browse_tex_cb(bContext *C, void *ntree_v, void *node_v) { @@ -491,427 +443,6 @@ static int node_resize_area_default(bNode *node, int x, int y) /* ****************** BUTTON CALLBACKS FOR COMMON NODES ***************** */ -/* width of socket columns in group display */ -#define NODE_GROUP_FRAME 120 - -/* based on settings in node, sets drawing rect info. each redraw! */ -/* note: this assumes only 1 group at a time is drawn (linked data) */ -/* in node->totr the entire boundbox for the group is stored */ -static void node_update_group(const bContext *C, bNodeTree *ntree, bNode *gnode) -{ - if (!(gnode->flag & NODE_GROUP_EDIT)) { - node_update_default(C, ntree, gnode); - } - else { - bNodeTree *ngroup = (bNodeTree *)gnode->id; - bNode *node; - bNodeSocket *sock, *gsock; - float locx, locy; - rctf *rect = &gnode->totr; - const float dpi_fac = UI_DPI_FAC; - const float node_group_frame = NODE_GROUP_FRAME * dpi_fac; - const float group_header = 26 * dpi_fac; - int counter; - int dy; - - /* get "global" coords */ - node_to_view(gnode, 0.0f, 0.0f, &locx, &locy); - - /* center them, is a bit of abuse of locx and locy though */ - node_update_nodetree(C, ngroup, locx, locy); - - rect->xmin = rect->xmax = locx; - rect->ymin = rect->ymax = locy; - - counter = 1; - for (node = ngroup->nodes.first; node; node = node->next) { - if (counter) { - *rect = node->totr; - counter = 0; - } - else - BLI_rctf_union(rect, &node->totr); - } - - /* add some room for links to group sockets */ - rect->xmin -= 4 * NODE_DY; - rect->xmax += 4 * NODE_DY; - rect->ymin -= NODE_DY; - rect->ymax += NODE_DY; - - /* input sockets */ - dy = BLI_rctf_cent_y(rect) + (NODE_DY * (BLI_countlist(&gnode->inputs) - 1)); - gsock = ngroup->inputs.first; - sock = gnode->inputs.first; - while (gsock || sock) { - while (sock && !sock->groupsock) { - sock->locx = rect->xmin - node_group_frame; - sock->locy = dy; - - /* prevent long socket lists from growing out of the group box */ - if (dy - 3 * NODE_DYS < rect->ymin) - rect->ymin = dy - 3 * NODE_DYS; - if (dy + 3 * NODE_DYS > rect->ymax) - rect->ymax = dy + 3 * NODE_DYS; - dy -= 2 * NODE_DY; - - sock = sock->next; - } - while (gsock && (!sock || sock->groupsock != gsock)) { - gsock->locx = rect->xmin; - gsock->locy = dy; - - /* prevent long socket lists from growing out of the group box */ - if (dy - 3 * NODE_DYS < rect->ymin) - rect->ymin = dy - 3 * NODE_DYS; - if (dy + 3 * NODE_DYS > rect->ymax) - rect->ymax = dy + 3 * NODE_DYS; - dy -= 2 * NODE_DY; - - gsock = gsock->next; - } - while (sock && gsock && sock->groupsock == gsock) { - gsock->locx = rect->xmin; - sock->locx = rect->xmin - node_group_frame; - sock->locy = gsock->locy = dy; - - /* prevent long socket lists from growing out of the group box */ - if (dy - 3 * NODE_DYS < rect->ymin) - rect->ymin = dy - 3 * NODE_DYS; - if (dy + 3 * NODE_DYS > rect->ymax) - rect->ymax = dy + 3 * NODE_DYS; - dy -= 2 * NODE_DY; - - sock = sock->next; - gsock = gsock->next; - } - } - - /* output sockets */ - dy = BLI_rctf_cent_y(rect) + (NODE_DY * (BLI_countlist(&gnode->outputs) - 1)); - gsock = ngroup->outputs.first; - sock = gnode->outputs.first; - while (gsock || sock) { - while (sock && !sock->groupsock) { - sock->locx = rect->xmax + node_group_frame; - sock->locy = dy - NODE_DYS; - - /* prevent long socket lists from growing out of the group box */ - if (dy - 3 * NODE_DYS < rect->ymin) - rect->ymin = dy - 3 * NODE_DYS; - if (dy + 3 * NODE_DYS > rect->ymax) - rect->ymax = dy + 3 * NODE_DYS; - dy -= 2 * NODE_DY; - - sock = sock->next; - } - while (gsock && (!sock || sock->groupsock != gsock)) { - gsock->locx = rect->xmax; - gsock->locy = dy - NODE_DYS; - - /* prevent long socket lists from growing out of the group box */ - if (dy - 3 * NODE_DYS < rect->ymin) - rect->ymin = dy - 3 * NODE_DYS; - if (dy + 3 * NODE_DYS > rect->ymax) - rect->ymax = dy + 3 * NODE_DYS; - dy -= 2 * NODE_DY; - - gsock = gsock->next; - } - while (sock && gsock && sock->groupsock == gsock) { - gsock->locx = rect->xmax; - sock->locx = rect->xmax + node_group_frame; - sock->locy = gsock->locy = dy - NODE_DYS; - - /* prevent long socket lists from growing out of the group box */ - if (dy - 3 * NODE_DYS < rect->ymin) - rect->ymin = dy - 3 * NODE_DYS; - if (dy + 3 * NODE_DYS > rect->ymax) - rect->ymax = dy + 3 * NODE_DYS; - dy -= 2 * NODE_DY; - - sock = sock->next; - gsock = gsock->next; - } - } - - /* Set the block bounds to clip mouse events from underlying nodes. - * Add margin for header and input/output columns. - */ - uiExplicitBoundsBlock(gnode->block, - rect->xmin - node_group_frame, - rect->ymin, - rect->xmax + node_group_frame, - rect->ymax + group_header); - } -} - -static void update_group_input_cb(bContext *UNUSED(C), void *UNUSED(snode_v), void *ngroup_v) -{ - bNodeTree *ngroup = (bNodeTree *)ngroup_v; - - ngroup->update |= NTREE_UPDATE_GROUP_IN; - ntreeUpdateTree(ngroup); -} - -static void update_group_output_cb(bContext *UNUSED(C), void *UNUSED(snode_v), void *ngroup_v) -{ - bNodeTree *ngroup = (bNodeTree *)ngroup_v; - - ngroup->update |= NTREE_UPDATE_GROUP_OUT; - ntreeUpdateTree(ngroup); -} - -static void draw_group_socket_name(SpaceNode *snode, bNode *gnode, bNodeSocket *sock, - int in_out, float xoffset, float yoffset, short width, short height) -{ - if (sock->flag & SOCK_DYNAMIC) { - bNodeTree *ngroup = (bNodeTree *)gnode->id; - uiBut *but; - but = uiDefBut(gnode->block, TEX, 0, "", - sock->locx + xoffset, sock->locy + 1 + yoffset, width, height, - sock->name, 0, sizeof(sock->name), 0, 0, ""); - if (in_out == SOCK_IN) - uiButSetFunc(but, update_group_input_cb, snode, ngroup); - else - uiButSetFunc(but, update_group_output_cb, snode, ngroup); - } - else { - const char *ui_name = IFACE_(sock->name); - uiDefBut(gnode->block, LABEL, 0, ui_name, - sock->locx + xoffset, sock->locy + 1 + yoffset, width, height, - NULL, 0, 0, 0, 0, ""); - } -} - -static void draw_group_socket(const bContext *C, SpaceNode *snode, bNodeTree *ntree, bNode *gnode, - bNodeSocket *sock, bNodeSocket *gsock, int index, int in_out) -{ - const float dpi_fac = UI_DPI_FAC; - bNodeTree *ngroup = (bNodeTree *)gnode->id; - bNodeSocketType *stype = ntreeGetSocketType(gsock ? gsock->type : sock->type); - uiBut *bt; - float offset; - int draw_value; - const float node_group_frame = NODE_GROUP_FRAME * dpi_fac; - const float socket_size = NODE_SOCKSIZE; - const float arrowbutw = 0.8f * UI_UNIT_X; - const short co_text_w = 72 * dpi_fac; - const float co_margin = 6.0f * dpi_fac; - /* layout stuff for buttons on group left frame */ - const float colw = 0.6f * node_group_frame; - const float col1 = co_margin - node_group_frame; - const float col2 = col1 + colw + co_margin; - const float col3 = -arrowbutw - co_margin; - /* layout stuff for buttons on group right frame */ - const float cor1 = co_margin; - const float cor2 = cor1 + arrowbutw; - const float cor3 = cor2 + arrowbutw + co_margin; - - /* node and group socket circles */ - if (sock) - node_socket_circle_draw(ntree, sock, socket_size, sock->flag & SELECT); - if (gsock) - node_socket_circle_draw(ngroup, gsock, socket_size, gsock->flag & SELECT); - - /* socket name */ - offset = (in_out == SOCK_IN ? col1 : cor3); - if (!gsock) - offset += (in_out == SOCK_IN ? node_group_frame : -node_group_frame); - - /* draw both name and value button if: - * 1) input: not internal - * 2) output: (node type uses const outputs) and (group output is unlinked) - */ - draw_value = 0; - switch (in_out) { - case SOCK_IN: - draw_value = !(gsock && (gsock->flag & SOCK_INTERNAL)); - break; - case SOCK_OUT: - if (gnode->typeinfo->flag & NODE_CONST_OUTPUT) - draw_value = !(gsock && gsock->link); - break; - } - if (draw_value) { - /* both name and value buttons */ - if (gsock) { - draw_group_socket_name(snode, gnode, gsock, in_out, offset, 0, co_text_w, NODE_DY); - if (stype->buttonfunc) - stype->buttonfunc(C, gnode->block, ngroup, NULL, gsock, "", - gsock->locx + offset, gsock->locy - NODE_DY, colw); - } - else { - draw_group_socket_name(snode, gnode, sock, in_out, offset, 0, co_text_w, NODE_DY); - if (stype->buttonfunc) - stype->buttonfunc(C, gnode->block, ngroup, NULL, sock, "", - sock->locx + offset, sock->locy - NODE_DY, colw); - } - } - else { - /* only name, no value button */ - if (gsock) - draw_group_socket_name(snode, gnode, gsock, in_out, offset, -NODE_DYS, co_text_w, NODE_DY); - else - draw_group_socket_name(snode, gnode, sock, in_out, offset, -NODE_DYS, co_text_w, NODE_DY); - } - - if (gsock && (gsock->flag & SOCK_DYNAMIC)) { - /* up/down buttons */ - offset = (in_out == SOCK_IN ? col2 : cor2); - uiBlockSetDirection(gnode->block, UI_TOP); - uiBlockBeginAlign(gnode->block); - bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_move_up", 0, ICON_TRIA_UP, - gsock->locx + offset, gsock->locy, arrowbutw, arrowbutw, ""); - if (!gsock->prev || !(gsock->prev->flag & SOCK_DYNAMIC)) - uiButSetFlag(bt, UI_BUT_DISABLED); - RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index); - RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", in_out); - bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_move_down", 0, ICON_TRIA_DOWN, - gsock->locx + offset, gsock->locy - arrowbutw, arrowbutw, arrowbutw, ""); - if (!gsock->next || !(gsock->next->flag & SOCK_DYNAMIC)) - uiButSetFlag(bt, UI_BUT_DISABLED); - RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index); - RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", in_out); - uiBlockEndAlign(gnode->block); - uiBlockSetDirection(gnode->block, 0); - - /* remove button */ - offset = (in_out == SOCK_IN ? col3 : cor1); - uiBlockSetEmboss(gnode->block, UI_EMBOSSN); - bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_remove", 0, ICON_X, - gsock->locx + offset, gsock->locy - 0.5f * arrowbutw, arrowbutw, arrowbutw, ""); - RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index); - RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", in_out); - uiBlockSetEmboss(gnode->block, UI_EMBOSS); - } -} - -/* groups are, on creation, centered around 0,0 */ -static void node_draw_group(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *gnode) -{ - if (!(gnode->flag & NODE_GROUP_EDIT)) { - node_draw_default(C, ar, snode, ntree, gnode); - } - else { - bNodeTree *ngroup = (bNodeTree *)gnode->id; - bNodeSocket *sock, *gsock; - uiLayout *layout; - PointerRNA ptr; - rctf rect = gnode->totr; - const float dpi_fac = UI_DPI_FAC; - const float node_group_frame = NODE_GROUP_FRAME * dpi_fac; - const float group_header = 26 * dpi_fac; - - int index; - - /* backdrop header */ - glEnable(GL_BLEND); - uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT); - UI_ThemeColorShadeAlpha(TH_NODE_GROUP, 0, -70); - uiDrawBox(GL_POLYGON, - rect.xmin - node_group_frame, rect.ymax, - rect.xmax + node_group_frame, rect.ymax + group_header, BASIS_RAD); - - /* backdrop body */ - UI_ThemeColorShadeAlpha(TH_BACK, -8, -70); - uiSetRoundBox(UI_CNR_NONE); - uiDrawBox(GL_POLYGON, rect.xmin, rect.ymin, rect.xmax, rect.ymax, BASIS_RAD); - - /* input column */ - UI_ThemeColorShadeAlpha(TH_BACK, 10, -50); - uiSetRoundBox(UI_CNR_BOTTOM_LEFT); - uiDrawBox(GL_POLYGON, rect.xmin - node_group_frame, rect.ymin, rect.xmin, rect.ymax, BASIS_RAD); - - /* output column */ - UI_ThemeColorShadeAlpha(TH_BACK, 10, -50); - uiSetRoundBox(UI_CNR_BOTTOM_RIGHT); - uiDrawBox(GL_POLYGON, rect.xmax, rect.ymin, rect.xmax + node_group_frame, rect.ymax, BASIS_RAD); - - /* input column separator */ - glColor4ub(200, 200, 200, 140); - glBegin(GL_LINES); - glVertex2f(rect.xmin, rect.ymin); - glVertex2f(rect.xmin, rect.ymax); - glEnd(); - - /* output column separator */ - glColor4ub(200, 200, 200, 140); - glBegin(GL_LINES); - glVertex2f(rect.xmax, rect.ymin); - glVertex2f(rect.xmax, rect.ymax); - glEnd(); - - /* group node outline */ - uiSetRoundBox(UI_CNR_ALL); - glColor4ub(200, 200, 200, 140); - glEnable(GL_LINE_SMOOTH); - uiDrawBox(GL_LINE_LOOP, - rect.xmin - node_group_frame, rect.ymin, - rect.xmax + node_group_frame, rect.ymax + group_header, BASIS_RAD); - glDisable(GL_LINE_SMOOTH); - glDisable(GL_BLEND); - - /* backdrop title */ - UI_ThemeColor(TH_TEXT_HI); - - layout = uiBlockLayout(gnode->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, - (int)(rect.xmin + NODE_MARGIN_X), (int)(rect.ymax + (group_header - (2.5f * dpi_fac))), - min_ii((int)(BLI_rctf_size_x(&rect) - 18.0f), node_group_frame + 20), group_header, UI_GetStyle()); - RNA_pointer_create(&ntree->id, &RNA_Node, gnode, &ptr); - uiTemplateIDBrowse(layout, (bContext *)C, &ptr, "node_tree", NULL, NULL, NULL); - uiBlockLayoutResolve(gnode->block, NULL, NULL); - - /* draw the internal tree nodes and links */ - node_draw_nodetree(C, ar, snode, ngroup); - - /* group sockets */ - gsock = ngroup->inputs.first; - sock = gnode->inputs.first; - index = 0; - while (gsock || sock) { - while (sock && !sock->groupsock) { - draw_group_socket(C, snode, ntree, gnode, sock, NULL, index, SOCK_IN); - sock = sock->next; - } - while (gsock && (!sock || sock->groupsock != gsock)) { - draw_group_socket(C, snode, ntree, gnode, NULL, gsock, index, SOCK_IN); - gsock = gsock->next; - index++; - } - while (sock && gsock && sock->groupsock == gsock) { - draw_group_socket(C, snode, ntree, gnode, sock, gsock, index, SOCK_IN); - sock = sock->next; - gsock = gsock->next; - index++; - } - } - gsock = ngroup->outputs.first; - sock = gnode->outputs.first; - index = 0; - while (gsock || sock) { - while (sock && !sock->groupsock) { - draw_group_socket(C, snode, ntree, gnode, sock, NULL, index, SOCK_OUT); - sock = sock->next; - } - while (gsock && (!sock || sock->groupsock != gsock)) { - draw_group_socket(C, snode, ntree, gnode, NULL, gsock, index, SOCK_OUT); - gsock = gsock->next; - index++; - } - while (sock && gsock && sock->groupsock == gsock) { - draw_group_socket(C, snode, ntree, gnode, sock, gsock, index, SOCK_OUT); - sock = sock->next; - gsock = gsock->next; - index++; - } - } - - uiEndBlock(C, gnode->block); - uiDrawBlock(C, gnode->block); - gnode->block = NULL; - } -} static void node_uifunc_group(uiLayout *layout, bContext *C, PointerRNA *ptr) { @@ -1003,7 +534,8 @@ static void node_draw_frame_label(bNode *node, const float aspect) BLF_disable(fontid, BLF_ASPECT); } -static void node_draw_frame(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *UNUSED(ntree), bNode *node) +static void node_draw_frame(const bContext *C, ARegion *ar, SpaceNode *snode, + bNodeTree *UNUSED(ntree), bNode *node, bNodeInstanceKey UNUSED(key)) { rctf *rct = &node->totr; int color_id = node_get_colorid(node); @@ -1118,7 +650,8 @@ static void node_update_reroute(const bContext *UNUSED(C), bNodeTree *UNUSED(ntr node->totr.ymin = locy - size; } -static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED(snode), bNodeTree *ntree, bNode *node) +static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED(snode), + bNodeTree *ntree, bNode *node, bNodeInstanceKey UNUSED(key)) { bNodeSocket *sock; char showname[128]; /* 128 used below */ @@ -1178,7 +711,7 @@ static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED( * highlight also if node itself is selected, since we don't display the node body separately! */ for (sock = node->inputs.first; sock; sock = sock->next) { - node_socket_circle_draw(ntree, sock, socket_size, (sock->flag & SELECT) || (node->flag & SELECT)); + node_socket_circle_draw(C, ntree, node, sock, socket_size, (sock->flag & SELECT) || (node->flag & SELECT)); } uiEndBlock(C, node->block); @@ -1205,8 +738,6 @@ static void node_common_set_butfunc(bNodeType *ntype) switch (ntype->type) { case NODE_GROUP: ntype->uifunc = node_uifunc_group; - ntype->drawfunc = node_draw_group; - ntype->drawupdatefunc = node_update_group; break; case NODE_FRAME: ntype->drawfunc = node_draw_frame; @@ -1491,8 +1022,6 @@ static void node_shader_buts_script_details(uiLayout *layout, bContext *C, Point static void node_shader_set_butfunc(bNodeType *ntype) { switch (ntype->type) { - /* case NODE_GROUP: note, typeinfo for group is generated... see "XXX ugly hack" */ - case SH_NODE_MATERIAL: case SH_NODE_MATERIAL_EXT: ntype->uifunc = node_shader_buts_material; @@ -2092,20 +1621,17 @@ static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), Po } /* draw function for file output node sockets, displays only sub-path and format, no value button */ -static void node_draw_input_file_output(const bContext *C, uiBlock *block, - bNodeTree *ntree, bNode *node, bNodeSocket *sock, - const char *UNUSED(name), int x, int y, int width) +static void node_draw_input_file_output(bContext *C, uiLayout *layout, PointerRNA *ptr, PointerRNA *node_ptr, int UNUSED(linked)) { - uiLayout *layout, *row; - PointerRNA nodeptr, inputptr, imfptr; + bNodeTree *ntree = ptr->id.data; + bNodeSocket *sock = ptr->data; + uiLayout *row; + PointerRNA inputptr, imfptr; int imtype; - int rx, ry; - RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr); - layout = uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, x, y + NODE_DY, width, 20, UI_GetStyle()); row = uiLayoutRow(layout, FALSE); - imfptr = RNA_pointer_get(&nodeptr, "format"); + imfptr = RNA_pointer_get(node_ptr, "format"); imtype = RNA_enum_get(&imfptr, "file_format"); if (imtype == R_IMF_IMTYPE_MULTILAYER) { NodeImageMultiFileSocket *input = sock->storage; @@ -2117,6 +1643,7 @@ static void node_draw_input_file_output(const bContext *C, uiBlock *block, NodeImageMultiFileSocket *input = sock->storage; PropertyRNA *imtype_prop; const char *imtype_name; + uiBlock *block; RNA_pointer_create(&ntree->id, &RNA_NodeOutputFileSlotFile, input, &inputptr); uiItemL(row, input->path, ICON_NONE); @@ -2127,12 +1654,11 @@ static void node_draw_input_file_output(const bContext *C, uiBlock *block, imtype_prop = RNA_struct_find_property(&imfptr, "file_format"); RNA_property_enum_name((bContext *)C, &imfptr, imtype_prop, RNA_property_enum_get(&imfptr, imtype_prop), &imtype_name); + block = uiLayoutGetBlock(row); uiBlockSetEmboss(block, UI_EMBOSSP); uiItemL(row, imtype_name, ICON_NONE); uiBlockSetEmboss(block, UI_EMBOSSN); } - - uiBlockLayoutResolve(block, &rx, &ry); } static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { @@ -2781,8 +2307,6 @@ static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRN static void node_composit_set_butfunc(bNodeType *ntype) { switch (ntype->type) { - /* case NODE_GROUP: note, typeinfo for group is generated... see "XXX ugly hack" */ - case CMP_NODE_IMAGE: ntype->uifunc = node_composit_buts_image; ntype->uifuncbut = node_composit_buts_image_details; @@ -2998,8 +2522,6 @@ static void node_composit_set_butfunc(bNodeType *ntype) case CMP_NODE_TRACKPOS: ntype->uifunc = node_composit_buts_trackpos; break; - default: - ntype->uifunc = NULL; } } @@ -3158,81 +2680,170 @@ static void node_texture_set_butfunc(bNodeType *ntype) /* ******* init draw callbacks for all tree types, only called in usiblender.c, once ************* */ -void ED_node_init_butfuncs(void) +static void node_property_update_default(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { - bNodeTreeType *treetype; - bNodeType *ntype; - bNodeSocketType *stype; - int i; + bNodeTree *ntree = ptr->id.data; + ED_node_tag_update_nodetree(bmain, ntree); +} + +static void node_socket_template_properties_update(bNodeType *ntype, bNodeSocketTemplate *stemp) +{ + StructRNA *srna = ntype->ext.srna; + PropertyRNA *prop = RNA_struct_type_find_property(srna, stemp->identifier); - /* node type ui functions */ - for (i = 0; i < NUM_NTREE_TYPES; ++i) { - treetype = ntreeGetType(i); - if (treetype) { - for (ntype = treetype->node_types.first; ntype; ntype = ntype->next) { - /* default ui functions */ - ntype->drawfunc = node_draw_default; - ntype->drawupdatefunc = node_update_default; - ntype->select_area_func = node_select_area_default; - ntype->tweak_area_func = node_tweak_area_default; - ntype->uifunc = NULL; - ntype->uifuncbut = NULL; - ntype->drawinputfunc = node_draw_input_default; - ntype->drawoutputfunc = node_draw_output_default; - ntype->resize_area_func = node_resize_area_default; - - node_common_set_butfunc(ntype); - - switch (i) { - case NTREE_COMPOSIT: - node_composit_set_butfunc(ntype); - break; - case NTREE_SHADER: - node_shader_set_butfunc(ntype); - break; - case NTREE_TEXTURE: - node_texture_set_butfunc(ntype); - break; - } - } - } + if (prop) + RNA_def_property_update_runtime(prop, node_property_update_default); +} + +static void node_template_properties_update(bNodeType *ntype) +{ + bNodeSocketTemplate *stemp; + + if (ntype->inputs) { + for (stemp = ntype->inputs; stemp->type >= 0; ++stemp) + node_socket_template_properties_update(ntype, stemp); } + if (ntype->outputs) { + for (stemp = ntype->outputs; stemp->type >= 0; ++stemp) + node_socket_template_properties_update(ntype, stemp); + } +} + +void ED_node_init_butfuncs(void) +{ + /* node type ui functions */ + NODE_TYPES_BEGIN(ntype) + /* default ui functions */ + ntype->drawfunc = node_draw_default; + ntype->drawupdatefunc = node_update_default; + ntype->select_area_func = node_select_area_default; + ntype->tweak_area_func = node_tweak_area_default; + ntype->uifunc = NULL; + ntype->uifuncbut = NULL; + ntype->drawinputfunc = node_draw_input_default; + ntype->drawoutputfunc = node_draw_output_default; + ntype->resize_area_func = node_resize_area_default; + + node_common_set_butfunc(ntype); + + node_composit_set_butfunc(ntype); + node_shader_set_butfunc(ntype); + node_texture_set_butfunc(ntype); + + /* define update callbacks for socket properties */ + node_template_properties_update(ntype); + NODE_TYPES_END - /* socket type ui functions */ - for (i = 0; i < NUM_SOCKET_TYPES; ++i) { - stype = ntreeGetSocketType(i); - if (stype) { - switch (stype->type) { - case SOCK_FLOAT: - case SOCK_INT: - case SOCK_BOOLEAN: - stype->buttonfunc = node_socket_button_default; - break; - case SOCK_STRING: - stype->buttonfunc = node_socket_button_string; - break; - case SOCK_VECTOR: - stype->buttonfunc = node_socket_button_components; - break; - case SOCK_RGBA: - stype->buttonfunc = node_socket_button_color; - break; - case SOCK_SHADER: - stype->buttonfunc = node_socket_button_label; - break; - default: - stype->buttonfunc = NULL; - } + /* tree type icons */ + ntreeType_Composite->ui_icon = ICON_RENDERLAYERS; + ntreeType_Composite->draw_add_menu = node_add_menu_default; + ntreeType_Shader->ui_icon = ICON_MATERIAL; + ntreeType_Shader->draw_add_menu = node_add_menu_default; + ntreeType_Texture->ui_icon = ICON_TEXTURE; + ntreeType_Texture->draw_add_menu = node_add_menu_default; +} + +void ED_init_custom_node_type(bNodeType *ntype) +{ + /* default ui functions */ + ntype->drawfunc = node_draw_default; + ntype->drawupdatefunc = node_update_default; + ntype->drawinputfunc = node_draw_input_default; + ntype->drawoutputfunc = node_draw_output_default; + ntype->resize_area_func = node_resize_area_default; + ntype->select_area_func = node_select_area_default; + ntype->tweak_area_func = node_tweak_area_default; +} + +void ED_init_custom_node_socket_type(bNodeSocketType *stype) +{ + /* default ui functions */ + stype->draw = node_socket_button_label; +} + +/* maps standard socket integer type to a color */ +static const float std_node_socket_colors[][4] = { + {0.63, 0.63, 0.63, 1.0}, /* SOCK_FLOAT */ + {0.39, 0.39, 0.78, 1.0}, /* SOCK_VECTOR */ + {0.78, 0.78, 0.16, 1.0}, /* SOCK_RGBA */ + {0.39, 0.78, 0.39, 1.0}, /* SOCK_SHADER */ + {0.70, 0.65, 0.19, 1.0}, /* SOCK_BOOLEAN */ + {0.0, 0.0, 0.0, 1.0}, /*__SOCK_MESH (deprecated) */ + {0.06, 0.52, 0.15, 1.0}, /* SOCK_INT */ + {1.0, 1.0, 1.0, 1.0}, /* SOCK_STRING */ +}; + +/* common color callbacks for standard types */ +static void std_node_socket_draw_color(bContext *UNUSED(C), PointerRNA *ptr, PointerRNA *UNUSED(node_ptr), float *r_color) +{ + bNodeSocket *sock = ptr->data; + int type = sock->typeinfo->type; + copy_v4_v4(r_color, std_node_socket_colors[type]); +} +static void std_node_socket_interface_draw_color(bContext *UNUSED(C), PointerRNA *ptr, float *r_color) +{ + bNodeSocket *sock = ptr->data; + int type = sock->typeinfo->type; + copy_v4_v4(r_color, std_node_socket_colors[type]); +} + +static void std_node_socket_draw(bContext *UNUSED(C), uiLayout *layout, PointerRNA *ptr, PointerRNA *UNUSED(node_ptr)) +{ + bNodeSocket *sock = ptr->data; + int type = sock->typeinfo->type; + /*int subtype = sock->typeinfo->subtype;*/ + + switch (type) { + case SOCK_FLOAT: + case SOCK_INT: + case SOCK_BOOLEAN: + uiItemR(layout, ptr, "default_value", 0, sock->name, 0); + break; + case SOCK_VECTOR: + uiTemplateComponentMenu(layout, ptr, "default_value", sock->name); + break; + case SOCK_RGBA: { + uiLayout *row = uiLayoutRow(layout, false); + uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT); + /* draw the socket name right of the actual button */ + uiItemR(row, ptr, "default_value", 0, "", 0); + uiItemL(row, sock->name, 0); + break; + } + case SOCK_STRING: { + uiLayout *row = uiLayoutRow(layout, true); + /* draw the socket name right of the actual button */ + uiItemR(row, ptr, "default_value", 0, "", 0); + uiItemL(row, sock->name, 0); + break; } } } +void ED_init_standard_node_socket_type(bNodeSocketType *stype) +{ + stype->draw = std_node_socket_draw; + stype->draw_color = std_node_socket_draw_color; + stype->interface_draw_color = std_node_socket_interface_draw_color; +} + +static void node_socket_virtual_draw_color(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PointerRNA *UNUSED(node_ptr), float *r_color) +{ + /* alpha = 0, empty circle */ + zero_v4(r_color); +} + +void ED_init_node_socket_type_virtual(bNodeSocketType *stype) +{ + stype->draw = node_socket_button_label; + stype->draw_color = node_socket_virtual_draw_color; +} + /* ************** Generic drawing ************** */ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode) { - - if ((snode->flag & SNODE_BACKDRAW) && snode->treetype == NTREE_COMPOSIT) { + if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) { Image *ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node"); void *lock; ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); @@ -3640,18 +3251,13 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link) do_triple = TRUE; } else { - int cycle = 0; - /* going to give issues once... */ if (link->tosock->flag & SOCK_UNAVAIL) return; if (link->fromsock->flag & SOCK_UNAVAIL) return; - /* check cyclic */ - if (link->fromnode && link->tonode) - cycle = (link->fromnode->level < link->tonode->level || link->tonode->level == 0xFFF); - if (!cycle && (link->flag & NODE_LINK_VALID)) { + if (link->flag & NODE_LINK_VALID) { /* special indicated link, on drop-node */ if (link->flag & NODE_LINKFLAG_HILITE) { th_col1 = th_col2 = TH_ACTIVE; diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c index 235d91ecd92..cd04957c0a5 100644 --- a/source/blender/editors/space_node/node_add.c +++ b/source/blender/editors/space_node/node_add.c @@ -62,62 +62,60 @@ #include "node_intern.h" /* own include */ -/* can be called from menus too, but they should do own undopush and redraws */ -bNode *node_add_node(SpaceNode *snode, Main *bmain, Scene *scene, - bNodeTemplate *ntemp, float locx, float locy) +/* XXX Does some additional initialization on top of nodeAddNode + * Can be used with both custom and static nodes, if idname==NULL the static int type will be used instead. + * Can be called from menus too, but they should do own undopush and redraws. + */ +bNode *node_add_node(const bContext *C, const char *idname, int type, float locx, float locy) { - bNode *node = NULL, *gnode; - + SpaceNode *snode = CTX_wm_space_node(C); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + bNode *node = NULL; + node_deselect_all(snode); - - node = nodeAddNode(snode->edittree, ntemp); - + + if (idname) + node = nodeAddNode(C, snode->edittree, idname); + else + node = nodeAddStaticNode(C, snode->edittree, type); + BLI_assert(node && node->typeinfo); + /* generics */ - if (node) { - node_select(node); - - /* node location is mapped */ - locx /= UI_DPI_FAC; - locy /= UI_DPI_FAC; - - gnode = node_tree_get_editgroup(snode->nodetree); - // arbitrary y offset of 60 so its visible - if (gnode) { - node_from_view(gnode, locx, locy + 60.0f, &node->locx, &node->locy); - } - else { - node->locx = locx; - node->locy = locy + 60.0f; + node->locx = locx; + node->locy = locy + 60.0f; // arbitrary.. so its visible, (0,0) is top of node + nodeSetSelected(node, TRUE); + + /* node location is mapped */ + locx /= UI_DPI_FAC; + locy /= UI_DPI_FAC; + + node->locx = locx; + node->locy = locy + 60.0f; + + ntreeUpdateTree(snode->edittree); + ED_node_set_active(bmain, snode->edittree, node); + + if (snode->nodetree->type == NTREE_COMPOSIT) { + if (ELEM4(node->type, CMP_NODE_R_LAYERS, CMP_NODE_COMPOSITE, CMP_NODE_DEFOCUS, CMP_NODE_OUTPUT_FILE)) { + node->id = &scene->id; } - - ntreeUpdateTree(snode->edittree); - ED_node_set_active(bmain, snode->edittree, node); - - if (snode->nodetree->type == NTREE_COMPOSIT) { - if (ELEM4(node->type, CMP_NODE_R_LAYERS, CMP_NODE_COMPOSITE, CMP_NODE_DEFOCUS, CMP_NODE_OUTPUT_FILE)) { - node->id = &scene->id; - } - else if (ELEM3(node->type, CMP_NODE_MOVIECLIP, CMP_NODE_MOVIEDISTORTION, CMP_NODE_STABILIZE2D)) { - node->id = (ID *)scene->clip; - } - - ntreeCompositForceHidden(snode->edittree, scene); + else if (ELEM3(node->type, CMP_NODE_MOVIECLIP, CMP_NODE_MOVIEDISTORTION, CMP_NODE_STABILIZE2D)) { + node->id = (ID *)scene->clip; } - - if (node->id) - id_us_plus(node->id); - - - if (snode->flag & SNODE_USE_HIDDEN_PREVIEW) - node->flag &= ~NODE_PREVIEW; - - snode_update(snode, node); + + ntreeCompositForceHidden(snode->edittree, scene); } - + + if (node->id) + id_us_plus(node->id); + + snode_update(snode, node); + if (snode->nodetree->type == NTREE_TEXTURE) { ntreeTexCheckCyclics(snode->edittree); } - + return node; } @@ -183,9 +181,7 @@ static bNodeSocketLink *add_reroute_do_socket_section(bContext *C, bNodeSocketLi /* create the reroute node for this cursock */ if (!reroute_node) { - bNodeTemplate ntemp; - ntemp.type = NODE_REROUTE; - reroute_node = nodeAddNode(ntree, &ntemp); + reroute_node = nodeAddStaticNode(C, ntree, NODE_REROUTE); /* add a single link to/from the reroute node to replace multiple links */ if (in_out == SOCK_OUT) { @@ -213,18 +209,11 @@ static bNodeSocketLink *add_reroute_do_socket_section(bContext *C, bNodeSocketLi } if (num_links > 0) { - bNode *gnode = node_tree_get_editgroup(snode->nodetree); - /* average cut point from shared links */ mul_v2_fl(insert_point, 1.0f / num_links); - if (gnode) { - node_from_view(gnode, insert_point[0], insert_point[1], &reroute_node->locx, &reroute_node->locy); - } - else { - reroute_node->locx = insert_point[0]; - reroute_node->locy = insert_point[1]; - } + reroute_node->locx = insert_point[0]; + reroute_node->locy = insert_point[1]; } return socklink; @@ -266,6 +255,8 @@ static int add_reroute_exec(bContext *C, wmOperator *op) output_links.first = output_links.last = NULL; input_links.first = input_links.last = NULL; for (link = ntree->links.first; link; link = link->next) { + if (nodeLinkIsHidden(link)) + continue; if (add_reroute_intersect_check(link, mcoords, i, insert_point)) { add_reroute_insert_socket_link(&output_links, link->fromsock, link, insert_point); add_reroute_insert_socket_link(&input_links, link->tosock, link, insert_point); @@ -330,12 +321,10 @@ void NODE_OT_add_reroute(wmOperatorType *ot) static int node_add_file_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); SpaceNode *snode = CTX_wm_space_node(C); bNode *node; Image *ima = NULL; - bNodeTemplate ntemp; + int type= 0; /* check input variables */ if (RNA_struct_property_is_set(op->ptr, "filepath")) { @@ -367,36 +356,35 @@ static int node_add_file_exec(bContext *C, wmOperator *op) switch (snode->nodetree->type) { case NTREE_SHADER: - ntemp.type = SH_NODE_TEX_IMAGE; + type = SH_NODE_TEX_IMAGE; break; case NTREE_TEXTURE: - ntemp.type = TEX_NODE_IMAGE; + type = TEX_NODE_IMAGE; break; case NTREE_COMPOSIT: - ntemp.type = CMP_NODE_IMAGE; + type = CMP_NODE_IMAGE; break; default: return OPERATOR_CANCELLED; } - + ED_preview_kill_jobs(C); - - node = node_add_node(snode, bmain, scene, &ntemp, snode->cursor[0], snode->cursor[1]); - + + node = node_add_node(C, NULL, type, snode->cursor[0], snode->cursor[1]); + if (!node) { BKE_report(op->reports, RPT_WARNING, "Could not add an image node"); return OPERATOR_CANCELLED; } - + node->id = (ID *)ima; - id_us_plus(node->id); - + BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD); WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima); snode_notify(C, snode); snode_dag_update(C, snode); - + return OPERATOR_FINISHED; } @@ -404,11 +392,11 @@ static int node_add_file_invoke(bContext *C, wmOperator *op, const wmEvent *even { ARegion *ar = CTX_wm_region(C); SpaceNode *snode = CTX_wm_space_node(C); - + /* convert mouse coordinates to v2d space */ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &snode->cursor[0], &snode->cursor[1]); - + if (RNA_struct_property_is_set(op->ptr, "filepath") || RNA_struct_property_is_set(op->ptr, "name")) return node_add_file_exec(C, op); else @@ -435,35 +423,35 @@ void NODE_OT_add_file(wmOperatorType *ot) RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Datablock name to assign"); } - /********************** New node tree operator *********************/ static int new_node_tree_exec(bContext *C, wmOperator *op) { - SpaceNode *snode; + SpaceNode *snode= CTX_wm_space_node(C); + Main *bmain = CTX_data_main(C); bNodeTree *ntree; - Main *bmain; PointerRNA ptr, idptr; PropertyRNA *prop; - int treetype; + const char *idname; char treename[MAX_ID_NAME - 2] = "NodeTree"; - - /* retrieve state */ - snode = CTX_wm_space_node(C); - bmain = CTX_data_main(C); - - if (RNA_struct_property_is_set(op->ptr, "type")) - treetype = RNA_enum_get(op->ptr, "type"); - else - treetype = snode->treetype; - + + if (RNA_struct_property_is_set(op->ptr, "type")) { + prop = RNA_struct_find_property(op->ptr, "type"); + RNA_property_enum_identifier(C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &idname); + } + else if (snode) + idname = snode->tree_idname; + if (RNA_struct_property_is_set(op->ptr, "name")) RNA_string_get(op->ptr, "name", treename); - - ntree = ntreeAddTree(bmain, treename, treetype, 0); - if (!ntree) + + if (!ntreeTypeFind(idname)) { + BKE_reportf(op->reports, RPT_ERROR, "Node tree type %s undefined", idname); return OPERATOR_CANCELLED; - + } + + ntree = ntreeAddTree(bmain, treename, idname); + /* hook into UI */ uiIDContextProperty(C, &ptr, &prop); @@ -477,29 +465,36 @@ static int new_node_tree_exec(bContext *C, wmOperator *op) RNA_property_update(C, &ptr, prop); } else if (snode) { - Scene *scene = CTX_data_scene(C); snode->nodetree = ntree; - - ED_node_tree_update(snode, scene); + + ED_node_tree_update(C); } - + return OPERATOR_FINISHED; } +static EnumPropertyItem *new_node_tree_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) +{ + return rna_node_tree_type_itemf(NULL, NULL, free); +} + void NODE_OT_new_node_tree(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "New Node Tree"; ot->idname = "NODE_OT_new_node_tree"; ot->description = "Create a new node tree"; - + /* api callbacks */ ot->exec = new_node_tree_exec; - ot->poll = ED_operator_node_active; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_enum(ot->srna, "type", nodetree_type_items, NTREE_COMPOSIT, "Tree Type", ""); + + prop = RNA_def_enum(ot->srna, "type", DummyRNA_NULL_items, 0, "Tree Type", ""); + RNA_def_enum_funcs(prop, new_node_tree_type_itemf); RNA_def_string(ot->srna, "name", "NodeTree", MAX_ID_NAME - 2, "Name", ""); } + diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c index 300328f5fd4..30cc3b93e8a 100644 --- a/source/blender/editors/space_node/node_buttons.c +++ b/source/blender/editors/space_node/node_buttons.c @@ -62,7 +62,7 @@ static int active_nodetree_poll(const bContext *C, PanelType *UNUSED(pt)) { SpaceNode *snode = CTX_wm_space_node(C); - return (snode && snode->nodetree); + return (snode && ntreeIsValid(snode->nodetree)); } /* poll callback for active node */ @@ -70,7 +70,7 @@ static int active_node_poll(const bContext *C, PanelType *UNUSED(pt)) { SpaceNode *snode = CTX_wm_space_node(C); - return (snode && snode->edittree && nodeGetActive(snode->edittree)); + return (snode && ntreeIsValid(snode->edittree) && nodeGetActive(snode->edittree)); } /* active node */ @@ -160,6 +160,86 @@ static void node_sockets_panel(const bContext *C, Panel *pa) } } +static int node_tree_interface_poll(const bContext *C, PanelType *UNUSED(pt)) +{ + SpaceNode *snode= CTX_wm_space_node(C); + + return (snode && snode->edittree && (snode->edittree->inputs.first || snode->edittree->outputs.first)); +} + +static int node_tree_find_active_socket(bNodeTree *ntree, bNodeSocket **r_sock, int *r_in_out) +{ + bNodeSocket *sock; + for (sock = ntree->inputs.first; sock; sock = sock->next) { + if (sock->flag & SELECT) { + *r_sock = sock; + *r_in_out = SOCK_IN; + return TRUE; + } + } + for (sock = ntree->outputs.first; sock; sock = sock->next) { + if (sock->flag & SELECT) { + *r_sock = sock; + *r_in_out = SOCK_OUT; + return TRUE; + } + } + + *r_sock = NULL; + *r_in_out = 0; + return FALSE; +} + +static void node_tree_interface_panel(const bContext *C, Panel *pa) +{ + SpaceNode *snode= CTX_wm_space_node(C); + bNodeTree *ntree= (snode) ? snode->edittree : NULL; + bNodeSocket *sock; + int in_out; + uiLayout *layout= pa->layout, *row, *split, *col; + PointerRNA ptr, sockptr, opptr; + + if(!ntree) + return; + + RNA_id_pointer_create((ID *)ntree, &ptr); + + node_tree_find_active_socket(ntree, &sock, &in_out); + RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, sock, &sockptr); + + row = uiLayoutRow(layout, FALSE); + + split = uiLayoutRow(row, TRUE); + col = uiLayoutColumn(split, TRUE); + uiItemL(col, "Inputs:", ICON_NONE); + uiTemplateList(col, (bContext*)C, "NODE_UL_interface_sockets", "", &ptr, "inputs", &ptr, "active_input", 0, 0, 0); + opptr = uiItemFullO(col, "NODE_OT_tree_socket_add", "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); + RNA_enum_set(&opptr, "in_out", SOCK_IN); + + col = uiLayoutColumn(split, TRUE); + uiItemL(col, "Outputs:", ICON_NONE); + uiTemplateList(col, (bContext*)C, "NODE_UL_interface_sockets", "", &ptr, "outputs", &ptr, "active_output", 0, 0, 0); + opptr = uiItemFullO(col, "NODE_OT_tree_socket_add", "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); + RNA_enum_set(&opptr, "in_out", SOCK_OUT); + + col = uiLayoutColumn(row, TRUE); + opptr = uiItemFullO(col, "NODE_OT_tree_socket_move", "", ICON_TRIA_UP, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); + RNA_enum_set(&opptr, "direction", 1); + opptr = uiItemFullO(col, "NODE_OT_tree_socket_move", "", ICON_TRIA_DOWN, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); + RNA_enum_set(&opptr, "direction", 2); + + if (sock) { + row = uiLayoutRow(layout, TRUE); + uiItemR(row, &sockptr, "name", 0, NULL, ICON_NONE); + uiItemO(row, "", ICON_X, "NODE_OT_tree_socket_remove"); + + uiItemS(layout); + + if (sock->typeinfo->interface_draw) + sock->typeinfo->interface_draw((bContext*)C, layout, &sockptr); + } +} + /* ******************* node buttons registration ************** */ void node_buttons_register(ARegionType *art) @@ -180,7 +260,14 @@ void node_buttons_register(ARegionType *art) pt->poll = node_sockets_poll; pt->flag |= PNL_DEFAULT_CLOSED; BLI_addtail(&art->paneltypes, pt); - + + pt= MEM_callocN(sizeof(PanelType), "spacetype node panel tree interface"); + strcpy(pt->idname, "NODE_PT_node_tree_interface"); + strcpy(pt->label, "Interface"); + pt->draw= node_tree_interface_panel; + pt->poll= node_tree_interface_poll; + BLI_addtail(&art->paneltypes, pt); + pt = MEM_callocN(sizeof(PanelType), "spacetype node panel gpencil"); strcpy(pt->idname, "NODE_PT_gpencil"); strcpy(pt->label, "Grease Pencil"); diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index d2cc42b0a56..80a6ff1a393 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -29,10 +29,14 @@ * \brief higher level node drawing for the node editor. */ +#include "DNA_lamp_types.h" #include "DNA_node_types.h" +#include "DNA_material_types.h" #include "DNA_object_types.h" -#include "DNA_space_types.h" #include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_texture_types.h" +#include "DNA_world_types.h" #include "BLI_math.h" #include "BLI_blenlib.h" @@ -44,6 +48,8 @@ #include "BKE_main.h" #include "BKE_node.h" +#include "BLF_api.h" + #include "BIF_gl.h" #include "BIF_glutil.h" @@ -52,6 +58,7 @@ #include "ED_node.h" #include "ED_gpencil.h" +#include "ED_screen.h" #include "ED_space_api.h" #include "UI_resources.h" @@ -65,25 +72,49 @@ /* XXX interface.h */ extern void ui_dropshadow(const rctf *rct, float radius, float aspect, float alpha, int select); -/* XXX update functions for node editor are a mess, needs a clear concept */ -void ED_node_tree_update(SpaceNode *snode, Scene *scene) +void ED_node_tree_update(const bContext *C) { - snode_set_context(snode, scene); + SpaceNode *snode = CTX_wm_space_node(C); + snode_set_context(C); if (snode->nodetree && snode->nodetree->id.us == 0) snode->nodetree->id.us = 1; } -void ED_node_changed_update(ID *id, bNode *node) +/* id is supposed to contain a node tree */ +static bNodeTree *node_tree_from_ID(ID *id) { - bNodeTree *nodetree, *edittree; - int treetype; - - node_tree_from_ID(id, &nodetree, &edittree, &treetype); + if (id) { + short idtype = GS(id->name); + + switch (idtype) { + case ID_NT: + return (bNodeTree*)id; + case ID_MA: + return ((Material*)id)->nodetree; + case ID_LA: + return ((Lamp*)id)->nodetree; + case ID_WO: + return ((World*)id)->nodetree; + case ID_SCE: + return ((Scene*)id)->nodetree; + case ID_TE: + return ((Tex*)id)->nodetree; + } + } + + return NULL; +} - if (treetype == NTREE_SHADER) { +void ED_node_tag_update_id(ID *id) +{ + bNodeTree *ntree = node_tree_from_ID(id); + if (id == NULL) + return; + + if (ntree->type == NTREE_SHADER) { DAG_id_tag_update(id, 0); - + if (GS(id->name) == ID_MA) WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, id); else if (GS(id->name) == ID_LA) @@ -91,18 +122,10 @@ void ED_node_changed_update(ID *id, bNode *node) else if (GS(id->name) == ID_WO) WM_main_add_notifier(NC_WORLD | ND_WORLD_DRAW, id); } - else if (treetype == NTREE_COMPOSIT) { - 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); - if (node) - nodeUpdateID(nodetree, node->id); - + else if (ntree->type == NTREE_COMPOSIT) { WM_main_add_notifier(NC_SCENE | ND_NODES, id); } - else if (treetype == NTREE_TEXTURE) { + else if (ntree->type == NTREE_TEXTURE) { DAG_id_tag_update(id, 0); WM_main_add_notifier(NC_TEXTURE | ND_NODES, id); } @@ -123,25 +146,17 @@ static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup) return 0; } -typedef struct NodeUpdateCalldata { - bNodeTree *ntree; - bNode *node; -} NodeUpdateCalldata; -static void node_generic_update_cb(void *calldata, ID *owner_id, bNodeTree *ntree) -{ - NodeUpdateCalldata *cd = (NodeUpdateCalldata *)calldata; - /* check if nodetree uses the group stored in calldata */ - if (has_nodetree(ntree, cd->ntree)) - ED_node_changed_update(owner_id, cd->node); -} -void ED_node_generic_update(Main *bmain, bNodeTree *ntree, bNode *node) +void ED_node_tag_update_nodetree(Main *bmain, bNodeTree *ntree) { - bNodeTreeType *tti = ntreeGetType(ntree->type); - NodeUpdateCalldata cd; - cd.ntree = ntree; - cd.node = node; + if (!ntreeIsValid(ntree)) + return; + /* look through all datablocks, to support groups */ - tti->foreach_nodetree(bmain, &cd, node_generic_update_cb); + FOREACH_NODETREE(bmain, tntree, id) { + /* check if nodetree uses the group */ + if (has_nodetree(tntree, ntree)) + ED_node_tag_update_id(id); + } FOREACH_NODETREE_END if (ntree->type == NTREE_TEXTURE) ntreeTexCheckCyclics(ntree); @@ -251,12 +266,12 @@ void ED_node_sort(bNodeTree *ntree) } -static void do_node_internal_buttons(bContext *C, void *node_v, int event) +static void do_node_internal_buttons(bContext *C, void *UNUSED(node_v), int event) { if (event == B_NODE_EXEC) { SpaceNode *snode = CTX_wm_space_node(C); if (snode && snode->id) - ED_node_changed_update(snode->id, node_v); + ED_node_tag_update_id(snode->id); } } @@ -296,13 +311,15 @@ void node_from_view(struct bNode *node, float x, float y, float *rx, float *ry) /* based on settings in node, sets drawing rect info. each redraw! */ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) { - uiLayout *layout; - PointerRNA ptr; + uiLayout *layout, *row; + PointerRNA nodeptr, sockptr; bNodeSocket *nsock; float locx, locy; float dy; int buty; + RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr); + /* get "global" coords */ node_to_view(node, 0.0f, 0.0f, &locx, &locy); dy = locy; @@ -313,14 +330,36 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) /* little bit space in top */ if (node->outputs.first) dy -= NODE_DYS / 2; - + /* output sockets */ for (nsock = node->outputs.first; nsock; nsock = nsock->next) { - if (!nodeSocketIsHidden(nsock)) { - nsock->locx = locx + NODE_WIDTH(node); - nsock->locy = dy - NODE_DYS; - dy -= NODE_DY; - } + if (nodeSocketIsHidden(nsock)) + continue; + + RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr); + + layout = uiBlockLayout(node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, + locx+NODE_DYS, dy, NODE_WIDTH(node)-NODE_DY, NODE_DY, UI_GetStyle()); + /* context pointers for current node and socket */ + uiLayoutSetContextPointer(layout, "node", &nodeptr); + uiLayoutSetContextPointer(layout, "socket", &sockptr); + + /* align output buttons to the right */ + row = uiLayoutRow(layout, 1); + uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT); + + node->typeinfo->drawoutputfunc((bContext *)C, row, &sockptr, &nodeptr, (nsock->flag & SOCK_IN_USE)); + + uiBlockEndAlign(node->block); + uiBlockLayoutResolve(node->block, NULL, &buty); + + /* ensure minimum socket height in case layout is empty */ + buty = MIN2(buty, dy - NODE_DY); + + nsock->locx = locx + NODE_WIDTH(node); + /* place the socket circle in the middle of the layout */ + nsock->locy = 0.5f * (dy + buty); + dy = buty; } node->prvr.xmin = locx + NODE_DYS; @@ -328,43 +367,32 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) /* preview rect? */ if (node->flag & NODE_PREVIEW) { - if (node->preview && node->preview->rect) { - float aspect = 1.0f; - - if (node->preview && node->preview->xsize && node->preview->ysize) - aspect = (float)node->preview->ysize / (float)node->preview->xsize; + float aspect = 1.0f; + + if (node->preview_xsize && node->preview_ysize) + aspect = (float)node->preview_ysize / (float)node->preview_xsize; + + dy -= NODE_DYS / 2; + node->prvr.ymax = dy; + + if (aspect <= 1.0f) + node->prvr.ymin = dy - aspect * (NODE_WIDTH(node) - NODE_DY); + else { + /* width correction of image */ + /* XXX huh? (ton) */ + float dx = (NODE_WIDTH(node) - NODE_DYS) - (NODE_WIDTH(node) - NODE_DYS) / aspect; - dy -= NODE_DYS / 2; - node->prvr.ymax = dy; + node->prvr.ymin = dy - (NODE_WIDTH(node) - NODE_DY); - if (aspect <= 1.0f) - node->prvr.ymin = dy - aspect * (NODE_WIDTH(node) - NODE_DY); - else { - /* width correction of image */ - /* XXX huh? (ton) */ - float dx = (NODE_WIDTH(node) - NODE_DYS) - (NODE_WIDTH(node) - NODE_DYS) / aspect; - - node->prvr.ymin = dy - (NODE_WIDTH(node) - NODE_DY); - - node->prvr.xmin += 0.5f * dx; - node->prvr.xmax -= 0.5f * dx; - } - - dy = node->prvr.ymin - NODE_DYS / 2; - - /* make sure that maximums are bigger or equal to minimums */ - if (node->prvr.xmax < node->prvr.xmin) SWAP(float, node->prvr.xmax, node->prvr.xmin); - if (node->prvr.ymax < node->prvr.ymin) SWAP(float, node->prvr.ymax, node->prvr.ymin); - } - else { - float oldh = BLI_rctf_size_y(&node->prvr); - if (oldh == 0.0f) - oldh = 0.6f * NODE_WIDTH(node) - NODE_DY; - dy -= NODE_DYS / 2; - node->prvr.ymax = dy; - node->prvr.ymin = dy - oldh; - dy = node->prvr.ymin - NODE_DYS / 2; + node->prvr.xmin += 0.5f * dx; + node->prvr.xmax -= 0.5f * dx; } + + dy = node->prvr.ymin - NODE_DYS / 2; + + /* make sure that maximums are bigger or equal to minimums */ + if (node->prvr.xmax < node->prvr.xmin) SWAP(float, node->prvr.xmax, node->prvr.xmin); + if (node->prvr.ymax < node->prvr.ymin) SWAP(float, node->prvr.ymax, node->prvr.ymin); } /* buttons rect? */ @@ -378,14 +406,12 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) node->butr.ymin = 0; node->butr.ymax = 0; - RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr); - layout = uiBlockLayout(node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, locx + NODE_DYS, dy, node->butr.xmax, 0, UI_GetStyle()); - uiLayoutSetContextPointer(layout, "node", &ptr); + uiLayoutSetContextPointer(layout, "node", &nodeptr); - node->typeinfo->uifunc(layout, (bContext *)C, &ptr); + node->typeinfo->uifunc(layout, (bContext *)C, &nodeptr); uiBlockEndAlign(node->block); uiBlockLayoutResolve(node->block, NULL, &buty); @@ -395,11 +421,29 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) /* input sockets */ for (nsock = node->inputs.first; nsock; nsock = nsock->next) { - if (!nodeSocketIsHidden(nsock)) { - nsock->locx = locx; - nsock->locy = dy - NODE_DYS; - dy -= NODE_DY; - } + if (nodeSocketIsHidden(nsock)) + continue; + + RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr); + + layout = uiBlockLayout(node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, + locx+NODE_DYS, dy, NODE_WIDTH(node)-NODE_DY, NODE_DY, UI_GetStyle()); + /* context pointers for current node and socket */ + uiLayoutSetContextPointer(layout, "node", &nodeptr); + uiLayoutSetContextPointer(layout, "socket", &sockptr); + + node->typeinfo->drawinputfunc((bContext *)C, layout, &sockptr, &nodeptr, (nsock->flag & SOCK_IN_USE)); + + uiBlockEndAlign(node->block); + uiBlockLayoutResolve(node->block, NULL, &buty); + + /* ensure minimum socket height in case layout is empty */ + buty = MIN2(buty, dy - NODE_DY); + + nsock->locx = locx; + /* place the socket circle in the middle of the layout */ + nsock->locy = 0.5f * (dy + buty); + dy = buty; } /* little bit space in end */ @@ -510,6 +554,7 @@ int node_get_colorid(bNode *node) case NODE_CLASS_OP_VECTOR: case NODE_CLASS_OP_FILTER: return TH_NODE_OPERATOR; case NODE_CLASS_GROUP: return TH_NODE_GROUP; + case NODE_CLASS_INTERFACE: return TH_NODE_INTERFACE; case NODE_CLASS_MATTE: return TH_NODE_MATTE; case NODE_CLASS_DISTORT: return TH_NODE_DISTORT; default: return TH_NODE; @@ -534,7 +579,7 @@ static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node) } /* this might have some more generic use */ -static void node_circle_draw(float x, float y, float size, char *col, int highlight) +static void node_circle_draw(float x, float y, float size, float *col, int highlight) { /* 16 values of sin function */ static float si[16] = { @@ -552,12 +597,14 @@ static void node_circle_draw(float x, float y, float size, char *col, int highli }; int a; - glColor3ub(col[0], col[1], col[2]); + glColor4fv(col); + glEnable(GL_BLEND); glBegin(GL_POLYGON); for (a = 0; a < 16; a++) glVertex2f(x + size * si[a], y + size * co[a]); glEnd(); + glDisable(GL_BLEND); if (highlight) { UI_ThemeColor(TH_TEXT_HI); @@ -577,66 +624,93 @@ static void node_circle_draw(float x, float y, float size, char *col, int highli glLineWidth(1.0f); } -void node_socket_circle_draw(bNodeTree *UNUSED(ntree), bNodeSocket *sock, float size, int highlight) +void node_socket_circle_draw(const bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *sock, float size, int highlight) { - bNodeSocketType *stype = ntreeGetSocketType(sock->type); - node_circle_draw(sock->locx, sock->locy, size, stype->ui_color, highlight); + PointerRNA ptr, node_ptr; + float color[4]; + + RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr); + RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr); + sock->typeinfo->draw_color((bContext *)C, &ptr, &node_ptr, color); + node_circle_draw(sock->locx, sock->locy, size, color, highlight); } /* ************** Socket callbacks *********** */ -/* not a callback */ -static void node_draw_preview(bNodePreview *preview, rctf *prv) +static void node_draw_preview_background(float tile, rctf *rect) { - float xscale = BLI_rctf_size_x(prv) / ((float)preview->xsize); - float yscale = BLI_rctf_size_y(prv) / ((float)preview->ysize); - float tile = BLI_rctf_size_x(prv) / 10.0f; float x, y; /* draw checkerboard backdrop to show alpha */ glColor3ub(120, 120, 120); - glRectf(prv->xmin, prv->ymin, prv->xmax, prv->ymax); + glRectf(rect->xmin, rect->ymin, rect->xmax, rect->ymax); glColor3ub(160, 160, 160); - for (y = prv->ymin; y < prv->ymax; y += tile * 2) { - for (x = prv->xmin; x < prv->xmax; x += tile * 2) { + for (y = rect->ymin; y < rect->ymax; y += tile * 2) { + for (x = rect->xmin; x < rect->xmax; x += tile * 2) { float tilex = tile, tiley = tile; - if (x + tile > prv->xmax) - tilex = prv->xmax - x; - if (y + tile > prv->ymax) - tiley = prv->ymax - y; + if (x + tile > rect->xmax) + tilex = rect->xmax - x; + if (y + tile > rect->ymax) + tiley = rect->ymax - y; glRectf(x, y, x + tilex, y + tiley); } } - for (y = prv->ymin + tile; y < prv->ymax; y += tile * 2) { - for (x = prv->xmin + tile; x < prv->xmax; x += tile * 2) { + for (y = rect->ymin + tile; y < rect->ymax; y += tile * 2) { + for (x = rect->xmin + tile; x < rect->xmax; x += tile * 2) { float tilex = tile, tiley = tile; - if (x + tile > prv->xmax) - tilex = prv->xmax - x; - if (y + tile > prv->ymax) - tiley = prv->ymax - y; + if (x + tile > rect->xmax) + tilex = rect->xmax - x; + if (y + tile > rect->ymax) + tiley = rect->ymax - y; glRectf(x, y, x + tilex, y + tiley); } } - - glPixelZoom(xscale, yscale); +} +/* not a callback */ +static void node_draw_preview(bNodePreview *preview, rctf *prv) +{ + float xrect = BLI_rctf_size_x(prv); + float yrect = BLI_rctf_size_y(prv); + float xscale = xrect / ((float)preview->xsize); + float yscale = yrect / ((float)preview->ysize); + float scale; + rctf draw_rect; + + /* uniform scale and offset */ + draw_rect = *prv; + if (xscale < yscale) { + float offset = 0.5f * (yrect - ((float)preview->ysize) * xscale); + draw_rect.ymin += offset; + draw_rect.ymax -= offset; + scale = xscale; + } + else { + float offset = 0.5f * (xrect - ((float)preview->xsize) * yscale); + draw_rect.xmin += offset; + draw_rect.xmax -= offset; + scale = yscale; + } + + node_draw_preview_background(BLI_rctf_size_x(prv) / 10.0f, &draw_rect); + glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /* premul graphics */ glColor4f(1.0, 1.0, 1.0, 1.0); - glaDrawPixelsTex(prv->xmin, prv->ymin, preview->xsize, preview->ysize, GL_UNSIGNED_BYTE, GL_LINEAR, preview->rect); + glPixelZoom(scale, scale); + glaDrawPixelsTex(draw_rect.xmin, draw_rect.ymin, preview->xsize, preview->ysize, GL_UNSIGNED_BYTE, GL_LINEAR, preview->rect); + glPixelZoom(1.0f, 1.0f); glDisable(GL_BLEND); - glPixelZoom(1.0f, 1.0f); UI_ThemeColorShadeAlpha(TH_BACK, -15, +100); - fdrawbox(prv->xmin, prv->ymin, prv->xmax, prv->ymax); - + fdrawbox(draw_rect.xmin, draw_rect.ymin, draw_rect.xmax, draw_rect.ymax); } /* common handle function for operator buttons that need to select the node first */ @@ -669,8 +743,9 @@ void node_draw_shadow(SpaceNode *snode, bNode *node, float radius, float alpha) } } -static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node) +static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node, bNodeInstanceKey key) { + bNodeInstanceHash *previews = CTX_data_pointer_get(C, "node_previews").data; bNodeSocket *sock; rctf *rct = &node->totr; float iconofs; @@ -680,9 +755,9 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN char showname[128]; /* 128 used below */ View2D *v2d = &ar->v2d; - /* hurmf... another candidate for callback, have to see how this works first */ - if (node->id && node->block && snode->treetype == NTREE_SHADER) - nodeShaderSynchronizeID(node, 0); + /* XXX hack: copy values from linked ID data where displayed as sockets */ + if (node->block) + nodeSynchronizeID(node, false); /* skip if out of view */ if (BLI_rctf_isect(&node->totr, &ar->v2d.cur, NULL) == FALSE) { @@ -823,11 +898,7 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN if (nodeSocketIsHidden(sock)) continue; - node_socket_circle_draw(ntree, sock, NODE_SOCKSIZE, sock->flag & SELECT); - - node->typeinfo->drawinputfunc(C, node->block, ntree, node, sock, IFACE_(sock->name), - sock->locx + (NODE_DYS), sock->locy - NODE_DYS, - NODE_WIDTH(node) - NODE_DY); + node_socket_circle_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT); } /* socket outputs */ @@ -835,17 +906,14 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN if (nodeSocketIsHidden(sock)) continue; - node_socket_circle_draw(ntree, sock, NODE_SOCKSIZE, sock->flag & SELECT); - - node->typeinfo->drawoutputfunc(C, node->block, ntree, node, sock, IFACE_(sock->name), - sock->locx - NODE_WIDTH(node) + (NODE_DYS), sock->locy - NODE_DYS, - NODE_WIDTH(node) - NODE_DY); + node_socket_circle_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT); } /* preview */ if (node->flag & NODE_PREVIEW) { - if (node->preview && node->preview->rect && !BLI_rctf_is_empty(&node->prvr)) - node_draw_preview(node->preview, &node->prvr); + bNodePreview *preview = previews ? BKE_node_instance_hash_lookup(previews, key) : NULL; + if (preview && preview->rect && !BLI_rctf_is_empty(&node->prvr)) + node_draw_preview(preview, &node->prvr); } UI_ThemeClearColor(color_id); @@ -855,7 +923,7 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN node->block = NULL; } -static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node) +static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node, bNodeInstanceKey UNUSED(key)) { bNodeSocket *sock; rctf *rct = &node->totr; @@ -957,12 +1025,12 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b /* sockets */ for (sock = node->inputs.first; sock; sock = sock->next) { if (!nodeSocketIsHidden(sock)) - node_socket_circle_draw(snode->nodetree, sock, socket_size, sock->flag & SELECT); + node_socket_circle_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT); } for (sock = node->outputs.first; sock; sock = sock->next) { if (!nodeSocketIsHidden(sock)) - node_socket_circle_draw(snode->nodetree, sock, socket_size, sock->flag & SELECT); + node_socket_circle_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT); } uiEndBlock(C, node->block); @@ -989,7 +1057,7 @@ void node_set_cursor(wmWindow *win, SpaceNode *snode) bNodeSocket *sock; int cursor = CURSOR_STD; - if (ntree) { + if (ntreeIsValid(ntree)) { if (node_find_indicated_socket(snode, &node, &sock, SOCK_IN | SOCK_OUT)) { /* pass */ } @@ -1009,12 +1077,12 @@ void node_set_cursor(wmWindow *win, SpaceNode *snode) WM_cursor_set(win, cursor); } -void node_draw_default(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node) +void node_draw_default(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node, bNodeInstanceKey key) { if (node->flag & NODE_HIDDEN) - node_draw_hidden(C, ar, snode, ntree, node); + node_draw_hidden(C, ar, snode, ntree, node, key); else - node_draw_basis(C, ar, snode, ntree, node); + node_draw_basis(C, ar, snode, ntree, node, key); } static void node_update(const bContext *C, bNodeTree *ntree, bNode *node) @@ -1023,34 +1091,28 @@ static void node_update(const bContext *C, bNodeTree *ntree, bNode *node) node->typeinfo->drawupdatefunc(C, ntree, node); } -void node_update_nodetree(const bContext *C, bNodeTree *ntree, float offsetx, float offsety) +void node_update_nodetree(const bContext *C, bNodeTree *ntree) { bNode *node; /* update nodes front to back, so children sizes get updated before parents */ for (node = ntree->nodes.last; node; node = node->prev) { - /* XXX little hack (not used anyore?) */ - node->locx += offsetx; - node->locy += offsety; - node_update(C, ntree, node); - - node->locx -= offsetx; - node->locy -= offsety; } } -static void node_draw(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node) +static void node_draw(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node, bNodeInstanceKey key) { if (node->typeinfo->drawfunc) - node->typeinfo->drawfunc(C, ar, snode, ntree, node); + node->typeinfo->drawfunc(C, ar, snode, ntree, node, key); } #define USE_DRAW_TOT_UPDATE -void node_draw_nodetree(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree) +void node_draw_nodetree(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNodeInstanceKey parent_key) { bNode *node; + bNodeInstanceKey key; bNodeLink *link; int a; @@ -1073,122 +1135,200 @@ void node_draw_nodetree(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeT if (!(node->flag & NODE_BACKGROUND)) continue; + + key = BKE_node_instance_key(parent_key, ntree, node); node->nr = a; /* index of node in list, used for exec event code */ - node_draw(C, ar, snode, ntree, node); + node_draw(C, ar, snode, ntree, node, key); } /* node lines */ glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); - for (link = ntree->links.first; link; link = link->next) - node_draw_link(&ar->v2d, snode, link); + for (link = ntree->links.first; link; link = link->next) { + if (!nodeLinkIsHidden(link)) + node_draw_link(&ar->v2d, snode, link); + } glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); /* draw foreground nodes, last nodes in front */ for (a = 0, node = ntree->nodes.first; node; node = node->next, a++) { + bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node); if (node->flag & NODE_BACKGROUND) continue; + + key = BKE_node_instance_key(parent_key, ntree, node); node->nr = a; /* index of node in list, used for exec event code */ - node_draw(C, ar, snode, ntree, node); + node_draw(C, ar, snode, ntree, node, key); } } -void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d) +/* draw tree path info in lower left corner */ +static void draw_tree_path(SpaceNode *snode) +{ + char info[256]; + + ED_node_tree_path_get_fixedbuf(snode, info, sizeof(info)); + + UI_ThemeColor(TH_TEXT_HI); + BLF_draw_default(30, 30, 0.0f, info, sizeof(info)); +} + +static void snode_setup_v2d(SpaceNode *snode, ARegion *ar, float centerx, float centery) +{ + View2D *v2d = &ar->v2d; + + /* shift view to node tree center */ + UI_view2d_setcenter(v2d, centerx, centery); + UI_view2d_view_ortho(v2d); + + /* aspect+font, set each time */ + snode->aspect = BLI_rctf_size_x(&v2d->cur) / (float)ar->winx; + // XXX snode->curfont = uiSetCurFont_ext(snode->aspect); +} + +static void draw_nodetree(const bContext *C, ARegion *ar, bNodeTree *ntree, bNodeInstanceKey parent_key) +{ + SpaceNode *snode = CTX_wm_space_node(C); + + node_uiblocks_init(C, ntree); + +#ifdef WITH_COMPOSITOR + if (ntree->type == NTREE_COMPOSIT) { + COM_startReadHighlights(); + } +#endif + + node_update_nodetree(C, ntree); + node_draw_nodetree(C, ar, snode, ntree, parent_key); +} + +/* shade the parent node group and add a uiBlock to clip mouse events */ +static void draw_group_overlay(const bContext *C, ARegion *ar) +{ + View2D *v2d = &ar->v2d; + rctf rect = v2d->cur; + uiBlock *block; + + /* shade node groups to separate them visually */ + UI_ThemeColorShadeAlpha(TH_NODE_GROUP, 0, -70); + glEnable(GL_BLEND); + uiSetRoundBox(0); + uiDrawBox(GL_POLYGON, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 0); + glDisable(GL_BLEND); + + /* set the block bounds to clip mouse events from underlying nodes */ + block = uiBeginBlock(C, ar, "node tree bounds block", UI_EMBOSS); + uiExplicitBoundsBlock(block, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + uiBlockSetFlag(block, UI_BLOCK_CLIP_EVENTS); + uiEndBlock(C, block); +} + +void drawnodespace(const bContext *C, ARegion *ar) { View2DScrollers *scrollers; SpaceNode *snode = CTX_wm_space_node(C); - bNodeLinkDrag *nldrag; - LinkData *linkdata; + View2D *v2d = &ar->v2d; UI_ThemeClearColor(TH_BACK); glClear(GL_COLOR_BUFFER_BIT); UI_view2d_view_ortho(v2d); - - //uiFreeBlocksWin(&sa->uiblocks, sa->win); ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW); /* only set once */ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_MAP1_VERTEX_3); - - /* aspect+font, set each time */ - snode->aspect = BLI_rctf_size_x(&v2d->cur) / (float)ar->winx; - // XXX snode->curfont = uiSetCurFont_ext(snode->aspect); - - /* grid */ - UI_view2d_multi_grid_draw(v2d, U.widget_unit, 5, 2); - - /* backdrop */ - draw_nodespace_back_pix(C, ar, snode); /* nodes */ - snode_set_context(snode, CTX_data_scene(C)); - - if (snode->nodetree) { - bNode *node; - /* void **highlights = 0; */ /* UNUSED */ + snode_set_context(C); + + /* draw parent node trees */ + if (snode->treepath.last) { + static const int max_depth = 2; + bNodeTreePath *path; + int depth, curdepth; + float center[2]; + bNodeTree *ntree; + bNodeLinkDrag *nldrag; + LinkData *linkdata; - node_uiblocks_init(C, snode->nodetree); + /* current View2D center, will be set temporarily for parent node trees */ + UI_view2d_getcenter(v2d, ¢er[0], ¢er[1]); - /* uiBlocks must be initialized in drawing order for correct event clipping. - * Node group internal blocks added after the main group block. - */ - for (node = snode->nodetree->nodes.first; node; node = node->next) { - if (node->flag & NODE_GROUP_EDIT) - node_uiblocks_init(C, (bNodeTree *)node->id); + /* store new view center in current edittree */ + if (snode->edittree) + copy_v2_v2(snode->edittree->view_center, center); + + depth = 0; + path = snode->treepath.last; + while (path->prev && depth < max_depth) { + path = path->prev; + ++depth; + } + /* parent node trees in the background */ + for (curdepth = depth; curdepth >= 0; path = path->next, --curdepth) { + ntree = path->nodetree; + + if (ntreeIsValid(ntree)) { + snode_setup_v2d(snode, ar, ntree->view_center[0], ntree->view_center[1]); + + if (curdepth == 0) { + /* grid, uses theme color based on node path depth */ + UI_view2d_multi_grid_draw(v2d, (depth > 0 ? TH_NODE_GROUP : TH_BACK), U.widget_unit, 5, 2); + + /* backdrop */ + draw_nodespace_back_pix(C, ar, snode); + } + + draw_nodetree(C, ar, ntree, path->parent_key); + + if (curdepth > 0) + draw_group_overlay(C, ar); + } } - node_update_nodetree(C, snode->nodetree, 0.0f, 0.0f); - -#ifdef WITH_COMPOSITOR - if (snode->nodetree->type == NTREE_COMPOSIT) { - COM_startReadHighlights(); + /* reset View2D */ + UI_view2d_setcenter(v2d, center[0], center[1]); + + /* temporary links */ + glEnable(GL_BLEND); + glEnable(GL_LINE_SMOOTH); + for (nldrag = snode->linkdrag.first; nldrag; nldrag = nldrag->next) { + for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) + node_draw_link(v2d, snode, (bNodeLink *)linkdata->data); } -#endif - - node_draw_nodetree(C, ar, snode, snode->nodetree); + glDisable(GL_LINE_SMOOTH); + glDisable(GL_BLEND); - #if 0 - /* active group */ - for (node = snode->nodetree->nodes.first; node; node = node->next) { - if (node->flag & NODE_GROUP_EDIT) - node_draw_group(C, ar, snode, snode->nodetree, node); + if (snode->flag & SNODE_SHOW_GPENCIL) { + /* draw grease-pencil ('canvas' strokes) */ + draw_gpencil_view2d(C, TRUE); } - #endif } - - /* temporary links */ - glEnable(GL_BLEND); - glEnable(GL_LINE_SMOOTH); - for (nldrag = snode->linkdrag.first; nldrag; nldrag = nldrag->next) { - for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) { - node_draw_link(&ar->v2d, snode, (bNodeLink *)linkdata->data); - } + else { + /* default grid */ + UI_view2d_multi_grid_draw(v2d, TH_BACK, U.widget_unit, 5, 2); + + /* backdrop */ + draw_nodespace_back_pix(C, ar, snode); } - glDisable(GL_LINE_SMOOTH); - glDisable(GL_BLEND); ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW); - if (snode->flag & SNODE_SHOW_GPENCIL) { - /* draw grease-pencil ('canvas' strokes) */ - if (snode->nodetree) { - draw_gpencil_view2d(C, TRUE); - } - } - /* reset view matrix */ UI_view2d_view_restore(C); - if (snode->flag & SNODE_SHOW_GPENCIL) { - /* draw grease-pencil (screen strokes, and also paintbuffer) */ - if (snode->nodetree) { + if (snode->treepath.last) { + if (snode->flag & SNODE_SHOW_GPENCIL) { + /* draw grease-pencil (screen strokes, and also paintbuffer) */ draw_gpencil_view2d(C, FALSE); } } + + /* tree path info */ + draw_tree_path(snode); /* scrollers */ scrollers = UI_view2d_scrollers_calc(C, v2d, 10, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY); diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 941bd783c39..2012284f39b 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -31,6 +31,8 @@ #include "MEM_guardedalloc.h" +#include "DNA_action_types.h" +#include "DNA_anim_types.h" #include "DNA_lamp_types.h" #include "DNA_material_types.h" #include "DNA_node_types.h" @@ -65,6 +67,7 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_enum_types.h" #include "WM_api.h" #include "WM_types.h" @@ -76,6 +79,12 @@ #include "IMB_imbuf_types.h" #include "node_intern.h" /* own include */ +#include "NOD_common.h" +#include "NOD_socket.h" +#include "NOD_composite.h" +#include "NOD_shader.h" +#include "NOD_texture.h" + #define USE_ESC_COMPO @@ -241,27 +250,12 @@ int composite_node_active(bContext *C) { if (ED_operator_node_active(C)) { SpaceNode *snode = CTX_wm_space_node(C); - if (snode->treetype == NTREE_COMPOSIT) + if (ED_node_is_compositor(snode)) return 1; } return 0; } -/* also checks for edited groups */ -bNode *editnode_get_active(bNodeTree *ntree) -{ - bNode *node; - - /* check for edited group */ - for (node = ntree->nodes.first; node; node = node->next) - if (nodeGroupEditGet(node)) - break; - if (node) - return nodeGetActive((bNodeTree *)node->id); - else - return nodeGetActive(ntree); -} - static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup) { bNode *node; @@ -277,20 +271,16 @@ static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup) return 0; } -static void snode_dag_update_group(void *calldata, ID *owner_id, bNodeTree *ntree) -{ - if (has_nodetree(ntree, calldata)) - DAG_id_tag_update(owner_id, 0); -} - void snode_dag_update(bContext *C, SpaceNode *snode) { Main *bmain = CTX_data_main(C); /* for groups, update all ID's using this */ if (snode->edittree != snode->nodetree) { - bNodeTreeType *tti = ntreeGetType(snode->edittree->type); - tti->foreach_nodetree(bmain, snode->edittree, snode_dag_update_group); + FOREACH_NODETREE(bmain, tntree, id) { + if (has_nodetree(tntree, snode->edittree)) + DAG_id_tag_update(id, 0); + } FOREACH_NODETREE_END } DAG_id_tag_update(snode->id, 0); @@ -300,37 +290,53 @@ void snode_notify(bContext *C, SpaceNode *snode) { WM_event_add_notifier(C, NC_NODE | NA_EDITED, NULL); - if (snode->treetype == NTREE_SHADER) + if(ED_node_is_shader(snode)) WM_event_add_notifier(C, NC_MATERIAL | ND_NODES, snode->id); - else if (snode->treetype == NTREE_COMPOSIT) + else if(ED_node_is_compositor(snode)) WM_event_add_notifier(C, NC_SCENE | ND_NODES, snode->id); - else if (snode->treetype == NTREE_TEXTURE) + else if(ED_node_is_texture(snode)) WM_event_add_notifier(C, NC_TEXTURE | ND_NODES, snode->id); } -bNode *node_tree_get_editgroup(bNodeTree *nodetree) +void ED_node_set_tree_type(SpaceNode *snode, bNodeTreeType *typeinfo) { - bNode *gnode; - - /* get the groupnode */ - for (gnode = nodetree->nodes.first; gnode; gnode = gnode->next) - if (nodeGroupEditGet(gnode)) - break; - return gnode; + if (typeinfo) + BLI_strncpy(snode->tree_idname, typeinfo->idname, sizeof(snode->tree_idname)); + else + snode->tree_idname[0] = '\0'; +} + +int ED_node_is_compositor(struct SpaceNode *snode) +{ + return (strcmp(snode->tree_idname, ntreeType_Composite->idname)==0); +} + +int ED_node_is_shader(struct SpaceNode *snode) +{ + return (strcmp(snode->tree_idname, ntreeType_Shader->idname)==0); +} + +int ED_node_is_texture(struct SpaceNode *snode) +{ + return (strcmp(snode->tree_idname, ntreeType_Texture->idname)==0); } /* 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 *scene, ID *id) +void ED_node_shader_default(const bContext *C, ID *id) { + Scene *scene = CTX_data_scene(C); bNode *in, *out; bNodeSocket *fromsock, *tosock, *sock; bNodeTree *ntree; - bNodeTemplate ntemp; + PointerRNA ptr; int output_type, shader_type; - float color[3], strength = 1.0f; + float color[4] = { 0.0f, 0.0f, 0.0f, 1.0f }, strength = 1.0f; - ntree = ntreeAddTree(G.main, "Shader Nodetree", NTREE_SHADER, 0); + ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); + + RNA_id_pointer_create((ID *)ntree, &ptr); + RNA_boolean_set(&ptr, "is_local_tree", TRUE); switch (GS(id->name)) { case ID_MA: @@ -383,12 +389,10 @@ void ED_node_shader_default(Scene *scene, ID *id) return; } - ntemp.type = output_type; - out = nodeAddNode(ntree, &ntemp); + out = nodeAddStaticNode(C, ntree, output_type); out->locx = 300.0f; out->locy = 300.0f; - ntemp.type = shader_type; - in = nodeAddNode(ntree, &ntemp); + in = nodeAddStaticNode(C, ntree, shader_type); in->locx = 10.0f; in->locy = 300.0f; nodeSetActive(ntree, in); @@ -399,12 +403,16 @@ void ED_node_shader_default(Scene *scene, ID *id) /* default values */ if (BKE_scene_use_new_shading_nodes(scene)) { + PointerRNA sockptr; sock = in->inputs.first; - copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, color); + RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sockptr); + + RNA_float_set_array(&sockptr, "default_value", color); if (strength != 0.0f) { sock = in->inputs.last; - ((bNodeSocketValueFloat *)sock->default_value)->value = strength; + RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sockptr); + RNA_float_set(&sockptr, "default_value", strength); } } @@ -413,11 +421,11 @@ void ED_node_shader_default(Scene *scene, ID *id) /* assumes nothing being done in ntree yet, sets the default in/out node */ /* called from shading buttons or header */ -void ED_node_composit_default(Scene *sce) +void ED_node_composit_default(const bContext *C, struct Scene *sce) { bNode *in, *out; bNodeSocket *fromsock, *tosock; - bNodeTemplate ntemp; + PointerRNA ptr; /* but lets check it anyway */ if (sce->nodetree) { @@ -426,20 +434,21 @@ void ED_node_composit_default(Scene *sce) return; } - sce->nodetree = ntreeAddTree(G.main, "Compositing Nodetree", NTREE_COMPOSIT, 0); - + sce->nodetree = ntreeAddTree(NULL, "Compositing Nodetree", ntreeType_Composite->idname); + + RNA_id_pointer_create((ID *)sce->nodetree, &ptr); + RNA_boolean_set(&ptr, "is_local_tree", TRUE); + sce->nodetree->chunksize = 256; sce->nodetree->edit_quality = NTREE_QUALITY_HIGH; sce->nodetree->render_quality = NTREE_QUALITY_HIGH; - ntemp.type = CMP_NODE_COMPOSITE; - out = nodeAddNode(sce->nodetree, &ntemp); + out = nodeAddStaticNode(C, sce->nodetree, CMP_NODE_COMPOSITE); out->locx = 300.0f; out->locy = 400.0f; out->id = &sce->id; id_us_plus(out->id); - ntemp.type = CMP_NODE_R_LAYERS; - in = nodeAddNode(sce->nodetree, &ntemp); + in = nodeAddStaticNode(C, sce->nodetree, CMP_NODE_R_LAYERS); in->locx = 10.0f; in->locy = 400.0f; in->id = &sce->id; id_us_plus(in->id); @@ -457,11 +466,11 @@ void ED_node_composit_default(Scene *sce) /* assumes nothing being done in ntree yet, sets the default in/out node */ /* called from shading buttons or header */ -void ED_node_texture_default(Tex *tx) +void ED_node_texture_default(const bContext *C, Tex *tx) { bNode *in, *out; bNodeSocket *fromsock, *tosock; - bNodeTemplate ntemp; + PointerRNA ptr; /* but lets check it anyway */ if (tx->nodetree) { @@ -470,14 +479,15 @@ void ED_node_texture_default(Tex *tx) return; } - tx->nodetree = ntreeAddTree(G.main, "Texture Nodetree", NTREE_TEXTURE, 0); + tx->nodetree = ntreeAddTree(NULL, "Texture Nodetree", ntreeType_Texture->idname); + + RNA_id_pointer_create((ID *)tx->nodetree, &ptr); + RNA_boolean_set(&ptr, "is_local_tree", TRUE); - ntemp.type = TEX_NODE_OUTPUT; - out = nodeAddNode(tx->nodetree, &ntemp); + out = nodeAddStaticNode(C, tx->nodetree, TEX_NODE_OUTPUT); out->locx = 300.0f; out->locy = 300.0f; - ntemp.type = TEX_NODE_CHECKER; - in = nodeAddNode(tx->nodetree, &ntemp); + in = nodeAddStaticNode(C, tx->nodetree, TEX_NODE_CHECKER); in->locx = 10.0f; in->locy = 300.0f; nodeSetActive(tx->nodetree, in); @@ -488,162 +498,66 @@ void ED_node_texture_default(Tex *tx) ntreeUpdateTree(tx->nodetree); } -/* id is supposed to contain a node tree */ -void node_tree_from_ID(ID *id, bNodeTree **ntree, bNodeTree **edittree, int *treetype) +/* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */ +void snode_set_context(const bContext *C) { - if (id) { - bNode *node = NULL; - short idtype = GS(id->name); + SpaceNode *snode = CTX_wm_space_node(C); + bNodeTreeType *treetype = ntreeTypeFind(snode->tree_idname); + bNodeTree *ntree = snode->nodetree; + ID *id = snode->id, *from = snode->from; - if (idtype == ID_NT) { - *ntree = (bNodeTree *)id; - if (treetype) *treetype = (*ntree)->type; - } - else if (idtype == ID_MA) { - *ntree = ((Material *)id)->nodetree; - if (treetype) *treetype = NTREE_SHADER; - } - else if (idtype == ID_LA) { - *ntree = ((Lamp *)id)->nodetree; - if (treetype) *treetype = NTREE_SHADER; - } - else if (idtype == ID_WO) { - *ntree = ((World *)id)->nodetree; - if (treetype) *treetype = NTREE_SHADER; - } - else if (idtype == ID_SCE) { - *ntree = ((Scene *)id)->nodetree; - if (treetype) *treetype = NTREE_COMPOSIT; - } - else if (idtype == ID_TE) { - *ntree = ((Tex *)id)->nodetree; - if (treetype) *treetype = NTREE_TEXTURE; - } - else { - if (treetype) *treetype = 0; - return; - } + /* we use this to signal warnings, when node shaders are drawn in wrong render engine */ + if (BKE_scene_use_new_shading_nodes(CTX_data_scene(C))) + snode->flag |= SNODE_NEW_SHADERS; + else + snode->flag &= ~SNODE_NEW_SHADERS; + + /* check the tree type */ + if (!treetype + || (treetype->poll && !treetype->poll(C, treetype))) { + /* invalid tree type, disable */ + snode->tree_idname[0] = '\0'; + ED_node_tree_start(snode, NULL, NULL, NULL); + return; + } - /* find editable group */ - if (edittree) { - if (*ntree) - for (node = (*ntree)->nodes.first; node; node = node->next) - if (nodeGroupEditGet(node)) - break; - - if (node && node->id) - *edittree = (bNodeTree *)node->id; - else - *edittree = *ntree; - } + if (snode->nodetree && strcmp(snode->nodetree->idname, snode->tree_idname) != 0) { + /* current tree does not match selected type, clear tree path */ + ntree = NULL; + id = NULL; + from = NULL; } - else { - *ntree = NULL; - *edittree = NULL; - if (treetype) *treetype = 0; + + if (!(snode->flag & SNODE_PIN) || ntree == NULL) { + if (treetype->get_from_context) + treetype->get_from_context(C, treetype, &ntree, &id, &from); } + + if (snode->nodetree!=ntree || snode->id!=id || snode->from!=snode->from) + ED_node_tree_start(snode, ntree, id, from); } -/* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */ -void snode_set_context(SpaceNode *snode, Scene *scene) +void snode_update(SpaceNode *snode, bNode *node) { - Object *ob = OBACT; + bNodeTreePath *path; - snode->id = snode->from = NULL; + /* XXX this only updates nodes in the current node space tree path. + * The function supposedly should update any potential group node linking to changed tree, + * this really requires a working depsgraph ... + */ - if (snode->treetype == NTREE_SHADER) { - /* we use this to signal warnings, when node shaders are drawn in wrong render engine */ - if (BKE_scene_use_new_shading_nodes(scene)) - snode->flag |= SNODE_NEW_SHADERS; - else - snode->flag &= ~SNODE_NEW_SHADERS; - - /* need active object, or we allow pinning... */ - if (snode->shaderfrom == SNODE_SHADER_OBJECT) { - if (ob) { - if (ob->type == OB_LAMP) { - snode->from = &ob->id; - snode->id = ob->data; - } - else { - Material *ma = give_current_material(ob, ob->actcol); - if (ma) { - snode->from = &ob->id; - snode->id = &ma->id; - } - } - } - } - else { /* SNODE_SHADER_WORLD */ - if (scene->world) { - snode->from = NULL; - snode->id = &scene->world->id; - } - } - } - else if (snode->treetype == NTREE_COMPOSIT) { - snode->id = &scene->id; - - /* update output sockets based on available layers */ - ntreeCompositForceHidden(scene->nodetree, scene); - } - else if (snode->treetype == NTREE_TEXTURE) { - Tex *tx = NULL; - - if (snode->texfrom == SNODE_TEX_OBJECT) { - if (ob) { - tx = give_current_object_texture(ob); - - if (ob->type == OB_LAMP) - snode->from = (ID *)ob->data; - else - snode->from = (ID *)give_current_material(ob, ob->actcol); - - /* from is not set fully for material nodes, should be ID + Node then */ - snode->id = &tx->id; - } - } - else if (snode->texfrom == SNODE_TEX_WORLD) { - tx = give_current_world_texture(scene->world); - snode->from = (ID *)scene->world; - snode->id = &tx->id; - } - else { - struct Brush *brush = NULL; - - if (ob && (ob->mode & OB_MODE_SCULPT)) - brush = paint_brush(&scene->toolsettings->sculpt->paint); - else - brush = paint_brush(&scene->toolsettings->imapaint.paint); - - if (brush) { - snode->from = (ID *)brush; - tx = give_current_brush_texture(brush); - snode->id = &tx->id; - } + /* update all edited group nodes */ + path=snode->treepath.last; + if (path) { + bNodeTree *ngroup = path->nodetree; + for (path=path->prev; path; path=path->prev) { + nodeUpdateID(path->nodetree, (ID*)ngroup); + ngroup = path->nodetree; } } - else { - if (snode->nodetree && snode->nodetree->type == snode->treetype) - snode->id = &snode->nodetree->id; - else - snode->id = NULL; - } - - node_tree_from_ID(snode->id, &snode->nodetree, &snode->edittree, NULL); -} -void snode_update(SpaceNode *snode, bNode *node) -{ - bNode *gnode; - if (node) nodeUpdate(snode->edittree, node); - - /* if inside group, tag entire group */ - gnode = node_tree_get_editgroup(snode->nodetree); - if (gnode) - nodeUpdateID(snode->nodetree, gnode->id); } void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node) @@ -654,6 +568,19 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node) if (node->type != NODE_GROUP) { int was_output = (node->flag & NODE_DO_OUTPUT); + int do_update = 0; + + /* generic node group output: set node as active output */ + if (node->type == NODE_GROUP_OUTPUT) { + bNode *tnode; + for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) + if (tnode->type == NODE_GROUP_OUTPUT) + tnode->flag &= ~NODE_DO_OUTPUT; + + node->flag |= NODE_DO_OUTPUT; + if (!was_output) + do_update = 1; + } /* tree specific activate calls */ if (ntree->type == NTREE_SHADER) { @@ -670,8 +597,10 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node) node->flag |= NODE_DO_OUTPUT; if (was_output == 0) - ED_node_generic_update(bmain, ntree, node); + ED_node_tag_update_nodetree(bmain, ntree); } + else if (do_update) + ED_node_tag_update_nodetree(bmain, ntree); /* if active texture changed, free glsl materials */ if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) { @@ -698,7 +627,7 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node) node->flag |= NODE_DO_OUTPUT; if (was_output == 0) - ED_node_generic_update(bmain, ntree, node); + ED_node_tag_update_nodetree(bmain, ntree); /* addnode() doesnt link this yet... */ node->id = (ID *)BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node"); @@ -723,9 +652,11 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node) tnode->flag &= ~NODE_DO_OUTPUT; node->flag |= NODE_DO_OUTPUT; - ED_node_generic_update(bmain, ntree, node); + ED_node_tag_update_nodetree(bmain, ntree); } } + else if (do_update) + ED_node_tag_update_nodetree(bmain, ntree); } else if (ntree->type == NTREE_TEXTURE) { // XXX @@ -762,7 +693,7 @@ static void edit_node_properties(wmOperatorType *ot) /* XXX could node be a context pointer? */ RNA_def_string(ot->srna, "node", "", MAX_NAME, "Node", ""); RNA_def_int(ot->srna, "socket", 0, 0, MAX_SOCKET, "Socket", "", 0, MAX_SOCKET); - RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Side", ""); + RNA_def_enum(ot->srna, "in_out", node_socket_in_out_items, SOCK_IN, "Socket Side", ""); } static int edit_node_invoke_properties(bContext *C, wmOperator *op) @@ -874,7 +805,7 @@ static int node_resize_modal(bContext *C, wmOperator *op, const wmEvent *event) { SpaceNode *snode = CTX_wm_space_node(C); ARegion *ar = CTX_wm_region(C); - bNode *node = editnode_get_active(snode->edittree); + bNode *node = nodeGetActive(snode->edittree); NodeSizeWidget *nsw = op->customdata; float mx, my, dx, dy; @@ -977,7 +908,7 @@ static int node_resize_invoke(bContext *C, wmOperator *op, const wmEvent *event) { SpaceNode *snode = CTX_wm_space_node(C); ARegion *ar = CTX_wm_region(C); - bNode *node = editnode_get_active(snode->edittree); + bNode *node = nodeGetActive(snode->edittree); int dir; if (node) { @@ -1056,33 +987,6 @@ void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set) } } -/* return 0, nothing done */ -static int UNUSED_FUNCTION(node_mouse_groupheader) (SpaceNode *snode) -{ - bNode *gnode; - float mx = 0, my = 0; -// XXX int mval[2]; - - gnode = node_tree_get_editgroup(snode->nodetree); - if (gnode == NULL) return 0; - -// XXX getmouseco_areawin(mval); -// XXX areamouseco_to_ipoco(G.v2d, mval, &mx, &my); - - /* click in header or outside? */ - if (BLI_rctf_isect_pt(&gnode->totr, mx, my) == 0) { - rctf rect = gnode->totr; - - rect.ymax += NODE_DY; - if (BLI_rctf_isect_pt(&rect, mx, my) == 0) - snode_make_group_editable(snode, NULL); /* toggles, so exits editmode */ -// else -// XXX transform_nodes(snode->nodetree, 'g', "Move group"); - - return 1; - } - return 0; -} /* checks snode->mouse position, and returns found node/socket */ /* type is SOCK_IN and/or SOCK_OUT */ @@ -1143,32 +1047,6 @@ int node_find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **so } } - /* check group sockets - * NB: using ngroup->outputs as input sockets and vice versa here! - */ - if (in_out & SOCK_IN) { - for (sock = snode->edittree->outputs.first; sock; sock = sock->next) { - if (!nodeSocketIsHidden(sock)) { - if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) { - *nodep = NULL; /* NULL node pointer indicates group socket */ - *sockp = sock; - return 1; - } - } - } - } - if (in_out & SOCK_OUT) { - for (sock = snode->edittree->inputs.first; sock; sock = sock->next) { - if (!nodeSocketIsHidden(sock)) { - if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) { - *nodep = NULL; /* NULL node pointer indicates group socket */ - *sockp = sock; - return 1; - } - } - } - } - return 0; } @@ -1215,7 +1093,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) * but operators and readfile.c do. */ id_us_plus(newnode->id); /* to ensure redraws or rerenders happen */ - ED_node_changed_update(snode->id, newnode); + ED_node_tag_update_id(snode->id); } } @@ -1276,9 +1154,9 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) /* has been set during copy above */ newnode = node->new_node; - node_deselect(node); + nodeSetSelected(node, FALSE); node->flag &= ~NODE_ACTIVE; - node_select(newnode); + nodeSetSelected(newnode, TRUE); } /* make sure we don't copy new nodes again! */ @@ -1312,6 +1190,8 @@ void NODE_OT_duplicate(wmOperatorType *ot) } int ED_node_select_check(ListBase *lb) + + { bNode *node; @@ -1456,6 +1336,7 @@ void NODE_OT_render_changed(wmOperatorType *ot) ot->flag = 0; } + /* ****************** Hide operator *********************** */ static void node_flag_toggle_exec(SpaceNode *snode, int toggle_flag) @@ -1962,8 +1843,6 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; - bNode *gnode = node_tree_get_editgroup(snode->nodetree); - float gnode_x = 0.0f, gnode_y = 0.0f; bNode *node; bNodeLink *link, *newlink; @@ -1973,10 +1852,6 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op)) BKE_node_clipboard_clear(); BKE_node_clipboard_init(ntree); - /* get group node offset */ - if (gnode) - node_to_view(gnode, 0.0f, 0.0f, &gnode_x, &gnode_y); - for (node = ntree->nodes.first; node; node = node->next) { if (node->flag & SELECT) { bNode *new_node; @@ -1999,12 +1874,6 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op)) nodeDetachNode(new_node); } } - - /* transform to basic view space. child node location is relative to parent */ - if (!new_node->parent) { - new_node->locx += gnode_x; - new_node->locy += gnode_y; - } } } @@ -2051,8 +1920,6 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) { SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; - bNode *gnode = node_tree_get_editgroup(snode->nodetree); - float gnode_center[2]; const ListBase *clipboard_nodes_lb; const ListBase *clipboard_links_lb; bNode *node; @@ -2086,14 +1953,6 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) /* deselect old nodes */ node_deselect_all(snode); - /* get group node offset */ - if (gnode) { - node_to_view(gnode, 0.0f, 0.0f, &gnode_center[0], &gnode_center[1]); - } - else { - zero_v2(gnode_center); - } - /* calculate "barycenter" for placing on mouse cursor */ zero_v2(center); for (node = clipboard_nodes_lb->first, num_nodes = 0; node; node = node->next, num_nodes++) { @@ -2110,7 +1969,7 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) id_us_plus(node->id); /* pasted nodes are selected */ - node_select(new_node); + nodeSetSelected(new_node, TRUE); } /* reparent copied nodes */ @@ -2118,13 +1977,6 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) bNode *new_node = node->new_node; if (new_node->parent) new_node->parent = new_node->parent->new_node; - - - /* place nodes around the mouse cursor. child nodes locations are relative to parent */ - if (!new_node->parent) { - new_node->locx += snode->cursor[0] - center[0] - gnode_center[0]; - new_node->locy += snode->cursor[1] - center[1] - gnode_center[1]; - } } for (link = clipboard_links_lb->first; link; link = link->next) { @@ -2167,15 +2019,186 @@ void NODE_OT_clipboard_paste(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ********************** Shader Script Update ******************/ +/********************** Add interface socket operator *********************/ -typedef struct ScriptUpdateData { - RenderEngine *engine; - RenderEngineType *type; +static bNodeSocket *ntree_get_active_interface_socket(ListBase *lb) +{ + bNodeSocket *sock; + for (sock = lb->first; sock; sock = sock->next) + if (sock->flag & SELECT) + return sock; + return NULL; +} - Text *text; - int found; -} ScriptUpdateData; +static int ntree_socket_add_exec(bContext *C, wmOperator *op) +{ + SpaceNode *snode = CTX_wm_space_node(C); + bNodeTree *ntree = snode->edittree; + int in_out = RNA_enum_get(op->ptr, "in_out"); + PointerRNA ntree_ptr; + bNodeSocket *sock, *tsock, *active_sock; + const char *default_name; + + RNA_id_pointer_create((ID *)ntree, &ntree_ptr); + + if (in_out == SOCK_IN) { + active_sock = ntree_get_active_interface_socket(&ntree->inputs); + default_name = "Input"; + } + else { + active_sock = ntree_get_active_interface_socket(&ntree->outputs); + default_name = "Output"; + } + + if (active_sock) { + /* insert a copy of the active socket right after it */ + sock = ntreeInsertSocketInterface(ntree, in_out, active_sock->idname, active_sock->next, active_sock->name); + /* XXX this only works for actual sockets, not interface templates! */ + /*nodeSocketCopyValue(sock, &ntree_ptr, active_sock, &ntree_ptr);*/ + } + else { + /* XXX TODO define default socket type for a tree! */ + sock = ntreeAddSocketInterface(ntree, in_out, "NodeSocketFloat", default_name); + } + + /* deactivate sockets (has to check both lists) */ + for (tsock = ntree->inputs.first; tsock; tsock = tsock->next) + tsock->flag &= ~SELECT; + for (tsock = ntree->outputs.first; tsock; tsock = tsock->next) + tsock->flag &= ~SELECT; + /* make the new socket active */ + sock->flag |= SELECT; + + ntreeUpdateTree(ntree); + + return OPERATOR_FINISHED; +} + +void NODE_OT_tree_socket_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Add Node Tree Interface Socket"; + ot->idname= "NODE_OT_tree_socket_add"; + + /* api callbacks */ + ot->exec= ntree_socket_add_exec; + ot->poll= ED_operator_node_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "in_out", node_socket_in_out_items, SOCK_IN, "Socket Type", ""); +} + +/********************** Remove interface socket operator *********************/ + +static int ntree_socket_remove_exec(bContext *C, wmOperator *UNUSED(op)) +{ + SpaceNode *snode = CTX_wm_space_node(C); + bNodeTree *ntree = snode->edittree; + bNodeSocket *iosock, *active_sock; + + iosock = ntree_get_active_interface_socket(&ntree->inputs); + if (!iosock) + iosock = ntree_get_active_interface_socket(&ntree->outputs); + if (!iosock) + return OPERATOR_CANCELLED; + + /* preferably next socket becomes active, otherwise try previous socket */ + active_sock = (iosock->next ? iosock->next : iosock->prev); + ntreeRemoveSocketInterface(ntree, iosock); + + /* set active socket */ + if (active_sock) + active_sock->flag |= SELECT; + + ntreeUpdateTree(ntree); + + return OPERATOR_FINISHED; +} + +void NODE_OT_tree_socket_remove(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Remove Node Tree Interface Socket"; + ot->idname= "NODE_OT_tree_socket_remove"; + + /* api callbacks */ + ot->exec= ntree_socket_remove_exec; + ot->poll= ED_operator_node_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/********************** Move interface socket operator *********************/ + +static EnumPropertyItem move_direction_items[] = { + { 1, "UP", 0, "Up", "" }, + { 2, "DOWN", 0, "Down", "" }, + { 0, NULL, 0, NULL, NULL }, +}; + +static int ntree_socket_move_exec(bContext *C, wmOperator *op) +{ + SpaceNode *snode = CTX_wm_space_node(C); + bNodeTree *ntree = snode->edittree; + int direction = RNA_enum_get(op->ptr, "direction"); + bNodeSocket *iosock; + ListBase *lb; + + lb = &ntree->inputs; + iosock = ntree_get_active_interface_socket(lb); + if (!iosock) { + lb = &ntree->outputs; + iosock = ntree_get_active_interface_socket(lb); + } + if (!iosock) + return OPERATOR_CANCELLED; + + switch (direction) { + case 1: { /* up */ + bNodeSocket *before = iosock->prev; + BLI_remlink(lb, iosock); + if (before) + BLI_insertlinkbefore(lb, before, iosock); + else + BLI_addhead(lb, iosock); + break; + } + case 2: { /* down */ + bNodeSocket *after = iosock->next; + BLI_remlink(lb, iosock); + if (after) + BLI_insertlinkafter(lb, after, iosock); + else + BLI_addtail(lb, iosock); + break; + } + } + + ntreeUpdateTree(ntree); + + return OPERATOR_FINISHED; +} + +void NODE_OT_tree_socket_move(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Move Node Tree Socket"; + ot->idname= "NODE_OT_tree_socket_move"; + + /* api callbacks */ + ot->exec= ntree_socket_move_exec; + ot->poll= ED_operator_node_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "direction", move_direction_items, 1, "Direction", ""); +} + +/* ********************** Shader Script Update ******************/ static int node_shader_script_update_poll(bContext *C) { @@ -2208,64 +2231,79 @@ static int node_shader_script_update_poll(bContext *C) return 0; } -static void node_shader_script_update_text(void *data_, ID *UNUSED(id), bNodeTree *ntree) +/* recursively check for script nodes in groups using this text and update */ +static int node_shader_script_update_text_recursive(RenderEngine *engine, RenderEngineType *type, bNodeTree *ntree, Text *text) { - ScriptUpdateData *data = (ScriptUpdateData *)data_; + int found = FALSE; bNode *node; - + + ntree->done = TRUE; + /* update each script that is using this text datablock */ for (node = ntree->nodes.first; node; node = node->next) { if (node->type == NODE_GROUP) { - node_shader_script_update_text(data_, NULL, (bNodeTree *)node->id); + bNodeTree *ngroup = (bNodeTree *)node->id; + if (ngroup && !ngroup->done) + found |= node_shader_script_update_text_recursive(engine, type, ngroup, text); } - else if (node->type == SH_NODE_SCRIPT && node->id == &data->text->id) { - data->type->update_script_node(data->engine, ntree, node); - data->found = TRUE; + else if (node->type == SH_NODE_SCRIPT && node->id == &text->id) { + type->update_script_node(engine, ntree, node); + found = TRUE; } } + + return found; } static int node_shader_script_update_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - ScriptUpdateData data; PointerRNA nodeptr = CTX_data_pointer_get_type(C, "node", &RNA_ShaderNodeScript); + RenderEngine *engine; + RenderEngineType *type; + int found = FALSE; /* setup render engine */ - data.type = RE_engines_find(scene->r.engine); - data.engine = RE_engine_create(data.type); - data.engine->reports = op->reports; - data.text = NULL; - data.found = FALSE; + type = RE_engines_find(scene->r.engine); + engine = RE_engine_create(type); + engine->reports = op->reports; if (nodeptr.data) { /* update single node */ bNodeTree *ntree = nodeptr.id.data; bNode *node = nodeptr.data; - data.type->update_script_node(data.engine, ntree, node); + type->update_script_node(engine, ntree, node); - data.found = TRUE; + found = TRUE; } else { /* update all nodes using text datablock */ - data.text = CTX_data_pointer_get_type(C, "edit_text", &RNA_Text).data; - - if (data.text) { - bNodeTreeType *ntreetype = ntreeGetType(NTREE_SHADER); - - if (ntreetype && ntreetype->foreach_nodetree) - ntreetype->foreach_nodetree(bmain, &data, node_shader_script_update_text); + Text *text = CTX_data_pointer_get_type(C, "edit_text", &RNA_Text).data; + + if (text) { + /* clear flags for recursion check */ + FOREACH_NODETREE(bmain, ntree, id) { + if (ntree->type == NTREE_SHADER) + ntree->done = FALSE; + } FOREACH_NODETREE_END + + FOREACH_NODETREE(bmain, ntree, id) { + if (ntree->type == NTREE_SHADER) { + if (!ntree->done) + found |= node_shader_script_update_text_recursive(engine, type, ntree, text); + } + } FOREACH_NODETREE_END - if (!data.found) + if (!found) BKE_report(op->reports, RPT_INFO, "Text not used by any node, no update done"); } } - RE_engine_free(data.engine); + RE_engine_free(engine); - return (data.found)? OPERATOR_FINISHED: OPERATOR_CANCELLED; + return (found)? OPERATOR_FINISHED: OPERATOR_CANCELLED; } void NODE_OT_shader_script_update(wmOperatorType *ot) diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c index 6696284b169..ba98f9ea94d 100644 --- a/source/blender/editors/space_node/node_group.c +++ b/source/blender/editors/space_node/node_group.c @@ -66,85 +66,132 @@ #include "UI_resources.h" #include "node_intern.h" /* own include */ +#include "NOD_common.h" #include "NOD_socket.h" -static EnumPropertyItem socket_in_out_items[] = { - { SOCK_IN, "SOCK_IN", 0, "Input", "" }, - { SOCK_OUT, "SOCK_OUT", 0, "Output", "" }, - { 0, NULL, 0, NULL, NULL }, -}; - -/* ***************** Edit Group operator ************* */ - -void snode_make_group_editable(SpaceNode *snode, bNode *gnode) +/* define common group node operator properties */ +static void node_group_operator_properties(wmOperatorType *ot) { - bNode *node; - - /* make sure nothing has group editing on */ - for (node = snode->nodetree->nodes.first; node; node = node->next) { - nodeGroupEditClear(node); + /* NB: not using an enum here, because that it would have to use an item callback and thus require + * copying of identifier strings anyway. node_type is not a user option, just a way of allowing + * node group operators to work on different types of group nodes. + */ + RNA_def_string(ot->srna, "node_type", "", 0, "Node Type", "Group node type the operator works on"); +} - /* while we're here, clear texture active */ - if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) { - /* this is not 100% sure to be reliable, see comment on the flag */ - node->flag &= ~NODE_ACTIVE_TEXTURE; - } +/* Internal poll functions so group node operators can work with different group node types. + * This checks the operator node type property and looks up the respective types. + * If this function returns FALSE the operator should return PASS_THROUGH to allow other variants. + */ +static int node_group_operator_check_type(bContext *C, wmOperator *op, char **r_node_idname, char **r_ntree_idname) +{ + SpaceNode *snode = CTX_wm_space_node(C); + bNodeTree *ntree = snode->edittree; + PropertyRNA *ntype_prop = RNA_struct_find_property(op->ptr, "node_type"); + char *node_idname, *ntree_idname; + bNodeType *ntype; + bNodeTreeType *ntreetype; + + if (!RNA_property_is_set(op->ptr, ntype_prop)) { + BKE_report(op->reports, RPT_ERROR, "Group node type not set"); + return FALSE; } - - if (gnode == NULL) { - /* with NULL argument we do a toggle */ - if (snode->edittree == snode->nodetree) - gnode = nodeGetActive(snode->nodetree); + + node_idname = RNA_property_string_get_alloc(op->ptr, ntype_prop, NULL, 0, NULL); + ntype = nodeTypeFind(node_idname); + if (!ntype) { + BKE_reportf(op->reports, RPT_ERROR, "Group node type %s undefined", node_idname); + MEM_freeN(node_idname); + return FALSE; } - - if (gnode) { - snode->edittree = nodeGroupEditSet(gnode, 1); - - /* deselect all other nodes, so we can also do grabbing of entire subtree */ - for (node = snode->nodetree->nodes.first; node; node = node->next) { - node_deselect(node); - - if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) { - /* this is not 100% sure to be reliable, see comment on the flag */ - node->flag &= ~NODE_ACTIVE_TEXTURE; - } - } - node_select(gnode); + + if (!ntype->poll(ntype, ntree)) { + MEM_freeN(node_idname); + return FALSE; } + + ntree_idname = BLI_strdup(ntype->group_tree_idname); + ntreetype = ntreeTypeFind(ntree_idname); + if (!ntreetype) { + BKE_reportf(op->reports, RPT_ERROR, "Group node tree type %s undefined", ntree_idname); + MEM_freeN(node_idname); + MEM_freeN(ntree_idname); + return FALSE; + } + + if (r_node_idname) + *r_node_idname = node_idname; + else + MEM_freeN(node_idname); + + if (r_ntree_idname) + *r_ntree_idname = ntree_idname; else - snode->edittree = snode->nodetree; + MEM_freeN(ntree_idname); + + return TRUE; } -static int node_group_edit_exec(bContext *C, wmOperator *UNUSED(op)) +static bNode *node_group_get_active(bContext *C, const char *node_idname) { SpaceNode *snode = CTX_wm_space_node(C); + bNode *node = nodeGetActive(snode->edittree); + + if (node && strcmp(node->idname, node_idname)==0) + return node; + else + return NULL; +} - ED_preview_kill_jobs(C); +/* ***************** Edit Group operator ************* */ - if (snode->nodetree == snode->edittree) { - bNode *gnode = nodeGetActive(snode->edittree); - snode_make_group_editable(snode, gnode); +static int node_group_edit_exec(bContext *C, wmOperator *op) +{ + SpaceNode *snode = CTX_wm_space_node(C); + char *node_idname; + bNode *gnode; + int exit = RNA_boolean_get(op->ptr, "exit"); + + ED_preview_kill_jobs(C); + + if (!node_group_operator_check_type(C, op, &node_idname, NULL)) + return OPERATOR_PASS_THROUGH; + + gnode = node_group_get_active(C, node_idname); + MEM_freeN(node_idname); + + if (gnode && !exit) { + bNodeTree *ngroup= (bNodeTree*)gnode->id; + + if (ngroup) { + if (ngroup->id.lib) + ntreeMakeLocal(ngroup); + + ED_node_tree_push(snode, ngroup, gnode); + } } else - snode_make_group_editable(snode, NULL); - + ED_node_tree_pop(snode); + WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL); - + return OPERATOR_FINISHED; } static int node_group_edit_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - SpaceNode *snode = CTX_wm_space_node(C); + char *node_idname; bNode *gnode; - - /* XXX callback? */ - if (snode->nodetree == snode->edittree) { - gnode = nodeGetActive(snode->edittree); - if (gnode && gnode->id && GS(gnode->id->name) == ID_NT && gnode->id->lib) { - uiPupMenuOkee(C, op->type->idname, "Make group local?"); - return OPERATOR_CANCELLED; - } + + if (!node_group_operator_check_type(C, op, &node_idname, NULL)) + return OPERATOR_PASS_THROUGH; + + gnode = node_group_get_active(C, node_idname); + MEM_freeN(node_idname); + + if (gnode && gnode->id && gnode->id->lib) { + WM_operator_confirm_message(C, op, "Make group local?"); + return OPERATOR_CANCELLED; } return node_group_edit_exec(C, op); @@ -156,258 +203,17 @@ void NODE_OT_group_edit(wmOperatorType *ot) ot->name = "Edit Group"; ot->description = "Edit node group"; ot->idname = "NODE_OT_group_edit"; - + /* api callbacks */ ot->invoke = node_group_edit_invoke; ot->exec = node_group_edit_exec; ot->poll = ED_operator_node_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/* ***************** Add Group Socket operator ************* */ - -static int node_group_socket_add_exec(bContext *C, wmOperator *op) -{ - SpaceNode *snode = CTX_wm_space_node(C); - int in_out = -1; - char name[MAX_NAME] = ""; - int type = SOCK_FLOAT; - bNodeTree *ngroup = snode->edittree; - /* bNodeSocket *sock; */ /* UNUSED */ - - ED_preview_kill_jobs(C); - - if (RNA_struct_property_is_set(op->ptr, "name")) - RNA_string_get(op->ptr, "name", name); - - if (RNA_struct_property_is_set(op->ptr, "type")) - type = RNA_enum_get(op->ptr, "type"); - - if (RNA_struct_property_is_set(op->ptr, "in_out")) - in_out = RNA_enum_get(op->ptr, "in_out"); - else - return OPERATOR_CANCELLED; - - /* using placeholder subtype first */ - /* sock = */ /* UNUSED */ node_group_add_socket(ngroup, name, type, in_out); - - ntreeUpdateTree(ngroup); - - snode_notify(C, snode); - - return OPERATOR_FINISHED; -} - -void NODE_OT_group_socket_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Group Socket"; - ot->description = "Add node group socket"; - ot->idname = "NODE_OT_group_socket_add"; - - /* api callbacks */ - ot->exec = node_group_socket_add_exec; - ot->poll = ED_operator_node_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output"); - RNA_def_string(ot->srna, "name", "", MAX_NAME, "Name", "Group socket name"); - RNA_def_enum(ot->srna, "type", node_socket_type_items, SOCK_FLOAT, "Type", "Type of the group socket"); -} - -/* ***************** Remove Group Socket operator ************* */ - -static int node_group_socket_remove_exec(bContext *C, wmOperator *op) -{ - SpaceNode *snode = CTX_wm_space_node(C); - int index = -1; - int in_out = -1; - bNodeTree *ngroup = snode->edittree; - bNodeSocket *sock; - - ED_preview_kill_jobs(C); - - if (RNA_struct_property_is_set(op->ptr, "index")) - index = RNA_int_get(op->ptr, "index"); - else - return OPERATOR_CANCELLED; - - if (RNA_struct_property_is_set(op->ptr, "in_out")) - in_out = RNA_enum_get(op->ptr, "in_out"); - else - return OPERATOR_CANCELLED; - - sock = (bNodeSocket *)BLI_findlink(in_out == SOCK_IN ? &ngroup->inputs : &ngroup->outputs, index); - if (sock) { - node_group_remove_socket(ngroup, sock, in_out); - ntreeUpdateTree(ngroup); - - snode_notify(C, snode); - } - - return OPERATOR_FINISHED; -} - -void NODE_OT_group_socket_remove(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Remove Group Socket"; - ot->description = "Remove a node group socket"; - ot->idname = "NODE_OT_group_socket_remove"; - - /* api callbacks */ - ot->exec = node_group_socket_remove_exec; - ot->poll = ED_operator_node_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, INT_MAX); - RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output"); -} - -/* ***************** Move Group Socket Up operator ************* */ - -static int node_group_socket_move_up_exec(bContext *C, wmOperator *op) -{ - SpaceNode *snode = CTX_wm_space_node(C); - int index = -1; - int in_out = -1; - bNodeTree *ngroup = snode->edittree; - bNodeSocket *sock, *prev; - - ED_preview_kill_jobs(C); - - if (RNA_struct_property_is_set(op->ptr, "index")) - index = RNA_int_get(op->ptr, "index"); - else - return OPERATOR_CANCELLED; - - if (RNA_struct_property_is_set(op->ptr, "in_out")) - in_out = RNA_enum_get(op->ptr, "in_out"); - else - return OPERATOR_CANCELLED; - - /* swap */ - if (in_out == SOCK_IN) { - sock = (bNodeSocket *)BLI_findlink(&ngroup->inputs, index); - prev = sock->prev; - /* can't move up the first socket */ - if (!prev) - return OPERATOR_CANCELLED; - BLI_remlink(&ngroup->inputs, sock); - BLI_insertlinkbefore(&ngroup->inputs, prev, sock); - - ngroup->update |= NTREE_UPDATE_GROUP_IN; - } - else if (in_out == SOCK_OUT) { - sock = (bNodeSocket *)BLI_findlink(&ngroup->outputs, index); - prev = sock->prev; - /* can't move up the first socket */ - if (!prev) - return OPERATOR_CANCELLED; - BLI_remlink(&ngroup->outputs, sock); - BLI_insertlinkbefore(&ngroup->outputs, prev, sock); - - ngroup->update |= NTREE_UPDATE_GROUP_OUT; - } - ntreeUpdateTree(ngroup); - - snode_notify(C, snode); - - return OPERATOR_FINISHED; -} - -void NODE_OT_group_socket_move_up(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Move Group Socket Up"; - ot->description = "Move up node group socket"; - ot->idname = "NODE_OT_group_socket_move_up"; - - /* api callbacks */ - ot->exec = node_group_socket_move_up_exec; - ot->poll = ED_operator_node_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, INT_MAX); - RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output"); -} - -/* ***************** Move Group Socket Up operator ************* */ - -static int node_group_socket_move_down_exec(bContext *C, wmOperator *op) -{ - SpaceNode *snode = CTX_wm_space_node(C); - int index = -1; - int in_out = -1; - bNodeTree *ngroup = snode->edittree; - bNodeSocket *sock, *next; - - ED_preview_kill_jobs(C); - - if (RNA_struct_property_is_set(op->ptr, "index")) - index = RNA_int_get(op->ptr, "index"); - else - return OPERATOR_CANCELLED; - - if (RNA_struct_property_is_set(op->ptr, "in_out")) - in_out = RNA_enum_get(op->ptr, "in_out"); - else - return OPERATOR_CANCELLED; - - /* swap */ - if (in_out == SOCK_IN) { - sock = (bNodeSocket *)BLI_findlink(&ngroup->inputs, index); - next = sock->next; - /* can't move down the last socket */ - if (!next) - return OPERATOR_CANCELLED; - BLI_remlink(&ngroup->inputs, sock); - BLI_insertlinkafter(&ngroup->inputs, next, sock); - - ngroup->update |= NTREE_UPDATE_GROUP_IN; - } - else if (in_out == SOCK_OUT) { - sock = (bNodeSocket *)BLI_findlink(&ngroup->outputs, index); - next = sock->next; - /* can't move down the last socket */ - if (!next) - return OPERATOR_CANCELLED; - BLI_remlink(&ngroup->outputs, sock); - BLI_insertlinkafter(&ngroup->outputs, next, sock); - - ngroup->update |= NTREE_UPDATE_GROUP_OUT; - } - ntreeUpdateTree(ngroup); - - snode_notify(C, snode); - - return OPERATOR_FINISHED; -} - -void NODE_OT_group_socket_move_down(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Move Group Socket Down"; - ot->description = "Move down node group socket"; - ot->idname = "NODE_OT_group_socket_move_down"; - - /* api callbacks */ - ot->exec = node_group_socket_move_down_exec; - ot->poll = ED_operator_node_active; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, INT_MAX); - RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output"); + + node_group_operator_properties(ot); + RNA_def_boolean(ot->srna, "exit", FALSE, "Exit", ""); } /* ******************** Ungroup operator ********************** */ @@ -415,180 +221,185 @@ void NODE_OT_group_socket_move_down(wmOperatorType *ot) /* returns 1 if its OK */ static int node_group_ungroup(bNodeTree *ntree, bNode *gnode) { - bNodeLink *link, *linkn; - bNode *node, *nextn; + bNodeLink *link, *linkn, *tlink; + bNode *node, *nextnode; bNodeTree *ngroup, *wgroup; ListBase anim_basepaths = {NULL, NULL}; - + ngroup = (bNodeTree *)gnode->id; - if (ngroup == NULL) return 0; - + /* clear new pointers, set in copytree */ for (node = ntree->nodes.first; node; node = node->next) node->new_node = NULL; - + /* wgroup is a temporary copy of the NodeTree we're merging in * - all of wgroup's nodes are transferred across to their new home * - ngroup (i.e. the source NodeTree) is left unscathed * - temp copy. don't change ID usercount */ wgroup = ntreeCopyTree_ex(ngroup, FALSE); - - /* add the nodes into the ntree */ - for (node = wgroup->nodes.first; node; node = nextn) { - nextn = node->next; - - /* keep track of this node's RNA "base" path (the part of the path identifying the node) + + /* Add the nodes into the ntree */ + for(node= wgroup->nodes.first; node; node= nextnode) { + nextnode= node->next; + + /* Remove interface nodes. + * This also removes remaining links to and from interface nodes. + */ + if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) { + nodeFreeNode(wgroup, node); + continue; + } + + /* keep track of this node's RNA "base" path (the part of the path identifying the node) * if the old nodetree has animation data which potentially covers this node */ if (wgroup->adt) { PointerRNA ptr; char *path; - + RNA_pointer_create(&wgroup->id, &RNA_Node, node, &ptr); path = RNA_path_from_ID_to_struct(&ptr); - + if (path) BLI_addtail(&anim_basepaths, BLI_genericNodeN(path)); } - + /* migrate node */ BLI_remlink(&wgroup->nodes, node); BLI_addtail(&ntree->nodes, node); - - /* ensure unique node name in the nodee tree */ + + /* ensure unique node name in the node tree */ nodeUniqueName(ntree, node); - + if (!node->parent) { node->locx += gnode->locx; node->locy += gnode->locy; } - + node->flag |= NODE_SELECT; } - - /* restore external links to and from the gnode */ - for (link = ntree->links.first; link; link = link->next) { - if (link->fromnode == gnode) { - if (link->fromsock->groupsock) { - bNodeSocket *gsock = link->fromsock->groupsock; - if (gsock->link) { - if (gsock->link->fromnode) { - /* NB: using the new internal copies here! the groupsock pointer still maps to the old tree */ - link->fromnode = (gsock->link->fromnode ? gsock->link->fromnode->new_node : NULL); - link->fromsock = gsock->link->fromsock->new_sock; - } - else { - /* group output directly maps to group input */ - bNodeSocket *insock = node_group_find_input(gnode, gsock->link->fromsock); - if (insock->link) { - link->fromnode = insock->link->fromnode; - link->fromsock = insock->link->fromsock; - } - } - } - else { - /* copy the default input value from the group socket default to the external socket */ - node_socket_convert_default_value(link->tosock->type, link->tosock->default_value, gsock->type, gsock->default_value); - } - } - } - } - /* remove internal output links, these are not used anymore */ - for (link = wgroup->links.first; link; link = linkn) { - linkn = link->next; - if (!link->tonode) - nodeRemLink(wgroup, link); - } - /* restore links from internal nodes */ - for (link = wgroup->links.first; link; link = linkn) { - linkn = link->next; - /* indicates link to group input */ - if (!link->fromnode) { - /* NB: can't use find_group_node_input here, - * because gnode sockets still point to the old tree! - */ - bNodeSocket *insock; - for (insock = gnode->inputs.first; insock; insock = insock->next) - if (insock->groupsock->new_sock == link->fromsock) - break; - if (insock->link) { - link->fromnode = insock->link->fromnode; - link->fromsock = insock->link->fromsock; - } - else { - /* copy the default input value from the group node socket default to the internal socket */ - node_socket_convert_default_value(link->tosock->type, link->tosock->default_value, insock->type, insock->default_value); - nodeRemLink(wgroup, link); - } - } - } - - /* add internal links to the ntree */ + + /* Add internal links to the ntree */ for (link = wgroup->links.first; link; link = linkn) { linkn = link->next; BLI_remlink(&wgroup->links, link); BLI_addtail(&ntree->links, link); } - + /* and copy across the animation, * note that the animation data's action can be NULL here */ if (wgroup->adt) { LinkData *ld, *ldn = NULL; bAction *waction; - + /* firstly, wgroup needs to temporary dummy action that can be destroyed, as it shares copies */ waction = wgroup->adt->action = BKE_action_copy(wgroup->adt->action); - + /* now perform the moving */ BKE_animdata_separate_by_basepath(&wgroup->id, &ntree->id, &anim_basepaths); - + /* paths + their wrappers need to be freed */ for (ld = anim_basepaths.first; ld; ld = ldn) { ldn = ld->next; - + MEM_freeN(ld->data); BLI_freelinkN(&anim_basepaths, ld); } - + /* free temp action too */ if (waction) { BKE_libblock_free(&G.main->action, waction); } } - - /* delete the group instance. this also removes old input links! */ - nodeFreeNode(ntree, gnode); - + /* free the group tree (takes care of user count) */ BKE_libblock_free(&G.main->nodetree, wgroup); - + + /* restore external links to and from the gnode */ + /* note: the nodes have been copied to intermediate wgroup first (so need to use new_node), + * then transferred to ntree (new_node pointers remain valid). + */ + + /* input links */ + for (link = ngroup->links.first; link; link = link->next) { + if (link->fromnode->type == NODE_GROUP_INPUT) { + const char *identifier = link->fromsock->identifier; + int num_external_links = 0; + + /* find external links to this input */ + for (tlink = ntree->links.first; tlink; tlink = tlink->next) { + if (tlink->tonode == gnode && strcmp(tlink->tosock->identifier, identifier)==0) { + nodeAddLink(ntree, tlink->fromnode, tlink->fromsock, link->tonode->new_node, link->tosock->new_sock); + ++num_external_links; + } + } + + /* if group output is not externally linked, + * convert the constant input value to ensure somewhat consistent behavior */ + if (num_external_links == 0) { + bNodeSocket *sock = node_group_find_input_socket(gnode, identifier); + BLI_assert(sock); + + /* XXX TODO nodeSocketCopy(ntree, link->tosock->new_sock, link->tonode->new_node, ntree, sock, gnode);*/ + } + } + } + + /* output links */ + for (link = ntree->links.first; link; link = link->next) { + if (link->fromnode == gnode) { + const char *identifier = link->fromsock->identifier; + int num_internal_links = 0; + + /* find internal links to this output */ + for (tlink = ngroup->links.first; tlink; tlink = tlink->next) { + /* only use active output node */ + if (tlink->tonode->type == NODE_GROUP_OUTPUT && (tlink->tonode->flag & NODE_DO_OUTPUT)) { + if (strcmp(tlink->tosock->identifier, identifier)==0) { + nodeAddLink(ntree, tlink->fromnode->new_node, tlink->fromsock->new_sock, link->tonode, link->tosock); + ++num_internal_links; + } + } + } + + /* if group output is not internally linked, + * convert the constant output value to ensure somewhat consistent behavior */ + if (num_internal_links == 0) { + bNodeSocket *sock = node_group_find_output_socket(gnode, identifier); + BLI_assert(sock); + + /* XXX TODO nodeSocketCopy(ntree, link->tosock, link->tonode, ntree, sock, gnode); */ + } + } + } + + /* delete the group instance */ + nodeFreeNode(ntree, gnode); + ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; - + return 1; } + static int node_group_ungroup_exec(bContext *C, wmOperator *op) { SpaceNode *snode = CTX_wm_space_node(C); + char *node_idname; bNode *gnode; ED_preview_kill_jobs(C); - /* are we inside of a group? */ - gnode = node_tree_get_editgroup(snode->nodetree); - if (gnode) - snode_make_group_editable(snode, NULL); - - gnode = nodeGetActive(snode->edittree); - if (gnode == NULL) + if (!node_group_operator_check_type(C, op, &node_idname, NULL)) + return OPERATOR_PASS_THROUGH; + + gnode = node_group_get_active(C, node_idname); + MEM_freeN(node_idname); + if (!gnode) return OPERATOR_CANCELLED; - - if (gnode->type != NODE_GROUP) { - BKE_report(op->reports, RPT_WARNING, "Not a group"); - return OPERATOR_CANCELLED; - } - else if (node_group_ungroup(snode->nodetree, gnode)) { + + if (gnode->id && node_group_ungroup(snode->edittree, gnode)) { ntreeUpdateTree(snode->nodetree); } else { @@ -608,93 +419,92 @@ void NODE_OT_group_ungroup(wmOperatorType *ot) ot->name = "Ungroup"; ot->description = "Ungroup selected nodes"; ot->idname = "NODE_OT_group_ungroup"; - + /* api callbacks */ ot->exec = node_group_ungroup_exec; ot->poll = ED_operator_node_active; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + node_group_operator_properties(ot); } /* ******************** Separate operator ********************** */ /* returns 1 if its OK */ -static int node_group_separate_selected(bNodeTree *ntree, bNode *gnode, int make_copy) +static int node_group_separate_selected(bNodeTree *ntree, bNodeTree *ngroup, float offx, float offy, int make_copy) { bNodeLink *link, *link_next; bNode *node, *node_next, *newnode; - bNodeTree *ngroup; ListBase anim_basepaths = {NULL, NULL}; - - ngroup = (bNodeTree *)gnode->id; - if (ngroup == NULL) return 0; - + /* deselect all nodes in the target tree */ for (node = ntree->nodes.first; node; node = node->next) - node_deselect(node); - + nodeSetSelected(node, FALSE); + /* clear new pointers, set in nodeCopyNode */ for (node = ngroup->nodes.first; node; node = node->next) node->new_node = NULL; - + /* add selected nodes into the ntree */ for (node = ngroup->nodes.first; node; node = node_next) { node_next = node->next; - if (node->flag & NODE_SELECT) { - - if (make_copy) { - /* make a copy */ - newnode = nodeCopyNode(ngroup, node); - } - else { - /* use the existing node */ - newnode = node; - } - - /* keep track of this node's RNA "base" path (the part of the path identifying the node) - * if the old nodetree has animation data which potentially covers this node - */ - if (ngroup->adt) { - PointerRNA ptr; - char *path; - - RNA_pointer_create(&ngroup->id, &RNA_Node, newnode, &ptr); - path = RNA_path_from_ID_to_struct(&ptr); - - if (path) - BLI_addtail(&anim_basepaths, BLI_genericNodeN(path)); - } - - /* ensure valid parent pointers, detach if parent stays inside the group */ - if (newnode->parent && !(newnode->parent->flag & NODE_SELECT)) - nodeDetachNode(newnode); - - /* migrate node */ - BLI_remlink(&ngroup->nodes, newnode); - BLI_addtail(&ntree->nodes, newnode); + if (!(node->flag & NODE_SELECT)) + continue; + + /* ignore interface nodes */ + if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) { + nodeSetSelected(node, FALSE); + continue; + } + + if (make_copy) { + /* make a copy */ + newnode = nodeCopyNode(ngroup, node); + } + else { + /* use the existing node */ + newnode = node; + } + + /* keep track of this node's RNA "base" path (the part of the path identifying the node) + * if the old nodetree has animation data which potentially covers this node + */ + if (ngroup->adt) { + PointerRNA ptr; + char *path; - /* ensure unique node name in the node tree */ - nodeUniqueName(ntree, newnode); + RNA_pointer_create(&ngroup->id, &RNA_Node, newnode, &ptr); + path = RNA_path_from_ID_to_struct(&ptr); - if (!newnode->parent) { - newnode->locx += gnode->locx; - newnode->locy += gnode->locy; - } + if (path) + BLI_addtail(&anim_basepaths, BLI_genericNodeN(path)); } - else { - /* ensure valid parent pointers, detach if child stays inside the group */ - if (node->parent && (node->parent->flag & NODE_SELECT)) - nodeDetachNode(node); + + /* ensure valid parent pointers, detach if parent stays inside the group */ + if (newnode->parent && !(newnode->parent->flag & NODE_SELECT)) + nodeDetachNode(newnode); + + /* migrate node */ + BLI_remlink(&ngroup->nodes, newnode); + BLI_addtail(&ntree->nodes, newnode); + + /* ensure unique node name in the node tree */ + nodeUniqueName(ntree, newnode); + + if (!newnode->parent) { + newnode->locx += offx; + newnode->locy += offy; } } - + /* add internal links to the ntree */ for (link = ngroup->links.first; link; link = link_next) { int fromselect = (link->fromnode && (link->fromnode->flag & NODE_SELECT)); int toselect = (link->tonode && (link->tonode->flag & NODE_SELECT)); link_next = link->next; - + if (make_copy) { /* make a copy of internal links */ if (fromselect && toselect) @@ -711,28 +521,28 @@ static int node_group_separate_selected(bNodeTree *ntree, bNode *gnode, int make } } } - + /* and copy across the animation, * note that the animation data's action can be NULL here */ if (ngroup->adt) { LinkData *ld, *ldn = NULL; - + /* now perform the moving */ BKE_animdata_separate_by_basepath(&ngroup->id, &ntree->id, &anim_basepaths); - + /* paths + their wrappers need to be freed */ for (ld = anim_basepaths.first; ld; ld = ldn) { ldn = ld->next; - + MEM_freeN(ld->data); BLI_freelinkN(&anim_basepaths, ld); } } - + ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; if (!make_copy) ngroup->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; - + return 1; } @@ -751,56 +561,64 @@ EnumPropertyItem node_group_separate_types[] = { static int node_group_separate_exec(bContext *C, wmOperator *op) { SpaceNode *snode = CTX_wm_space_node(C); - bNode *gnode; + bNodeTree *ngroup, *nparent; int type = RNA_enum_get(op->ptr, "type"); + float offx, offy; ED_preview_kill_jobs(C); /* are we inside of a group? */ - gnode = node_tree_get_editgroup(snode->nodetree); - if (!gnode) { + ngroup = snode->edittree; + nparent = ED_node_tree_get(snode, 1); + if (!nparent) { BKE_report(op->reports, RPT_WARNING, "Not inside node group"); return OPERATOR_CANCELLED; } - + /* get node tree offset */ + snode_group_offset(snode, &offx, &offy); + switch (type) { case NODE_GS_COPY: - if (!node_group_separate_selected(snode->nodetree, gnode, 1)) { + if (!node_group_separate_selected(nparent, ngroup, offx, offy, 1)) { BKE_report(op->reports, RPT_WARNING, "Cannot separate nodes"); return OPERATOR_CANCELLED; } break; case NODE_GS_MOVE: - if (!node_group_separate_selected(snode->nodetree, gnode, 0)) { + if (!node_group_separate_selected(nparent, ngroup, offx, offy, 0)) { BKE_report(op->reports, RPT_WARNING, "Cannot separate nodes"); return OPERATOR_CANCELLED; } break; } - + /* switch to parent tree */ - snode_make_group_editable(snode, NULL); - + ED_node_tree_pop(snode); + ntreeUpdateTree(snode->nodetree); - + snode_notify(C, snode); snode_dag_update(C, snode); return OPERATOR_FINISHED; } -static int node_group_separate_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) +static int node_group_separate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - uiPopupMenu *pup = uiPupMenuBegin(C, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Separate"), ICON_NONE); - uiLayout *layout = uiPupMenuLayout(pup); - - uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT); - uiItemEnumO(layout, "NODE_OT_group_separate", NULL, 0, "type", NODE_GS_COPY); - uiItemEnumO(layout, "NODE_OT_group_separate", NULL, 0, "type", NODE_GS_MOVE); - - uiPupMenuEnd(C, pup); - - return OPERATOR_CANCELLED; + if (!node_group_operator_check_type(C, op, NULL, NULL)) + return OPERATOR_PASS_THROUGH; + else { + uiPopupMenu *pup = uiPupMenuBegin(C, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Separate"), ICON_NONE); + uiLayout *layout = uiPupMenuLayout(pup); + + uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT); + uiItemEnumO(layout, "NODE_OT_group_separate", NULL, 0, "type", NODE_GS_COPY); + uiItemEnumO(layout, "NODE_OT_group_separate", NULL, 0, "type", NODE_GS_MOVE); + + uiPupMenuEnd(C, pup); + + return OPERATOR_CANCELLED; + } } void NODE_OT_group_separate(wmOperatorType *ot) @@ -809,162 +627,181 @@ void NODE_OT_group_separate(wmOperatorType *ot) ot->name = "Separate"; ot->description = "Separate selected nodes from the node group"; ot->idname = "NODE_OT_group_separate"; - + /* api callbacks */ ot->invoke = node_group_separate_invoke; ot->exec = node_group_separate_exec; ot->poll = ED_operator_node_active; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + + node_group_operator_properties(ot); RNA_def_enum(ot->srna, "type", node_group_separate_types, NODE_GS_COPY, "Type", ""); } /* ****************** Make Group operator ******************* */ -static int node_group_make_test(bNodeTree *ntree, bNode *gnode) +static int node_group_make_use_node(bNode *node, bNode *gnode) { + return (node != gnode + && !ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT) + && (node->flag & NODE_SELECT)); +} + +static int node_group_make_test_selected(bNodeTree *ntree, bNode *gnode, const char *ntree_idname, struct ReportList *reports) +{ + bNodeTree *ngroup; bNode *node; bNodeLink *link; - int totnode = 0; - - /* is there something to group? also do some clearing */ + int ok = TRUE; + + /* make a local pseudo node tree to pass to the node poll functions */ + ngroup = ntreeAddTree(NULL, "Pseudo Node Group", ntree_idname); + + /* check poll functions for selected nodes */ for (node = ntree->nodes.first; node; node = node->next) { - if (node == gnode) - continue; - - if (node->flag & NODE_SELECT) { - /* no groups in groups */ - if (node->type == NODE_GROUP) - return 0; - totnode++; + if (node_group_make_use_node(node, gnode)) { + if (!node->typeinfo->poll_instance(node, ngroup)) { + BKE_reportf(reports, RPT_WARNING, "Can not add node '%s' in a group", node->name); + ok = FALSE; + break; + } } node->done = 0; } - if (totnode == 0) return 0; - + + /* free local pseudo node tree again */ + ntreeFreeTree(ngroup); + MEM_freeN(ngroup); + if (!ok) + return FALSE; + /* check if all connections are OK, no unselected node has both * inputs and outputs to a selection */ for (link = ntree->links.first; link; link = link->next) { - if (link->fromnode && link->tonode && link->fromnode->flag & NODE_SELECT && link->fromnode != gnode) + if (node_group_make_use_node(link->fromnode, gnode)) link->tonode->done |= 1; - if (link->fromnode && link->tonode && link->tonode->flag & NODE_SELECT && link->tonode != gnode) + if (node_group_make_use_node(link->tonode, gnode)) link->fromnode->done |= 2; } - for (node = ntree->nodes.first; node; node = node->next) { - if (node == gnode) - continue; - if ((node->flag & NODE_SELECT) == 0) - if (node->done == 3) - break; + if (!(node->flag & NODE_SELECT) + && node != gnode + && node->done == 3) + return FALSE; } - if (node) - return 0; - - return 1; + return TRUE; } - -static void node_get_selected_minmax(bNodeTree *ntree, bNode *gnode, float *min, float *max) +static int node_get_selected_minmax(bNodeTree *ntree, bNode *gnode, float *min, float *max) { bNode *node; float loc[2]; + int totselect = 0; + INIT_MINMAX2(min, max); for (node = ntree->nodes.first; node; node = node->next) { - if (node == gnode) - continue; - if (node->flag & NODE_SELECT) { + if (node_group_make_use_node(node, gnode)) { nodeToView(node, 0.0f, 0.0f, &loc[0], &loc[1]); minmax_v2v2_v2(min, max, loc); + ++totselect; } } + + /* sane min/max if no selected nodes */ + if (totselect == 0) { + min[0] = min[1] = max[0] = max[1] = 0.0f; + } + + return totselect; } -static int node_group_make_insert_selected(bNodeTree *ntree, bNode *gnode) +static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree, bNode *gnode) { bNodeTree *ngroup = (bNodeTree *)gnode->id; bNodeLink *link, *linkn; bNode *node, *nextn; - bNodeSocket *gsock, *sock; + bNodeSocket *sock; ListBase anim_basepaths = {NULL, NULL}; - float min[2], max[2]; - + float min[2], max[2], center[2]; + int totselect; + int expose_all = FALSE; + bNode *input_node = NULL, *output_node = NULL; /* lazy initialized, in case there are no external links */ + + /* XXX rough guess, not nice but we don't have access to UI constants here ... */ + static const float offsetx = 200; + static const float offsety = 0.0f; + /* deselect all nodes in the target tree */ for (node = ngroup->nodes.first; node; node = node->next) - node_deselect(node); - - node_get_selected_minmax(ntree, gnode, min, max); - + nodeSetSelected(node, FALSE); + + totselect = node_get_selected_minmax(ntree, gnode, min, max); + add_v2_v2v2(center, min, max); + mul_v2_fl(center, 0.5f); + + /* auto-add interface for "solo" nodes */ + if (totselect == 1) + expose_all = TRUE; + /* move nodes over */ for (node = ntree->nodes.first; node; node = nextn) { nextn = node->next; - if (node == gnode) - continue; - if (node->flag & NODE_SELECT) { - /* keep track of this node's RNA "base" path (the part of the pat identifying the node) + if (node_group_make_use_node(node, gnode)) { + /* keep track of this node's RNA "base" path (the part of the pat identifying the node) * if the old nodetree has animation data which potentially covers this node */ if (ntree->adt) { PointerRNA ptr; char *path; - + RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr); path = RNA_path_from_ID_to_struct(&ptr); - + if (path) BLI_addtail(&anim_basepaths, BLI_genericNodeN(path)); } - + /* ensure valid parent pointers, detach if parent stays outside the group */ if (node->parent && !(node->parent->flag & NODE_SELECT)) nodeDetachNode(node); - + /* change node-collection membership */ BLI_remlink(&ntree->nodes, node); BLI_addtail(&ngroup->nodes, node); - + /* ensure unique node name in the ngroup */ nodeUniqueName(ngroup, node); - - if (!node->parent) { - node->locx -= 0.5f * (min[0] + max[0]); - node->locy -= 0.5f * (min[1] + max[1]); - } - } - else { - /* if the parent is to be inserted but not the child, detach properly */ - if (node->parent && (node->parent->flag & NODE_SELECT)) - nodeDetachNode(node); } } - + /* move animation data over */ if (ntree->adt) { LinkData *ld, *ldn = NULL; - + BKE_animdata_separate_by_basepath(&ntree->id, &ngroup->id, &anim_basepaths); - + /* paths + their wrappers need to be freed */ for (ld = anim_basepaths.first; ld; ld = ldn) { ldn = ld->next; - + MEM_freeN(ld->data); BLI_freelinkN(&anim_basepaths, ld); } } - + /* node groups don't use internal cached data */ ntreeFreeCache(ngroup); - + /* relink external sockets */ for (link = ntree->links.first; link; link = linkn) { - int fromselect = (link->fromnode && (link->fromnode->flag & NODE_SELECT) && link->fromnode != gnode); - int toselect = (link->tonode && (link->tonode->flag & NODE_SELECT) && link->tonode != gnode); + int fromselect = node_group_make_use_node(link->fromnode, gnode); + int toselect = node_group_make_use_node(link->tonode, gnode); + linkn = link->next; - + if ((fromselect && link->tonode == gnode) || (toselect && link->fromnode == gnode)) { /* remove all links to/from the gnode. * this can remove link information, but there's no general way to preserve it. @@ -976,58 +813,123 @@ static int node_group_make_insert_selected(bNodeTree *ntree, bNode *gnode) BLI_addtail(&ngroup->links, link); } else if (toselect) { - gsock = node_group_expose_socket(ngroup, link->tosock, SOCK_IN); - link->tosock->link = nodeAddLink(ngroup, NULL, gsock, link->tonode, link->tosock); - link->tosock = node_group_add_extern_socket(ntree, &gnode->inputs, SOCK_IN, gsock); + bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, link->tonode, link->tosock); + bNodeSocket *input_sock; + + /* lazy init */ + if (!input_node) { + input_node = nodeAddStaticNode(C, ngroup, NODE_GROUP_INPUT); + + input_node->locx = min[0] - center[0] - offsetx; + input_node->locy = -offsety; + } + /* update the group node and interface node sockets, + * so the new interface socket can be linked. + */ + node_group_verify(ntree, gnode, (ID *)ngroup); + node_group_input_verify(ngroup, input_node, (ID *)ngroup); + + /* create new internal link */ + input_sock = node_group_input_find_socket(input_node, iosock->identifier); + nodeAddLink(ngroup, input_node, input_sock, link->tonode, link->tosock); + + /* redirect external link */ link->tonode = gnode; + link->tosock = node_group_find_input_socket(gnode, iosock->identifier); } else if (fromselect) { - /* search for existing group node socket */ - for (gsock = ngroup->outputs.first; gsock; gsock = gsock->next) - if (gsock->link && gsock->link->fromsock == link->fromsock) - break; - if (!gsock) { - gsock = node_group_expose_socket(ngroup, link->fromsock, SOCK_OUT); - gsock->link = nodeAddLink(ngroup, link->fromnode, link->fromsock, NULL, gsock); - link->fromsock = node_group_add_extern_socket(ntree, &gnode->outputs, SOCK_OUT, gsock); + bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, link->fromnode, link->fromsock); + bNodeSocket *output_sock; + + /* lazy init */ + if (!output_node) { + output_node = nodeAddStaticNode(C, ngroup, NODE_GROUP_OUTPUT); + + output_node->locx = max[0] - center[0] + offsetx; + output_node->locy = -offsety; } - else - link->fromsock = node_group_find_output(gnode, gsock); + /* update the group node and interface node sockets, + * so the new interface socket can be linked. + */ + node_group_verify(ntree, gnode, (ID *)ngroup); + node_group_output_verify(ngroup, output_node, (ID *)ngroup); + + /* create new internal link */ + output_sock = node_group_output_find_socket(output_node, iosock->identifier); + nodeAddLink(ngroup, link->fromnode, link->fromsock, output_node, output_sock); + + /* redirect external link */ link->fromnode = gnode; + link->fromsock = node_group_find_output_socket(gnode, iosock->identifier); } } - /* auto-add interface for "solo" nodes */ - node = ((bNodeTree *)gnode->id)->nodes.first; - if (node && !node->next) { - for (sock = node->inputs.first; sock; sock = sock->next) { - int skip = FALSE; - - for (link = ((bNodeTree *)gnode->id)->links.first; link; link = link->next) - if (link->tosock == sock) - skip = TRUE; - - if (skip == TRUE) - continue; - - gsock = node_group_expose_socket(ngroup, sock, SOCK_IN); - node_group_add_extern_socket(ntree, &gnode->inputs, SOCK_IN, gsock); - nodeAddLink(ngroup, NULL, gsock, node, sock); + /* move nodes in the group to the center */ + for (node = ngroup->nodes.first; node; node = node->next) { + if (node_group_make_use_node(node, gnode) && !node->parent) { + node->locx -= center[0]; + node->locy -= center[1]; } - - for (sock = node->outputs.first; sock; sock = sock->next) { - int skip = FALSE; - - for (link = ((bNodeTree *)gnode->id)->links.first; link; link = link->next) - if (link->fromsock == sock) - skip = TRUE; - - if (skip == TRUE) - continue; - - gsock = node_group_expose_socket(ngroup, sock, SOCK_OUT); - node_group_add_extern_socket(ntree, &gnode->outputs, SOCK_OUT, gsock); - nodeAddLink(ngroup, NULL, gsock, node, sock); + } + + /* expose all unlinked sockets too */ + if (expose_all) { + for (node = ngroup->nodes.first; node; node = node->next) { + if (node_group_make_use_node(node, gnode)) { + for (sock = node->inputs.first; sock; sock = sock->next) { + bNodeSocket *iosock, *input_sock; + int skip = FALSE; + for (link = ngroup->links.first; link; link = link->next) { + if (link->tosock == sock) { + skip = TRUE; + break; + } + } + if (skip) + continue; + + iosock = ntreeAddSocketInterfaceFromSocket(ngroup, node, sock); + + /* lazy init */ + if (!input_node) { + input_node = nodeAddStaticNode(C, ngroup, NODE_GROUP_INPUT); + + input_node->locx = min[0] - center[0] - offsetx; + input_node->locy = -offsety; + } + node_group_input_verify(ngroup, input_node, (ID *)ngroup); + + /* create new internal link */ + input_sock = node_group_input_find_socket(input_node, iosock->identifier); + nodeAddLink(ngroup, input_node, input_sock, node, sock); + } + + for (sock = node->outputs.first; sock; sock = sock->next) { + bNodeSocket *iosock, *output_sock; + int skip = FALSE; + for (link = ngroup->links.first; link; link = link->next) + if (link->fromsock == sock) + skip = TRUE; + if (skip) + continue; + + iosock = ntreeAddSocketInterfaceFromSocket(ngroup, node, sock); + + /* lazy init */ + if (!output_node) { + output_node = nodeAddStaticNode(C, ngroup, NODE_GROUP_OUTPUT); + + output_node->locx = max[0] - center[0] + offsetx; + output_node->locy = -offsety; + } + + node_group_output_verify(ngroup, output_node, (ID *)ngroup); + + /* create new internal link */ + output_sock = node_group_output_find_socket(output_node, iosock->identifier); + nodeAddLink(ngroup, node, sock, output_node, output_sock); + } + } } } @@ -1035,30 +937,32 @@ static int node_group_make_insert_selected(bNodeTree *ntree, bNode *gnode) ngroup->update |= NTREE_UPDATE | NTREE_UPDATE_LINKS; /* update of the tree containing the group instance node */ ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; - - return 1; } -static bNode *node_group_make_from_selected(bNodeTree *ntree) +static bNode *node_group_make_from_selected(const bContext *C, bNodeTree *ntree, const char *ntype, const char *ntreetype) { + Main *bmain = CTX_data_main(C); bNode *gnode; bNodeTree *ngroup; float min[2], max[2]; - bNodeTemplate ntemp; - - node_get_selected_minmax(ntree, NULL, min, max); - + int totselect; + + totselect = node_get_selected_minmax(ntree, NULL, min, max); + /* don't make empty group */ + if (totselect == 0) + return NULL; + /* new nodetree */ - ngroup = ntreeAddTree(G.main, "NodeGroup", ntree->type, NODE_GROUP); - + ngroup = ntreeAddTree(bmain, "NodeGroup", ntreetype); + /* make group node */ - ntemp.type = NODE_GROUP; - ntemp.ngroup = ngroup; - gnode = nodeAddNode(ntree, &ntemp); + gnode = nodeAddNode(C, ntree, ntype); + gnode->id = (ID *)ngroup; + gnode->locx = 0.5f * (min[0] + max[0]); gnode->locy = 0.5f * (min[1] + max[1]); - - node_group_make_insert_selected(ntree, gnode); + + node_group_make_insert_selected(C, ntree, gnode); /* update of the tree containing the group instance node */ ntree->update |= NTREE_UPDATE_NODES; @@ -1066,120 +970,116 @@ static bNode *node_group_make_from_selected(bNodeTree *ntree) return gnode; } -typedef enum eNodeGroupMakeType { - NODE_GM_NEW, - NODE_GM_INSERT -} eNodeGroupMakeType; - -/* Operator Property */ -EnumPropertyItem node_group_make_types[] = { - {NODE_GM_NEW, "NEW", 0, "New", "Create a new node group from selected nodes"}, - {NODE_GM_INSERT, "INSERT", 0, "Insert", "Insert into active node group"}, - {0, NULL, 0, NULL, NULL} -}; - static int node_group_make_exec(bContext *C, wmOperator *op) { SpaceNode *snode = CTX_wm_space_node(C); + bNodeTree *ntree = snode->edittree; + char *node_idname, *ntree_idname; + bNodeTree *ngroup; bNode *gnode; - int type = RNA_enum_get(op->ptr, "type"); - - if (snode->edittree != snode->nodetree) { - BKE_report(op->reports, RPT_WARNING, "Cannot add a new group in a group"); - return OPERATOR_CANCELLED; - } - - /* for time being... is too complex to handle */ - if (snode->treetype == NTREE_COMPOSIT) { - for (gnode = snode->nodetree->nodes.first; gnode; gnode = gnode->next) { - if (gnode->flag & SELECT) - if (gnode->type == CMP_NODE_R_LAYERS) - break; - } - - if (gnode) { - BKE_report(op->reports, RPT_WARNING, "Cannot add a Render Layers node in a group"); - return OPERATOR_CANCELLED; - } - } - + ED_preview_kill_jobs(C); - - switch (type) { - case NODE_GM_NEW: - if (node_group_make_test(snode->nodetree, NULL)) { - gnode = node_group_make_from_selected(snode->nodetree); - } - else { - BKE_report(op->reports, RPT_WARNING, "Cannot make group"); - return OPERATOR_CANCELLED; - } - break; - case NODE_GM_INSERT: - gnode = nodeGetActive(snode->nodetree); - if (!gnode || gnode->type != NODE_GROUP) { - BKE_report(op->reports, RPT_WARNING, "No active group node"); - return OPERATOR_CANCELLED; - } - if (node_group_make_test(snode->nodetree, gnode)) { - node_group_make_insert_selected(snode->nodetree, gnode); - } - else { - BKE_report(op->reports, RPT_WARNING, "Cannot insert into group"); - return OPERATOR_CANCELLED; - } - break; + + if (!node_group_operator_check_type(C, op, &node_idname, &ntree_idname)) + return OPERATOR_PASS_THROUGH; + + if (!node_group_make_test_selected(ntree, NULL, ntree_idname, op->reports)) { + MEM_freeN(node_idname); + MEM_freeN(ntree_idname); + return OPERATOR_CANCELLED; } - + + gnode = node_group_make_from_selected(C, ntree, node_idname, ntree_idname); + MEM_freeN(node_idname); + MEM_freeN(ntree_idname); + if (gnode) { - nodeSetActive(snode->nodetree, gnode); - snode_make_group_editable(snode, gnode); + ngroup = (bNodeTree *)gnode->id; + + nodeSetActive(ntree, gnode); + if (ngroup) { + ED_node_tree_push(snode, ngroup, gnode); + ntreeUpdateTree(ngroup); + } } - - if (gnode) - ntreeUpdateTree((bNodeTree *)gnode->id); - ntreeUpdateTree(snode->nodetree); + + ntreeUpdateTree(ntree); snode_notify(C, snode); snode_dag_update(C, snode); - + return OPERATOR_FINISHED; } -static int node_group_make_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) -{ - SpaceNode *snode = CTX_wm_space_node(C); - bNode *act = nodeGetActive(snode->edittree); - uiPopupMenu *pup = uiPupMenuBegin(C, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Make Group"), ICON_NONE); - uiLayout *layout = uiPupMenuLayout(pup); - - uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT); - uiItemEnumO(layout, "NODE_OT_group_make", NULL, 0, "type", NODE_GM_NEW); - - /* if active node is a group, add insert option */ - if (act && act->type == NODE_GROUP) { - uiItemEnumO(layout, "NODE_OT_group_make", NULL, 0, "type", NODE_GM_INSERT); - } - - uiPupMenuEnd(C, pup); - - return OPERATOR_CANCELLED; -} - void NODE_OT_group_make(wmOperatorType *ot) { /* identifiers */ - ot->name = "Group"; + ot->name = "Make Group"; ot->description = "Make group from selected nodes"; ot->idname = "NODE_OT_group_make"; - + /* api callbacks */ - ot->invoke = node_group_make_invoke; ot->exec = node_group_make_exec; ot->poll = ED_operator_node_active; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + node_group_operator_properties(ot); +} - RNA_def_enum(ot->srna, "type", node_group_make_types, NODE_GM_NEW, "Type", ""); +/* ****************** Group Insert operator ******************* */ + +static int node_group_insert_exec(bContext *C, wmOperator *op) +{ + SpaceNode *snode = CTX_wm_space_node(C); + bNodeTree *ntree = snode->edittree; + bNodeTree *ngroup; + char *node_idname; + bNode *gnode; + + ED_preview_kill_jobs(C); + + if (!node_group_operator_check_type(C, op, &node_idname, NULL)) + return OPERATOR_PASS_THROUGH; + + gnode = node_group_get_active(C, node_idname); + MEM_freeN(node_idname); + + if (!gnode || !gnode->id) + return OPERATOR_CANCELLED; + + ngroup = (bNodeTree *)gnode->id; + if (!node_group_make_test_selected(ntree, gnode, ngroup->idname, op->reports)) + return OPERATOR_CANCELLED; + + node_group_make_insert_selected(C, ntree, gnode); + + nodeSetActive(ntree, gnode); + ED_node_tree_push(snode, ngroup, gnode); + ntreeUpdateTree(ngroup); + + ntreeUpdateTree(ntree); + + snode_notify(C, snode); + snode_dag_update(C, snode); + + return OPERATOR_FINISHED; +} + +void NODE_OT_group_insert(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Group Insert"; + ot->description = "Insert selected nodes into a node group"; + ot->idname = "NODE_OT_group_insert"; + + /* api callbacks */ + ot->exec = node_group_insert_exec; + ot->poll = ED_operator_node_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + node_group_operator_properties(ot); } diff --git a/source/blender/editors/space_node/node_header.c b/source/blender/editors/space_node/node_header.c index f26b6ff0f54..175bbce756e 100644 --- a/source/blender/editors/space_node/node_header.c +++ b/source/blender/editors/space_node/node_header.c @@ -58,186 +58,21 @@ /* ************************ add menu *********************** */ -static void do_node_add(bContext *C, bNodeTemplate *ntemp) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - SpaceNode *snode = CTX_wm_space_node(C); - ScrArea *sa = CTX_wm_area(C); - ARegion *ar; - bNode *node, *node_new; - - /* get location to add node at mouse */ - for (ar = sa->regionbase.first; ar; ar = ar->next) { - if (ar->regiontype == RGN_TYPE_WINDOW) { - wmWindow *win = CTX_wm_window(C); - int x = win->eventstate->x - ar->winrct.xmin; - int y = win->eventstate->y - ar->winrct.ymin; - - if (y < 60) y += 60; - UI_view2d_region_to_view(&ar->v2d, x, y, &snode->cursor[0], &snode->cursor[1]); - } - } - - /* store selection in temp test flag */ - for (node = snode->edittree->nodes.first; node; node = node->next) { - if (node->flag & NODE_SELECT) node->flag |= NODE_TEST; - else node->flag &= ~NODE_TEST; - } - - node_new = node_add_node(snode, bmain, scene, ntemp, snode->cursor[0], snode->cursor[1]); - - /* select previous selection before autoconnect */ - for (node = snode->edittree->nodes.first; node; node = node->next) { - if (node->flag & NODE_TEST) node->flag |= NODE_SELECT; - } - - /* deselect after autoconnection */ - for (node = snode->edittree->nodes.first; node; node = node->next) { - if (node->flag & NODE_TEST) node->flag &= ~NODE_SELECT; - } - - /* once this is called from an operator, this should be removed */ - if (node_new) { - char undostr[BKE_UNDO_STR_MAX]; - BLI_snprintf(undostr, sizeof(undostr), "Add Node %s", nodeLabel(node_new)); - BKE_write_undo(C, undostr); - } - - snode_notify(C, snode); - snode_dag_update(C, snode); -} - -static void do_node_add_static(bContext *C, void *UNUSED(arg), int event) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - bNodeTemplate ntemp; - - ntemp.type = event; - ntemp.main = bmain; - ntemp.scene = scene; - - do_node_add(C, &ntemp); -} - -static void do_node_add_group(bContext *C, void *UNUSED(arg), int event) -{ - SpaceNode *snode = CTX_wm_space_node(C); - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - bNodeTemplate ntemp; - - if (event >= 0) { - ntemp.ngroup = BLI_findlink(&G.main->nodetree, event); - ntemp.type = ntemp.ngroup->nodetype; - } - else { - ntemp.type = -event; - switch (ntemp.type) { - case NODE_GROUP: - ntemp.ngroup = ntreeAddTree(bmain, "Group", snode->treetype, ntemp.type); - break; - default: - ntemp.ngroup = NULL; - } - } - if (!ntemp.ngroup) - return; - - ntemp.main = bmain; - ntemp.scene = scene; - - do_node_add(C, &ntemp); -} - -static int node_tree_has_type(int treetype, int nodetype) -{ - bNodeTreeType *ttype = ntreeGetType(treetype); - bNodeType *ntype; - for (ntype = ttype->node_types.first; ntype; ntype = ntype->next) { - if (ntype->type == nodetype) - return 1; - } - return 0; -} - -static void node_add_menu(bContext *C, uiLayout *layout, void *arg_nodeclass) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - SpaceNode *snode = CTX_wm_space_node(C); - bNodeTree *ntree; - int nodeclass = GET_INT_FROM_POINTER(arg_nodeclass); - int event, compatibility = 0; - - ntree = snode->nodetree; - - if (!ntree) { - uiItemS(layout); - return; - } - - if (ntree->type == NTREE_SHADER) { - if (BKE_scene_use_new_shading_nodes(scene)) - compatibility = NODE_NEW_SHADING; - else - compatibility = NODE_OLD_SHADING; - } - - if (nodeclass == NODE_CLASS_GROUP) { - bNodeTree *ngroup; - - uiLayoutSetFunc(layout, do_node_add_group, NULL); - - /* XXX hack: negative numbers used for empty group types */ - if (node_tree_has_type(ntree->type, NODE_GROUP)) - uiItemV(layout, IFACE_("New Group"), 0, -NODE_GROUP); - uiItemS(layout); - - for (ngroup = bmain->nodetree.first, event = 0; ngroup; ngroup = ngroup->id.next, ++event) { - /* only use group trees */ - if (ngroup->type == ntree->type && ngroup->nodetype == NODE_GROUP) { - uiItemV(layout, ngroup->id.name + 2, 0, event); - } - } - } - else { - bNodeType *ntype; - - uiLayoutSetFunc(layout, do_node_add_static, NULL); - - for (ntype = ntreeGetType(ntree->type)->node_types.first; ntype; ntype = ntype->next) { - if (ntype->nclass == nodeclass && ntype->name) { - if (!compatibility || (ntype->compatibility & compatibility)) { - uiItemV(layout, IFACE_(ntype->name), 0, ntype->type); - } - } - } - } -} - -static void node_menu_add_foreach_cb(void *calldata, int nclass, const char *name) -{ - uiLayout *layout = calldata; - uiItemMenuF(layout, IFACE_(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); + bNodeTree *ntree = snode->edittree; - if (!snode->nodetree) + if (!ntree || !ntree->typeinfo || !ntree->typeinfo->draw_add_menu) { uiLayoutSetActive(layout, FALSE); - + return; + } + uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); uiItemO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Search ..."), 0, "NODE_OT_add_search"); - if (ntreetype && ntreetype->foreach_nodeclass) - ntreetype->foreach_nodeclass(scene, layout, node_menu_add_foreach_cb); + ntree->typeinfo->draw_add_menu(C, layout, ntree); } void node_menus_register(void) diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index cbf7101a101..a24da7143f9 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -32,6 +32,7 @@ #define __NODE_INTERN_H__ #include <stddef.h> /* for size_t */ +#include "BKE_node.h" #include "UI_interface.h" /* internal exports only */ @@ -43,7 +44,6 @@ struct bContext; struct wmWindow; struct wmWindowManager; struct wmEvent; -struct bNodeTemplate; struct bNode; struct bNodeSocket; struct bNodeLink; @@ -66,21 +66,26 @@ typedef struct bNodeLinkDrag { ARegion *node_has_buttons_region(ScrArea *sa); ARegion *node_has_tools_region(ScrArea *sa); +void snode_group_offset(struct SpaceNode *snode, float *x, float *y); /* transform between View2Ds in the tree path */ + /* node_header.c */ void node_menus_register(void); /* node_draw.c */ int node_get_colorid(struct bNode *node); -void node_socket_circle_draw(struct bNodeTree *ntree, struct bNodeSocket *sock, float size, int highlight); +void node_socket_circle_draw(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node, + struct bNodeSocket *sock, float size, int highlight); int node_get_resize_cursor(int directions); void node_draw_shadow(struct SpaceNode *snode, struct bNode *node, float radius, float alpha); -void node_draw_default(const struct bContext *C, struct ARegion *ar, struct SpaceNode *snode, struct bNodeTree *ntree, struct bNode *node); +void node_draw_default(const struct bContext *C, struct ARegion *ar, struct SpaceNode *snode, + struct bNodeTree *ntree, struct bNode *node, bNodeInstanceKey key); void node_update_default(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node); int node_select_area_default(struct bNode *node, int x, int y); int node_tweak_area_default(struct bNode *node, int x, int y); -void node_update_nodetree(const struct bContext *C, struct bNodeTree *ntree, float offsetx, float offsety); -void node_draw_nodetree(const struct bContext *C, struct ARegion *ar, struct SpaceNode *snode, struct bNodeTree *ntree); -void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d); +void node_update_nodetree(const struct bContext *C, struct bNodeTree *ntree); +void node_draw_nodetree(const struct bContext *C, struct ARegion *ar, struct SpaceNode *snode, + struct bNodeTree *ntree, bNodeInstanceKey parent_key); +void drawnodespace(const bContext *C, ARegion *ar); void node_set_cursor(struct wmWindow *win, struct SpaceNode *snode); /* DPI scaled coords */ @@ -100,8 +105,6 @@ void node_operatortypes(void); void node_keymap(struct wmKeyConfig *keyconf); /* node_select.c */ -void node_select(struct bNode *node); -void node_deselect(struct bNode *node); void node_deselect_all(struct SpaceNode *snode); void node_socket_select(struct bNode *node, struct bNodeSocket *sock); void node_socket_deselect(struct bNode *node, struct bNodeSocket *sock, int deselect_node); @@ -138,13 +141,15 @@ void draw_nodespace_back_pix(const struct bContext *C, struct ARegion *ar, struc /* node_add.c */ -bNode *node_add_node(struct SpaceNode *snode, struct Main *bmain, struct Scene *scene, - struct bNodeTemplate *ntemp, float locx, float locy); +bNode *node_add_node(const struct bContext *C, const char *idname, int type, float locx, float locy); void NODE_OT_add_reroute(struct wmOperatorType *ot); +void NODE_OT_add_file(struct wmOperatorType *ot); +void NODE_OT_new_node_tree(struct wmOperatorType *ot); /* node_group.c */ void NODE_OT_group_make(struct wmOperatorType *ot); +void NODE_OT_group_insert(struct wmOperatorType *ot); void NODE_OT_group_ungroup(struct wmOperatorType *ot); void NODE_OT_group_separate(struct wmOperatorType *ot); void NODE_OT_group_edit(struct wmOperatorType *ot); @@ -154,11 +159,6 @@ void NODE_OT_group_socket_move_up(struct wmOperatorType *ot); void NODE_OT_group_socket_move_down(struct wmOperatorType *ot); -/* note_add.c */ -void NODE_OT_add_file(struct wmOperatorType *ot); -void NODE_OT_new_node_tree(struct wmOperatorType *ot); - - /* node_relationships.c */ void NODE_OT_link(struct wmOperatorType *ot); void NODE_OT_link_make(struct wmOperatorType *ot); @@ -175,11 +175,9 @@ void NODE_OT_show_cyclic_dependencies(struct wmOperatorType *ot); void NODE_OT_link_viewer(struct wmOperatorType *ot); /* node_edit.c */ -void node_tree_from_ID(ID *id, bNodeTree **ntree, bNodeTree **edittree, int *treetype); void snode_notify(struct bContext *C, struct SpaceNode *snode); void snode_dag_update(struct bContext *C, struct SpaceNode *snode); -void snode_set_context(struct SpaceNode *snode, Scene *scene); -void snode_make_group_editable(struct SpaceNode *snode, struct bNode *gnode); +void snode_set_context(const struct bContext *C); bNode *node_tree_get_editgroup(bNodeTree *ntree); void snode_update(struct SpaceNode *snode, struct bNode *node); @@ -215,6 +213,10 @@ void NODE_OT_output_file_move_active_socket(struct wmOperatorType *ot); void NODE_OT_clipboard_copy(struct wmOperatorType *ot); void NODE_OT_clipboard_paste(struct wmOperatorType *ot); +void NODE_OT_tree_socket_add(struct wmOperatorType *ot); +void NODE_OT_tree_socket_remove(struct wmOperatorType *ot); +void NODE_OT_tree_socket_move(struct wmOperatorType *ot); + void NODE_OT_shader_script_update(struct wmOperatorType *ot); void NODE_OT_viewer_border(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c index d16c6627d3f..db664265466 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -84,13 +84,10 @@ void node_operatortypes(void) WM_operatortype_append(NODE_OT_add_reroute); WM_operatortype_append(NODE_OT_group_make); + WM_operatortype_append(NODE_OT_group_insert); WM_operatortype_append(NODE_OT_group_ungroup); WM_operatortype_append(NODE_OT_group_separate); WM_operatortype_append(NODE_OT_group_edit); - WM_operatortype_append(NODE_OT_group_socket_add); - WM_operatortype_append(NODE_OT_group_socket_remove); - WM_operatortype_append(NODE_OT_group_socket_move_up); - WM_operatortype_append(NODE_OT_group_socket_move_down); WM_operatortype_append(NODE_OT_link_viewer); @@ -122,6 +119,10 @@ void node_operatortypes(void) WM_operatortype_append(NODE_OT_shader_script_update); WM_operatortype_append(NODE_OT_viewer_border); + + WM_operatortype_append(NODE_OT_tree_socket_add); + WM_operatortype_append(NODE_OT_tree_socket_remove); + WM_operatortype_append(NODE_OT_tree_socket_move); } void ED_operatormacros_node(void) @@ -198,6 +199,29 @@ static void node_select_keymap(wmKeyMap *keymap, int extend) } } +/* register group operators for a specific group node type */ +static void node_group_operators(wmKeyMap *keymap, const char *node_type) +{ + wmKeyMapItem *kmi; + + kmi = WM_keymap_add_item(keymap, "NODE_OT_group_make", GKEY, KM_PRESS, KM_CTRL, 0); + RNA_string_set(kmi->ptr, "node_type", node_type); + + kmi = WM_keymap_add_item(keymap, "NODE_OT_group_ungroup", GKEY, KM_PRESS, KM_ALT, 0); + RNA_string_set(kmi->ptr, "node_type", node_type); + + kmi = WM_keymap_add_item(keymap, "NODE_OT_group_separate", PKEY, KM_PRESS, 0, 0); + RNA_string_set(kmi->ptr, "node_type", node_type); + + kmi= WM_keymap_add_item(keymap, "NODE_OT_group_edit", TABKEY, KM_PRESS, 0, 0); + RNA_string_set(kmi->ptr, "node_type", node_type); + RNA_boolean_set(kmi->ptr, "exit", FALSE); + + kmi= WM_keymap_add_item(keymap, "NODE_OT_group_edit", TABKEY, KM_PRESS, KM_SHIFT, 0); + RNA_string_set(kmi->ptr, "node_type", node_type); + RNA_boolean_set(kmi->ptr, "exit", TRUE); +} + void node_keymap(struct wmKeyConfig *keyconf) { wmKeyMap *keymap; @@ -230,9 +254,18 @@ void node_keymap(struct wmKeyConfig *keyconf) RNA_boolean_set(kmi->ptr, "deselect", TRUE); /* each of these falls through if not handled... */ - WM_keymap_add_item(keymap, "NODE_OT_link", LEFTMOUSE, KM_PRESS, 0, 0); + kmi = WM_keymap_add_item(keymap, "NODE_OT_link", LEFTMOUSE, KM_PRESS, 0, 0); + RNA_boolean_set(kmi->ptr, "detach", FALSE); + RNA_boolean_set(kmi->ptr, "expose", FALSE); kmi = WM_keymap_add_item(keymap, "NODE_OT_link", LEFTMOUSE, KM_PRESS, KM_CTRL, 0); RNA_boolean_set(kmi->ptr, "detach", TRUE); + RNA_boolean_set(kmi->ptr, "expose", FALSE); + kmi = WM_keymap_add_item(keymap, "NODE_OT_link", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "detach", FALSE); + RNA_boolean_set(kmi->ptr, "expose", TRUE); + kmi = WM_keymap_add_item(keymap, "NODE_OT_link", LEFTMOUSE, KM_PRESS, KM_SHIFT|KM_CTRL, 0); + RNA_boolean_set(kmi->ptr, "detach", TRUE); + RNA_boolean_set(kmi->ptr, "expose", TRUE); WM_keymap_add_item(keymap, "NODE_OT_resize", LEFTMOUSE, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "NODE_OT_add_reroute", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0); @@ -288,11 +321,10 @@ void node_keymap(struct wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "NODE_OT_select_same_type_next", RIGHTBRACKETKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "NODE_OT_select_same_type_prev", LEFTBRACKETKEY, KM_PRESS, KM_SHIFT, 0); - WM_keymap_add_item(keymap, "NODE_OT_group_make", GKEY, KM_PRESS, KM_CTRL, 0); - WM_keymap_add_item(keymap, "NODE_OT_group_ungroup", GKEY, KM_PRESS, KM_ALT, 0); - WM_keymap_add_item(keymap, "NODE_OT_group_separate", PKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "NODE_OT_group_edit", TABKEY, KM_PRESS, 0, 0); - + node_group_operators(keymap, "ShaderNodeGroup"); + node_group_operators(keymap, "CompositorNodeGroup"); + node_group_operators(keymap, "TextureNodeGroup"); + WM_keymap_add_item(keymap, "NODE_OT_read_renderlayers", RKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "NODE_OT_read_fullsamplelayers", RKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "NODE_OT_render_changed", ZKEY, KM_PRESS, 0, 0); diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c index 097e4f418e0..d95487bb24e 100644 --- a/source/blender/editors/space_node/node_relationships.c +++ b/source/blender/editors/space_node/node_relationships.c @@ -54,6 +54,7 @@ #include "UI_view2d.h" #include "node_intern.h" /* own include */ +#include "NOD_common.h" /* ****************** Add *********************** */ @@ -323,13 +324,8 @@ static int node_link_viewer(const bContext *C, bNode *tonode) if (sock) { /* add a new viewer if none exists yet */ if (!node) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - bNodeTemplate ntemp; - - ntemp.type = CMP_NODE_VIEWER; /* XXX location is a quick hack, just place it next to the linked socket */ - node = node_add_node(snode, bmain, scene, &ntemp, sock->locx + 100, sock->locy); + node = node_add_node(C, NULL, CMP_NODE_VIEWER, sock->locx + 100, sock->locy); if (!node) return OPERATOR_CANCELLED; @@ -364,7 +360,7 @@ static int node_active_link_viewer(bContext *C, wmOperator *UNUSED(op)) SpaceNode *snode = CTX_wm_space_node(C); bNode *node; - node = editnode_get_active(snode->edittree); + node = nodeGetActive(snode->edittree); if (!node) return OPERATOR_CANCELLED; @@ -434,18 +430,6 @@ static void node_remove_extra_links(SpaceNode *snode, bNodeSocket *tsock, bNodeL } } -static int outside_group_rect(SpaceNode *snode) -{ - bNode *gnode = node_tree_get_editgroup(snode->nodetree); - if (gnode) { - return (snode->cursor[0] < gnode->totr.xmin || - snode->cursor[0] >= gnode->totr.xmax || - snode->cursor[1] < gnode->totr.ymin || - snode->cursor[1] >= gnode->totr.ymax); - } - return 0; -} - /* loop that adds a nodelink, called by function below */ /* in_out = starting socket */ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event) @@ -459,55 +443,41 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event) bNodeLink *link; LinkData *linkdata; int in_out; + int expose; in_out = nldrag->in_out; - + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &snode->cursor[0], &snode->cursor[1]); + expose = RNA_boolean_get(op->ptr, "expose"); + switch (event->type) { case MOUSEMOVE: - + if (in_out == SOCK_OUT) { if (node_find_indicated_socket(snode, &tnode, &tsock, SOCK_IN)) { for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) { link = linkdata->data; - + /* skip if this is already the target socket */ if (link->tosock == tsock) continue; /* skip if socket is on the same node as the fromsock */ if (tnode && link->fromnode == tnode) continue; - + /* attach links to the socket */ link->tonode = tnode; link->tosock = tsock; - /* add it to the node tree temporarily */ - if (BLI_findindex(&ntree->links, link) < 0) - BLI_addtail(&ntree->links, link); - - ntree->update |= NTREE_UPDATE_LINKS; } - ntreeUpdateTree(ntree); } else { - int do_update = FALSE; for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) { link = linkdata->data; - - if (link->tonode || link->tosock) { - BLI_remlink(&ntree->links, link); - link->prev = link->next = NULL; - link->tonode = NULL; - link->tosock = NULL; - - ntree->update |= NTREE_UPDATE_LINKS; - do_update = TRUE; - } - } - if (do_update) { - ntreeUpdateTree(ntree); + + link->tonode = NULL; + link->tosock = NULL; } } } @@ -515,108 +485,126 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event) if (node_find_indicated_socket(snode, &tnode, &tsock, SOCK_OUT)) { for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) { link = linkdata->data; - + /* skip if this is already the target socket */ if (link->fromsock == tsock) continue; /* skip if socket is on the same node as the fromsock */ if (tnode && link->tonode == tnode) continue; - + /* attach links to the socket */ link->fromnode = tnode; link->fromsock = tsock; - /* add it to the node tree temporarily */ - if (BLI_findindex(&ntree->links, link) < 0) - BLI_addtail(&ntree->links, link); - - ntree->update |= NTREE_UPDATE_LINKS; } - ntreeUpdateTree(ntree); } else { - int do_update = FALSE; for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) { link = linkdata->data; - - if (link->fromnode || link->fromsock) { - BLI_remlink(&ntree->links, link); - link->prev = link->next = NULL; - link->fromnode = NULL; - link->fromsock = NULL; - - ntree->update |= NTREE_UPDATE_LINKS; - do_update = TRUE; - } - } - if (do_update) { - ntreeUpdateTree(ntree); + + link->fromnode = NULL; + link->fromsock = NULL; } } } - + ED_region_tag_redraw(ar); break; - + case LEFTMOUSE: case RIGHTMOUSE: case MIDDLEMOUSE: { + /* XXX expose + detach could have some ugly corner cases and is not great. + * The first link will define the exposed socket type, which is arbitrary. + * Some of the resulting links may turn out to be invalid. + */ + bNode *ionode = NULL; + bNodeSocket *iosock = NULL, *gsock; for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) { link = linkdata->data; - + if (link->tosock && link->fromsock) { - /* send changed events for original tonode and new */ - if (link->tonode) - snode_update(snode, link->tonode); - + /* add link to the node tree */ + BLI_addtail(&ntree->links, link); + + ntree->update |= NTREE_UPDATE_LINKS; + + /* tag tonode for update */ + link->tonode->update |= NODE_UPDATE; + /* we might need to remove a link */ if (in_out == SOCK_OUT) node_remove_extra_links(snode, link->tosock, link); - - /* when linking to group outputs, update the socket type */ - /* XXX this should all be part of a generic update system */ - if (!link->tonode) { - if (link->tosock->type != link->fromsock->type) - nodeSocketSetType(link->tosock, link->fromsock->type); - } } - else if (outside_group_rect(snode) && (link->tonode || link->fromnode)) { - /* automatically add new group socket */ - if (link->tonode && link->tosock) { - link->fromsock = node_group_expose_socket(ntree, link->tosock, SOCK_IN); - link->fromnode = NULL; - if (BLI_findindex(&ntree->links, link) < 0) - BLI_addtail(&ntree->links, link); - + else if (expose) { + if (link->tosock) { + if (!ionode) { + ionode = nodeAddStaticNode(C, snode->edittree, NODE_GROUP_INPUT); + gsock = ntreeAddSocketInterfaceFromSocket(snode->edittree, link->tonode, link->tosock); + node_group_input_verify(snode->edittree, ionode, (ID *)snode->edittree); + iosock = node_group_input_find_socket(ionode, gsock->identifier); + + { + /* place the node at the mouse pointer */ + float sockx = 42.f + 3*HIDDEN_RAD; /* XXX totally arbitrary initial hidden node size ... */ + float socky = -HIDDEN_RAD; + + ionode->locx = snode->cursor[0] - sockx; + ionode->locy = snode->cursor[1] - socky; + } + } + link->fromnode = ionode; + link->fromsock = iosock; + + BLI_addtail(&ntree->links, link); + ntree->update |= NTREE_UPDATE_GROUP_IN | NTREE_UPDATE_LINKS; } - else if (link->fromnode && link->fromsock) { - link->tosock = node_group_expose_socket(ntree, link->fromsock, SOCK_OUT); - link->tonode = NULL; - if (BLI_findindex(&ntree->links, link) < 0) - BLI_addtail(&ntree->links, link); - + else if (link->fromsock) { + if (!ionode) { + ionode = nodeAddStaticNode(C, snode->edittree, NODE_GROUP_OUTPUT); + gsock = ntreeAddSocketInterfaceFromSocket(snode->edittree, link->fromnode, link->fromsock); + node_group_output_verify(snode->edittree, ionode, (ID *)snode->edittree); + iosock = node_group_output_find_socket(ionode, gsock->identifier); + + { + /* place the node at the mouse pointer */ + float sockx = 0; + float socky = -HIDDEN_RAD; + + ionode->locx = snode->cursor[0] - sockx; + ionode->locy = snode->cursor[1] - socky; + } + } + link->tonode = ionode; + link->tosock = iosock; + + BLI_addtail(&ntree->links, link); + ntree->update |= NTREE_UPDATE_GROUP_OUT | NTREE_UPDATE_LINKS; } + else { + nodeRemLink(snode->edittree, link); + } } else nodeRemLink(ntree, link); } - + ntreeUpdateTree(ntree); snode_notify(C, snode); snode_dag_update(C, snode); - + BLI_remlink(&snode->linkdrag, nldrag); /* links->data pointers are either held by the tree or freed already */ BLI_freelistN(&nldrag->links); MEM_freeN(nldrag); - + return OPERATOR_FINISHED; } } - + return OPERATOR_RUNNING_MODAL; } @@ -646,6 +634,8 @@ static bNodeLinkDrag *node_link_init(SpaceNode *snode, int detach) linkdata->data = oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link"); *oplink = *link; oplink->next = oplink->prev = NULL; + oplink->flag |= NODE_LINK_VALID; + BLI_addtail(&nldrag->links, linkdata); nodeRemLink(snode->edittree, link); } @@ -659,6 +649,8 @@ static bNodeLinkDrag *node_link_init(SpaceNode *snode, int detach) linkdata->data = oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link"); oplink->fromnode = node; oplink->fromsock = sock; + oplink->flag |= NODE_LINK_VALID; + BLI_addtail(&nldrag->links, linkdata); } } @@ -678,9 +670,11 @@ static bNodeLinkDrag *node_link_init(SpaceNode *snode, int detach) linkdata->data = oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link"); *oplink = *link; oplink->next = oplink->prev = NULL; + oplink->flag |= NODE_LINK_VALID; + BLI_addtail(&nldrag->links, linkdata); nodeRemLink(snode->edittree, link); - + /* send changed event to original link->tonode */ if (node) snode_update(snode, node); @@ -695,6 +689,8 @@ static bNodeLinkDrag *node_link_init(SpaceNode *snode, int detach) linkdata->data = oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link"); oplink->tonode = node; oplink->tosock = sock; + oplink->flag |= NODE_LINK_VALID; + BLI_addtail(&nldrag->links, linkdata); } } @@ -760,6 +756,7 @@ void NODE_OT_link(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; RNA_def_boolean(ot->srna, "detach", FALSE, "Detach", "Detach and redirect existing links"); + RNA_def_boolean(ot->srna, "expose", FALSE, "Expose", "Expose the socket as an interface node"); } /* ********************** Make Link operator ***************** */ @@ -845,6 +842,8 @@ static int cut_links_exec(bContext *C, wmOperator *op) for (link = snode->edittree->links.first; link; link = next) { next = link->next; + if (nodeLinkIsHidden(link)) + continue; if (cut_links_intersect(link, mcoords, i)) { @@ -1075,11 +1074,8 @@ static void node_join_attach_recursive(bNode *node, bNode *frame) static int node_join_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceNode *snode = CTX_wm_space_node(C); - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); bNodeTree *ntree = snode->edittree; bNode *node, *frame; - bNodeTemplate ntemp; /* XXX save selection: node_add_node call below sets the new frame as single active+selected node */ for (node = ntree->nodes.first; node; node = node->next) { @@ -1089,10 +1085,7 @@ static int node_join_exec(bContext *C, wmOperator *UNUSED(op)) node->flag &= ~NODE_TEST; } - ntemp.main = bmain; - ntemp.scene = scene; - ntemp.type = NODE_FRAME; - frame = node_add_node(snode, bmain, scene, &ntemp, 0.0f, 0.0f); + frame = node_add_node(C, NULL, NODE_FRAME, 0.0f, 0.0f); /* reset tags */ for (node = ntree->nodes.first; node; node = node->next) @@ -1310,6 +1303,9 @@ static SpaceNode *ed_node_link_conditions(ScrArea *sa, bNode **select) /* test node for links */ for (link = snode->edittree->links.first; link; link = link->next) { + if (nodeLinkIsHidden(link)) + continue; + if (link->tonode == *select || link->fromnode == *select) return NULL; } @@ -1350,7 +1346,9 @@ void ED_node_link_intersect_test(ScrArea *sa, int test) /* we only tag a single link for intersect now */ /* idea; use header dist when more? */ for (link = snode->edittree->links.first; link; link = link->next) { - + if (nodeLinkIsHidden(link)) + continue; + if (cut_links_intersect(link, mcoords, 5)) { /* intersect code wants edges */ if (selink) break; @@ -1415,11 +1413,12 @@ void ED_node_link_insert(ScrArea *sa) link->tonode = select; link->tosock = socket_best_match(&select->inputs); + node_remove_extra_links(snode, link->tosock, link); link->flag &= ~NODE_LINKFLAG_HILITE; nodeAddLink(snode->edittree, select, socket_best_match(&select->outputs), node, sockto); ntreeUpdateTree(snode->edittree); /* needed for pointers */ snode_update(snode, select); - ED_node_changed_update(snode->id, select); + ED_node_tag_update_id(snode->id); } } diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index c917b8ee756..291fe86e016 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -82,30 +82,9 @@ static bNode *node_under_mouse_tweak(bNodeTree *ntree, int mx, int my) return NULL; } -void node_select(bNode *node) -{ - node->flag |= SELECT; -} - -void node_deselect(bNode *node) -{ - bNodeSocket *sock; - - node->flag &= ~SELECT; - - /* deselect sockets too */ - for (sock = node->inputs.first; sock; sock = sock->next) - sock->flag &= ~SELECT; - for (sock = node->outputs.first; sock; sock = sock->next) - sock->flag &= ~SELECT; -} - static void node_toggle(bNode *node) { - if (node->flag & SELECT) - node_deselect(node); - else - node_select(node); + nodeSetSelected(node, !(node->flag & SELECT)); } void node_socket_select(bNode *node, bNodeSocket *sock) @@ -157,7 +136,7 @@ void node_deselect_all(SpaceNode *snode) bNode *node; for (node = snode->edittree->nodes.first; node; node = node->next) - node_deselect(node); + nodeSetSelected(node, FALSE); } void node_deselect_all_input_sockets(SpaceNode *snode, int deselect_nodes) @@ -189,9 +168,6 @@ void node_deselect_all_input_sockets(SpaceNode *snode, int deselect_nodes) node->flag &= ~SELECT; } } - - for (sock = snode->edittree->outputs.first; sock; sock = sock->next) - sock->flag &= ~SELECT; } void node_deselect_all_output_sockets(SpaceNode *snode, int deselect_nodes) @@ -223,9 +199,6 @@ void node_deselect_all_output_sockets(SpaceNode *snode, int deselect_nodes) node->flag &= ~SELECT; } } - - for (sock = snode->edittree->inputs.first; sock; sock = sock->next) - sock->flag &= ~SELECT; } /* return 1 if we need redraw otherwise zero. */ @@ -249,12 +222,12 @@ int node_select_same_type(SpaceNode *snode) if (p->type != nac->type && p->flag & SELECT) { /* if it's selected but different type, unselect */ redraw = 1; - node_deselect(p); + nodeSetSelected(p, FALSE); } else if (p->type == nac->type && (!(p->flag & SELECT))) { /* if it's the same type and is not selected, select! */ redraw = 1; - node_select(p); + nodeSetSelected(p, TRUE); } } return(redraw); @@ -296,8 +269,8 @@ int node_select_same_type_np(SpaceNode *snode, int dir) if (p) { for (tnode = snode->edittree->nodes.first; tnode; tnode = tnode->next) if (tnode != p) - node_deselect(tnode); - node_select(p); + nodeSetSelected(tnode, FALSE); + nodeSetSelected(p, TRUE); return(1); } return(0); @@ -311,8 +284,8 @@ void node_select_single(bContext *C, bNode *node) for (tnode = snode->edittree->nodes.first; tnode; tnode = tnode->next) if (tnode != node) - node_deselect(tnode); - node_select(node); + nodeSetSelected(tnode, FALSE); + nodeSetSelected(node, TRUE); ED_node_set_active(bmain, snode->edittree, node); @@ -387,8 +360,8 @@ static int node_mouse_select(Main *bmain, SpaceNode *snode, ARegion *ar, const i if (node) { for (tnode = snode->edittree->nodes.first; tnode; tnode = tnode->next) - node_deselect(tnode); - node_select(node); + nodeSetSelected(tnode, FALSE); + nodeSetSelected(node, TRUE); ED_node_set_active(bmain, snode->edittree, node); selected = 1; } @@ -477,13 +450,10 @@ static int node_borderselect_exec(bContext *C, wmOperator *op) for (node = snode->edittree->nodes.first; node; node = node->next) { if (BLI_rctf_isect(&rectf, &node->totr, NULL)) { - if (gesture_mode == GESTURE_MODAL_SELECT) - node_select(node); - else - node_deselect(node); + nodeSetSelected(node, (gesture_mode == GESTURE_MODAL_SELECT)); } else if (!extend) { - node_deselect(node); + nodeSetSelected(node, FALSE); } } @@ -566,11 +536,7 @@ static int do_lasso_select_node(bContext *C, const int mcords[][2], short moves, if (BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) && BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], INT_MAX)) { - if (select) - node_select(node); - else - node_deselect(node); - + nodeSetSelected(node, select); change = TRUE; } } @@ -642,13 +608,13 @@ static int node_select_all_exec(bContext *C, wmOperator *op) for (node = node_lb->first; node; node = node->next) { switch (action) { case SEL_SELECT: - node_select(node); + nodeSetSelected(node, TRUE); break; case SEL_DESELECT: - node_deselect(node); + nodeSetSelected(node, FALSE); break; case SEL_INVERT: - ((node->flag & SELECT) ? node_deselect : node_select)(node); + nodeSetSelected(node, !(node->flag & SELECT)); break; } } @@ -688,13 +654,15 @@ static int node_select_linked_to_exec(bContext *C, wmOperator *UNUSED(op)) node->flag &= ~NODE_TEST; for (link = snode->edittree->links.first; link; link = link->next) { + if (nodeLinkIsHidden(link)) + continue; if (link->fromnode && link->tonode && (link->fromnode->flag & NODE_SELECT)) link->tonode->flag |= NODE_TEST; } for (node = snode->edittree->nodes.first; node; node = node->next) { if (node->flag & NODE_TEST) - node_select(node); + nodeSetSelected(node, TRUE); } ED_node_sort(snode->edittree); @@ -730,13 +698,15 @@ static int node_select_linked_from_exec(bContext *C, wmOperator *UNUSED(op)) node->flag &= ~NODE_TEST; for (link = snode->edittree->links.first; link; link = link->next) { + if (nodeLinkIsHidden(link)) + continue; if (link->fromnode && link->tonode && (link->tonode->flag & NODE_SELECT)) link->fromnode->flag |= NODE_TEST; } for (node = snode->edittree->nodes.first; node; node = node->next) { if (node->flag & NODE_TEST) - node_select(node); + nodeSetSelected(node, TRUE); } ED_node_sort(snode->edittree); diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c index ca85415cb5a..e4b0512d992 100644 --- a/source/blender/editors/space_node/node_templates.c +++ b/source/blender/editors/space_node/node_templates.c @@ -130,7 +130,7 @@ static void node_socket_disconnect(Main *bmain, bNodeTree *ntree, bNode *node_to nodeUpdate(ntree, node_to); ntreeUpdateTree(ntree); - ED_node_generic_update(bmain, ntree, node_to); + ED_node_tag_update_nodetree(bmain, ntree); } /* remove all nodes connected to this socket, if they aren't connected to other nodes */ @@ -145,11 +145,11 @@ static void node_socket_remove(Main *bmain, bNodeTree *ntree, bNode *node_to, bN nodeUpdate(ntree, node_to); ntreeUpdateTree(ntree); - ED_node_generic_update(bmain, ntree, node_to); + ED_node_tag_update_nodetree(bmain, ntree); } /* 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) +static void node_socket_add_replace(const bContext *C, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to, int type, bNodeTree *ngroup, int sock_num) { bNode *node_from; bNodeSocket *sock_from_tmp; @@ -163,24 +163,29 @@ static void node_socket_add_replace(Main *bmain, bNodeTree *ntree, bNode *node_t /* 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) + if (node_from->type == 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)) - { + /* XXX how can this be done nicely? bNodeTemplate is removed, it doesn't work for generic custom nodes */ + if (node_prev && node_prev->type == type && + (type != NODE_GROUP || node_prev->id == &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 = nodeAddStaticNode(C, ntree, type); node_from->locx = node_to->locx - (node_from->typeinfo->width + 50); node_from->locy = node_to->locy; - + + /* XXX bad, should be dispatched to generic operator or something ... */ + if (type==NODE_GROUP) { + node_from->id = (ID*)ngroup; + } + if (node_from->id) id_us_plus(node_from->id); } @@ -209,9 +214,11 @@ static void node_socket_add_replace(Main *bmain, bNodeTree *ntree, bNode *node_t nodeRemLink(ntree, link); } - node_socket_free_default_value(sock_from->type, sock_from->default_value); - sock_from->default_value = node_socket_make_default_value(sock_from->type); - node_socket_copy_default_value(sock_from->type, sock_from->default_value, sock_prev->default_value); +#if 0 /* XXX TODO */ + node_socket_free_default_value(sock_from->typeinfo, sock_from->default_value); + sock_from->default_value = node_socket_make_default_value(sock_from->typeinfo); + node_socket_copy_default_value(sock_from->typeinfo, sock_from->default_value, sock_prev->default_value); +#endif } } } @@ -231,7 +238,7 @@ static void node_socket_add_replace(Main *bmain, bNodeTree *ntree, bNode *node_t nodeUpdate(ntree, node_to); ntreeUpdateTree(ntree); - ED_node_generic_update(bmain, ntree, node_to); + ED_node_tag_update_nodetree(CTX_data_main(C), ntree); } /****************************** Node Link Menu *******************************/ @@ -262,19 +269,13 @@ static void ui_node_link(bContext *C, void *arg_p, void *event_p) 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; - ntemp.scene = CTX_data_scene(C); - ntemp.main = CTX_data_main(C); 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); + node_socket_add_replace(C, ntree, node_to, sock_to, arg->type, arg->ngroup, arg->output); ED_undo_push(C, "Node input modify"); } @@ -289,10 +290,10 @@ static void ui_node_sock_name(bNodeSocket *sock, char name[UI_MAX_NAME_STR]) if (node->id) BLI_strncpy(node_name, node->id->name + 2, UI_MAX_NAME_STR); else - BLI_strncpy(node_name, N_("Group"), UI_MAX_NAME_STR); + BLI_strncpy(node_name, N_(node->typeinfo->ui_name), UI_MAX_NAME_STR); } else - BLI_strncpy(node_name, node->typeinfo->name, UI_MAX_NAME_STR); + BLI_strncpy(node_name, node->typeinfo->ui_name, UI_MAX_NAME_STR); if (node->inputs.first == NULL && node->outputs.first != node->outputs.last) @@ -316,19 +317,16 @@ static int ui_compatible_sockets(int typeA, int 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 (BKE_scene_use_new_shading_nodes(arg->scene)) compatibility = NODE_NEW_SHADING; @@ -336,114 +334,58 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname) 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) + NODE_TYPES_BEGIN(ntype) + 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; - - 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, FALSE); - uiBlockSetCurLayout(block, column); - - uiItemL(column, IFACE_(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, TIP_("Add node to input")); - - argN = MEM_dupallocN(arg); - argN->type = NODE_GROUP; - argN->ngroup = ngroup; - argN->output = i; - uiButSetNFunc(but, ui_node_link, argN, NULL); + + if (first) { + column = uiLayoutColumn(layout, 0); + uiBlockSetCurLayout(block, column); + + uiItemL(column, IFACE_(cname), ICON_NODE); + but = block->buttons.last; + but->flag = UI_TEXT_LEFT; + + first = 0; } - } - } - 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, FALSE); - uiBlockSetCurLayout(block, column); - - uiItemL(column, IFACE_(cname), ICON_NODE); + + if (num > 1) { + if (j == 0) { + uiItemL(column, IFACE_(ntype->ui_name), ICON_NODE); but = block->buttons.last; but->flag = UI_TEXT_LEFT; - - first = 0; - } - - if (num > 1) { - if (j == 0) { - uiItemL(column, IFACE_(ntype->name), ICON_NODE); - but = block->buttons.last; - but->flag = UI_TEXT_LEFT; - } - - BLI_snprintf(name, UI_MAX_NAME_STR, " %s", IFACE_(stemp->name)); - j++; } - else - BLI_strncpy(name, IFACE_(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, TIP_("Add node to input")); - - argN = MEM_dupallocN(arg); - argN->type = ntype->type; - argN->output = i; - uiButSetNFunc(but, ui_node_link, argN, NULL); + + BLI_snprintf(name, UI_MAX_NAME_STR, " %s", IFACE_(stemp->name)); + j++; } + else + BLI_strncpy(name, IFACE_(ntype->ui_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, TIP_("Add node to input")); + + argN = MEM_dupallocN(arg); + argN->type = ntype->type; + argN->output = i; + uiButSetNFunc(but, ui_node_link, argN, NULL); } - } + NODE_TYPES_END } static void node_menu_column_foreach_cb(void *calldata, int nclass, const char *name) @@ -463,7 +405,7 @@ static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_ uiLayout *split, *column; NodeLinkArg *arg = (NodeLinkArg *)but->func_argN; bNodeSocket *sock = arg->sock; - bNodeTreeType *ntreetype = ntreeGetType(arg->ntree->type); + bNodeTreeType *ntreetype = arg->ntree->typeinfo; uiBlockSetCurLayout(block, layout); split = uiLayoutSplit(layout, 0.0f, FALSE); @@ -557,7 +499,7 @@ static void ui_node_draw_node(uiLayout *layout, bContext *C, bNodeTree *ntree, b static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input, int depth) { - PointerRNA inputptr; + PointerRNA inputptr, nodeptr; uiBlock *block = uiLayoutGetBlock(layout); uiBut *bt; uiLayout *split, *row, *col; @@ -579,6 +521,7 @@ static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree, /* socket RNA pointer */ RNA_pointer_create(&ntree->id, &RNA_NodeSocket, input, &inputptr); + RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr); /* indented label */ memset(label, ' ', indent); @@ -627,16 +570,25 @@ static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree, } else { /* input not linked, show value */ - if (input->type != SOCK_SHADER && !(input->flag & SOCK_HIDE_VALUE)) { - if (input->type == SOCK_VECTOR) { + if (!(input->flag & SOCK_HIDE_VALUE)) { + switch (input->type) { + case SOCK_FLOAT: + case SOCK_INT: + case SOCK_BOOLEAN: + case SOCK_RGBA: + case SOCK_STRING: + row = uiLayoutRow(split, TRUE); + uiItemR(row, &inputptr, "default_value", 0, "", ICON_NONE); + break; + case SOCK_VECTOR: row = uiLayoutRow(split, FALSE); col = uiLayoutColumn(row, FALSE); - uiItemR(col, &inputptr, "default_value", 0, "", ICON_NONE); - } - else { - row = uiLayoutRow(split, TRUE); - uiItemR(row, &inputptr, "default_value", 0, "", ICON_NONE); + break; + + default: + row = uiLayoutRow(split, FALSE); + break; } } else @@ -653,7 +605,7 @@ void uiTemplateNodeView(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode * { bNode *tnode; - if (!ntree) + if (!ntreeIsValid(ntree)) return; /* clear for cycle check */ diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c index a2fa7d3caf6..1241227c9d8 100644 --- a/source/blender/editors/space_node/node_view.c +++ b/source/blender/editors/space_node/node_view.c @@ -61,6 +61,7 @@ #include "IMB_imbuf_types.h" #include "node_intern.h" /* own include */ +#include "NOD_composite.h" /* **************** View All Operator ************** */ @@ -370,7 +371,7 @@ int ED_space_node_color_sample(SpaceNode *snode, ARegion *ar, int mval[2], float float fx, fy, bufx, bufy; int ret = FALSE; - if (snode->treetype != NTREE_COMPOSIT || (snode->flag & SNODE_BACKDRAW) == 0) { + if (strcmp(snode->tree_idname, ntreeType_Composite->idname)==0 || (snode->flag & SNODE_BACKDRAW) == 0) { /* use viewer image for color sampling only if we're in compositor tree * with backdrop enabled */ @@ -524,7 +525,7 @@ static int sample_invoke(bContext *C, wmOperator *op, const wmEvent *event) ARegion *ar = CTX_wm_region(C); ImageSampleInfo *info; - if (snode->treetype != NTREE_COMPOSIT || !(snode->flag & SNODE_BACKDRAW)) + if (!ED_node_is_compositor(snode) || !(snode->flag & SNODE_BACKDRAW)) return OPERATOR_CANCELLED; info = MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo"); diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index 75f28baf558..ac2f36ed51d 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -45,10 +45,10 @@ #include "BKE_node.h" #include "ED_space_api.h" +#include "ED_node.h" #include "ED_render.h" #include "ED_screen.h" #include "ED_node.h" - #include "WM_api.h" #include "WM_types.h" @@ -59,6 +59,168 @@ #include "node_intern.h" /* own include */ + +/* ******************** tree path ********************* */ + +void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from) +{ + bNodeTreePath *path, *path_next; + for (path=snode->treepath.first; path; path=path_next) { + path_next = path->next; + MEM_freeN(path); + } + snode->treepath.first = snode->treepath.last = NULL; + + if (ntree) { + path = MEM_callocN(sizeof(bNodeTreePath), "node tree path"); + path->nodetree = ntree; + path->parent_key = NODE_INSTANCE_KEY_BASE; + if (id) + BLI_strncpy(path->node_name, id->name+2, sizeof(path->node_name)); + BLI_addtail(&snode->treepath, path); + } + + /* update current tree */ + snode->nodetree = snode->edittree = ntree; + snode->id = id; + snode->from = from; + + /* listener updates the View2D center from edittree */ + WM_main_add_notifier(NC_SCENE|ND_NODES, NULL); +} + +void ED_node_tree_push(SpaceNode *snode, bNodeTree *ntree, bNode *gnode) +{ + bNodeTreePath *path = MEM_callocN(sizeof(bNodeTreePath), "node tree path"); + bNodeTreePath *prev_path = snode->treepath.last; + path->nodetree = ntree; + if (gnode) { + if (prev_path) + path->parent_key = BKE_node_instance_key(prev_path->parent_key, prev_path->nodetree, gnode); + else + path->parent_key = NODE_INSTANCE_KEY_BASE; + + BLI_strncpy(path->node_name, gnode->name, sizeof(path->node_name)); + } + else + path->parent_key = NODE_INSTANCE_KEY_BASE; + + BLI_addtail(&snode->treepath, path); + + /* update current tree */ + snode->edittree = ntree; + + /* listener updates the View2D center from edittree */ + WM_main_add_notifier(NC_SCENE|ND_NODES, NULL); +} + +void ED_node_tree_pop(SpaceNode *snode) +{ + bNodeTreePath *path = snode->treepath.last; + + /* don't remove root */ + if (path == snode->treepath.first) + return; + + BLI_remlink(&snode->treepath, path); + MEM_freeN(path); + + /* update current tree */ + path = snode->treepath.last; + snode->edittree = path->nodetree; + + /* listener updates the View2D center from edittree */ + WM_main_add_notifier(NC_SCENE|ND_NODES, NULL); +} + +int ED_node_tree_depth(SpaceNode *snode) +{ + return BLI_countlist(&snode->treepath); +} + +bNodeTree *ED_node_tree_get(SpaceNode *snode, int level) +{ + bNodeTreePath *path; + int i; + for (path = snode->treepath.last, i = 0; path; path=path->prev, ++i) { + if (i == level) + return path->nodetree; + } + return NULL; +} + +int ED_node_tree_path_length(SpaceNode *snode) +{ + bNodeTreePath *path; + int length = 0; + int i; + for (path=snode->treepath.first, i=0; path; path=path->next, ++i) { + length += strlen(path->node_name); + if (i > 0) + length += 1; /* for separator char */ + } + return length; +} + +void ED_node_tree_path_get(SpaceNode *snode, char *value) +{ + bNodeTreePath *path; + int i; + + value[0] = '\0'; + for (path=snode->treepath.first, i=0; path; path=path->next, ++i) { + if (i == 0) { + strcpy(value, path->node_name); + value += strlen(path->node_name); + } + else { + sprintf(value, "/%s", path->node_name); + value += strlen(path->node_name) + 1; + } + } +} + +void ED_node_tree_path_get_fixedbuf(SpaceNode *snode, char *value, int max_length) +{ + bNodeTreePath *path; + int size, i; + + value[0] = '\0'; + for (path=snode->treepath.first, i=0; path; path=path->next, ++i) { + if (i == 0) { + BLI_strncpy(value, path->node_name, max_length); + size = strlen(path->node_name); + } + else { + BLI_snprintf(value, max_length, "/%s", path->node_name); + size = strlen(path->node_name) + 1; + } + max_length -= size; + if (max_length <= 0) + break; + value += size; + } +} + +void snode_group_offset(SpaceNode *snode, float *x, float *y) +{ + bNodeTreePath *path = snode->treepath.last; + float cx, cy; + + if (path) { + cx = path->nodetree->view_center[0]; + cy = path->nodetree->view_center[1]; + + if (path->prev) { + *x = cx - path->prev->nodetree->view_center[0]; + *y = cy - path->prev->nodetree->view_center[1]; + return; + } + } + + *x = *y = 0.0f; +} + /* ******************** manage regions ********************* */ ARegion *node_has_buttons_region(ScrArea *sa) @@ -124,6 +286,12 @@ static SpaceLink *node_new(const bContext *UNUSED(C)) /* backdrop */ snode->zoom = 1.0f; + /* select the first tree type for valid type */ + NODE_TREE_TYPES_BEGIN(treetype) + strcpy(snode->tree_idname, treetype->idname); + break; + NODE_TREE_TYPES_END + /* header */ ar = MEM_callocN(sizeof(ARegion), "header for node"); @@ -167,10 +335,15 @@ static SpaceLink *node_new(const bContext *UNUSED(C)) return (SpaceLink *)snode; } -/* not spacelink itself */ -static void node_free(SpaceLink *UNUSED(sl)) +static void node_free(SpaceLink *sl) { + SpaceNode *snode = (SpaceNode*)sl; + bNodeTreePath *path, *path_next; + for (path=snode->treepath.first; path; path=path_next) { + path_next = path->next; + MEM_freeN(path); + } } @@ -184,14 +357,21 @@ static void node_area_listener(ScrArea *sa, wmNotifier *wmn) { /* note, ED_area_tag_refresh will re-execute compositor */ SpaceNode *snode = sa->spacedata.first; - int type = snode->treetype; short shader_type = snode->shaderfrom; /* preview renders */ switch (wmn->category) { case NC_SCENE: switch (wmn->data) { - case ND_NODES: + case ND_NODES: { + ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); + /* shift view to node tree center */ + if (ar && snode->edittree) + UI_view2d_setcenter(&ar->v2d, snode->edittree->view_center[0], snode->edittree->view_center[1]); + + ED_area_tag_refresh(sa); + break; + } case ND_FRAME: ED_area_tag_refresh(sa); break; @@ -199,7 +379,7 @@ static void node_area_listener(ScrArea *sa, wmNotifier *wmn) ED_area_tag_redraw(sa); break; case ND_TRANSFORM_DONE: - if (type == NTREE_COMPOSIT) { + if (ED_node_is_compositor(snode)) { if (snode->flag & SNODE_AUTO_RENDER) { snode->recalc = 1; ED_area_tag_refresh(sa); @@ -211,7 +391,7 @@ static void node_area_listener(ScrArea *sa, wmNotifier *wmn) /* future: add ID checks? */ case NC_MATERIAL: - if (type == NTREE_SHADER) { + if (ED_node_is_shader(snode)) { if (wmn->data == ND_SHADING) ED_area_tag_refresh(sa); else if (wmn->data == ND_SHADING_DRAW) @@ -224,18 +404,18 @@ static void node_area_listener(ScrArea *sa, wmNotifier *wmn) } break; case NC_TEXTURE: - if (type == NTREE_SHADER || type == NTREE_TEXTURE) { + if (ED_node_is_shader(snode) || ED_node_is_texture(snode)) { if (wmn->data == ND_NODES) ED_area_tag_refresh(sa); } break; case NC_WORLD: - if (type == NTREE_SHADER && shader_type == SNODE_SHADER_WORLD) { + if (ED_node_is_shader(snode) && shader_type == SNODE_SHADER_WORLD) { ED_area_tag_refresh(sa); } break; case NC_OBJECT: - if (type == NTREE_SHADER) { + if (ED_node_is_shader(snode)) { if (wmn->data == ND_OB_SHADING) ED_area_tag_refresh(sa); } @@ -261,7 +441,7 @@ static void node_area_listener(ScrArea *sa, wmNotifier *wmn) break; case NC_MASK: if (wmn->action == NA_EDITED) { - if (type == NTREE_COMPOSIT) { + if (snode->nodetree && snode->nodetree->type == NTREE_COMPOSIT) { ED_area_tag_refresh(sa); } } @@ -269,7 +449,7 @@ static void node_area_listener(ScrArea *sa, wmNotifier *wmn) case NC_IMAGE: if (wmn->action == NA_EDITED) { - if (type == NTREE_COMPOSIT) { + if (ED_node_is_compositor(snode)) { /* note that nodeUpdateID is already called by BKE_image_signal() on all * scenes so really this is just to know if the images is used in the compo else * painting on images could become very slow when the compositor is open. */ @@ -281,7 +461,7 @@ static void node_area_listener(ScrArea *sa, wmNotifier *wmn) case NC_MOVIECLIP: if (wmn->action == NA_EDITED) { - if (type == NTREE_COMPOSIT) { + if (ED_node_is_compositor(snode)) { if (nodeUpdateID(snode->nodetree, wmn->reference)) ED_area_tag_refresh(sa); } @@ -294,11 +474,13 @@ static void node_area_refresh(const struct bContext *C, ScrArea *sa) { /* default now: refresh node is starting preview */ SpaceNode *snode = sa->spacedata.first; + + ED_preview_kill_jobs(C); + + snode_set_context(C); - snode_set_context(snode, CTX_data_scene(C)); - - if (snode->nodetree) { - if (snode->treetype == NTREE_SHADER) { + if (ntreeIsValid(snode->nodetree)) { + if (snode->nodetree->type == NTREE_SHADER) { if (GS(snode->id->name) == ID_MA) { Material *ma = (Material *)snode->id; if (ma->use_nodes) @@ -315,7 +497,7 @@ static void node_area_refresh(const struct bContext *C, ScrArea *sa) ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER); } } - else if (snode->treetype == NTREE_COMPOSIT) { + else if (snode->nodetree->type == NTREE_COMPOSIT) { Scene *scene = (Scene *)snode->id; if (scene->use_nodes) { /* recalc is set on 3d view changes for auto compo */ @@ -328,7 +510,7 @@ static void node_area_refresh(const struct bContext *C, ScrArea *sa) } } } - else if (snode->treetype == NTREE_TEXTURE) { + else if (snode->nodetree->type == NTREE_TEXTURE) { Tex *tex = (Tex *)snode->id; if (tex->use_nodes) { ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER); @@ -339,11 +521,14 @@ static void node_area_refresh(const struct bContext *C, ScrArea *sa) static SpaceLink *node_duplicate(SpaceLink *sl) { - SpaceNode *snoden = MEM_dupallocN(sl); + SpaceNode *snode = (SpaceNode*)sl; + SpaceNode *snoden = MEM_dupallocN(snode); /* clear or remove stuff from old */ snoden->nodetree = NULL; snoden->linkdrag.first = snoden->linkdrag.last = NULL; + + BLI_duplicatelist(&snoden->treepath, &snode->treepath); return (SpaceLink *)snoden; } @@ -415,9 +600,7 @@ static void node_main_area_init(wmWindowManager *wm, ARegion *ar) static void node_main_area_draw(const bContext *C, ARegion *ar) { - View2D *v2d = &ar->v2d; - - drawnodespace(C, ar, v2d); + drawnodespace(C, ar); } @@ -469,11 +652,8 @@ static void node_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar) static void node_header_area_draw(const bContext *C, ARegion *ar) { - SpaceNode *snode = CTX_wm_space_node(C); - Scene *scene = CTX_data_scene(C); - /* find and set the context */ - snode_set_context(snode, scene); + snode_set_context(C); ED_region_header(C, ar); } @@ -549,6 +729,14 @@ static int node_context(const bContext *C, const char *member, bContextDataResul CTX_data_type_set(result, CTX_DATA_TYPE_POINTER); return 1; } + else if (CTX_data_equals(member, "node_previews")) { + if (snode->nodetree) { + CTX_data_pointer_set(result, &snode->nodetree->id, &RNA_NodeInstanceHash, snode->nodetree->previews); + } + + CTX_data_type_set(result, CTX_DATA_TYPE_POINTER); + return 1; + } return 0; } diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 85375bcaf83..6ea37644533 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -159,7 +159,7 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i if (node && is_image_texture_node(node)) { node->id = &ima->id; - ED_node_generic_update(bmain, ma->nodetree, node); + ED_node_tag_update_nodetree(bmain, ma->nodetree); } } |