Merging r41246 through r41535 from trunk into soc-2011-tomato
[blender.git] / source / blender / blenkernel / intern / mesh_validate.c
index 4cef8c5560e40f3dfea1764b26ce28a1c5ed1795..0dac4b8cd808c251cba3d0c45d73e94942ee3b59 100644 (file)
@@ -1,6 +1,4 @@
-/**
- * $Id: mesh_ops.c 34569 2011-01-30 16:19:08Z ton $
- *
+/*
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  * ***** END GPL LICENSE BLOCK *****
  */
 
+/** \file blender/blenkernel/intern/mesh_validate.c
+ *  \ingroup bke
+ */
+
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -31,6 +34,8 @@
 #include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
 
+#include "BLO_sys_types.h"
+
 #include "BLI_utildefines.h"
 #include "BLI_edgehash.h"
 
 
 #include "MEM_guardedalloc.h"
 
-#include "ED_mesh.h"
+#include "BKE_mesh.h"
+
+#define SELECT 1
+
+typedef union {
+       uint32_t verts[2];
+       int64_t edval;
+} EdgeUUID;
+
+typedef struct SortFace {
+//     unsigned int    v[4];
+       EdgeUUID                es[4];
+       unsigned int    index;
+} SortFace;
+
+static void edge_store_assign(uint32_t verts[2],  const uint32_t v1, const uint32_t v2)
+{
+       if(v1 < v2) {
+               verts[0]= v1;
+               verts[1]= v2;
+       }
+       else {
+               verts[0]= v2;
+               verts[1]= v1;
+       }
+}
+
+static void edge_store_from_mface_quad(EdgeUUID es[4], MFace *mf)
+{
+       edge_store_assign(es[0].verts, mf->v1, mf->v2);
+       edge_store_assign(es[1].verts, mf->v2, mf->v3);
+       edge_store_assign(es[2].verts, mf->v3, mf->v4);
+       edge_store_assign(es[3].verts, mf->v4, mf->v1);
+}
 
-typedef struct SearchFace {
-       unsigned int v[4];
-       unsigned int index;
-} SearchFace;
+static void edge_store_from_mface_tri(EdgeUUID es[4], MFace *mf)
+{
+       edge_store_assign(es[0].verts, mf->v1, mf->v2);
+       edge_store_assign(es[1].verts, mf->v2, mf->v3);
+       edge_store_assign(es[2].verts, mf->v3, mf->v1);
+       es[3].verts[0] = es[3].verts[1] = UINT_MAX;
+}
 
