Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_node.h10
-rw-r--r--source/blender/blenkernel/intern/node.cc20
-rw-r--r--source/blender/blenloader/intern/versioning_270.c4
-rw-r--r--source/blender/nodes/CMakeLists.txt4
-rw-r--r--source/blender/nodes/NOD_node_declaration.hh135
-rw-r--r--source/blender/nodes/NOD_socket.h2
-rw-r--r--source/blender/nodes/NOD_socket_declarations.hh239
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh1
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc38
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc32
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_edge_split.cc36
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_material.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc25
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc31
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_object_info.cc27
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transform.cc24
-rw-r--r--source/blender/nodes/intern/node_declaration.cc65
-rw-r--r--source/blender/nodes/intern/node_socket.cc93
-rw-r--r--source/blender/nodes/intern/node_socket_declarations.cc330
20 files changed, 1001 insertions, 143 deletions
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 379d4332473..5e0526ab262 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -113,6 +113,7 @@ namespace blender {
namespace nodes {
class NodeMultiFunctionBuilder;
class GeoNodeExecParams;
+class NodeDeclarationBuilder;
} // namespace nodes
namespace fn {
class CPPType;
@@ -122,6 +123,7 @@ class MFDataType;
using NodeMultiFunctionBuildFunction = void (*)(blender::nodes::NodeMultiFunctionBuilder &builder);
using NodeGeometryExecFunction = void (*)(blender::nodes::GeoNodeExecParams params);
+using NodeDeclareFunction = void (*)(blender::nodes::NodeDeclarationBuilder &builder);
using SocketGetCPPTypeFunction = const blender::fn::CPPType *(*)();
using SocketGetCPPValueFunction = void (*)(const struct bNodeSocket &socket, void *r_value);
using SocketGetGeometryNodesCPPTypeFunction = const blender::fn::CPPType *(*)();
@@ -131,6 +133,7 @@ using SocketGetGeometryNodesCPPValueFunction = void (*)(const struct bNodeSocket
#else
typedef void *NodeMultiFunctionBuildFunction;
typedef void *NodeGeometryExecFunction;
+typedef void *NodeDeclareFunction;
typedef void *SocketGetCPPTypeFunction;
typedef void *SocketGetGeometryNodesCPPTypeFunction;
typedef void *SocketGetGeometryNodesCPPValueFunction;
@@ -334,6 +337,9 @@ typedef struct bNodeType {
NodeGeometryExecFunction geometry_node_execute;
bool geometry_node_execute_supports_laziness;
+ /* Declares which sockets the node has. */
+ NodeDeclareFunction declare;
+
/* RNA integration */
ExtensionRNA rna_ext;
} bNodeType;
@@ -615,6 +621,10 @@ struct bNodeSocket *nodeInsertStaticSocket(struct bNodeTree *ntree,
const char *identifier,
const char *name);
void nodeRemoveSocket(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock);
+void nodeRemoveSocketEx(struct bNodeTree *ntree,
+ struct bNode *node,
+ struct bNodeSocket *sock,
+ bool do_id_user);
void nodeRemoveAllSockets(struct bNodeTree *ntree, struct bNode *node);
void nodeModifySocketType(struct bNodeTree *ntree,
struct bNode *node,
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index fb43d1fc87f..48d747e2bf3 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -79,6 +79,7 @@
#include "NOD_composite.h"
#include "NOD_function.h"
#include "NOD_geometry.h"
+#include "NOD_node_declaration.hh"
#include "NOD_shader.h"
#include "NOD_socket.h"
#include "NOD_texture.h"
@@ -887,7 +888,7 @@ void ntreeBlendReadLib(struct BlendLibReader *reader, struct bNodeTree *ntree)
* to match the static layout. */
if (!BLO_read_lib_is_undo(reader)) {
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- node_verify_socket_templates(ntree, node);
+ node_verify_sockets(ntree, node, false);
}
}
}
@@ -1011,6 +1012,13 @@ IDTypeInfo IDType_ID_NT = {
static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype)
{
+ if (ntype->declare != nullptr) {
+ blender::nodes::NodeDeclaration node_decl;
+ blender::nodes::NodeDeclarationBuilder builder{node_decl};
+ ntype->declare(builder);
+ node_decl.build(*ntree, *node);
+ return;
+ }
bNodeSocketTemplate *sockdef;
/* bNodeSocket *sock; */ /* UNUSED */
@@ -1916,6 +1924,14 @@ static void node_socket_free(bNodeTree *UNUSED(ntree),
void nodeRemoveSocket(bNodeTree *ntree, bNode *node, bNodeSocket *sock)
{
+ nodeRemoveSocketEx(ntree, node, sock, true);
+}
+
+void nodeRemoveSocketEx(struct bNodeTree *ntree,
+ struct bNode *node,
+ struct bNodeSocket *sock,
+ bool do_id_user)
+{
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
if (link->fromsock == sock || link->tosock == sock) {
nodeRemLink(ntree, link);
@@ -1926,7 +1942,7 @@ void nodeRemoveSocket(bNodeTree *ntree, bNode *node, bNodeSocket *sock)
BLI_remlink(&node->inputs, sock);
BLI_remlink(&node->outputs, sock);
- node_socket_free(ntree, sock, node, true);
+ node_socket_free(ntree, sock, node, do_id_user);
MEM_freeN(sock);
node->update |= NODE_UPDATE;
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index 6492f0d1f69..fa15e541e43 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -291,7 +291,7 @@ static void do_version_hue_sat_node(bNodeTree *ntree, bNode *node)
}
/* Make sure new sockets are properly created. */
- node_verify_socket_templates(ntree, node);
+ node_verify_sockets(ntree, node, false);
/* Convert value from old storage to new sockets. */
NodeHueSat *nhs = node->storage;
bNodeSocket *hue = nodeFindSocket(node, SOCK_IN, "Hue"),
@@ -357,7 +357,7 @@ static void do_versions_compositor_render_passes(bNodeTree *ntree)
*/
do_versions_compositor_render_passes_storage(node);
/* Make sure new sockets are properly created. */
- node_verify_socket_templates(ntree, node);
+ node_verify_sockets(ntree, node, false);
/* Make sure all possibly created sockets have proper storage. */
do_versions_compositor_render_passes_storage(node);
}
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 8dfab671565..29a1de381b5 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -347,6 +347,8 @@ set(SRC
intern/node_exec.cc
intern/node_geometry_exec.cc
intern/node_multi_function.cc
+ intern/node_declaration.cc
+ intern/node_socket_declarations.cc
intern/node_socket.cc
intern/node_tree_ref.cc
intern/node_util.c
@@ -367,6 +369,8 @@ set(SRC
NOD_geometry_nodes_eval_log.hh
NOD_math_functions.hh
NOD_multi_function.hh
+ NOD_node_declaration.hh
+ NOD_socket_declarations.hh
NOD_node_tree_ref.hh
NOD_shader.h
NOD_socket.h
diff --git a/source/blender/nodes/NOD_node_declaration.hh b/source/blender/nodes/NOD_node_declaration.hh
new file mode 100644
index 00000000000..9c461885859
--- /dev/null
+++ b/source/blender/nodes/NOD_node_declaration.hh
@@ -0,0 +1,135 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include <type_traits>
+
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+
+#include "DNA_node_types.h"
+
+namespace blender::nodes {
+
+class NodeDeclarationBuilder;
+
+class SocketDeclaration {
+ protected:
+ std::string name_;
+ std::string identifier_;
+
+ friend NodeDeclarationBuilder;
+
+ public:
+ virtual bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const = 0;
+ virtual bool matches(const bNodeSocket &socket) const = 0;
+ virtual bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const;
+
+ StringRefNull name() const;
+ StringRefNull identifier() const;
+};
+
+using SocketDeclarationPtr = std::unique_ptr<SocketDeclaration>;
+
+class NodeDeclaration {
+ private:
+ Vector<SocketDeclarationPtr> inputs_;
+ Vector<SocketDeclarationPtr> outputs_;
+
+ friend NodeDeclarationBuilder;
+
+ public:
+ void build(bNodeTree &ntree, bNode &node) const;
+ bool matches(const bNode &node) const;
+
+ Span<SocketDeclarationPtr> inputs() const;
+ Span<SocketDeclarationPtr> outputs() const;
+};
+
+class NodeDeclarationBuilder {
+ private:
+ NodeDeclaration &declaration_;
+
+ public:
+ NodeDeclarationBuilder(NodeDeclaration &declaration);
+
+ template<typename DeclType> DeclType &add_input(StringRef name, StringRef identifier = "");
+ template<typename DeclType> DeclType &add_output(StringRef name, StringRef identifier = "");
+};
+
+/* --------------------------------------------------------------------
+ * SocketDeclaration inline methods.
+ */
+
+inline StringRefNull SocketDeclaration::name() const
+{
+ return name_;
+}
+
+inline StringRefNull SocketDeclaration::identifier() const
+{
+ return identifier_;
+}
+
+/* --------------------------------------------------------------------
+ * NodeDeclarationBuilder inline methods.
+ */
+
+inline NodeDeclarationBuilder::NodeDeclarationBuilder(NodeDeclaration &declaration)
+ : declaration_(declaration)
+{
+}
+
+template<typename DeclType>
+inline DeclType &NodeDeclarationBuilder::add_input(StringRef name, StringRef identifier)
+{
+ static_assert(std::is_base_of_v<SocketDeclaration, DeclType>);
+ std::unique_ptr<DeclType> socket_decl = std::make_unique<DeclType>();
+ DeclType &ref = *socket_decl;
+ ref.name_ = name;
+ ref.identifier_ = identifier.is_empty() ? name : identifier;
+ declaration_.inputs_.append(std::move(socket_decl));
+ return ref;
+}
+
+template<typename DeclType>
+inline DeclType &NodeDeclarationBuilder::add_output(StringRef name, StringRef identifier)
+{
+ static_assert(std::is_base_of_v<SocketDeclaration, DeclType>);
+ std::unique_ptr<DeclType> socket_decl = std::make_unique<DeclType>();
+ DeclType &ref = *socket_decl;
+ ref.name_ = name;
+ ref.identifier_ = identifier.is_empty() ? name : identifier;
+ declaration_.outputs_.append(std::move(socket_decl));
+ return ref;
+}
+
+/* --------------------------------------------------------------------
+ * NodeDeclaration inline methods.
+ */
+
+inline Span<SocketDeclarationPtr> NodeDeclaration::inputs() const
+{
+ return inputs_;
+}
+
+inline Span<SocketDeclarationPtr> NodeDeclaration::outputs() const
+{
+ return outputs_;
+}
+
+} // namespace blender::nodes
diff --git a/source/blender/nodes/NOD_socket.h b/source/blender/nodes/NOD_socket.h
index 6bcfda70d04..4f8e114c34a 100644
--- a/source/blender/nodes/NOD_socket.h
+++ b/source/blender/nodes/NOD_socket.h
@@ -43,7 +43,7 @@ struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree,
struct bNodeSocketTemplate *stemp,
eNodeSocketInOut in_out);
-void node_verify_socket_templates(struct bNodeTree *ntree, struct bNode *node);
+void node_verify_sockets(struct bNodeTree *ntree, struct bNode *node, bool do_id_user);
void node_socket_init_default_value(struct bNodeSocket *sock);
void node_socket_copy_default_value(struct bNodeSocket *to, const struct bNodeSocket *from);
diff --git a/source/blender/nodes/NOD_socket_declarations.hh b/source/blender/nodes/NOD_socket_declarations.hh
new file mode 100644
index 00000000000..639d2c12d73
--- /dev/null
+++ b/source/blender/nodes/NOD_socket_declarations.hh
@@ -0,0 +1,239 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include "NOD_node_declaration.hh"
+
+#include "RNA_types.h"
+
+#include "BLI_color.hh"
+#include "BLI_float3.hh"
+
+namespace blender::nodes::decl {
+
+class Float : public SocketDeclaration {
+ private:
+ float default_value_ = 0.0f;
+ float soft_min_value_ = -FLT_MAX;
+ float soft_max_value_ = FLT_MAX;
+ PropertySubType subtype_ = PROP_NONE;
+
+ public:
+ Float &min(const float value)
+ {
+ soft_min_value_ = value;
+ return *this;
+ }
+
+ Float &max(const float value)
+ {
+ soft_max_value_ = value;
+ return *this;
+ }
+
+ Float &default_value(const float value)
+ {
+ default_value_ = value;
+ return *this;
+ }
+
+ Float &subtype(PropertySubType subtype)
+ {
+ subtype_ = subtype;
+ return *this;
+ }
+
+ bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bool matches(const bNodeSocket &socket) const override;
+ bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override;
+};
+
+class Int : public SocketDeclaration {
+ private:
+ int default_value_ = 0;
+ int soft_min_value_ = INT32_MIN;
+ int soft_max_value_ = INT32_MAX;
+ PropertySubType subtype_ = PROP_NONE;
+
+ public:
+ Int &min(const int value)
+ {
+ soft_min_value_ = value;
+ return *this;
+ }
+
+ Int &max(const int value)
+ {
+ soft_max_value_ = value;
+ return *this;
+ }
+
+ Int &default_value(const int value)
+ {
+ default_value_ = value;
+ return *this;
+ }
+
+ Int &subtype(PropertySubType subtype)
+ {
+ subtype_ = subtype;
+ return *this;
+ }
+
+ bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bool matches(const bNodeSocket &socket) const override;
+ bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override;
+};
+
+class Vector : public SocketDeclaration {
+ private:
+ float3 default_value_ = {0, 0, 0};
+ PropertySubType subtype_ = PROP_NONE;
+
+ public:
+ Vector &default_value(const float3 value)
+ {
+ default_value_ = value;
+ return *this;
+ }
+
+ Vector &subtype(PropertySubType subtype)
+ {
+ subtype_ = subtype;
+ return *this;
+ }
+
+ bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bool matches(const bNodeSocket &socket) const override;
+ bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override;
+};
+
+class Bool : public SocketDeclaration {
+ private:
+ bool default_value_ = false;
+
+ public:
+ Bool &default_value(const bool value)
+ {
+ default_value_ = value;
+ return *this;
+ }
+
+ bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bool matches(const bNodeSocket &socket) const override;
+};
+
+class Color : public SocketDeclaration {
+ private:
+ ColorGeometry4f default_value_;
+
+ public:
+ Color &default_value(const ColorGeometry4f value)
+ {
+ default_value_ = value;
+ return *this;
+ }
+
+ bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bool matches(const bNodeSocket &socket) const override;
+};
+
+class String : public SocketDeclaration {
+ public:
+ bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bool matches(const bNodeSocket &socket) const override;
+};
+
+namespace detail {
+struct CommonIDSocketData {
+ const char *idname;
+ bool hide_label = false;
+};
+
+bNodeSocket &build_id_socket(bNodeTree &ntree,
+ bNode &node,
+ eNodeSocketInOut in_out,
+ const CommonIDSocketData &data,
+ StringRefNull name,
+ StringRefNull identifier);
+bool matches_id_socket(const bNodeSocket &socket,
+ const CommonIDSocketData &data,
+ StringRefNull name,
+ StringRefNull identifier);
+
+template<typename Subtype> class IDSocketDeclaration : public SocketDeclaration {
+ private:
+ CommonIDSocketData data_;
+
+ public:
+ IDSocketDeclaration(const char *idname) : data_({idname})
+ {
+ }
+
+ Subtype &hide_label(bool value)
+ {
+ data_.hide_label = value;
+ return *(Subtype *)this;
+ }
+
+ bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override
+ {
+ return build_id_socket(ntree, node, in_out, data_, name_, identifier_);
+ }
+
+ bool matches(const bNodeSocket &socket) const override
+ {
+ return matches_id_socket(socket, data_, name_, identifier_);
+ }
+};
+} // namespace detail
+
+class Object : public detail::IDSocketDeclaration<Object> {
+ public:
+ Object() : detail::IDSocketDeclaration<Object>("NodeSocketObject")
+ {
+ }
+};
+
+class Material : public detail::IDSocketDeclaration<Material> {
+ public:
+ Material() : detail::IDSocketDeclaration<Material>("NodeSocketMaterial")
+ {
+ }
+};
+
+class Collection : public detail::IDSocketDeclaration<Collection> {
+ public:
+ Collection() : detail::IDSocketDeclaration<Collection>("NodeSocketCollection")
+ {
+ }
+};
+
+class Texture : public detail::IDSocketDeclaration<Texture> {
+ public:
+ Texture() : detail::IDSocketDeclaration<Texture>("NodeSocketTexture")
+ {
+ }
+};
+
+class Geometry : public SocketDeclaration {
+ public:
+ bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bool matches(const bNodeSocket &socket) const override;
+};
+
+} // namespace blender::nodes::decl
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index 3251f9977bc..6a69c3d24ec 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -31,6 +31,7 @@
#include "NOD_geometry.h"
#include "NOD_geometry_exec.hh"
+#include "NOD_socket_declarations.hh"
#include "node_util.h"
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
index 389abe3b2aa..632e4f86572 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
@@ -19,21 +19,19 @@
#include "node_geometry_util.hh"
-static bNodeSocketTemplate geo_node_attribute_fill_in[] = {
- {SOCK_GEOMETRY, N_("Geometry")},
- {SOCK_STRING, N_("Attribute")},
- {SOCK_VECTOR, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
- {SOCK_FLOAT, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
- {SOCK_RGBA, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
- {SOCK_BOOLEAN, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
- {SOCK_INT, N_("Value"), 0, 0, 0, 0, -10000000.0f, 10000000.0f},
- {-1, ""},
-};
-
-static bNodeSocketTemplate geo_node_attribute_fill_out[] = {
- {SOCK_GEOMETRY, N_("Geometry")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void geo_node_attribute_fill_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Geometry");
+ b.add_input<decl::String>("Attribute");
+ b.add_input<decl::Vector>("Value", "Value");
+ b.add_input<decl::Float>("Value", "Value_001");
+ b.add_input<decl::Color>("Value", "Value_002");
+ b.add_input<decl::Bool>("Value", "Value_003");
+ b.add_input<decl::Int>("Value", "Value_004");
+ b.add_output<decl::Geometry>("Geometry");
+}
static void geo_node_attribute_fill_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
@@ -66,8 +64,6 @@ static void geo_node_attribute_fill_update(bNodeTree *UNUSED(ntree), bNode *node
nodeSetSocketAvailability(socket_value_int32, data_type == CD_PROP_INT32);
}
-namespace blender::nodes {
-
static AttributeDomain get_result_domain(const GeometryComponent &component, const StringRef name)
{
/* Use the domain of the result attribute if it already exists. */
@@ -157,10 +153,10 @@ void register_node_type_geo_attribute_fill()
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_ATTRIBUTE_FILL, "Attribute Fill", NODE_CLASS_ATTRIBUTE, 0);
- node_type_socket_templates(&ntype, geo_node_attribute_fill_in, geo_node_attribute_fill_out);
- node_type_init(&ntype, geo_node_attribute_fill_init);
- node_type_update(&ntype, geo_node_attribute_fill_update);
+ node_type_init(&ntype, blender::nodes::geo_node_attribute_fill_init);
+ node_type_update(&ntype, blender::nodes::geo_node_attribute_fill_update);
ntype.geometry_node_execute = blender::nodes::geo_node_attribute_fill_exec;
- ntype.draw_buttons = geo_node_attribute_fill_layout;
+ ntype.draw_buttons = blender::nodes::geo_node_attribute_fill_layout;
+ ntype.declare = blender::nodes::geo_node_attribute_fill_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
index f9415c6d27b..578f0298a19 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
@@ -24,19 +24,17 @@
using blender::attribute_math::mix2;
-static bNodeSocketTemplate geo_node_curve_trim_in[] = {
- {SOCK_GEOMETRY, N_("Curve")},
- {SOCK_FLOAT, N_("Start"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("End"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Start"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 10000.0f, PROP_DISTANCE},
- {SOCK_FLOAT, N_("End"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 10000.0f, PROP_DISTANCE},
- {-1, ""},
-};
+namespace blender::nodes {
-static bNodeSocketTemplate geo_node_curve_trim_out[] = {
- {SOCK_GEOMETRY, N_("Curve")},
- {-1, ""},
-};
+static void geo_node_curve_trim_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Curve");
+ b.add_input<decl::Float>("Start").min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Float>("End").min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Float>("Start", "Start_001").min(0.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>("End", "End_001").min(0.0f).subtype(PROP_DISTANCE);
+ b.add_output<decl::Geometry>("Curve");
+}
static void geo_node_curve_trim_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
@@ -69,8 +67,6 @@ static void geo_node_curve_trim_update(bNodeTree *UNUSED(ntree), bNode *node)
nodeSetSocketAvailability(end_len, mode == GEO_NODE_CURVE_INTERPOLATE_LENGTH);
}
-namespace blender::nodes {
-
struct TrimLocation {
/* Control point index at the start side of the trim location. */
int left_index;
@@ -399,12 +395,12 @@ void register_node_type_geo_curve_trim()
{
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_CURVE_TRIM, "Curve Trim", NODE_CLASS_GEOMETRY, 0);
- node_type_socket_templates(&ntype, geo_node_curve_trim_in, geo_node_curve_trim_out);
ntype.geometry_node_execute = blender::nodes::geo_node_curve_trim_exec;
- ntype.draw_buttons = geo_node_curve_trim_layout;
+ ntype.draw_buttons = blender::nodes::geo_node_curve_trim_layout;
+ ntype.declare = blender::nodes::geo_node_curve_trim_declare;
node_type_storage(
&ntype, "NodeGeometryCurveTrim", node_free_standard_storage, node_copy_standard_storage);
- node_type_init(&ntype, geo_node_curve_trim_init);
- node_type_update(&ntype, geo_node_curve_trim_update);
+ node_type_init(&ntype, blender::nodes::geo_node_curve_trim_init);
+ node_type_update(&ntype, blender::nodes::geo_node_curve_trim_update);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
index 740b828d503..867fecea251 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
@@ -22,29 +22,21 @@ extern "C" {
Mesh *doEdgeSplit(const Mesh *mesh, EdgeSplitModifierData *emd);
}
-static bNodeSocketTemplate geo_node_edge_split_in[] = {
- {SOCK_GEOMETRY, N_("Geometry")},
- {SOCK_BOOLEAN, N_("Edge Angle"), true},
- {SOCK_FLOAT,
- N_("Angle"),
- DEG2RADF(30.0f),
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- DEG2RADF(180.0f),
- PROP_ANGLE},
- {SOCK_BOOLEAN, N_("Sharp Edges")},
- {-1, ""},
-};
-
-static bNodeSocketTemplate geo_node_edge_split_out[] = {
- {SOCK_GEOMETRY, N_("Geometry")},
- {-1, ""},
-};
-
namespace blender::nodes {
+static void geo_node_edge_split_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Geometry");
+ b.add_input<decl::Bool>("Edge Angle").default_value(true);
+ b.add_input<decl::Float>("Angle")
+ .default_value(DEG2RADF(30.0f))
+ .min(0.0f)
+ .max(DEG2RADF(180.0f))
+ .subtype(PROP_ANGLE);
+ b.add_input<decl::Bool>("Sharp Edges");
+ b.add_output<decl::Geometry>("Geometry");
+}
+
static void geo_node_edge_split_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -91,7 +83,7 @@ void register_node_type_geo_edge_split()
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_EDGE_SPLIT, "Edge Split", NODE_CLASS_GEOMETRY, 0);
- node_type_socket_templates(&ntype, geo_node_edge_split_in, geo_node_edge_split_out);
ntype.geometry_node_execute = blender::nodes::geo_node_edge_split_exec;
+ ntype.declare = blender::nodes::geo_node_edge_split_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
index 6bad71a62a2..8e805bd1359 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
@@ -19,18 +19,18 @@
#include "node_geometry_util.hh"
-static bNodeSocketTemplate geo_node_input_material_out[] = {
- {SOCK_MATERIAL, N_("Material")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void geo_node_input_material_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Material>("Material");
+}
static void geo_node_input_material_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "material", 0, "", ICON_NONE);
}
-namespace blender::nodes {
-
static void geo_node_input_material_exec(GeoNodeExecParams params)
{
Material *material = (Material *)params.node().id;
@@ -44,8 +44,8 @@ void register_node_type_geo_input_material()
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL, "Material", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, nullptr, geo_node_input_material_out);
- ntype.draw_buttons = geo_node_input_material_layout;
+ ntype.draw_buttons = blender::nodes::geo_node_input_material_layout;
+ ntype.declare = blender::nodes::geo_node_input_material_declare;
ntype.geometry_node_execute = blender::nodes::geo_node_input_material_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc b/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc
index ec875b9f983..f8a1c764f61 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc
@@ -18,13 +18,13 @@
#include "node_geometry_util.hh"
-static bNodeSocketTemplate geo_node_is_viewport_out[] = {
- {SOCK_BOOLEAN, N_("Is Viewport")},
- {-1, ""},
-};
-
namespace blender::nodes {
+static void geo_node_is_viewport_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Bool>("Is Viewport");
+}
+
static void geo_node_is_viewport_exec(GeoNodeExecParams params)
{
const Depsgraph *depsgraph = params.depsgraph();
@@ -41,7 +41,7 @@ void register_node_type_geo_is_viewport()
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_IS_VIEWPORT, "Is Viewport", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, nullptr, geo_node_is_viewport_out);
ntype.geometry_node_execute = blender::nodes::geo_node_is_viewport_exec;
+ ntype.declare = blender::nodes::geo_node_is_viewport_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
index b0bb547eb45..9c477c639a2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
@@ -25,16 +25,14 @@
#include "node_geometry_util.hh"
-static bNodeSocketTemplate geo_node_mesh_primitive_circle_in[] = {
- {SOCK_INT, N_("Vertices"), 32, 0.0f, 0.0f, 0.0f, 3, 4096},
- {SOCK_FLOAT, N_("Radius"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
- {-1, ""},
-};
+namespace blender::nodes {
-static bNodeSocketTemplate geo_node_mesh_primitive_circle_out[] = {
- {SOCK_GEOMETRY, N_("Geometry")},
- {-1, ""},
-};
+static void geo_node_mesh_primitive_circle_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>("Vertices").default_value(32).min(3);
+ b.add_input<decl::Float>("Radius").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_output<decl::Geometry>("Geometry");
+}
static void geo_node_mesh_primitive_circle_layout(uiLayout *layout,
bContext *UNUSED(C),
@@ -55,8 +53,6 @@ static void geo_node_mesh_primitive_circle_init(bNodeTree *UNUSED(ntree), bNode
node->storage = node_storage;
}
-namespace blender::nodes {
-
static int circle_vert_total(const GeometryNodeMeshCircleFillType fill_type, const int verts_num)
{
switch (fill_type) {
@@ -227,12 +223,11 @@ void register_node_type_geo_mesh_primitive_circle()
geo_node_type_base(
&ntype, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Mesh Circle", NODE_CLASS_GEOMETRY, 0);
- node_type_socket_templates(
- &ntype, geo_node_mesh_primitive_circle_in, geo_node_mesh_primitive_circle_out);
- node_type_init(&ntype, geo_node_mesh_primitive_circle_init);
+ node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_circle_init);
node_type_storage(
&ntype, "NodeGeometryMeshCircle", node_free_standard_storage, node_copy_standard_storage);
ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_circle_exec;
- ntype.draw_buttons = geo_node_mesh_primitive_circle_layout;
+ ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_circle_layout;
+ ntype.declare = blender::nodes::geo_node_mesh_primitive_circle_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
index b834f5e2fa0..0d58476fc58 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
@@ -25,18 +25,16 @@
#include "node_geometry_util.hh"
-static bNodeSocketTemplate geo_node_mesh_primitive_cone_in[] = {
- {SOCK_INT, N_("Vertices"), 32, 0.0f, 0.0f, 0.0f, 3, 4096},
- {SOCK_FLOAT, N_("Radius Top"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
- {SOCK_FLOAT, N_("Radius Bottom"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
- {SOCK_FLOAT, N_("Depth"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate geo_node_mesh_primitive_cone_out[] = {
- {SOCK_GEOMETRY, N_("Geometry")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void geo_node_mesh_primitive_cone_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>("Vertices").default_value(32).min(3);
+ b.add_input<decl::Float>("Radius Top").min(0.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>("Radius Bottom").default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>("Depth").default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_output<decl::Geometry>("Geometry");
+}
static void geo_node_mesh_primitive_cone_layout(uiLayout *layout,
bContext *UNUSED(C),
@@ -57,8 +55,6 @@ static void geo_node_mesh_primitive_cone_init(bNodeTree *UNUSED(ntree), bNode *n
node->storage = node_storage;
}
-namespace blender::nodes {
-
static int vert_total(const GeometryNodeMeshCircleFillType fill_type,
const int verts_num,
const bool top_is_point,
@@ -575,12 +571,11 @@ void register_node_type_geo_mesh_primitive_cone()
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CONE, "Cone", NODE_CLASS_GEOMETRY, 0);
- node_type_socket_templates(
- &ntype, geo_node_mesh_primitive_cone_in, geo_node_mesh_primitive_cone_out);
- node_type_init(&ntype, geo_node_mesh_primitive_cone_init);
+ node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_cone_init);
node_type_storage(
&ntype, "NodeGeometryMeshCone", node_free_standard_storage, node_copy_standard_storage);
ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cone_exec;
- ntype.draw_buttons = geo_node_mesh_primitive_cone_layout;
+ ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_cone_layout;
+ ntype.declare = blender::nodes::geo_node_mesh_primitive_cone_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
index 167812d5656..ab99c9bb3f8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
@@ -21,25 +21,22 @@
#include "node_geometry_util.hh"
-static bNodeSocketTemplate geo_node_object_info_in[] = {
- {SOCK_OBJECT, N_("Object"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, PROP_NONE, SOCK_HIDE_LABEL},
- {-1, ""},
-};
-
-static bNodeSocketTemplate geo_node_object_info_out[] = {
- {SOCK_VECTOR, N_("Location")},
- {SOCK_VECTOR, N_("Rotation")},
- {SOCK_VECTOR, N_("Scale")},
- {SOCK_GEOMETRY, N_("Geometry")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void geo_node_object_info_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Object>("Object").hide_label(true);
+ b.add_output<decl::Vector>("Location");
+ b.add_output<decl::Vector>("Rotation");
+ b.add_output<decl::Vector>("Scale");
+ b.add_output<decl::Geometry>("Geometry");
+}
static void geo_node_object_info_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "transform_space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-namespace blender::nodes {
static void geo_node_object_info_exec(GeoNodeExecParams params)
{
const bNode &bnode = params.node();
@@ -105,11 +102,11 @@ void register_node_type_geo_object_info()
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, geo_node_object_info_in, geo_node_object_info_out);
node_type_init(&ntype, blender::nodes::geo_node_object_info_node_init);
node_type_storage(
&ntype, "NodeGeometryObjectInfo", node_free_standard_storage, node_copy_standard_storage);
ntype.geometry_node_execute = blender::nodes::geo_node_object_info_exec;
- ntype.draw_buttons = geo_node_object_info_layout;
+ ntype.draw_buttons = blender::nodes::geo_node_object_info_layout;
+ ntype.declare = blender::nodes::geo_node_object_info_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
index 1ad5dbea492..d7423aa6d32 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
@@ -32,21 +32,17 @@
#include "node_geometry_util.hh"
-static bNodeSocketTemplate geo_node_transform_in[] = {
- {SOCK_GEOMETRY, N_("Geometry")},
- {SOCK_VECTOR, N_("Translation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
- {SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
- {SOCK_VECTOR, N_("Scale"), 1.0f, 1.0f, 1.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_XYZ},
- {-1, ""},
-};
-
-static bNodeSocketTemplate geo_node_transform_out[] = {
- {SOCK_GEOMETRY, N_("Geometry")},
- {-1, ""},
-};
-
namespace blender::nodes {
+static void geo_node_transform_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Geometry");
+ b.add_input<decl::Vector>("Translation").subtype(PROP_TRANSLATION);
+ b.add_input<decl::Vector>("Rotation").subtype(PROP_EULER);
+ b.add_input<decl::Vector>("Scale").default_value({1, 1, 1}).subtype(PROP_XYZ);
+ b.add_output<decl::Geometry>("Geometry");
+}
+
static bool use_translate(const float3 rotation, const float3 scale)
{
if (compare_ff(rotation.length_squared(), 0.0f, 1e-9f) != 1) {
@@ -206,7 +202,7 @@ void register_node_type_geo_transform()
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_TRANSFORM, "Transform", NODE_CLASS_GEOMETRY, 0);
- node_type_socket_templates(&ntype, geo_node_transform_in, geo_node_transform_out);
+ ntype.declare = blender::nodes::geo_node_transform_declare;
ntype.geometry_node_execute = blender::nodes::geo_node_transform_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/intern/node_declaration.cc b/source/blender/nodes/intern/node_declaration.cc
new file mode 100644
index 00000000000..dff92d5884f
--- /dev/null
+++ b/source/blender/nodes/intern/node_declaration.cc
@@ -0,0 +1,65 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "NOD_node_declaration.hh"
+
+namespace blender::nodes {
+
+void NodeDeclaration::build(bNodeTree &ntree, bNode &node) const
+{
+ for (const SocketDeclarationPtr &decl : inputs_) {
+ decl->build(ntree, node, SOCK_IN);
+ }
+ for (const SocketDeclarationPtr &decl : outputs_) {
+ decl->build(ntree, node, SOCK_OUT);
+ }
+}
+
+bool NodeDeclaration::matches(const bNode &node) const
+{
+ auto check_sockets = [&](ListBase sockets, Span<SocketDeclarationPtr> socket_decls) {
+ const int tot_sockets = BLI_listbase_count(&sockets);
+ if (tot_sockets != socket_decls.size()) {
+ return false;
+ }
+ int i;
+ LISTBASE_FOREACH_INDEX (const bNodeSocket *, socket, &sockets, i) {
+ const SocketDeclaration &socket_decl = *socket_decls[i];
+ if (!socket_decl.matches(*socket)) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ if (!check_sockets(node.inputs, inputs_)) {
+ return false;
+ }
+ if (!check_sockets(node.outputs, outputs_)) {
+ return false;
+ }
+ return true;
+}
+
+bNodeSocket &SocketDeclaration::update_or_build(bNodeTree &ntree,
+ bNode &node,
+ bNodeSocket &socket) const
+{
+ /* By default just rebuild. */
+ return this->build(ntree, node, (eNodeSocketInOut)socket.in_out);
+}
+
+} // namespace blender::nodes
diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc
index 528616eb23a..d386781e3ce 100644
--- a/source/blender/nodes/intern/node_socket.cc
+++ b/source/blender/nodes/intern/node_socket.cc
@@ -44,10 +44,14 @@
#include "MEM_guardedalloc.h"
+#include "NOD_node_declaration.hh"
#include "NOD_socket.h"
#include "FN_cpp_type_make.hh"
+using namespace blender;
+using blender::nodes::SocketDeclarationPtr;
+
struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree,
struct bNode *node,
struct bNodeSocketTemplate *stemp,
@@ -182,9 +186,96 @@ static void verify_socket_template_list(bNodeTree *ntree,
}
}
-void node_verify_socket_templates(bNodeTree *ntree, bNode *node)
+static void refresh_socket_list(bNodeTree &ntree,
+ bNode &node,
+ ListBase &sockets,
+ Span<SocketDeclarationPtr> socket_decls,
+ const eNodeSocketInOut in_out,
+ const bool do_id_user)
+{
+ Vector<bNodeSocket *> old_sockets = sockets;
+ VectorSet<bNodeSocket *> new_sockets;
+ for (const SocketDeclarationPtr &socket_decl : socket_decls) {
+ /* Try to find a socket that corresponds to the declaration. */
+ bNodeSocket *old_socket_with_same_identifier = nullptr;
+ for (const int i : old_sockets.index_range()) {
+ bNodeSocket &old_socket = *old_sockets[i];
+ if (old_socket.identifier == socket_decl->identifier()) {
+ old_sockets.remove_and_reorder(i);
+ old_socket_with_same_identifier = &old_socket;
+ break;
+ }
+ }
+ bNodeSocket *new_socket = nullptr;
+ if (old_socket_with_same_identifier == nullptr) {
+ /* Create a completely new socket. */
+ new_socket = &socket_decl->build(ntree, node, in_out);
+ }
+ else {
+ STRNCPY(old_socket_with_same_identifier->name, socket_decl->name().c_str());
+ if (socket_decl->matches(*old_socket_with_same_identifier)) {
+ /* The existing socket matches exactly, just use it. */
+ new_socket = old_socket_with_same_identifier;
+ }
+ else {
+ /* Clear out identifier to avoid name collisions when a new socket is created. */
+ old_socket_with_same_identifier->identifier[0] = '\0';
+ new_socket = &socket_decl->update_or_build(ntree, node, *old_socket_with_same_identifier);
+
+ if (new_socket == old_socket_with_same_identifier) {
+ /* The existing socket has been updated, set the correct identifier again. */
+ STRNCPY(new_socket->identifier, socket_decl->identifier().c_str());
+ }
+ else {
+ /* Move links to new socket with same identifier. */
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+ if (link->fromsock == old_socket_with_same_identifier) {
+ link->fromsock = new_socket;
+ }
+ else if (link->tosock == old_socket_with_same_identifier) {
+ link->tosock = new_socket;
+ }
+ }
+ }
+ }
+ }
+ new_sockets.add_new(new_socket);
+ }
+ LISTBASE_FOREACH_MUTABLE (bNodeSocket *, old_socket, &sockets) {
+ if (!new_sockets.contains(old_socket)) {
+ nodeRemoveSocketEx(&ntree, &node, old_socket, do_id_user);
+ }
+ }
+ BLI_listbase_clear(&sockets);
+ for (bNodeSocket *socket : new_sockets) {
+ BLI_addtail(&sockets, socket);
+ }
+}
+
+static void refresh_node(bNodeTree &ntree,
+ bNode &node,
+ blender::nodes::NodeDeclaration &node_decl,
+ bool do_id_user)
+{
+ refresh_socket_list(ntree, node, node.inputs, node_decl.inputs(), SOCK_IN, do_id_user);
+ refresh_socket_list(ntree, node, node.outputs, node_decl.outputs(), SOCK_OUT, do_id_user);
+}
+
+void node_verify_sockets(bNodeTree *ntree, bNode *node, bool do_id_user)
{
bNodeType *ntype = node->typeinfo;
+ if (ntype == nullptr) {
+ return;
+ }
+ if (ntype->declare != nullptr) {
+ blender::nodes::NodeDeclaration node_decl;
+ blender::nodes::NodeDeclarationBuilder builder{node_decl};
+ ntype->declare(builder);
+ if (!node_decl.matches(*node)) {
+ refresh_node(*ntree, *node, node_decl, do_id_user);
+ }
+ return;
+ }
/* Don't try to match socket lists when there are no templates.
* This prevents dynamically generated sockets to be removed, like for
* group, image or render layer nodes. We have an explicit check for the
diff --git a/source/blender/nodes/intern/node_socket_declarations.cc b/source/blender/nodes/intern/node_socket_declarations.cc
new file mode 100644
index 00000000000..418fed146fb
--- /dev/null
+++ b/source/blender/nodes/intern/node_socket_declarations.cc
@@ -0,0 +1,330 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "NOD_socket_declarations.hh"
+
+#include "BKE_node.h"
+
+#include "BLI_math_vector.h"
+
+namespace blender::nodes::decl {
+
+static void modify_subtype_except_for_storage(bNodeSocket &socket, int new_subtype)
+{
+ const char *idname = nodeStaticSocketType(socket.type, new_subtype);
+ BLI_strncpy(socket.idname, idname, sizeof(socket.idname));
+ bNodeSocketType *socktype = nodeSocketTypeFind(idname);
+ socket.typeinfo = socktype;
+}
+
+/* --------------------------------------------------------------------
+ * Float.
+ */
+
+bNodeSocket &Float::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+{
+ bNodeSocket &socket = *nodeAddStaticSocket(
+ &ntree, &node, in_out, SOCK_FLOAT, subtype_, identifier_.c_str(), name_.c_str());
+ bNodeSocketValueFloat &value = *(bNodeSocketValueFloat *)socket.default_value;
+ value.min = soft_min_value_;
+ value.max = soft_max_value_;
+ value.value = default_value_;
+ return socket;
+}
+
+bool Float::matches(const bNodeSocket &socket) const
+{
+ if (socket.type != SOCK_FLOAT) {
+ return false;
+ }
+ if (socket.typeinfo->subtype != subtype_) {
+ return false;
+ }
+ if (socket.name != name_) {
+ return false;
+ }
+ if (socket.identifier != identifier_) {
+ return false;
+ }
+ bNodeSocketValueFloat &value = *(bNodeSocketValueFloat *)socket.default_value;
+ if (value.min != soft_min_value_) {
+ return false;
+ }
+ if (value.max != soft_max_value_) {
+ return false;
+ }
+ return true;
+}
+
+bNodeSocket &Float::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
+{
+ if (socket.type != SOCK_FLOAT) {
+ return this->build(ntree, node, (eNodeSocketInOut)socket.in_out);
+ }
+ if (socket.typeinfo->subtype != subtype_) {
+ modify_subtype_except_for_storage(socket, subtype_);
+ }
+ bNodeSocketValueFloat &value = *(bNodeSocketValueFloat *)socket.default_value;
+ value.min = soft_min_value_;
+ value.max = soft_max_value_;
+ value.subtype = subtype_;
+ return socket;
+}
+
+/* --------------------------------------------------------------------
+ * Int.
+ */
+
+bNodeSocket &Int::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+{
+ bNodeSocket &socket = *nodeAddStaticSocket(
+ &ntree, &node, in_out, SOCK_INT, subtype_, identifier_.c_str(), name_.c_str());
+ bNodeSocketValueInt &value = *(bNodeSocketValueInt *)socket.default_value;
+ value.min = soft_min_value_;
+ value.max = soft_max_value_;
+ value.value = default_value_;
+ return socket;
+}
+
+bool Int::matches(const bNodeSocket &socket) const
+{
+ if (socket.type != SOCK_INT) {
+ return false;
+ }
+ if (socket.typeinfo->subtype != subtype_) {
+ return false;
+ }
+ if (socket.name != name_) {
+ return false;
+ }
+ if (socket.identifier != identifier_) {
+ return false;
+ }
+ bNodeSocketValueInt &value = *(bNodeSocketValueInt *)socket.default_value;
+ if (value.min != soft_min_value_) {
+ return false;
+ }
+ if (value.max != soft_max_value_) {
+ return false;
+ }
+ return true;
+}
+
+bNodeSocket &Int::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
+{
+ if (socket.type != SOCK_INT) {
+ return this->build(ntree, node, (eNodeSocketInOut)socket.in_out);
+ }
+ if (socket.typeinfo->subtype != subtype_) {
+ modify_subtype_except_for_storage(socket, subtype_);
+ }
+ bNodeSocketValueInt &value = *(bNodeSocketValueInt *)socket.default_value;
+ value.min = soft_min_value_;
+ value.max = soft_max_value_;
+ value.subtype = subtype_;
+ return socket;
+}
+
+/* --------------------------------------------------------------------
+ * Vector.
+ */
+
+bNodeSocket &Vector::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+{
+ bNodeSocket &socket = *nodeAddStaticSocket(
+ &ntree, &node, in_out, SOCK_VECTOR, subtype_, identifier_.c_str(), name_.c_str());
+ bNodeSocketValueVector &value = *(bNodeSocketValueVector *)socket.default_value;
+ copy_v3_v3(value.value, default_value_);
+ return socket;
+}
+
+bool Vector::matches(const bNodeSocket &socket) const
+{
+ if (socket.type != SOCK_VECTOR) {
+ return false;
+ }
+ if (socket.typeinfo->subtype != subtype_) {
+ return false;
+ }
+ if (socket.name != name_) {
+ return false;
+ }
+ if (socket.identifier != identifier_) {
+ return false;
+ }
+ return true;
+}
+
+bNodeSocket &Vector::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
+{
+ if (socket.type != SOCK_VECTOR) {
+ return this->build(ntree, node, (eNodeSocketInOut)socket.in_out);
+ }
+ if (socket.typeinfo->subtype != subtype_) {
+ modify_subtype_except_for_storage(socket, subtype_);
+ }
+ bNodeSocketValueVector &value = *(bNodeSocketValueVector *)socket.default_value;
+ value.subtype = subtype_;
+ STRNCPY(socket.name, name_.c_str());
+ return socket;
+}
+
+/* --------------------------------------------------------------------
+ * Bool.
+ */
+
+bNodeSocket &Bool::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+{
+ bNodeSocket &socket = *nodeAddStaticSocket(
+ &ntree, &node, in_out, SOCK_BOOLEAN, PROP_NONE, identifier_.c_str(), name_.c_str());
+ bNodeSocketValueBoolean &value = *(bNodeSocketValueBoolean *)socket.default_value;
+ value.value = default_value_;
+ return socket;
+}
+
+bool Bool::matches(const bNodeSocket &socket) const
+{
+ if (socket.type != SOCK_BOOLEAN) {
+ return false;
+ }
+ if (socket.name != name_) {
+ return false;
+ }
+ if (socket.identifier != identifier_) {
+ return false;
+ }
+ return true;
+}
+
+/* --------------------------------------------------------------------
+ * Color.
+ */
+
+bNodeSocket &Color::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+{
+ bNodeSocket &socket = *nodeAddStaticSocket(
+ &ntree, &node, in_out, SOCK_RGBA, PROP_NONE, identifier_.c_str(), name_.c_str());
+ bNodeSocketValueRGBA &value = *(bNodeSocketValueRGBA *)socket.default_value;
+ copy_v4_v4(value.value, default_value_);
+ return socket;
+}
+
+bool Color::matches(const bNodeSocket &socket) const
+{
+ if (socket.type != SOCK_RGBA) {
+ return false;
+ }
+ if (socket.name != name_) {
+ return false;
+ }
+ if (socket.identifier != identifier_) {
+ return false;
+ }
+ return true;
+}
+
+/* --------------------------------------------------------------------
+ * String.
+ */
+
+bNodeSocket &String::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+{
+ bNodeSocket &socket = *nodeAddStaticSocket(
+ &ntree, &node, in_out, SOCK_STRING, PROP_NONE, identifier_.c_str(), name_.c_str());
+ return socket;
+}
+
+bool String::matches(const bNodeSocket &socket) const
+{
+ if (socket.type != SOCK_STRING) {
+ return false;
+ }
+ if (socket.name != name_) {
+ return false;
+ }
+ if (socket.identifier != identifier_) {
+ return false;
+ }
+ return true;
+}
+
+/* --------------------------------------------------------------------
+ * IDSocketDeclaration.
+ */
+
+namespace detail {
+bNodeSocket &build_id_socket(bNodeTree &ntree,
+ bNode &node,
+ eNodeSocketInOut in_out,
+ const CommonIDSocketData &data,
+ StringRefNull name,
+ StringRefNull identifier)
+{
+ bNodeSocket &socket = *nodeAddSocket(
+ &ntree, &node, in_out, data.idname, name.c_str(), identifier.c_str());
+ if (data.hide_label) {
+ socket.flag |= SOCK_HIDE_LABEL;
+ }
+ return socket;
+}
+
+bool matches_id_socket(const bNodeSocket &socket,
+ const CommonIDSocketData &data,
+ StringRefNull name,
+ StringRefNull identifier)
+{
+ if (!STREQ(socket.idname, data.idname)) {
+ return false;
+ }
+ if (data.hide_label != ((socket.flag & SOCK_HIDE_LABEL) != 0)) {
+ return false;
+ }
+ if (socket.name != name) {
+ return false;
+ }
+ if (socket.identifier != identifier) {
+ return false;
+ }
+ return true;
+}
+} // namespace detail
+
+/* --------------------------------------------------------------------
+ * Geometry.
+ */
+
+bNodeSocket &Geometry::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+{
+ bNodeSocket &socket = *nodeAddSocket(
+ &ntree, &node, in_out, "NodeSocketGeometry", identifier_.c_str(), name_.c_str());
+ return socket;
+}
+
+bool Geometry::matches(const bNodeSocket &socket) const
+{
+ if (socket.type != SOCK_GEOMETRY) {
+ return false;
+ }
+ if (socket.name != name_) {
+ return false;
+ }
+ if (socket.identifier != identifier_) {
+ return false;
+ }
+ return true;
+}
+
+} // namespace blender::nodes::decl