33 for (
const int i :
indices.index_range()) {
63 if (src_mesh.
runtime->face_normals_cache.is_cached()) {
64 return src_mesh.face_normals();
66 if (selection_size > src_mesh.
faces_num / 4) {
67 return src_mesh.face_normals();
74 const auto &src_cache = src.
runtime->loose_verts_cache;
75 if (src_cache.is_cached() && src_cache.data().count == 0) {
76 dst.tag_loose_verts_none();
82 const auto &src_cache = src.
runtime->loose_edges_cache;
83 if (src_cache.is_cached() && src_cache.data().count == 0) {
84 dst.tag_loose_edges_none();
95 src_faces, unselected, new_tri_offsets.
last(), offsets.
take_back(unselected.
size() + 1));
125 if (
UNLIKELY(flip_flag & (1 << 0))) {
128 if (
UNLIKELY(flip_flag & (1 << 1))) {
188 switch (directions[
i]) {
196 const int src_face_start = face_offsets[
i];
197 for (
int &
i : quad_map) {
218 data.directions.reinitialize(quads.
size());
237 const int quads_num = quad_corner_verts.
size() / 6;
247 const int edges_start,
253 corner_edges[3 * tri + 0] = edges_start + tri / 2;
254 corner_edges[3 * tri + 1] = src_corner_edges[corner_tris[tri][1]];
255 corner_edges[3 * tri + 2] = src_corner_edges[corner_tris[tri][2]];
262 const int edges_start,
266 const int quads_num = corner_tris.
size() / 2;
272 corner_tris.
slice(tris_range),
273 edges_start + quads.
start(),
274 quad_corner_edges.
slice(corners));
282 dst[2 * dst_i + 0] = src[src_i];
283 dst[2 * dst_i + 1] = src[src_i];
290 using T = decltype(dummy);
291 copy_quad_data_to_tris(src.typed<T>(), quads, dst.typed<T>());
303 dst_offsets[
i] = offset;
304 offset += src_offsets[selection[
i]].
size();
306 dst_offsets.
last() = offset;
328 edge_offset_data[
mask] = src_faces[face].
size() - 3;
349 Heap *heap =
nullptr;
368 data.offset_data.reinitialize(ngons.
size() + 1);
370 src_faces, ngons,
data.offset_data);
373 data.projections.reinitialize(ngons.
size());
390 data.projected_positions.reinitialize(local_corner_offsets.
total_size());
420 reinterpret_cast<uint(*)[3]
>(map.
data()));
424 reinterpret_cast<uint(*)[3]
>(map.
data()),
435 const int src_face_start = src_faces[ngons[
i]].start();
437 for (
int &vert : map) {
438 vert += src_face_start;
448 const int edges_start,
453 auto add_edge = [&](
const OrderedEdge corner_edge) ->
int {
454 if (corner_edge == last_edge) {
455 return src_corner_edges[src_face.
last()];
457 if (corner_edge.v_high == corner_edge.v_low + 1) {
458 return src_corner_edges[corner_edge.v_low];
460 const OrderedEdge vert_edge(src_corner_verts[corner_edge.v_low],
461 src_corner_verts[corner_edge.v_high]);
462 return edges_start +
deduplication.index_of_or_add(vert_edge);
466 const int3 tri = corner_tris[
i];
467 corner_edges[3 *
i + 0] = add_edge({tri[0], tri[1]});
468 corner_edges[3 *
i + 1] = add_edge({tri[1], tri[2]});
469 corner_edges[3 *
i + 2] = add_edge({tri[2], tri[0]});
496 corner_tris.
slice(tris_range),
497 ngon_edges_range[edges.
start()],
498 corner_edges.
slice(corners),
522 for (const int tri : range) {
523 for (const int vert : {vert_tris[tri][0], vert_tris[tri][1], vert_tris[tri][2]}) {
524 const int index_in_group = atomic_fetch_and_add_int32(&counts[vert], 1);
525 r_indices[offsets[vert][index_in_group]] = tri;
530 return {r_offsets.as_span(), r_indices.as_span()};
546 if (mesh.no_overlapping_topology()) {
562 return universe_segment.
offset();
566 for (
const int16_t
i : universe_segment.
base_span()) {
567 const int face = int(universe_segment.
offset() +
i);
568 if (src_faces[face].
size() == 3) {
572 return universe_segment.
offset();
586 mesh.
verts_num, vert_tris, vert_to_tri_offsets, vert_to_tri_indices);
588 auto tri_exists = [&](
const std::array<int, 3> &tri_verts) {
591 return std::any_of(tri_verts.begin(), tri_verts.end(), [&](
const int vert) {
592 return std::any_of(vert_to_tri[vert].begin(), vert_to_tri[vert].end(), [&](const int tri) {
593 const Set<int, 3> other_tri_verts(Span(&vert_tris[tri].x, 3));
594 return other_tri_verts == vert_set;
600 unselected_tris,
GrainSize(1024), memory, [&](
const int i) {
602 return tri_exists({face_verts[0], face_verts[1], face_verts[2]});
613 for (
const int src_edge : vert_to_edge_map[vert]) {
634 if (src_mesh.no_overlapping_topology()) {
641 src_edges, src_mesh.
verts_num, vert_to_edge_offsets, vert_to_edge_indices);
646 for (const int i : range) {
647 duplicate_remap[i] = find_edge_duplicate(vert_to_edge, src_edges, new_edges[i]).value_or(-1);
652 new_edges.index_range(),
GrainSize(4096), memory, [&](
const int i) {
653 return duplicate_remap[
i] == -1;
655 if (non_duplicate_new_edges.
size() == new_edges.size()) {
661 duplicate_remap[index] =
pos + new_edges_range.start();
663 threading::parallel_for(corner_edges.index_range(), 4096, [&](
const IndexRange range) {
664 for (const int corner : range) {
665 const int edge = corner_edges[corner];
666 if (edge < new_edges_range.start()) {
669 const int remap_index = edge - new_edges_range.start();
670 corner_edges[corner] = duplicate_remap[remap_index];
675 array_utils::gather(edges_with_duplicates.
as_span(),
676 non_duplicate_new_edges,
677 edges.slice(new_edges_range.start(), non_duplicate_new_edges.
size()));
678 return src_edges.size() + non_duplicate_new_edges.
size();
689 const Span<float3> positions = src_mesh.vert_positions();
690 const Span<int2> src_edges = src_mesh.edges();
692 const Span<int> src_corner_verts = src_mesh.corner_verts();
693 const Span<int> src_corner_edges = src_mesh.corner_edges();
701 selection_with_tris,
GrainSize(4096), memory, [&](
const int i) {
702 return src_faces[
i].
size() == 4;
705 selection_with_tris,
GrainSize(4096), memory, [&](
const int i) {
706 return src_faces[
i].
size() > 4;
708 if (quads.
is_empty() && ngons.is_empty()) {
717 Array<int> tris_by_ngon_data(ngons.size() + 1);
719 const int ngon_tris_num = tris_by_ngon.
total_size();
720 const int quad_tris_num = quads.
size() * 2;
721 const IndexRange tris_range(ngon_tris_num + quad_tris_num);
725 const int ngon_corners_num = tris_by_ngon.
total_size() * 3;
726 const int quad_corners_num = quads.
size() * 6;
727 const IndexRange tri_corners_range(quad_corners_num + ngon_corners_num);
733 Array<int> edge_offset_data(ngons.size() + 1);
735 const int ngon_edges_num = edges_by_ngon.
total_size();
736 const int quad_edges_num = quads.
size();
739 ngon_edges_num + quad_edges_num);
749 if (!ngons.is_empty()) {
769 src_mesh, src_faces, src_corner_verts, selection, corner_tris, memory);
779 src_edges.
size() + tri_edges_range.
size(),
780 tris_range.
size() + unselected.
size(),
787 src_faces, unselected, mesh->face_offsets_for_write());
801 src_corner_verts, corner_tris.
as_span().cast<
int>(), corner_verts.
slice(tri_corners_range));
803 if (!ngons.is_empty()) {
812 edges_with_duplicates,
813 corner_edges.
slice(ngon_corners_range));
819 corner_verts.
slice(quad_corners_range),
820 quad_edges_range.
start(),
821 edges_with_duplicates.slice(quad_edges_range),
822 corner_edges.
slice(quad_corners_range));
826 src_mesh, src_edges, tri_edges_range, edges_with_duplicates, corner_edges);
828 edges_with_duplicates.take_front(src_edges.
size()).copy_from(src_edges);
840 attribute.dst.span.slice(src_edges_range).copy_from(attribute.src);
846 attribute.dst.finish();
863 tris_by_ngon, ngons, attribute.src, attribute.dst.span.
slice(ngon_tris_range));
866 attribute.dst.finish();
881 src_faces, faces_unselected, unselected, src_corner_verts, corner_verts);
883 src_faces, faces_unselected, unselected, src_corner_edges, corner_edges);
889 {
".corner_vert",
".corner_edge"})))
892 src_faces, faces_unselected, unselected, attribute.src, attribute.dst.span);
894 corner_tris.
as_span().cast<
int>(),
895 attribute.dst.span.slice(tri_corners_range));
896 attribute.dst.finish();
902 if (src_mesh.no_overlapping_topology()) {
903 mesh->tag_overlapping_none();
@ ATTR_DOMAIN_MASK_CORNER
CustomData interface, see also DNA_customdata_types.h.
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
bool CustomData_merge(const CustomData *source, CustomData *dest, eCustomDataMask mask, int totelem)
bool CustomData_has_layer(const CustomData *data, eCustomDataType type)
void * CustomData_add_layer(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem)
const CustomData_MeshMasks CD_MASK_MESH
void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src)
bool BKE_mesh_is_valid(Mesh *mesh)
A min-heap / priority queue ADT.
void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1)
Heap * BLI_heap_new_ex(unsigned int reserve_num) ATTR_WARN_UNUSED_RESULT
int is_quad_flip_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
void axis_dominant_v3_to_m3_negate(float r_mat[3][3], const float normal[3])
void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3])
MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
void BLI_memarena_free(MemArena *ma) ATTR_NONNULL(1)
void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1)
#define BLI_SCOPED_DEFER(function_to_defer)
#define BLI_POLYFILL_ARENA_SIZE
void BLI_polyfill_calc(const float(*coords)[2], unsigned int coords_num, int coords_sign, unsigned int(*r_tris)[3])
#define BLI_POLYFILL_ALLOC_NGON_RESERVE
void BLI_polyfill_beautify(const float(*coords)[2], unsigned int coords_num, unsigned int(*tris)[3], struct MemArena *arena, struct Heap *eheap)
float BLI_polyfill_edge_calc_rotate_beauty__area(const float v1[3], const float v2[3], const float v3[3], const float v4[3], bool lock_degenerate)
Provides wrapper around system-specific atomic primitives, and some extensions (faked-atomic operatio...
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v2
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Span< T > as_span() const
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
static IndexMask from_union(const IndexMask &mask_a, const IndexMask &mask_b, IndexMaskMemory &memory)
Span< T > as_span() const
MutableSpan< T > as_mutable_span()
void reinitialize(const int64_t new_size)
void fill_construct_n(const void *value, void *dst, int64_t n) const
const void * default_value() const
const CPPType & type() const
GMutableSpan drop_front(const int64_t n) const
const CPPType & type() const
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
static IndexMask from_batch_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, FunctionRef< int64_t(const IndexMaskSegment &universe_segment, IndexRangesBuilder< int16_t > &builder)> batch_predicate)
static IndexMask from_difference(const IndexMask &mask_a, const IndexMask &mask_b, IndexMaskMemory &memory)
constexpr int64_t first() const
constexpr int64_t one_after_last() const
constexpr IndexRange shift(int64_t n) const
constexpr int64_t last(const int64_t n=0) const
constexpr int64_t size() const
constexpr int64_t start() const
constexpr IndexRange take_back(int64_t n) const
constexpr IndexRange take_front(int64_t n) const
bool add_range(const T start, const T end)
constexpr int64_t size() const
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
constexpr MutableSpan< NewT > cast() const
constexpr MutableSpan take_back(const int64_t n) const
constexpr T * data() const
constexpr MutableSpan drop_back(const int64_t n) const
constexpr void fill(const T &value) const
constexpr MutableSpan drop_front(const int64_t n) const
constexpr T & first() const
constexpr void copy_from(Span< T > values) const
constexpr T & last(const int64_t n=0) const
IndexRange index_range() const
Span< BaseT > base_span() const
constexpr Span drop_front(int64_t n) const
Span< NewT > constexpr cast() const
constexpr Span slice(int64_t start, int64_t size) const
constexpr const T * data() const
constexpr int64_t size() const
constexpr IndexRange index_range() const
constexpr bool is_empty() const
void reinitialize(const int64_t new_size)
Span< T > as_span() const
bool add(const StringRef attribute_id, const AttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer)
void foreach_index_optimized(Fn &&fn) const
IndexMask slice(IndexRange range) const
IndexRange index_range() const
IndexMask complement(const IndexMask &universe, IndexMaskMemory &memory) const
void foreach_index(Fn &&fn) const
void foreach_segment(Fn &&fn) const
IndexRange index_range() const
OffsetIndices slice(const IndexRange range) const
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
void MEM_freeN(void *vmemh)
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static void copy_loose_edge_hint(const Mesh &src, Mesh &dst)
static void copy_loose_vert_hint(const Mesh &src, Mesh &dst)
void copy(const GVArray &src, GMutableSpan dst, int64_t grain_size=4096)
void gather_group_to_group(const OffsetIndices< int > src_offsets, const OffsetIndices< int > dst_offsets, const IndexMask &selection, const Span< T > src, MutableSpan< T > dst)
void gather(const GVArray &src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size=4096)
void gather(GSpan src, Span< int > map, GMutableSpan dst)
void gather_to_groups(OffsetIndices< int > dst_offsets, const IndexMask &src_selection, GSpan src, GMutableSpan dst)
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
void gather_group_to_group(OffsetIndices< int > src_offsets, OffsetIndices< int > dst_offsets, const IndexMask &selection, GSpan src, GMutableSpan dst)
float3 face_normal_calc(Span< float3 > vert_positions, Span< int > face_verts)
int face_triangles_num(const int face_size)
GroupedSpan< int > build_vert_to_edge_map(Span< int2 > edges, int verts_num, Array< int > &r_offsets, Array< int > &r_indices)
Vector< AttributeTransferData > retrieve_attributes_for_transfer(const AttributeAccessor src_attributes, MutableAttributeAccessor dst_attributes, AttrDomainMask domain_mask, const AttributeFilter &attribute_filter={})
auto attribute_filter_with_skip_ref(AttributeFilter filter, const Span< StringRef > skip)
Mesh * mesh_new_no_attributes(int verts_num, int edges_num, int faces_num, int corners_num)
static IndexMask calc_unselected_faces(const Mesh &mesh, const OffsetIndices< int > src_faces, const Span< int > src_corner_verts, const IndexMask &selection, const Span< int3 > corner_tris, IndexMaskMemory &memory)
static std::optional< int > find_edge_duplicate(const GroupedSpan< int > vert_to_edge_map, const Span< int2 > edges, const OrderedEdge edge)
static int calc_new_edges(const Mesh &src_mesh, const Span< int2 > src_edges, const IndexRange new_edges_range, MutableSpan< int2 > edges, MutableSpan< int > corner_edges)
static GroupedSpan< int > build_vert_to_tri_map(const int verts_num, const Span< int3 > vert_tris, Array< int > &r_offsets, Array< int > &r_indices)
static void calc_corner_tris(const Span< float3 > positions, const OffsetIndices< int > src_faces, const Span< int > src_corner_verts, const Span< float3 > face_normals, const IndexMask &ngons, const OffsetIndices< int > tris_by_ngon, const TriangulateNGonMode ngon_mode, MutableSpan< int3 > corner_tris)
static void calc_inner_tri_edges(const IndexRange src_face, const Span< int > src_corner_verts, const Span< int > src_corner_edges, const Span< int3 > corner_tris, const int edges_start, MutableSpan< int > corner_edges, VectorSet< OrderedEdge > &deduplication)
static void calc_edges(const OffsetIndices< int > src_faces, const Span< int > src_corner_verts, const Span< int > src_corner_edges, const IndexMask &ngons, const OffsetIndices< int > tris_by_ngon, const OffsetIndices< int > edges_by_ngon, const IndexRange ngon_edges_range, const Span< int3 > corner_tris, MutableSpan< int2 > edges, MutableSpan< int > corner_edges)
static OffsetIndices< int > calc_edges_by_ngon(const OffsetIndices< int > src_faces, const IndexMask &selection, MutableSpan< int > edge_offset_data)
static OffsetIndices< int > calc_tris_by_ngon(const OffsetIndices< int > src_faces, const IndexMask &ngons, MutableSpan< int > face_offset_data)
static void copy_quad_data_to_tris(const Span< T > src, const IndexMask &quads, MutableSpan< T > dst)
static void calc_corner_tris(const Span< int > face_offsets, const Span< QuadDirection > directions, MutableSpan< int3 > corner_tris)
static void calc_edges(const Span< int > quad_corner_verts, MutableSpan< int2 > new_quad_edges)
static void calc_quad_directions(const Span< float3 > positions, const Span< int > face_offsets, const Span< int > corner_verts, const TriangulateQuadMode quad_mode, MutableSpan< QuadDirection > directions)
static void calc_quad_corner_edges(const Span< int > src_corner_edges, const Span< int3 > corner_tris, const int edges_start, MutableSpan< int > corner_edges)
static QuadDirection calc_quad_direction_beauty(const float3 &v0, const float3 &v1, const float3 &v2, const float3 &v3)
std::optional< Mesh * > mesh_triangulate(const Mesh &src_mesh, const IndexMask &selection, TriangulateNGonMode ngon_mode, TriangulateQuadMode quad_mode, const bke::AttributeFilter &attribute_filter)
static void copy_loose_edge_hint(const Mesh &src, Mesh &dst)
static void gather(const Span< int > src, const Span< int16_t > indices, MutableSpan< int > dst)
static OffsetIndices< int > gather_selected_offsets(const OffsetIndices< int > src_offsets, const IndexMaskSegment selection, MutableSpan< int > dst_offsets)
static Span< float3 > face_normals_if_worthwhile(const Mesh &src_mesh, const int selection_size)
static Span< int > gather_or_reference(const Span< int > src, const Span< int16_t > indices, Vector< int > &dst)
static OffsetIndices< int > calc_face_offsets(const OffsetIndices< int > src_faces, const IndexMask &unselected, MutableSpan< int > offsets)
static void copy_loose_vert_hint(const Mesh &src, Mesh &dst)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
OffsetIndices< int > accumulate_counts_to_offsets(MutableSpan< int > counts_to_offsets, int start_offset=0)
void fill_constant_group_size(int size, int start_offset, MutableSpan< int > offsets)
void build_reverse_offsets(Span< int > indices, MutableSpan< int > offsets)
OffsetIndices< int > gather_selected_offsets(OffsetIndices< int > src_offsets, const IndexMask &selection, int start_offset, MutableSpan< int > dst_offsets)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
bool non_empty_is_range(const Span< T > indices)
IndexRange non_empty_as_range(const Span< T > indices)
VecBase< int32_t, 2 > int2
VecBase< int32_t, 3 > int3
MatBase< float, 3, 3 > float3x3
VecBase< float, 3 > float3
MeshRuntimeHandle * runtime
const c_style_mat & ptr() const