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/nodes/intern')
-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
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