Geometry Nodes: improve socket shapes for bundle and closure nodes
Previously, the closure and bundle nodes were a bit restrictive when it comes to socket shapes. Especially the bundle nodes did not support customizing the socket shape at all, so they always worked with dynamic values. This was problematic, because it meant that e.g. the outputs of the Separate Bundle node looked like they couldn't be used as single values, and other similar issues. With this patch, the following is supported (a few aspects were supported before but now it all fits better together): * Support manually selecting socket shapes in Combine Bundle, Separate Bundle, Closure Input, Closure Output and Evaluate Closure nodes. * Automatic inferencing of shapes in all these nodes, as long as the socket shape is set to "auto". * A new "Define Signature" option can be enabled in the nodes. If enabled, linked nodes will also sync the socket shapes from that node. In the future, we also want to add support for naming the signature. Pull Request: https://projects.blender.org/blender/blender/pulls/145550
This commit is contained in:
@@ -173,12 +173,6 @@ class bNodeTreeRuntime : NonCopyable, NonMovable {
|
||||
std::unique_ptr<nodes::FieldInferencingInterface> field_inferencing_interface;
|
||||
/** Field status for every socket, accessed with #bNodeSocket::index_in_tree(). */
|
||||
Array<FieldSocketState> field_states;
|
||||
/**
|
||||
* Inferred structure type for every socket, accessed with #bNodeSocket::index_in_tree().
|
||||
* This is not necessarily the structure type that is displayed in the node editor. E.g. it may
|
||||
* be Single for an unconnected field input.
|
||||
*/
|
||||
Array<nodes::StructureType> inferred_structure_types;
|
||||
/** Information about usage of anonymous attributes within the group. */
|
||||
std::unique_ptr<node_tree_reference_lifetimes::ReferenceLifetimesInfo> reference_lifetimes_info;
|
||||
std::unique_ptr<nodes::gizmos::TreeGizmoPropagation> gizmo_propagation;
|
||||
@@ -293,6 +287,17 @@ class bNodeSocketRuntime : NonCopyable, NonMovable {
|
||||
*/
|
||||
short total_inputs = 0;
|
||||
|
||||
/**
|
||||
* Inferred structure type of the socket. This is not necessarily the same as the structure type
|
||||
* that is displayed in the UI. For example, it would be #StructureType::Single for an unlinked
|
||||
* input of the Math node, but the socket is displayed as #StructureType::Dynamic.
|
||||
*
|
||||
* This is stored on the socket instead of as array in #bNodeTreeRuntime because the data needs
|
||||
* to stay attached to the socket even when the node tree changes. This is used when e.g. syncing
|
||||
* a newly created Separate Bundle node to an existing Combine Bundle node.
|
||||
*/
|
||||
nodes::StructureType inferred_structure_type = nodes::StructureType::Dynamic;
|
||||
|
||||
/**
|
||||
* The location of the socket in the tree, calculated while drawing the nodes and invalid if the
|
||||
* node tree hasn't been drawn yet. In the node tree's "world space" (the same as
|
||||
@@ -1032,7 +1037,7 @@ inline bool bNodeSocket::is_icon_visible() const
|
||||
|
||||
inline bool bNodeSocket::may_be_field() const
|
||||
{
|
||||
return ELEM(this->owner_tree().runtime->inferred_structure_types[this->index_in_tree()],
|
||||
return ELEM(this->runtime->inferred_structure_type,
|
||||
blender::nodes::StructureType::Field,
|
||||
blender::nodes::StructureType::Dynamic);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BLI_array_utils.hh"
|
||||
#include "BLI_bit_span_ops.hh"
|
||||
#include "BLI_bit_vector.hh"
|
||||
#include "BLI_stack.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
@@ -129,19 +131,107 @@ static StructureType data_requirement_to_auto_structure_type(const DataRequireme
|
||||
return StructureType::Dynamic;
|
||||
}
|
||||
|
||||
static void find_auto_structure_type_sockets(const bNodeTree &tree,
|
||||
bits::MutableBoundedBitSpan is_auto_structure_type)
|
||||
{
|
||||
/* Handle group inputs. */
|
||||
for (const int i : tree.interface_inputs().index_range()) {
|
||||
const bNodeTreeInterfaceSocket &io_socket = *tree.interface_inputs()[i];
|
||||
if (io_socket.structure_type != NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO) {
|
||||
continue;
|
||||
}
|
||||
for (const bNode *node : tree.group_input_nodes()) {
|
||||
const bNodeSocket &socket = node->output_socket(i);
|
||||
is_auto_structure_type[socket.index_in_tree()].set();
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle group outputs. */
|
||||
if (const bNode *group_output_node = tree.group_output_node()) {
|
||||
is_auto_structure_type.slice(group_output_node->input_socket_indices_in_tree().drop_back(1))
|
||||
.set_all();
|
||||
}
|
||||
|
||||
/* Handle closure inputs and outputs. */
|
||||
const bke::bNodeZoneType *closure_zone_type = bke::zone_type_by_node_type(NODE_CLOSURE_OUTPUT);
|
||||
for (const bNode *closure_input_node : tree.nodes_by_type("NodeClosureInput")) {
|
||||
const auto *closure_output_node = closure_zone_type->get_corresponding_output(
|
||||
tree, *closure_input_node);
|
||||
if (!closure_output_node) {
|
||||
continue;
|
||||
}
|
||||
const auto &storage = *static_cast<const NodeClosureOutput *>(closure_output_node->storage);
|
||||
for (const int i : IndexRange(storage.input_items.items_num)) {
|
||||
const NodeClosureInputItem &item = storage.input_items.items[i];
|
||||
if (item.structure_type == NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO) {
|
||||
const bNodeSocket &socket = closure_input_node->output_socket(i);
|
||||
is_auto_structure_type[socket.index_in_tree()].set();
|
||||
}
|
||||
}
|
||||
for (const int i : IndexRange(storage.output_items.items_num)) {
|
||||
const NodeClosureOutputItem &item = storage.output_items.items[i];
|
||||
if (item.structure_type == NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO) {
|
||||
const bNodeSocket &socket = closure_output_node->input_socket(i);
|
||||
is_auto_structure_type[socket.index_in_tree()].set();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle Evaluate Closure nodes. */
|
||||
for (const bNode *evaluate_closure_node : tree.nodes_by_type("NodeEvaluateClosure")) {
|
||||
auto &storage = *static_cast<NodeEvaluateClosure *>(evaluate_closure_node->storage);
|
||||
for (const int i : IndexRange(storage.input_items.items_num)) {
|
||||
const NodeEvaluateClosureInputItem &item = storage.input_items.items[i];
|
||||
if (item.structure_type == NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO) {
|
||||
const bNodeSocket &socket = evaluate_closure_node->input_socket(i + 1);
|
||||
is_auto_structure_type[socket.index_in_tree()].set();
|
||||
}
|
||||
}
|
||||
for (const int i : IndexRange(storage.output_items.items_num)) {
|
||||
const NodeEvaluateClosureOutputItem &item = storage.output_items.items[i];
|
||||
if (item.structure_type == NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO) {
|
||||
const bNodeSocket &socket = evaluate_closure_node->output_socket(i);
|
||||
is_auto_structure_type[socket.index_in_tree()].set();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle Combine Bundle nodes. */
|
||||
for (const bNode *node : tree.nodes_by_type("NodeCombineBundle")) {
|
||||
auto &storage = *static_cast<NodeCombineBundle *>(node->storage);
|
||||
for (const int i : IndexRange(storage.items_num)) {
|
||||
const NodeCombineBundleItem &item = storage.items[i];
|
||||
if (item.structure_type == NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO) {
|
||||
const bNodeSocket &socket = node->input_socket(i);
|
||||
is_auto_structure_type[socket.index_in_tree()].set();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle Separate Bundle nodes. */
|
||||
for (const bNode *node : tree.nodes_by_type("NodeSeparateBundle")) {
|
||||
auto &storage = *static_cast<NodeSeparateBundle *>(node->storage);
|
||||
for (const int i : IndexRange(storage.items_num)) {
|
||||
const NodeSeparateBundleItem &item = storage.items[i];
|
||||
if (item.structure_type == NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO) {
|
||||
const bNodeSocket &socket = node->output_socket(i);
|
||||
is_auto_structure_type[socket.index_in_tree()].set();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void init_input_requirements(const bNodeTree &tree,
|
||||
const bits::BoundedBitSpan is_auto_structure_type,
|
||||
MutableSpan<DataRequirement> input_requirements)
|
||||
{
|
||||
for (const bNode *node : tree.all_nodes()) {
|
||||
if (ELEM(node->type_legacy, NODE_GROUP_OUTPUT, NODE_CLOSURE_OUTPUT)) {
|
||||
for (const bNodeSocket *socket : node->input_sockets()) {
|
||||
/* Inputs of these nodes have no requirements. */
|
||||
input_requirements[socket->index_in_all_inputs()] = DataRequirement::None;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
for (const bNodeSocket *socket : node->input_sockets()) {
|
||||
DataRequirement &requirement = input_requirements[socket->index_in_all_inputs()];
|
||||
if (is_auto_structure_type[socket->index_in_tree()]) {
|
||||
requirement = DataRequirement::None;
|
||||
continue;
|
||||
}
|
||||
const nodes::SocketDeclaration *declaration = socket->runtime->declaration;
|
||||
if (!declaration) {
|
||||
requirement = DataRequirement::None;
|
||||
@@ -222,37 +312,27 @@ static void store_group_input_structure_types(const bNodeTree &tree,
|
||||
}
|
||||
}
|
||||
|
||||
static void store_closure_input_structure_types(const bNodeTree &tree,
|
||||
const Span<DataRequirement> input_requirements,
|
||||
MutableSpan<StructureType> structure_types)
|
||||
static void store_auto_output_structure_types(const bNodeTree &tree,
|
||||
const Span<DataRequirement> input_requirements,
|
||||
const bits::BoundedBitSpan is_auto_structure_type,
|
||||
MutableSpan<StructureType> structure_types)
|
||||
{
|
||||
const bNodeTreeZones *zones = tree.zones();
|
||||
if (!zones) {
|
||||
return;
|
||||
}
|
||||
for (const bNodeTreeZone *zone : zones->zones) {
|
||||
const bNode *input_node = zone->input_node();
|
||||
const bNode *output_node = zone->output_node();
|
||||
if (!input_node || !output_node) {
|
||||
continue;
|
||||
const Span<const bNodeSocket *> all_sockets = tree.all_sockets();
|
||||
bits::foreach_1_index(is_auto_structure_type, [&](const int i) {
|
||||
const bNodeSocket &socket = *all_sockets[i];
|
||||
if (socket.is_input()) {
|
||||
return;
|
||||
}
|
||||
if (!output_node->is_type("NodeClosureOutput")) {
|
||||
continue;
|
||||
const bNode &node = socket.owner_node();
|
||||
if (node.is_group_input()) {
|
||||
/* Group input nodes have special handling in #store_group_input_structure_types because
|
||||
* corresponding sockets on all group input nodes should have the same structure type. */
|
||||
return;
|
||||
}
|
||||
const auto *storage = static_cast<const NodeClosureOutput *>(output_node->storage);
|
||||
for (const int i : IndexRange(storage->input_items.items_num)) {
|
||||
const NodeClosureInputItem &item = storage->input_items.items[i];
|
||||
const bNodeSocket &socket = input_node->output_socket(i);
|
||||
StructureType &structure_type = structure_types[socket.index_in_tree()];
|
||||
if (item.structure_type != NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO) {
|
||||
structure_type = StructureType(item.structure_type);
|
||||
continue;
|
||||
}
|
||||
const DataRequirement requirement = calc_output_socket_requirement(socket,
|
||||
input_requirements);
|
||||
structure_type = data_requirement_to_auto_structure_type(requirement);
|
||||
}
|
||||
}
|
||||
|
||||
const DataRequirement requirement = calc_output_socket_requirement(socket, input_requirements);
|
||||
structure_types[socket.index_in_tree()] = data_requirement_to_auto_structure_type(requirement);
|
||||
});
|
||||
}
|
||||
|
||||
enum class ZoneInOutChange {
|
||||
@@ -601,6 +681,7 @@ static StructureType get_unconnected_input_structure_type(
|
||||
static void propagate_left_to_right(const bNodeTree &tree,
|
||||
const Span<nodes::StructureTypeInterface> node_interfaces,
|
||||
const Span<StructureType> group_input_structure_types,
|
||||
const bits::BoundedBitSpan is_auto_structure_type,
|
||||
MutableSpan<StructureType> structure_types)
|
||||
{
|
||||
for (const bNodeSocket *input : tree.all_input_sockets()) {
|
||||
@@ -638,10 +719,6 @@ static void propagate_left_to_right(const bNodeTree &tree,
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->type_legacy == NODE_CLOSURE_INPUT) {
|
||||
/* Initialized in #store_closure_input_structure_types already. */
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const bNodeSocket *input : input_sockets) {
|
||||
if (!input->is_available()) {
|
||||
@@ -673,6 +750,10 @@ static void propagate_left_to_right(const bNodeTree &tree,
|
||||
if (!output.is_available() || !output.runtime->declaration) {
|
||||
continue;
|
||||
}
|
||||
if (is_auto_structure_type[output.index_in_tree()]) {
|
||||
/* Has been initialized in #store_auto_output_structure_types. */
|
||||
continue;
|
||||
}
|
||||
const nodes::SocketDeclaration &declaration = *output.runtime->declaration;
|
||||
|
||||
std::optional<StructureType> output_type;
|
||||
@@ -798,15 +879,21 @@ static StructureTypeInferenceResult calc_structure_type_interface(const bNodeTre
|
||||
}
|
||||
|
||||
Array<nodes::StructureTypeInterface> node_interfaces = calc_node_interfaces(tree);
|
||||
bits::BitVector<> is_auto_structure_type(tree.all_sockets().size(), false);
|
||||
|
||||
Array<DataRequirement> data_requirements(tree.all_input_sockets().size());
|
||||
|
||||
init_input_requirements(tree, data_requirements);
|
||||
find_auto_structure_type_sockets(tree, is_auto_structure_type);
|
||||
init_input_requirements(tree, is_auto_structure_type, data_requirements);
|
||||
propagate_right_to_left(tree, node_interfaces, data_requirements);
|
||||
store_group_input_structure_types(tree, data_requirements, result.group_interface);
|
||||
store_closure_input_structure_types(tree, data_requirements, result.socket_structure_types);
|
||||
propagate_left_to_right(
|
||||
tree, node_interfaces, result.group_interface.inputs, result.socket_structure_types);
|
||||
store_auto_output_structure_types(
|
||||
tree, data_requirements, is_auto_structure_type, result.socket_structure_types);
|
||||
propagate_left_to_right(tree,
|
||||
node_interfaces,
|
||||
result.group_interface.inputs,
|
||||
is_auto_structure_type,
|
||||
result.socket_structure_types);
|
||||
store_group_output_structure_types(
|
||||
tree, node_interfaces, result.socket_structure_types, result.group_interface);
|
||||
|
||||
@@ -824,7 +911,10 @@ static StructureTypeInferenceResult calc_structure_type_interface(const bNodeTre
|
||||
bool update_structure_type_interface(bNodeTree &tree)
|
||||
{
|
||||
StructureTypeInferenceResult result = calc_structure_type_interface(tree);
|
||||
tree.runtime->inferred_structure_types = std::move(result.socket_structure_types);
|
||||
for (const int i : tree.all_sockets().index_range()) {
|
||||
const bNodeSocket &socket = *tree.all_sockets()[i];
|
||||
socket.runtime->inferred_structure_type = result.socket_structure_types[i];
|
||||
}
|
||||
if (tree.runtime->structure_type_interface &&
|
||||
*tree.runtime->structure_type_interface == result.group_interface)
|
||||
{
|
||||
|
||||
@@ -931,16 +931,23 @@ class NodeTreeMainUpdater {
|
||||
}
|
||||
}
|
||||
|
||||
static int get_input_socket_shape(const SocketDeclaration &decl,
|
||||
const StructureType structure_type)
|
||||
static int get_socket_shape(const bNodeSocket &socket,
|
||||
const bool use_inferred_structure_type = false)
|
||||
{
|
||||
if (decl.identifier == "__extend__") {
|
||||
return SOCK_DISPLAY_SHAPE_CIRCLE;
|
||||
}
|
||||
if (nodes::socket_type_always_single(decl.socket_type)) {
|
||||
if (nodes::socket_type_always_single(socket.typeinfo->type)) {
|
||||
return SOCK_DISPLAY_SHAPE_LINE;
|
||||
}
|
||||
switch (structure_type) {
|
||||
const SocketDeclaration *decl = socket.runtime->declaration;
|
||||
if (!decl) {
|
||||
return SOCK_DISPLAY_SHAPE_CIRCLE;
|
||||
}
|
||||
if (decl->identifier == "__extend__") {
|
||||
return SOCK_DISPLAY_SHAPE_CIRCLE;
|
||||
}
|
||||
const StructureType display_structure_type = use_inferred_structure_type ?
|
||||
socket.runtime->inferred_structure_type :
|
||||
decl->structure_type;
|
||||
switch (display_structure_type) {
|
||||
case StructureType::Single:
|
||||
return SOCK_DISPLAY_SHAPE_LINE;
|
||||
case StructureType::Dynamic:
|
||||
@@ -956,36 +963,6 @@ class NodeTreeMainUpdater {
|
||||
return SOCK_DISPLAY_SHAPE_CIRCLE;
|
||||
}
|
||||
|
||||
static int get_output_socket_shape(const SocketDeclaration &decl,
|
||||
const StructureType structure_type)
|
||||
{
|
||||
if (decl.identifier == "__extend__") {
|
||||
return SOCK_DISPLAY_SHAPE_CIRCLE;
|
||||
}
|
||||
if (nodes::socket_type_always_single(decl.socket_type)) {
|
||||
return SOCK_DISPLAY_SHAPE_LINE;
|
||||
}
|
||||
switch (structure_type) {
|
||||
case StructureType::Single: {
|
||||
return SOCK_DISPLAY_SHAPE_LINE;
|
||||
}
|
||||
case StructureType::Dynamic: {
|
||||
return SOCK_DISPLAY_SHAPE_CIRCLE;
|
||||
}
|
||||
case StructureType::Field: {
|
||||
return SOCK_DISPLAY_SHAPE_DIAMOND;
|
||||
}
|
||||
case StructureType::Grid: {
|
||||
return SOCK_DISPLAY_SHAPE_VOLUME_GRID;
|
||||
}
|
||||
case StructureType::List: {
|
||||
return SOCK_DISPLAY_SHAPE_LIST;
|
||||
}
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
return SOCK_DISPLAY_SHAPE_CIRCLE;
|
||||
}
|
||||
|
||||
void update_socket_shapes(bNodeTree &ntree)
|
||||
{
|
||||
ntree.ensure_topology_cache();
|
||||
@@ -993,33 +970,89 @@ class NodeTreeMainUpdater {
|
||||
if (node->is_undefined()) {
|
||||
continue;
|
||||
}
|
||||
/* For input/output nodes we use the inferred structure types. */
|
||||
if (node->is_group_input() || node->is_group_output() ||
|
||||
ELEM(node->type_legacy, NODE_CLOSURE_INPUT, NODE_CLOSURE_OUTPUT))
|
||||
{
|
||||
for (bNodeSocket *socket : node->input_sockets()) {
|
||||
socket->display_shape = get_input_socket_shape(
|
||||
*socket->runtime->declaration,
|
||||
ntree.runtime->inferred_structure_types[socket->index_in_tree()]);
|
||||
const bke::bNodeZoneType *closure_zone_type = bke::zone_type_by_node_type(
|
||||
NODE_CLOSURE_OUTPUT);
|
||||
switch (node->type_legacy) {
|
||||
case NODE_GROUP_OUTPUT:
|
||||
case NODE_GROUP_INPUT: {
|
||||
for (bNodeSocket *socket : node->input_sockets()) {
|
||||
socket->display_shape = get_socket_shape(*socket, true);
|
||||
}
|
||||
for (bNodeSocket *socket : node->output_sockets()) {
|
||||
socket->display_shape = get_socket_shape(*socket, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (bNodeSocket *socket : node->output_sockets()) {
|
||||
socket->display_shape = get_output_socket_shape(
|
||||
*socket->runtime->declaration,
|
||||
ntree.runtime->inferred_structure_types[socket->index_in_tree()]);
|
||||
case NODE_COMBINE_BUNDLE: {
|
||||
const auto &storage = *static_cast<const NodeCombineBundle *>(node->storage);
|
||||
for (const int i : IndexRange(storage.items_num)) {
|
||||
const NodeCombineBundleItem &item = storage.items[i];
|
||||
bNodeSocket &socket = node->input_socket(i);
|
||||
socket.display_shape = get_socket_shape(
|
||||
socket, item.structure_type == NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO);
|
||||
}
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* For other nodes we just use the static structure types defined in the declaration. */
|
||||
for (bNodeSocket *socket : node->input_sockets()) {
|
||||
if (const SocketDeclaration *declaration = socket->runtime->declaration) {
|
||||
socket->display_shape = get_input_socket_shape(*declaration,
|
||||
declaration->structure_type);
|
||||
case NODE_SEPARATE_BUNDLE: {
|
||||
const auto &storage = *static_cast<const NodeSeparateBundle *>(node->storage);
|
||||
for (const int i : IndexRange(storage.items_num)) {
|
||||
const NodeSeparateBundleItem &item = storage.items[i];
|
||||
bNodeSocket &socket = node->output_socket(i);
|
||||
socket.display_shape = get_socket_shape(
|
||||
socket, item.structure_type == NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (bNodeSocket *socket : node->output_sockets()) {
|
||||
if (const SocketDeclaration *declaration = socket->runtime->declaration) {
|
||||
socket->display_shape = get_output_socket_shape(*declaration,
|
||||
declaration->structure_type);
|
||||
case NODE_CLOSURE_INPUT: {
|
||||
if (const bNode *closure_output_node = closure_zone_type->get_corresponding_output(
|
||||
ntree, *node))
|
||||
{
|
||||
const auto &storage = *static_cast<const NodeClosureOutput *>(
|
||||
closure_output_node->storage);
|
||||
for (const int i : IndexRange(storage.input_items.items_num)) {
|
||||
const NodeClosureInputItem &item = storage.input_items.items[i];
|
||||
bNodeSocket &socket = node->output_socket(i);
|
||||
socket.display_shape = get_socket_shape(
|
||||
socket, item.structure_type == NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_CLOSURE_OUTPUT: {
|
||||
const auto &storage = *static_cast<const NodeClosureOutput *>(node->storage);
|
||||
for (const int i : IndexRange(storage.output_items.items_num)) {
|
||||
const NodeClosureOutputItem &item = storage.output_items.items[i];
|
||||
bNodeSocket &socket = node->input_socket(i);
|
||||
socket.display_shape = get_socket_shape(
|
||||
socket, item.structure_type == NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_EVALUATE_CLOSURE: {
|
||||
const auto &storage = *static_cast<const NodeEvaluateClosure *>(node->storage);
|
||||
for (const int i : IndexRange(storage.input_items.items_num)) {
|
||||
const NodeEvaluateClosureInputItem &item = storage.input_items.items[i];
|
||||
bNodeSocket &socket = node->input_socket(i + 1);
|
||||
socket.display_shape = get_socket_shape(
|
||||
socket, item.structure_type == NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO);
|
||||
}
|
||||
for (const int i : IndexRange(storage.output_items.items_num)) {
|
||||
const NodeEvaluateClosureOutputItem &item = storage.output_items.items[i];
|
||||
bNodeSocket &socket = node->output_socket(i);
|
||||
socket.display_shape = get_socket_shape(
|
||||
socket, item.structure_type == NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
/* For other nodes we just use the static structure types defined in the declaration. */
|
||||
for (bNodeSocket *socket : node->input_sockets()) {
|
||||
socket->display_shape = get_socket_shape(*socket);
|
||||
}
|
||||
for (bNodeSocket *socket : node->output_sockets()) {
|
||||
socket->display_shape = get_socket_shape(*socket);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1373,14 +1406,6 @@ class NodeTreeMainUpdater {
|
||||
NodeLinkError{TIP_("Use node groups to reuse the same menu multiple times")});
|
||||
continue;
|
||||
}
|
||||
if (ntree.type == NTREE_GEOMETRY) {
|
||||
if (this->is_invalid_field_link(*link)) {
|
||||
link->flag &= ~NODE_LINK_VALID;
|
||||
ntree.runtime->link_errors.add(
|
||||
NodeLinkKey{*link}, NodeLinkError{TIP_("The node input does not support fields")});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const bNode &from_node = *link->fromnode;
|
||||
const bNode &to_node = *link->tonode;
|
||||
if (from_node.runtime->toposort_left_to_right_index >
|
||||
@@ -1421,25 +1446,67 @@ class NodeTreeMainUpdater {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (const char *error = this->get_structure_type_link_error(*link)) {
|
||||
link->flag &= ~NODE_LINK_VALID;
|
||||
ntree.runtime->link_errors.add(NodeLinkKey{*link}, NodeLinkError{error});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool is_invalid_field_link(const bNodeLink &link)
|
||||
const char *get_structure_type_link_error(const bNodeLink &link)
|
||||
{
|
||||
if (!link.fromsock->may_be_field()) {
|
||||
return false;
|
||||
const nodes::StructureType from_inferred_type =
|
||||
link.fromsock->runtime->inferred_structure_type;
|
||||
if (from_inferred_type == StructureType::Dynamic) {
|
||||
/* Showing errors in this case results in many false positives in cases where Blender is not
|
||||
* sure what the actual type is. */
|
||||
return nullptr;
|
||||
}
|
||||
const nodes::SocketDeclaration *to_socket_decl = link.tosock->runtime->declaration;
|
||||
if (!to_socket_decl) {
|
||||
return false;
|
||||
const int from_shape = link.fromsock->display_shape;
|
||||
const int to_shape = link.tosock->display_shape;
|
||||
switch (to_shape) {
|
||||
case SOCK_DISPLAY_SHAPE_CIRCLE: {
|
||||
return nullptr;
|
||||
}
|
||||
case SOCK_DISPLAY_SHAPE_LINE: {
|
||||
if (from_shape == SOCK_DISPLAY_SHAPE_LINE) {
|
||||
return nullptr;
|
||||
}
|
||||
if (from_inferred_type == StructureType::Single) {
|
||||
return nullptr;
|
||||
}
|
||||
return TIP_("Input expects a single value");
|
||||
}
|
||||
case SOCK_DISPLAY_SHAPE_DIAMOND: {
|
||||
if (ELEM(from_shape, SOCK_DISPLAY_SHAPE_LINE, SOCK_DISPLAY_SHAPE_DIAMOND)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (ELEM(from_inferred_type, StructureType::Single, StructureType::Field)) {
|
||||
return nullptr;
|
||||
}
|
||||
return TIP_("Input expects a field or single value");
|
||||
}
|
||||
case SOCK_DISPLAY_SHAPE_VOLUME_GRID: {
|
||||
if (from_shape == SOCK_DISPLAY_SHAPE_VOLUME_GRID) {
|
||||
return nullptr;
|
||||
}
|
||||
if (from_inferred_type == StructureType::Grid) {
|
||||
return nullptr;
|
||||
}
|
||||
return TIP_("Input expects a volume grid");
|
||||
}
|
||||
case SOCK_DISPLAY_SHAPE_LIST: {
|
||||
if (from_shape == SOCK_DISPLAY_SHAPE_LIST) {
|
||||
return nullptr;
|
||||
}
|
||||
if (from_inferred_type == StructureType::List) {
|
||||
return nullptr;
|
||||
}
|
||||
return TIP_("Input expects a list");
|
||||
}
|
||||
}
|
||||
if (ELEM(to_socket_decl->structure_type, StructureType::Dynamic, StructureType::Field)) {
|
||||
return false;
|
||||
}
|
||||
if (link.tonode->is_group_output() || link.tonode->is_type("NodeClosureOutput")) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool check_if_output_changed(const bNodeTree &tree)
|
||||
|
||||
@@ -1134,6 +1134,12 @@ static void std_node_socket_draw(
|
||||
draw_node_socket_without_value(layout, sock, text);
|
||||
return;
|
||||
}
|
||||
if (tree->type == NTREE_GEOMETRY &&
|
||||
ELEM(sock->display_shape, SOCK_DISPLAY_SHAPE_LIST, SOCK_DISPLAY_SHAPE_VOLUME_GRID))
|
||||
{
|
||||
draw_node_socket_without_value(layout, sock, text);
|
||||
return;
|
||||
}
|
||||
|
||||
const StringRefNull label = text;
|
||||
text = (sock->flag & SOCK_HIDE_LABEL) ? "" : text;
|
||||
|
||||
@@ -2307,7 +2307,9 @@ typedef struct NodeClosureOutputItem {
|
||||
char *name;
|
||||
/** #eNodeSocketDatatype. */
|
||||
short socket_type;
|
||||
char _pad[2];
|
||||
/** #NodeSocketInterfaceStructureType. */
|
||||
int8_t structure_type;
|
||||
char _pad[1];
|
||||
int identifier;
|
||||
} NodeClosureOutputItem;
|
||||
|
||||
@@ -2327,9 +2329,16 @@ typedef struct NodeClosureOutputItems {
|
||||
char _pad[4];
|
||||
} NodeClosureOutputItems;
|
||||
|
||||
typedef enum NodeClosureFlag {
|
||||
NODE_CLOSURE_FLAG_DEFINE_SIGNATURE = (1 << 0),
|
||||
} NodeClosureFlag;
|
||||
|
||||
typedef struct NodeClosureOutput {
|
||||
NodeClosureInputItems input_items;
|
||||
NodeClosureOutputItems output_items;
|
||||
/** #NodeClosureFlag. */
|
||||
uint8_t flag;
|
||||
char _pad[7];
|
||||
} NodeClosureOutput;
|
||||
|
||||
typedef struct NodeEvaluateClosureInputItem {
|
||||
@@ -2352,6 +2361,10 @@ typedef struct NodeEvaluateClosureOutputItem {
|
||||
int identifier;
|
||||
} NodeEvaluateClosureOutputItem;
|
||||
|
||||
typedef enum NodeEvaluateClosureFlag {
|
||||
NODE_EVALUATE_CLOSURE_FLAG_DEFINE_SIGNATURE = (1 << 0),
|
||||
} NodeEvaluateClosureFlag;
|
||||
|
||||
typedef struct NodeEvaluateClosureInputItems {
|
||||
NodeEvaluateClosureInputItem *items;
|
||||
int items_num;
|
||||
@@ -2371,6 +2384,9 @@ typedef struct NodeEvaluateClosureOutputItems {
|
||||
typedef struct NodeEvaluateClosure {
|
||||
NodeEvaluateClosureInputItems input_items;
|
||||
NodeEvaluateClosureOutputItems output_items;
|
||||
/** #NodeEvaluateClosureFlag. */
|
||||
uint8_t flag;
|
||||
char _pad[7];
|
||||
} NodeEvaluateClosure;
|
||||
|
||||
typedef struct IndexSwitchItem {
|
||||
@@ -2491,30 +2507,46 @@ typedef struct NodeCombineBundleItem {
|
||||
char *name;
|
||||
int identifier;
|
||||
int16_t socket_type;
|
||||
char _pad[2];
|
||||
/** #NodeSocketInterfaceStructureType. */
|
||||
int8_t structure_type;
|
||||
char _pad[1];
|
||||
} NodeCombineBundleItem;
|
||||
|
||||
typedef enum NodeCombineBundleFlag {
|
||||
NODE_COMBINE_BUNDLE_FLAG_DEFINE_SIGNATURE = (1 << 0),
|
||||
} NodeCombineBundleFlag;
|
||||
|
||||
typedef struct NodeCombineBundle {
|
||||
NodeCombineBundleItem *items;
|
||||
int items_num;
|
||||
int next_identifier;
|
||||
int active_index;
|
||||
char _pad[4];
|
||||
/** #NodeCombineBundleFlag. */
|
||||
uint8_t flag;
|
||||
char _pad[3];
|
||||
} NodeCombineBundle;
|
||||
|
||||
typedef struct NodeSeparateBundleItem {
|
||||
char *name;
|
||||
int identifier;
|
||||
int16_t socket_type;
|
||||
char _pad[2];
|
||||
/** #NodeSocketInterfaceStructureType. */
|
||||
int8_t structure_type;
|
||||
char _pad[1];
|
||||
} NodeSeparateBundleItem;
|
||||
|
||||
typedef enum NodeSeparateBundleFlag {
|
||||
NODE_SEPARATE_BUNDLE_FLAG_DEFINE_SIGNATURE = (1 << 0),
|
||||
} NodeSeparateBundleFlag;
|
||||
|
||||
typedef struct NodeSeparateBundle {
|
||||
NodeSeparateBundleItem *items;
|
||||
int items_num;
|
||||
int next_identifier;
|
||||
int active_index;
|
||||
char _pad[4];
|
||||
/** #NodeSeparateBundleFlag. */
|
||||
uint8_t flag;
|
||||
char _pad[3];
|
||||
} NodeSeparateBundle;
|
||||
|
||||
typedef struct NodeFunctionFormatStringItem {
|
||||
|
||||
@@ -279,15 +279,8 @@ static void rna_NodeSocket_type_set(PointerRNA *ptr, int value)
|
||||
|
||||
static int rna_NodeSocket_inferred_structure_type_get(PointerRNA *ptr)
|
||||
{
|
||||
bNodeTree *tree = reinterpret_cast<bNodeTree *>(ptr->owner_id);
|
||||
bNodeSocket *socket = ptr->data_as<bNodeSocket>();
|
||||
tree->ensure_topology_cache();
|
||||
if (tree->runtime->inferred_structure_types.size() != tree->all_sockets().size()) {
|
||||
/* This cache is outdated or not available on this tree type. */
|
||||
return int(blender::nodes::StructureType::Dynamic);
|
||||
}
|
||||
const int index = socket->index_in_tree();
|
||||
return int(tree->runtime->inferred_structure_types[index]);
|
||||
return int(socket->runtime->inferred_structure_type);
|
||||
}
|
||||
|
||||
static void rna_NodeSocket_bl_idname_get(PointerRNA *ptr, char *value)
|
||||
|
||||
@@ -97,6 +97,7 @@ static const EnumPropertyItem node_default_input_items[] = {
|
||||
# include "BLT_translation.hh"
|
||||
|
||||
# include "NOD_node_declaration.hh"
|
||||
# include "NOD_rna_define.hh"
|
||||
# include "NOD_socket.hh"
|
||||
|
||||
# include "DNA_material_types.h"
|
||||
@@ -477,19 +478,14 @@ static void rna_NodeTreeInterfaceSocket_force_non_field_set(PointerRNA *ptr, con
|
||||
NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO;
|
||||
}
|
||||
|
||||
static const EnumPropertyItem *rna_NodeTreeInterfaceSocket_structure_type_itemf(
|
||||
bContext * /*C*/, PointerRNA *ptr, PropertyRNA * /*prop*/, bool *r_free)
|
||||
const EnumPropertyItem *rna_NodeSocket_structure_type_item_filter(
|
||||
const bNodeTree *ntree, const eNodeSocketDatatype socket_type, bool *r_free)
|
||||
{
|
||||
const bNodeTree *ntree = reinterpret_cast<const bNodeTree *>(ptr->owner_id);
|
||||
const bNodeTreeInterfaceSocket *socket = static_cast<const bNodeTreeInterfaceSocket *>(
|
||||
ptr->data);
|
||||
if (!ntree) {
|
||||
return rna_enum_dummy_NULL_items;
|
||||
}
|
||||
|
||||
const bool is_geometry_nodes = ntree->type == NTREE_GEOMETRY;
|
||||
|
||||
const eNodeSocketDatatype socket_type = socket->socket_typeinfo()->type;
|
||||
const bool supports_fields = is_geometry_nodes &&
|
||||
blender::nodes::socket_type_supports_fields(socket_type);
|
||||
const bool supports_grids = is_geometry_nodes &&
|
||||
@@ -541,6 +537,16 @@ static const EnumPropertyItem *rna_NodeTreeInterfaceSocket_structure_type_itemf(
|
||||
return items;
|
||||
}
|
||||
|
||||
static const EnumPropertyItem *rna_NodeTreeInterfaceSocket_structure_type_itemf(
|
||||
bContext * /*C*/, PointerRNA *ptr, PropertyRNA * /*prop*/, bool *r_free)
|
||||
{
|
||||
const bNodeTree *ntree = reinterpret_cast<const bNodeTree *>(ptr->owner_id);
|
||||
const bNodeTreeInterfaceSocket *socket = static_cast<const bNodeTreeInterfaceSocket *>(
|
||||
ptr->data);
|
||||
const eNodeSocketDatatype socket_type = socket->socket_typeinfo()->type;
|
||||
return rna_NodeSocket_structure_type_item_filter(ntree, socket_type, r_free);
|
||||
}
|
||||
|
||||
static const EnumPropertyItem *rna_NodeTreeInterfaceSocket_default_input_itemf(
|
||||
bContext * /*C*/, PointerRNA *ptr, PropertyRNA * /*prop*/, bool *r_free)
|
||||
{
|
||||
|
||||
@@ -659,6 +659,7 @@ static const EnumPropertyItem node_cryptomatte_layer_name_items[] = {
|
||||
# include "NOD_geo_viewer.hh"
|
||||
# include "NOD_geometry.hh"
|
||||
# include "NOD_geometry_nodes_lazy_function.hh"
|
||||
# include "NOD_rna_define.hh"
|
||||
# include "NOD_shader.h"
|
||||
# include "NOD_socket.hh"
|
||||
# include "NOD_socket_items.hh"
|
||||
@@ -2353,26 +2354,6 @@ static const EnumPropertyItem *rna_GeometryNodeAttributeDomain_attribute_domain_
|
||||
return item_array;
|
||||
}
|
||||
|
||||
static const EnumPropertyItem *rna_structure_type_no_auto_itemf(bContext * /*C*/,
|
||||
PointerRNA * /*ptr*/,
|
||||
PropertyRNA * /*prop*/,
|
||||
bool *r_free)
|
||||
{
|
||||
EnumPropertyItem *items = nullptr;
|
||||
int items_len = 0;
|
||||
for (const EnumPropertyItem *item = rna_enum_node_socket_structure_type_items; item->identifier;
|
||||
item++)
|
||||
{
|
||||
if (item->value != NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO) {
|
||||
RNA_enum_item_add(&items, &items_len, item);
|
||||
}
|
||||
}
|
||||
RNA_enum_item_end(&items, &items_len);
|
||||
|
||||
*r_free = true;
|
||||
return items;
|
||||
}
|
||||
|
||||
static StructRNA *rna_ShaderNode_register(Main *bmain,
|
||||
ReportList *reports,
|
||||
void *data,
|
||||
@@ -3837,6 +3818,20 @@ typename Accessor::ItemT *rna_Node_ItemArray_new_with_socket_and_name(
|
||||
return new_item;
|
||||
}
|
||||
|
||||
template<typename Accessor>
|
||||
static const EnumPropertyItem *rna_Node_ItemArray_structure_type_itemf(bContext * /*C*/,
|
||||
PointerRNA *ptr,
|
||||
PropertyRNA * /*prop*/,
|
||||
bool *r_free)
|
||||
{
|
||||
using ItemT = typename Accessor::ItemT;
|
||||
|
||||
const bNodeTree *ntree = reinterpret_cast<const bNodeTree *>(ptr->owner_id);
|
||||
const ItemT &item = *static_cast<const ItemT *>(ptr->data);
|
||||
const eNodeSocketDatatype socket_type = Accessor::get_socket_type(item);
|
||||
return rna_NodeSocket_structure_type_item_filter(ntree, socket_type, r_free);
|
||||
}
|
||||
|
||||
static IndexSwitchItem *rna_NodeIndexSwitchItems_new(ID *id, bNode *node, Main *bmain)
|
||||
{
|
||||
IndexSwitchItem *new_item = blender::nodes::socket_items::add_item<IndexSwitchItemsAccessor>(
|
||||
@@ -7530,6 +7525,11 @@ static void rna_def_closure_input_item(BlenderRNA *brna)
|
||||
|
||||
prop = RNA_def_property(srna, "structure_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, rna_enum_node_socket_structure_type_items);
|
||||
RNA_def_property_enum_funcs(
|
||||
prop,
|
||||
nullptr,
|
||||
nullptr,
|
||||
"rna_Node_ItemArray_structure_type_itemf<ClosureInputItemsAccessor>");
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Structure Type",
|
||||
@@ -7552,11 +7552,27 @@ static void rna_def_closure_input_items(BlenderRNA *brna)
|
||||
|
||||
static void rna_def_closure_output_item(BlenderRNA *brna)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
StructRNA *srna = RNA_def_struct(brna, "NodeClosureOutputItem", nullptr);
|
||||
RNA_def_struct_ui_text(srna, "Closure Output Item", "");
|
||||
RNA_def_struct_sdna(srna, "NodeClosureOutputItem");
|
||||
|
||||
rna_def_node_item_array_socket_item_common(srna, "ClosureOutputItemsAccessor", true);
|
||||
|
||||
prop = RNA_def_property(srna, "structure_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, rna_enum_node_socket_structure_type_items);
|
||||
RNA_def_property_enum_funcs(
|
||||
prop,
|
||||
nullptr,
|
||||
nullptr,
|
||||
"rna_Node_ItemArray_structure_type_itemf<ClosureOutputItemsAccessor>");
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Structure Type",
|
||||
"What kind of higher order types are expected to flow through this socket");
|
||||
RNA_def_property_update(
|
||||
prop, NC_NODE | NA_EDITED, "rna_Node_ItemArray_item_update<ClosureOutputItemsAccessor>");
|
||||
}
|
||||
|
||||
static void rna_def_closure_output_items(BlenderRNA *brna)
|
||||
@@ -7606,6 +7622,16 @@ static void def_closure_output(BlenderRNA *brna, StructRNA *srna)
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE);
|
||||
RNA_def_property_update(prop, NC_NODE, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "define_signature", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", NODE_CLOSURE_FLAG_DEFINE_SIGNATURE);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Define Signature",
|
||||
"This zone defines a closure signature that should be used by other nodes");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE);
|
||||
RNA_def_property_update(prop, NC_NODE, "rna_Node_update");
|
||||
}
|
||||
|
||||
static void rna_def_geo_capture_attribute_item(BlenderRNA *brna)
|
||||
@@ -7690,7 +7716,11 @@ static void rna_def_evaluate_closure_input_item(BlenderRNA *brna)
|
||||
|
||||
prop = RNA_def_property(srna, "structure_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, rna_enum_node_socket_structure_type_items);
|
||||
RNA_def_property_enum_funcs(prop, nullptr, nullptr, "rna_structure_type_no_auto_itemf");
|
||||
RNA_def_property_enum_funcs(
|
||||
prop,
|
||||
nullptr,
|
||||
nullptr,
|
||||
"rna_Node_ItemArray_structure_type_itemf<EvaluateClosureInputItemsAccessor>");
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Structure Type",
|
||||
@@ -7726,7 +7756,11 @@ static void rna_def_evaluate_closure_output_item(BlenderRNA *brna)
|
||||
|
||||
prop = RNA_def_property(srna, "structure_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, rna_enum_node_socket_structure_type_items);
|
||||
RNA_def_property_enum_funcs(prop, nullptr, nullptr, "rna_structure_type_no_auto_itemf");
|
||||
RNA_def_property_enum_funcs(
|
||||
prop,
|
||||
nullptr,
|
||||
nullptr,
|
||||
"rna_Node_ItemArray_structure_type_itemf<EvaluateClosureOutputItemsAccessor>");
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Structure Type",
|
||||
@@ -7787,6 +7821,17 @@ static void def_evaluate_closure(BlenderRNA *brna, StructRNA *srna)
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE);
|
||||
RNA_def_property_update(prop, NC_NODE, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "define_signature", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(
|
||||
prop, nullptr, "flag", NODE_EVALUATE_CLOSURE_FLAG_DEFINE_SIGNATURE);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Define Signature",
|
||||
"This node defines a closure signature that should be used by other nodes");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE);
|
||||
RNA_def_property_update(prop, NC_NODE, "rna_Node_update");
|
||||
}
|
||||
|
||||
static void rna_def_geo_bake_item(BlenderRNA *brna)
|
||||
@@ -7866,10 +7911,26 @@ static void rna_def_geo_bake(BlenderRNA *brna, StructRNA *srna)
|
||||
|
||||
static void rna_def_combine_bundle_item(BlenderRNA *brna)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
StructRNA *srna = RNA_def_struct(brna, "NodeCombineBundleItem", nullptr);
|
||||
RNA_def_struct_ui_text(srna, "Combine Bundle Item", "");
|
||||
|
||||
rna_def_node_item_array_socket_item_common(srna, "CombineBundleItemsAccessor", true);
|
||||
|
||||
prop = RNA_def_property(srna, "structure_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, rna_enum_node_socket_structure_type_items);
|
||||
RNA_def_property_enum_funcs(
|
||||
prop,
|
||||
nullptr,
|
||||
nullptr,
|
||||
"rna_Node_ItemArray_structure_type_itemf<CombineBundleItemsAccessor>");
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Structure Type",
|
||||
"What kind of higher order types are expected to flow through this socket");
|
||||
RNA_def_property_update(
|
||||
prop, NC_NODE | NA_EDITED, "rna_Node_ItemArray_item_update<CombineBundleItemsAccessor>");
|
||||
}
|
||||
|
||||
static void rna_def_combine_bundle_items(BlenderRNA *brna)
|
||||
@@ -7905,14 +7966,40 @@ static void def_combine_bundle(BlenderRNA *brna, StructRNA *srna)
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE);
|
||||
RNA_def_property_update(prop, NC_NODE, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "define_signature", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", NODE_COMBINE_BUNDLE_FLAG_DEFINE_SIGNATURE);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Define Signature",
|
||||
"This node defines a bundle signature that should be used by other nodes");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE);
|
||||
RNA_def_property_update(prop, NC_NODE, "rna_Node_update");
|
||||
}
|
||||
|
||||
static void rna_def_separate_bundle_item(BlenderRNA *brna)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
StructRNA *srna = RNA_def_struct(brna, "NodeSeparateBundleItem", nullptr);
|
||||
RNA_def_struct_ui_text(srna, "Separate Bundle Item", "");
|
||||
|
||||
rna_def_node_item_array_socket_item_common(srna, "SeparateBundleItemsAccessor", true);
|
||||
|
||||
prop = RNA_def_property(srna, "structure_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, rna_enum_node_socket_structure_type_items);
|
||||
RNA_def_property_enum_funcs(
|
||||
prop,
|
||||
nullptr,
|
||||
nullptr,
|
||||
"rna_Node_ItemArray_structure_type_itemf<SeparateBundleItemsAccessor>");
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Structure Type",
|
||||
"What kind of higher order types are expected to flow through this socket");
|
||||
RNA_def_property_update(
|
||||
prop, NC_NODE | NA_EDITED, "rna_Node_ItemArray_item_update<SeparateBundleItemsAccessor>");
|
||||
}
|
||||
|
||||
static void rna_def_separate_bundle_items(BlenderRNA *brna)
|
||||
@@ -7948,6 +8035,16 @@ static void def_separate_bundle(BlenderRNA *brna, StructRNA *srna)
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE);
|
||||
RNA_def_property_update(prop, NC_NODE, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "define_signature", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", NODE_SEPARATE_BUNDLE_FLAG_DEFINE_SIGNATURE);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Define Signature",
|
||||
"This node defines a bundle signature that should be used by other nodes");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE);
|
||||
RNA_def_property_update(prop, NC_NODE, "rna_Node_update");
|
||||
}
|
||||
|
||||
static void rna_def_index_switch_item(BlenderRNA *brna)
|
||||
|
||||
@@ -8,24 +8,21 @@
|
||||
|
||||
#include "BKE_node.hh"
|
||||
|
||||
#include "NOD_node_in_compute_context.hh"
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
struct BundleSignature {
|
||||
|
||||
struct Item {
|
||||
std::string key;
|
||||
const bke::bNodeSocketType *type = nullptr;
|
||||
NodeSocketInterfaceStructureType structure_type;
|
||||
|
||||
uint64_t hash() const
|
||||
{
|
||||
return get_default_hash(this->key);
|
||||
}
|
||||
|
||||
BLI_STRUCT_EQUALITY_OPERATORS_1(Item, key)
|
||||
BLI_STRUCT_EQUALITY_OPERATORS_3(Item, key, type, structure_type);
|
||||
};
|
||||
|
||||
struct ItemKeyGetter {
|
||||
std::string operator()(const Item &item)
|
||||
StringRefNull operator()(const Item &item)
|
||||
{
|
||||
return item.key;
|
||||
}
|
||||
@@ -33,12 +30,35 @@ struct BundleSignature {
|
||||
|
||||
CustomIDVectorSet<Item, ItemKeyGetter> items;
|
||||
|
||||
bool matches_exactly(const BundleSignature &other) const;
|
||||
friend bool operator==(const BundleSignature &a, const BundleSignature &b);
|
||||
friend bool operator!=(const BundleSignature &a, const BundleSignature &b);
|
||||
|
||||
static bool all_matching_exactly(const Span<BundleSignature> signatures);
|
||||
static BundleSignature from_combine_bundle_node(const bNode &node,
|
||||
bool allow_auto_structure_type);
|
||||
static BundleSignature from_separate_bundle_node(const bNode &node,
|
||||
bool allow_auto_structure_type);
|
||||
|
||||
static BundleSignature from_combine_bundle_node(const bNode &node);
|
||||
static BundleSignature from_separate_bundle_node(const bNode &node);
|
||||
void set_auto_structure_types();
|
||||
};
|
||||
|
||||
/**
|
||||
* Multiple bundle signatures that may be linked to a single node.
|
||||
*/
|
||||
struct LinkedBundleSignatures {
|
||||
struct Item {
|
||||
BundleSignature signature;
|
||||
bool is_signature_definition = false;
|
||||
SocketInContext source_socket;
|
||||
};
|
||||
Vector<Item> items;
|
||||
bool has_type_definition() const;
|
||||
|
||||
std::optional<BundleSignature> get_merged_signature() const;
|
||||
};
|
||||
|
||||
NodeSocketInterfaceStructureType get_structure_type_for_bundle_signature(
|
||||
const bNodeSocket &socket,
|
||||
const NodeSocketInterfaceStructureType stored_structure_type,
|
||||
const bool allow_auto_structure_type);
|
||||
|
||||
} // namespace blender::nodes
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#include "BLI_vector_set.hh"
|
||||
|
||||
#include "NOD_node_in_compute_context.hh"
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
/** Describes the names and types of the inputs and outputs of a closure. */
|
||||
@@ -16,7 +18,9 @@ class ClosureSignature {
|
||||
struct Item {
|
||||
std::string key;
|
||||
const bke::bNodeSocketType *type = nullptr;
|
||||
std::optional<StructureType> structure_type = std::nullopt;
|
||||
NodeSocketInterfaceStructureType structure_type;
|
||||
|
||||
BLI_STRUCT_EQUALITY_OPERATORS_3(Item, key, type, structure_type);
|
||||
};
|
||||
|
||||
struct ItemKeyGetter {
|
||||
@@ -32,11 +36,30 @@ class ClosureSignature {
|
||||
std::optional<int> find_input_index(StringRef key) const;
|
||||
std::optional<int> find_output_index(StringRef key) const;
|
||||
|
||||
bool matches_exactly(const ClosureSignature &other) const;
|
||||
static bool all_matching_exactly(Span<ClosureSignature> signatures);
|
||||
friend bool operator==(const ClosureSignature &a, const ClosureSignature &b);
|
||||
friend bool operator!=(const ClosureSignature &a, const ClosureSignature &b);
|
||||
|
||||
static ClosureSignature from_closure_output_node(const bNode &node);
|
||||
static ClosureSignature from_evaluate_closure_node(const bNode &node);
|
||||
static ClosureSignature from_closure_output_node(const bNode &node,
|
||||
bool allow_auto_structure_type);
|
||||
static ClosureSignature from_evaluate_closure_node(const bNode &node,
|
||||
bool allow_auto_structure_type);
|
||||
|
||||
void set_auto_structure_types();
|
||||
};
|
||||
|
||||
/**
|
||||
* Multiple closure signatures that may be linked to a single node.
|
||||
*/
|
||||
struct LinkedClosureSignatures {
|
||||
struct Item {
|
||||
ClosureSignature signature;
|
||||
bool define_signature = false;
|
||||
SocketInContext socket;
|
||||
};
|
||||
Vector<Item> items;
|
||||
bool has_type_definition() const;
|
||||
|
||||
std::optional<ClosureSignature> get_merged_signature() const;
|
||||
};
|
||||
|
||||
} // namespace blender::nodes
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#include "BLI_function_ref.hh"
|
||||
|
||||
#include "DNA_node_types.h"
|
||||
|
||||
#include "RNA_define.hh"
|
||||
|
||||
#include "WM_types.hh" /* For notifier defines */
|
||||
@@ -16,6 +18,8 @@ void rna_Node_update(Main *bmain, Scene *scene, PointerRNA *ptr);
|
||||
void rna_Node_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr);
|
||||
void rna_Node_update_relations(Main *bmain, Scene *scne, PointerRNA *ptr);
|
||||
void rna_Node_Viewer_shortcut_node_set(PointerRNA *ptr, PropertyRNA *prop, int value);
|
||||
const EnumPropertyItem *rna_NodeSocket_structure_type_item_filter(
|
||||
const bNodeTree *ntree, const eNodeSocketDatatype socket_type, bool *r_free);
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "NOD_geometry_nodes_bundle_signature.hh"
|
||||
#include "NOD_geometry_nodes_closure_location.hh"
|
||||
#include "NOD_geometry_nodes_closure_signature.hh"
|
||||
#include "NOD_node_in_compute_context.hh"
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
@@ -27,19 +28,19 @@ namespace blender::nodes {
|
||||
bke::ComputeContextCache &compute_context_cache,
|
||||
const std::optional<ClosureSourceLocation> &source_location);
|
||||
|
||||
Vector<BundleSignature> gather_linked_target_bundle_signatures(
|
||||
LinkedBundleSignatures gather_linked_target_bundle_signatures(
|
||||
const ComputeContext *bundle_socket_context,
|
||||
const bNodeSocket &bundle_socket,
|
||||
bke::ComputeContextCache &compute_context_cache);
|
||||
Vector<BundleSignature> gather_linked_origin_bundle_signatures(
|
||||
LinkedBundleSignatures gather_linked_origin_bundle_signatures(
|
||||
const ComputeContext *bundle_socket_context,
|
||||
const bNodeSocket &bundle_socket,
|
||||
bke::ComputeContextCache &compute_context_cache);
|
||||
Vector<ClosureSignature> gather_linked_target_closure_signatures(
|
||||
LinkedClosureSignatures gather_linked_target_closure_signatures(
|
||||
const ComputeContext *closure_socket_context,
|
||||
const bNodeSocket &closure_socket,
|
||||
bke::ComputeContextCache &compute_context_cache);
|
||||
Vector<ClosureSignature> gather_linked_origin_closure_signatures(
|
||||
LinkedClosureSignatures gather_linked_origin_closure_signatures(
|
||||
const ComputeContext *closure_socket_context,
|
||||
const bNodeSocket &closure_socket,
|
||||
bke::ComputeContextCache &compute_context_cache);
|
||||
|
||||
@@ -258,7 +258,6 @@ struct EvaluateClosureInputItemsAccessor : public socket_items::SocketItemsAcces
|
||||
auto *storage = static_cast<NodeEvaluateClosure *>(node.storage);
|
||||
item.socket_type = socket_type;
|
||||
item.identifier = storage->input_items.next_identifier++;
|
||||
item.structure_type = NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_DYNAMIC;
|
||||
socket_items::set_item_name_and_make_unique<EvaluateClosureInputItemsAccessor>(
|
||||
node, item, name);
|
||||
}
|
||||
@@ -334,7 +333,6 @@ struct EvaluateClosureOutputItemsAccessor : public socket_items::SocketItemsAcce
|
||||
auto *storage = static_cast<NodeEvaluateClosure *>(node.storage);
|
||||
item.socket_type = socket_type;
|
||||
item.identifier = storage->output_items.next_identifier++;
|
||||
item.structure_type = NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_DYNAMIC;
|
||||
socket_items::set_item_name_and_make_unique<EvaluateClosureOutputItemsAccessor>(
|
||||
node, item, name);
|
||||
}
|
||||
|
||||
@@ -42,15 +42,23 @@ static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *current_no
|
||||
layout->use_property_split_set(true);
|
||||
layout->use_property_decorate_set(false);
|
||||
|
||||
PointerRNA output_node_ptr = RNA_pointer_create_discrete(&ntree.id, &RNA_Node, &output_node);
|
||||
|
||||
layout->op("node.sockets_sync", "Sync", ICON_FILE_REFRESH);
|
||||
layout->prop(&output_node_ptr, "define_signature", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
if (current_node->type_legacy == NODE_CLOSURE_INPUT) {
|
||||
if (uiLayout *panel = layout->panel(C, "input_items", false, TIP_("Input Items"))) {
|
||||
socket_items::ui::draw_items_list_with_operators<ClosureInputItemsAccessor>(
|
||||
C, panel, ntree, output_node);
|
||||
socket_items::ui::draw_active_item_props<ClosureInputItemsAccessor>(
|
||||
ntree, output_node, [&](PointerRNA *item_ptr) {
|
||||
const auto &item = *item_ptr->data_as<NodeClosureInputItem>();
|
||||
panel->use_property_split_set(true);
|
||||
panel->use_property_decorate_set(false);
|
||||
panel->prop(item_ptr, "socket_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
panel->prop(item_ptr, "structure_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
if (!socket_type_always_single(eNodeSocketDatatype(item.socket_type))) {
|
||||
panel->prop(item_ptr, "structure_type", UI_ITEM_NONE, "Shape", ICON_NONE);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -60,7 +68,13 @@ static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *current_no
|
||||
C, panel, ntree, output_node);
|
||||
socket_items::ui::draw_active_item_props<ClosureOutputItemsAccessor>(
|
||||
ntree, output_node, [&](PointerRNA *item_ptr) {
|
||||
const auto &item = *item_ptr->data_as<NodeClosureOutputItem>();
|
||||
panel->use_property_split_set(true);
|
||||
panel->use_property_decorate_set(false);
|
||||
panel->prop(item_ptr, "socket_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
if (!socket_type_always_single(eNodeSocketDatatype(item.socket_type))) {
|
||||
panel->prop(item_ptr, "structure_type", UI_ITEM_NONE, "Shape", ICON_NONE);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -83,7 +97,13 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
const NodeClosureInputItem &item = output_storage.input_items.items[i];
|
||||
const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
|
||||
const std::string identifier = ClosureInputItemsAccessor::socket_identifier_for_item(item);
|
||||
b.add_output(socket_type, item.name, identifier);
|
||||
auto &decl = b.add_output(socket_type, item.name, identifier);
|
||||
if (item.structure_type != NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO) {
|
||||
decl.structure_type(StructureType(item.structure_type));
|
||||
}
|
||||
else {
|
||||
decl.structure_type(StructureType::Dynamic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,7 +169,13 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
const NodeClosureOutputItem &item = storage.output_items.items[i];
|
||||
const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
|
||||
const std::string identifier = ClosureOutputItemsAccessor::socket_identifier_for_item(item);
|
||||
b.add_input(socket_type, item.name, identifier).supports_field();
|
||||
auto &decl = b.add_input(socket_type, item.name, identifier).supports_field();
|
||||
if (item.structure_type != NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO) {
|
||||
decl.structure_type(StructureType(item.structure_type));
|
||||
}
|
||||
else {
|
||||
decl.structure_type(StructureType::Dynamic);
|
||||
}
|
||||
}
|
||||
}
|
||||
b.add_input<decl::Extend>("", "__extend__");
|
||||
|
||||
@@ -35,10 +35,16 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
|
||||
const StringRef name = item.name ? item.name : "";
|
||||
const std::string identifier = CombineBundleItemsAccessor::socket_identifier_for_item(item);
|
||||
b.add_input(socket_type, name, identifier)
|
||||
.socket_name_ptr(&tree->id, CombineBundleItemsAccessor::item_srna, &item, "name")
|
||||
.supports_field()
|
||||
.structure_type(StructureType::Dynamic);
|
||||
auto &decl = b.add_input(socket_type, name, identifier)
|
||||
.socket_name_ptr(
|
||||
&tree->id, CombineBundleItemsAccessor::item_srna, &item, "name")
|
||||
.supports_field();
|
||||
if (item.structure_type != NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO) {
|
||||
decl.structure_type(StructureType(item.structure_type));
|
||||
}
|
||||
else {
|
||||
decl.structure_type(StructureType::Dynamic);
|
||||
}
|
||||
}
|
||||
}
|
||||
b.add_input<decl::Extend>("", "__extend__");
|
||||
@@ -89,12 +95,19 @@ static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *node_ptr)
|
||||
bNode &node = *static_cast<bNode *>(node_ptr->data);
|
||||
|
||||
layout->op("node.sockets_sync", "Sync", ICON_FILE_REFRESH);
|
||||
layout->prop(node_ptr, "define_signature", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
if (uiLayout *panel = layout->panel(C, "bundle_items", false, TIP_("Bundle Items"))) {
|
||||
socket_items::ui::draw_items_list_with_operators<CombineBundleItemsAccessor>(
|
||||
C, panel, ntree, node);
|
||||
socket_items::ui::draw_active_item_props<CombineBundleItemsAccessor>(
|
||||
ntree, node, [&](PointerRNA *item_ptr) {
|
||||
const auto &item = *item_ptr->data_as<NodeCombineBundleItem>();
|
||||
panel->use_property_split_set(true);
|
||||
panel->use_property_decorate_set(false);
|
||||
panel->prop(item_ptr, "socket_type", UI_ITEM_NONE, "Type", ICON_NONE);
|
||||
if (!socket_type_always_single(eNodeSocketDatatype(item.socket_type))) {
|
||||
panel->prop(item_ptr, "structure_type", UI_ITEM_NONE, "Shape", ICON_NONE);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,8 +39,13 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
|
||||
const std::string identifier =
|
||||
EvaluateClosureOutputItemsAccessor::socket_identifier_for_item(item);
|
||||
panel.add_output(socket_type, item.name, identifier)
|
||||
.structure_type(StructureType(item.structure_type));
|
||||
auto &decl = panel.add_output(socket_type, item.name, identifier);
|
||||
if (item.structure_type != NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO) {
|
||||
decl.structure_type(StructureType(item.structure_type));
|
||||
}
|
||||
else {
|
||||
decl.structure_type(StructureType::Dynamic);
|
||||
}
|
||||
}
|
||||
panel.add_output<decl::Extend>("", "__extend__");
|
||||
for (const int i : IndexRange(storage.input_items.items_num)) {
|
||||
@@ -48,8 +53,13 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
|
||||
const std::string identifier = EvaluateClosureInputItemsAccessor::socket_identifier_for_item(
|
||||
item);
|
||||
panel.add_input(socket_type, item.name, identifier)
|
||||
.structure_type(StructureType(item.structure_type));
|
||||
auto &decl = panel.add_input(socket_type, item.name, identifier);
|
||||
if (item.structure_type != NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO) {
|
||||
decl.structure_type(StructureType(item.structure_type));
|
||||
}
|
||||
else {
|
||||
decl.structure_type(StructureType::Dynamic);
|
||||
}
|
||||
}
|
||||
panel.add_input<decl::Extend>("", "__extend__");
|
||||
}
|
||||
@@ -109,14 +119,20 @@ static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
|
||||
layout->use_property_decorate_set(false);
|
||||
|
||||
layout->op("node.sockets_sync", "Sync", ICON_FILE_REFRESH);
|
||||
layout->prop(ptr, "define_signature", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
|
||||
if (uiLayout *panel = layout->panel(C, "input_items", false, IFACE_("Input Items"))) {
|
||||
socket_items::ui::draw_items_list_with_operators<EvaluateClosureInputItemsAccessor>(
|
||||
C, panel, tree, node);
|
||||
socket_items::ui::draw_active_item_props<EvaluateClosureInputItemsAccessor>(
|
||||
tree, node, [&](PointerRNA *item_ptr) {
|
||||
const auto &item = *item_ptr->data_as<NodeEvaluateClosureInputItem>();
|
||||
panel->use_property_split_set(true);
|
||||
panel->use_property_decorate_set(false);
|
||||
panel->prop(item_ptr, "socket_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
panel->prop(item_ptr, "structure_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
if (!socket_type_always_single(eNodeSocketDatatype(item.socket_type))) {
|
||||
panel->prop(item_ptr, "structure_type", UI_ITEM_NONE, "Shape", ICON_NONE);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (uiLayout *panel = layout->panel(C, "output_items", false, IFACE_("Output Items"))) {
|
||||
@@ -124,8 +140,13 @@ static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
|
||||
C, panel, tree, node);
|
||||
socket_items::ui::draw_active_item_props<EvaluateClosureOutputItemsAccessor>(
|
||||
tree, node, [&](PointerRNA *item_ptr) {
|
||||
const auto &item = *item_ptr->data_as<NodeEvaluateClosureOutputItem>();
|
||||
panel->use_property_split_set(true);
|
||||
panel->use_property_decorate_set(false);
|
||||
panel->prop(item_ptr, "socket_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
panel->prop(item_ptr, "structure_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
if (!socket_type_always_single(eNodeSocketDatatype(item.socket_type))) {
|
||||
panel->prop(item_ptr, "structure_type", UI_ITEM_NONE, "Shape", ICON_NONE);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,11 +39,17 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
|
||||
const StringRef name = item.name ? item.name : "";
|
||||
const std::string identifier = SeparateBundleItemsAccessor::socket_identifier_for_item(item);
|
||||
b.add_output(socket_type, name, identifier)
|
||||
.socket_name_ptr(&tree->id, SeparateBundleItemsAccessor::item_srna, &item, "name")
|
||||
.propagate_all()
|
||||
.reference_pass_all()
|
||||
.structure_type(StructureType::Dynamic);
|
||||
auto &decl = b.add_output(socket_type, name, identifier)
|
||||
.socket_name_ptr(
|
||||
&tree->id, SeparateBundleItemsAccessor::item_srna, &item, "name")
|
||||
.propagate_all()
|
||||
.reference_pass_all();
|
||||
if (item.structure_type != NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO) {
|
||||
decl.structure_type(StructureType(item.structure_type));
|
||||
}
|
||||
else {
|
||||
decl.structure_type(StructureType::Dynamic);
|
||||
}
|
||||
}
|
||||
}
|
||||
b.add_output<decl::Extend>("", "__extend__");
|
||||
@@ -93,12 +99,19 @@ static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *node_ptr)
|
||||
bNode &node = *static_cast<bNode *>(node_ptr->data);
|
||||
|
||||
layout->op("node.sockets_sync", "Sync", ICON_FILE_REFRESH);
|
||||
layout->prop(node_ptr, "define_signature", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
if (uiLayout *panel = layout->panel(C, "bundle_items", false, TIP_("Bundle Items"))) {
|
||||
socket_items::ui::draw_items_list_with_operators<SeparateBundleItemsAccessor>(
|
||||
C, panel, ntree, node);
|
||||
socket_items::ui::draw_active_item_props<SeparateBundleItemsAccessor>(
|
||||
ntree, node, [&](PointerRNA *item_ptr) {
|
||||
const auto &item = *item_ptr->data_as<NodeSeparateBundleItem>();
|
||||
panel->use_property_split_set(true);
|
||||
panel->use_property_decorate_set(false);
|
||||
panel->prop(item_ptr, "socket_type", UI_ITEM_NONE, "Type", ICON_NONE);
|
||||
if (!socket_type_always_single(eNodeSocketDatatype(item.socket_type))) {
|
||||
panel->prop(item_ptr, "structure_type", UI_ITEM_NONE, "Shape", ICON_NONE);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,33 +14,22 @@
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
bool BundleSignature::matches_exactly(const BundleSignature &other) const
|
||||
bool operator==(const BundleSignature &a, const BundleSignature &b)
|
||||
{
|
||||
if (items.size() != other.items.size()) {
|
||||
return false;
|
||||
}
|
||||
for (const Item &item : items) {
|
||||
if (std::none_of(other.items.begin(), other.items.end(), [&](const Item &other_item) {
|
||||
return item.key == other_item.key;
|
||||
}))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return a.items.as_span() == b.items.as_span();
|
||||
}
|
||||
|
||||
bool BundleSignature::all_matching_exactly(const Span<BundleSignature> signatures)
|
||||
bool operator!=(const BundleSignature &a, const BundleSignature &b)
|
||||
{
|
||||
if (signatures.is_empty()) {
|
||||
return true;
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
void BundleSignature::set_auto_structure_types()
|
||||
{
|
||||
for (const BundleSignature::Item &item : this->items) {
|
||||
const_cast<BundleSignature::Item &>(item).structure_type =
|
||||
NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO;
|
||||
}
|
||||
for (const BundleSignature &signature : signatures.drop_front(1)) {
|
||||
if (!signatures[0].matches_exactly(signature)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
BundlePtr Bundle::create()
|
||||
@@ -212,29 +201,87 @@ void Bundle::delete_self()
|
||||
MEM_delete(this);
|
||||
}
|
||||
|
||||
BundleSignature BundleSignature::from_combine_bundle_node(const bNode &node)
|
||||
NodeSocketInterfaceStructureType get_structure_type_for_bundle_signature(
|
||||
const bNodeSocket &socket,
|
||||
const NodeSocketInterfaceStructureType stored_structure_type,
|
||||
const bool allow_auto_structure_type)
|
||||
{
|
||||
if (stored_structure_type != NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO) {
|
||||
return stored_structure_type;
|
||||
}
|
||||
if (allow_auto_structure_type) {
|
||||
return NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO;
|
||||
}
|
||||
return NodeSocketInterfaceStructureType(socket.runtime->inferred_structure_type);
|
||||
}
|
||||
|
||||
BundleSignature BundleSignature::from_combine_bundle_node(const bNode &node,
|
||||
const bool allow_auto_structure_type)
|
||||
{
|
||||
BLI_assert(node.is_type("NodeCombineBundle"));
|
||||
const auto &storage = *static_cast<const NodeCombineBundle *>(node.storage);
|
||||
BundleSignature signature;
|
||||
for (const int i : IndexRange(storage.items_num)) {
|
||||
const NodeCombineBundleItem &item = storage.items[i];
|
||||
const bNodeSocket &socket = node.input_socket(i);
|
||||
if (const bke::bNodeSocketType *stype = bke::node_socket_type_find_static(item.socket_type)) {
|
||||
signature.items.add({item.name, stype});
|
||||
const NodeSocketInterfaceStructureType structure_type =
|
||||
get_structure_type_for_bundle_signature(
|
||||
socket,
|
||||
NodeSocketInterfaceStructureType(item.structure_type),
|
||||
allow_auto_structure_type);
|
||||
signature.items.add({item.name, stype, structure_type});
|
||||
}
|
||||
}
|
||||
return signature;
|
||||
}
|
||||
|
||||
BundleSignature BundleSignature::from_separate_bundle_node(const bNode &node)
|
||||
BundleSignature BundleSignature::from_separate_bundle_node(const bNode &node,
|
||||
const bool allow_auto_structure_type)
|
||||
{
|
||||
BLI_assert(node.is_type("NodeSeparateBundle"));
|
||||
const auto &storage = *static_cast<const NodeSeparateBundle *>(node.storage);
|
||||
BundleSignature signature;
|
||||
for (const int i : IndexRange(storage.items_num)) {
|
||||
const NodeSeparateBundleItem &item = storage.items[i];
|
||||
const bNodeSocket &socket = node.output_socket(i);
|
||||
if (const bke::bNodeSocketType *stype = bke::node_socket_type_find_static(item.socket_type)) {
|
||||
signature.items.add({item.name, stype});
|
||||
const NodeSocketInterfaceStructureType structure_type =
|
||||
get_structure_type_for_bundle_signature(
|
||||
socket,
|
||||
NodeSocketInterfaceStructureType(item.structure_type),
|
||||
allow_auto_structure_type);
|
||||
signature.items.add({item.name, stype, structure_type});
|
||||
}
|
||||
}
|
||||
return signature;
|
||||
}
|
||||
|
||||
bool LinkedBundleSignatures::has_type_definition() const
|
||||
{
|
||||
for (const Item &item : this->items) {
|
||||
if (item.is_signature_definition) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<BundleSignature> LinkedBundleSignatures::get_merged_signature() const
|
||||
{
|
||||
BundleSignature signature;
|
||||
for (const Item &src_signature : this->items) {
|
||||
for (const BundleSignature::Item &item : src_signature.signature.items) {
|
||||
if (!signature.items.add(item)) {
|
||||
const BundleSignature::Item &existing_item = *signature.items.lookup_key_ptr_as(item.key);
|
||||
if (item.type->type != existing_item.type->type) {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (existing_item.structure_type != item.structure_type) {
|
||||
const_cast<BundleSignature::Item &>(existing_item).structure_type =
|
||||
NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_DYNAMIC;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return signature;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "BKE_node_runtime.hh"
|
||||
|
||||
#include "NOD_geometry_nodes_bundle_signature.hh"
|
||||
#include "NOD_geometry_nodes_closure.hh"
|
||||
|
||||
namespace blender::nodes {
|
||||
@@ -30,97 +31,137 @@ std::optional<int> ClosureSignature::find_output_index(const StringRef key) cons
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
static bool items_equal(const ClosureSignature::Item &a, const ClosureSignature::Item &b)
|
||||
void ClosureSignature::set_auto_structure_types()
|
||||
{
|
||||
if (a.key != b.key) {
|
||||
return false;
|
||||
for (const Item &item : this->inputs) {
|
||||
const_cast<Item &>(item).structure_type = NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO;
|
||||
}
|
||||
if (a.type != b.type) {
|
||||
return false;
|
||||
for (const Item &item : this->outputs) {
|
||||
const_cast<Item &>(item).structure_type = NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO;
|
||||
}
|
||||
if (a.structure_type.has_value() && b.structure_type.has_value()) {
|
||||
if (*a.structure_type != *b.structure_type) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClosureSignature::matches_exactly(const ClosureSignature &other) const
|
||||
bool operator==(const ClosureSignature &a, const ClosureSignature &b)
|
||||
{
|
||||
if (inputs.size() != other.inputs.size()) {
|
||||
return false;
|
||||
}
|
||||
if (outputs.size() != other.outputs.size()) {
|
||||
return false;
|
||||
}
|
||||
for (const Item &item : inputs) {
|
||||
if (std::none_of(other.inputs.begin(), other.inputs.end(), [&](const Item &other_item) {
|
||||
return items_equal(item, other_item);
|
||||
}))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const Item &item : outputs) {
|
||||
if (std::none_of(other.outputs.begin(), other.outputs.end(), [&](const Item &other_item) {
|
||||
return items_equal(item, other_item);
|
||||
}))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return a.inputs.as_span() == b.inputs.as_span() && a.outputs.as_span() == b.outputs.as_span();
|
||||
}
|
||||
|
||||
bool ClosureSignature::all_matching_exactly(const Span<ClosureSignature> signatures)
|
||||
bool operator!=(const ClosureSignature &a, const ClosureSignature &b)
|
||||
{
|
||||
if (signatures.is_empty()) {
|
||||
return true;
|
||||
}
|
||||
for (const ClosureSignature &signature : signatures.drop_front(1)) {
|
||||
if (!signatures[0].matches_exactly(signature)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
ClosureSignature ClosureSignature::from_closure_output_node(const bNode &node)
|
||||
ClosureSignature ClosureSignature::from_closure_output_node(const bNode &node,
|
||||
const bool allow_auto_structure_type)
|
||||
{
|
||||
BLI_assert(node.is_type("NodeClosureOutput"));
|
||||
const bNodeTree &tree = node.owner_tree();
|
||||
const bNode *input_node =
|
||||
bke::zone_type_by_node_type(node.type_legacy)->get_corresponding_input(tree, node);
|
||||
const auto &storage = *static_cast<const NodeClosureOutput *>(node.storage);
|
||||
nodes::ClosureSignature signature;
|
||||
for (const int i : IndexRange(storage.input_items.items_num)) {
|
||||
const NodeClosureInputItem &item = storage.input_items.items[i];
|
||||
if (const bke::bNodeSocketType *stype = bke::node_socket_type_find_static(item.socket_type)) {
|
||||
signature.inputs.add({item.name, stype});
|
||||
if (input_node) {
|
||||
for (const int i : IndexRange(storage.input_items.items_num)) {
|
||||
const NodeClosureInputItem &item = storage.input_items.items[i];
|
||||
const bNodeSocket &socket = input_node->output_socket(i);
|
||||
if (const bke::bNodeSocketType *stype = bke::node_socket_type_find_static(item.socket_type))
|
||||
{
|
||||
const NodeSocketInterfaceStructureType structure_type =
|
||||
get_structure_type_for_bundle_signature(
|
||||
socket,
|
||||
NodeSocketInterfaceStructureType(item.structure_type),
|
||||
allow_auto_structure_type);
|
||||
signature.inputs.add({item.name, stype, structure_type});
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const int i : IndexRange(storage.output_items.items_num)) {
|
||||
const NodeClosureOutputItem &item = storage.output_items.items[i];
|
||||
const bNodeSocket &socket = node.input_socket(i);
|
||||
if (const bke::bNodeSocketType *stype = bke::node_socket_type_find_static(item.socket_type)) {
|
||||
signature.outputs.add({item.name, stype});
|
||||
const NodeSocketInterfaceStructureType structure_type =
|
||||
get_structure_type_for_bundle_signature(
|
||||
socket,
|
||||
NodeSocketInterfaceStructureType(item.structure_type),
|
||||
allow_auto_structure_type);
|
||||
signature.outputs.add({item.name, stype, structure_type});
|
||||
}
|
||||
}
|
||||
return signature;
|
||||
}
|
||||
|
||||
ClosureSignature ClosureSignature::from_evaluate_closure_node(const bNode &node)
|
||||
ClosureSignature ClosureSignature::from_evaluate_closure_node(const bNode &node,
|
||||
const bool allow_auto_structure_type)
|
||||
{
|
||||
BLI_assert(node.is_type("NodeEvaluateClosure"));
|
||||
const auto &storage = *static_cast<const NodeEvaluateClosure *>(node.storage);
|
||||
nodes::ClosureSignature signature;
|
||||
for (const int i : IndexRange(storage.input_items.items_num)) {
|
||||
const NodeEvaluateClosureInputItem &item = storage.input_items.items[i];
|
||||
const bNodeSocket &socket = node.input_socket(i + 1);
|
||||
if (const bke::bNodeSocketType *stype = bke::node_socket_type_find_static(item.socket_type)) {
|
||||
signature.inputs.add({item.name, stype, nodes::StructureType(item.structure_type)});
|
||||
const NodeSocketInterfaceStructureType structure_type =
|
||||
get_structure_type_for_bundle_signature(
|
||||
socket,
|
||||
NodeSocketInterfaceStructureType(item.structure_type),
|
||||
allow_auto_structure_type);
|
||||
signature.inputs.add({item.name, stype, structure_type});
|
||||
}
|
||||
}
|
||||
for (const int i : IndexRange(storage.output_items.items_num)) {
|
||||
const NodeEvaluateClosureOutputItem &item = storage.output_items.items[i];
|
||||
const bNodeSocket &socket = node.output_socket(i);
|
||||
if (const bke::bNodeSocketType *stype = bke::node_socket_type_find_static(item.socket_type)) {
|
||||
signature.outputs.add({item.name, stype, nodes::StructureType(item.structure_type)});
|
||||
const NodeSocketInterfaceStructureType structure_type =
|
||||
get_structure_type_for_bundle_signature(
|
||||
socket,
|
||||
NodeSocketInterfaceStructureType(item.structure_type),
|
||||
allow_auto_structure_type);
|
||||
signature.outputs.add({item.name, stype, structure_type});
|
||||
}
|
||||
}
|
||||
return signature;
|
||||
}
|
||||
|
||||
bool LinkedClosureSignatures::has_type_definition() const
|
||||
{
|
||||
for (const Item &item : this->items) {
|
||||
if (item.define_signature) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<ClosureSignature> LinkedClosureSignatures::get_merged_signature() const
|
||||
{
|
||||
ClosureSignature signature;
|
||||
for (const Item &src_signature : this->items) {
|
||||
for (const ClosureSignature::Item &item : src_signature.signature.inputs) {
|
||||
if (!signature.inputs.add(item)) {
|
||||
const ClosureSignature::Item &existing_item = *signature.inputs.lookup_key_ptr_as(
|
||||
item.key);
|
||||
if (existing_item.type->type != item.type->type) {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (existing_item.structure_type != item.structure_type) {
|
||||
const_cast<ClosureSignature::Item &>(existing_item).structure_type =
|
||||
NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_DYNAMIC;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const ClosureSignature::Item &item : src_signature.signature.outputs) {
|
||||
if (!signature.outputs.add(item)) {
|
||||
const ClosureSignature::Item &existing_item = *signature.outputs.lookup_key_ptr_as(
|
||||
item.key);
|
||||
if (existing_item.type->type != item.type->type) {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (existing_item.structure_type != item.structure_type) {
|
||||
const_cast<ClosureSignature::Item &>(existing_item).structure_type =
|
||||
NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_DYNAMIC;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return signature;
|
||||
|
||||
@@ -68,19 +68,22 @@ static BundleSyncState get_sync_state_separate_bundle(
|
||||
bke::ComputeContextCache compute_context_cache;
|
||||
const ComputeContext *current_context = ed::space_node::compute_context_for_edittree_socket(
|
||||
snode, compute_context_cache, *src_bundle_socket);
|
||||
const Vector<nodes::BundleSignature> source_signatures = gather_linked_origin_bundle_signatures(
|
||||
const LinkedBundleSignatures linked_signatures = gather_linked_origin_bundle_signatures(
|
||||
current_context, *src_bundle_socket, compute_context_cache);
|
||||
if (source_signatures.is_empty()) {
|
||||
if (linked_signatures.items.is_empty()) {
|
||||
return {NodeSyncState::NoSyncSource};
|
||||
}
|
||||
if (!nodes::BundleSignature::all_matching_exactly(source_signatures)) {
|
||||
std::optional<BundleSignature> merged_signature = linked_signatures.get_merged_signature();
|
||||
if (!merged_signature.has_value()) {
|
||||
return {NodeSyncState::ConflictingSyncSources};
|
||||
}
|
||||
const nodes::BundleSignature &source_signature = source_signatures[0];
|
||||
if (!linked_signatures.has_type_definition()) {
|
||||
merged_signature->set_auto_structure_types();
|
||||
}
|
||||
const nodes::BundleSignature ¤t_signature =
|
||||
nodes::BundleSignature::from_separate_bundle_node(separate_bundle_node);
|
||||
if (!source_signature.matches_exactly(current_signature)) {
|
||||
return {NodeSyncState::CanBeSynced, source_signature};
|
||||
nodes::BundleSignature::from_separate_bundle_node(separate_bundle_node, true);
|
||||
if (*merged_signature != current_signature) {
|
||||
return {NodeSyncState::CanBeSynced, std::move(merged_signature)};
|
||||
}
|
||||
return {NodeSyncState::Synced};
|
||||
}
|
||||
@@ -100,19 +103,22 @@ static BundleSyncState get_sync_state_combine_bundle(
|
||||
bke::ComputeContextCache compute_context_cache;
|
||||
const ComputeContext *current_context = ed::space_node::compute_context_for_edittree_socket(
|
||||
snode, compute_context_cache, *src_bundle_socket);
|
||||
const Vector<nodes::BundleSignature> source_signatures = gather_linked_target_bundle_signatures(
|
||||
const LinkedBundleSignatures linked_signatures = gather_linked_target_bundle_signatures(
|
||||
current_context, *src_bundle_socket, compute_context_cache);
|
||||
if (source_signatures.is_empty()) {
|
||||
if (linked_signatures.items.is_empty()) {
|
||||
return {NodeSyncState::NoSyncSource};
|
||||
}
|
||||
if (!nodes::BundleSignature::all_matching_exactly(source_signatures)) {
|
||||
std::optional<BundleSignature> merged_signature = linked_signatures.get_merged_signature();
|
||||
if (!merged_signature.has_value()) {
|
||||
return {NodeSyncState::ConflictingSyncSources};
|
||||
}
|
||||
const nodes::BundleSignature &source_signature = source_signatures[0];
|
||||
if (!linked_signatures.has_type_definition()) {
|
||||
merged_signature->set_auto_structure_types();
|
||||
}
|
||||
const nodes::BundleSignature ¤t_signature =
|
||||
nodes::BundleSignature::from_combine_bundle_node(combine_bundle_node);
|
||||
if (!source_signature.matches_exactly(current_signature)) {
|
||||
return {NodeSyncState::CanBeSynced, source_signature};
|
||||
nodes::BundleSignature::from_combine_bundle_node(combine_bundle_node, true);
|
||||
if (*merged_signature != current_signature) {
|
||||
return {NodeSyncState::CanBeSynced, std::move(merged_signature)};
|
||||
}
|
||||
return {NodeSyncState::Synced};
|
||||
}
|
||||
@@ -131,20 +137,22 @@ static ClosureSyncState get_sync_state_closure_output(
|
||||
bke::ComputeContextCache compute_context_cache;
|
||||
const ComputeContext *current_context = ed::space_node::compute_context_for_edittree_socket(
|
||||
snode, compute_context_cache, *src_closure_socket);
|
||||
const Vector<nodes::ClosureSignature> source_signatures =
|
||||
gather_linked_target_closure_signatures(
|
||||
current_context, *src_closure_socket, compute_context_cache);
|
||||
if (source_signatures.is_empty()) {
|
||||
const LinkedClosureSignatures linked_signatures = gather_linked_target_closure_signatures(
|
||||
current_context, *src_closure_socket, compute_context_cache);
|
||||
if (linked_signatures.items.is_empty()) {
|
||||
return {NodeSyncState::NoSyncSource};
|
||||
}
|
||||
if (!nodes::ClosureSignature::all_matching_exactly(source_signatures)) {
|
||||
std::optional<ClosureSignature> merged_signature = linked_signatures.get_merged_signature();
|
||||
if (!merged_signature.has_value()) {
|
||||
return {NodeSyncState::ConflictingSyncSources};
|
||||
}
|
||||
const nodes::ClosureSignature &source_signature = source_signatures[0];
|
||||
if (!linked_signatures.has_type_definition()) {
|
||||
merged_signature->set_auto_structure_types();
|
||||
}
|
||||
const nodes::ClosureSignature ¤t_signature =
|
||||
nodes::ClosureSignature::from_closure_output_node(closure_output_node);
|
||||
if (!source_signature.matches_exactly(current_signature)) {
|
||||
return {NodeSyncState::CanBeSynced, source_signature};
|
||||
nodes::ClosureSignature::from_closure_output_node(closure_output_node, true);
|
||||
if (*merged_signature != current_signature) {
|
||||
return {NodeSyncState::CanBeSynced, merged_signature};
|
||||
}
|
||||
return {NodeSyncState::Synced};
|
||||
}
|
||||
@@ -163,20 +171,22 @@ static ClosureSyncState get_sync_state_evaluate_closure(
|
||||
bke::ComputeContextCache compute_context_cache;
|
||||
const ComputeContext *current_context = ed::space_node::compute_context_for_edittree_socket(
|
||||
snode, compute_context_cache, *src_closure_socket);
|
||||
const Vector<nodes::ClosureSignature> source_signatures =
|
||||
gather_linked_origin_closure_signatures(
|
||||
current_context, *src_closure_socket, compute_context_cache);
|
||||
if (source_signatures.is_empty()) {
|
||||
const LinkedClosureSignatures linked_signatures = gather_linked_origin_closure_signatures(
|
||||
current_context, *src_closure_socket, compute_context_cache);
|
||||
if (linked_signatures.items.is_empty()) {
|
||||
return {NodeSyncState::NoSyncSource};
|
||||
}
|
||||
if (!nodes::ClosureSignature::all_matching_exactly(source_signatures)) {
|
||||
std::optional<ClosureSignature> merged_signature = linked_signatures.get_merged_signature();
|
||||
if (!merged_signature.has_value()) {
|
||||
return {NodeSyncState::ConflictingSyncSources};
|
||||
}
|
||||
const nodes::ClosureSignature &source_signature = source_signatures[0];
|
||||
if (!linked_signatures.has_type_definition()) {
|
||||
merged_signature->set_auto_structure_types();
|
||||
}
|
||||
const nodes::ClosureSignature ¤t_signature =
|
||||
nodes::ClosureSignature::from_evaluate_closure_node(evaluate_closure_node);
|
||||
if (!source_signature.matches_exactly(current_signature)) {
|
||||
return {NodeSyncState::CanBeSynced, source_signature};
|
||||
nodes::ClosureSignature::from_evaluate_closure_node(evaluate_closure_node, true);
|
||||
if (*merged_signature != current_signature) {
|
||||
return {NodeSyncState::CanBeSynced, merged_signature};
|
||||
}
|
||||
return {NodeSyncState::Synced};
|
||||
}
|
||||
@@ -214,6 +224,7 @@ void sync_sockets_separate_bundle(SpaceNode &snode,
|
||||
NodeSeparateBundleItem &new_item = *nodes::socket_items::add_item_with_socket_type_and_name<
|
||||
nodes ::SeparateBundleItemsAccessor>(
|
||||
*snode.edittree, separate_bundle_node, item.type->type, item.key.c_str());
|
||||
new_item.structure_type = int(item.structure_type);
|
||||
if (const std::optional<int> old_identifier = old_identifiers.lookup_try(item.key)) {
|
||||
new_item.identifier = *old_identifier;
|
||||
}
|
||||
@@ -254,6 +265,7 @@ void sync_sockets_combine_bundle(SpaceNode &snode,
|
||||
NodeCombineBundleItem &new_item = *nodes::socket_items::add_item_with_socket_type_and_name<
|
||||
nodes ::CombineBundleItemsAccessor>(
|
||||
*snode.edittree, combine_bundle_node, item.type->type, item.key.c_str());
|
||||
new_item.structure_type = int(item.structure_type);
|
||||
if (const std::optional<int> old_identifier = old_identifiers.lookup_try(item.key)) {
|
||||
new_item.identifier = *old_identifier;
|
||||
}
|
||||
@@ -303,6 +315,7 @@ void sync_sockets_evaluate_closure(SpaceNode &snode,
|
||||
*nodes::socket_items::add_item_with_socket_type_and_name<
|
||||
nodes::EvaluateClosureInputItemsAccessor>(
|
||||
*snode.edittree, evaluate_closure_node, item.type->type, item.key.c_str());
|
||||
new_item.structure_type = int(item.structure_type);
|
||||
if (const std::optional<int> old_identifier = old_input_identifiers.lookup_try(item.key)) {
|
||||
new_item.identifier = *old_identifier;
|
||||
}
|
||||
@@ -312,6 +325,7 @@ void sync_sockets_evaluate_closure(SpaceNode &snode,
|
||||
*nodes::socket_items::add_item_with_socket_type_and_name<
|
||||
nodes::EvaluateClosureOutputItemsAccessor>(
|
||||
*snode.edittree, evaluate_closure_node, item.type->type, item.key.c_str());
|
||||
new_item.structure_type = int(item.structure_type);
|
||||
if (const std::optional<int> old_identifier = old_output_identifiers.lookup_try(item.key)) {
|
||||
new_item.identifier = *old_identifier;
|
||||
}
|
||||
@@ -361,9 +375,7 @@ void sync_sockets_closure(SpaceNode &snode,
|
||||
NodeClosureInputItem &new_item =
|
||||
*nodes::socket_items::add_item_with_socket_type_and_name<nodes::ClosureInputItemsAccessor>(
|
||||
*snode.edittree, closure_output_node, item.type->type, item.key.c_str());
|
||||
if (item.structure_type) {
|
||||
new_item.structure_type = int(*item.structure_type);
|
||||
}
|
||||
new_item.structure_type = int(item.structure_type);
|
||||
if (const std::optional<int> old_identifier = old_input_identifiers.lookup_try(item.key)) {
|
||||
new_item.identifier = *old_identifier;
|
||||
}
|
||||
@@ -372,6 +384,7 @@ void sync_sockets_closure(SpaceNode &snode,
|
||||
NodeClosureOutputItem &new_item = *nodes::socket_items::add_item_with_socket_type_and_name<
|
||||
nodes::ClosureOutputItemsAccessor>(
|
||||
*snode.edittree, closure_output_node, item.type->type, item.key.c_str());
|
||||
new_item.structure_type = int(item.structure_type);
|
||||
if (const std::optional<int> old_identifier = old_output_identifiers.lookup_try(item.key)) {
|
||||
new_item.identifier = *old_identifier;
|
||||
}
|
||||
@@ -413,20 +426,25 @@ static std::string get_bundle_sync_tooltip(const nodes::BundleSignature &old_sig
|
||||
Vector<StringRef> added_items;
|
||||
Vector<StringRef> removed_items;
|
||||
Vector<StringRef> changed_items;
|
||||
bool order_changed = false;
|
||||
|
||||
for (const nodes::BundleSignature::Item &new_item : new_signature.items) {
|
||||
if (const nodes::BundleSignature::Item *old_item = old_signature.items.lookup_key_ptr_as(
|
||||
new_item.key))
|
||||
{
|
||||
if (new_item.type->type != old_item->type->type) {
|
||||
changed_items.append(new_item.key);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const int new_item_i : new_signature.items.index_range()) {
|
||||
const BundleSignature::Item &new_item = new_signature.items[new_item_i];
|
||||
const int old_item_i = old_signature.items.index_of_try_as(new_item.key);
|
||||
if (old_item_i == -1) {
|
||||
added_items.append(new_item.key);
|
||||
}
|
||||
else {
|
||||
const BundleSignature::Item &old_item = old_signature.items[old_item_i];
|
||||
if (new_item != old_item) {
|
||||
changed_items.append(new_item.key);
|
||||
}
|
||||
if (old_item_i != new_item_i) {
|
||||
order_changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const nodes::BundleSignature ::Item &old_item : old_signature.items) {
|
||||
for (const nodes::BundleSignature::Item &old_item : old_signature.items) {
|
||||
if (!new_signature.items.contains_as(old_item.key)) {
|
||||
removed_items.append(old_item.key);
|
||||
}
|
||||
@@ -435,13 +453,16 @@ static std::string get_bundle_sync_tooltip(const nodes::BundleSignature &old_sig
|
||||
fmt::memory_buffer string_buffer;
|
||||
auto buf = fmt::appender(string_buffer);
|
||||
if (!added_items.is_empty()) {
|
||||
fmt::format_to(buf, "{}: {}\n", TIP_("Add"), fmt::join(added_items, ", "));
|
||||
fmt::format_to(buf, "\u2022 {}: {}\n", TIP_("Add"), fmt::join(added_items, ", "));
|
||||
}
|
||||
if (!removed_items.is_empty()) {
|
||||
fmt::format_to(buf, "{}: {}\n", TIP_("Remove"), fmt::join(removed_items, ", "));
|
||||
fmt::format_to(buf, "\u2022 {}: {}\n", TIP_("Remove"), fmt::join(removed_items, ", "));
|
||||
}
|
||||
if (!changed_items.is_empty()) {
|
||||
fmt::format_to(buf, "{}: {}\n", TIP_("Change"), fmt::join(changed_items, ", "));
|
||||
fmt::format_to(buf, "\u2022 {}: {}\n", TIP_("Change"), fmt::join(changed_items, ", "));
|
||||
}
|
||||
if (order_changed) {
|
||||
fmt::format_to(buf, "\u2022 {}", TIP_("Reorder"));
|
||||
}
|
||||
fmt::format_to(buf, "\n{}", TIP_("Update based on linked bundle signature"));
|
||||
|
||||
@@ -454,21 +475,27 @@ static std::string get_closure_sync_tooltip(const nodes::ClosureSignature &old_s
|
||||
Vector<StringRef> added_inputs;
|
||||
Vector<StringRef> removed_inputs;
|
||||
Vector<StringRef> changed_inputs;
|
||||
bool input_order = false;
|
||||
|
||||
Vector<StringRef> added_outputs;
|
||||
Vector<StringRef> removed_outputs;
|
||||
Vector<StringRef> changed_outputs;
|
||||
bool output_order = false;
|
||||
|
||||
for (const nodes::ClosureSignature::Item &new_item : new_signature.inputs) {
|
||||
if (const nodes::ClosureSignature::Item *old_item = old_signature.inputs.lookup_key_ptr_as(
|
||||
new_item.key))
|
||||
{
|
||||
if (new_item.type->type != old_item->type->type) {
|
||||
changed_inputs.append(new_item.key);
|
||||
}
|
||||
for (const int new_item_i : new_signature.inputs.index_range()) {
|
||||
const nodes::ClosureSignature::Item &new_item = new_signature.inputs[new_item_i];
|
||||
const int old_item_i = old_signature.inputs.index_of_try_as(new_item.key);
|
||||
if (old_item_i == -1) {
|
||||
added_inputs.append(new_item.key);
|
||||
}
|
||||
else {
|
||||
added_inputs.append(new_item.key);
|
||||
const nodes::ClosureSignature::Item &old_item = old_signature.inputs[old_item_i];
|
||||
if (new_item != old_item) {
|
||||
changed_inputs.append(new_item.key);
|
||||
}
|
||||
if (old_item_i != new_item_i) {
|
||||
input_order = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const nodes::ClosureSignature::Item &old_item : old_signature.inputs) {
|
||||
@@ -476,16 +503,20 @@ static std::string get_closure_sync_tooltip(const nodes::ClosureSignature &old_s
|
||||
removed_inputs.append(old_item.key);
|
||||
}
|
||||
}
|
||||
for (const nodes::ClosureSignature::Item &new_item : new_signature.outputs) {
|
||||
if (const nodes::ClosureSignature::Item *old_item = old_signature.outputs.lookup_key_ptr_as(
|
||||
new_item.key))
|
||||
{
|
||||
if (new_item.type->type != old_item->type->type) {
|
||||
changed_outputs.append(new_item.key);
|
||||
}
|
||||
for (const int new_item_i : new_signature.outputs.index_range()) {
|
||||
const nodes::ClosureSignature::Item &new_item = new_signature.outputs[new_item_i];
|
||||
const int old_item_i = old_signature.outputs.index_of_try_as(new_item.key);
|
||||
if (old_item_i == -1) {
|
||||
added_outputs.append(new_item.key);
|
||||
}
|
||||
else {
|
||||
added_outputs.append(new_item.key);
|
||||
const nodes::ClosureSignature::Item &old_item = old_signature.outputs[old_item_i];
|
||||
if (new_item != old_item) {
|
||||
changed_outputs.append(new_item.key);
|
||||
}
|
||||
if (old_item_i != new_item_i) {
|
||||
output_order = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const nodes::ClosureSignature::Item &old_item : old_signature.outputs) {
|
||||
@@ -497,22 +528,30 @@ static std::string get_closure_sync_tooltip(const nodes::ClosureSignature &old_s
|
||||
fmt::memory_buffer string_buffer;
|
||||
auto buf = fmt::appender(string_buffer);
|
||||
if (!added_inputs.is_empty()) {
|
||||
fmt::format_to(buf, "{}: {}\n", TIP_("Add Inputs"), fmt::join(added_inputs, ", "));
|
||||
fmt::format_to(buf, "\u2022 {}: {}\n", TIP_("Add Inputs"), fmt::join(added_inputs, ", "));
|
||||
}
|
||||
if (!removed_inputs.is_empty()) {
|
||||
fmt::format_to(buf, "{}: {}\n", TIP_("Remove Inputs"), fmt::join(removed_inputs, ", "));
|
||||
fmt::format_to(buf, "\u2022 {}: {}\n", TIP_("Remove Inputs"), fmt::join(removed_inputs, ", "));
|
||||
}
|
||||
if (!changed_inputs.is_empty()) {
|
||||
fmt::format_to(buf, "{}: {}\n", TIP_("Change Inputs"), fmt::join(changed_inputs, ", "));
|
||||
fmt::format_to(buf, "\u2022 {}: {}\n", TIP_("Change Inputs"), fmt::join(changed_inputs, ", "));
|
||||
}
|
||||
if (input_order) {
|
||||
fmt::format_to(buf, "\u2022 {}\n", TIP_("Reorder Inputs"));
|
||||
}
|
||||
if (!added_outputs.is_empty()) {
|
||||
fmt::format_to(buf, "{}: {}\n", TIP_("Add Outputs"), fmt::join(added_outputs, ", "));
|
||||
fmt::format_to(buf, "\u2022 {}: {}\n", TIP_("Add Outputs"), fmt::join(added_outputs, ", "));
|
||||
}
|
||||
if (!removed_outputs.is_empty()) {
|
||||
fmt::format_to(buf, "{}: {}\n", TIP_("Remove Outputs"), fmt::join(removed_outputs, ", "));
|
||||
fmt::format_to(
|
||||
buf, "\u2022 {}: {}\n", TIP_("Remove Outputs"), fmt::join(removed_outputs, ", "));
|
||||
}
|
||||
if (!changed_outputs.is_empty()) {
|
||||
fmt::format_to(buf, "{}: {}\n", TIP_("Change Outputs"), fmt::join(changed_outputs, ", "));
|
||||
fmt::format_to(
|
||||
buf, "\u2022 {}: {}\n", TIP_("Change Outputs"), fmt::join(changed_outputs, ", "));
|
||||
}
|
||||
if (output_order) {
|
||||
fmt::format_to(buf, "\u2022 {}\n", TIP_("Reorder Outputs"));
|
||||
}
|
||||
fmt::format_to(buf, "\n{}", TIP_("Update based on linked closure signature"));
|
||||
|
||||
@@ -559,7 +598,7 @@ std::string sync_node_description_get(const bContext &C, const bNode &node)
|
||||
|
||||
if (node.is_type("NodeSeparateBundle")) {
|
||||
const nodes::BundleSignature old_signature = nodes::BundleSignature::from_separate_bundle_node(
|
||||
node);
|
||||
node, true);
|
||||
if (const std::optional<nodes::BundleSignature> new_signature =
|
||||
get_sync_state_separate_bundle(*snode, node).source_signature)
|
||||
{
|
||||
@@ -568,7 +607,7 @@ std::string sync_node_description_get(const bContext &C, const bNode &node)
|
||||
}
|
||||
else if (node.is_type("NodeCombineBundle")) {
|
||||
const nodes::BundleSignature old_signature = nodes::BundleSignature::from_combine_bundle_node(
|
||||
node);
|
||||
node, true);
|
||||
if (const std::optional<nodes::BundleSignature> new_signature =
|
||||
get_sync_state_combine_bundle(*snode, node).source_signature)
|
||||
{
|
||||
@@ -577,7 +616,7 @@ std::string sync_node_description_get(const bContext &C, const bNode &node)
|
||||
}
|
||||
else if (node.is_type("NodeEvaluateClosure")) {
|
||||
const nodes::ClosureSignature old_signature =
|
||||
nodes::ClosureSignature::from_evaluate_closure_node(node);
|
||||
nodes::ClosureSignature::from_evaluate_closure_node(node, true);
|
||||
if (const std::optional<nodes::ClosureSignature> new_signature =
|
||||
get_sync_state_evaluate_closure(*snode, node).source_signature)
|
||||
{
|
||||
@@ -586,7 +625,7 @@ std::string sync_node_description_get(const bContext &C, const bNode &node)
|
||||
}
|
||||
else if (node.is_type("NodeClosureOutput")) {
|
||||
const nodes::ClosureSignature old_signature =
|
||||
nodes::ClosureSignature::from_closure_output_node(node);
|
||||
nodes::ClosureSignature::from_closure_output_node(node, true);
|
||||
if (const std::optional<nodes::ClosureSignature> new_signature =
|
||||
get_sync_state_closure_output(*snode, node).source_signature)
|
||||
{
|
||||
|
||||
@@ -570,82 +570,100 @@ static Vector<SocketInContext> find_origin_sockets_through_contexts(
|
||||
return found_origins.extract_vector();
|
||||
}
|
||||
|
||||
Vector<BundleSignature> gather_linked_target_bundle_signatures(
|
||||
LinkedBundleSignatures gather_linked_target_bundle_signatures(
|
||||
const ComputeContext *bundle_socket_context,
|
||||
const bNodeSocket &bundle_socket,
|
||||
bke::ComputeContextCache &compute_context_cache)
|
||||
{
|
||||
const Vector<SocketInContext> target_sockets = find_target_sockets_through_contexts(
|
||||
LinkedBundleSignatures result;
|
||||
find_target_sockets_through_contexts(
|
||||
{bundle_socket_context, &bundle_socket},
|
||||
compute_context_cache,
|
||||
[](const SocketInContext &socket) {
|
||||
return socket->is_input() && socket->owner_node().is_type("NodeSeparateBundle");
|
||||
},
|
||||
true);
|
||||
Vector<BundleSignature> signatures;
|
||||
for (const SocketInContext &target_socket : target_sockets) {
|
||||
const NodeInContext &target_node = target_socket.owner_node();
|
||||
signatures.append(BundleSignature::from_separate_bundle_node(*target_node.node));
|
||||
}
|
||||
return signatures;
|
||||
}
|
||||
|
||||
Vector<BundleSignature> gather_linked_origin_bundle_signatures(
|
||||
const ComputeContext *bundle_socket_context,
|
||||
const bNodeSocket &bundle_socket,
|
||||
bke::ComputeContextCache &compute_context_cache)
|
||||
{
|
||||
const Vector<SocketInContext> origin_sockets = find_origin_sockets_through_contexts(
|
||||
{bundle_socket_context, &bundle_socket},
|
||||
compute_context_cache,
|
||||
[](const SocketInContext &socket) {
|
||||
return socket->is_output() && socket->owner_node().is_type("NodeCombineBundle");
|
||||
},
|
||||
true);
|
||||
Vector<BundleSignature> signatures;
|
||||
for (const SocketInContext &origin_socket : origin_sockets) {
|
||||
const NodeInContext &origin_node = origin_socket.owner_node();
|
||||
signatures.append(BundleSignature::from_combine_bundle_node(*origin_node.node));
|
||||
}
|
||||
return signatures;
|
||||
}
|
||||
|
||||
Vector<ClosureSignature> gather_linked_target_closure_signatures(
|
||||
const ComputeContext *closure_socket_context,
|
||||
const bNodeSocket &closure_socket,
|
||||
bke::ComputeContextCache &compute_context_cache)
|
||||
{
|
||||
const Vector<SocketInContext> target_sockets = find_target_sockets_through_contexts(
|
||||
{closure_socket_context, &closure_socket},
|
||||
compute_context_cache,
|
||||
is_evaluate_closure_node_input,
|
||||
true);
|
||||
Vector<ClosureSignature> signatures;
|
||||
for (const SocketInContext &target_socket : target_sockets) {
|
||||
const NodeInContext &target_node = target_socket.owner_node();
|
||||
signatures.append(ClosureSignature::from_evaluate_closure_node(*target_node.node));
|
||||
}
|
||||
return signatures;
|
||||
}
|
||||
|
||||
Vector<ClosureSignature> gather_linked_origin_closure_signatures(
|
||||
const ComputeContext *closure_socket_context,
|
||||
const bNodeSocket &closure_socket,
|
||||
bke::ComputeContextCache &compute_context_cache)
|
||||
{
|
||||
Vector<ClosureSignature> signatures;
|
||||
find_origin_sockets_through_contexts(
|
||||
{closure_socket_context, &closure_socket},
|
||||
compute_context_cache,
|
||||
[&](const SocketInContext &socket) {
|
||||
if (is_closure_zone_output_socket(socket)) {
|
||||
signatures.append(ClosureSignature::from_closure_output_node(socket->owner_node()));
|
||||
const bNode &node = socket->owner_node();
|
||||
if (socket->is_input() && node.is_type("NodeSeparateBundle")) {
|
||||
const auto &storage = *static_cast<const NodeSeparateBundle *>(node.storage);
|
||||
result.items.append({BundleSignature::from_separate_bundle_node(node, false),
|
||||
bool(storage.flag & NODE_SEPARATE_BUNDLE_FLAG_DEFINE_SIGNATURE),
|
||||
socket});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
true);
|
||||
return signatures;
|
||||
return result;
|
||||
}
|
||||
|
||||
LinkedBundleSignatures gather_linked_origin_bundle_signatures(
|
||||
const ComputeContext *bundle_socket_context,
|
||||
const bNodeSocket &bundle_socket,
|
||||
bke::ComputeContextCache &compute_context_cache)
|
||||
{
|
||||
LinkedBundleSignatures result;
|
||||
find_origin_sockets_through_contexts(
|
||||
{bundle_socket_context, &bundle_socket},
|
||||
compute_context_cache,
|
||||
[&](const SocketInContext &socket) {
|
||||
const bNode &node = socket->owner_node();
|
||||
if (socket->is_output() && node.is_type("NodeCombineBundle")) {
|
||||
const auto &storage = *static_cast<const NodeCombineBundle *>(node.storage);
|
||||
result.items.append({BundleSignature::from_combine_bundle_node(node, false),
|
||||
bool(storage.flag & NODE_COMBINE_BUNDLE_FLAG_DEFINE_SIGNATURE),
|
||||
socket});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
true);
|
||||
return result;
|
||||
}
|
||||
|
||||
LinkedClosureSignatures gather_linked_target_closure_signatures(
|
||||
const ComputeContext *closure_socket_context,
|
||||
const bNodeSocket &closure_socket,
|
||||
bke::ComputeContextCache &compute_context_cache)
|
||||
{
|
||||
LinkedClosureSignatures result;
|
||||
find_target_sockets_through_contexts(
|
||||
{closure_socket_context, &closure_socket},
|
||||
compute_context_cache,
|
||||
[&](const SocketInContext &socket) {
|
||||
const bNode &node = socket->owner_node();
|
||||
if (is_evaluate_closure_node_input(socket)) {
|
||||
const auto &storage = *static_cast<const NodeEvaluateClosure *>(node.storage);
|
||||
result.items.append({ClosureSignature::from_evaluate_closure_node(node, false),
|
||||
bool(storage.flag & NODE_EVALUATE_CLOSURE_FLAG_DEFINE_SIGNATURE),
|
||||
socket});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
true);
|
||||
return result;
|
||||
}
|
||||
|
||||
LinkedClosureSignatures gather_linked_origin_closure_signatures(
|
||||
const ComputeContext *closure_socket_context,
|
||||
const bNodeSocket &closure_socket,
|
||||
bke::ComputeContextCache &compute_context_cache)
|
||||
{
|
||||
LinkedClosureSignatures result;
|
||||
find_origin_sockets_through_contexts(
|
||||
{closure_socket_context, &closure_socket},
|
||||
compute_context_cache,
|
||||
[&](const SocketInContext &socket) {
|
||||
const bNode &node = socket->owner_node();
|
||||
if (is_closure_zone_output_socket(socket)) {
|
||||
const auto &storage = *static_cast<const NodeClosureOutput *>(node.storage);
|
||||
result.items.append({ClosureSignature::from_closure_output_node(node, false),
|
||||
bool(storage.flag & NODE_CLOSURE_FLAG_DEFINE_SIGNATURE),
|
||||
socket});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
true);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace blender::nodes
|
||||
|
||||
Reference in New Issue
Block a user