Blender V5.0
node_socket_value.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
8
9#include <sstream>
10
11#include "BKE_geometry_set.hh"
12#include "BKE_node.hh"
14#include "BKE_volume_grid.hh"
15
19#include "NOD_menu_value.hh"
20
21#include "BLI_color.hh"
24
25#include "FN_field.hh"
26
27namespace blender::bke {
28
29template<typename T, typename U>
31 U,
33#ifdef WITH_OPENVDB
34 ,
36#endif
37 >;
38
42template<typename T> static std::optional<eNodeSocketDatatype> static_type_to_socket_type()
43{
45 return SOCK_INT;
46 }
48 return SOCK_FLOAT;
49 }
51 return SOCK_BOOLEAN;
52 }
54 return SOCK_VECTOR;
55 }
57 return SOCK_RGBA;
58 }
60 return SOCK_ROTATION;
61 }
63 return SOCK_MENU;
64 }
66 return SOCK_MATRIX;
67 }
68 if constexpr (is_same_any_v<T, std::string>) {
69 return SOCK_STRING;
70 }
72 return SOCK_BUNDLE;
73 }
75 return SOCK_CLOSURE;
76 }
77 if constexpr (is_same_any_v<T, Object *>) {
78 return SOCK_OBJECT;
79 }
80 if constexpr (is_same_any_v<T, Collection *>) {
81 return SOCK_COLLECTION;
82 }
83 if constexpr (is_same_any_v<T, Tex *>) {
84 return SOCK_TEXTURE;
85 }
86 if constexpr (is_same_any_v<T, Image *>) {
87 return SOCK_IMAGE;
88 }
89 if constexpr (is_same_any_v<T, Material *>) {
90 return SOCK_MATERIAL;
91 }
93 return SOCK_GEOMETRY;
94 }
95 return std::nullopt;
96}
97
101template<typename T>
103{
104 switch (socket_type) {
105 case SOCK_INT:
106 return std::is_same_v<T, int>;
107 case SOCK_FLOAT:
108 return std::is_same_v<T, float>;
109 case SOCK_BOOLEAN:
110 return std::is_same_v<T, bool>;
111 case SOCK_VECTOR:
112 return std::is_same_v<T, float3>;
113 case SOCK_RGBA:
114 return std::is_same_v<T, ColorGeometry4f>;
115 case SOCK_ROTATION:
116 return std::is_same_v<T, math::Quaternion>;
117 case SOCK_MATRIX:
118 return std::is_same_v<T, float4x4>;
119 case SOCK_STRING:
120 return std::is_same_v<T, std::string>;
121 case SOCK_MENU:
122 return std::is_same_v<T, nodes::MenuValue>;
123 case SOCK_BUNDLE:
124 return std::is_same_v<T, nodes::BundlePtr>;
125 case SOCK_CLOSURE:
126 return std::is_same_v<T, nodes::ClosurePtr>;
127 case SOCK_OBJECT:
128 return std::is_same_v<T, Object *>;
129 case SOCK_COLLECTION:
130 return std::is_same_v<T, Collection *>;
131 case SOCK_TEXTURE:
132 return std::is_same_v<T, Tex *>;
133 case SOCK_IMAGE:
134 return std::is_same_v<T, Image *>;
135 case SOCK_MATERIAL:
136 return std::is_same_v<T, Material *>;
137 case SOCK_GEOMETRY:
138 return std::is_same_v<T, bke::GeometrySet>;
139 case SOCK_CUSTOM:
140 case SOCK_SHADER:
141 return false;
142 }
144 return false;
145}
146
147template<typename T> T SocketValueVariant::extract()
148{
149 if constexpr (std::is_same_v<T, fn::GField>) {
150 switch (kind_) {
151 case Kind::Field: {
152 return std::move(value_.get<fn::GField>());
153 }
154 case Kind::Single: {
155 const GPointer single_value = this->get_single_ptr();
156 return fn::make_constant_field(*single_value.type(), single_value.get());
157 }
158 case Kind::List:
159 case Kind::Grid: {
160 const CPPType *cpp_type = socket_type_to_geo_nodes_base_cpp_type(socket_type_);
161 BLI_assert(cpp_type);
162 return fn::make_constant_field(*cpp_type, cpp_type->default_value());
163 }
164 case Kind::None: {
166 break;
167 }
168 }
169 }
170 else if constexpr (fn::is_field_v<T>) {
172 return T(this->extract<fn::GField>());
173 }
174 else if constexpr (std::is_same_v<T, nodes::ListPtr>) {
175 if (kind_ != Kind::List) {
176 return {};
177 }
178 return std::move(value_.get<nodes::ListPtr>());
179 }
180#ifdef WITH_OPENVDB
181 else if constexpr (std::is_same_v<T, GVolumeGrid>) {
182 switch (kind_) {
183 case Kind::Grid: {
184 BLI_assert(value_);
185 return std::move(value_.get<GVolumeGrid>());
186 }
187 case Kind::Single:
188 case Kind::List:
189 case Kind::Field: {
190 const std::optional<VolumeGridType> grid_type = socket_type_to_grid_type(socket_type_);
191 BLI_assert(grid_type);
192 return GVolumeGrid(*grid_type);
193 }
194 case Kind::None: {
196 break;
197 }
198 }
199 }
200 else if constexpr (is_VolumeGrid_v<T>) {
202 return this->extract<GVolumeGrid>().typed<typename T::base_type>();
203 }
204#endif
205 else {
207 if (kind_ == Kind::Single) {
208 return std::move(value_.get<T>());
209 }
210 if (kind_ == Kind::Field) {
211 T ret_value;
212 std::destroy_at(&ret_value);
213 fn::evaluate_constant_field(value_.get<fn::GField>(), &ret_value);
214 return ret_value;
215 }
216 if (kind_ == Kind::List) {
217 return {};
218 }
219 }
221 return T();
222}
223
224template<typename T> T SocketValueVariant::get() const
225{
226 /* Simple implementation in terms of #extract for now. This could potentially use a specialized
227 * implementation at some point, but for now it's unlikely to be a bottleneck. */
228 SocketValueVariant copied_variant = *this;
229 return copied_variant.extract<T>();
230}
231
232template<typename T> void SocketValueVariant::store_impl(T value)
233{
234 if constexpr (std::is_same_v<T, fn::GField>) {
235 const std::optional<eNodeSocketDatatype> new_socket_type =
237 BLI_assert(new_socket_type);
238 socket_type_ = *new_socket_type;
239 kind_ = Kind::Field;
240 value_.emplace<fn::GField>(std::move(value));
241 }
242 else if constexpr (fn::is_field_v<T>) {
243 /* Always store #Field<T> as #GField. */
244 this->store_impl<fn::GField>(std::move(value));
245 }
246 else if constexpr (std::is_same_v<T, nodes::ListPtr>) {
247 kind_ = Kind::List;
248 const std::optional<eNodeSocketDatatype> new_socket_type =
250 BLI_assert(new_socket_type);
251 socket_type_ = *new_socket_type;
252 value_.emplace<nodes::ListPtr>(std::move(value));
253 }
254#ifdef WITH_OPENVDB
255 else if constexpr (std::is_same_v<T, GVolumeGrid>) {
256 BLI_assert(value);
257 const VolumeGridType volume_grid_type = value->grid_type();
258 const std::optional<eNodeSocketDatatype> new_socket_type = grid_type_to_socket_type(
259 volume_grid_type);
260 BLI_assert(new_socket_type);
261 socket_type_ = *new_socket_type;
262 kind_ = Kind::Grid;
263 value_.emplace<GVolumeGrid>(std::move(value));
264 }
265 else if constexpr (is_VolumeGrid_v<T>) {
266 BLI_assert(value);
267 this->store_impl<GVolumeGrid>(std::move(value));
268 }
269#endif
270 else {
271 const std::optional<eNodeSocketDatatype> new_socket_type = static_type_to_socket_type<T>();
272 BLI_assert(new_socket_type);
273 socket_type_ = *new_socket_type;
274 kind_ = Kind::Single;
275 value_.emplace<T>(std::move(value));
276 }
277}
278
279void SocketValueVariant::store_single(const eNodeSocketDatatype socket_type, const void *value)
280{
281 kind_ = Kind::Single;
282 socket_type_ = socket_type;
283 switch (socket_type) {
284 case SOCK_FLOAT: {
285 value_.emplace<float>(*static_cast<const float *>(value));
286 break;
287 }
288 case SOCK_INT: {
289 value_.emplace<int>(*static_cast<const int *>(value));
290 break;
291 }
292 case SOCK_VECTOR: {
293 value_.emplace<float3>(*static_cast<const float3 *>(value));
294 break;
295 }
296 case SOCK_BOOLEAN: {
297 value_.emplace<bool>(*static_cast<const bool *>(value));
298 break;
299 }
300 case SOCK_ROTATION: {
301 value_.emplace<math::Quaternion>(*static_cast<const math::Quaternion *>(value));
302 break;
303 }
304 case SOCK_MENU: {
305 value_.emplace<nodes::MenuValue>(*static_cast<const nodes::MenuValue *>(value));
306 break;
307 }
308 case SOCK_MATRIX: {
309 value_.emplace<float4x4>(*static_cast<const float4x4 *>(value));
310 break;
311 }
312 case SOCK_RGBA: {
313 value_.emplace<ColorGeometry4f>(*static_cast<const ColorGeometry4f *>(value));
314 break;
315 }
316 case SOCK_STRING: {
317 value_.emplace<std::string>(*static_cast<const std::string *>(value));
318 break;
319 }
320 case SOCK_BUNDLE: {
321 value_.emplace<nodes::BundlePtr>(*static_cast<const nodes::BundlePtr *>(value));
322 break;
323 }
324 case SOCK_CLOSURE: {
325 value_.emplace<nodes::ClosurePtr>(*static_cast<const nodes::ClosurePtr *>(value));
326 break;
327 }
328 case SOCK_OBJECT: {
329 value_.emplace<Object *>(*static_cast<Object *const *>(value));
330 break;
331 }
332 case SOCK_COLLECTION: {
333 value_.emplace<Collection *>(*static_cast<Collection *const *>(value));
334 break;
335 }
336 case SOCK_TEXTURE: {
337 value_.emplace<Tex *>(*static_cast<Tex *const *>(value));
338 break;
339 }
340 case SOCK_IMAGE: {
341 value_.emplace<Image *>(*static_cast<Image *const *>(value));
342 break;
343 }
344 case SOCK_MATERIAL: {
345 value_.emplace<Material *>(*static_cast<Material *const *>(value));
346 break;
347 }
348 case SOCK_GEOMETRY: {
349 value_.emplace<bke::GeometrySet>(*static_cast<const bke::GeometrySet *>(value));
350 break;
351 }
352 default: {
354 break;
355 }
356 }
357}
358
360{
361 if (!value_.is<fn::GField>()) {
362 return false;
363 }
364 const fn::GField &field = value_.get<fn::GField>();
365 if (!field) {
366 return false;
367 }
368 return field.node().depends_on_input();
369}
370
372{
373 return kind_ == Kind::Grid;
374}
375
377{
378 return kind_ == Kind::Single;
379}
380
382{
383 return kind_ == Kind::List;
384}
385
387{
388 switch (kind_) {
389 case Kind::Single: {
390 /* Nothing to do. */
391 break;
392 }
393 case Kind::Field: {
394 /* Evaluates the field without inputs to try to get a single value. If the field depends on
395 * context, the default value is used instead. */
396 fn::GField field = std::move(value_.get<fn::GField>());
397 void *buffer = this->allocate_single(socket_type_);
398 fn::evaluate_constant_field(field, buffer);
399 break;
400 }
401 case Kind::List:
402 case Kind::Grid: {
403 /* Can't convert a grid to a single value, so just use the default value of the current
404 * socket type. */
405 const CPPType &cpp_type = *socket_type_to_geo_nodes_base_cpp_type(socket_type_);
406 this->store_single(socket_type_, cpp_type.default_value());
407 break;
408 }
409 case Kind::None: {
411 break;
412 }
413 }
414}
415
417{
418 BLI_assert(kind_ == Kind::Single);
419 const CPPType *type = socket_type_to_geo_nodes_base_cpp_type(socket_type_);
420 BLI_assert(type != nullptr);
421 const void *data = value_.get();
422 return GPointer(*type, data);
423}
424
426{
427 const GPointer ptr = const_cast<const SocketValueVariant *>(this)->get_single_ptr();
428 return GMutablePointer(ptr.type(), const_cast<void *>(ptr.get()));
429}
430
432{
433 kind_ = Kind::Single;
434 socket_type_ = socket_type;
435 switch (socket_type) {
436 case SOCK_FLOAT:
437 return value_.allocate<float>();
438 case SOCK_INT:
439 return value_.allocate<int>();
440 case SOCK_VECTOR:
441 return value_.allocate<float3>();
442 case SOCK_BOOLEAN:
443 return value_.allocate<bool>();
444 case SOCK_ROTATION:
445 return value_.allocate<math::Quaternion>();
446 case SOCK_MATRIX:
447 return value_.allocate<float4x4>();
448 case SOCK_RGBA:
449 return value_.allocate<ColorGeometry4f>();
450 case SOCK_STRING:
451 return value_.allocate<std::string>();
452 case SOCK_MENU:
453 return value_.allocate<nodes::MenuValue>();
454 case SOCK_BUNDLE:
455 return value_.allocate<nodes::BundlePtr>();
456 case SOCK_CLOSURE:
457 return value_.allocate<nodes::ClosurePtr>();
458 case SOCK_OBJECT:
459 return value_.allocate<Object *>();
460 case SOCK_COLLECTION:
461 return value_.allocate<Collection *>();
462 case SOCK_TEXTURE:
463 return value_.allocate<Tex *>();
464 case SOCK_IMAGE:
465 return value_.allocate<Image *>();
466 case SOCK_MATERIAL:
467 return value_.allocate<Material *>();
468 default: {
470 return nullptr;
471 }
472 }
473}
474
475std::ostream &operator<<(std::ostream &stream, const SocketValueVariant &value_variant)
476{
477 SocketValueVariant variant_copy = value_variant;
478 variant_copy.convert_to_single();
479 if (value_variant.kind_ == SocketValueVariant::Kind::Single) {
480 const GPointer value = variant_copy.get_single_ptr();
481 const CPPType &cpp_type = *value.type();
482 if (cpp_type.is_printable()) {
483 std::stringstream ss;
484 cpp_type.print(value.get(), ss);
485 stream << ss.str();
486 return stream;
487 }
488 }
489 stream << "SocketValueVariant";
490 return stream;
491}
492
494{
495 if (kind_ == Kind::None) {
496 return false;
497 }
498 return socket_type_ == socket_type;
499}
500
501#define INSTANTIATE(TYPE) \
502 template TYPE SocketValueVariant::extract(); \
503 template TYPE SocketValueVariant::get() const; \
504 template void SocketValueVariant::store_impl(TYPE);
505
506#ifdef WITH_OPENVDB
507# define INSTANTIATE_SINGLE_AND_FIELD_AND_GRID(TYPE) \
508 INSTANTIATE(TYPE) \
509 INSTANTIATE(fn::Field<TYPE>) \
510 INSTANTIATE(VolumeGrid<TYPE>)
511#else
512# define INSTANTIATE_SINGLE_AND_FIELD_AND_GRID(TYPE) \
513 INSTANTIATE(TYPE) \
514 INSTANTIATE(fn::Field<TYPE>)
515#endif
516
523
524INSTANTIATE(std::string)
525INSTANTIATE(fn::GField)
530
536
538INSTANTIATE(fn::Field<float4x4>)
539
540INSTANTIATE(nodes::MenuValue)
541INSTANTIATE(fn::Field<nodes::MenuValue>)
542
543#ifdef WITH_OPENVDB
544INSTANTIATE(GVolumeGrid)
545#endif
546
547} // namespace blender::bke
VolumeGridType
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
eNodeSocketDatatype
@ SOCK_INT
@ SOCK_TEXTURE
@ SOCK_VECTOR
@ SOCK_CLOSURE
@ SOCK_BOOLEAN
@ SOCK_MATERIAL
@ SOCK_SHADER
@ SOCK_MATRIX
@ SOCK_FLOAT
@ SOCK_IMAGE
@ SOCK_COLLECTION
@ SOCK_CUSTOM
@ SOCK_BUNDLE
@ SOCK_GEOMETRY
@ SOCK_ROTATION
@ SOCK_OBJECT
@ SOCK_STRING
@ SOCK_RGBA
@ SOCK_MENU
#define U
BMesh const char void * data
std::decay_t< T > & emplace(Args &&...args)
Definition BLI_any.hh:258
bool is_printable() const
const void * default_value() const
void print(const void *value, std::stringstream &ss) const
const CPPType * type() const
const void * get() const
bool valid_for_socket(eNodeSocketDatatype socket_type) const
void store_single(eNodeSocketDatatype socket_type, const void *value)
void * allocate_single(eNodeSocketDatatype socket_type)
bool depends_on_input() const
Definition FN_field.hh:554
const FieldNode & node() const
Definition FN_field.hh:135
MatBase< 4, 4 > float4x4
#define T
std::optional< eNodeSocketDatatype > geo_nodes_base_cpp_type_to_socket_type(const CPPType &type)
Definition node.cc:5241
static constexpr bool is_VolumeGrid_v
std::optional< VolumeGridType > socket_type_to_grid_type(eNodeSocketDatatype type)
Definition node.cc:5298
static constexpr bool is_single_or_field_or_grid_v
std::optional< eNodeSocketDatatype > grid_type_to_socket_type(VolumeGridType type)
Definition node.cc:5314
static std::optional< eNodeSocketDatatype > static_type_to_socket_type()
const CPPType * socket_type_to_geo_nodes_base_cpp_type(eNodeSocketDatatype type)
Definition node.cc:5202
static bool static_type_is_base_socket_type(const eNodeSocketDatatype socket_type)
std::ostream & operator<<(std::ostream &stream, const GeometrySet &geometry_set)
GField make_constant_field(const CPPType &type, const void *value)
Definition field.cc:528
void evaluate_constant_field(const GField &field, void *r_value)
Definition field.cc:493
static constexpr bool is_field_v
Definition FN_field.hh:215
QuaternionBase< float > Quaternion
ImplicitSharingPtr< Bundle > BundlePtr
ImplicitSharingPtr< List > ListPtr
ImplicitSharingPtr< Closure > ClosurePtr
constexpr bool is_same_any_v
MatBase< float, 4, 4 > float4x4
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
VecBase< float, 3 > float3
#define INSTANTIATE_SINGLE_AND_FIELD_AND_GRID(TYPE)
#define INSTANTIATE(TYPE)
PointerRNA * ptr
Definition wm_files.cc:4238