diff options
18 files changed, 338 insertions, 21 deletions
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index ab126ecb152..2ce8ce5749f 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -141,6 +141,12 @@ class GeometryComponent { /* The returned component should be of the same type as the type this is called on. */ virtual GeometryComponent *copy() const = 0; + /* Direct data is everything except for instances of objects/collections. + * If this returns true, the geometry set can be cached and is still valid after e.g. modifier + * evaluation ends. Instances can only be valid as long as the data they instance is valid. */ + virtual bool owns_direct_data() const = 0; + virtual void ensure_owns_direct_data() = 0; + void user_add() const; void user_remove() const; bool is_mutable() const; @@ -315,6 +321,8 @@ struct GeometrySet { void clear(); + void ensure_owns_direct_data(); + /* Utility methods for creation. */ static GeometrySet create_with_mesh( Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned); @@ -374,6 +382,9 @@ class MeshComponent : public GeometryComponent { bool is_empty() const final; + bool owns_direct_data() const override; + void ensure_owns_direct_data() override; + static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_MESH; private: @@ -404,6 +415,9 @@ class PointCloudComponent : public GeometryComponent { bool is_empty() const final; + bool owns_direct_data() const override; + void ensure_owns_direct_data() override; + static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_POINT_CLOUD; private: @@ -444,6 +458,9 @@ class InstancesComponent : public GeometryComponent { bool is_empty() const final; + bool owns_direct_data() const override; + void ensure_owns_direct_data() override; + static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_INSTANCES; }; @@ -466,5 +483,8 @@ class VolumeComponent : public GeometryComponent { const Volume *get_for_read() const; Volume *get_for_write(); + bool owns_direct_data() const override; + void ensure_owns_direct_data() override; + static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_VOLUME; }; diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 0c2c6313dde..6d5638375d6 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -34,6 +34,7 @@ struct Base; struct BoundBox; struct Curve; struct Depsgraph; +struct GeometrySet; struct GpencilModifierData; struct HookGpencilModifierData; struct HookModifierData; @@ -69,6 +70,8 @@ void BKE_object_free_curve_cache(struct Object *ob); void BKE_object_free_derived_caches(struct Object *ob); void BKE_object_free_caches(struct Object *object); +void BKE_object_set_preview_geometry_set(struct Object *ob, struct GeometrySet *geometry_set); + void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd); void BKE_object_modifier_gpencil_hook_reset(struct Object *ob, struct HookGpencilModifierData *hmd); diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc index 68c551645d2..11526eda762 100644 --- a/source/blender/blenkernel/intern/geometry_component_instances.cc +++ b/source/blender/blenkernel/intern/geometry_component_instances.cc @@ -108,6 +108,18 @@ bool InstancesComponent::is_empty() const return transforms_.size() == 0; } +bool InstancesComponent::owns_direct_data() const +{ + /* The object and collection instances are not direct data. Instance transforms are direct data + * and are always owned. Therefore, instance components always own all their direct data. */ + return true; +} + +void InstancesComponent::ensure_owns_direct_data() +{ + BLI_assert(this->is_mutable()); +} + static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids) { using namespace blender; diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index f0f46717744..df451b5db1d 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -157,6 +157,20 @@ bool MeshComponent::is_empty() const return mesh_ == nullptr; } +bool MeshComponent::owns_direct_data() const +{ + return ownership_ == GeometryOwnershipType::Owned; +} + +void MeshComponent::ensure_owns_direct_data() +{ + BLI_assert(this->is_mutable()); + if (ownership_ != GeometryOwnershipType::Owned) { + mesh_ = BKE_mesh_copy_for_eval(mesh_, false); + ownership_ = GeometryOwnershipType::Owned; + } +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc index 32c4ee8a6a6..135de14b4f7 100644 --- a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc +++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc @@ -107,6 +107,20 @@ bool PointCloudComponent::is_empty() const return pointcloud_ == nullptr; } +bool PointCloudComponent::owns_direct_data() const +{ + return ownership_ == GeometryOwnershipType::Owned; +} + +void PointCloudComponent::ensure_owns_direct_data() +{ + BLI_assert(this->is_mutable()); + if (ownership_ != GeometryOwnershipType::Owned) { + pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false); + ownership_ = GeometryOwnershipType::Owned; + } +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/geometry_component_volume.cc b/source/blender/blenkernel/intern/geometry_component_volume.cc index fd2327e0bf5..94ed07a63de 100644 --- a/source/blender/blenkernel/intern/geometry_component_volume.cc +++ b/source/blender/blenkernel/intern/geometry_component_volume.cc @@ -97,4 +97,18 @@ Volume *VolumeComponent::get_for_write() return volume_; } +bool VolumeComponent::owns_direct_data() const +{ + return ownership_ == GeometryOwnershipType::Owned; +} + +void VolumeComponent::ensure_owns_direct_data() +{ + BLI_assert(this->is_mutable()); + if (ownership_ != GeometryOwnershipType::Owned) { + volume_ = BKE_volume_copy_for_eval(volume_, false); + ownership_ = GeometryOwnershipType::Owned; + } +} + /** \} */ diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index 3b027c05f39..fd86f4e550c 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -207,6 +207,19 @@ void GeometrySet::clear() components_.clear(); } +/* Make sure that the geometry can be cached. This does not ensure ownership of object/collection + * instances. */ +void GeometrySet::ensure_owns_direct_data() +{ + for (GeometryComponentType type : components_.keys()) { + const GeometryComponent *component = this->get_component_for_read(type); + if (!component->owns_direct_data()) { + GeometryComponent &component_for_write = this->get_component_for_write(type); + component_for_write.ensure_owns_direct_data(); + } + } +} + /* Returns a read-only mesh or null. */ const Mesh *GeometrySet::get_mesh_for_read() const { diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 1c56312b38b..002071fac30 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1756,6 +1756,10 @@ void BKE_object_free_derived_caches(Object *ob) BKE_geometry_set_free(ob->runtime.geometry_set_eval); ob->runtime.geometry_set_eval = NULL; } + if (ob->runtime.geometry_set_preview != NULL) { + BKE_geometry_set_free(ob->runtime.geometry_set_preview); + ob->runtime.geometry_set_preview = NULL; + } } void BKE_object_free_caches(Object *object) @@ -1806,6 +1810,18 @@ void BKE_object_free_caches(Object *object) } } +/* Can be called from multiple threads. */ +void BKE_object_set_preview_geometry_set(Object *ob, struct GeometrySet *geometry_set) +{ + static ThreadMutex mutex = BLI_MUTEX_INITIALIZER; + BLI_mutex_lock(&mutex); + if (ob->runtime.geometry_set_preview != NULL) { + BKE_geometry_set_free(ob->runtime.geometry_set_preview); + } + ob->runtime.geometry_set_preview = geometry_set; + BLI_mutex_unlock(&mutex); +} + /** * Actual check for internal data, not context or flags. */ diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index 07a5dbe1d7b..88234c861a0 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -1404,6 +1404,28 @@ 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 in Node mode"); + 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.c b/source/blender/editors/space_node/node_edit.c index 8fdee01f78e..518f5639c93 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -41,6 +41,7 @@ #include "BKE_node.h" #include "BKE_report.h" #include "BKE_scene.h" +#include "BKE_workspace.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" @@ -1316,6 +1317,7 @@ 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)); } @@ -1692,6 +1694,55 @@ void NODE_OT_hide_socket_toggle(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +static void disable_active_preview_on_all_nodes(bNodeTree *ntree) +{ + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + node->flag &= ~NODE_ACTIVE_PREVIEW; + } +} + +static int node_active_preview_toggle_exec(bContext *C, wmOperator *UNUSED(op)) +{ + SpaceNode *snode = CTX_wm_space_node(C); + Main *bmain = CTX_data_main(C); + bNodeTree *ntree = snode->edittree; + disable_active_preview_on_all_nodes(ntree); + bNode *active_node = nodeGetActive(ntree); + active_node->flag |= NODE_ACTIVE_PREVIEW; + + /* Tag for update, so that dependent objects are reevaluated. This is necessary when a + * spreadsheet editor displays data from a node. */ + LISTBASE_FOREACH (wmWindow *, window, &((wmWindowManager *)bmain->wm.first)->windows) { + bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook); + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + if (area->spacetype == SPACE_SPREADSHEET) { + SpaceSpreadsheet *sspreadsheet = area->spacedata.first; + if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_NODE) { + DEG_id_tag_update(&ntree->id, ID_RECALC_COPY_ON_WRITE); + ED_area_tag_redraw(area); + } + } + } + } + + return OPERATOR_FINISHED; +} + +void NODE_OT_active_preview_toggle(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Toggle Active Preview"; + ot->description = "Toggle active preview state of node"; + ot->idname = "NODE_OT_active_preview_toggle"; + + /* callbacks */ + ot->exec = node_active_preview_toggle_exec; + ot->poll = ED_operator_node_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + /* ****************** Mute operator *********************** */ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op)) diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index c0952cbaa42..6f281ee05cc 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -273,6 +273,7 @@ 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_ops.c b/source/blender/editors/space_node/node_ops.c index e35b444aa11..4168ff2922d 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -57,6 +57,7 @@ void node_operatortypes(void) WM_operatortype_append(NODE_OT_preview_toggle); WM_operatortype_append(NODE_OT_options_toggle); WM_operatortype_append(NODE_OT_hide_socket_toggle); + WM_operatortype_append(NODE_OT_active_preview_toggle); WM_operatortype_append(NODE_OT_node_copy_color); WM_operatortype_append(NODE_OT_duplicate); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc index 7eea6c48676..5e050517710 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc @@ -200,25 +200,7 @@ static GeometrySet get_display_geometry_set(SpaceSpreadsheet *sspreadsheet, const GeometryComponentType used_component_type) { GeometrySet geometry_set; - if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_FINAL) { - 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) { - return geometry_set; - } - BKE_mesh_wrapper_ensure_mdata(mesh); - MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); - mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly); - mesh_component.copy_vertex_group_names_from_object(*object_eval); - } - else { - if (object_eval->runtime.geometry_set_eval != nullptr) { - /* This does not copy the geometry data itself. */ - geometry_set = *object_eval->runtime.geometry_set_eval; - } - } - } - else { + if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) { Object *object_orig = DEG_get_original_object(object_eval); if (object_orig->type == OB_MESH) { MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); @@ -247,6 +229,30 @@ static GeometrySet get_display_geometry_set(SpaceSpreadsheet *sspreadsheet, pointcloud_component.replace(pointcloud, GeometryOwnershipType::ReadOnly); } } + 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) { + return geometry_set; + } + BKE_mesh_wrapper_ensure_mdata(mesh); + MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); + mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly); + mesh_component.copy_vertex_group_names_from_object(*object_eval); + } + else { + if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_NODE) { + if (object_eval->runtime.geometry_set_preview != nullptr) { + geometry_set = *object_eval->runtime.geometry_set_preview; + } + } + else if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_FINAL) { + if (object_eval->runtime.geometry_set_eval != nullptr) { + geometry_set = *object_eval->runtime.geometry_set_eval; + } + } + } + } return geometry_set; } @@ -377,7 +383,7 @@ static Span<int64_t> filter_mesh_elements_by_selection(const bContext *C, static GeometryComponentType get_display_component_type(const bContext *C, Object *object_eval) { SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); - if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_FINAL) { + if (sspreadsheet->object_eval_state != SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) { return (GeometryComponentType)sspreadsheet->geometry_component_type; } if (object_eval->type == OB_POINTCLOUD) { diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 7b4788737f8..334d683deff 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -348,6 +348,8 @@ typedef struct bNode { * composite out nodes when editing tree */ #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) /* node->update */ /* XXX NODE_UPDATE is a generic update flag. More fine-grained updates diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 686cf2048eb..9822aa4f7e4 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -169,6 +169,11 @@ typedef struct Object_Runtime { struct GeometrySet *geometry_set_eval; /** + * Data from this geometry set is previewed in the spreadsheet editor. + */ + struct GeometrySet *geometry_set_preview; + + /** * Mesh structure created during object evaluation. * It has deformation only modifiers applied on it. */ diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 46e28c9282d..0ad66c63169 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -1889,6 +1889,7 @@ typedef enum eSpaceSpreadsheet_FilterFlag { typedef enum eSpaceSpreadsheet_ObjectEvalState { SPREADSHEET_OBJECT_EVAL_STATE_FINAL = 0, SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL = 1, + SPREADSHEET_OBJECT_EVAL_STATE_NODE = 2, } eSpaceSpreadsheet_Context; /* -------------------------------------------------------------------- */ diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index b6c0bce4342..3590b93620c 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -7365,6 +7365,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_NODE, + "NODE", + ICON_NONE, + "Node", + "Use data from the first geometry output of the node tagged for preview"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 843797e0f72..c7d822e5418 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -43,17 +43,22 @@ #include "DNA_pointcloud_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_windowmanager_types.h" #include "BKE_customdata.h" #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_lib_query.h" +#include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_modifier.h" #include "BKE_node_ui_storage.hh" +#include "BKE_object.h" #include "BKE_pointcloud.h" #include "BKE_screen.h" #include "BKE_simulation.h" +#include "BKE_workspace.h" #include "BLO_read_write.h" @@ -1088,6 +1093,110 @@ static void reset_tree_ui_storage(Span<const blender::nodes::NodeTreeRef *> tree } } +static const DTreeContext *find_derived_tree_context_that_matches_tree_path( + const SpaceNode &snode, const DerivedNodeTree &tree) +{ + const DTreeContext &root_context = tree.root_context(); + bNodeTree *root_tree_eval = root_context.tree().btree(); + bNodeTree *root_tree_orig = (bNodeTree *)DEG_get_original_id(&root_tree_eval->id); + if (snode.nodetree != root_tree_orig) { + return nullptr; + } + + const DTreeContext *current_context = &root_context; + bool is_first = true; + LISTBASE_FOREACH (const bNodeTreePath *, path, &snode.treepath) { + if (is_first) { + is_first = false; + continue; + } + StringRef parent_node_name = path->node_name; + const NodeTreeRef &tree_ref = current_context->tree(); + const NodeRef *parent_node_ref = nullptr; + for (const NodeRef *node_ref : tree_ref.nodes()) { + if (node_ref->name() == parent_node_name) { + parent_node_ref = node_ref; + break; + } + } + if (parent_node_ref == nullptr) { + return nullptr; + } + current_context = current_context->child_context(*parent_node_ref); + if (current_context == nullptr) { + return nullptr; + } + } + return current_context; +} + +static DNode find_active_preview_node_in_node_editor(const SpaceNode &snode, + const DerivedNodeTree &tree) +{ + const DTreeContext *context = find_derived_tree_context_that_matches_tree_path(snode, tree); + if (context == nullptr) { + return {}; + } + const NodeTreeRef &tree_ref = context->tree(); + for (const NodeRef *node_ref : tree_ref.nodes()) { + if (node_ref->bnode()->flag & NODE_ACTIVE_PREVIEW) { + return {context, node_ref}; + } + } + return {}; +} + +static DNode find_active_preview_node_in_all_node_editors(Depsgraph *depsgraph, + const DerivedNodeTree &tree) +{ + Main *bmain = DEG_get_bmain(depsgraph); + wmWindowManager *wm = (wmWindowManager *)bmain->wm.first; + 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; + DNode preview_node = find_active_preview_node_in_node_editor(*snode, tree); + if (!preview_node) { + continue; + } + return preview_node; + } + } + return {}; +} + +static DSocket find_preview_socket_in_all_node_editors(Depsgraph *depsgraph, + const DerivedNodeTree &tree) +{ + DNode preview_node = find_active_preview_node_in_all_node_editors(depsgraph, tree); + if (!preview_node) { + return {}; + } + for (const SocketRef *socket : preview_node->outputs()) { + if (socket->bsocket()->type == SOCK_GEOMETRY) { + return {preview_node.context(), socket}; + } + } + for (const SocketRef *socket : preview_node->inputs()) { + if (socket->bsocket()->type == SOCK_GEOMETRY && + (socket->bsocket()->flag & SOCK_MULTI_INPUT) == 0) { + return {preview_node.context(), socket}; + } + } + return {}; +} + +static void log_preview_socket_value(const Span<GPointer> values, Object *object) +{ + GeometrySet geometry_set = *(const GeometrySet *)values[0].get(); + geometry_set.ensure_owns_direct_data(); + BKE_object_set_preview_geometry_set(object, new GeometrySet(std::move(geometry_set))); +} + /** * Evaluate a node group to compute the output geometry. * Currently, this uses a fairly basic and inefficient algorithm that might compute things more @@ -1143,6 +1252,14 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, Vector<DInputSocket> group_outputs; group_outputs.append({root_context, &socket_to_compute}); + const DSocket preview_socket = find_preview_socket_in_all_node_editors(ctx->depsgraph, tree); + + auto log_socket_value = [&](const DSocket socket, const Span<GPointer> values) { + if (socket == preview_socket && nmd->modifier.flag & eModifierFlag_Active) { + log_preview_socket_value(values, ctx->object); + } + }; + GeometryNodesEvaluator evaluator{group_inputs, group_outputs, mf_by_node, @@ -1150,7 +1267,7 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, ctx->object, (ModifierData *)nmd, ctx->depsgraph, - {}}; + log_socket_value}; Vector<GMutablePointer> results = evaluator.execute(); BLI_assert(results.size() == 1); |