44#define INVALID_CORNER_EDGE_MARKER 4294967295u
125 for (
int idx = 0; idx < max_idx; idx++) {
126 const int v1_i = sp1.
verts[idx];
127 const int v2_i = sp2.
verts[idx];
151#define PRINT_MSG(...) \
153 CLOG_INFO(&LOG, 1, __VA_ARGS__); \
157#define PRINT_ERR(...) \
161 CLOG_ERROR(&LOG, __VA_ARGS__); \
167 float (*vert_positions)[3],
172 uint legacy_faces_num,
173 const int *corner_verts,
176 const int *face_offsets,
179 const bool do_verbose,
185#define REMOVE_EDGE_TAG(_me) \
188 free_flag.edges = do_fixes; \
191#define IS_REMOVED_EDGE(_me) (_me[0] == _me[1])
193#define REMOVE_CORNER_TAG(corner) \
195 corner_edges[corner] = INVALID_CORNER_EDGE_MARKER; \
196 free_flag.face_corners = do_fixes; \
202 mesh->attributes_for_write().lookup_for_write<
int>(
"material_index");
213 int verts_weight : 1;
214 int corners_edge : 1;
224 int face_corners : 1;
237 Map<OrderedEdge, int> edge_hash;
238 edge_hash.reserve(edges_num);
242 fix_flag.as_flag = 0;
243 free_flag.as_flag = 0;
244 recalc_flag.as_flag = 0;
246 PRINT_MSG(
"verts(%u), edges(%u), corners(%u), faces(%u)",
252 if (edges_num == 0 && faces_num != 0) {
253 PRINT_ERR(
"\tLogical error, %u faces and 0 edges", faces_num);
254 recalc_flag.edges = do_fixes;
257 for (i = 0; i < verts_num; i++) {
258 for (j = 0; j < 3; j++) {
259 if (!isfinite(vert_positions[i][j])) {
260 PRINT_ERR(
"\tVertex %u: has invalid coordinate", i);
265 fix_flag.verts =
true;
271 for (i = 0; i < edges_num; i++) {
275 if (edge[0] == edge[1]) {
276 PRINT_ERR(
"\tEdge %u: has matching verts, both %d", i, edge[0]);
279 if (edge[0] >= verts_num) {
280 PRINT_ERR(
"\tEdge %u: v1 index out of range, %d", i, edge[0]);
283 if (edge[1] >= verts_num) {
284 PRINT_ERR(
"\tEdge %u: v2 index out of range, %d", i, edge[1]);
288 if ((edge[0] != edge[1]) && edge_hash.contains(edge)) {
289 PRINT_ERR(
"\tEdge %u: is a duplicate of %d", i, edge_hash.lookup(edge));
293 if (remove ==
false) {
294 if (edge[0] != edge[1]) {
295 edge_hash.add(edge, i);
303 if (legacy_faces && !face_offsets) {
304#define REMOVE_FACE_TAG(_mf) \
307 free_flag.faces = do_fixes; \
310#define CHECK_FACE_VERT_INDEX(a, b) \
311 if (mf->a == mf->b) { \
312 PRINT_ERR(" face %u: verts invalid, " STRINGIFY(a) "/" STRINGIFY(b) " both %u", i, mf->a); \
316#define CHECK_FACE_EDGE(a, b) \
317 if (!edge_hash.contains({mf->a, mf->b})) { \
318 PRINT_ERR(" face %u: edge " STRINGIFY(a) "/" STRINGIFY(b) " (%u,%u) is missing edge data", \
322 recalc_flag.edges = do_fixes; \
327 const MFace *mf_prev;
332 uint totsortface = 0;
334 PRINT_ERR(
"No faces, only tessellated Faces");
336 for (i = 0, mf = legacy_faces, sf = sort_faces.
data(); i < legacy_faces_num; i++, mf++) {
341 fidx = mf->
v4 ? 3 : 2;
343 fv[fidx] = *(&(mf->
v1) + fidx);
344 if (fv[fidx] >= verts_num) {
345 PRINT_ERR(
"\tFace %u: 'v%d' index out of range, %u", i, fidx + 1, fv[fidx]);
350 if (remove ==
false) {
368 if (remove ==
false) {
388 return a.edval < b.edval;
394 return a.edval < b.edval;
410 sf = sort_faces.
data();
414 for (i = 1; i < totsortface; i++, sf++) {
418 if (memcmp(sf->
es, sf_prev->
es,
sizeof(sf_prev->
es)) == 0) {
419 mf = legacy_faces + sf->
index;
422 mf_prev = legacy_faces + sf_prev->
index;
425 PRINT_ERR(
"\tFace %u & %u: are duplicates (%u,%u,%u,%u) (%u,%u,%u,%u)",
438 PRINT_ERR(
"\tFace %u & %u: are duplicates (%u,%u,%u) (%u,%u,%u)",
461#undef REMOVE_FACE_TAG
462#undef CHECK_FACE_VERT_INDEX
463#undef CHECK_FACE_EDGE
481 BitVector<> vert_tag(mesh->verts_num);
483 Array<int> sort_face_verts(faces_num == 0 ? 0 : face_offsets[faces_num]);
484 int64_t sort_face_verts_offset = 0;
488 const int face_start = face_offsets[i];
489 const int face_size = face_offsets[i + 1] - face_start;
495 if (material_indices && material_indices_span[i] < 0) {
496 PRINT_ERR(
"\tFace %u has invalid material (%d)", sp->
index, material_indices_span[i]);
498 material_indices_span[i] = 0;
502 if (face_start < 0 || face_size < 3) {
504 PRINT_ERR(
"\tFace %u is invalid (corner_start: %d, corners_num: %d)",
510 else if (face_start + face_size > corners_num) {
513 "\tFace %u uses corners out of range "
514 "(corner_start: %d, corner_end: %d, max number of corners: %u)",
517 face_start + face_size - 1,
525 sp->
verts =
v = sort_face_verts.
data() + sort_face_verts_offset;
526 sort_face_verts_offset += face_size;
533 for (j = 0; j < face_size; j++) {
535 if (vert < verts_num) {
536 vert_tag[vert].reset();
541 for (j = 0; j < face_size; j++,
v++) {
543 if (vert >= verts_num) {
548 else if (vert_tag[vert].test()) {
549 PRINT_ERR(
"\tFace %u has duplicated vert reference at corner (%u)",
uint(i), j);
553 vert_tag[vert].set();
564 for (j = 0; j < face_size; j++) {
566 const int vert = corner_verts[corner];
567 const int edge_i = corner_edges[corner];
570 if (!edge_hash.contains({v1, v2})) {
574 recalc_flag.edges =
true;
580 else if (edge_i >= edges_num) {
585 corner_edges[corner] = edge_hash.lookup({v1,
v2});
586 fix_flag.corners_edge =
true;
587 PRINT_ERR(
"\tCorner %d has invalid edge reference (%d), fixed using edge %d",
590 corner_edges[corner]);
593 PRINT_ERR(
"\tCorner %d has invalid edge reference (%d)", corner, edge_i);
600 !((edge[0] == v1 && edge[1] ==
v2) || (edge[0] ==
v2 && edge[1] == v1)))
607 corner_edges[corner] = edge_hash.lookup({v1,
v2});
608 fix_flag.corners_edge =
true;
610 "\tFace %u has invalid edge reference (%d, is_removed: %d), fixed using edge "
615 corner_edges[corner]);
618 PRINT_ERR(
"\tFace %u has invalid edge reference (%d)", sp->
index, edge_i);
634 vert_tag.clear_and_shrink();
639 sp = prev_sp = sort_faces.
data();
642 for (i = 1; i < faces_num; i++, sp++) {
644 const int *p1_v = sp->
verts, *p2_v = prev_sp->
verts;
652 if ((p1_nv == p2_nv) && (memcmp(p1_v, p2_v, p1_nv *
sizeof(*p1_v)) == 0)) {
656 for (j = 1; j < p1_nv; j++) {
673 sp = sort_faces.
data();
676 for (i = 0; i < faces_num; i++, sp++) {
684 faces_to_remove[sp->
index].set();
685 free_flag.face_corners = do_fixes;
696 if (prev_end < sp->corner_start) {
698 for (j = prev_end, corner = prev_end; j < sp->
corner_start; j++, corner++) {
710 "\tFaces %u and %u share corners from %d to %d, considering face %u as invalid.",
717 faces_to_remove[sp->
index].set();
718 free_flag.face_corners = do_fixes;
732 if (prev_end < corners_num) {
734 for (j = prev_end, corner = prev_end; j < corners_num; j++, corner++) {
746 for (i = 0, dv = dverts; i < verts_num; i++, dv++) {
749 for (j = 0, dw = dv->
dw; j < dv->
totweight; j++, dw++) {
751 if (!isfinite(dw->
weight)) {
755 fix_flag.verts_weight =
true;
762 fix_flag.verts_weight =
true;
768 if (dw->
def_nr >= INT_MAX) {
772 fix_flag.verts_weight =
true;
789#undef REMOVE_EDGE_TAG
790#undef IS_REMOVED_EDGE
791#undef REMOVE_CORNER_TAG
792#undef REMOVE_FACE_TAG
795 if (free_flag.faces) {
799 if (free_flag.face_corners) {
803 if (free_flag.edges) {
807 if (recalc_flag.edges) {
808 mesh_calc_edges(*mesh,
true,
false);
812 if (mesh && mesh->mselect) {
815 for (i = 0, msel = mesh->mselect; i < mesh->totselect; i++, msel++) {
818 if (msel->
index < 0) {
820 "\tMesh select element %u type %d index is negative, "
821 "resetting selection stack.\n",
824 free_flag.mselect = do_fixes;
828 switch (msel->
type) {
830 tot_elem = mesh->verts_num;
833 tot_elem = mesh->edges_num;
836 tot_elem = mesh->faces_num;
840 if (msel->
index > tot_elem) {
842 "\tMesh select element %u type %d index %d is larger than data array size %d, "
843 "resetting selection stack.\n",
849 free_flag.mselect = do_fixes;
854 if (free_flag.mselect) {
856 mesh->mselect =
nullptr;
861 material_indices_span.save();
862 material_indices.
finish();
866 *r_changed = (fix_flag.as_flag || free_flag.as_flag || recalc_flag.as_flag);
868 BLI_assert((*r_changed ==
false) || (do_fixes ==
true));
874 eCustomDataMask mask,
876 const bool do_verbose,
881 bool has_fixes =
false;
884 PRINT_MSG(
"%s: Checking %d CD layers...\n", __func__, data->totlayer);
888 int layer_num_type = -1;
890 while (i < data->totlayer) {
896 if (layer_num_type != type) {
898 layer_num_type = type;
902 int *active_index_array[] = {
905 &layer->active_clone,
908 for (
int *active_index :
Span(active_index_array,
ARRAY_SIZE(active_index_array))) {
909 if (*active_index < 0) {
910 PRINT_ERR(
"\tCustomDataLayer type %d has a negative active index (%d)\n",
919 if (*active_index >= layer_num) {
920 PRINT_ERR(
"\tCustomDataLayer type %d has an out of bounds active index (%d >= %d)\n",
926 *active_index = layer_num - 1;
935 PRINT_ERR(
"\tCustomDataLayer type %d is a singleton, found %d in Mesh structure\n",
944 if ((layer_typemask & mask) == 0) {
945 PRINT_ERR(
"\tCustomDataLayer type %d which isn't in the mask\n", type);
959 PRINT_ERR(
"\tCustomDataLayer type %d has some invalid data\n", type);
960 has_fixes = do_fixes;
966 PRINT_MSG(
"%s: Finished (is_valid=%d)\n\n", __func__,
int(!has_fixes));
968 *r_change = has_fixes;
974 const uint verts_num,
976 const uint edges_num,
978 const uint corners_num,
980 const uint faces_num,
981 const bool check_meshmask,
982 const bool do_verbose,
987 bool is_change_v, is_change_e, is_change_l, is_change_p;
989 if (check_meshmask) {
994 vert_data, mask.vmask, verts_num, do_verbose, do_fixes, &is_change_v);
996 edge_data, mask.emask, edges_num, do_verbose, do_fixes, &is_change_e);
998 corner_data, mask.lmask, corners_num, do_verbose, do_fixes, &is_change_l);
1000 face_data, mask.pmask, faces_num, do_verbose, do_fixes, &is_change_p);
1005 "\tMore UV layers than %d allowed, %d last ones won't be available for render, shaders, "
1021 *r_change = (is_change_v || is_change_e || is_change_l || is_change_p);
1048 Span<int> face_offsets = mesh->face_offsets();
1049 Span<int> corner_verts = mesh->corner_verts();
1056 reinterpret_cast<float(*)[3]
>(positions.data()),
1061 mesh->totface_legacy,
1062 corner_verts.
data(),
1063 corner_edges.
data(),
1064 corner_verts.
size(),
1065 face_offsets.
data(),
1083 const bool do_verbose =
true;
1084 const bool do_fixes =
false;
1087 bool changed =
true;
1105 Span<int> face_offsets = mesh->face_offsets();
1106 Span<int> corner_verts = mesh->corner_verts();
1113 reinterpret_cast<float(*)[3]
>(positions.data()),
1118 mesh->totface_legacy,
1119 corner_verts.
data(),
1120 corner_edges.
data(),
1121 corner_verts.
size(),
1122 face_offsets.
data(),
1136 const int mat_nr_max =
max_ii(0, mesh->totcol - 1);
1140 mesh->attributes_for_write().lookup_for_write<
int>(
"material_index");
1142 for (
const int i : material_indices_span.index_range()) {
1143 if (material_indices_span[i] < 0 || material_indices_span[i] > mat_nr_max) {
1144 material_indices_span[i] = 0;
1148 material_indices_span.save();
1149 material_indices.
finish();
1172 int *new_idx = (
int *)
MEM_mallocN(
sizeof(
int) * mesh->corners_num, __func__);
1174 for (a =
b = 0; a < mesh->faces_num; a++) {
1175 bool invalid =
false;
1176 int start = face_offsets[a];
1177 int size = face_offsets[a + 1] - start;
1178 int stop = start +
size;
1180 if (faces_to_remove[a]) {
1183 else if (stop > mesh->corners_num || stop < start || size < 0) {
1193 if (size >= 3 && !invalid) {
1195 face_offsets[
b] = face_offsets[a];
1203 mesh->faces_num =
b;
1208 for (a =
b = 0; a < mesh->corners_num; a++, corner++) {
1224 mesh->corners_num =
b;
1227 face_offsets[mesh->faces_num] = mesh->corners_num;
1232 face_offsets[i] = new_idx[face_offsets[i]];
1246 for (a =
b = 0,
e = edges.data(); a < mesh->edges_num; a++,
e++) {
1247 if ((*
e)[0] != (*e)[1]) {
1249 memcpy(&edges[
b],
e,
sizeof(edges[
b]));
1261 mesh->edges_num =
b;
1269 corner_edges[i] = new_idx[corner_edges[i]];
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_clone_layer(const CustomData *data, eCustomDataType type)
int CustomData_get_stencil_layer(const CustomData *data, eCustomDataType type)
bool CustomData_free_layer(CustomData *data, eCustomDataType type, int totelem, int index)
void CustomData_set_layer_clone(CustomData *data, eCustomDataType type, int n)
bool CustomData_layer_validate(CustomDataLayer *layer, uint totitems, bool do_fixes)
void * CustomData_get_layer_for_write(CustomData *data, eCustomDataType type, int totelem)
void CustomData_free_elem(CustomData *data, int index, int count)
void CustomData_copy_data(const CustomData *source, CustomData *dest, int source_index, int dest_index, int count)
bool CustomData_layertype_is_singleton(eCustomDataType type)
int CustomData_number_of_layers(const CustomData *data, eCustomDataType type)
#define CD_TYPE_AS_MASK(_type)
const CustomData_MeshMasks CD_MASK_MESH
void CustomData_set_layer_stencil(CustomData *data, eCustomDataType type, int n)
void BKE_mesh_strip_loose_faces(Mesh *mesh)
void BKE_mesh_runtime_clear_cache(Mesh *mesh)
MINLINE int max_ii(int a, int b)
MINLINE void zero_v3(float r[3])
#define CLOG_INFO(clg_ref, level,...)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY_ALL_MODES
Object is a sort of wrapper for general info.
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
constexpr T * data() const
constexpr Span< T > as_span() const
constexpr IndexRange index_range() const
constexpr const T * data() const
constexpr int64_t size() const
local_group_size(16, 16) .push_constant(Type b
void *(* MEM_mallocN)(size_t len, const char *str)
void MEM_freeN(void *vmemh)
#define CHECK_FACE_EDGE(a, b)
static bool mesh_validate_customdata(CustomData *data, eCustomDataMask mask, const uint totitems, const bool do_verbose, const bool do_fixes, bool *r_change)
static bool search_face_cmp(const SortFace &sp1, const SortFace &sp2)
void mesh_strip_edges(Mesh *mesh)
#define IS_REMOVED_EDGE(_me)
bool BKE_mesh_validate_all_customdata(CustomData *vert_data, const uint verts_num, CustomData *edge_data, const uint edges_num, CustomData *corner_data, const uint corners_num, CustomData *face_data, const uint faces_num, const bool check_meshmask, const bool do_verbose, const bool do_fixes, bool *r_change)
bool BKE_mesh_validate_material_indices(Mesh *mesh)
static void edge_store_from_mface_tri(EdgeUUID es[4], const MFace *mf)
static void edge_store_from_mface_quad(EdgeUUID es[4], const MFace *mf)
static bool search_face_corner_cmp(const SortFace &sp1, const SortFace &sp2)
void strip_loose_faces_corners(Mesh *mesh, blender::BitSpan faces_to_remove)
static bool search_legacy_face_cmp(const SortFaceLegacy &sfa, const SortFaceLegacy &sfb)
static void edge_store_assign(uint32_t verts[2], const uint32_t v1, const uint32_t v2)
#define CHECK_FACE_VERT_INDEX(a, b)
bool BKE_mesh_validate_arrays(Mesh *mesh, float(*vert_positions)[3], uint verts_num, blender::int2 *edges, uint edges_num, MFace *legacy_faces, uint legacy_faces_num, const int *corner_verts, int *corner_edges, uint corners_num, const int *face_offsets, uint faces_num, MDeformVert *dverts, const bool do_verbose, const bool do_fixes, bool *r_changed)
#define REMOVE_FACE_TAG(_mf)
#define REMOVE_CORNER_TAG(corner)
#define REMOVE_EDGE_TAG(_me)
bool BKE_mesh_is_valid(Mesh *mesh)
#define INVALID_CORNER_EDGE_MARKER
bool BKE_mesh_validate(Mesh *mesh, const bool do_verbose, const bool cddata_check_mask)
void parallel_sort(RandomAccessIterator begin, RandomAccessIterator end)
VMutableArray< T > varray