Blender V4.5
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_node.hh"
13#include "BKE_volume_grid.hh"
16
17#include "BLI_color.hh"
20
21#include "FN_field.hh"
22
23namespace blender::bke {
24
25template<typename T, typename U>
27 U,
29#ifdef WITH_OPENVDB
30 ,
32#endif
33 >;
34
38template<typename T> static std::optional<eNodeSocketDatatype> static_type_to_socket_type()
39{
41 return SOCK_INT;
42 }
44 return SOCK_FLOAT;
45 }
47 return SOCK_BOOLEAN;
48 }
50 return SOCK_VECTOR;
51 }
53 return SOCK_RGBA;
54 }
56 return SOCK_ROTATION;
57 }
59 return SOCK_MATRIX;
60 }
61 if constexpr (is_same_any_v<T, std::string>) {
62 return SOCK_STRING;
63 }
65 return SOCK_BUNDLE;
66 }
68 return SOCK_CLOSURE;
69 }
70 return std::nullopt;
71}
72
76template<typename T>
78{
79 switch (socket_type) {
80 case SOCK_INT:
81 return std::is_same_v<T, int>;
82 case SOCK_FLOAT:
83 return std::is_same_v<T, float>;
84 case SOCK_BOOLEAN:
85 return std::is_same_v<T, bool>;
86 case SOCK_VECTOR:
87 return std::is_same_v<T, float3>;
88 case SOCK_RGBA:
89 return std::is_same_v<T, ColorGeometry4f>;
90 case SOCK_ROTATION:
91 return std::is_same_v<T, math::Quaternion>;
92 case SOCK_MATRIX:
93 return std::is_same_v<T, float4x4>;
94 case SOCK_STRING:
95 return std::is_same_v<T, std::string>;
96 case SOCK_MENU:
97 return std::is_same_v<T, int>;
98 case SOCK_BUNDLE:
99 return std::is_same_v<T, nodes::BundlePtr>;
100 case SOCK_CLOSURE:
101 return std::is_same_v<T, nodes::ClosurePtr>;
102 case SOCK_CUSTOM:
103 case SOCK_SHADER:
104 case SOCK_OBJECT:
105 case SOCK_IMAGE:
106 case SOCK_GEOMETRY:
107 case SOCK_COLLECTION:
108 case SOCK_TEXTURE:
109 case SOCK_MATERIAL:
110 return false;
111 }
113 return false;
114}
115
116template<typename T> T SocketValueVariant::extract()
117{
118 if constexpr (std::is_same_v<T, fn::GField>) {
119 switch (kind_) {
120 case Kind::Field: {
121 return std::move(value_.get<fn::GField>());
122 }
123 case Kind::Single: {
124 const GPointer single_value = this->get_single_ptr();
125 return fn::make_constant_field(*single_value.type(), single_value.get());
126 }
127 case Kind::Grid: {
128 const CPPType *cpp_type = socket_type_to_geo_nodes_base_cpp_type(socket_type_);
129 BLI_assert(cpp_type);
130 return fn::make_constant_field(*cpp_type, cpp_type->default_value());
131 }
132 case Kind::None: {
134 break;
135 }
136 }
137 }
138 else if constexpr (fn::is_field_v<T>) {
140 return T(this->extract<fn::GField>());
141 }
142#ifdef WITH_OPENVDB
143 else if constexpr (std::is_same_v<T, GVolumeGrid>) {
144 switch (kind_) {
145 case Kind::Grid: {
146 BLI_assert(value_);
147 return std::move(value_.get<GVolumeGrid>());
148 }
149 case Kind::Single:
150 case Kind::Field: {
151 const std::optional<VolumeGridType> grid_type = socket_type_to_grid_type(socket_type_);
152 BLI_assert(grid_type);
153 return GVolumeGrid(*grid_type);
154 }
155 case Kind::None: {
157 break;
158 }
159 }
160 }
161 else if constexpr (is_VolumeGrid_v<T>) {
163 return this->extract<GVolumeGrid>().typed<typename T::base_type>();
164 }
165#endif
166 else {
168 if (kind_ == Kind::Single) {
169 return std::move(value_.get<T>());
170 }
171 if (kind_ == Kind::Field) {
172 T ret_value;
173 std::destroy_at(&ret_value);
174 fn::evaluate_constant_field(value_.get<fn::GField>(), &ret_value);
175 return ret_value;
176 }
177 }
179 return T();
180}
181
182template<typename T> T SocketValueVariant::get() const
183{
184 /* Simple implementation in terms of #extract for now. This could potentially use a specialized
185 * implementation at some point, but for now it's unlikely to be a bottleneck. */
186 SocketValueVariant copied_variant = *this;
187 return copied_variant.extract<T>();
188}
189
190template<typename T> void SocketValueVariant::store_impl(T value)
191{
192 if constexpr (std::is_same_v<T, fn::GField>) {
193 const std::optional<eNodeSocketDatatype> new_socket_type =
195 BLI_assert(new_socket_type);
196 socket_type_ = *new_socket_type;
197 kind_ = Kind::Field;
198 value_.emplace<fn::GField>(std::move(value));
199 }
200 else if constexpr (fn::is_field_v<T>) {
201 /* Always store #Field<T> as #GField. */
202 this->store_impl<fn::GField>(std::move(value));
203 }
204#ifdef WITH_OPENVDB
205 else if constexpr (std::is_same_v<T, GVolumeGrid>) {
206 BLI_assert(value);
207 const VolumeGridType volume_grid_type = value->grid_type();
208 const std::optional<eNodeSocketDatatype> new_socket_type = grid_type_to_socket_type(
209 volume_grid_type);
210 BLI_assert(new_socket_type);
211 socket_type_ = *new_socket_type;
212 kind_ = Kind::Grid;
213 value_.emplace<GVolumeGrid>(std::move(value));
214 }
215 else if constexpr (is_VolumeGrid_v<T>) {
216 BLI_assert(value);
217 this->store_impl<GVolumeGrid>(std::move(value));
218 }
219#endif
220 else {
221 const std::optional<eNodeSocketDatatype> new_socket_type = static_type_to_socket_type<T>();
222 BLI_assert(new_socket_type);
223 socket_type_ = *new_socket_type;
224 kind_ = Kind::Single;
225 value_.emplace<T>(std::move(value));
226 }
227}
228
229void SocketValueVariant::store_single(const eNodeSocketDatatype socket_type, const void *value)
230{
231 kind_ = Kind::Single;
232 socket_type_ = socket_type;
233 switch (socket_type) {
234 case SOCK_FLOAT: {
235 value_.emplace<float>(*static_cast<const float *>(value));
236 break;
237 }
238 case SOCK_INT: {
239 value_.emplace<int>(*static_cast<const int *>(value));
240 break;
241 }
242 case SOCK_VECTOR: {
243 value_.emplace<float3>(*static_cast<const float3 *>(value));
244 break;
245 }
246 case SOCK_BOOLEAN: {
247 value_.emplace<bool>(*static_cast<const bool *>(value));
248 break;
249 }
250 case SOCK_ROTATION: {
251 value_.emplace<math::Quaternion>(*static_cast<const math::Quaternion *>(value));
252 break;
253 }
254 case SOCK_MATRIX: {
255 value_.emplace<float4x4>(*static_cast<const float4x4 *>(value));
256 break;
257 }
258 case SOCK_RGBA: {
259 value_.emplace<ColorGeometry4f>(*static_cast<const ColorGeometry4f *>(value));
260 break;
261 }
262 case SOCK_STRING: {
263 value_.emplace<std::string>(*static_cast<const std::string *>(value));
264 break;
265 }
266 case SOCK_BUNDLE: {
267 value_.emplace<nodes::BundlePtr>(*static_cast<const nodes::BundlePtr *>(value));
268 break;
269 }
270 case SOCK_CLOSURE: {
271 value_.emplace<nodes::ClosurePtr>(*static_cast<const nodes::ClosurePtr *>(value));
272 break;
273 }
274 default: {
276 break;
277 }
278 }
279}
280
282{
283 if (!value_.is<fn::GField>()) {
284 return false;
285 }
286 const fn::GField &field = value_.get<fn::GField>();
287 if (!field) {
288 return false;
289 }
290 return field.node().depends_on_input();
291}
292
294{
295 return kind_ == Kind::Grid;
296}
297
299{
300 return kind_ == Kind::Single;
301}
302
303void SocketValueVariant::convert_to_single()
304{
305 switch (kind_) {
306 case Kind::Single: {
307 /* Nothing to do. */
308 break;
309 }
310 case Kind::Field: {
311 /* Evaluates the field without inputs to try to get a single value. If the field depends on
312 * context, the default value is used instead. */
313 fn::GField field = std::move(value_.get<fn::GField>());
314 void *buffer = this->allocate_single(socket_type_);
315 fn::evaluate_constant_field(field, buffer);
316 break;
317 }
318 case Kind::Grid: {
319 /* Can't convert a grid to a single value, so just use the default value of the current
320 * socket type. */
321 const CPPType &cpp_type = *socket_type_to_geo_nodes_base_cpp_type(socket_type_);
322 this->store_single(socket_type_, cpp_type.default_value());
323 break;
324 }
325 case Kind::None: {
327 break;
328 }
329 }
330}
331
333{
334 BLI_assert(kind_ == Kind::Single);
335 const CPPType *type = socket_type_to_geo_nodes_base_cpp_type(socket_type_);
336 BLI_assert(type != nullptr);
337 const void *data = value_.get();
338 return GPointer(*type, data);
339}
340
342{
343 const GPointer ptr = const_cast<const SocketValueVariant *>(this)->get_single_ptr();
344 return GMutablePointer(ptr.type(), const_cast<void *>(ptr.get()));
345}
346
348{
349 kind_ = Kind::Single;
350 socket_type_ = socket_type;
351 switch (socket_type) {
352 case SOCK_FLOAT:
353 return value_.allocate<float>();
354 case SOCK_INT:
355 return value_.allocate<int>();
356 case SOCK_VECTOR:
357 return value_.allocate<float3>();
358 case SOCK_BOOLEAN:
359 return value_.allocate<bool>();
360 case SOCK_ROTATION:
361 return value_.allocate<math::Quaternion>();
362 case SOCK_MATRIX:
363 return value_.allocate<float4x4>();
364 case SOCK_RGBA:
365 return value_.allocate<ColorGeometry4f>();
366 case SOCK_STRING:
367 return value_.allocate<std::string>();
368 case SOCK_MENU:
369 return value_.allocate<int>();
370 case SOCK_BUNDLE:
371 return value_.allocate<nodes::BundlePtr>();
372 case SOCK_CLOSURE:
373 return value_.allocate<nodes::ClosurePtr>();
374 default: {
376 return nullptr;
377 }
378 }
379}
380
381std::ostream &operator<<(std::ostream &stream, const SocketValueVariant &value_variant)
382{
383 SocketValueVariant variant_copy = value_variant;
384 variant_copy.convert_to_single();
385 if (value_variant.kind_ == SocketValueVariant::Kind::Single) {
386 const GPointer value = variant_copy.get_single_ptr();
387 const CPPType &cpp_type = *value.type();
388 if (cpp_type.is_printable()) {
389 std::stringstream ss;
390 cpp_type.print(value.get(), ss);
391 stream << ss.str();
392 return stream;
393 }
394 }
395 stream << "SocketValueVariant";
396 return stream;
397}
398
400{
401 if (kind_ == Kind::None) {
402 return false;
403 }
404 return socket_type_ == socket_type;
405}
406
407#define INSTANTIATE(TYPE) \
408 template TYPE SocketValueVariant::extract(); \
409 template TYPE SocketValueVariant::get() const; \
410 template void SocketValueVariant::store_impl(TYPE);
411
412#ifdef WITH_OPENVDB
413# define INSTANTIATE_SINGLE_AND_FIELD_AND_GRID(TYPE) \
414 INSTANTIATE(TYPE) \
415 INSTANTIATE(fn::Field<TYPE>) \
416 INSTANTIATE(VolumeGrid<TYPE>)
417#else
418# define INSTANTIATE_SINGLE_AND_FIELD_AND_GRID(TYPE) \
419 INSTANTIATE(TYPE) \
420 INSTANTIATE(fn::Field<TYPE>)
421#endif
422
429
430INSTANTIATE(std::string)
431INSTANTIATE(fn::GField)
434
436INSTANTIATE(fn::Field<float4x4>)
437
438#ifdef WITH_OPENVDB
439INSTANTIATE(GVolumeGrid)
440#endif
441
442} // 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
const void * default_value() const
std::decay_t< T > & emplace(Args &&...args)
Definition BLI_any.hh:258
void * get()
Definition BLI_any.hh:322
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:5452
static constexpr bool is_VolumeGrid_v
std::optional< VolumeGridType > socket_type_to_grid_type(eNodeSocketDatatype type)
Definition node.cc:5487
static constexpr bool is_single_or_field_or_grid_v
std::optional< eNodeSocketDatatype > grid_type_to_socket_type(VolumeGridType type)
Definition node.cc:5503
static std::optional< eNodeSocketDatatype > static_type_to_socket_type()
const CPPType * socket_type_to_geo_nodes_base_cpp_type(eNodeSocketDatatype type)
Definition node.cc:5413
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< Closure > ClosurePtr
constexpr bool is_same_any_v
MatBase< float, 4, 4 > float4x4
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:342
VecBase< float, 3 > float3
#define INSTANTIATE_SINGLE_AND_FIELD_AND_GRID(TYPE)
#define INSTANTIATE(TYPE)
PointerRNA * ptr
Definition wm_files.cc:4227