1
1

Compare commits

...

14 Commits

11 changed files with 354 additions and 11 deletions

View File

@@ -731,7 +731,7 @@ void nodeSetSocketAvailability(struct bNodeSocket *sock, bool is_available);
int nodeSocketLinkLimit(const struct bNodeSocket *sock);
void nodeDeclarationEnsure(struct bNodeTree *ntree, struct bNode *node);
NodeDeclarationHandle *nodeDeclarationEnsure(struct bNodeTree *ntree, struct bNode *node);
/* Node Clipboard */
void BKE_node_clipboard_init(const struct bNodeTree *ntree);

View File

@@ -29,6 +29,7 @@
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <queue>
/* Allow using deprecated functionality for .blend file I/O. */
#define DNA_DEPRECATED_ALLOW
@@ -52,9 +53,12 @@
#include "BLI_map.hh"
#include "BLI_math.h"
#include "BLI_path_util.h"
#include "BLI_set.hh"
#include "BLI_stack.hh"
#include "BLI_string.h"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BLI_vector_set.hh"
#include "BLT_translation.h"
@@ -80,6 +84,7 @@
#include "NOD_function.h"
#include "NOD_geometry.h"
#include "NOD_node_declaration.hh"
#include "NOD_node_tree_ref.hh"
#include "NOD_shader.h"
#include "NOD_socket.h"
#include "NOD_texture.h"
@@ -93,6 +98,14 @@
#define NODE_DEFAULT_MAX_WIDTH 700
using blender::Array;
using blender::Set;
using blender::Span;
using blender::Stack;
using blender::Vector;
using blender::VectorSet;
using namespace blender::nodes::node_tree_ref_types;
/* Fallback types for undefined tree, nodes, sockets */
static bNodeTreeType NodeTreeTypeUndefined;
bNodeType NodeTypeUndefined;
@@ -647,6 +660,8 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
ntree->progress = nullptr;
ntree->execdata = nullptr;
ntree->output_field_dependencies = nullptr;
BLO_read_data_address(reader, &ntree->adt);
BKE_animdata_blend_read_data(reader, ntree->adt);
@@ -1015,8 +1030,8 @@ IDTypeInfo IDType_ID_NT = {
static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype)
{
if (ntype->declare != nullptr) {
nodeDeclarationEnsure(ntree, node);
node->declaration->build(*ntree, *node);
blender::nodes::NodeDeclaration *node_decl = nodeDeclarationEnsure(ntree, node);
node_decl->build(*ntree, *node);
return;
}
bNodeSocketTemplate *sockdef;
@@ -3942,18 +3957,19 @@ int nodeSocketLinkLimit(const bNodeSocket *sock)
* If the node implements a `declare` function, this function makes sure that `node->declaration`
* is up to date.
*/
void nodeDeclarationEnsure(bNodeTree *UNUSED(ntree), bNode *node)
NodeDeclarationHandle *nodeDeclarationEnsure(bNodeTree *UNUSED(ntree), bNode *node)
{
if (node->typeinfo->declare == nullptr) {
return;
return nullptr;
}
if (node->declaration != nullptr) {
return;
return node->declaration;
}
node->declaration = new blender::nodes::NodeDeclaration();
blender::nodes::NodeDeclarationBuilder builder{*node->declaration};
node->typeinfo->declare(builder);
return node->declaration;
}
/* ************** Node Clipboard *********** */
@@ -4468,6 +4484,296 @@ void ntreeUpdateAllUsers(Main *main, ID *id)
}
}
static bool is_field_socket_type(eNodeSocketDatatype type)
{
return ELEM(type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA);
}
static bool sockets_have_links(blender::Span<const SocketRef *> sockets)
{
for (const SocketRef *socket : sockets) {
if (!socket->directly_linked_links().is_empty()) {
return true;
}
}
return false;
}
using OutputFieldDependencies = Vector<std::optional<Vector<int>>>;
static const std::optional<Vector<int>> *get_group_output_field_dependencies(
const OutputSocketRef &output_socket)
{
const NodeRef &node = output_socket.node();
BLI_assert(node.is_group_node());
bNodeTree *group = (bNodeTree *)node.bnode()->id;
if (group == nullptr) {
return nullptr;
}
if (group->output_field_dependencies == nullptr) {
return nullptr;
}
const OutputFieldDependencies *output_field_dependencies = (const OutputFieldDependencies *)
group->output_field_dependencies;
if (output_socket.index() >= output_field_dependencies->size()) {
return nullptr;
}
return &(*output_field_dependencies)[output_socket.index()];
}
static Vector<int> get_linked_field_input_indices(const OutputSocketRef &output_socket)
{
Vector<int> indices;
const NodeRef &node = output_socket.node();
if (node.is_group_node()) {
const std::optional<Vector<int>> *optional_dependencies = get_group_output_field_dependencies(
output_socket);
if (optional_dependencies && optional_dependencies->has_value()) {
indices.extend(**optional_dependencies);
}
}
else {
for (const InputSocketRef *input_socket : output_socket.node().inputs()) {
if (is_field_socket_type((eNodeSocketDatatype)input_socket->typeinfo()->type)) {
indices.append(input_socket->index());
}
}
}
return indices;
}
static Vector<const NodeRef *> toposort_nodes(const NodeTreeRef &tree, bool left_to_right = true)
{
Vector<const NodeRef *> toposort;
toposort.reserve(tree.nodes().size());
Array<bool> node_is_pushed_by_id(tree.nodes().size(), false);
std::queue<const NodeRef *> nodes_to_check;
for (const NodeRef *node : tree.nodes()) {
if (!sockets_have_links(node->inputs_or_outputs(!left_to_right))) {
node_is_pushed_by_id[node->id()] = true;
nodes_to_check.push(node);
}
}
while (!nodes_to_check.empty()) {
const NodeRef *node = nodes_to_check.front();
nodes_to_check.pop();
toposort.append(node);
for (const SocketRef *input_socket : node->inputs_or_outputs(left_to_right)) {
for (const SocketRef *linked_socket : input_socket->directly_linked_sockets()) {
const NodeRef &linked_node = linked_socket->node();
const int linked_node_id = linked_node.id();
if (!node_is_pushed_by_id[linked_node_id]) {
node_is_pushed_by_id[linked_node_id] = true;
nodes_to_check.push(&linked_node);
}
}
}
}
toposort.as_mutable_span().reverse();
return toposort;
}
struct SocketFieldState {
bool is_single = true;
bool is_field_source = false;
bool requires_single = false;
};
static std::optional<Vector<int>> find_dependent_group_input_indices(
const InputSocketRef &group_output_socket,
const Span<SocketFieldState> field_state_by_socket_id)
{
Set<const InputSocketRef *> handled_sockets;
Stack<const InputSocketRef *> sockets_to_check;
handled_sockets.add(&group_output_socket);
sockets_to_check.push(&group_output_socket);
Set<int> found_input_indices;
while (!sockets_to_check.is_empty()) {
const InputSocketRef *input_socket = sockets_to_check.pop();
for (const OutputSocketRef *origin_socket : input_socket->logically_linked_sockets()) {
const NodeRef &origin_node = origin_socket->node();
const SocketFieldState &origin_state = field_state_by_socket_id[origin_socket->id()];
if (origin_state.is_field_source) {
if (origin_node.is_group_input_node()) {
found_input_indices.add(origin_socket->index());
}
else {
return std::nullopt;
}
}
else if (!origin_state.is_single) {
const Vector<int> input_socket_indices = get_linked_field_input_indices(*origin_socket);
for (const int input_index : input_socket_indices) {
const InputSocketRef &origin_input_socket = origin_node.input(input_index);
if (!field_state_by_socket_id[origin_input_socket.id()].is_single) {
if (handled_sockets.add(&origin_input_socket)) {
sockets_to_check.push(&origin_input_socket);
}
}
}
}
}
}
return Vector<int>(found_input_indices.begin(), found_input_indices.end());
}
static void update_socket_shapes_for_fields(bNodeTree &btree)
{
using namespace blender;
using namespace blender::nodes;
if (btree.type != NTREE_GEOMETRY) {
return;
}
NodeTreeRef tree{&btree};
Vector<const NodeRef *> toposort_left_to_right = toposort_nodes(tree, true);
Vector<const NodeRef *> toposort_right_to_left = toposort_nodes(tree, false);
Array<SocketFieldState> field_state_by_socket_id(tree.sockets().size());
auto check_if_node_is_adaptive = [](const NodeRef &node) {
const StringRef node_idname = node.idname();
return !node_idname.startswith("GeometryNode");
};
for (const NodeRef *node : toposort_right_to_left) {
NodeDeclaration *node_decl = nodeDeclarationEnsure(&btree, node->bnode());
const bool node_is_adaptive = check_if_node_is_adaptive(*node);
for (const OutputSocketRef *output_socket : node->outputs()) {
SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
for (const InputSocketRef *target_socket : output_socket->directly_linked_sockets()) {
state.requires_single |= field_state_by_socket_id[target_socket->id()].requires_single;
}
if (state.requires_single) {
const Vector<int> input_socket_indices = get_linked_field_input_indices(*output_socket);
for (const int input_index : input_socket_indices) {
const InputSocketRef &input_socket = node->input(input_index);
field_state_by_socket_id[input_socket.id()].requires_single = true;
}
}
}
for (const InputSocketRef *input_socket : node->inputs()) {
SocketFieldState &state = field_state_by_socket_id[input_socket->id()];
if (state.requires_single) {
continue;
}
if (node_decl != nullptr && !node_is_adaptive) {
const SocketDeclaration &socket_decl = *node_decl->inputs()[input_socket->index()];
state.requires_single |= !socket_decl.is_field();
}
if (!is_field_socket_type((eNodeSocketDatatype)input_socket->bsocket()->type)) {
state.requires_single = true;
}
}
}
for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) {
for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) {
SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
if (!state.requires_single) {
state.is_single = false;
state.is_field_source = true;
}
}
}
for (const NodeRef *node : toposort_left_to_right) {
NodeDeclaration *node_decl = nodeDeclarationEnsure(&btree, node->bnode());
for (const InputSocketRef *input_socket : node->inputs()) {
SocketFieldState &state = field_state_by_socket_id[input_socket->id()];
if (state.requires_single) {
state.is_single = true;
continue;
}
state.is_single = true;
for (const OutputSocketRef *origin_socket : input_socket->logically_linked_sockets()) {
if (!field_state_by_socket_id[origin_socket->id()].is_single) {
state.is_single = false;
break;
}
}
}
for (const OutputSocketRef *output_socket : node->outputs()) {
SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
if (node_decl != nullptr) {
const SocketDeclaration &socket_decl = *node_decl->outputs()[output_socket->index()];
if (socket_decl.is_field()) {
state.is_single = false;
state.is_field_source = true;
}
}
if (output_socket->node().is_group_node()) {
const std::optional<Vector<int>> *optional_dependencies =
get_group_output_field_dependencies(*output_socket);
if (optional_dependencies && !optional_dependencies->has_value()) {
state.is_single = false;
state.is_field_source = true;
}
}
const Vector<int> input_socket_indices = get_linked_field_input_indices(*output_socket);
for (const int input_index : input_socket_indices) {
const InputSocketRef &input_socket = node->input(input_index);
if (!field_state_by_socket_id[input_socket.id()].is_single) {
state.is_single = false;
break;
}
}
}
}
for (const NodeRef *group_output_node : tree.nodes_by_type("NodeGroupOutput")) {
if (!(group_output_node->bnode()->flag & NODE_DO_OUTPUT)) {
continue;
}
OutputFieldDependencies *output_field_dependencies = new OutputFieldDependencies();
for (const InputSocketRef *group_output_socket : group_output_node->inputs().drop_back(1)) {
std::optional<Vector<int>> dependent_input_indices = find_dependent_group_input_indices(
*group_output_socket, field_state_by_socket_id);
output_field_dependencies->append(std::move(dependent_input_indices));
}
if (btree.output_field_dependencies != nullptr) {
delete (OutputFieldDependencies *)btree.output_field_dependencies;
}
btree.output_field_dependencies = output_field_dependencies;
break;
}
for (const InputSocketRef *socket : tree.input_sockets()) {
bNodeSocket *bsocket = socket->bsocket();
const SocketFieldState &state = field_state_by_socket_id[socket->id()];
if (state.requires_single) {
bsocket->display_shape = SOCK_DISPLAY_SHAPE_CIRCLE;
}
else {
bsocket->display_shape = SOCK_DISPLAY_SHAPE_DIAMOND;
}
}
for (const OutputSocketRef *socket : tree.output_sockets()) {
bNodeSocket *bsocket = socket->bsocket();
const SocketFieldState &state = field_state_by_socket_id[socket->id()];
if (state.is_single) {
bsocket->display_shape = SOCK_DISPLAY_SHAPE_CIRCLE;
}
else {
bsocket->display_shape = SOCK_DISPLAY_SHAPE_DIAMOND;
}
}
}
void ntreeUpdateTree(Main *bmain, bNodeTree *ntree)
{
if (!ntree) {
@@ -4519,6 +4825,8 @@ void ntreeUpdateTree(Main *bmain, bNodeTree *ntree)
/* update the node level from link dependencies */
ntree_update_node_level(ntree);
update_socket_shapes_for_fields(*ntree);
/* check link validity */
ntree_validate_links(ntree);
}

View File

@@ -4282,6 +4282,12 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
// th_col3 = -1; /* no shadow */
}
}
if (snode->edittree->type == NTREE_GEOMETRY) {
if ((link->fromsock && link->fromsock->display_shape == SOCK_DISPLAY_SHAPE_DIAMOND) &&
(link->tosock && link->tosock->display_shape == SOCK_DISPLAY_SHAPE_CIRCLE)) {
th_col1 = th_col2 = th_col3 = TH_REDALERT;
}
}
node_draw_link_bezier(v2d, snode, link, th_col1, th_col2, th_col3);
}

