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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2021-07-05 11:46:00 +0300
committerJacques Lucke <jacques@blender.org>2021-07-05 11:46:36 +0300
commit9009ac2c3d62e0d30d96b8d35ff5ff620cfe053b (patch)
treeb5b25b36ed769fcdc707aa4d6efd1146fb54621d
parent04313f1bb5ff89168099cdc03d1855ae5118d29c (diff)
Geometry Nodes: new Viewer node
This adds a viewer node similar to the one in the compositor. The icon in the headers of nodes is removed because it served the same purpose and is not necessary anymore. Node outputs can be connected to the active viewer using ctrl+shift+LMB, just like in the compositor. Right now this collides with the shortcut used in the node wrangler addon, which will be changed separately. As of now, the viewed geometry is only visible in the spreadsheet. Viewport visualization will be added separately. There are a couple of benefits of using a viewer node compared to the old approach with the icon in the node header: * Better support for nodes that have more than one geometry output. * It's more consistent with the compositor. * If attributes become decoupled from geometry in the future, the viewer can have a separate input for the attribute to visualize. * The viewer node could potentially have visualization settings. * Allows to keep "visualization points" around by having multiple viewer nodes. * Less visual clutter in node headers. Differential Revision: https://developer.blender.org/D11470
-rw-r--r--release/scripts/startup/bl_operators/node.py62
-rw-r--r--release/scripts/startup/bl_operators/spreadsheet.py13
-rw-r--r--release/scripts/startup/bl_ui/space_spreadsheet.py3
-rw-r--r--release/scripts/startup/nodeitems_builtins.py3
-rw-r--r--source/blender/blenkernel/BKE_node.h1
-rw-r--r--source/blender/blenkernel/intern/node.cc5
-rw-r--r--source/blender/editors/include/ED_node.h2
-rw-r--r--source/blender/editors/include/ED_spreadsheet.h22
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c2
-rw-r--r--source/blender/editors/space_node/node_add.cc2
-rw-r--r--source/blender/editors/space_node/node_draw.cc22
-rw-r--r--source/blender/editors/space_node/node_edit.cc18
-rw-r--r--source/blender/editors/space_node/node_intern.h1
-rw-r--r--source/blender/editors/space_node/node_relationships.cc33
-rw-r--r--source/blender/editors/space_node/node_select.cc13
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc44
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_context.cc301
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc2
-rw-r--r--source/blender/makesdna/DNA_node_types.h3
-rw-r--r--source/blender/makesdna/DNA_space_types.h1
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c1
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c6
-rw-r--r--source/blender/makesrna/intern/rna_object.c2
-rw-r--r--source/blender/makesrna/intern/rna_space.c28
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc30
-rw-r--r--source/blender/modifiers/intern/MOD_nodes_evaluator.cc32
-rw-r--r--source/blender/modifiers/intern/MOD_nodes_evaluator.hh6
-rw-r--r--source/blender/nodes/CMakeLists.txt1
-rw-r--r--source/blender/nodes/NOD_geometry.h1
-rw-r--r--source/blender/nodes/NOD_static_types.h1
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_viewer.cc31
31 files changed, 484 insertions, 208 deletions
diff --git a/release/scripts/startup/bl_operators/node.py b/release/scripts/startup/bl_operators/node.py
index 3cefaf6929b..2959232fa51 100644
--- a/release/scripts/startup/bl_operators/node.py
+++ b/release/scripts/startup/bl_operators/node.py
@@ -306,67 +306,6 @@ class NODE_OT_tree_path_parent(Operator):
return {'FINISHED'}
-class NODE_OT_active_preview_toggle(Operator):
- '''Toggle active preview state of node'''
- bl_idname = "node.active_preview_toggle"
- bl_label = "Toggle Active Preview"
- bl_options = {'REGISTER', 'UNDO'}
-
- @classmethod
- def poll(cls, context):
- space = context.space_data
- if space is None:
- return False
- if space.type != 'NODE_EDITOR':
- return False
- if space.edit_tree is None:
- return False
- if space.edit_tree.nodes.active is None:
- return False
- return True
-
- def execute(self, context):
- node_editor = context.space_data
- ntree = node_editor.edit_tree
- active_node = ntree.nodes.active
-
- if active_node.active_preview:
- self._disable_preview(context, active_node)
- else:
- self._enable_preview(context, node_editor, ntree, active_node)
-
- return {'FINISHED'}
-
- @classmethod
- def _enable_preview(cls, context, node_editor, ntree, active_node):
- spreadsheets = cls._find_unpinned_spreadsheets(context)
-
- for spreadsheet in spreadsheets:
- spreadsheet.set_geometry_node_context(node_editor, active_node)
-
- for node in ntree.nodes:
- node.active_preview = False
- active_node.active_preview = True
-
- @classmethod
- def _disable_preview(cls, context, active_node):
- spreadsheets = cls._find_unpinned_spreadsheets(context)
- for spreadsheet in spreadsheets:
- spreadsheet.context_path.clear()
-
- active_node.active_preview = False
-
- @staticmethod
- def _find_unpinned_spreadsheets(context):
- spreadsheets = []
- for window in context.window_manager.windows:
- for area in window.screen.areas:
- space = area.spaces.active
- if space.type == 'SPREADSHEET' and not space.is_pinned:
- spreadsheets.append(space)
- return spreadsheets
-
-
classes = (
NodeSetting,
@@ -375,5 +314,4 @@ classes = (
NODE_OT_add_search,
NODE_OT_collapse_hide_unused_toggle,
NODE_OT_tree_path_parent,
- NODE_OT_active_preview_toggle,
)
diff --git a/release/scripts/startup/bl_operators/spreadsheet.py b/release/scripts/startup/bl_operators/spreadsheet.py
index 5cc83d4eddd..1907a69a3d3 100644
--- a/release/scripts/startup/bl_operators/spreadsheet.py
+++ b/release/scripts/startup/bl_operators/spreadsheet.py
@@ -47,18 +47,7 @@ class SPREADSHEET_OT_toggle_pin(Operator):
def unpin(self, context):
space = context.space_data
space.is_pinned = False
-
- space.context_path.clear()
-
- # Try to find a node with an active preview in any open editor.
- if space.object_eval_state == 'EVALUATED':
- node_editors = self.find_geometry_node_editors(context)
- for node_editor in node_editors:
- ntree = node_editor.edit_tree
- for node in ntree.nodes:
- if node.active_preview:
- space.set_geometry_node_context(node_editor, node)
- return
+ space.context_path.guess()
def find_geometry_node_editors(self, context):
editors = []
diff --git a/release/scripts/startup/bl_ui/space_spreadsheet.py b/release/scripts/startup/bl_ui/space_spreadsheet.py
index 178be9ef0b7..ad696f23db4 100644
--- a/release/scripts/startup/bl_ui/space_spreadsheet.py
+++ b/release/scripts/startup/bl_ui/space_spreadsheet.py
@@ -54,6 +54,9 @@ class SPREADSHEET_HT_header(bpy.types.Header):
pin_icon = 'PINNED' if space.is_pinned else 'UNPINNED'
layout.operator("spreadsheet.toggle_pin", text="", icon=pin_icon, emboss=False)
+ if space.object_eval_state == 'VIEWER_NODE' and len(context_path) < 3:
+ layout.label(text="No active viewer node.", icon='INFO')
+
layout.separator_spacer()
row = layout.row(align=True)
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index c85d7a9db04..4a7d34f1b69 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -581,6 +581,9 @@ geometry_node_categories = [
NodeItem("ShaderNodeVectorMath"),
NodeItem("ShaderNodeVectorRotate"),
]),
+ GeometryNodeCategory("GEO_OUTPUT", "Output", items=[
+ NodeItem("GeometryNodeViewer"),
+ ]),
GeometryNodeCategory("GEO_VOLUME", "Volume", items=[
NodeItem("GeometryNodePointsToVolume"),
NodeItem("GeometryNodeVolumeToMesh"),
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);
+}