Changeset View
Changeset View
Standalone View
Standalone View
source/blender/modifiers/intern/MOD_nodes.cc
| Show All 23 Lines | |||||
| #include <cstring> | #include <cstring> | ||||
| #include <iostream> | #include <iostream> | ||||
| #include <string> | #include <string> | ||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "BLI_float3.hh" | #include "BLI_float3.hh" | ||||
| #include "BLI_listbase.h" | #include "BLI_listbase.h" | ||||
| #include "BLI_multi_value_map.hh" | |||||
| #include "BLI_set.hh" | #include "BLI_set.hh" | ||||
| #include "BLI_string.h" | #include "BLI_string.h" | ||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "DNA_collection_types.h" | #include "DNA_collection_types.h" | ||||
| #include "DNA_defaults.h" | #include "DNA_defaults.h" | ||||
| #include "DNA_mesh_types.h" | #include "DNA_mesh_types.h" | ||||
| #include "DNA_meshdata_types.h" | #include "DNA_meshdata_types.h" | ||||
| Show All 31 Lines | |||||
| #include "DEG_depsgraph_build.h" | #include "DEG_depsgraph_build.h" | ||||
| #include "DEG_depsgraph_query.h" | #include "DEG_depsgraph_query.h" | ||||
| #include "MOD_modifiertypes.h" | #include "MOD_modifiertypes.h" | ||||
| #include "MOD_nodes.h" | #include "MOD_nodes.h" | ||||
| #include "MOD_ui_common.h" | #include "MOD_ui_common.h" | ||||
| #include "ED_spreadsheet.h" | |||||
| #include "NOD_derived_node_tree.hh" | #include "NOD_derived_node_tree.hh" | ||||
| #include "NOD_geometry.h" | #include "NOD_geometry.h" | ||||
| #include "NOD_geometry_exec.hh" | #include "NOD_geometry_exec.hh" | ||||
| #include "NOD_node_tree_multi_function.hh" | #include "NOD_node_tree_multi_function.hh" | ||||
| #include "NOD_type_callbacks.hh" | #include "NOD_type_callbacks.hh" | ||||
| using blender::float3; | using blender::float3; | ||||
| using blender::FunctionRef; | using blender::FunctionRef; | ||||
| ▲ Show 20 Lines • Show All 1,009 Lines • ▼ Show 20 Lines | static void reset_tree_ui_storage(Span<const blender::nodes::NodeTreeRef *> trees, | ||||
| for (const blender::nodes::NodeTreeRef *tree : trees) { | for (const blender::nodes::NodeTreeRef *tree : trees) { | ||||
| bNodeTree *btree_cow = tree->btree(); | bNodeTree *btree_cow = tree->btree(); | ||||
| bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow); | bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow); | ||||
| BKE_nodetree_ui_storage_free_for_context(*btree_original, context); | BKE_nodetree_ui_storage_free_for_context(*btree_original, context); | ||||
| } | } | ||||
| } | } | ||||
| static const DTreeContext *find_derived_tree_context_that_matches_tree_path( | static Vector<SpaceSpreadsheet *> find_spreadsheet_editors(Main *bmain) | ||||
| const SpaceNode &snode, const DerivedNodeTree &tree) | |||||
| { | { | ||||
| const DTreeContext &root_context = tree.root_context(); | Vector<SpaceSpreadsheet *> spreadsheets; | ||||
| bNodeTree *root_tree_eval = root_context.tree().btree(); | wmWindowManager *wm = (wmWindowManager *)bmain->wm.first; | ||||
| bNodeTree *root_tree_orig = (bNodeTree *)DEG_get_original_id(&root_tree_eval->id); | LISTBASE_FOREACH (wmWindow *, window, &wm->windows) { | ||||
| if (snode.nodetree != root_tree_orig) { | bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook); | ||||
| return nullptr; | LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { | ||||
| SpaceLink *sl = (SpaceLink *)area->spacedata.first; | |||||
| if (sl->spacetype == SPACE_SPREADSHEET) { | |||||
| spreadsheets.append((SpaceSpreadsheet *)sl); | |||||
| } | } | ||||
| 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; | |||||
| } | } | ||||
| return spreadsheets; | |||||
| } | } | ||||
| if (parent_node_ref == nullptr) { | |||||
| return nullptr; | 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}; | |||||
| } | } | ||||
| current_context = current_context->child_context(*parent_node_ref); | |||||
| if (current_context == nullptr) { | |||||
| return nullptr; | |||||
| } | } | ||||
| for (const SocketRef *socket : node->inputs()) { | |||||
| if (socket->bsocket()->type == SOCK_GEOMETRY && | |||||
| (socket->bsocket()->flag & SOCK_MULTI_INPUT) == 0) { | |||||
| return {node.context(), socket}; | |||||
| } | } | ||||
| return current_context; | } | ||||
| return {}; | |||||
| } | } | ||||
| static DNode find_active_preview_node_in_node_editor(const SpaceNode &snode, | static DSocket try_get_socket_to_preview_for_spreadsheet(SpaceSpreadsheet *sspreadsheet, | ||||
| NodesModifierData *nmd, | |||||
| const ModifierEvalContext *ctx, | |||||
| const DerivedNodeTree &tree) | const DerivedNodeTree &tree) | ||||
| { | { | ||||
| const DTreeContext *context = find_derived_tree_context_that_matches_tree_path(snode, tree); | Vector<SpreadsheetContext *> context_path = sspreadsheet->context_path; | ||||
| if (context == nullptr) { | if (context_path.size() < 3) { | ||||
| return {}; | return {}; | ||||
| } | } | ||||
| const NodeTreeRef &tree_ref = context->tree(); | if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) { | ||||
| for (const NodeRef *node_ref : tree_ref.nodes()) { | return {}; | ||||
| if (node_ref->bnode()->flag & NODE_ACTIVE_PREVIEW) { | |||||
| return {context, node_ref}; | |||||
| } | } | ||||
| if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) { | |||||
| return {}; | |||||
| } | } | ||||
| SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context_path[0]; | |||||
| if (object_context->object != DEG_get_original_object(ctx->object)) { | |||||
| return {}; | return {}; | ||||
| } | } | ||||
| SpreadsheetContextModifier *modifier_context = (SpreadsheetContextModifier *)context_path[1]; | |||||
| static DNode find_active_preview_node_in_all_node_editors(Depsgraph *depsgraph, | if (StringRef(modifier_context->modifier_name) != nmd->modifier.name) { | ||||
| const DerivedNodeTree &tree) | return {}; | ||||
| { | |||||
| 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; | for (SpreadsheetContext *context : context_path.as_span().drop_front(2)) { | ||||
| DNode preview_node = find_active_preview_node_in_node_editor(*snode, tree); | if (context->type != SPREADSHEET_CONTEXT_NODE) { | ||||
| if (!preview_node) { | return {}; | ||||
| continue; | |||||
| } | } | ||||
| return preview_node; | |||||
| } | } | ||||
| Span<SpreadsheetContextNode *> nested_group_contexts = | |||||
| context_path.as_span().drop_front(2).drop_back(1).cast<SpreadsheetContextNode *>(); | |||||
| SpreadsheetContextNode *last_context = (SpreadsheetContextNode *)context_path.last(); | |||||
| const DTreeContext *context = &tree.root_context(); | |||||
| for (SpreadsheetContextNode *node_context : nested_group_contexts) { | |||||
| const NodeTreeRef &tree_ref = context->tree(); | |||||
| const NodeRef *found_node = nullptr; | |||||
| for (const NodeRef *node_ref : tree_ref.nodes()) { | |||||
| if (node_ref->name() == node_context->node_name) { | |||||
| found_node = node_ref; | |||||
| break; | |||||
| } | } | ||||
| return {}; | |||||
| } | } | ||||
| if (found_node == nullptr) { | |||||
| 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 {}; | return {}; | ||||
| } | } | ||||
| for (const SocketRef *socket : preview_node->outputs()) { | context = context->child_context(*found_node); | ||||
| if (socket->bsocket()->type == SOCK_GEOMETRY) { | if (context == nullptr) { | ||||
| return {preview_node.context(), socket}; | return {}; | ||||
| } | } | ||||
| } | } | ||||
| for (const SocketRef *socket : preview_node->inputs()) { | |||||
| if (socket->bsocket()->type == SOCK_GEOMETRY && | const NodeTreeRef &tree_ref = context->tree(); | ||||
| (socket->bsocket()->flag & SOCK_MULTI_INPUT) == 0) { | for (const NodeRef *node_ref : tree_ref.nodes()) { | ||||
| return {preview_node.context(), socket}; | if (node_ref->name() == last_context->node_name) { | ||||
| return try_find_preview_socket_in_node({context, node_ref}); | |||||
| } | } | ||||
| } | } | ||||
| return {}; | return {}; | ||||
| } | } | ||||
| static void log_preview_socket_value(const Span<GPointer> values, Object *object) | static void find_sockets_to_preview(NodesModifierData *nmd, | ||||
| const ModifierEvalContext *ctx, | |||||
| const DerivedNodeTree &tree, | |||||
| PreviewSocketMap &r_sockets_to_preview) | |||||
HooglyBoogly: Once I figured this out I saw that this section of the code is actually quite elegant. The… | |||||
| { | |||||
| Main *bmain = DEG_get_bmain(ctx->depsgraph); | |||||
| /* Based on every visible spreadsheet context path, get a list of sockets that need to have their | |||||
| * intermediate geometries cached for display. */ | |||||
| Vector<SpaceSpreadsheet *> spreadsheets = find_spreadsheet_editors(bmain); | |||||
| for (SpaceSpreadsheet *sspreadsheet : spreadsheets) { | |||||
| const DSocket socket = try_get_socket_to_preview_for_spreadsheet(sspreadsheet, nmd, ctx, tree); | |||||
| if (socket) { | |||||
| const uint64_t key = ED_spreadsheet_context_path_hash(sspreadsheet); | |||||
| r_sockets_to_preview.add_non_duplicates(socket, key); | |||||
| } | |||||
| } | |||||
| } | |||||
| static void log_preview_socket_value(const Span<GPointer> values, | |||||
| Object *object, | |||||
| Span<uint64_t> keys) | |||||
| { | { | ||||
| GeometrySet geometry_set = *(const GeometrySet *)values[0].get(); | GeometrySet geometry_set = *(const GeometrySet *)values[0].get(); | ||||
| geometry_set.ensure_owns_direct_data(); | geometry_set.ensure_owns_direct_data(); | ||||
| BKE_object_set_preview_geometry_set(object, new GeometrySet(std::move(geometry_set))); | for (uint64_t key : keys) { | ||||
| BKE_object_preview_geometry_set_add(object, key, new GeometrySet(geometry_set)); | |||||
| } | |||||
| } | } | ||||
| /** | /** | ||||
| * Evaluate a node group to compute the output geometry. | * Evaluate a node group to compute the output geometry. | ||||
| * Currently, this uses a fairly basic and inefficient algorithm that might compute things more | * Currently, this uses a fairly basic and inefficient algorithm that might compute things more | ||||
| * often than necessary. It's going to be replaced soon. | * often than necessary. It's going to be replaced soon. | ||||
| */ | */ | ||||
| static GeometrySet compute_geometry(const DerivedNodeTree &tree, | static GeometrySet compute_geometry(const DerivedNodeTree &tree, | ||||
| ▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | static GeometrySet compute_geometry(const DerivedNodeTree &tree, | ||||
| } | } | ||||
| /* Don't keep a reference to the input geometry components to avoid copies during evaluation. */ | /* Don't keep a reference to the input geometry components to avoid copies during evaluation. */ | ||||
| input_geometry_set.clear(); | input_geometry_set.clear(); | ||||
| Vector<DInputSocket> group_outputs; | Vector<DInputSocket> group_outputs; | ||||
| group_outputs.append({root_context, &socket_to_compute}); | group_outputs.append({root_context, &socket_to_compute}); | ||||
| const DSocket preview_socket = find_preview_socket_in_all_node_editors(ctx->depsgraph, tree); | PreviewSocketMap preview_sockets; | ||||
| find_sockets_to_preview(nmd, ctx, tree, preview_sockets); | |||||
| auto log_socket_value = [&](const DSocket socket, const Span<GPointer> values) { | auto log_socket_value = [&](const DSocket socket, const Span<GPointer> values) { | ||||
| if (socket == preview_socket && nmd->modifier.flag & eModifierFlag_Active) { | if (!DEG_is_active(ctx->depsgraph)) { | ||||
| log_preview_socket_value(values, ctx->object); | return; | ||||
| } | |||||
| Span<uint64_t> keys = preview_sockets.lookup(socket); | |||||
| if (!keys.is_empty()) { | |||||
| log_preview_socket_value(values, ctx->object, keys); | |||||
| } | } | ||||
| }; | }; | ||||
| GeometryNodesEvaluator evaluator{group_inputs, | GeometryNodesEvaluator evaluator{group_inputs, | ||||
| group_outputs, | group_outputs, | ||||
| mf_by_node, | mf_by_node, | ||||
| handle_map, | handle_map, | ||||
| ctx->object, | ctx->object, | ||||
| ▲ Show 20 Lines • Show All 305 Lines • Show Last 20 Lines | |||||
Once I figured this out I saw that this section of the code is actually quite elegant. The explicit typing combined with the way it's broken up-- well done.
However, it would have been a bit faster to figure out with a sentence or two of prose to offer a different perspective than the code. I don't think that's just me, at least I hope not.
Suggest:
Or something like that anyway. Maybe the important thing to realize is that it is not based on any of the flags in the nodes themselves, it's only based on the spreadsheets.