diff options
Diffstat (limited to 'source')
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 |