Files
test/source/blender/nodes/geometry/nodes/node_geo_repeat.cc
Jacques Lucke 42093bbe3d Nodes: have either input or output socket in declaration
Support for having an input and output socket in the same socket declaration
builder was added for the original node panels to be able to support inline
sockets. However, those were generally disabled for now. As can be seen in the
simulation and repeat zone, inline sockets can work differently too. Having an
input and output in the same socket declaration builder builder makes some
things simpler but makes other things much harder. For example, the current
design wouldn't work all that well if the input and output socket has different
types. This is easier to do with the `align_with_previous_socket` approach.

I'm not yet entirely sure whether we want to use the same approach for
corresponding sockets in the node tree interface, but that can be tried and
decided separately.

Pull Request: https://projects.blender.org/blender/blender/pulls/119599
2024-03-18 14:36:03 +01:00

188 lines
6.1 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "NOD_socket.hh"
#include "NOD_zone_socket_items.hh"
#include "BLI_string_utils.hh"
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_repeat_cc {
namespace repeat_input_node {
NODE_STORAGE_FUNCS(NodeGeometryRepeatInput);
static void node_declare(NodeDeclarationBuilder &b)
{
b.use_custom_socket_order();
b.allow_any_socket_order();
b.add_input<decl::Int>("Iterations").min(0).default_value(1);
const bNode *node = b.node_or_null();
const bNodeTree *tree = b.tree_or_null();
if (node && tree) {
const NodeGeometryRepeatInput &storage = node_storage(*node);
const bNode *output_node = tree->node_by_id(storage.output_node_id);
if (output_node) {
const auto &output_storage = *static_cast<const NodeGeometryRepeatOutput *>(
output_node->storage);
for (const int i : IndexRange(output_storage.items_num)) {
const NodeRepeatItem &item = output_storage.items[i];
const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
const StringRef name = item.name ? item.name : "";
const std::string identifier = RepeatItemsAccessor::socket_identifier_for_item(item);
auto &input_decl = b.add_input(socket_type, name, identifier);
auto &output_decl = b.add_output(socket_type, name, identifier).align_with_previous();
if (socket_type_supports_fields(socket_type)) {
input_decl.supports_field();
output_decl.dependent_field({input_decl.index()});
}
}
}
}
b.add_input<decl::Extend>("", "__extend__");
b.add_output<decl::Extend>("", "__extend__").align_with_previous();
}
static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryRepeatInput *data = MEM_cnew<NodeGeometryRepeatInput>(__func__);
/* Needs to be initialized for the node to work. */
data->output_node_id = 0;
node->storage = data;
}
static void node_label(const bNodeTree * /*ntree*/,
const bNode * /*node*/,
char *label,
const int label_maxncpy)
{
BLI_strncpy_utf8(label, IFACE_("Repeat"), label_maxncpy);
}
static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
{
bNode *output_node = ntree->node_by_id(node_storage(*node).output_node_id);
if (!output_node) {
return true;
}
return socket_items::try_add_item_via_any_extend_socket<RepeatItemsAccessor>(
*ntree, *node, *output_node, *link);
}
static void node_register()
{
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_REPEAT_INPUT, "Repeat Input", NODE_CLASS_INTERFACE);
ntype.initfunc = node_init;
ntype.declare = node_declare;
ntype.labelfunc = node_label;
ntype.gather_link_search_ops = nullptr;
ntype.insert_link = node_insert_link;
ntype.no_muting = true;
node_type_storage(
&ntype, "NodeGeometryRepeatInput", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
}
NOD_REGISTER_NODE(node_register)
} // namespace repeat_input_node
namespace repeat_output_node {
NODE_STORAGE_FUNCS(NodeGeometryRepeatOutput);
static void node_declare(NodeDeclarationBuilder &b)
{
b.use_custom_socket_order();
b.allow_any_socket_order();
const bNode *node = b.node_or_null();
if (node) {
const NodeGeometryRepeatOutput &storage = node_storage(*node);
for (const int i : IndexRange(storage.items_num)) {
const NodeRepeatItem &item = storage.items[i];
const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
const StringRef name = item.name ? item.name : "";
const std::string identifier = RepeatItemsAccessor::socket_identifier_for_item(item);
auto &input_decl = b.add_input(socket_type, name, identifier);
auto &output_decl = b.add_output(socket_type, name, identifier).align_with_previous();
if (socket_type_supports_fields(socket_type)) {
input_decl.supports_field();
output_decl.dependent_field({input_decl.index()});
}
}
}
b.add_input<decl::Extend>("", "__extend__");
b.add_output<decl::Extend>("", "__extend__").align_with_previous();
}
static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeGeometryRepeatOutput *data = MEM_cnew<NodeGeometryRepeatOutput>(__func__);
data->next_identifier = 0;
data->items = MEM_cnew_array<NodeRepeatItem>(1, __func__);
data->items[0].name = BLI_strdup(DATA_("Geometry"));
data->items[0].socket_type = SOCK_GEOMETRY;
data->items[0].identifier = data->next_identifier++;
data->items_num = 1;
node->storage = data;
}
static void node_free_storage(bNode *node)
{
socket_items::destruct_array<RepeatItemsAccessor>(*node);
MEM_freeN(node->storage);
}
static void node_copy_storage(bNodeTree * /*dst_tree*/, bNode *dst_node, const bNode *src_node)
{
const NodeGeometryRepeatOutput &src_storage = node_storage(*src_node);
auto *dst_storage = MEM_new<NodeGeometryRepeatOutput>(__func__, src_storage);
dst_node->storage = dst_storage;
socket_items::copy_array<RepeatItemsAccessor>(*src_node, *dst_node);
}
static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
{
return socket_items::try_add_item_via_any_extend_socket<RepeatItemsAccessor>(
*ntree, *node, *node, *link);
}
static void node_register()
{
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_REPEAT_OUTPUT, "Repeat Output", NODE_CLASS_INTERFACE);
ntype.initfunc = node_init;
ntype.declare = node_declare;
ntype.labelfunc = repeat_input_node::node_label;
ntype.insert_link = node_insert_link;
ntype.no_muting = true;
node_type_storage(&ntype, "NodeGeometryRepeatOutput", node_free_storage, node_copy_storage);
nodeRegisterType(&ntype);
}
NOD_REGISTER_NODE(node_register)
} // namespace repeat_output_node
} // namespace blender::nodes::node_geo_repeat_cc
blender::Span<NodeRepeatItem> NodeGeometryRepeatOutput::items_span() const
{
return blender::Span<NodeRepeatItem>(items, items_num);
}
blender::MutableSpan<NodeRepeatItem> NodeGeometryRepeatOutput::items_span()
{
return blender::MutableSpan<NodeRepeatItem>(items, items_num);
}