Blender  V2.93
mesh_validate.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2011 Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include <limits.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "CLG_log.h"
30 
31 #include "DNA_mesh_types.h"
32 #include "DNA_meshdata_types.h"
33 #include "DNA_object_types.h"
34 
35 #include "BLI_sys_types.h"
36 
37 #include "BLI_edgehash.h"
38 #include "BLI_math_base.h"
39 #include "BLI_math_vector.h"
40 #include "BLI_utildefines.h"
41 
42 #include "BKE_customdata.h"
43 #include "BKE_deform.h"
44 #include "BKE_mesh.h"
45 
46 #include "DEG_depsgraph.h"
47 
48 #include "MEM_guardedalloc.h"
49 
50 /* loop v/e are unsigned, so using max uint_32 value as invalid marker... */
51 #define INVALID_LOOP_EDGE_MARKER 4294967295u
52 
53 static CLG_LogRef LOG = {"bke.mesh"};
54 
55 /* -------------------------------------------------------------------- */
59 typedef union {
62 } EdgeUUID;
63 
64 typedef struct SortFace {
66  unsigned int index;
68 
69 /* Used to detect polys (faces) using exactly the same vertices. */
70 /* Used to detect loops used by no (disjoint) or more than one (intersect) polys. */
71 typedef struct SortPoly {
72  int *verts;
73  int numverts;
74  int loopstart;
75  unsigned int index;
76  bool invalid; /* Poly index. */
78 
79 static void edge_store_assign(uint32_t verts[2], const uint32_t v1, const uint32_t v2)
80 {
81  if (v1 < v2) {
82  verts[0] = v1;
83  verts[1] = v2;
84  }
85  else {
86  verts[0] = v2;
87  verts[1] = v1;
88  }
89 }
90 
91 static void edge_store_from_mface_quad(EdgeUUID es[4], MFace *mf)
92 {
93  edge_store_assign(es[0].verts, mf->v1, mf->v2);
94  edge_store_assign(es[1].verts, mf->v2, mf->v3);
95  edge_store_assign(es[2].verts, mf->v3, mf->v4);
96  edge_store_assign(es[3].verts, mf->v4, mf->v1);
97 }
98 
99 static void edge_store_from_mface_tri(EdgeUUID es[4], MFace *mf)
100 {
101  edge_store_assign(es[0].verts, mf->v1, mf->v2);
102  edge_store_assign(es[1].verts, mf->v2, mf->v3);
103  edge_store_assign(es[2].verts, mf->v3, mf->v1);
104  es[3].verts[0] = es[3].verts[1] = UINT_MAX;
105 }
106 
107 static int int64_cmp(const void *v1, const void *v2)
108 {
109  const int64_t x1 = *(const int64_t *)v1;
110  const int64_t x2 = *(const int64_t *)v2;
111 
112  if (x1 > x2) {
113  return 1;
114  }
115  if (x1 < x2) {
116  return -1;
117  }
118 
119  return 0;
120 }
121 
122 static int search_face_cmp(const void *v1, const void *v2)
123 {
124  const SortFace *sfa = v1, *sfb = v2;
125 
126  if (sfa->es[0].edval > sfb->es[0].edval) {
127  return 1;
128  }
129  if (sfa->es[0].edval < sfb->es[0].edval) {
130  return -1;
131  }
132 
133  if (sfa->es[1].edval > sfb->es[1].edval) {
134  return 1;
135  }
136  if (sfa->es[1].edval < sfb->es[1].edval) {
137  return -1;
138  }
139 
140  if (sfa->es[2].edval > sfb->es[2].edval) {
141  return 1;
142  }
143  if (sfa->es[2].edval < sfb->es[2].edval) {
144  return -1;
145  }
146 
147  if (sfa->es[3].edval > sfb->es[3].edval) {
148  return 1;
149  }
150  if (sfa->es[3].edval < sfb->es[3].edval) {
151  return -1;
152  }
153 
154  return 0;
155 }
156 
157 /* TODO check there is not some standard define of this somewhere! */
158 static int int_cmp(const void *v1, const void *v2)
159 {
160  return *(int *)v1 > *(int *)v2 ? 1 : *(int *)v1 < *(int *)v2 ? -1 : 0;
161 }
162 
163 static int search_poly_cmp(const void *v1, const void *v2)
164 {
165  const SortPoly *sp1 = v1;
166  const SortPoly *sp2 = v2;
167 
168  /* Reject all invalid polys at end of list! */
169  if (sp1->invalid || sp2->invalid) {
170  return sp1->invalid ? (sp2->invalid ? 0 : 1) : -1;
171  }
172  /* Else, sort on first non-equal verts (remember verts of valid polys are sorted). */
173  const int max_idx = sp1->numverts > sp2->numverts ? sp2->numverts : sp1->numverts;
174  for (int idx = 0; idx < max_idx; idx++) {
175  const int v1_i = sp1->verts[idx];
176  const int v2_i = sp2->verts[idx];
177  if (v1_i != v2_i) {
178  return (v1_i > v2_i) ? 1 : -1;
179  }
180  }
181  return sp1->numverts > sp2->numverts ? 1 : sp1->numverts < sp2->numverts ? -1 : 0;
182 }
183 
184 static int search_polyloop_cmp(const void *v1, const void *v2)
185 {
186  const SortPoly *sp1 = v1;
187  const SortPoly *sp2 = v2;
188 
189  /* Reject all invalid polys at end of list! */
190  if (sp1->invalid || sp2->invalid) {
191  return sp1->invalid && sp2->invalid ? 0 : sp1->invalid ? 1 : -1;
192  }
193  /* Else, sort on loopstart. */
194  return sp1->loopstart > sp2->loopstart ? 1 : sp1->loopstart < sp2->loopstart ? -1 : 0;
195 }
198 /* -------------------------------------------------------------------- */
202 #define PRINT_MSG(...) \
203  if (do_verbose) { \
204  CLOG_INFO(&LOG, 1, __VA_ARGS__); \
205  } \
206  ((void)0)
207 
208 #define PRINT_ERR(...) \
209  do { \
210  is_valid = false; \
211  if (do_verbose) { \
212  CLOG_ERROR(&LOG, __VA_ARGS__); \
213  } \
214  } while (0)
215 
221 /* NOLINTNEXTLINE: readability-function-size */
223  MVert *mverts,
224  unsigned int totvert,
225  MEdge *medges,
226  unsigned int totedge,
227  MFace *mfaces,
228  unsigned int totface,
229  MLoop *mloops,
230  unsigned int totloop,
231  MPoly *mpolys,
232  unsigned int totpoly,
233  MDeformVert *dverts, /* assume totvert length */
234  const bool do_verbose,
235  const bool do_fixes,
236  bool *r_changed)
237 {
238 #define REMOVE_EDGE_TAG(_me) \
239  { \
240  _me->v2 = _me->v1; \
241  free_flag.edges = do_fixes; \
242  } \
243  (void)0
244 #define IS_REMOVED_EDGE(_me) (_me->v2 == _me->v1)
245 
246 #define REMOVE_LOOP_TAG(_ml) \
247  { \
248  _ml->e = INVALID_LOOP_EDGE_MARKER; \
249  free_flag.polyloops = do_fixes; \
250  } \
251  (void)0
252 #define REMOVE_POLY_TAG(_mp) \
253  { \
254  _mp->totloop *= -1; \
255  free_flag.polyloops = do_fixes; \
256  } \
257  (void)0
258 
259  MVert *mv = mverts;
260  MEdge *me;
261  MLoop *ml;
262  MPoly *mp;
263  unsigned int i, j;
264  int *v;
265 
266  bool is_valid = true;
267 
268  union {
269  struct {
270  int verts : 1;
271  int verts_weight : 1;
272  int loops_edge : 1;
273  };
274  int as_flag;
275  } fix_flag;
276 
277  union {
278  struct {
279  int edges : 1;
280  int faces : 1;
281  /* This regroups loops and polys! */
282  int polyloops : 1;
283  int mselect : 1;
284  };
285  int as_flag;
286  } free_flag;
287 
288  union {
289  struct {
290  int edges : 1;
291  };
292  int as_flag;
293  } recalc_flag;
294 
295  EdgeHash *edge_hash = BLI_edgehash_new_ex(__func__, totedge);
296 
297  BLI_assert(!(do_fixes && mesh == NULL));
298 
299  fix_flag.as_flag = 0;
300  free_flag.as_flag = 0;
301  recalc_flag.as_flag = 0;
302 
303  PRINT_MSG("verts(%u), edges(%u), loops(%u), polygons(%u)", totvert, totedge, totloop, totpoly);
304 
305  if (totedge == 0 && totpoly != 0) {
306  PRINT_ERR("\tLogical error, %u polygons and 0 edges", totpoly);
307  recalc_flag.edges = do_fixes;
308  }
309 
310  for (i = 0; i < totvert; i++, mv++) {
311  bool fix_normal = true;
312 
313  for (j = 0; j < 3; j++) {
314  if (!isfinite(mv->co[j])) {
315  PRINT_ERR("\tVertex %u: has invalid coordinate", i);
316 
317  if (do_fixes) {
318  zero_v3(mv->co);
319 
320  fix_flag.verts = true;
321  }
322  }
323 
324  if (mv->no[j] != 0) {
325  fix_normal = false;
326  break;
327  }
328  }
329 
330  if (fix_normal) {
331  PRINT_ERR("\tVertex %u: has zero normal, assuming Z-up normal", i);
332  if (do_fixes) {
333  mv->no[2] = SHRT_MAX;
334  fix_flag.verts = true;
335  }
336  }
337  }
338 
339  for (i = 0, me = medges; i < totedge; i++, me++) {
340  bool remove = false;
341 
342  if (me->v1 == me->v2) {
343  PRINT_ERR("\tEdge %u: has matching verts, both %u", i, me->v1);
344  remove = do_fixes;
345  }
346  if (me->v1 >= totvert) {
347  PRINT_ERR("\tEdge %u: v1 index out of range, %u", i, me->v1);
348  remove = do_fixes;
349  }
350  if (me->v2 >= totvert) {
351  PRINT_ERR("\tEdge %u: v2 index out of range, %u", i, me->v2);
352  remove = do_fixes;
353  }
354 
355  if ((me->v1 != me->v2) && BLI_edgehash_haskey(edge_hash, me->v1, me->v2)) {
356  PRINT_ERR("\tEdge %u: is a duplicate of %d",
357  i,
358  POINTER_AS_INT(BLI_edgehash_lookup(edge_hash, me->v1, me->v2)));
359  remove = do_fixes;
360  }
361 
362  if (remove == false) {
363  if (me->v1 != me->v2) {
364  BLI_edgehash_insert(edge_hash, me->v1, me->v2, POINTER_FROM_INT(i));
365  }
366  }
367  else {
368  REMOVE_EDGE_TAG(me);
369  }
370  }
371 
372  if (mfaces && !mpolys) {
373 #define REMOVE_FACE_TAG(_mf) \
374  { \
375  _mf->v3 = 0; \
376  free_flag.faces = do_fixes; \
377  } \
378  (void)0
379 #define CHECK_FACE_VERT_INDEX(a, b) \
380  if (mf->a == mf->b) { \
381  PRINT_ERR(" face %u: verts invalid, " STRINGIFY(a) "/" STRINGIFY(b) " both %u", i, mf->a); \
382  remove = do_fixes; \
383  } \
384  (void)0
385 #define CHECK_FACE_EDGE(a, b) \
386  if (!BLI_edgehash_haskey(edge_hash, mf->a, mf->b)) { \
387  PRINT_ERR(" face %u: edge " STRINGIFY(a) "/" STRINGIFY(b) " (%u,%u) is missing edge data", \
388  i, \
389  mf->a, \
390  mf->b); \
391  recalc_flag.edges = do_fixes; \
392  } \
393  (void)0
394 
395  MFace *mf;
396  MFace *mf_prev;
397 
398  SortFace *sort_faces = MEM_callocN(sizeof(SortFace) * totface, "search faces");
399  SortFace *sf;
400  SortFace *sf_prev;
401  unsigned int totsortface = 0;
402 
403  PRINT_ERR("No Polys, only tessellated Faces");
404 
405  for (i = 0, mf = mfaces, sf = sort_faces; i < totface; i++, mf++) {
406  bool remove = false;
407  int fidx;
408  unsigned int fv[4];
409 
410  fidx = mf->v4 ? 3 : 2;
411  do {
412  fv[fidx] = *(&(mf->v1) + fidx);
413  if (fv[fidx] >= totvert) {
414  PRINT_ERR("\tFace %u: 'v%d' index out of range, %u", i, fidx + 1, fv[fidx]);
415  remove = do_fixes;
416  }
417  } while (fidx--);
418 
419  if (remove == false) {
420  if (mf->v4) {
424 
427 
428  CHECK_FACE_VERT_INDEX(v3, v4);
429  }
430  else {
433 
435  }
436 
437  if (remove == false) {
438  if (totedge) {
439  if (mf->v4) {
441  CHECK_FACE_EDGE(v2, v3);
442  CHECK_FACE_EDGE(v3, v4);
443  CHECK_FACE_EDGE(v4, v1);
444  }
445  else {
447  CHECK_FACE_EDGE(v2, v3);
448  CHECK_FACE_EDGE(v3, v1);
449  }
450  }
451 
452  sf->index = i;
453 
454  if (mf->v4) {
456 
457  qsort(sf->es, 4, sizeof(int64_t), int64_cmp);
458  }
459  else {
460  edge_store_from_mface_tri(sf->es, mf);
461  qsort(sf->es, 3, sizeof(int64_t), int64_cmp);
462  }
463 
464  totsortface++;
465  sf++;
466  }
467  }
468 
469  if (remove) {
470  REMOVE_FACE_TAG(mf);
471  }
472  }
473 
474  qsort(sort_faces, totsortface, sizeof(SortFace), search_face_cmp);
475 
476  sf = sort_faces;
477  sf_prev = sf;
478  sf++;
479 
480  for (i = 1; i < totsortface; i++, sf++) {
481  bool remove = false;
482 
483  /* on a valid mesh, code below will never run */
484  if (memcmp(sf->es, sf_prev->es, sizeof(sf_prev->es)) == 0) {
485  mf = mfaces + sf->index;
486 
487  if (do_verbose) {
488  mf_prev = mfaces + sf_prev->index;
489 
490  if (mf->v4) {
491  PRINT_ERR("\tFace %u & %u: are duplicates (%u,%u,%u,%u) (%u,%u,%u,%u)",
492  sf->index,
493  sf_prev->index,
494  mf->v1,
495  mf->v2,
496  mf->v3,
497  mf->v4,
498  mf_prev->v1,
499  mf_prev->v2,
500  mf_prev->v3,
501  mf_prev->v4);
502  }
503  else {
504  PRINT_ERR("\tFace %u & %u: are duplicates (%u,%u,%u) (%u,%u,%u)",
505  sf->index,
506  sf_prev->index,
507  mf->v1,
508  mf->v2,
509  mf->v3,
510  mf_prev->v1,
511  mf_prev->v2,
512  mf_prev->v3);
513  }
514  }
515 
516  remove = do_fixes;
517  }
518  else {
519  sf_prev = sf;
520  }
521 
522  if (remove) {
523  REMOVE_FACE_TAG(mf);
524  }
525  }
526 
527  MEM_freeN(sort_faces);
528 
529 #undef REMOVE_FACE_TAG
530 #undef CHECK_FACE_VERT_INDEX
531 #undef CHECK_FACE_EDGE
532  }
533 
534  /* Checking loops and polys is a bit tricky, as they are quite intricate...
535  *
536  * Polys must have:
537  * - a valid loopstart value.
538  * - a valid totloop value (>= 3 and loopstart+totloop < me.totloop).
539  *
540  * Loops must have:
541  * - a valid v value.
542  * - a valid e value (corresponding to the edge it defines with the next loop in poly).
543  *
544  * Also, loops not used by polys can be discarded.
545  * And "intersecting" loops (i.e. loops used by more than one poly) are invalid,
546  * so be sure to leave at most one poly per loop!
547  */
548  {
549  SortPoly *sort_polys = MEM_callocN(sizeof(SortPoly) * totpoly, "mesh validate's sort_polys");
550  SortPoly *prev_sp, *sp = sort_polys;
551  int prev_end;
552 
553  for (i = 0, mp = mpolys; i < totpoly; i++, mp++, sp++) {
554  sp->index = i;
555 
556  /* Material index, isolated from other tests here. While large indices are clamped,
557  * negative indices aren't supported by drawing, exporters etc.
558  * To check the indices are in range, use #BKE_mesh_validate_material_indices */
559  if (mp->mat_nr < 0) {
560  PRINT_ERR("\tPoly %u has invalid material (%d)", sp->index, mp->mat_nr);
561  if (do_fixes) {
562  mp->mat_nr = 0;
563  }
564  }
565 
566  if (mp->loopstart < 0 || mp->totloop < 3) {
567  /* Invalid loop data. */
568  PRINT_ERR("\tPoly %u is invalid (loopstart: %d, totloop: %d)",
569  sp->index,
570  mp->loopstart,
571  mp->totloop);
572  sp->invalid = true;
573  }
574  else if (mp->loopstart + mp->totloop > totloop) {
575  /* Invalid loop data. */
576  PRINT_ERR(
577  "\tPoly %u uses loops out of range (loopstart: %d, loopend: %d, max nbr of loops: %u)",
578  sp->index,
579  mp->loopstart,
580  mp->loopstart + mp->totloop - 1,
581  totloop - 1);
582  sp->invalid = true;
583  }
584  else {
585  /* Poly itself is valid, for now. */
586  int v1, v2; /* v1 is prev loop vert idx, v2 is current loop one. */
587  sp->invalid = false;
588  sp->verts = v = MEM_mallocN(sizeof(int) * mp->totloop, "Vert idx of SortPoly");
589  sp->numverts = mp->totloop;
590  sp->loopstart = mp->loopstart;
591 
592  /* Ideally we would only have to do that once on all vertices
593  * before we start checking each poly, but several polys can use same vert,
594  * so we have to ensure here all verts of current poly are cleared. */
595  for (j = 0, ml = &mloops[sp->loopstart]; j < mp->totloop; j++, ml++) {
596  if (ml->v < totvert) {
597  mverts[ml->v].flag &= ~ME_VERT_TMP_TAG;
598  }
599  }
600 
601  /* Test all poly's loops' vert idx. */
602  for (j = 0, ml = &mloops[sp->loopstart]; j < mp->totloop; j++, ml++, v++) {
603  if (ml->v >= totvert) {
604  /* Invalid vert idx. */
605  PRINT_ERR("\tLoop %u has invalid vert reference (%u)", sp->loopstart + j, ml->v);
606  sp->invalid = true;
607  }
608  else if (mverts[ml->v].flag & ME_VERT_TMP_TAG) {
609  PRINT_ERR("\tPoly %u has duplicated vert reference at corner (%u)", i, j);
610  sp->invalid = true;
611  }
612  else {
613  mverts[ml->v].flag |= ME_VERT_TMP_TAG;
614  }
615  *v = ml->v;
616  }
617 
618  if (sp->invalid) {
619  continue;
620  }
621 
622  /* Test all poly's loops. */
623  for (j = 0, ml = &mloops[sp->loopstart]; j < mp->totloop; j++, ml++) {
624  v1 = ml->v;
625  v2 = mloops[sp->loopstart + (j + 1) % mp->totloop].v;
626  if (!BLI_edgehash_haskey(edge_hash, v1, v2)) {
627  /* Edge not existing. */
628  PRINT_ERR("\tPoly %u needs missing edge (%d, %d)", sp->index, v1, v2);
629  if (do_fixes) {
630  recalc_flag.edges = true;
631  }
632  else {
633  sp->invalid = true;
634  }
635  }
636  else if (ml->e >= totedge) {
637  /* Invalid edge idx.
638  * We already know from previous text that a valid edge exists, use it (if allowed)! */
639  if (do_fixes) {
640  int prev_e = ml->e;
641  ml->e = POINTER_AS_INT(BLI_edgehash_lookup(edge_hash, v1, v2));
642  fix_flag.loops_edge = true;
643  PRINT_ERR("\tLoop %u has invalid edge reference (%d), fixed using edge %u",
644  sp->loopstart + j,
645  prev_e,
646  ml->e);
647  }
648  else {
649  PRINT_ERR("\tLoop %u has invalid edge reference (%u)", sp->loopstart + j, ml->e);
650  sp->invalid = true;
651  }
652  }
653  else {
654  me = &medges[ml->e];
655  if (IS_REMOVED_EDGE(me) ||
656  !((me->v1 == v1 && me->v2 == v2) || (me->v1 == v2 && me->v2 == v1))) {
657  /* The pointed edge is invalid (tagged as removed, or vert idx mismatch),
658  * and we already know from previous test that a valid one exists,
659  * use it (if allowed)! */
660  if (do_fixes) {
661  int prev_e = ml->e;
662  ml->e = POINTER_AS_INT(BLI_edgehash_lookup(edge_hash, v1, v2));
663  fix_flag.loops_edge = true;
664  PRINT_ERR(
665  "\tPoly %u has invalid edge reference (%d, is_removed: %d), fixed using edge "
666  "%u",
667  sp->index,
668  prev_e,
669  IS_REMOVED_EDGE(me),
670  ml->e);
671  }
672  else {
673  PRINT_ERR("\tPoly %u has invalid edge reference (%u)", sp->index, ml->e);
674  sp->invalid = true;
675  }
676  }
677  }
678  }
679 
680  if (!sp->invalid) {
681  /* Needed for checking polys using same verts below. */
682  qsort(sp->verts, sp->numverts, sizeof(int), int_cmp);
683  }
684  }
685  }
686 
687  /* Second check pass, testing polys using the same verts. */
688  qsort(sort_polys, totpoly, sizeof(SortPoly), search_poly_cmp);
689  sp = prev_sp = sort_polys;
690  sp++;
691 
692  for (i = 1; i < totpoly; i++, sp++) {
693  int p1_nv = sp->numverts, p2_nv = prev_sp->numverts;
694  const int *p1_v = sp->verts, *p2_v = prev_sp->verts;
695 
696  if (sp->invalid) {
697  /* Break, because all known invalid polys have been put at the end
698  * by qsort with search_poly_cmp. */
699  break;
700  }
701 
702  /* Test same polys. */
703  if ((p1_nv == p2_nv) && (memcmp(p1_v, p2_v, p1_nv * sizeof(*p1_v)) == 0)) {
704  if (do_verbose) {
705  /* TODO: convert list to string */
706  PRINT_ERR("\tPolys %u and %u use same vertices (%d", prev_sp->index, sp->index, *p1_v);
707  for (j = 1; j < p1_nv; j++) {
708  PRINT_ERR(", %d", p1_v[j]);
709  }
710  PRINT_ERR("), considering poly %u as invalid.", sp->index);
711  }
712  else {
713  is_valid = false;
714  }
715  sp->invalid = true;
716  }
717  else {
718  prev_sp = sp;
719  }
720  }
721 
722  /* Third check pass, testing loops used by none or more than one poly. */
723  qsort(sort_polys, totpoly, sizeof(SortPoly), search_polyloop_cmp);
724  sp = sort_polys;
725  prev_sp = NULL;
726  prev_end = 0;
727  for (i = 0; i < totpoly; i++, sp++) {
728  /* Free this now, we don't need it anymore, and avoid us another loop! */
729  if (sp->verts) {
730  MEM_freeN(sp->verts);
731  }
732 
733  /* Note above prev_sp: in following code, we make sure it is always valid poly (or NULL). */
734  if (sp->invalid) {
735  if (do_fixes) {
736  REMOVE_POLY_TAG((&mpolys[sp->index]));
737  /* DO NOT REMOVE ITS LOOPS!!!
738  * As already invalid polys are at the end of the SortPoly list, the loops they
739  * were the only users have already been tagged as "to remove" during previous
740  * iterations, and we don't want to remove some loops that may be used by
741  * another valid poly! */
742  }
743  }
744  /* Test loops users. */
745  else {
746  /* Unused loops. */
747  if (prev_end < sp->loopstart) {
748  for (j = prev_end, ml = &mloops[prev_end]; j < sp->loopstart; j++, ml++) {
749  PRINT_ERR("\tLoop %u is unused.", j);
750  if (do_fixes) {
751  REMOVE_LOOP_TAG(ml);
752  }
753  }
754  prev_end = sp->loopstart + sp->numverts;
755  prev_sp = sp;
756  }
757  /* Multi-used loops. */
758  else if (prev_end > sp->loopstart) {
759  PRINT_ERR("\tPolys %u and %u share loops from %d to %d, considering poly %u as invalid.",
760  prev_sp->index,
761  sp->index,
762  sp->loopstart,
763  prev_end,
764  sp->index);
765  if (do_fixes) {
766  REMOVE_POLY_TAG((&mpolys[sp->index]));
767  /* DO NOT REMOVE ITS LOOPS!!!
768  * They might be used by some next, valid poly!
769  * Just not updating prev_end/prev_sp vars is enough to ensure the loops
770  * effectively no more needed will be marked as "to be removed"! */
771  }
772  }
773  else {
774  prev_end = sp->loopstart + sp->numverts;
775  prev_sp = sp;
776  }
777  }
778  }
779  /* We may have some remaining unused loops to get rid of! */
780  if (prev_end < totloop) {
781  for (j = prev_end, ml = &mloops[prev_end]; j < totloop; j++, ml++) {
782  PRINT_ERR("\tLoop %u is unused.", j);
783  if (do_fixes) {
784  REMOVE_LOOP_TAG(ml);
785  }
786  }
787  }
788 
789  MEM_freeN(sort_polys);
790  }
791 
792  BLI_edgehash_free(edge_hash, NULL);
793 
794  /* fix deform verts */
795  if (dverts) {
796  MDeformVert *dv;
797  for (i = 0, dv = dverts; i < totvert; i++, dv++) {
798  MDeformWeight *dw;
799 
800  for (j = 0, dw = dv->dw; j < dv->totweight; j++, dw++) {
801  /* note, greater than max defgroups is accounted for in our code, but not < 0 */
802  if (!isfinite(dw->weight)) {
803  PRINT_ERR("\tVertex deform %u, group %u has weight: %f", i, dw->def_nr, dw->weight);
804  if (do_fixes) {
805  dw->weight = 0.0f;
806  fix_flag.verts_weight = true;
807  }
808  }
809  else if (dw->weight < 0.0f || dw->weight > 1.0f) {
810  PRINT_ERR("\tVertex deform %u, group %u has weight: %f", i, dw->def_nr, dw->weight);
811  if (do_fixes) {
812  CLAMP(dw->weight, 0.0f, 1.0f);
813  fix_flag.verts_weight = true;
814  }
815  }
816 
817  /* Not technically incorrect since this is unsigned, however,
818  * a value over INT_MAX is almost certainly caused by wrapping an unsigned int. */
819  if (dw->def_nr >= INT_MAX) {
820  PRINT_ERR("\tVertex deform %u, has invalid group %u", i, dw->def_nr);
821  if (do_fixes) {
822  BKE_defvert_remove_group(dv, dw);
823  fix_flag.verts_weight = true;
824 
825  if (dv->dw) {
826  /* re-allocated, the new values compensate for stepping
827  * within the for loop and may not be valid */
828  j--;
829  dw = dv->dw + j;
830  }
831  else { /* all freed */
832  break;
833  }
834  }
835  }
836  }
837  }
838  }
839 
840 #undef REMOVE_EDGE_TAG
841 #undef IS_REMOVED_EDGE
842 #undef REMOVE_LOOP_TAG
843 #undef REMOVE_POLY_TAG
844 
845  if (mesh) {
846  if (free_flag.faces) {
848  }
849 
850  if (free_flag.polyloops) {
852  }
853 
854  if (free_flag.edges) {
856  }
857 
858  if (recalc_flag.edges) {
859  BKE_mesh_calc_edges(mesh, true, false);
860  }
861  }
862 
863  if (mesh && mesh->mselect) {
864  MSelect *msel;
865 
866  for (i = 0, msel = mesh->mselect; i < mesh->totselect; i++, msel++) {
867  int tot_elem = 0;
868 
869  if (msel->index < 0) {
870  PRINT_ERR(
871  "\tMesh select element %u type %d index is negative, "
872  "resetting selection stack.\n",
873  i,
874  msel->type);
875  free_flag.mselect = do_fixes;
876  break;
877  }
878 
879  switch (msel->type) {
880  case ME_VSEL:
881  tot_elem = mesh->totvert;
882  break;
883  case ME_ESEL:
884  tot_elem = mesh->totedge;
885  break;
886  case ME_FSEL:
887  tot_elem = mesh->totpoly;
888  break;
889  }
890 
891  if (msel->index > tot_elem) {
892  PRINT_ERR(
893  "\tMesh select element %u type %d index %d is larger than data array size %d, "
894  "resetting selection stack.\n",
895  i,
896  msel->type,
897  msel->index,
898  tot_elem);
899 
900  free_flag.mselect = do_fixes;
901  break;
902  }
903  }
904 
905  if (free_flag.mselect) {
907  mesh->mselect = NULL;
908  mesh->totselect = 0;
909  }
910  }
911 
912  PRINT_MSG("%s: finished\n\n", __func__);
913 
914  *r_changed = (fix_flag.as_flag || free_flag.as_flag || recalc_flag.as_flag);
915 
916  BLI_assert((*r_changed == false) || (do_fixes == true));
917 
918  return is_valid;
919 }
920 
923  const uint totitems,
924  const bool do_verbose,
925  const bool do_fixes,
926  bool *r_change)
927 {
928  bool is_valid = true;
929  bool has_fixes = false;
930  int i = 0;
931 
932  PRINT_MSG("%s: Checking %d CD layers...\n", __func__, data->totlayer);
933 
934  while (i < data->totlayer) {
935  CustomDataLayer *layer = &data->layers[i];
936  bool ok = true;
937 
939  const int layer_tot = CustomData_number_of_layers(data, layer->type);
940  if (layer_tot > 1) {
941  PRINT_ERR("\tCustomDataLayer type %d is a singleton, found %d in Mesh structure\n",
942  layer->type,
943  layer_tot);
944  ok = false;
945  }
946  }
947 
948  if (mask != 0) {
949  CustomDataMask layer_typemask = CD_TYPE_AS_MASK(layer->type);
950  if ((layer_typemask & mask) == 0) {
951  PRINT_ERR("\tCustomDataLayer type %d which isn't in the mask\n", layer->type);
952  ok = false;
953  }
954  }
955 
956  if (ok == false) {
957  if (do_fixes) {
958  CustomData_free_layer(data, layer->type, 0, i);
959  has_fixes = true;
960  }
961  }
962 
963  if (ok) {
964  if (CustomData_layer_validate(layer, totitems, do_fixes)) {
965  PRINT_ERR("\tCustomDataLayer type %d has some invalid data\n", layer->type);
966  has_fixes = do_fixes;
967  }
968  i++;
969  }
970  }
971 
972  PRINT_MSG("%s: Finished (is_valid=%d)\n\n", __func__, (int)!has_fixes);
973 
974  *r_change = has_fixes;
975 
976  return is_valid;
977 }
978 
983  const uint totvert,
984  CustomData *edata,
985  const uint totedge,
986  CustomData *ldata,
987  const uint totloop,
988  CustomData *pdata,
989  const uint totpoly,
990  const bool check_meshmask,
991  const bool do_verbose,
992  const bool do_fixes,
993  bool *r_change)
994 {
995  bool is_valid = true;
996  bool is_change_v, is_change_e, is_change_l, is_change_p;
998  if (check_meshmask) {
999  mask = CD_MASK_MESH;
1000  }
1001 
1003  vdata, mask.vmask, totvert, do_verbose, do_fixes, &is_change_v);
1005  edata, mask.emask, totedge, do_verbose, do_fixes, &is_change_e);
1007  ldata, mask.lmask, totloop, do_verbose, do_fixes, &is_change_l);
1009  pdata, mask.pmask, totpoly, do_verbose, do_fixes, &is_change_p);
1010 
1011  const int tot_uvloop = CustomData_number_of_layers(ldata, CD_MLOOPUV);
1012  const int tot_vcolloop = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
1013  if (tot_uvloop > MAX_MTFACE) {
1014  PRINT_ERR(
1015  "\tMore UV layers than %d allowed, %d last ones won't be available for render, shaders, "
1016  "etc.\n",
1017  MAX_MTFACE,
1018  tot_uvloop - MAX_MTFACE);
1019  }
1020  if (tot_vcolloop > MAX_MCOL) {
1021  PRINT_ERR(
1022  "\tMore VCol layers than %d allowed, %d last ones won't be available for render, shaders, "
1023  "etc.\n",
1024  MAX_MCOL,
1025  tot_vcolloop - MAX_MCOL);
1026  }
1027 
1028  /* check indices of clone/stencil */
1029  if (do_fixes && CustomData_get_clone_layer(ldata, CD_MLOOPUV) >= tot_uvloop) {
1031  is_change_l = true;
1032  }
1033  if (do_fixes && CustomData_get_stencil_layer(ldata, CD_MLOOPUV) >= tot_uvloop) {
1035  is_change_l = true;
1036  }
1037 
1038  *r_change = (is_change_v || is_change_e || is_change_l || is_change_p);
1039 
1040  return is_valid;
1041 }
1042 
1048 bool BKE_mesh_validate(Mesh *me, const bool do_verbose, const bool cddata_check_mask)
1049 {
1050  bool is_valid = true;
1051  bool changed;
1052 
1053  if (do_verbose) {
1054  CLOG_INFO(&LOG, 0, "MESH: %s", me->id.name + 2);
1055  }
1056 
1058  me->totvert,
1059  &me->edata,
1060  me->totedge,
1061  &me->ldata,
1062  me->totloop,
1063  &me->pdata,
1064  me->totpoly,
1065  cddata_check_mask,
1066  do_verbose,
1067  true,
1068  &changed);
1069 
1071  me->mvert,
1072  me->totvert,
1073  me->medge,
1074  me->totedge,
1075  me->mface,
1076  me->totface,
1077  me->mloop,
1078  me->totloop,
1079  me->mpoly,
1080  me->totpoly,
1081  me->dvert,
1082  do_verbose,
1083  true,
1084  &changed);
1085 
1086  if (changed) {
1088  return true;
1089  }
1090 
1091  return false;
1092 }
1093 
1102 {
1103  const bool do_verbose = true;
1104  const bool do_fixes = false;
1105 
1106  bool is_valid = true;
1107  bool changed = true;
1108 
1110  &me->vdata,
1111  me->totvert,
1112  &me->edata,
1113  me->totedge,
1114  &me->ldata,
1115  me->totloop,
1116  &me->pdata,
1117  me->totpoly,
1118  false, /* setting mask here isn't useful, gives false positives */
1119  do_verbose,
1120  do_fixes,
1121  &changed);
1122 
1124  me->mvert,
1125  me->totvert,
1126  me->medge,
1127  me->totedge,
1128  me->mface,
1129  me->totface,
1130  me->mloop,
1131  me->totloop,
1132  me->mpoly,
1133  me->totpoly,
1134  me->dvert,
1135  do_verbose,
1136  do_fixes,
1137  &changed);
1138 
1139  BLI_assert(changed == false);
1140 
1141  return is_valid;
1142 }
1143 
1149 {
1150  /* Cast to unsigned to catch negative indices too. */
1151  const uint16_t mat_nr_max = max_ii(0, me->totcol - 1);
1152  MPoly *mp;
1153  const int totpoly = me->totpoly;
1154  int i;
1155  bool is_valid = true;
1156 
1157  for (mp = me->mpoly, i = 0; i < totpoly; i++, mp++) {
1158  if ((uint16_t)mp->mat_nr > mat_nr_max) {
1159  mp->mat_nr = 0;
1160  is_valid = false;
1161  }
1162  }
1163 
1164  if (!is_valid) {
1166  return true;
1167  }
1168 
1169  return false;
1170 }
1171 
1174 /* -------------------------------------------------------------------- */
1178 /* We need to keep this for edge creation (for now?), and some old readfile code... */
1180 {
1181  MFace *f;
1182  int a, b;
1183 
1184  for (a = b = 0, f = me->mface; a < me->totface; a++, f++) {
1185  if (f->v3) {
1186  if (a != b) {
1187  memcpy(&me->mface[b], f, sizeof(me->mface[b]));
1188  CustomData_copy_data(&me->fdata, &me->fdata, a, b, 1);
1189  }
1190  b++;
1191  }
1192  }
1193  if (a != b) {
1194  CustomData_free_elem(&me->fdata, b, a - b);
1195  me->totface = b;
1196  }
1197 }
1198 
1207 {
1208  MPoly *p;
1209  MLoop *l;
1210  int a, b;
1211  /* New loops idx! */
1212  int *new_idx = MEM_mallocN(sizeof(int) * me->totloop, __func__);
1213 
1214  for (a = b = 0, p = me->mpoly; a < me->totpoly; a++, p++) {
1215  bool invalid = false;
1216  int i = p->loopstart;
1217  int stop = i + p->totloop;
1218 
1219  if (stop > me->totloop || stop < i || p->loopstart < 0) {
1220  invalid = true;
1221  }
1222  else {
1223  l = &me->mloop[i];
1224  i = stop - i;
1225  /* If one of the poly's loops is invalid, the whole poly is invalid! */
1226  for (; i--; l++) {
1227  if (l->e == INVALID_LOOP_EDGE_MARKER) {
1228  invalid = true;
1229  break;
1230  }
1231  }
1232  }
1233 
1234  if (p->totloop >= 3 && !invalid) {
1235  if (a != b) {
1236  memcpy(&me->mpoly[b], p, sizeof(me->mpoly[b]));
1237  CustomData_copy_data(&me->pdata, &me->pdata, a, b, 1);
1238  }
1239  b++;
1240  }
1241  }
1242  if (a != b) {
1243  CustomData_free_elem(&me->pdata, b, a - b);
1244  me->totpoly = b;
1245  }
1246 
1247  /* And now, get rid of invalid loops. */
1248  for (a = b = 0, l = me->mloop; a < me->totloop; a++, l++) {
1249  if (l->e != INVALID_LOOP_EDGE_MARKER) {
1250  if (a != b) {
1251  memcpy(&me->mloop[b], l, sizeof(me->mloop[b]));
1252  CustomData_copy_data(&me->ldata, &me->ldata, a, b, 1);
1253  }
1254  new_idx[a] = b;
1255  b++;
1256  }
1257  else {
1258  /* XXX Theoretically, we should be able to not do this, as no remaining poly
1259  * should use any stripped loop. But for security's sake... */
1260  new_idx[a] = -a;
1261  }
1262  }
1263  if (a != b) {
1264  CustomData_free_elem(&me->ldata, b, a - b);
1265  me->totloop = b;
1266  }
1267 
1268  /* And now, update polys' start loop index. */
1269  /* Note: At this point, there should never be any poly using a striped loop! */
1270  for (a = 0, p = me->mpoly; a < me->totpoly; a++, p++) {
1271  p->loopstart = new_idx[p->loopstart];
1272  }
1273 
1274  MEM_freeN(new_idx);
1275 }
1276 
1278 {
1279  MEdge *e;
1280  MLoop *l;
1281  int a, b;
1282  unsigned int *new_idx = MEM_mallocN(sizeof(int) * me->totedge, __func__);
1283 
1284  for (a = b = 0, e = me->medge; a < me->totedge; a++, e++) {
1285  if (e->v1 != e->v2) {
1286  if (a != b) {
1287  memcpy(&me->medge[b], e, sizeof(me->medge[b]));
1288  CustomData_copy_data(&me->edata, &me->edata, a, b, 1);
1289  }
1290  new_idx[a] = b;
1291  b++;
1292  }
1293  else {
1294  new_idx[a] = INVALID_LOOP_EDGE_MARKER;
1295  }
1296  }
1297  if (a != b) {
1298  CustomData_free_elem(&me->edata, b, a - b);
1299  me->totedge = b;
1300  }
1301 
1302  /* And now, update loops' edge indices. */
1303  /* XXX We hope no loop was pointing to a striped edge!
1304  * Else, its e will be set to INVALID_LOOP_EDGE_MARKER :/ */
1305  for (a = 0, l = me->mloop; a < me->totloop; a++, l++) {
1306  l->e = new_idx[l->e];
1307  }
1308 
1309  MEM_freeN(new_idx);
1310 }
1313 /* -------------------------------------------------------------------- */
1317 /* make edges in a Mesh, for outside of editmode */
1318 
1319 struct EdgeSort {
1320  unsigned int v1, v2;
1322 };
1323 
1324 /* edges have to be added with lowest index first for sorting */
1325 static void to_edgesort(
1326  struct EdgeSort *ed, unsigned int v1, unsigned int v2, char is_loose, short is_draw)
1327 {
1328  if (v1 < v2) {
1329  ed->v1 = v1;
1330  ed->v2 = v2;
1331  }
1332  else {
1333  ed->v1 = v2;
1334  ed->v2 = v1;
1335  }
1336  ed->is_loose = is_loose;
1337  ed->is_draw = is_draw;
1338 }
1339 
1340 static int vergedgesort(const void *v1, const void *v2)
1341 {
1342  const struct EdgeSort *x1 = v1, *x2 = v2;
1343 
1344  if (x1->v1 > x2->v1) {
1345  return 1;
1346  }
1347  if (x1->v1 < x2->v1) {
1348  return -1;
1349  }
1350  if (x1->v2 > x2->v2) {
1351  return 1;
1352  }
1353  if (x1->v2 < x2->v2) {
1354  return -1;
1355  }
1356 
1357  return 0;
1358 }
1359 
1360 /* Create edges based on known verts and faces,
1361  * this function is only used when loading very old blend files */
1362 
1363 static void mesh_calc_edges_mdata(MVert *UNUSED(allvert),
1364  MFace *allface,
1365  MLoop *allloop,
1366  MPoly *allpoly,
1367  int UNUSED(totvert),
1368  int totface,
1369  int UNUSED(totloop),
1370  int totpoly,
1371  const bool use_old,
1372  MEdge **r_medge,
1373  int *r_totedge)
1374 {
1375  MPoly *mpoly;
1376  MFace *mface;
1377  MEdge *medge, *med;
1378  EdgeHash *hash;
1379  struct EdgeSort *edsort, *ed;
1380  int a, totedge = 0;
1381  unsigned int totedge_final = 0;
1382  unsigned int edge_index;
1383 
1384  /* we put all edges in array, sort them, and detect doubles that way */
1385 
1386  for (a = totface, mface = allface; a > 0; a--, mface++) {
1387  if (mface->v4) {
1388  totedge += 4;
1389  }
1390  else if (mface->v3) {
1391  totedge += 3;
1392  }
1393  else {
1394  totedge += 1;
1395  }
1396  }
1397 
1398  if (totedge == 0) {
1399  /* flag that mesh has edges */
1400  (*r_medge) = MEM_callocN(0, __func__);
1401  (*r_totedge) = 0;
1402  return;
1403  }
1404 
1405  ed = edsort = MEM_mallocN(totedge * sizeof(struct EdgeSort), "EdgeSort");
1406 
1407  for (a = totface, mface = allface; a > 0; a--, mface++) {
1408  to_edgesort(ed++, mface->v1, mface->v2, !mface->v3, mface->edcode & ME_V1V2);
1409  if (mface->v4) {
1410  to_edgesort(ed++, mface->v2, mface->v3, 0, mface->edcode & ME_V2V3);
1411  to_edgesort(ed++, mface->v3, mface->v4, 0, mface->edcode & ME_V3V4);
1412  to_edgesort(ed++, mface->v4, mface->v1, 0, mface->edcode & ME_V4V1);
1413  }
1414  else if (mface->v3) {
1415  to_edgesort(ed++, mface->v2, mface->v3, 0, mface->edcode & ME_V2V3);
1416  to_edgesort(ed++, mface->v3, mface->v1, 0, mface->edcode & ME_V3V1);
1417  }
1418  }
1419 
1420  qsort(edsort, totedge, sizeof(struct EdgeSort), vergedgesort);
1421 
1422  /* count final amount */
1423  for (a = totedge, ed = edsort; a > 1; a--, ed++) {
1424  /* edge is unique when it differs from next edge, or is last */
1425  if (ed->v1 != (ed + 1)->v1 || ed->v2 != (ed + 1)->v2) {
1426  totedge_final++;
1427  }
1428  }
1429  totedge_final++;
1430 
1431  medge = MEM_callocN(sizeof(MEdge) * totedge_final, __func__);
1432 
1433  for (a = totedge, med = medge, ed = edsort; a > 1; a--, ed++) {
1434  /* edge is unique when it differs from next edge, or is last */
1435  if (ed->v1 != (ed + 1)->v1 || ed->v2 != (ed + 1)->v2) {
1436  med->v1 = ed->v1;
1437  med->v2 = ed->v2;
1438  if (use_old == false || ed->is_draw) {
1439  med->flag = ME_EDGEDRAW | ME_EDGERENDER;
1440  }
1441  if (ed->is_loose) {
1442  med->flag |= ME_LOOSEEDGE;
1443  }
1444 
1445  /* order is swapped so extruding this edge as a surface wont flip face normals
1446  * with cyclic curves */
1447  if (ed->v1 + 1 != ed->v2) {
1448  SWAP(unsigned int, med->v1, med->v2);
1449  }
1450  med++;
1451  }
1452  else {
1453  /* equal edge, we merge the drawflag */
1454  (ed + 1)->is_draw |= ed->is_draw;
1455  }
1456  }
1457  /* last edge */
1458  med->v1 = ed->v1;
1459  med->v2 = ed->v2;
1460  med->flag = ME_EDGEDRAW;
1461  if (ed->is_loose) {
1462  med->flag |= ME_LOOSEEDGE;
1463  }
1464  med->flag |= ME_EDGERENDER;
1465 
1466  MEM_freeN(edsort);
1467 
1468  /* set edge members of mloops */
1469  hash = BLI_edgehash_new_ex(__func__, totedge_final);
1470  for (edge_index = 0, med = medge; edge_index < totedge_final; edge_index++, med++) {
1471  BLI_edgehash_insert(hash, med->v1, med->v2, POINTER_FROM_UINT(edge_index));
1472  }
1473 
1474  mpoly = allpoly;
1475  for (a = 0; a < totpoly; a++, mpoly++) {
1476  MLoop *ml, *ml_next;
1477  int i = mpoly->totloop;
1478 
1479  ml_next = allloop + mpoly->loopstart; /* first loop */
1480  ml = &ml_next[i - 1]; /* last loop */
1481 
1482  while (i-- != 0) {
1483  ml->e = POINTER_AS_UINT(BLI_edgehash_lookup(hash, ml->v, ml_next->v));
1484  ml = ml_next;
1485  ml_next++;
1486  }
1487  }
1488 
1490 
1491  *r_medge = medge;
1492  *r_totedge = totedge_final;
1493 }
1494 
1499 void BKE_mesh_calc_edges_legacy(Mesh *me, const bool use_old)
1500 {
1501  MEdge *medge;
1502  int totedge = 0;
1503 
1505  me->mface,
1506  me->mloop,
1507  me->mpoly,
1508  me->totvert,
1509  me->totface,
1510  me->totloop,
1511  me->totpoly,
1512  use_old,
1513  &medge,
1514  &totedge);
1515 
1516  if (totedge == 0) {
1517  /* flag that mesh has edges */
1518  me->medge = medge;
1519  me->totedge = 0;
1520  return;
1521  }
1522 
1523  medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, totedge);
1524  me->medge = medge;
1525  me->totedge = totedge;
1526 
1528 }
1529 
1531 {
1532  MEdge *med = mesh->medge;
1533  for (int i = 0; i < mesh->totedge; i++, med++) {
1534  med->flag |= ME_LOOSEEDGE;
1535  }
1536  MLoop *ml = mesh->mloop;
1537  for (int i = 0; i < mesh->totloop; i++, ml++) {
1538  mesh->medge[ml->e].flag &= ~ME_LOOSEEDGE;
1539  }
1540  med = mesh->medge;
1541  for (int i = 0; i < mesh->totedge; i++, med++) {
1542  if (med->flag & ME_LOOSEEDGE) {
1543  med->flag |= ME_EDGEDRAW;
1544  }
1545  }
1546 }
1547 
1555 {
1556  const int numFaces = mesh->totface;
1558 
1559  MFace *mf = mesh->mface;
1560  for (int i = 0; i < numFaces; i++, mf++) {
1561  BLI_edgeset_add(eh, mf->v1, mf->v2);
1562  BLI_edgeset_add(eh, mf->v2, mf->v3);
1563 
1564  if (mf->v4) {
1565  BLI_edgeset_add(eh, mf->v3, mf->v4);
1566  BLI_edgeset_add(eh, mf->v4, mf->v1);
1567  }
1568  else {
1569  BLI_edgeset_add(eh, mf->v3, mf->v1);
1570  }
1571  }
1572 
1573  const int numEdges = BLI_edgeset_len(eh);
1574 
1575  /* write new edges into a temporary CustomData */
1576  CustomData edgeData;
1577  CustomData_reset(&edgeData);
1578  CustomData_add_layer(&edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
1579  CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
1580 
1581  MEdge *med = CustomData_get_layer(&edgeData, CD_MEDGE);
1582  int *index = CustomData_get_layer(&edgeData, CD_ORIGINDEX);
1583 
1585  for (int i = 0; BLI_edgesetIterator_isDone(ehi) == false;
1586  BLI_edgesetIterator_step(ehi), i++, med++, index++) {
1587  BLI_edgesetIterator_getKey(ehi, &med->v1, &med->v2);
1588 
1589  med->flag = ME_EDGEDRAW | ME_EDGERENDER;
1590  *index = ORIGINDEX_NONE;
1591  }
1593 
1594  /* free old CustomData and assign new one */
1595  CustomData_free(&mesh->edata, mesh->totedge);
1596  mesh->edata = edgeData;
1597  mesh->totedge = numEdges;
1598 
1600 
1601  BLI_edgeset_free(eh);
1602 }
1603 
CustomData interface, see also DNA_customdata_types.h.
void CustomData_free(struct CustomData *data, int totelem)
Definition: customdata.c:2239
int CustomData_number_of_layers(const struct CustomData *data, int type)
int CustomData_get_clone_layer(const struct CustomData *data, int type)
bool CustomData_free_layer(struct CustomData *data, int type, int totelem, int index)
Definition: customdata.c:2655
@ CD_ASSIGN
@ CD_CALLOC
uint64_t CustomDataMask
bool CustomData_layertype_is_singleton(int type)
Definition: customdata.c:4292
bool CustomData_layer_validate(struct CustomDataLayer *layer, const uint totitems, const bool do_fixes)
Definition: customdata.c:4460
void CustomData_set_layer_clone(struct CustomData *data, int type, int n)
Definition: customdata.c:2419
int CustomData_get_stencil_layer(const struct CustomData *data, int type)
#define ORIGINDEX_NONE
void * CustomData_get_layer(const struct CustomData *data, int type)
void * CustomData_add_layer(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem)
Definition: customdata.c:2620
void CustomData_free_elem(struct CustomData *data, int index, int count)
Definition: customdata.c:3004
void CustomData_set_layer_stencil(struct CustomData *data, int type, int n)
Definition: customdata.c:2428
#define CD_TYPE_AS_MASK(_type)
void CustomData_copy_data(const struct CustomData *source, struct CustomData *dest, int source_index, int dest_index, int count)
const CustomData_MeshMasks CD_MASK_MESH
Definition: customdata.c:1933
void CustomData_reset(struct CustomData *data)
Definition: customdata.c:2233
support for deformation groups and hooks.
void BKE_defvert_remove_group(struct MDeformVert *dvert, struct MDeformWeight *dw)
Definition: deform.c:754
void BKE_mesh_calc_edges(struct Mesh *mesh, bool keep_existing_edges, const bool select_new_edges)
#define BLI_assert(a)
Definition: BLI_assert.h:58
void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP free_value)
Definition: edgehash.c:244
BLI_INLINE bool BLI_edgesetIterator_isDone(EdgeSetIterator *esi)
Definition: BLI_edgehash.h:153
EdgeHash * BLI_edgehash_new_ex(const char *info, const unsigned int nentries_reserve)
Definition: edgehash.c:226
void BLI_edgehash_insert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val)
Definition: edgehash.c:279
bool BLI_edgeset_add(EdgeSet *es, unsigned int v0, unsigned int v1)
Definition: edgehash.c:578
int BLI_edgeset_len(EdgeSet *es) ATTR_WARN_UNUSED_RESULT
Definition: edgehash.c:536
BLI_INLINE void BLI_edgesetIterator_step(EdgeSetIterator *esi)
Definition: BLI_edgehash.h:149
BLI_INLINE void BLI_edgesetIterator_getKey(EdgeSetIterator *esi, unsigned int *r_v0, unsigned int *r_v1)
Definition: BLI_edgehash.h:141
void BLI_edgesetIterator_free(EdgeSetIterator *esi)
Definition: edgehash.c:634
void BLI_edgeset_free(EdgeSet *es)
Definition: edgehash.c:529
#define BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(totpoly)
Definition: BLI_edgehash.h:115
EdgeSetIterator * BLI_edgesetIterator_new(EdgeSet *es)
Definition: edgehash.c:625
void * BLI_edgehash_lookup(EdgeHash *eh, unsigned int v0, unsigned int v1) ATTR_WARN_UNUSED_RESULT
Definition: edgehash.c:325
EdgeSet * BLI_edgeset_new_ex(const char *info, const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: edgehash.c:512
bool BLI_edgehash_haskey(EdgeHash *eh, unsigned int v0, unsigned int v1) ATTR_WARN_UNUSED_RESULT
Definition: edgehash.c:426
MINLINE int max_ii(int a, int b)
MINLINE void zero_v3(float r[3])
unsigned int uint
Definition: BLI_sys_types.h:83
#define SWAP(type, a, b)
#define POINTER_FROM_INT(i)
#define POINTER_AS_UINT(i)
#define UNUSED(x)
#define POINTER_AS_INT(i)
#define POINTER_FROM_UINT(i)
#define CLOG_INFO(clg_ref, level,...)
Definition: CLG_log.h:201
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:611
#define MAX_MCOL
@ CD_ORIGINDEX
@ CD_MLOOPCOL
@ CD_MLOOPUV
#define MAX_MTFACE
@ ME_VSEL
@ ME_FSEL
@ ME_ESEL
@ ME_VERT_TMP_TAG
@ ME_V4V1
@ ME_V2V3
@ ME_V1V2
@ ME_V3V4
@ ME_V3V1
@ ME_EDGEDRAW
@ ME_EDGERENDER
@ ME_LOOSEEDGE
Object is a sort of wrapper for general info.
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble x2
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
Read Guarded memory(de)allocation.
Group RGB to Bright Vector Camera CLAMP
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
bool is_valid
static float verts[][3]
#define UINT_MAX
Definition: hash_md5.c:58
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static char faces[256]
void BKE_mesh_strip_loose_polysloops(Mesh *me)
#define CHECK_FACE_EDGE(a, b)
static void edge_store_from_mface_quad(EdgeUUID es[4], MFace *mf)
Definition: mesh_validate.c:91
#define PRINT_ERR(...)
#define IS_REMOVED_EDGE(_me)
static void mesh_calc_edges_mdata(MVert *UNUSED(allvert), MFace *allface, MLoop *allloop, MPoly *allpoly, int UNUSED(totvert), int totface, int UNUSED(totloop), int totpoly, const bool use_old, MEdge **r_medge, int *r_totedge)
static int search_face_cmp(const void *v1, const void *v2)
static int vergedgesort(const void *v1, const void *v2)
static int search_poly_cmp(const void *v1, const void *v2)
static void edge_store_assign(uint32_t verts[2], const uint32_t v1, const uint32_t v2)
Definition: mesh_validate.c:79
void BKE_mesh_calc_edges_legacy(Mesh *me, const bool use_old)
void BKE_mesh_calc_edges_tessface(Mesh *mesh)
#define CHECK_FACE_VERT_INDEX(a, b)
#define REMOVE_FACE_TAG(_mf)
static int search_polyloop_cmp(const void *v1, const void *v2)
#define REMOVE_POLY_TAG(_mp)
#define INVALID_LOOP_EDGE_MARKER
Definition: mesh_validate.c:51
static void to_edgesort(struct EdgeSort *ed, unsigned int v1, unsigned int v2, char is_loose, short is_draw)
#define REMOVE_EDGE_TAG(_me)
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, const bool do_verbose, const bool do_fixes, bool *r_changed)
static int int64_cmp(const void *v1, const void *v2)
void BKE_mesh_strip_loose_edges(Mesh *me)
#define REMOVE_LOOP_TAG(_ml)
static bool mesh_validate_customdata(CustomData *data, CustomDataMask mask, const uint totitems, const bool do_verbose, const bool do_fixes, bool *r_change)
static int int_cmp(const void *v1, const void *v2)
bool BKE_mesh_validate_material_indices(Mesh *me)
bool BKE_mesh_validate(Mesh *me, const bool do_verbose, const bool cddata_check_mask)
struct SortFace SortFace
static CLG_LogRef LOG
Definition: mesh_validate.c:53
void BKE_mesh_calc_edges_loose(Mesh *mesh)
bool BKE_mesh_is_valid(Mesh *me)
static void edge_store_from_mface_tri(EdgeUUID es[4], MFace *mf)
Definition: mesh_validate.c:99
bool BKE_mesh_validate_all_customdata(CustomData *vdata, const uint totvert, CustomData *edata, const uint totedge, CustomData *ldata, const uint totloop, CustomData *pdata, const uint totpoly, const bool check_meshmask, const bool do_verbose, const bool do_fixes, bool *r_change)
#define PRINT_MSG(...)
struct SortPoly SortPoly
void BKE_mesh_strip_loose_faces(Mesh *me)
bool isfinite(uchar)
Definition: image.cpp:44
static unsigned a[3]
Definition: RandGen.cpp:92
#define hash
Definition: noise.c:169
unsigned short uint16_t
Definition: stdint.h:82
unsigned int uint32_t
Definition: stdint.h:83
__int64 int64_t
Definition: stdint.h:92
struct BMEdge * e
Definition: bmesh_class.h:176
unsigned int v1
unsigned int v2
char name[66]
Definition: DNA_ID.h:283
struct MDeformWeight * dw
unsigned int def_nr
unsigned int v1
unsigned int v2
unsigned int v2
unsigned int v1
unsigned int v4
unsigned int v3
unsigned int e
unsigned int v
short mat_nr
struct MEdge * medge
struct CustomData pdata ldata
struct MVert * mvert
struct MDeformVert * dvert
int totedge
int totvert
struct MLoop * mloop
int totface
struct CustomData vdata edata fdata
int totpoly
short totcol
int totloop
int totselect
struct MFace * mface
struct MPoly * mpoly
struct MSelect * mselect
EdgeUUID es[4]
Definition: mesh_validate.c:65
unsigned int index
Definition: mesh_validate.c:66
unsigned int index
Definition: mesh_validate.c:75
int * verts
Definition: mesh_validate.c:72
int numverts
Definition: mesh_validate.c:73
bool invalid
Definition: mesh_validate.c:76
int loopstart
Definition: mesh_validate.c:74
int64_t edval
Definition: mesh_validate.c:61
uint32_t verts[2]
Definition: mesh_validate.c:60
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)