-static int uint_cmp(const void *v1, const void *v2)
+static int int64_cmp(const void *v1, const void *v2)
 {
-       const unsigned int x1= GET_INT_FROM_POINTER(v1), x2= GET_INT_FROM_POINTER(v2);
+       const int64_t x1= *(const int64_t *)v1;
+       const int64_t x2= *(const int64_t *)v2;
 
        if( x1 > x2 ) return 1;
        else if( x1 < x2 ) return -1;
@@ -56,204 +98,332 @@ static int uint_cmp(const void *v1, const void *v2)
 
 static int search_face_cmp(const void *v1, const void *v2)
 {
-       const SearchFace *sfa= v1, *sfb= v2;
+       const SortFace *sfa= v1, *sfb= v2;
 
-       if              (sfa->v[0] > sfb->v[0]) return 1;
-       else if (sfa->v[0] < sfb->v[0]) return -1;
+       if      (sfa->es[0].edval > sfb->es[0].edval) return 1;
+       else if (sfa->es[0].edval < sfb->es[0].edval) return -1;
 
-       if              (sfa->v[1] > sfb->v[1]) return 1;
-       else if (sfa->v[1] < sfb->v[1]) return -1;
+       else if (sfa->es[1].edval > sfb->es[1].edval) return 1;
+       else if (sfa->es[1].edval < sfb->es[1].edval) return -1;
 
-       if              (sfa->v[2] > sfb->v[2]) return 1;
-       else if (sfa->v[2] < sfb->v[2]) return -1;
+       else if (sfa->es[2].edval > sfb->es[2].edval) return 1;
+       else if (sfa->es[2].edval < sfb->es[2].edval) return -1;
 
-       if              (sfa->v[3] > sfb->v[3]) return 1;
-       else if (sfa->v[3] < sfb->v[3]) return -1;
+       else if (sfa->es[3].edval > sfb->es[3].edval) return 1;
+       else if (sfa->es[3].edval < sfb->es[3].edval) return -1;
+       else                                                                              return 0;
 
-       return 0;
 }
 
-void BKE_mesh_validate_arrays(MVert *UNUSED(mverts), int totvert, MEdge *medges, int totedge, MFace *mfaces, int totface)
+#define PRINT if(do_verbose) printf
+
+int BKE_mesh_validate_arrays(Mesh *me, MVert *UNUSED(mverts), unsigned int totvert, MEdge *medges, unsigned int totedge, MFace *mfaces, unsigned int totface, const short do_verbose, const short do_fixes)
 {
+#      define REMOVE_EDGE_TAG(_med) { _med->v2= _med->v1; do_edge_free= 1; }
+#      define REMOVE_FACE_TAG(_mf) { _mf->v3=0; do_face_free= 1; }
+
 //     MVert *mv;
        MEdge *med;
        MFace *mf;
-       int i;
+       MFace *mf_prev;
+       unsigned int i;
+
+       int do_face_free= FALSE;
+       int do_edge_free= FALSE;
+
+       int do_edge_recalc= FALSE;
 
        EdgeHash *edge_hash = BLI_edgehash_new();
 
-       SearchFace *search_faces= MEM_callocN(sizeof(SearchFace) * totface, "search faces");
-       SearchFace *sf;
-       SearchFace *sf_prev;
+       SortFace *sort_faces= MEM_callocN(sizeof(SortFace) * totface, "search faces");
+       SortFace *sf;
+       SortFace *sf_prev;
+       unsigned int totsortface= 0;
 
-       printf("ED_mesh_validate: verts(%d), edges(%d), faces(%d)\n", totvert, totedge, totface);
+       BLI_assert(!(do_fixes && me == NULL));
 
-       if(totedge==0 && totface != 0) {
-               printf("    locical error, %d faces and 0 edges\n", totface);
+       PRINT("%s: verts(%u), edges(%u), faces(%u)\n", __func__, totvert, totedge, totface);
+
+       if(totedge == 0 && totface != 0) {
+               PRINT("    locical error, %u faces and 0 edges\n", totface);
+               do_edge_recalc= TRUE;
        }
 
-       for(i=0, med=medges; i<totedge; i++, med++) {
+       for(i=0, med= medges; i<totedge; i++, med++) {
+               int remove= FALSE;
                if(med->v1 == med->v2) {
-                       printf("    edge %d: has matching verts, both %d\n", i, med->v1);
+                       PRINT("    edge %u: has matching verts, both %u\n", i, med->v1);
+                       remove= do_fixes;
                }
-               if(med->v1 < 0 || med->v1 >= totvert) {
-                       printf("    edge %d: v1 index out of range, %d\n", i, med->v1);
+               if(med->v1 >= totvert) {
+                       PRINT("    edge %u: v1 index out of range, %u\n", i, med->v1);
+                       remove= do_fixes;
                }
-               if(med->v2 < 0 || med->v2 >= totvert) {
-                       printf("    edge %d: v2 index out of range, %d\n", i, med->v2);
+               if(med->v2 >= totvert) {
+                       PRINT("    edge %u: v2 index out of range, %u\n", i, med->v2);
+                       remove= do_fixes;
                }
 
                if(BLI_edgehash_haskey(edge_hash, med->v1, med->v2)) {
-                       printf("    edge %d: is a duplicate of, %d\n", i, GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, med->v1, med->v2)));
+                       PRINT("    edge %u: is a duplicate of, %d\n", i, GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, med->v1, med->v2)));
+                       remove= do_fixes;
                }
 
-               BLI_edgehash_insert(edge_hash, med->v1, med->v2, SET_INT_IN_POINTER(i));
+               if(remove == FALSE){
+                       BLI_edgehash_insert(edge_hash, med->v1, med->v2, SET_INT_IN_POINTER(i));
+               }
+               else {
+                       REMOVE_EDGE_TAG(med);
+               }
        }
 
-       for(i=0, mf=mfaces; i<totface; i++, mf++) {
-               unsigned int fverts[4];
-               // unsigned int fedges[4];
+       for(i=0, mf=mfaces, sf=sort_faces; i<totface; i++, mf++) {
+               int remove= FALSE;
                int fidx;
+               unsigned int fv[4];
 
                fidx = mf->v4 ? 3:2;
                do {
-                       fverts[fidx]= *(&mf->v1 + fidx);
-                       if(fverts[fidx] < 0 || fverts[fidx] >= totvert) {
-                               printf("    face %d: 'v%d' index out of range, %d\n", i, fidx + 1, fverts[fidx]);
+                       fv[fidx]= *(&(mf->v1) + fidx);
+                       if(fv[fidx] >= totvert) {
+                               PRINT("    face %u: 'v%d' index out of range, %u\n", i, fidx + 1, fv[fidx]);
+                               remove= do_fixes;
                        }
                } while (fidx--);
 
-               if(mf->v4) {
-                       if(mf->v1 == mf->v2) printf("    face %d: verts invalid, v1/v2 both %d\n", i, mf->v1);
-                       if(mf->v1 == mf->v3) printf("    face %d: verts invalid, v1/v3 both %d\n", i, mf->v1);
-                       if(mf->v1 == mf->v4) printf("    face %d: verts invalid, v1/v4 both %d\n", i, mf->v1);
+               if(remove == FALSE) {
+                       if(mf->v4) {
+                               if(mf->v1 == mf->v2) { PRINT("    face %u: verts invalid, v1/v2 both %u\n", i, mf->v1); remove= do_fixes; }
+                               if(mf->v1 == mf->v3) { PRINT("    face %u: verts invalid, v1/v3 both %u\n", i, mf->v1); remove= do_fixes;  }
+                               if(mf->v1 == mf->v4) { PRINT("    face %u: verts invalid, v1/v4 both %u\n", i, mf->v1); remove= do_fixes;  }
 
-                       if(mf->v2 == mf->v3) printf("    face %d: verts invalid, v2/v3 both %d\n", i, mf->v2);
-                       if(mf->v2 == mf->v4) printf("    face %d: verts invalid, v2/v4 both %d\n", i, mf->v2);
+                               if(mf->v2 == mf->v3) { PRINT("    face %u: verts invalid, v2/v3 both %u\n", i, mf->v2); remove= do_fixes;  }
+                               if(mf->v2 == mf->v4) { PRINT("    face %u: verts invalid, v2/v4 both %u\n", i, mf->v2); remove= do_fixes;  }
 
-                       if(mf->v3 == mf->v4) printf("    face %d: verts invalid, v3/v4 both %d\n", i, mf->v3);
+                               if(mf->v3 == mf->v4) { PRINT("    face %u: verts invalid, v3/v4 both %u\n", i, mf->v3); remove= do_fixes;  }
+                       }
+                       else {
+                               if(mf->v1 == mf->v2) { PRINT("    faceT %u: verts invalid, v1/v2 both %u\n", i, mf->v1); remove= do_fixes; }
+                               if(mf->v1 == mf->v3) { PRINT("    faceT %u: verts invalid, v1/v3 both %u\n", i, mf->v1); remove= do_fixes; }
 
-                       if(totedge) {
-                               if(!BLI_edgehash_haskey(edge_hash, mf->v1, mf->v2)) printf("    face %d: edge v1/v2 (%d,%d) is missing egde data\n", i, mf->v1, mf->v2);
-                               if(!BLI_edgehash_haskey(edge_hash, mf->v2, mf->v3)) printf("    face %d: edge v2/v3 (%d,%d) is missing egde data\n", i, mf->v2, mf->v3);
-                               if(!BLI_edgehash_haskey(edge_hash, mf->v3, mf->v4)) printf("    face %d: edge v3/v4 (%d,%d) is missing egde data\n", i, mf->v3, mf->v4);
-                               if(!BLI_edgehash_haskey(edge_hash, mf->v4, mf->v1)) printf("    face %d: edge v4/v1 (%d,%d) is missing egde data\n", i, mf->v4, mf->v1);
+                               if(mf->v2 == mf->v3) { PRINT("    faceT %u: verts invalid, v2/v3 both %u\n", i, mf->v2); remove= do_fixes; }
                        }
-                       /* TODO, avoid double lookop */
-                       /*
-                       fedges[0]= GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, mf->v1, mf->v2));
-                       fedges[1]= GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, mf->v2, mf->v3));
-                       fedges[2]= GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, mf->v3, mf->v4));
-                       fedges[3]= GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, mf->v4, mf->v1));
-                       */
-                       qsort(fverts, 4, sizeof(int), uint_cmp);
-               }
-               else {
-                       if(mf->v1 == mf->v2) printf("    face %d: verts invalid, v1/v2 both %d\n", i, mf->v1);
-                       if(mf->v1 == mf->v3) printf("    face %d: verts invalid, v1/v3 both %d\n", i, mf->v1);
 
-                       if(mf->v2 == mf->v3) printf("    face %d: verts invalid, v2/v3 both %d\n", i, mf->v2);
+                       if(remove == FALSE) {
+                               if(totedge) {
+                                       if(mf->v4) {
+                                               if(!BLI_edgehash_haskey(edge_hash, mf->v1, mf->v2)) { PRINT("    face %u: edge v1/v2 (%u,%u) is missing egde data\n", i, mf->v1, mf->v2); do_edge_recalc= TRUE; }
+                                               if(!BLI_edgehash_haskey(edge_hash, mf->v2, mf->v3)) { PRINT("    face %u: edge v2/v3 (%u,%u) is missing egde data\n", i, mf->v2, mf->v3); do_edge_recalc= TRUE; }
+                                               if(!BLI_edgehash_haskey(edge_hash, mf->v3, mf->v4)) { PRINT("    face %u: edge v3/v4 (%u,%u) is missing egde data\n", i, mf->v3, mf->v4); do_edge_recalc= TRUE; }
+                                               if(!BLI_edgehash_haskey(edge_hash, mf->v4, mf->v1)) { PRINT("    face %u: edge v4/v1 (%u,%u) is missing egde data\n", i, mf->v4, mf->v1); do_edge_recalc= TRUE; }
+                                       }
+                                       else {
+                                               if(!BLI_edgehash_haskey(edge_hash, mf->v1, mf->v2)) { PRINT("    face %u: edge v1/v2 (%u,%u) is missing egde data\n", i, mf->v1, mf->v2); do_edge_recalc= TRUE; }
+                                               if(!BLI_edgehash_haskey(edge_hash, mf->v2, mf->v3)) { PRINT("    face %u: edge v2/v3 (%u,%u) is missing egde data\n", i, mf->v2, mf->v3); do_edge_recalc= TRUE; }
+                                               if(!BLI_edgehash_haskey(edge_hash, mf->v3, mf->v1)) { PRINT("    face %u: edge v3/v1 (%u,%u) is missing egde data\n", i, mf->v3, mf->v1); do_edge_recalc= TRUE; }
+                                       }
+                               }
 
-                       if(totedge) {
-                               if(!BLI_edgehash_haskey(edge_hash, mf->v1, mf->v2)) printf("    face %d: edge v1/v2 (%d,%d) is missing egde data\n", i, mf->v1, mf->v2);
-                               if(!BLI_edgehash_haskey(edge_hash, mf->v2, mf->v3)) printf("    face %d: edge v2/v3 (%d,%d) is missing egde data\n", i, mf->v2, mf->v3);
-                               if(!BLI_edgehash_haskey(edge_hash, mf->v3, mf->v1)) printf("    face %d: edge v3/v1 (%d,%d) is missing egde data\n", i, mf->v3, mf->v1);
-                       }
-                       /* TODO, avoid double lookop */
-                       /*
-                       fedges[0]= GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, mf->v1, mf->v2));
-                       fedges[1]= GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, mf->v2, mf->v3));
-                       fedges[2]= GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, mf->v3, mf->v1));
-                       */
-                       qsort(fverts, 3, sizeof(int), uint_cmp);
-               }
+                               sf->index = i;
 
-               search_faces[i].index = i;
+                               if(mf->v4) {
+                                       edge_store_from_mface_quad(sf->es, mf);
 
-               if(mf->v4) {
-                       search_faces[i].v[0] = fverts[0];
-                       search_faces[i].v[1] = fverts[1];
-                       search_faces[i].v[2] = fverts[2];
-                       search_faces[i].v[3] = fverts[3];
+                                       qsort(sf->es, 4, sizeof(int64_t), int64_cmp);
+                               }
+                               else {
+                                       edge_store_from_mface_tri(sf->es, mf);
+                                       qsort(sf->es, 3, sizeof(int64_t), int64_cmp);
+                               }
+
+                               totsortface++;
+                               sf++;
+                       }
                }
-               else {
-                       search_faces[i].v[0] = fverts[0];
-                       search_faces[i].v[1] = fverts[1];
-                       search_faces[i].v[2] = fverts[2];
-                       search_faces[i].v[3] = UINT_MAX;
+               if(remove) {
+                       REMOVE_FACE_TAG(mf);
                }
        }
 
-       qsort(search_faces, totface, sizeof(SearchFace), search_face_cmp);
+       qsort(sort_faces, totsortface, sizeof(SortFace), search_face_cmp);
 
-       sf= search_faces;
+       sf= sort_faces;
        sf_prev= sf;
        sf++;
 
-       for(i=1; i<totface; i++, sf++, sf_prev++) {
+       for(i=1; i<totsortface; i++, sf++) {
+               int remove= FALSE;
                /* on a valid mesh, code below will never run */
-               if(memcmp(sf->v, sf_prev->v, sizeof(sf_prev->v)) == 0) {
-                       /* slow, could be smarter here */
-                       MFace *mf= mfaces + sf->index;
-                       MFace *mf_prev= mfaces + sf_prev->index;
-                       int size_expect, size_found;
+               if(memcmp(sf->es, sf_prev->es, sizeof(sf_prev->es)) == 0) {
+                       mf= mfaces + sf->index;
 
-                       EdgeHash *eh_tmp= BLI_edgehash_new();
-                       if(mf->v4) {
-                               BLI_edgehash_insert(eh_tmp, mf->v1, mf->v2, NULL);
-                               BLI_edgehash_insert(eh_tmp, mf->v2, mf->v3, NULL);
-                               BLI_edgehash_insert(eh_tmp, mf->v3, mf->v4, NULL);
-                               BLI_edgehash_insert(eh_tmp, mf->v4, mf->v1, NULL);
+                       if(do_verbose) {
+                               mf_prev= mfaces + sf_prev->index;
+                               if(mf->v4) {
+                                       PRINT("    face %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("    face %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);
+                               }
+                       }
 
-                               BLI_edgehash_insert(eh_tmp, mf_prev->v1, mf_prev->v2, NULL);
-                               BLI_edgehash_insert(eh_tmp, mf_prev->v2, mf_prev->v3, NULL);
-                               BLI_edgehash_insert(eh_tmp, mf_prev->v3, mf_prev->v4, NULL);
-                               BLI_edgehash_insert(eh_tmp, mf_prev->v4, mf_prev->v1, NULL);
+                       remove= do_fixes;
+               }
+               else {
+                       sf_prev= sf;
+               }
 
-                               size_expect= 4;
-                       }
-                       else {
-                               BLI_edgehash_insert(eh_tmp, mf->v1, mf->v2, NULL);
-                               BLI_edgehash_insert(eh_tmp, mf->v2, mf->v3, NULL);
-                               BLI_edgehash_insert(eh_tmp, mf->v3, mf->v1, NULL);
+               if(remove) {
+                       REMOVE_FACE_TAG(mf);
+               }
+       }
 
-                               BLI_edgehash_insert(eh_tmp, mf_prev->v1, mf_prev->v2, NULL);
-                               BLI_edgehash_insert(eh_tmp, mf_prev->v2, mf_prev->v3, NULL);
-                               BLI_edgehash_insert(eh_tmp, mf_prev->v3, mf_prev->v1, NULL);
+       BLI_edgehash_free(edge_hash, NULL);
+       MEM_freeN(sort_faces);
 
-                               size_expect= 3;
-                       }
+       PRINT("BKE_mesh_validate: finished\n\n");
 
-                       size_found= BLI_edgehash_size(eh_tmp);
-                       BLI_edgehash_free(eh_tmp, NULL);
+#       undef REMOVE_EDGE_TAG
+#       undef REMOVE_FACE_TAG
 
-                       if(size_found != size_expect) {
-                               printf("    face %d & %d: are duplicates ", sf->index, sf_prev->index);
-                               if(mf->v4) {
-                                       printf("(%d,%d,%d,%d) ", mf->v1, mf->v2, mf->v3, mf->v4);
-                                       printf("(%d,%d,%d,%d)\n", mf_prev->v1, mf_prev->v2, mf_prev->v3, mf_prev->v4);
-                               }
-                               else {
-                                       printf("(%d,%d,%d) ", mf->v1, mf->v2, mf->v3);
-                                       printf("(%d,%d,%d)\n", mf_prev->v1, mf_prev->v2, mf_prev->v3);
-                               }
+       if(me) {
+               if(do_face_free) {
+                       mesh_strip_loose_faces(me);
+               }
+
+               if (do_edge_free) {
+                       mesh_strip_loose_edges(me);
+               }
+
+               if(do_fixes && do_edge_recalc) {
+                       BKE_mesh_calc_edges(me, TRUE);
+               }
+       }
+
+       return (do_face_free || do_edge_free || do_edge_recalc);
+}
+
+static int mesh_validate_customdata(CustomData *data, short do_verbose, const short do_fixes)
+{
+       int i= 0, has_fixes= 0;
+
+       while(i<data->totlayer) {
+               CustomDataLayer *layer= &data->layers[i];
+               int mask= 1 << layer->type;
+               int ok= 1;
+
+               if((mask&CD_MASK_MESH)==0) {
+                       PRINT("CustomDataLayer type %d which isn't in CD_MASK_MESH is stored in Mehs structure\n", layer->type);
+
+                       if(do_fixes) {
+                               CustomData_free_layer(data, layer->type, 0, i);
+                               ok= 0;
+                               has_fixes= 1;
                        }
                }
+
+               if(ok)
+                       i++;
        }
 
-       BLI_edgehash_free(edge_hash, NULL);
-       MEM_freeN(search_faces);
+       return has_fixes;
+}
+
+#undef PRINT
+
+int BKE_mesh_validate_all_customdata(CustomData *vdata, CustomData *edata, CustomData *fdata, short do_verbose, const short do_fixes)
+{
+       int vfixed= 0, efixed= 0, ffixed= 0;
 
-       printf("BKE_mesh_validate: finished\n\n");
+       vfixed= mesh_validate_customdata(vdata, do_verbose, do_fixes);
+       efixed= mesh_validate_customdata(edata, do_verbose, do_fixes);
+       ffixed= mesh_validate_customdata(fdata, do_verbose, do_fixes);
+
+       return vfixed || efixed || ffixed;
 }
 
-void BKE_mesh_validate(Mesh *me)
+int BKE_mesh_validate(Mesh *me, int do_verbose)
 {
-       printf("MESH: %s\n", me->id.name+2);
-       BKE_mesh_validate_arrays(me->mvert, me->totvert, me->medge, me->totedge, me->mface, me->totface);
+       int layers_fixed= 0, arrays_fixed= 0;
+
+       if(do_verbose) {
+               printf("MESH: %s\n", me->id.name+2);
+       }
+
+       layers_fixed= BKE_mesh_validate_all_customdata(&me->vdata, &me->edata, &me->fdata, do_verbose, TRUE);
+       arrays_fixed= BKE_mesh_validate_arrays(me, me->mvert, me->totvert, me->medge, me->totedge, me->mface, me->totface, do_verbose, TRUE);
+
+       return layers_fixed || arrays_fixed;
+}
+
+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->getFaceArray(dm), dm->getNumFaces(dm), TRUE, FALSE);
 }
 
-void BKE_mesh_validate_dm(DerivedMesh *dm)
+void BKE_mesh_calc_edges(Mesh *mesh, int update)
 {
-       BKE_mesh_validate_arrays(dm->getVertArray(dm), dm->getNumVerts(dm), dm->getEdgeArray(dm), dm->getNumEdges(dm), dm->getFaceArray(dm), dm->getNumFaces(dm));
+       CustomData edata;
+       EdgeHashIterator *ehi;
+       MFace *mf = mesh->mface;
+       MEdge *med, *med_orig;
+       EdgeHash *eh = BLI_edgehash_new();
+       int i, totedge, totface = mesh->totface;
+
+       if(mesh->totedge==0)
+               update= 0;
+
+       if(update) {
+               /* assume existing edges are valid
+                * useful when adding more faces and generating edges from them */
+               med= mesh->medge;
+               for(i= 0; i<mesh->totedge; i++, med++)
+                       BLI_edgehash_insert(eh, med->v1, med->v2, med);
+       }
+
+       for (i = 0; i < totface; i++, mf++) {
+               if (!BLI_edgehash_haskey(eh, mf->v1, mf->v2))
+                       BLI_edgehash_insert(eh, mf->v1, mf->v2, NULL);
+               if (!BLI_edgehash_haskey(eh, mf->v2, mf->v3))
+                       BLI_edgehash_insert(eh, mf->v2, mf->v3, NULL);
+
+               if (mf->v4) {
+                       if (!BLI_edgehash_haskey(eh, mf->v3, mf->v4))
+                               BLI_edgehash_insert(eh, mf->v3, mf->v4, NULL);
+                       if (!BLI_edgehash_haskey(eh, mf->v4, mf->v1))
+                               BLI_edgehash_insert(eh, mf->v4, mf->v1, NULL);
+               } else {
+                       if (!BLI_edgehash_haskey(eh, mf->v3, mf->v1))
+                               BLI_edgehash_insert(eh, mf->v3, mf->v1, NULL);
+               }
+       }
+
+       totedge = BLI_edgehash_size(eh);
+
+       /* write new edges into a temporary CustomData */
+       memset(&edata, 0, sizeof(edata));
+       CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
+
+       ehi = BLI_edgehashIterator_new(eh);
+       med = CustomData_get_layer(&edata, CD_MEDGE);
+       for(i = 0; !BLI_edgehashIterator_isDone(ehi);
+               BLI_edgehashIterator_step(ehi), ++i, ++med) {
+
+               if(update && (med_orig=BLI_edgehashIterator_getValue(ehi))) {
+                       *med= *med_orig; /* copy from the original */
+               } else {
+                       BLI_edgehashIterator_getKey(ehi, (int*)&med->v1, (int*)&med->v2);
+                       med->flag = ME_EDGEDRAW|ME_EDGERENDER|SELECT; /* select for newly created meshes which are selected [#25595] */
+               }
+       }
+       BLI_edgehashIterator_free(ehi);
+
+       /* free old CustomData and assign new one */
+       CustomData_free(&mesh->edata, mesh->totedge);
+       mesh->edata = edata;
+       mesh->totedge = totedge;
+
+       mesh->medge = CustomData_get_layer(&mesh->edata, CD_MEDGE);
+
+       BLI_edgehash_free(eh, NULL);
 }