Nodes: Add PanelDeclarationBuilder for panels in builtin nodes #111695

Merged
Lukas Tönne merged 10 commits from LukasTonne/blender:panels-for-builtin-nodes into main 2023-09-11 13:39:34 +02:00
2 changed files with 198 additions and 2 deletions

View File

@ -513,17 +513,34 @@ class PanelDeclaration : public ItemDeclaration {
class PanelDeclarationBuilder {
protected:
using Self = PanelDeclarationBuilder;
NodeDeclarationBuilder *node_decl_builder_ = nullptr;
PanelDeclaration *decl_;
/**
LukasTonne marked this conversation as resolved Outdated

Proper doxygen syntax for multi-line class variable documentation (just for consistency)

/** 
 * Panel is complete once items are added after it.
 * Completed panels are locked and no more items can be added.
 */
Proper doxygen syntax for multi-line class variable documentation (just for consistency) ``` /** * Panel is complete once items are added after it. * Completed panels are locked and no more items can be added. */
* Panel is complete once items are added after it.
* Completed panels are locked and no more items can be added.
*/
bool is_complete_ = false;
friend class NodeDeclarationBuilder;
public:
PanelDeclarationBuilder &default_closed(bool collapsed)
Self &description(std::string value = "")
{
decl_->default_collapsed = collapsed;
decl_->description = std::move(value);
return *this;
}
Self &default_closed(bool closed)
{
decl_->default_collapsed = closed;
return *this;
}
template<typename DeclType>
typename DeclType::Builder &add_input(StringRef name, StringRef identifier = "");
template<typename DeclType>
typename DeclType::Builder &add_output(StringRef name, StringRef identifier = "");
};
using PanelDeclarationPtr = std::unique_ptr<PanelDeclaration>;
@ -549,6 +566,9 @@ class NodeDeclaration {
friend NodeDeclarationBuilder;
/** Returns true if the declaration is considered valid. */
bool is_valid() const;
bool matches(const bNode &node) const;
Span<SocketDeclaration *> sockets(eNodeSocketInOut in_out) const;
@ -565,8 +585,12 @@ class NodeDeclarationBuilder {
NodeDeclaration &declaration_;
Vector<std::unique_ptr<BaseSocketDeclarationBuilder>> input_builders_;
Vector<std::unique_ptr<BaseSocketDeclarationBuilder>> output_builders_;
Vector<std::unique_ptr<PanelDeclarationBuilder>> panel_builders_;
bool is_function_node_ = false;
private:
friend PanelDeclarationBuilder;
public:
NodeDeclarationBuilder(NodeDeclaration &declaration);
@ -581,10 +605,13 @@ class NodeDeclarationBuilder {
void finalize();
void use_custom_socket_order(bool enable = true);
template<typename DeclType>
typename DeclType::Builder &add_input(StringRef name, StringRef identifier = "");
template<typename DeclType>
typename DeclType::Builder &add_output(StringRef name, StringRef identifier = "");
PanelDeclarationBuilder &add_panel(StringRef name, int identifier = -1);
aal::RelationsInNode &get_anonymous_attribute_relations()
{
@ -599,6 +626,10 @@ class NodeDeclarationBuilder {
typename DeclType::Builder &add_socket(StringRef name,
StringRef identifier,
eNodeSocketInOut in_out);
/* Mark the most recent builder as 'complete' when changing builders
* so no more items can be added. */
void set_active_panel_builder(const PanelDeclarationBuilder *panel_builder);
};
namespace implicit_field_inputs {
@ -758,6 +789,38 @@ inline void SocketDeclaration::make_available(bNode &node) const
/** \} */
/* -------------------------------------------------------------------- */
/** \name #PanelDeclarationBuilder Inline Methods
* \{ */
template<typename DeclType>
typename DeclType::Builder &PanelDeclarationBuilder::add_input(StringRef name,
StringRef identifier)
{
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, SOCK_IN);
}
template<typename DeclType>
typename DeclType::Builder &PanelDeclarationBuilder::add_output(StringRef name,
StringRef identifier)
{
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, SOCK_OUT);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name #NodeDeclarationBuilder Inline Methods
* \{ */
@ -767,10 +830,16 @@ inline NodeDeclarationBuilder::NodeDeclarationBuilder(NodeDeclaration &declarati
{
}
inline void NodeDeclarationBuilder::use_custom_socket_order(bool enable)
{
declaration_.use_custom_socket_order = enable;
}
template<typename DeclType>
inline typename DeclType::Builder &NodeDeclarationBuilder::add_input(StringRef name,
StringRef identifier)
{
set_active_panel_builder(nullptr);
return this->add_socket<DeclType>(name, identifier, SOCK_IN);
}
@ -778,6 +847,7 @@ template<typename DeclType>
inline typename DeclType::Builder &NodeDeclarationBuilder::add_output(StringRef name,
StringRef identifier)
{
set_active_panel_builder(nullptr);
return this->add_socket<DeclType>(name, identifier, SOCK_OUT);
}
@ -802,9 +872,11 @@ inline typename DeclType::Builder &NodeDeclarationBuilder::add_socket(StringRef
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));
Builder &socket_decl_builder_ref = *socket_decl_builder;
((in_out == SOCK_IN) ? input_builders_ : output_builders_)
.append(std::move(socket_decl_builder));
LukasTonne marked this conversation as resolved Outdated

This doesn't have to be in the header.

This doesn't have to be in the header.
return socket_decl_builder_ref;
}

View File

@ -6,6 +6,7 @@
#include "NOD_socket_declarations.hh"
#include "NOD_socket_declarations_geometry.hh"
#include "BLI_stack.hh"
#include "BLI_utildefines.h"
#include "BKE_geometry_fields.hh"
@ -33,6 +34,8 @@ void build_node_declaration_dynamic(const bNodeTree &node_tree,
void NodeDeclarationBuilder::finalize()
{
BLI_assert(declaration_.is_valid());
if (is_function_node_) {
for (std::unique_ptr<BaseSocketDeclarationBuilder> &socket_builder : input_builders_) {
SocketDeclaration &socket_decl = *socket_builder->declaration();
@ -97,6 +100,20 @@ void NodeDeclarationBuilder::finalize()
}
}
void NodeDeclarationBuilder::set_active_panel_builder(const PanelDeclarationBuilder *panel_builder)
{
if (panel_builders_.is_empty()) {
BLI_assert(panel_builder == nullptr);
return;
}
BLI_assert(!panel_builder || !panel_builder->is_complete_);
PanelDeclarationBuilder *last_panel_builder = panel_builders_.last().get();
if (last_panel_builder != panel_builder) {
last_panel_builder->is_complete_ = true;
}
}
namespace anonymous_attribute_lifetime {
bool operator==(const RelationsInNode &a, const RelationsInNode &b)
@ -141,6 +158,88 @@ std::ostream &operator<<(std::ostream &stream, const RelationsInNode &relations)
} // namespace anonymous_attribute_lifetime
bool NodeDeclaration::is_valid() const
{
if (!this->use_custom_socket_order) {
/* Skip validation for conventional socket layouts. */
return true;
}
/* Validation state for the interface root items as well as any panel content. */
struct ValidationState {
/* Remaining number of items expected in a panel */
int remaining_items = 0;
/* Sockets first, followed by panels. */
NodeTreeInterfaceItemType item_type = NODE_INTERFACE_SOCKET;
/* Output sockets first, followed by input sockets. */
eNodeSocketInOut socket_in_out = SOCK_OUT;
};
Stack<ValidationState> panel_states;
panel_states.push({});
for (const ItemDeclarationPtr &item_decl : items) {
BLI_assert(panel_states.size() >= 1);
ValidationState &state = panel_states.peek();
if (const SocketDeclaration *socket_decl = dynamic_cast<const SocketDeclaration *>(
item_decl.get()))
{
if (state.item_type != NODE_INTERFACE_SOCKET) {
std::cout << "Socket added after panel" << std::endl;
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;
}
/* Item counting for the panels, but ignore for root items. */
if (panel_states.size() > 1) {
if (state.remaining_items <= 0) {
std::cout << "More sockets than expected in panel" << std::endl;
return false;
}
--state.remaining_items;
/* Panel closed after last item is added. */
if (state.remaining_items == 0) {
panel_states.pop();
}
}
}
else if (const PanelDeclaration *panel_decl = dynamic_cast<const PanelDeclaration *>(
item_decl.get()))
{
if (state.item_type == NODE_INTERFACE_SOCKET) {
/* Start of panels section */
state.item_type = NODE_INTERFACE_PANEL;
}
BLI_assert(state.item_type == NODE_INTERFACE_PANEL);
if (panel_decl->num_child_decls > 0) {
/* New panel started. */
panel_states.push({panel_decl->num_child_decls});
}
}
else {
BLI_assert_unreachable();
return false;
}
}
/* All panels complete? */
if (panel_states.size() != 1) {
std::cout << "Incomplete last panel" << std::endl;
return false;
}
return true;
}
bool NodeDeclaration::matches(const bNode &node) const
{
const bNodeSocket *current_input = static_cast<bNodeSocket *>(node.inputs.first);
@ -237,6 +336,31 @@ bool SocketDeclaration::matches_common_data(const bNodeSocket &socket) const
return true;
}
PanelDeclarationBuilder &NodeDeclarationBuilder::add_panel(StringRef name, int identifier)
{
std::unique_ptr<PanelDeclaration> panel_decl = std::make_unique<PanelDeclaration>();
std::unique_ptr<PanelDeclarationBuilder> panel_decl_builder =
std::make_unique<PanelDeclarationBuilder>();
panel_decl_builder->decl_ = &*panel_decl;
panel_decl_builder->node_decl_builder_ = this;
if (identifier >= 0) {
panel_decl->identifier = identifier;
}
else {
/* Use index as identifier. */
panel_decl->identifier = declaration_.items.size();
}
panel_decl->name = name;
declaration_.items.append(std::move(panel_decl));
PanelDeclarationBuilder &builder_ref = *panel_decl_builder;
panel_builders_.append(std::move(panel_decl_builder));
set_active_panel_builder(&builder_ref);
return builder_ref;
}
void PanelDeclaration::build(bNodePanelState &panel) const
{
panel = {0};