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");
208 bool is_valid =
true;
213 int verts_weight : 1;
214 int corners_edge : 1;
224 int face_corners : 1;
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
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);
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) {
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,
880 bool is_valid =
true;
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[] = {
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,
986 bool is_valid =
true;
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);
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;
1086 bool is_valid =
true;
1087 bool changed =
true;
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);
1137 bool is_valid =
true;
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.
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Map
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 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)
ccl_device_inline float4 mask(const int4 mask, const float4 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