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/blenkernel/intern/curve_to_mesh_convert.cc')
-rw-r--r--source/blender/blenkernel/intern/curve_to_mesh_convert.cc1092
1 files changed, 574 insertions, 518 deletions
diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
index 9b22a4c9726..c48d155f5ce 100644
--- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
+++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
@@ -9,65 +9,15 @@
#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
+#include "BKE_curves.hh"
#include "BKE_geometry_set.hh"
#include "BKE_material.h"
#include "BKE_mesh.h"
-#include "BKE_spline.hh"
#include "BKE_curve_to_mesh.hh"
namespace blender::bke {
-/** Information about the creation of one curve spline and profile spline combination. */
-struct ResultInfo {
- const Spline &spline;
- const Spline &profile;
- int vert_offset;
- int edge_offset;
- int loop_offset;
- int poly_offset;
- int spline_vert_len;
- int spline_edge_len;
- int profile_vert_len;
- int profile_edge_len;
-};
-
-static void vert_extrude_to_mesh_data(const Spline &spline,
- const float3 profile_vert,
- MutableSpan<MVert> r_verts,
- MutableSpan<MEdge> r_edges,
- const int vert_offset,
- const int edge_offset)
-{
- const int eval_size = spline.evaluated_points_size();
- for (const int i : IndexRange(eval_size - 1)) {
- MEdge &edge = r_edges[edge_offset + i];
- edge.v1 = vert_offset + i;
- edge.v2 = vert_offset + i + 1;
- edge.flag = ME_LOOSEEDGE;
- }
-
- if (spline.is_cyclic() && spline.evaluated_edges_size() > 1) {
- MEdge &edge = r_edges[edge_offset + spline.evaluated_edges_size() - 1];
- edge.v1 = vert_offset + eval_size - 1;
- edge.v2 = vert_offset;
- edge.flag = ME_LOOSEEDGE;
- }
-
- Span<float3> positions = spline.evaluated_positions();
- Span<float3> tangents = spline.evaluated_tangents();
- Span<float3> normals = spline.evaluated_normals();
- VArray<float> radii = spline.interpolate_to_evaluated(spline.radii());
- for (const int i : IndexRange(eval_size)) {
- float4x4 point_matrix = float4x4::from_normalized_axis_data(
- positions[i], normals[i], tangents[i]);
- point_matrix.apply_scale(radii[i]);
-
- MVert &vert = r_verts[vert_offset + i];
- copy_v3_v3(vert.co, point_matrix * profile_vert);
- }
-}
-
static void mark_edges_sharp(MutableSpan<MEdge> edges)
{
for (MEdge &edge : edges) {
@@ -75,36 +25,50 @@ static void mark_edges_sharp(MutableSpan<MEdge> edges)
}
}
-static void spline_extrude_to_mesh_data(const ResultInfo &info,
- const bool fill_caps,
- MutableSpan<MVert> r_verts,
- MutableSpan<MEdge> r_edges,
- MutableSpan<MLoop> r_loops,
- MutableSpan<MPoly> r_polys)
+static void fill_mesh_topology(const int vert_offset,
+ const int edge_offset,
+ const int poly_offset,
+ const int loop_offset,
+ const int main_point_num,
+ const int profile_point_num,
+ const bool main_cyclic,
+ const bool profile_cyclic,
+ const bool fill_caps,
+ MutableSpan<MEdge> edges,
+ MutableSpan<MLoop> loops,
+ MutableSpan<MPoly> polys)
{
- const Spline &spline = info.spline;
- const Spline &profile = info.profile;
- if (info.profile_vert_len == 1) {
- vert_extrude_to_mesh_data(spline,
- profile.evaluated_positions()[0],
- r_verts,
- r_edges,
- info.vert_offset,
- info.edge_offset);
+ const int main_segment_num = curves::curve_segment_size(main_point_num, main_cyclic);
+ const int profile_segment_num = curves::curve_segment_size(profile_point_num, profile_cyclic);
+
+ if (profile_point_num == 1) {
+ for (const int i : IndexRange(main_point_num - 1)) {
+ MEdge &edge = edges[edge_offset + i];
+ edge.v1 = vert_offset + i;
+ edge.v2 = vert_offset + i + 1;
+ edge.flag = ME_LOOSEEDGE;
+ }
+
+ if (main_cyclic && main_segment_num > 1) {
+ MEdge &edge = edges[edge_offset + main_segment_num - 1];
+ edge.v1 = vert_offset + main_point_num - 1;
+ edge.v2 = vert_offset;
+ edge.flag = ME_LOOSEEDGE;
+ }
return;
}
/* Add the edges running along the length of the curve, starting at each profile vertex. */
- const int spline_edges_start = info.edge_offset;
- for (const int i_profile : IndexRange(info.profile_vert_len)) {
- const int profile_edge_offset = spline_edges_start + i_profile * info.spline_edge_len;
- for (const int i_ring : IndexRange(info.spline_edge_len)) {
- const int i_next_ring = (i_ring == info.spline_vert_len - 1) ? 0 : i_ring + 1;
+ const int main_edges_start = edge_offset;
+ for (const int i_profile : IndexRange(profile_point_num)) {
+ const int profile_edge_offset = main_edges_start + i_profile * main_segment_num;
+ for (const int i_ring : IndexRange(main_segment_num)) {
+ const int i_next_ring = (i_ring == main_point_num - 1) ? 0 : i_ring + 1;
- const int ring_vert_offset = info.vert_offset + info.profile_vert_len * i_ring;
- const int next_ring_vert_offset = info.vert_offset + info.profile_vert_len * i_next_ring;
+ const int ring_vert_offset = vert_offset + profile_point_num * i_ring;
+ const int next_ring_vert_offset = vert_offset + profile_point_num * i_next_ring;
- MEdge &edge = r_edges[profile_edge_offset + i_ring];
+ MEdge &edge = edges[profile_edge_offset + i_ring];
edge.v1 = ring_vert_offset + i_profile;
edge.v2 = next_ring_vert_offset + i_profile;
edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
@@ -112,16 +76,15 @@ static void spline_extrude_to_mesh_data(const ResultInfo &info,
}
/* Add the edges running along each profile ring. */
- const int profile_edges_start = spline_edges_start +
- info.profile_vert_len * info.spline_edge_len;
- for (const int i_ring : IndexRange(info.spline_vert_len)) {
- const int ring_vert_offset = info.vert_offset + info.profile_vert_len * i_ring;
+ const int profile_edges_start = main_edges_start + profile_point_num * main_segment_num;
+ for (const int i_ring : IndexRange(main_point_num)) {
+ const int ring_vert_offset = vert_offset + profile_point_num * i_ring;
- const int ring_edge_offset = profile_edges_start + i_ring * info.profile_edge_len;
- for (const int i_profile : IndexRange(info.profile_edge_len)) {
- const int i_next_profile = (i_profile == info.profile_vert_len - 1) ? 0 : i_profile + 1;
+ const int ring_edge_offset = profile_edges_start + i_ring * profile_segment_num;
+ for (const int i_profile : IndexRange(profile_segment_num)) {
+ const int i_next_profile = (i_profile == profile_point_num - 1) ? 0 : i_profile + 1;
- MEdge &edge = r_edges[ring_edge_offset + i_profile];
+ MEdge &edge = edges[ring_edge_offset + i_profile];
edge.v1 = ring_vert_offset + i_profile;
edge.v2 = ring_vert_offset + i_next_profile;
edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
@@ -129,368 +92,410 @@ static void spline_extrude_to_mesh_data(const ResultInfo &info,
}
/* Calculate poly and corner indices. */
- for (const int i_ring : IndexRange(info.spline_edge_len)) {
- const int i_next_ring = (i_ring == info.spline_vert_len - 1) ? 0 : i_ring + 1;
+ for (const int i_ring : IndexRange(main_segment_num)) {
+ const int i_next_ring = (i_ring == main_point_num - 1) ? 0 : i_ring + 1;
- const int ring_vert_offset = info.vert_offset + info.profile_vert_len * i_ring;
- const int next_ring_vert_offset = info.vert_offset + info.profile_vert_len * i_next_ring;
+ const int ring_vert_offset = vert_offset + profile_point_num * i_ring;
+ const int next_ring_vert_offset = vert_offset + profile_point_num * i_next_ring;
- const int ring_edge_start = profile_edges_start + info.profile_edge_len * i_ring;
- const int next_ring_edge_offset = profile_edges_start + info.profile_edge_len * i_next_ring;
+ const int ring_edge_start = profile_edges_start + profile_segment_num * i_ring;
+ const int next_ring_edge_offset = profile_edges_start + profile_segment_num * i_next_ring;
- const int ring_poly_offset = info.poly_offset + i_ring * info.profile_edge_len;
- const int ring_loop_offset = info.loop_offset + i_ring * info.profile_edge_len * 4;
+ const int ring_poly_offset = poly_offset + i_ring * profile_segment_num;
+ const int ring_loop_offset = loop_offset + i_ring * profile_segment_num * 4;
- for (const int i_profile : IndexRange(info.profile_edge_len)) {
+ for (const int i_profile : IndexRange(profile_segment_num)) {
const int ring_segment_loop_offset = ring_loop_offset + i_profile * 4;
- const int i_next_profile = (i_profile == info.profile_vert_len - 1) ? 0 : i_profile + 1;
+ const int i_next_profile = (i_profile == profile_point_num - 1) ? 0 : i_profile + 1;
- const int spline_edge_start = spline_edges_start + info.spline_edge_len * i_profile;
- const int next_spline_edge_start = spline_edges_start +
- info.spline_edge_len * i_next_profile;
+ const int main_edge_start = main_edges_start + main_segment_num * i_profile;
+ const int next_main_edge_start = main_edges_start + main_segment_num * i_next_profile;
- MPoly &poly = r_polys[ring_poly_offset + i_profile];
+ MPoly &poly = polys[ring_poly_offset + i_profile];
poly.loopstart = ring_segment_loop_offset;
poly.totloop = 4;
poly.flag = ME_SMOOTH;
- MLoop &loop_a = r_loops[ring_segment_loop_offset];
+ MLoop &loop_a = loops[ring_segment_loop_offset];
loop_a.v = ring_vert_offset + i_profile;
loop_a.e = ring_edge_start + i_profile;
- MLoop &loop_b = r_loops[ring_segment_loop_offset + 1];
+ MLoop &loop_b = loops[ring_segment_loop_offset + 1];
loop_b.v = ring_vert_offset + i_next_profile;
- loop_b.e = next_spline_edge_start + i_ring;
- MLoop &loop_c = r_loops[ring_segment_loop_offset + 2];
+ loop_b.e = next_main_edge_start + i_ring;
+ MLoop &loop_c = loops[ring_segment_loop_offset + 2];
loop_c.v = next_ring_vert_offset + i_next_profile;
loop_c.e = next_ring_edge_offset + i_profile;
- MLoop &loop_d = r_loops[ring_segment_loop_offset + 3];
+ MLoop &loop_d = loops[ring_segment_loop_offset + 3];
loop_d.v = next_ring_vert_offset + i_profile;
- loop_d.e = spline_edge_start + i_ring;
+ loop_d.e = main_edge_start + i_ring;
}
}
- const bool has_caps = fill_caps && profile.is_cyclic() && !spline.is_cyclic();
+ const bool has_caps = fill_caps && !main_cyclic && profile_cyclic;
if (has_caps) {
- const int poly_size = info.spline_edge_len * info.profile_edge_len;
- const int cap_loop_offset = info.loop_offset + poly_size * 4;
- const int cap_poly_offset = info.poly_offset + poly_size;
+ const int poly_size = main_segment_num * profile_segment_num;
+ const int cap_loop_offset = loop_offset + poly_size * 4;
+ const int cap_poly_offset = poly_offset + poly_size;
- MPoly &poly_start = r_polys[cap_poly_offset];
+ MPoly &poly_start = polys[cap_poly_offset];
poly_start.loopstart = cap_loop_offset;
- poly_start.totloop = info.profile_edge_len;
- MPoly &poly_end = r_polys[cap_poly_offset + 1];
- poly_end.loopstart = cap_loop_offset + info.profile_edge_len;
- poly_end.totloop = info.profile_edge_len;
-
- const int last_ring_index = info.spline_vert_len - 1;
- const int last_ring_vert_offset = info.vert_offset + info.profile_vert_len * last_ring_index;
- const int last_ring_edge_offset = profile_edges_start +
- info.profile_edge_len * last_ring_index;
-
- for (const int i : IndexRange(info.profile_edge_len)) {
- const int i_inv = info.profile_edge_len - i - 1;
- MLoop &loop_start = r_loops[cap_loop_offset + i];
- loop_start.v = info.vert_offset + i_inv;
- loop_start.e = profile_edges_start + ((i == (info.profile_edge_len - 1)) ?
- (info.profile_edge_len - 1) :
- (i_inv - 1));
- MLoop &loop_end = r_loops[cap_loop_offset + info.profile_edge_len + i];
+ poly_start.totloop = profile_segment_num;
+ MPoly &poly_end = polys[cap_poly_offset + 1];
+ poly_end.loopstart = cap_loop_offset + profile_segment_num;
+ poly_end.totloop = profile_segment_num;
+
+ const int last_ring_index = main_point_num - 1;
+ const int last_ring_vert_offset = vert_offset + profile_point_num * last_ring_index;
+ const int last_ring_edge_offset = profile_edges_start + profile_segment_num * last_ring_index;
+
+ for (const int i : IndexRange(profile_segment_num)) {
+ const int i_inv = profile_segment_num - i - 1;
+ MLoop &loop_start = loops[cap_loop_offset + i];
+ loop_start.v = vert_offset + i_inv;
+ loop_start.e = profile_edges_start +
+ ((i == (profile_segment_num - 1)) ? (profile_segment_num - 1) : (i_inv - 1));
+ MLoop &loop_end = loops[cap_loop_offset + profile_segment_num + i];
loop_end.v = last_ring_vert_offset + i;
loop_end.e = last_ring_edge_offset + i;
}
- mark_edges_sharp(r_edges.slice(profile_edges_start, info.profile_edge_len));
- mark_edges_sharp(r_edges.slice(last_ring_edge_offset, info.profile_edge_len));
+ mark_edges_sharp(edges.slice(profile_edges_start, profile_segment_num));
+ mark_edges_sharp(edges.slice(last_ring_edge_offset, profile_segment_num));
}
+}
- /* Calculate the positions of each profile ring profile along the spline. */
- Span<float3> positions = spline.evaluated_positions();
- Span<float3> tangents = spline.evaluated_tangents();
- Span<float3> normals = spline.evaluated_normals();
- Span<float3> profile_positions = profile.evaluated_positions();
-
- VArray<float> radii = spline.interpolate_to_evaluated(spline.radii());
- for (const int i_ring : IndexRange(info.spline_vert_len)) {
- float4x4 point_matrix = float4x4::from_normalized_axis_data(
- positions[i_ring], normals[i_ring], tangents[i_ring]);
- point_matrix.apply_scale(radii[i_ring]);
-
- const int ring_vert_start = info.vert_offset + i_ring * info.profile_vert_len;
- for (const int i_profile : IndexRange(info.profile_vert_len)) {
- MVert &vert = r_verts[ring_vert_start + i_profile];
- copy_v3_v3(vert.co, point_matrix * profile_positions[i_profile]);
- }
+static void mark_bezier_vector_edges_sharp(const int profile_point_num,
+ const int main_segment_num,
+ const Span<int> control_point_offsets,
+ const Span<int8_t> handle_types_left,
+ const Span<int8_t> handle_types_right,
+ MutableSpan<MEdge> edges)
+{
+ const int main_edges_start = 0;
+ if (curves::bezier::point_is_sharp(handle_types_left, handle_types_right, 0)) {
+ mark_edges_sharp(edges.slice(main_edges_start, main_segment_num));
}
- /* Mark edge loops from sharp vector control points sharp. */
- if (profile.type() == CURVE_TYPE_BEZIER) {
- const BezierSpline &bezier_spline = static_cast<const BezierSpline &>(profile);
- Span<int> control_point_offsets = bezier_spline.control_point_offsets();
- for (const int i : IndexRange(bezier_spline.size())) {
- if (bezier_spline.point_is_sharp(i)) {
- mark_edges_sharp(
- r_edges.slice(spline_edges_start + info.spline_edge_len * control_point_offsets[i],
- info.spline_edge_len));
- }
+ for (const int i : IndexRange(profile_point_num).drop_front(1)) {
+ if (curves::bezier::point_is_sharp(handle_types_left, handle_types_right, i)) {
+ mark_edges_sharp(edges.slice(
+ main_edges_start + main_segment_num * control_point_offsets[i - 1], main_segment_num));
}
}
}
-static inline int spline_extrude_vert_size(const Spline &curve, const Spline &profile)
+static void fill_mesh_positions(const int main_point_num,
+ const int profile_point_num,
+ const Span<float3> main_positions,
+ const Span<float3> profile_positions,
+ const Span<float3> tangents,
+ const Span<float3> normals,
+ const Span<float> radii,
+ MutableSpan<MVert> mesh_positions)
{
- return curve.evaluated_points_size() * profile.evaluated_points_size();
-}
+ if (profile_point_num == 1) {
+ for (const int i_ring : IndexRange(main_point_num)) {
+ float4x4 point_matrix = float4x4::from_normalized_axis_data(
+ main_positions[i_ring], normals[i_ring], tangents[i_ring]);
+ if (!radii.is_empty()) {
+ point_matrix.apply_scale(radii[i_ring]);
+ }
-static inline int spline_extrude_edge_size(const Spline &curve, const Spline &profile)
-{
- /* Add the ring edges, with one ring for every curve vertex, and the edge loops
- * that run along the length of the curve, starting on the first profile. */
- return curve.evaluated_points_size() * profile.evaluated_edges_size() +
- curve.evaluated_edges_size() * profile.evaluated_points_size();
-}
+ MVert &vert = mesh_positions[i_ring];
+ copy_v3_v3(vert.co, point_matrix * profile_positions.first());
+ }
+ }
+ else {
+ for (const int i_ring : IndexRange(main_point_num)) {
+ float4x4 point_matrix = float4x4::from_normalized_axis_data(
+ main_positions[i_ring], normals[i_ring], tangents[i_ring]);
+ if (!radii.is_empty()) {
+ point_matrix.apply_scale(radii[i_ring]);
+ }
-static inline int spline_extrude_loop_size(const Spline &curve,
- const Spline &profile,
- const bool fill_caps)
-{
- const int tube = curve.evaluated_edges_size() * profile.evaluated_edges_size() * 4;
- const bool has_caps = fill_caps && profile.is_cyclic() && !curve.is_cyclic();
- const int caps = has_caps ? profile.evaluated_edges_size() * 2 : 0;
- return tube + caps;
+ const int ring_vert_start = i_ring * profile_point_num;
+ for (const int i_profile : IndexRange(profile_point_num)) {
+ MVert &vert = mesh_positions[ring_vert_start + i_profile];
+ copy_v3_v3(vert.co, point_matrix * profile_positions[i_profile]);
+ }
+ }
+ }
}
-static inline int spline_extrude_poly_size(const Spline &curve,
- const Spline &profile,
- const bool fill_caps)
+struct CurvesInfo {
+ const CurvesGeometry &main;
+ const CurvesGeometry &profile;
+
+ /* Make sure these are spans because they are potentially accessed many times. */
+ VArray_Span<bool> main_cyclic;
+ VArray_Span<bool> profile_cyclic;
+
+ /* TODO: Remove once these are cached on #CurvesGeometry. */
+ std::array<int, CURVE_TYPES_NUM> main_type_counts;
+ std::array<int, CURVE_TYPES_NUM> profile_type_counts;
+};
+static CurvesInfo get_curves_info(const CurvesGeometry &main, const CurvesGeometry &profile)
{
- const int tube = curve.evaluated_edges_size() * profile.evaluated_edges_size();
- const bool has_caps = fill_caps && profile.is_cyclic() && !curve.is_cyclic();
- const int caps = has_caps ? 2 : 0;
- return tube + caps;
+ return {main,
+ profile,
+ main.cyclic(),
+ profile.cyclic(),
+ main.count_curve_types(),
+ profile.count_curve_types()};
}
struct ResultOffsets {
+ /** The total number of curve combinations. */
+ int total;
+
+ /** Offsets into the result mesh for each combination. */
Array<int> vert;
Array<int> edge;
Array<int> loop;
Array<int> poly;
+
+ /* The indices of the main and profile curves that form each combination. */
+ Array<int> main_indices;
+ Array<int> profile_indices;
};
-static ResultOffsets calculate_result_offsets(Span<SplinePtr> profiles,
- Span<SplinePtr> curves,
- const bool fill_caps)
+static ResultOffsets calculate_result_offsets(const CurvesInfo &info, const bool fill_caps)
{
- const int total = profiles.size() * curves.size();
- Array<int> vert(total + 1);
- Array<int> edge(total + 1);
- Array<int> loop(total + 1);
- Array<int> poly(total + 1);
+ ResultOffsets result;
+ result.total = info.main.curves_num() * info.profile.curves_num();
+ result.vert.reinitialize(result.total + 1);
+ result.edge.reinitialize(result.total + 1);
+ result.loop.reinitialize(result.total + 1);
+ result.poly.reinitialize(result.total + 1);
+
+ result.main_indices.reinitialize(result.total);
+ result.profile_indices.reinitialize(result.total);
+
+ info.main.ensure_evaluated_offsets();
+ info.profile.ensure_evaluated_offsets();
int mesh_index = 0;
int vert_offset = 0;
int edge_offset = 0;
int loop_offset = 0;
int poly_offset = 0;
- for (const int i_spline : curves.index_range()) {
- for (const int i_profile : profiles.index_range()) {
- vert[mesh_index] = vert_offset;
- edge[mesh_index] = edge_offset;
- loop[mesh_index] = loop_offset;
- poly[mesh_index] = poly_offset;
- vert_offset += spline_extrude_vert_size(*curves[i_spline], *profiles[i_profile]);
- edge_offset += spline_extrude_edge_size(*curves[i_spline], *profiles[i_profile]);
- loop_offset += spline_extrude_loop_size(*curves[i_spline], *profiles[i_profile], fill_caps);
- poly_offset += spline_extrude_poly_size(*curves[i_spline], *profiles[i_profile], fill_caps);
+ for (const int i_main : info.main.curves_range()) {
+ const bool main_cyclic = info.main_cyclic[i_main];
+ const int main_point_num = info.main.evaluated_points_for_curve(i_main).size();
+ const int main_segment_num = curves::curve_segment_size(main_point_num, main_cyclic);
+ for (const int i_profile : info.profile.curves_range()) {
+ result.vert[mesh_index] = vert_offset;
+ result.edge[mesh_index] = edge_offset;
+ result.loop[mesh_index] = loop_offset;
+ result.poly[mesh_index] = poly_offset;
+
+ result.main_indices[mesh_index] = i_main;
+ result.profile_indices[mesh_index] = i_profile;
+
+ const bool profile_cyclic = info.profile_cyclic[i_profile];
+ const int profile_point_num = info.profile.evaluated_points_for_curve(i_profile).size();
+ const int profile_segment_num = curves::curve_segment_size(profile_point_num,
+ profile_cyclic);
+
+ const bool has_caps = fill_caps && !main_cyclic && profile_cyclic;
+ const int tube_face_num = main_segment_num * profile_segment_num;
+
+ vert_offset += main_point_num * profile_point_num;
+
+ /* Add the ring edges, with one ring for every curve vertex, and the edge loops
+ * that run along the length of the curve, starting on the first profile. */
+ edge_offset += main_point_num * profile_segment_num + main_segment_num * profile_point_num;
+
+ /* Add two cap N-gons for every ending. */
+ poly_offset += tube_face_num + (has_caps ? 2 : 0);
+
+ /* All faces on the tube are quads, and all cap faces are N-gons with an edge for each
+ * profile edge. */
+ loop_offset += tube_face_num * 4 + (has_caps ? profile_segment_num * 2 : 0);
+
mesh_index++;
}
}
- vert.last() = vert_offset;
- edge.last() = edge_offset;
- loop.last() = loop_offset;
- poly.last() = poly_offset;
- return {std::move(vert), std::move(edge), std::move(loop), std::move(poly)};
+ result.vert.last() = vert_offset;
+ result.edge.last() = edge_offset;
+ result.loop.last() = loop_offset;
+ result.poly.last() = poly_offset;
+
+ return result;
}
-static AttributeDomain get_result_attribute_domain(const MeshComponent &component,
- const AttributeIDRef &attribute_id)
+static AttributeDomain get_attribute_domain_for_mesh(const MeshComponent &mesh,
+ const AttributeIDRef &attribute_id)
{
/* Only use a different domain if it is builtin and must only exist on one domain. */
- if (!component.attribute_is_builtin(attribute_id)) {
+ if (!mesh.attribute_is_builtin(attribute_id)) {
return ATTR_DOMAIN_POINT;
}
- std::optional<AttributeMetaData> meta_data = component.attribute_get_meta_data(attribute_id);
+ std::optional<AttributeMetaData> meta_data = mesh.attribute_get_meta_data(attribute_id);
if (!meta_data) {
- /* This function has to return something in this case, but it shouldn't be used,
- * so return an output that will assert later if the code attempts to handle it. */
- return ATTR_DOMAIN_AUTO;
+ return ATTR_DOMAIN_POINT;
}
return meta_data->domain;
}
-/**
- * The data stored in the attribute and its domain from #OutputAttribute, to avoid calling
- * `as_span()` for every single profile and curve spline combination, and for readability.
- */
-struct ResultAttributeData {
- GMutableSpan data;
- AttributeDomain domain;
-};
-
-static std::optional<ResultAttributeData> create_attribute_and_get_span(
- MeshComponent &component,
- const AttributeIDRef &attribute_id,
- AttributeMetaData meta_data,
- Vector<OutputAttribute> &r_attributes)
+static bool should_add_attribute_to_mesh(const CurveComponent &curve_component,
+ const MeshComponent &mesh_component,
+ const AttributeIDRef &id)
{
- const AttributeDomain domain = get_result_attribute_domain(component, attribute_id);
- OutputAttribute attribute = component.attribute_try_get_for_output_only(
- attribute_id, domain, meta_data.data_type);
- if (!attribute) {
- return std::nullopt;
+ /* The position attribute has special non-generic evaluation. */
+ if (id.is_named() && id.name() == "position") {
+ return false;
+ }
+ /* Don't propagate built-in curves attributes that are not built-in on meshes. */
+ if (curve_component.attribute_is_builtin(id) && !mesh_component.attribute_is_builtin(id)) {
+ return false;
}
+ if (!id.should_be_kept()) {
+ return false;
+ }
+ return true;
+}
- GMutableSpan span = attribute.as_span();
- r_attributes.append(std::move(attribute));
- return std::make_optional<ResultAttributeData>({span, domain});
+static GSpan evaluated_attribute_if_necessary(const GVArray &src,
+ const CurvesGeometry &curves,
+ const Span<int> type_counts,
+ Vector<std::byte> &buffer)
+{
+ if (type_counts[CURVE_TYPE_POLY] == curves.curves_num() && src.is_span()) {
+ return src.get_internal_span();
+ }
+ buffer.reinitialize(curves.evaluated_points_num() * src.type().size());
+ GMutableSpan eval{src.type(), buffer.data(), curves.evaluated_points_num()};
+ curves.interpolate_to_evaluated(src.get_internal_span(), eval);
+ return eval;
}
-/**
- * Store the references to the attribute data from the curve and profile inputs. Here we rely on
- * the invariants of the storage of curve attributes, that the order will be consistent between
- * splines, and all splines will have the same attributes.
- */
-struct ResultAttributes {
- /**
- * Result attributes on the mesh corresponding to each attribute on the curve input, in the same
- * order. The data is optional only in case the attribute does not exist on the mesh for some
- * reason, like "shade_smooth" when the result has no faces.
- */
- Vector<std::optional<ResultAttributeData>> curve_point_attributes;
- Vector<std::optional<ResultAttributeData>> curve_spline_attributes;
-
- /**
- * Result attributes corresponding the attributes on the profile input, in the same order. The
- * attributes are optional in case the attribute names correspond to a names used by the curve
- * input, in which case the curve input attributes take precedence.
- */
- Vector<std::optional<ResultAttributeData>> profile_point_attributes;
- Vector<std::optional<ResultAttributeData>> profile_spline_attributes;
-
- /**
- * Because some builtin attributes are not stored contiguously, and the curve inputs might have
- * attributes with those names, it's necessary to keep OutputAttributes around to give access to
- * the result data in a contiguous array.
- */
- Vector<OutputAttribute> attributes;
+/** Information at a specific combination of main and profile curves. */
+struct CombinationInfo {
+ int i_main;
+ int i_profile;
+
+ IndexRange main_points;
+ IndexRange profile_points;
+
+ bool main_cyclic;
+ bool profile_cyclic;
+
+ int main_segment_num;
+ int profile_segment_num;
+
+ IndexRange vert_range;
+ IndexRange edge_range;
+ IndexRange poly_range;
+ IndexRange loop_range;
};
-static ResultAttributes create_result_attributes(const CurveEval &curve,
- const CurveEval &profile,
- MeshComponent &mesh_component)
+template<typename Fn>
+static void foreach_curve_combination(const CurvesInfo &info,
+ const ResultOffsets &offsets,
+ const Fn &fn)
{
- Set<AttributeIDRef> curve_attributes;
-
- /* In order to prefer attributes on the main curve input when there are name collisions, first
- * check the attributes on the curve, then add attributes on the profile that are not also on the
- * main curve input. */
- ResultAttributes result;
- curve.splines().first()->attributes.foreach_attribute(
- [&](const AttributeIDRef &id, const AttributeMetaData &meta_data) {
- curve_attributes.add_new(id);
- result.curve_point_attributes.append(
- create_attribute_and_get_span(mesh_component, id, meta_data, result.attributes));
- return true;
- },
- ATTR_DOMAIN_POINT);
- curve.attributes.foreach_attribute(
- [&](const AttributeIDRef &id, const AttributeMetaData &meta_data) {
- curve_attributes.add_new(id);
- result.curve_spline_attributes.append(
- create_attribute_and_get_span(mesh_component, id, meta_data, result.attributes));
- return true;
- },
- ATTR_DOMAIN_CURVE);
- profile.splines().first()->attributes.foreach_attribute(
- [&](const AttributeIDRef &id, const AttributeMetaData &meta_data) {
- if (curve_attributes.contains(id)) {
- result.profile_point_attributes.append({});
- }
- else {
- result.profile_point_attributes.append(
- create_attribute_and_get_span(mesh_component, id, meta_data, result.attributes));
- }
- return true;
- },
- ATTR_DOMAIN_POINT);
- profile.attributes.foreach_attribute(
- [&](const AttributeIDRef &id, const AttributeMetaData &meta_data) {
- if (curve_attributes.contains(id)) {
- result.profile_spline_attributes.append({});
- }
- else {
- result.profile_spline_attributes.append(
- create_attribute_and_get_span(mesh_component, id, meta_data, result.attributes));
- }
- return true;
- },
- ATTR_DOMAIN_CURVE);
-
- return result;
+ threading::parallel_for(IndexRange(offsets.total), 512, [&](IndexRange range) {
+ for (const int i : range) {
+ const int i_main = offsets.main_indices[i];
+ const int i_profile = offsets.profile_indices[i];
+
+ const IndexRange main_points = info.main.evaluated_points_for_curve(i_main);
+ const IndexRange profile_points = info.profile.evaluated_points_for_curve(i_profile);
+
+ const bool main_cyclic = info.main_cyclic[i_main];
+ const bool profile_cyclic = info.profile_cyclic[i_profile];
+
+ /* Pass all information in a struct to avoid repeating arguments in many lambdas.
+ * The idea is that inlining `fn` will help avoid accessing unnecessary information,
+ * though that may or may not happen in practice. */
+ fn(CombinationInfo{i_main,
+ i_profile,
+ main_points,
+ profile_points,
+ main_cyclic,
+ profile_cyclic,
+ curves::curve_segment_size(main_points.size(), main_cyclic),
+ curves::curve_segment_size(profile_points.size(), profile_cyclic),
+ offsets_to_range(offsets.vert.as_span(), i),
+ offsets_to_range(offsets.edge.as_span(), i),
+ offsets_to_range(offsets.poly.as_span(), i),
+ offsets_to_range(offsets.loop.as_span(), i)});
+ }
+ });
}
template<typename T>
-static void copy_curve_point_data_to_mesh_verts(const Span<T> src,
- const ResultInfo &info,
- MutableSpan<T> dst)
+static void copy_main_point_data_to_mesh_verts(const Span<T> src,
+ const int profile_point_num,
+ MutableSpan<T> dst)
{
- for (const int i_ring : IndexRange(info.spline_vert_len)) {
- const int ring_vert_start = info.vert_offset + i_ring * info.profile_vert_len;
- dst.slice(ring_vert_start, info.profile_vert_len).fill(src[i_ring]);
+ for (const int i_ring : src.index_range()) {
+ const int ring_vert_start = i_ring * profile_point_num;
+ dst.slice(ring_vert_start, profile_point_num).fill(src[i_ring]);
}
}
template<typename T>
-static void copy_curve_point_data_to_mesh_edges(const Span<T> src,
- const ResultInfo &info,
- MutableSpan<T> dst)
+static void copy_main_point_data_to_mesh_edges(const Span<T> src,
+ const int profile_point_num,
+ const int main_segment_num,
+ const int profile_segment_num,
+ MutableSpan<T> dst)
{
- const int edges_start = info.edge_offset + info.profile_vert_len * info.spline_edge_len;
- for (const int i_ring : IndexRange(info.spline_vert_len)) {
- const int ring_edge_start = edges_start + info.profile_edge_len * i_ring;
- dst.slice(ring_edge_start, info.profile_edge_len).fill(src[i_ring]);
+ const int edges_start = profile_point_num * main_segment_num;
+ for (const int i_ring : src.index_range()) {
+ const int ring_edge_start = edges_start + profile_segment_num * i_ring;
+ dst.slice(ring_edge_start, profile_segment_num).fill(src[i_ring]);
}
}
template<typename T>
-static void copy_curve_point_data_to_mesh_faces(const Span<T> src,
- const ResultInfo &info,
- MutableSpan<T> dst)
+static void copy_main_point_data_to_mesh_faces(const Span<T> src,
+ const int main_segment_num,
+ const int profile_segment_num,
+ MutableSpan<T> dst)
{
- for (const int i_ring : IndexRange(info.spline_edge_len)) {
- const int ring_face_start = info.poly_offset + info.profile_edge_len * i_ring;
- dst.slice(ring_face_start, info.profile_edge_len).fill(src[i_ring]);
+ for (const int i_ring : IndexRange(main_segment_num)) {
+ const int ring_face_start = profile_segment_num * i_ring;
+ dst.slice(ring_face_start, profile_segment_num).fill(src[i_ring]);
}
}
-static void copy_curve_point_attribute_to_mesh(const GSpan src,
- const ResultInfo &info,
- ResultAttributeData &dst)
+static void copy_main_point_domain_attribute_to_mesh(const CurvesInfo &curves_info,
+ const ResultOffsets &offsets,
+ const AttributeDomain dst_domain,
+ const GSpan src_all,
+ GMutableSpan dst_all)
{
- GVArray interpolated_gvarray = info.spline.interpolate_to_evaluated(src);
- GSpan interpolated = interpolated_gvarray.get_internal_span();
-
- attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ attribute_math::convert_to_static_type(src_all.type(), [&](auto dummy) {
using T = decltype(dummy);
- switch (dst.domain) {
+ const Span<T> src = src_all.typed<T>();
+ MutableSpan<T> dst = dst_all.typed<T>();
+ switch (dst_domain) {
case ATTR_DOMAIN_POINT:
- copy_curve_point_data_to_mesh_verts(interpolated.typed<T>(), info, dst.data.typed<T>());
+ foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
+ copy_main_point_data_to_mesh_verts(
+ src.slice(info.main_points), info.profile_points.size(), dst.slice(info.vert_range));
+ });
break;
case ATTR_DOMAIN_EDGE:
- copy_curve_point_data_to_mesh_edges(interpolated.typed<T>(), info, dst.data.typed<T>());
+ foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
+ copy_main_point_data_to_mesh_edges(src.slice(info.main_points),
+ info.profile_points.size(),
+ info.main_segment_num,
+ info.profile_segment_num,
+ dst.slice(info.edge_range));
+ });
break;
case ATTR_DOMAIN_FACE:
- copy_curve_point_data_to_mesh_faces(interpolated.typed<T>(), info, dst.data.typed<T>());
+ foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
+ copy_main_point_data_to_mesh_faces(src.slice(info.main_points),
+ info.main_segment_num,
+ info.profile_segment_num,
+ dst.slice(info.poly_range));
+ });
break;
case ATTR_DOMAIN_CORNER:
/* Unsupported for now, since there are no builtin attributes to convert into. */
@@ -504,12 +509,12 @@ static void copy_curve_point_attribute_to_mesh(const GSpan src,
template<typename T>
static void copy_profile_point_data_to_mesh_verts(const Span<T> src,
- const ResultInfo &info,
+ const int main_point_num,
MutableSpan<T> dst)
{
- for (const int i_ring : IndexRange(info.spline_vert_len)) {
- const int profile_vert_start = info.vert_offset + i_ring * info.profile_vert_len;
- for (const int i_profile : IndexRange(info.profile_vert_len)) {
+ for (const int i_ring : IndexRange(main_point_num)) {
+ const int profile_vert_start = i_ring * src.size();
+ for (const int i_profile : src.index_range()) {
dst[profile_vert_start + i_profile] = src[i_profile];
}
}
@@ -517,46 +522,59 @@ static void copy_profile_point_data_to_mesh_verts(const Span<T> src,
template<typename T>
static void copy_profile_point_data_to_mesh_edges(const Span<T> src,
- const ResultInfo &info,
+ const int main_segment_num,
MutableSpan<T> dst)
{
- for (const int i_profile : IndexRange(info.profile_vert_len)) {
- const int profile_edge_offset = info.edge_offset + i_profile * info.spline_edge_len;
- dst.slice(profile_edge_offset, info.spline_edge_len).fill(src[i_profile]);
+ for (const int i_profile : src.index_range()) {
+ const int profile_edge_offset = i_profile * main_segment_num;
+ dst.slice(profile_edge_offset, main_segment_num).fill(src[i_profile]);
}
}
template<typename T>
static void copy_profile_point_data_to_mesh_faces(const Span<T> src,
- const ResultInfo &info,
+ const int main_segment_num,
+ const int profile_segment_num,
MutableSpan<T> dst)
{
- for (const int i_ring : IndexRange(info.spline_edge_len)) {
- const int profile_face_start = info.poly_offset + i_ring * info.profile_edge_len;
- for (const int i_profile : IndexRange(info.profile_edge_len)) {
+ for (const int i_ring : IndexRange(main_segment_num)) {
+ const int profile_face_start = i_ring * profile_segment_num;
+ for (const int i_profile : IndexRange(profile_segment_num)) {
dst[profile_face_start + i_profile] = src[i_profile];
}
}
}
-static void copy_profile_point_attribute_to_mesh(const GSpan src,
- const ResultInfo &info,
- ResultAttributeData &dst)
+static void copy_profile_point_domain_attribute_to_mesh(const CurvesInfo &curves_info,
+ const ResultOffsets &offsets,
+ const AttributeDomain dst_domain,
+ const GSpan src_all,
+ GMutableSpan dst_all)
{
- GVArray interpolated_gvarray = info.profile.interpolate_to_evaluated(src);
- GSpan interpolated = interpolated_gvarray.get_internal_span();
-
- attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ attribute_math::convert_to_static_type(src_all.type(), [&](auto dummy) {
using T = decltype(dummy);
- switch (dst.domain) {
+ const Span<T> src = src_all.typed<T>();
+ MutableSpan<T> dst = dst_all.typed<T>();
+ switch (dst_domain) {
case ATTR_DOMAIN_POINT:
- copy_profile_point_data_to_mesh_verts(interpolated.typed<T>(), info, dst.data.typed<T>());
+ foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
+ copy_profile_point_data_to_mesh_verts(
+ src.slice(info.profile_points), info.main_points.size(), dst.slice(info.vert_range));
+ });
break;
case ATTR_DOMAIN_EDGE:
- copy_profile_point_data_to_mesh_edges(interpolated.typed<T>(), info, dst.data.typed<T>());
+ foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
+ copy_profile_point_data_to_mesh_edges(
+ src.slice(info.profile_points), info.main_segment_num, dst.slice(info.edge_range));
+ });
break;
case ATTR_DOMAIN_FACE:
- copy_profile_point_data_to_mesh_faces(interpolated.typed<T>(), info, dst.data.typed<T>());
+ foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
+ copy_profile_point_data_to_mesh_faces(src.slice(info.profile_points),
+ info.main_segment_num,
+ info.profile_segment_num,
+ dst.slice(info.poly_range));
+ });
break;
case ATTR_DOMAIN_CORNER:
/* Unsupported for now, since there are no builtin attributes to convert into. */
@@ -568,198 +586,236 @@ static void copy_profile_point_attribute_to_mesh(const GSpan src,
});
}
-static void copy_point_domain_attributes_to_mesh(const ResultInfo &info,
- ResultAttributes &attributes)
-{
- if (!attributes.curve_point_attributes.is_empty()) {
- int i = 0;
- info.spline.attributes.foreach_attribute(
- [&](const AttributeIDRef &id, const AttributeMetaData &UNUSED(meta_data)) {
- if (attributes.curve_point_attributes[i]) {
- copy_curve_point_attribute_to_mesh(*info.spline.attributes.get_for_read(id),
- info,
- *attributes.curve_point_attributes[i]);
- }
- i++;
- return true;
- },
- ATTR_DOMAIN_POINT);
- }
- if (!attributes.profile_point_attributes.is_empty()) {
- int i = 0;
- info.profile.attributes.foreach_attribute(
- [&](const AttributeIDRef &id, const AttributeMetaData &UNUSED(meta_data)) {
- if (attributes.profile_point_attributes[i]) {
- copy_profile_point_attribute_to_mesh(*info.profile.attributes.get_for_read(id),
- info,
- *attributes.profile_point_attributes[i]);
- }
- i++;
- return true;
- },
- ATTR_DOMAIN_POINT);
- }
-}
-
template<typename T>
-static void copy_spline_data_to_mesh(Span<T> src, Span<int> offsets, MutableSpan<T> dst)
+static void copy_indices_to_offset_ranges(const VArray<T> &src,
+ const Span<int> curve_indices,
+ const Span<int> mesh_offsets,
+ MutableSpan<T> dst)
{
- for (const int i : IndexRange(src.size())) {
- dst.slice(offsets[i], offsets[i + 1] - offsets[i]).fill(src[i]);
- }
+ /* This unnecessarily instantiates the "is single" case (which should be handled elsewhere if
+ * it's ever used for attributes), but the alternative is duplicating the function for spans and
+ * other virtual arrays. */
+ devirtualize_varray(src, [&](const auto &src) {
+ threading::parallel_for(curve_indices.index_range(), 512, [&](IndexRange range) {
+ for (const int i : range) {
+ dst.slice(offsets_to_range(mesh_offsets, i)).fill(src[curve_indices[i]]);
+ }
+ });
+ });
}
-/**
- * Since the offsets for each combination of curve and profile spline are stored for every mesh
- * domain, and this just needs to fill the chunks corresponding to each combination, we can use
- * the same function for all mesh domains.
- */
-static void copy_spline_attribute_to_mesh(const GSpan src,
- const ResultOffsets &offsets,
- ResultAttributeData &dst_attribute)
+static void copy_curve_domain_attribute_to_mesh(const ResultOffsets &mesh_offsets,
+ const Span<int> curve_indices,
+ const AttributeDomain dst_domain,
+ const GVArray &src,
+ GMutableSpan dst)
{
+ Span<int> offsets;
+ switch (dst_domain) {
+ case ATTR_DOMAIN_POINT:
+ offsets = mesh_offsets.vert;
+ break;
+ case ATTR_DOMAIN_EDGE:
+ offsets = mesh_offsets.edge;
+ break;
+ case ATTR_DOMAIN_FACE:
+ offsets = mesh_offsets.poly;
+ break;
+ case ATTR_DOMAIN_CORNER:
+ offsets = mesh_offsets.loop;
+ break;
+ default:
+ BLI_assert_unreachable();
+ return;
+ }
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
- switch (dst_attribute.domain) {
- case ATTR_DOMAIN_POINT:
- copy_spline_data_to_mesh(src.typed<T>(), offsets.vert, dst_attribute.data.typed<T>());
- break;
- case ATTR_DOMAIN_EDGE:
- copy_spline_data_to_mesh(src.typed<T>(), offsets.edge, dst_attribute.data.typed<T>());
- break;
- case ATTR_DOMAIN_FACE:
- copy_spline_data_to_mesh(src.typed<T>(), offsets.poly, dst_attribute.data.typed<T>());
- break;
- case ATTR_DOMAIN_CORNER:
- copy_spline_data_to_mesh(src.typed<T>(), offsets.loop, dst_attribute.data.typed<T>());
- break;
- default:
- BLI_assert_unreachable();
- break;
- }
+ copy_indices_to_offset_ranges(src.typed<T>(), curve_indices, offsets, dst.typed<T>());
});
}
-static void copy_spline_domain_attributes_to_mesh(const CurveEval &curve,
- const CurveEval &profile,
- const ResultOffsets &offsets,
- ResultAttributes &attributes)
-{
- if (!attributes.curve_spline_attributes.is_empty()) {
- int i = 0;
- curve.attributes.foreach_attribute(
- [&](const AttributeIDRef &id, const AttributeMetaData &UNUSED(meta_data)) {
- if (attributes.curve_spline_attributes[i]) {
- copy_spline_attribute_to_mesh(*curve.attributes.get_for_read(id),
- offsets,
- *attributes.curve_spline_attributes[i]);
- }
- i++;
- return true;
- },
- ATTR_DOMAIN_CURVE);
- }
- if (!attributes.profile_spline_attributes.is_empty()) {
- int i = 0;
- profile.attributes.foreach_attribute(
- [&](const AttributeIDRef &id, const AttributeMetaData &UNUSED(meta_data)) {
- if (attributes.profile_spline_attributes[i]) {
- copy_spline_attribute_to_mesh(*profile.attributes.get_for_read(id),
- offsets,
- *attributes.profile_spline_attributes[i]);
- }
- i++;
- return true;
- },
- ATTR_DOMAIN_CURVE);
- }
-}
-
-Mesh *curve_to_mesh_sweep(const CurveEval &curve, const CurveEval &profile, const bool fill_caps)
+Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
+ const CurvesGeometry &profile,
+ const bool fill_caps)
{
- Span<SplinePtr> profiles = profile.splines();
- Span<SplinePtr> curves = curve.splines();
+ const CurvesInfo curves_info = get_curves_info(main, profile);
- const ResultOffsets offsets = calculate_result_offsets(profiles, curves, fill_caps);
+ const ResultOffsets offsets = calculate_result_offsets(curves_info, fill_caps);
if (offsets.vert.last() == 0) {
return nullptr;
}
Mesh *mesh = BKE_mesh_new_nomain(
offsets.vert.last(), offsets.edge.last(), 0, offsets.loop.last(), offsets.poly.last());
- BKE_id_material_eval_ensure_default_slot(&mesh->id);
mesh->flag |= ME_AUTOSMOOTH;
mesh->smoothresh = DEG2RADF(180.0f);
BKE_mesh_normals_tag_dirty(mesh);
+ MutableSpan<MVert> verts(mesh->mvert, mesh->totvert);
+ MutableSpan<MEdge> edges(mesh->medge, mesh->totedge);
+ MutableSpan<MLoop> loops(mesh->mloop, mesh->totloop);
+ MutableSpan<MPoly> polys(mesh->mpoly, mesh->totpoly);
+
+ foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
+ fill_mesh_topology(info.vert_range.start(),
+ info.edge_range.start(),
+ info.poly_range.start(),
+ info.loop_range.start(),
+ info.main_points.size(),
+ info.profile_points.size(),
+ info.main_cyclic,
+ info.profile_cyclic,
+ fill_caps,
+ edges,
+ loops,
+ polys);
+ });
+
+ const Span<float3> main_positions = main.evaluated_positions();
+ const Span<float3> tangents = main.evaluated_tangents();
+ const Span<float3> normals = main.evaluated_normals();
+ const Span<float3> profile_positions = profile.evaluated_positions();
+
+ Vector<std::byte> eval_buffer;
+
+ Curves main_id = {nullptr};
+ main_id.geometry = reinterpret_cast<const ::CurvesGeometry &>(main);
+ CurveComponent main_component;
+ main_component.replace(&main_id, GeometryOwnershipType::Editable);
+
+ Curves profile_id = {nullptr};
+ profile_id.geometry = reinterpret_cast<const ::CurvesGeometry &>(profile);
+ CurveComponent profile_component;
+ profile_component.replace(&profile_id, GeometryOwnershipType::Editable);
+
+ Span<float> radii = {};
+ if (main_component.attribute_exists("radius")) {
+ radii = evaluated_attribute_if_necessary(
+ main_component.attribute_get_for_read<float>("radius", ATTR_DOMAIN_POINT, 1.0f),
+ main,
+ curves_info.main_type_counts,
+ eval_buffer)
+ .typed<float>();
+ }
+
+ foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
+ fill_mesh_positions(info.main_points.size(),
+ info.profile_points.size(),
+ main_positions.slice(info.main_points),
+ profile_positions.slice(info.profile_points),
+ tangents.slice(info.main_points),
+ normals.slice(info.main_points),
+ radii.is_empty() ? radii : radii.slice(info.main_points),
+ verts.slice(info.vert_range));
+ });
+
+ if (curves_info.profile_type_counts[CURVE_TYPE_BEZIER] > 0) {
+ const VArray<int8_t> curve_types = profile.curve_types();
+ const VArray_Span<int8_t> handle_types_left{profile.handle_types_left()};
+ const VArray_Span<int8_t> handle_types_right{profile.handle_types_right()};
+
+ foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
+ if (curve_types[info.i_profile] == CURVE_TYPE_BEZIER) {
+ const IndexRange points = profile.points_for_curve(info.i_profile);
+ mark_bezier_vector_edges_sharp(points.size(),
+ info.main_segment_num,
+ profile.bezier_evaluated_offsets_for_curve(info.i_profile),
+ handle_types_left.slice(points),
+ handle_types_right.slice(points),
+ edges.slice(info.edge_range));
+ }
+ });
+ }
+
+ Set<AttributeIDRef> main_attributes;
- /* Create the mesh component for retrieving attributes at this scope, since output attributes
- * can keep a reference to the component for updating after retrieving write access. */
MeshComponent mesh_component;
mesh_component.replace(mesh, GeometryOwnershipType::Editable);
- ResultAttributes attributes = create_result_attributes(curve, profile, mesh_component);
- threading::parallel_for(curves.index_range(), 128, [&](IndexRange curves_range) {
- for (const int i_spline : curves_range) {
- const Spline &spline = *curves[i_spline];
- if (spline.evaluated_points_size() == 0) {
- continue;
- }
- const int spline_start_index = i_spline * profiles.size();
- threading::parallel_for(profiles.index_range(), 128, [&](IndexRange profiles_range) {
- for (const int i_profile : profiles_range) {
- const Spline &profile = *profiles[i_profile];
- const int i_mesh = spline_start_index + i_profile;
- ResultInfo info{
- spline,
- profile,
- offsets.vert[i_mesh],
- offsets.edge[i_mesh],
- offsets.loop[i_mesh],
- offsets.poly[i_mesh],
- spline.evaluated_points_size(),
- spline.evaluated_edges_size(),
- profile.evaluated_points_size(),
- profile.evaluated_edges_size(),
- };
-
- spline_extrude_to_mesh_data(info,
- fill_caps,
- {mesh->mvert, mesh->totvert},
- {mesh->medge, mesh->totedge},
- {mesh->mloop, mesh->totloop},
- {mesh->mpoly, mesh->totpoly});
-
- copy_point_domain_attributes_to_mesh(info, attributes);
- }
- });
+ main_component.attribute_foreach([&](const AttributeIDRef &id,
+ const AttributeMetaData meta_data) {
+ if (!should_add_attribute_to_mesh(main_component, mesh_component, id)) {
+ return true;
}
+ main_attributes.add_new(id);
+
+ const AttributeDomain src_domain = meta_data.domain;
+ const CustomDataType type = meta_data.data_type;
+ GVArray src = main_component.attribute_try_get_for_read(id, src_domain, type);
+
+ const AttributeDomain dst_domain = get_attribute_domain_for_mesh(mesh_component, id);
+ OutputAttribute dst = mesh_component.attribute_try_get_for_output_only(id, dst_domain, type);
+ if (!dst) {
+ return true;
+ }
+
+ if (src_domain == ATTR_DOMAIN_POINT) {
+ copy_main_point_domain_attribute_to_mesh(
+ curves_info,
+ offsets,
+ dst_domain,
+ evaluated_attribute_if_necessary(src, main, curves_info.main_type_counts, eval_buffer),
+ dst.as_span());
+ }
+ else if (src_domain == ATTR_DOMAIN_CURVE) {
+ copy_curve_domain_attribute_to_mesh(
+ offsets, offsets.main_indices, dst_domain, src, dst.as_span());
+ }
+
+ dst.save();
+ return true;
});
- copy_spline_domain_attributes_to_mesh(curve, profile, offsets, attributes);
+ profile_component.attribute_foreach([&](const AttributeIDRef &id,
+ const AttributeMetaData meta_data) {
+ if (main_attributes.contains(id)) {
+ return true;
+ }
+ if (!should_add_attribute_to_mesh(profile_component, mesh_component, id)) {
+ return true;
+ }
+ const AttributeDomain src_domain = meta_data.domain;
+ const CustomDataType type = meta_data.data_type;
+ GVArray src = profile_component.attribute_try_get_for_read(id, src_domain, type);
+
+ const AttributeDomain dst_domain = get_attribute_domain_for_mesh(mesh_component, id);
+ OutputAttribute dst = mesh_component.attribute_try_get_for_output_only(id, dst_domain, type);
+ if (!dst) {
+ return true;
+ }
+
+ if (src_domain == ATTR_DOMAIN_POINT) {
+ copy_profile_point_domain_attribute_to_mesh(
+ curves_info,
+ offsets,
+ dst_domain,
+ evaluated_attribute_if_necessary(
+ src, profile, curves_info.profile_type_counts, eval_buffer),
+ dst.as_span());
+ }
+ else if (src_domain == ATTR_DOMAIN_CURVE) {
+ copy_curve_domain_attribute_to_mesh(
+ offsets, offsets.profile_indices, dst_domain, src, dst.as_span());
+ }
- for (OutputAttribute &output_attribute : attributes.attributes) {
- output_attribute.save();
- }
+ dst.save();
+ return true;
+ });
return mesh;
}
-static CurveEval get_curve_single_vert()
+static CurvesGeometry get_curve_single_vert()
{
- CurveEval curve;
- std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
- spline->resize(1.0f);
- spline->positions().fill(float3(0));
- spline->radii().fill(1.0f);
- spline->tilts().fill(0.0f);
- curve.add_spline(std::move(spline));
-
- return curve;
+ CurvesGeometry curves(1, 1);
+ curves.offsets_for_write().last() = 1;
+ curves.positions_for_write().fill(float3(0));
+
+ return curves;
}
-Mesh *curve_to_wire_mesh(const CurveEval &curve)
+Mesh *curve_to_wire_mesh(const CurvesGeometry &curve)
{
- static const CurveEval vert_curve = get_curve_single_vert();
+ static const CurvesGeometry vert_curve = get_curve_single_vert();
return curve_to_mesh_sweep(curve, vert_curve, false);
}