diff options
Diffstat (limited to 'source/blender')
27 files changed, 477 insertions, 134 deletions
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index d740b651780..a3387ab554e 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1444,6 +1444,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER 1064 #define GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT 1065 #define GEO_NODE_CURVE_PRIMITIVE_CIRCLE 1066 +#define GEO_NODE_VIEWER 1067 /** \} */ diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 56d8853f0cb..293a1b2f69d 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -3151,8 +3151,8 @@ void ntreeSetOutput(bNodeTree *ntree) if (ntree->type == NTREE_COMPOSIT) { /* same type, exception for viewer */ if (tnode->type == node->type || - (ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER) && - ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))) { + (ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER) && + ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER))) { if (tnode->flag & NODE_DO_OUTPUT) { output++; if (output > 1) { @@ -5097,6 +5097,7 @@ static void registerGeometryNodes() register_node_type_geo_switch(); register_node_type_geo_transform(); register_node_type_geo_triangulate(); + register_node_type_geo_viewer(); register_node_type_geo_volume_to_mesh(); } diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h index 73a1548362c..058d4fa91a3 100644 --- a/source/blender/editors/include/ED_node.h +++ b/source/blender/editors/include/ED_node.h @@ -40,6 +40,7 @@ struct bNodeSocketType; struct bNodeTree; struct bNodeTreeType; struct bNodeType; +struct SpaceNode; typedef enum { NODE_TOP = 1, @@ -114,6 +115,7 @@ bool ED_node_select_check(const ListBase *lb); void ED_node_select_all(ListBase *lb, int action); void ED_node_post_apply_transform(struct bContext *C, struct bNodeTree *ntree); void ED_node_set_active(struct Main *bmain, + struct SpaceNode *snode, struct bNodeTree *ntree, struct bNode *node, bool *r_active_texture_changed); diff --git a/source/blender/editors/include/ED_spreadsheet.h b/source/blender/editors/include/ED_spreadsheet.h index 88bc4738c0b..ff77135a51c 100644 --- a/source/blender/editors/include/ED_spreadsheet.h +++ b/source/blender/editors/include/ED_spreadsheet.h @@ -21,6 +21,9 @@ struct SpaceSpreadsheet; struct SpaceNode; struct ID; struct bNode; +struct Main; +struct bContext; +struct Object; #ifdef __cplusplus extern "C" { @@ -29,14 +32,25 @@ extern "C" { struct SpreadsheetContext *ED_spreadsheet_context_new(int type); void ED_spreadsheet_context_free(struct SpreadsheetContext *context); void ED_spreadsheet_context_path_clear(struct SpaceSpreadsheet *sspreadsheet); -void ED_spreadsheet_context_path_update_tag(struct SpaceSpreadsheet *sspreadsheet); +bool ED_spreadsheet_context_path_update_tag(struct SpaceSpreadsheet *sspreadsheet); uint64_t ED_spreadsheet_context_path_hash(const struct SpaceSpreadsheet *sspreadsheet); struct ID *ED_spreadsheet_get_current_id(const struct SpaceSpreadsheet *sspreadsheet); -void ED_spreadsheet_set_geometry_node_context(struct SpaceSpreadsheet *sspreadsheet, - struct SpaceNode *snode, - struct bNode *node); +void ED_spreadsheet_context_path_set_geometry_node(struct SpaceSpreadsheet *sspreadsheet, + struct SpaceNode *snode, + struct bNode *node); +void ED_spreadsheet_context_paths_set_geometry_node(struct Main *bmain, + struct SpaceNode *snode, + struct bNode *node); +void ED_spreadsheet_context_path_set_evaluated_object(struct SpaceSpreadsheet *sspreadsheet, + struct Object *object); + +void ED_spreadsheet_context_path_guess(const struct bContext *C, + struct SpaceSpreadsheet *sspreadsheet); +bool ED_spreadsheet_context_path_is_active(const struct bContext *C, + struct SpaceSpreadsheet *sspreadsheet); +bool ED_spreadsheet_context_path_exists(struct Main *bmain, struct SpaceSpreadsheet *sspreadsheet); #ifdef __cplusplus } diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c index 97e3cb750c1..f1debcef5a9 100644 --- a/source/blender/editors/space_buttons/buttons_texture.c +++ b/source/blender/editors/space_buttons/buttons_texture.c @@ -451,7 +451,7 @@ static void template_texture_select(bContext *C, void *user_p, void *UNUSED(arg) /* set user as active */ if (user->node) { - ED_node_set_active(CTX_data_main(C), user->ntree, user->node, NULL); + ED_node_set_active(CTX_data_main(C), NULL, user->ntree, user->node, NULL); ct->texture = NULL; /* Not totally sure if we should also change selection? */ diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc index 6143af8ed70..c167744de01 100644 --- a/source/blender/editors/space_node/node_add.cc +++ b/source/blender/editors/space_node/node_add.cc @@ -90,7 +90,7 @@ bNode *node_add_node(const bContext *C, const char *idname, int type, float locx nodeSetSelected(node, true); ntreeUpdateTree(bmain, snode->edittree); - ED_node_set_active(bmain, snode->edittree, node, nullptr); + ED_node_set_active(bmain, snode, snode->edittree, node, nullptr); snode_update(snode, node); diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index c15cc4240a5..8a341da0b5c 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -1405,28 +1405,6 @@ static void node_draw_basis(const bContext *C, ""); UI_block_emboss_set(node->block, UI_EMBOSS); } - if (ntree->type == NTREE_GEOMETRY) { - /* Active preview toggle. */ - iconofs -= iconbutw; - UI_block_emboss_set(node->block, UI_EMBOSS_NONE); - int icon = (node->flag & NODE_ACTIVE_PREVIEW) ? ICON_RESTRICT_VIEW_OFF : ICON_RESTRICT_VIEW_ON; - uiBut *but = uiDefIconBut(node->block, - UI_BTYPE_BUT_TOGGLE, - 0, - icon, - iconofs, - rct->ymax - NODE_DY, - iconbutw, - UI_UNIT_Y, - nullptr, - 0, - 0, - 0, - 0, - "Show this node's geometry output in the spreadsheet"); - UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_active_preview_toggle"); - UI_block_emboss_set(node->block, UI_EMBOSS); - } node_add_error_message_button(C, *ntree, *node, *rct, iconofs); diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index 56064e92d70..9a6603eb589 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -54,6 +54,7 @@ #include "ED_render.h" #include "ED_screen.h" #include "ED_select_utils.h" +#include "ED_spreadsheet.h" #include "RNA_access.h" #include "RNA_define.h" @@ -662,7 +663,8 @@ void snode_update(SpaceNode *snode, bNode *node) } } -void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed) +void ED_node_set_active( + Main *bmain, SpaceNode *snode, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed) { const bool was_active_texture = (node->flag & NODE_ACTIVE_TEXTURE) != 0; if (r_active_texture_changed) { @@ -782,6 +784,19 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node, bool *r_acti } #endif } + else if (ntree->type == NTREE_GEOMETRY) { + if (node->type == GEO_NODE_VIEWER) { + if ((node->flag & NODE_DO_OUTPUT) == 0) { + LISTBASE_FOREACH (bNode *, node_iter, &ntree->nodes) { + if (node_iter->type == GEO_NODE_VIEWER) { + node_iter->flag &= ~NODE_DO_OUTPUT; + } + } + node->flag |= NODE_DO_OUTPUT; + ED_spreadsheet_context_paths_set_geometry_node(bmain, snode, node); + } + } + } } } @@ -1318,7 +1333,6 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) nodeSetSelected(node, false); node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_TEXTURE); nodeSetSelected(newnode, true); - newnode->flag &= ~NODE_ACTIVE_PREVIEW; do_tag_update |= (do_tag_update || node_connected_to_output(bmain, ntree, newnode)); } diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index 58c3c8181b2..e69f0cbea7f 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -279,7 +279,6 @@ void NODE_OT_hide_toggle(struct wmOperatorType *ot); void NODE_OT_hide_socket_toggle(struct wmOperatorType *ot); void NODE_OT_preview_toggle(struct wmOperatorType *ot); void NODE_OT_options_toggle(struct wmOperatorType *ot); -void NODE_OT_active_preview_toggle(struct wmOperatorType *ot); void NODE_OT_node_copy_color(struct wmOperatorType *ot); void NODE_OT_read_viewlayers(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index a1b8e4e3395..aadf93961e9 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -40,11 +40,14 @@ #include "ED_node.h" /* own include */ #include "ED_render.h" #include "ED_screen.h" +#include "ED_spreadsheet.h" #include "ED_util.h" #include "RNA_access.h" #include "RNA_define.h" +#include "DEG_depsgraph.h" + #include "WM_api.h" #include "WM_types.h" @@ -160,6 +163,11 @@ bool node_connected_to_output(Main *bmain, bNodeTree *ntree, bNode *node) return true; } } + if (current_node->type == GEO_NODE_VIEWER) { + if (ntree_check_nodes_connected(ntree, node, current_node)) { + return true; + } + } } return false; } @@ -610,14 +618,14 @@ static int node_link_viewer(const bContext *C, bNode *tonode) if (tonode == nullptr || BLI_listbase_is_empty(&tonode->outputs)) { return OPERATOR_CANCELLED; } - if (ELEM(tonode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { + if (ELEM(tonode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER)) { return OPERATOR_CANCELLED; } /* get viewer */ bNode *viewer_node = nullptr; LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { - if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { + if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER)) { if (node->flag & NODE_DO_OUTPUT) { viewer_node = node; break; @@ -627,7 +635,7 @@ static int node_link_viewer(const bContext *C, bNode *tonode) /* no viewer, we make one active */ if (viewer_node == nullptr) { LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { - if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { + if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER)) { node->flag |= NODE_DO_OUTPUT; viewer_node = node; break; @@ -686,7 +694,8 @@ static int node_link_viewer(const bContext *C, bNode *tonode) /* add a new viewer if none exists yet */ if (!viewer_node) { /* XXX location is a quick hack, just place it next to the linked socket */ - viewer_node = node_add_node(C, nullptr, CMP_NODE_VIEWER, sock->locx + 100, sock->locy); + const int viewer_type = ED_node_is_compositor(snode) ? CMP_NODE_VIEWER : GEO_NODE_VIEWER; + viewer_node = node_add_node(C, nullptr, viewer_type, sock->locx + 100, sock->locy); if (!viewer_node) { return OPERATOR_CANCELLED; } @@ -712,8 +721,13 @@ static int node_link_viewer(const bContext *C, bNode *tonode) /* make sure the dependency sorting is updated */ snode->edittree->update |= NTREE_UPDATE_LINKS; } + if (ED_node_is_geometry(snode)) { + ED_spreadsheet_context_paths_set_geometry_node(CTX_data_main(C), snode, viewer_node); + } + ntreeUpdateTree(CTX_data_main(C), snode->edittree); snode_update(snode, viewer_node); + DEG_id_tag_update(&snode->edittree->id, 0); } return OPERATOR_FINISHED; @@ -739,6 +753,15 @@ static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } +static bool node_active_link_viewer_poll(bContext *C) +{ + if (!ED_operator_node_editable(C)) { + return false; + } + SpaceNode *snode = CTX_wm_space_node(C); + return ED_node_is_compositor(snode) || ED_node_is_geometry(snode); +} + void NODE_OT_link_viewer(wmOperatorType *ot) { /* identifiers */ @@ -748,7 +771,7 @@ void NODE_OT_link_viewer(wmOperatorType *ot) /* api callbacks */ ot->exec = node_active_link_viewer_exec; - ot->poll = composite_node_editable; + ot->poll = node_active_link_viewer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc index 2c8e78de8d2..a081cc83481 100644 --- a/source/blender/editors/space_node/node_select.cc +++ b/source/blender/editors/space_node/node_select.cc @@ -44,6 +44,7 @@ #include "ED_node.h" /* own include */ #include "ED_screen.h" #include "ED_select_utils.h" +#include "ED_spreadsheet.h" #include "ED_view3d.h" #include "RNA_access.h" @@ -469,7 +470,7 @@ void node_select_single(bContext *C, bNode *node) } nodeSetSelected(node, true); - ED_node_set_active(bmain, snode->edittree, node, &active_texture_changed); + ED_node_set_active(bmain, snode, snode->edittree, node, &active_texture_changed); ED_node_set_active_viewer_key(snode); ED_node_sort(snode->edittree); @@ -606,12 +607,18 @@ static int node_mouse_select(bContext *C, /* update node order */ if (ret_value != OPERATOR_CANCELLED) { bool active_texture_changed = false; + bool viewer_node_changed = false; if (node != nullptr && ret_value != OPERATOR_RUNNING_MODAL) { - ED_node_set_active(bmain, snode->edittree, node, &active_texture_changed); + viewer_node_changed = (node->flag & NODE_DO_OUTPUT) == 0 && node->type == GEO_NODE_VIEWER; + ED_node_set_active(bmain, snode, snode->edittree, node, &active_texture_changed); + } + else if (node != nullptr && node->type == GEO_NODE_VIEWER) { + ED_spreadsheet_context_paths_set_geometry_node(bmain, snode, node); } ED_node_set_active_viewer_key(snode); ED_node_sort(snode->edittree); - if (active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) { + if ((active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) || + viewer_node_changed) { DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE); } diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc index 07517f9e60f..fcc92345bea 100644 --- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc +++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc @@ -222,24 +222,11 @@ ID *ED_spreadsheet_get_current_id(const struct SpaceSpreadsheet *sspreadsheet) static void update_pinned_context_path_if_outdated(const bContext *C) { SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); - - /* Currently, this only checks if the object has been deleted. In the future we can have a more - * sophisticated check for the entire context (including modifier and nodes). */ - LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) { - if (context->type == SPREADSHEET_CONTEXT_OBJECT) { - SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context; - if (object_context->object == nullptr) { - ED_spreadsheet_context_path_clear(sspreadsheet); - break; - } - } - } - if (BLI_listbase_is_empty(&sspreadsheet->context_path)) { - Object *active_object = CTX_data_active_object(C); - if (active_object != nullptr) { - SpreadsheetContext *new_context = spreadsheet_context_new(SPREADSHEET_CONTEXT_OBJECT); - ((SpreadsheetContextObject *)new_context)->object = active_object; - BLI_addtail(&sspreadsheet->context_path, new_context); + Main *bmain = CTX_data_main(C); + if (!ED_spreadsheet_context_path_exists(bmain, sspreadsheet)) { + ED_spreadsheet_context_path_guess(C, sspreadsheet); + if (ED_spreadsheet_context_path_update_tag(sspreadsheet)) { + ED_area_tag_redraw(CTX_wm_area(C)); } } @@ -252,25 +239,12 @@ static void update_pinned_context_path_if_outdated(const bContext *C) static void update_context_path_from_context(const bContext *C) { SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); - Object *active_object = CTX_data_active_object(C); - if (active_object == nullptr) { - ED_spreadsheet_context_path_clear(sspreadsheet); - return; - } - if (!BLI_listbase_is_empty(&sspreadsheet->context_path)) { - SpreadsheetContext *root_context = (SpreadsheetContext *)sspreadsheet->context_path.first; - if (root_context->type == SPREADSHEET_CONTEXT_OBJECT) { - SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)root_context; - if (object_context->object != active_object) { - ED_spreadsheet_context_path_clear(sspreadsheet); - } + if (!ED_spreadsheet_context_path_is_active(C, sspreadsheet)) { + ED_spreadsheet_context_path_guess(C, sspreadsheet); + if (ED_spreadsheet_context_path_update_tag(sspreadsheet)) { + ED_area_tag_redraw(CTX_wm_area(C)); } } - if (BLI_listbase_is_empty(&sspreadsheet->context_path)) { - SpreadsheetContext *new_context = spreadsheet_context_new(SPREADSHEET_CONTEXT_OBJECT); - ((SpreadsheetContextObject *)new_context)->object = active_object; - BLI_addtail(&sspreadsheet->context_path, new_context); - } } void spreadsheet_update_context_path(const bContext *C) diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc b/source/blender/editors/space_spreadsheet/spreadsheet_context.cc index af6ab5d1b92..93d7c6d9804 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_context.cc @@ -24,16 +24,28 @@ #include "BLI_utildefines.h" #include "BLI_vector.hh" +#include "ED_screen.h" #include "ED_spreadsheet.h" #include "DEG_depsgraph.h" +#include "BKE_context.h" #include "BKE_main.h" #include "BKE_modifier.h" +#include "BKE_node.h" #include "BKE_object.h" +#include "BKE_workspace.h" + +#include "DNA_modifier_types.h" +#include "DNA_windowmanager_types.h" #include "spreadsheet_context.hh" +using blender::IndexRange; +using blender::Span; +using blender::StringRef; +using blender::Vector; + namespace blender::ed::spreadsheet { static SpreadsheetContextObject *spreadsheet_context_object_new() @@ -206,28 +218,30 @@ void spreadsheet_context_free(SpreadsheetContext *context) /** * Tag any data relevant to the spreadsheet's context for recalculation in order to collect * information to display in the editor, which may be cached during evaluation. + * \return True when any data has been tagged for update. */ -static void spreadsheet_context_update_tag(SpaceSpreadsheet *sspreadsheet) +static bool spreadsheet_context_update_tag(SpaceSpreadsheet *sspreadsheet) { using namespace blender; Vector<const SpreadsheetContext *> context_path = sspreadsheet->context_path; if (context_path.is_empty()) { - return; + return false; } if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) { - return; + return false; } SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context_path[0]; Object *object = object_context->object; if (object == nullptr) { - return; + return false; } if (context_path.size() == 1) { /* No need to reevaluate, when the final or original object is viewed. */ - return; + return false; } DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY); + return true; } } // namespace blender::ed::spreadsheet @@ -250,9 +264,9 @@ void ED_spreadsheet_context_path_clear(struct SpaceSpreadsheet *sspreadsheet) BLI_listbase_clear(&sspreadsheet->context_path); } -void ED_spreadsheet_context_path_update_tag(SpaceSpreadsheet *sspreadsheet) +bool ED_spreadsheet_context_path_update_tag(SpaceSpreadsheet *sspreadsheet) { - blender::ed::spreadsheet::spreadsheet_context_update_tag(sspreadsheet); + return blender::ed::spreadsheet::spreadsheet_context_update_tag(sspreadsheet); } uint64_t ED_spreadsheet_context_path_hash(const SpaceSpreadsheet *sspreadsheet) @@ -265,15 +279,32 @@ uint64_t ED_spreadsheet_context_path_hash(const SpaceSpreadsheet *sspreadsheet) return BLI_hash_mm2a_end(&mm2); } -void ED_spreadsheet_set_geometry_node_context(struct SpaceSpreadsheet *sspreadsheet, - struct SpaceNode *snode, - struct bNode *node) +void ED_spreadsheet_context_path_set_geometry_node(struct SpaceSpreadsheet *sspreadsheet, + struct SpaceNode *snode, + struct bNode *node) { using namespace blender::ed::spreadsheet; - ED_spreadsheet_context_path_clear(sspreadsheet); Object *object = (Object *)snode->id; + /* Try to find the modifier the node tree belongs to. */ ModifierData *modifier = BKE_object_active_modifier(object); + if (modifier && modifier->type != eModifierType_Nodes) { + modifier = nullptr; + LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { + if (md->type == eModifierType_Nodes) { + NodesModifierData *nmd = (NodesModifierData *)md; + if (nmd->node_group == snode->nodetree) { + modifier = md; + break; + } + } + } + } + if (modifier == nullptr) { + return; + } + + ED_spreadsheet_context_path_clear(sspreadsheet); { SpreadsheetContextObject *context = spreadsheet_context_object_new(); @@ -302,5 +333,251 @@ void ED_spreadsheet_set_geometry_node_context(struct SpaceSpreadsheet *sspreadsh BLI_addtail(&sspreadsheet->context_path, context); } - sspreadsheet->object_eval_state = SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED; + sspreadsheet->object_eval_state = SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE; +} + +void ED_spreadsheet_context_paths_set_geometry_node(Main *bmain, SpaceNode *snode, bNode *node) +{ + wmWindowManager *wm = (wmWindowManager *)bmain->wm.first; + if (wm == nullptr) { + return; + } + LISTBASE_FOREACH (wmWindow *, window, &wm->windows) { + bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook); + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + SpaceLink *sl = (SpaceLink *)area->spacedata.first; + if (sl->spacetype == SPACE_SPREADSHEET) { + SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl; + if ((sspreadsheet->flag & SPREADSHEET_FLAG_PINNED) == 0) { + const uint64_t context_hash_before = ED_spreadsheet_context_path_hash(sspreadsheet); + ED_spreadsheet_context_path_set_geometry_node(sspreadsheet, snode, node); + const uint64_t context_hash_after = ED_spreadsheet_context_path_hash(sspreadsheet); + if (context_hash_before != context_hash_after) { + ED_spreadsheet_context_path_update_tag(sspreadsheet); + } + ED_area_tag_redraw(area); + } + } + } + } +} + +void ED_spreadsheet_context_path_set_evaluated_object(SpaceSpreadsheet *sspreadsheet, + Object *object) +{ + using namespace blender::ed::spreadsheet; + ED_spreadsheet_context_path_clear(sspreadsheet); + + SpreadsheetContextObject *context = spreadsheet_context_object_new(); + context->object = object; + BLI_addtail(&sspreadsheet->context_path, context); +} + +void ED_spreadsheet_context_path_guess(const bContext *C, SpaceSpreadsheet *sspreadsheet) +{ + ED_spreadsheet_context_path_clear(sspreadsheet); + + Main *bmain = CTX_data_main(C); + wmWindowManager *wm = (wmWindowManager *)bmain->wm.first; + if (wm == nullptr) { + return; + } + + if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE) { + LISTBASE_FOREACH (wmWindow *, window, &wm->windows) { + bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook); + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + SpaceLink *sl = (SpaceLink *)area->spacedata.first; + if (sl->spacetype == SPACE_NODE) { + SpaceNode *snode = (SpaceNode *)sl; + if (snode->edittree != nullptr) { + if (snode->edittree->type == NTREE_GEOMETRY) { + LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { + if (node->type == GEO_NODE_VIEWER) { + if (node->flag & NODE_DO_OUTPUT) { + ED_spreadsheet_context_path_set_geometry_node(sspreadsheet, snode, node); + return; + } + } + } + } + } + } + } + } + } + + Object *active_object = CTX_data_active_object(C); + if (active_object != nullptr) { + ED_spreadsheet_context_path_set_evaluated_object(sspreadsheet, active_object); + return; + } +} + +bool ED_spreadsheet_context_path_is_active(const bContext *C, SpaceSpreadsheet *sspreadsheet) +{ + Main *bmain = CTX_data_main(C); + wmWindowManager *wm = (wmWindowManager *)bmain->wm.first; + if (wm == nullptr) { + return false; + } + Vector<SpreadsheetContext *> context_path = sspreadsheet->context_path; + if (context_path.is_empty()) { + return false; + } + if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) { + return false; + } + Object *object = ((SpreadsheetContextObject *)context_path[0])->object; + if (object == nullptr) { + return false; + } + if (context_path.size() == 1) { + if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE) { + return false; + } + Object *active_object = CTX_data_active_object(C); + return object == active_object; + } + if (sspreadsheet->object_eval_state != SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE) { + return false; + } + if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) { + return false; + } + const char *modifier_name = ((SpreadsheetContextModifier *)context_path[1])->modifier_name; + const ModifierData *modifier = BKE_modifiers_findby_name(object, modifier_name); + if (modifier == nullptr) { + return false; + } + if (!(modifier->flag & eModifierFlag_Active)) { + return false; + } + if (modifier->type != eModifierType_Nodes) { + return false; + } + bNodeTree *root_node_tree = ((NodesModifierData *)modifier)->node_group; + if (root_node_tree == nullptr) { + return false; + } + const Span<SpreadsheetContext *> node_context_path = context_path.as_span().drop_front(2); + if (node_context_path.is_empty()) { + return false; + } + + LISTBASE_FOREACH (wmWindow *, window, &wm->windows) { + bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook); + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + SpaceLink *sl = (SpaceLink *)area->spacedata.first; + if (sl->spacetype != SPACE_NODE) { + continue; + } + SpaceNode *snode = (SpaceNode *)sl; + if (snode->nodetree != root_node_tree) { + continue; + } + if (snode->id != &object->id) { + continue; + } + Vector<bNodeTreePath *> tree_path = snode->treepath; + if (node_context_path.size() != tree_path.size()) { + continue; + } + int valid_count = 0; + for (const int i : IndexRange(tree_path.size() - 1)) { + if (node_context_path[i]->type != SPREADSHEET_CONTEXT_NODE) { + break; + } + SpreadsheetContextNode *node_context = (SpreadsheetContextNode *)node_context_path[i]; + if (!STREQ(node_context->node_name, tree_path[i]->node_name)) { + break; + } + valid_count++; + } + if (valid_count != tree_path.size() - 1) { + continue; + } + SpreadsheetContext *last_context = node_context_path.last(); + if (last_context->type != SPREADSHEET_CONTEXT_NODE) { + return false; + } + const char *node_name = ((SpreadsheetContextNode *)last_context)->node_name; + bNode *node = nodeFindNodebyName(snode->edittree, node_name); + if (node == nullptr) { + return false; + } + if (node->type != GEO_NODE_VIEWER) { + return false; + } + if (!(node->flag & NODE_DO_OUTPUT)) { + return false; + } + return true; + } + } + return false; +} + +bool ED_spreadsheet_context_path_exists(Main *UNUSED(bmain), SpaceSpreadsheet *sspreadsheet) +{ + Vector<SpreadsheetContext *> context_path = sspreadsheet->context_path; + if (context_path.is_empty()) { + return false; + } + if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) { + return false; + } + Object *object = ((SpreadsheetContextObject *)context_path[0])->object; + if (object == nullptr) { + return false; + } + if (context_path.size() == 1) { + return true; + } + if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) { + return false; + } + const char *modifier_name = ((SpreadsheetContextModifier *)context_path[1])->modifier_name; + const ModifierData *modifier = BKE_modifiers_findby_name(object, modifier_name); + if (modifier == nullptr) { + return false; + } + if (modifier->type != eModifierType_Nodes) { + return false; + } + bNodeTree *root_node_tree = ((NodesModifierData *)modifier)->node_group; + if (root_node_tree == nullptr) { + return false; + } + const Span<SpreadsheetContext *> node_context_path = context_path.as_span().drop_front(2); + if (node_context_path.is_empty()) { + return false; + } + bNodeTree *node_tree = root_node_tree; + for (const int i : node_context_path.index_range()) { + if (node_context_path[i]->type != SPREADSHEET_CONTEXT_NODE) { + return false; + } + const char *node_name = ((SpreadsheetContextNode *)node_context_path[i])->node_name; + bNode *node = nodeFindNodebyName(node_tree, node_name); + if (node == nullptr) { + return false; + } + if (node->type == GEO_NODE_VIEWER) { + if (i == node_context_path.index_range().last()) { + return true; + } + return false; + } + else if (node->id != nullptr) { + if (GS(node->id->name) != ID_NT) { + return false; + } + node_tree = (bNodeTree *)node->id; + } + else { + return false; + } + } + return false; } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc index 6d244a1bda6..f730f199ca4 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -419,7 +419,7 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread pointcloud_component.replace(pointcloud, GeometryOwnershipType::ReadOnly); } } - else if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED) { + else { if (used_component_type == GEO_COMPONENT_TYPE_MESH && object_eval->mode == OB_MODE_EDIT) { Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval, false); if (mesh == nullptr) { diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 6b9ef6a2e54..54bd792294f 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -325,6 +325,7 @@ typedef struct bNode { #define NODE_HIDDEN 8 #define NODE_ACTIVE 16 #define NODE_ACTIVE_ID 32 +/* Used to indicate which group output node is used and which viewer node is active. */ #define NODE_DO_OUTPUT 64 #define __NODE_GROUP_EDIT 128 /* DEPRECATED */ /* free test flag, undefined */ @@ -359,7 +360,7 @@ typedef struct bNode { */ #define NODE_DO_OUTPUT_RECALC (1 << 17) /* A preview for the data in this node can be displayed in the spreadsheet editor. */ -#define NODE_ACTIVE_PREVIEW (1 << 18) +#define __NODE_ACTIVE_PREVIEW (1 << 18) /* deprecated */ /* node->update */ /* XXX NODE_UPDATE is a generic update flag. More fine-grained updates diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index bf5d820056b..557343f79cd 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -1922,6 +1922,7 @@ typedef enum eSpreadsheetFilterOperation { typedef enum eSpaceSpreadsheet_ObjectEvalState { SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED = 0, SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL = 1, + SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE = 2, } eSpaceSpreadsheet_Context; typedef enum eSpaceSpreadsheet_ContextType { diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 73f26f87a74..7def9bdb636 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -690,6 +690,7 @@ static void rna_Modifier_is_active_set(PointerRNA *ptr, bool value) } md->flag |= eModifierFlag_Active; + WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ptr->owner_id); } } diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 50e8f78df8f..d9e199e5eb2 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -11320,12 +11320,6 @@ static void rna_def_node(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Show Texture", "Display node in viewport textured shading mode"); RNA_def_property_update(prop, 0, "rna_Node_update"); - prop = RNA_def_property(srna, "active_preview", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_ACTIVE_PREVIEW); - RNA_def_property_ui_text(prop, "Active Preview", "Node is previewed in other editor"); - RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE); - RNA_def_property_update(prop, NC_NODE, NULL); - /* generic property update function */ func = RNA_def_function(srna, "socket_value_update", "rna_Node_socket_value_update"); RNA_def_function_ui_description(func, "Update after property changes"); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 86a679550f4..7c012922c2c 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -1706,6 +1706,8 @@ static void rna_Object_active_modifier_set(PointerRNA *ptr, PointerRNA value, Re Object *ob = (Object *)ptr->owner_id; ModifierData *md = value.data; + WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob); + if (RNA_pointer_is_null(&value)) { BKE_object_modifier_set_active(ob, NULL); return; diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 8b2927019dd..c05842d3cfe 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -3177,11 +3177,9 @@ static void rna_spreadsheet_context_update(Main *UNUSED(bmain), } } -static void rna_spreadsheet_set_geometry_node_context(SpaceSpreadsheet *sspreadsheet, - SpaceNode *snode, - bNode *node) +static void rna_SpaceSpreadsheet_context_path_guess(SpaceSpreadsheet *sspreadsheet, bContext *C) { - ED_spreadsheet_set_geometry_node_context(sspreadsheet, snode, node); + ED_spreadsheet_context_path_guess(C, sspreadsheet); ED_spreadsheet_context_path_update_tag(sspreadsheet); WM_main_add_notifier(NC_SPACE | ND_SPACE_SPREADSHEET, NULL); } @@ -7646,13 +7644,16 @@ static void rna_def_space_spreadsheet_context_path(BlenderRNA *brna, PropertyRNA func = RNA_def_function(srna, "clear", "rna_SpaceSpreadsheet_context_path_clear"); RNA_def_function_ui_description(func, "Clear entire context path"); + + func = RNA_def_function(srna, "guess", "rna_SpaceSpreadsheet_context_path_guess"); + RNA_def_function_ui_description(func, "Guess the context path from the current context"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); } static void rna_def_space_spreadsheet(BlenderRNA *brna) { - PropertyRNA *prop, *parm; + PropertyRNA *prop; StructRNA *srna; - FunctionRNA *func; static const EnumPropertyItem geometry_component_type_items[] = { {GEO_COMPONENT_TYPE_MESH, @@ -7689,6 +7690,11 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna) ICON_NONE, "Original", "Use data from original object without any modifiers applied"}, + {SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE, + "VIEWER_NODE", + ICON_NONE, + "Viewer Node", + "Use intermediate data from viewer node"}, {0, NULL, 0, NULL, NULL}, }; @@ -7764,16 +7770,6 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna) RNA_def_property_struct_type(prop, "SpreadsheetRowFilter"); RNA_def_property_ui_text(prop, "Row Filters", "Filters to remove rows from the displayed data"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL); - - func = RNA_def_function( - srna, "set_geometry_node_context", "rna_spreadsheet_set_geometry_node_context"); - RNA_def_function_ui_description( - func, "Update context_path to point to a specific node in a node editor"); - parm = RNA_def_pointer( - func, "node_editor", "SpaceNodeEditor", "", "Editor to take the context from"); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); - parm = RNA_def_pointer(func, "node", "Node", "", ""); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } void RNA_def_space(BlenderRNA *brna) diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index f7f7c7b0276..76eec76acb4 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -768,22 +768,6 @@ static Vector<SpaceSpreadsheet *> find_spreadsheet_editors(Main *bmain) using PreviewSocketMap = blender::MultiValueMap<DSocket, uint64_t>; -static DSocket try_find_preview_socket_in_node(const DNode node) -{ - for (const SocketRef *socket : node->outputs()) { - if (socket->bsocket()->type == SOCK_GEOMETRY) { - return {node.context(), socket}; - } - } - for (const SocketRef *socket : node->inputs()) { - if (socket->bsocket()->type == SOCK_GEOMETRY && - (socket->bsocket()->flag & SOCK_MULTI_INPUT) == 0) { - return {node.context(), socket}; - } - } - return {}; -} - static DSocket try_get_socket_to_preview_for_spreadsheet(SpaceSpreadsheet *sspreadsheet, NodesModifierData *nmd, const ModifierEvalContext *ctx, @@ -839,7 +823,17 @@ static DSocket try_get_socket_to_preview_for_spreadsheet(SpaceSpreadsheet *sspre const NodeTreeRef &tree_ref = context->tree(); for (const NodeRef *node_ref : tree_ref.nodes()) { if (node_ref->name() == last_context->node_name) { - return try_find_preview_socket_in_node({context, node_ref}); + const DNode viewer_node{context, node_ref}; + DSocket socket_to_view; + viewer_node.input(0).foreach_origin_socket( + [&](const DSocket socket) { socket_to_view = socket; }); + if (!socket_to_view) { + return {}; + } + bNodeSocket *bsocket = socket_to_view->bsocket(); + if (bsocket->type == SOCK_GEOMETRY && bsocket->flag != SOCK_MULTI_INPUT) { + return socket_to_view; + } } } return {}; @@ -975,6 +969,8 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, blender::modifiers::geometry_nodes::GeometryNodesEvaluationParams eval_params; eval_params.input_values = group_inputs; eval_params.output_sockets = group_outputs; + eval_params.force_compute_sockets.extend(preview_sockets.keys().begin(), + preview_sockets.keys().end()); eval_params.mf_by_node = &mf_by_node; eval_params.modifier_ = nmd; eval_params.depsgraph = ctx->depsgraph; diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc index 8314a443ba6..205bfa34465 100644 --- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc +++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc @@ -404,6 +404,9 @@ class GeometryNodesEvaluator { for (const DInputSocket &socket : params_.output_sockets) { nodes_to_check.push(socket.node()); } + for (const DSocket &socket : params_.force_compute_sockets) { + nodes_to_check.push(socket.node()); + } /* Use the local allocator because the states do not need to outlive the evaluator. */ LinearAllocator<> &allocator = local_allocators_.local(); while (!nodes_to_check.is_empty()) { @@ -501,7 +504,8 @@ class GeometryNodesEvaluator { }, {}); if (output_state.potential_users == 0) { - /* If it does not have any potential users, it is unused. */ + /* If it does not have any potential users, it is unused. It might become required again in + * `schedule_initial_nodes`. */ output_state.output_usage = ValueUsage::Unused; } } @@ -576,6 +580,20 @@ class GeometryNodesEvaluator { this->set_input_required(locked_node, socket); }); } + for (const DSocket socket : params_.force_compute_sockets) { + const DNode node = socket.node(); + NodeState &node_state = this->get_node_state(node); + this->with_locked_node(node, node_state, [&](LockedNode &locked_node) { + if (socket->is_input()) { + this->set_input_required(locked_node, DInputSocket(socket)); + } + else { + OutputState &output_state = node_state.outputs[socket->index()]; + output_state.output_usage = ValueUsage::Required; + this->schedule_node(locked_node); + } + }); + } } void schedule_node(LockedNode &locked_node) @@ -1124,10 +1142,14 @@ class GeometryNodesEvaluator { this->with_locked_node(node, node_state, [&](LockedNode &locked_node) { output_state.potential_users -= 1; if (output_state.potential_users == 0) { - /* The output socket has no users anymore. */ - output_state.output_usage = ValueUsage::Unused; - /* Schedule the origin node in case it wants to set its inputs as unused as well. */ - this->schedule_node(locked_node); + /* The socket might be required even though the output is not used by other sockets. That + * can happen when the socket is forced to be computed. */ + if (output_state.output_usage != ValueUsage::Required) { + /* The output socket has no users anymore. */ + output_state.output_usage = ValueUsage::Unused; + /* Schedule the origin node in case it wants to set its inputs as unused as well. */ + this->schedule_node(locked_node); + } } }); } diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.hh b/source/blender/modifiers/intern/MOD_nodes_evaluator.hh index 84249e4244e..58eb6a4cd0b 100644 --- a/source/blender/modifiers/intern/MOD_nodes_evaluator.hh +++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.hh @@ -38,6 +38,12 @@ struct GeometryNodesEvaluationParams { Map<DOutputSocket, GMutablePointer> input_values; Vector<DInputSocket> output_sockets; + /* These sockets will be computed but are not part of the output. Their value can be retrieved in + * `log_socket_value_fn`. These sockets are not part of `output_sockets` because then the + * evaluator would have to keep the socket values in memory until the end, which might not be + * necessary in all cases. Sometimes `log_socket_value_fn` might just want to look at the value + * and then it can be freed. */ + Vector<DSocket> force_compute_sockets; nodes::MultiFunctionByNode *mf_by_node; const NodesModifierData *modifier_; Depsgraph *depsgraph; diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 77d2f043b64..49e40060c0f 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -206,6 +206,7 @@ set(SRC geometry/nodes/node_geo_switch.cc geometry/nodes/node_geo_transform.cc geometry/nodes/node_geo_triangulate.cc + geometry/nodes/node_geo_viewer.cc geometry/nodes/node_geo_volume_to_mesh.cc geometry/node_geometry_exec.cc geometry/node_geometry_tree.cc diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index 3e41c37ca75..5422eb6a5bf 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -95,6 +95,7 @@ void register_node_type_geo_subdivision_surface(void); void register_node_type_geo_switch(void); void register_node_type_geo_transform(void); void register_node_type_geo_triangulate(void); +void register_node_type_geo_viewer(void); void register_node_type_geo_volume_to_mesh(void); #ifdef __cplusplus diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index f6063039bfc..1d906033128 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -333,6 +333,7 @@ DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE, 0, "SUBDIVISION_SURFACE", Su DefNode(GeometryNode, GEO_NODE_SWITCH, def_geo_switch, "SWITCH", Switch, "Switch", "") DefNode(GeometryNode, GEO_NODE_TRANSFORM, 0, "TRANSFORM", Transform, "Transform", "") DefNode(GeometryNode, GEO_NODE_TRIANGULATE, def_geo_triangulate, "TRIANGULATE", Triangulate, "Triangulate", "") +DefNode(GeometryNode, GEO_NODE_VIEWER, 0, "VIEWER", Viewer, "Viewer", "") DefNode(GeometryNode, GEO_NODE_VOLUME_TO_MESH, def_geo_volume_to_mesh, "VOLUME_TO_MESH", VolumeToMesh, "Volume to Mesh", "") /* undefine macros */ diff --git a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc new file mode 100644 index 00000000000..f0b91f49f52 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc @@ -0,0 +1,31 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "node_geometry_util.hh" + +static bNodeSocketTemplate geo_node_viewer_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +void register_node_type_geo_viewer() +{ + static bNodeType ntype; + + geo_node_type_base(&ntype, GEO_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, 0); + node_type_socket_templates(&ntype, geo_node_viewer_in, nullptr); + nodeRegisterType(&ntype); +} |