/* SPDX-FileCopyrightText: 2023 Blender Authors * * SPDX-License-Identifier: GPL-2.0-or-later */ /** \file * \ingroup bke */ #include #include "BKE_geometry_set.hh" #include "BKE_node.hh" #include "BKE_node_socket_value.hh" #include "BKE_volume_grid.hh" #include "NOD_geometry_nodes_bundle.hh" #include "NOD_geometry_nodes_closure.hh" #include "NOD_geometry_nodes_list.hh" #include "NOD_menu_value.hh" #include "BLI_color.hh" #include "BLI_math_rotation_types.hh" #include "BLI_math_vector_types.hh" #include "FN_field.hh" namespace blender::bke { template static constexpr bool is_single_or_field_or_grid_v = is_same_any_v #ifdef WITH_OPENVDB , VolumeGrid #endif >; /** * Very fast (compile-time) conversion from a static C++ type to the corresponding socket type. */ template static std::optional static_type_to_socket_type() { if constexpr (is_single_or_field_or_grid_v) { return SOCK_INT; } if constexpr (is_single_or_field_or_grid_v) { return SOCK_FLOAT; } if constexpr (is_single_or_field_or_grid_v) { return SOCK_BOOLEAN; } if constexpr (is_single_or_field_or_grid_v) { return SOCK_VECTOR; } if constexpr (is_single_or_field_or_grid_v) { return SOCK_RGBA; } if constexpr (is_single_or_field_or_grid_v) { return SOCK_ROTATION; } if constexpr (is_same_any_v>) { return SOCK_MENU; } if constexpr (is_same_any_v>) { return SOCK_MATRIX; } if constexpr (is_same_any_v) { return SOCK_STRING; } if constexpr (is_same_any_v) { return SOCK_BUNDLE; } if constexpr (is_same_any_v) { return SOCK_CLOSURE; } if constexpr (is_same_any_v) { return SOCK_OBJECT; } if constexpr (is_same_any_v) { return SOCK_COLLECTION; } if constexpr (is_same_any_v) { return SOCK_TEXTURE; } if constexpr (is_same_any_v) { return SOCK_IMAGE; } if constexpr (is_same_any_v) { return SOCK_MATERIAL; } if constexpr (is_same_any_v) { return SOCK_GEOMETRY; } return std::nullopt; } /** * Check if a socket type stores the static C++ type. */ template static bool static_type_is_base_socket_type(const eNodeSocketDatatype socket_type) { switch (socket_type) { case SOCK_INT: return std::is_same_v; case SOCK_FLOAT: return std::is_same_v; case SOCK_BOOLEAN: return std::is_same_v; case SOCK_VECTOR: return std::is_same_v; case SOCK_RGBA: return std::is_same_v; case SOCK_ROTATION: return std::is_same_v; case SOCK_MATRIX: return std::is_same_v; case SOCK_STRING: return std::is_same_v; case SOCK_MENU: return std::is_same_v; case SOCK_BUNDLE: return std::is_same_v; case SOCK_CLOSURE: return std::is_same_v; case SOCK_OBJECT: return std::is_same_v; case SOCK_COLLECTION: return std::is_same_v; case SOCK_TEXTURE: return std::is_same_v; case SOCK_IMAGE: return std::is_same_v; case SOCK_MATERIAL: return std::is_same_v; case SOCK_GEOMETRY: return std::is_same_v; case SOCK_CUSTOM: case SOCK_SHADER: return false; } BLI_assert_unreachable(); return false; } template T SocketValueVariant::extract() { if constexpr (std::is_same_v) { switch (kind_) { case Kind::Field: { return std::move(value_.get()); } case Kind::Single: { const GPointer single_value = this->get_single_ptr(); return fn::make_constant_field(*single_value.type(), single_value.get()); } case Kind::List: case Kind::Grid: { const CPPType *cpp_type = socket_type_to_geo_nodes_base_cpp_type(socket_type_); BLI_assert(cpp_type); return fn::make_constant_field(*cpp_type, cpp_type->default_value()); } case Kind::None: { BLI_assert_unreachable(); break; } } } else if constexpr (fn::is_field_v) { BLI_assert(static_type_is_base_socket_type(socket_type_)); return T(this->extract()); } else if constexpr (std::is_same_v) { if (kind_ != Kind::List) { return {}; } return std::move(value_.get()); } #ifdef WITH_OPENVDB else if constexpr (std::is_same_v) { switch (kind_) { case Kind::Grid: { BLI_assert(value_); return std::move(value_.get()); } case Kind::Single: case Kind::List: case Kind::Field: { const std::optional grid_type = socket_type_to_grid_type(socket_type_); BLI_assert(grid_type); return GVolumeGrid(*grid_type); } case Kind::None: { BLI_assert_unreachable(); break; } } } else if constexpr (is_VolumeGrid_v) { BLI_assert(static_type_is_base_socket_type(socket_type_)); return this->extract().typed(); } #endif else { BLI_assert(static_type_is_base_socket_type(socket_type_)); if (kind_ == Kind::Single) { return std::move(value_.get()); } if (kind_ == Kind::Field) { T ret_value; std::destroy_at(&ret_value); fn::evaluate_constant_field(value_.get(), &ret_value); return ret_value; } if (kind_ == Kind::List) { return {}; } } BLI_assert_unreachable(); return T(); } template T SocketValueVariant::get() const { /* Simple implementation in terms of #extract for now. This could potentially use a specialized * implementation at some point, but for now it's unlikely to be a bottleneck. */ SocketValueVariant copied_variant = *this; return copied_variant.extract(); } template void SocketValueVariant::store_impl(T value) { if constexpr (std::is_same_v) { const std::optional new_socket_type = geo_nodes_base_cpp_type_to_socket_type(value.cpp_type()); BLI_assert(new_socket_type); socket_type_ = *new_socket_type; kind_ = Kind::Field; value_.emplace(std::move(value)); } else if constexpr (fn::is_field_v) { /* Always store #Field as #GField. */ this->store_impl(std::move(value)); } else if constexpr (std::is_same_v) { kind_ = Kind::List; const std::optional new_socket_type = geo_nodes_base_cpp_type_to_socket_type(value->cpp_type()); BLI_assert(new_socket_type); socket_type_ = *new_socket_type; value_.emplace(std::move(value)); } #ifdef WITH_OPENVDB else if constexpr (std::is_same_v) { BLI_assert(value); const VolumeGridType volume_grid_type = value->grid_type(); const std::optional new_socket_type = grid_type_to_socket_type( volume_grid_type); BLI_assert(new_socket_type); socket_type_ = *new_socket_type; kind_ = Kind::Grid; value_.emplace(std::move(value)); } else if constexpr (is_VolumeGrid_v) { BLI_assert(value); this->store_impl(std::move(value)); } #endif else { const std::optional new_socket_type = static_type_to_socket_type(); BLI_assert(new_socket_type); socket_type_ = *new_socket_type; kind_ = Kind::Single; value_.emplace(std::move(value)); } } void SocketValueVariant::store_single(const eNodeSocketDatatype socket_type, const void *value) { kind_ = Kind::Single; socket_type_ = socket_type; switch (socket_type) { case SOCK_FLOAT: { value_.emplace(*static_cast(value)); break; } case SOCK_INT: { value_.emplace(*static_cast(value)); break; } case SOCK_VECTOR: { value_.emplace(*static_cast(value)); break; } case SOCK_BOOLEAN: { value_.emplace(*static_cast(value)); break; } case SOCK_ROTATION: { value_.emplace(*static_cast(value)); break; } case SOCK_MENU: { value_.emplace(*static_cast(value)); break; } case SOCK_MATRIX: { value_.emplace(*static_cast(value)); break; } case SOCK_RGBA: { value_.emplace(*static_cast(value)); break; } case SOCK_STRING: { value_.emplace(*static_cast(value)); break; } case SOCK_BUNDLE: { value_.emplace(*static_cast(value)); break; } case SOCK_CLOSURE: { value_.emplace(*static_cast(value)); break; } case SOCK_OBJECT: { value_.emplace(*static_cast(value)); break; } case SOCK_COLLECTION: { value_.emplace(*static_cast(value)); break; } case SOCK_TEXTURE: { value_.emplace(*static_cast(value)); break; } case SOCK_IMAGE: { value_.emplace(*static_cast(value)); break; } case SOCK_MATERIAL: { value_.emplace(*static_cast(value)); break; } case SOCK_GEOMETRY: { value_.emplace(*static_cast(value)); break; } default: { BLI_assert_unreachable(); break; } } } bool SocketValueVariant::is_context_dependent_field() const { if (!value_.is()) { return false; } const fn::GField &field = value_.get(); if (!field) { return false; } return field.node().depends_on_input(); } bool SocketValueVariant::is_volume_grid() const { return kind_ == Kind::Grid; } bool SocketValueVariant::is_single() const { return kind_ == Kind::Single; } bool SocketValueVariant::is_list() const { return kind_ == Kind::List; } void SocketValueVariant::convert_to_single() { switch (kind_) { case Kind::Single: { /* Nothing to do. */ break; } case Kind::Field: { /* Evaluates the field without inputs to try to get a single value. If the field depends on * context, the default value is used instead. */ fn::GField field = std::move(value_.get()); void *buffer = this->allocate_single(socket_type_); fn::evaluate_constant_field(field, buffer); break; } case Kind::List: case Kind::Grid: { /* Can't convert a grid to a single value, so just use the default value of the current * socket type. */ const CPPType &cpp_type = *socket_type_to_geo_nodes_base_cpp_type(socket_type_); this->store_single(socket_type_, cpp_type.default_value()); break; } case Kind::None: { BLI_assert_unreachable(); break; } } } GPointer SocketValueVariant::get_single_ptr() const { BLI_assert(kind_ == Kind::Single); const CPPType *type = socket_type_to_geo_nodes_base_cpp_type(socket_type_); BLI_assert(type != nullptr); const void *data = value_.get(); return GPointer(*type, data); } GMutablePointer SocketValueVariant::get_single_ptr() { const GPointer ptr = const_cast(this)->get_single_ptr(); return GMutablePointer(ptr.type(), const_cast(ptr.get())); } void *SocketValueVariant::allocate_single(const eNodeSocketDatatype socket_type) { kind_ = Kind::Single; socket_type_ = socket_type; switch (socket_type) { case SOCK_FLOAT: return value_.allocate(); case SOCK_INT: return value_.allocate(); case SOCK_VECTOR: return value_.allocate(); case SOCK_BOOLEAN: return value_.allocate(); case SOCK_ROTATION: return value_.allocate(); case SOCK_MATRIX: return value_.allocate(); case SOCK_RGBA: return value_.allocate(); case SOCK_STRING: return value_.allocate(); case SOCK_MENU: return value_.allocate(); case SOCK_BUNDLE: return value_.allocate(); case SOCK_CLOSURE: return value_.allocate(); case SOCK_OBJECT: return value_.allocate(); case SOCK_COLLECTION: return value_.allocate(); case SOCK_TEXTURE: return value_.allocate(); case SOCK_IMAGE: return value_.allocate(); case SOCK_MATERIAL: return value_.allocate(); default: { BLI_assert_unreachable(); return nullptr; } } } std::ostream &operator<<(std::ostream &stream, const SocketValueVariant &value_variant) { SocketValueVariant variant_copy = value_variant; variant_copy.convert_to_single(); if (value_variant.kind_ == SocketValueVariant::Kind::Single) { const GPointer value = variant_copy.get_single_ptr(); const CPPType &cpp_type = *value.type(); if (cpp_type.is_printable()) { std::stringstream ss; cpp_type.print(value.get(), ss); stream << ss.str(); return stream; } } stream << "SocketValueVariant"; return stream; } bool SocketValueVariant::valid_for_socket(eNodeSocketDatatype socket_type) const { if (kind_ == Kind::None) { return false; } return socket_type_ == socket_type; } #define INSTANTIATE(TYPE) \ template TYPE SocketValueVariant::extract(); \ template TYPE SocketValueVariant::get() const; \ template void SocketValueVariant::store_impl(TYPE); #ifdef WITH_OPENVDB # define INSTANTIATE_SINGLE_AND_FIELD_AND_GRID(TYPE) \ INSTANTIATE(TYPE) \ INSTANTIATE(fn::Field) \ INSTANTIATE(VolumeGrid) #else # define INSTANTIATE_SINGLE_AND_FIELD_AND_GRID(TYPE) \ INSTANTIATE(TYPE) \ INSTANTIATE(fn::Field) #endif INSTANTIATE_SINGLE_AND_FIELD_AND_GRID(int) INSTANTIATE_SINGLE_AND_FIELD_AND_GRID(bool) INSTANTIATE_SINGLE_AND_FIELD_AND_GRID(float) INSTANTIATE_SINGLE_AND_FIELD_AND_GRID(blender::float3) INSTANTIATE_SINGLE_AND_FIELD_AND_GRID(blender::ColorGeometry4f) INSTANTIATE_SINGLE_AND_FIELD_AND_GRID(blender::math::Quaternion) INSTANTIATE(std::string) INSTANTIATE(fn::GField) INSTANTIATE(blender::nodes::BundlePtr) INSTANTIATE(blender::nodes::ClosurePtr) INSTANTIATE(blender::nodes::ListPtr) INSTANTIATE(blender::bke::GeometrySet) INSTANTIATE(Object *) INSTANTIATE(Collection *) INSTANTIATE(Tex *) INSTANTIATE(Image *) INSTANTIATE(Material *) INSTANTIATE(float4x4) INSTANTIATE(fn::Field) INSTANTIATE(nodes::MenuValue) INSTANTIATE(fn::Field) #ifdef WITH_OPENVDB INSTANTIATE(GVolumeGrid) #endif } // namespace blender::bke