Nodes: Add support for 2D and 4D vector sockets

This patch adds support for 2D and 4D vector sockets. The default value
structure for vectors was extended to include a new dimensions input,
which can be 2, 3, or 4. The default value was also extended to be a
float4, but only some of its components might be used depending on the
dimensions members.

Each vector subtype now has three variants ending with 2D or 4D as a
prefix depending on its dimensions, and the 2D/4D prefix was taken into
account for the socket type RNA enum functions.

All node systems currently always treat the vectors as 3D, but support
for it in the compositor will shortly follow in another patch.

Depends on #138805.

Pull Request: https://projects.blender.org/blender/blender/pulls/138824
This commit is contained in:
Omar Emara
2025-05-26 11:41:54 +02:00
committed by Omar Emara
parent eb37d19b41
commit 02a95d088e
16 changed files with 533 additions and 106 deletions

View File

@@ -27,7 +27,7 @@
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 78
#define BLENDER_FILE_SUBVERSION 79
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and cancel loading the file, showing a warning to

View File

@@ -628,8 +628,15 @@ void node_unregister_socket_type(bNodeSocketType &stype);
bool node_socket_is_registered(const bNodeSocket &sock);
StringRefNull node_socket_type_label(const bNodeSocketType &stype);
std::optional<StringRefNull> node_static_socket_type(int type, int subtype);
std::optional<StringRefNull> node_static_socket_interface_type_new(int type, int subtype);
/* The optional dimensions argument can be provided for types that support multiple possible
* dimensions like Vector. It is expected to be in the range [2, 4] and if not provided, 3 will be
* assumed. */
std::optional<StringRefNull> node_static_socket_type(int type,
int subtype,
std::optional<int> dimensions = std::nullopt);
std::optional<StringRefNull> node_static_socket_interface_type_new(
int type, int subtype, std::optional<int> dimensions = std::nullopt);
std::optional<StringRefNull> node_static_socket_label(int type, int subtype);
Span<bNodeSocketType *> node_socket_types_get();

View File

