diff options
Diffstat (limited to 'source/blender/nodes/intern')
-rw-r--r-- | source/blender/nodes/intern/node_declaration.cc | 65 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_socket.cc | 93 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_socket_declarations.cc | 330 |
3 files changed, 487 insertions, 1 deletions
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 |