22 if (points_num == 0) {
25 if (points_num <= 2) {
31static inline bool has_caps(
const bool main_cyclic,
32 const bool profile_cyclic,
33 const int profile_segment_num)
35 return !main_cyclic && profile_cyclic && profile_segment_num > 2;
39 const int edge_offset,
40 const int face_offset,
41 const int loop_offset,
42 const int main_point_num,
43 const int profile_point_num,
44 const bool main_cyclic,
45 const bool profile_cyclic,
55 if (profile_point_num == 1) {
56 for (
const int i :
IndexRange(main_point_num - 1)) {
57 int2 &edge = edges[edge_offset +
i];
58 edge[0] = vert_offset +
i;
59 edge[1] = vert_offset +
i + 1;
62 if (main_cyclic && main_segment_num > 2) {
63 int2 &edge = edges[edge_offset + main_segment_num - 1];
64 edge[0] = vert_offset + main_point_num - 1;
65 edge[1] = vert_offset;
71 const int main_edges_start = edge_offset;
72 for (
const int i_profile :
IndexRange(profile_point_num)) {
73 const int profile_edge_offset = main_edges_start + i_profile * main_segment_num;
74 for (
const int i_ring :
IndexRange(main_segment_num)) {
75 const int i_next_ring = (i_ring == main_point_num - 1) ? 0 : i_ring + 1;
77 const int ring_vert_offset = vert_offset + profile_point_num * i_ring;
78 const int next_ring_vert_offset = vert_offset + profile_point_num * i_next_ring;
80 int2 &edge = edges[profile_edge_offset + i_ring];
81 edge[0] = ring_vert_offset + i_profile;
82 edge[1] = next_ring_vert_offset + i_profile;
87 const int profile_edges_start = main_edges_start + profile_point_num * main_segment_num;
88 for (
const int i_ring :
IndexRange(main_point_num)) {
89 const int ring_vert_offset = vert_offset + profile_point_num * i_ring;
91 const int ring_edge_offset = profile_edges_start + i_ring * profile_segment_num;
92 for (
const int i_profile :
IndexRange(profile_segment_num)) {
93 const int i_next_profile = (i_profile == profile_point_num - 1) ? 0 : i_profile + 1;
95 int2 &edge = edges[ring_edge_offset + i_profile];
96 edge[0] = ring_vert_offset + i_profile;
97 edge[1] = ring_vert_offset + i_next_profile;
102 for (
const int i_ring :
IndexRange(main_segment_num)) {
103 const int i_next_ring = (i_ring == main_point_num - 1) ? 0 : i_ring + 1;
105 const int ring_vert_offset = vert_offset + profile_point_num * i_ring;
106 const int next_ring_vert_offset = vert_offset + profile_point_num * i_next_ring;
108 const int ring_edge_start = profile_edges_start + profile_segment_num * i_ring;
109 const int next_ring_edge_offset = profile_edges_start + profile_segment_num * i_next_ring;
111 const int ring_face_offset = face_offset + i_ring * profile_segment_num;
112 const int ring_loop_offset = loop_offset + i_ring * profile_segment_num * 4;
114 for (
const int i_profile :
IndexRange(profile_segment_num)) {
115 const int ring_segment_loop_offset = ring_loop_offset + i_profile * 4;
116 const int i_next_profile = (i_profile == profile_point_num - 1) ? 0 : i_profile + 1;
118 const int main_edge_start = main_edges_start + main_segment_num * i_profile;
119 const int next_main_edge_start = main_edges_start + main_segment_num * i_next_profile;
121 face_offsets[ring_face_offset + i_profile] = ring_segment_loop_offset;
123 corner_verts[ring_segment_loop_offset] = ring_vert_offset + i_profile;
124 corner_edges[ring_segment_loop_offset] = ring_edge_start + i_profile;
126 corner_verts[ring_segment_loop_offset + 1] = ring_vert_offset + i_next_profile;
127 corner_edges[ring_segment_loop_offset + 1] = next_main_edge_start + i_ring;
129 corner_verts[ring_segment_loop_offset + 2] = next_ring_vert_offset + i_next_profile;
130 corner_edges[ring_segment_loop_offset + 2] = next_ring_edge_offset + i_profile;
132 corner_verts[ring_segment_loop_offset + 3] = next_ring_vert_offset + i_profile;
133 corner_edges[ring_segment_loop_offset + 3] = main_edge_start + i_ring;
137 if (fill_caps &
has_caps(main_cyclic, profile_cyclic, profile_segment_num)) {
138 const int face_num = main_segment_num * profile_segment_num;
139 const int cap_loop_offset = loop_offset + face_num * 4;
140 const int cap_face_offset = face_offset + face_num;
142 face_offsets[cap_face_offset] = cap_loop_offset;
143 face_offsets[cap_face_offset + 1] = cap_loop_offset + profile_segment_num;
145 const int last_ring_index = main_point_num - 1;
146 const int last_ring_vert_offset = vert_offset + profile_point_num * last_ring_index;
147 const int last_ring_edge_offset = profile_edges_start + profile_segment_num * last_ring_index;
149 for (
const int i :
IndexRange(profile_segment_num)) {
150 const int i_inv = profile_segment_num -
i - 1;
151 corner_verts[cap_loop_offset +
i] = vert_offset + i_inv;
152 corner_edges[cap_loop_offset +
i] = profile_edges_start + ((
i == (profile_segment_num - 1)) ?
153 (profile_segment_num - 1) :
155 corner_verts[cap_loop_offset + profile_segment_num +
i] = last_ring_vert_offset +
i;
156 corner_edges[cap_loop_offset + profile_segment_num +
i] = last_ring_edge_offset +
i;
163 const int main_segment_num,
169 const int main_edges_start = 0;
171 sharp_edges.
slice(main_edges_start, main_segment_num).
fill(
true);
174 for (
const int i :
IndexRange(profile_point_num).drop_front(1)) {
176 const int offset = main_edges_start + main_segment_num * control_point_offsets[
i];
177 sharp_edges.
slice(offset, main_segment_num).
fill(
true);
187 matrix.
x_axis() = tangent;
196 const int profile_point_num,
204 if (profile_point_num == 1) {
205 for (
const int i_ring :
IndexRange(main_point_num)) {
207 main_positions[i_ring],
normals[i_ring], tangents[i_ring]);
215 for (
const int i_ring :
IndexRange(main_point_num)) {
217 main_positions[i_ring],
normals[i_ring], tangents[i_ring]);
222 const int ring_vert_start = i_ring * profile_point_num;
223 for (
const int i_profile :
IndexRange(profile_point_num)) {
225 point_matrix, profile_positions[i_profile]);
241 return {
main, profile,
main.cyclic(), profile.cyclic()};
247 if (offsets[
i].
size() == 1) {
283 result.vert.reinitialize(result.total + 1);
284 result.edge.reinitialize(result.total + 1);
285 result.loop.reinitialize(result.total + 1);
286 result.face.reinitialize(result.total + 1);
293 for (const int i_main : main_offsets.index_range()) {
294 const bool main_cyclic = info.main_cyclic[i_main];
295 const int main_point_num = main_offsets[i_main].size();
296 const int main_segment_num = segments_num_no_duplicate_edge(main_point_num, main_cyclic);
297 for (const int i_profile : profile_offsets.index_range()) {
298 result.vert[mesh_index] = vert_offset;
299 result.edge[mesh_index] = edge_offset;
300 result.loop[mesh_index] = loop_offset;
301 result.face[mesh_index] = face_offset;
303 const bool profile_cyclic = info.profile_cyclic[i_profile];
304 const int profile_point_num = profile_offsets[i_profile].size();
305 if (profile_point_num == 0) {
308 const int profile_segment_num = curves::segments_num(profile_point_num,
311 const bool caps = fill_caps &
312 has_caps(main_cyclic, profile_cyclic, profile_segment_num);
313 const int tube_face_num = main_segment_num * profile_segment_num;
315 vert_offset += main_point_num * profile_point_num;
319 edge_offset += main_point_num * profile_segment_num +
320 main_segment_num * profile_point_num;
323 face_offset += tube_face_num + (caps ? 2 : 0);
327 loop_offset += tube_face_num * 4 + (caps ? profile_segment_num * 2 : 0);
333 result.vert.last() = vert_offset;
334 result.edge.last() = edge_offset;
335 result.loop.last() = loop_offset;
336 result.face.last() = face_offset;
343 for (
const int i_main : main_offsets.index_range()) {
344 for (
const int i_profile : profile_offsets.index_range()) {
345 result.main_indices[mesh_index] = i_main;
346 result.profile_indices[mesh_index] = i_profile;
361 if (!mesh_attributes.
is_builtin(attribute_id)) {
365 std::optional<AttributeMetaData> meta_data = mesh_attributes.
lookup_meta_data(attribute_id);
370 return meta_data->domain;
380 if (
id ==
"position") {
384 if (
id ==
"custom_normal") {
426 curves.interpolate_to_evaluated(src_buffer, eval);
461 for (const int i : range) {
462 const int i_main = offsets.main_indices[i];
463 const int i_profile = offsets.profile_indices[i];
465 const IndexRange main_points = main_offsets[i_main];
466 const IndexRange profile_points = profile_offsets[i_profile];
467 if (main_points.is_empty() || profile_points.is_empty()) {
471 const bool main_cyclic = info.main_cyclic[i_main];
472 const bool profile_cyclic = info.profile_cyclic[i_profile];
477 fn(CombinationInfo{i_main,
483 curves::segments_num(main_points.size(), main_cyclic),
484 curves::segments_num(profile_points.size(), profile_cyclic),
501 const bool ignore_profile_position = profile_positions.
size() == 1 &&
503 if (ignore_profile_position) {
520 if (ignore_profile_position) {
544 const int profile_point_num,
548 const int ring_vert_start = i_ring * profile_point_num;
549 dst.
slice(ring_vert_start, profile_point_num).
fill(src[i_ring]);
555 const int profile_point_num,
556 const int main_segment_num,
557 const int profile_segment_num,
560 const int edges_start = profile_point_num * main_segment_num;
562 const int ring_edge_start = edges_start + profile_segment_num * i_ring;
563 dst.
slice(ring_edge_start, profile_segment_num).
fill(src[i_ring]);
569 const int main_segment_num,
570 const int profile_segment_num,
573 for (
const int i_ring :
IndexRange(main_segment_num)) {
574 const int ring_face_start = profile_segment_num * i_ring;
575 dst.
slice(ring_face_start, profile_segment_num).
fill(src[i_ring]);
590 return mesh_attributes.
add(
601 if (dst.
size() !=
main.evaluated_points_num()) {
626 if (!dst_attribute) {
637 using T = decltype(dummy);
638 const Span<T> src = src_all.typed<T>();
639 MutableSpan<T> dst = dst_attribute.span.typed<T>();
640 switch (dst_domain) {
641 case AttrDomain::Point:
642 foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
643 copy_main_point_data_to_mesh_verts(
644 src.slice(info.main_points), info.profile_points.size(), dst.slice(info.vert_range));
647 case AttrDomain::Edge:
648 foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
649 copy_main_point_data_to_mesh_edges(src.slice(info.main_points),
650 info.profile_points.size(),
651 info.main_segment_num,
652 info.profile_segment_num,
653 dst.slice(info.edge_range));
656 case AttrDomain::Face:
657 foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
658 copy_main_point_data_to_mesh_faces(src.slice(info.main_points),
659 info.main_segment_num,
660 info.profile_segment_num,
661 dst.slice(info.face_range));
664 case AttrDomain::Corner:
668 BLI_assert_unreachable();
672 dst_attribute.finish();
677 const int main_point_num,
680 for (
const int i_ring :
IndexRange(main_point_num)) {
681 const int profile_vert_start = i_ring * src.
size();
683 dst[profile_vert_start + i_profile] = src[i_profile];
690 const int main_segment_num,
694 const int profile_edge_offset = i_profile * main_segment_num;
695 dst.
slice(profile_edge_offset, main_segment_num).
fill(src[i_profile]);
701 const int main_segment_num,
702 const int profile_segment_num,
705 for (
const int i_ring :
IndexRange(main_segment_num)) {
706 const int profile_face_start = i_ring * profile_segment_num;
707 for (
const int i_profile :
IndexRange(profile_segment_num)) {
708 dst[profile_face_start + i_profile] = src[i_profile];
720 using T = decltype(dummy);
721 const Span<T> src = src_all.typed<T>();
722 MutableSpan<T> dst = dst_all.typed<T>();
723 switch (dst_domain) {
724 case AttrDomain::Point:
725 foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
726 copy_profile_point_data_to_mesh_verts(
727 src.slice(info.profile_points), info.main_points.size(), dst.slice(info.vert_range));
730 case AttrDomain::Edge:
731 foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
732 copy_profile_point_data_to_mesh_edges(
733 src.slice(info.profile_points), info.main_segment_num, dst.slice(info.edge_range));
736 case AttrDomain::Face:
737 foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
738 copy_profile_point_data_to_mesh_faces(src.slice(info.profile_points),
739 info.main_segment_num,
740 info.profile_segment_num,
741 dst.slice(info.face_range));
744 case AttrDomain::Corner:
748 BLI_assert_unreachable();
765 for (const int i : range) {
766 dst.slice(mesh_offsets[i]).fill(src[curve_indices[i]]);
779 switch (dst_domain) {
781 offsets = mesh_offsets.
vert;
784 offsets = mesh_offsets.
edge;
787 offsets = mesh_offsets.
face;
790 offsets = mesh_offsets.
loop;
797 using T = decltype(dummy);
798 copy_indices_to_offset_ranges(src.typed<T>(), curve_indices, offsets, dst.typed<T>());
829 handle_types_left.
slice(points),
830 handle_types_right.
slice(points),
839 const bool fill_caps,
886 sharp_faces.
span[cap_face_offset] =
true;
887 sharp_faces.
span[cap_face_offset + 1] =
true;
896 main.ensure_can_interpolate_to_evaluated();
900 mesh->tag_overlapping_none();
903 mesh->tag_loose_verts_none();
906 mesh->tag_loose_edges_none();
923 const int profile_edges_start = main_edges_start +
925 const int last_ring_edge_offset = profile_edges_start +
939 {iter.domain, iter.data_type},
952 curves_info, iter.
name, offsets, dst_domain, src, eval_buffer, mesh_attributes);
956 iter.
name, dst_domain, type);
976 {iter.domain, iter.data_type},
987 iter.
name, dst_domain, type);
1013 curves.offsets_for_write().last() = 1;
Low-level operations for curves.
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_free_layer_named(CustomData *data, blender::StringRef name)
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 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
constexpr bool contains(const T &value) const
std::optional< T > get_if_single() 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
bool contains(StringRef attribute_id) const
GAttributeReader lookup(const StringRef attribute_id) const
int domain_size(const AttrDomain domain) const
std::optional< AttributeMetaData > lookup_meta_data(StringRef attribute_id) const
GAttributeReader get() const
VArray< int8_t > handle_types_left() const
OffsetIndices< int > points_by_curve() const
VArray< int8_t > handle_types_right() const
void ensure_can_interpolate_to_evaluated() const
Span< float3 > evaluated_tangents() const
Span< int > bezier_evaluated_offsets_for_curve(int curve_index) const
Span< float3 > evaluated_normals() const
OffsetIndices< int > evaluated_points_by_curve() const
bool has_curve_with_type(CurveType type) const
AttributeAccessor attributes() const
Span< float3 > evaluated_positions() const
VArray< int8_t > curve_types() const
bool add(const StringRef attribute_id, const AttrDomain domain, const AttrType data_type, const AttributeInit &initializer)
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, AttrType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, AttrType data_type)
IndexRange index_range() const
static float normals[][3]
VecBase< float, 3 > float3
void copy(const GVArray &src, GMutableSpan dst, int64_t grain_size=4096)
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
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 bool has_caps(const bool main_cyclic, const bool profile_cyclic, const int profile_segment_num)
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)
static CurvesGeometry get_curve_single_vert()
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 > scales, MutableSpan< float3 > mesh_positions)
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 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_mesh_sweep(const CurvesGeometry &main, const CurvesGeometry &profile, const VArray< float > &scales, bool fill_caps, const bke::AttributeFilter &attribute_filter={})
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 void build_mesh_positions(const CurvesInfo &curves_info, const ResultOffsets &offsets, const VArray< float > &scales, Vector< std::byte > &eval_buffer, Mesh &mesh)
AttrType cpp_type_to_attribute_type(const CPPType &type)
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 parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
void devirtualize_varray(const VArray< T > &varray, const Func &func, bool enable=true)
MatBase< float, 4, 4 > float4x4
VecBase< int32_t, 2 > int2
VecBase< float, 3 > float3
static void init(bNodeTree *, bNode *node)
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