Welcome to mirror list, hosted at ThFree Co, Russian Federation.

NOD_node_declaration.hh « nodes « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 32e63ffb2df59a5b4286d3d4cd2ee6cbe6bf2293 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#pragma once

#include <type_traits>

#include "BLI_string_ref.hh"
#include "BLI_vector.hh"

#include "DNA_node_types.h"

namespace blender::nodes {

class NodeDeclarationBuilder;

enum class InputSocketFieldType {
  /** The input is required to be a single value. */
  None,
  /** The input can be a field. */
  IsSupported,
  /** The input can be a field and is a field implicitly if nothing is connected. */
  Implicit,
};

enum class OutputSocketFieldType {
  /** The output is always a single value. */
  None,
  /** The output is always a field, independent of the inputs. */
  FieldSource,
  /** If any input is a field, this output will be a field as well. */
  DependentField,
  /** If any of a subset of inputs is a field, this out will be a field as well.
   * The subset is defined by the vector of indices. */
  PartiallyDependent,
};

/**
 * Contains information about how a node output's field state depends on inputs of the same node.
 */
class OutputFieldDependency {
 private:
  OutputSocketFieldType type_ = OutputSocketFieldType::None;
  Vector<int> linked_input_indices_;

 public:
  static OutputFieldDependency ForFieldSource()
  {
    OutputFieldDependency field_dependency;
    field_dependency.type_ = OutputSocketFieldType::FieldSource;
    return field_dependency;
  }

  static OutputFieldDependency ForDataSource()
  {
    OutputFieldDependency field_dependency;
    field_dependency.type_ = OutputSocketFieldType::None;
    return field_dependency;
  }

  static OutputFieldDependency ForPartiallyDependentField(Vector<int> indices)
  {
    OutputFieldDependency field_dependency;
    if (indices.is_empty()) {
      field_dependency.type_ = OutputSocketFieldType::None;
    }
    else {
      field_dependency.type_ = OutputSocketFieldType::PartiallyDependent;
      field_dependency.linked_input_indices_ = std::move(indices);
    }
    return field_dependency;
  }

  static OutputFieldDependency ForDependentField()
  {
    OutputFieldDependency field_dependency;
    field_dependency.type_ = OutputSocketFieldType::DependentField;
    return field_dependency;
  }

  OutputSocketFieldType field_type() const
  {
    return type_;
  }

  Span<int> linked_input_indices() const
  {
    return linked_input_indices_;
  }

  friend bool operator==(const OutputFieldDependency &a, const OutputFieldDependency &b)
  {
    return a.type_ == b.type_ && a.linked_input_indices_ == b.linked_input_indices_;
  }

  friend bool operator!=(const OutputFieldDependency &a, const OutputFieldDependency &b)
  {
    return !(a == b);
  }
};

/**
 * Describes a single input or output socket. This is subclassed for different socket types.
 */
class SocketDeclaration {
 protected:
  std::string name_;
  std::string identifier_;
  bool hide_label_ = false;
  bool hide_value_ = false;
  bool is_multi_input_ = false;
  bool no_mute_links_ = false;

  InputSocketFieldType input_field_type_ = InputSocketFieldType::None;
  OutputFieldDependency output_field_dependency_;

  friend NodeDeclarationBuilder;
  template<typename SocketDecl> friend class SocketDeclarationBuilder;

 public:
  virtual ~SocketDeclaration() = default;

  virtual bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const = 0;
  virtual bool matches(const bNodeSocket &socket) const = 0;
  virtual bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const;

  StringRefNull name() const;
  StringRefNull identifier() const;

  InputSocketFieldType input_field_type() const;
  const OutputFieldDependency &output_field_dependency() const;

 protected:
  void set_common_flags(bNodeSocket &socket) const;
  bool matches_common_data(const bNodeSocket &socket) const;
};

class BaseSocketDeclarationBuilder {
 public:
  virtual ~BaseSocketDeclarationBuilder() = default;
};

/**
 * Wraps a #SocketDeclaration and provides methods to set it up correctly.
 * This is separate from #SocketDeclaration, because it allows separating the API used by nodes to
 * declare themselves from how the declaration is stored internally.
 */
template<typename SocketDecl>
class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
 protected:
  using Self = typename SocketDecl::Builder;
  static_assert(std::is_base_of_v<SocketDeclaration, SocketDecl>);
  SocketDecl *decl_;

  friend class NodeDeclarationBuilder;

 public:
  Self &hide_label(bool value = true)
  {
    decl_->hide_label_ = value;
    return *(Self *)this;
  }

  Self &hide_value(bool value = true)
  {
    decl_->hide_value_ = value;
    return *(Self *)this;
  }

  Self &multi_input(bool value = true)
  {
    decl_->is_multi_input_ = value;
    return *(Self *)this;
  }

  Self &no_muted_links(bool value = true)
  {
    decl_->no_mute_links_ = value;
    return *(Self *)this;
  }

  /** The input socket allows passing in a field. */
  Self &supports_field()
  {
    decl_->input_field_type_ = InputSocketFieldType::IsSupported;
    return *(Self *)this;
  }

