2023-08-16 00:20:26 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2021-08-30 17:13:46 +02:00
|
|
|
|
|
|
|
|
#include "NOD_socket_declarations.hh"
|
2021-10-26 20:00:03 +02:00
|
|
|
#include "NOD_socket_declarations_geometry.hh"
|
2021-08-30 17:13:46 +02:00
|
|
|
|
2024-01-15 12:44:04 -05:00
|
|
|
#include "BKE_lib_id.hh"
|
2022-05-30 15:31:13 +02:00
|
|
|
#include "BKE_node_runtime.hh"
|
2021-08-30 17:13:46 +02:00
|
|
|
|
|
|
|
|
#include "BLI_math_vector.h"
|
Nodes: initial support for built-in menu sockets
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
2025-07-16 08:31:59 +02:00
|
|
|
#include "BLI_string.h"
|
2025-07-26 12:33:15 +00:00
|
|
|
#include "BLI_string_utf8.h"
|
2021-08-30 17:13:46 +02:00
|
|
|
|
|
|
|
|
namespace blender::nodes::decl {
|
|
|
|
|
|
2021-12-15 09:51:57 -06:00
|
|
|
/**
|
|
|
|
|
* \note This function only deals with declarations, not the field status of existing nodes. If the
|
|
|
|
|
* field status of existing nodes was stored on the sockets, an improvement would be to check the
|
|
|
|
|
* existing socket's current status instead of the declaration.
|
|
|
|
|
*/
|
|
|
|
|
static bool field_types_are_compatible(const SocketDeclaration &input,
|
|
|
|
|
const SocketDeclaration &output)
|
|
|
|
|
{
|
2022-12-29 14:55:27 -05:00
|
|
|
if (output.output_field_dependency.field_type() == OutputSocketFieldType::FieldSource) {
|
|
|
|
|
if (input.input_field_type == InputSocketFieldType::None) {
|
2021-12-15 09:51:57 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool sockets_can_connect(const SocketDeclaration &socket_decl,
|
|
|
|
|
const bNodeSocket &other_socket)
|
|
|
|
|
{
|
|
|
|
|
/* Input sockets cannot connect to input sockets, outputs cannot connect to outputs. */
|
2022-12-29 14:55:27 -05:00
|
|
|
if (socket_decl.in_out == other_socket.in_out) {
|
2021-12-15 09:51:57 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-30 15:31:13 +02:00
|
|
|
if (other_socket.runtime->declaration) {
|
2022-12-29 14:55:27 -05:00
|
|
|
if (socket_decl.in_out == SOCK_IN) {
|
2022-05-30 15:31:13 +02:00
|
|
|
if (!field_types_are_compatible(socket_decl, *other_socket.runtime->declaration)) {
|
2021-12-15 09:51:57 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2022-05-30 15:31:13 +02:00
|
|
|
if (!field_types_are_compatible(*other_socket.runtime->declaration, socket_decl)) {
|
2021-12-15 09:51:57 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-03 17:37:25 -05:00
|
|
|
static bool basic_types_can_connect(const SocketDeclaration & /*socket_decl*/,
|
2021-12-15 09:51:57 -06:00
|
|
|
const bNodeSocket &other_socket)
|
|
|
|
|
{
|
|
|
|
|
return ELEM(other_socket.type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-30 17:13:46 +02:00
|
|
|
static void modify_subtype_except_for_storage(bNodeSocket &socket, int new_subtype)
|
|
|
|
|
{
|
2024-12-02 19:24:07 +01:00
|
|
|
const StringRefNull idname = *bke::node_static_socket_type(socket.type, new_subtype);
|
2025-07-26 12:33:15 +00:00
|
|
|
STRNCPY_UTF8(socket.idname, idname.c_str());
|
2024-08-19 20:27:37 +02:00
|
|
|
bke::bNodeSocketType *socktype = bke::node_socket_type_find(idname);
|
2021-08-30 17:13:46 +02:00
|
|
|
socket.typeinfo = socktype;
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-26 11:41:54 +02:00
|
|
|
static void modify_subtype_except_for_storage(bNodeSocket &socket, int subtype, int dimensions)
|
|
|
|
|
{
|
|
|
|
|
const StringRefNull idname = *bke::node_static_socket_type(socket.type, subtype, dimensions);
|
2025-07-26 12:33:15 +00:00
|
|
|
STRNCPY_UTF8(socket.idname, idname.c_str());
|
2025-05-26 11:41:54 +02:00
|
|
|
bke::bNodeSocketType *socktype = bke::node_socket_type_find(idname);
|
|
|
|
|
socket.typeinfo = socktype;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-05 11:10:25 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name #Float
|
|
|
|
|
* \{ */
|
2021-08-30 17:13:46 +02:00
|
|
|
|
2021-12-15 09:51:57 -06:00
|
|
|
bNodeSocket &Float::build(bNodeTree &ntree, bNode &node) const
|
2021-08-30 17:13:46 +02:00
|
|
|
{
|
2025-02-19 13:44:11 +01:00
|
|
|
bNodeSocket &socket = *bke::node_add_static_socket(ntree,
|
|
|
|
|
node,
|
2024-08-19 20:27:37 +02:00
|
|
|
this->in_out,
|
|
|
|
|
SOCK_FLOAT,
|
|
|
|
|
this->subtype,
|
|
|
|
|
this->identifier.c_str(),
|
|
|
|
|
this->name.c_str());
|
2021-09-15 16:09:00 +02:00
|
|
|
this->set_common_flags(socket);
|
2021-08-30 17:13:46 +02:00
|
|
|
bNodeSocketValueFloat &value = *(bNodeSocketValueFloat *)socket.default_value;
|
2022-12-27 11:50:17 -05:00
|
|
|
value.min = this->soft_min_value;
|
|
|
|
|
value.max = this->soft_max_value;
|
|
|
|
|
value.value = this->default_value;
|
2021-08-30 17:13:46 +02:00
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Float::matches(const bNodeSocket &socket) const
|
|
|
|
|
{
|
2021-09-15 16:09:00 +02:00
|
|
|
if (!this->matches_common_data(socket)) {
|
2021-08-30 17:13:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2021-09-15 16:09:00 +02:00
|
|
|
if (socket.type != SOCK_FLOAT) {
|
2021-08-30 17:13:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2022-12-27 11:50:17 -05:00
|
|
|
if (socket.typeinfo->subtype != this->subtype) {
|
2021-08-30 17:13:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
bNodeSocketValueFloat &value = *(bNodeSocketValueFloat *)socket.default_value;
|
2022-12-27 11:50:17 -05:00
|
|
|
if (value.min != this->soft_min_value) {
|
2021-08-30 17:13:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2022-12-27 11:50:17 -05:00
|
|
|
if (value.max != this->soft_max_value) {
|
2021-08-30 17:13:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 09:51:57 -06:00
|
|
|
bool Float::can_connect(const bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (!sockets_can_connect(*this, socket)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-11-15 18:56:00 +01:00
|
|
|
if (this->in_out == SOCK_OUT && socket.type == SOCK_ROTATION) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2021-12-15 09:51:57 -06:00
|
|
|
return basic_types_can_connect(*this, socket);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-30 17:13:46 +02:00
|
|
|
bNodeSocket &Float::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (socket.type != SOCK_FLOAT) {
|
2022-12-29 14:55:27 -05:00
|
|
|
BLI_assert(socket.in_out == this->in_out);
|
2021-12-15 09:51:57 -06:00
|
|
|
return this->build(ntree, node);
|
2021-08-30 17:13:46 +02:00
|
|
|
}
|
2022-12-27 11:50:17 -05:00
|
|
|
if (socket.typeinfo->subtype != this->subtype) {
|
|
|
|
|
modify_subtype_except_for_storage(socket, this->subtype);
|
2021-08-30 17:13:46 +02:00
|
|
|
}
|
2021-09-15 16:09:00 +02:00
|
|
|
this->set_common_flags(socket);
|
2021-08-30 17:13:46 +02:00
|
|
|
bNodeSocketValueFloat &value = *(bNodeSocketValueFloat *)socket.default_value;
|
2022-12-27 11:50:17 -05:00
|
|
|
value.min = this->soft_min_value;
|
|
|
|
|
value.max = this->soft_max_value;
|
|
|
|
|
value.subtype = this->subtype;
|
2021-08-30 17:13:46 +02:00
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-05 11:10:25 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name #Int
|
|
|
|
|
* \{ */
|
2021-08-30 17:13:46 +02:00
|
|
|
|
2021-12-15 09:51:57 -06:00
|
|
|
bNodeSocket &Int::build(bNodeTree &ntree, bNode &node) const
|
2021-08-30 17:13:46 +02:00
|
|
|
{
|
2025-02-19 13:44:11 +01:00
|
|
|
bNodeSocket &socket = *bke::node_add_static_socket(ntree,
|
|
|
|
|
node,
|
2024-08-19 20:27:37 +02:00
|
|
|
this->in_out,
|
|
|
|
|
SOCK_INT,
|
|
|
|
|
this->subtype,
|
|
|
|
|
this->identifier.c_str(),
|
|
|
|
|
this->name.c_str());
|
2021-09-15 16:09:00 +02:00
|
|
|
this->set_common_flags(socket);
|
2021-08-30 17:13:46 +02:00
|
|
|
bNodeSocketValueInt &value = *(bNodeSocketValueInt *)socket.default_value;
|
2022-12-27 11:50:17 -05:00
|
|
|
value.min = this->soft_min_value;
|
|
|
|
|
value.max = this->soft_max_value;
|
|
|
|
|
value.value = this->default_value;
|
2021-08-30 17:13:46 +02:00
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Int::matches(const bNodeSocket &socket) const
|
|
|
|
|
{
|
2021-09-15 16:09:00 +02:00
|
|
|
if (!this->matches_common_data(socket)) {
|
2021-08-30 17:13:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2021-09-15 16:09:00 +02:00
|
|
|
if (socket.type != SOCK_INT) {
|
2021-08-30 17:13:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2022-12-27 11:50:17 -05:00
|
|
|
if (socket.typeinfo->subtype != this->subtype) {
|
2021-08-30 17:13:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
bNodeSocketValueInt &value = *(bNodeSocketValueInt *)socket.default_value;
|
2022-12-27 11:50:17 -05:00
|
|
|
if (value.min != this->soft_min_value) {
|
2021-08-30 17:13:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2022-12-27 11:50:17 -05:00
|
|
|
if (value.max != this->soft_max_value) {
|
2021-08-30 17:13:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 09:51:57 -06:00
|
|
|
bool Int::can_connect(const bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (!sockets_can_connect(*this, socket)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return basic_types_can_connect(*this, socket);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-30 17:13:46 +02:00
|
|
|
bNodeSocket &Int::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (socket.type != SOCK_INT) {
|
2022-12-29 14:55:27 -05:00
|
|
|
BLI_assert(socket.in_out == this->in_out);
|
2021-12-15 09:51:57 -06:00
|
|
|
return this->build(ntree, node);
|
2021-08-30 17:13:46 +02:00
|
|
|
}
|
2022-12-27 11:50:17 -05:00
|
|
|
if (socket.typeinfo->subtype != this->subtype) {
|
|
|
|
|
modify_subtype_except_for_storage(socket, this->subtype);
|
2021-08-30 17:13:46 +02:00
|
|
|
}
|
2021-09-15 16:09:00 +02:00
|
|
|
this->set_common_flags(socket);
|
2021-08-30 17:13:46 +02:00
|
|
|
bNodeSocketValueInt &value = *(bNodeSocketValueInt *)socket.default_value;
|
2022-12-27 11:50:17 -05:00
|
|
|
value.min = this->soft_min_value;
|
|
|
|
|
value.max = this->soft_max_value;
|
|
|
|
|
value.subtype = this->subtype;
|
2021-08-30 17:13:46 +02:00
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-05 11:10:25 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name #Vector
|
|
|
|
|
* \{ */
|
2021-08-30 17:13:46 +02:00
|
|
|
|
2021-12-15 09:51:57 -06:00
|
|
|
bNodeSocket &Vector::build(bNodeTree &ntree, bNode &node) const
|
2021-08-30 17:13:46 +02:00
|
|
|
{
|
2025-05-26 11:41:54 +02:00
|
|
|
const StringRefNull idname = *bke::node_static_socket_type(
|
|
|
|
|
SOCK_VECTOR, this->subtype, this->dimensions);
|
|
|
|
|
bNodeSocket &socket = *bke::node_add_socket(
|
|
|
|
|
ntree, node, this->in_out, idname, this->identifier.c_str(), this->name.c_str());
|
2021-09-15 16:09:00 +02:00
|
|
|
this->set_common_flags(socket);
|
2021-08-30 17:13:46 +02:00
|
|
|
bNodeSocketValueVector &value = *(bNodeSocketValueVector *)socket.default_value;
|
2025-05-26 11:41:54 +02:00
|
|
|
std::copy_n(&this->default_value[0], this->dimensions, value.value);
|
|
|
|
|
value.dimensions = this->dimensions;
|
2022-12-27 11:50:17 -05:00
|
|
|
value.min = this->soft_min_value;
|
|
|
|
|
value.max = this->soft_max_value;
|
2021-08-30 17:13:46 +02:00
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Vector::matches(const bNodeSocket &socket) const
|
|
|
|
|
{
|
2021-09-15 16:09:00 +02:00
|
|
|
if (!this->matches_common_data(socket)) {
|
2021-08-30 17:13:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2021-09-15 16:09:00 +02:00
|
|
|
if (socket.type != SOCK_VECTOR) {
|
2021-08-30 17:13:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2022-12-27 11:50:17 -05:00
|
|
|
if (socket.typeinfo->subtype != this->subtype) {
|
2021-08-30 17:13:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2023-01-16 15:47:10 -06:00
|
|
|
const bNodeSocketValueVector &value = *static_cast<const bNodeSocketValueVector *>(
|
|
|
|
|
socket.default_value);
|
2025-05-26 11:41:54 +02:00
|
|
|
if (value.dimensions != this->dimensions) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-01-16 15:47:10 -06:00
|
|
|
if (value.min != this->soft_min_value) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (value.max != this->soft_max_value) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2021-08-30 17:13:46 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 09:51:57 -06:00
|
|
|
bool Vector::can_connect(const bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (!sockets_can_connect(*this, socket)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-11-15 18:56:00 +01:00
|
|
|
if (socket.type == SOCK_ROTATION) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2021-12-15 09:51:57 -06:00
|
|
|
return basic_types_can_connect(*this, socket);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-30 17:13:46 +02:00
|
|
|
bNodeSocket &Vector::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (socket.type != SOCK_VECTOR) {
|
2022-12-29 14:55:27 -05:00
|
|
|
BLI_assert(socket.in_out == this->in_out);
|
2021-12-15 09:51:57 -06:00
|
|
|
return this->build(ntree, node);
|
2021-08-30 17:13:46 +02:00
|
|
|
}
|
2022-12-27 11:50:17 -05:00
|
|
|
if (socket.typeinfo->subtype != this->subtype) {
|
2025-05-26 11:41:54 +02:00
|
|
|
modify_subtype_except_for_storage(socket, this->subtype, this->dimensions);
|
2021-08-30 17:13:46 +02:00
|
|
|
}
|
2021-09-15 16:09:00 +02:00
|
|
|
this->set_common_flags(socket);
|
2021-08-30 17:13:46 +02:00
|
|
|
bNodeSocketValueVector &value = *(bNodeSocketValueVector *)socket.default_value;
|
2025-05-26 11:41:54 +02:00
|
|
|
if (value.dimensions != this->dimensions) {
|
|
|
|
|
modify_subtype_except_for_storage(socket, this->subtype, this->dimensions);
|
|
|
|
|
}
|
2022-12-27 11:50:17 -05:00
|
|
|
value.subtype = this->subtype;
|
2025-05-26 11:41:54 +02:00
|
|
|
value.dimensions = this->dimensions;
|
2023-01-16 15:47:10 -06:00
|
|
|
value.min = this->soft_min_value;
|
|
|
|
|
value.max = this->soft_max_value;
|
2021-08-30 17:13:46 +02:00
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-05 11:10:25 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name #Bool
|
|
|
|
|
* \{ */
|
2021-08-30 17:13:46 +02:00
|
|
|
|
2021-12-15 09:51:57 -06:00
|
|
|
bNodeSocket &Bool::build(bNodeTree &ntree, bNode &node) const
|
2021-08-30 17:13:46 +02:00
|
|
|
{
|
2025-02-19 13:44:11 +01:00
|
|
|
bNodeSocket &socket = *bke::node_add_static_socket(ntree,
|
|
|
|
|
node,
|
2024-08-19 20:27:37 +02:00
|
|
|
this->in_out,
|
|
|
|
|
SOCK_BOOLEAN,
|
|
|
|
|
PROP_NONE,
|
|
|
|
|
this->identifier.c_str(),
|
|
|
|
|
this->name.c_str());
|
2021-09-15 16:09:00 +02:00
|
|
|
this->set_common_flags(socket);
|
2021-08-30 17:13:46 +02:00
|
|
|
bNodeSocketValueBoolean &value = *(bNodeSocketValueBoolean *)socket.default_value;
|
2022-12-27 11:50:17 -05:00
|
|
|
value.value = this->default_value;
|
2021-08-30 17:13:46 +02:00
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Bool::matches(const bNodeSocket &socket) const
|
|
|
|
|
{
|
2021-09-15 16:09:00 +02:00
|
|
|
if (!this->matches_common_data(socket)) {
|
2021-08-30 17:13:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2021-09-15 16:09:00 +02:00
|
|
|
if (socket.type != SOCK_BOOLEAN) {
|
2021-08-30 17:13:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 09:51:57 -06:00
|
|
|
bool Bool::can_connect(const bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (!sockets_can_connect(*this, socket)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return basic_types_can_connect(*this, socket);
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 15:47:10 -06:00
|
|
|
bNodeSocket &Bool::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (socket.type != SOCK_BOOLEAN) {
|
|
|
|
|
BLI_assert(socket.in_out == this->in_out);
|
|
|
|
|
return this->build(ntree, node);
|
|
|
|
|
}
|
|
|
|
|
this->set_common_flags(socket);
|
|
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-05 11:10:25 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name #Color
|
|
|
|
|
* \{ */
|
2021-08-30 17:13:46 +02:00
|
|
|
|
2021-12-15 09:51:57 -06:00
|
|
|
bNodeSocket &Color::build(bNodeTree &ntree, bNode &node) const
|
2021-08-30 17:13:46 +02:00
|
|
|
{
|
2025-02-19 13:44:11 +01:00
|
|
|
bNodeSocket &socket = *bke::node_add_static_socket(ntree,
|
|
|
|
|
node,
|
2024-08-19 20:27:37 +02:00
|
|
|
this->in_out,
|
|
|
|
|
SOCK_RGBA,
|
|
|
|
|
PROP_NONE,
|
|
|
|
|
this->identifier.c_str(),
|
|
|
|
|
this->name.c_str());
|
2021-09-15 16:09:00 +02:00
|
|
|
this->set_common_flags(socket);
|
2021-08-30 17:13:46 +02:00
|
|
|
bNodeSocketValueRGBA &value = *(bNodeSocketValueRGBA *)socket.default_value;
|
2022-12-27 11:50:17 -05:00
|
|
|
copy_v4_v4(value.value, this->default_value);
|
2021-08-30 17:13:46 +02:00
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Color::matches(const bNodeSocket &socket) const
|
|
|
|
|
{
|
2021-09-15 16:09:00 +02:00
|
|
|
if (!this->matches_common_data(socket)) {
|
2023-07-27 14:55:15 +02:00
|
|
|
return false;
|
2021-08-30 17:13:46 +02:00
|
|
|
}
|
2021-09-15 16:09:00 +02:00
|
|
|
if (socket.type != SOCK_RGBA) {
|
2021-08-30 17:13:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 09:51:57 -06:00
|
|
|
bool Color::can_connect(const bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (!sockets_can_connect(*this, socket)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return basic_types_can_connect(*this, socket);
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 15:47:10 -06:00
|
|
|
bNodeSocket &Color::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (socket.type != SOCK_RGBA) {
|
|
|
|
|
BLI_assert(socket.in_out == this->in_out);
|
|
|
|
|
return this->build(ntree, node);
|
|
|
|
|
}
|
|
|
|
|
this->set_common_flags(socket);
|
|
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 20:30:10 +02:00
|
|
|
/** \} */
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name #Rotation
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
bNodeSocket &Rotation::build(bNodeTree &ntree, bNode &node) const
|
|
|
|
|
{
|
2025-02-19 13:44:11 +01:00
|
|
|
bNodeSocket &socket = *bke::node_add_static_socket(ntree,
|
|
|
|
|
node,
|
2024-08-19 20:27:37 +02:00
|
|
|
this->in_out,
|
|
|
|
|
SOCK_ROTATION,
|
|
|
|
|
PROP_NONE,
|
|
|
|
|
this->identifier.c_str(),
|
|
|
|
|
this->name.c_str());
|
2023-06-14 20:30:10 +02:00
|
|
|
this->set_common_flags(socket);
|
|
|
|
|
bNodeSocketValueRotation &value = *static_cast<bNodeSocketValueRotation *>(socket.default_value);
|
|
|
|
|
copy_v3_v3(value.value_euler, float3(this->default_value));
|
|
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Rotation::matches(const bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (!this->matches_common_data(socket)) {
|
2023-07-27 14:55:15 +02:00
|
|
|
return false;
|
2023-06-14 20:30:10 +02:00
|
|
|
}
|
|
|
|
|
if (socket.type != SOCK_ROTATION) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Rotation::can_connect(const bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (!sockets_can_connect(*this, socket)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-11-15 18:56:00 +01:00
|
|
|
if (this->in_out == SOCK_IN) {
|
2024-02-13 18:59:36 +01:00
|
|
|
return ELEM(socket.type, SOCK_ROTATION, SOCK_FLOAT, SOCK_VECTOR, SOCK_MATRIX);
|
2023-11-15 18:56:00 +01:00
|
|
|
}
|
2024-02-13 18:59:36 +01:00
|
|
|
return ELEM(socket.type, SOCK_ROTATION, SOCK_VECTOR, SOCK_MATRIX);
|
2023-06-14 20:30:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bNodeSocket &Rotation::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (socket.type != SOCK_ROTATION) {
|
|
|
|
|
BLI_assert(socket.in_out == this->in_out);
|
|
|
|
|
return this->build(ntree, node);
|
|
|
|
|
}
|
|
|
|
|
this->set_common_flags(socket);
|
|
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-05 11:10:25 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
2024-02-13 18:59:36 +01:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name #Matrix
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
bNodeSocket &Matrix::build(bNodeTree &ntree, bNode &node) const
|
|
|
|
|
{
|
2025-02-19 13:44:11 +01:00
|
|
|
bNodeSocket &socket = *bke::node_add_static_socket(ntree,
|
|
|
|
|
node,
|
2024-08-19 20:27:37 +02:00
|
|
|
this->in_out,
|
|
|
|
|
SOCK_MATRIX,
|
|
|
|
|
PROP_NONE,
|
|
|
|
|
this->identifier.c_str(),
|
|
|
|
|
this->name.c_str());
|
2024-02-13 18:59:36 +01:00
|
|
|
this->set_common_flags(socket);
|
|
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Matrix::matches(const bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (!this->matches_common_data(socket)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (socket.type != SOCK_MATRIX) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Matrix::can_connect(const bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (!sockets_can_connect(*this, socket)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (this->in_out == SOCK_IN) {
|
|
|
|
|
return ELEM(socket.type, SOCK_MATRIX, SOCK_FLOAT, SOCK_VECTOR, SOCK_MATRIX);
|
|
|
|
|
}
|
|
|
|
|
return ELEM(socket.type, SOCK_MATRIX, SOCK_VECTOR, SOCK_MATRIX);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bNodeSocket &Matrix::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (socket.type != SOCK_MATRIX) {
|
|
|
|
|
BLI_assert(socket.in_out == this->in_out);
|
|
|
|
|
return this->build(ntree, node);
|
|
|
|
|
}
|
|
|
|
|
this->set_common_flags(socket);
|
|
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
2021-10-05 11:10:25 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name #String
|
|
|
|
|
* \{ */
|
2021-08-30 17:13:46 +02:00
|
|
|
|
2021-12-15 09:51:57 -06:00
|
|
|
bNodeSocket &String::build(bNodeTree &ntree, bNode &node) const
|
2021-08-30 17:13:46 +02:00
|
|
|
{
|
2025-02-19 13:44:11 +01:00
|
|
|
bNodeSocket &socket = *bke::node_add_static_socket(ntree,
|
|
|
|
|
node,
|
2024-08-19 20:27:37 +02:00
|
|
|
this->in_out,
|
|
|
|
|
SOCK_STRING,
|
|
|
|
|
this->subtype,
|
|
|
|
|
this->identifier.c_str(),
|
|
|
|
|
this->name.c_str());
|
2022-12-27 11:50:17 -05:00
|
|
|
STRNCPY(((bNodeSocketValueString *)socket.default_value)->value, this->default_value.c_str());
|
2021-09-15 16:09:00 +02:00
|
|
|
this->set_common_flags(socket);
|
2021-08-30 17:13:46 +02:00
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool String::matches(const bNodeSocket &socket) const
|
|
|
|
|
{
|
2021-09-15 16:09:00 +02:00
|
|
|
if (!this->matches_common_data(socket)) {
|
2021-08-30 17:13:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2021-09-15 16:09:00 +02:00
|
|
|
if (socket.type != SOCK_STRING) {
|
2021-08-30 17:13:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2024-06-24 16:28:33 +02:00
|
|
|
if (socket.typeinfo->subtype != this->subtype) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2021-08-30 17:13:46 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 09:51:57 -06:00
|
|
|
bool String::can_connect(const bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
return sockets_can_connect(*this, socket) && socket.type == SOCK_STRING;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 15:47:10 -06:00
|
|
|
bNodeSocket &String::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (socket.type != SOCK_STRING) {
|
|
|
|
|
BLI_assert(socket.in_out == this->in_out);
|
|
|
|
|
return this->build(ntree, node);
|
2024-01-26 12:40:01 +01:00
|
|
|
}
|
2024-06-24 16:28:33 +02:00
|
|
|
if (socket.typeinfo->subtype != this->subtype) {
|
|
|
|
|
modify_subtype_except_for_storage(socket, this->subtype);
|
|
|
|
|
}
|
2024-01-26 12:40:01 +01:00
|
|
|
this->set_common_flags(socket);
|
2024-06-24 16:28:33 +02:00
|
|
|
bNodeSocketValueString &value = *(bNodeSocketValueString *)socket.default_value;
|
|
|
|
|
value.subtype = this->subtype;
|
2024-01-26 12:40:01 +01:00
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-24 18:52:10 +01:00
|
|
|
StringBuilder &StringBuilder::path_filter(std::optional<std::string> filter)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(decl_->subtype == PROP_FILEPATH);
|
|
|
|
|
decl_->path_filter = std::move(filter);
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-26 12:40:01 +01:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name #Menu
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
bNodeSocket &Menu::build(bNodeTree &ntree, bNode &node) const
|
|
|
|
|
{
|
2025-02-19 13:44:11 +01:00
|
|
|
bNodeSocket &socket = *bke::node_add_static_socket(ntree,
|
|
|
|
|
node,
|
2024-08-19 20:27:37 +02:00
|
|
|
this->in_out,
|
|
|
|
|
SOCK_MENU,
|
|
|
|
|
PROP_NONE,
|
|
|
|
|
this->identifier.c_str(),
|
|
|
|
|
this->name.c_str());
|
2024-01-26 12:40:01 +01:00
|
|
|
|
2025-08-13 15:43:37 +02:00
|
|
|
((bNodeSocketValueMenu *)socket.default_value)->value = this->default_value.value;
|
2024-01-26 12:40:01 +01:00
|
|
|
this->set_common_flags(socket);
|
|
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Menu::matches(const bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (!this->matches_common_data(socket)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (socket.type != SOCK_MENU) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Menu::can_connect(const bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
return sockets_can_connect(*this, socket) && socket.type == SOCK_MENU;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bNodeSocket &Menu::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (socket.type != SOCK_MENU) {
|
|
|
|
|
BLI_assert(socket.in_out == this->in_out);
|
|
|
|
|
return this->build(ntree, node);
|
2023-01-16 15:47:10 -06:00
|
|
|
}
|
|
|
|
|
this->set_common_flags(socket);
|
|
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
Nodes: initial support for built-in menu sockets
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
2025-07-16 08:31:59 +02:00
|
|
|
MenuBuilder &MenuBuilder::static_items(const EnumPropertyItem *items)
|
|
|
|
|
{
|
|
|
|
|
/* Using a global map ensures that the same runtime data is used for the same static items.
|
|
|
|
|
* This is necessary because otherwise each node would have a different (incompatible) menu
|
|
|
|
|
* definition. */
|
|
|
|
|
static Mutex mutex;
|
|
|
|
|
static Map<const EnumPropertyItem *, ImplicitSharingPtr<bke::RuntimeNodeEnumItems>>
|
|
|
|
|
items_by_enum_ptr;
|
|
|
|
|
|
|
|
|
|
std::lock_guard lock{mutex};
|
|
|
|
|
decl_->items = items_by_enum_ptr.lookup_or_add_cb(items, [&]() {
|
|
|
|
|
bke::RuntimeNodeEnumItems *runtime_items = new bke::RuntimeNodeEnumItems();
|
|
|
|
|
for (const EnumPropertyItem *item = items; item->identifier; item++) {
|
|
|
|
|
bke::RuntimeNodeEnumItem runtime_item;
|
|
|
|
|
runtime_item.name = item->name;
|
|
|
|
|
runtime_item.description = item->description;
|
|
|
|
|
runtime_item.identifier = item->value;
|
|
|
|
|
runtime_items->items.append(std::move(runtime_item));
|
|
|
|
|
}
|
|
|
|
|
return ImplicitSharingPtr<bke::RuntimeNodeEnumItems>(runtime_items);
|
|
|
|
|
});
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-05 11:10:25 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
2025-04-03 15:44:06 +02:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name #Bundle
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
bNodeSocket &Bundle::build(bNodeTree &ntree, bNode &node) const
|
|
|
|
|
{
|
|
|
|
|
bNodeSocket &socket = *bke::node_add_static_socket(ntree,
|
|
|
|
|
node,
|
|
|
|
|
this->in_out,
|
|
|
|
|
SOCK_BUNDLE,
|
|
|
|
|
PROP_NONE,
|
|
|
|
|
this->identifier.c_str(),
|
|
|
|
|
this->name.c_str());
|
|
|
|
|
this->set_common_flags(socket);
|
|
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Bundle::matches(const bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (!this->matches_common_data(socket)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (socket.type != SOCK_BUNDLE) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Bundle::can_connect(const bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (!sockets_can_connect(*this, socket)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return ELEM(socket.type, SOCK_BUNDLE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bNodeSocket &Bundle::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (socket.type != SOCK_BUNDLE) {
|
|
|
|
|
BLI_assert(socket.in_out == this->in_out);
|
|
|
|
|
return this->build(ntree, node);
|
|
|
|
|
}
|
|
|
|
|
this->set_common_flags(socket);
|
|
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-02 22:28:17 +02:00
|
|
|
BundleBuilder &BundleBuilder::pass_through_input_index(const std::optional<int> index)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(this->is_output());
|
|
|
|
|
decl_->pass_through_input_index = std::move(index);
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-03 15:44:06 +02:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name #Closure
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
bNodeSocket &Closure::build(bNodeTree &ntree, bNode &node) const
|
|
|
|
|
{
|
|
|
|
|
bNodeSocket &socket = *bke::node_add_static_socket(ntree,
|
|
|
|
|
node,
|
|
|
|
|
this->in_out,
|
|
|
|
|
SOCK_CLOSURE,
|
|
|
|
|
PROP_NONE,
|
|
|
|
|
this->identifier.c_str(),
|
|
|
|
|
this->name.c_str());
|
|
|
|
|
this->set_common_flags(socket);
|
|
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Closure::matches(const bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (!this->matches_common_data(socket)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (socket.type != SOCK_CLOSURE) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Closure::can_connect(const bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (!sockets_can_connect(*this, socket)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return ELEM(socket.type, SOCK_CLOSURE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bNodeSocket &Closure::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (socket.type != SOCK_CLOSURE) {
|
|
|
|
|
BLI_assert(socket.in_out == this->in_out);
|
|
|
|
|
return this->build(ntree, node);
|
|
|
|
|
}
|
|
|
|
|
this->set_common_flags(socket);
|
|
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
2021-10-05 11:10:25 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name #IDSocketDeclaration
|
|
|
|
|
* \{ */
|
2021-08-30 17:13:46 +02:00
|
|
|
|
2021-12-15 09:51:57 -06:00
|
|
|
bNodeSocket &IDSocketDeclaration::build(bNodeTree &ntree, bNode &node) const
|
2021-08-30 17:13:46 +02:00
|
|
|
{
|
2024-08-19 20:27:37 +02:00
|
|
|
bNodeSocket &socket = *bke::node_add_socket(
|
2025-02-19 13:44:11 +01:00
|
|
|
ntree, node, this->in_out, this->idname, this->identifier.c_str(), this->name.c_str());
|
2023-04-20 22:27:45 +02:00
|
|
|
if (this->default_value_fn) {
|
|
|
|
|
ID *id = this->default_value_fn(node);
|
|
|
|
|
/* Assumes that all ID sockets like #bNodeSocketValueObject and #bNodeSocketValueImage have the
|
|
|
|
|
* ID pointer at the start of the struct. */
|
|
|
|
|
*static_cast<ID **>(socket.default_value) = id;
|
|
|
|
|
id_us_plus(id);
|
|
|
|
|
}
|
2021-09-15 16:09:00 +02:00
|
|
|
this->set_common_flags(socket);
|
2021-08-30 17:13:46 +02:00
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-15 16:09:00 +02:00
|
|
|
bool IDSocketDeclaration::matches(const bNodeSocket &socket) const
|
2021-08-30 17:13:46 +02:00
|
|
|
{
|
2021-09-15 16:09:00 +02:00
|
|
|
if (!this->matches_common_data(socket)) {
|
2021-08-30 17:13:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2022-12-27 11:50:17 -05:00
|
|
|
if (!STREQ(socket.idname, this->idname)) {
|
2021-08-30 17:13:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2021-09-15 16:09:00 +02:00
|
|
|
|
2021-12-15 09:51:57 -06:00
|
|
|
bool IDSocketDeclaration::can_connect(const bNodeSocket &socket) const
|
|
|
|
|
{
|
2022-12-27 11:50:17 -05:00
|
|
|
return sockets_can_connect(*this, socket) && STREQ(socket.idname, this->idname);
|
2021-12-15 09:51:57 -06:00
|
|
|
}
|
|
|
|
|
|
2021-09-15 16:09:00 +02:00
|
|
|
bNodeSocket &IDSocketDeclaration::update_or_build(bNodeTree &ntree,
|
|
|
|
|
bNode &node,
|
|
|
|
|
bNodeSocket &socket) const
|
|
|
|
|
{
|
2022-12-27 11:50:17 -05:00
|
|
|
if (StringRef(socket.idname) != this->idname) {
|
2022-12-29 14:55:27 -05:00
|
|
|
BLI_assert(socket.in_out == this->in_out);
|
2021-12-15 09:51:57 -06:00
|
|
|
return this->build(ntree, node);
|
2021-09-15 16:09:00 +02:00
|
|
|
}
|
|
|
|
|
this->set_common_flags(socket);
|
|
|
|
|
return socket;
|
|
|
|
|
}
|
2021-08-30 17:13:46 +02:00
|
|
|
|
2021-10-05 11:10:25 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name #Geometry
|
|
|
|
|
* \{ */
|
2021-08-30 17:13:46 +02:00
|
|
|
|
2021-12-15 09:51:57 -06:00
|
|
|
bNodeSocket &Geometry::build(bNodeTree &ntree, bNode &node) const
|
2021-08-30 17:13:46 +02:00
|
|
|
{
|
2025-02-19 13:44:11 +01:00
|
|
|
bNodeSocket &socket = *bke::node_add_socket(ntree,
|
|
|
|
|
node,
|
2024-08-19 20:27:37 +02:00
|
|
|
this->in_out,
|
|
|
|
|
"NodeSocketGeometry",
|
|
|
|
|
this->identifier.c_str(),
|
|
|
|
|
this->name.c_str());
|
2021-09-15 16:09:00 +02:00
|
|
|
this->set_common_flags(socket);
|
2021-08-30 17:13:46 +02:00
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Geometry::matches(const bNodeSocket &socket) const
|
|
|
|
|
{
|
2021-09-15 16:09:00 +02:00
|
|
|
if (!this->matches_common_data(socket)) {
|
2021-08-30 17:13:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2021-09-15 16:09:00 +02:00
|
|
|
if (socket.type != SOCK_GEOMETRY) {
|
2021-08-30 17:13:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 09:51:57 -06:00
|
|
|
bool Geometry::can_connect(const bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
return sockets_can_connect(*this, socket) && socket.type == SOCK_GEOMETRY;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-15 22:18:28 +02:00
|
|
|
Span<bke::GeometryComponent::Type> Geometry::supported_types() const
|
2021-10-26 20:00:03 +02:00
|
|
|
{
|
|
|
|
|
return supported_types_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Geometry::only_realized_data() const
|
|
|
|
|
{
|
|
|
|
|
return only_realized_data_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Geometry::only_instances() const
|
|
|
|
|
{
|
|
|
|
|
return only_instances_;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-15 22:18:28 +02:00
|
|
|
GeometryBuilder &GeometryBuilder::supported_type(bke::GeometryComponent::Type supported_type)
|
2021-10-26 20:00:03 +02:00
|
|
|
{
|
2024-03-18 14:36:03 +01:00
|
|
|
decl_->supported_types_ = {supported_type};
|
2021-10-26 20:00:03 +02:00
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GeometryBuilder &GeometryBuilder::supported_type(
|
2023-06-15 22:18:28 +02:00
|
|
|
blender::Vector<bke::GeometryComponent::Type> supported_types)
|
2021-10-26 20:00:03 +02:00
|
|
|
{
|
2024-03-18 14:36:03 +01:00
|
|
|
decl_->supported_types_ = supported_types;
|
2021-10-26 20:00:03 +02:00
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GeometryBuilder &GeometryBuilder::only_realized_data(bool value)
|
|
|
|
|
{
|
2024-03-18 14:36:03 +01:00
|
|
|
decl_->only_realized_data_ = value;
|
2021-10-26 20:00:03 +02:00
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GeometryBuilder &GeometryBuilder::only_instances(bool value)
|
|
|
|
|
{
|
2024-03-18 14:36:03 +01:00
|
|
|
decl_->only_instances_ = value;
|
2021-10-26 20:00:03 +02:00
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-05 11:10:25 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
2021-12-07 21:05:13 -05:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name #Shader
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2021-12-15 09:51:57 -06:00
|
|
|
bNodeSocket &Shader::build(bNodeTree &ntree, bNode &node) const
|
2021-12-07 21:05:13 -05:00
|
|
|
{
|
2025-02-19 13:44:11 +01:00
|
|
|
bNodeSocket &socket = *bke::node_add_socket(
|
|
|
|
|
ntree, node, this->in_out, "NodeSocketShader", this->identifier.c_str(), this->name.c_str());
|
2021-12-07 21:05:13 -05:00
|
|
|
this->set_common_flags(socket);
|
|
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Shader::matches(const bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (!this->matches_common_data(socket)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (socket.type != SOCK_SHADER) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 09:51:57 -06:00
|
|
|
bool Shader::can_connect(const bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (!sockets_can_connect(*this, socket)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
/* Basic types can convert to shaders, but not the other way around. */
|
2022-12-29 14:55:27 -05:00
|
|
|
if (this->in_out == SOCK_IN) {
|
2022-01-20 16:26:43 -06:00
|
|
|
return ELEM(
|
|
|
|
|
socket.type, SOCK_VECTOR, SOCK_RGBA, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_SHADER);
|
2021-12-15 09:51:57 -06:00
|
|
|
}
|
|
|
|
|
return socket.type == SOCK_SHADER;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-07 21:05:13 -05:00
|
|
|
/** \} */
|
|
|
|
|
|
2023-01-16 15:47:10 -06:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name #Extend
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
bNodeSocket &Extend::build(bNodeTree &ntree, bNode &node) const
|
|
|
|
|
{
|
2025-02-19 13:44:11 +01:00
|
|
|
bNodeSocket &socket = *bke::node_add_socket(ntree,
|
|
|
|
|
node,
|
2024-08-19 20:27:37 +02:00
|
|
|
this->in_out,
|
|
|
|
|
"NodeSocketVirtual",
|
|
|
|
|
this->identifier.c_str(),
|
|
|
|
|
this->name.c_str());
|
2023-01-16 15:47:10 -06:00
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Extend::matches(const bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (socket.identifier != this->identifier) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Extend::can_connect(const bNodeSocket & /*socket*/) const
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bNodeSocket &Extend::update_or_build(bNodeTree & /*ntree*/,
|
|
|
|
|
bNode & /*node*/,
|
|
|
|
|
bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name #Custom
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
bNodeSocket &Custom::build(bNodeTree &ntree, bNode &node) const
|
|
|
|
|
{
|
2024-08-19 20:27:37 +02:00
|
|
|
bNodeSocket &socket = *bke::node_add_socket(
|
2025-02-19 13:44:11 +01:00
|
|
|
ntree, node, this->in_out, idname_, this->identifier.c_str(), this->name.c_str());
|
2023-08-30 12:37:21 +02:00
|
|
|
if (this->init_socket_fn) {
|
|
|
|
|
this->init_socket_fn(node, socket, "interface");
|
|
|
|
|
}
|
2023-01-16 15:47:10 -06:00
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Custom::matches(const bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
if (!this->matches_common_data(socket)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (socket.type != SOCK_CUSTOM) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2025-01-08 16:34:41 +01:00
|
|
|
if (socket.typeinfo->idname != idname_) {
|
2023-06-23 17:47:37 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2023-01-16 15:47:10 -06:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Custom::can_connect(const bNodeSocket &socket) const
|
|
|
|
|
{
|
|
|
|
|
return sockets_can_connect(*this, socket) && STREQ(socket.idname, idname_);
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-23 17:47:37 +02:00
|
|
|
bNodeSocket &Custom::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
|
2023-01-16 15:47:10 -06:00
|
|
|
{
|
2025-01-08 16:34:41 +01:00
|
|
|
if (socket.typeinfo->idname != idname_) {
|
2023-06-23 17:47:37 +02:00
|
|
|
return this->build(ntree, node);
|
|
|
|
|
}
|
|
|
|
|
this->set_common_flags(socket);
|
2023-01-16 15:47:10 -06:00
|
|
|
return socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
2021-08-30 17:13:46 +02:00
|
|
|
} // namespace blender::nodes::decl
|