Blender V5.0
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
5#include "BLI_listbase.h"
6
9#include "BKE_context.hh"
10#include "BKE_node.hh"
12#include "BKE_node_runtime.hh"
14#include "BKE_object.hh"
15#include "BKE_workspace.hh"
16
19#include "NOD_partial_eval.hh"
21
22#include "DNA_modifier_types.h"
23#include "DNA_space_types.h"
25
26#include "ED_node.hh"
27
28namespace blender::nodes::gizmos {
29
35
39static ie::ElemVariant get_gizmo_socket_elem(const bNode &node, const bNodeSocket &socket)
40{
41 switch (node.type_legacy) {
43 return {ie::FloatElem::all()};
44 }
46 return {ie::FloatElem::all()};
47 }
49 const auto &storage = *static_cast<const NodeGeometryTransformGizmo *>(node.storage);
50 ie::MatrixElem elem;
52 elem.translation = ie::VectorElem::all();
53 }
54 if (storage.flag &
56 {
57 elem.rotation = ie::RotationElem::all();
58 elem.scale = ie::VectorElem::all();
59 }
60 return {elem};
61 }
62 }
63 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(socket.type);
64 if (std::optional<ie::ElemVariant> elem = ie::get_elem_variant_for_socket_type(socket_type)) {
65 elem->set_all();
66 return *elem;
67 }
69 return {};
70}
71
73{
74 BLI_assert(!tree.has_available_link_cycle());
75
76 TreeGizmoPropagation gizmo_propagation;
77
78 struct GizmoInput {
79 const bNodeSocket *gizmo_socket;
80 /* For multi-input sockets we start propagation at the origin socket. */
81 const bNodeSocket *propagation_start_socket;
82 ie::ElemVariant elem;
83 };
84
85 /* Gather all gizmo inputs so that we can find their inverse evaluation targets afterwards. */
86 Vector<GizmoInput> all_gizmo_inputs;
87 for (const bNode *node : tree.all_nodes()) {
88 if (node->is_muted()) {
89 continue;
90 }
91 if (node->is_group()) {
92 if (!node->id) {
93 continue;
94 }
95 const bNodeTree &group = *reinterpret_cast<const bNodeTree *>(node->id);
96 if (!group.runtime->gizmo_propagation) {
97 continue;
98 }
99 const TreeGizmoPropagation &group_gizmo_propagation = *group.runtime->gizmo_propagation;
100 for (const ie::GroupInputElem &group_input_elem :
101 group_gizmo_propagation.gizmo_inputs_by_group_inputs.keys())
102 {
103 const bNodeSocket &input_socket = node->input_socket(group_input_elem.group_input_index);
104 all_gizmo_inputs.append({&input_socket, &input_socket, group_input_elem.elem});
105 }
106 }
107 if (is_builtin_gizmo_node(*node)) {
108 gizmo_propagation.gizmo_nodes.append(node);
109 const bNodeSocket &gizmo_input_socket = node->input_socket(0);
110 gizmo_propagation.gizmo_endpoint_sockets.add(&gizmo_input_socket);
111 const ie::ElemVariant elem = get_gizmo_socket_elem(*node, gizmo_input_socket);
112 for (const bNodeLink *link : gizmo_input_socket.directly_linked_links()) {
113 if (!link->is_used()) {
114 continue;
115 }
116 all_gizmo_inputs.append({&gizmo_input_socket, link->fromsock, elem});
117 }
118 }
119 }
120
121 /* Find the local gizmo targets for all gizmo inputs. */
122 for (const GizmoInput &gizmo_input : all_gizmo_inputs) {
123 gizmo_propagation.gizmo_endpoint_sockets.add(gizmo_input.gizmo_socket);
124 const ie::SocketElem gizmo_input_socket_elem{gizmo_input.gizmo_socket, gizmo_input.elem};
125 /* The conversion is necessary when e.g. connecting a Rotation directly to the matrix input of
126 * the Transform Gizmo node. */
127 const std::optional<ie::ElemVariant> converted_elem = ie::convert_socket_elem(
128 *gizmo_input.gizmo_socket, *gizmo_input.propagation_start_socket, gizmo_input.elem);
129 if (!converted_elem) {
130 continue;
131 }
132 const ie::LocalInverseEvalTargets targets = ie::find_local_inverse_eval_targets(
133 tree, {gizmo_input.propagation_start_socket, *converted_elem});
134 const bool has_target = !targets.input_sockets.is_empty() ||
135 !targets.group_inputs.is_empty() || !targets.value_nodes.is_empty();
136 if (!has_target) {
137 continue;
138 }
139 /* Remember all the gizmo targets for quick lookup later on. */
140 for (const ie::SocketElem &input_socket : targets.input_sockets) {
141 gizmo_propagation.gizmo_inputs_by_node_inputs.add(input_socket, gizmo_input_socket_elem);
142 gizmo_propagation.gizmo_endpoint_sockets.add(input_socket.socket);
143 }
144 for (const ie::ValueNodeElem &value_node : targets.value_nodes) {
145 gizmo_propagation.gizmo_inputs_by_value_nodes.add(value_node, gizmo_input_socket_elem);
146 gizmo_propagation.gizmo_endpoint_sockets.add(&value_node.node->output_socket(0));
147 }
148 for (const ie::GroupInputElem &group_input : targets.group_inputs) {
149 gizmo_propagation.gizmo_inputs_by_group_inputs.add(group_input, gizmo_input_socket_elem);
150 for (const bNode *group_input_node : tree.group_input_nodes()) {
151 gizmo_propagation.gizmo_endpoint_sockets.add(
152 &group_input_node->output_socket(group_input.group_input_index));
153 }
154 }
155 }
156
157 return gizmo_propagation;
158}
159
161{
162 tree.ensure_topology_cache();
163
164 if (tree.has_available_link_cycle()) {
165 const bool changed = tree.runtime->gizmo_propagation != nullptr;
166 tree.runtime->gizmo_propagation.reset();
167 return changed;
168 }
169
171 const bool changed = tree.runtime->gizmo_propagation ?
172 *tree.runtime->gizmo_propagation != new_gizmo_propagation :
173 true;
174 tree.runtime->gizmo_propagation = std::make_unique<TreeGizmoPropagation>(
175 std::move(new_gizmo_propagation));
176 return changed;
177}
178
179static void foreach_gizmo_for_input(const ie::SocketElem &input_socket,
180 bke::ComputeContextCache &compute_context_cache,
181 const ComputeContext *compute_context,
182 const bNodeTree &tree,
184
186 const ie::GroupInputElem &group_input,
187 bke::ComputeContextCache &compute_context_cache,
188 const ComputeContext *compute_context,
190{
191 const TreeGizmoPropagation &gizmo_propagation = *tree.runtime->gizmo_propagation;
192 for (const ie::SocketElem &gizmo_input :
193 gizmo_propagation.gizmo_inputs_by_group_inputs.lookup(group_input))
194 {
195 foreach_gizmo_for_input(gizmo_input, compute_context_cache, compute_context, tree, fn);
196 }
197}
198
199static void foreach_gizmo_for_input(const ie::SocketElem &input_socket,
200 bke::ComputeContextCache &compute_context_cache,
201 const ComputeContext *compute_context,
202 const bNodeTree &tree,
204{
205 const bke::bNodeTreeZones *zones = tree.zones();
206 if (!zones) {
207 /* There are invalid zones. */
208 return;
209 }
210 const bNode &node = input_socket.socket->owner_node();
211 if (zones->get_zone_by_node(node.identifier) != nullptr) {
212 /* Gizmos in zones are not supported yet. */
213 return;
214 }
215 if (is_builtin_gizmo_node(node)) {
216 if (node.is_muted()) {
217 return;
218 }
219 /* Found an actual built-in gizmo node. */
220 fn(*compute_context, node, *input_socket.socket);
221 return;
222 }
223 if (node.is_group()) {
224 const bNodeTree &group = *reinterpret_cast<const bNodeTree *>(node.id);
225 group.ensure_topology_cache();
226 const ComputeContext &group_compute_context = compute_context_cache.for_group_node(
227 compute_context, node.identifier, &tree);
229 group,
230 ie::GroupInputElem{input_socket.socket->index(), input_socket.elem},
231 compute_context_cache,
232 &group_compute_context,
233 fn);
234 }
235}
236
238 const SpaceNode &snode,
239 const Object *object_filter,
240 const NodesModifierData *nmd_filter,
241 bke::ComputeContextCache &compute_context_cache,
242 const ForeachGizmoFn fn)
243{
244 if (snode.nodetree == nullptr) {
245 return;
246 }
247 if (snode.edittree == nullptr || !snode.edittree->runtime->gizmo_propagation) {
248 return;
249 }
250 const std::optional<ed::space_node::ObjectAndModifier> object_and_modifier =
252 if (!object_and_modifier) {
253 return;
254 }
255 if (object_filter) {
256 if (object_and_modifier->object != object_filter) {
257 return;
258 }
259 }
260 if (nmd_filter) {
261 if (object_and_modifier->nmd != nmd_filter) {
262 return;
263 }
264 }
265
266 const Object &object = *object_and_modifier->object;
267 const NodesModifierData &nmd = *object_and_modifier->nmd;
268
269 if (!(nmd.modifier.mode & eModifierMode_Realtime)) {
270 /* Disabled modifiers can't have gizmos currently. */
271 return;
272 }
273
274 const ComputeContext *current_compute_context = ed::space_node::compute_context_for_edittree(
275 snode, compute_context_cache);
276 if (!current_compute_context) {
277 return;
278 }
279
280 snode.edittree->ensure_topology_cache();
281 const TreeGizmoPropagation &gizmo_propagation = *snode.edittree->runtime->gizmo_propagation;
282 Set<ie::SocketElem> used_gizmo_inputs;
283
284 /* Check gizmos on value nodes. */
285 for (auto &&item : gizmo_propagation.gizmo_inputs_by_value_nodes.items()) {
286 const bNode &node = *item.key.node;
287 const bNodeSocket &output_socket = node.output_socket(0);
288 if ((node.flag & NODE_SELECT) || (output_socket.flag & SOCK_GIZMO_PIN)) {
289 used_gizmo_inputs.add_multiple(item.value);
290 continue;
291 }
292 for (const ie::SocketElem &socket_elem : item.value) {
293 if (socket_elem.socket->owner_node().flag & NODE_SELECT) {
294 used_gizmo_inputs.add(socket_elem);
295 }
296 }
297 }
298 /* Check gizmos on input sockets. */
299 for (auto &&item : gizmo_propagation.gizmo_inputs_by_node_inputs.items()) {
300 const bNodeSocket &socket = *item.key.socket;
301 if (socket.is_inactive()) {
302 continue;
303 }
304 const bNode &node = socket.owner_node();
305 if ((node.flag & NODE_SELECT) || (socket.flag & SOCK_GIZMO_PIN)) {
306 used_gizmo_inputs.add_multiple(item.value);
307 continue;
308 }
309 for (const ie::SocketElem &socket_elem : item.value) {
310 if (socket_elem.socket->owner_node().flag & NODE_SELECT) {
311 used_gizmo_inputs.add(socket_elem);
312 }
313 }
314 }
315 /* Check built-in gizmo nodes. */
316 for (const bNode *gizmo_node : gizmo_propagation.gizmo_nodes) {
317 if (gizmo_node->is_muted()) {
318 continue;
319 }
320 const bNodeSocket &gizmo_input_socket = gizmo_node->input_socket(0);
321 if ((gizmo_node->flag & NODE_SELECT) || (gizmo_input_socket.flag & SOCK_GIZMO_PIN)) {
322 used_gizmo_inputs.add(
323 {&gizmo_input_socket,
324 *ie::get_elem_variant_for_socket_type(eNodeSocketDatatype(gizmo_input_socket.type))});
325 }
326 }
327 for (const ie::SocketElem &gizmo_input : used_gizmo_inputs) {
328 foreach_gizmo_for_input(gizmo_input,
329 compute_context_cache,
330 current_compute_context,
331 *snode.edittree,
332 [&](const ComputeContext &compute_context,
333 const bNode &gizmo_node,
334 const bNodeSocket &gizmo_socket) {
335 fn(object, nmd, compute_context, gizmo_node, gizmo_socket);
336 });
337 }
338}
339
341 const Object *object_filter,
342 const NodesModifierData *nmd_filter,
343 bke::ComputeContextCache &compute_context_cache,
344 const ForeachGizmoFn fn)
345{
346 LISTBASE_FOREACH (const wmWindow *, window, &wm.windows) {
347 const bScreen *active_screen = BKE_workspace_active_screen_get(window->workspace_hook);
348 Vector<const bScreen *> screens = {active_screen};
349 if (ELEM(active_screen->state, SCREENMAXIMIZED, SCREENFULL)) {
350 const ScrArea *area = static_cast<const ScrArea *>(active_screen->areabase.first);
351 screens.append(area->full);
352 }
353 for (const bScreen *screen : screens) {
354 LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
355 const SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
356 if (sl == nullptr) {
357 continue;
358 }
359 if (sl->spacetype != SPACE_NODE) {
360 continue;
361 }
362 const SpaceNode &snode = *reinterpret_cast<const SpaceNode *>(sl);
364 snode, object_filter, nmd_filter, compute_context_cache, fn);
365 }
366 }
367 }
368}
369
371 const NodesModifierData &nmd,
372 bke::ComputeContextCache &compute_context_cache,
374{
375 if (!nmd.node_group) {
376 return;
377 }
378 const bNodeTree &tree = *nmd.node_group;
379 if (!tree.runtime->gizmo_propagation) {
380 return;
381 }
382
383 tree.ensure_interface_cache();
384
385 ResourceScope scope;
387 *nmd.node_group, nmd.settings.properties, scope);
388
389 const auto get_input_value = [&](const int group_input_i) {
390 return input_values[group_input_i];
391 };
392 SocketValueInferencer value_inferencer{
393 *nmd.node_group, scope, compute_context_cache, get_input_value};
395 *nmd.node_group, scope, value_inferencer, compute_context_cache);
396
397 const ComputeContext &root_compute_context = compute_context_cache.for_modifier(nullptr, nmd);
398 for (auto &&item : tree.runtime->gizmo_propagation->gizmo_inputs_by_group_inputs.items()) {
399 const ie::GroupInputElem &group_input_elem = item.key;
400 if (item.value.is_empty()) {
401 continue;
402 }
403 if (!usage_inferencer.is_group_input_used(group_input_elem.group_input_index)) {
404 continue;
405 }
406 for (const ie::SocketElem &socket_elem : item.value) {
407 foreach_gizmo_for_input(socket_elem, compute_context_cache, &root_compute_context, tree, fn);
408 }
409 }
410}
411
413 const NodesModifierData &nmd,
414 const wmWindowManager &wm,
415 bke::ComputeContextCache &compute_context_cache,
417{
418 if (!nmd.node_group) {
419 return;
420 }
421
423 &object,
424 &nmd,
425 compute_context_cache,
426 [&](const Object &object_with_gizmo,
427 const NodesModifierData &nmd_with_gizmo,
428 const ComputeContext &compute_context,
429 const bNode &gizmo_node,
430 const bNodeSocket &gizmo_socket) {
431 BLI_assert(&object == &object_with_gizmo);
432 BLI_assert(&nmd == &nmd_with_gizmo);
433 UNUSED_VARS_NDEBUG(object_with_gizmo, nmd_with_gizmo);
434 fn(compute_context, gizmo_node, gizmo_socket);
435 });
436
437 foreach_active_gizmo_exposed_to_modifier(nmd, compute_context_cache, fn);
438}
439
441 bke::ComputeContextCache &compute_context_cache,
442 const ForeachGizmoFn fn)
443{
445 if (!wm) {
446 return;
447 }
448 foreach_active_gizmo_in_open_editors(*wm, nullptr, nullptr, compute_context_cache, fn);
449
450 if (const Base *active_base = CTX_data_active_base(&C)) {
451 if (!(active_base->flag & BASE_SELECTED)) {
452 return;
453 }
454 Object *active_object = active_base->object;
455
456 if (const ModifierData *md = BKE_object_active_modifier(active_object)) {
457 if (!(md->mode & eModifierMode_Realtime)) {
458 return;
459 }
460 if (md->type == eModifierType_Nodes) {
461 const NodesModifierData &nmd = *reinterpret_cast<const NodesModifierData *>(md);
463 nmd,
464 compute_context_cache,
465 [&](const ComputeContext &compute_context,
466 const bNode &gizmo_node,
467 const bNodeSocket &gizmo_socket) {
468 fn(*active_object, nmd, compute_context, gizmo_node, gizmo_socket);
469 });
470 }
471 }
472 }
473}
474
476 const bNode &gizmo_node,
477 const bNodeSocket &gizmo_socket,
478 FunctionRef<void(const ComputeContext &context)> fn)
479{
480 ie::foreach_element_on_inverse_eval_path(
481 gizmo_context, {&gizmo_socket, get_gizmo_socket_elem(gizmo_node, gizmo_socket)}, fn, {});
482}
483
485 const ComputeContext &gizmo_context,
486 const bNode &gizmo_node,
487 const bNodeSocket &gizmo_socket,
488 FunctionRef<void(
489 const ComputeContext &context, const bNodeSocket &socket, const ie::ElemVariant &elem)> fn)
490{
491 ie::foreach_element_on_inverse_eval_path(
492 gizmo_context, {&gizmo_socket, get_gizmo_socket_elem(gizmo_node, gizmo_socket)}, {}, fn);
493}
494
495ie::ElemVariant get_editable_gizmo_elem(const ComputeContext &gizmo_context,
496 const bNode &gizmo_node,
497 const bNodeSocket &gizmo_socket)
498{
499 std::optional<ie::ElemVariant> found_elem = ie::get_elem_variant_for_socket_type(
500 eNodeSocketDatatype(gizmo_socket.type));
501 BLI_assert(found_elem.has_value());
502
503 ie::foreach_element_on_inverse_eval_path(
504 gizmo_context,
505 {&gizmo_socket, get_gizmo_socket_elem(gizmo_node, gizmo_socket)},
506 {},
507 [&](const ComputeContext &context, const bNodeSocket &socket, const ie::ElemVariant &elem) {
508 if (context.hash() == gizmo_context.hash() && &socket == &gizmo_socket) {
509 found_elem->merge(elem);
510 }
511 });
512
513 return *found_elem;
514}
515
517 bContext &C,
518 Object &object,
521 const ComputeContext &gizmo_context,
522 const bNodeSocket &gizmo_socket,
523 const FunctionRef<void(bke::SocketValueVariant &value)> apply_on_gizmo_value_fn)
524{
525 Vector<ie::SocketToUpdate> sockets_to_update;
526
527 const bNodeTree &gizmo_node_tree = gizmo_socket.owner_tree();
528 geo_eval_log::GeoTreeLog &gizmo_tree_log = eval_log.get_tree_log(gizmo_context.hash());
529
530 /* Gather all sockets to update together with their new values. */
531 for (const bNodeLink *link : gizmo_socket.directly_linked_links()) {
532 gizmo_node_tree.ensure_topology_cache();
533 if (!link->is_used()) {
534 continue;
535 }
536 if (link->fromnode->is_dangling_reroute()) {
537 continue;
538 }
539 const std::optional<bke::SocketValueVariant> old_value = ie::get_logged_socket_value(
540 gizmo_tree_log, *link->fromsock);
541 if (!old_value) {
542 continue;
543 }
544 const std::optional<bke::SocketValueVariant> old_value_converted =
545 ie::convert_single_socket_value(*link->fromsock, *link->tosock, *old_value);
546 if (!old_value_converted) {
547 continue;
548 }
549 bke::SocketValueVariant new_value = *old_value_converted;
550 apply_on_gizmo_value_fn(new_value);
551
552 sockets_to_update.append({&gizmo_context, &gizmo_socket, link, new_value});
553 }
554
555 /* Actually backpropagate the socket values. */
556 ie::backpropagate_socket_values(C, object, nmd, eval_log, sockets_to_update);
557}
558
559bool value_node_has_gizmo(const bNodeTree &tree, const bNode &node)
560{
562 if (!tree.runtime->gizmo_propagation) {
563 return false;
564 }
565 return tree.runtime->gizmo_propagation->gizmo_endpoint_sockets.contains(&node.output_socket(0));
566}
567
568} // namespace blender::nodes::gizmos
Base * CTX_data_active_base(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
#define GEO_NODE_GIZMO_LINEAR
#define GEO_NODE_GIZMO_DIAL
#define GEO_NODE_GIZMO_TRANSFORM
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:614
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
#define UNUSED_VARS_NDEBUG(...)
#define ELEM(...)
@ eModifierMode_Realtime
@ eModifierType_Nodes
#define GEO_NODE_TRANSFORM_GIZMO_USE_ROTATION_ALL
@ NODE_SELECT
#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
#define C
Definition RandGen.cpp:29
MapType::KeyIterator keys() const
Span< Value > lookup(const Key &key) const
MapType::ItemIterator items() const
void add(const Key &key, const Value &value)
bool add(const Key &key)
Definition BLI_set.hh:248
void append(const T &value)
const ComputeContextHash & hash() const
bool add(const Key &key)
Definition BLI_set.hh:248
void add_multiple(Span< Key > keys)
Definition BLI_set.hh:287
void append(const T &value)
const ModifierComputeContext & for_modifier(const ComputeContext *parent, const NodesModifierData &nmd)
const GroupNodeComputeContext & for_group_node(const ComputeContext *parent, int32_t node_id, const bNodeTree *tree=nullptr)
const bNodeTreeZone * get_zone_by_node(const int32_t node_id) const
GeoTreeLog & get_tree_log(const ComputeContextHash &compute_context_hash)
KDTree_3d * tree
const ComputeContext * compute_context_for_edittree(const SpaceNode &snode, bke::ComputeContextCache &compute_context_cache)
std::optional< ObjectAndModifier > get_modifier_for_node_editor(const SpaceNode &snode)
bool update_tree_gizmo_propagation(bNodeTree &tree)
static void foreach_active_gizmo_exposed_to_modifier(const NodesModifierData &nmd, bke::ComputeContextCache &compute_context_cache, const ForeachGizmoInModifierFn fn)
static void foreach_gizmo_for_input(const ie::SocketElem &input_socket, bke::ComputeContextCache &compute_context_cache, const ComputeContext *compute_context, const bNodeTree &tree, const ForeachGizmoInModifierFn fn)
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)
void apply_gizmo_change(bContext &C, Object &object, NodesModifierData &nmd, geo_eval_log::GeoNodesLog &eval_log, const ComputeContext &gizmo_context, const bNodeSocket &gizmo_socket, const FunctionRef< void(bke::SocketValueVariant &value)> apply_on_gizmo_value_fn)
static ie::ElemVariant get_gizmo_socket_elem(const bNode &node, const bNodeSocket &socket)
static TreeGizmoPropagation build_tree_gizmo_propagation(bNodeTree &tree)
void foreach_active_gizmo(const bContext &C, bke::ComputeContextCache &compute_context_cache, const ForeachGizmoFn fn)
static void foreach_active_gizmo_in_open_editors(const wmWindowManager &wm, const Object *object_filter, const NodesModifierData *nmd_filter, bke::ComputeContextCache &compute_context_cache, const ForeachGizmoFn fn)
void foreach_active_gizmo_in_modifier(const Object &object, const NodesModifierData &nmd, const wmWindowManager &wm, bke::ComputeContextCache &compute_context_cache, const ForeachGizmoInModifierFn fn)
FunctionRef< void(const Object &object, const NodesModifierData &nmd, const ComputeContext &compute_context, const bNode &gizmo_node, const bNodeSocket &gizmo_socket)> ForeachGizmoFn
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)
bool value_node_has_gizmo(const bNodeTree &tree, const bNode &node)
FunctionRef< void(const ComputeContext &compute_context, const bNode &gizmo_node, const bNodeSocket &gizmo_socket)> ForeachGizmoInModifierFn
static void foreach_gizmo_for_group_input(const bNodeTree &tree, const ie::GroupInputElem &group_input, bke::ComputeContextCache &compute_context_cache, const ComputeContext *compute_context, const ForeachGizmoInModifierFn fn)
static void foreach_active_gizmo_in_open_node_editor(const SpaceNode &snode, const Object *object_filter, const NodesModifierData *nmd_filter, bke::ComputeContextCache &compute_context_cache, const ForeachGizmoFn fn)
bool is_supported_value_node(const bNode &node)
Vector< InferenceValue > get_geometry_nodes_input_inference_values(const bNodeTree &btree, const IDProperty *properties, ResourceScope &scope)
void * first
struct bNodeTree * node_group
struct NodesModifierSettings settings
struct IDProperty * properties
bScreen * full
struct bNodeTree * edittree
struct bNodeTree * nodetree
bNodeTreeRuntimeHandle * runtime
struct ID * id
int16_t type_legacy
void * storage
int32_t identifier
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