View File

@@ -481,6 +481,8 @@ typedef struct bNodeTree {
float view_center[2];
ListBase nodes, links;
/* Vector<std::optional<Vector<int>>>. */
void *output_field_dependencies;
/** Set init on fileread. */
int type, init;

View File

@@ -37,6 +37,7 @@ class SocketDeclaration {
bool hide_label_ = false;
bool hide_value_ = false;
bool is_multi_input_ = false;
bool is_field_ = false;
friend NodeDeclarationBuilder;
template<typename SocketDecl> friend class SocketDeclarationBuilder;
@@ -51,6 +52,8 @@ class SocketDeclaration {
StringRefNull name() const;
StringRefNull identifier() const;
bool is_field() const;
protected:
void set_common_flags(bNodeSocket &socket) const;
bool matches_common_data(const bNodeSocket &socket) const;
@@ -93,6 +96,12 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
decl_->is_multi_input_ = value;
return *(Self *)this;
}
Self &is_field(bool value = true)
{
decl_->is_field_ = value;
return *(Self *)this;
}
};
using SocketDeclarationPtr = std::unique_ptr<SocketDeclaration>;
@@ -148,6 +157,11 @@ inline StringRefNull SocketDeclaration::identifier() const
return identifier_;
}
inline bool SocketDeclaration::is_field() const
{
return is_field_;
}
/* --------------------------------------------------------------------
* NodeDeclarationBuilder inline methods.
*/

