Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/nodes')
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc139
1 files changed, 132 insertions, 7 deletions
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 66199769586..8bcd7d69bc5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -23,8 +23,12 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "NOD_type_conversions.hh"
+
#include "node_geometry_util.hh"
+using blender::fn::GVArray_For_GSpan;
+
static bNodeSocketTemplate geo_node_join_geometry_in[] = {
{SOCK_GEOMETRY,
N_("Geometry"),
@@ -298,6 +302,127 @@ static void join_components(Span<const VolumeComponent *> src_components, Geomet
UNUSED_VARS(src_components, dst_component);
}
+/**
+ * \note This takes advantage of the fact that creating attributes on joined curves never
+ * changes a point attribute into a spline attribute; it is always the other way around.
+ */
+static void ensure_control_point_attribute(const StringRef name,
+ const CustomDataType data_type,
+ Span<CurveComponent *> src_components,
+ CurveEval &result)
+{
+ MutableSpan<SplinePtr> splines = result.splines();
+ const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
+
+ /* In order to fill point attributes with spline domain attribute values where necessary, keep
+ * track of the curve each spline came from while iterating over the splines in the result. */
+ int src_component_index = 0;
+ int spline_index_in_component = 0;
+ const CurveEval *current_curve = src_components[src_component_index]->get_for_read();
+
+ for (SplinePtr &spline : splines) {
+ std::optional<GSpan> attribute = spline->attributes.get_for_read(name);
+
+ if (attribute) {
+ if (attribute->type() != type) {
+ /* In this case, the attribute exists, but it has the wrong type. So create a buffer
+ * for the converted values, do the conversion, and then replace the attribute. */
+ void *converted_buffer = MEM_mallocN_aligned(
+ spline->size() * type.size(), type.alignment(), __func__);
+
+ const DataTypeConversions &conversions = blender::nodes::get_implicit_type_conversions();
+ conversions.try_convert(std::make_unique<GVArray_For_GSpan>(*attribute), type)
+ ->materialize(converted_buffer);
+
+ spline->attributes.remove(name);
+ spline->attributes.create_by_move(name, data_type, converted_buffer);
+ }
+ }
+ else {
+ spline->attributes.create(name, data_type);
+
+ if (current_curve->attributes.get_for_read(name)) {
+ /* In this case the attribute did not exist, but there is a spline domain attribute
+ * we can retrieve a value from, as a spline to point domain conversion. So fill the
+ * new attribute with the value for this spline. */
+ GVArrayPtr current_curve_attribute = current_curve->attributes.get_for_read(
+ name, data_type, nullptr);
+
+ BLI_assert(spline->attributes.get_for_read(name));
+ std::optional<GMutableSpan> new_attribute = spline->attributes.get_for_write(name);
+
+ BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
+ current_curve_attribute->get(spline_index_in_component, buffer);
+ type.fill_initialized(buffer, new_attribute->data(), new_attribute->size());
+ }
+ }
+
+ /* Move to the next spline and maybe the next input component. */
+ spline_index_in_component++;
+ if (spline != splines.last() && spline_index_in_component >= current_curve->splines().size()) {
+ src_component_index++;
+ spline_index_in_component = 0;
+
+ current_curve = src_components[src_component_index]->get_for_read();
+ }
+ }
+}
+
+/**
+ * Fill data for an attribute on the new curve based on all source curves.
+ */
+static void ensure_spline_attribute(const StringRef name,
+ const CustomDataType data_type,
+ Span<CurveComponent *> src_components,
+ CurveEval &result)
+{
+ const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
+
+ result.attributes.create(name, data_type);
+ GMutableSpan result_attribute = *result.attributes.get_for_write(name);
+
+ int offset = 0;
+ for (const CurveComponent *component : src_components) {
+ const CurveEval &curve = *component->get_for_read();
+ const int size = curve.splines().size();
+ if (size == 0) {
+ continue;
+ }
+ GVArrayPtr read_attribute = curve.attributes.get_for_read(name, data_type, nullptr);
+ GVArray_GSpan src_span{*read_attribute};
+
+ const void *src_buffer = src_span.data();
+ type.copy_to_initialized_n(src_buffer, result_attribute[offset], size);
+
+ offset += size;
+ }
+}
+
+/**
+ * Special handling for copying spline attributes. This is necessary because we move the splines
+ * out of the source components instead of copying them, meaning we can no longer access point
+ * domain attributes on the source components.
+ *
+ * \warning Splines have been moved out of the source components at this point, so it
+ * is important to only read curve-level data (spline domain attributes) from them.
+ */
+static void join_curve_attributes(const Map<std::string, AttributeMetaData> &info,
+ Span<CurveComponent *> src_components,
+ CurveEval &result)
+{
+ for (const Map<std::string, AttributeMetaData>::Item &item : info.items()) {
+ const StringRef name = item.key;
+ const AttributeMetaData meta_data = item.value;
+
+ if (meta_data.domain == ATTR_DOMAIN_CURVE) {
+ ensure_spline_attribute(name, meta_data.data_type, src_components, result);
+ }
+ else {
+ ensure_control_point_attribute(name, meta_data.data_type, src_components, result);
+ }
+ }
+}
+
static void join_curve_components(MutableSpan<GeometrySet> src_geometry_sets, GeometrySet &result)
{
Vector<CurveComponent *> src_components;
@@ -320,6 +445,11 @@ static void join_curve_components(MutableSpan<GeometrySet> src_geometry_sets, Ge
return;
}
+ /* Retrieve attribute info before moving the splines out of the input components. */
+ const Map<std::string, AttributeMetaData> info = get_final_attribute_info(
+ {(const GeometryComponent **)src_components.data(), src_components.size()},
+ {"position", "radius", "tilt", "cyclic", "resolution"});
+
CurveComponent &dst_component = result.get_component_for_write<CurveComponent>();
CurveEval *dst_curve = new CurveEval();
for (CurveComponent *component : src_components) {
@@ -328,14 +458,9 @@ static void join_curve_components(MutableSpan<GeometrySet> src_geometry_sets, Ge
dst_curve->add_spline(std::move(spline));
}
}
-
- /* For now, remove all custom attributes, since they might have different types,
- * or an attribute might not exist on all splines. */
dst_curve->attributes.reallocate(dst_curve->splines().size());
- CustomData_reset(&dst_curve->attributes.data);
- for (SplinePtr &spline : dst_curve->splines()) {
- CustomData_reset(&spline->attributes.data);
- }
+
+ join_curve_attributes(info, src_components, *dst_curve);
dst_component.replace(dst_curve);
}