25 if (points_num <= 2) {
32 const int edge_offset,
33 const int face_offset,
34 const int loop_offset,
35 const int main_point_num,
36 const int profile_point_num,
37 const bool main_cyclic,
38 const bool profile_cyclic,
48 if (profile_point_num == 1) {
49 for (
const int i :
IndexRange(main_point_num - 1)) {
50 int2 &edge = edges[edge_offset + i];
51 edge[0] = vert_offset + i;
52 edge[1] = vert_offset + i + 1;
55 if (main_cyclic && main_segment_num > 2) {
56 int2 &edge = edges[edge_offset + main_segment_num - 1];
57 edge[0] = vert_offset + main_point_num - 1;
58 edge[1] = vert_offset;
64 const int main_edges_start = edge_offset;
65 for (
const int i_profile :
IndexRange(profile_point_num)) {
66 const int profile_edge_offset = main_edges_start + i_profile * main_segment_num;
67 for (
const int i_ring :
IndexRange(main_segment_num)) {
68 const int i_next_ring = (i_ring == main_point_num - 1) ? 0 : i_ring + 1;
70 const int ring_vert_offset = vert_offset + profile_point_num * i_ring;
71 const int next_ring_vert_offset = vert_offset + profile_point_num * i_next_ring;
73 int2 &edge = edges[profile_edge_offset + i_ring];
74 edge[0] = ring_vert_offset + i_profile;
75 edge[1] = next_ring_vert_offset + i_profile;
80 const int profile_edges_start = main_edges_start + profile_point_num * main_segment_num;
81 for (
const int i_ring :
IndexRange(main_point_num)) {
82 const int ring_vert_offset = vert_offset + profile_point_num * i_ring;
84 const int ring_edge_offset = profile_edges_start + i_ring * profile_segment_num;
85 for (
const int i_profile :
IndexRange(profile_segment_num)) {
86 const int i_next_profile = (i_profile == profile_point_num - 1) ? 0 : i_profile + 1;
88 int2 &edge = edges[ring_edge_offset + i_profile];
89 edge[0] = ring_vert_offset + i_profile;
90 edge[1] = ring_vert_offset + i_next_profile;
95 for (
const int i_ring :
IndexRange(main_segment_num)) {
96 const int i_next_ring = (i_ring == main_point_num - 1) ? 0 : i_ring + 1;
98 const int ring_vert_offset = vert_offset + profile_point_num * i_ring;
99 const int next_ring_vert_offset = vert_offset + profile_point_num * i_next_ring;
101 const int ring_edge_start = profile_edges_start + profile_segment_num * i_ring;
102 const int next_ring_edge_offset = profile_edges_start + profile_segment_num * i_next_ring;
104 const int ring_face_offset = face_offset + i_ring * profile_segment_num;
105 const int ring_loop_offset = loop_offset + i_ring * profile_segment_num * 4;
107 for (
const int i_profile :
IndexRange(profile_segment_num)) {
108 const int ring_segment_loop_offset = ring_loop_offset + i_profile * 4;
109 const int i_next_profile = (i_profile == profile_point_num - 1) ? 0 : i_profile + 1;
111 const int main_edge_start = main_edges_start + main_segment_num * i_profile;
112 const int next_main_edge_start = main_edges_start + main_segment_num * i_next_profile;
114 face_offsets[ring_face_offset + i_profile] = ring_segment_loop_offset;
116 corner_verts[ring_segment_loop_offset] = ring_vert_offset + i_profile;
117 corner_edges[ring_segment_loop_offset] = ring_edge_start + i_profile;
119 corner_verts[ring_segment_loop_offset + 1] = ring_vert_offset + i_next_profile;
120 corner_edges[ring_segment_loop_offset + 1] = next_main_edge_start + i_ring;
122 corner_verts[ring_segment_loop_offset + 2] = next_ring_vert_offset + i_next_profile;
123 corner_edges[ring_segment_loop_offset + 2] = next_ring_edge_offset + i_profile;
125 corner_verts[ring_segment_loop_offset + 3] = next_ring_vert_offset + i_profile;
126 corner_edges[ring_segment_loop_offset + 3] = main_edge_start + i_ring;
130 const bool has_caps = fill_caps && !main_cyclic && profile_cyclic && profile_point_num > 2;
132 const int face_num = main_segment_num * profile_segment_num;
133 const int cap_loop_offset = loop_offset + face_num * 4;
134 const int cap_face_offset = face_offset + face_num;
136 face_offsets[cap_face_offset] = cap_loop_offset;
137 face_offsets[cap_face_offset + 1] = cap_loop_offset + profile_segment_num;
139 const int last_ring_index = main_point_num - 1;
140 const int last_ring_vert_offset = vert_offset + profile_point_num * last_ring_index;
141 const int last_ring_edge_offset = profile_edges_start + profile_segment_num * last_ring_index;
143 for (
const int i :
IndexRange(profile_segment_num)) {
144 const int i_inv = profile_segment_num - i - 1;
145 corner_verts[cap_loop_offset + i] = vert_offset + i_inv;
146 corner_edges[cap_loop_offset + i] = profile_edges_start + ((i == (profile_segment_num - 1)) ?
147 (profile_segment_num - 1) :
149 corner_verts[cap_loop_offset + profile_segment_num + i] = last_ring_vert_offset + i;
150 corner_edges[cap_loop_offset + profile_segment_num + i] = last_ring_edge_offset + i;
157 const int main_segment_num,
163 const int main_edges_start = 0;
165 sharp_edges.
slice(main_edges_start, main_segment_num).
fill(
true);
170 const int offset = main_edges_start + main_segment_num * control_point_offsets[i];
171 sharp_edges.
slice(offset, main_segment_num).
fill(
true);
181 matrix.x_axis() = tangent;
184 matrix.z_axis() = normal;
185 matrix.location() = location;
190 const int profile_point_num,
198 if (profile_point_num == 1) {
199 for (
const int i_ring :
IndexRange(main_point_num)) {
201 main_positions[i_ring], normals[i_ring], tangents[i_ring]);
202 if (!radii.is_empty()) {
209 for (
const int i_ring :
IndexRange(main_point_num)) {
211 main_positions[i_ring], normals[i_ring], tangents[i_ring]);
212 if (!radii.is_empty()) {
216 const int ring_vert_start = i_ring * profile_point_num;
217 for (
const int i_profile :
IndexRange(profile_point_num)) {
219 point_matrix, profile_positions[i_profile]);
235 return {
main, profile,
main.cyclic(), profile.cyclic()};
241 if (offsets[i].
size() == 1) {
277 result.vert.reinitialize(result.total + 1);
278 result.edge.reinitialize(result.total + 1);
279 result.loop.reinitialize(result.total + 1);
280 result.face.reinitialize(result.total + 1);
287 for (const int i_main : main_offsets.index_range()) {
288 const bool main_cyclic = info.main_cyclic[i_main];
289 const int main_point_num = main_offsets[i_main].size();
290 const int main_segment_num = segments_num_no_duplicate_edge(main_point_num, main_cyclic);
291 for (const int i_profile : profile_offsets.index_range()) {
292 result.vert[mesh_index] = vert_offset;
293 result.edge[mesh_index] = edge_offset;
294 result.loop[mesh_index] = loop_offset;
295 result.face[mesh_index] = face_offset;
297 const bool profile_cyclic = info.profile_cyclic[i_profile];
298 const int profile_point_num = profile_offsets[i_profile].size();
299 const int profile_segment_num = curves::segments_num(profile_point_num,
302 const bool has_caps = fill_caps && !main_cyclic && profile_cyclic &&
303 profile_point_num > 2;
304 const int tube_face_num = main_segment_num * profile_segment_num;
306 vert_offset += main_point_num * profile_point_num;
310 edge_offset += main_point_num * profile_segment_num +
311 main_segment_num * profile_point_num;
314 face_offset += tube_face_num + (has_caps ? 2 : 0);
318 loop_offset += tube_face_num * 4 + (has_caps ? profile_segment_num * 2 : 0);
324 result.vert.last() = vert_offset;
325 result.edge.last() = edge_offset;
326 result.loop.last() = loop_offset;
327 result.face.last() = face_offset;
330 result.main_indices.reinitialize(result.total);
331 result.profile_indices.reinitialize(result.total);
334 for (
const int i_main : main_offsets.index_range()) {
335 for (
const int i_profile : profile_offsets.index_range()) {
336 result.main_indices[mesh_index] = i_main;
337 result.profile_indices[mesh_index] = i_profile;
352 if (!mesh_attributes.
is_builtin(attribute_id)) {
353 return AttrDomain::Point;
356 std::optional<AttributeMetaData> meta_data = mesh_attributes.
lookup_meta_data(attribute_id);
358 return AttrDomain::Point;
361 return meta_data->domain;
372 if (
id ==
"position") {
412 curves.interpolate_to_evaluated(src_buffer, eval);
447 for (const int i : range) {
448 const int i_main = offsets.main_indices[i];
449 const int i_profile = offsets.profile_indices[i];
451 const IndexRange main_points = main_offsets[i_main];
452 const IndexRange profile_points = profile_offsets[i_profile];
454 const bool main_cyclic = info.main_cyclic[i_main];
455 const bool profile_cyclic = info.profile_cyclic[i_profile];
460 fn(CombinationInfo{i_main,
466 curves::segments_num(main_points.size(), main_cyclic),
467 curves::segments_num(profile_points.size(), profile_cyclic),
481 BLI_assert(!mesh.attributes().contains(
"position"));
483 const bool ignore_profile_position = profile_positions.
size() == 1 &&
485 if (ignore_profile_position) {
490 if (mesh.attributes_for_write().add<
float3>(
"position", AttrDomain::Point,
init)) {
499 if (ignore_profile_position) {
500 array_utils::copy(main_positions, positions);
523 const int profile_point_num,
527 const int ring_vert_start = i_ring * profile_point_num;
528 dst.
slice(ring_vert_start, profile_point_num).
fill(src[i_ring]);
534 const int profile_point_num,
535 const int main_segment_num,
536 const int profile_segment_num,
539 const int edges_start = profile_point_num * main_segment_num;
541 const int ring_edge_start = edges_start + profile_segment_num * i_ring;
542 dst.
slice(ring_edge_start, profile_segment_num).
fill(src[i_ring]);
548 const int main_segment_num,
549 const int profile_segment_num,
552 for (
const int i_ring :
IndexRange(main_segment_num)) {
553 const int ring_face_start = profile_segment_num * i_ring;
554 dst.
slice(ring_face_start, profile_segment_num).
fill(src[i_ring]);
563 if (mesh_attributes.
domain_size(AttrDomain::Point) !=
main.points_num()) {
569 return mesh_attributes.
add(
572 bke::cpp_type_to_custom_data_type(src.
varray.
type()),
580 if (dst.
size() !=
main.evaluated_points_num()) {
598 if (dst_domain == AttrDomain::Point) {
604 id, dst_domain, bke::cpp_type_to_custom_data_type(src_attribute.
varray.
type()));
605 if (!dst_attribute) {
608 if (dst_domain == AttrDomain::Point) {
615 attribute_math::convert_to_static_type(src_attribute.
varray.
type(), [&](
auto dummy) {
616 using T = decltype(dummy);
617 const Span<T> src = src_all.typed<T>();
618 MutableSpan<T> dst = dst_attribute.span.typed<T>();
619 switch (dst_domain) {
620 case AttrDomain::Point:
621 foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
622 copy_main_point_data_to_mesh_verts(
623 src.slice(info.main_points), info.profile_points.size(), dst.slice(info.vert_range));
626 case AttrDomain::Edge:
627 foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
628 copy_main_point_data_to_mesh_edges(src.slice(info.main_points),
629 info.profile_points.size(),
630 info.main_segment_num,
631 info.profile_segment_num,
632 dst.slice(info.edge_range));
635 case AttrDomain::Face:
636 foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
637 copy_main_point_data_to_mesh_faces(src.slice(info.main_points),
638 info.main_segment_num,
639 info.profile_segment_num,
640 dst.slice(info.face_range));
643 case AttrDomain::Corner:
647 BLI_assert_unreachable();
651 dst_attribute.finish();
656 const int main_point_num,
659 for (
const int i_ring :
IndexRange(main_point_num)) {
660 const int profile_vert_start = i_ring * src.
size();
662 dst[profile_vert_start + i_profile] = src[i_profile];
669 const int main_segment_num,
673 const int profile_edge_offset = i_profile * main_segment_num;
674 dst.
slice(profile_edge_offset, main_segment_num).
fill(src[i_profile]);
680 const int main_segment_num,
681 const int profile_segment_num,
684 for (
const int i_ring :
IndexRange(main_segment_num)) {
685 const int profile_face_start = i_ring * profile_segment_num;
686 for (
const int i_profile :
IndexRange(profile_segment_num)) {
687 dst[profile_face_start + i_profile] = src[i_profile];
698 attribute_math::convert_to_static_type(src_all.
type(), [&](
auto dummy) {
699 using T = decltype(dummy);
700 const Span<T> src = src_all.typed<T>();
701 MutableSpan<T> dst = dst_all.typed<T>();
702 switch (dst_domain) {
703 case AttrDomain::Point:
704 foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
705 copy_profile_point_data_to_mesh_verts(
706 src.slice(info.profile_points), info.main_points.size(), dst.slice(info.vert_range));
709 case AttrDomain::Edge:
710 foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
711 copy_profile_point_data_to_mesh_edges(
712 src.slice(info.profile_points), info.main_segment_num, dst.slice(info.edge_range));
715 case AttrDomain::Face:
716 foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
717 copy_profile_point_data_to_mesh_faces(src.slice(info.profile_points),
718 info.main_segment_num,
719 info.profile_segment_num,
720 dst.slice(info.face_range));
723 case AttrDomain::Corner:
727 BLI_assert_unreachable();
744 for (const int i : range) {
745 dst.slice(mesh_offsets[i]).fill(src[curve_indices[i]]);
758 switch (dst_domain) {
759 case AttrDomain::Point:
760 offsets = mesh_offsets.
vert;
762 case AttrDomain::Edge:
763 offsets = mesh_offsets.
edge;
765 case AttrDomain::Face:
766 offsets = mesh_offsets.
face;
768 case AttrDomain::Corner:
769 offsets = mesh_offsets.
loop;
775 attribute_math::convert_to_static_type(src.
type(), [&](
auto dummy) {
776 using T = decltype(dummy);
777 copy_indices_to_offset_ranges(src.typed<T>(), curve_indices, offsets, dst.typed<T>());
800 const OffsetIndices profile_points_by_curve = profile.points_by_curve();
804 const IndexRange points = profile_points_by_curve[info.i_profile];
805 mark_bezier_vector_edges_sharp(points.size(),
806 info.main_segment_num,
807 profile.bezier_evaluated_offsets_for_curve(info.i_profile),
808 handle_types_left.slice(points),
809 handle_types_right.slice(points),
810 sharp_edges.span.slice(info.edge_range));
817 const bool fill_caps,
831 mesh->verts_num = offsets.
vert.
last();
859 "sharp_face", AttrDomain::Face);
865 sharp_faces.
span[cap_face_offset] =
true;
866 sharp_faces.
span[cap_face_offset + 1] =
true;
875 main.ensure_can_interpolate_to_evaluated();
879 mesh->tag_overlapping_none();
882 mesh->tag_loose_verts_none();
885 mesh->tag_loose_edges_none();
902 const int profile_edges_start = main_edges_start +
904 const int last_ring_edge_offset = profile_edges_start +
918 {iter.domain, iter.data_type},
929 if (src_domain == AttrDomain::Point) {
931 curves_info, iter.
name, offsets, dst_domain, src, eval_buffer, mesh_attributes);
933 else if (src_domain == AttrDomain::Curve) {
935 iter.
name, dst_domain, type);
945 profile.ensure_can_interpolate_to_evaluated();
955 {iter.domain, iter.data_type},
966 iter.
name, dst_domain, type);
971 if (src_domain == AttrDomain::Point) {
978 else if (src_domain == AttrDomain::Curve) {
992 curves.offsets_for_write().last() = 1;
993 curves.positions_for_write().fill(
float3(0.0f));
Low-level operations for curves.
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_free_layer_named(CustomData *data, blender::StringRef name, const int totelem)
General operations, lookup, etc. for materials.
Mesh * BKE_mesh_new_nomain(int verts_num, int edges_num, int faces_num, int corners_num)
#define BLI_assert_unreachable()
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
const T & last(const int64_t n=0) const
const CPPType & type() const
const void * data() const
GSpan get_internal_span() const
const CPPType & type() const
void materialize(void *dst) const
constexpr int64_t size() const
constexpr int64_t start() const
constexpr IndexRange drop_front(int64_t n) const
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
constexpr void fill(const T &value) const
constexpr Span slice(int64_t start, int64_t size) const
constexpr const T & first() const
constexpr int64_t size() const
constexpr IndexRange index_range() const
constexpr bool is_empty() const
void reinitialize(const int64_t new_size)
bool is_builtin(const StringRef attribute_id) const
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
GAttributeReader lookup(const StringRef attribute_id) const
std::optional< AttributeMetaData > lookup_meta_data(const StringRef attribute_id) const
int domain_size(const AttrDomain domain) const
bool contains(const StringRef attribute_id) const
eCustomDataType data_type
GAttributeReader get() const
Span< float3 > evaluated_tangents() const
Span< float3 > evaluated_normals() const
OffsetIndices< int > evaluated_points_by_curve() const
AttributeAccessor attributes() const
Span< float3 > evaluated_positions() const
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
bool add(const StringRef attribute_id, const AttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer)
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type)
IndexRange index_range() const
bool point_is_sharp(Span< int8_t > handle_types_left, Span< int8_t > handle_types_right, int index)
int segments_num(const int points_num, const bool cyclic)
static void copy_main_point_data_to_mesh_verts(const Span< T > src, const int profile_point_num, MutableSpan< T > dst)
static void copy_indices_to_offset_ranges(const VArray< T > &src, const Span< int > curve_indices, const OffsetIndices< int > mesh_offsets, MutableSpan< T > dst)
static GSpan evaluate_attribute(const GVArray &src, const CurvesGeometry &curves, Vector< std::byte > &buffer)
static void copy_curve_domain_attribute_to_mesh(const ResultOffsets &mesh_offsets, const Span< int > curve_indices, const AttrDomain dst_domain, const GVArray &src, GMutableSpan dst)
static CurvesInfo get_curves_info(const CurvesGeometry &main, const CurvesGeometry &profile)
static void copy_profile_point_data_to_mesh_edges(const Span< T > src, const int main_segment_num, MutableSpan< T > dst)
Mesh * curve_to_mesh_sweep(const CurvesGeometry &main, const CurvesGeometry &profile, bool fill_caps, const bke::AttributeFilter &attribute_filter={})
static CurvesGeometry get_curve_single_vert()
static void build_mesh_positions(const CurvesInfo &curves_info, const ResultOffsets &offsets, Vector< std::byte > &eval_buffer, Mesh &mesh)
static bool try_sharing_point_data(const CurvesGeometry &main, const StringRef id, const GAttributeReader &src, MutableAttributeAccessor mesh_attributes)
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)
static void foreach_curve_combination(const CurvesInfo &info, const ResultOffsets &offsets, const Fn &fn)
static void copy_profile_point_domain_attribute_to_mesh(const CurvesInfo &curves_info, const ResultOffsets &offsets, const AttrDomain dst_domain, const GSpan src_all, GMutableSpan dst_all)
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< bool > sharp_edges)
static AttrDomain get_attribute_domain_for_mesh(const AttributeAccessor &mesh_attributes, const StringRef attribute_id)
static void copy_main_point_domain_attribute_to_mesh(const CurvesInfo &curves_info, const StringRef id, const ResultOffsets &offsets, const AttrDomain dst_domain, const GAttributeReader &src_attribute, Vector< std::byte > &eval_buffer, MutableAttributeAccessor mesh_attributes)
static void fill_mesh_topology(const int vert_offset, const int edge_offset, const int face_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< int2 > edges, MutableSpan< int > corner_verts, MutableSpan< int > corner_edges, MutableSpan< int > face_offsets)
static void write_sharp_bezier_edges(const CurvesInfo &curves_info, const ResultOffsets &offsets, MutableAttributeAccessor mesh_attributes, SpanAttributeWriter< bool > &sharp_edges)
static ResultOffsets calculate_result_offsets(const CurvesInfo &info, const bool fill_caps)
static bool should_add_attribute_to_mesh(const AttributeAccessor &curve_attributes, const AttributeAccessor &mesh_attributes, const StringRef id, const AttributeMetaData &meta_data, const AttributeFilter &attribute_filter)
static void copy_profile_point_data_to_mesh_verts(const Span< T > src, const int main_point_num, MutableSpan< T > dst)
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< float3 > mesh_positions)
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)
static bool try_direct_evaluate_point_data(const CurvesGeometry &main, const GAttributeReader &src, GMutableSpan dst)
Mesh * curve_to_wire_mesh(const CurvesGeometry &curve, const bke::AttributeFilter &attribute_filter={})
static float4x4 build_point_matrix(const float3 &location, const float3 &tangent, const float3 &normal)
static int segments_num_no_duplicate_edge(const int points_num, const bool cyclic)
static bool offsets_contain_single_point(const OffsetIndices< int > offsets)
static void copy_profile_point_data_to_mesh_faces(const Span< T > src, const int main_segment_num, const int profile_segment_num, MutableSpan< T > dst)
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
AxisSigned cross(const AxisSigned a, const AxisSigned b)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
bool is_equal(const MatBase< T, NumCol, NumRow > &a, const MatBase< T, NumCol, NumRow > &b, const T epsilon=T(0))
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
void parallel_invoke(Functions &&...functions)
void devirtualize_varray(const VArray< T > &varray, const Func &func, bool enable=true)
VecBase< float, 3 > float3
static MatBase identity()
bool allow_skip(const StringRef name) const
IndexRange profile_points
const CurvesGeometry & profile
VArraySpan< bool > profile_cyclic
const CurvesGeometry & main
VArraySpan< bool > main_cyclic
const ImplicitSharingInfo * sharing_info
bool any_single_point_profile
Array< int > main_indices
bool any_single_point_main
Array< int > profile_indices
MutableVArraySpan< T > span