Cleanup: rename some animation-related functions
[blender.git] / source / blender / nodes / intern / node_geometry_exec.cc
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_derived_node_tree.hh"
24 #include "NOD_geometry_exec.hh"
25 #include "NOD_type_callbacks.hh"
26
27 #include "node_geometry_util.hh"
28
29 namespace blender::nodes {
30
31 void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::string message) const
32 {
33   bNodeTree *btree_cow = node_.node_ref().tree().btree();
34   BLI_assert(btree_cow != nullptr);
35   if (btree_cow == nullptr) {
36     return;
37   }
38   bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow);
39
40   const NodeTreeEvaluationContext context(*self_object_, *modifier_);
41
42   BKE_nodetree_error_message_add(
43       *btree_original, context, *node_.bnode(), type, std::move(message));
44 }
45
46 const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const
47 {
48   for (const DSocket *socket : node_.inputs()) {
49     if (socket->is_available() && socket->name() == name) {
50       return socket->bsocket();
51     }
52   }
53
54   return nullptr;
55 }
56
57 ReadAttributePtr GeoNodeExecParams::get_input_attribute(const StringRef name,
58                                                         const GeometryComponent &component,
59                                                         const AttributeDomain domain,
60                                                         const CustomDataType type,
61                                                         const void *default_value) const
62 {
63   const bNodeSocket *found_socket = this->find_available_socket(name);
64   BLI_assert(found_socket != nullptr); /* There should always be available socket for the name. */
65   if (found_socket == nullptr) {
66     return component.attribute_get_constant_for_read(domain, type, default_value);
67   }
68
69   if (found_socket->type == SOCK_STRING) {
70     const std::string name = this->get_input<std::string>(found_socket->identifier);
71     /* Try getting the attribute without the default value. */
72     ReadAttributePtr attribute = component.attribute_try_get_for_read(name, domain, type);
73     if (attribute) {
74       return attribute;
75     }
76
77     /* If the attribute doesn't exist, use the default value and output an error message
78      * (except when the field is empty, to avoid spamming error messages, and not when
79      * the domain is empty and we don't expect an attribute anyway). */
80     if (!name.empty() && component.attribute_domain_size(domain) != 0) {
81       this->error_message_add(NodeWarningType::Error,
82                               std::string("No attribute with name '") + name + "'.");
83     }
84     return component.attribute_get_constant_for_read(domain, type, default_value);
85   }
86   if (found_socket->type == SOCK_FLOAT) {
87     const float value = this->get_input<float>(found_socket->identifier);
88     return component.attribute_get_constant_for_read_converted(
89         domain, CD_PROP_FLOAT, type, &value);
90   }
91   if (found_socket->type == SOCK_VECTOR) {
92     const float3 value = this->get_input<float3>(found_socket->identifier);
93     return component.attribute_get_constant_for_read_converted(
94         domain, CD_PROP_FLOAT3, type, &value);
95   }
96   if (found_socket->type == SOCK_RGBA) {
97     const Color4f value = this->get_input<Color4f>(found_socket->identifier);
98     return component.attribute_get_constant_for_read_converted(
99         domain, CD_PROP_COLOR, type, &value);
100   }
101   BLI_assert(false);
102   return component.attribute_get_constant_for_read(domain, type, default_value);
103 }
104
105 CustomDataType GeoNodeExecParams::get_input_attribute_data_type(
106     const StringRef name,
107     const GeometryComponent &component,
108     const CustomDataType default_type) const
109 {
110   const bNodeSocket *found_socket = this->find_available_socket(name);
111   BLI_assert(found_socket != nullptr); /* There should always be available socket for the name. */
112   if (found_socket == nullptr) {
113     return default_type;
114   }
115
116   if (found_socket->type == SOCK_STRING) {
117     const std::string name = this->get_input<std::string>(found_socket->identifier);
118     ReadAttributePtr attribute = component.attribute_try_get_for_read(name);
119     if (!attribute) {
120       return default_type;
121     }
122     return attribute->custom_data_type();
123   }
124   if (found_socket->type == SOCK_FLOAT) {
125     return CD_PROP_FLOAT;
126   }
127   if (found_socket->type == SOCK_VECTOR) {
128     return CD_PROP_FLOAT3;
129   }
130   if (found_socket->type == SOCK_RGBA) {
131     return CD_PROP_COLOR;
132   }
133   if (found_socket->type == SOCK_BOOLEAN) {
134     return CD_PROP_BOOL;
135   }
136
137   BLI_assert(false);
138   return default_type;
139 }
140
141 /**
142  * If any of the corresponding input sockets are attributes instead of single values,
143  * use the highest priority attribute domain from among them.
144  * Otherwise return the default domain.
145  */
146 AttributeDomain GeoNodeExecParams::get_highest_priority_input_domain(
147     Span<std::string> names,
148     const GeometryComponent &component,
149     const AttributeDomain default_domain) const
150 {
151   Vector<AttributeDomain, 8> input_domains;
152   for (const std::string &name : names) {
153     const bNodeSocket *found_socket = this->find_available_socket(name);
154     BLI_assert(found_socket != nullptr); /* A socket should be available socket for the name. */
155     if (found_socket == nullptr) {
156       continue;
157     }
158
159     if (found_socket->type == SOCK_STRING) {
160       const std::string name = this->get_input<std::string>(found_socket->identifier);
161       ReadAttributePtr attribute = component.attribute_try_get_for_read(name);
162       if (attribute) {
163         input_domains.append(attribute->domain());
164       }
165     }
166   }
167
168   if (input_domains.size() > 0) {
169     return bke::attribute_domain_highest_priority(input_domains);
170   }
171
172   return default_domain;
173 }
174
175 void GeoNodeExecParams::check_extract_input(StringRef identifier,
176                                             const CPPType *requested_type) const
177 {
178   bNodeSocket *found_socket = nullptr;
179   for (const DSocket *socket : node_.inputs()) {
180     if (socket->identifier() == identifier) {
181       found_socket = socket->bsocket();
182       break;
183     }
184   }
185
186   if (found_socket == nullptr) {
187     std::cout << "Did not find an input socket with the identifier '" << identifier << "'.\n";
188     std::cout << "Possible identifiers are: ";
189     for (const DSocket *socket : node_.inputs()) {
190       if (socket->is_available()) {
191         std::cout << "'" << socket->identifier() << "', ";
192       }
193     }
194     std::cout << "\n";
195     BLI_assert(false);
196   }
197   else if (found_socket->flag & SOCK_UNAVAIL) {
198     std::cout << "The socket corresponding to the identifier '" << identifier
199               << "' is disabled.\n";
200     BLI_assert(false);
201   }
202   else if (!input_values_.contains(identifier)) {
203     std::cout << "The identifier '" << identifier
204               << "' is valid, but there is no value for it anymore.\n";
205     std::cout << "Most likely it has been extracted before.\n";
206     BLI_assert(false);
207   }
208   else if (requested_type != nullptr) {
209     const CPPType &expected_type = *socket_cpp_type_get(*found_socket->typeinfo);
210     if (*requested_type != expected_type) {
211       std::cout << "The requested type '" << requested_type->name() << "' is incorrect. Expected '"
212                 << expected_type.name() << "'.\n";
213       BLI_assert(false);
214     }
215   }
216 }
217
218 void GeoNodeExecParams::check_set_output(StringRef identifier, const CPPType &value_type) const
219 {
220   bNodeSocket *found_socket = nullptr;
221   for (const DSocket *socket : node_.outputs()) {
222     if (socket->identifier() == identifier) {
223       found_socket = socket->bsocket();
224       break;
225     }
226   }
227
228   if (found_socket == nullptr) {
229     std::cout << "Did not find an output socket with the identifier '" << identifier << "'.\n";
230     std::cout << "Possible identifiers are: ";
231     for (const DSocket *socket : node_.outputs()) {
232       if (socket->is_available()) {
233         std::cout << "'" << socket->identifier() << "', ";
234       }
235     }
236     std::cout << "\n";
237     BLI_assert(false);
238   }
239   else if (found_socket->flag & SOCK_UNAVAIL) {
240     std::cout << "The socket corresponding to the identifier '" << identifier
241               << "' is disabled.\n";
242     BLI_assert(false);
243   }
244   else if (output_values_.contains(identifier)) {
245     std::cout << "The identifier '" << identifier << "' has been set already.\n";
246     BLI_assert(false);
247   }
248   else {
249     const CPPType &expected_type = *socket_cpp_type_get(*found_socket->typeinfo);
250     if (value_type != expected_type) {
251       std::cout << "The value type '" << value_type.name() << "' is incorrect. Expected '"
252                 << expected_type.name() << "'.\n";
253       BLI_assert(false);
254     }
255   }
256 }
257
258 }  // namespace blender::nodes