Blender V4.3
geometry_nodes_gizmos.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
7
9#include "BKE_context.hh"
10#include "BKE_modifier.hh"
11#include "BKE_node.hh"
12#include "BKE_node_runtime.hh"
14#include "BKE_object.hh"
15#include "BKE_workspace.hh"
16
20
21#include "DNA_modifier_types.h"
22#include "DNA_space_types.h"
24
25#include "ED_node.hh"
26
27namespace blender::nodes::gizmos {
28
30{
31 return ELEM(node.type, GEO_NODE_GIZMO_LINEAR, GEO_NODE_GIZMO_DIAL, GEO_NODE_GIZMO_TRANSFORM);
32}
33
37static ie::ElemVariant get_gizmo_socket_elem(const bNode &node, const bNodeSocket &socket)
38{
39 switch (node.type) {
41 return {ie::FloatElem::all()};
42 }
44 return {ie::FloatElem::all()};
45 }
47 const auto &storage = *static_cast<const NodeGeometryTransformGizmo *>(node.storage);
48 ie::MatrixElem elem;
50 elem.translation = ie::VectorElem::all();
51 }
52 if (storage.flag &
54 {
55 elem.rotation = ie::RotationElem::all();
56 elem.scale = ie::VectorElem::all();
57 }
58 return {elem};
59 }
60 }
61 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(socket.type);
62 if (std::optional<ie::ElemVariant> elem = ie::get_elem_variant_for_socket_type(socket_type)) {
63 elem->set_all();
64 return *elem;
65 }
67 return {};
68}
69
71{
72 BLI_assert(!tree.has_available_link_cycle());
73
74 TreeGizmoPropagation gizmo_propagation;
75
76 struct GizmoInput {
77 const bNodeSocket *gizmo_socket;
78 /* For multi-input sockets we start propagation at the origin socket. */
79 const bNodeSocket *propagation_start_socket;
80 ie::ElemVariant elem;
81 };
82
83 /* Gather all gizmo inputs so that we can find their inverse evaluation targets afterwards. */
84 Vector<GizmoInput> all_gizmo_inputs;
85 for (const bNode *node : tree.all_nodes()) {
86 if (node->is_muted()) {
87 continue;
88 }
89 if (node->is_group()) {
90 if (!node->id) {
91 continue;
92 }
93 const bNodeTree &group = *reinterpret_cast<const bNodeTree *>(node->id);
94 if (!group.runtime->gizmo_propagation) {
95 continue;
96 }
97 const TreeGizmoPropagation &group_gizmo_propagation = *group.runtime->gizmo_propagation;
98 for (const ie::GroupInputElem &group_input_elem :
99 group_gizmo_propagation.gizmo_inputs_by_group_inputs.keys())
100 {
101 const bNodeSocket &input_socket = node->input_socket(group_input_elem.group_input_index);
102 all_gizmo_inputs.append({&input_socket, &input_socket, group_input_elem.elem});
103 }
104 }
105 if (is_builtin_gizmo_node(*node)) {
106 gizmo_propagation.gizmo_nodes.append(node);
107 const bNodeSocket &gizmo_input_socket = node->input_socket(0);
108 gizmo_propagation.gizmo_endpoint_sockets.add(&gizmo_input_socket);
109 const ie::ElemVariant elem = get_gizmo_socket_elem(*node, gizmo_input_socket);
110 for (const bNodeLink *link : gizmo_input_socket.directly_linked_links()) {
111 if (!link->is_used()) {
112 continue;
113 }
114 all_gizmo_inputs.append({&gizmo_input_socket, link->fromsock, elem});
115 }
116 }
117 }
118
119 /* Find the local gizmo targets for all gizmo inputs. */
120 for (const GizmoInput &gizmo_input : all_gizmo_inputs) {
121 gizmo_propagation.gizmo_endpoint_sockets.add(gizmo_input.gizmo_socket);
122 const ie::SocketElem gizmo_input_socket_elem{gizmo_input.gizmo_socket, gizmo_input.elem};
123 /* The conversion is necessary when e.g. connecting a Rotation directly to the matrix input of
124 * the Transform Gizmo node. */
125 const std::optional<ie::ElemVariant> converted_elem = ie::convert_socket_elem(
126 *gizmo_input.gizmo_socket, *gizmo_input.propagation_start_socket, gizmo_input.elem);
127 if (!converted_elem) {
128 continue;
129 }
131 tree, {gizmo_input.propagation_start_socket, *converted_elem});
132 const bool has_target = !targets.input_sockets.is_empty() ||
133 !targets.group_inputs.is_empty() || !targets.value_nodes.is_empty();
134 if (!has_target) {
135 continue;
136 }
137 /* Remember all the gizmo targets for quick lookup later on. */
138 for (const ie::SocketElem &input_socket : targets.input_sockets) {
139 gizmo_propagation.gizmo_inputs_by_node_inputs.add(input_socket, gizmo_input_socket_elem);
140 gizmo_propagation.gizmo_endpoint_sockets.add(input_socket.socket);
141 }
142 for (const ie::ValueNodeElem &value_node : targets.value_nodes) {
143 gizmo_propagation.gizmo_inputs_by_value_nodes.add(value_node, gizmo_input_socket_elem);
144 gizmo_propagation.gizmo_endpoint_sockets.add(&value_node.node->output_socket(0));
145 }
146 for (const ie::GroupInputElem &group_input : targets.group_inputs) {
147 gizmo_propagation.gizmo_inputs_by_group_inputs.add(group_input, gizmo_input_socket_elem);
148 for (const bNode *group_input_node : tree.group_input_nodes()) {
149 gizmo_propagation.gizmo_endpoint_sockets.add(
150 &group_input_node->output_socket(group_input.group_input_index));
151 }
152 }
153 }
154
155 return gizmo_propagation;
156}
157
159{
160 tree.ensure_topology_cache();
161
162 if (tree.has_available_link_cycle()) {
163 const bool changed = tree.runtime->gizmo_propagation.get() != nullptr;
164 tree.runtime->gizmo_propagation.reset();
165 return changed;
166 }
167
169 const bool changed = tree.runtime->gizmo_propagation ?
170 *tree.runtime->gizmo_propagation != new_gizmo_propagation :
171 true;
172 tree.runtime->gizmo_propagation = std::make_unique<TreeGizmoPropagation>(
173 std::move(new_gizmo_propagation));
174 return changed;
175}
176
177static void foreach_gizmo_for_input(const ie::SocketElem &input_socket,
178 ComputeContextBuilder &compute_context_builder,
179 const bNodeTree &tree,
180 const ForeachGizmoInModifierFn fn);
181
183 const ie::GroupInputElem &group_input,
184 ComputeContextBuilder &compute_context_builder,
186{
187 const TreeGizmoPropagation &gizmo_propagation = *tree.runtime->gizmo_propagation;
188 for (const ie::SocketElem &gizmo_input :
189 gizmo_propagation.gizmo_inputs_by_group_inputs.lookup(group_input))
190 {
191 foreach_gizmo_for_input(gizmo_input, compute_context_builder, tree, fn);
192 }
193}
194
195static void foreach_gizmo_for_input(const ie::SocketElem &input_socket,
196 ComputeContextBuilder &compute_context_builder,
197 const bNodeTree &tree,
199{
200 const bke::bNodeTreeZones *zones = tree.zones();
201 if (!zones) {
202 /* There are invalid zones. */
203 return;
204 }
205 const bNode &node = input_socket.socket->owner_node();
206 if (zones->get_zone_by_node(node.identifier) != nullptr) {
207 /* Gizmos in zones are not supported yet. */
208 return;
209 }
210 if (is_builtin_gizmo_node(node)) {
211 if (node.is_muted()) {
212 return;
213 }
214 /* Found an actual built-in gizmo node. */
215 fn(*compute_context_builder.current(), node, *input_socket.socket);
216 return;
217 }
218 if (node.is_group()) {
219 const bNodeTree &group = *reinterpret_cast<const bNodeTree *>(node.id);
220 group.ensure_topology_cache();
221 compute_context_builder.push<bke::GroupNodeComputeContext>(node, tree);
223 group,
224 ie::GroupInputElem{input_socket.socket->index(), input_socket.elem},
225 compute_context_builder,
226 fn);
227 compute_context_builder.pop();
228 }
229}
230
232 const SpaceNode &snode,
233 const Object *object_filter,
234 const NodesModifierData *nmd_filter,
235 ComputeContextBuilder &compute_context_builder,
236 const ForeachGizmoFn fn)
237{
238 if (snode.nodetree == nullptr) {
239 return;
240 }
241 if (snode.edittree == nullptr || !snode.edittree->runtime->gizmo_propagation) {
242 return;
243 }
244 const std::optional<ed::space_node::ObjectAndModifier> object_and_modifier =
246 if (!object_and_modifier) {
247 return;
248 }
249 if (object_filter) {
250 if (object_and_modifier->object != object_filter) {
251 return;
252 }
253 }
254 if (nmd_filter) {
255 if (object_and_modifier->nmd != nmd_filter) {
256 return;
257 }
258 }
259
260 const Object &object = *object_and_modifier->object;
261 const NodesModifierData &nmd = *object_and_modifier->nmd;
262
263 if (!(nmd.modifier.mode & eModifierMode_Realtime)) {
264 /* Disabled modifiers can't have gizmos currently. */
265 return;
266 }
267
268 const ComputeContext *prev_compute_context = compute_context_builder.current();
269 compute_context_builder.push<bke::ModifierComputeContext>(nmd.modifier.name);
270 BLI_SCOPED_DEFER([&]() { compute_context_builder.pop_until(prev_compute_context); });
271
272 if (!ed::space_node::push_compute_context_for_tree_path(snode, compute_context_builder)) {
273 return;
274 }
275 snode.edittree->ensure_topology_cache();
276 const TreeGizmoPropagation &gizmo_propagation = *snode.edittree->runtime->gizmo_propagation;
277 Set<ie::SocketElem> used_gizmo_inputs;
278
279 /* Check gizmos on value nodes. */
280 for (auto &&item : gizmo_propagation.gizmo_inputs_by_value_nodes.items()) {
281 const bNode &node = *item.key.node;
282 const bNodeSocket &output_socket = node.output_socket(0);
283 if ((node.flag & NODE_SELECT) || (output_socket.flag & SOCK_GIZMO_PIN)) {
284 used_gizmo_inputs.add_multiple(item.value);
285 continue;
286 }
287 for (const ie::SocketElem &socket_elem : item.value) {
288 if (socket_elem.socket->owner_node().flag & NODE_SELECT) {
289 used_gizmo_inputs.add(socket_elem);
290 }
291 }
292 }
293 /* Check gizmos on input sockets. */
294 for (auto &&item : gizmo_propagation.gizmo_inputs_by_node_inputs.items()) {
295 const bNodeSocket &socket = *item.key.socket;
296 const bNode &node = socket.owner_node();
297 if ((node.flag & NODE_SELECT) || (socket.flag & SOCK_GIZMO_PIN)) {
298 used_gizmo_inputs.add_multiple(item.value);
299 continue;
300 }
301 for (const ie::SocketElem &socket_elem : item.value) {
302 if (socket_elem.socket->owner_node().flag & NODE_SELECT) {
303 used_gizmo_inputs.add(socket_elem);
304 }
305 }
306 }
307 /* Check built-in gizmo nodes. */
308 for (const bNode *gizmo_node : gizmo_propagation.gizmo_nodes) {
309 if (gizmo_node->is_muted()) {
310 continue;
311 }
312 const bNodeSocket &gizmo_input_socket = gizmo_node->input_socket(0);
313 if ((gizmo_node->flag & NODE_SELECT) || (gizmo_input_socket.flag & SOCK_GIZMO_PIN)) {
314 used_gizmo_inputs.add(
315 {&gizmo_input_socket,
317 }
318 }
319 for (const ie::SocketElem &gizmo_input : used_gizmo_inputs) {
320 foreach_gizmo_for_input(gizmo_input,
321 compute_context_builder,
322 *snode.edittree,
323 [&](const ComputeContext &compute_context,
324 const bNode &gizmo_node,
325 const bNodeSocket &gizmo_socket) {
326 fn(object, nmd, compute_context, gizmo_node, gizmo_socket);
327 });
328 }
329}
330
332 const Object *object_filter,
333 const NodesModifierData *nmd_filter,
334 ComputeContextBuilder &compute_context_builder,
335 const ForeachGizmoFn fn)
336{
337 LISTBASE_FOREACH (const wmWindow *, window, &wm.windows) {
338 const bScreen *active_screen = BKE_workspace_active_screen_get(window->workspace_hook);
339 Vector<const bScreen *> screens = {active_screen};
340 if (ELEM(active_screen->state, SCREENMAXIMIZED, SCREENFULL)) {
341 const ScrArea *area = static_cast<const ScrArea *>(active_screen->areabase.first);
342 screens.append(area->full);
343 }
344 for (const bScreen *screen : screens) {
345 LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
346 const SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
347 if (sl == nullptr) {
348 continue;
349 }
350 if (sl->spacetype != SPACE_NODE) {
351 continue;
352 }
353 const SpaceNode &snode = *reinterpret_cast<const SpaceNode *>(sl);
355 snode, object_filter, nmd_filter, compute_context_builder, fn);
356 }
357 }
358 }
359}
360
362 const NodesModifierData &nmd,
363 ComputeContextBuilder &compute_context_builder,
365{
366 if (!nmd.node_group) {
367 return;
368 }
369 const bNodeTree &tree = *nmd.node_group;
370 if (!tree.runtime->gizmo_propagation) {
371 return;
372 }
373 compute_context_builder.push<bke::ModifierComputeContext>(nmd.modifier.name);
374 BLI_SCOPED_DEFER([&]() { compute_context_builder.pop(); });
375
376 for (auto &&item : tree.runtime->gizmo_propagation->gizmo_inputs_by_group_inputs.items()) {
377 for (const ie::SocketElem &socket_elem : item.value) {
378 foreach_gizmo_for_input(socket_elem, compute_context_builder, tree, fn);
379 }
380 }
381}
382
384 const NodesModifierData &nmd,
385 const wmWindowManager &wm,
386 ComputeContextBuilder &compute_context_builder,
388{
389 if (!nmd.node_group) {
390 return;
391 }
392
394 &object,
395 &nmd,
396 compute_context_builder,
397 [&](const Object &object_with_gizmo,
398 const NodesModifierData &nmd_with_gizmo,
399 const ComputeContext &compute_context,
400 const bNode &gizmo_node,
401 const bNodeSocket &gizmo_socket) {
402 BLI_assert(&object == &object_with_gizmo);
403 BLI_assert(&nmd == &nmd_with_gizmo);
404 UNUSED_VARS_NDEBUG(object_with_gizmo, nmd_with_gizmo);
405 fn(compute_context, gizmo_node, gizmo_socket);
406 });
407
408 foreach_active_gizmo_exposed_to_modifier(nmd, compute_context_builder, fn);
409}
410
412 ComputeContextBuilder &compute_context_builder,
413 const ForeachGizmoFn fn)
414{
415 const wmWindowManager *wm = CTX_wm_manager(&C);
416 if (!wm) {
417 return;
418 }
419 foreach_active_gizmo_in_open_editors(*wm, nullptr, nullptr, compute_context_builder, fn);
420
421 if (const Base *active_base = CTX_data_active_base(&C)) {
422 if (!(active_base->flag & BASE_SELECTED)) {
423 return;
424 }
425 Object *active_object = active_base->object;
426
427 if (const ModifierData *md = BKE_object_active_modifier(active_object)) {
428 if (!(md->mode & eModifierMode_Realtime)) {
429 return;
430 }
431 if (md->type == eModifierType_Nodes) {
432 const NodesModifierData &nmd = *reinterpret_cast<const NodesModifierData *>(md);
434 nmd,
435 compute_context_builder,
436 [&](const ComputeContext &compute_context,
437 const bNode &gizmo_node,
438 const bNodeSocket &gizmo_socket) {
439 fn(*active_object, nmd, compute_context, gizmo_node, gizmo_socket);
440 });
441 }
442 }
443 }
444}
445
447 const bNode &gizmo_node,
448 const bNodeSocket &gizmo_socket,
449 FunctionRef<void(const ComputeContext &context)> fn)
450{
452 gizmo_context, {&gizmo_socket, get_gizmo_socket_elem(gizmo_node, gizmo_socket)}, fn, {});
453}
454
456 const ComputeContext &gizmo_context,
457 const bNode &gizmo_node,
458 const bNodeSocket &gizmo_socket,
459 FunctionRef<void(
460 const ComputeContext &context, const bNodeSocket &socket, const ie::ElemVariant &elem)> fn)
461{
463 gizmo_context, {&gizmo_socket, get_gizmo_socket_elem(gizmo_node, gizmo_socket)}, {}, fn);
464}
465
467 const bNode &gizmo_node,
468 const bNodeSocket &gizmo_socket)
469{
470 std::optional<ie::ElemVariant> found_elem = ie::get_elem_variant_for_socket_type(
471 eNodeSocketDatatype(gizmo_socket.type));
472 BLI_assert(found_elem.has_value());
473
475 gizmo_context,
476 {&gizmo_socket, get_gizmo_socket_elem(gizmo_node, gizmo_socket)},
477 {},
478 [&](const ComputeContext &context, const bNodeSocket &socket, const ie::ElemVariant &elem) {
479 if (context.hash() == gizmo_context.hash() && &socket == &gizmo_socket) {
480 found_elem->merge(elem);
481 }
482 });
483
484 return *found_elem;
485}
486
488 bContext &C,
489 Object &object,
492 const ComputeContext &gizmo_context,
493 const bNodeSocket &gizmo_socket,
494 const FunctionRef<void(bke::SocketValueVariant &value)> apply_on_gizmo_value_fn)
495{
496 Vector<ie::SocketToUpdate> sockets_to_update;
497
498 const bNodeTree &gizmo_node_tree = gizmo_socket.owner_tree();
499 geo_eval_log::GeoTreeLog &gizmo_tree_log = eval_log.get_tree_log(gizmo_context.hash());
500
501 /* Gather all sockets to update together with their new values. */
502 for (const bNodeLink *link : gizmo_socket.directly_linked_links()) {
503 gizmo_node_tree.ensure_topology_cache();
504 if (!link->is_used()) {
505 continue;
506 }
507 if (link->fromnode->is_dangling_reroute()) {
508 continue;
509 }
510 const std::optional<bke::SocketValueVariant> old_value = ie::get_logged_socket_value(
511 gizmo_tree_log, *link->fromsock);
512 if (!old_value) {
513 continue;
514 }
515 const std::optional<bke::SocketValueVariant> old_value_converted =
516 ie::convert_single_socket_value(*link->fromsock, *link->tosock, *old_value);
517 if (!old_value_converted) {
518 continue;
519 }
520 bke::SocketValueVariant new_value = *old_value_converted;
521 apply_on_gizmo_value_fn(new_value);
522
523 sockets_to_update.append({&gizmo_context, &gizmo_socket, link, new_value});
524 }
525
526 /* Actually backpropagate the socket values. */
527 ie::backpropagate_socket_values(C, object, nmd, eval_log, sockets_to_update);
528}
529
530} // namespace blender::nodes::gizmos
Base * CTX_data_active_base(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
#define GEO_NODE_GIZMO_LINEAR
Definition BKE_node.hh:1371
#define GEO_NODE_GIZMO_DIAL
Definition BKE_node.hh:1372
#define GEO_NODE_GIZMO_TRANSFORM
Definition BKE_node.hh:1373
General operations, lookup, etc. for blender objects.
ModifierData * BKE_object_active_modifier(const Object *ob)
bScreen * BKE_workspace_active_screen_get(const WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition workspace.cc:613
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH(type, var, list)
#define BLI_SCOPED_DEFER(function_to_defer)
#define UNUSED_VARS_NDEBUG(...)
#define ELEM(...)
@ eModifierMode_Realtime
@ eModifierType_Nodes
@ NODE_SELECT
#define GEO_NODE_TRANSFORM_GIZMO_USE_ROTATION_ALL
#define GEO_NODE_TRANSFORM_GIZMO_USE_TRANSLATION_ALL
@ SOCK_GIZMO_PIN
eNodeSocketDatatype
#define GEO_NODE_TRANSFORM_GIZMO_USE_SCALE_ALL
#define BASE_SELECTED(v3d, base)
@ SCREENFULL
@ SCREENMAXIMIZED
@ SPACE_NODE
void pop_until(const ComputeContext *context)
const ComputeContext * current() const
const ComputeContextHash & hash() const
bool add(const Key &key)
Definition BLI_set.hh:248
void add_multiple(Span< Key > keys)
Definition BLI_set.hh:268
void append(const T &value)
const bNodeTreeZone * get_zone_by_node(const int32_t node_id) const
Vector< std::unique_ptr< bNodeTreeZone > > zones
GeoTreeLog & get_tree_log(const ComputeContextHash &compute_context_hash)
OperationNode * node
KDTree_3d * tree
bool push_compute_context_for_tree_path(const SpaceNode &snode, ComputeContextBuilder &compute_context_builder)
std::optional< ObjectAndModifier > get_modifier_for_node_editor(const SpaceNode &snode)
static void foreach_active_gizmo_in_open_editors(const wmWindowManager &wm, const Object *object_filter, const NodesModifierData *nmd_filter, ComputeContextBuilder &compute_context_builder, const ForeachGizmoFn fn)
void foreach_active_gizmo(const bContext &C, ComputeContextBuilder &compute_context_builder, const ForeachGizmoFn fn)
static void foreach_active_gizmo_exposed_to_modifier(const NodesModifierData &nmd, ComputeContextBuilder &compute_context_builder, const ForeachGizmoInModifierFn fn)
void apply_gizmo_change(bContext &C, Object &object, NodesModifierData &nmd, geo_eval_log::GeoModifierLog &eval_log, const ComputeContext &gizmo_context, const bNodeSocket &gizmo_socket, const FunctionRef< void(bke::SocketValueVariant &value)> apply_on_gizmo_value_fn)
bool update_tree_gizmo_propagation(bNodeTree &tree)
bool is_builtin_gizmo_node(const bNode &node)
ie::ElemVariant get_editable_gizmo_elem(const ComputeContext &gizmo_context, const bNode &gizmo_node, const bNodeSocket &gizmo_socket)
void foreach_socket_on_gizmo_path(const ComputeContext &gizmo_context, const bNode &gizmo_node, const bNodeSocket &gizmo_socket, FunctionRef< void(const ComputeContext &context, const bNodeSocket &socket, const ie::ElemVariant &elem)> fn)
static ie::ElemVariant get_gizmo_socket_elem(const bNode &node, const bNodeSocket &socket)
static TreeGizmoPropagation build_tree_gizmo_propagation(bNodeTree &tree)
static void foreach_gizmo_for_group_input(const bNodeTree &tree, const ie::GroupInputElem &group_input, ComputeContextBuilder &compute_context_builder, const ForeachGizmoInModifierFn fn)
void foreach_active_gizmo_in_modifier(const Object &object, const NodesModifierData &nmd, const wmWindowManager &wm, ComputeContextBuilder &compute_context_builder, const ForeachGizmoInModifierFn fn)
void foreach_compute_context_on_gizmo_path(const ComputeContext &gizmo_context, const bNode &gizmo_node, const bNodeSocket &gizmo_socket, FunctionRef< void(const ComputeContext &context)> fn)
FunctionRef< void(const ComputeContext &compute_context, const bNode &gizmo_node, const bNodeSocket &gizmo_socket)> ForeachGizmoInModifierFn
static void foreach_active_gizmo_in_open_node_editor(const SpaceNode &snode, const Object *object_filter, const NodesModifierData *nmd_filter, ComputeContextBuilder &compute_context_builder, const ForeachGizmoFn fn)
static void foreach_gizmo_for_input(const ie::SocketElem &input_socket, ComputeContextBuilder &compute_context_builder, const bNodeTree &tree, const ForeachGizmoInModifierFn fn)
bool backpropagate_socket_values(bContext &C, Object &object, NodesModifierData &nmd, geo_eval_log::GeoModifierLog &eval_log, const Span< SocketToUpdate > sockets_to_update)
LocalInverseEvalTargets find_local_inverse_eval_targets(const bNodeTree &tree, const SocketElem &initial_socket_elem)
void foreach_element_on_inverse_eval_path(const ComputeContext &initial_context, const SocketElem &initial_socket_elem, FunctionRef< void(const ComputeContext &context)> foreach_context_fn, FunctionRef< void(const ComputeContext &context, const bNodeSocket &socket, const ElemVariant &elem)> foreach_socket_fn)
std::optional< SocketValueVariant > get_logged_socket_value(geo_eval_log::GeoTreeLog &tree_log, const bNodeSocket &socket)
std::optional< SocketValueVariant > convert_single_socket_value(const bNodeSocket &old_socket, const bNodeSocket &new_socket, const SocketValueVariant &old_value)
std::optional< ElemVariant > get_elem_variant_for_socket_type(const eNodeSocketDatatype type)
Definition value_elem.cc:9
std::optional< ElemVariant > convert_socket_elem(const bNodeSocket &old_socket, const bNodeSocket &new_socket, const ElemVariant &old_elem)
Definition value_elem.cc:29
void * first
struct bNodeTree * node_group
struct bNodeTree * edittree
struct bNodeTree * nodetree
bNodeTreeRuntimeHandle * runtime
ListBase areabase
MultiValueMap< ie::SocketElem, ie::SocketElem > gizmo_inputs_by_node_inputs
MultiValueMap< ie::GroupInputElem, ie::SocketElem > gizmo_inputs_by_group_inputs
MultiValueMap< ie::ValueNodeElem, ie::SocketElem > gizmo_inputs_by_value_nodes
void merge(const ElemVariant &other)