debug option for modifier stack calculation USE_MODIFIER_VALIDATE,

checks that every modifier gives a valid mesh (very slow) - so off by default even in debug mode.
This commit is contained in:
Campbell Barton 2013-09-04 01:29:34 +00:00
parent 8b723dfafd
commit f3af9de618
5 changed files with 223 additions and 117 deletions

View File

@ -735,6 +735,8 @@ void DM_init_origspace(DerivedMesh *dm);
char *DM_debug_info(DerivedMesh *dm);
void DM_debug_print(DerivedMesh *dm);
void DM_debug_print_cdlayers(CustomData *cdata);
bool DM_is_valid(DerivedMesh *dm);
#endif
BLI_INLINE int DM_origindex_mface_mpoly(const int *index_mf_to_mpoly, const int *index_mp_to_orig, const int i) ATTR_NONNULL(1);

View File

@ -341,7 +341,7 @@ void BKE_mesh_translate(struct Mesh *me, const float offset[3], const bool do_ke
/* mesh_validate.c */
/* XXX Loop v/e are unsigned, so using max uint_32 value as invalid marker... */
#define INVALID_LOOP_EDGE_MARKER 4294967295u
int BKE_mesh_validate_arrays(
bool BKE_mesh_validate_arrays(
struct Mesh *me,
struct MVert *mverts, unsigned int totvert,
struct MEdge *medges, unsigned int totedge,
@ -349,9 +349,17 @@ int BKE_mesh_validate_arrays(
struct MLoop *mloops, unsigned int totloop,
struct MPoly *mpolys, unsigned int totpoly,
struct MDeformVert *dverts, /* assume totvert length */
const bool do_verbose, const bool do_fixes);
const bool do_verbose, const bool do_fixes,
bool *r_change);
bool BKE_mesh_validate_all_customdata(
struct CustomData *vdata, struct CustomData *edata,
struct CustomData *ldata, struct CustomData *pdata,
uint64_t mask, /* should be CustomDataMask but thats not defined */
const bool do_verbose, const bool do_fixes,
bool *r_change);
int BKE_mesh_validate(struct Mesh *me, const int do_verbose);
int BKE_mesh_validate_dm(struct DerivedMesh *dm);
void BKE_mesh_calc_edges(struct Mesh *mesh, bool update, const bool select);

View File

@ -82,11 +82,20 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm);
#include "GPU_extensions.h"
#include "GPU_material.h"
/* very slow! enable for testing only! */
// #define USE_MODIFIER_VALIDATE
#ifdef USE_MODIFIER_VALIDATE
# define ASSERT_IS_VALID_DM(dm) (BLI_assert((dm == NULL) || (DM_is_valid(dm) == true)))
#else
# define ASSERT_IS_VALID_DM(dm)
#endif
static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *ob);
static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape_uid);
///////////////////////////////////
///////////////////////////////////
/* -------------------------------------------------------------------- */
static MVert *dm_getVertArray(DerivedMesh *dm)
{
@ -879,6 +888,7 @@ DerivedMesh *mesh_create_derived_for_modifier(Scene *scene, Object *ob,
add_shapekey_layers(tdm, me, ob);
dm = modwrap_applyModifier(md, ob, tdm, 0);
ASSERT_IS_VALID_DM(dm);
if (tdm != dm) tdm->release(tdm);
}
@ -1650,6 +1660,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
}
else {
dm = CDDM_from_mesh(me, ob);
ASSERT_IS_VALID_DM(dm);
if (build_shapekey_layers)
add_shapekey_layers(dm, me, ob);
@ -1707,6 +1718,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
}
ndm = modwrap_applyModifier(md, ob, dm, app_flags);
ASSERT_IS_VALID_DM(ndm);
if (ndm) {
/* if the modifier returned a new dm, release the old one */
@ -1733,6 +1745,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
mti->requiredDataMask(ob, md) : 0));
ndm = modwrap_applyModifier(md, ob, orcodm, (app_flags & ~MOD_APPLY_USECACHE) | MOD_APPLY_ORCO);
ASSERT_IS_VALID_DM(ndm);
if (ndm) {
/* if the modifier returned a new dm, release the old one */
@ -1750,6 +1763,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
DM_set_only_copy(clothorcodm, nextmask | CD_MASK_ORIGINDEX);
ndm = modwrap_applyModifier(md, ob, clothorcodm, (app_flags & ~MOD_APPLY_USECACHE) | MOD_APPLY_ORCO);
ASSERT_IS_VALID_DM(ndm);
if (ndm) {
/* if the modifier returned a new dm, release the old one */
@ -2052,6 +2066,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
}
else {
dm = CDDM_from_editbmesh(em, FALSE, FALSE);
ASSERT_IS_VALID_DM(dm);
if (deformedVerts) {
CDDM_apply_vert_coords(dm, deformedVerts);
@ -2075,6 +2090,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
ndm = modwrap_applyModifierEM(md, ob, em, orcodm, MOD_APPLY_ORCO);
else
ndm = modwrap_applyModifier(md, ob, orcodm, MOD_APPLY_ORCO);
ASSERT_IS_VALID_DM(ndm);
if (ndm) {
/* if the modifier returned a new dm, release the old one */
@ -2100,6 +2116,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
ndm = modwrap_applyModifierEM(md, ob, em, dm, MOD_APPLY_USECACHE);
else
ndm = modwrap_applyModifier(md, ob, dm, MOD_APPLY_USECACHE);
ASSERT_IS_VALID_DM(ndm);
if (ndm) {
if (dm && dm != ndm)
@ -3261,4 +3278,35 @@ void DM_debug_print_cdlayers(CustomData *data)
printf("}\n");
}
bool DM_is_valid(DerivedMesh *dm)
{
const bool do_verbose = true;
const bool do_fixes = false;
bool is_valid = true;
bool is_change = true;
is_valid &= BKE_mesh_validate_all_customdata(
dm->getVertDataLayout(dm),
dm->getEdgeDataLayout(dm),
dm->getLoopDataLayout(dm),
dm->getPolyDataLayout(dm),
0, /* setting mask here isn't useful, gives false positives */
do_verbose, do_fixes, &is_change);
is_valid &= BKE_mesh_validate_arrays(
NULL,
dm->getVertArray(dm), dm->getNumVerts(dm),
dm->getEdgeArray(dm), dm->getNumEdges(dm),
dm->getTessFaceArray(dm), dm->getNumTessFaces(dm),
dm->getLoopArray(dm), dm->getNumLoops(dm),
dm->getPolyArray(dm), dm->getNumPolys(dm),
dm->getVertDataArray(dm, CD_MDEFORMVERT),
do_verbose, do_fixes, &is_change);
BLI_assert(is_change == false);
return is_valid;
}
#endif /* NDEBUG */

View File

@ -182,16 +182,28 @@ static int search_polyloop_cmp(const void *v1, const void *v2)
return sp1->loopstart > sp2->loopstart ? 1 : sp1->loopstart < sp2->loopstart ? -1 : 0;
}
#define PRINT if (do_verbose) printf
#define PRINT_MSG(...) (void) \
( \
((do_verbose) ? printf(__VA_ARGS__) : 0))
int BKE_mesh_validate_arrays(Mesh *mesh,
MVert *mverts, unsigned int totvert,
MEdge *medges, unsigned int totedge,
MFace *mfaces, unsigned int totface,
MLoop *mloops, unsigned int totloop,
MPoly *mpolys, unsigned int totpoly,
MDeformVert *dverts, /* assume totvert length */
const bool do_verbose, const bool do_fixes)
#define PRINT_ERR(...) (void) \
(is_valid = false, \
((do_verbose) ? printf(__VA_ARGS__) : 0))
/**
* Validate the mesh, \a do_fixes requires \a mesh to be non-null.
*
* \return false if no changes needed to be made.
*/
bool BKE_mesh_validate_arrays(Mesh *mesh,
MVert *mverts, unsigned int totvert,
MEdge *medges, unsigned int totedge,
MFace *mfaces, unsigned int totface,
MLoop *mloops, unsigned int totloop,
MPoly *mpolys, unsigned int totpoly,
MDeformVert *dverts, /* assume totvert length */
const bool do_verbose, const bool do_fixes,
bool *r_change)
{
# define REMOVE_EDGE_TAG(_me) { _me->v2 = _me->v1; do_edge_free = true; } (void)0
# define IS_REMOVED_EDGE(_me) (_me->v2 == _me->v1)
@ -206,6 +218,8 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
unsigned int i, j;
int *v;
bool is_valid = true;
bool do_edge_free = false;
bool do_face_free = false;
bool do_polyloop_free = false; /* This regroups loops and polys! */
@ -220,11 +234,11 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
BLI_assert(!(do_fixes && mesh == NULL));
PRINT("%s: verts(%u), edges(%u), loops(%u), polygons(%u)\n",
__func__, totvert, totedge, totloop, totpoly);
PRINT_MSG("%s: verts(%u), edges(%u), loops(%u), polygons(%u)\n",
__func__, totvert, totedge, totloop, totpoly);
if (totedge == 0 && totpoly != 0) {
PRINT("\tLogical error, %u polygons and 0 edges\n", totpoly);
PRINT_ERR("\tLogical error, %u polygons and 0 edges\n", totpoly);
do_edge_recalc = do_fixes;
}
@ -233,7 +247,7 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
for (j = 0; j < 3; j++) {
if (!finite(mv->co[j])) {
PRINT("\tVertex %u: has invalid coordinate\n", i);
PRINT_ERR("\tVertex %u: has invalid coordinate\n", i);
if (do_fixes) {
zero_v3(mv->co);
@ -247,7 +261,7 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
}
if (fix_normal) {
PRINT("\tVertex %u: has zero normal, assuming Z-up normal\n", i);
PRINT_ERR("\tVertex %u: has zero normal, assuming Z-up normal\n", i);
if (do_fixes) {
mv->no[2] = SHRT_MAX;
verts_fixed = TRUE;
@ -258,21 +272,21 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
for (i = 0, me = medges; i < totedge; i++, me++) {
int remove = FALSE;
if (me->v1 == me->v2) {
PRINT("\tEdge %u: has matching verts, both %u\n", i, me->v1);
PRINT_ERR("\tEdge %u: has matching verts, both %u\n", i, me->v1);
remove = do_fixes;
}
if (me->v1 >= totvert) {
PRINT("\tEdge %u: v1 index out of range, %u\n", i, me->v1);
PRINT_ERR("\tEdge %u: v1 index out of range, %u\n", i, me->v1);
remove = do_fixes;
}
if (me->v2 >= totvert) {
PRINT("\tEdge %u: v2 index out of range, %u\n", i, me->v2);
PRINT_ERR("\tEdge %u: v2 index out of range, %u\n", i, me->v2);
remove = do_fixes;
}
if (BLI_edgehash_haskey(edge_hash, me->v1, me->v2)) {
PRINT("\tEdge %u: is a duplicate of %d\n", i,
GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, me->v1, me->v2)));
PRINT_ERR("\tEdge %u: is a duplicate of %d\n", i,
GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, me->v1, me->v2)));
remove = do_fixes;
}
@ -288,13 +302,13 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
# define REMOVE_FACE_TAG(_mf) { _mf->v3 = 0; do_face_free = TRUE; } (void)0
# define CHECK_FACE_VERT_INDEX(a, b) \
if (mf->a == mf->b) { \
PRINT(" face %u: verts invalid, " STRINGIFY(a) "/" STRINGIFY(b) " both %u\n", i, mf->a); \
PRINT_ERR(" face %u: verts invalid, " STRINGIFY(a) "/" STRINGIFY(b) " both %u\n", i, mf->a); \
remove = do_fixes; \
} (void)0
# define CHECK_FACE_EDGE(a, b) \
if (!BLI_edgehash_haskey(edge_hash, mf->a, mf->b)) { \
PRINT(" face %u: edge " STRINGIFY(a) "/" STRINGIFY(b) \
" (%u,%u) is missing edge data\n", i, mf->a, mf->b); \
PRINT_ERR(" face %u: edge " STRINGIFY(a) "/" STRINGIFY(b) \
" (%u,%u) is missing edge data\n", i, mf->a, mf->b); \
do_edge_recalc = TRUE; \
} (void)0
@ -306,7 +320,7 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
SortFace *sf_prev;
unsigned int totsortface = 0;
PRINT("No Polys, only tesselated Faces\n");
PRINT_ERR("No Polys, only tesselated Faces\n");
for (i = 0, mf = mfaces, sf = sort_faces; i < totface; i++, mf++) {
int remove = FALSE;
@ -317,7 +331,7 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
do {
fv[fidx] = *(&(mf->v1) + fidx);
if (fv[fidx] >= totvert) {
PRINT("\tFace %u: 'v%d' index out of range, %u\n", i, fidx + 1, fv[fidx]);
PRINT_ERR("\tFace %u: 'v%d' index out of range, %u\n", i, fidx + 1, fv[fidx]);
remove = do_fixes;
}
} while (fidx--);
@ -394,14 +408,14 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
mf_prev = mfaces + sf_prev->index;
if (mf->v4) {
PRINT("\tFace %u & %u: are duplicates (%u,%u,%u,%u) (%u,%u,%u,%u)\n",
sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3, mf->v4,
mf_prev->v1, mf_prev->v2, mf_prev->v3, mf_prev->v4);
PRINT_ERR("\tFace %u & %u: are duplicates (%u,%u,%u,%u) (%u,%u,%u,%u)\n",
sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3, mf->v4,
mf_prev->v1, mf_prev->v2, mf_prev->v3, mf_prev->v4);
}
else {
PRINT("\tFace %u & %u: are duplicates (%u,%u,%u) (%u,%u,%u)\n",
sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3,
mf_prev->v1, mf_prev->v2, mf_prev->v3);
PRINT_ERR("\tFace %u & %u: are duplicates (%u,%u,%u) (%u,%u,%u)\n",
sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3,
mf_prev->v1, mf_prev->v2, mf_prev->v3);
}
}
@ -446,13 +460,14 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
if (mp->loopstart < 0 || mp->totloop < 3) {
/* Invalid loop data. */
PRINT("\tPoly %u is invalid (loopstart: %u, totloop: %u)\n", sp->index, mp->loopstart, mp->totloop);
PRINT_ERR("\tPoly %u is invalid (loopstart: %u, totloop: %u)\n",
sp->index, mp->loopstart, mp->totloop);
sp->invalid = TRUE;
}
else if (mp->loopstart + mp->totloop > totloop) {
/* Invalid loop data. */
PRINT("\tPoly %u uses loops out of range (loopstart: %u, loopend: %u, max nbr of loops: %u)\n",
sp->index, mp->loopstart, mp->loopstart + mp->totloop - 1, totloop - 1);
PRINT_ERR("\tPoly %u uses loops out of range (loopstart: %u, loopend: %u, max nbr of loops: %u)\n",
sp->index, mp->loopstart, mp->loopstart + mp->totloop - 1, totloop - 1);
sp->invalid = TRUE;
}
else {
@ -467,7 +482,7 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
for (j = 0, ml = &mloops[sp->loopstart]; j < mp->totloop; j++, ml++, v++) {
if (ml->v >= totvert) {
/* Invalid vert idx. */
PRINT("\tLoop %u has invalid vert reference (%u)\n", sp->loopstart + j, ml->v);
PRINT_ERR("\tLoop %u has invalid vert reference (%u)\n", sp->loopstart + j, ml->v);
sp->invalid = TRUE;
}
@ -480,7 +495,7 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
v = sp->verts;
for (j = 0; j < mp->totloop; j++, v++) {
if ((mverts[*v].flag & ME_VERT_TMP_TAG) == 0) {
PRINT("\tPoly %u has duplicate vert reference at corner (%u)\n", i, j);
PRINT_ERR("\tPoly %u has duplicate vert reference at corner (%u)\n", i, j);
sp->invalid = TRUE;
}
mverts[*v].flag &= ~ME_VERT_TMP_TAG;
@ -496,7 +511,7 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
v2 = mloops[sp->loopstart + (j + 1) % mp->totloop].v;
if (!BLI_edgehash_haskey(edge_hash, v1, v2)) {
/* Edge not existing. */
PRINT("\tPoly %u needs missing edge (%u, %u)\n", sp->index, v1, v2);
PRINT_ERR("\tPoly %u needs missing edge (%u, %u)\n", sp->index, v1, v2);
if (do_fixes)
do_edge_recalc = TRUE;
else
@ -508,11 +523,11 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
if (do_fixes) {
int prev_e = ml->e;
ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, v1, v2));
PRINT("\tLoop %u has invalid edge reference (%u), fixed using edge %u\n",
sp->loopstart + j, prev_e, ml->e);
PRINT_ERR("\tLoop %u has invalid edge reference (%u), fixed using edge %u\n",
sp->loopstart + j, prev_e, ml->e);
}
else {
PRINT("\tLoop %u has invalid edge reference (%u)\n", sp->loopstart + j, ml->e);
PRINT_ERR("\tLoop %u has invalid edge reference (%u)\n", sp->loopstart + j, ml->e);
sp->invalid = TRUE;
}
}
@ -524,11 +539,11 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
if (do_fixes) {
int prev_e = ml->e;
ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, v1, v2));
PRINT("\tPoly %u has invalid edge reference (%u), fixed using edge %u\n",
sp->index, prev_e, ml->e);
PRINT_ERR("\tPoly %u has invalid edge reference (%u), fixed using edge %u\n",
sp->index, prev_e, ml->e);
}
else {
PRINT("\tPoly %u has invalid edge reference (%u)\n", sp->index, ml->e);
PRINT_ERR("\tPoly %u has invalid edge reference (%u)\n", sp->index, ml->e);
sp->invalid = TRUE;
}
}
@ -546,16 +561,16 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
if (*v != *prev_v) {
int dlt = v - prev_v;
if (dlt > 1) {
PRINT("\tPoly %u is invalid, it multi-uses vertex %u (%u times)\n",
sp->index, *prev_v, dlt);
PRINT_ERR("\tPoly %u is invalid, it multi-uses vertex %u (%u times)\n",
sp->index, *prev_v, dlt);
sp->invalid = TRUE;
}
prev_v = v;
}
}
if (v - prev_v > 1) { /* Don't forget final verts! */
PRINT("\tPoly %u is invalid, it multi-uses vertex %u (%u times)\n",
sp->index, *prev_v, (int)(v - prev_v));
PRINT_ERR("\tPoly %u is invalid, it multi-uses vertex %u (%u times)\n",
sp->index, *prev_v, (int)(v - prev_v));
sp->invalid = TRUE;
}
}
@ -633,11 +648,14 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
}
if ((p1_nv == p2_nv) && (memcmp(p1_v, p2_v, p1_nv * sizeof(*p1_v)) == 0)) {
if (do_verbose) {
PRINT("\tPolys %u and %u use same vertices (%u",
prev_sp->index, sp->index, *p1_v);
PRINT_ERR("\tPolys %u and %u use same vertices (%u",
prev_sp->index, sp->index, *p1_v);
for (j = 1; j < p1_nv; j++)
PRINT(", %u", p1_v[j]);
PRINT("), considering poly %u as invalid.\n", sp->index);
PRINT_ERR(", %u", p1_v[j]);
PRINT_ERR("), considering poly %u as invalid.\n", sp->index);
}
else {
is_valid = false;
}
sp->invalid = TRUE;
}
@ -673,7 +691,7 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
/* Unused loops. */
if (prev_end < sp->loopstart) {
for (j = prev_end, ml = &mloops[prev_end]; j < sp->loopstart; j++, ml++) {
PRINT("\tLoop %u is unused.\n", j);
PRINT_ERR("\tLoop %u is unused.\n", j);
if (do_fixes)
REMOVE_LOOP_TAG(ml);
}
@ -682,8 +700,8 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
}
/* Multi-used loops. */
else if (prev_end > sp->loopstart) {
PRINT("\tPolys %u and %u share loops from %u to %u, considering poly %u as invalid.\n",
prev_sp->index, sp->index, sp->loopstart, prev_end, sp->index);
PRINT_ERR("\tPolys %u and %u share loops from %u to %u, considering poly %u as invalid.\n",
prev_sp->index, sp->index, sp->loopstart, prev_end, sp->index);
if (do_fixes) {
REMOVE_POLY_TAG((&mpolys[sp->index]));
/* DO NOT REMOVE ITS LOOPS!!!
@ -701,7 +719,7 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
/* We may have some remaining unused loops to get rid of! */
if (prev_end < totloop) {
for (j = prev_end, ml = &mloops[prev_end]; j < totloop; j++, ml++) {
PRINT("\tLoop %u is unused.\n", j);
PRINT_ERR("\tLoop %u is unused.\n", j);
if (do_fixes)
REMOVE_LOOP_TAG(ml);
}
@ -721,14 +739,14 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
for (j = 0, dw = dv->dw; j < dv->totweight; j++, dw++) {
/* note, greater then max defgroups is accounted for in our code, but not < 0 */
if (!finite(dw->weight)) {
PRINT("\tVertex deform %u, group %d has weight: %f\n", i, dw->def_nr, dw->weight);
PRINT_ERR("\tVertex deform %u, group %d has weight: %f\n", i, dw->def_nr, dw->weight);
if (do_fixes) {
dw->weight = 0.0f;
vert_weights_fixed = TRUE;
}
}
else if (dw->weight < 0.0f || dw->weight > 1.0f) {
PRINT("\tVertex deform %u, group %d has weight: %f\n", i, dw->def_nr, dw->weight);
PRINT_ERR("\tVertex deform %u, group %d has weight: %f\n", i, dw->def_nr, dw->weight);
if (do_fixes) {
CLAMP(dw->weight, 0.0f, 1.0f);
vert_weights_fixed = TRUE;
@ -736,7 +754,7 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
}
if (dw->def_nr < 0) {
PRINT("\tVertex deform %u, has invalid group %d\n", i, dw->def_nr);
PRINT_ERR("\tVertex deform %u, has invalid group %d\n", i, dw->def_nr);
if (do_fixes) {
defvert_remove_group(dv, dw);
if (dv->dw) {
@ -787,8 +805,8 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
int tot_elem = 0;
if (msel->index < 0) {
PRINT("\tMesh select element %d type %d index is negative, "
"resetting selection stack.\n", i, msel->type);
PRINT_ERR("\tMesh select element %d type %d index is negative, "
"resetting selection stack.\n", i, msel->type);
free_msel = TRUE;
break;
}
@ -806,8 +824,8 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
}
if (msel->index > tot_elem) {
PRINT("\tMesh select element %d type %d index %d is larger than data array size %d, "
"resetting selection stack.\n", i, msel->type, msel->index, tot_elem);
PRINT_ERR("\tMesh select element %d type %d index %d is larger than data array size %d, "
"resetting selection stack.\n", i, msel->type, msel->index, tot_elem);
free_msel = TRUE;
break;
@ -821,29 +839,49 @@ int BKE_mesh_validate_arrays(Mesh *mesh,
}
}
PRINT("%s: finished\n\n", __func__);
PRINT_MSG("%s: finished\n\n", __func__);
return (verts_fixed || vert_weights_fixed || do_polyloop_free || do_edge_free || do_edge_recalc || msel_fixed);
*r_change = (verts_fixed || vert_weights_fixed || do_polyloop_free || do_edge_free || do_edge_recalc || msel_fixed);
return is_valid;
}
static int mesh_validate_customdata(CustomData *data, const bool do_verbose, const bool do_fixes)
static bool mesh_validate_customdata(CustomData *data, CustomDataMask mask,
const bool do_verbose, const bool do_fixes,
bool *r_change)
{
int i = 0, has_fixes = 0;
bool is_valid = true;
bool has_fixes = false;
int i = 0;
PRINT("%s: Checking %d CD layers...\n", __func__, data->totlayer);
PRINT_MSG("%s: Checking %d CD layers...\n", __func__, data->totlayer);
while (i < data->totlayer) {
CustomDataLayer *layer = &data->layers[i];
CustomDataMask mask = CD_TYPE_AS_MASK(layer->type);
int ok = 1;
bool ok = true;
if ((mask & CD_MASK_MESH) == 0) {
PRINT("\tCustomDataLayer type %d which isn't in CD_MASK_MESH is stored in Mesh structure\n", layer->type);
if (CustomData_layertype_is_singleton(layer->type)) {
const int layer_tot = CustomData_number_of_layers(data, layer->type);
if (layer_tot > 1) {
PRINT_ERR("\tCustomDataLayer type %d is a singleton, found %d in Mesh structure\n",
layer->type, layer_tot);
ok = false;
}
}
if (mask != 0) {
CustomDataMask layer_typemask = CD_TYPE_AS_MASK(layer->type);
if ((layer_typemask & mask) == 0) {
PRINT_ERR("\tCustomDataLayer type %d which isn't in the mask\n",
layer->type);
ok = false;
}
}
if (ok == false) {
if (do_fixes) {
CustomData_free_layer(data, layer->type, 0, i);
ok = 0;
has_fixes = 1;
has_fixes = true;
}
}
@ -851,62 +889,75 @@ static int mesh_validate_customdata(CustomData *data, const bool do_verbose, con
i++;
}
PRINT("%s: Finished\n\n", __func__);
PRINT_MSG("%s: Finished (is_valid=%d)\n\n", __func__, (int)!has_fixes);
return has_fixes;
*r_change = has_fixes;
return is_valid;
}
#undef PRINT
static int BKE_mesh_validate_all_customdata(CustomData *vdata, CustomData *edata,
CustomData *ldata, CustomData *pdata,
const bool do_verbose, const short do_fixes)
/**
* \returns is_valid.
*/
bool BKE_mesh_validate_all_customdata(CustomData *vdata, CustomData *edata,
CustomData *ldata, CustomData *pdata,
CustomDataMask mask,
const bool do_verbose, const bool do_fixes,
bool *r_change)
{
int vfixed = 0, efixed = 0, lfixed = 0, pfixed = 0;
bool is_valid = true;
bool is_change_v, is_change_e, is_change_l, is_change_p;
vfixed = mesh_validate_customdata(vdata, do_verbose, do_fixes);
efixed = mesh_validate_customdata(edata, do_verbose, do_fixes);
lfixed = mesh_validate_customdata(ldata, do_verbose, do_fixes);
pfixed = mesh_validate_customdata(pdata, do_verbose, do_fixes);
is_valid &= mesh_validate_customdata(vdata, mask, do_verbose, do_fixes, &is_change_v);
is_valid &= mesh_validate_customdata(edata, mask, do_verbose, do_fixes, &is_change_e);
is_valid &= mesh_validate_customdata(ldata, mask, do_verbose, do_fixes, &is_change_l);
is_valid &= mesh_validate_customdata(pdata, mask, do_verbose, do_fixes, &is_change_p);
return vfixed || efixed || lfixed || pfixed;
*r_change = (is_change_v || is_change_e || is_change_l || is_change_p);
return is_valid;
}
/**
* \see #DM_is_valid to call on derived meshes
*
* \returns true if a change is made.
*/
int BKE_mesh_validate(Mesh *me, const int do_verbose)
{
int layers_fixed = 0, arrays_fixed = 0;
bool is_valid = true;
bool is_change;
if (do_verbose) {
printf("MESH: %s\n", me->id.name + 2);
}
layers_fixed = BKE_mesh_validate_all_customdata(&me->vdata, &me->edata, &me->ldata, &me->pdata, do_verbose, TRUE);
arrays_fixed = BKE_mesh_validate_arrays(me,
me->mvert, me->totvert,
me->medge, me->totedge,
me->mface, me->totface,
me->mloop, me->totloop,
me->mpoly, me->totpoly,
me->dvert,
do_verbose, true);
is_valid &= BKE_mesh_validate_all_customdata(
&me->vdata, &me->edata, &me->ldata, &me->pdata,
CD_MASK_MESH,
do_verbose, true,
&is_change);
if (layers_fixed || arrays_fixed) {
is_valid &= BKE_mesh_validate_arrays(
me,
me->mvert, me->totvert,
me->medge, me->totedge,
me->mface, me->totface,
me->mloop, me->totloop,
me->mpoly, me->totpoly,
me->dvert,
do_verbose, true,
&is_change);
if (is_change) {
DAG_id_tag_update(&me->id, OB_RECALC_DATA);
return true;
}
return false;
}
int BKE_mesh_validate_dm(DerivedMesh *dm)
{
return BKE_mesh_validate_arrays(NULL,
dm->getVertArray(dm), dm->getNumVerts(dm),
dm->getEdgeArray(dm), dm->getNumEdges(dm),
dm->getTessFaceArray(dm), dm->getNumTessFaces(dm),
dm->getLoopArray(dm), dm->getNumLoops(dm),
dm->getPolyArray(dm), dm->getNumPolys(dm),
dm->getVertDataArray(dm, CD_MDEFORMVERT),
TRUE, FALSE);
else {
return false;
}
}
/**

View File

@ -3189,8 +3189,10 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
ccgdm->dm.getVert = ccgDM_getFinalVert;
ccgdm->dm.getEdge = ccgDM_getFinalEdge;
ccgdm->dm.getTessFace = ccgDM_getFinalFace;
ccgdm->dm.getVertCo = ccgDM_getFinalVertCo;
ccgdm->dm.getVertNo = ccgDM_getFinalVertNo;
ccgdm->dm.copyVertArray = ccgDM_copyFinalVertArray;
ccgdm->dm.copyEdgeArray = ccgDM_copyFinalEdgeArray;
ccgdm->dm.copyTessFaceArray = ccgDM_copyFinalFaceArray;
@ -3216,11 +3218,6 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
ccgdm->dm.getPolyMap = ccgDM_getPolyMap;
ccgdm->dm.getPBVH = ccgDM_getPBVH;
ccgdm->dm.getTessFace = ccgDM_getFinalFace;
ccgdm->dm.copyVertArray = ccgDM_copyFinalVertArray;
ccgdm->dm.copyEdgeArray = ccgDM_copyFinalEdgeArray;
ccgdm->dm.copyTessFaceArray = ccgDM_copyFinalFaceArray;
ccgdm->dm.calcNormals = ccgDM_calcNormals;
ccgdm->dm.recalcTessellation = ccgDM_recalcTessellation;