Blender V4.3
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
9#include <sstream>
10
11#include "BKE_customdata.hh"
12#include "BKE_node.hh"
14#include "BKE_volume_grid.hh"
15
16#include "BLI_color.hh"
19
20#include "FN_field.hh"
21
22namespace blender::bke {
23
24template<typename T, typename U>
26 U,
28#ifdef WITH_OPENVDB
29 ,
31#endif
32 >;
33
37template<typename T> static std::optional<eNodeSocketDatatype> static_type_to_socket_type()
38{
40 return SOCK_INT;
41 }
43 return SOCK_FLOAT;
44 }
46 return SOCK_BOOLEAN;
47 }
49 return SOCK_VECTOR;
50 }
52 return SOCK_RGBA;
53 }
55 return SOCK_ROTATION;
56 }
58 return SOCK_MATRIX;
59 }
60 if constexpr (is_same_any_v<T, std::string>) {
61 return SOCK_STRING;
62 }
63 return std::nullopt;
64}
65
69template<typename T>
71{
72 switch (socket_type) {
73 case SOCK_INT:
74 return std::is_same_v<T, int>;
75 case SOCK_FLOAT:
76 return std::is_same_v<T, float>;
77 case SOCK_BOOLEAN:
78 return std::is_same_v<T, bool>;
79 case SOCK_VECTOR:
80 return std::is_same_v<T, float3>;
81 case SOCK_RGBA:
82 return std::is_same_v<T, ColorGeometry4f>;
83 case SOCK_ROTATION:
84 return std::is_same_v<T, math::Quaternion>;
85 case SOCK_MATRIX:
86 return std::is_same_v<T, float4x4>;
87 case SOCK_STRING:
88 return std::is_same_v<T, std::string>;
89 case SOCK_MENU:
90 return std::is_same_v<T, int>;
91 case SOCK_CUSTOM:
92 case SOCK_SHADER:
93 case SOCK_OBJECT:
94 case SOCK_IMAGE:
95 case SOCK_GEOMETRY:
96 case SOCK_COLLECTION:
97 case SOCK_TEXTURE:
98 case SOCK_MATERIAL:
99 return false;
100 }
102 return false;
103}
104
105template<typename T> T SocketValueVariant::extract()
106{
107 if constexpr (std::is_same_v<T, fn::GField>) {
108 switch (kind_) {
109 case Kind::Field: {
110 return std::move(value_.get<fn::GField>());
111 }
112 case Kind::Single: {
113 const GPointer single_value = this->get_single_ptr();
114 return fn::make_constant_field(*single_value.type(), single_value.get());
115 }
116 case Kind::Grid: {
117 const CPPType *cpp_type = socket_type_to_geo_nodes_base_cpp_type(socket_type_);
118 BLI_assert(cpp_type);
119 return fn::make_constant_field(*cpp_type, cpp_type->default_value());
120 }
121 case Kind::None: {
123 break;
124 }
125 }
126 }
127 else if constexpr (fn::is_field_v<T>) {
129 return T(this->extract<fn::GField>());
130 }
131#ifdef WITH_OPENVDB
132 else if constexpr (std::is_same_v<T, GVolumeGrid>) {
133 switch (kind_) {
134 case Kind::Grid: {
135 BLI_assert(value_);
136 return std::move(value_.get<GVolumeGrid>());
137 }
138 case Kind::Single:
139 case Kind::Field: {
140 const std::optional<VolumeGridType> grid_type = socket_type_to_grid_type(socket_type_);
141 BLI_assert(grid_type);
142 return GVolumeGrid(*grid_type);
143 }
144 case Kind::None: {
146 break;
147 }
148 }
149 }
150 else if constexpr (is_VolumeGrid_v<T>) {
152 return this->extract<GVolumeGrid>().typed<typename T::base_type>();
153 }
154#endif
155 else {
157 if (kind_ == Kind::Single) {
158 return std::move(value_.get<T>());
159 }
160 if (kind_ == Kind::Field) {
161 T ret_value;
162 std::destroy_at(&ret_value);
163 fn::evaluate_constant_field(value_.get<fn::GField>(), &ret_value);
164 return ret_value;
165 }
166 }
168 return T();
169}
170
171template<typename T> T SocketValueVariant::get() const
172{
173 /* Simple implementation in terms of #extract for now. This could potentially use a specialized
174 * implementation at some point, but for now it's unlikely to be a bottleneck. */
175 SocketValueVariant copied_variant = *this;
176 return copied_variant.extract<T>();
177}
178
179template<typename T> void SocketValueVariant::store_impl(T value)
180{
181 if constexpr (std::is_same_v<T, fn::GField>) {
182 const std::optional<eNodeSocketDatatype> new_socket_type =
184 BLI_assert(new_socket_type);
185 socket_type_ = *new_socket_type;
186 kind_ = Kind::Field;
187 value_.emplace<fn::GField>(std::move(value));
188 }
189 else if constexpr (fn::is_field_v<T>) {
190 /* Always store #Field<T> as #GField. */
191 this->store_impl<fn::GField>(std::move(value));
192 }
193#ifdef WITH_OPENVDB
194 else if constexpr (std::is_same_v<T, GVolumeGrid>) {
195 BLI_assert(value);
196 const VolumeGridType volume_grid_type = value->grid_type();
197 const std::optional<eNodeSocketDatatype> new_socket_type = grid_type_to_socket_type(
198 volume_grid_type);
199 BLI_assert(new_socket_type);
200 socket_type_ = *new_socket_type;
201 kind_ = Kind::Grid;
202 value_.emplace<GVolumeGrid>(std::move(value));
203 }
204 else if constexpr (is_VolumeGrid_v<T>) {
205 BLI_assert(value);
206 this->store_impl<GVolumeGrid>(std::move(value));
207 }
208#endif
209 else {
210 const std::optional<eNodeSocketDatatype> new_socket_type = static_type_to_socket_type<T>();
211 BLI_assert(new_socket_type);
212 socket_type_ = *new_socket_type;
213 kind_ = Kind::Single;
214 value_.emplace<T>(std::move(value));
215 }
216}
217
218void SocketValueVariant::store_single(const eNodeSocketDatatype socket_type, const void *value)
219{
220 kind_ = Kind::Single;
221 socket_type_ = socket_type;
222 switch (socket_type) {
223 case SOCK_FLOAT: {
224 value_.emplace<float>(*static_cast<const float *>(value));
225 break;
226 }
227 case SOCK_INT: {
228 value_.emplace<int>(*static_cast<const int *>(value));
229 break;
230 }
231 case SOCK_VECTOR: {
232 value_.emplace<float3>(*static_cast<const float3 *>(value));
233 break;
234 }
235 case SOCK_BOOLEAN: {
236 value_.emplace<bool>(*static_cast<const bool *>(value));
237 break;
238 }
239 case SOCK_ROTATION: {
240 value_.emplace<math::Quaternion>(*static_cast<const math::Quaternion *>(value));
241 break;
242 }
243 case SOCK_MATRIX: {
244 value_.emplace<float4x4>(*static_cast<const float4x4 *>(value));
245 break;
246 }
247 case SOCK_RGBA: {
248 value_.emplace<ColorGeometry4f>(*static_cast<const ColorGeometry4f *>(value));
249 break;
250 }
251 case SOCK_STRING: {
252 value_.emplace<std::string>(*static_cast<const std::string *>(value));
253 break;
254 }
255 default: {
257 break;
258 }
259 }
260}
261
263{
264 if (!value_.is<fn::GField>()) {
265 return false;
266 }
267 const fn::GField &field = value_.get<fn::GField>();
268 if (!field) {
269 return false;
270 }
271 return field.node().depends_on_input();
272}
273
275{
276 return kind_ == Kind::Grid;
277}
278
280{
281 switch (kind_) {
282 case Kind::Single: {
283 /* Nothing to do. */
284 break;
285 }
286 case Kind::Field: {
287 /* Evaluates the field without inputs to try to get a single value. If the field depends on
288 * context, the default value is used instead. */
289 fn::GField field = std::move(value_.get<fn::GField>());
290 void *buffer = this->allocate_single(socket_type_);
291 fn::evaluate_constant_field(field, buffer);
292 break;
293 }
294 case Kind::Grid: {
295 /* Can't convert a grid to a single value, so just use the default value of the current
296 * socket type. */
297 const CPPType &cpp_type = *socket_type_to_geo_nodes_base_cpp_type(socket_type_);
298 this->store_single(socket_type_, cpp_type.default_value());
299 break;
300 }
301 case Kind::None: {
303 break;
304 }
305 }
306}
307
309{
310 BLI_assert(kind_ == Kind::Single);
311 const CPPType *type = socket_type_to_geo_nodes_base_cpp_type(socket_type_);
312 BLI_assert(type != nullptr);
313 const void *data = value_.get();
314 return GPointer(*type, data);
315}
316
318{
319 const GPointer ptr = const_cast<const SocketValueVariant *>(this)->get_single_ptr();
320 return GMutablePointer(ptr.type(), const_cast<void *>(ptr.get()));
321}
322
324{
325 kind_ = Kind::Single;
326 socket_type_ = socket_type;
327 switch (socket_type) {
328 case SOCK_FLOAT:
329 return value_.allocate<float>();
330 case SOCK_INT:
331 return value_.allocate<int>();
332 case SOCK_VECTOR:
333 return value_.allocate<float3>();
334 case SOCK_BOOLEAN:
335 return value_.allocate<bool>();
336 case SOCK_ROTATION:
337 return value_.allocate<math::Quaternion>();
338 case SOCK_MATRIX:
339 return value_.allocate<float4x4>();
340 case SOCK_RGBA:
341 return value_.allocate<ColorGeometry4f>();
342 case SOCK_STRING:
343 return value_.allocate<std::string>();
344 case SOCK_MENU:
345 return value_.allocate<int>();
346 default: {
348 return nullptr;
349 }
350 }
351}
352
353std::ostream &operator<<(std::ostream &stream, const SocketValueVariant &value_variant)
354{
355 SocketValueVariant variant_copy = value_variant;
356 variant_copy.convert_to_single();
357 if (value_variant.kind_ == SocketValueVariant::Kind::Single) {
358 const GPointer value = variant_copy.get_single_ptr();
359 const CPPType &cpp_type = *value.type();
360 if (cpp_type.is_printable()) {
361 std::stringstream ss;
362 cpp_type.print(value.get(), ss);
363 stream << ss.str();
364 return stream;
365 }
366 }
367 stream << "SocketValueVariant";
368 return stream;
369}
370
372{
373 if (kind_ == Kind::None) {
374 return false;
375 }
376 return socket_type_ == socket_type;
377}
378
379#define INSTANTIATE(TYPE) \
380 template TYPE SocketValueVariant::extract(); \
381 template TYPE SocketValueVariant::get() const; \
382 template void SocketValueVariant::store_impl(TYPE);
383
384#ifdef WITH_OPENVDB
385# define INSTANTIATE_SINGLE_AND_FIELD_AND_GRID(TYPE) \
386 INSTANTIATE(TYPE) \
387 INSTANTIATE(fn::Field<TYPE>) \
388 INSTANTIATE(VolumeGrid<TYPE>)
389#else
390# define INSTANTIATE_SINGLE_AND_FIELD_AND_GRID(TYPE) \
391 INSTANTIATE(TYPE) \
392 INSTANTIATE(fn::Field<TYPE>)
393#endif
394
401
402INSTANTIATE(std::string)
403INSTANTIATE(fn::GField)
404
406INSTANTIATE(fn::Field<float4x4>)
407
408#ifdef WITH_OPENVDB
409INSTANTIATE(GVolumeGrid)
410#endif
411
412} // namespace blender::bke
CustomData interface, see also DNA_customdata_types.h.
VolumeGridType
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
eNodeSocketDatatype
@ SOCK_INT
@ SOCK_TEXTURE
@ SOCK_VECTOR
@ SOCK_BOOLEAN
@ SOCK_MATERIAL
@ SOCK_SHADER
@ SOCK_MATRIX
@ SOCK_FLOAT
@ SOCK_IMAGE
@ SOCK_COLLECTION
@ SOCK_CUSTOM
@ SOCK_GEOMETRY
@ SOCK_ROTATION
@ SOCK_OBJECT
@ SOCK_STRING
@ SOCK_RGBA
@ SOCK_MENU
#define U
std::decay_t< T > & emplace(Args &&...args)
Definition BLI_any.hh:260
void * allocate()
Definition BLI_any.hh:291
bool is() const
Definition BLI_any.hh:318
void * get()
Definition BLI_any.hh:324
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:556
const FieldNode & node() const
Definition FN_field.hh:137
#define T
std::optional< eNodeSocketDatatype > geo_nodes_base_cpp_type_to_socket_type(const CPPType &type)
Definition node.cc:4471
std::optional< VolumeGridType > socket_type_to_grid_type(eNodeSocketDatatype type)
Definition node.cc:4500
static constexpr bool is_single_or_field_or_grid_v
std::optional< eNodeSocketDatatype > grid_type_to_socket_type(VolumeGridType type)
Definition node.cc:4516
static std::optional< eNodeSocketDatatype > static_type_to_socket_type()
const CPPType * socket_type_to_geo_nodes_base_cpp_type(eNodeSocketDatatype type)
Definition node.cc:4438
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:533
void evaluate_constant_field(const GField &field, void *r_value)
Definition field.cc:498
static constexpr bool is_field_v
Definition FN_field.hh:217
constexpr bool is_same_any_v
MatBase< float, 4, 4 > float4x4
#define INSTANTIATE_SINGLE_AND_FIELD_AND_GRID(TYPE)
#define INSTANTIATE(TYPE)
StructRNA * type
Definition RNA_types.hh:41
PointerRNA * ptr
Definition wm_files.cc:4126