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/geometry')
-rw-r--r--source/blender/nodes/geometry/CMakeLists.txt2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc27
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc26
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc45
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc38
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc23
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc7
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc9
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc30
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc26
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_length.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc126
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc23
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc59
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc63
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc27
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc44
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc37
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc26
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc24
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc50
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc38
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc15
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc30
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc31
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc1119
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_edge_split.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc119
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc25
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc37
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_raycast.cc9
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc76
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_position.cc35
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transform.cc9
58 files changed, 1878 insertions, 579 deletions
diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt
index f38562a8926..48a83dc825b 100644
--- a/source/blender/nodes/geometry/CMakeLists.txt
+++ b/source/blender/nodes/geometry/CMakeLists.txt
@@ -98,6 +98,7 @@ set(SRC
nodes/node_geo_curve_to_points.cc
nodes/node_geo_curve_trim.cc
nodes/node_geo_delete_geometry.cc
+ nodes/node_geo_duplicate_elements.cc
nodes/node_geo_distribute_points_on_faces.cc
nodes/node_geo_dual_mesh.cc
nodes/node_geo_edge_split.cc
@@ -116,6 +117,7 @@ set(SRC
nodes/node_geo_input_mesh_edge_neighbors.cc
nodes/node_geo_input_mesh_edge_vertices.cc
nodes/node_geo_input_mesh_face_area.cc
+ nodes/node_geo_input_mesh_face_is_planar.cc
nodes/node_geo_input_mesh_face_neighbors.cc
nodes/node_geo_input_mesh_island.cc
nodes/node_geo_input_mesh_vertex_neighbors.cc
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc
index b83aa8b69a9..0980c2d6e72 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc
@@ -137,15 +137,15 @@ static void node_geo_exec(GeoNodeExecParams params)
geometry_set = geometry::realize_instances_legacy(geometry_set);
- if (!geometry_set.has_curve()) {
+ if (!geometry_set.has_curves()) {
params.set_default_remaining_outputs();
return;
}
const CurveComponent &curve_component = *geometry_set.get_component_for_read<CurveComponent>();
- const CurveEval &curve = *curve_component.get_for_read();
- const Span<SplinePtr> splines = curve.splines();
- curve.assert_valid_point_attributes();
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read());
+ const Span<SplinePtr> splines = curve->splines();
+ curve->assert_valid_point_attributes();
evaluate_splines(splines);
@@ -167,9 +167,9 @@ static void node_geo_exec(GeoNodeExecParams params)
end_result.get_component_for_write<PointCloudComponent>();
CurveToPointsResults start_attributes = curve_to_points_create_result_attributes(
- start_point_component, curve);
+ start_point_component, *curve);
CurveToPointsResults end_attributes = curve_to_points_create_result_attributes(
- end_point_component, curve);
+ end_point_component, *curve);
copy_endpoint_attributes(splines, offsets.as_span(), start_attributes, end_attributes);
copy_spline_domain_attributes(curve_component, offsets.as_span(), start_point_component);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc
index 6deaf5b554a..2fe06a17adf 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc
@@ -19,15 +19,15 @@ static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
geometry_set = geometry::realize_instances_legacy(geometry_set);
- if (!geometry_set.has_curve()) {
+ if (!geometry_set.has_curves()) {
params.set_output("Curve", geometry_set);
return;
}
/* Retrieve data for write access so we can avoid new allocations for the reversed data. */
CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
- CurveEval &curve = *curve_component.get_for_write();
- MutableSpan<SplinePtr> splines = curve.splines();
+ std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read());
+ MutableSpan<SplinePtr> splines = curve->splines();
const std::string selection_name = params.extract_input<std::string>("Selection");
VArray<bool> selection = curve_component.attribute_get_for_read(
@@ -41,6 +41,8 @@ static void node_geo_exec(GeoNodeExecParams params)
}
});
+ geometry_set.replace_curve(curve_eval_to_curves(*curve));
+
params.set_output("Curve", geometry_set);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
index f0a201c5adf..729ccca5f04 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
@@ -33,24 +33,24 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static BezierSpline::HandleType handle_type_from_input_type(const GeometryNodeCurveHandleType type)
+static HandleType handle_type_from_input_type(const GeometryNodeCurveHandleType type)
{
switch (type) {
case GEO_NODE_CURVE_HANDLE_AUTO:
- return BezierSpline::HandleType::Auto;
+ return BEZIER_HANDLE_AUTO;
case GEO_NODE_CURVE_HANDLE_ALIGN:
- return BezierSpline::HandleType::Align;
+ return BEZIER_HANDLE_ALIGN;
case GEO_NODE_CURVE_HANDLE_FREE:
- return BezierSpline::HandleType::Free;
+ return BEZIER_HANDLE_FREE;
case GEO_NODE_CURVE_HANDLE_VECTOR:
- return BezierSpline::HandleType::Vector;
+ return BEZIER_HANDLE_VECTOR;
}
BLI_assert_unreachable();
- return BezierSpline::HandleType::Auto;
+ return BEZIER_HANDLE_AUTO;
}
static void select_curve_by_handle_type(const CurveEval &curve,
- const BezierSpline::HandleType type,
+ const HandleType type,
const GeometryNodeCurveHandleMode mode,
const MutableSpan<bool> r_selection)
{
@@ -59,10 +59,10 @@ static void select_curve_by_handle_type(const CurveEval &curve,
threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
for (const int i_spline : range) {
const Spline &spline = *splines[i_spline];
- if (spline.type() == Spline::Type::Bezier) {
+ if (spline.type() == CURVE_TYPE_BEZIER) {
const BezierSpline &bezier_spline = static_cast<const BezierSpline &>(spline);
- Span<BezierSpline::HandleType> types_left = bezier_spline.handle_types_left();
- Span<BezierSpline::HandleType> types_right = bezier_spline.handle_types_right();
+ Span<int8_t> types_left = bezier_spline.handle_types_left();
+ Span<int8_t> types_right = bezier_spline.handle_types_right();
for (const int i_point : IndexRange(bezier_spline.size())) {
r_selection[offsets[i_spline] + i_point] = (mode & GEO_NODE_CURVE_HANDLE_LEFT &&
types_left[i_point] == type) ||
@@ -81,7 +81,7 @@ static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryCurveSelectHandles *storage =
(const NodeGeometryCurveSelectHandles *)params.node().storage;
- const BezierSpline::HandleType handle_type = handle_type_from_input_type(
+ const HandleType handle_type = handle_type_from_input_type(
(GeometryNodeCurveHandleType)storage->handle_type);
const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)storage->mode;
@@ -89,9 +89,8 @@ static void node_geo_exec(GeoNodeExecParams params)
geometry_set = geometry::realize_instances_legacy(geometry_set);
CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
- const CurveEval *curve = curve_component.get_for_read();
-
- if (curve != nullptr) {
+ if (curve_component.has_curves()) {
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read());
const std::string selection_name = params.extract_input<std::string>("Selection");
OutputAttribute_Typed<bool> selection =
curve_component.attribute_try_get_for_output_only<bool>(selection_name, ATTR_DOMAIN_POINT);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc
index b574b2e3cff..537c7c42610 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc
@@ -31,20 +31,20 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static BezierSpline::HandleType handle_type_from_input_type(GeometryNodeCurveHandleType type)
+static HandleType handle_type_from_input_type(GeometryNodeCurveHandleType type)
{
switch (type) {
case GEO_NODE_CURVE_HANDLE_AUTO:
- return BezierSpline::HandleType::Auto;
+ return BEZIER_HANDLE_AUTO;
case GEO_NODE_CURVE_HANDLE_ALIGN:
- return BezierSpline::HandleType::Align;
+ return BEZIER_HANDLE_ALIGN;
case GEO_NODE_CURVE_HANDLE_FREE:
- return BezierSpline::HandleType::Free;
+ return BEZIER_HANDLE_FREE;
case GEO_NODE_CURVE_HANDLE_VECTOR:
- return BezierSpline::HandleType::Vector;
+ return BEZIER_HANDLE_VECTOR;
}
BLI_assert_unreachable();
- return BezierSpline::HandleType::Auto;
+ return BEZIER_HANDLE_AUTO;
}
static void node_geo_exec(GeoNodeExecParams params)
@@ -56,31 +56,31 @@ static void node_geo_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
geometry_set = geometry::realize_instances_legacy(geometry_set);
- if (!geometry_set.has_curve()) {
+ if (!geometry_set.has_curves()) {
params.set_output("Curve", geometry_set);
return;
}
/* Retrieve data for write access so we can avoid new allocations for the handles data. */
CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
- CurveEval &curve = *curve_component.get_for_write();
- MutableSpan<SplinePtr> splines = curve.splines();
+ std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read());
+ MutableSpan<SplinePtr> splines = curve->splines();
const std::string selection_name = params.extract_input<std::string>("Selection");
VArray<bool> selection = curve_component.attribute_get_for_read(
selection_name, ATTR_DOMAIN_POINT, true);
- const BezierSpline::HandleType new_handle_type = handle_type_from_input_type(type);
+ const HandleType new_handle_type = handle_type_from_input_type(type);
int point_index = 0;
bool has_bezier_spline = false;
for (SplinePtr &spline : splines) {
- if (spline->type() != Spline::Type::Bezier) {
+ if (spline->type() != CURVE_TYPE_BEZIER) {
point_index += spline->positions().size();
continue;
}
BezierSpline &bezier_spline = static_cast<BezierSpline &>(*spline);
- if (ELEM(new_handle_type, BezierSpline::HandleType::Free, BezierSpline::HandleType::Align)) {
+ if (ELEM(new_handle_type, BEZIER_HANDLE_FREE, BEZIER_HANDLE_ALIGN)) {
/* In this case the automatically calculated handle types need to be "baked", because
* they're possibly changing from a type that is calculated automatically to a type that
* is positioned manually. */
@@ -101,6 +101,8 @@ static void node_geo_exec(GeoNodeExecParams params)
bezier_spline.mark_cache_invalid();
}
+ geometry_set.replace_curve(curve_eval_to_curves(*curve));
+
if (!has_bezier_spline) {
params.error_message_add(NodeWarningType::Info, TIP_("No Bezier splines in input curve"));
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc
index b8696e1eb52..4e3b0839da7 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc
@@ -148,8 +148,8 @@ static SplinePtr poly_to_bezier(const Spline &input)
output->positions().copy_from(input.positions());
output->radii().copy_from(input.radii());
output->tilts().copy_from(input.tilts());
- output->handle_types_left().fill(BezierSpline::HandleType::Vector);
- output->handle_types_right().fill(BezierSpline::HandleType::Vector);
+ output->handle_types_left().fill(BEZIER_HANDLE_VECTOR);
+ output->handle_types_right().fill(BEZIER_HANDLE_VECTOR);
output->set_resolution(12);
Spline::copy_base_settings(input, *output);
output->attributes = input.attributes;
@@ -166,8 +166,8 @@ static SplinePtr nurbs_to_bezier(const Spline &input)
scale_input_assign<float3>(input.positions(), 3, 2, output->handle_positions_right());
scale_input_assign<float>(input.radii(), 3, 2, output->radii());
scale_input_assign<float>(input.tilts(), 3, 2, output->tilts());
- output->handle_types_left().fill(BezierSpline::HandleType::Align);
- output->handle_types_right().fill(BezierSpline::HandleType::Align);
+ output->handle_types_left().fill(BEZIER_HANDLE_ALIGN);
+ output->handle_types_right().fill(BEZIER_HANDLE_ALIGN);
output->set_resolution(nurbs_spline.resolution());
Spline::copy_base_settings(input, *output);
output->attributes.reallocate(output->size());
@@ -183,11 +183,11 @@ static SplinePtr nurbs_to_bezier(const Spline &input)
static SplinePtr convert_to_bezier(const Spline &input, GeoNodeExecParams params)
{
switch (input.type()) {
- case Spline::Type::Bezier:
+ case CURVE_TYPE_BEZIER:
return input.copy();
- case Spline::Type::Poly:
+ case CURVE_TYPE_POLY:
return poly_to_bezier(input);
- case Spline::Type::NURBS:
+ case CURVE_TYPE_NURBS:
if (input.size() < 6) {
params.error_message_add(
NodeWarningType::Info,
@@ -202,6 +202,10 @@ static SplinePtr convert_to_bezier(const Spline &input, GeoNodeExecParams params
}
return nurbs_to_bezier(input);
}
+ case CURVE_TYPE_CATMULL_ROM: {
+ BLI_assert_unreachable();
+ return {};
+ }
}
BLI_assert_unreachable();
return {};
@@ -210,12 +214,15 @@ static SplinePtr convert_to_bezier(const Spline &input, GeoNodeExecParams params
static SplinePtr convert_to_nurbs(const Spline &input)
{
switch (input.type()) {
- case Spline::Type::NURBS:
+ case CURVE_TYPE_NURBS:
return input.copy();
- case Spline::Type::Bezier:
+ case CURVE_TYPE_BEZIER:
return bezier_to_nurbs(input);
- case Spline::Type::Poly:
+ case CURVE_TYPE_POLY:
return poly_to_nurbs(input);
+ case CURVE_TYPE_CATMULL_ROM:
+ BLI_assert_unreachable();
+ return {};
}
BLI_assert_unreachable();
return {};
@@ -229,40 +236,40 @@ static void node_geo_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
geometry_set = geometry::realize_instances_legacy(geometry_set);
- if (!geometry_set.has_curve()) {
+ if (!geometry_set.has_curves()) {
params.set_output("Curve", geometry_set);
return;
}
const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>();
- const CurveEval &curve = *curve_component->get_for_read();
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component->get_for_read());
const std::string selection_name = params.extract_input<std::string>("Selection");
VArray<bool> selection = curve_component->attribute_get_for_read(
selection_name, ATTR_DOMAIN_CURVE, true);
std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>();
- for (const int i : curve.splines().index_range()) {
+ for (const int i : curve->splines().index_range()) {
if (selection[i]) {
switch (output_type) {
case GEO_NODE_SPLINE_TYPE_POLY:
- new_curve->add_spline(convert_to_poly_spline(*curve.splines()[i]));
+ new_curve->add_spline(convert_to_poly_spline(*curve->splines()[i]));
break;
case GEO_NODE_SPLINE_TYPE_BEZIER:
- new_curve->add_spline(convert_to_bezier(*curve.splines()[i], params));
+ new_curve->add_spline(convert_to_bezier(*curve->splines()[i], params));
break;
case GEO_NODE_SPLINE_TYPE_NURBS:
- new_curve->add_spline(convert_to_nurbs(*curve.splines()[i]));
+ new_curve->add_spline(convert_to_nurbs(*curve->splines()[i]));
break;
}
}
else {
- new_curve->add_spline(curve.splines()[i]->copy());
+ new_curve->add_spline(curve->splines()[i]->copy());
}
}
- new_curve->attributes = curve.attributes;
- params.set_output("Curve", GeometrySet::create_with_curve(new_curve.release()));
+ new_curve->attributes = curve->attributes;
+ params.set_output("Curve", GeometrySet::create_with_curves(curve_eval_to_curves(*new_curve)));
}
} // namespace blender::nodes::node_geo_legacy_curve_spline_type_cc
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc
index 8ae9df78936..03f7aec8838 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc
@@ -111,8 +111,8 @@ static void subdivide_bezier_segment(const BezierSpline &src,
MutableSpan<float3> dst_positions,
MutableSpan<float3> dst_handles_left,
MutableSpan<float3> dst_handles_right,
- MutableSpan<BezierSpline::HandleType> dst_type_left,
- MutableSpan<BezierSpline::HandleType> dst_type_right)
+ MutableSpan<int8_t> dst_type_left,
+ MutableSpan<int8_t> dst_type_right)
{
const bool is_last_cyclic_segment = index == (src.size() - 1);
const int next_index = is_last_cyclic_segment ? 0 : index + 1;
@@ -122,10 +122,10 @@ static void subdivide_bezier_segment(const BezierSpline &src,
if (src.segment_is_vector(index)) {
if (is_last_cyclic_segment) {
- dst_type_left.first() = BezierSpline::HandleType::Vector;
+ dst_type_left.first() = BEZIER_HANDLE_VECTOR;
}
- dst_type_left.slice(offset + 1, result_size).fill(BezierSpline::HandleType::Vector);
- dst_type_right.slice(offset, result_size).fill(BezierSpline::HandleType::Vector);
+ dst_type_left.slice(offset + 1, result_size).fill(BEZIER_HANDLE_VECTOR);
+ dst_type_right.slice(offset, result_size).fill(BEZIER_HANDLE_VECTOR);
const float factor_delta = 1.0f / result_size;
for (const int cut : IndexRange(result_size)) {
@@ -136,10 +136,10 @@ static void subdivide_bezier_segment(const BezierSpline &src,
}
else {
if (is_last_cyclic_segment) {
- dst_type_left.first() = BezierSpline::HandleType::Free;
+ dst_type_left.first() = BEZIER_HANDLE_FREE;
}
- dst_type_left.slice(offset + 1, result_size).fill(BezierSpline::HandleType::Free);
- dst_type_right.slice(offset, result_size).fill(BezierSpline::HandleType::Free);
+ dst_type_left.slice(offset + 1, result_size).fill(BEZIER_HANDLE_FREE);
+ dst_type_right.slice(offset, result_size).fill(BEZIER_HANDLE_FREE);
const int i_segment_last = is_last_cyclic_segment ? 0 : offset + result_size;
@@ -187,8 +187,8 @@ static void subdivide_bezier_spline(const BezierSpline &src,
MutableSpan<float3> dst_positions = dst.positions();
MutableSpan<float3> dst_handles_left = dst.handle_positions_left();
MutableSpan<float3> dst_handles_right = dst.handle_positions_right();
- MutableSpan<BezierSpline::HandleType> dst_type_left = dst.handle_types_left();
- MutableSpan<BezierSpline::HandleType> dst_type_right = dst.handle_types_right();
+ MutableSpan<int8_t> dst_type_left = dst.handle_types_left();
+ MutableSpan<int8_t> dst_type_right = dst.handle_types_right();
threading::parallel_for(IndexRange(src.size() - 1), 512, [&](IndexRange range) {
for (const int i : range) {
@@ -235,26 +235,30 @@ static void subdivide_builtin_attributes(const Spline &src_spline,
subdivide_attribute<float>(src_spline.radii(), offsets, is_cyclic, dst_spline.radii());
subdivide_attribute<float>(src_spline.tilts(), offsets, is_cyclic, dst_spline.tilts());
switch (src_spline.type()) {
- case Spline::Type::Poly: {
+ case CURVE_TYPE_POLY: {
const PolySpline &src = static_cast<const PolySpline &>(src_spline);
PolySpline &dst = static_cast<PolySpline &>(dst_spline);
subdivide_attribute<float3>(src.positions(), offsets, is_cyclic, dst.positions());
break;
}
- case Spline::Type::Bezier: {
+ case CURVE_TYPE_BEZIER: {
const BezierSpline &src = static_cast<const BezierSpline &>(src_spline);
BezierSpline &dst = static_cast<BezierSpline &>(dst_spline);
subdivide_bezier_spline(src, offsets, dst);
dst.mark_cache_invalid();
break;
}
- case Spline::Type::NURBS: {
+ case CURVE_TYPE_NURBS: {
const NURBSpline &src = static_cast<const NURBSpline &>(src_spline);
NURBSpline &dst = static_cast<NURBSpline &>(dst_spline);
subdivide_attribute<float3>(src.positions(), offsets, is_cyclic, dst.positions());
subdivide_attribute<float>(src.weights(), offsets, is_cyclic, dst.weights());
break;
}
+ case CURVE_TYPE_CATMULL_ROM: {
+ BLI_assert_unreachable();
+ break;
+ }
}
}
@@ -338,7 +342,7 @@ static void node_geo_exec(GeoNodeExecParams params)
geometry_set = geometry::realize_instances_legacy(geometry_set);
- if (!geometry_set.has_curve()) {
+ if (!geometry_set.has_curves()) {
params.set_output("Geometry", geometry_set);
return;
}
@@ -350,9 +354,11 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
- std::unique_ptr<CurveEval> output_curve = subdivide_curve(*component.get_for_read(), cuts);
+ std::unique_ptr<CurveEval> output_curve = subdivide_curve(
+ *curves_to_curve_eval(*component.get_for_read()), cuts);
- params.set_output("Geometry", GeometrySet::create_with_curve(output_curve.release()));
+ params.set_output("Geometry",
+ GeometrySet::create_with_curves(curve_eval_to_curves(*output_curve)));
}
} // namespace blender::nodes::node_geo_legacy_curve_subdivide_cc
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc
index 64627e61910..f8fcc3cc363 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc
@@ -283,19 +283,19 @@ static void node_geo_exec(GeoNodeExecParams params)
geometry_set = geometry::realize_instances_legacy(geometry_set);
- if (!geometry_set.has_curve()) {
+ if (!geometry_set.has_curves()) {
params.set_output("Geometry", GeometrySet());
return;
}
const CurveComponent &curve_component = *geometry_set.get_component_for_read<CurveComponent>();
- const CurveEval &curve = *curve_component.get_for_read();
- const Span<SplinePtr> splines = curve.splines();
- curve.assert_valid_point_attributes();
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read());
+ const Span<SplinePtr> splines = curve->splines();
+ curve->assert_valid_point_attributes();
evaluate_splines(splines);
- const Array<int> offsets = calculate_spline_point_offsets(params, mode, curve, splines);
+ const Array<int> offsets = calculate_spline_point_offsets(params, mode, *curve, splines);
const int total_size = offsets.last();
if (total_size == 0) {
params.set_output("Geometry", GeometrySet());
@@ -306,7 +306,7 @@ static void node_geo_exec(GeoNodeExecParams params)
PointCloudComponent &point_component = result.get_component_for_write<PointCloudComponent>();
CurveToPointsResults new_attributes = curve_to_points_create_result_attributes(point_component,
- curve);
+ *curve);
switch (mode) {
case GEO_NODE_CURVE_RESAMPLE_COUNT:
case GEO_NODE_CURVE_RESAMPLE_LENGTH:
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc
index a0b862546bc..ca98d83c137 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc
@@ -111,9 +111,9 @@ static void spline_copy_builtin_attributes(const Spline &spline,
copy_data(spline.radii(), r_spline.radii(), mask);
copy_data(spline.tilts(), r_spline.tilts(), mask);
switch (spline.type()) {
- case Spline::Type::Poly:
+ case CURVE_TYPE_POLY:
break;
- case Spline::Type::Bezier: {
+ case CURVE_TYPE_BEZIER: {
const BezierSpline &src = static_cast<const BezierSpline &>(spline);
BezierSpline &dst = static_cast<BezierSpline &>(r_spline);
copy_data(src.handle_positions_left(), dst.handle_positions_left(), mask);
@@ -122,12 +122,16 @@ static void spline_copy_builtin_attributes(const Spline &spline,
copy_data(src.handle_types_right(), dst.handle_types_right(), mask);
break;
}
- case Spline::Type::NURBS: {
+ case CURVE_TYPE_NURBS: {
const NURBSpline &src = static_cast<const NURBSpline &>(spline);
NURBSpline &dst = static_cast<NURBSpline &>(r_spline);
copy_data(src.weights(), dst.weights(), mask);
break;
}
+ case CURVE_TYPE_CATMULL_ROM: {
+ BLI_assert_unreachable();
+ break;
+ }
}
}
@@ -231,9 +235,9 @@ static void delete_curve_selection(const CurveComponent &in_component,
const bool invert)
{
std::unique_ptr<CurveEval> r_curve = curve_delete(
- *in_component.get_for_read(), selection_name, invert);
+ *curves_to_curve_eval(*in_component.get_for_read()), selection_name, invert);
if (r_curve) {
- r_component.replace(r_curve.release());
+ r_component.replace(curve_eval_to_curves(*r_curve));
}
else {
r_component.clear();
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc
index ff86a92f2c7..8991261a21a 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc
@@ -48,7 +48,7 @@ static void node_geo_exec(GeoNodeExecParams params)
std::unique_ptr<CurveEval> curve = geometry::mesh_to_curve_convert(
component, IndexMask(selected_edge_indices));
- params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+ params.set_output("Curve", GeometrySet::create_with_curves(curve_eval_to_curves(*curve)));
}
} // namespace blender::nodes::node_geo_legacy_mesh_to_curve_cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc
index b6d677154d0..b3fe9d160b3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc
@@ -84,7 +84,7 @@ static void node_geo_exec(GeoNodeExecParams params)
break;
}
case GEO_COMPONENT_TYPE_CURVE: {
- if (geometry_set.has_curve()) {
+ if (geometry_set.has_curves()) {
const CurveComponent *component = geometry_set.get_component_for_read<CurveComponent>();
params.set_output("Point Count", component->attribute_domain_size(ATTR_DOMAIN_POINT));
params.set_output("Spline Count", component->attribute_domain_size(ATTR_DOMAIN_CURVE));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
index 6424fccbe04..cb7132d5ea2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
@@ -33,25 +33,18 @@ static void node_geo_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
Vector<std::string> attribute_names = params.extract_multi_input<std::string>("Attribute");
- if (geometry_set.has<MeshComponent>()) {
- remove_attribute(
- geometry_set.get_component_for_write<MeshComponent>(), params, attribute_names);
- }
- if (geometry_set.has<PointCloudComponent>()) {
- remove_attribute(
- geometry_set.get_component_for_write<PointCloudComponent>(), params, attribute_names);
- }
- if (geometry_set.has<CurveComponent>()) {
- remove_attribute(
- geometry_set.get_component_for_write<CurveComponent>(), params, attribute_names);
- }
- if (geometry_set.has<InstancesComponent>()) {
- remove_attribute(
- geometry_set.get_component_for_write<InstancesComponent>(), params, attribute_names);
+ for (const GeometryComponentType type : {GEO_COMPONENT_TYPE_MESH,
+ GEO_COMPONENT_TYPE_POINT_CLOUD,
+ GEO_COMPONENT_TYPE_CURVE,
+ GEO_COMPONENT_TYPE_INSTANCES}) {
+ if (geometry_set.has(type)) {
+ remove_attribute(geometry_set.get_component_for_write(type), params, attribute_names);
+ }
}
params.set_output("Geometry", geometry_set);
}
+
} // namespace blender::nodes::node_geo_attribute_remove_cc
void register_node_type_geo_attribute_remove()
diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
index 59147e9b23f..412f35d62fd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
@@ -161,9 +161,10 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
positions_span = varray.get_internal_span();
}
- if (geometry_set.has_curve()) {
- const CurveEval &curve = *geometry_set.get_curve_for_read();
- for (const SplinePtr &spline : curve.splines()) {
+ if (geometry_set.has_curves()) {
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *geometry_set.get_curves_for_read());
+ for (const SplinePtr &spline : curve->splines()) {
positions_span = spline->evaluated_positions();
total_size += positions_span.size();
count++;
@@ -201,9 +202,10 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
offset += varray.size();
}
- if (geometry_set.has_curve()) {
- const CurveEval &curve = *geometry_set.get_curve_for_read();
- for (const SplinePtr &spline : curve.splines()) {
+ if (geometry_set.has_curves()) {
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *geometry_set.get_curves_for_read());
+ for (const SplinePtr &spline : curve->splines()) {
Span<float3> array = spline->evaluated_positions();
positions.as_mutable_span().slice(offset, array.size()).copy_from(array);
offset += array.size();
@@ -272,8 +274,8 @@ static Mesh *convex_hull_from_instances(const GeometrySet &geometry_set)
if (set.has_mesh()) {
read_positions(*set.get_component_for_read<MeshComponent>(), transforms, &coords);
}
- if (set.has_curve()) {
- read_curve_positions(*set.get_curve_for_read(), transforms, &coords);
+ if (set.has_curves()) {
+ read_curve_positions(*curves_to_curve_eval(*set.get_curves_for_read()), transforms, &coords);
}
}
return hull_from_bullet(nullptr, coords);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
index 65aad0fcbf1..ce3058c7d42 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
@@ -59,10 +59,13 @@ class EndpointFieldInput final : public GeometryFieldInput {
}
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const CurveEval *curve = curve_component.get_for_read();
+ if (!curve_component.has_curves()) {
+ return nullptr;
+ }
- Array<int> control_point_offsets = curve->control_point_offsets();
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read());
+ Array<int> control_point_offsets = curve->control_point_offsets();
if (curve == nullptr || control_point_offsets.last() == 0) {
return nullptr;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
index 9824b2b2ece..6702ee6c0aa 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
@@ -113,12 +113,13 @@ static Mesh *cdt_to_mesh(const blender::meshintersect::CDT_result<double> &resul
static void curve_fill_calculate(GeometrySet &geometry_set, const GeometryNodeCurveFillMode mode)
{
- if (!geometry_set.has_curve()) {
+ if (!geometry_set.has_curves()) {
return;
}
- const CurveEval &curve = *geometry_set.get_curve_for_read();
- if (curve.splines().is_empty()) {
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *geometry_set.get_curves_for_read());
+ if (curve->splines().is_empty()) {
geometry_set.replace_curve(nullptr);
return;
}
@@ -127,7 +128,7 @@ static void curve_fill_calculate(GeometrySet &geometry_set, const GeometryNodeCu
CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES :
CDT_INSIDE_WITH_HOLES;
- const blender::meshintersect::CDT_result<double> results = do_cdt(curve, output_type);
+ const blender::meshintersect::CDT_result<double> results = do_cdt(*curve, output_type);
Mesh *mesh = cdt_to_mesh(results);
geometry_set.replace_mesh(mesh);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
index 94425ab48f4..24d72ad553b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
@@ -394,9 +394,9 @@ static void update_bezier_positions(const FilletData &fd,
dst_spline.handle_positions_left()[end_i] = dst_spline.positions()[end_i] -
handle_length * next_dir;
dst_spline.handle_types_right()[i_dst] = dst_spline.handle_types_left()[end_i] =
- BezierSpline::HandleType::Align;
+ BEZIER_HANDLE_ALIGN;
dst_spline.handle_types_left()[i_dst] = dst_spline.handle_types_right()[end_i] =
- BezierSpline::HandleType::Vector;
+ BEZIER_HANDLE_VECTOR;
dst_spline.mark_cache_invalid();
/* Calculate the center of the radius to be formed. */
@@ -406,8 +406,8 @@ static void update_bezier_positions(const FilletData &fd,
float radius;
radius_vec = math::normalize_and_get_length(radius_vec, radius);
- dst_spline.handle_types_right().slice(1, count - 2).fill(BezierSpline::HandleType::Align);
- dst_spline.handle_types_left().slice(1, count - 2).fill(BezierSpline::HandleType::Align);
+ dst_spline.handle_types_right().slice(1, count - 2).fill(BEZIER_HANDLE_ALIGN);
+ dst_spline.handle_types_left().slice(1, count - 2).fill(BEZIER_HANDLE_ALIGN);
/* For each of the vertices in between the end points. */
for (const int j : IndexRange(1, count - 2)) {
@@ -512,12 +512,12 @@ static SplinePtr fillet_spline(const Spline &spline,
copy_common_attributes_by_mapping(spline, *dst_spline_ptr, dst_to_src);
switch (spline.type()) {
- case Spline::Type::Bezier: {
+ case CURVE_TYPE_BEZIER: {
const BezierSpline &src_spline = static_cast<const BezierSpline &>(spline);
BezierSpline &dst_spline = static_cast<BezierSpline &>(*dst_spline_ptr);
if (fillet_param.mode == GEO_NODE_CURVE_FILLET_POLY) {
- dst_spline.handle_types_left().fill(BezierSpline::HandleType::Vector);
- dst_spline.handle_types_right().fill(BezierSpline::HandleType::Vector);
+ dst_spline.handle_types_left().fill(BEZIER_HANDLE_VECTOR);
+ dst_spline.handle_types_right().fill(BEZIER_HANDLE_VECTOR);
update_poly_positions(fd, dst_spline, src_spline, point_counts);
}
else {
@@ -525,17 +525,21 @@ static SplinePtr fillet_spline(const Spline &spline,
}
break;
}
- case Spline::Type::Poly: {
+ case CURVE_TYPE_POLY: {
update_poly_positions(fd, *dst_spline_ptr, spline, point_counts);
break;
}
- case Spline::Type::NURBS: {
+ case CURVE_TYPE_NURBS: {
const NURBSpline &src_spline = static_cast<const NURBSpline &>(spline);
NURBSpline &dst_spline = static_cast<NURBSpline &>(*dst_spline_ptr);
copy_attribute_by_mapping(src_spline.weights(), dst_spline.weights(), dst_to_src);
update_poly_positions(fd, dst_spline, src_spline, point_counts);
break;
}
+ case CURVE_TYPE_CATMULL_ROM: {
+ BLI_assert_unreachable();
+ break;
+ }
}
return dst_spline_ptr;
@@ -568,7 +572,7 @@ static void calculate_curve_fillet(GeometrySet &geometry_set,
const std::optional<Field<int>> &count_field,
const bool limit_radius)
{
- if (!geometry_set.has_curve()) {
+ if (!geometry_set.has_curves()) {
return;
}
@@ -599,10 +603,10 @@ static void calculate_curve_fillet(GeometrySet &geometry_set,
fillet_param.limit_radius = limit_radius;
- const CurveEval &input_curve = *geometry_set.get_curve_for_read();
- std::unique_ptr<CurveEval> output_curve = fillet_curve(input_curve, fillet_param);
+ const std::unique_ptr<CurveEval> input_curve = curves_to_curve_eval(*component.get_for_read());
+ std::unique_ptr<CurveEval> output_curve = fillet_curve(*input_curve, fillet_param);
- geometry_set.replace_curve(output_curve.release());
+ geometry_set.replace_curve(curve_eval_to_curves(*output_curve));
}
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
index 26a8ad2d988..ccd3a587e63 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
@@ -31,30 +31,30 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static BezierSpline::HandleType handle_type_from_input_type(const GeometryNodeCurveHandleType type)
+static HandleType handle_type_from_input_type(const GeometryNodeCurveHandleType type)
{
switch (type) {
case GEO_NODE_CURVE_HANDLE_AUTO:
- return BezierSpline::HandleType::Auto;
+ return BEZIER_HANDLE_AUTO;
case GEO_NODE_CURVE_HANDLE_ALIGN:
- return BezierSpline::HandleType::Align;
+ return BEZIER_HANDLE_ALIGN;
case GEO_NODE_CURVE_HANDLE_FREE:
- return BezierSpline::HandleType::Free;
+ return BEZIER_HANDLE_FREE;
case GEO_NODE_CURVE_HANDLE_VECTOR:
- return BezierSpline::HandleType::Vector;
+ return BEZIER_HANDLE_VECTOR;
}
BLI_assert_unreachable();
- return BezierSpline::HandleType::Auto;
+ return BEZIER_HANDLE_AUTO;
}
static void select_by_handle_type(const CurveEval &curve,
- const BezierSpline::HandleType type,
+ const HandleType type,
const GeometryNodeCurveHandleMode mode,
const MutableSpan<bool> r_selection)
{
int offset = 0;
for (const SplinePtr &spline : curve.splines()) {
- if (spline->type() != Spline::Type::Bezier) {
+ if (spline->type() != CURVE_TYPE_BEZIER) {
r_selection.slice(offset, spline->size()).fill(false);
offset += spline->size();
}
@@ -71,11 +71,11 @@ static void select_by_handle_type(const CurveEval &curve,
}
class HandleTypeFieldInput final : public GeometryFieldInput {
- BezierSpline::HandleType type_;
+ HandleType type_;
GeometryNodeCurveHandleMode mode_;
public:
- HandleTypeFieldInput(BezierSpline::HandleType type, GeometryNodeCurveHandleMode mode)
+ HandleTypeFieldInput(HandleType type, GeometryNodeCurveHandleMode mode)
: GeometryFieldInput(CPPType::get<bool>(), "Handle Type Selection node"),
type_(type),
mode_(mode)
@@ -92,14 +92,14 @@ class HandleTypeFieldInput final : public GeometryFieldInput {
}
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const CurveEval *curve = curve_component.get_for_read();
+ const Curves *curve = curve_component.get_for_read();
if (curve == nullptr) {
return {};
}
if (domain == ATTR_DOMAIN_POINT) {
Array<bool> selection(mask.min_array_size());
- select_by_handle_type(*curve, type_, mode_, selection);
+ select_by_handle_type(*curves_to_curve_eval(*curve), type_, mode_, selection);
return VArray<bool>::ForContainer(std::move(selection));
}
return {};
@@ -124,7 +124,7 @@ class HandleTypeFieldInput final : public GeometryFieldInput {
static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryCurveSelectHandles &storage = node_storage(params.node());
- const BezierSpline::HandleType handle_type = handle_type_from_input_type(
+ const HandleType handle_type = handle_type_from_input_type(
(GeometryNodeCurveHandleType)storage.handle_type);
const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)storage.mode;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
index 82621189964..d5769c691c8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
@@ -14,13 +14,13 @@ static void node_declare(NodeDeclarationBuilder &b)
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet curve_set = params.extract_input<GeometrySet>("Curve");
- if (!curve_set.has_curve()) {
+ if (!curve_set.has_curves()) {
params.set_default_remaining_outputs();
return;
}
- const CurveEval &curve = *curve_set.get_curve_for_read();
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_set.get_curves_for_read());
float length = 0.0f;
- for (const SplinePtr &spline : curve.splines()) {
+ for (const SplinePtr &spline : curve->splines()) {
length += spline->length();
}
params.set_output("Length", length);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc
index 9919e24473e..6c7d7ed375b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc
@@ -1,11 +1,15 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BKE_spline.hh"
+#include <numeric>
+
#include "BLI_math_base_safe.h"
+
+#include "BKE_curves.hh"
+
#include "UI_interface.h"
#include "UI_resources.h"
+
#include "node_geometry_util.hh"
-#include <numeric>
namespace blender::nodes::node_geo_curve_primitive_arc_cc {
@@ -139,32 +143,24 @@ static bool colinear_f3_f3_f3(const float3 p1, const float3 p2, const float3 p3)
return (ELEM(a, b, b * -1.0f));
}
-static std::unique_ptr<CurveEval> create_arc_curve_from_points(const int resolution,
- const float3 a,
- const float3 b,
- const float3 c,
- float angle_offset,
- const bool connect_center,
- const bool invert_arc,
- float3 &r_center,
- float3 &r_normal,
- float &r_radius)
+static Curves *create_arc_curve_from_points(const int resolution,
+ const float3 a,
+ const float3 b,
+ const float3 c,
+ float angle_offset,
+ const bool connect_center,
+ const bool invert_arc,
+ float3 &r_center,
+ float3 &r_normal,
+ float &r_radius)
{
- std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
- std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
-
- if (connect_center) {
- spline->resize(resolution + 1);
- }
- else {
- spline->resize(resolution);
- }
+ const int size = connect_center ? resolution + 1 : resolution;
+ Curves *curves_id = bke::curves_new_nomain_single(size, CURVE_TYPE_POLY);
+ bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
const int stepcount = resolution - 1;
const int centerpoint = resolution;
- MutableSpan<float3> positions = spline->positions();
- spline->radii().fill(1.0f);
- spline->tilts().fill(0.0f);
+ MutableSpan<float3> positions = curves.positions();
const bool is_colinear = colinear_f3_f3_f3(a, b, c);
@@ -254,7 +250,7 @@ static std::unique_ptr<CurveEval> create_arc_curve_from_points(const int resolut
}
if (connect_center) {
- spline->set_cyclic(true);
+ curves.cyclic().first() = true;
positions[centerpoint] = center;
}
@@ -263,36 +259,26 @@ static std::unique_ptr<CurveEval> create_arc_curve_from_points(const int resolut
normal = -normal;
}
- curve->add_spline(std::move(spline));
- curve->attributes.reallocate(curve->splines().size());
r_center = center;
r_radius = radius;
r_normal = normal;
- return curve;
+ return curves_id;
}
-static std::unique_ptr<CurveEval> create_arc_curve_from_radius(const int resolution,
- const float radius,
- const float start_angle,
- const float sweep_angle,
- const bool connect_center,
- const bool invert_arc)
+static Curves *create_arc_curve_from_radius(const int resolution,
+ const float radius,
+ const float start_angle,
+ const float sweep_angle,
+ const bool connect_center,
+ const bool invert_arc)
{
- std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
- std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
-
- if (connect_center) {
- spline->resize(resolution + 1);
- }
- else {
- spline->resize(resolution);
- }
+ const int size = connect_center ? resolution + 1 : resolution;
+ Curves *curves_id = bke::curves_new_nomain_single(size, CURVE_TYPE_POLY);
+ bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
const int stepcount = resolution - 1;
const int centerpoint = resolution;
- MutableSpan<float3> positions = spline->positions();
- spline->radii().fill(1.0f);
- spline->tilts().fill(0.0f);
+ MutableSpan<float3> positions = curves.positions();
const float sweep = (invert_arc) ? -(2.0f * M_PI - sweep_angle) : sweep_angle;
@@ -305,13 +291,11 @@ static std::unique_ptr<CurveEval> create_arc_curve_from_radius(const int resolut
}
if (connect_center) {
- spline->set_cyclic(true);
+ curves.cyclic().first() = true;
positions[centerpoint] = float3(0.0f, 0.0f, 0.0f);
}
- curve->add_spline(std::move(spline));
- curve->attributes.reallocate(curve->splines().size());
- return curve;
+ return curves_id;
}
static void node_geo_exec(GeoNodeExecParams params)
@@ -322,35 +306,35 @@ static void node_geo_exec(GeoNodeExecParams params)
switch (mode) {
case GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS: {
- std::unique_ptr<CurveEval> curve;
float3 r_center, r_normal;
float r_radius;
- curve = create_arc_curve_from_points(std::max(params.extract_input<int>("Resolution"), 2),
- params.extract_input<float3>("Start"),
- params.extract_input<float3>("Middle"),
- params.extract_input<float3>("End"),
- params.extract_input<float>("Offset Angle"),
- params.extract_input<bool>("Connect Center"),
- params.extract_input<bool>("Invert Arc"),
- r_center,
- r_normal,
- r_radius);
- params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+ Curves *curves = create_arc_curve_from_points(
+ std::max(params.extract_input<int>("Resolution"), 2),
+ params.extract_input<float3>("Start"),
+ params.extract_input<float3>("Middle"),
+ params.extract_input<float3>("End"),
+ params.extract_input<float>("Offset Angle"),
+ params.extract_input<bool>("Connect Center"),
+ params.extract_input<bool>("Invert Arc"),
+ r_center,
+ r_normal,
+ r_radius);
+ params.set_output("Curve", GeometrySet::create_with_curves(curves));
params.set_output("Center", r_center);
params.set_output("Normal", r_normal);
params.set_output("Radius", r_radius);
break;
}
case GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_RADIUS: {
- std::unique_ptr<CurveEval> curve;
- curve = create_arc_curve_from_radius(std::max(params.extract_input<int>("Resolution"), 2),
- params.extract_input<float>("Radius"),
- params.extract_input<float>("Start Angle"),
- params.extract_input<float>("Sweep Angle"),
- params.extract_input<bool>("Connect Center"),
- params.extract_input<bool>("Invert Arc"));
-
- params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+ Curves *curves = create_arc_curve_from_radius(
+ std::max(params.extract_input<int>("Resolution"), 2),
+ params.extract_input<float>("Radius"),
+ params.extract_input<float>("Start Angle"),
+ params.extract_input<float>("Sweep Angle"),
+ params.extract_input<bool>("Connect Center"),
+ params.extract_input<bool>("Invert Arc"));
+
+ params.set_output("Curve", GeometrySet::create_with_curves(curves));
break;
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
index c6b9018f0db..78e1613b630 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
@@ -69,21 +69,30 @@ static std::unique_ptr<CurveEval> create_bezier_segment_curve(
spline->resize(2);
MutableSpan<float3> positions = spline->positions();
- spline->handle_types_left().fill(BezierSpline::HandleType::Align);
- spline->handle_types_right().fill(BezierSpline::HandleType::Align);
+ spline->handle_types_left().fill(BEZIER_HANDLE_ALIGN);
+ spline->handle_types_right().fill(BEZIER_HANDLE_ALIGN);
spline->radii().fill(1.0f);
spline->tilts().fill(0.0f);
positions.first() = start;
positions.last() = end;
+ MutableSpan<float3> handles_right = spline->handle_positions_right();
+ MutableSpan<float3> handles_left = spline->handle_positions_left();
+
if (mode == GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT_POSITION) {
- spline->set_handle_position_right(0, start_handle_right);
- spline->set_handle_position_left(1, end_handle_left);
+ handles_left.first() = 2.0f * start - start_handle_right;
+ handles_right.first() = start_handle_right;
+
+ handles_left.last() = end_handle_left;
+ handles_right.last() = 2.0f * end - end_handle_left;
}
else {
- spline->set_handle_position_right(0, start + start_handle_right);
- spline->set_handle_position_left(1, end + end_handle_left);
+ handles_left.first() = start - start_handle_right;
+ handles_right.first() = start + start_handle_right;
+
+ handles_left.last() = end + end_handle_left;
+ handles_right.last() = end - end_handle_left;
}
curve->add_spline(std::move(spline));
@@ -104,7 +113,7 @@ static void node_geo_exec(GeoNodeExecParams params)
params.extract_input<float3>("End Handle"),
std::max(params.extract_input<int>("Resolution"), 1),
mode);
- params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+ params.set_output("Curve", GeometrySet::create_with_curves(curve_eval_to_curves(*curve)));
}
} // namespace blender::nodes::node_geo_curve_primitive_bezier_segment_cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
index 44505b61a27..874e29dda86 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BKE_spline.hh"
+#include "BKE_curves.hh"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -92,7 +92,7 @@ static bool colinear_f3_f3_f3(const float3 p1, const float3 p2, const float3 p3)
return (ELEM(a, b, b * -1.0f));
}
-static std::unique_ptr<CurveEval> create_point_circle_curve(
+static Curves *create_point_circle_curve(
const float3 p1, const float3 p2, const float3 p3, const int resolution, float3 &r_center)
{
if (colinear_f3_f3_f3(p1, p2, p3)) {
@@ -100,11 +100,11 @@ static std::unique_ptr<CurveEval> create_point_circle_curve(
return nullptr;
}
- std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
- std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+ Curves *curves_id = bke::curves_new_nomain_single(resolution, CURVE_TYPE_POLY);
+ bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
+ curves.cyclic().first() = true;
- spline->resize(resolution);
- MutableSpan<float3> positions = spline->positions();
+ MutableSpan<float3> positions = curves.positions();
float3 center;
/* Midpoints of `P1->P2` and `P2->P3`. */
@@ -147,24 +147,17 @@ static std::unique_ptr<CurveEval> create_point_circle_curve(
positions[i] = center + r * sin(theta) * v1 + r * cos(theta) * v4;
}
- spline->radii().fill(1.0f);
- spline->tilts().fill(0.0f);
- spline->set_cyclic(true);
- curve->add_spline(std::move(spline));
- curve->attributes.reallocate(curve->splines().size());
-
r_center = center;
- return curve;
+ return curves_id;
}
-static std::unique_ptr<CurveEval> create_radius_circle_curve(const int resolution,
- const float radius)
+static Curves *create_radius_circle_curve(const int resolution, const float radius)
{
- std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
- std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+ Curves *curves_id = bke::curves_new_nomain_single(resolution, CURVE_TYPE_POLY);
+ bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
+ curves.cyclic().first() = true;
- spline->resize(resolution);
- MutableSpan<float3> positions = spline->positions();
+ MutableSpan<float3> positions = curves.positions();
const float theta_step = (2.0f * M_PI) / float(resolution);
for (int i : IndexRange(resolution)) {
@@ -173,12 +166,8 @@ static std::unique_ptr<CurveEval> create_radius_circle_curve(const int resolutio
const float y = radius * sin(theta);
positions[i] = float3(x, y, 0.0f);
}
- spline->radii().fill(1.0f);
- spline->tilts().fill(0.0f);
- spline->set_cyclic(true);
- curve->add_spline(std::move(spline));
- curve->attributes.reallocate(curve->splines().size());
- return curve;
+
+ return curves_id;
}
static void node_geo_exec(GeoNodeExecParams params)
@@ -187,23 +176,23 @@ static void node_geo_exec(GeoNodeExecParams params)
const GeometryNodeCurvePrimitiveCircleMode mode = (GeometryNodeCurvePrimitiveCircleMode)
storage.mode;
- std::unique_ptr<CurveEval> curve;
+ Curves *curves;
if (mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS) {
float3 center_point;
- curve = create_point_circle_curve(params.extract_input<float3>("Point 1"),
- params.extract_input<float3>("Point 2"),
- params.extract_input<float3>("Point 3"),
- std::max(params.extract_input<int>("Resolution"), 3),
- center_point);
+ curves = create_point_circle_curve(params.extract_input<float3>("Point 1"),
+ params.extract_input<float3>("Point 2"),
+ params.extract_input<float3>("Point 3"),
+ std::max(params.extract_input<int>("Resolution"), 3),
+ center_point);
params.set_output("Center", center_point);
}
else if (mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS) {
- curve = create_radius_circle_curve(std::max(params.extract_input<int>("Resolution"), 3),
- params.extract_input<float>("Radius"));
+ curves = create_radius_circle_curve(std::max(params.extract_input<int>("Resolution"), 3),
+ params.extract_input<float>("Radius"));
}
- if (curve) {
- params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+ if (curves) {
+ params.set_output("Curve", GeometrySet::create_with_curves(curves));
}
else {
params.set_default_remaining_outputs();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
index d11af3b1cc0..2e2f4254752 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BKE_spline.hh"
+#include "BKE_curves.hh"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -60,39 +60,28 @@ static void node_update(bNodeTree *ntree, bNode *node)
ntree, length_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION);
}
-static std::unique_ptr<CurveEval> create_point_line_curve(const float3 start, const float3 end)
+static Curves *create_point_line_curve(const float3 start, const float3 end)
{
- std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
- std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
-
- spline->resize(2);
- MutableSpan<float3> positions = spline->positions();
- positions[0] = start;
- positions[1] = end;
- spline->radii().fill(1.0f);
- spline->tilts().fill(0.0f);
- curve->add_spline(std::move(spline));
- curve->attributes.reallocate(curve->splines().size());
- return curve;
+ Curves *curves_id = bke::curves_new_nomain_single(2, CURVE_TYPE_POLY);
+ bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
+
+ curves.positions().first() = start;
+ curves.positions().last() = end;
+
+ return curves_id;
}
-static std::unique_ptr<CurveEval> create_direction_line_curve(const float3 start,
- const float3 direction,
- const float length)
+static Curves *create_direction_line_curve(const float3 start,
+ const float3 direction,
+ const float length)
{
- std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
- std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
-
- spline->resize(2);
- MutableSpan<float3> positions = spline->positions();
- positions[0] = start;
- positions[1] = math::normalize(direction) * length + start;
-
- spline->radii().fill(1.0f);
- spline->tilts().fill(0.0f);
- curve->add_spline(std::move(spline));
- curve->attributes.reallocate(curve->splines().size());
- return curve;
+ Curves *curves_id = bke::curves_new_nomain_single(2, CURVE_TYPE_POLY);
+ bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
+
+ curves.positions().first() = start;
+ curves.positions().last() = math::normalize(direction) * length + start;
+
+ return curves_id;
}
static void node_geo_exec(GeoNodeExecParams params)
@@ -100,18 +89,18 @@ static void node_geo_exec(GeoNodeExecParams params)
const NodeGeometryCurvePrimitiveLine &storage = node_storage(params.node());
const GeometryNodeCurvePrimitiveLineMode mode = (GeometryNodeCurvePrimitiveLineMode)storage.mode;
- std::unique_ptr<CurveEval> curve;
+ Curves *curves = nullptr;
if (mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS) {
- curve = create_point_line_curve(params.extract_input<float3>("Start"),
- params.extract_input<float3>("End"));
+ curves = create_point_line_curve(params.extract_input<float3>("Start"),
+ params.extract_input<float3>("End"));
}
else if (mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION) {
- curve = create_direction_line_curve(params.extract_input<float3>("Start"),
- params.extract_input<float3>("Direction"),
- params.extract_input<float>("Length"));
+ curves = create_direction_line_curve(params.extract_input<float3>("Start"),
+ params.extract_input<float3>("Direction"),
+ params.extract_input<float>("Length"));
}
- params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+ params.set_output("Curve", GeometrySet::create_with_curves(curves));
}
} // namespace blender::nodes::node_geo_curve_primitive_line_cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
index 456f6e55c1e..37810ccaff5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BKE_spline.hh"
+#include "BKE_curves.hh"
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc {
@@ -28,18 +28,15 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Curve"));
}
-static std::unique_ptr<CurveEval> create_quadratic_bezier_curve(const float3 p1,
- const float3 p2,
- const float3 p3,
- const int resolution)
+static Curves *create_quadratic_bezier_curve(const float3 p1,
+ const float3 p2,
+ const float3 p3,
+ const int resolution)
{
- std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
- std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+ Curves *curves_id = bke::curves_new_nomain_single(resolution + 1, CURVE_TYPE_POLY);
+ bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
- spline->resize(resolution + 1);
- MutableSpan<float3> positions = spline->positions();
- spline->radii().fill(1.0f);
- spline->tilts().fill(0.0f);
+ MutableSpan<float3> positions = curves.positions();
const float step = 1.0f / resolution;
for (const int i : IndexRange(resolution + 1)) {
@@ -49,19 +46,17 @@ static std::unique_ptr<CurveEval> create_quadratic_bezier_curve(const float3 p1,
positions[i] = math::interpolate(q1, q2, factor);
}
- curve->add_spline(std::move(spline));
- curve->attributes.reallocate(curve->splines().size());
- return curve;
+ return curves_id;
}
static void node_geo_exec(GeoNodeExecParams params)
{
- std::unique_ptr<CurveEval> curve = create_quadratic_bezier_curve(
+ Curves *curves = create_quadratic_bezier_curve(
params.extract_input<float3>("Start"),
params.extract_input<float3>("Middle"),
params.extract_input<float3>("End"),
std::max(params.extract_input<int>("Resolution"), 3));
- params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+ params.set_output("Curve", GeometrySet::create_with_curves(curves));
}
} // namespace blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
index b6a847eebf4..ad3123a6a4a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BKE_spline.hh"
+#include "BKE_curves.hh"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -216,13 +216,11 @@ static void node_geo_exec(GeoNodeExecParams params)
const NodeGeometryCurvePrimitiveQuad &storage = node_storage(params.node());
const GeometryNodeCurvePrimitiveQuadMode mode = (GeometryNodeCurvePrimitiveQuadMode)storage.mode;
- std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
- std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
- spline->resize(4);
- spline->radii().fill(1.0f);
- spline->tilts().fill(0.0f);
- spline->set_cyclic(true);
- MutableSpan<float3> positions = spline->positions();
+ Curves *curves_id = bke::curves_new_nomain_single(4, CURVE_TYPE_POLY);
+ bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
+ curves.cyclic().first() = true;
+
+ MutableSpan<float3> positions = curves.positions();
switch (mode) {
case GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE:
@@ -262,9 +260,7 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
- curve->add_spline(std::move(spline));
- curve->attributes.reallocate(curve->splines().size());
- params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+ params.set_output("Curve", GeometrySet::create_with_curves(curves_id));
}
} // namespace blender::nodes::node_geo_curve_primitive_quadrilateral_cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
index f448ddabd2b..22619577d04 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BKE_spline.hh"
+#include "BKE_curves.hh"
#include "node_geometry_util.hh"
@@ -35,26 +35,23 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Curve"));
}
-static std::unique_ptr<CurveEval> create_spiral_curve(const float rotations,
- const int resolution,
- const float start_radius,
- const float end_radius,
- const float height,
- const bool direction)
+static Curves *create_spiral_curve(const float rotations,
+ const int resolution,
+ const float start_radius,
+ const float end_radius,
+ const float height,
+ const bool direction)
{
- std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
- std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
-
const int totalpoints = std::max(int(resolution * rotations), 1);
const float delta_radius = (end_radius - start_radius) / (float)totalpoints;
const float delta_height = height / (float)totalpoints;
const float delta_theta = (M_PI * 2 * rotations) / (float)totalpoints *
(direction ? 1.0f : -1.0f);
- spline->resize(totalpoints + 1);
- MutableSpan<float3> positions = spline->positions();
- spline->radii().fill(1.0f);
- spline->tilts().fill(0.0f);
+ Curves *curves_id = bke::curves_new_nomain_single(totalpoints + 1, CURVE_TYPE_POLY);
+ bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
+
+ MutableSpan<float3> positions = curves.positions();
for (const int i : IndexRange(totalpoints + 1)) {
const float theta = i * delta_theta;
@@ -66,9 +63,7 @@ static std::unique_ptr<CurveEval> create_spiral_curve(const float rotations,
positions[i] = {x, y, z};
}
- curve->add_spline(std::move(spline));
- curve->attributes.reallocate(curve->splines().size());
- return curve;
+ return curves_id;
}
static void node_geo_exec(GeoNodeExecParams params)
@@ -79,14 +74,13 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
- std::unique_ptr<CurveEval> curve = create_spiral_curve(
- rotations,
- std::max(params.extract_input<int>("Resolution"), 1),
- params.extract_input<float>("Start Radius"),
- params.extract_input<float>("End Radius"),
- params.extract_input<float>("Height"),
- params.extract_input<bool>("Reverse"));
- params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+ Curves *curves = create_spiral_curve(rotations,
+ std::max(params.extract_input<int>("Resolution"), 1),
+ params.extract_input<float>("Start Radius"),
+ params.extract_input<float>("End Radius"),
+ params.extract_input<float>("Height"),
+ params.extract_input<bool>("Reverse"));
+ params.set_output("Curve", GeometrySet::create_with_curves(curves));
}
} // namespace blender::nodes::node_geo_curve_primitive_spiral_cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
index 5969af43bc1..e7e899881cf 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BKE_spline.hh"
+#include "BKE_curves.hh"
#include "node_geometry_util.hh"
@@ -33,19 +33,16 @@ static void node_declare(NodeDeclarationBuilder &b)
.description(N_("An attribute field with a selection of the outer points"));
}
-static std::unique_ptr<CurveEval> create_star_curve(const float inner_radius,
- const float outer_radius,
- const float twist,
- const int points)
+static Curves *create_star_curve(const float inner_radius,
+ const float outer_radius,
+ const float twist,
+ const int points)
{
- std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
- std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
- spline->set_cyclic(true);
+ Curves *curves_id = bke::curves_new_nomain_single(points * 2, CURVE_TYPE_POLY);
+ bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
+ curves.cyclic().first() = true;
- spline->resize(points * 2);
- MutableSpan<float3> positions = spline->positions();
- spline->radii().fill(1.0f);
- spline->tilts().fill(0.0f);
+ MutableSpan<float3> positions = curves.positions();
const float theta_step = (2.0f * M_PI) / float(points);
for (const int i : IndexRange(points)) {
@@ -58,10 +55,7 @@ static std::unique_ptr<CurveEval> create_star_curve(const float inner_radius,
positions[i * 2 + 1] = {inner_x, inner_y, 0.0f};
}
- curve->add_spline(std::move(spline));
- curve->attributes.reallocate(curve->splines().size());
-
- return curve;
+ return curves_id;
}
static void create_selection_output(CurveComponent &component,
@@ -78,12 +72,11 @@ static void create_selection_output(CurveComponent &component,
static void node_geo_exec(GeoNodeExecParams params)
{
- std::unique_ptr<CurveEval> curve = create_star_curve(
- std::max(params.extract_input<float>("Inner Radius"), 0.0f),
- std::max(params.extract_input<float>("Outer Radius"), 0.0f),
- params.extract_input<float>("Twist"),
- std::max(params.extract_input<int>("Points"), 3));
- GeometrySet output = GeometrySet::create_with_curve(curve.release());
+ Curves *curves = create_star_curve(std::max(params.extract_input<float>("Inner Radius"), 0.0f),
+ std::max(params.extract_input<float>("Outer Radius"), 0.0f),
+ params.extract_input<float>("Twist"),
+ std::max(params.extract_input<int>("Points"), 3));
+ GeometrySet output = GeometrySet::create_with_curves(curves);
if (params.output_is_required("Outer Points")) {
StrongAnonymousAttributeID attribute_output("Outer Points");
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
index d2afeaa7094..c5814a9a1dd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -158,7 +158,7 @@ static SplinePtr resample_spline_evaluated(const Spline &src)
static std::unique_ptr<CurveEval> resample_curve(const CurveComponent *component,
const SampleModeParam &mode_param)
{
- const CurveEval *input_curve = component->get_for_read();
+ const std::unique_ptr<CurveEval> input_curve = curves_to_curve_eval(*component->get_for_read());
GeometryComponentFieldContext field_context{*component, ATTR_DOMAIN_CURVE};
const int domain_size = component->attribute_domain_size(ATTR_DOMAIN_CURVE);
@@ -235,14 +235,14 @@ static std::unique_ptr<CurveEval> resample_curve(const CurveComponent *component
static void geometry_set_curve_resample(GeometrySet &geometry_set,
const SampleModeParam &mode_param)
{
- if (!geometry_set.has_curve()) {
+ if (!geometry_set.has_curves()) {
return;
}
std::unique_ptr<CurveEval> output_curve = resample_curve(
geometry_set.get_component_for_read<CurveComponent>(), mode_param);
- geometry_set.replace_curve(output_curve.release());
+ geometry_set.replace_curve(curve_eval_to_curves(*output_curve));
}
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
index 0ef3230937b..8393f9615aa 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
@@ -20,7 +20,7 @@ static void node_geo_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (!geometry_set.has_curve()) {
+ if (!geometry_set.has_curves()) {
return;
}
@@ -34,13 +34,15 @@ static void node_geo_exec(GeoNodeExecParams params)
selection_evaluator.evaluate();
const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
- CurveEval &curve = *component.get_for_write();
- MutableSpan<SplinePtr> splines = curve.splines();
+ std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_write());
+ MutableSpan<SplinePtr> splines = curve->splines();
threading::parallel_for(selection.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
splines[selection[i]]->reverse();
}
});
+
+ component.replace(curve_eval_to_curves(*curve));
});
params.set_output("Curve", std::move(geometry_set));
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 152828b284c..6661d03a851 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
@@ -122,12 +122,13 @@ class SampleCurveFunction : public fn::MultiFunction {
}
};
- if (!geometry_set_.has_curve()) {
+ if (!geometry_set_.has_curves()) {
return return_default();
}
const CurveComponent *curve_component = geometry_set_.get_component_for_read<CurveComponent>();
- const CurveEval *curve = curve_component->get_for_read();
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *curve_component->get_for_read());
Span<SplinePtr> splines = curve->splines();
if (splines.is_empty()) {
return return_default();
@@ -234,12 +235,13 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
- const CurveEval *curve = component->get_for_read();
- if (curve == nullptr) {
+ if (!component->has_curves()) {
params.set_default_remaining_outputs();
return;
}
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component->get_for_read());
+
if (curve->splines().is_empty()) {
params.set_default_remaining_outputs();
return;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
index 3d7b2fddf72..e8da4154586 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
@@ -33,20 +33,20 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static BezierSpline::HandleType handle_type_from_input_type(GeometryNodeCurveHandleType type)
+static HandleType handle_type_from_input_type(GeometryNodeCurveHandleType type)
{
switch (type) {
case GEO_NODE_CURVE_HANDLE_AUTO:
- return BezierSpline::HandleType::Auto;
+ return BEZIER_HANDLE_AUTO;
case GEO_NODE_CURVE_HANDLE_ALIGN:
- return BezierSpline::HandleType::Align;
+ return BEZIER_HANDLE_ALIGN;
case GEO_NODE_CURVE_HANDLE_FREE:
- return BezierSpline::HandleType::Free;
+ return BEZIER_HANDLE_FREE;
case GEO_NODE_CURVE_HANDLE_VECTOR:
- return BezierSpline::HandleType::Vector;
+ return BEZIER_HANDLE_VECTOR;
}
BLI_assert_unreachable();
- return BezierSpline::HandleType::Auto;
+ return BEZIER_HANDLE_AUTO;
}
static void node_geo_exec(GeoNodeExecParams params)
@@ -60,14 +60,14 @@ static void node_geo_exec(GeoNodeExecParams params)
bool has_bezier_spline = false;
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (!geometry_set.has_curve()) {
+ if (!geometry_set.has_curves()) {
return;
}
/* Retrieve data for write access so we can avoid new allocations for the handles data. */
CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
- CurveEval &curve = *curve_component.get_for_write();
- MutableSpan<SplinePtr> splines = curve.splines();
+ std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read());
+ MutableSpan<SplinePtr> splines = curve->splines();
GeometryComponentFieldContext field_context{curve_component, ATTR_DOMAIN_POINT};
const int domain_size = curve_component.attribute_domain_size(ATTR_DOMAIN_POINT);
@@ -77,18 +77,18 @@ static void node_geo_exec(GeoNodeExecParams params)
selection_evaluator.evaluate();
const VArray<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
- const BezierSpline::HandleType new_handle_type = handle_type_from_input_type(type);
+ const HandleType new_handle_type = handle_type_from_input_type(type);
int point_index = 0;
for (SplinePtr &spline : splines) {
- if (spline->type() != Spline::Type::Bezier) {
+ if (spline->type() != CURVE_TYPE_BEZIER) {
point_index += spline->positions().size();
continue;
}
has_bezier_spline = true;
BezierSpline &bezier_spline = static_cast<BezierSpline &>(*spline);
- if (ELEM(new_handle_type, BezierSpline::HandleType::Free, BezierSpline::HandleType::Align)) {
+ if (ELEM(new_handle_type, BEZIER_HANDLE_FREE, BEZIER_HANDLE_ALIGN)) {
/* In this case the automatically calculated handle types need to be "baked", because
* they're possibly changing from a type that is calculated automatically to a type that
* is positioned manually. */
@@ -108,6 +108,8 @@ static void node_geo_exec(GeoNodeExecParams params)
}
bezier_spline.mark_cache_invalid();
}
+
+ curve_component.replace(curve_eval_to_curves(*curve));
});
if (!has_bezier_spline) {
params.error_message_add(NodeWarningType::Info, TIP_("No Bezier splines in input curve"));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
index a303be99242..3edaccba506 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
@@ -100,18 +100,22 @@ static Array<float> curve_length_point_domain(const CurveEval &curve)
MutableSpan spline_factors{lengths.as_mutable_span().slice(offsets[i], spline.size())};
spline_factors.first() = 0.0f;
switch (splines[i]->type()) {
- case Spline::Type::Bezier: {
+ case CURVE_TYPE_BEZIER: {
calculate_bezier_lengths(static_cast<const BezierSpline &>(spline), spline_factors);
break;
}
- case Spline::Type::Poly: {
+ case CURVE_TYPE_POLY: {
calculate_poly_length(static_cast<const PolySpline &>(spline), spline_factors);
break;
}
- case Spline::Type::NURBS: {
+ case CURVE_TYPE_NURBS: {
calculate_nurbs_lengths(static_cast<const NURBSpline &>(spline), spline_factors);
break;
}
+ case CURVE_TYPE_CATMULL_ROM: {
+ BLI_assert_unreachable();
+ break;
+ }
}
}
});
@@ -201,8 +205,9 @@ class CurveParameterFieldInput final : public GeometryFieldInput {
{
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const CurveEval *curve = curve_component.get_for_read();
- if (curve) {
+ if (curve_component.has_curves()) {
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *curve_component.get_for_read());
return construct_curve_parameter_varray(*curve, mask, domain);
}
}
@@ -234,8 +239,8 @@ class CurveLengthFieldInput final : public GeometryFieldInput {
{
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const CurveEval *curve = curve_component.get_for_read();
- if (curve) {
+ if (curve_component.has_curves()) {
+ std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read());
return construct_curve_length_varray(*curve, mask, domain);
}
}
@@ -267,8 +272,9 @@ class IndexOnSplineFieldInput final : public GeometryFieldInput {
{
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const CurveEval *curve = curve_component.get_for_read();
- if (curve) {
+ if (curve_component.has_curves()) {
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *curve_component.get_for_read());
return construct_index_on_spline_varray(*curve, mask, domain);
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
index 4e4cabd3c33..55610ec86ab 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
@@ -259,8 +259,8 @@ static SplinePtr poly_to_bezier(const Spline &input)
output->positions().copy_from(input.positions());
output->radii().copy_from(input.radii());
output->tilts().copy_from(input.tilts());
- output->handle_types_left().fill(BezierSpline::HandleType::Vector);
- output->handle_types_right().fill(BezierSpline::HandleType::Vector);
+ output->handle_types_left().fill(BEZIER_HANDLE_VECTOR);
+ output->handle_types_right().fill(BEZIER_HANDLE_VECTOR);
output->set_resolution(12);
Spline::copy_base_settings(input, *output);
output->attributes = input.attributes;
@@ -298,8 +298,8 @@ static SplinePtr nurbs_to_bezier(const Spline &input)
nurbs_to_bezier_assign(nurbs_spline.tilts(), output->tilts(), knots_mode);
scale_input_assign(handle_positions.as_span(), 2, 0, output->handle_positions_left());
scale_input_assign(handle_positions.as_span(), 2, 1, output->handle_positions_right());
- output->handle_types_left().fill(BezierSpline::HandleType::Align);
- output->handle_types_right().fill(BezierSpline::HandleType::Align);
+ output->handle_types_left().fill(BEZIER_HANDLE_ALIGN);
+ output->handle_types_right().fill(BEZIER_HANDLE_ALIGN);
output->set_resolution(nurbs_spline.resolution());
Spline::copy_base_settings(nurbs_spline, *output);
output->attributes.reallocate(output->size());
@@ -315,11 +315,11 @@ static SplinePtr nurbs_to_bezier(const Spline &input)
static SplinePtr convert_to_bezier(const Spline &input, GeoNodeExecParams params)
{
switch (input.type()) {
- case Spline::Type::Bezier:
+ case CURVE_TYPE_BEZIER:
return input.copy();
- case Spline::Type::Poly:
+ case CURVE_TYPE_POLY:
return poly_to_bezier(input);
- case Spline::Type::NURBS:
+ case CURVE_TYPE_NURBS:
if (input.size() < 4) {
params.error_message_add(
NodeWarningType::Info,
@@ -327,6 +327,10 @@ static SplinePtr convert_to_bezier(const Spline &input, GeoNodeExecParams params
return input.copy();
}
return nurbs_to_bezier(input);
+ case CURVE_TYPE_CATMULL_ROM: {
+ BLI_assert_unreachable();
+ return {};
+ }
}
BLI_assert_unreachable();
return {};
@@ -335,12 +339,15 @@ static SplinePtr convert_to_bezier(const Spline &input, GeoNodeExecParams params
static SplinePtr convert_to_nurbs(const Spline &input)
{
switch (input.type()) {
- case Spline::Type::NURBS:
+ case CURVE_TYPE_NURBS:
return input.copy();
- case Spline::Type::Bezier:
+ case CURVE_TYPE_BEZIER:
return bezier_to_nurbs(input);
- case Spline::Type::Poly:
+ case CURVE_TYPE_POLY:
return poly_to_nurbs(input);
+ case CURVE_TYPE_CATMULL_ROM:
+ BLI_assert_unreachable();
+ return {};
}
BLI_assert_unreachable();
return {};
@@ -355,45 +362,48 @@ static void node_geo_exec(GeoNodeExecParams params)
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (!geometry_set.has_curve()) {
+ if (!geometry_set.has_curves()) {
return;
}
const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>();
- const CurveEval &curve = *curve_component->get_for_read();
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *curve_component->get_for_read());
GeometryComponentFieldContext field_context{*curve_component, ATTR_DOMAIN_CURVE};
const int domain_size = curve_component->attribute_domain_size(ATTR_DOMAIN_CURVE);
+ Span<SplinePtr> src_splines = curve->splines();
+
fn::FieldEvaluator selection_evaluator{field_context, domain_size};
selection_evaluator.add(selection_field);
selection_evaluator.evaluate();
const VArray<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>();
- new_curve->resize(curve.splines().size());
+ new_curve->resize(src_splines.size());
- threading::parallel_for(curve.splines().index_range(), 512, [&](IndexRange range) {
+ threading::parallel_for(src_splines.index_range(), 512, [&](IndexRange range) {
for (const int i : range) {
if (selection[i]) {
switch (output_type) {
case GEO_NODE_SPLINE_TYPE_POLY:
- new_curve->splines()[i] = convert_to_poly_spline(*curve.splines()[i]);
+ new_curve->splines()[i] = convert_to_poly_spline(*src_splines[i]);
break;
case GEO_NODE_SPLINE_TYPE_BEZIER:
- new_curve->splines()[i] = convert_to_bezier(*curve.splines()[i], params);
+ new_curve->splines()[i] = convert_to_bezier(*src_splines[i], params);
break;
case GEO_NODE_SPLINE_TYPE_NURBS:
- new_curve->splines()[i] = convert_to_nurbs(*curve.splines()[i]);
+ new_curve->splines()[i] = convert_to_nurbs(*src_splines[i]);
break;
}
}
else {
- new_curve->splines()[i] = curve.splines()[i]->copy();
+ new_curve->splines()[i] = src_splines[i]->copy();
}
}
});
- new_curve->attributes = curve.attributes;
- geometry_set.replace_curve(new_curve.release());
+ new_curve->attributes = curve->attributes;
+ geometry_set.replace_curve(curve_eval_to_curves(*new_curve));
});
params.set_output("Curve", std::move(geometry_set));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
index 9daf3ff0594..bbe57b2b3fa 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
@@ -93,8 +93,8 @@ static void subdivide_bezier_segment(const BezierSpline &src,
MutableSpan<float3> dst_positions,
MutableSpan<float3> dst_handles_left,
MutableSpan<float3> dst_handles_right,
- MutableSpan<BezierSpline::HandleType> dst_type_left,
- MutableSpan<BezierSpline::HandleType> dst_type_right)
+ MutableSpan<int8_t> dst_type_left,
+ MutableSpan<int8_t> dst_type_right)
{
const bool is_last_cyclic_segment = index == (src.size() - 1);
const int next_index = is_last_cyclic_segment ? 0 : index + 1;
@@ -104,10 +104,10 @@ static void subdivide_bezier_segment(const BezierSpline &src,
if (src.segment_is_vector(index)) {
if (is_last_cyclic_segment) {
- dst_type_left.first() = BezierSpline::HandleType::Vector;
+ dst_type_left.first() = BEZIER_HANDLE_VECTOR;
}
- dst_type_left.slice(offset + 1, result_size).fill(BezierSpline::HandleType::Vector);
- dst_type_right.slice(offset, result_size).fill(BezierSpline::HandleType::Vector);
+ dst_type_left.slice(offset + 1, result_size).fill(BEZIER_HANDLE_VECTOR);
+ dst_type_right.slice(offset, result_size).fill(BEZIER_HANDLE_VECTOR);
const float factor_delta = 1.0f / result_size;
for (const int cut : IndexRange(result_size)) {
@@ -118,10 +118,10 @@ static void subdivide_bezier_segment(const BezierSpline &src,
}
else {
if (is_last_cyclic_segment) {
- dst_type_left.first() = BezierSpline::HandleType::Free;
+ dst_type_left.first() = BEZIER_HANDLE_FREE;
}
- dst_type_left.slice(offset + 1, result_size).fill(BezierSpline::HandleType::Free);
- dst_type_right.slice(offset, result_size).fill(BezierSpline::HandleType::Free);
+ dst_type_left.slice(offset + 1, result_size).fill(BEZIER_HANDLE_FREE);
+ dst_type_right.slice(offset, result_size).fill(BEZIER_HANDLE_FREE);
const int i_segment_last = is_last_cyclic_segment ? 0 : offset + result_size;
@@ -169,8 +169,8 @@ static void subdivide_bezier_spline(const BezierSpline &src,
MutableSpan<float3> dst_positions = dst.positions();
MutableSpan<float3> dst_handles_left = dst.handle_positions_left();
MutableSpan<float3> dst_handles_right = dst.handle_positions_right();
- MutableSpan<BezierSpline::HandleType> dst_type_left = dst.handle_types_left();
- MutableSpan<BezierSpline::HandleType> dst_type_right = dst.handle_types_right();
+ MutableSpan<int8_t> dst_type_left = dst.handle_types_left();
+ MutableSpan<int8_t> dst_type_right = dst.handle_types_right();
threading::parallel_for(IndexRange(src.size() - 1), 512, [&](IndexRange range) {
for (const int i : range) {
@@ -217,26 +217,30 @@ static void subdivide_builtin_attributes(const Spline &src_spline,
subdivide_attribute<float>(src_spline.radii(), offsets, is_cyclic, dst_spline.radii());
subdivide_attribute<float>(src_spline.tilts(), offsets, is_cyclic, dst_spline.tilts());
switch (src_spline.type()) {
- case Spline::Type::Poly: {
+ case CURVE_TYPE_POLY: {
const PolySpline &src = static_cast<const PolySpline &>(src_spline);
PolySpline &dst = static_cast<PolySpline &>(dst_spline);
subdivide_attribute<float3>(src.positions(), offsets, is_cyclic, dst.positions());
break;
}
- case Spline::Type::Bezier: {
+ case CURVE_TYPE_BEZIER: {
const BezierSpline &src = static_cast<const BezierSpline &>(src_spline);
BezierSpline &dst = static_cast<BezierSpline &>(dst_spline);
subdivide_bezier_spline(src, offsets, dst);
dst.mark_cache_invalid();
break;
}
- case Spline::Type::NURBS: {
+ case CURVE_TYPE_NURBS: {
const NURBSpline &src = static_cast<const NURBSpline &>(src_spline);
NURBSpline &dst = static_cast<NURBSpline &>(dst_spline);
subdivide_attribute<float3>(src.positions(), offsets, is_cyclic, dst.positions());
subdivide_attribute<float>(src.weights(), offsets, is_cyclic, dst.weights());
break;
}
+ case CURVE_TYPE_CATMULL_ROM: {
+ BLI_assert_unreachable();
+ break;
+ }
}
}
@@ -320,7 +324,7 @@ static void node_geo_exec(GeoNodeExecParams params)
Field<int> cuts_field = params.extract_input<Field<int>>("Cuts");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (!geometry_set.has_curve()) {
+ if (!geometry_set.has_curves()) {
return;
}
@@ -336,9 +340,9 @@ static void node_geo_exec(GeoNodeExecParams params)
if (cuts.is_single() && cuts.get_internal_single() < 1) {
return;
}
-
- std::unique_ptr<CurveEval> output_curve = subdivide_curve(*component.get_for_read(), cuts);
- geometry_set.replace_curve(output_curve.release());
+ std::unique_ptr<CurveEval> output_curve = subdivide_curve(
+ *curves_to_curve_eval(*component.get_for_read()), cuts);
+ geometry_set.replace_curve(curve_eval_to_curves(*output_curve));
});
params.set_output("Curve", geometry_set);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
index ed497b6fbe0..e7a8c61290b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
@@ -27,14 +27,16 @@ static void geometry_set_curve_to_mesh(GeometrySet &geometry_set,
const GeometrySet &profile_set,
const bool fill_caps)
{
- const CurveEval *curve = geometry_set.get_curve_for_read();
- const CurveEval *profile_curve = profile_set.get_curve_for_read();
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *geometry_set.get_curves_for_read());
+ const Curves *profile_curves = profile_set.get_curves_for_read();
- if (profile_curve == nullptr) {
+ if (profile_curves == nullptr) {
Mesh *mesh = bke::curve_to_wire_mesh(*curve);
geometry_set.replace_mesh(mesh);
}
else {
+ const std::unique_ptr<CurveEval> profile_curve = curves_to_curve_eval(*profile_curves);
Mesh *mesh = bke::curve_to_mesh_sweep(*curve, *profile_curve, fill_caps);
geometry_set.replace_mesh(mesh);
}
@@ -46,10 +48,10 @@ static void node_geo_exec(GeoNodeExecParams params)
GeometrySet profile_set = params.extract_input<GeometrySet>("Profile Curve");
const bool fill_caps = params.extract_input<bool>("Fill Caps");
- bool has_curve = false;
+ bool has_curves = false;
curve_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (geometry_set.has_curve()) {
- has_curve = true;
+ if (geometry_set.has_curves()) {
+ has_curves = true;
geometry_set_curve_to_mesh(geometry_set, profile_set, fill_caps);
}
geometry_set.keep_only({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_INSTANCES});
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
index 7481f7248a1..1eb18b2f910 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
@@ -321,15 +321,16 @@ static void node_geo_exec(GeoNodeExecParams params)
attribute_outputs.rotation_id = StrongAnonymousAttributeID("Rotation");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (!geometry_set.has_curve()) {
+ if (!geometry_set.has_curves()) {
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
return;
}
- const CurveEval &curve = *geometry_set.get_curve_for_read();
- const Span<SplinePtr> splines = curve.splines();
- curve.assert_valid_point_attributes();
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *geometry_set.get_curves_for_read());
+ const Span<SplinePtr> splines = curve->splines();
+ curve->assert_valid_point_attributes();
- const Array<int> offsets = calculate_spline_point_offsets(params, mode, curve, splines);
+ const Array<int> offsets = calculate_spline_point_offsets(params, mode, *curve, splines);
const int total_size = offsets.last();
if (total_size == 0) {
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
@@ -339,7 +340,7 @@ static void node_geo_exec(GeoNodeExecParams params)
geometry_set.replace_pointcloud(BKE_pointcloud_new_nomain(total_size));
PointCloudComponent &points = geometry_set.get_component_for_write<PointCloudComponent>();
ResultAttributes point_attributes = create_attributes_for_transfer(
- points, curve, attribute_outputs);
+ points, *curve, attribute_outputs);
switch (mode) {
case GEO_NODE_CURVE_RESAMPLE_COUNT:
@@ -351,7 +352,7 @@ static void node_geo_exec(GeoNodeExecParams params)
break;
}
- copy_spline_domain_attributes(curve, offsets, points);
+ copy_spline_domain_attributes(*curve, offsets, points);
if (!point_attributes.rotations.is_empty()) {
curve_create_default_rotation_attribute(
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
index abc5b1649c7..a3dab1b50fe 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
@@ -367,15 +367,18 @@ static void trim_spline(SplinePtr &spline,
const Spline::LookupResult end)
{
switch (spline->type()) {
- case Spline::Type::Bezier:
+ case CURVE_TYPE_BEZIER:
trim_bezier_spline(*spline, start, end);
break;
- case Spline::Type::Poly:
+ case CURVE_TYPE_POLY:
trim_poly_spline(*spline, start, end);
break;
- case Spline::Type::NURBS:
+ case CURVE_TYPE_NURBS:
spline = std::make_unique<PolySpline>(trim_nurbs_spline(*spline, start, end));
break;
+ case CURVE_TYPE_CATMULL_ROM:
+ BLI_assert_unreachable();
+ spline = {};
}
spline->mark_cache_invalid();
}
@@ -400,8 +403,8 @@ static void to_single_point_bezier(Spline &spline, const Spline::LookupResult &l
const BezierSpline::InsertResult new_point = bezier.calculate_segment_insertion(
trim.left_index, trim.right_index, trim.factor);
bezier.positions().first() = new_point.position;
- bezier.handle_types_left().first() = BezierSpline::HandleType::Free;
- bezier.handle_types_right().first() = BezierSpline::HandleType::Free;
+ bezier.handle_types_left().first() = BEZIER_HANDLE_FREE;
+ bezier.handle_types_right().first() = BEZIER_HANDLE_FREE;
bezier.handle_positions_left().first() = new_point.left_handle;
bezier.handle_positions_right().first() = new_point.right_handle;
@@ -477,15 +480,18 @@ static PolySpline to_single_point_nurbs(const Spline &spline, const Spline::Look
static void to_single_point_spline(SplinePtr &spline, const Spline::LookupResult &lookup)
{
switch (spline->type()) {
- case Spline::Type::Bezier:
+ case CURVE_TYPE_BEZIER:
to_single_point_bezier(*spline, lookup);
break;
- case Spline::Type::Poly:
+ case CURVE_TYPE_POLY:
to_single_point_poly(*spline, lookup);
break;
- case Spline::Type::NURBS:
+ case CURVE_TYPE_NURBS:
spline = std::make_unique<PolySpline>(to_single_point_nurbs(*spline, lookup));
break;
+ case CURVE_TYPE_CATMULL_ROM:
+ BLI_assert_unreachable();
+ spline = {};
}
}
@@ -494,7 +500,7 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set,
Field<float> &start_field,
Field<float> &end_field)
{
- if (!geometry_set.has_curve()) {
+ if (!geometry_set.has_curves()) {
return;
}
@@ -509,8 +515,8 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set,
const blender::VArray<float> &starts = evaluator.get_evaluated<float>(0);
const blender::VArray<float> &ends = evaluator.get_evaluated<float>(1);
- CurveEval &curve = *geometry_set.get_curve_for_write();
- MutableSpan<SplinePtr> splines = curve.splines();
+ std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*geometry_set.get_curves_for_read());
+ MutableSpan<SplinePtr> splines = curve->splines();
threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
@@ -559,6 +565,8 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set,
}
}
});
+
+ geometry_set.replace_curve(curve_eval_to_curves(*curve));
}
static void node_geo_exec(GeoNodeExecParams params)
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 2eeb957c123..3baee8a25bb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -332,9 +332,9 @@ static void spline_copy_builtin_attributes(const Spline &spline,
copy_data_based_on_mask(spline.radii(), r_spline.radii(), mask);
copy_data_based_on_mask(spline.tilts(), r_spline.tilts(), mask);
switch (spline.type()) {
- case Spline::Type::Poly:
+ case CURVE_TYPE_POLY:
break;
- case Spline::Type::Bezier: {
+ case CURVE_TYPE_BEZIER: {
const BezierSpline &src = static_cast<const BezierSpline &>(spline);
BezierSpline &dst = static_cast<BezierSpline &>(r_spline);
copy_data_based_on_mask(src.handle_positions_left(), dst.handle_positions_left(), mask);
@@ -343,12 +343,16 @@ static void spline_copy_builtin_attributes(const Spline &spline,
copy_data_based_on_mask(src.handle_types_right(), dst.handle_types_right(), mask);
break;
}
- case Spline::Type::NURBS: {
+ case CURVE_TYPE_NURBS: {
const NURBSpline &src = static_cast<const NURBSpline &>(spline);
NURBSpline &dst = static_cast<NURBSpline &>(r_spline);
copy_data_based_on_mask(src.weights(), dst.weights(), mask);
break;
}
+ case CURVE_TYPE_CATMULL_ROM: {
+ BLI_assert_unreachable();
+ break;
+ }
}
}
@@ -471,9 +475,9 @@ static void separate_curve_selection(GeometrySet &geometry_set,
selection_evaluator.evaluate();
const VArray_Span<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
std::unique_ptr<CurveEval> r_curve = curve_separate(
- *src_component.get_for_read(), selection, selection_domain, invert);
+ *curves_to_curve_eval(*src_component.get_for_read()), selection, selection_domain, invert);
if (r_curve) {
- geometry_set.replace_curve(r_curve.release());
+ geometry_set.replace_curve(curve_eval_to_curves(*r_curve));
}
else {
geometry_set.replace_curve(nullptr);
@@ -1282,7 +1286,7 @@ void separate_geometry(GeometrySet &geometry_set,
some_valid_domain = true;
}
}
- if (geometry_set.has_curve()) {
+ if (geometry_set.has_curves()) {
if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE)) {
file_ns::separate_curve_selection(geometry_set, selection_field, domain, invert);
some_valid_domain = true;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
index 51932d341bc..bdd4d74fe4b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
@@ -152,6 +152,7 @@ BLI_NOINLINE static void update_elimination_mask_for_close_points(
}
KDTree_3d *kdtree = build_kdtree(positions);
+ BLI_SCOPED_DEFER([&]() { BLI_kdtree_3d_free(kdtree); });
for (const int i : positions.index_range()) {
if (elimination_mask[i]) {
@@ -176,8 +177,6 @@ BLI_NOINLINE static void update_elimination_mask_for_close_points(
},
&callback_data);
}
-
- BLI_kdtree_3d_free(kdtree);
}
BLI_NOINLINE static void update_elimination_mask_based_on_density_factors(
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 a526f4f9e65..5a2c32a6c8e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
@@ -272,7 +272,7 @@ static void create_vertex_poly_map(const Mesh &mesh,
* boundary vertex, the first and last polygon have a boundary edge connected to the vertex. The
* `r_shared_edges` array at index i is set to the index of the shared edge between the i-th and
* `(i+1)-th` sorted polygon. Similarly the `r_sorted_corners` array at index i is set to the
- * corner in the i-th sorted polygon.
+ * corner in the i-th sorted polygon. If the polygons couldn't be sorted, `false` is returned.
*
* How the faces are sorted (see diagrams below):
* (For this explanation we'll assume all faces are oriented clockwise)
@@ -321,7 +321,7 @@ static void create_vertex_poly_map(const Mesh &mesh,
* - Finally if we are in the normal case we also need to add the last "shared edge" to close the
* loop.
*/
-static void sort_vertex_polys(const Mesh &mesh,
+static bool sort_vertex_polys(const Mesh &mesh,
const int vertex_index,
const bool boundary_vertex,
const Span<EdgeType> edge_types,
@@ -330,7 +330,7 @@ static void sort_vertex_polys(const Mesh &mesh,
MutableSpan<int> r_sorted_corners)
{
if (connected_polygons.size() <= 2 && (!boundary_vertex || connected_polygons.size() == 0)) {
- return;
+ return true;
}
/* For each polygon store the two corners whose edge contains the vertex. */
@@ -434,8 +434,11 @@ static void sort_vertex_polys(const Mesh &mesh,
break;
}
}
-
- BLI_assert(j != connected_polygons.size());
+ if (j == connected_polygons.size()) {
+ /* The vertex is not manifold because the polygons around the vertex don't form a loop, and
+ * hence can't be sorted. */
+ return false;
+ }
std::swap(connected_polygons[i + 1], connected_polygons[j]);
std::swap(poly_vertex_corners[i + 1], poly_vertex_corners[j]);
@@ -445,6 +448,7 @@ static void sort_vertex_polys(const Mesh &mesh,
/* Shared edge between first and last polygon. */
r_shared_edges.last() = shared_edge_i;
}
+ return true;
}
/**
@@ -637,19 +641,26 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
}
MutableSpan<int> loop_indices = vertex_poly_indices[i];
Array<int> sorted_corners(loop_indices.size());
+ bool vertex_ok = true;
if (vertex_types[i] == VertexType::Normal) {
Array<int> shared_edges(loop_indices.size());
- sort_vertex_polys(
+ vertex_ok = sort_vertex_polys(
mesh_in, i, false, edge_types, loop_indices, shared_edges, sorted_corners);
- vertex_shared_edges[i] = shared_edges;
+ vertex_shared_edges[i] = std::move(shared_edges);
}
else {
Array<int> shared_edges(loop_indices.size() - 1);
- sort_vertex_polys(
+ vertex_ok = sort_vertex_polys(
mesh_in, i, true, edge_types, loop_indices, shared_edges, sorted_corners);
- vertex_shared_edges[i] = shared_edges;
+ vertex_shared_edges[i] = std::move(shared_edges);
+ }
+ if (!vertex_ok) {
+ /* The sorting failed which means that the vertex is non-manifold and should be ignored
+ * further on. */
+ vertex_types[i] = VertexType::NonManifold;
+ continue;
}
- vertex_corners[i] = sorted_corners;
+ vertex_corners[i] = std::move(sorted_corners);
}
});
diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
new file mode 100644
index 00000000000..1ceab18c01b
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
@@ -0,0 +1,1119 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BLI_map.hh"
+#include "BLI_noise.hh"
+#include "BLI_span.hh"
+#include "BLI_task.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_pointcloud_types.h"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_mesh.h"
+#include "BKE_pointcloud.h"
+#include "BKE_spline.hh"
+
+#include "node_geometry_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_geo_duplicate_elements_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryDuplicateElements);
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Bool>(N_("Selection")).hide_value().default_value(true).supports_field();
+ b.add_input<decl::Int>(N_("Amount"))
+ .min(0)
+ .default_value(1)
+ .supports_field()
+ .description(N_("The number of duplicates to create for each element"));
+
+ b.add_output<decl::Geometry>(N_("Geometry"))
+ .description(
+ N_("The duplicated geometry only. The output does not contain the original geometry"));
+ b.add_output<decl::Int>(N_("Duplicate Index"))
+ .field_source()
+ .description(N_("The indices of the duplicates for each element"));
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryDuplicateElements *data = MEM_cnew<NodeGeometryDuplicateElements>(__func__);
+ data->domain = ATTR_DOMAIN_POINT;
+ node->storage = data;
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
+}
+
+struct IndexAttributes {
+ StrongAnonymousAttributeID duplicate_index;
+};
+
+/* -------------------------------------------------------------------- */
+/** \name Attribute Copy/Creation Functions
+ * \{ */
+
+static void gather_attributes_without_id(const GeometrySet &geometry_set,
+ const GeometryComponentType component_type,
+ const Span<std::string> skip_attributes,
+ const bool include_instances,
+ Map<AttributeIDRef, AttributeKind> &r_gathered_attributes)
+{
+ geometry_set.gather_attributes_for_propagation(
+ {component_type}, component_type, include_instances, r_gathered_attributes);
+ for (const std::string &attribute : skip_attributes) {
+ r_gathered_attributes.remove(attribute);
+ }
+ r_gathered_attributes.remove("id");
+};
+
+static IndexRange range_for_offsets_index(const Span<int> offsets, const int index)
+{
+ return {offsets[index], offsets[index + 1] - offsets[index]};
+}
+
+static Array<int> accumulate_counts_to_offsets(const IndexMask selection,
+ const VArray<int> &counts)
+{
+ Array<int> offsets(selection.size() + 1);
+ int dst_points_size = 0;
+ for (const int i_point : selection.index_range()) {
+ offsets[i_point] = dst_points_size;
+ dst_points_size += std::max(counts[selection[i_point]], 0);
+ }
+ offsets.last() = dst_points_size;
+ return offsets;
+}
+
+/* Utility functions for threaded copying of attribute data where possible. */
+template<typename T>
+static void threaded_slice_fill(Span<int> offsets, Span<T> src, MutableSpan<T> dst)
+{
+ BLI_assert(offsets.last() == dst.size());
+ threading::parallel_for(IndexRange(offsets.size() - 1), 512, [&](IndexRange range) {
+ for (const int i : range) {
+ dst.slice(offsets[i], offsets[i + 1] - offsets[i]).fill(src[i]);
+ }
+ });
+}
+
+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 threaded_id_offset_copy(const Span<int> offsets,
+ const Span<int> src,
+ MutableSpan<int> dst)
+{
+ BLI_assert(offsets.last() == dst.size());
+ threading::parallel_for(IndexRange(offsets.size() - 1), 512, [&](IndexRange range) {
+ for (const int i : range) {
+ dst[offsets[i]] = src[i];
+ const int count = offsets[i + 1] - offsets[i];
+ for (const int i_duplicate : IndexRange(1, count - 1)) {
+ dst[offsets[i] + i_duplicate] = noise::hash(src[i], i_duplicate);
+ }
+ }
+ });
+}
+
+/** Create the copy indices for the duplication domain. */
+static void create_duplicate_index_attribute(GeometryComponent &component,
+ const AttributeDomain output_domain,
+ const IndexMask selection,
+ const IndexAttributes &attributes,
+ const Span<int> offsets)
+{
+ OutputAttribute_Typed<int> copy_attribute = component.attribute_try_get_for_output_only<int>(
+ attributes.duplicate_index.get(), output_domain);
+ MutableSpan<int> duplicate_indices = copy_attribute.as_span();
+ for (const int i : IndexRange(selection.size())) {
+ const IndexRange range = range_for_offsets_index(offsets, i);
+ MutableSpan<int> indices = duplicate_indices.slice(range);
+ for (const int i : indices.index_range()) {
+ indices[i] = i;
+ }
+ }
+ copy_attribute.save();
+}
+
+/**
+ * Copy the stable ids to the first duplicate and create new ids based on a hash of the original id
+ * and the duplicate number. This function is used for the point domain elements.
+ */
+static void copy_stable_id_point(const Span<int> offsets,
+ const GeometryComponent &src_component,
+ GeometryComponent &dst_component)
+{
+ ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
+ if (!src_attribute) {
+ return;
+ }
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
+ if (!dst_attribute) {
+ return;
+ }
+
+ VArray_Span<int> src{src_attribute.varray.typed<int>()};
+ MutableSpan<int> dst = dst_attribute.as_span<int>();
+ threaded_id_offset_copy(offsets, src, dst);
+ dst_attribute.save();
+}
+
+/**
+ * Copy the stable ids to the first duplicate and create new ids based on a hash of the original id
+ * and the duplicate number. This function is used for points when duplicating the edge domain.
+ */
+static void copy_stable_id_edges(const Mesh &mesh,
+ const IndexMask selection,
+ const Span<int> edge_offsets,
+ const GeometryComponent &src_component,
+ GeometryComponent &dst_component)
+{
+ ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
+ if (!src_attribute) {
+ return;
+ }
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
+ if (!dst_attribute) {
+ return;
+ }
+
+ Span<MEdge> edges(mesh.medge, mesh.totedge);
+
+ VArray_Span<int> src{src_attribute.varray.typed<int>()};
+ MutableSpan<int> dst = dst_attribute.as_span<int>();
+ threading::parallel_for(IndexRange(selection.size()), 1024, [&](IndexRange range) {
+ for (const int i_edge : range) {
+ const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_edge);
+ if (edge_range.size() == 0) {
+ continue;
+ }
+ const MEdge &edge = edges[i_edge];
+ const IndexRange vert_range = {edge_range.start() * 2, edge_range.size() * 2};
+
+ dst[vert_range[0]] = src[edge.v1];
+ dst[vert_range[1]] = src[edge.v2];
+ for (const int i_duplicate : IndexRange(1, edge_range.size() - 1)) {
+ dst[vert_range[i_duplicate * 2]] = noise::hash(src[edge.v1], i_duplicate);
+ dst[vert_range[i_duplicate * 2 + 1]] = noise::hash(src[edge.v2], i_duplicate);
+ }
+ }
+ });
+ dst_attribute.save();
+}
+
+/**
+ * Copy the stable ids to the first duplicate and create new ids based on a hash of the original id
+ * and the duplicate number. This function is used for points when duplicating the face domain.
+ *
+ * This function could be threaded in the future, but since it is only 1 attribute and the
+ * `face->edge->vert` mapping would mean creating a 1/1 mapping to allow for it, is it worth it?
+ */
+static void copy_stable_id_faces(const Mesh &mesh,
+ const IndexMask selection,
+ const Span<int> poly_offsets,
+ const Span<int> vert_mapping,
+ const GeometryComponent &src_component,
+ GeometryComponent &dst_component)
+{
+ ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
+ if (!src_attribute) {
+ return;
+ }
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
+ if (!dst_attribute) {
+ return;
+ }
+
+ VArray_Span<int> src{src_attribute.varray.typed<int>()};
+ MutableSpan<int> dst = dst_attribute.as_span<int>();
+
+ Span<MPoly> polys(mesh.mpoly, mesh.totpoly);
+ int loop_index = 0;
+ for (const int i_poly : selection.index_range()) {
+ const IndexRange range = range_for_offsets_index(poly_offsets, i_poly);
+ if (range.size() == 0) {
+ continue;
+ }
+ const MPoly &source = polys[i_poly];
+ for ([[maybe_unused]] const int i_duplicate : IndexRange(range.size())) {
+ for ([[maybe_unused]] const int i_loops : IndexRange(source.totloop)) {
+ if (i_duplicate == 0) {
+ dst[loop_index] = src[vert_mapping[loop_index]];
+ }
+ else {
+ dst[loop_index] = noise::hash(src[vert_mapping[loop_index]], i_duplicate);
+ }
+ loop_index++;
+ }
+ }
+ }
+
+ dst_attribute.save();
+}
+
+/**
+ * Copy the stable ids to the first duplicate and create new ids based on a hash of the original id
+ * and the duplicate number. In the spline case, copy the entire spline's points to the
+ * destination,
+ * then loop over the remaining ones point by point, hashing their ids to the new ids.
+ */
+static void copy_stable_id_splines(const CurveEval &curve,
+ const IndexMask selection,
+ const Span<int> curve_offsets,
+ const GeometryComponent &src_component,
+ GeometryComponent &dst_component)
+{
+ ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
+ if (!src_attribute) {
+ return;
+ }
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
+ if (!dst_attribute) {
+ return;
+ }
+
+ Array<int> control_point_offsets = curve.control_point_offsets();
+ VArray_Span<int> src{src_attribute.varray.typed<int>()};
+ MutableSpan<int> dst = dst_attribute.as_span<int>();
+
+ Array<int> curve_point_offsets(selection.size() + 1);
+ int dst_point_size = 0;
+ for (const int i_curve : selection.index_range()) {
+ const int spline_size = curve.splines()[i_curve]->size();
+ const IndexRange curve_range = range_for_offsets_index(curve_offsets, i_curve);
+
+ curve_point_offsets[i_curve] = dst_point_size;
+ dst_point_size += curve_range.size() * spline_size;
+ }
+ curve_point_offsets.last() = dst_point_size;
+
+ threading::parallel_for(IndexRange(curve_point_offsets.size() - 1), 512, [&](IndexRange range) {
+ for (const int i_curve : range) {
+ const int spline_size = curve.splines()[i_curve]->size();
+ const IndexRange curve_range = range_for_offsets_index(curve_offsets, i_curve);
+
+ dst.slice(curve_point_offsets[i_curve], spline_size)
+ .copy_from(src.slice(control_point_offsets[i_curve], spline_size));
+ for (const int i_duplicate : IndexRange(1, curve_range.size() - 1)) {
+ for (const int i_point : IndexRange(spline_size)) {
+ dst[curve_point_offsets[i_curve] + i_duplicate * spline_size + i_point] = noise::hash(
+ src[control_point_offsets[i_curve] + i_point], i_duplicate);
+ }
+ }
+ }
+ });
+ dst_attribute.save();
+}
+
+/* The attributes for the point (also instance) duplicated elements are stored sequentially
+ * (1,1,1,2,2,2,3,3,3,etc) They can be copied by using a simple offset array. For each domain, if
+ * elements are ordered differently a custom function is called to copy the attributes.
+ */
+
+static void copy_point_attributes_without_id(GeometrySet &geometry_set,
+ const GeometryComponentType component_type,
+ const bool include_instances,
+ const Span<int> offsets,
+ const GeometryComponent &src_component,
+ GeometryComponent &dst_component)
+{
+ Map<AttributeIDRef, AttributeKind> gathered_attributes;
+ gather_attributes_without_id(
+ geometry_set, component_type, {}, include_instances, gathered_attributes);
+
+ for (const Map<AttributeIDRef, AttributeKind>::Item entry : gathered_attributes.items()) {
+ const AttributeIDRef attribute_id = entry.key;
+ ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id);
+ if (!src_attribute || src_attribute.domain != ATTR_DOMAIN_POINT) {
+ continue;
+ }
+ AttributeDomain out_domain = src_attribute.domain;
+ const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
+ src_attribute.varray.type());
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ attribute_id, out_domain, data_type);
+ if (!dst_attribute) {
+ continue;
+ }
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ VArray_Span<T> src = src_attribute.varray.typed<T>();
+ MutableSpan<T> dst = dst_attribute.as_span<T>();
+ threaded_slice_fill<T>(offsets, src, dst);
+ });
+ dst_attribute.save();
+ }
+}
+
+/**
+ * Copies the attributes for spline duplicates. If copying the spline domain, the attributes are
+ * copied with an offset fill, otherwise a mapping is used.
+ */
+static void copy_spline_attributes_without_id(const GeometrySet &geometry_set,
+ const Span<int> point_mapping,
+ const Span<int> offsets,
+ const Span<std::string> attributes_to_ignore,
+ const GeometryComponent &src_component,
+ GeometryComponent &dst_component)
+{
+ Map<AttributeIDRef, AttributeKind> gathered_attributes;
+ gather_attributes_without_id(
+ geometry_set, GEO_COMPONENT_TYPE_CURVE, attributes_to_ignore, false, gathered_attributes);
+
+ for (const Map<AttributeIDRef, AttributeKind>::Item entry : gathered_attributes.items()) {
+
+ const AttributeIDRef attribute_id = entry.key;
+ ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id);
+ if (!src_attribute) {
+ continue;
+ }
+
+ AttributeDomain out_domain = src_attribute.domain;
+ const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
+ src_attribute.varray.type());
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ attribute_id, out_domain, data_type);
+ if (!dst_attribute) {
+ continue;
+ }
+
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ VArray_Span<T> src{src_attribute.varray.typed<T>()};
+ MutableSpan<T> dst = dst_attribute.as_span<T>();
+
+ switch (out_domain) {
+ case ATTR_DOMAIN_CURVE:
+ threaded_slice_fill<T>(offsets, src, dst);
+ break;
+ case ATTR_DOMAIN_POINT:
+ threaded_mapped_copy<T>(point_mapping, src, dst);
+ break;
+ default:
+ break;
+ }
+ });
+ dst_attribute.save();
+ }
+}
+
+/**
+ * Copies the attributes for edge duplicates. If copying the edge domain, the attributes are
+ * copied with an offset fill, for point domain a mapping is used.
+ */
+static void copy_edge_attributes_without_id(GeometrySet &geometry_set,
+ const Span<int> point_mapping,
+ const Span<int> offsets,
+ const GeometryComponent &src_component,
+ GeometryComponent &dst_component)
+{
+ Map<AttributeIDRef, AttributeKind> gathered_attributes;
+ gather_attributes_without_id(
+ geometry_set, GEO_COMPONENT_TYPE_MESH, {}, false, gathered_attributes);
+
+ for (const Map<AttributeIDRef, AttributeKind>::Item entry : gathered_attributes.items()) {
+ const AttributeIDRef attribute_id = entry.key;
+ ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id);
+ if (!src_attribute) {
+ continue;
+ }
+
+ const AttributeDomain out_domain = src_attribute.domain;
+ const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
+ src_attribute.varray.type());
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ attribute_id, out_domain, data_type);
+ if (!dst_attribute) {
+ continue;
+ }
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ VArray_Span<T> src{src_attribute.varray.typed<T>()};
+ MutableSpan<T> dst = dst_attribute.as_span<T>();
+
+ switch (out_domain) {
+ case ATTR_DOMAIN_EDGE:
+ threaded_slice_fill<T>(offsets, src, dst);
+ break;
+ case ATTR_DOMAIN_POINT:
+ threaded_mapped_copy<T>(point_mapping, src, dst);
+ break;
+ default:
+ break;
+ }
+ });
+ dst_attribute.save();
+ }
+}
+
+/**
+ * Copies the attributes for face duplicates. If copying the face domain, the attributes are
+ * copied with an offset fill, otherwise a mapping is used.
+ */
+static void copy_face_attributes_without_id(GeometrySet &geometry_set,
+ const Span<int> edge_mapping,
+ const Span<int> vert_mapping,
+ const Span<int> loop_mapping,
+ const Span<int> offsets,
+ const GeometryComponent &src_component,
+ GeometryComponent &dst_component)
+{
+ Map<AttributeIDRef, AttributeKind> gathered_attributes;
+ gather_attributes_without_id(
+ geometry_set, GEO_COMPONENT_TYPE_MESH, {}, false, gathered_attributes);
+
+ for (const Map<AttributeIDRef, AttributeKind>::Item entry : gathered_attributes.items()) {
+ const AttributeIDRef attribute_id = entry.key;
+ ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id);
+ if (!src_attribute) {
+ continue;
+ }
+
+ AttributeDomain out_domain = src_attribute.domain;
+ const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
+ src_attribute.varray.type());
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ attribute_id, out_domain, data_type);
+ if (!dst_attribute) {
+ continue;
+ }
+
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ VArray_Span<T> src{src_attribute.varray.typed<T>()};
+ MutableSpan<T> dst = dst_attribute.as_span<T>();
+
+ switch (out_domain) {
+ case ATTR_DOMAIN_FACE:
+ threaded_slice_fill<T>(offsets, src, dst);
+ break;
+ case ATTR_DOMAIN_EDGE:
+ threaded_mapped_copy<T>(edge_mapping, src, dst);
+ break;
+ case ATTR_DOMAIN_POINT:
+ threaded_mapped_copy<T>(vert_mapping, src, dst);
+ break;
+ case ATTR_DOMAIN_CORNER:
+ threaded_mapped_copy<T>(loop_mapping, src, dst);
+ break;
+ default:
+ break;
+ }
+ });
+ dst_attribute.save();
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Duplication Functions
+ * \{ */
+
+static void duplicate_splines(GeometrySet &geometry_set,
+ const Field<int> &count_field,
+ const Field<bool> &selection_field,
+ IndexAttributes &attributes)
+{
+ if (!geometry_set.has_curves()) {
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
+ return;
+ }
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_CURVE, GEO_COMPONENT_TYPE_INSTANCES});
+
+ const GeometryComponent &src_component = *geometry_set.get_component_for_read(
+ GEO_COMPONENT_TYPE_CURVE);
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *geometry_set.get_curves_for_read());
+ const int domain_size = src_component.attribute_domain_size(ATTR_DOMAIN_CURVE);
+ GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE};
+ FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(count_field);
+ evaluator.set_selection(selection_field);
+ evaluator.evaluate();
+ const VArray<int> counts = evaluator.get_evaluated<int>(0);
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+
+ Array<int> curve_offsets(selection.size() + 1);
+
+ int dst_splines_size = 0;
+ int dst_points_size = 0;
+ for (const int i_spline : selection.index_range()) {
+ int count = std::max(counts[selection[i_spline]], 0);
+ curve_offsets[i_spline] = dst_splines_size;
+ dst_splines_size += count;
+ dst_points_size += count * curve->splines()[selection[i_spline]]->size();
+ }
+ curve_offsets.last() = dst_splines_size;
+
+ Array<int> control_point_offsets = curve->control_point_offsets();
+ Array<int> point_mapping(dst_points_size);
+
+ std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>();
+ int point_index = 0;
+ for (const int i_spline : selection.index_range()) {
+ const IndexRange spline_range = range_for_offsets_index(curve_offsets, i_spline);
+ for ([[maybe_unused]] const int i_duplicate : IndexRange(spline_range.size())) {
+ SplinePtr spline = curve->splines()[selection[i_spline]]->copy();
+ for (const int i_point : IndexRange(curve->splines()[selection[i_spline]]->size())) {
+ point_mapping[point_index++] = control_point_offsets[selection[i_spline]] + i_point;
+ }
+ new_curve->add_spline(std::move(spline));
+ }
+ }
+ new_curve->attributes.reallocate(new_curve->splines().size());
+
+ CurveComponent dst_component;
+ dst_component.replace(curve_eval_to_curves(*new_curve), GeometryOwnershipType::Editable);
+
+ Vector<std::string> skip(
+ {"position", "radius", "resolution", "cyclic", "tilt", "handle_left", "handle_right"});
+
+ copy_spline_attributes_without_id(
+ geometry_set, point_mapping, curve_offsets, skip, src_component, dst_component);
+
+ copy_stable_id_splines(*curve, selection, curve_offsets, src_component, dst_component);
+
+ if (attributes.duplicate_index) {
+ create_duplicate_index_attribute(
+ dst_component, ATTR_DOMAIN_CURVE, selection, attributes, curve_offsets);
+ }
+
+ geometry_set.replace_curve(dst_component.get_for_write());
+}
+
+static void duplicate_faces(GeometrySet &geometry_set,
+ const Field<int> &count_field,
+ const Field<bool> &selection_field,
+ IndexAttributes &attributes)
+{
+ if (!geometry_set.has_mesh()) {
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
+ return;
+ }
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_INSTANCES});
+
+ GeometryComponent &component = geometry_set.get_component_for_write(GEO_COMPONENT_TYPE_MESH);
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
+
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
+ FieldEvaluator evaluator(field_context, domain_size);
+
+ evaluator.add(count_field);
+ evaluator.set_selection(selection_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ const VArray<int> counts = evaluator.get_evaluated<int>(0);
+
+ MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
+ const Mesh &mesh = *mesh_component.get_for_read();
+ Span<MVert> verts(mesh.mvert, mesh.totvert);
+ Span<MEdge> edges(mesh.medge, mesh.totedge);
+ Span<MPoly> polys(mesh.mpoly, mesh.totpoly);
+ Span<MLoop> loops(mesh.mloop, mesh.totloop);
+
+ int total_polys = 0;
+ int total_loops = 0;
+ Array<int> offsets(selection.size() + 1);
+ for (const int i_selection : selection.index_range()) {
+ const int count = std::max(counts[selection[i_selection]], 0);
+ offsets[i_selection] = total_polys;
+ total_polys += count;
+ total_loops += count * polys[selection[i_selection]].totloop;
+ }
+ offsets[selection.size()] = total_polys;
+
+ Array<int> vert_mapping(total_loops);
+ Array<int> edge_mapping(total_loops);
+ Array<int> loop_mapping(total_loops);
+
+ Mesh *new_mesh = BKE_mesh_new_nomain(total_loops, total_loops, 0, total_loops, total_polys);
+
+ MutableSpan<MVert> new_verts(new_mesh->mvert, new_mesh->totvert);
+ MutableSpan<MEdge> new_edges(new_mesh->medge, new_mesh->totedge);
+ MutableSpan<MLoop> new_loops(new_mesh->mloop, new_mesh->totloop);
+ MutableSpan<MPoly> new_poly(new_mesh->mpoly, new_mesh->totpoly);
+
+ int poly_index = 0;
+ int loop_index = 0;
+ for (const int i_selection : selection.index_range()) {
+ const IndexRange poly_range = range_for_offsets_index(offsets, i_selection);
+
+ const MPoly &source = polys[selection[i_selection]];
+ for ([[maybe_unused]] const int i_duplicate : IndexRange(poly_range.size())) {
+ new_poly[poly_index] = source;
+ new_poly[poly_index].loopstart = loop_index;
+ for (const int i_loops : IndexRange(source.totloop)) {
+ const MLoop &current_loop = loops[source.loopstart + i_loops];
+ loop_mapping[loop_index] = source.loopstart + i_loops;
+ new_verts[loop_index] = verts[current_loop.v];
+ vert_mapping[loop_index] = current_loop.v;
+ new_edges[loop_index] = edges[current_loop.e];
+ edge_mapping[loop_index] = current_loop.e;
+ new_edges[loop_index].v1 = loop_index;
+ if (i_loops + 1 != source.totloop) {
+ new_edges[loop_index].v2 = loop_index + 1;
+ }
+ else {
+ new_edges[loop_index].v2 = new_poly[poly_index].loopstart;
+ }
+ new_loops[loop_index].v = loop_index;
+ new_loops[loop_index].e = loop_index;
+ loop_index++;
+ }
+ poly_index++;
+ }
+ }
+ MeshComponent dst_component;
+ dst_component.replace(new_mesh, GeometryOwnershipType::Editable);
+
+ copy_face_attributes_without_id(geometry_set,
+ edge_mapping,
+ vert_mapping,
+ loop_mapping,
+ offsets,
+ mesh_component,
+ dst_component);
+
+ copy_stable_id_faces(mesh, selection, offsets, vert_mapping, mesh_component, dst_component);
+ mesh_component.replace(dst_component.get_for_write());
+
+ if (attributes.duplicate_index) {
+ create_duplicate_index_attribute(
+ dst_component, ATTR_DOMAIN_FACE, selection, attributes, offsets);
+ }
+}
+
+static void duplicate_edges(GeometrySet &geometry_set,
+ const Field<int> &count_field,
+ const Field<bool> &selection_field,
+ IndexAttributes &attributes)
+{
+ if (!geometry_set.has_mesh()) {
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
+ return;
+ };
+ const GeometryComponent &src_component = *geometry_set.get_component_for_read(
+ GEO_COMPONENT_TYPE_MESH);
+ const int domain_size = src_component.attribute_domain_size(ATTR_DOMAIN_EDGE);
+
+ GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_EDGE};
+ FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(count_field);
+ evaluator.set_selection(selection_field);
+ evaluator.evaluate();
+ const VArray<int> counts = evaluator.get_evaluated<int>(0);
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+
+ Array<int> edge_offsets = accumulate_counts_to_offsets(selection, counts);
+
+ const Mesh *mesh = geometry_set.get_mesh_for_read();
+ Span<MVert> verts(mesh->mvert, mesh->totvert);
+ Span<MEdge> edges(mesh->medge, mesh->totedge);
+
+ Mesh *new_mesh = BKE_mesh_new_nomain(edge_offsets.last() * 2, edge_offsets.last(), 0, 0, 0);
+ MutableSpan<MVert> new_verts(new_mesh->mvert, new_mesh->totvert);
+ MutableSpan<MEdge> new_edges(new_mesh->medge, new_mesh->totedge);
+
+ Array<int> vert_orig_indices(edge_offsets.last() * 2);
+ threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
+ for (const int i_edge : range) {
+ const MEdge &edge = edges[i_edge];
+ const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_edge);
+ const IndexRange vert_range(edge_range.start() * 2, edge_range.size() * 2);
+
+ for (const int i_duplicate : IndexRange(edge_range.size())) {
+ vert_orig_indices[vert_range[i_duplicate * 2]] = edge.v1;
+ vert_orig_indices[vert_range[i_duplicate * 2 + 1]] = edge.v2;
+ }
+ }
+ });
+
+ threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
+ for (const int i_edge : range) {
+ const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_edge);
+ const IndexRange vert_range(edge_range.start() * 2, edge_range.size() * 2);
+ for (const int i_duplicate : IndexRange(edge_range.size())) {
+ MEdge &new_edge = new_edges[edge_range[i_duplicate]];
+ new_edge.v1 = vert_range[i_duplicate * 2];
+ new_edge.v2 = vert_range[i_duplicate * 2] + 1;
+ }
+ }
+ });
+
+ MeshComponent dst_component;
+ dst_component.replace(new_mesh, GeometryOwnershipType::Editable);
+
+ copy_edge_attributes_without_id(
+ geometry_set, vert_orig_indices, edge_offsets, src_component, dst_component);
+
+ copy_stable_id_edges(*mesh, selection, edge_offsets, src_component, dst_component);
+
+ if (attributes.duplicate_index) {
+ create_duplicate_index_attribute(
+ dst_component, ATTR_DOMAIN_EDGE, selection, attributes, edge_offsets);
+ }
+
+ MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
+ mesh_component.replace(dst_component.get_for_write());
+}
+
+static void duplicate_points_curve(const GeometryComponentType component_type,
+ const Field<int> &count_field,
+ const Field<bool> &selection_field,
+ GeometrySet &geometry_set,
+ IndexAttributes &attributes)
+{
+ const GeometryComponent &src_component = *geometry_set.get_component_for_read(component_type);
+ const int domain_size = src_component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ if (domain_size == 0) {
+ return;
+ }
+
+ GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_POINT};
+ FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(count_field);
+ evaluator.set_selection(selection_field);
+ evaluator.evaluate();
+ const VArray<int> counts = evaluator.get_evaluated<int>(0);
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+
+ Array<int> offsets = accumulate_counts_to_offsets(selection, counts);
+
+ CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *geometry_set.get_curves_for_read());
+ Array<int> control_point_offsets = curve->control_point_offsets();
+ std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>();
+
+ Array<int> parent(domain_size);
+ int spline = 0;
+ for (const int i_spline : IndexRange(domain_size)) {
+ if (i_spline == control_point_offsets[spline + 1]) {
+ spline++;
+ }
+ parent[i_spline] = spline;
+ }
+
+ for (const int i_point : selection) {
+ const IndexRange point_range = range_for_offsets_index(offsets, i_point);
+ for ([[maybe_unused]] const int i_duplicate : IndexRange(point_range.size())) {
+ const SplinePtr &parent_spline = curve->splines()[parent[i_point]];
+ switch (parent_spline->type()) {
+ case CurveType::CURVE_TYPE_BEZIER: {
+ std::unique_ptr<BezierSpline> spline = std::make_unique<BezierSpline>();
+ spline->resize(1);
+ spline->set_resolution(2);
+ new_curve->add_spline(std::move(spline));
+ break;
+ }
+ case CurveType::CURVE_TYPE_NURBS: {
+ std::unique_ptr<NURBSpline> spline = std::make_unique<NURBSpline>();
+ spline->resize(1);
+ spline->set_resolution(2);
+ new_curve->add_spline(std::move(spline));
+ break;
+ }
+ case CurveType::CURVE_TYPE_POLY: {
+ std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+ spline->resize(1);
+ new_curve->add_spline(std::move(spline));
+ break;
+ }
+ case CurveType::CURVE_TYPE_CATMULL_ROM: {
+ /* Catmull Rom curves are not supported yet. */
+ break;
+ }
+ }
+ }
+ }
+ new_curve->attributes.reallocate(new_curve->splines().size());
+ CurveComponent dst_component;
+ dst_component.replace(curve_eval_to_curves(*new_curve), GeometryOwnershipType::Editable);
+
+ copy_point_attributes_without_id(
+ geometry_set, GEO_COMPONENT_TYPE_CURVE, false, offsets, src_component, dst_component);
+
+ copy_stable_id_point(offsets, src_component, dst_component);
+
+ if (attributes.duplicate_index) {
+ create_duplicate_index_attribute(
+ dst_component, ATTR_DOMAIN_POINT, selection, attributes, offsets.as_span());
+ }
+
+ curve_component.replace(dst_component.get_for_write());
+}
+
+static void duplicate_points_mesh(const GeometryComponentType component_type,
+ const Field<int> &count_field,
+ const Field<bool> &selection_field,
+ GeometrySet &geometry_set,
+ IndexAttributes &attributes)
+{
+ const GeometryComponent &src_component = *geometry_set.get_component_for_read(component_type);
+ const int domain_size = src_component.attribute_domain_size(ATTR_DOMAIN_POINT);
+
+ GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_POINT};
+ FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(count_field);
+ evaluator.set_selection(selection_field);
+ evaluator.evaluate();
+ const VArray<int> counts = evaluator.get_evaluated<int>(0);
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+
+ Array<int> offsets = accumulate_counts_to_offsets(selection, counts);
+
+ const Mesh *mesh = geometry_set.get_mesh_for_read();
+ Span<MVert> src_verts(mesh->mvert, mesh->totvert);
+
+ Mesh *new_mesh = BKE_mesh_new_nomain(offsets.last(), 0, 0, 0, 0);
+ MutableSpan<MVert> dst_verts(new_mesh->mvert, new_mesh->totvert);
+
+ threaded_slice_fill<MVert>(offsets.as_span(), src_verts, dst_verts);
+
+ MeshComponent dst_component;
+ dst_component.replace(new_mesh, GeometryOwnershipType::Editable);
+ copy_point_attributes_without_id(
+ geometry_set, GEO_COMPONENT_TYPE_MESH, false, offsets, src_component, dst_component);
+
+ copy_stable_id_point(offsets, src_component, dst_component);
+
+ if (attributes.duplicate_index) {
+ create_duplicate_index_attribute(
+ dst_component, ATTR_DOMAIN_POINT, selection, attributes, offsets.as_span());
+ }
+
+ MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
+ mesh_component.replace(dst_component.get_for_write());
+}
+
+static void duplicate_points_pointcloud(const GeometryComponentType component_type,
+ const Field<int> &count_field,
+ const Field<bool> &selection_field,
+ GeometrySet &geometry_set,
+ IndexAttributes &attributes)
+{
+ const GeometryComponent &src_component = *geometry_set.get_component_for_read(component_type);
+ const int domain_size = src_component.attribute_domain_size(ATTR_DOMAIN_POINT);
+
+ GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_POINT};
+ FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(count_field);
+ evaluator.set_selection(selection_field);
+ evaluator.evaluate();
+ const VArray<int> counts = evaluator.get_evaluated<int>(0);
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+
+ Array<int> offsets = accumulate_counts_to_offsets(selection, counts);
+
+ PointCloud *pointcloud = BKE_pointcloud_new_nomain(offsets.last());
+ PointCloudComponent dst_component;
+ dst_component.replace(pointcloud, GeometryOwnershipType::Editable);
+
+ copy_point_attributes_without_id(
+ geometry_set, GEO_COMPONENT_TYPE_POINT_CLOUD, false, offsets, src_component, dst_component);
+
+ copy_stable_id_point(offsets, src_component, dst_component);
+
+ if (attributes.duplicate_index) {
+ create_duplicate_index_attribute(
+ dst_component, ATTR_DOMAIN_POINT, selection, attributes, offsets);
+ }
+ geometry_set.replace_pointcloud(pointcloud);
+}
+
+static void duplicate_points(GeometrySet &geometry_set,
+ const Field<int> &count_field,
+ const Field<bool> &selection_field,
+ IndexAttributes &attributes)
+{
+ if (!geometry_set.has_mesh() && !geometry_set.has_curves() && !geometry_set.has_pointcloud()) {
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
+ return;
+ }
+
+ Vector<GeometryComponentType> component_types = geometry_set.gather_component_types(true, true);
+ Vector<GeometryComponentType> types_to_keep;
+ for (const GeometryComponentType component_type : component_types) {
+ switch (component_type) {
+ case GEO_COMPONENT_TYPE_POINT_CLOUD:
+ types_to_keep.append(component_type);
+ duplicate_points_pointcloud(
+ component_type, count_field, selection_field, geometry_set, attributes);
+ break;
+ case GEO_COMPONENT_TYPE_MESH:
+ types_to_keep.append(component_type);
+ duplicate_points_mesh(
+ component_type, count_field, selection_field, geometry_set, attributes);
+ break;
+ case GEO_COMPONENT_TYPE_CURVE:
+ types_to_keep.append(component_type);
+ duplicate_points_curve(
+ component_type, count_field, selection_field, geometry_set, attributes);
+ break;
+ default:
+ break;
+ }
+ }
+ types_to_keep.append(GEO_COMPONENT_TYPE_INSTANCES);
+ geometry_set.keep_only(types_to_keep);
+}
+
+static void duplicate_instances(GeometrySet &geometry_set,
+ const Field<int> &count_field,
+ const Field<bool> &selection_field,
+ IndexAttributes &attributes)
+{
+ if (!geometry_set.has_instances()) {
+ geometry_set.clear();
+ return;
+ }
+
+ const InstancesComponent &src_instances =
+ *geometry_set.get_component_for_read<InstancesComponent>();
+
+ const int domain_size = src_instances.attribute_domain_size(ATTR_DOMAIN_INSTANCE);
+ GeometryComponentFieldContext field_context{src_instances, ATTR_DOMAIN_INSTANCE};
+ FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(count_field);
+ evaluator.set_selection(selection_field);
+ evaluator.evaluate();
+ IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ const VArray<int> counts = evaluator.get_evaluated<int>(0);
+
+ Array<int> offsets = accumulate_counts_to_offsets(selection, counts);
+
+ if (offsets.last() == 0) {
+ geometry_set.clear();
+ return;
+ }
+
+ GeometrySet instances_geometry;
+ InstancesComponent &dst_instances =
+ instances_geometry.get_component_for_write<InstancesComponent>();
+ dst_instances.resize(offsets.last());
+ for (const int i_selection : selection.index_range()) {
+ const int count = offsets[i_selection + 1] - offsets[i_selection];
+ if (count == 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(offsets[i_selection], count).fill(transform);
+ dst_instances.instance_reference_handles().slice(offsets[i_selection], count).fill(new_handle);
+ }
+
+ copy_point_attributes_without_id(
+ geometry_set, GEO_COMPONENT_TYPE_INSTANCES, true, offsets, src_instances, dst_instances);
+
+ if (attributes.duplicate_index) {
+ create_duplicate_index_attribute(
+ dst_instances, ATTR_DOMAIN_INSTANCE, selection, attributes, offsets);
+ }
+
+ geometry_set.remove(GEO_COMPONENT_TYPE_INSTANCES);
+ geometry_set.add(dst_instances);
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
+ const NodeGeometryDuplicateElements &storage = node_storage(params.node());
+ const AttributeDomain duplicate_domain = AttributeDomain(storage.domain);
+
+ Field<int> count_field = params.extract_input<Field<int>>("Amount");
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+ IndexAttributes attributes;
+ if (params.output_is_required("Duplicate Index")) {
+ attributes.duplicate_index = StrongAnonymousAttributeID("duplicate_index");
+ }
+
+ if (duplicate_domain == ATTR_DOMAIN_INSTANCE) {
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
+ duplicate_instances(geometry_set, count_field, selection_field, attributes);
+ }
+ else {
+ if (geometry_set.is_empty()) {
+ params.set_default_remaining_outputs();
+ return;
+ }
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ switch (duplicate_domain) {
+ case ATTR_DOMAIN_CURVE:
+ duplicate_splines(geometry_set, count_field, selection_field, attributes);
+ break;
+ case ATTR_DOMAIN_FACE:
+ duplicate_faces(geometry_set, count_field, selection_field, attributes);
+ break;
+ case ATTR_DOMAIN_EDGE:
+ duplicate_edges(geometry_set, count_field, selection_field, attributes);
+ break;
+ case ATTR_DOMAIN_POINT:
+ duplicate_points(geometry_set, count_field, selection_field, attributes);
+ break;
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+ });
+ }
+
+ if (geometry_set.is_empty()) {
+ params.set_default_remaining_outputs();
+ return;
+ }
+
+ if (attributes.duplicate_index) {
+ params.set_output(
+ "Duplicate Index",
+ AnonymousAttributeFieldInput::Create<int>(std::move(attributes.duplicate_index),
+ params.attribute_producer_name()));
+ }
+ params.set_output("Geometry", geometry_set);
+}
+
+} // namespace blender::nodes::node_geo_duplicate_elements_cc
+
+void register_node_type_geo_duplicate_elements()
+{
+ namespace file_ns = blender::nodes::node_geo_duplicate_elements_cc;
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_DUPLICATE_ELEMENTS, "Duplicate Elements", NODE_CLASS_GEOMETRY);
+
+ node_type_storage(&ntype,
+ "NodeGeometryDuplicateElements",
+ node_free_standard_storage,
+ node_copy_standard_storage);
+
+ node_type_init(&ntype, file_ns::node_init);
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
+
+/** \} */
diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
index 4e053dbc1a3..c03a340a0c8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
@@ -25,6 +25,9 @@ static Mesh *mesh_edge_split(const Mesh &mesh, const IndexMask selection)
BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params);
BMeshFromMeshParams bmesh_from_mesh_params{};
+ bmesh_from_mesh_params.cd_mask_extra.vmask = CD_MASK_ORIGINDEX;
+ bmesh_from_mesh_params.cd_mask_extra.emask = CD_MASK_ORIGINDEX;
+ bmesh_from_mesh_params.cd_mask_extra.pmask = CD_MASK_ORIGINDEX;
BM_mesh_bm_from_me(bm, &mesh, &bmesh_from_mesh_params);
BM_mesh_elem_table_ensure(bm, BM_EDGE);
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 5aeeb72961d..82584f6f413 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
@@ -302,7 +302,6 @@ static void extrude_mesh_vertices(MeshComponent &component,
}
BKE_mesh_runtime_clear_cache(&mesh);
- BKE_mesh_normals_tag_dirty(&mesh);
}
static Array<Vector<int, 2>> mesh_calculate_polys_of_edge(const Mesh &mesh)
@@ -626,7 +625,6 @@ static void extrude_mesh_edges(MeshComponent &component,
}
BKE_mesh_runtime_clear_cache(&mesh);
- BKE_mesh_normals_tag_dirty(&mesh);
}
/**
@@ -995,7 +993,6 @@ static void extrude_mesh_face_regions(MeshComponent &component,
}
BKE_mesh_runtime_clear_cache(&mesh);
- BKE_mesh_normals_tag_dirty(&mesh);
}
/* Get the range into an array of extruded corners, edges, or vertices for a particular polygon. */
@@ -1263,7 +1260,6 @@ static void extrude_individual_mesh_faces(MeshComponent &component,
}
BKE_mesh_runtime_clear_cache(&mesh);
- BKE_mesh_normals_tag_dirty(&mesh);
}
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
new file mode 100644
index 00000000000..62af0476057
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
@@ -0,0 +1,119 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_mesh_face_is_planar_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>("Threshold")
+ .field_source()
+ .default_value(0.01f)
+ .subtype(PROP_DISTANCE)
+ .supports_field()
+ .description(N_("The distance a point can be from the surface before the face is no longer "
+ "considered planar"))
+ .min(0.0f);
+ b.add_output<decl::Bool>("Planar").field_source();
+}
+
+class PlanarFieldInput final : public GeometryFieldInput {
+ private:
+ Field<float> threshold_;
+
+ public:
+ PlanarFieldInput(Field<float> threshold)
+ : GeometryFieldInput(CPPType::get<bool>(), "Planar"), threshold_(threshold)
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ [[maybe_unused]] IndexMask mask) const final
+ {
+ if (component.type() != GEO_COMPONENT_TYPE_MESH) {
+ return {};
+ }
+
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ GeometryComponentFieldContext context{mesh_component, ATTR_DOMAIN_FACE};
+ fn::FieldEvaluator evaluator{context, mesh->totpoly};
+ evaluator.add(threshold_);
+ evaluator.evaluate();
+ const VArray<float> &thresholds = evaluator.get_evaluated<float>(0);
+
+ Span<float3> poly_normals{(float3 *)BKE_mesh_poly_normals_ensure(mesh), mesh->totpoly};
+
+ auto planar_fn = [mesh, thresholds, poly_normals](const int i_poly) -> bool {
+ if (mesh->mpoly[i_poly].totloop <= 3) {
+ return true;
+ }
+ const int loopstart = mesh->mpoly[i_poly].loopstart;
+ const int loops = mesh->mpoly[i_poly].totloop;
+ Span<MLoop> poly_loops(&mesh->mloop[loopstart], loops);
+ float3 reference_normal = poly_normals[i_poly];
+
+ float min = FLT_MAX;
+ float max = FLT_MIN;
+
+ for (const int i_loop : poly_loops.index_range()) {
+ const float3 vert = mesh->mvert[poly_loops[i_loop].v].co;
+ float dot = math::dot(reference_normal, vert);
+ if (dot > max) {
+ max = dot;
+ }
+ if (dot < min) {
+ min = dot;
+ }
+ }
+ return max - min < thresholds[i_poly] / 2.0f;
+ };
+
+ return component.attribute_try_adapt_domain<bool>(
+ VArray<bool>::ForFunc(mesh->totpoly, planar_fn), ATTR_DOMAIN_FACE, domain);
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 2356235652;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const PlanarFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void geo_node_exec(GeoNodeExecParams params)
+{
+ Field<float> threshold = params.extract_input<Field<float>>("Threshold");
+ Field<bool> planar_field{std::make_shared<PlanarFieldInput>(threshold)};
+ params.set_output("Planar", std::move(planar_field));
+}
+
+} // namespace blender::nodes::node_geo_input_mesh_face_is_planar_cc
+
+void register_node_type_geo_input_mesh_face_is_planar()
+{
+ namespace file_ns = blender::nodes::node_geo_input_mesh_face_is_planar_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_INPUT_MESH_FACE_IS_PLANAR, "Face is Planar", NODE_CLASS_INPUT);
+ ntype.geometry_node_execute = file_ns::geo_node_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
index 4537721d173..f952e15fbbe 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
@@ -19,10 +19,10 @@ static void node_declare(NodeDeclarationBuilder &b)
static VArray<float> construct_spline_length_gvarray(const CurveComponent &component,
const AttributeDomain domain)
{
- const CurveEval *curve = component.get_for_read();
- if (curve == nullptr) {
+ if (!component.has_curves()) {
return {};
}
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_read());
Span<SplinePtr> splines = curve->splines();
auto length_fn = [splines](int i) { return splines[i]->length(); };
@@ -76,10 +76,10 @@ class SplineLengthFieldInput final : public GeometryFieldInput {
static VArray<int> construct_spline_count_gvarray(const CurveComponent &component,
const AttributeDomain domain)
{
- const CurveEval *curve = component.get_for_read();
- if (curve == nullptr) {
+ if (!component.has_curves()) {
return {};
}
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_read());
Span<SplinePtr> splines = curve->splines();
auto count_fn = [splines](int i) { return splines[i]->size(); };
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
index 9ae99b4d83e..435dd969c03 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
@@ -52,18 +52,22 @@ static Array<float3> curve_tangent_point_domain(const CurveEval &curve)
const Spline &spline = *splines[i];
MutableSpan spline_tangents{tangents.as_mutable_span().slice(offsets[i], spline.size())};
switch (splines[i]->type()) {
- case Spline::Type::Bezier: {
+ case CURVE_TYPE_BEZIER: {
calculate_bezier_tangents(static_cast<const BezierSpline &>(spline), spline_tangents);
break;
}
- case Spline::Type::Poly: {
+ case CURVE_TYPE_POLY: {
calculate_poly_tangents(static_cast<const PolySpline &>(spline), spline_tangents);
break;
}
- case Spline::Type::NURBS: {
+ case CURVE_TYPE_NURBS: {
calculate_nurbs_tangents(static_cast<const NURBSpline &>(spline), spline_tangents);
break;
}
+ case CURVE_TYPE_CATMULL_ROM: {
+ BLI_assert_unreachable();
+ break;
+ }
}
}
});
@@ -73,21 +77,12 @@ static Array<float3> curve_tangent_point_domain(const CurveEval &curve)
static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &component,
const AttributeDomain domain)
{
- const CurveEval *curve = component.get_for_read();
- if (curve == nullptr) {
- return nullptr;
+ if (!component.has_curves()) {
+ return {};
}
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_read());
if (domain == ATTR_DOMAIN_POINT) {
- const Span<SplinePtr> splines = curve->splines();
-
- /* Use a reference to evaluated tangents if possible to avoid an allocation and a copy.
- * This is only possible when there is only one poly spline. */
- if (splines.size() == 1 && splines.first()->type() == Spline::Type::Poly) {
- const PolySpline &spline = static_cast<PolySpline &>(*splines.first());
- return VArray<float3>::ForSpan(spline.evaluated_tangents());
- }
-
Array<float3> tangents = curve_tangent_point_domain(*curve);
return VArray<float3>::ForContainer(std::move(tangents));
}
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 df6d10991fb..61f719ade4e 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
@@ -195,35 +195,24 @@ static void node_geo_exec(GeoNodeExecParams params)
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+ const Array<GeometryComponentType> types{
+ GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE};
+
Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
geometry_set.gather_attributes_for_propagation(
- {GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE},
- GEO_COMPONENT_TYPE_INSTANCES,
- false,
- attributes_to_propagate);
+ types, GEO_COMPONENT_TYPE_INSTANCES, false, attributes_to_propagate);
attributes_to_propagate.remove("position");
- if (geometry_set.has<MeshComponent>()) {
- add_instances_from_component(instances,
- *geometry_set.get_component_for_read<MeshComponent>(),
- instance,
- params,
- attributes_to_propagate);
- }
- if (geometry_set.has<PointCloudComponent>()) {
- add_instances_from_component(instances,
- *geometry_set.get_component_for_read<PointCloudComponent>(),
- instance,
- params,
- attributes_to_propagate);
- }
- if (geometry_set.has<CurveComponent>()) {
- add_instances_from_component(instances,
- *geometry_set.get_component_for_read<CurveComponent>(),
- instance,
- params,
- attributes_to_propagate);
+ for (const GeometryComponentType type : types) {
+ if (geometry_set.has(type)) {
+ add_instances_from_component(instances,
+ *geometry_set.get_component_for_read(type),
+ instance,
+ params,
+ attributes_to_propagate);
+ }
}
+
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
});
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
index 3284378a2cb..91cde52f9eb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
@@ -35,7 +35,7 @@ static void node_geo_exec(GeoNodeExecParams params)
}
std::unique_ptr<CurveEval> curve = geometry::mesh_to_curve_convert(component, selection);
- geometry_set.replace_curve(curve.release());
+ geometry_set.replace_curve(curve_eval_to_curves(*curve));
geometry_set.keep_only({GEO_COMPONENT_TYPE_CURVE, GEO_COMPONENT_TYPE_INSTANCES});
});
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
index 1731ba64b97..c99b51ffd4c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
@@ -198,17 +198,12 @@ static void initialize_volume_component_from_points(GeoNodeExecParams &params,
Vector<float3> positions;
Vector<float> radii;
- if (r_geometry_set.has<MeshComponent>()) {
- gather_point_data_from_component(
- params, *r_geometry_set.get_component_for_read<MeshComponent>(), positions, radii);
- }
- if (r_geometry_set.has<PointCloudComponent>()) {
- gather_point_data_from_component(
- params, *r_geometry_set.get_component_for_read<PointCloudComponent>(), positions, radii);
- }
- if (r_geometry_set.has<CurveComponent>()) {
- gather_point_data_from_component(
- params, *r_geometry_set.get_component_for_read<CurveComponent>(), positions, radii);
+ for (const GeometryComponentType type :
+ {GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}) {
+ if (r_geometry_set.has(type)) {
+ gather_point_data_from_component(
+ params, *r_geometry_set.get_component_for_read(type), positions, radii);
+ }
}
const float max_radius = *std::max_element(radii.begin(), radii.end());
diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
index 1797364ad72..231ef547a8b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
@@ -141,10 +141,13 @@ static void raycast_to_mesh(IndexMask mask,
{
BVHTreeFromMesh tree_data;
BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_LOOPTRI, 4);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&tree_data); });
+
if (tree_data.tree == nullptr) {
- free_bvhtree_from_mesh(&tree_data);
return;
}
+ /* We shouldn't be rebuilding the BVH tree when calling this function in parallel. */
+ BLI_assert(tree_data.cached);
for (const int i : mask) {
const float ray_length = ray_lengths[i];
@@ -197,10 +200,6 @@ static void raycast_to_mesh(IndexMask mask,
}
}
}
-
- /* We shouldn't be rebuilding the BVH tree when calling this function in parallel. */
- BLI_assert(tree_data.cached);
- free_bvhtree_from_mesh(&tree_data);
}
class RaycastFunction : public fn::MultiFunction {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
index fb648baad08..301410f5126 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
@@ -35,7 +35,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
}
static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
- GeometryComponent &component,
+ CurveComponent &component,
const Field<bool> &selection_field,
const Field<float3> &position_field,
const Field<float3> &offset_field)
@@ -53,37 +53,31 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
- CurveComponent *curve_component = static_cast<CurveComponent *>(&component);
- CurveEval *curve = curve_component->get_for_write();
-
- StringRef side = mode & GEO_NODE_CURVE_HANDLE_LEFT ? "handle_left" : "handle_right";
+ std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_read());
int current_point = 0;
int current_mask = 0;
-
for (const SplinePtr &spline : curve->splines()) {
- if (spline->type() == Spline::Type::Bezier) {
+ if (spline->type() == CURVE_TYPE_BEZIER) {
BezierSpline &bezier = static_cast<BezierSpline &>(*spline);
- for (int i : bezier.positions().index_range()) {
+
+ bezier.ensure_auto_handles();
+ for (const int i : bezier.positions().index_range()) {
if (current_mask < selection.size() && selection[current_mask] == current_point) {
if (mode & GEO_NODE_CURVE_HANDLE_LEFT) {
- if (bezier.handle_types_left()[i] == BezierSpline::HandleType::Vector) {
- bezier.ensure_auto_handles();
- bezier.handle_types_left()[i] = BezierSpline::HandleType::Free;
+ if (bezier.handle_types_left()[i] == BEZIER_HANDLE_VECTOR) {
+ bezier.handle_types_left()[i] = BEZIER_HANDLE_FREE;
}
- else if (bezier.handle_types_left()[i] == BezierSpline::HandleType::Auto) {
- bezier.ensure_auto_handles();
- bezier.handle_types_left()[i] = BezierSpline::HandleType::Align;
+ else if (bezier.handle_types_left()[i] == BEZIER_HANDLE_AUTO) {
+ bezier.handle_types_left()[i] = BEZIER_HANDLE_ALIGN;
}
}
else {
- if (bezier.handle_types_right()[i] == BezierSpline::HandleType::Vector) {
- bezier.ensure_auto_handles();
- bezier.handle_types_right()[i] = BezierSpline::HandleType::Free;
+ if (bezier.handle_types_right()[i] == BEZIER_HANDLE_VECTOR) {
+ bezier.handle_types_right()[i] = BEZIER_HANDLE_FREE;
}
- else if (bezier.handle_types_right()[i] == BezierSpline::HandleType::Auto) {
- bezier.ensure_auto_handles();
- bezier.handle_types_right()[i] = BezierSpline::HandleType::Align;
+ else if (bezier.handle_types_right()[i] == BEZIER_HANDLE_AUTO) {
+ bezier.handle_types_right()[i] = BEZIER_HANDLE_ALIGN;
}
}
current_mask++;
@@ -104,15 +98,35 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
const VArray<float3> &positions_input = evaluator.get_evaluated<float3>(0);
const VArray<float3> &offsets_input = evaluator.get_evaluated<float3>(1);
- OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>(
- side, ATTR_DOMAIN_POINT, {0, 0, 0});
- MutableSpan<float3> position_mutable = positions.as_span();
-
- for (int i : selection) {
- position_mutable[i] = positions_input[i] + offsets_input[i];
+ current_point = 0;
+ current_mask = 0;
+ for (const SplinePtr &spline : curve->splines()) {
+ if (spline->type() == CURVE_TYPE_BEZIER) {
+ BezierSpline &bezier = static_cast<BezierSpline &>(*spline);
+ for (const int i : bezier.positions().index_range()) {
+ if (current_mask < selection.size() && selection[current_mask] == current_point) {
+ if (mode & GEO_NODE_CURVE_HANDLE_LEFT) {
+ bezier.set_handle_position_left(i, positions_input[i] + offsets_input[i]);
+ }
+ else {
+ bezier.set_handle_position_right(i, positions_input[i] + offsets_input[i]);
+ }
+ current_mask++;
+ }
+ current_point++;
+ }
+ }
+ else {
+ for ([[maybe_unused]] int i : spline->positions().index_range()) {
+ if (current_mask < selection.size() && selection[current_mask] == current_point) {
+ current_mask++;
+ }
+ current_point++;
+ }
+ }
}
- positions.save();
+ component.replace(curve_eval_to_curves(*curve), GeometryOwnershipType::Owned);
}
static void node_geo_exec(GeoNodeExecParams params)
@@ -127,9 +141,11 @@ static void node_geo_exec(GeoNodeExecParams params)
bool has_bezier = false;
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (geometry_set.has_curve() &&
- geometry_set.get_curve_for_read()->has_spline_with_type(Spline::Type::Bezier)) {
- has_bezier = true;
+ if (geometry_set.has_curves()) {
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *geometry_set.get_curves_for_read());
+ has_bezier = curve->has_spline_with_type(CURVE_TYPE_BEZIER);
+
set_position_in_component(mode,
geometry_set.get_component_for_write<CurveComponent>(),
selection_field,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
index 2f59d008df0..a23a6c09551 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
@@ -44,7 +44,7 @@ static void node_geo_exec(GeoNodeExecParams params)
Field<float> radii_field = params.extract_input<Field<float>>("Radius");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (geometry_set.has_curve()) {
+ if (geometry_set.has_curves()) {
set_radius_in_component(
geometry_set.get_component_for_write<CurveComponent>(), selection_field, radii_field);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
index b94782b8c4c..1155c97dc38 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
@@ -40,7 +40,7 @@ static void node_geo_exec(GeoNodeExecParams params)
Field<float> tilt_field = params.extract_input<Field<float>>("Tilt");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (geometry_set.has_curve()) {
+ if (geometry_set.has_curves()) {
set_tilt_in_component(
geometry_set.get_component_for_write<CurveComponent>(), selection_field, tilt_field);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
index 361a75ee0a8..eb035aa9b6b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
@@ -61,6 +61,41 @@ static void set_computed_position_and_offset(GeometryComponent &component,
}
break;
}
+ case GEO_COMPONENT_TYPE_CURVE: {
+ if (component.attribute_exists("handle_right") &&
+ component.attribute_exists("handle_left")) {
+ OutputAttribute_Typed<float3> handle_right_attribute =
+ component.attribute_try_get_for_output<float3>(
+ "handle_right", ATTR_DOMAIN_POINT, {0, 0, 0});
+ OutputAttribute_Typed<float3> handle_left_attribute =
+ component.attribute_try_get_for_output<float3>(
+ "handle_left", ATTR_DOMAIN_POINT, {0, 0, 0});
+ MutableSpan<float3> handle_right = handle_right_attribute.as_span();
+ MutableSpan<float3> handle_left = handle_left_attribute.as_span();
+
+ MutableSpan<float3> out_positions_span = positions.as_span();
+ devirtualize_varray2(
+ in_positions, in_offsets, [&](const auto in_positions, const auto in_offsets) {
+ threading::parallel_for(
+ selection.index_range(), grain_size, [&](const IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const float3 new_position = in_positions[i] + in_offsets[i];
+ const float3 delta = new_position - out_positions_span[i];
+ handle_right[i] += delta;
+ handle_left[i] += delta;
+ out_positions_span[i] = new_position;
+ }
+ });
+ });
+
+ handle_right_attribute.save();
+ handle_left_attribute.save();
+ break;
+ }
+ else {
+ ATTR_FALLTHROUGH;
+ }
+ }
default: {
MutableSpan<float3> out_positions_span = positions.as_span();
if (in_positions.is_same(positions.varray())) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
index 70e363064cd..dc7f3b1343a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
@@ -40,7 +40,7 @@ static void node_geo_exec(GeoNodeExecParams params)
Field<bool> cyclic_field = params.extract_input<Field<bool>>("Cyclic");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (geometry_set.has_curve()) {
+ if (geometry_set.has_curves()) {
set_cyclic_in_component(
geometry_set.get_component_for_write<CurveComponent>(), selection_field, cyclic_field);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
index e4702035eec..da8d7bcf255 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
@@ -43,10 +43,12 @@ static void node_geo_exec(GeoNodeExecParams params)
bool only_poly = true;
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (geometry_set.has_curve()) {
+ if (geometry_set.has_curves()) {
if (only_poly) {
- for (const SplinePtr &spline : geometry_set.get_curve_for_read()->splines()) {
- if (ELEM(spline->type(), Spline::Type::Bezier, Spline::Type::NURBS)) {
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *geometry_set.get_curves_for_read());
+ for (const SplinePtr &spline : curve->splines()) {
+ if (ELEM(spline->type(), CURVE_TYPE_BEZIER, CURVE_TYPE_NURBS)) {
only_poly = false;
break;
}
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 ddc0bb2bc11..bc34a1a6f2c 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
@@ -298,7 +298,8 @@ static Map<int, int> create_curve_instances(GeoNodeExecParams &params,
layout.pivot_points.add_new(layout.char_codes[i], pivot_point);
}
- GeometrySet geometry_set_curve = GeometrySet::create_with_curve(curve_eval.release());
+ GeometrySet geometry_set_curve = GeometrySet::create_with_curves(
+ curve_eval_to_curves(*curve_eval));
handles.add_new(layout.char_codes[i],
instance_component.add_reference(std::move(geometry_set_curve)));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
index 789478873f6..2d5b0e58367 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
@@ -778,7 +778,7 @@ static void node_geo_exec(GeoNodeExecParams params)
break;
}
case GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST: {
- if (geometry.has_curve() && !geometry.has_mesh() && !geometry.has_pointcloud()) {
+ if (geometry.has_curves() && !geometry.has_mesh() && !geometry.has_pointcloud()) {
params.error_message_add(NodeWarningType::Error,
TIP_("The source geometry must contain a mesh or a point cloud"));
return return_default();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
index 5950a2a16d2..95cec8eab11 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
@@ -10,6 +10,7 @@
#include "DNA_pointcloud_types.h"
#include "DNA_volume_types.h"
+#include "BKE_curves.hh"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
#include "BKE_spline.hh"
@@ -125,8 +126,10 @@ static void translate_geometry_set(GeometrySet &geometry,
const float3 translation,
const Depsgraph &depsgraph)
{
- if (CurveEval *curve = geometry.get_curve_for_write()) {
+ if (Curves *curves = geometry.get_curves_for_write()) {
+ std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curves);
curve->translate(translation);
+ geometry.replace_curve(curve_eval_to_curves(*curve));
}
if (Mesh *mesh = geometry.get_mesh_for_write()) {
translate_mesh(*mesh, translation);
@@ -146,8 +149,10 @@ void transform_geometry_set(GeometrySet &geometry,
const float4x4 &transform,
const Depsgraph &depsgraph)
{
- if (CurveEval *curve = geometry.get_curve_for_write()) {
+ if (Curves *curves = geometry.get_curves_for_write()) {
+ std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curves);
curve->transform(transform);
+ geometry.replace_curve(curve_eval_to_curves(*curve));
}
if (Mesh *mesh = geometry.get_mesh_for_write()) {
transform_mesh(*mesh, transform);