Geometry Nodes: align input and output sockets in simulation and repeat zone nodes

This changes the drawing of the zone nodes to align corresponding input
and output sockets. The resulting nodes are smaller and it's easier to see
how data is passed through them.

Drawing aligned sockets is already technically supported for quite a while
already, but we haven't used it so far. Using them for zone nodes seems to
provide benefits only. How we use aligned sockets in other nodes still has
to be discussed more.

This patch only changes run-time data. It doesn't affect what is written to
.blend files.

In the node declaration, aligned sockets are created by tagging a socket
so that it is aligned with the previous socket. This is a bit different from
what we had before where a single socket declaration would be used for
an input and output socket. I think the approach used here works better,
especially in a potential future scenario where the input and output socket
has a different type.

Pull Request: https://projects.blender.org/blender/blender/pulls/118335
This commit is contained in:
Jacques Lucke
2024-02-19 13:32:01 +01:00
parent 05f6a32b18
commit 1f30f41af8
5 changed files with 78 additions and 21 deletions
+30 -11
View File
@@ -614,17 +614,36 @@ static Vector<NodeInterfaceItemData> node_build_item_data(bNode &node)
if (const nodes::SocketDeclaration *socket_decl =
dynamic_cast<const nodes::SocketDeclaration *>(item_decl->get()))
{
switch (socket_decl->in_out) {
case SOCK_IN:
BLI_assert(input != input_end);
result.append({socket_decl, *input, nullptr});
++input;
break;
case SOCK_OUT:
BLI_assert(output != output_end);
result.append({socket_decl, nullptr, *output});
++output;
break;
if (socket_decl->align_with_previous_socket) {
NodeInterfaceItemData &last_item = result.last();
switch (socket_decl->in_out) {
case SOCK_IN:
BLI_assert(input != input_end);
BLI_assert(last_item.input == nullptr);
last_item.input = *input;
++input;
break;
case SOCK_OUT:
BLI_assert(output != output_end);
BLI_assert(last_item.output == nullptr);
last_item.output = *output;
++output;
break;
}
}
else {
switch (socket_decl->in_out) {
case SOCK_IN:
BLI_assert(input != input_end);
result.append({socket_decl, *input, nullptr});
++input;
break;
case SOCK_OUT:
BLI_assert(output != output_end);
result.append({socket_decl, nullptr, *output});
++output;
break;
}
}
++item_decl;
}
@@ -179,6 +179,8 @@ class SocketDeclaration : public ItemDeclaration {
bool is_unavailable = false;
bool is_attribute_name = false;
bool is_default_link_socket = false;
/** Puts this socket on the same line as the previous one in the UI. */
bool align_with_previous_socket = false;
InputSocketFieldType input_field_type = InputSocketFieldType::None;
OutputFieldDependency output_field_dependency;
@@ -356,6 +358,12 @@ class BaseSocketDeclarationBuilder {
*/
BaseSocketDeclarationBuilder &make_available(std::function<void(bNode &)> fn);
/**
* Puts this socket on the same row as the previous socket. This only works when one of them is
* an input and the other is an output.
*/
BaseSocketDeclarationBuilder &align_with_previous(bool value = true);
int input_index() const
{
BLI_assert(decl_in_base_ != nullptr);
@@ -459,6 +467,10 @@ class NodeDeclaration {
* outputs | buttons | inputs order. Panels are only supported when using custom socket order. */
bool use_custom_socket_order = false;
/** Usually output sockets come before input sockets currently. Only some specific nodes are
* exempt from that rule for now. */
bool allow_any_socket_order = false;
/**
* True if any context was used to build this declaration.
*/
@@ -521,6 +533,7 @@ class NodeDeclarationBuilder {
void finalize();
void use_custom_socket_order(bool enable = true);
void allow_any_socket_order(bool enable = true);
template<typename DeclType>
typename DeclType::Builder &add_input(StringRef name, StringRef identifier = "");
@@ -20,6 +20,8 @@ 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();
@@ -36,7 +38,7 @@ static void node_declare(NodeDeclarationBuilder &b)
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);
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.input_index()});
@@ -45,7 +47,7 @@ static void node_declare(NodeDeclarationBuilder &b)
}
}
b.add_input<decl::Extend>("", "__extend__");
b.add_output<decl::Extend>("", "__extend__");
b.add_output<decl::Extend>("", "__extend__").align_with_previous();
}
static void node_init(bNodeTree * /*tree*/, bNode *node)
@@ -98,6 +100,8 @@ 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);
@@ -107,7 +111,7 @@ static void node_declare(NodeDeclarationBuilder &b)
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);
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.input_index()});
@@ -115,7 +119,7 @@ static void node_declare(NodeDeclarationBuilder &b)
}
}
b.add_input<decl::Extend>("", "__extend__");
b.add_output<decl::Extend>("", "__extend__");
b.add_output<decl::Extend>("", "__extend__").align_with_previous();
}
static void node_init(bNodeTree * /*tree*/, bNode *node)
@@ -341,6 +341,8 @@ class LazyFunctionForSimulationInputNode final : public LazyFunction {
static void node_declare(NodeDeclarationBuilder &b)
{
b.use_custom_socket_order();
b.allow_any_socket_order();
b.add_output<decl::Float>("Delta Time");
const bNode *node = b.node_or_null();
@@ -362,14 +364,14 @@ static void node_declare(NodeDeclarationBuilder &b)
const StringRef name = item.name;
const std::string identifier = SimulationItemsAccessor::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);
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.input_index()});
}
}
b.add_input<decl::Extend>("", "__extend__");
b.add_output<decl::Extend>("", "__extend__");
b.add_output<decl::Extend>("", "__extend__").align_with_previous();
}
static void node_init(bNodeTree * /*tree*/, bNode *node)
@@ -681,6 +683,8 @@ class LazyFunctionForSimulationOutputNode final : public LazyFunction {
static void node_declare(NodeDeclarationBuilder &b)
{
b.use_custom_socket_order();
b.allow_any_socket_order();
b.add_input<decl::Bool>("Skip").description(
"Forward the output of the simulation input node directly to the output node and ignore "
"the nodes in the simulation zone");
@@ -698,14 +702,14 @@ static void node_declare(NodeDeclarationBuilder &b)
const StringRef name = item.name;
const std::string identifier = SimulationItemsAccessor::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);
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.input_index()});
}
}
b.add_input<decl::Extend>("", "__extend__");
b.add_output<decl::Extend>("", "__extend__");
b.add_output<decl::Extend>("", "__extend__").align_with_previous();
}
static void node_init(bNodeTree * /*tree*/, bNode *node)
@@ -123,6 +123,12 @@ void NodeDeclarationBuilder::use_custom_socket_order(bool enable)
declaration_.use_custom_socket_order = enable;
}
void NodeDeclarationBuilder::allow_any_socket_order(bool enable)
{
BLI_assert(declaration_.use_custom_socket_order);
declaration_.allow_any_socket_order = enable;
}
Span<SocketDeclaration *> NodeDeclaration::sockets(eNodeSocketInOut in_out) const
{
if (in_out == SOCK_IN) {
@@ -203,7 +209,7 @@ bool NodeDeclaration::is_valid() const
if (const SocketDeclaration *socket_decl = dynamic_cast<const SocketDeclaration *>(
item_decl.get()))
{
if (state.item_type != NODE_INTERFACE_SOCKET) {
if (state.item_type != NODE_INTERFACE_SOCKET && !this->allow_any_socket_order) {
std::cout << "Socket added after panel" << std::endl;
return false;
}
@@ -213,7 +219,7 @@ bool NodeDeclaration::is_valid() const
/* Start of input sockets. */
state.socket_in_out = SOCK_IN;
}
if (socket_decl->in_out != state.socket_in_out) {
if (socket_decl->in_out != state.socket_in_out && !this->allow_any_socket_order) {
std::cout << "Output socket added after input socket" << std::endl;
return false;
}
@@ -812,6 +818,17 @@ BaseSocketDeclarationBuilder &BaseSocketDeclarationBuilder::make_available(
return *this;
}
BaseSocketDeclarationBuilder &BaseSocketDeclarationBuilder::align_with_previous(const bool value)
{
if (decl_in_base_) {
decl_in_base_->align_with_previous_socket = value;
}
if (decl_out_base_) {
decl_out_base_->align_with_previous_socket = value;
}
return *this;
}
OutputFieldDependency OutputFieldDependency::ForFieldSource()
{
OutputFieldDependency field_dependency;