@@ -146,6 +146,7 @@ static const bNodeSocketStaticTypeInfo node_socket_subtypes[] = {
{"NodeSocketBool", "NodeTreeInterfaceSocketBool", SOCK_BOOLEAN, PROP_NONE},
{"NodeSocketRotation", "NodeTreeInterfaceSocketRotation", SOCK_ROTATION, PROP_NONE},
{"NodeSocketMatrix", "NodeTreeInterfaceSocketMatrix", SOCK_MATRIX, PROP_NONE},
{"NodeSocketVector", "NodeTreeInterfaceSocketVector", SOCK_VECTOR, PROP_NONE},
{"NodeSocketVectorFactor", "NodeTreeInterfaceSocketVectorFactor", SOCK_VECTOR, PROP_FACTOR},
{"NodeSocketVectorPercentage",
@@ -170,6 +171,63 @@ static const bNodeSocketStaticTypeInfo node_socket_subtypes[] = {
PROP_ACCELERATION},
{"NodeSocketVectorEuler", "NodeTreeInterfaceSocketVectorEuler", SOCK_VECTOR, PROP_EULER},
{"NodeSocketVectorXYZ", "NodeTreeInterfaceSocketVectorXYZ", SOCK_VECTOR, PROP_XYZ},
{"NodeSocketVector2D", "NodeTreeInterfaceSocketVector2D", SOCK_VECTOR, PROP_NONE},
{"NodeSocketVectorFactor2D",
"NodeTreeInterfaceSocketVectorFactor2D",
SOCK_VECTOR,
PROP_FACTOR},
{"NodeSocketVectorPercentage2D",
"NodeTreeInterfaceSocketVectorPercentage2D",
SOCK_VECTOR,
PROP_PERCENTAGE},
{"NodeSocketVectorTranslation2D",
"NodeTreeInterfaceSocketVectorTranslation2D",
SOCK_VECTOR,
PROP_TRANSLATION},
{"NodeSocketVectorDirection2D",
"NodeTreeInterfaceSocketVectorDirection2D",
SOCK_VECTOR,
PROP_DIRECTION},
{"NodeSocketVectorVelocity2D",
"NodeTreeInterfaceSocketVectorVelocity2D",
SOCK_VECTOR,
PROP_VELOCITY},
{"NodeSocketVectorAcceleration2D",
"NodeTreeInterfaceSocketVectorAcceleration2D",
SOCK_VECTOR,
PROP_ACCELERATION},
{"NodeSocketVectorEuler2D", "NodeTreeInterfaceSocketVectorEuler2D", SOCK_VECTOR, PROP_EULER},
{"NodeSocketVectorXYZ2D", "NodeTreeInterfaceSocketVectorXYZ2D", SOCK_VECTOR, PROP_XYZ},
{"NodeSocketVector4D", "NodeTreeInterfaceSocketVector4D", SOCK_VECTOR, PROP_NONE},
{"NodeSocketVectorFactor4D",
"NodeTreeInterfaceSocketVectorFactor4D",
SOCK_VECTOR,
PROP_FACTOR},
{"NodeSocketVectorPercentage4D",
"NodeTreeInterfaceSocketVectorPercentage4D",
SOCK_VECTOR,
PROP_PERCENTAGE},
{"NodeSocketVectorTranslation4D",
"NodeTreeInterfaceSocketVectorTranslation4D",
SOCK_VECTOR,
PROP_TRANSLATION},
{"NodeSocketVectorDirection4D",
"NodeTreeInterfaceSocketVectorDirection4D",
SOCK_VECTOR,
PROP_DIRECTION},
{"NodeSocketVectorVelocity4D",
"NodeTreeInterfaceSocketVectorVelocity4D",
SOCK_VECTOR,
PROP_VELOCITY},
{"NodeSocketVectorAcceleration4D",
"NodeTreeInterfaceSocketVectorAcceleration4D",
SOCK_VECTOR,
PROP_ACCELERATION},
{"NodeSocketVectorEuler4D", "NodeTreeInterfaceSocketVectorEuler4D", SOCK_VECTOR, PROP_EULER},
{"NodeSocketVectorXYZ4D", "NodeTreeInterfaceSocketVectorXYZ4D", SOCK_VECTOR, PROP_XYZ},
{"NodeSocketColor", "NodeTreeInterfaceSocketColor", SOCK_RGBA, PROP_NONE},
{"NodeSocketString", "NodeTreeInterfaceSocketString", SOCK_STRING, PROP_NONE},
{"NodeSocketStringFilePath",

View File

@@ -2979,8 +2979,12 @@ bool node_is_static_socket_type(const bNodeSocketType &stype)
return RNA_struct_is_a(stype.ext_socket.srna, &RNA_NodeSocketStandard);
}
std::optional<StringRefNull> node_static_socket_type(const int type, const int subtype)
std::optional<StringRefNull> node_static_socket_type(const int type,
const int subtype,
const std::optional<int> dimensions)
{
BLI_assert(!(dimensions.has_value() && type != SOCK_VECTOR));
switch (eNodeSocketDatatype(type)) {
case SOCK_FLOAT:
switch (PropertySubType(subtype)) {
@@ -3027,26 +3031,78 @@ std::optional<StringRefNull> node_static_socket_type(const int type, const int s
case SOCK_MATRIX:
return "NodeSocketMatrix";
case SOCK_VECTOR:
switch (PropertySubType(subtype)) {
case PROP_FACTOR:
return "NodeSocketVectorFactor";
case PROP_PERCENTAGE:
return "NodeSocketVectorPercentage";
case PROP_TRANSLATION:
return "NodeSocketVectorTranslation";
case PROP_DIRECTION:
return "NodeSocketVectorDirection";
case PROP_VELOCITY:
return "NodeSocketVectorVelocity";
case PROP_ACCELERATION:
return "NodeSocketVectorAcceleration";
case PROP_EULER:
return "NodeSocketVectorEuler";
case PROP_XYZ:
return "NodeSocketVectorXYZ";
case PROP_NONE:
default:
return "NodeSocketVector";
if (!dimensions.has_value() || dimensions.value() == 3) {
switch (PropertySubType(subtype)) {
case PROP_FACTOR:
return "NodeSocketVectorFactor";
case PROP_PERCENTAGE:
return "NodeSocketVectorPercentage";
case PROP_TRANSLATION:
return "NodeSocketVectorTranslation";
case PROP_DIRECTION:
return "NodeSocketVectorDirection";
case PROP_VELOCITY:
return "NodeSocketVectorVelocity";
case PROP_ACCELERATION:
return "NodeSocketVectorAcceleration";
case PROP_EULER:
return "NodeSocketVectorEuler";
case PROP_XYZ:
return "NodeSocketVectorXYZ";
case PROP_NONE:
default:
return "NodeSocketVector";
}
}
else if (dimensions.value() == 2) {
switch (PropertySubType(subtype)) {
case PROP_FACTOR:
return "NodeSocketVectorFactor2D";
case PROP_PERCENTAGE:
return "NodeSocketVectorPercentage2D";
case PROP_TRANSLATION:
return "NodeSocketVectorTranslation2D";
case PROP_DIRECTION:
return "NodeSocketVectorDirection2D";
case PROP_VELOCITY:
return "NodeSocketVectorVelocity2D";
case PROP_ACCELERATION:
return "NodeSocketVectorAcceleration2D";
case PROP_EULER:
return "NodeSocketVectorEuler2D";
case PROP_XYZ:
return "NodeSocketVectorXYZ2D";
case PROP_NONE:
default:
return "NodeSocketVector2D";
}
}
else if (dimensions.value() == 4) {
switch (PropertySubType(subtype)) {
case PROP_FACTOR:
return "NodeSocketVectorFactor4D";
case PROP_PERCENTAGE:
return "NodeSocketVectorPercentage4D";
case PROP_TRANSLATION:
return "NodeSocketVectorTranslation4D";
case PROP_DIRECTION:
return "NodeSocketVectorDirection4D";
case PROP_VELOCITY:
return "NodeSocketVectorVelocity4D";
case PROP_ACCELERATION:
return "NodeSocketVectorAcceleration4D";
case PROP_EULER:
return "NodeSocketVectorEuler4D";
case PROP_XYZ:
return "NodeSocketVectorXYZ4D";
case PROP_NONE:
default:
return "NodeSocketVector4D";
}
}
else {
BLI_assert_unreachable();
return "NodeSocketVector";
}
case SOCK_RGBA:
return "NodeSocketColor";
@@ -3083,8 +3139,8 @@ std::optional<StringRefNull> node_static_socket_type(const int type, const int s
return std::nullopt;
}
std::optional<StringRefNull> node_static_socket_interface_type_new(const int type,
const int subtype)
std::optional<StringRefNull> node_static_socket_interface_type_new(
const int type, const int subtype, const std::optional<int> dimensions)
{
switch (eNodeSocketDatatype(type)) {
case SOCK_FLOAT:
@@ -3132,26 +3188,78 @@ std::optional<StringRefNull> node_static_socket_interface_type_new(const int typ
case SOCK_MATRIX:
return "NodeTreeInterfaceSocketMatrix";
case SOCK_VECTOR:
switch (PropertySubType(subtype)) {
case PROP_FACTOR:
return "NodeTreeInterfaceSocketVectorFactor";
case PROP_PERCENTAGE:
return "NodeTreeInterfaceSocketVectorPercentage";
case PROP_TRANSLATION:
return "NodeTreeInterfaceSocketVectorTranslation";
case PROP_DIRECTION:
return "NodeTreeInterfaceSocketVectorDirection";
case PROP_VELOCITY:
return "NodeTreeInterfaceSocketVectorVelocity";
case PROP_ACCELERATION:
return "NodeTreeInterfaceSocketVectorAcceleration";
case PROP_EULER:
return "NodeTreeInterfaceSocketVectorEuler";
case PROP_XYZ:
return "NodeTreeInterfaceSocketVectorXYZ";
case PROP_NONE:
default:
return "NodeTreeInterfaceSocketVector";
if (!dimensions.has_value() || dimensions.value() == 3) {
switch (PropertySubType(subtype)) {
case PROP_FACTOR:
return "NodeTreeInterfaceSocketVectorFactor";
case PROP_PERCENTAGE:
return "NodeTreeInterfaceSocketVectorPercentage";
case PROP_TRANSLATION:
return "NodeTreeInterfaceSocketVectorTranslation";
case PROP_DIRECTION:
return "NodeTreeInterfaceSocketVectorDirection";
case PROP_VELOCITY:
return "NodeTreeInterfaceSocketVectorVelocity";
case PROP_ACCELERATION:
return "NodeTreeInterfaceSocketVectorAcceleration";
case PROP_EULER:
return "NodeTreeInterfaceSocketVectorEuler";
case PROP_XYZ:
return "NodeTreeInterfaceSocketVectorXYZ";
case PROP_NONE:
default:
return "NodeTreeInterfaceSocketVector";
}
}
else if (dimensions.value() == 2) {
switch (PropertySubType(subtype)) {
case PROP_FACTOR:
return "NodeTreeInterfaceSocketVectorFactor2D";
case PROP_PERCENTAGE:
return "NodeTreeInterfaceSocketVectorPercentage2D";
case PROP_TRANSLATION:
return "NodeTreeInterfaceSocketVectorTranslation2D";
case PROP_DIRECTION:
return "NodeTreeInterfaceSocketVectorDirection2D";
case PROP_VELOCITY:
return "NodeTreeInterfaceSocketVectorVelocity2D";
case PROP_ACCELERATION:
return "NodeTreeInterfaceSocketVectorAcceleration2D";
case PROP_EULER:
return "NodeTreeInterfaceSocketVectorEuler2D";
case PROP_XYZ:
return "NodeTreeInterfaceSocketVectorXYZ2D";
case PROP_NONE:
default:
return "NodeTreeInterfaceSocketVector2D";
}
}
else if (dimensions.value() == 4) {
switch (PropertySubType(subtype)) {
case PROP_FACTOR:
return "NodeTreeInterfaceSocketVectorFactor4D";
case PROP_PERCENTAGE:
return "NodeTreeInterfaceSocketVectorPercentage4D";
case PROP_TRANSLATION:
return "NodeTreeInterfaceSocketVectorTranslation4D";
case PROP_DIRECTION:
return "NodeTreeInterfaceSocketVectorDirection4D";
case PROP_VELOCITY:
return "NodeTreeInterfaceSocketVectorVelocity4D";
case PROP_ACCELERATION:
return "NodeTreeInterfaceSocketVectorAcceleration4D";
case PROP_EULER:
return "NodeTreeInterfaceSocketVectorEuler4D";
case PROP_XYZ:
return "NodeTreeInterfaceSocketVectorXYZ4D";
case PROP_NONE:
default:
return "NodeTreeInterfaceSocketVector4D";
}
}
else {
BLI_assert_unreachable();
return "NodeTreeInterfaceSocketVector";
}
case SOCK_RGBA:
return "NodeTreeInterfaceSocketColor";

View File

@@ -147,6 +147,7 @@ template<> void socket_data_init_impl(bNodeSocketValueVector &data)
{
static float default_value[] = {0.0f, 0.0f, 0.0f};
data.subtype = PROP_NONE;
data.dimensions = 3;
copy_v3_v3(data.value, default_value);
data.min = -FLT_MAX;
data.max = FLT_MAX;

View File

@@ -4050,6 +4050,41 @@ static void do_version_replace_image_info_node_coordinates(bNodeTree *node_tree)
}
}
/* Vector sockets can now have different dimensions, so set the dimensions for existing sockets to
* 3.*/
static void do_version_vector_sockets_dimensions(bNodeTree *node_tree)
{
node_tree->tree_interface.foreach_item([&](bNodeTreeInterfaceItem &item) {
if (item.item_type != NODE_INTERFACE_SOCKET) {
return true;
}
bNodeTreeInterfaceSocket &interface_socket =
blender::bke::node_interface::get_item_as<bNodeTreeInterfaceSocket>(item);
blender::bke::bNodeSocketType *base_typeinfo = blender::bke::node_socket_type_find(
interface_socket.socket_type);
if (base_typeinfo->type == SOCK_VECTOR) {
blender::bke::node_interface::get_socket_data_as<bNodeSocketValueVector>(interface_socket)
.dimensions = 3;
}
return true;
});
LISTBASE_FOREACH (bNode *, node, &node_tree->nodes) {
LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
if (socket->type == SOCK_VECTOR) {
socket->default_value_typed<bNodeSocketValueVector>()->dimensions = 3;
}
}
LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
if (socket->type == SOCK_VECTOR) {
socket->default_value_typed<bNodeSocketValueVector>()->dimensions = 3;
}
}
}
}
void do_versions_after_linking_450(FileData * /*fd*/, Main *bmain)
{
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 405, 8)) {
@@ -5820,6 +5855,13 @@ void blo_do_versions_450(FileData * /*fd*/, Library * /*lib*/, Main *bmain)
FOREACH_NODETREE_END;
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 405, 79)) {
FOREACH_NODETREE_BEGIN (bmain, node_tree, id) {
do_version_vector_sockets_dimensions(node_tree);
}
FOREACH_NODETREE_END;
}
/* Always run this versioning (keep at the bottom of the function). Meshes are written with the
* legacy format which always needs to be converted to the new format on file load. To be moved
* to a subversion check in 5.0. */

View File

@@ -1458,6 +1458,7 @@ static void std_node_socket_interface_draw(ID *id,
}
case SOCK_VECTOR: {
col->prop(&ptr, "subtype", DEFAULT_FLAGS, IFACE_("Subtype"), ICON_NONE);
col->prop(&ptr, "dimensions", DEFAULT_FLAGS, IFACE_("Dimensions"), ICON_NONE);
col->prop(&ptr, "default_value", UI_ITEM_R_EXPAND, IFACE_("Default"), ICON_NONE);
uiLayout *sub = &col->column(true);
sub->prop(&ptr, "min_value", DEFAULT_FLAGS, IFACE_("Min"), ICON_NONE);

View File

@@ -988,8 +988,11 @@ typedef struct bNodeSocketValueBoolean {
typedef struct bNodeSocketValueVector {
/** RNA subtype. */
int subtype;
float value[3];
/* Only some of the values might be used depending on the dimensions. */
float value[4];
float min, max;
/* The number of dimensions of the vector. Can be 2, 3, or 4. */
int dimensions;
} bNodeSocketValueVector;
typedef struct bNodeSocketValueRotation {

View File

@@ -529,11 +529,12 @@ void rna_NodeSocketStandard_vector_default(PointerRNA *ptr,
{
bNodeSocket *sock = static_cast<bNodeSocket *>(ptr->data);
if (!sock->runtime->declaration) {
std::fill_n(r_values, 3, 0.0f);
const int dimensions = sock->default_value_typed<bNodeSocketValueVector>()->dimensions;
std::fill_n(r_values, dimensions, 0.0f);
return;
}
auto *decl = static_cast<const blender::nodes::decl::Vector *>(sock->runtime->declaration);
std::copy_n(&decl->default_value.x, 3, r_values);
std::copy_n(&decl->default_value.x, decl->dimensions, r_values);
}
void rna_NodeSocketStandard_color_default(PointerRNA *ptr, PropertyRNA * /*prop*/, float *r_values)
@@ -1226,7 +1227,8 @@ static void rna_def_node_socket_interface_matrix(BlenderRNA *brna, const char *i
static void rna_def_node_socket_vector(BlenderRNA *brna,
const char *identifier,
PropertySubType subtype)
PropertySubType subtype,
int dimensions)
{
StructRNA *srna;
PropertyRNA *prop;
@@ -1240,6 +1242,7 @@ static void rna_def_node_socket_vector(BlenderRNA *brna,
prop = RNA_def_property(srna, "default_value", PROP_FLOAT, subtype);
RNA_def_property_float_sdna(prop, nullptr, "value");
RNA_def_property_array(prop, dimensions);
RNA_def_property_float_default_func(prop, "rna_NodeSocketStandard_vector_default");
RNA_def_property_float_funcs(prop, nullptr, nullptr, "rna_NodeSocketStandard_vector_range");
RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket");
@@ -1251,7 +1254,8 @@ static void rna_def_node_socket_vector(BlenderRNA *brna,
static void rna_def_node_socket_interface_vector(BlenderRNA *brna,
const char *identifier,
PropertySubType subtype)
PropertySubType subtype,
int dimensions)
{
StructRNA *srna;
PropertyRNA *prop;
@@ -1271,8 +1275,17 @@ static void rna_def_node_socket_interface_vector(BlenderRNA *brna,
RNA_def_property_ui_text(prop, "Subtype", "Subtype of the default value");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeTreeInterfaceSocket_value_update");
prop = RNA_def_property(srna, "dimensions", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, nullptr, "dimensions");
RNA_def_property_range(prop, 2, 4);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Dimensions", "Dimensions of the vector socket");
RNA_def_property_update(
prop, NC_NODE | NA_EDITED, "rna_NodeTreeInterfaceSocketVector_dimensions_update");
prop = RNA_def_property(srna, "default_value", PROP_FLOAT, subtype);
RNA_def_property_float_sdna(prop, nullptr, "value");
RNA_def_property_array(prop, dimensions);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_float_funcs(
prop, nullptr, nullptr, "rna_NodeTreeInterfaceSocketVector_default_value_range");
@@ -1810,6 +1823,7 @@ static const bNodeSocketStaticTypeInfo node_socket_subtypes[] = {
{"NodeSocketBool", "NodeTreeInterfaceSocketBool", SOCK_BOOLEAN, PROP_NONE},
{"NodeSocketRotation", "NodeTreeInterfaceSocketRotation", SOCK_ROTATION, PROP_NONE},
{"NodeSocketMatrix", "NodeTreeInterfaceSocketMatrix", SOCK_MATRIX, PROP_NONE},
{"NodeSocketVector", "NodeTreeInterfaceSocketVector", SOCK_VECTOR, PROP_NONE},
{"NodeSocketVectorFactor", "NodeTreeInterfaceSocketVectorFactor", SOCK_VECTOR, PROP_FACTOR},
{"NodeSocketVectorPercentage",
@@ -1834,6 +1848,63 @@ static const bNodeSocketStaticTypeInfo node_socket_subtypes[] = {
PROP_ACCELERATION},
{"NodeSocketVectorEuler", "NodeTreeInterfaceSocketVectorEuler", SOCK_VECTOR, PROP_EULER},
{"NodeSocketVectorXYZ", "NodeTreeInterfaceSocketVectorXYZ", SOCK_VECTOR, PROP_XYZ},
{"NodeSocketVector2D", "NodeTreeInterfaceSocketVector2D", SOCK_VECTOR, PROP_NONE},
{"NodeSocketVectorFactor2D",
"NodeTreeInterfaceSocketVectorFactor2D",
SOCK_VECTOR,
PROP_FACTOR},
{"NodeSocketVectorPercentage2D",
"NodeTreeInterfaceSocketVectorPercentage2D",
SOCK_VECTOR,
PROP_PERCENTAGE},
{"NodeSocketVectorTranslation2D",
"NodeTreeInterfaceSocketVectorTranslation2D",
SOCK_VECTOR,
PROP_TRANSLATION},
{"NodeSocketVectorDirection2D",
"NodeTreeInterfaceSocketVectorDirection2D",
SOCK_VECTOR,
PROP_DIRECTION},
{"NodeSocketVectorVelocity2D",
"NodeTreeInterfaceSocketVectorVelocity2D",
SOCK_VECTOR,
PROP_VELOCITY},
{"NodeSocketVectorAcceleration2D",
"NodeTreeInterfaceSocketVectorAcceleration2D",
SOCK_VECTOR,
PROP_ACCELERATION},
{"NodeSocketVectorEuler2D", "NodeTreeInterfaceSocketVectorEuler2D", SOCK_VECTOR, PROP_EULER},
{"NodeSocketVectorXYZ2D", "NodeTreeInterfaceSocketVectorXYZ2D", SOCK_VECTOR, PROP_XYZ},
{"NodeSocketVector4D", "NodeTreeInterfaceSocketVector4D", SOCK_VECTOR, PROP_NONE},
{"NodeSocketVectorFactor4D",
"NodeTreeInterfaceSocketVectorFactor4D",
SOCK_VECTOR,
PROP_FACTOR},
{"NodeSocketVectorPercentage4D",
"NodeTreeInterfaceSocketVectorPercentage4D",
SOCK_VECTOR,
PROP_PERCENTAGE},
{"NodeSocketVectorTranslation4D",
"NodeTreeInterfaceSocketVectorTranslation4D",
SOCK_VECTOR,
PROP_TRANSLATION},
{"NodeSocketVectorDirection4D",
"NodeTreeInterfaceSocketVectorDirection4D",
SOCK_VECTOR,
PROP_DIRECTION},
{"NodeSocketVectorVelocity4D",
"NodeTreeInterfaceSocketVectorVelocity4D",
SOCK_VECTOR,
PROP_VELOCITY},
{"NodeSocketVectorAcceleration4D",
"NodeTreeInterfaceSocketVectorAcceleration4D",
SOCK_VECTOR,
PROP_ACCELERATION},
{"NodeSocketVectorEuler4D", "NodeTreeInterfaceSocketVectorEuler4D", SOCK_VECTOR, PROP_EULER},
{"NodeSocketVectorXYZ4D", "NodeTreeInterfaceSocketVectorXYZ4D", SOCK_VECTOR, PROP_XYZ},
{"NodeSocketColor", "NodeTreeInterfaceSocketColor", SOCK_RGBA, PROP_NONE},
{"NodeSocketString", "NodeTreeInterfaceSocketString", SOCK_STRING, PROP_NONE},
{"NodeSocketStringFilePath",
@@ -1874,7 +1945,15 @@ static void rna_def_node_socket_subtypes(BlenderRNA *brna)
rna_def_node_socket_matrix(brna, identifier);
break;
case SOCK_VECTOR:
rna_def_node_socket_vector(brna, identifier, info.subtype);
if (blender::StringRef(identifier).endswith("2D")) {
rna_def_node_socket_vector(brna, identifier, info.subtype, 2);
}
else if (blender::StringRef(identifier).endswith("4D")) {
rna_def_node_socket_vector(brna, identifier, info.subtype, 4);
}
else {
rna_def_node_socket_vector(brna, identifier, info.subtype, 3);
}
break;
case SOCK_RGBA:
rna_def_node_socket_color(brna, identifier);
@@ -1947,7 +2026,15 @@ void rna_def_node_socket_interface_subtypes(BlenderRNA *brna)
rna_def_node_socket_interface_matrix(brna, identifier);
break;
case SOCK_VECTOR:
rna_def_node_socket_interface_vector(brna, identifier, info.subtype);
if (blender::StringRef(identifier).endswith("2D")) {
rna_def_node_socket_interface_vector(brna, identifier, info.subtype, 2);
}
else if (blender::StringRef(identifier).endswith("4D")) {
rna_def_node_socket_interface_vector(brna, identifier, info.subtype, 4);
}
else {
rna_def_node_socket_interface_vector(brna, identifier, info.subtype, 3);
}
break;
case SOCK_RGBA:
rna_def_node_socket_interface_color(brna, identifier);

View File

@@ -397,8 +397,10 @@ static bool is_socket_type_supported(blender::bke::bNodeTreeType *ntreetype,
return false;
}
/* Only use basic socket types for this enum. */
if (socket_type->subtype != PROP_NONE) {
/* Only basic socket types are supported. */
blender::bke::bNodeSocketType *base_socket_type = blender::bke::node_socket_type_find_static(
socket_type->type, PROP_NONE);
if (socket_type != base_socket_type) {
return false;
}
@@ -816,6 +818,31 @@ static void rna_NodeTreeInterfaceSocket_value_update(Main *bmain, Scene *scene,
rna_NodeTreeInterfaceItem_update(bmain, scene, ptr);
}
/* If the dimensions of the vector socket changed, we need to update the socket type, since each
* dimensions value has its own sub-type. */
static void rna_NodeTreeInterfaceSocketVector_dimensions_update(Main *bmain,
Scene *scene,
PointerRNA *ptr)
{
bNodeTreeInterfaceSocket *socket = static_cast<bNodeTreeInterfaceSocket *>(ptr->data);
/* Store a copy of the existing default value since it will be freed when setting the socket type
* below.*/
const bNodeSocketValueVector default_value = *static_cast<bNodeSocketValueVector *>(
socket->socket_data);
const blender::StringRefNull socket_idname = *blender::bke::node_static_socket_type(
SOCK_VECTOR, default_value.subtype, default_value.dimensions);
socket->set_socket_type(socket_idname);
/* Restore existing default value. */
*static_cast<bNodeSocketValueVector *>(socket->socket_data) = default_value;
rna_NodeTreeInterfaceSocket_value_update(bmain, scene, ptr);
}
static bool rna_NodeTreeInterfaceSocketMaterial_default_value_poll(PointerRNA * /*ptr*/,
PointerRNA value)
{

View File

@@ -747,14 +747,11 @@ const EnumPropertyItem *rna_node_tree_type_itemf(
int rna_node_socket_idname_to_enum(const char *idname)
{
using namespace blender;
Span<const bke::bNodeSocketType *> types = bke::node_socket_types_get();
for (const int i : types.index_range()) {
const bke::bNodeSocketType *nt = types[i];
if (nt->idname == idname) {
return i;
}
}
return -1;
bke::bNodeSocketType *socket_type = bke::node_socket_type_find(idname);
bke::bNodeSocketType *base_socket_type = bke::node_socket_type_find_static(socket_type->type,
PROP_NONE);
return bke::node_socket_types_get().first_index(base_socket_type);
}
blender::bke::bNodeSocketType *rna_node_socket_type_from_enum(int value)

View File

@@ -78,9 +78,10 @@ class Vector : public SocketDeclaration {
public:
static constexpr eNodeSocketDatatype static_socket_type = SOCK_VECTOR;
float3 default_value = {0, 0, 0};
float4 default_value = {0, 0, 0, 0};
float soft_min_value = -FLT_MAX;
float soft_max_value = FLT_MAX;
int dimensions = 3;
PropertySubType subtype = PROP_NONE;
friend VectorBuilder;
@@ -95,8 +96,11 @@ class Vector : public SocketDeclaration {
class VectorBuilder : public SocketDeclarationBuilder<Vector> {
public:
VectorBuilder &default_value(const float2 value);
VectorBuilder &default_value(const float3 value);
VectorBuilder &default_value(const float4 value);
VectorBuilder &subtype(PropertySubType subtype);
VectorBuilder &dimensions(int dimensions);
VectorBuilder &min(float min);
VectorBuilder &max(float max);
VectorBuilder &compact();
@@ -481,7 +485,19 @@ inline IntBuilder &IntBuilder::subtype(PropertySubType subtype)
/** \name #VectorBuilder Inline Methods
* \{ */
inline VectorBuilder &VectorBuilder::default_value(const float2 value)
{
decl_->default_value = float4(value, 0.0f, 0.0f);
return *this;
}
inline VectorBuilder &VectorBuilder::default_value(const float3 value)
{
decl_->default_value = float4(value, 0.0f);
return *this;
}
inline VectorBuilder &VectorBuilder::default_value(const float4 value)
{
decl_->default_value = value;
return *this;
@@ -493,6 +509,13 @@ inline VectorBuilder &VectorBuilder::subtype(PropertySubType subtype)
return *this;
}
inline VectorBuilder &VectorBuilder::dimensions(int dimensions)
{
BLI_assert(dimensions >= 2 && dimensions <= 4);
decl_->dimensions = dimensions;
return *this;
}
inline VectorBuilder &VectorBuilder::min(const float min)
{
decl_->soft_min_value = min;

View File

@@ -141,14 +141,16 @@ std::unique_ptr<IDProperty, bke::idprop::IDPropertyDeleter> id_property_create_f
const bNodeSocketValueVector *value = static_cast<const bNodeSocketValueVector *>(
socket.socket_data);
auto property = bke::idprop::create(
identifier, Span<float>{value->value[0], value->value[1], value->value[2]});
identifier,
Span<float>{value->value[0], value->value[1], value->value[2], value->value[3]}
.take_front(value->dimensions));
IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property.get());
ui_data->base.rna_subtype = value->subtype;
ui_data->soft_min = double(value->min);
ui_data->soft_max = double(value->max);
ui_data->default_array = MEM_malloc_arrayN<double>(3, "mod_prop_default");
ui_data->default_array_len = 3;
for (const int i : IndexRange(3)) {
ui_data->default_array = MEM_malloc_arrayN<double>(value->dimensions, "mod_prop_default");
ui_data->default_array_len = value->dimensions;
for (const int i : IndexRange(value->dimensions)) {
ui_data->default_array[i] = double(value->value[i]);
}
return property;
@@ -273,21 +275,25 @@ static bool old_id_property_type_matches_socket_convert_to_new_float_vec(
const IDProperty &old_property, IDProperty *new_property, const int len)
{
if (!(old_property.type == IDP_ARRAY &&
ELEM(old_property.subtype, IDP_INT, IDP_FLOAT, IDP_DOUBLE) && old_property.len == len))
ELEM(old_property.subtype, IDP_INT, IDP_FLOAT, IDP_DOUBLE)))
{
return false;
}
if (new_property) {
BLI_assert(new_property->type == IDP_ARRAY && new_property->subtype == IDP_FLOAT &&
new_property->len == len);
BLI_assert(new_property->type == IDP_ARRAY && new_property->subtype == IDP_FLOAT);
switch (old_property.subtype) {
case IDP_DOUBLE: {
double *const old_value = static_cast<double *const>(IDP_Array(&old_property));
float *new_value = static_cast<float *>(new_property->data.pointer);
for (int i = 0; i < len; i++) {
new_value[i] = float(old_value[i]);
if (i < old_property.len) {
new_value[i] = float(old_value[i]);
}
else {
new_value[i] = 0.0f;
}
}
break;
}
@@ -295,13 +301,26 @@ static bool old_id_property_type_matches_socket_convert_to_new_float_vec(
int *const old_value = static_cast<int *const>(IDP_Array(&old_property));
float *new_value = static_cast<float *>(new_property->data.pointer);
for (int i = 0; i < len; i++) {
new_value[i] = float(old_value[i]);
if (i < old_property.len) {
new_value[i] = float(old_value[i]);
}
else {
new_value[i] = 0.0f;
}
}
break;
}
case IDP_FLOAT: {
float *const old_value = static_cast<float *const>(IDP_Array(&old_property));
memcpy(new_property->data.pointer, old_value, sizeof(float) * size_t(len));
float *new_value = static_cast<float *>(new_property->data.pointer);
for (int i = 0; i < len; i++) {
if (i < old_property.len) {
new_value[i] = old_value[i];
}
else {
new_value[i] = 0.0f;
}
}
break;
}
}
@@ -360,7 +379,12 @@ static bool old_id_property_type_matches_socket_convert_to_new(
return true;
case SOCK_INT:
return old_id_property_type_matches_socket_convert_to_new_int(old_property, new_property);
case SOCK_VECTOR:
case SOCK_VECTOR: {
const bNodeSocketValueVector *value = static_cast<const bNodeSocketValueVector *>(
socket.socket_data);
return old_id_property_type_matches_socket_convert_to_new_float_vec(
old_property, new_property, value->dimensions);
}
case SOCK_ROTATION:
return old_id_property_type_matches_socket_convert_to_new_float_vec(
old_property, new_property, 3);
@@ -468,18 +492,30 @@ static void init_socket_cpp_value_from_property(const IDProperty &property,
}
case SOCK_VECTOR: {
const void *property_array = IDP_Array(&property);
float3 value;
BLI_assert(property.len >= 2 && property.len <= 4);
float4 values = float4(0.0f);
if (property.subtype == IDP_FLOAT) {
value = float3(static_cast<const float *>(property_array));
for (int i = 0; i < property.len; i++) {
values[i] = static_cast<const float *>(property_array)[i];
}
}
else if (property.subtype == IDP_INT) {
value = float3(int3(static_cast<const int *>(property_array)));
for (int i = 0; i < property.len; i++) {
values[i] = float(static_cast<const int *>(property_array)[i]);
}
}
else if (property.subtype == IDP_DOUBLE) {
for (int i = 0; i < property.len; i++) {
values[i] = float(static_cast<const double *>(property_array)[i]);
}
}
else {
BLI_assert(property.subtype == IDP_DOUBLE);
value = float3(double3(static_cast<const double *>(property_array)));
BLI_assert_unreachable();
}
new (r_value) bke::SocketValueVariant(value);
/* Only float3 vectors are supported for now. */
new (r_value) bke::SocketValueVariant(float3(values));
break;
}
case SOCK_RGBA: {

View File

@@ -281,7 +281,8 @@ static BaseSocketDeclarationBuilder &build_interface_socket_declaration(
const auto &value = node_interface::get_socket_data_as<bNodeSocketValueVector>(io_socket);
decl = &b.add_socket<decl::Vector>(name, identifier, in_out)
.subtype(PropertySubType(value.subtype))
.default_value(value.value)
.default_value(float4(value.value))
.dimensions(value.dimensions)
.min(value.min)
.max(value.max);
break;

View File

@@ -79,6 +79,7 @@ bNodeSocket *node_add_socket_from_template(bNodeTree *ntree,
dval->value[0] = stemp->val1;
dval->value[1] = stemp->val2;
dval->value[2] = stemp->val3;
dval->dimensions = 3;
dval->min = stemp->min;
dval->max = stemp->max;
break;
@@ -610,6 +611,7 @@ void node_socket_init_default_value_data(eNodeSocketDatatype datatype, int subty
bNodeSocketValueVector *dval = MEM_callocN<bNodeSocketValueVector>(
"node socket value vector");
dval->subtype = subtype;
dval->dimensions = 3;
copy_v3_v3(dval->value, default_value);
dval->min = -FLT_MAX;
dval->max = FLT_MAX;
@@ -854,11 +856,12 @@ static void standard_node_socket_interface_from_socket(ID * /*id*/,
void ED_init_standard_node_socket_type(bke::bNodeSocketType *);
static bke::bNodeSocketType *make_standard_socket_type(int type, int subtype)
static bke::bNodeSocketType *make_standard_socket_type(
int type, int subtype, std::optional<int> dimensions = std::nullopt)
{
const StringRefNull socket_idname = *bke::node_static_socket_type(type, subtype);
const StringRefNull interface_idname = *bke::node_static_socket_interface_type_new(type,
subtype);
const StringRefNull socket_idname = *bke::node_static_socket_type(type, subtype, dimensions);
const StringRefNull interface_idname = *bke::node_static_socket_interface_type_new(
type, subtype, dimensions);
const StringRefNull socket_label = *bke::node_static_socket_label(type, subtype);
const StringRefNull socket_subtype_label = blender::bke::node_socket_sub_type_label(subtype);
bke::bNodeSocketType *stype;
@@ -1051,9 +1054,9 @@ static bke::bNodeSocketType *make_socket_type_int(PropertySubType subtype)
return socktype;
}
static bke::bNodeSocketType *make_socket_type_vector(PropertySubType subtype)
static bke::bNodeSocketType *make_socket_type_vector(PropertySubType subtype, const int dimensions)
{
bke::bNodeSocketType *socktype = make_standard_socket_type(SOCK_VECTOR, subtype);
bke::bNodeSocketType *socktype = make_standard_socket_type(SOCK_VECTOR, subtype, dimensions);
socktype->base_cpp_type = &blender::CPPType::get<blender::float3>();
socktype->get_base_cpp_value = [](const void *socket_value, void *r_value) {
*(blender::float3 *)r_value = ((bNodeSocketValueVector *)socket_value)->value;
@@ -1216,15 +1219,35 @@ void register_standard_node_socket_types()
bke::node_register_socket_type(*make_socket_type_rotation());
bke::node_register_socket_type(*make_socket_type_matrix());
bke::node_register_socket_type(*make_socket_type_vector(PROP_NONE));
bke::node_register_socket_type(*make_socket_type_vector(PROP_FACTOR));
bke::node_register_socket_type(*make_socket_type_vector(PROP_PERCENTAGE));
bke::node_register_socket_type(*make_socket_type_vector(PROP_TRANSLATION));
bke::node_register_socket_type(*make_socket_type_vector(PROP_DIRECTION));
bke::node_register_socket_type(*make_socket_type_vector(PROP_VELOCITY));
bke::node_register_socket_type(*make_socket_type_vector(PROP_ACCELERATION));
bke::node_register_socket_type(*make_socket_type_vector(PROP_EULER));
bke::node_register_socket_type(*make_socket_type_vector(PROP_XYZ));
bke::node_register_socket_type(*make_socket_type_vector(PROP_NONE, 3));
bke::node_register_socket_type(*make_socket_type_vector(PROP_FACTOR, 3));
bke::node_register_socket_type(*make_socket_type_vector(PROP_PERCENTAGE, 3));
bke::node_register_socket_type(*make_socket_type_vector(PROP_TRANSLATION, 3));
bke::node_register_socket_type(*make_socket_type_vector(PROP_DIRECTION, 3));
bke::node_register_socket_type(*make_socket_type_vector(PROP_VELOCITY, 3));
bke::node_register_socket_type(*make_socket_type_vector(PROP_ACCELERATION, 3));
bke::node_register_socket_type(*make_socket_type_vector(PROP_EULER, 3));
bke::node_register_socket_type(*make_socket_type_vector(PROP_XYZ, 3));
bke::node_register_socket_type(*make_socket_type_vector(PROP_NONE, 2));
bke::node_register_socket_type(*make_socket_type_vector(PROP_FACTOR, 2));
bke::node_register_socket_type(*make_socket_type_vector(PROP_PERCENTAGE, 2));
bke::node_register_socket_type(*make_socket_type_vector(PROP_TRANSLATION, 2));
bke::node_register_socket_type(*make_socket_type_vector(PROP_DIRECTION, 2));
bke::node_register_socket_type(*make_socket_type_vector(PROP_VELOCITY, 2));
bke::node_register_socket_type(*make_socket_type_vector(PROP_ACCELERATION, 2));
bke::node_register_socket_type(*make_socket_type_vector(PROP_EULER, 2));
bke::node_register_socket_type(*make_socket_type_vector(PROP_XYZ, 2));
bke::node_register_socket_type(*make_socket_type_vector(PROP_NONE, 4));
bke::node_register_socket_type(*make_socket_type_vector(PROP_FACTOR, 4));
bke::node_register_socket_type(*make_socket_type_vector(PROP_PERCENTAGE, 4));
bke::node_register_socket_type(*make_socket_type_vector(PROP_TRANSLATION, 4));
bke::node_register_socket_type(*make_socket_type_vector(PROP_DIRECTION, 4));
bke::node_register_socket_type(*make_socket_type_vector(PROP_VELOCITY, 4));
bke::node_register_socket_type(*make_socket_type_vector(PROP_ACCELERATION, 4));
bke::node_register_socket_type(*make_socket_type_vector(PROP_EULER, 4));
bke::node_register_socket_type(*make_socket_type_vector(PROP_XYZ, 4));
bke::node_register_socket_type(*make_socket_type_rgba());

View File

@@ -68,6 +68,14 @@ static void modify_subtype_except_for_storage(bNodeSocket &socket, int new_subty
socket.typeinfo = socktype;
}
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);
STRNCPY(socket.idname, idname.c_str());
bke::bNodeSocketType *socktype = bke::node_socket_type_find(idname);
socket.typeinfo = socktype;
}
/* -------------------------------------------------------------------- */
/** \name #Float
* \{ */
@@ -215,16 +223,14 @@ bNodeSocket &Int::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &so
bNodeSocket &Vector::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *bke::node_add_static_socket(ntree,
node,
this->in_out,
SOCK_VECTOR,
this->subtype,
this->identifier.c_str(),
this->name.c_str());
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());
this->set_common_flags(socket);
bNodeSocketValueVector &value = *(bNodeSocketValueVector *)socket.default_value;
copy_v3_v3(value.value, this->default_value);
std::copy_n(&this->default_value[0], this->dimensions, value.value);
value.dimensions = this->dimensions;
value.min = this->soft_min_value;
value.max = this->soft_max_value;
return socket;
@@ -243,6 +249,9 @@ bool Vector::matches(const bNodeSocket &socket) const
}
const bNodeSocketValueVector &value = *static_cast<const bNodeSocketValueVector *>(
socket.default_value);
if (value.dimensions != this->dimensions) {
return false;
}
if (value.min != this->soft_min_value) {
return false;
}
@@ -270,11 +279,15 @@ bNodeSocket &Vector::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket
return this->build(ntree, node);
}
if (socket.typeinfo->subtype != this->subtype) {
modify_subtype_except_for_storage(socket, this->subtype);
modify_subtype_except_for_storage(socket, this->subtype, this->dimensions);
}
this->set_common_flags(socket);
bNodeSocketValueVector &value = *(bNodeSocketValueVector *)socket.default_value;
if (value.dimensions != this->dimensions) {
modify_subtype_except_for_storage(socket, this->subtype, this->dimensions);
}
value.subtype = this->subtype;
value.dimensions = this->dimensions;
value.min = this->soft_min_value;
value.max = this->soft_max_value;
return socket;