41#define INVALID_CORNER_EDGE_MARKER 4294967295u
122 for (
int idx = 0; idx < max_idx; idx++) {
123 const int v1_i = sp1.
verts[idx];
124 const int v2_i = sp2.
verts[idx];
148#define PRINT_MSG(...) \
150 CLOG_INFO(&LOG, __VA_ARGS__); \
154#define PRINT_ERR(...) \
158 CLOG_ERROR(&LOG, __VA_ARGS__); \
164 float (*vert_positions)[3],
169 uint legacy_faces_num,
170 const int *corner_verts,
173 const int *face_offsets,
176 const bool do_verbose,
182#define REMOVE_EDGE_TAG(_me) \
185 free_flag.edges = do_fixes; \
188#define IS_REMOVED_EDGE(_me) (_me[0] == _me[1])
190#define REMOVE_CORNER_TAG(corner) \
192 corner_edges[corner] = INVALID_CORNER_EDGE_MARKER; \
193 free_flag.face_corners = do_fixes; \
199 mesh->attributes_for_write().lookup_for_write<
int>(
"material_index");
205 bool is_valid =
true;
210 int verts_weight : 1;
211 int corners_edge : 1;
221 int face_corners : 1;
239 fix_flag.as_flag = 0;
240 free_flag.as_flag = 0;
241 recalc_flag.as_flag = 0;
243 PRINT_MSG(
"verts(%u), edges(%u), corners(%u), faces(%u)",
249 if (edges_num == 0 && faces_num != 0) {
250 PRINT_ERR(
"\tLogical error, %u faces and 0 edges", faces_num);
251 recalc_flag.edges = do_fixes;
254 for (
i = 0;
i < verts_num;
i++) {
255 for (j = 0; j < 3; j++) {
256 if (!isfinite(vert_positions[
i][j])) {
257 PRINT_ERR(
"\tVertex %u: has invalid coordinate",
i);
262 fix_flag.verts =
true;
268 for (
i = 0;
i < edges_num;
i++) {
272 if (edge[0] == edge[1]) {
273 PRINT_ERR(
"\tEdge %u: has matching verts, both %d",
i, edge[0]);
276 if (edge[0] >= verts_num) {
277 PRINT_ERR(
"\tEdge %u: v1 index out of range, %d",
i, edge[0]);
280 if (edge[1] >= verts_num) {
281 PRINT_ERR(
"\tEdge %u: v2 index out of range, %d",
i, edge[1]);
285 if ((edge[0] != edge[1]) && edge_hash.
contains(edge)) {
290 if (remove ==
false) {
291 if (edge[0] != edge[1]) {
292 edge_hash.
add(edge,
i);
300 if (legacy_faces && !face_offsets) {
301#define REMOVE_FACE_TAG(_mf) \
304 free_flag.faces = do_fixes; \
307#define CHECK_FACE_VERT_INDEX(a, b) \
308 if (mf->a == mf->b) { \
309 PRINT_ERR(" face %u: verts invalid, " STRINGIFY(a) "/" STRINGIFY(b) " both %u", i, mf->a); \
313#define CHECK_FACE_EDGE(a, b) \
314 if (!edge_hash.contains({mf->a, mf->b})) { \
315 PRINT_ERR(" face %u: edge " STRINGIFY(a) "/" STRINGIFY(b) " (%u,%u) is missing edge data", \
319 recalc_flag.edges = do_fixes; \
324 const MFace *mf_prev;
329 uint totsortface = 0;
331 PRINT_ERR(
"No faces, only tessellated Faces");
333 for (
i = 0, mf = legacy_faces, sf = sort_faces.
data();
i < legacy_faces_num;
i++, mf++) {
338 fidx = mf->
v4 ? 3 : 2;
340 fv[fidx] = *(&(mf->
v1) + fidx);
341 if (fv[fidx] >= verts_num) {
342 PRINT_ERR(
"\tFace %u: 'v%d' index out of range, %u",
i, fidx + 1, fv[fidx]);
347 if (remove ==
false) {
365 if (remove ==
false) {
385 return a.edval < b.edval;
391 return a.edval < b.edval;
407 sf = sort_faces.
data();
411 for (
i = 1;
i < totsortface;
i++, sf++) {
415 if (memcmp(sf->
es, sf_prev->
es,
sizeof(sf_prev->
es)) == 0) {
416 mf = legacy_faces + sf->
index;
419 mf_prev = legacy_faces + sf_prev->
index;
422 PRINT_ERR(
"\tFace %u & %u: are duplicates (%u,%u,%u,%u) (%u,%u,%u,%u)",
435 PRINT_ERR(
"\tFace %u & %u: are duplicates (%u,%u,%u) (%u,%u,%u)",
458#undef REMOVE_FACE_TAG
459#undef CHECK_FACE_VERT_INDEX
460#undef CHECK_FACE_EDGE
480 Array<int> sort_face_verts(faces_num == 0 ? 0 : face_offsets[faces_num]);
481 int64_t sort_face_verts_offset = 0;
485 const int face_start = face_offsets[
i];
486 const int face_size = face_offsets[
i + 1] - face_start;
492 if (material_indices && material_indices_span[
i] < 0) {
493 PRINT_ERR(
"\tFace %u has invalid material (%d)", sp->
index, material_indices_span[
i]);
495 material_indices_span[
i] = 0;
499 if (face_start < 0 || face_size < 3) {
501 PRINT_ERR(
"\tFace %u is invalid (corner_start: %d, corners_num: %d)",
507 else if (face_start + face_size > corners_num) {
510 "\tFace %u uses corners out of range "
511 "(corner_start: %d, corner_end: %d, max number of corners: %u)",
514 face_start + face_size - 1,
522 sp->
verts =
v = sort_face_verts.
data() + sort_face_verts_offset;
523 sort_face_verts_offset += face_size;
530 for (j = 0; j < face_size; j++) {
532 if (vert < verts_num) {
533 vert_tag[vert].reset();
538 for (j = 0; j < face_size; j++,
v++) {
540 if (vert >= verts_num) {
545 else if (vert_tag[vert].test()) {
546 PRINT_ERR(
"\tFace %u has duplicated vert reference at corner (%u)",
uint(
i), j);
550 vert_tag[vert].set();
561 for (j = 0; j < face_size; j++) {
563 const int vert = corner_verts[corner];
564 const int edge_i = corner_edges[corner];
567 if (!edge_hash.
contains({v1, v2})) {
571 recalc_flag.edges =
true;
577 else if (edge_i >= edges_num) {
582 corner_edges[corner] = edge_hash.
lookup({v1,
v2});
583 fix_flag.corners_edge =
true;
584 PRINT_ERR(
"\tCorner %d has invalid edge reference (%d), fixed using edge %d",
587 corner_edges[corner]);
590 PRINT_ERR(
"\tCorner %d has invalid edge reference (%d)", corner, edge_i);
597 !((edge[0] == v1 && edge[1] ==
v2) || (edge[0] ==
v2 && edge[1] == v1)))
604 corner_edges[corner] = edge_hash.
lookup({v1,
v2});
605 fix_flag.corners_edge =
true;
607 "\tFace %u has invalid edge reference (%d, is_removed: %d), fixed using edge "
612 corner_edges[corner]);
615 PRINT_ERR(
"\tFace %u has invalid edge reference (%d)", sp->
index, edge_i);
636 sp = prev_sp = sort_faces.
data();
639 for (
i = 1;
i < faces_num;
i++, sp++) {
641 const int *p1_v = sp->
verts, *p2_v = prev_sp->
verts;
649 if ((p1_nv == p2_nv) && (memcmp(p1_v, p2_v, p1_nv *
sizeof(*p1_v)) == 0)) {
653 for (j = 1; j < p1_nv; j++) {
670 sp = sort_faces.
data();
673 for (
i = 0;
i < faces_num;
i++, sp++) {
681 faces_to_remove[sp->
index].set();
682 free_flag.face_corners = do_fixes;
693 if (prev_end < sp->corner_start) {
695 for (j = prev_end, corner = prev_end; j < sp->
corner_start; j++, corner++) {
707 "\tFaces %u and %u share corners from %d to %d, considering face %u as invalid.",
714 faces_to_remove[sp->
index].set();
715 free_flag.face_corners = do_fixes;
729 if (prev_end < corners_num) {
731 for (j = prev_end, corner = prev_end; j < corners_num; j++, corner++) {
743 for (
i = 0, dv = dverts;
i < verts_num;
i++, dv++) {
746 for (j = 0, dw = dv->
dw; j < dv->totweight; j++, dw++) {
748 if (!isfinite(dw->
weight)) {
752 fix_flag.verts_weight =
true;
759 fix_flag.verts_weight =
true;
765 if (dw->
def_nr >= INT_MAX) {
769 fix_flag.verts_weight =
true;
786#undef REMOVE_EDGE_TAG
787#undef IS_REMOVED_EDGE
788#undef REMOVE_CORNER_TAG
789#undef REMOVE_FACE_TAG
792 if (free_flag.faces) {
796 if (free_flag.face_corners) {
800 if (free_flag.edges) {
804 if (recalc_flag.edges) {
815 if (msel->
index < 0) {
817 "\tMesh select element %u type %d index is negative, "
818 "resetting selection stack.\n",
821 free_flag.mselect = do_fixes;
825 switch (msel->
type) {
827 tot_elem =
mesh->verts_num;
830 tot_elem =
mesh->edges_num;
833 tot_elem =
mesh->faces_num;
837 if (msel->
index > tot_elem) {
839 "\tMesh select element %u type %d index %d is larger than data array size %d, "
840 "resetting selection stack.\n",
846 free_flag.mselect = do_fixes;
851 if (free_flag.mselect) {
853 mesh->mselect =
nullptr;
858 material_indices_span.save();
859 material_indices.
finish();
863 *r_changed = (fix_flag.as_flag || free_flag.as_flag || recalc_flag.as_flag);
865 BLI_assert((*r_changed ==
false) || (do_fixes ==
true));
871 eCustomDataMask
mask,
873 const bool do_verbose,
877 bool is_valid =
true;
878 bool has_fixes =
false;
881 PRINT_MSG(
"%s: Checking %d CD layers...\n", __func__,
data->totlayer);
885 int layer_num_type = -1;
893 if (layer_num_type != type) {
895 layer_num_type = type;
899 int *active_index_array[] = {
905 for (
int *active_index :
Span(active_index_array,
ARRAY_SIZE(active_index_array))) {
906 if (*active_index < 0) {
907 PRINT_ERR(
"\tCustomDataLayer type %d has a negative active index (%d)\n",
916 if (*active_index >= layer_num) {
917 PRINT_ERR(
"\tCustomDataLayer type %d has an out of bounds active index (%d >= %d)\n",
923 *active_index = layer_num - 1;
932 PRINT_ERR(
"\tCustomDataLayer type %d is a singleton, found %d in Mesh structure\n",
941 if ((layer_typemask &
mask) == 0) {
942 PRINT_ERR(
"\tCustomDataLayer type %d which isn't in the mask\n", type);
956 PRINT_ERR(
"\tCustomDataLayer type %d has some invalid data\n", type);
957 has_fixes = do_fixes;
963 PRINT_MSG(
"%s: Finished (is_valid=%d)\n\n", __func__,
int(!has_fixes));
965 *r_change = has_fixes;
971 const uint verts_num,
973 const uint edges_num,
975 const uint corners_num,
977 const uint faces_num,
978 const bool check_meshmask,
979 const bool do_verbose,
983 bool is_valid =
true;
984 bool is_change_v, is_change_e, is_change_l, is_change_p;
986 if (check_meshmask) {
991 vert_data,
mask.vmask, verts_num, do_verbose, do_fixes, &is_change_v);
993 edge_data,
mask.emask, edges_num, do_verbose, do_fixes, &is_change_e);
995 corner_data,
mask.lmask, corners_num, do_verbose, do_fixes, &is_change_l);
997 face_data,
mask.pmask, faces_num, do_verbose, do_fixes, &is_change_p);
1002 "\tMore UV layers than %d allowed, %d last ones won't be available for render, shaders, "
1018 *r_change = (is_change_v || is_change_e || is_change_l || is_change_p);
1053 reinterpret_cast<float (*)[3]
>(positions.
data()),
1058 mesh->totface_legacy,
1059 corner_verts.
data(),
1060 corner_edges.
data(),
1061 corner_verts.
size(),
1062 face_offsets.
data(),
1080 const bool do_verbose =
true;
1081 const bool do_fixes =
false;
1083 bool is_valid =
true;
1084 bool changed =
true;
1110 reinterpret_cast<float (*)[3]
>(positions.
data()),
1115 mesh->totface_legacy,
1116 corner_verts.
data(),
1117 corner_edges.
data(),
1118 corner_verts.
size(),
1119 face_offsets.
data(),
1133 const int mat_nr_max =
max_ii(0,
mesh->totcol - 1);
1134 bool is_valid =
true;
1137 mesh->attributes_for_write().lookup_for_write<
int>(
"material_index");
1139 for (
const int i : material_indices_span.index_range()) {
1140 if (material_indices_span[
i] < 0 || material_indices_span[
i] > mat_nr_max) {
1141 material_indices_span[
i] = 0;
1145 material_indices_span.save();
1146 material_indices.
finish();
1175 for (a =
b = 0; a <
mesh->faces_num; a++) {
1176 bool invalid =
false;
1177 int start = face_offsets[a];
1178 int size = face_offsets[a + 1] - start;
1179 int stop = start +
size;
1181 if (faces_to_remove[a]) {
1184 else if (stop >
mesh->corners_num || stop < start ||
size < 0) {
1194 if (
size >= 3 && !invalid) {
1196 face_offsets[
b] = face_offsets[a];
1204 mesh->faces_num =
b;
1209 for (a =
b = 0; a <
mesh->corners_num; a++, corner++) {
1225 mesh->corners_num =
b;
1228 face_offsets[
mesh->faces_num] =
mesh->corners_num;
1233 face_offsets[
i] = new_idx[face_offsets[
i]];
1250 for (a =
b = 0,
e = edges.
data(); a < mesh->edges_num; a++,
e++) {
1251 if ((*
e)[0] != (*
e)[1]) {
1253 memcpy(&edges[
b],
e,
sizeof(edges[
b]));
1265 mesh->edges_num =
b;
1273 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)
eCustomDataMask CD_TYPE_AS_MASK(eCustomDataType type)
bool CustomData_free_layer(CustomData *data, eCustomDataType type, int index)
int CustomData_get_stencil_layer(const CustomData *data, eCustomDataType type)
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)
void CustomData_ensure_layers_are_mutable(CustomData *data, int totelem)
bool CustomData_layertype_is_singleton(eCustomDataType type)
int CustomData_number_of_layers(const CustomData *data, eCustomDataType 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,...)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY_ALL_MODES
Read Guarded memory(de)allocation.
BMesh const char void * data
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)
bool add(const Key &key, const Value &value)
const Value & lookup(const Key &key) const
bool contains(const Key &key) const
constexpr int64_t size() const
constexpr bool contains(const T &value) const
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
constexpr T * data() const
constexpr IndexRange index_range() const
constexpr const T * data() const
constexpr int64_t size() const
void * MEM_malloc_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)
#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 mesh_calc_edges(Mesh &mesh, bool keep_existing_edges, bool select_new_edges)
void parallel_sort(RandomAccessIterator begin, RandomAccessIterator end)
VecBase< int32_t, 2 > int2
VecBase< float, 3 > float3
VMutableArray< T > varray