From 675628d24deba0afdc3da5b7a5bc802b13506251 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 22 Mar 2012 05:13:43 +0000 Subject: bmesh: debugging function to help resolve issues with corrupt mesh data - BM_mesh_validate() --- source/blender/bmesh/CMakeLists.txt | 4 +- source/blender/bmesh/bmesh.h | 1 + source/blender/bmesh/intern/bmesh_mesh_validate.c | 172 ++++++++++++++++++++++ source/blender/bmesh/intern/bmesh_mesh_validate.h | 35 +++++ source/blender/editors/mesh/bmesh_utils.c | 2 + source/blender/modifiers/intern/MOD_edgesplit.c | 2 + 6 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 source/blender/bmesh/intern/bmesh_mesh_validate.c create mode 100644 source/blender/bmesh/intern/bmesh_mesh_validate.h (limited to 'source') diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt index 7f7f36e1d83..eaa0df49382 100644 --- a/source/blender/bmesh/CMakeLists.txt +++ b/source/blender/bmesh/CMakeLists.txt @@ -67,7 +67,9 @@ set(SRC intern/bmesh_mesh.c intern/bmesh_mesh.h intern/bmesh_mesh_conv.c - intern/bmesh_mesh_conv.h + intern/bmesh_mesh_conv.h + intern/bmesh_mesh_validate.c + intern/bmesh_mesh_validate.h intern/bmesh_mods.c intern/bmesh_mods.h intern/bmesh_opdefines.c diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h index 2e568a15117..a7f66bb8345 100644 --- a/source/blender/bmesh/bmesh.h +++ b/source/blender/bmesh/bmesh.h @@ -217,6 +217,7 @@ extern "C" { #include "intern/bmesh_marking.h" #include "intern/bmesh_mesh.h" #include "intern/bmesh_mesh_conv.h" +#include "intern/bmesh_mesh_validate.h" #include "intern/bmesh_mods.h" #include "intern/bmesh_operators.h" #include "intern/bmesh_polygon.h" diff --git a/source/blender/bmesh/intern/bmesh_mesh_validate.c b/source/blender/bmesh/intern/bmesh_mesh_validate.c new file mode 100644 index 00000000000..aa49a8405d7 --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_mesh_validate.c @@ -0,0 +1,172 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2012 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/bmesh/intern/bmesh_mesh_validate.c + * \ingroup bmesh + * + * BM mesh validation function. + */ + +/* debug builds only */ +#ifdef DEBUG + +#include "bmesh.h" + +#include "bmesh_mesh_validate.h" + + +/* macro which inserts the function name */ +#if defined __GNUC__ || defined __sun +# define ERRMSG(format, args...) { fprintf(stderr, "%s: " format ", " AT "\n", __func__, ##args); errtot++; } (void)0 +#else +# define ERRMSG(format, ...) { fprintf(stderr, "%s: " format ", " AT "\n", __func__, __VA_ARGS__); errtot++; } (void)0 +#endif + +/** + * Check of this BMesh is valid, this function can be slow since its intended to help with debugging. + * + * \return TRUE when the mesh is valid. + */ +int BM_mesh_validate(BMesh *bm) +{ + int errtot; + + BMIter iter; + BMVert *v; + BMEdge *e; + BMFace *f; + + int i, j; + + errtot = -1; + fprintf(stderr, "\n"); + ERRMSG("This is a debugging function and not intended for general use, running slow test!"); + + /* force recalc, even if tagged as valid, since this mesh is suspect! */ + bm->elem_index_dirty |= BM_ALL; + BM_mesh_elem_index_ensure(bm, BM_ALL); + + BM_ITER_INDEX(v, &iter, bm, BM_VERTS_OF_MESH, NULL, i) { + if (v->e) { + if (!BM_vert_in_edge(v->e, v)) { + ERRMSG("vert: %d - is not in its referenced edge: %d", i, BM_elem_index_get(v->e)); + } + } + } + + /* check edges */ + BM_ITER_INDEX(e, &iter, bm, BM_EDGES_OF_MESH, NULL, i) { + if (e->v1 == e->v2) + ERRMSG("edge %d: duplicate index: %d", i, BM_elem_index_get(e->v1)); + } + + /* edge radial structure */ + BM_ITER_INDEX(e, &iter, bm, BM_EDGES_OF_MESH, NULL, i) { + if (e->l) { + BMLoop *l_iter; + BMLoop *l_first; + + j = 0; + + l_iter = l_first = e->l; + /* we could do more checks here, but save for face checks */ + do { + if (l_iter->e != e) { + ERRMSG("edge %d: has invalid loop, loop is of face %d", i, BM_elem_index_get(l_iter->f)); + } + else if (BM_vert_in_edge(e, l_iter->v) == FALSE) { + ERRMSG("edge %d: has invalid loop with vert not in edge, loop is of face %d", i, BM_elem_index_get(l_iter->f)); + } + else if (BM_vert_in_edge(e, l_iter->next->v) == FALSE) { + ERRMSG("edge %d: has invalid loop with next vert not in edge, loop is of face %d", i, BM_elem_index_get(l_iter->f)); + } + } while ((l_iter = l_iter->radial_next) != l_first); + } + } + + /* face structure */ + BM_ITER_INDEX(f, &iter, bm, BM_FACES_OF_MESH, NULL, i) { + BMLoop *l_iter; + BMLoop *l_first; + + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + + do { + BM_elem_flag_disable(l_iter, BM_ELEM_INTERNAL_TAG); + BM_elem_flag_disable(l_iter->v, BM_ELEM_INTERNAL_TAG); + BM_elem_flag_disable(l_iter->e, BM_ELEM_INTERNAL_TAG); + } while ((l_iter = l_iter->next) != l_first); + + j = 0; + + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (BM_elem_flag_test(l_iter, BM_ELEM_INTERNAL_TAG)) { + ERRMSG("face %d: has duplicate loop at corner: %d", i, j); + } + if (BM_elem_flag_test(l_iter->v, BM_ELEM_INTERNAL_TAG)) { + ERRMSG("face %d: has duplicate vert: %d, at corner: %d", i, BM_elem_index_get(l_iter->v), j); + } + if (BM_elem_flag_test(l_iter->e, BM_ELEM_INTERNAL_TAG)) { + ERRMSG("face %d: has duplicate edge: %d, at corner: %d", i, BM_elem_index_get(l_iter->e), j); + } + + /* adjacent data checks */ + if (l_iter->f != f) { + ERRMSG("face %d: has loop that points to face: %d at corner: %d", i, BM_elem_index_get(l_iter->f), j); + } + if (l_iter != l_iter->prev->next) { + ERRMSG("face %d: has invalid 'prev/next' at corner: %d", i, j); + } + if (l_iter != l_iter->next->prev) { + ERRMSG("face %d: has invalid 'next/prev' at corner: %d", i, j); + } + if (l_iter != l_iter->radial_prev->radial_next) { + ERRMSG("face %d: has invalid 'radial_prev/radial_next' at corner: %d", i, j); + } + if (l_iter != l_iter->radial_next->radial_prev) { + ERRMSG("face %d: has invalid 'radial_next/radial_prev' at corner: %d", i, j); + } + + BM_elem_flag_enable(l_iter, BM_ELEM_INTERNAL_TAG); + BM_elem_flag_enable(l_iter->v, BM_ELEM_INTERNAL_TAG); + BM_elem_flag_enable(l_iter->e, BM_ELEM_INTERNAL_TAG); + j++; + } while ((l_iter = l_iter->next) != l_first); + + if (j != f->len) { + ERRMSG("face %d: has length if %d but should be %d", i, f->len, j); + } + } + + + + ERRMSG("Finished - errors %d", errtot); + + return TRUE; +} + + +#endif diff --git a/source/blender/bmesh/intern/bmesh_mesh_validate.h b/source/blender/bmesh/intern/bmesh_mesh_validate.h new file mode 100644 index 00000000000..6839dc74d25 --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_mesh_validate.h @@ -0,0 +1,35 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2012 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BMESH_MESH_VALIDATE_H__ +#define __BMESH_MESH_VALIDATE_H__ + +/** \file blender/bmesh/intern/bmesh_mesh_validate.h + * \ingroup bmesh + */ + +int BM_mesh_validate(BMesh *bm); + +#endif /* __BMESH_MESH_VALIDATE_H__ */ diff --git a/source/blender/editors/mesh/bmesh_utils.c b/source/blender/editors/mesh/bmesh_utils.c index 085624fe23f..9bff0e7310c 100644 --- a/source/blender/editors/mesh/bmesh_utils.c +++ b/source/blender/editors/mesh/bmesh_utils.c @@ -527,6 +527,8 @@ static void *editbtMesh_to_undoMesh(void *emv, void *obdata) #endif + /* BM_mesh_validate(em->bm); */ /* for troubleshooting */ + BMO_op_callf(em->bm, "bmesh_to_mesh mesh=%p notessellation=%b", &um->me, TRUE); um->selectmode = em->selectmode; diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c index 9fb4821229c..e50c0d5521b 100644 --- a/source/blender/modifiers/intern/MOD_edgesplit.c +++ b/source/blender/modifiers/intern/MOD_edgesplit.c @@ -103,6 +103,8 @@ static DerivedMesh *doEdgeSplit(DerivedMesh *dm, EdgeSplitModifierData *emd, Obj BMO_pop(bm); + /* BM_mesh_validate(bm); */ /* for troubleshooting */ + BLI_assert(em->looptris == NULL); result = CDDM_from_BMEditMesh(em, NULL, TRUE, FALSE); BMEdit_Free(em); -- cgit v1.2.3