So far, only node group were able to have menu input sockets. Built-in nodes did not support them. Currently, all menus of built-in nodes are stored on the node instead of on the sockets. This limits their flexibility because it's not possible to expose these inputs. This patch adds initial support for having menu inputs in built-in nodes. For testing purposes, it also changes a couple built-in nodes to use an input socket instead of a node property: Points to Volume, Transform Geometry, Triangulate, Volume to Mesh and Match String. ### Compatibility Forward and backward compatibility is maintained where possible (it's not possible when the menu input is linked in 5.0). The overall compatibility approach is the same as what was done for the compositor with two differences: there are no wrapper RNA properties (not necessary for 5.0, those were removed for the compositor already too), no need to version animation (animation on the menu properties was already disabled). This also makes menu sockets not animatable in general which is kind of brittle (e.g. doesn't properly update when the menu definition changes). To animate a menu it's better to animate an integer and to drive an index switch with it. ### Which nodes to update? Many existing menu properties can become sockets, but it's currently not the intention to convert all of them. In some cases, converting them might restrict future improvements too much. This mainly affects Math nodes. Other existing nodes should be updated but are a bit more tricky to update for different reasons: * We don't support dynamic output visibility yet. This is something I'll need to look into at some point. * They are shared with shader/compositor nodes, which may be more limited in what can become a socket. * There may be performance implications unless extra special cases are implemented, especially for multi-function nodes. * Some nodes use socket renaming instead of dynamic socket visibility which isn't something we support more generally yet. ### Implementation The core implementation is fairly straight forward. The heavy lifting is done by the existing socket visibility inferencing. There is a new simple API that allows individual nodes to implement custom input-usage-rules based on other inputs in a decentralized way. In most cases, the nodes to update just have a single menu, so there is a new node-declaration utility that links a socket to a specific value of the menu input. This internally handles the usage inferencing as well as making the socket available when using link-drag-search. In the modified nodes, I also had to explicitly set the "main input" now which is used when inserting the node in a link. The automatic behavior doesn't work currently when the first input is a menu. This is something we'll have to solve more generally at some point but is out of scope for this patch. Pull Request: https://projects.blender.org/blender/blender/pulls/140705
135 lines
4.2 KiB
C++
135 lines
4.2 KiB
C++
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#pragma once
|
|
|
|
#include "BLI_array.hh"
|
|
#include "BLI_generic_pointer.hh"
|
|
|
|
#include "BKE_node.hh"
|
|
|
|
#include "NOD_geometry_nodes_execute.hh"
|
|
#include "NOD_socket_usage_inference_fwd.hh"
|
|
|
|
struct bNodeTree;
|
|
struct bNodeSocket;
|
|
struct IDProperty;
|
|
|
|
namespace blender::nodes::socket_usage_inference {
|
|
|
|
struct SocketUsageInferencer;
|
|
|
|
/**
|
|
* During socket usage inferencing, some socket values are computed. This class represents such a
|
|
* computed value. Not all possible values can be presented here, only "basic" once (like int, but
|
|
* not int-field). A value can also be unknown if it can't be determined statically.
|
|
*/
|
|
class InferenceValue {
|
|
private:
|
|
/**
|
|
* Non-owning pointer to a value of type #bNodeSocketType.base_cpp_type of the corresponding
|
|
* socket. If this is null, the value is assumed to be unknown (aka, it can't be determined
|
|
* statically).
|
|
*/
|
|
const void *value_ = nullptr;
|
|
|
|
public:
|
|
explicit InferenceValue(const void *value) : value_(value) {}
|
|
|
|
static InferenceValue Unknown()
|
|
{
|
|
return InferenceValue(nullptr);
|
|
}
|
|
|
|
bool is_unknown() const
|
|
{
|
|
return value_ == nullptr;
|
|
}
|
|
|
|
const void *data() const
|
|
{
|
|
return value_;
|
|
}
|
|
|
|
template<typename T> T get_known() const
|
|
{
|
|
BLI_assert(!this->is_unknown());
|
|
return *static_cast<const T *>(this->value_);
|
|
}
|
|
|
|
template<typename T> std::optional<T> get() const
|
|
{
|
|
if (this->is_unknown()) {
|
|
return std::nullopt;
|
|
}
|
|
return this->get_known<T>();
|
|
}
|
|
};
|
|
|
|
class InputSocketUsageParams {
|
|
private:
|
|
SocketUsageInferencer &inferencer_;
|
|
const ComputeContext *compute_context_ = nullptr;
|
|
|
|
public:
|
|
const bNodeTree &tree;
|
|
const bNode &node;
|
|
const bNodeSocket &socket;
|
|
|
|
InputSocketUsageParams(SocketUsageInferencer &inferencer,
|
|
const ComputeContext *compute_context,
|
|
const bNodeTree &tree,
|
|
const bNode &node,
|
|
const bNodeSocket &socket);
|
|
|
|
/**
|
|
* Get an the statically known input value for the given socket identifier. The value may be
|
|
* unknown, in which case null is returned.
|
|
*/
|
|
InferenceValue get_input(StringRef identifier) const;
|
|
|
|
/**
|
|
* Utility for the case when the socket depends on a specific menu input to have a certain value.
|
|
*/
|
|
bool menu_input_may_be(StringRef identifier, int enum_value) const;
|
|
};
|
|
|
|
/**
|
|
* Get a boolean value for each input socket in the given tree that indicates whether that input is
|
|
* used. It is assumed that all output sockets in the tree are used.
|
|
*/
|
|
Array<SocketUsage> infer_all_input_sockets_usage(const bNodeTree &tree);
|
|
|
|
/**
|
|
* Get a boolean value for each node group input that indicates whether that input is used by the
|
|
* outputs. The result can be used to e.g. gray out or hide individual inputs that are unused.
|
|
*
|
|
* \param group: The node group that is called.
|
|
* \param group_input_values: An optional input value for each node group input. The type is
|
|
* expected to be `bNodeSocketType::base_cpp_type`. If the input value for a socket is not known
|
|
* or can't be represented as base type, null has to be passed instead.
|
|
* \param r_input_usages: The destination array where the inferred usages are written.
|
|
*/
|
|
void infer_group_interface_inputs_usage(const bNodeTree &group,
|
|
Span<GPointer> group_input_values,
|
|
MutableSpan<SocketUsage> r_input_usages);
|
|
|
|
/**
|
|
* Same as above, but automatically retrieves the input values from the given sockets..
|
|
* This is used for group nodes.
|
|
*/
|
|
void infer_group_interface_inputs_usage(const bNodeTree &group,
|
|
Span<const bNodeSocket *> input_sockets,
|
|
MutableSpan<SocketUsage> r_input_usages);
|
|
|
|
/**
|
|
* Same as above, but automatically retrieves the input values from the given properties.
|
|
* This is used with the geometry nodes modifier and node tools.
|
|
*/
|
|
void infer_group_interface_inputs_usage(const bNodeTree &group,
|
|
const PropertiesVectorSet &properties,
|
|
MutableSpan<SocketUsage> r_input_usages);
|
|
|
|
} // namespace blender::nodes::socket_usage_inference
|