diff options
Diffstat (limited to 'source/blender/nodes/geometry')
24 files changed, 534 insertions, 347 deletions
diff --git a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc index c4bee09e07b..1129e954360 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc @@ -8,6 +8,7 @@ #include "UI_resources.h" #include "BKE_collection.h" +#include "BKE_instances.hh" #include "node_geometry_util.hh" @@ -69,8 +70,7 @@ static void node_geo_exec(GeoNodeExecParams params) const bool use_relative_transform = (storage.transform_space == GEO_NODE_TRANSFORM_SPACE_RELATIVE); - GeometrySet geometry_set_out; - InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>(); + std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>(); const bool separate_children = params.get_input<bool>("Separate Children"); if (separate_children) { @@ -84,7 +84,7 @@ static void node_geo_exec(GeoNodeExecParams params) children_objects.append(collection_object->ob); } - instances.reserve(children_collections.size() + children_objects.size()); + instances->reserve(children_collections.size() + children_objects.size()); Vector<InstanceListEntry> entries; entries.reserve(children_collections.size() + children_objects.size()); @@ -93,26 +93,26 @@ static void node_geo_exec(GeoNodeExecParams params) if (!reset_children) { add_v3_v3(transform.values[3], child_collection->instance_offset); if (use_relative_transform) { - mul_m4_m4_pre(transform.values, self_object->imat); + mul_m4_m4_pre(transform.values, self_object->world_to_object); } else { sub_v3_v3(transform.values[3], collection->instance_offset); } } - const int handle = instances.add_reference(*child_collection); + const int handle = instances->add_reference(*child_collection); entries.append({handle, &(child_collection->id.name[2]), transform}); } for (Object *child_object : children_objects) { - const int handle = instances.add_reference(*child_object); + const int handle = instances->add_reference(*child_object); float4x4 transform = float4x4::identity(); if (!reset_children) { if (use_relative_transform) { - transform = self_object->imat; + transform = self_object->world_to_object; } else { sub_v3_v3(transform.values[3], collection->instance_offset); } - mul_m4_m4_post(transform.values, child_object->obmat); + mul_m4_m4_post(transform.values, child_object->object_to_world); } entries.append({handle, &(child_object->id.name[2]), transform}); } @@ -123,21 +123,21 @@ static void node_geo_exec(GeoNodeExecParams params) return BLI_strcasecmp_natural(a.name, b.name) < 0; }); for (const InstanceListEntry &entry : entries) { - instances.add_instance(entry.handle, entry.transform); + instances->add_instance(entry.handle, entry.transform); } } else { float4x4 transform = float4x4::identity(); if (use_relative_transform) { copy_v3_v3(transform.values[3], collection->instance_offset); - mul_m4_m4_pre(transform.values, self_object->imat); + mul_m4_m4_pre(transform.values, self_object->world_to_object); } - const int handle = instances.add_reference(*collection); - instances.add_instance(handle, transform); + const int handle = instances->add_reference(*collection); + instances->add_instance(handle, transform); } - params.set_output("Geometry", geometry_set_out); + params.set_output("Geometry", GeometrySet::create_with_instances(instances.release())); } } // namespace blender::nodes::node_geo_collection_info_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc index 27e111822bf..2b732bba889 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #include "BLI_devirtualize_parameters.hh" +#include "BLI_generic_array.hh" #include "BLI_length_parameterize.hh" #include "BKE_curves.hh" @@ -8,6 +9,8 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "NOD_socket_search_link.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_curve_sample_cc { @@ -16,9 +19,16 @@ NODE_STORAGE_FUNCS(NodeGeometryCurveSample) static void node_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Geometry>(N_("Curve")) + b.add_input<decl::Geometry>(N_("Curves")) .only_realized_data() .supported_type(GEO_COMPONENT_TYPE_CURVE); + + b.add_input<decl::Float>(N_("Value"), "Value_Float").hide_value().supports_field(); + b.add_input<decl::Int>(N_("Value"), "Value_Int").hide_value().supports_field(); + b.add_input<decl::Vector>(N_("Value"), "Value_Vector").hide_value().supports_field(); + b.add_input<decl::Color>(N_("Value"), "Value_Color").hide_value().supports_field(); + b.add_input<decl::Bool>(N_("Value"), "Value_Bool").hide_value().supports_field(); + b.add_input<decl::Float>(N_("Factor")) .min(0.0f) .max(1.0f) @@ -30,6 +40,16 @@ static void node_declare(NodeDeclarationBuilder &b) .subtype(PROP_DISTANCE) .supports_field() .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_LENGTH; }); + b.add_input<decl::Int>(N_("Curve Index")).supports_field().make_available([](bNode &node) { + node_storage(node).use_all_curves = false; + }); + + b.add_output<decl::Float>(N_("Value"), "Value_Float").dependent_field(); + b.add_output<decl::Int>(N_("Value"), "Value_Int").dependent_field(); + b.add_output<decl::Vector>(N_("Value"), "Value_Vector").dependent_field(); + b.add_output<decl::Color>(N_("Value"), "Value_Color").dependent_field(); + b.add_output<decl::Bool>(N_("Value"), "Value_Bool").dependent_field(); + b.add_output<decl::Vector>(N_("Position")).dependent_field(); b.add_output<decl::Vector>(N_("Tangent")).dependent_field(); b.add_output<decl::Vector>(N_("Normal")).dependent_field(); @@ -37,13 +57,17 @@ static void node_declare(NodeDeclarationBuilder &b) static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) { + uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); + uiItemR(layout, ptr, "use_all_curves", 0, nullptr, ICON_NONE); } static void node_type_init(bNodeTree * /*tree*/, bNode *node) { NodeGeometryCurveSample *data = MEM_cnew<NodeGeometryCurveSample>(__func__); - data->mode = GEO_NODE_CURVE_SAMPLE_LENGTH; + data->mode = GEO_NODE_CURVE_SAMPLE_FACTOR; + data->use_all_curves = false; + data->data_type = CD_PROP_FLOAT; node->storage = data; } @@ -51,16 +75,62 @@ static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryCurveSample &storage = node_storage(*node); const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode; + const eCustomDataType data_type = eCustomDataType(storage.data_type); + + bNodeSocket *in_socket_float = static_cast<bNodeSocket *>(node->inputs.first)->next; + bNodeSocket *in_socket_int32 = in_socket_float->next; + bNodeSocket *in_socket_vector = in_socket_int32->next; + bNodeSocket *in_socket_color4f = in_socket_vector->next; + bNodeSocket *in_socket_bool = in_socket_color4f->next; - bNodeSocket *factor = static_cast<bNodeSocket *>(node->inputs.first)->next; + bNodeSocket *factor = in_socket_bool->next; bNodeSocket *length = factor->next; + bNodeSocket *curve_index = length->next; nodeSetSocketAvailability(ntree, factor, mode == GEO_NODE_CURVE_SAMPLE_FACTOR); nodeSetSocketAvailability(ntree, length, mode == GEO_NODE_CURVE_SAMPLE_LENGTH); + nodeSetSocketAvailability(ntree, curve_index, !storage.use_all_curves); + + nodeSetSocketAvailability(ntree, in_socket_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, in_socket_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, in_socket_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, in_socket_bool, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, in_socket_int32, data_type == CD_PROP_INT32); + + bNodeSocket *out_socket_float = static_cast<bNodeSocket *>(node->outputs.first); + bNodeSocket *out_socket_int32 = out_socket_float->next; + bNodeSocket *out_socket_vector = out_socket_int32->next; + bNodeSocket *out_socket_color4f = out_socket_vector->next; + bNodeSocket *out_socket_bool = out_socket_color4f->next; + + nodeSetSocketAvailability(ntree, out_socket_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, out_socket_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, out_socket_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, out_socket_bool, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, out_socket_int32, data_type == CD_PROP_INT32); +} + +static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) +{ + const NodeDeclaration &declaration = *params.node_type().fixed_declaration; + search_link_ops_for_declarations(params, declaration.inputs().take_front(4)); + search_link_ops_for_declarations(params, declaration.outputs().take_front(3)); + + const std::optional<eCustomDataType> type = node_data_type_to_custom_data_type( + eNodeSocketDatatype(params.other_socket().type)); + if (type && *type != CD_PROP_STRING) { + /* The input and output sockets have the same name. */ + params.add_item(IFACE_("Value"), [type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("GeometryNodeSampleCurve"); + node_storage(node).data_type = *type; + params.update_and_connect_available_socket(node, "Value"); + }); + } } static void sample_indices_and_lengths(const Span<float> accumulated_lengths, const Span<float> sample_lengths, + const GeometryNodeCurveSampleMode length_mode, const IndexMask mask, MutableSpan<int> r_segment_indices, MutableSpan<float> r_length_in_segment) @@ -70,10 +140,13 @@ static void sample_indices_and_lengths(const Span<float> accumulated_lengths, mask.to_best_mask_type([&](const auto mask) { for (const int64_t i : mask) { + const float sample_length = length_mode == GEO_NODE_CURVE_SAMPLE_FACTOR ? + sample_lengths[i] * total_length : + sample_lengths[i]; int segment_i; float factor_in_segment; length_parameterize::sample_at_length(accumulated_lengths, - std::clamp(sample_lengths[i], 0.0f, total_length), + std::clamp(sample_length, 0.0f, total_length), segment_i, factor_in_segment, &hint); @@ -89,6 +162,7 @@ static void sample_indices_and_lengths(const Span<float> accumulated_lengths, static void sample_indices_and_factors_to_compressed(const Span<float> accumulated_lengths, const Span<float> sample_lengths, + const GeometryNodeCurveSampleMode length_mode, const IndexMask mask, MutableSpan<int> r_segment_indices, MutableSpan<float> r_factor_in_segment) @@ -96,16 +170,32 @@ static void sample_indices_and_factors_to_compressed(const Span<float> accumulat const float total_length = accumulated_lengths.last(); length_parameterize::SampleSegmentHint hint; - mask.to_best_mask_type([&](const auto mask) { - for (const int64_t i : IndexRange(mask.size())) { - const float length = sample_lengths[mask[i]]; - length_parameterize::sample_at_length(accumulated_lengths, - std::clamp(length, 0.0f, total_length), - r_segment_indices[i], - r_factor_in_segment[i], - &hint); - } - }); + switch (length_mode) { + case GEO_NODE_CURVE_SAMPLE_FACTOR: + mask.to_best_mask_type([&](const auto mask) { + for (const int64_t i : IndexRange(mask.size())) { + const float length = sample_lengths[mask[i]] * total_length; + length_parameterize::sample_at_length(accumulated_lengths, + std::clamp(length, 0.0f, total_length), + r_segment_indices[i], + r_factor_in_segment[i], + &hint); + } + }); + break; + case GEO_NODE_CURVE_SAMPLE_LENGTH: + mask.to_best_mask_type([&](const auto mask) { + for (const int64_t i : IndexRange(mask.size())) { + const float length = sample_lengths[mask[i]]; + length_parameterize::sample_at_length(accumulated_lengths, + std::clamp(length, 0.0f, total_length), + r_segment_indices[i], + r_factor_in_segment[i], + &hint); + } + }); + break; + } } /** @@ -115,10 +205,12 @@ static void sample_indices_and_factors_to_compressed(const Span<float> accumulat class SampleFloatSegmentsFunction : public fn::MultiFunction { private: Array<float> accumulated_lengths_; + GeometryNodeCurveSampleMode length_mode_; public: - SampleFloatSegmentsFunction(Array<float> accumulated_lengths) - : accumulated_lengths_(std::move(accumulated_lengths)) + SampleFloatSegmentsFunction(Array<float> accumulated_lengths, + const GeometryNodeCurveSampleMode length_mode) + : accumulated_lengths_(std::move(accumulated_lengths)), length_mode_(length_mode) { static fn::MFSignature signature = create_signature(); this->set_signature(&signature); @@ -141,7 +233,8 @@ class SampleFloatSegmentsFunction : public fn::MultiFunction { MutableSpan<float> lengths_in_segments = params.uninitialized_single_output<float>( 2, "Length in Curve"); - sample_indices_and_lengths(accumulated_lengths_, lengths, mask, indices, lengths_in_segments); + sample_indices_and_lengths( + accumulated_lengths_, lengths, length_mode_, mask, indices, lengths_in_segments); } }; @@ -153,15 +246,27 @@ class SampleCurveFunction : public fn::MultiFunction { * that the curve is not freed before the function can execute. */ GeometrySet geometry_set_; + GField src_field_; + GeometryNodeCurveSampleMode length_mode_; + + fn::MFSignature signature_; + + std::optional<bke::CurvesFieldContext> source_context_; + std::unique_ptr<FieldEvaluator> source_evaluator_; + const GVArray *source_data_; public: - SampleCurveFunction(GeometrySet geometry_set) : geometry_set_(std::move(geometry_set)) + SampleCurveFunction(GeometrySet geometry_set, + const GeometryNodeCurveSampleMode length_mode, + const GField &src_field) + : geometry_set_(std::move(geometry_set)), src_field_(src_field), length_mode_(length_mode) { - static fn::MFSignature signature = create_signature(); - this->set_signature(&signature); + signature_ = create_signature(); + this->set_signature(&signature_); + this->evaluate_source(); } - static fn::MFSignature create_signature() + fn::MFSignature create_signature() { blender::fn::MFSignatureBuilder signature{"Sample Curve"}; signature.single_input<int>("Curve Index"); @@ -169,6 +274,7 @@ class SampleCurveFunction : public fn::MultiFunction { signature.single_output<float3>("Position"); signature.single_output<float3>("Tangent"); signature.single_output<float3>("Normal"); + signature.single_output("Value", src_field_.cpp_type()); return signature.build(); } @@ -180,6 +286,7 @@ class SampleCurveFunction : public fn::MultiFunction { 3, "Tangent"); MutableSpan<float3> sampled_normals = params.uninitialized_single_output_if_required<float3>( 4, "Normal"); + GMutableSpan sampled_values = params.uninitialized_single_output_if_required(5, "Value"); auto return_default = [&]() { if (!sampled_positions.is_empty()) { @@ -218,18 +325,40 @@ class SampleCurveFunction : public fn::MultiFunction { Array<int> indices; Array<float> factors; + GArray<> src_original_values(source_data_->type()); + GArray<> src_evaluated_values(source_data_->type()); + + auto fill_invalid = [&](const IndexMask mask) { + if (!sampled_positions.is_empty()) { + sampled_positions.fill_indices(mask, float3(0)); + } + if (!sampled_tangents.is_empty()) { + sampled_tangents.fill_indices(mask, float3(0)); + } + if (!sampled_normals.is_empty()) { + sampled_normals.fill_indices(mask, float3(0)); + } + if (!sampled_values.is_empty()) { + attribute_math::convert_to_static_type(source_data_->type(), [&](auto dummy) { + using T = decltype(dummy); + sampled_values.typed<T>().fill_indices(mask, {}); + }); + } + }; auto sample_curve = [&](const int curve_i, const IndexMask mask) { + const Span<float> accumulated_lengths = curves.evaluated_lengths_for_curve(curve_i, + cyclic[curve_i]); + if (accumulated_lengths.is_empty()) { + fill_invalid(mask); + return; + } /* Store the sampled indices and factors in arrays the size of the mask. * Then, during interpolation, move the results back to the masked indices. */ indices.reinitialize(mask.size()); factors.reinitialize(mask.size()); sample_indices_and_factors_to_compressed( - curves.evaluated_lengths_for_curve(curve_i, cyclic[curve_i]), - lengths, - mask, - indices, - factors); + accumulated_lengths, lengths, length_mode_, mask, indices, factors); const IndexRange evaluated_points = curves.evaluated_points_for_curve(curve_i); if (!sampled_positions.is_empty()) { @@ -254,54 +383,67 @@ class SampleCurveFunction : public fn::MultiFunction { sampled_normals[i] = math::normalize(sampled_normals[i]); } } + if (!sampled_values.is_empty()) { + const IndexRange points = curves.points_for_curve(curve_i); + src_original_values.reinitialize(points.size()); + source_data_->materialize_compressed_to_uninitialized(points, src_original_values.data()); + src_evaluated_values.reinitialize(curves.evaluated_points_for_curve(curve_i).size()); + curves.interpolate_to_evaluated(curve_i, src_original_values, src_evaluated_values); + attribute_math::convert_to_static_type(source_data_->type(), [&](auto dummy) { + using T = decltype(dummy); + const Span<T> src_evaluated_values_typed = src_evaluated_values.as_span().typed<T>(); + MutableSpan<T> sampled_values_typed = sampled_values.typed<T>(); + length_parameterize::interpolate_to_masked<T>( + src_evaluated_values_typed, indices, factors, mask, sampled_values_typed); + }); + } }; - if (curve_indices.is_single()) { - sample_curve(curve_indices.get_internal_single(), mask); + if (const std::optional<int> curve_i = curve_indices.get_if_single()) { + if (curves.curves_range().contains(*curve_i)) { + sample_curve(*curve_i, mask); + } + else { + fill_invalid(mask); + } } else { + Vector<int64_t> invalid_indices; MultiValueMap<int, int64_t> indices_per_curve; devirtualize_varray(curve_indices, [&](const auto curve_indices) { for (const int64_t i : mask) { - indices_per_curve.add(curve_indices[i], i); + const int curve_i = curve_indices[i]; + if (curves.curves_range().contains(curve_i)) { + indices_per_curve.add(curve_i, i); + } + else { + invalid_indices.append(i); + } } }); for (const int curve_i : indices_per_curve.keys()) { sample_curve(curve_i, IndexMask(indices_per_curve.lookup(curve_i))); } + fill_invalid(IndexMask(invalid_indices)); } } -}; -/** - * Pre-process the lengths or factors used for the sampling, turning factors into lengths, and - * clamping between zero and the total length of the curves. Do this as a separate operation in the - * field tree to make the sampling simpler, and to let the evaluator optimize better. - * - * \todo Use a mutable single input instead when they are supported. - */ -static Field<float> get_length_input_field(GeoNodeExecParams params, - const GeometryNodeCurveSampleMode mode, - const float curves_total_length) -{ - if (mode == GEO_NODE_CURVE_SAMPLE_LENGTH) { - return params.extract_input<Field<float>>("Length"); + private: + void evaluate_source() + { + const Curves &curves_id = *geometry_set_.get_curves_for_read(); + const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry); + source_context_.emplace(bke::CurvesFieldContext{curves, ATTR_DOMAIN_POINT}); + source_evaluator_ = std::make_unique<FieldEvaluator>(*source_context_, curves.points_num()); + source_evaluator_->add(src_field_); + source_evaluator_->evaluate(); + source_data_ = &source_evaluator_->get_evaluated(0); } - - /* Convert the factor to a length. */ - Field<float> factor_field = params.get_input<Field<float>>("Factor"); - auto clamp_fn = std::make_unique<fn::CustomMF_SI_SO<float, float>>( - __func__, - [curves_total_length](float factor) { return factor * curves_total_length; }, - fn::CustomMF_presets::AllSpanOrSingle()); - - return Field<float>(FieldOperation::Create(std::move(clamp_fn), {std::move(factor_field)}), 0); -} +}; static Array<float> curve_accumulated_lengths(const bke::CurvesGeometry &curves) { - curves.ensure_evaluated_lengths(); Array<float> curve_lengths(curves.curves_num()); const VArray<bool> cyclic = curves.cyclic(); @@ -313,9 +455,56 @@ static Array<float> curve_accumulated_lengths(const bke::CurvesGeometry &curves) return curve_lengths; } +static GField get_input_attribute_field(GeoNodeExecParams ¶ms, const eCustomDataType data_type) +{ + switch (data_type) { + case CD_PROP_FLOAT: + return params.extract_input<Field<float>>("Value_Float"); + case CD_PROP_FLOAT3: + return params.extract_input<Field<float3>>("Value_Vector"); + case CD_PROP_COLOR: + return params.extract_input<Field<ColorGeometry4f>>("Value_Color"); + case CD_PROP_BOOL: + return params.extract_input<Field<bool>>("Value_Bool"); + case CD_PROP_INT32: + return params.extract_input<Field<int>>("Value_Int"); + default: + BLI_assert_unreachable(); + } + return {}; +} + +static void output_attribute_field(GeoNodeExecParams ¶ms, GField field) +{ + switch (bke::cpp_type_to_custom_data_type(field.cpp_type())) { + case CD_PROP_FLOAT: { + params.set_output("Value_Float", Field<float>(field)); + break; + } + case CD_PROP_FLOAT3: { + params.set_output("Value_Vector", Field<float3>(field)); + break; + } + case CD_PROP_COLOR: { + params.set_output("Value_Color", Field<ColorGeometry4f>(field)); + break; + } + case CD_PROP_BOOL: { + params.set_output("Value_Bool", Field<bool>(field)); + break; + } + case CD_PROP_INT32: { + params.set_output("Value_Int", Field<int>(field)); + break; + } + default: + break; + } +} + static void node_geo_exec(GeoNodeExecParams params) { - GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); + GeometrySet geometry_set = params.extract_input<GeometrySet>("Curves"); if (!geometry_set.has_curves()) { params.set_default_remaining_outputs(); return; @@ -328,18 +517,18 @@ static void node_geo_exec(GeoNodeExecParams params) return; } - Array<float> curve_lengths = curve_accumulated_lengths(curves); - const float total_length = curve_lengths.last(); - if (total_length == 0.0f) { - params.set_default_remaining_outputs(); - return; - } + curves.ensure_evaluated_lengths(); const NodeGeometryCurveSample &storage = node_storage(params.node()); const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode; - Field<float> length_field = get_length_input_field(params, mode, total_length); + const eCustomDataType data_type = eCustomDataType(storage.data_type); - auto sample_fn = std::make_unique<SampleCurveFunction>(std::move(geometry_set)); + Field<float> length_field = params.extract_input<Field<float>>( + mode == GEO_NODE_CURVE_SAMPLE_FACTOR ? "Factor" : "Length"); + GField src_values_field = get_input_attribute_field(params, data_type); + + auto sample_fn = std::make_unique<SampleCurveFunction>( + std::move(geometry_set), mode, std::move(src_values_field)); std::shared_ptr<FieldOperation> sample_op; if (curves.curves_num() == 1) { @@ -347,15 +536,26 @@ static void node_geo_exec(GeoNodeExecParams params) {fn::make_constant_field<int>(0), std::move(length_field)}); } else { - auto index_fn = std::make_unique<SampleFloatSegmentsFunction>(std::move(curve_lengths)); - auto index_op = FieldOperation::Create(std::move(index_fn), {std::move(length_field)}); - sample_op = FieldOperation::Create(std::move(sample_fn), - {Field<int>(index_op, 0), Field<float>(index_op, 1)}); + Field<int> curve_index; + Field<float> length_in_curve; + if (storage.use_all_curves) { + auto index_fn = std::make_unique<SampleFloatSegmentsFunction>( + curve_accumulated_lengths(curves), mode); + auto index_op = FieldOperation::Create(std::move(index_fn), {std::move(length_field)}); + curve_index = Field<int>(index_op, 0); + length_in_curve = Field<float>(index_op, 1); + } + else { + curve_index = params.extract_input<Field<int>>("Curve Index"); + length_in_curve = std::move(length_field); + } + sample_op = FieldOperation::Create(std::move(sample_fn), {curve_index, length_in_curve}); } params.set_output("Position", Field<float3>(sample_op, 0)); params.set_output("Tangent", Field<float3>(sample_op, 1)); params.set_output("Normal", Field<float3>(sample_op, 2)); + output_attribute_field(params, GField(sample_op, 3)); } } // namespace blender::nodes::node_geo_curve_sample_cc @@ -374,6 +574,6 @@ void register_node_type_geo_curve_sample() node_type_storage( &ntype, "NodeGeometryCurveSample", node_free_standard_storage, node_copy_standard_storage); ntype.draw_buttons = file_ns::node_layout; - + ntype.gather_link_search_ops = file_ns::node_gather_link_searches; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc index 7cdb7cc55f4..7a63aa59509 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc @@ -310,7 +310,8 @@ static void node_geo_exec(GeoNodeExecParams params) ATTR_DOMAIN_CORNER); const VArraySpan<float3> rest_positions = mesh_attributes_eval.lookup<float3>(rest_position_name, ATTR_DOMAIN_POINT); - const Span<float2> surface_uv_coords = curves.surface_uv_coords(); + const VArraySpan<float2> surface_uv_coords = curves.attributes().lookup_or_default( + "surface_uv_coordinate", ATTR_DOMAIN_CURVE, float2(0)); const Span<MLoopTri> looptris_orig = surface_mesh_orig->looptris(); const Span<MLoopTri> looptris_eval = surface_mesh_eval->looptris(); @@ -379,19 +380,23 @@ static void node_geo_exec(GeoNodeExecParams params) invalid_uv_count); /* Then also deform edit curve information for use in sculpt mode. */ const CurvesGeometry &curves_orig = CurvesGeometry::wrap(edit_hints->curves_id_orig.geometry); - deform_curves(curves_orig, - *surface_mesh_orig, - *surface_mesh_eval, - surface_uv_coords, - reverse_uv_sampler_orig, - reverse_uv_sampler_eval, - corner_normals_orig, - corner_normals_eval, - rest_positions, - transforms.surface_to_curves, - edit_hint_positions, - edit_hint_rotations, - invalid_uv_count); + const VArraySpan<float2> surface_uv_coords_orig = curves_orig.attributes().lookup_or_default( + "surface_uv_coordinate", ATTR_DOMAIN_CURVE, float2(0)); + if (!surface_uv_coords_orig.is_empty()) { + deform_curves(curves_orig, + *surface_mesh_orig, + *surface_mesh_eval, + surface_uv_coords_orig, + reverse_uv_sampler_orig, + reverse_uv_sampler_eval, + corner_normals_orig, + corner_normals_eval, + rest_positions, + transforms.surface_to_curves, + edit_hint_positions, + edit_hint_rotations, + invalid_uv_count); + } } curves.tag_positions_changed(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc index 85938dff81d..e7775760c58 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc @@ -4,6 +4,7 @@ #include "UI_resources.h" #include "BLI_array.hh" +#include "BLI_array_utils.hh" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -12,6 +13,7 @@ #include "BKE_attribute_math.hh" #include "BKE_curves.hh" #include "BKE_customdata.h" +#include "BKE_instances.hh" #include "BKE_mesh.h" #include "BKE_pointcloud.h" @@ -22,15 +24,9 @@ namespace blender::nodes::node_geo_delete_geometry_cc { using blender::bke::CustomDataAttributes; template<typename T> -static void copy_data_based_on_mask(Span<T> data, MutableSpan<T> r_data, IndexMask mask) -{ - for (const int i_out : mask.index_range()) { - r_data[i_out] = data[mask[i_out]]; - } -} - -template<typename T> -static void copy_data_based_on_map(Span<T> src, MutableSpan<T> dst, Span<int> index_map) +static void copy_data_based_on_map(const Span<T> src, + const Span<int> index_map, + MutableSpan<T> dst) { for (const int i_src : index_map.index_range()) { const int i_dst = index_map[i_src]; @@ -54,26 +50,17 @@ static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes if (!attribute) { continue; } - /* Only copy if it is on a domain we want. */ if (!domains.contains(attribute.domain)) { continue; } const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); - GSpanAttributeWriter result_attribute = dst_attributes.lookup_or_add_for_write_only_span( attribute_id, attribute.domain, data_type); - if (!result_attribute) { continue; } - - attribute_math::convert_to_static_type(data_type, [&](auto dummy) { - using T = decltype(dummy); - VArraySpan<T> span{attribute.varray.typed<T>()}; - MutableSpan<T> out_span = result_attribute.span.typed<T>(); - out_span.copy_from(span); - }); + attribute.varray.materialize(result_attribute.span.data()); result_attribute.finish(); } } @@ -94,26 +81,19 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin if (!attribute) { continue; } - /* Only copy if it is on a domain we want. */ if (domain != attribute.domain) { continue; } const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); - GSpanAttributeWriter result_attribute = dst_attributes.lookup_or_add_for_write_only_span( attribute_id, attribute.domain, data_type); - if (!result_attribute) { continue; } - attribute_math::convert_to_static_type(data_type, [&](auto dummy) { - using T = decltype(dummy); - VArraySpan<T> span{attribute.varray.typed<T>()}; - MutableSpan<T> out_span = result_attribute.span.typed<T>(); - copy_data_based_on_mask(span, out_span, mask); - }); + array_utils::gather(attribute.varray, mask, result_attribute.span); + result_attribute.finish(); } } @@ -130,16 +110,13 @@ static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind if (!attribute) { continue; } - /* Only copy if it is on a domain we want. */ if (domain != attribute.domain) { continue; } const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); - GSpanAttributeWriter result_attribute = dst_attributes.lookup_or_add_for_write_only_span( attribute_id, attribute.domain, data_type); - if (!result_attribute) { continue; } @@ -148,7 +125,7 @@ static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind using T = decltype(dummy); VArraySpan<T> span{attribute.varray.typed<T>()}; MutableSpan<T> out_span = result_attribute.span.typed<T>(); - copy_data_based_on_map(span, out_span, index_map); + copy_data_based_on_map(span, index_map, out_span); }); result_attribute.finish(); } @@ -375,8 +352,8 @@ static void separate_point_cloud_selection(GeometrySet &geometry_set, static void delete_selected_instances(GeometrySet &geometry_set, const Field<bool> &selection_field) { - InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); - bke::GeometryFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE}; + bke::Instances &instances = *geometry_set.get_instances_for_write(); + bke::InstancesFieldContext field_context{instances}; fn::FieldEvaluator evaluator{field_context, instances.instances_num()}; evaluator.set_selection(selection_field); @@ -387,7 +364,7 @@ static void delete_selected_instances(GeometrySet &geometry_set, return; } - instances.remove_instances(selection); + instances.remove(selection); } static void compute_selected_verts_from_vertex_selection(const Span<bool> vertex_selection, diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc index 091337c28cf..95173bd23a5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc @@ -15,6 +15,8 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "DEG_depsgraph_query.h" + #include "node_geometry_util.hh" namespace blender::nodes { @@ -208,6 +210,7 @@ static void geo_node_distribute_points_in_volume_exec(GeoNodeExecParams params) } const VolumeComponent *component = geometry_set.get_component_for_read<VolumeComponent>(); const Volume *volume = component->get_for_read(); + BKE_volume_load(volume, DEG_get_bmain(params.depsgraph())); Vector<float3> positions; diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc index f3a2b589490..bf018e1e04f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "BLI_array_utils.hh" #include "BLI_task.hh" #include "DNA_mesh_types.h" @@ -105,18 +106,6 @@ static void copy_data_based_on_pairs(Span<T> data, } } -/* Copy using the map. */ -template<typename T> -static void copy_data_based_on_new_to_old_map(Span<T> data, - MutableSpan<T> r_data, - const Span<int> new_to_old_map) -{ - for (const int i : r_data.index_range()) { - const int old_i = new_to_old_map[i]; - r_data[i] = data[old_i]; - } -} - /** * Transfers the attributes from the original mesh to the new mesh using the following logic: * - If the attribute was on the face domain it is now on the point domain, and this is true @@ -168,7 +157,6 @@ static void transfer_attributes( src_attribute.varray.type()); GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_only_span( attribute_id, out_domain, data_type); - if (!dst_attribute) { continue; } @@ -177,20 +165,24 @@ static void transfer_attributes( using T = decltype(dummy); VArraySpan<T> span{src_attribute.varray.typed<T>()}; MutableSpan<T> dst_span = dst_attribute.span.typed<T>(); - if (src_attribute.domain == ATTR_DOMAIN_FACE) { - dst_span.take_front(span.size()).copy_from(span); - if (keep_boundaries) { - copy_data_based_on_pairs(span, dst_span, boundary_vertex_to_relevant_face_map); - } - } - else if (src_attribute.domain == ATTR_DOMAIN_POINT) { - copy_data_based_on_vertex_types(span, dst_span, vertex_types, keep_boundaries); - } - else if (src_attribute.domain == ATTR_DOMAIN_EDGE) { - copy_data_based_on_new_to_old_map(span, dst_span, new_to_old_edges_map); - } - else { - copy_data_based_on_new_to_old_map(span, dst_span, new_to_old_face_corners_map); + switch (src_attribute.domain) { + case ATTR_DOMAIN_POINT: + copy_data_based_on_vertex_types(span, dst_span, vertex_types, keep_boundaries); + break; + case ATTR_DOMAIN_EDGE: + array_utils::gather(span, new_to_old_edges_map, dst_span); + break; + case ATTR_DOMAIN_FACE: + dst_span.take_front(span.size()).copy_from(span); + if (keep_boundaries) { + copy_data_based_on_pairs(span, dst_span, boundary_vertex_to_relevant_face_map); + } + break; + case ATTR_DOMAIN_CORNER: + array_utils::gather(span, new_to_old_face_corners_map, dst_span); + break; + default: + BLI_assert_unreachable(); } }); dst_attribute.finish(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc index 31f735da104..bcdb5b0800d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "BLI_array_utils.hh" #include "BLI_map.hh" #include "BLI_noise.hh" #include "BLI_span.hh" @@ -11,6 +12,7 @@ #include "BKE_attribute_math.hh" #include "BKE_curves.hh" +#include "BKE_instances.hh" #include "BKE_mesh.h" #include "BKE_pointcloud.h" @@ -104,16 +106,6 @@ static void threaded_slice_fill(Span<int> offsets, }); } -template<typename T> -static void threaded_mapped_copy(const Span<int> mapping, const Span<T> src, MutableSpan<T> dst) -{ - threading::parallel_for(mapping.index_range(), 512, [&](IndexRange range) { - for (const int i : range) { - dst[i] = src[mapping[i]]; - } - }); -} - static void copy_hashed_ids(const Span<int> src, const int hash, MutableSpan<int> dst) { for (const int i : src.index_range()) { @@ -439,17 +431,17 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set, MutableSpan<T> dst = dst_attribute.span.typed<T>(); switch (out_domain) { - case ATTR_DOMAIN_FACE: - threaded_slice_fill<T>(offsets, selection, src, dst); + case ATTR_DOMAIN_POINT: + array_utils::gather(src, vert_mapping, dst); break; case ATTR_DOMAIN_EDGE: - threaded_mapped_copy<T>(edge_mapping, src, dst); + array_utils::gather(src, edge_mapping, dst); break; - case ATTR_DOMAIN_POINT: - threaded_mapped_copy<T>(vert_mapping, src, dst); + case ATTR_DOMAIN_FACE: + threaded_slice_fill<T>(offsets, selection, src, dst); break; case ATTR_DOMAIN_CORNER: - threaded_mapped_copy<T>(loop_mapping, src, dst); + array_utils::gather(src, loop_mapping, dst); break; default: break; @@ -649,7 +641,7 @@ static void copy_edge_attributes_without_id(GeometrySet &geometry_set, threaded_slice_fill<T>(offsets, selection, src, dst); break; case ATTR_DOMAIN_POINT: - threaded_mapped_copy<T>(point_mapping, src, dst); + array_utils::gather(src, point_mapping, dst); break; default: break; @@ -1024,10 +1016,9 @@ static void duplicate_instances(GeometrySet &geometry_set, return; } - const InstancesComponent &src_instances = - *geometry_set.get_component_for_read<InstancesComponent>(); + const bke::Instances &src_instances = *geometry_set.get_instances_for_read(); - bke::GeometryFieldContext field_context{src_instances, ATTR_DOMAIN_INSTANCE}; + bke::InstancesFieldContext field_context{src_instances}; FieldEvaluator evaluator{field_context, src_instances.instances_num()}; evaluator.add(count_field); evaluator.set_selection(selection_field); @@ -1041,20 +1032,20 @@ static void duplicate_instances(GeometrySet &geometry_set, return; } - GeometrySet dst_geometry; - InstancesComponent &dst_instances = dst_geometry.get_component_for_write<InstancesComponent>(); - dst_instances.resize(offsets.last()); + std::unique_ptr<bke::Instances> dst_instances = std::make_unique<bke::Instances>(); + + dst_instances->resize(offsets.last()); for (const int i_selection : selection.index_range()) { const IndexRange range = range_for_offsets_index(offsets, i_selection); if (range.size() == 0) { continue; } - const int old_handle = src_instances.instance_reference_handles()[i_selection]; - const InstanceReference reference = src_instances.references()[old_handle]; - const int new_handle = dst_instances.add_reference(reference); - const float4x4 transform = src_instances.instance_transforms()[i_selection]; - dst_instances.instance_transforms().slice(range).fill(transform); - dst_instances.instance_reference_handles().slice(range).fill(new_handle); + const int old_handle = src_instances.reference_handles()[i_selection]; + const bke::InstanceReference reference = src_instances.references()[old_handle]; + const int new_handle = dst_instances->add_reference(reference); + const float4x4 transform = src_instances.transforms()[i_selection]; + dst_instances->transforms().slice(range).fill(transform); + dst_instances->reference_handles().slice(range).fill(new_handle); } copy_attributes_without_id(geometry_set, @@ -1062,18 +1053,18 @@ static void duplicate_instances(GeometrySet &geometry_set, ATTR_DOMAIN_INSTANCE, offsets, selection, - *src_instances.attributes(), - *dst_instances.attributes_for_write()); + src_instances.attributes(), + dst_instances->attributes_for_write()); if (attribute_outputs.duplicate_index) { - create_duplicate_index_attribute(*dst_instances.attributes_for_write(), + create_duplicate_index_attribute(dst_instances->attributes_for_write(), ATTR_DOMAIN_INSTANCE, selection, attribute_outputs, offsets); } - geometry_set = std::move(dst_geometry); + geometry_set = GeometrySet::create_with_instances(dst_instances.release()); } /** \} */ diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc index 786c88eb15d..b7b54b89883 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "BLI_array_utils.hh" #include "BLI_disjoint_set.hh" #include "BLI_task.hh" #include "BLI_vector_set.hh" @@ -175,24 +176,6 @@ static MPoly new_poly(const int loopstart, const int totloop) return poly; } -template<typename T> void copy_with_indices(MutableSpan<T> dst, Span<T> src, Span<int> indices) -{ - BLI_assert(dst.size() == indices.size()); - for (const int i : dst.index_range()) { - dst[i] = src[indices[i]]; - } -} - -template<typename T> void copy_with_mask(MutableSpan<T> dst, Span<T> src, IndexMask mask) -{ - BLI_assert(dst.size() == mask.size()); - threading::parallel_for(mask.index_range(), 512, [&](const IndexRange range) { - for (const int i : range) { - dst[i] = src[mask[i]]; - } - }); -} - /** * \param get_mix_indices_fn: Returns a Span of indices of the source points to mix for every * result point. @@ -260,28 +243,29 @@ static void extrude_mesh_vertices(Mesh &mesh, if (!ELEM(meta_data.domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE)) { return true; } + if (meta_data.data_type == CD_PROP_STRING) { + return true; + } GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span( id, meta_data.domain, meta_data.data_type); - attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) { - using T = decltype(dummy); - MutableSpan<T> data = attribute.span.typed<T>(); - switch (attribute.domain) { - case ATTR_DOMAIN_POINT: { - /* New vertices copy the attribute values from their source vertex. */ - copy_with_mask(data.slice(new_vert_range), data.as_span(), selection); - break; - } - case ATTR_DOMAIN_EDGE: { + switch (attribute.domain) { + case ATTR_DOMAIN_POINT: + /* New vertices copy the attribute values from their source vertex. */ + array_utils::gather(attribute.span, selection, attribute.span.slice(new_vert_range)); + break; + case ATTR_DOMAIN_EDGE: + attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) { + using T = decltype(dummy); + MutableSpan<T> data = attribute.span.typed<T>(); /* New edge values are mixed from of all the edges connected to the source vertex. */ copy_with_mixing(data.slice(new_edge_range), data.as_span(), [&](const int i) { return vert_to_edge_map[selection[i]].as_span(); }); - break; - } - default: - BLI_assert_unreachable(); - } - }); + }); + break; + default: + BLI_assert_unreachable(); + } attribute.finish(); return true; @@ -505,6 +489,9 @@ static void extrude_mesh_edges(Mesh &mesh, MutableAttributeAccessor attributes = mesh.attributes_for_write(); attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) { + if (meta_data.data_type == CD_PROP_STRING) { + return true; + } GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span( id, meta_data.domain, meta_data.data_type); if (!attribute) { @@ -517,13 +504,14 @@ static void extrude_mesh_edges(Mesh &mesh, switch (attribute.domain) { case ATTR_DOMAIN_POINT: { /* New vertices copy the attribute values from their source vertex. */ - copy_with_indices(data.slice(new_vert_range), data.as_span(), new_vert_indices); + array_utils::gather( + data.as_span(), new_vert_indices.as_span(), data.slice(new_vert_range)); break; } case ATTR_DOMAIN_EDGE: { /* Edges parallel to original edges copy the edge attributes from the original edges. */ MutableSpan<T> duplicate_data = data.slice(duplicate_edge_range); - copy_with_mask(duplicate_data, data.as_span(), edge_selection); + array_utils::gather(data.as_span(), edge_selection, duplicate_data); /* Edges connected to original vertices mix values of selected connected edges. */ MutableSpan<T> connect_data = data.slice(connect_edge_range); @@ -888,6 +876,9 @@ static void extrude_mesh_face_regions(Mesh &mesh, MutableAttributeAccessor attributes = mesh.attributes_for_write(); attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) { + if (meta_data.data_type == CD_PROP_STRING) { + return true; + } GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span( id, meta_data.domain, meta_data.data_type); if (!attribute) { @@ -900,17 +891,18 @@ static void extrude_mesh_face_regions(Mesh &mesh, switch (attribute.domain) { case ATTR_DOMAIN_POINT: { /* New vertices copy the attributes from their original vertices. */ - copy_with_indices(data.slice(new_vert_range), data.as_span(), new_vert_indices); + array_utils::gather( + data.as_span(), new_vert_indices.as_span(), data.slice(new_vert_range)); break; } case ATTR_DOMAIN_EDGE: { /* Edges parallel to original edges copy the edge attributes from the original edges. */ MutableSpan<T> boundary_data = data.slice(boundary_edge_range); - copy_with_indices(boundary_data, data.as_span(), boundary_edge_indices); + array_utils::gather(data.as_span(), boundary_edge_indices.as_span(), boundary_data); /* Edges inside of face regions also just duplicate their source data. */ MutableSpan<T> new_inner_data = data.slice(new_inner_edge_range); - copy_with_indices(new_inner_data, data.as_span(), new_inner_edge_indices); + array_utils::gather(data.as_span(), new_inner_edge_indices.as_span(), new_inner_data); /* Edges connected to original vertices mix values of selected connected edges. */ MutableSpan<T> connect_data = data.slice(connect_edge_range); @@ -922,8 +914,8 @@ static void extrude_mesh_face_regions(Mesh &mesh, case ATTR_DOMAIN_FACE: { /* New faces on the side of extrusions get the values from the corresponding selected * face. */ - copy_with_indices( - data.slice(side_poly_range), data.as_span(), edge_extruded_face_indices); + array_utils::gather( + data.as_span(), edge_extruded_face_indices.as_span(), data.slice(side_poly_range)); break; } case ATTR_DOMAIN_CORNER: { @@ -1150,6 +1142,9 @@ static void extrude_individual_mesh_faces(Mesh &mesh, MutableAttributeAccessor attributes = mesh.attributes_for_write(); attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) { + if (meta_data.data_type == CD_PROP_STRING) { + return true; + } GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span( id, meta_data.domain, meta_data.data_type); if (!attribute) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc index 613425716d4..95a0013a9e1 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc @@ -47,6 +47,9 @@ static void mesh_flip_faces(Mesh &mesh, const Field<bool> &selection_field) MutableAttributeAccessor attributes = mesh.attributes_for_write(); attributes.for_all( [&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { + if (meta_data.data_type == CD_PROP_STRING) { + return true; + } if (meta_data.domain == ATTR_DOMAIN_CORNER) { GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span( attribute_id, ATTR_DOMAIN_CORNER, meta_data.data_type); diff --git a/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc index 8e64209a418..45808ff9996 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "BKE_instances.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_geometry_to_instance_cc { @@ -13,15 +15,13 @@ static void node_declare(NodeDeclarationBuilder &b) static void node_geo_exec(GeoNodeExecParams params) { Vector<GeometrySet> geometries = params.extract_input<Vector<GeometrySet>>("Geometry"); - GeometrySet instances_geometry; - InstancesComponent &instances_component = - instances_geometry.get_component_for_write<InstancesComponent>(); + std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>(); for (GeometrySet &geometry : geometries) { geometry.ensure_owns_direct_data(); - const int handle = instances_component.add_reference(std::move(geometry)); - instances_component.add_instance(handle, float4x4::identity()); + const int handle = instances->add_reference(std::move(geometry)); + instances->add_instance(handle, float4x4::identity()); } - params.set_output("Instances", std::move(instances_geometry)); + params.set_output("Instances", GeometrySet::create_with_instances(instances.release())); } } // namespace blender::nodes::node_geo_geometry_to_instance_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc b/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc index 75d43d2f771..f78815ebe74 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc @@ -2,6 +2,8 @@ #include "node_geometry_util.hh" +#include "BKE_instances.hh" + namespace blender::nodes::node_geo_input_instance_rotation_cc { static void node_declare(NodeDeclarationBuilder &b) @@ -15,12 +17,9 @@ class InstanceRotationFieldInput final : public bke::InstancesFieldInput { { } - GVArray get_varray_for_context(const InstancesComponent &instances, - const IndexMask /*mask*/) const final + GVArray get_varray_for_context(const bke::Instances &instances, IndexMask /*mask*/) const final { - auto rotation_fn = [&](const int i) -> float3 { - return instances.instance_transforms()[i].to_euler(); - }; + auto rotation_fn = [&](const int i) -> float3 { return instances.transforms()[i].to_euler(); }; return VArray<float3>::ForFunc(instances.instances_num(), rotation_fn); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc b/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc index dbb98d7e393..12ac48f8f11 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc @@ -2,6 +2,8 @@ #include "node_geometry_util.hh" +#include "BKE_instances.hh" + namespace blender::nodes::node_geo_input_instance_scale_cc { static void node_declare(NodeDeclarationBuilder &b) @@ -15,12 +17,9 @@ class InstanceScaleFieldInput final : public bke::InstancesFieldInput { { } - GVArray get_varray_for_context(const InstancesComponent &instances, - const IndexMask /*mask*/) const final + GVArray get_varray_for_context(const bke::Instances &instances, IndexMask /*mask*/) const final { - auto scale_fn = [&](const int i) -> float3 { - return instances.instance_transforms()[i].scale(); - }; + auto scale_fn = [&](const int i) -> float3 { return instances.transforms()[i].scale(); }; return VArray<float3>::ForFunc(instances.instances_num(), scale_fn); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc index c6f214e72ac..64546684186 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc @@ -2,6 +2,7 @@ #include "DNA_collection_types.h" +#include "BLI_array_utils.hh" #include "BLI_hash.h" #include "BLI_task.hh" @@ -9,6 +10,7 @@ #include "UI_resources.h" #include "BKE_attribute_math.hh" +#include "BKE_instances.hh" #include "node_geometry_util.hh" @@ -43,7 +45,7 @@ static void node_declare(NodeDeclarationBuilder &b) } static void add_instances_from_component( - InstancesComponent &dst_component, + bke::Instances &dst_component, const GeometryComponent &src_component, const GeometrySet &instance, const GeoNodeExecParams ¶ms, @@ -80,25 +82,23 @@ static void add_instances_from_component( const int select_len = selection.index_range().size(); dst_component.resize(start_len + select_len); - MutableSpan<int> dst_handles = dst_component.instance_reference_handles().slice(start_len, - select_len); - MutableSpan<float4x4> dst_transforms = dst_component.instance_transforms().slice(start_len, - select_len); + MutableSpan<int> dst_handles = dst_component.reference_handles().slice(start_len, select_len); + MutableSpan<float4x4> dst_transforms = dst_component.transforms().slice(start_len, select_len); VArray<float3> positions = src_component.attributes()->lookup_or_default<float3>( "position", domain, {0, 0, 0}); - const InstancesComponent *src_instances = instance.get_component_for_read<InstancesComponent>(); + const bke::Instances *src_instances = instance.get_instances_for_read(); /* Maps handles from the source instances to handles on the new instance. */ Array<int> handle_mapping; /* Only fill #handle_mapping when it may be used below. */ if (src_instances != nullptr && (!pick_instance.is_single() || pick_instance.get_internal_single())) { - Span<InstanceReference> src_references = src_instances->references(); + Span<bke::InstanceReference> src_references = src_instances->references(); handle_mapping.reinitialize(src_references.size()); for (const int src_instance_handle : src_references.index_range()) { - const InstanceReference &reference = src_references[src_instance_handle]; + const bke::InstanceReference &reference = src_references[src_instance_handle]; const int dst_instance_handle = dst_component.add_reference(reference); handle_mapping[src_instance_handle] = dst_instance_handle; } @@ -106,7 +106,7 @@ static void add_instances_from_component( const int full_instance_handle = dst_component.add_reference(instance); /* Add this reference last, because it is the most likely one to be removed later on. */ - const int empty_reference_handle = dst_component.add_reference(InstanceReference()); + const int empty_reference_handle = dst_component.add_reference(bke::InstanceReference()); threading::parallel_for(selection.index_range(), 1024, [&](IndexRange selection_range) { for (const int range_i : selection_range) { @@ -129,12 +129,11 @@ static void add_instances_from_component( const int index = mod_i(original_index, std::max(src_instances_num, 1)); if (index < src_instances_num) { /* Get the reference to the source instance. */ - const int src_handle = src_instances->instance_reference_handles()[index]; + const int src_handle = src_instances->reference_handles()[index]; dst_handle = handle_mapping[src_handle]; /* Take transforms of the source instance into account. */ - mul_m4_m4_post(dst_transform.values, - src_instances->instance_transforms()[index].values); + mul_m4_m4_post(dst_transform.values, src_instances->transforms()[index].values); } } } @@ -157,7 +156,7 @@ static void add_instances_from_component( } } - bke::CustomDataAttributes &instance_attributes = dst_component.instance_attributes(); + bke::CustomDataAttributes &instance_attributes = dst_component.custom_data_attributes(); for (const auto item : attributes_to_propagate.items()) { const AttributeIDRef &attribute_id = item.key; const AttributeKind attribute_kind = item.value; @@ -174,18 +173,7 @@ static void add_instances_from_component( dst_attribute_opt = instance_attributes.get_for_write(attribute_id); } BLI_assert(dst_attribute_opt); - const GMutableSpan dst_attribute = dst_attribute_opt->slice(start_len, select_len); - threading::parallel_for(selection.index_range(), 1024, [&](IndexRange selection_range) { - attribute_math::convert_to_static_type(attribute_kind.data_type, [&](auto dummy) { - using T = decltype(dummy); - VArray<T> src = src_attribute.typed<T>(); - MutableSpan<T> dst = dst_attribute.typed<T>(); - for (const int range_i : selection_range) { - const int i = selection[range_i]; - dst[range_i] = src[i]; - } - }); - }); + array_utils::gather(src_attribute, selection, dst_attribute_opt->slice(start_len, select_len)); } } @@ -196,7 +184,15 @@ static void node_geo_exec(GeoNodeExecParams params) instance.ensure_owns_direct_data(); geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { - InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); + /* It's important not to invalidate the existing #InstancesComponent because it owns references + * to other geometry sets that are processed by this node. */ + InstancesComponent &instances_component = + geometry_set.get_component_for_write<InstancesComponent>(); + bke::Instances *dst_instances = instances_component.get_for_write(); + if (dst_instances == nullptr) { + dst_instances = new bke::Instances(); + instances_component.replace(dst_instances); + } const Array<GeometryComponentType> types{ GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}; @@ -208,14 +204,13 @@ static void node_geo_exec(GeoNodeExecParams params) for (const GeometryComponentType type : types) { if (geometry_set.has(type)) { - add_instances_from_component(instances, + add_instances_from_component(*dst_instances, *geometry_set.get_component_for_read(type), instance, params, attributes_to_propagate); } } - geometry_set.remove_geometry_during_modify(); }); @@ -223,8 +218,9 @@ static void node_geo_exec(GeoNodeExecParams params) * process them needlessly. * This should eventually be moved into the loop above, but currently this is quite tricky * because it might remove references that the loop still wants to iterate over. */ - InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); - instances.remove_unused_references(); + if (bke::Instances *instances = geometry_set.get_instances_for_write()) { + instances->remove_unused_references(); + } params.set_output("Instances", std::move(geometry_set)); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc index d4072a05e5f..acd00d119ab 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc @@ -3,6 +3,7 @@ #include "DNA_pointcloud_types.h" #include "BKE_attribute_math.hh" +#include "BKE_instances.hh" #include "BKE_pointcloud.h" #include "node_geometry_util.hh" @@ -27,7 +28,7 @@ static void convert_instances_to_points(GeometrySet &geometry_set, Field<float> radius_field, const Field<bool> selection_field) { - const InstancesComponent &instances = *geometry_set.get_component_for_read<InstancesComponent>(); + const bke::Instances &instances = *geometry_set.get_instances_for_read(); const bke::InstancesFieldContext context{instances}; fn::FieldEvaluator evaluator{context, instances.instances_num()}; @@ -70,7 +71,7 @@ static void convert_instances_to_points(GeometrySet &geometry_set, const AttributeIDRef &attribute_id = item.key; const AttributeKind attribute_kind = item.value; - const GVArray src = instances.attributes()->lookup_or_default( + const GVArray src = instances.attributes().lookup_or_default( attribute_id, ATTR_DOMAIN_INSTANCE, attribute_kind.data_type); BLI_assert(src); GSpanAttributeWriter dst = point_attributes.lookup_or_add_for_write_only_span( diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc index 74d1b5561bb..ea2646a9786 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -2,6 +2,8 @@ #include "GEO_realize_instances.hh" +#include "BKE_instances.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_join_geometry_cc { @@ -29,6 +31,9 @@ static Map<AttributeIDRef, AttributeMetaData> get_final_attribute_info( if (attribute_id.is_named() && ignored_attributes.contains(attribute_id.name())) { return true; } + if (meta_data.data_type == CD_PROP_STRING) { + return true; + } info.add_or_modify( attribute_id, [&](AttributeMetaData *meta_data_final) { *meta_data_final = meta_data; }, @@ -97,31 +102,36 @@ static void join_attributes(Span<const GeometryComponent *> src_components, static void join_components(Span<const InstancesComponent *> src_components, GeometrySet &result) { - InstancesComponent &dst_component = result.get_component_for_write<InstancesComponent>(); + std::unique_ptr<bke::Instances> dst_instances = std::make_unique<bke::Instances>(); int tot_instances = 0; for (const InstancesComponent *src_component : src_components) { - tot_instances += src_component->instances_num(); + tot_instances += src_component->get_for_read()->instances_num(); } - dst_component.reserve(tot_instances); + dst_instances->reserve(tot_instances); for (const InstancesComponent *src_component : src_components) { - Span<InstanceReference> src_references = src_component->references(); + const bke::Instances &src_instances = *src_component->get_for_read(); + + Span<bke::InstanceReference> src_references = src_instances.references(); Array<int> handle_map(src_references.size()); for (const int src_handle : src_references.index_range()) { - handle_map[src_handle] = dst_component.add_reference(src_references[src_handle]); + handle_map[src_handle] = dst_instances->add_reference(src_references[src_handle]); } - Span<float4x4> src_transforms = src_component->instance_transforms(); - Span<int> src_reference_handles = src_component->instance_reference_handles(); + Span<float4x4> src_transforms = src_instances.transforms(); + Span<int> src_reference_handles = src_instances.reference_handles(); for (const int i : src_transforms.index_range()) { const int src_handle = src_reference_handles[i]; const int dst_handle = handle_map[src_handle]; const float4x4 &transform = src_transforms[i]; - dst_component.add_instance(dst_handle, transform); + dst_instances->add_instance(dst_handle, transform); } } + + result.replace_instances(dst_instances.release()); + InstancesComponent &dst_component = result.get_component_for_write<InstancesComponent>(); join_attributes(to_base_components(src_components), dst_component, {"position"}); } @@ -151,25 +161,23 @@ static void join_component_type(Span<GeometrySet> src_geometry_sets, GeometrySet return; } - GeometrySet instances_geometry_set; - InstancesComponent &instances = - instances_geometry_set.get_component_for_write<InstancesComponent>(); - if constexpr (is_same_any_v<Component, InstancesComponent, VolumeComponent>) { join_components(components, result); } else { + std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>(); for (const Component *component : components) { GeometrySet tmp_geo; tmp_geo.add(*component); - const int handle = instances.add_reference(InstanceReference{tmp_geo}); - instances.add_instance(handle, float4x4::identity()); + const int handle = instances->add_reference(bke::InstanceReference{tmp_geo}); + instances->add_instance(handle, float4x4::identity()); } geometry::RealizeInstancesOptions options; options.keep_original_ids = true; options.realize_instance_attributes = false; - GeometrySet joined_components = geometry::realize_instances(instances_geometry_set, options); + GeometrySet joined_components = geometry::realize_instances( + GeometrySet::create_with_instances(instances.release()), options); result.add(joined_components.get_component_for_write<Component>()); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc index cce3f4e3648..036af2d3b93 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc @@ -93,6 +93,10 @@ class CornersOfVertInput final : public bke::MeshFieldInput { } const Span<int> corners = vert_to_loop_map[vert_i]; + if (corners.is_empty()) { + corner_of_vertex[selection_i] = 0; + continue; + } /* Retrieve the connected edge indices as 64 bit integers for #materialize_compressed. */ corner_indices.reinitialize(corners.size()); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc index 053ef61deed..f0cc191e217 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc @@ -93,6 +93,10 @@ class EdgesOfVertInput final : public bke::MeshFieldInput { } const Span<int> edges = vert_to_edge_map[vert_i]; + if (edges.is_empty()) { + edge_of_vertex[selection_i] = 0; + continue; + } /* Retrieve the connected edge indices as 64 bit integers for #materialize_compressed. */ edge_indices.reinitialize(edges.size()); diff --git a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc index 3ce16fac464..83a2ddb1629 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc @@ -3,6 +3,7 @@ #include "BLI_math_matrix.h" #include "BKE_geometry_set_instances.hh" +#include "BKE_instances.hh" #include "UI_interface.h" #include "UI_resources.h" @@ -44,8 +45,8 @@ static void node_geo_exec(GeoNodeExecParams params) return; } - const float4x4 &object_matrix = object->obmat; - const float4x4 transform = float4x4(self_object->imat) * object_matrix; + const float4x4 &object_matrix = object->object_to_world; + const float4x4 transform = float4x4(self_object->world_to_object) * object_matrix; if (transform_space_relative) { params.set_output("Location", transform.translation()); @@ -68,14 +69,15 @@ static void node_geo_exec(GeoNodeExecParams params) GeometrySet geometry_set; if (params.get_input<bool>("As Instance")) { - InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); - const int handle = instances.add_reference(*object); + std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>(); + const int handle = instances->add_reference(*object); if (transform_space_relative) { - instances.add_instance(handle, transform); + instances->add_instance(handle, transform); } else { - instances.add_instance(handle, float4x4::identity()); + instances->add_instance(handle, float4x4::identity()); } + geometry_set = GeometrySet::create_with_instances(instances.release()); } else { geometry_set = bke::object_get_evaluated_geometry_set(*object); diff --git a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc index 4ed94e67e74..fac92a7500c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc @@ -2,6 +2,8 @@ #include "BLI_task.hh" +#include "BKE_instances.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_rotate_instances_cc { @@ -16,10 +18,10 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Instances")); } -static void rotate_instances(GeoNodeExecParams ¶ms, InstancesComponent &instances_component) +static void rotate_instances(GeoNodeExecParams ¶ms, bke::Instances &instances) { - const bke::InstancesFieldContext context{instances_component}; - fn::FieldEvaluator evaluator{context, instances_component.instances_num()}; + const bke::InstancesFieldContext context{instances}; + fn::FieldEvaluator evaluator{context, instances.instances_num()}; evaluator.set_selection(params.extract_input<Field<bool>>("Selection")); evaluator.add(params.extract_input<Field<float3>>("Rotation")); evaluator.add(params.extract_input<Field<float3>>("Pivot Point")); @@ -31,14 +33,14 @@ static void rotate_instances(GeoNodeExecParams ¶ms, InstancesComponent &inst const VArray<float3> pivots = evaluator.get_evaluated<float3>(1); const VArray<bool> local_spaces = evaluator.get_evaluated<bool>(2); - MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms(); + MutableSpan<float4x4> transforms = instances.transforms(); threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) { for (const int i_selection : range) { const int i = selection[i_selection]; const float3 pivot = pivots[i]; const float3 euler = rotations[i]; - float4x4 &instance_transform = instance_transforms[i]; + float4x4 &instance_transform = transforms[i]; float4x4 rotation_matrix; float3 used_pivot; @@ -81,9 +83,8 @@ static void rotate_instances(GeoNodeExecParams ¶ms, InstancesComponent &inst static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances"); - if (geometry_set.has_instances()) { - InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); - rotate_instances(params, instances); + if (bke::Instances *instances = geometry_set.get_instances_for_write()) { + rotate_instances(params, *instances); } params.set_output("Instances", std::move(geometry_set)); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc index 44851a0ade5..95bf7199d63 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc @@ -240,7 +240,11 @@ static void node_geo_exec(GeoNodeExecParams params) params.set_default_remaining_outputs(); return; } - if (mesh->totpoly == 0 && mesh->totvert != 0) { + if (mesh->totvert == 0) { + params.set_default_remaining_outputs(); + return; + } + if (mesh->totpoly == 0) { params.error_message_add(NodeWarningType::Error, TIP_("The source mesh must have faces")); params.set_default_remaining_outputs(); return; diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc index 21fe724e194..dacb130337f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc @@ -2,6 +2,8 @@ #include "BLI_task.hh" +#include "BKE_instances.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_scale_instances_cc { @@ -19,10 +21,10 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Instances")); } -static void scale_instances(GeoNodeExecParams ¶ms, InstancesComponent &instances_component) +static void scale_instances(GeoNodeExecParams ¶ms, bke::Instances &instances) { - const bke::InstancesFieldContext context{instances_component}; - fn::FieldEvaluator evaluator{context, instances_component.instances_num()}; + const bke::InstancesFieldContext context{instances}; + fn::FieldEvaluator evaluator{context, instances.instances_num()}; evaluator.set_selection(params.extract_input<Field<bool>>("Selection")); evaluator.add(params.extract_input<Field<float3>>("Scale")); evaluator.add(params.extract_input<Field<float3>>("Center")); @@ -34,13 +36,13 @@ static void scale_instances(GeoNodeExecParams ¶ms, InstancesComponent &insta const VArray<float3> pivots = evaluator.get_evaluated<float3>(1); const VArray<bool> local_spaces = evaluator.get_evaluated<bool>(2); - MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms(); + MutableSpan<float4x4> transforms = instances.transforms(); threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) { for (const int i_selection : range) { const int i = selection[i_selection]; const float3 pivot = pivots[i]; - float4x4 &instance_transform = instance_transforms[i]; + float4x4 &instance_transform = transforms[i]; if (local_spaces[i]) { instance_transform *= float4x4::from_location(pivot); @@ -61,9 +63,8 @@ static void scale_instances(GeoNodeExecParams ¶ms, InstancesComponent &insta static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances"); - if (geometry_set.has_instances()) { - InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); - scale_instances(params, instances); + if (bke::Instances *instances = geometry_set.get_instances_for_write()) { + scale_instances(params, *instances); } params.set_output("Instances", std::move(geometry_set)); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc index bbdabc09099..769a63f58cf 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc @@ -6,6 +6,7 @@ #include "BKE_curve.h" #include "BKE_curve_legacy_convert.hh" #include "BKE_curves.hh" +#include "BKE_instances.hh" #include "BKE_vfont.h" #include "BLI_hash.h" @@ -270,7 +271,7 @@ static std::optional<TextLayout> get_text_layout(GeoNodeExecParams ¶ms) /* Returns a mapping of UTF-32 character code to instance handle. */ static Map<int, int> create_curve_instances(GeoNodeExecParams ¶ms, TextLayout &layout, - InstancesComponent &instances) + bke::Instances &instances) { VFont *vfont = reinterpret_cast<VFont *>(params.node().id); Map<int, int> handles; @@ -315,13 +316,13 @@ static Map<int, int> create_curve_instances(GeoNodeExecParams ¶ms, return handles; } -static void add_instances_from_handles(InstancesComponent &instances, +static void add_instances_from_handles(bke::Instances &instances, const Map<int, int> &char_handles, const TextLayout &layout) { instances.resize(layout.positions.size()); - MutableSpan<int> handles = instances.instance_reference_handles(); - MutableSpan<float4x4> transforms = instances.instance_transforms(); + MutableSpan<int> handles = instances.reference_handles(); + MutableSpan<float4x4> transforms = instances.transforms(); threading::parallel_for(IndexRange(layout.positions.size()), 256, [&](IndexRange range) { for (const int i : range) { @@ -333,9 +334,9 @@ static void add_instances_from_handles(InstancesComponent &instances, static void create_attributes(GeoNodeExecParams ¶ms, const TextLayout &layout, - InstancesComponent &instances) + bke::Instances &instances) { - MutableAttributeAccessor attributes = *instances.attributes_for_write(); + MutableAttributeAccessor attributes = instances.attributes_for_write(); if (params.output_is_required("Line")) { StrongAnonymousAttributeID line_id = StrongAnonymousAttributeID("Line"); @@ -385,13 +386,12 @@ static void node_geo_exec(GeoNodeExecParams params) } /* Create and add instances. */ - GeometrySet geometry_set_out; - InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>(); - Map<int, int> char_handles = create_curve_instances(params, *layout, instances); - add_instances_from_handles(instances, char_handles, *layout); - create_attributes(params, *layout, instances); + std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>(); + Map<int, int> char_handles = create_curve_instances(params, *layout, *instances); + add_instances_from_handles(*instances, char_handles, *layout); + create_attributes(params, *layout, *instances); - params.set_output("Curve Instances", std::move(geometry_set_out)); + params.set_output("Curve Instances", GeometrySet::create_with_instances(instances.release())); } } // namespace blender::nodes::node_geo_string_to_curves_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc index 4130cad3bda..3c8a3f3ca76 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc @@ -11,6 +11,7 @@ #include "DNA_volume_types.h" #include "BKE_curves.hh" +#include "BKE_instances.hh" #include "BKE_mesh.h" #include "BKE_pointcloud.h" #include "BKE_volume.h" @@ -67,18 +68,18 @@ static void transform_pointcloud(PointCloud &pointcloud, const float4x4 &transfo position.finish(); } -static void translate_instances(InstancesComponent &instances, const float3 translation) +static void translate_instances(bke::Instances &instances, const float3 translation) { - MutableSpan<float4x4> transforms = instances.instance_transforms(); + MutableSpan<float4x4> transforms = instances.transforms(); for (float4x4 &transform : transforms) { add_v3_v3(transform.ptr()[3], translation); } } -static void transform_instances(InstancesComponent &instances, const float4x4 &transform) +static void transform_instances(bke::Instances &instances, const float4x4 &transform) { - MutableSpan<float4x4> instance_transforms = instances.instance_transforms(); - for (float4x4 &instance_transform : instance_transforms) { + MutableSpan<float4x4> transforms = instances.transforms(); + for (float4x4 &instance_transform : transforms) { instance_transform = transform * instance_transform; } } @@ -185,8 +186,8 @@ static void translate_geometry_set(GeoNodeExecParams ¶ms, if (Volume *volume = geometry.get_volume_for_write()) { translate_volume(params, *volume, translation, depsgraph); } - if (geometry.has_instances()) { - translate_instances(geometry.get_component_for_write<InstancesComponent>(), translation); + if (bke::Instances *instances = geometry.get_instances_for_write()) { + translate_instances(*instances, translation); } if (bke::CurvesEditHints *curve_edit_hints = geometry.get_curve_edit_hints_for_write()) { translate_curve_edit_hints(*curve_edit_hints, translation); @@ -210,8 +211,8 @@ void transform_geometry_set(GeoNodeExecParams ¶ms, if (Volume *volume = geometry.get_volume_for_write()) { transform_volume(params, *volume, transform, depsgraph); } - if (geometry.has_instances()) { - transform_instances(geometry.get_component_for_write<InstancesComponent>(), transform); + if (bke::Instances *instances = geometry.get_instances_for_write()) { + transform_instances(*instances, transform); } if (bke::CurvesEditHints *curve_edit_hints = geometry.get_curve_edit_hints_for_write()) { transform_curve_edit_hints(*curve_edit_hints, transform); diff --git a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc index 3e9fe99adb0..23052abddc4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc @@ -2,6 +2,8 @@ #include "BLI_task.hh" +#include "BKE_instances.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_translate_instances_cc { @@ -15,10 +17,10 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Instances")); } -static void translate_instances(GeoNodeExecParams ¶ms, InstancesComponent &instances_component) +static void translate_instances(GeoNodeExecParams ¶ms, bke::Instances &instances) { - const bke::InstancesFieldContext context{instances_component}; - fn::FieldEvaluator evaluator{context, instances_component.instances_num()}; + const bke::InstancesFieldContext context{instances}; + fn::FieldEvaluator evaluator{context, instances.instances_num()}; evaluator.set_selection(params.extract_input<Field<bool>>("Selection")); evaluator.add(params.extract_input<Field<float3>>("Translation")); evaluator.add(params.extract_input<Field<bool>>("Local Space")); @@ -28,16 +30,16 @@ static void translate_instances(GeoNodeExecParams ¶ms, InstancesComponent &i const VArray<float3> translations = evaluator.get_evaluated<float3>(0); const VArray<bool> local_spaces = evaluator.get_evaluated<bool>(1); - MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms(); + MutableSpan<float4x4> transforms = instances.transforms(); threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) { for (const int i_selection : range) { const int i = selection[i_selection]; if (local_spaces[i]) { - instance_transforms[i] *= float4x4::from_location(translations[i]); + transforms[i] *= float4x4::from_location(translations[i]); } else { - add_v3_v3(instance_transforms[i].values[3], translations[i]); + add_v3_v3(transforms[i].values[3], translations[i]); } } }); @@ -46,9 +48,8 @@ static void translate_instances(GeoNodeExecParams ¶ms, InstancesComponent &i static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances"); - if (geometry_set.has_instances()) { - InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); - translate_instances(params, instances); + if (bke::Instances *instances = geometry_set.get_instances_for_write()) { + translate_instances(params, *instances); } params.set_output("Instances", std::move(geometry_set)); } |