Nodes: Support for input/output sockets in same vertical space #112250

Merged
Lukas Tönne merged 25 commits from LukasTonne/blender:node-inline-sockets into main 2023-09-14 16:08:11 +02:00
6 changed files with 606 additions and 217 deletions

View File

@ -401,26 +401,26 @@ static bool node_update_basis_buttons(
static bool node_update_basis_socket(const bContext &C,
bNodeTree &ntree,
bNode &node,
bNodeSocket &socket,
bNodeSocket *input_socket,
bNodeSocket *output_socket,
uiBlock &block,
const int &locx,
int &locy)
{
if (!socket.is_visible()) {
if ((!input_socket || !input_socket->is_visible()) &&
(!output_socket || !output_socket->is_visible()))
{
return false;
}
const int topy = locy;
PointerRNA nodeptr = RNA_pointer_create(&ntree.id, &RNA_Node, &node);
PointerRNA sockptr = RNA_pointer_create(&ntree.id, &RNA_NodeSocket, &socket);
const eNodeSocketInOut in_out = eNodeSocketInOut(socket.in_out);
/* Add the half the height of a multi-input socket to cursor Y
* to account for the increased height of the taller sockets. */
const bool is_multi_input = (in_out == SOCK_IN && socket.flag & SOCK_MULTI_INPUT);
const bool is_multi_input = (input_socket ? input_socket->flag & SOCK_MULTI_INPUT : false);
const float multi_input_socket_offset = is_multi_input ?
std::max(socket.runtime->total_inputs - 2, 0) *
std::max(input_socket->runtime->total_inputs - 2,
0) *
NODE_MULTI_INPUT_LINK_GAP :
0.0f;
locy -= multi_input_socket_offset * 0.5f;
@ -439,39 +439,189 @@ static bool node_update_basis_socket(const bContext &C,
uiLayoutSetActive(layout, false);
}
/* Context pointers for current node and socket. */
uiLayoutSetContextPointer(layout, "node", &nodeptr);
uiLayoutSetContextPointer(layout, "socket", &sockptr);
uiLayout *row = uiLayoutRow(layout, true);
/* Align output buttons to the right. */
uiLayoutSetAlignment(row, in_out == SOCK_IN ? UI_LAYOUT_ALIGN_EXPAND : UI_LAYOUT_ALIGN_RIGHT);
PointerRNA nodeptr = RNA_pointer_create(&ntree.id, &RNA_Node, &node);
uiLayoutSetContextPointer(row, "node", &nodeptr);
const char *socket_label = bke::nodeSocketLabel(&socket);
const char *socket_translation_context = node_socket_get_translation_context(socket);
socket.typeinfo->draw((bContext *)&C,
row,
&sockptr,
&nodeptr,
CTX_IFACE_(socket_translation_context, socket_label));
if (input_socket) {
/* Context pointers for current node and socket. */
PointerRNA sockptr = RNA_pointer_create(&ntree.id, &RNA_NodeSocket, input_socket);
LukasTonne marked this conversation as resolved
Review

Might as well set the node constext pointer only once above

Might as well set the node constext pointer only once above
uiLayoutSetContextPointer(row, "socket", &sockptr);
node_socket_add_tooltip_in_node_editor(ntree, socket, *row);
uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_EXPAND);
const char *socket_label = bke::nodeSocketLabel(input_socket);
const char *socket_translation_context = node_socket_get_translation_context(*input_socket);
input_socket->typeinfo->draw((bContext *)&C,
row,
&sockptr,
&nodeptr,
CTX_IFACE_(socket_translation_context, socket_label));
}
else {
/* Context pointers for current node and socket. */
PointerRNA sockptr = RNA_pointer_create(&ntree.id, &RNA_NodeSocket, output_socket);
uiLayoutSetContextPointer(row, "socket", &sockptr);
/* Align output buttons to the right. */
uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
const char *socket_label = bke::nodeSocketLabel(output_socket);
const char *socket_translation_context = node_socket_get_translation_context(*output_socket);
output_socket->typeinfo->draw((bContext *)&C,
row,
&sockptr,
&nodeptr,
CTX_IFACE_(socket_translation_context, socket_label));
}
if (input_socket) {
node_socket_add_tooltip_in_node_editor(ntree, *input_socket, *row);
/* Round the socket location to stop it from jiggling. */
input_socket->runtime->location = float2(round(locx), round(locy - NODE_DYS));
}
if (output_socket) {
node_socket_add_tooltip_in_node_editor(ntree, *output_socket, *row);
/* Round the socket location to stop it from jiggling. */
output_socket->runtime->location = float2(round(locx + NODE_WIDTH(node)),
round(locy - NODE_DYS));
}
UI_block_align_end(&block);
int buty;
UI_block_layout_resolve(&block, nullptr, &buty);
/* Ensure minimum socket height in case layout is empty. */
buty = min_ii(buty, topy - NODE_DY);
/* Horizontal position for input/output. */
const float offsetx = (in_out == SOCK_IN ? 0.0f : NODE_WIDTH(node));
/* Round the socket location to stop it from jiggling. */
socket.runtime->location = float2(round(locx + offsetx), round(locy - NODE_DYS));
locy = buty - multi_input_socket_offset * 0.5;
return true;
}
struct NodeInterfaceItemData {
/* Declaration of a socket (only for socket items). */
const nodes::SocketDeclaration *socket_decl = nullptr;
bNodeSocket *input = nullptr;
bNodeSocket *output = nullptr;
LukasTonne marked this conversation as resolved Outdated

Since this is drawing code, it would be nice if these were const pointers. Same below.

Since this is drawing code, it would be nice if these were const pointers. Same below.

I've added some comments to this struct. state could potentially be made const, but currently draw code also updates the NODE_PANEL_PARENT_COLLAPSED flag in there (hiding the panel and its content). This could be done in a separate pass, but that would just duplicate the drawing code loop.

The runtime data stores transient draw info like the location, so it needs to be mutable.

I've added some comments to this struct. `state` could potentially be made const, but currently draw code also updates the `NODE_PANEL_PARENT_COLLAPSED` flag in there (hiding the panel and its content). This could be done in a separate pass, but that would just duplicate the drawing code loop. The `runtime` data stores transient draw info like the location, so it needs to be mutable.

Okay-- I'd like to move that runtime location storage to SpaceNode runtime, but while we still reorder nodes based on selection that's too tricky.

Okay-- I'd like to move that runtime location storage to `SpaceNode` runtime, but while we still reorder nodes based on selection that's too tricky.
/* Declaration of a panel (only for panel items). */
const nodes::PanelDeclaration *panel_decl = nullptr;
/* State of the panel instance on the node.
* Mutable so that panel visibility can be updated. */
bNodePanelState *state = nullptr;
/* Runtime panel state for draw locations. */
bke::bNodePanelRuntime *runtime = nullptr;
NodeInterfaceItemData(const nodes::SocketDeclaration *_socket_decl,
LukasTonne marked this conversation as resolved Outdated

These are public members, which shouldn't have the _ suffix. Same above.

These are public members, which shouldn't have the `_` suffix. Same above.
bNodeSocket *_input,
bNodeSocket *_output)
: socket_decl(_socket_decl), input(_input), output(_output)
{
}
NodeInterfaceItemData(const nodes::PanelDeclaration *_panel_decl,
LukasTonne marked this conversation as resolved Outdated

It's not clear what "valid" means here

It's not clear what "valid" means here
bNodePanelState *_state,
bke::bNodePanelRuntime *_runtime)
: panel_decl(_panel_decl), state(_state), runtime(_runtime)
{
}
bool is_valid_socket() const
{
/* At least one socket pointer must be valid. */
return this->socket_decl && (input || output);
}

In my experience it is often easier to just fill a vector with all the elements instead of building an iterator that has to keep track of the current iteration state explicitly. You could just build a Vector<std::variant<NodeInterfaceSocketData, NodeInterfacePanelData>> in one go (with some large inline buffer), and then iterate over it afterwards. That also often makes debugging easier, because it's much easier to check that the generated vector contains what you expect.

In my experience it is often easier to just fill a vector with all the elements instead of building an iterator that has to keep track of the current iteration state explicitly. You could just build a `Vector<std::variant<NodeInterfaceSocketData, NodeInterfacePanelData>>` in one go (with some large inline buffer), and then iterate over it afterwards. That also often makes debugging easier, because it's much easier to check that the generated vector contains what you expect.

Sounds reasonable, i'll give it a try.

Sounds reasonable, i'll give it a try.

I've replaced the iterator as suggested, hopefully the code is a little bit easier to understand.

I've replaced the iterator as suggested, hopefully the code is a little bit easier to understand.
LukasTonne marked this conversation as resolved Outdated

Maybe it's worth mentioning the similarity to bNodeTreeInterface::foreach_item here? Or how it's different too maybe?

Maybe it's worth mentioning the similarity to `bNodeTreeInterface::foreach_item` here? Or how it's different too maybe?
bool is_valid_panel() const
LukasTonne marked this conversation as resolved Outdated

Instead of struct ... { private:, this could just be class ...

Instead of `struct ... { private:`, this could just be `class ...`
{
/* Panel can only be drawn when state data is available. */
return this->panel_decl && this->state && this->runtime;
}
};
/* Compile relevant socket and panel pointer data into a vector.
* This helps ensure correct pointer access in complex situations like inlined sockets.
*/
static Vector<NodeInterfaceItemData> node_build_item_data(bNode &node)
{
namespace nodes = blender::nodes;
using ItemDeclIterator = blender::Span<nodes::ItemDeclarationPtr>::iterator;
LukasTonne marked this conversation as resolved Outdated

Can use node.inputs() and node.outputs() spans here instead of using the next and prev pointers I think

Can use `node.inputs()` and `node.outputs()` spans here instead of using the next and prev pointers I think
using SocketIterator = blender::Span<bNodeSocket *>::iterator;
using PanelStateIterator = blender::MutableSpan<bNodePanelState>::iterator;
using PanelRuntimeIterator = blender::MutableSpan<bke::bNodePanelRuntime>::iterator;
BLI_assert(is_node_panels_supported(node));
BLI_assert(node.runtime->panels.size() == node.num_panel_states);
ItemDeclIterator item_decl = node.declaration()->items.begin();
SocketIterator input = node.input_sockets().begin();
SocketIterator output = node.output_sockets().begin();
PanelStateIterator panel_state = node.panel_states().begin();
PanelRuntimeIterator panel_runtime = node.runtime->panels.begin();
const ItemDeclIterator item_decl_end = node.declaration()->items.end();
const SocketIterator input_end = node.input_sockets().end();
const SocketIterator output_end = node.output_sockets().end();
const PanelStateIterator panel_state_end = node.panel_states().end();
const PanelRuntimeIterator panel_runtime_end = node.runtime->panels.end();
Vector<NodeInterfaceItemData> result;
result.reserve(node.declaration()->items.size());
while (item_decl != item_decl_end) {
if (const nodes::SocketDeclaration *socket_decl =
dynamic_cast<const nodes::SocketDeclaration *>(item_decl->get()))
{
bNodeSocket *used_input = nullptr;
bNodeSocket *used_output = nullptr;
switch (socket_decl->in_out) {
case SOCK_IN:
BLI_assert(input != input_end);
used_input = *input;
++input;
break;
case SOCK_OUT:
BLI_assert(output != output_end);
used_output = *output;
++output;
break;
}
++item_decl;
if (socket_decl->inline_with_next && item_decl != item_decl_end) {
/* Consume the next item as well when inlining sockets. */
const nodes::SocketDeclaration *next_socket_decl =
dynamic_cast<const nodes::SocketDeclaration *>(item_decl->get());
if (next_socket_decl && next_socket_decl->in_out != socket_decl->in_out) {
switch (next_socket_decl->in_out) {
case SOCK_IN:
BLI_assert(input != input_end);
used_input = *input;
++input;
break;
case SOCK_OUT:
BLI_assert(output != output_end);
used_output = *output;
++output;
break;
}
++item_decl;
}
}
result.append({socket_decl, used_input, used_output});
}
else if (const nodes::PanelDeclaration *panel_decl =
dynamic_cast<const nodes::PanelDeclaration *>(item_decl->get()))
{
BLI_assert(panel_state != panel_state_end);
BLI_assert(panel_runtime != panel_runtime_end);
result.append({panel_decl, panel_state, panel_runtime});
++item_decl;
++panel_state;
++panel_runtime;
}
}
return result;
}
/* Advanced drawing with panels and arbitrary input/output ordering. */
static void node_update_basis_from_declaration(
const bContext &C, bNodeTree &ntree, bNode &node, uiBlock &block, const int locx, int &locy)
@ -480,7 +630,6 @@ static void node_update_basis_from_declaration(
BLI_assert(is_node_panels_supported(node));
BLI_assert(node.runtime->panels.size() == node.num_panel_states);
const nodes::NodeDeclaration &decl = *node.declaration();
/* Checked at various places to avoid adding duplicate spacers without anything in between. */
bool need_spacer_after_item = false;
@ -490,15 +639,10 @@ static void node_update_basis_from_declaration(
/* Makes sure buttons are only drawn once. */
bool buttons_drawn = false;
bNodeSocket *current_input = static_cast<bNodeSocket *>(node.inputs.first);
bNodeSocket *current_output = static_cast<bNodeSocket *>(node.outputs.first);
bNodePanelState *current_panel_state = node.panel_states_array;
bke::bNodePanelRuntime *current_panel_runtime = node.runtime->panels.begin();
/* The panel stack keeps track of the hierarchy of panels. When a panel declaration is found a
* new #PanelUpdate is added to the stack. Items in the declaration are added to the top panel of
* the stack. Each panel expects a number of items to be added, after which the panel is removed
* from the stack again. */
* new #PanelUpdate is added to the stack. Items in the declaration are added to the top panel
* of the stack. Each panel expects a number of items to be added, after which the panel is
* removed from the stack again. */
struct PanelUpdate {
/* How many declarations still to add. */
LukasTonne marked this conversation as resolved Outdated

Unnecessary formatting change?

Unnecessary formatting change?

Bah, clang-format keeps doing this, and it's usually in a multiline comment where it's not immediately obvious ...

Bah, clang-format keeps doing this, and it's usually in a multiline comment where it's not immediately obvious ...

make format insists on this, guess it was wrong before 🤷

`make format` insists on this, guess it was wrong before 🤷
int remaining_decls;
@ -507,10 +651,12 @@ static void node_update_basis_from_declaration(
/* Location data, needed to finalize the panel when all items have been added. */
bke::bNodePanelRuntime *runtime;
};
bool is_first = true;
Stack<PanelUpdate> panel_updates;
for (const nodes::ItemDeclarationPtr &item_decl : decl.items) {
/* Only true for the first item in the layout. */
bool is_first = true;
const Vector<NodeInterfaceItemData> item_data = node_build_item_data(node);
for (const NodeInterfaceItemData &item : item_data) {
bool is_parent_collapsed = false;
if (PanelUpdate *parent_update = panel_updates.is_empty() ? nullptr : &panel_updates.peek()) {
/* Adding an item to the parent panel, will be popped when reaching 0. */
@ -519,11 +665,7 @@ static void node_update_basis_from_declaration(
is_parent_collapsed = parent_update->is_collapsed;
}
if (nodes::PanelDeclaration *panel_decl = dynamic_cast<nodes::PanelDeclaration *>(
item_decl.get())) {
BLI_assert(node.panel_states().contains_ptr(current_panel_state));
BLI_assert(node.runtime->panels.as_span().contains_ptr(current_panel_runtime));
if (item.is_valid_panel()) {
/* Draw buttons before the first panel. */
if (!buttons_drawn) {
buttons_drawn = true;
@ -535,70 +677,58 @@ static void node_update_basis_from_declaration(
is_first = false;
}
SET_FLAG_FROM_TEST(
current_panel_state->flag, is_parent_collapsed, NODE_PANEL_PARENT_COLLAPSED);
SET_FLAG_FROM_TEST(item.state->flag, is_parent_collapsed, NODE_PANEL_PARENT_COLLAPSED);
/* New top panel is collapsed if self or parent is collapsed. */
const bool is_collapsed = is_parent_collapsed || current_panel_state->is_collapsed();
panel_updates.push({panel_decl->num_child_decls, is_collapsed, current_panel_runtime});
const bool is_collapsed = is_parent_collapsed || item.state->is_collapsed();
panel_updates.push({item.panel_decl->num_child_decls, is_collapsed, item.runtime});
/* Round the socket location to stop it from jiggling. */
current_panel_runtime->location_y = round(locy + NODE_DYS);
current_panel_runtime->max_content_y = current_panel_runtime->min_content_y = round(locy);
++current_panel_state;
++current_panel_runtime;
item.runtime->location_y = round(locy + NODE_DYS);
item.runtime->max_content_y = item.runtime->min_content_y = round(locy);
}
else if (nodes::SocketDeclaration *socket_decl = dynamic_cast<nodes::SocketDeclaration *>(
item_decl.get()))
{
switch (socket_decl->in_out) {
case SOCK_IN:
/* Must match the declaration. */
BLI_assert(current_input != nullptr);
else if (item.is_valid_socket()) {
if (item.input) {
SET_FLAG_FROM_TEST(item.input->flag, is_parent_collapsed, SOCK_PANEL_COLLAPSED);
/* Draw buttons before the first input, unless it's inline with an output. */
if (!item.socket_decl->inline_with_next && !buttons_drawn) {
buttons_drawn = true;
need_spacer_after_item = node_update_basis_buttons(C, ntree, node, block, locy);
}
/* Draw buttons before the first input. */
if (!buttons_drawn) {
buttons_drawn = true;
need_spacer_after_item = node_update_basis_buttons(C, ntree, node, block, locy);
if (is_parent_collapsed) {
item.input->runtime->location = float2(locx, round(locy + NODE_DYS));
}
else {
/* Space between items. */
if (!is_first && item.input->is_visible()) {
locy -= NODE_SOCKDY;
}
SET_FLAG_FROM_TEST(current_input->flag, is_parent_collapsed, SOCK_PANEL_COLLAPSED);
if (is_parent_collapsed) {
current_input->runtime->location = float2(locx, round(locy + NODE_DYS));
}
else {
/* Space between items. */
if (!is_first && current_input->is_visible()) {
locy -= NODE_SOCKDY;
}
if (node_update_basis_socket(C, ntree, node, *current_input, block, locx, locy)) {
is_first = false;
need_spacer_after_item = true;
}
}
current_input = current_input->next;
break;
case SOCK_OUT:
/* Must match the declaration. */
BLI_assert(current_output != nullptr);
SET_FLAG_FROM_TEST(current_output->flag, is_parent_collapsed, SOCK_PANEL_COLLAPSED);
if (is_parent_collapsed) {
current_output->runtime->location = float2(round(locx + NODE_WIDTH(node)),
round(locy + NODE_DYS));
}
else {
/* Space between items. */
if (!is_first && current_output->is_visible()) {
locy -= NODE_SOCKDY;
}
if (node_update_basis_socket(C, ntree, node, *current_output, block, locx, locy)) {
is_first = false;
need_spacer_after_item = true;
}
}
current_output = current_output->next;
break;
}
}
if (item.output) {
SET_FLAG_FROM_TEST(item.output->flag, is_parent_collapsed, SOCK_PANEL_COLLAPSED);
if (is_parent_collapsed) {
item.output->runtime->location = float2(round(locx + NODE_WIDTH(node)),
round(locy + NODE_DYS));
}
else {
/* Space between items. */
if (!is_first && item.output->is_visible()) {
locy -= NODE_SOCKDY;
}
}
}
if (!is_parent_collapsed &&
node_update_basis_socket(C, ntree, node, item.input, item.output, block, locx, locy))
{
is_first = false;
need_spacer_after_item = true;
}
}
else {
/* Should not happen. */
BLI_assert_unreachable();
}
/* Close parent panels that have all items added. */
@ -646,7 +776,7 @@ static void node_update_basis_from_socket_lists(
/* Clear flag, conventional drawing does not support panels. */
socket->flag &= ~SOCK_PANEL_COLLAPSED;
if (node_update_basis_socket(C, ntree, node, *socket, block, locx, locy)) {
if (node_update_basis_socket(C, ntree, node, nullptr, socket, block, locx, locy)) {
if (socket->next) {
locy -= NODE_SOCKDY;
}
@ -665,7 +795,7 @@ static void node_update_basis_from_socket_lists(
/* Clear flag, conventional drawing does not support panels. */
socket->flag &= ~SOCK_PANEL_COLLAPSED;
if (node_update_basis_socket(C, ntree, node, *socket, block, locx, locy)) {
if (node_update_basis_socket(C, ntree, node, socket, nullptr, block, locx, locy)) {
if (socket->next) {
locy -= NODE_SOCKDY;
}
@ -904,13 +1034,14 @@ static void node_socket_draw_multi_input(const float color[4],
const float height,
const float2 location)
{
/* The other sockets are drawn with the keyframe shader. There, the outline has a base thickness
* that can be varied but always scales with the size the socket is drawn at. Using
/* The other sockets are drawn with the keyframe shader. There, the outline has a base
* thickness that can be varied but always scales with the size the socket is drawn at. Using
* `UI_SCALE_FAC` has the same effect here. It scales the outline correctly across different
* screen DPI's and UI scales without being affected by the 'line-width'. */
const float outline_width = NODE_SOCK_OUTLINE_SCALE * UI_SCALE_FAC;
/* UI_draw_roundbox draws the outline on the outer side, so compensate for the outline width. */
/* UI_draw_roundbox draws the outline on the outer side, so compensate for the outline width.
*/
const rctf rect = {
location.x - width + outline_width * 0.5f,
location.x + width - outline_width * 0.5f,
@ -2306,7 +2437,8 @@ static Vector<NodeExtraInfoRow> node_get_extra_info(TreeDrawContext &tree_draw_c
row.text = node_get_execution_time_label(tree_draw_ctx, snode, node);
if (!row.text.empty()) {
row.tooltip = TIP_(
"The execution time from the node tree's latest evaluation. For frame and group nodes, "
"The execution time from the node tree's latest evaluation. For frame and group "
"nodes, "
"the time for all sub-nodes");
row.icon = ICON_PREVIEW_RANGE;
rows.append(std::move(row));
@ -3601,7 +3733,8 @@ static void node_draw_zones(TreeDrawContext & /*tree_draw_ctx*/,
return bounding_box_area_by_zone[a] > bounding_box_area_by_zone[b];
});
/* Draw all the contour lines after to prevent them from getting hidden by overlapping zones. */
/* Draw all the contour lines after to prevent them from getting hidden by overlapping zones.
*/
for (const int zone_i : zone_draw_order) {
float zone_color[4];
UI_GetThemeColor4fv(get_theme_id(zone_i), zone_color);

View File

@ -182,6 +182,7 @@ class SocketDeclaration : public ItemDeclaration {
bool is_unavailable = false;
bool is_attribute_name = false;
bool is_default_link_socket = false;
bool inline_with_next = false;
InputSocketFieldType input_field_type = InputSocketFieldType::None;
OutputFieldDependency output_field_dependency;
@ -246,7 +247,10 @@ class NodeDeclarationBuilder;
class BaseSocketDeclarationBuilder {
protected:
int index_ = -1;
/* Socket builder can hold both an input and an output declaration.
LukasTonne marked this conversation as resolved Outdated

Seems important to add comments here

Seems important to add comments here
* Each socket declaration has its own index for dependencies. */
int index_in_ = -1;
int index_out_ = -1;
bool reference_pass_all_ = false;
bool field_on_all_ = false;
bool propagate_from_all_ = false;
@ -258,7 +262,8 @@ class BaseSocketDeclarationBuilder {
virtual ~BaseSocketDeclarationBuilder() = default;
protected:
virtual SocketDeclaration *declaration() = 0;
virtual SocketDeclaration *input_declaration() = 0;
virtual SocketDeclaration *output_declaration() = 0;
};
/**
@ -271,44 +276,72 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
protected:
using Self = typename SocketDecl::Builder;
static_assert(std::is_base_of_v<SocketDeclaration, SocketDecl>);
SocketDecl *decl_;
SocketDecl *decl_in_;
SocketDecl *decl_out_;
LukasTonne marked this conversation as resolved
Review

What do you think about also storing a Vector<SocketDecl *, 2> here that either contains one or two decls? This could reduce some redundancy in the methods below because one could use a loop instead of repeating the code twice.

What do you think about also storing a `Vector<SocketDecl *, 2>` here that either contains one or two decls? This could reduce some redundancy in the methods below because one could use a loop instead of repeating the code twice.
Review

I've tried this and it doesn't meaningfully reduce the amount of code. There are also a bunch of places where an input declaration is treated differently from an output declaration and would have to check the type, for example (code from main):

  Self &field_on_all()
  {
    if (decl_->in_out == SOCK_IN) {
      this->supports_field();
    }
    else {
      this->field_source();
    }
    field_on_all_ = true;
    return *(Self *)this;
  }

We might eventually have cases where a single declaration builder can generate a whole bunch of sockets, like a multi-input, but i'd rather implement this when needed.

I've tried this and it doesn't meaningfully reduce the amount of code. There are also a bunch of places where an input declaration is treated differently from an output declaration and would have to check the type, for example (code from `main`): ```cpp Self &field_on_all() { if (decl_->in_out == SOCK_IN) { this->supports_field(); } else { this->field_source(); } field_on_all_ = true; return *(Self *)this; } ``` We might eventually have cases where a single declaration builder can generate a whole bunch of sockets, like a multi-input, but i'd rather implement this when needed.
friend class NodeDeclarationBuilder;
public:
Self &hide_label(bool value = true)
{
decl_->hide_label = value;
if (decl_in_) {
decl_in_->hide_label = value;
}
if (decl_out_) {
decl_out_->hide_label = value;
}
return *(Self *)this;
}
Self &hide_value(bool value = true)
{
decl_->hide_value = value;
if (decl_in_) {
decl_in_->hide_value = value;
}
if (decl_out_) {
decl_out_->hide_value = value;
}
return *(Self *)this;
}
Self &multi_input(bool value = true)
{
decl_->is_multi_input = value;
if (decl_in_) {
decl_in_->is_multi_input = value;
}
return *(Self *)this;
}
Self &description(std::string value = "")
{
decl_->description = std::move(value);
if (decl_in_) {
decl_in_->description = std::move(value);
}
if (decl_out_) {
decl_out_->description = std::move(value);
}
return *(Self *)this;
}
Self &translation_context(std::string value = BLT_I18NCONTEXT_DEFAULT)
{
decl_->translation_context = std::move(value);
if (decl_in_) {
decl_in_->translation_context = std::move(value);
}
if (decl_out_) {
decl_out_->translation_context = std::move(value);
}
return *(Self *)this;
}
Self &no_muted_links(bool value = true)
{
decl_->no_mute_links = value;
if (decl_in_) {
decl_in_->no_mute_links = value;
}
if (decl_out_) {
decl_out_->no_mute_links = value;
}
return *(Self *)this;
}
@ -318,26 +351,43 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
*/
Self &unavailable(bool value = true)
{
decl_->is_unavailable = value;
if (decl_in_) {
decl_in_->is_unavailable = value;
}
if (decl_out_) {
decl_out_->is_unavailable = value;
}
return *(Self *)this;
}
Self &is_attribute_name(bool value = true)
{
decl_->is_attribute_name = value;
if (decl_in_) {
decl_in_->is_attribute_name = value;
}
if (decl_out_) {
decl_out_->is_attribute_name = value;
}
return *(Self *)this;
}
Self &is_default_link_socket(bool value = true)
{
decl_->is_default_link_socket = value;
if (decl_in_) {
decl_in_->is_default_link_socket = value;
}
if (decl_out_) {
decl_out_->is_default_link_socket = value;
}
return *(Self *)this;
}
/** The input socket allows passing in a field. */
Self &supports_field()
{
decl_->input_field_type = InputSocketFieldType::IsSupported;
if (decl_in_) {
decl_in_->input_field_type = InputSocketFieldType::IsSupported;
}
return *(Self *)this;
}
@ -350,10 +400,10 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
*/
Self &field_on_all()
{
if (decl_->in_out == SOCK_IN) {
if (decl_in_) {
this->supports_field();
}
else {
if (decl_out_) {
this->field_source();
}
field_on_all_ = true;
@ -367,8 +417,10 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
Self &implicit_field(ImplicitInputValueFn fn)
{
this->hide_value();
decl_->input_field_type = InputSocketFieldType::Implicit;
decl_->implicit_input_fn_ = std::make_unique<ImplicitInputValueFn>(std::move(fn));
if (decl_in_) {
decl_in_->input_field_type = InputSocketFieldType::Implicit;
decl_in_->implicit_input_fn_ = std::make_unique<ImplicitInputValueFn>(std::move(fn));
}
return *(Self *)this;
}
@ -391,14 +443,18 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
/** The output is always a field, regardless of any inputs. */
Self &field_source()
{
decl_->output_field_dependency = OutputFieldDependency::ForFieldSource();
if (decl_out_) {
decl_out_->output_field_dependency = OutputFieldDependency::ForFieldSource();
}
return *(Self *)this;
}
/** The output is a field if any of the inputs are a field. */
Self &dependent_field()
{
decl_->output_field_dependency = OutputFieldDependency::ForDependentField();
if (decl_out_) {
decl_out_->output_field_dependency = OutputFieldDependency::ForDependentField();
}
this->reference_pass_all();
return *(Self *)this;
}
@ -407,8 +463,10 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
Self &dependent_field(Vector<int> input_dependencies)
{
this->reference_pass(input_dependencies);
decl_->output_field_dependency = OutputFieldDependency::ForPartiallyDependentField(
std::move(input_dependencies));
if (decl_out_) {
decl_out_->output_field_dependency = OutputFieldDependency::ForPartiallyDependentField(
std::move(input_dependencies));
}
return *(Self *)this;
}
@ -446,7 +504,12 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
Self &compositor_realization_options(CompositorInputRealizationOptions value)
{
decl_->compositor_realization_options_ = value;
if (decl_in_) {
decl_in_->compositor_realization_options_ = value;
}
if (decl_out_) {
decl_out_->compositor_realization_options_ = value;
}
return *(Self *)this;
}
@ -454,7 +517,12 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
* realtime_compositor::InputDescriptor for more information. */
Self &compositor_domain_priority(int priority)
{
decl_->compositor_domain_priority_ = priority;
if (decl_in_) {
decl_in_->compositor_domain_priority_ = priority;
}
if (decl_out_) {
decl_out_->compositor_domain_priority_ = priority;
}
return *(Self *)this;
}
@ -462,7 +530,12 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
* realtime_compositor::InputDescriptor for more information. */
Self &compositor_expects_single_value(bool value = true)
{
decl_->compositor_expects_single_value_ = value;
if (decl_in_) {
decl_in_->compositor_expects_single_value_ = value;
}
if (decl_out_) {
decl_out_->compositor_expects_single_value_ = value;
}
return *(Self *)this;
}
@ -474,14 +547,23 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
*/
Self &make_available(std::function<void(bNode &)> fn)
{
decl_->make_available_fn_ = std::move(fn);
if (decl_in_) {
decl_in_->make_available_fn_ = std::move(fn);
}
if (decl_out_) {
decl_out_->make_available_fn_ = std::move(fn);
}
return *(Self *)this;
}
protected:
SocketDeclaration *declaration() override
SocketDeclaration *input_declaration() override
{
return decl_;
return decl_in_;
}
SocketDeclaration *output_declaration() override
{
return decl_out_;
}
};
@ -541,6 +623,10 @@ class PanelDeclarationBuilder {
typename DeclType::Builder &add_input(StringRef name, StringRef identifier = "");
template<typename DeclType>
typename DeclType::Builder &add_output(StringRef name, StringRef identifier = "");
template<typename DeclType>
typename DeclType::Builder &add_input_output(StringRef name,
StringRef identifier_in = "",
StringRef identifier_out = "");
};
using PanelDeclarationPtr = std::unique_ptr<PanelDeclaration>;
@ -583,8 +669,7 @@ class NodeDeclaration {
class NodeDeclarationBuilder {
private:
NodeDeclaration &declaration_;
Vector<std::unique_ptr<BaseSocketDeclarationBuilder>> input_builders_;
Vector<std::unique_ptr<BaseSocketDeclarationBuilder>> output_builders_;
Vector<std::unique_ptr<BaseSocketDeclarationBuilder>> socket_builders_;
Vector<std::unique_ptr<PanelDeclarationBuilder>> panel_builders_;
bool is_function_node_ = false;
@ -611,6 +696,10 @@ class NodeDeclarationBuilder {
typename DeclType::Builder &add_input(StringRef name, StringRef identifier = "");
template<typename DeclType>
typename DeclType::Builder &add_output(StringRef name, StringRef identifier = "");
template<typename DeclType>
typename DeclType::Builder &add_input_output(StringRef name,
StringRef identifier_in = "",
StringRef identifier_out = "");
PanelDeclarationBuilder &add_panel(StringRef name, int identifier = -1);
aal::RelationsInNode &get_anonymous_attribute_relations()
@ -622,9 +711,12 @@ class NodeDeclarationBuilder {
}
private:
/* Note: in_out can be a combination of SOCK_IN and SOCK_OUT.
* The generated socket declarations only have a single flag set. */
template<typename DeclType>
typename DeclType::Builder &add_socket(StringRef name,
StringRef identifier,
StringRef identifier_in,
StringRef identifier_out,
eNodeSocketInOut in_out);
/* Mark the most recent builder as 'complete' when changing builders
@ -652,7 +744,7 @@ typename SocketDeclarationBuilder<SocketDecl>::Self &SocketDeclarationBuilder<
for (const int from_input : input_indices) {
aal::ReferenceRelation relation;
relation.from_field_input = from_input;
relation.to_field_output = index_;
relation.to_field_output = index_out_;
relations.reference_relations.append(relation);
}
return *(Self *)this;
@ -663,20 +755,20 @@ typename SocketDeclarationBuilder<SocketDecl>::Self &SocketDeclarationBuilder<
SocketDecl>::field_on(const Span<int> indices)
{
aal::RelationsInNode &relations = node_decl_builder_->get_anonymous_attribute_relations();
if (decl_->in_out == SOCK_IN) {
if (decl_in_) {
this->supports_field();
for (const int input_index : indices) {
aal::EvalRelation relation;
relation.field_input = index_;
relation.field_input = index_in_;
relation.geometry_input = input_index;
relations.eval_relations.append(relation);
}
}
else {
if (decl_out_) {
this->field_source();
for (const int output_index : indices) {
aal::AvailableRelation relation;
relation.field_output = index_;
relation.field_output = index_out_;
relation.geometry_output = output_index;
relations.available_relations.append(relation);
}
@ -803,7 +895,7 @@ typename DeclType::Builder &PanelDeclarationBuilder::add_input(StringRef name,
return dummy_builder;
}
++this->decl_->num_child_decls;
return node_decl_builder_->add_socket<DeclType>(name, identifier, SOCK_IN);
return node_decl_builder_->add_socket<DeclType>(name, identifier, "", SOCK_IN);
}
template<typename DeclType>
@ -816,7 +908,22 @@ typename DeclType::Builder &PanelDeclarationBuilder::add_output(StringRef name,
return dummy_builder;
}
++this->decl_->num_child_decls;
return node_decl_builder_->add_socket<DeclType>(name, identifier, SOCK_OUT);
return node_decl_builder_->add_socket<DeclType>(name, "", identifier, SOCK_OUT);
}
template<typename DeclType>
typename DeclType::Builder &PanelDeclarationBuilder::add_input_output(StringRef name,
StringRef identifier_in,
StringRef identifier_out)
{
if (is_complete_) {
static typename DeclType::Builder dummy_builder = {};
BLI_assert_unreachable();
return dummy_builder;
}
++this->decl_->num_child_decls;
return node_decl_builder_->add_socket<DeclType>(
name, identifier_in, identifier_out, SOCK_IN | SOCK_OUT);
}
/** \} */
@ -840,7 +947,7 @@ inline typename DeclType::Builder &NodeDeclarationBuilder::add_input(StringRef n
StringRef identifier)
{
set_active_panel_builder(nullptr);
return this->add_socket<DeclType>(name, identifier, SOCK_IN);
return this->add_socket<DeclType>(name, identifier, "", SOCK_IN);
}
template<typename DeclType>
@ -848,34 +955,50 @@ inline typename DeclType::Builder &NodeDeclarationBuilder::add_output(StringRef
StringRef identifier)
{
set_active_panel_builder(nullptr);
return this->add_socket<DeclType>(name, identifier, SOCK_OUT);
return this->add_socket<DeclType>(name, "", identifier, SOCK_OUT);
}
template<typename DeclType>
inline typename DeclType::Builder &NodeDeclarationBuilder::add_input_output(
StringRef name, StringRef identifier_in, StringRef identifier_out)
{
set_active_panel_builder(nullptr);
return this->add_socket<DeclType>(name, identifier_in, identifier_out, SOCK_IN | SOCK_OUT);
}
template<typename DeclType>
inline typename DeclType::Builder &NodeDeclarationBuilder::add_socket(StringRef name,
StringRef identifier,
StringRef identifier_in,
StringRef identifier_out,
eNodeSocketInOut in_out)
{
static_assert(std::is_base_of_v<SocketDeclaration, DeclType>);
using Builder = typename DeclType::Builder;
Vector<SocketDeclaration *> &declarations = in_out == SOCK_IN ? declaration_.inputs :
declaration_.outputs;
std::unique_ptr<DeclType> socket_decl = std::make_unique<DeclType>();
std::unique_ptr<Builder> socket_decl_builder = std::make_unique<Builder>();
socket_decl_builder->decl_ = &*socket_decl;
socket_decl_builder->node_decl_builder_ = this;
socket_decl->name = name;
socket_decl->identifier = identifier.is_empty() ? name : identifier;
socket_decl->in_out = in_out;
socket_decl_builder->index_ = declarations.append_and_get_index(socket_decl.get());
declaration_.items.append(std::move(socket_decl));
if (in_out & SOCK_IN) {
std::unique_ptr<DeclType> socket_decl = std::make_unique<DeclType>();
socket_decl_builder->decl_in_ = &*socket_decl;
socket_decl->name = name;
socket_decl->identifier = identifier_in.is_empty() ? name : identifier_in;
socket_decl->in_out = SOCK_IN;
socket_decl_builder->index_in_ = declaration_.inputs.append_and_get_index(socket_decl.get());
declaration_.items.append(std::move(socket_decl));
}
if (in_out & SOCK_OUT) {
std::unique_ptr<DeclType> socket_decl = std::make_unique<DeclType>();
socket_decl_builder->decl_out_ = &*socket_decl;
socket_decl->name = name;
socket_decl->identifier = identifier_out.is_empty() ? name : identifier_out;
socket_decl->in_out = SOCK_OUT;
socket_decl_builder->index_out_ = declaration_.outputs.append_and_get_index(socket_decl.get());
declaration_.items.append(std::move(socket_decl));
}
Builder &socket_decl_builder_ref = *socket_decl_builder;
((in_out == SOCK_IN) ? input_builders_ : output_builders_)
.append(std::move(socket_decl_builder));
socket_builders_.append(std::move(socket_decl_builder));
return socket_decl_builder_ref;
}

View File

@ -284,25 +284,45 @@ class Custom : public SocketDeclaration {
inline FloatBuilder &FloatBuilder::min(const float value)
{
decl_->soft_min_value = value;
if (decl_in_) {
decl_in_->soft_min_value = value;
}
if (decl_out_) {
decl_out_->soft_min_value = value;
}
return *this;
}
inline FloatBuilder &FloatBuilder::max(const float value)
{
decl_->soft_max_value = value;
if (decl_in_) {
decl_in_->soft_max_value = value;
}
if (decl_out_) {
decl_out_->soft_max_value = value;
}
return *this;
}
inline FloatBuilder &FloatBuilder::default_value(const float value)
{
decl_->default_value = value;
if (decl_in_) {
decl_in_->default_value = value;
}
if (decl_out_) {
decl_out_->default_value = value;
}
return *this;
}
inline FloatBuilder &FloatBuilder::subtype(PropertySubType subtype)
{
decl_->subtype = subtype;
if (decl_in_) {
decl_in_->subtype = subtype;
}
if (decl_out_) {
decl_out_->subtype = subtype;
}
return *this;
}
@ -314,25 +334,45 @@ inline FloatBuilder &FloatBuilder::subtype(PropertySubType subtype)
inline IntBuilder &IntBuilder::min(const int value)
{
decl_->soft_min_value = value;
if (decl_in_) {
decl_in_->soft_min_value = value;
}
if (decl_out_) {
decl_out_->soft_min_value = value;
}
return *this;
}
inline IntBuilder &IntBuilder::max(const int value)
{
decl_->soft_max_value = value;
if (decl_in_) {
decl_in_->soft_max_value = value;
}
if (decl_out_) {
decl_out_->soft_max_value = value;
}
return *this;
}
inline IntBuilder &IntBuilder::default_value(const int value)
{
decl_->default_value = value;
if (decl_in_) {
decl_in_->default_value = value;
}
if (decl_out_) {
decl_out_->default_value = value;
}
return *this;
}
inline IntBuilder &IntBuilder::subtype(PropertySubType subtype)
{
decl_->subtype = subtype;
if (decl_in_) {
decl_in_->subtype = subtype;
}
if (decl_out_) {
decl_out_->subtype = subtype;
}
return *this;
}
@ -344,31 +384,56 @@ inline IntBuilder &IntBuilder::subtype(PropertySubType subtype)
inline VectorBuilder &VectorBuilder::default_value(const float3 value)
{
decl_->default_value = value;
if (decl_in_) {
decl_in_->default_value = value;
}
if (decl_out_) {
decl_out_->default_value = value;
}
return *this;
}
inline VectorBuilder &VectorBuilder::subtype(PropertySubType subtype)
{
decl_->subtype = subtype;
if (decl_in_) {
decl_in_->subtype = subtype;
}
if (decl_out_) {
decl_out_->subtype = subtype;
}
return *this;
}
inline VectorBuilder &VectorBuilder::min(const float min)
{
decl_->soft_min_value = min;
if (decl_in_) {
decl_in_->soft_min_value = min;
}
if (decl_out_) {
decl_out_->soft_min_value = min;
}
return *this;
}
inline VectorBuilder &VectorBuilder::max(const float max)
{
decl_->soft_max_value = max;
if (decl_in_) {
decl_in_->soft_max_value = max;
}
if (decl_out_) {
decl_out_->soft_max_value = max;
}
return *this;
}
inline VectorBuilder &VectorBuilder::compact()
{
decl_->compact = true;
if (decl_in_) {
decl_in_->compact = true;
}
if (decl_out_) {
decl_out_->compact = true;
}
return *this;
}
@ -380,7 +445,12 @@ inline VectorBuilder &VectorBuilder::compact()
inline BoolBuilder &BoolBuilder::default_value(const bool value)
{
decl_->default_value = value;
if (decl_in_) {
decl_in_->default_value = value;
}
if (decl_out_) {
decl_out_->default_value = value;
}
return *this;
}
@ -392,7 +462,12 @@ inline BoolBuilder &BoolBuilder::default_value(const bool value)
inline ColorBuilder &ColorBuilder::default_value(const ColorGeometry4f value)
{
decl_->default_value = value;
if (decl_in_) {
decl_in_->default_value = value;
}
if (decl_out_) {
decl_out_->default_value = value;
}
return *this;
}
@ -404,7 +479,12 @@ inline ColorBuilder &ColorBuilder::default_value(const ColorGeometry4f value)
inline StringBuilder &StringBuilder::default_value(std::string value)
{
decl_->default_value = std::move(value);
if (decl_in_) {
decl_in_->default_value = std::move(value);
}
if (decl_out_) {
decl_out_->default_value = std::move(value);
}
return *this;
}
@ -416,7 +496,12 @@ inline StringBuilder &StringBuilder::default_value(std::string value)
inline RotationBuilder &RotationBuilder::default_value(const math::EulerXYZ &value)
{
decl_->default_value = value;
if (decl_in_) {
decl_in_->default_value = value;
}
if (decl_out_) {
decl_out_->default_value = value;
}
return *this;
}

View File

@ -378,19 +378,26 @@ void node_group_declare_dynamic(const bNodeTree & /*node_tree*/,
case NODE_INTERFACE_SOCKET: {
const bNodeTreeInterfaceSocket &socket =
node_interface::get_item_as<bNodeTreeInterfaceSocket>(item);
if (socket.flag & NODE_INTERFACE_SOCKET_OUTPUT) {
if (SocketDeclarationPtr socket_decl = declaration_for_interface_socket(
*group, socket, SOCK_OUT)) {
r_declaration.outputs.append(socket_decl.get());
r_declaration.items.append(std::move(socket_decl));
}
SocketDeclarationPtr input_decl = (socket.flag & NODE_INTERFACE_SOCKET_INPUT) ?
declaration_for_interface_socket(
*group, socket, SOCK_IN) :
nullptr;
SocketDeclarationPtr output_decl = (socket.flag & NODE_INTERFACE_SOCKET_OUTPUT) ?
declaration_for_interface_socket(
*group, socket, SOCK_OUT) :
nullptr;
/* Inline with the output socket if using input+output mode. */
if (input_decl && output_decl) {
input_decl->inline_with_next = true;
}
if (socket.flag & NODE_INTERFACE_SOCKET_INPUT) {
if (SocketDeclarationPtr socket_decl = declaration_for_interface_socket(
*group, socket, SOCK_IN)) {
r_declaration.inputs.append(socket_decl.get());
r_declaration.items.append(std::move(socket_decl));
}
if (input_decl) {
r_declaration.inputs.append(input_decl.get());
r_declaration.items.append(std::move(input_decl));
}
if (output_decl) {
r_declaration.outputs.append(output_decl.get());
r_declaration.items.append(std::move(output_decl));
}
break;
}

View File

@ -34,19 +34,26 @@ void build_node_declaration_dynamic(const bNodeTree &node_tree,
void NodeDeclarationBuilder::finalize()
{
BLI_assert(declaration_.is_valid());
/* Declarations generating both input and output should align these sockets. */
for (std::unique_ptr<BaseSocketDeclarationBuilder> &socket_builder : socket_builders_) {
if (socket_builder->input_declaration() && socket_builder->output_declaration()) {
socket_builder->input_declaration()->inline_with_next = true;
}
}
if (is_function_node_) {
for (std::unique_ptr<BaseSocketDeclarationBuilder> &socket_builder : input_builders_) {
SocketDeclaration &socket_decl = *socket_builder->declaration();
if (socket_decl.input_field_type != InputSocketFieldType::Implicit) {
socket_decl.input_field_type = InputSocketFieldType::IsSupported;
for (std::unique_ptr<BaseSocketDeclarationBuilder> &socket_builder : socket_builders_) {
if (SocketDeclaration *socket_decl = socket_builder->input_declaration()) {
if (socket_decl->input_field_type != InputSocketFieldType::Implicit) {
socket_decl->input_field_type = InputSocketFieldType::IsSupported;
}
}
}
for (std::unique_ptr<BaseSocketDeclarationBuilder> &socket_builder : output_builders_) {
SocketDeclaration &socket_decl = *socket_builder->declaration();
socket_decl.output_field_dependency = OutputFieldDependency::ForDependentField();
socket_builder->reference_pass_all_ = true;
for (std::unique_ptr<BaseSocketDeclarationBuilder> &socket_builder : socket_builders_) {
if (SocketDeclaration *socket_decl = socket_builder->output_declaration()) {
socket_decl->output_field_dependency = OutputFieldDependency::ForDependentField();
socket_builder->reference_pass_all_ = true;
}
}
}
@ -63,26 +70,34 @@ void NodeDeclarationBuilder::finalize()
}
}
for (std::unique_ptr<BaseSocketDeclarationBuilder> &socket_builder : input_builders_) {
for (std::unique_ptr<BaseSocketDeclarationBuilder> &socket_builder : socket_builders_) {
if (!socket_builder->input_declaration()) {
continue;
}
if (socket_builder->field_on_all_) {
aal::RelationsInNode &relations = this->get_anonymous_attribute_relations();
const int field_input = socket_builder->index_;
const int field_input = socket_builder->index_in_;
for (const int geometry_input : geometry_inputs) {
relations.eval_relations.append({field_input, geometry_input});
}
}
}
for (std::unique_ptr<BaseSocketDeclarationBuilder> &socket_builder : output_builders_) {
for (std::unique_ptr<BaseSocketDeclarationBuilder> &socket_builder : socket_builders_) {
if (!socket_builder->output_declaration()) {
continue;
}
if (socket_builder->field_on_all_) {
aal::RelationsInNode &relations = this->get_anonymous_attribute_relations();
const int field_output = socket_builder->index_;
const int field_output = socket_builder->index_out_;
for (const int geometry_output : geometry_outputs) {
relations.available_relations.append({field_output, geometry_output});
}
}
if (socket_builder->reference_pass_all_) {
aal::RelationsInNode &relations = this->get_anonymous_attribute_relations();
const int field_output = socket_builder->index_;
const int field_output = socket_builder->index_out_;
for (const int input_i : declaration_.inputs.index_range()) {
SocketDeclaration &input_socket_decl = *declaration_.inputs[input_i];
if (input_socket_decl.input_field_type != InputSocketFieldType::None) {
@ -92,12 +107,14 @@ void NodeDeclarationBuilder::finalize()
}
if (socket_builder->propagate_from_all_) {
aal::RelationsInNode &relations = this->get_anonymous_attribute_relations();
const int geometry_output = socket_builder->index_;
const int geometry_output = socket_builder->index_out_;
for (const int geometry_input : geometry_inputs) {
relations.propagate_relations.append({geometry_input, geometry_output});
}
}
}
BLI_assert(declaration_.is_valid());
}
void NodeDeclarationBuilder::set_active_panel_builder(const PanelDeclarationBuilder *panel_builder)
@ -190,13 +207,17 @@ bool NodeDeclaration::is_valid() const
return false;
}
if (state.socket_in_out == SOCK_OUT && socket_decl->in_out == SOCK_IN) {
/* Start of input sockets. */
state.socket_in_out = SOCK_IN;
}
if (socket_decl->in_out != state.socket_in_out) {
std::cout << "Output socket added after input socket" << std::endl;
return false;
/* Check for consistent outputs.., inputs.. blocks.
* Ignored for sockets that are inline pairs. */
if (!socket_decl->inline_with_next) {
if (state.socket_in_out == SOCK_OUT && socket_decl->in_out == SOCK_IN) {
/* Start of input sockets. */
state.socket_in_out = SOCK_IN;
}
if (socket_decl->in_out != state.socket_in_out) {
std::cout << "Output socket added after input socket" << std::endl;
return false;
}
}
/* Item counting for the panels, but ignore for root items. */

View File

@ -570,26 +570,46 @@ bool Geometry::only_instances() const
GeometryBuilder &GeometryBuilder::supported_type(bke::GeometryComponent::Type supported_type)
{
decl_->supported_types_ = {supported_type};
if (decl_in_) {
decl_in_->supported_types_ = {supported_type};
}
if (decl_out_) {
decl_out_->supported_types_ = {supported_type};
}
return *this;
}
GeometryBuilder &GeometryBuilder::supported_type(
blender::Vector<bke::GeometryComponent::Type> supported_types)
{
decl_->supported_types_ = std::move(supported_types);
if (decl_in_) {
decl_in_->supported_types_ = supported_types;
}
if (decl_out_) {
decl_out_->supported_types_ = supported_types;
}
return *this;
}
GeometryBuilder &GeometryBuilder::only_realized_data(bool value)
{
decl_->only_realized_data_ = value;
if (decl_in_) {
decl_in_->only_realized_data_ = value;
}
if (decl_out_) {
decl_out_->only_realized_data_ = value;
}
return *this;
}
GeometryBuilder &GeometryBuilder::only_instances(bool value)
{
decl_->only_instances_ = value;
if (decl_in_) {
decl_in_->only_instances_ = value;
}
if (decl_out_) {
decl_out_->only_instances_ = value;
}
return *this;
}