diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/editors/space_node/node_draw.cc | 48 | ||||
-rw-r--r-- | source/blender/functions/FN_field.hh | 63 | ||||
-rw-r--r-- | source/blender/functions/FN_field_cpp_type.hh | 87 | ||||
-rw-r--r-- | source/blender/functions/intern/field.cc | 10 | ||||
-rw-r--r-- | source/blender/modifiers/intern/MOD_nodes.cc | 29 | ||||
-rw-r--r-- | source/blender/modifiers/intern/MOD_nodes_evaluator.cc | 143 | ||||
-rw-r--r-- | source/blender/nodes/NOD_geometry_exec.hh | 43 | ||||
-rw-r--r-- | source/blender/nodes/intern/geometry_nodes_eval_log.cc | 46 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_socket.cc | 28 |
9 files changed, 388 insertions, 109 deletions
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index 867544d0805..f9a9e491403 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -843,29 +843,43 @@ struct SocketTooltipData { bNodeSocket *socket; }; -static void create_inspection_string_for_generic_value(const geo_log::GenericValueLog &value_log, - std::stringstream &ss) +static void create_inspection_string_for_generic_value(const GPointer value, std::stringstream &ss) { auto id_to_inspection_string = [&](ID *id, short idcode) { ss << (id ? id->name + 2 : TIP_("None")) << " (" << BKE_idtype_idcode_to_name(idcode) << ")"; }; - const GPointer value = value_log.value(); const CPPType &type = *value.type(); + const void *buffer = value.get(); if (type.is<Object *>()) { - id_to_inspection_string((ID *)*value.get<Object *>(), ID_OB); + id_to_inspection_string((ID *)buffer, ID_OB); } else if (type.is<Material *>()) { - id_to_inspection_string((ID *)*value.get<Material *>(), ID_MA); + id_to_inspection_string((ID *)buffer, ID_MA); } else if (type.is<Tex *>()) { - id_to_inspection_string((ID *)*value.get<Tex *>(), ID_TE); + id_to_inspection_string((ID *)buffer, ID_TE); } else if (type.is<Image *>()) { - id_to_inspection_string((ID *)*value.get<Image *>(), ID_IM); + id_to_inspection_string((ID *)buffer, ID_IM); } else if (type.is<Collection *>()) { - id_to_inspection_string((ID *)*value.get<Collection *>(), ID_GR); + id_to_inspection_string((ID *)buffer, ID_GR); + } + else if (type.is<int>()) { + ss << *(int *)buffer << TIP_(" (Integer)"); + } + else if (type.is<float>()) { + ss << *(float *)buffer << TIP_(" (Float)"); + } + else if (type.is<blender::float3>()) { + ss << *(blender::float3 *)buffer << TIP_(" (Vector)"); + } + else if (type.is<bool>()) { + ss << ((*(bool *)buffer) ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)"); + } + else if (type.is<std::string>()) { + ss << *(std::string *)buffer << TIP_(" (String)"); } } @@ -880,21 +894,7 @@ static void create_inspection_string_for_gfield(const geo_log::GFieldValueLog &v if (field) { BUFFER_FOR_CPP_TYPE_VALUE(type, buffer); blender::fn::evaluate_constant_field(field, buffer); - if (type.is<int>()) { - ss << *(int *)buffer << TIP_(" (Integer)"); - } - else if (type.is<float>()) { - ss << *(float *)buffer << TIP_(" (Float)"); - } - else if (type.is<blender::float3>()) { - ss << *(blender::float3 *)buffer << TIP_(" (Vector)"); - } - else if (type.is<bool>()) { - ss << ((*(bool *)buffer) ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)"); - } - else if (type.is<std::string>()) { - ss << *(std::string *)buffer << TIP_(" (String)"); - } + create_inspection_string_for_generic_value({type, buffer}, ss); type.destruct(buffer); } else { @@ -1023,7 +1023,7 @@ static std::optional<std::string> create_socket_inspection_string(bContext *C, std::stringstream ss; if (const geo_log::GenericValueLog *generic_value_log = dynamic_cast<const geo_log::GenericValueLog *>(value_log)) { - create_inspection_string_for_generic_value(*generic_value_log, ss); + create_inspection_string_for_generic_value(generic_value_log->value(), ss); } if (const geo_log::GFieldValueLog *gfield_value_log = dynamic_cast<const geo_log::GFieldValueLog *>(value_log)) { diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh index fb488fdbfa9..28bb120bb17 100644 --- a/source/blender/functions/FN_field.hh +++ b/source/blender/functions/FN_field.hh @@ -178,11 +178,19 @@ class GFieldRef : public GFieldBase<const FieldNode *> { } }; +namespace detail { +/* Utility class to make #is_field_v work. */ +struct TypedFieldBase { +}; +} // namespace detail + /** * A typed version of #GField. It has the same memory layout as #GField. */ -template<typename T> class Field : public GField { +template<typename T> class Field : public GField, detail::TypedFieldBase { public: + using base_type = T; + Field() = default; Field(GField field) : GField(std::move(field)) @@ -196,6 +204,11 @@ template<typename T> class Field : public GField { } }; +/** True when T is any Field<...> type. */ +template<typename T> +static constexpr bool is_field_v = std::is_base_of_v<detail::TypedFieldBase, T> && + !std::is_same_v<detail::TypedFieldBase, T>; + /** * A #FieldNode that allows composing existing fields into new fields. */ @@ -419,6 +432,8 @@ template<typename T> Field<T> make_constant_field(T value) return Field<T>{GField{std::move(operation), 0}}; } +GField make_constant_field(const CPPType &type, const void *value); + GField make_field_constant_if_possible(GField field); class IndexFieldInput final : public FieldInput { @@ -438,6 +453,52 @@ class IndexFieldInput final : public FieldInput { /** \} */ /* -------------------------------------------------------------------- */ +/** \name Value or Field Class + * + * Utility class that wraps a single value and a field, to simplify accessing both of the types. + * \{ */ + +template<typename T> struct ValueOrField { + /** Value that is used when the field is empty. */ + T value{}; + Field<T> field; + + ValueOrField() = default; + + ValueOrField(T value) : value(std::move(value)) + { + } + + ValueOrField(Field<T> field) : field(std::move(field)) + { + } + + bool is_field() const + { + return (bool)this->field; + } + + Field<T> as_field() const + { + if (this->field) { + return this->field; + } + return make_constant_field(this->value); + } + + T as_value() const + { + if (this->field) { + /* This returns a default value when the field is not constant. */ + return evaluate_constant_field(this->field); + } + return this->value; + } +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name #FieldNode Inline Methods * \{ */ diff --git a/source/blender/functions/FN_field_cpp_type.hh b/source/blender/functions/FN_field_cpp_type.hh index c3636fb3c7b..940faba6d70 100644 --- a/source/blender/functions/FN_field_cpp_type.hh +++ b/source/blender/functions/FN_field_cpp_type.hh @@ -60,6 +60,84 @@ class FieldCPPType : public CPPType { } }; +class ValueOrFieldCPPType : public CPPType { + private: + const CPPType &base_type_; + void (*construct_from_value_)(void *dst, const void *value); + void (*construct_from_field_)(void *dst, GField field); + const void *(*get_value_ptr_)(const void *value_or_field); + const GField *(*get_field_ptr_)(const void *value_or_field); + bool (*is_field_)(const void *value_or_field); + GField (*as_field_)(const void *value_or_field); + + public: + template<typename T> + ValueOrFieldCPPType(FieldCPPTypeParam<ValueOrField<T>> /* unused */, StringRef debug_name) + : CPPType(CPPTypeParam<ValueOrField<T>, CPPTypeFlags::None>(), debug_name), + base_type_(CPPType::get<T>()) + { + construct_from_value_ = [](void *dst, const void *value_or_field) { + new (dst) ValueOrField<T>(*(const T *)value_or_field); + }; + construct_from_field_ = [](void *dst, GField field) { + new (dst) ValueOrField<T>(Field<T>(std::move(field))); + }; + get_value_ptr_ = [](const void *value_or_field) { + return (const void *)&((ValueOrField<T> *)value_or_field)->value; + }; + get_field_ptr_ = [](const void *value_or_field) -> const GField * { + return &((ValueOrField<T> *)value_or_field)->field; + }; + is_field_ = [](const void *value_or_field) { + return ((ValueOrField<T> *)value_or_field)->is_field(); + }; + as_field_ = [](const void *value_or_field) -> GField { + return ((ValueOrField<T> *)value_or_field)->as_field(); + }; + } + + const CPPType &base_type() const + { + return base_type_; + } + + void construct_from_value(void *dst, const void *value) const + { + construct_from_value_(dst, value); + } + + void construct_from_field(void *dst, GField field) const + { + construct_from_field_(dst, field); + } + + const void *get_value_ptr(const void *value_or_field) const + { + return get_value_ptr_(value_or_field); + } + + void *get_value_ptr(void *value_or_field) const + { + /* Use `const_cast` to avoid duplicating the callback for the non-const case. */ + return const_cast<void *>(get_value_ptr_(value_or_field)); + } + + const GField *get_field_ptr(const void *value_or_field) const + { + return get_field_ptr_(value_or_field); + } + + bool is_field(const void *value_or_field) const + { + return is_field_(value_or_field); + } + + GField as_field(const void *value_or_field) const + { + return as_field_(value_or_field); + } +}; + } // namespace blender::fn #define MAKE_FIELD_CPP_TYPE(DEBUG_NAME, FIELD_TYPE) \ @@ -69,4 +147,13 @@ class FieldCPPType : public CPPType { static blender::fn::FieldCPPType cpp_type{ \ blender::fn::FieldCPPTypeParam<blender::fn::Field<FIELD_TYPE>>(), STRINGIFY(DEBUG_NAME)}; \ return cpp_type; \ + } \ + template<> \ + const blender::fn::CPPType & \ + blender::fn::CPPType::get_impl<blender::fn::ValueOrField<FIELD_TYPE>>() \ + { \ + static blender::fn::ValueOrFieldCPPType cpp_type{ \ + blender::fn::FieldCPPTypeParam<blender::fn::ValueOrField<FIELD_TYPE>>(), \ + STRINGIFY(DEBUG_NAME##OrValue)}; \ + return cpp_type; \ } diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc index 91b1bdfd8f0..7934490a6d9 100644 --- a/source/blender/functions/intern/field.cc +++ b/source/blender/functions/intern/field.cc @@ -511,10 +511,16 @@ GField make_field_constant_if_possible(GField field) const CPPType &type = field.cpp_type(); BUFFER_FOR_CPP_TYPE_VALUE(type, buffer); evaluate_constant_field(field, buffer); - auto constant_fn = std::make_unique<CustomMF_GenericConstant>(type, buffer, true); + GField new_field = make_constant_field(type, buffer); type.destruct(buffer); + return new_field; +} + +GField make_constant_field(const CPPType &type, const void *value) +{ + auto constant_fn = std::make_unique<CustomMF_GenericConstant>(type, value, true); auto operation = std::make_shared<FieldOperation>(std::move(constant_fn)); - return GField{operation, 0}; + return GField{std::move(operation), 0}; } GVArray FieldContext::get_varray_for_input(const FieldInput &field_input, diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index d027be0a7f6..05e9bd7d233 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -98,6 +98,7 @@ #include "NOD_node_declaration.hh" #include "FN_field.hh" +#include "FN_field_cpp_type.hh" #include "FN_multi_function.hh" using blender::Array; @@ -113,9 +114,11 @@ using blender::StringRef; using blender::StringRefNull; using blender::Vector; using blender::bke::OutputAttribute; +using blender::fn::Field; using blender::fn::GField; using blender::fn::GMutablePointer; using blender::fn::GPointer; +using blender::fn::ValueOrField; using blender::nodes::FieldInferencingInterface; using blender::nodes::GeoNodeExecParams; using blender::nodes::InputSocketFieldType; @@ -491,35 +494,34 @@ static void init_socket_cpp_value_from_property(const IDProperty &property, else if (property.type == IDP_DOUBLE) { value = (float)IDP_Double(&property); } - new (r_value) blender::fn::Field<float>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<float>(value); break; } case SOCK_INT: { int value = IDP_Int(&property); - new (r_value) blender::fn::Field<int>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<int>(value); break; } case SOCK_VECTOR: { float3 value; copy_v3_v3(value, (const float *)IDP_Array(&property)); - new (r_value) blender::fn::Field<float3>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<float3>(value); break; } case SOCK_RGBA: { blender::ColorGeometry4f value; copy_v4_v4((float *)value, (const float *)IDP_Array(&property)); - new (r_value) blender::fn::Field<ColorGeometry4f>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<ColorGeometry4f>(value); break; } case SOCK_BOOLEAN: { bool value = IDP_Int(&property) != 0; - new (r_value) blender::fn::Field<bool>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<bool>(value); break; } case SOCK_STRING: { std::string value = IDP_String(&property); - new (r_value) - blender::fn::Field<std::string>(blender::fn::make_constant_field(std::move(value))); + new (r_value) ValueOrField<std::string>(std::move(value)); break; } case SOCK_OBJECT: { @@ -740,7 +742,12 @@ static void initialize_group_input(NodesModifierData &nmd, const StringRef attribute_name{IDP_String(property_attribute_name)}; auto attribute_input = std::make_shared<blender::bke::AttributeFieldInput>( attribute_name, *socket_type.base_cpp_type); - new (r_value) blender::fn::GField(std::move(attribute_input), 0); + GField attribute_field{std::move(attribute_input), 0}; + const blender::fn::ValueOrFieldCPPType *cpp_type = + dynamic_cast<const blender::fn::ValueOrFieldCPPType *>( + socket_type.geometry_nodes_cpp_type); + BLI_assert(cpp_type != nullptr); + cpp_type->construct_from_field(r_value, std::move(attribute_field)); } else { init_socket_cpp_value_from_property( @@ -904,7 +911,11 @@ static void store_output_value_in_geometry(GeometrySet &geometry_set, if (attribute_name.is_empty()) { return; } - const GField &field = *(const GField *)value.get(); + const blender::fn::ValueOrFieldCPPType *cpp_type = + dynamic_cast<const blender::fn::ValueOrFieldCPPType *>(value.type()); + BLI_assert(cpp_type != nullptr); + + const GField field = cpp_type->as_field(value.get()); const bNodeSocket *interface_socket = (bNodeSocket *)BLI_findlink(&nmd->node_group->outputs, socket.index()); const AttributeDomain domain = (AttributeDomain)interface_socket->attribute_domain; diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc index fd2fe2161c9..4d081450fd8 100644 --- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc +++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc @@ -39,9 +39,11 @@ namespace blender::modifiers::geometry_nodes { using fn::CPPType; using fn::Field; -using fn::FieldCPPType; using fn::GField; using fn::GValueMap; +using fn::GVArray; +using fn::ValueOrField; +using fn::ValueOrFieldCPPType; using nodes::GeoNodeExecParams; using namespace fn::multi_function_types; @@ -348,18 +350,19 @@ static bool get_implicit_socket_input(const SocketRef &socket, void *r_value) GEO_NODE_CURVE_HANDLE_LEFT ? "handle_left" : "handle_right"; - new (r_value) Field<float3>(bke::AttributeFieldInput::Create<float3>(side)); + new (r_value) ValueOrField<float3>(bke::AttributeFieldInput::Create<float3>(side)); return true; } - new (r_value) Field<float3>(bke::AttributeFieldInput::Create<float3>("position")); + new (r_value) ValueOrField<float3>(bke::AttributeFieldInput::Create<float3>("position")); return true; } if (socket.typeinfo()->type == SOCK_INT) { if (ELEM(bnode.type, FN_NODE_RANDOM_VALUE, GEO_NODE_INSTANCE_ON_POINTS)) { - new (r_value) Field<int>(std::make_shared<bke::IDAttributeFieldInput>()); + new (r_value) + ValueOrField<int>(Field<int>(std::make_shared<bke::IDAttributeFieldInput>())); return true; } - new (r_value) Field<int>(std::make_shared<fn::IndexFieldInput>()); + new (r_value) ValueOrField<int>(Field<int>(std::make_shared<fn::IndexFieldInput>())); return true; } } @@ -943,8 +946,9 @@ class GeometryNodesEvaluator { LinearAllocator<> &allocator = local_allocators_.local(); - /* Prepare the inputs for the multi function. */ - Vector<GField> input_fields; + bool any_input_is_field = false; + Vector<const void *, 16> input_values; + Vector<const ValueOrFieldCPPType *, 16> input_types; for (const int i : node->inputs().index_range()) { const InputSocketRef &socket_ref = node->input(i); if (!socket_ref.is_available()) { @@ -955,7 +959,37 @@ class GeometryNodesEvaluator { BLI_assert(input_state.was_ready_for_execution); SingleInputValue &single_value = *input_state.value.single; BLI_assert(single_value.value != nullptr); - input_fields.append(std::move(*(GField *)single_value.value)); + const ValueOrFieldCPPType &field_cpp_type = static_cast<const ValueOrFieldCPPType &>( + *input_state.type); + input_values.append(single_value.value); + input_types.append(&field_cpp_type); + if (field_cpp_type.is_field(single_value.value)) { + any_input_is_field = true; + } + } + + if (any_input_is_field) { + this->execute_multi_function_node__field( + node, fn_item, node_state, allocator, input_values, input_types); + } + else { + this->execute_multi_function_node__value( + node, *fn_item.fn, node_state, allocator, input_values, input_types); + } + } + + void execute_multi_function_node__field(const DNode node, + const nodes::NodeMultiFunctions::Item &fn_item, + NodeState &node_state, + LinearAllocator<> &allocator, + Span<const void *> input_values, + Span<const ValueOrFieldCPPType *> input_types) + { + Vector<GField> input_fields; + for (const int i : input_values.index_range()) { + const void *input_value_or_field = input_values[i]; + const ValueOrFieldCPPType &field_cpp_type = *input_types[i]; + input_fields.append(field_cpp_type.as_field(input_value_or_field)); } std::shared_ptr<fn::FieldOperation> operation; @@ -966,7 +1000,6 @@ class GeometryNodesEvaluator { operation = std::make_shared<fn::FieldOperation>(*fn_item.fn, std::move(input_fields)); } - /* Forward outputs. */ int output_index = 0; for (const int i : node->outputs().index_range()) { const OutputSocketRef &socket_ref = node->output(i); @@ -975,16 +1008,68 @@ class GeometryNodesEvaluator { } OutputState &output_state = node_state.outputs[i]; const DOutputSocket socket{node.context(), &socket_ref}; - const CPPType *cpp_type = get_socket_cpp_type(socket_ref); + const ValueOrFieldCPPType *cpp_type = static_cast<const ValueOrFieldCPPType *>( + get_socket_cpp_type(socket_ref)); GField new_field{operation, output_index}; - new_field = fn::make_field_constant_if_possible(std::move(new_field)); - GField &field_to_forward = *allocator.construct<GField>(std::move(new_field)).release(); - this->forward_output(socket, {cpp_type, &field_to_forward}); + void *buffer = allocator.allocate(cpp_type->size(), cpp_type->alignment()); + cpp_type->construct_from_field(buffer, std::move(new_field)); + this->forward_output(socket, {cpp_type, buffer}); output_state.has_been_computed = true; output_index++; } } + void execute_multi_function_node__value(const DNode node, + const MultiFunction &fn, + NodeState &node_state, + LinearAllocator<> &allocator, + Span<const void *> input_values, + Span<const ValueOrFieldCPPType *> input_types) + { + MFParamsBuilder params{fn, 1}; + for (const int i : input_values.index_range()) { + const void *input_value_or_field = input_values[i]; + const ValueOrFieldCPPType &field_cpp_type = *input_types[i]; + const CPPType &base_type = field_cpp_type.base_type(); + const void *input_value = field_cpp_type.get_value_ptr(input_value_or_field); + params.add_readonly_single_input(GVArray::ForSingleRef(base_type, 1, input_value)); + } + + Vector<GMutablePointer, 16> output_buffers; + for (const int i : node->outputs().index_range()) { + const DOutputSocket socket = node.output(i); + if (!socket->is_available()) { + output_buffers.append({}); + continue; + } + const ValueOrFieldCPPType *value_or_field_type = static_cast<const ValueOrFieldCPPType *>( + get_socket_cpp_type(socket)); + const CPPType &base_type = value_or_field_type->base_type(); + void *value_or_field_buffer = allocator.allocate(value_or_field_type->size(), + value_or_field_type->alignment()); + value_or_field_type->default_construct(value_or_field_buffer); + void *value_buffer = value_or_field_type->get_value_ptr(value_or_field_buffer); + base_type.destruct(value_buffer); + params.add_uninitialized_single_output(GMutableSpan{base_type, value_buffer, 1}); + output_buffers.append({value_or_field_type, value_or_field_buffer}); + } + + MFContextBuilder context; + fn.call(IndexRange(1), params, context); + + for (const int i : output_buffers.index_range()) { + GMutablePointer buffer = output_buffers[i]; + if (buffer.get() == nullptr) { + continue; + } + const DOutputSocket socket = node.output(i); + this->forward_output(socket, buffer); + + OutputState &output_state = node_state.outputs[i]; + output_state.has_been_computed = true; + } + } + void execute_unknown_node(const DNode node, NodeState &node_state) { LinearAllocator<> &allocator = local_allocators_.local(); @@ -1466,18 +1551,28 @@ class GeometryNodesEvaluator { from_type.copy_construct(from_value, to_value); return; } - const FieldCPPType *from_field_type = dynamic_cast<const FieldCPPType *>(&from_type); - const FieldCPPType *to_field_type = dynamic_cast<const FieldCPPType *>(&to_type); + const ValueOrFieldCPPType *from_field_type = dynamic_cast<const ValueOrFieldCPPType *>( + &from_type); + const ValueOrFieldCPPType *to_field_type = dynamic_cast<const ValueOrFieldCPPType *>(&to_type); if (from_field_type != nullptr && to_field_type != nullptr) { const CPPType &from_base_type = from_field_type->base_type(); const CPPType &to_base_type = to_field_type->base_type(); if (conversions_.is_convertible(from_base_type, to_base_type)) { - const MultiFunction &fn = *conversions_.get_conversion_multi_function( - MFDataType::ForSingle(from_base_type), MFDataType::ForSingle(to_base_type)); - const GField &from_field = *(const GField *)from_value; - auto operation = std::make_shared<fn::FieldOperation>(fn, Vector<GField>{from_field}); - new (to_value) GField(std::move(operation), 0); + if (from_field_type->is_field(from_value)) { + const GField &from_field = *from_field_type->get_field_ptr(from_value); + const MultiFunction &fn = *conversions_.get_conversion_multi_function( + MFDataType::ForSingle(from_base_type), MFDataType::ForSingle(to_base_type)); + auto operation = std::make_shared<fn::FieldOperation>(fn, Vector<GField>{from_field}); + to_field_type->construct_from_field(to_value, GField(std::move(operation), 0)); + } + else { + to_field_type->default_construct(to_value); + const void *from_value_ptr = from_field_type->get_value_ptr(from_value); + void *to_value_ptr = to_field_type->get_value_ptr(to_value); + conversions_.get_conversion_functions(from_base_type, to_base_type) + ->convert_single_to_initialized(from_value_ptr, to_value_ptr); + } return; } } @@ -1493,14 +1588,6 @@ class GeometryNodesEvaluator { void construct_default_value(const CPPType &type, void *r_value) { - if (const FieldCPPType *field_cpp_type = dynamic_cast<const FieldCPPType *>(&type)) { - const CPPType &base_type = field_cpp_type->base_type(); - auto constant_fn = std::make_unique<fn::CustomMF_GenericConstant>( - base_type, base_type.default_value(), false); - auto operation = std::make_shared<fn::FieldOperation>(std::move(constant_fn)); - new (r_value) GField(std::move(operation), 0); - return; - } type.copy_construct(type.default_value(), r_value); } diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index 700f32ee414..6b6e8a89240 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -59,6 +59,7 @@ using fn::GVArray; using fn::GVArray_GSpan; using fn::GVMutableArray; using fn::GVMutableArray_GSpan; +using fn::ValueOrField; using geometry_nodes_eval_log::NodeWarningType; /** @@ -129,7 +130,7 @@ class GeoNodeExecParams { } template<typename T> - static inline constexpr bool is_stored_as_field_v = std::is_same_v<T, float> || + static inline constexpr bool is_field_base_type_v = std::is_same_v<T, float> || std::is_same_v<T, int> || std::is_same_v<T, bool> || std::is_same_v<T, ColorGeometry4f> || @@ -157,9 +158,15 @@ class GeoNodeExecParams { */ template<typename T> T extract_input(StringRef identifier) { - if constexpr (is_stored_as_field_v<T>) { - Field<T> field = this->extract_input<Field<T>>(identifier); - return fn::evaluate_constant_field(field); + if constexpr (is_field_base_type_v<T>) { + ValueOrField<T> value_or_field = this->extract_input<ValueOrField<T>>(identifier); + return value_or_field.as_value(); + } + else if constexpr (fn::is_field_v<T>) { + using BaseType = typename T::base_type; + ValueOrField<BaseType> value_or_field = this->extract_input<ValueOrField<BaseType>>( + identifier); + return value_or_field.as_field(); } else { #ifdef DEBUG @@ -186,9 +193,9 @@ class GeoNodeExecParams { Vector<GMutablePointer> gvalues = provider_->extract_multi_input(identifier); Vector<T> values; for (GMutablePointer gvalue : gvalues) { - if constexpr (is_stored_as_field_v<T>) { - const Field<T> field = gvalue.relocate_out<Field<T>>(); - values.append(fn::evaluate_constant_field(field)); + if constexpr (is_field_base_type_v<T>) { + const ValueOrField<T> value_or_field = gvalue.relocate_out<ValueOrField<T>>(); + values.append(value_or_field.as_value()); } else { values.append(gvalue.relocate_out<T>()); @@ -200,11 +207,16 @@ class GeoNodeExecParams { /** * Get the input value for the input socket with the given identifier. */ - template<typename T> const T get_input(StringRef identifier) const + template<typename T> T get_input(StringRef identifier) const { - if constexpr (is_stored_as_field_v<T>) { - const Field<T> &field = this->get_input<Field<T>>(identifier); - return fn::evaluate_constant_field(field); + if constexpr (is_field_base_type_v<T>) { + ValueOrField<T> value_or_field = this->get_input<ValueOrField<T>>(identifier); + return value_or_field.as_value(); + } + else if constexpr (fn::is_field_v<T>) { + using BaseType = typename T::base_type; + ValueOrField<BaseType> value_or_field = this->get_input<ValueOrField<BaseType>>(identifier); + return value_or_field.as_field(); } else { #ifdef DEBUG @@ -226,9 +238,12 @@ class GeoNodeExecParams { template<typename T> void set_output(StringRef identifier, T &&value) { using StoredT = std::decay_t<T>; - if constexpr (is_stored_as_field_v<StoredT>) { - this->set_output<Field<StoredT>>(identifier, - fn::make_constant_field<StoredT>(std::forward<T>(value))); + if constexpr (is_field_base_type_v<StoredT>) { + this->set_output(identifier, ValueOrField<StoredT>(std::forward<T>(value))); + } + else if constexpr (fn::is_field_v<StoredT>) { + using BaseType = typename StoredT::base_type; + this->set_output(identifier, ValueOrField<BaseType>(std::forward<T>(value))); } else { const CPPType &type = CPPType::get<StoredT>(); diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc index ddd3c991518..782ab43336c 100644 --- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc +++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc @@ -31,6 +31,7 @@ using fn::CPPType; using fn::FieldCPPType; using fn::FieldInput; using fn::GField; +using fn::ValueOrFieldCPPType; ModifierLog::ModifierLog(GeoLogger &logger) : input_geometry_log_(std::move(logger.input_geometry_log_)), @@ -417,25 +418,38 @@ void LocalGeoLogger::log_value_for_sockets(Span<DSocket> sockets, GPointer value geometry_set, log_full_geometry); values_.append({copied_sockets, std::move(value_log)}); } - else if (const FieldCPPType *field_type = dynamic_cast<const FieldCPPType *>(&type)) { - GField field = field_type->get_gfield(value.get()); - bool log_full_field = false; - if (!field.node().depends_on_input()) { - /* Always log constant fields so that their value can be shown in socket inspection. - * In the future we can also evaluate the field here and only store the value. */ - log_full_field = true; - } - if (!log_full_field) { - for (const DSocket &socket : sockets) { - if (main_logger_->log_full_sockets_.contains(socket)) { - log_full_field = true; - break; + else if (const ValueOrFieldCPPType *value_or_field_type = + dynamic_cast<const ValueOrFieldCPPType *>(&type)) { + const void *value_or_field = value.get(); + if (value_or_field_type->is_field(value_or_field)) { + GField field = *value_or_field_type->get_field_ptr(value_or_field); + bool log_full_field = false; + if (!field.node().depends_on_input()) { + /* Always log constant fields so that their value can be shown in socket inspection. + * In the future we can also evaluate the field here and only store the value. */ + log_full_field = true; + } + if (!log_full_field) { + for (const DSocket &socket : sockets) { + if (main_logger_->log_full_sockets_.contains(socket)) { + log_full_field = true; + break; + } } } + destruct_ptr<GFieldValueLog> value_log = allocator_->construct<GFieldValueLog>( + std::move(field), log_full_field); + values_.append({copied_sockets, std::move(value_log)}); + } + else { + const CPPType &base_type = value_or_field_type->base_type(); + const void *value = value_or_field_type->get_value_ptr(value_or_field); + void *buffer = allocator_->allocate(base_type.size(), base_type.alignment()); + base_type.copy_construct(value, buffer); + destruct_ptr<GenericValueLog> value_log = allocator_->construct<GenericValueLog>( + GMutablePointer{base_type, buffer}); + values_.append({copied_sockets, std::move(value_log)}); } - destruct_ptr<GFieldValueLog> value_log = allocator_->construct<GFieldValueLog>( - std::move(field), log_full_field); - values_.append({copied_sockets, std::move(value_log)}); } else { void *buffer = allocator_->allocate(type.size(), type.alignment()); diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index 200e4120346..68e8f6421bd 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -51,6 +51,7 @@ #include "FN_field.hh" using namespace blender; +using blender::fn::ValueOrField; using blender::nodes::SocketDeclarationPtr; struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, @@ -701,11 +702,11 @@ static bNodeSocketType *make_socket_type_bool() socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(bool *)r_value = ((bNodeSocketValueBoolean *)socket.default_value)->value; }; - socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<blender::fn::Field<bool>>(); + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<bool>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { bool value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<bool>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<bool>(value); }; return socktype; } @@ -717,11 +718,11 @@ static bNodeSocketType *make_socket_type_float(PropertySubType subtype) socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(float *)r_value = ((bNodeSocketValueFloat *)socket.default_value)->value; }; - socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<blender::fn::Field<float>>(); + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<float>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { float value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<float>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<float>(value); }; return socktype; } @@ -733,11 +734,11 @@ static bNodeSocketType *make_socket_type_int(PropertySubType subtype) socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(int *)r_value = ((bNodeSocketValueInt *)socket.default_value)->value; }; - socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<blender::fn::Field<int>>(); + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<int>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { int value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<int>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<int>(value); }; return socktype; } @@ -749,12 +750,11 @@ static bNodeSocketType *make_socket_type_vector(PropertySubType subtype) socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(blender::float3 *)r_value = ((bNodeSocketValueVector *)socket.default_value)->value; }; - socktype->geometry_nodes_cpp_type = - &blender::fn::CPPType::get<blender::fn::Field<blender::float3>>(); + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<blender::float3>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { blender::float3 value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<blender::float3>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<blender::float3>(value); }; return socktype; } @@ -767,12 +767,11 @@ static bNodeSocketType *make_socket_type_rgba() *(blender::ColorGeometry4f *)r_value = ((bNodeSocketValueRGBA *)socket.default_value)->value; }; socktype->geometry_nodes_cpp_type = - &blender::fn::CPPType::get<blender::fn::Field<blender::ColorGeometry4f>>(); + &blender::fn::CPPType::get<ValueOrField<blender::ColorGeometry4f>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { blender::ColorGeometry4f value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) - blender::fn::Field<blender::ColorGeometry4f>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<blender::ColorGeometry4f>(value); }; return socktype; } @@ -784,13 +783,12 @@ static bNodeSocketType *make_socket_type_string() socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { new (r_value) std::string(((bNodeSocketValueString *)socket.default_value)->value); }; - socktype->geometry_nodes_cpp_type = - &blender::fn::CPPType::get<blender::fn::Field<std::string>>(); + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<std::string>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { std::string value; value.~basic_string(); socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<std::string>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<std::string>(value); }; return socktype; } |