View File

@@ -181,6 +181,7 @@ class NodeRef : NonCopyable, NonMovable {
Span<const InputSocketRef *> inputs() const;
Span<const OutputSocketRef *> outputs() const;
Span<const SocketRef *> inputs_or_outputs(bool get_inputs) const;
Span<const InternalLinkRef *> internal_links() const;
const InputSocketRef &input(int index) const;
@@ -496,6 +497,12 @@ inline Span<const OutputSocketRef *> NodeRef::outputs() const
return outputs_;
}
inline Span<const SocketRef *> NodeRef::inputs_or_outputs(bool get_inputs) const
{
return get_inputs ? inputs_.as_span().cast<const SocketRef *>() :
outputs_.as_span().cast<const SocketRef *>();
}
inline Span<const InternalLinkRef *> NodeRef::internal_links() const
{
return internal_links_;

View File

@@ -173,6 +173,12 @@ class Bool : public SocketDeclaration {
public:
using Builder = BoolBuilder;
Bool &is_field(bool value)
{
is_field_ = value;
return *this;
}
bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
bool matches(const bNodeSocket &socket) const override;
};

View File

@@ -20,7 +20,7 @@ namespace blender::nodes {
static void geo_node_input_index_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Int>("Index");
b.add_output<decl::Int>("Index").is_field();
}
class IndexFieldInput final : public fn::FieldInput {

View File

@@ -25,7 +25,7 @@ namespace blender::nodes {
static void geo_node_input_normal_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Vector>("Normal");
b.add_output<decl::Vector>("Normal").is_field();
}
static GVArrayPtr mesh_face_normals(const Mesh &mesh,

View File

@@ -20,7 +20,7 @@ namespace blender::nodes {
static void geo_node_input_position_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Vector>("Position");
b.add_output<decl::Vector>("Position").is_field();
}
static void geo_node_input_position_exec(GeoNodeExecParams params)

View File

@@ -23,8 +23,8 @@ namespace blender::nodes {
static void geo_node_set_position_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Vector>("Position");
b.add_input<decl::Bool>("Selection").default_value(true).hide_value();
b.add_input<decl::Vector>("Position").is_field();
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().is_field();
b.add_output<decl::Geometry>("Geometry");
}