Blender V4.5
node_geometry_exec.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <iostream>
6
7#include "DNA_curves_types.h"
9#include "DNA_mesh_types.h"
11
13
14#include "BKE_curves.hh"
15#include "BKE_library.hh"
16#include "BKE_main.hh"
17#include "BKE_node_runtime.hh"
18
19#include "BLI_path_utils.hh"
20#include "BLI_string.h"
21
22#include "BLT_translation.hh"
23
24#include "NOD_geometry_exec.hh"
25
26#include "node_geometry_util.hh"
27
28namespace blender::nodes {
29
31{
32 return DEG_get_bmain(this->depsgraph());
33}
34
36 const StringRef message) const
37{
38 if (geo_eval_log::GeoTreeLogger *tree_logger = this->get_local_tree_logger()) {
39 tree_logger->node_warnings.append(
40 *tree_logger->allocator,
41 {node_.identifier, {type, tree_logger->allocator->copy_string(message)}});
42 }
43}
44
46 const NamedAttributeUsage usage)
47{
48 if (geo_eval_log::GeoTreeLogger *tree_logger = this->get_local_tree_logger()) {
49 tree_logger->used_named_attributes.append(
50 *tree_logger->allocator,
51 {node_.identifier, tree_logger->allocator->copy_string(attribute_name), usage});
52 }
53}
54
56 const GeometrySet &geometry_set) const
57{
58 const SocketDeclaration &decl = *node_.input_by_identifier(identifier).runtime->declaration;
59 const decl::Geometry *geo_decl = dynamic_cast<const decl::Geometry *>(&decl);
60 if (geo_decl == nullptr) {
61 return;
62 }
63
64 const bool only_realized_data = geo_decl->only_realized_data();
65 const bool only_instances = geo_decl->only_instances();
66 const Span<GeometryComponent::Type> supported_types = geo_decl->supported_types();
67
68 if (only_realized_data) {
69 if (geometry_set.has_instances()) {
71 TIP_("Instances in input geometry are ignored"));
72 }
73 }
74 if (only_instances) {
75 if (geometry_set.has_realized_data()) {
77 TIP_("Realized data in input geometry is ignored"));
78 }
79 }
80 if (supported_types.is_empty()) {
81 /* Assume all types are supported. */
82 return;
83 }
84 const Vector<GeometryComponent::Type> types_in_geometry = geometry_set.gather_component_types(
85 true, true);
86 for (const GeometryComponent::Type type : types_in_geometry) {
87 if (type == GeometryComponent::Type::Instance) {
88 continue;
89 }
90 if (supported_types.contains(type)) {
91 continue;
92 }
93 std::string message = RPT_("Input geometry has unsupported type: ");
94 switch (type) {
95 case GeometryComponent::Type::Mesh: {
96 if (const Mesh *mesh = geometry_set.get_mesh()) {
97 if (mesh->verts_num == 0) {
98 continue;
99 }
100 }
101 message += RPT_("Mesh");
102 break;
103 }
104 case GeometryComponent::Type::PointCloud: {
105 if (const PointCloud *pointcloud = geometry_set.get_pointcloud()) {
106 if (pointcloud->totpoint == 0) {
107 continue;
108 }
109 }
110 message += RPT_("Point Cloud");
111 break;
112 }
113 case GeometryComponent::Type::Instance: {
115 break;
116 }
117 case GeometryComponent::Type::Volume: {
118 message += CTX_RPT_(BLT_I18NCONTEXT_ID_ID, "Volume");
119 break;
120 }
121 case GeometryComponent::Type::Curve: {
122 if (const Curves *curves = geometry_set.get_curves()) {
123 if (curves->geometry.point_num == 0) {
124 continue;
125 }
126 }
127 message += RPT_("Curve");
128 break;
129 }
130 case GeometryComponent::Type::Edit: {
131 continue;
132 }
133 case GeometryComponent::Type::GreasePencil: {
134 if (const GreasePencil *grease_pencil = geometry_set.get_grease_pencil()) {
135 if (grease_pencil->drawing_array_num == 0) {
136 continue;
137 }
138 }
139 message += RPT_("Grease Pencil");
140 break;
141 }
142 }
143 this->error_message_add(NodeWarningType::Info, std::move(message));
144 }
145}
146
148{
149 UNUSED_VARS_NDEBUG(geometry_set);
150#ifndef NDEBUG
151 if (const bke::CurvesEditHints *curve_edit_hints = geometry_set.get_curve_edit_hints()) {
152 /* If this is not valid, it's likely that the number of stored deformed points does not match
153 * the number of points in the original data. */
154 BLI_assert(curve_edit_hints->is_valid());
155 }
156#endif
157}
158
159const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const
160{
161 for (const bNodeSocket *socket : node_.input_sockets()) {
162 if (socket->is_available() && socket->name == name) {
163 return socket;
164 }
165 }
166
167 return nullptr;
168}
169
174
175void GeoNodeExecParams::check_input_access(StringRef identifier,
176 const CPPType *requested_type) const
177{
178 const bNodeSocket *found_socket = nullptr;
179 for (const bNodeSocket *socket : node_.input_sockets()) {
180 if (socket->identifier == identifier) {
181 found_socket = socket;
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 bNodeSocket *socket : node_.input_sockets()) {
190 if (socket->is_available()) {
191 std::cout << "'" << socket->identifier << "', ";
192 }
193 }
194 std::cout << "\n";
196 }
197 else if (found_socket->flag & SOCK_UNAVAIL) {
198 std::cout << "The socket corresponding to the identifier '" << identifier
199 << "' is disabled.\n";
201 }
202 else if (requested_type != nullptr && (found_socket->flag & SOCK_MULTI_INPUT) == 0) {
203 const CPPType &expected_type = *found_socket->typeinfo->geometry_nodes_cpp_type;
204 if (*requested_type != expected_type) {
205 std::cout << "The requested type '" << requested_type->name() << "' is incorrect. Expected '"
206 << expected_type.name() << "'.\n";
208 }
209 }
210}
211
212void GeoNodeExecParams::check_output_access(StringRef identifier, const CPPType &value_type) const
213{
214 const bNodeSocket *found_socket = nullptr;
215 for (const bNodeSocket *socket : node_.output_sockets()) {
216 if (socket->identifier == identifier) {
217 found_socket = socket;
218 break;
219 }
220 }
221
222 if (found_socket == nullptr) {
223 std::cout << "Did not find an output socket with the identifier '" << identifier << "'.\n";
224 std::cout << "Possible identifiers are: ";
225 for (const bNodeSocket *socket : node_.output_sockets()) {
226 if (socket->is_available()) {
227 std::cout << "'" << socket->identifier << "', ";
228 }
229 }
230 std::cout << "\n";
232 }
233 else if (found_socket->flag & SOCK_UNAVAIL) {
234 std::cout << "The socket corresponding to the identifier '" << identifier
235 << "' is disabled.\n";
237 }
238 else if (params_.output_was_set(this->get_output_index(identifier))) {
239 std::cout << "The identifier '" << identifier << "' has been set already.\n";
241 }
242 else {
243 const CPPType &expected_type = *found_socket->typeinfo->geometry_nodes_cpp_type;
244 if (value_type != expected_type) {
245 std::cout << "The value type '" << value_type.name() << "' is incorrect. Expected '"
246 << expected_type.name() << "'.\n";
248 }
249 }
250}
251
253{
254 if (!bke::attribute_name_is_anonymous(attribute_name)) {
255 return AttributeFilter::Result::Process;
256 }
257 if (!set_.names) {
258 return AttributeFilter::Result::AllowSkip;
259 }
260 if (set_.names->contains(attribute_name)) {
261 return AttributeFilter::Result::Process;
262 }
263 return AttributeFilter::Result::AllowSkip;
264}
265
266std::optional<std::string> GeoNodeExecParams::ensure_absolute_path(const StringRefNull path) const
267{
268 if (path.is_empty()) {
269 return std::nullopt;
270 }
271 if (!BLI_path_is_rel(path.c_str())) {
272 return path;
273 }
274 const Main &bmain = *this->bmain();
275 const bNodeTree &tree = node_.owner_tree();
276 const char *base_path = ID_BLEND_PATH(&bmain, &tree.id);
277 if (!base_path || base_path[0] == '\0') {
278 return std::nullopt;
279 }
280 char absolute_path[FILE_MAX];
281 STRNCPY(absolute_path, path.c_str());
282 BLI_path_abs(absolute_path, base_path);
283 return absolute_path;
284}
285
286} // namespace blender::nodes
Low-level operations for curves.
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
#define FILE_MAX
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
#define UNUSED_VARS_NDEBUG(...)
#define RPT_(msgid)
#define BLT_I18NCONTEXT_ID_ID
#define TIP_(msgid)
#define CTX_RPT_(context, msgid)
Main * DEG_get_bmain(const Depsgraph *graph)
@ SOCK_MULTI_INPUT
@ SOCK_UNAVAIL
struct bNodeSocket bNodeSocket
StringRefNull name() const
StringRefNull name() const
constexpr bool is_empty() const
Definition BLI_span.hh:260
constexpr bool contains(const T &value) const
Definition BLI_span.hh:277
constexpr bool is_empty() const
constexpr const char * c_str() const
geo_eval_log::GeoTreeLogger * get_local_tree_logger() const
void error_message_add(const NodeWarningType type, StringRef message) const
void check_output_geometry_set(const GeometrySet &geometry_set) const
void check_input_geometry_set(StringRef identifier, const GeometrySet &geometry_set) const
std::optional< std::string > ensure_absolute_path(StringRefNull path) const
void used_named_attribute(StringRef attribute_name, NamedAttributeUsage usage)
const Depsgraph * depsgraph() const
Result filter(StringRef attribute_name) const override
Span< bke::GeometryComponent::Type > supported_types() const
KDTree_3d * tree
#define this
#define ID_BLEND_PATH(_bmain, _id)
bool attribute_name_is_anonymous(const StringRef name)
void set_default_remaining_node_outputs(lf::Params &params, const bNode &node)
bNodeSocketTypeHandle * typeinfo
const CurvesEditHints * get_curve_edit_hints() const
const GreasePencil * get_grease_pencil() const
const Curves * get_curves() const
const PointCloud * get_pointcloud() const
const Mesh * get_mesh() const
Vector< GeometryComponent::Type > gather_component_types(bool include_instances, bool ignore_empty) const