Blender  V2.93
intern/node_geometry_exec.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 #include "DNA_modifier_types.h"
18 
19 #include "BKE_node_ui_storage.hh"
20 
21 #include "DEG_depsgraph_query.h"
22 
23 #include "NOD_geometry_exec.hh"
24 #include "NOD_type_callbacks.hh"
25 
26 #include "node_geometry_util.hh"
27 
28 namespace blender::nodes {
29 
30 void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::string message) const
31 {
32  bNodeTree *btree_cow = node_->btree();
33  BLI_assert(btree_cow != nullptr);
34  if (btree_cow == nullptr) {
35  return;
36  }
37  bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow);
38 
39  const NodeTreeEvaluationContext context(*self_object_, *modifier_);
40 
42  *btree_original, context, *node_->bnode(), type, std::move(message));
43 }
44 
45 const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const
46 {
47  for (const InputSocketRef *socket : node_->inputs()) {
48  if (socket->is_available() && socket->name() == name) {
49  return socket->bsocket();
50  }
51  }
52 
53  return nullptr;
54 }
55 
58  const AttributeDomain domain,
59  const CustomDataType type,
60  const void *default_value) const
61 {
62  const bNodeSocket *found_socket = this->find_available_socket(name);
63  BLI_assert(found_socket != nullptr); /* There should always be available socket for the name. */
64  if (found_socket == nullptr) {
65  return component.attribute_get_constant_for_read(domain, type, default_value);
66  }
67 
68  if (found_socket->type == SOCK_STRING) {
69  const std::string name = this->get_input<std::string>(found_socket->identifier);
70  /* Try getting the attribute without the default value. */
71  ReadAttributePtr attribute = component.attribute_try_get_for_read(name, domain, type);
72  if (attribute) {
73  return attribute;
74  }
75 
76  /* If the attribute doesn't exist, use the default value and output an error message
77  * (except when the field is empty, to avoid spamming error messages, and not when
78  * the domain is empty and we don't expect an attribute anyway). */
79  if (!name.empty() && component.attribute_domain_size(domain) != 0) {
81  TIP_("No attribute with name \"") + name + "\"");
82  }
83  return component.attribute_get_constant_for_read(domain, type, default_value);
84  }
85  if (found_socket->type == SOCK_FLOAT) {
86  const float value = this->get_input<float>(found_socket->identifier);
87  return component.attribute_get_constant_for_read_converted(
88  domain, CD_PROP_FLOAT, type, &value);
89  }
90  if (found_socket->type == SOCK_VECTOR) {
91  const float3 value = this->get_input<float3>(found_socket->identifier);
92  return component.attribute_get_constant_for_read_converted(
93  domain, CD_PROP_FLOAT3, type, &value);
94  }
95  if (found_socket->type == SOCK_RGBA) {
96  const Color4f value = this->get_input<Color4f>(found_socket->identifier);
97  return component.attribute_get_constant_for_read_converted(
98  domain, CD_PROP_COLOR, type, &value);
99  }
100  BLI_assert(false);
101  return component.attribute_get_constant_for_read(domain, type, default_value);
102 }
103 
105  const StringRef name,
107  const CustomDataType default_type) const
108 {
109  const bNodeSocket *found_socket = this->find_available_socket(name);
110  BLI_assert(found_socket != nullptr); /* There should always be available socket for the name. */
111  if (found_socket == nullptr) {
112  return default_type;
113  }
114 
115  if (found_socket->type == SOCK_STRING) {
116  const std::string name = this->get_input<std::string>(found_socket->identifier);
117  ReadAttributePtr attribute = component.attribute_try_get_for_read(name);
118  if (!attribute) {
119  return default_type;
120  }
121  return attribute->custom_data_type();
122  }
123  if (found_socket->type == SOCK_FLOAT) {
124  return CD_PROP_FLOAT;
125  }
126  if (found_socket->type == SOCK_VECTOR) {
127  return CD_PROP_FLOAT3;
128  }
129  if (found_socket->type == SOCK_RGBA) {
130  return CD_PROP_COLOR;
131  }
132  if (found_socket->type == SOCK_BOOLEAN) {
133  return CD_PROP_BOOL;
134  }
135 
136  BLI_assert(false);
137  return default_type;
138 }
139 
148  const AttributeDomain default_domain) const
149 {
150  Vector<AttributeDomain, 8> input_domains;
151  for (const std::string &name : names) {
152  const bNodeSocket *found_socket = this->find_available_socket(name);
153  BLI_assert(found_socket != nullptr); /* A socket should be available socket for the name. */
154  if (found_socket == nullptr) {
155  continue;
156  }
157 
158  if (found_socket->type == SOCK_STRING) {
159  const std::string name = this->get_input<std::string>(found_socket->identifier);
160  ReadAttributePtr attribute = component.attribute_try_get_for_read(name);
161  if (attribute) {
162  input_domains.append(attribute->domain());
163  }
164  }
165  }
166 
167  if (input_domains.size() > 0) {
168  return bke::attribute_domain_highest_priority(input_domains);
169  }
170 
171  return default_domain;
172 }
173 
174 void GeoNodeExecParams::check_extract_input(StringRef identifier,
175  const CPPType *requested_type) const
176 {
177  bNodeSocket *found_socket = nullptr;
178  for (const InputSocketRef *socket : node_->inputs()) {
179  if (socket->identifier() == identifier) {
180  found_socket = socket->bsocket();
181  break;
182  }
183  }
184 
185  if (found_socket == nullptr) {
186  std::cout << "Did not find an input socket with the identifier '" << identifier << "'.\n";
187  std::cout << "Possible identifiers are: ";
188  for (const InputSocketRef *socket : node_->inputs()) {
189  if (socket->is_available()) {
190  std::cout << "'" << socket->identifier() << "', ";
191  }
192  }
193  std::cout << "\n";
194  BLI_assert(false);
195  }
196  else if (found_socket->flag & SOCK_UNAVAIL) {
197  std::cout << "The socket corresponding to the identifier '" << identifier
198  << "' is disabled.\n";
199  BLI_assert(false);
200  }
201  else if (!input_values_.contains(identifier)) {
202  std::cout << "The identifier '" << identifier
203  << "' is valid, but there is no value for it anymore.\n";
204  std::cout << "Most likely it has been extracted before.\n";
205  BLI_assert(false);
206  }
207  else if (requested_type != nullptr) {
208  const CPPType &expected_type = *socket_cpp_type_get(*found_socket->typeinfo);
209  if (*requested_type != expected_type) {
210  std::cout << "The requested type '" << requested_type->name() << "' is incorrect. Expected '"
211  << expected_type.name() << "'.\n";
212  BLI_assert(false);
213  }
214  }
215 }
216 
217 void GeoNodeExecParams::check_set_output(StringRef identifier, const CPPType &value_type) const
218 {
219  bNodeSocket *found_socket = nullptr;
220  for (const OutputSocketRef *socket : node_->outputs()) {
221  if (socket->identifier() == identifier) {
222  found_socket = socket->bsocket();
223  break;
224  }
225  }
226 
227  if (found_socket == nullptr) {
228  std::cout << "Did not find an output socket with the identifier '" << identifier << "'.\n";
229  std::cout << "Possible identifiers are: ";
230  for (const OutputSocketRef *socket : node_->outputs()) {
231  if (socket->is_available()) {
232  std::cout << "'" << socket->identifier() << "', ";
233  }
234  }
235  std::cout << "\n";
236  BLI_assert(false);
237  }
238  else if (found_socket->flag & SOCK_UNAVAIL) {
239  std::cout << "The socket corresponding to the identifier '" << identifier
240  << "' is disabled.\n";
241  BLI_assert(false);
242  }
243  else if (output_values_.contains(identifier)) {
244  std::cout << "The identifier '" << identifier << "' has been set already.\n";
245  BLI_assert(false);
246  }
247  else {
248  const CPPType &expected_type = *socket_cpp_type_get(*found_socket->typeinfo);
249  if (value_type != expected_type) {
250  std::cout << "The value type '" << value_type.name() << "' is incorrect. Expected '"
251  << expected_type.name() << "'.\n";
252  BLI_assert(false);
253  }
254  }
255 }
256 
257 } // namespace blender::nodes
AttributeDomain
Definition: BKE_attribute.h:41
NodeWarningType
void BKE_nodetree_error_message_add(bNodeTree &ntree, const NodeTreeEvaluationContext &context, const bNode &node, const NodeWarningType type, std::string message)
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define TIP_(msgid)
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:126
struct ID * DEG_get_original_id(struct ID *id)
CustomDataType
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
@ CD_PROP_COLOR
@ CD_PROP_BOOL
@ SOCK_UNAVAIL
@ SOCK_VECTOR
@ SOCK_BOOLEAN
@ SOCK_FLOAT
@ SOCK_STRING
@ SOCK_RGBA
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
static std::string default_domain
int64_t size() const
Definition: BLI_vector.hh:662
void append(const T &value)
Definition: BLI_vector.hh:438
StringRefNull name() const
Definition: FN_cpp_type.hh:269
AttributeDomain get_highest_priority_input_domain(Span< std::string > names, const GeometryComponent &component, const AttributeDomain default_domain) const
CustomDataType get_input_attribute_data_type(const StringRef name, const GeometryComponent &component, const CustomDataType default_type) const
ReadAttributePtr get_input_attribute(const StringRef name, const GeometryComponent &component, const AttributeDomain domain, const CustomDataType type, const void *default_value) const
void error_message_add(const NodeWarningType type, std::string message) const
Span< const InputSocketRef * > inputs() const
bNodeTree * btree() const
Span< const OutputSocketRef * > outputs() const
static char ** names
Definition: makesdna.c:162
AttributeDomain attribute_domain_highest_priority(Span< AttributeDomain > domains)
std::unique_ptr< ReadAttribute > ReadAttributePtr
const CPPType * socket_cpp_type_get(const bNodeSocketType &stype)
struct SELECTID_Context context
Definition: select_engine.c:47
Definition: DNA_ID.h:273
struct bNodeSocketType * typeinfo
char identifier[64]