  /** The input supports a field and is a field by default when nothing is connected. */
  Self &implicit_field()
  {
    decl_->input_field_type_ = InputSocketFieldType::Implicit;
    return *(Self *)this;
  }

  /** The output is always a field, regardless of any inputs. */
  Self &field_source()
  {
    decl_->output_field_dependency_ = OutputFieldDependency::ForFieldSource();
    return *(Self *)this;
  }

  /** The output is a field if any of the inputs is a field. */
  Self &dependent_field()
  {
    decl_->output_field_dependency_ = OutputFieldDependency::ForDependentField();
    return *(Self *)this;
  }

  /** The output is a field if any of the inputs with indices in the given list is a field. */
  Self &dependent_field(Vector<int> input_dependencies)
  {
    decl_->output_field_dependency_ = OutputFieldDependency::ForPartiallyDependentField(
        std::move(input_dependencies));
  }
};

using SocketDeclarationPtr = std::unique_ptr<SocketDeclaration>;

class NodeDeclaration {
 private:
  Vector<SocketDeclarationPtr> inputs_;
  Vector<SocketDeclarationPtr> outputs_;
  bool is_function_node_ = false;

  friend NodeDeclarationBuilder;

 public:
  void build(bNodeTree &ntree, bNode &node) const;
  bool matches(const bNode &node) const;

  Span<SocketDeclarationPtr> inputs() const;
  Span<SocketDeclarationPtr> outputs() const;

  bool is_function_node() const
  {
    return is_function_node_;
  }

  MEM_CXX_CLASS_ALLOC_FUNCS("NodeDeclaration")
};

class NodeDeclarationBuilder {
 private:
  NodeDeclaration &declaration_;
  Vector<std::unique_ptr<BaseSocketDeclarationBuilder>> builders_;

 public:
  NodeDeclarationBuilder(NodeDeclaration &declaration);

  /**
   * All inputs support fields, and all outputs are fields if any of the inputs is a field.
   * Calling field status definitions on each socket is unnecessary.
   */
  void is_function_node(bool value = true)
  {
    declaration_.is_function_node_ = value;
  }

  template<typename DeclType>
  typename DeclType::Builder &add_input(StringRef name, StringRef identifier = "");
  template<typename DeclType>
  typename DeclType::Builder &add_output(StringRef name, StringRef identifier = "");

 private:
  template<typename DeclType>
  typename DeclType::Builder &add_socket(StringRef name,
                                         StringRef identifier,
                                         Vector<SocketDeclarationPtr> &r_decls);
};

/* --------------------------------------------------------------------
 * SocketDeclaration inline methods.
 */

inline StringRefNull SocketDeclaration::name() const
{
  return name_;
}

inline StringRefNull SocketDeclaration::identifier() const
{
  return identifier_;
}

inline InputSocketFieldType SocketDeclaration::input_field_type() const
{
  return input_field_type_;
}

inline const OutputFieldDependency &SocketDeclaration::output_field_dependency() const
{
  return output_field_dependency_;
}

/* --------------------------------------------------------------------
 * NodeDeclarationBuilder inline methods.
 */

inline NodeDeclarationBuilder::NodeDeclarationBuilder(NodeDeclaration &declaration)
    : declaration_(declaration)
{
}

template<typename DeclType>
inline typename DeclType::Builder &NodeDeclarationBuilder::add_input(StringRef name,
                                                                     StringRef identifier)
{
  return this->add_socket<DeclType>(name, identifier, declaration_.inputs_);
}

template<typename DeclType>
inline typename DeclType::Builder &NodeDeclarationBuilder::add_output(StringRef name,
                                                                      StringRef identifier)
{
  return this->add_socket<DeclType>(name, identifier, declaration_.outputs_);
}

template<typename DeclType>
inline typename DeclType::Builder &NodeDeclarationBuilder::add_socket(
    StringRef name, StringRef identifier, Vector<SocketDeclarationPtr> &r_decls)
{
  static_assert(std::is_base_of_v<SocketDeclaration, DeclType>);
  using Builder = typename DeclType::Builder;
  std::unique_ptr<DeclType> socket_decl = std::make_unique<DeclType>();
  std::unique_ptr<Builder> socket_decl_builder = std::make_unique<Builder>();
  socket_decl_builder->decl_ = &*socket_decl;
  socket_decl->name_ = name;
  socket_decl->identifier_ = identifier.is_empty() ? name : identifier;
  r_decls.append(std::move(socket_decl));
  Builder &socket_decl_builder_ref = *socket_decl_builder;
  builders_.append(std::move(socket_decl_builder));
  return socket_decl_builder_ref;
}

/* --------------------------------------------------------------------
 * NodeDeclaration inline methods.
 */

inline Span<SocketDeclarationPtr> NodeDeclaration::inputs() const
{
  return inputs_;
}

inline Span<SocketDeclarationPtr> NodeDeclaration::outputs() const
{
  return outputs_;
}

}  // namespace blender::nodes