Fix error in recent vert/edge-slide commits
[blender.git] / source / blender / bmesh / tools / bmesh_decimate_collapse.c
index e94bb9f5417c9265e7fdc007f9131e175de1642e..230cb302d283aef5499d2e32ce27c23b70316693 100644 (file)
@@ -30,7 +30,6 @@
 
 #include "MEM_guardedalloc.h"
 
-#include "DNA_scene_types.h"
 
 #include "BLI_math.h"
 #include "BLI_quadric.h"
@@ -116,7 +115,7 @@ static void bm_decim_build_quadrics(BMesh *bm, Quadric *vquadrics)
 static void bm_decim_calc_target_co(BMEdge *e, float optimize_co[3],
                                     const Quadric *vquadrics)
 {
-       /* compute an edge contration target for edge 'e'
+       /* compute an edge contraction target for edge 'e'
         * this is computed by summing it's vertices quadrics and
         * optimizing the result. */
        Quadric q;
@@ -146,8 +145,8 @@ static bool bm_edge_collapse_is_degenerate_flip(BMEdge *e, const float optimize_
 
                BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
                        if (l->e != e && l->prev->e != e) {
-                               float *co_prev = l->prev->v->co;
-                               float *co_next = l->next->v->co;
+                               const float *co_prev = l->prev->v->co;
+                               const float *co_next = l->next->v->co;
                                float cross_exist[3];
                                float cross_optim[3];
 
@@ -250,6 +249,9 @@ static void bm_decim_build_edge_cost_single(BMEdge *e,
        }
        // print("COST %.12f\n");
 
+       /* note, 'cost' shouldn't be negative but happens sometimes with small values.
+        * this can cause faces that make up a flat surface to over-collapse, see [#37121] */
+       cost = fabsf(cost);
        eheap_table[BM_elem_index_get(e)] = BLI_heap_insert(eheap, cost, e);
 }
 
@@ -310,12 +312,14 @@ static bool bm_decim_triangulate_begin(BMesh *bm)
 
                l_iter = l_first = BM_FACE_FIRST_LOOP(f);
                do {
-                       BM_elem_index_set(l_iter, -1);
+                       BM_elem_index_set(l_iter, -1);  /* set_dirty */
                } while ((l_iter = l_iter->next) != l_first);
 
                // has_quad |= (f->len == 4)
        }
 
+       bm->elem_index_dirty |= BM_LOOP;
+
        /* adding new faces as we loop over faces
         * is normally best avoided, however in this case its not so bad because any face touched twice
         * will already be triangulated*/
@@ -345,7 +349,7 @@ static bool bm_decim_triangulate_begin(BMesh *bm)
                        }
 
 #ifdef USE_SAFETY_CHECKS
-                       if (BM_edge_exists(l_a->v, l_b->v) == false)
+                       if (BM_edge_exists(l_a->v, l_b->v) == NULL)
 #endif
                        {
                                BMFace *f_new;
@@ -355,7 +359,7 @@ static bool bm_decim_triangulate_begin(BMesh *bm)
                                 * - if there is a quad that has a free standing edge joining it along
                                 * where we want to split the face, there isnt a good way we can handle this.
                                 * currently that edge will get removed when joining the tris back into a quad. */
-                               f_new = BM_face_split(bm, f, l_a->v, l_b->v, &l_new, NULL, false);
+                               f_new = BM_face_split(bm, f, l_a, l_b, &l_new, NULL, false);
 
                                if (f_new) {
                                        /* the value of this doesn't matter, only that the 2 loops match and have unique values */
@@ -364,8 +368,8 @@ static bool bm_decim_triangulate_begin(BMesh *bm)
                                        /* since we just split theres only ever 2 loops */
                                        BLI_assert(BM_edge_is_manifold(l_new->e));
 
-                                       BM_elem_index_set(l_new, f_index);
-                                       BM_elem_index_set(l_new->radial_next, f_index);
+                                       BM_elem_index_set(l_new, f_index);  /* set_dirty */
+                                       BM_elem_index_set(l_new->radial_next, f_index);  /* set_dirty */
 
                                        BM_face_normal_update(f);
                                        BM_face_normal_update(f_new);
@@ -390,10 +394,10 @@ static void bm_decim_triangulate_end(BMesh *bm)
 {
        /* decimation finished, now re-join */
        BMIter iter;
-       BMEdge *e;
+       BMEdge *e, *e_next;
 
        /* boundary edges */
-       BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+       BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) {
                BMLoop *l_a, *l_b;
                if (BM_edge_loop_pair(e, &l_a, &l_b)) {
                        const int l_a_index = BM_elem_index_get(l_a);
@@ -410,10 +414,10 @@ static void bm_decim_triangulate_end(BMesh *bm)
                                                                BM_vert_in_edge(e, l_b->next->v) ? l_b->prev->v : l_b->next->v,
                                                        };
 
-                                                       BLI_assert(ELEM3(vquad[0], vquad[1], vquad[2], vquad[3]) == false);
-                                                       BLI_assert(ELEM3(vquad[1], vquad[0], vquad[2], vquad[3]) == false);
-                                                       BLI_assert(ELEM3(vquad[2], vquad[1], vquad[0], vquad[3]) == false);
-                                                       BLI_assert(ELEM3(vquad[3], vquad[1], vquad[2], vquad[0]) == false);
+                                                       BLI_assert(ELEM(vquad[0], vquad[1], vquad[2], vquad[3]) == false);
+                                                       BLI_assert(ELEM(vquad[1], vquad[0], vquad[2], vquad[3]) == false);
+                                                       BLI_assert(ELEM(vquad[2], vquad[1], vquad[0], vquad[3]) == false);
+                                                       BLI_assert(ELEM(vquad[3], vquad[1], vquad[2], vquad[0]) == false);
 
                                                        if (is_quad_convex_v3(vquad[0]->co, vquad[1]->co, vquad[2]->co, vquad[3]->co)) {
                                                                /* highly unlikely to fail, but prevents possible double-ups */
@@ -515,13 +519,17 @@ static void bm_edge_collapse_loop_customdata(BMesh *bm, BMLoop *l, BMVert *v_cle
                                if (CustomData_layer_has_math(&bm->ldata, i)) {
                                        const int offset = bm->ldata.layers[i].offset;
                                        const int type = bm->ldata.layers[i].type;
-                                       void *cd_src[2] = {(char *)src[0] + offset,
-                                                          (char *)src[1] + offset};
-                                       void *cd_iter = (char *)l_iter->head.data + offset;
+                                       const void *cd_src[2] = {
+                                           POINTER_OFFSET(src[0], offset),
+                                           POINTER_OFFSET(src[1], offset),
+                                       };
+                                       void *cd_iter = POINTER_OFFSET(l_iter->head.data, offset);
 
                                        /* detect seams */
                                        if (CustomData_data_equals(type, cd_src[0], cd_iter)) {
-                                               CustomData_bmesh_interp_n(&bm->ldata, cd_src, w, NULL, 2, l_iter->head.data, i);
+                                               CustomData_bmesh_interp_n(
+                                                       &bm->ldata, cd_src, w, NULL, ARRAY_SIZE(cd_src),
+                                                       POINTER_OFFSET(l_iter->head.data, offset), i);
 #ifdef USE_SEAM
                                                is_seam = false;
 #endif
@@ -575,7 +583,7 @@ static void bm_edge_tag_disable(BMEdge *e)
        }
 }
 
-static int bm_edge_tag_test(BMEdge *e)
+static bool bm_edge_tag_test(BMEdge *e)
 {
        /* is the edge or one of its faces tagged? */
        return (BM_elem_flag_test(e->v1, BM_ELEM_TAG) ||
@@ -682,7 +690,7 @@ static bool bm_edge_collapse_is_degenerate_topology(BMEdge *e_first)
 
 /**
  * special, highly limited edge collapse function
- * intended for speed over flexibiliy.
+ * intended for speed over flexibility.
  * can only collapse edges connected to (1, 2) tris.
  *
  * Important - dont add vert/edge/face data on collapsing!
@@ -735,9 +743,6 @@ static bool bm_edge_collapse(BMesh *bm, BMEdge *e_clear, BMVert *v_clear, int r_
                        e_b_other[0] = l_b->next->e;
                }
 
-               BLI_assert(BM_edge_share_vert(e_a_other[0], e_b_other[0]));
-               BLI_assert(BM_edge_share_vert(e_a_other[1], e_b_other[1]));
-
                /* we could assert this case, but better just bail out */
 #if 0
                BLI_assert(e_a_other[0] != e_b_other[0]);
@@ -752,6 +757,9 @@ static bool bm_edge_collapse(BMesh *bm, BMEdge *e_clear, BMVert *v_clear, int r_
                        return false;
                }
 
+               BLI_assert(BM_edge_share_vert(e_a_other[0], e_b_other[0]));
+               BLI_assert(BM_edge_share_vert(e_a_other[1], e_b_other[1]));
+
                r_e_clear_other[0] = BM_elem_index_get(e_a_other[0]);
                r_e_clear_other[1] = BM_elem_index_get(e_b_other[0]);
 
@@ -993,7 +1001,7 @@ void BM_mesh_decimate_collapse(BMesh *bm, const float factor, float *vweights, c
        vquadrics = MEM_callocN(sizeof(Quadric) * bm->totvert, __func__);
        /* since some edges may be degenerate, we might be over allocing a little here */
        eheap = BLI_heap_new_ex(bm->totedge);
-       eheap_table = MEM_callocN(sizeof(HeapNode *) * bm->totedge, __func__);
+       eheap_table = MEM_mallocN(sizeof(HeapNode *) * bm->totedge, __func__);
        tot_edge_orig = bm->totedge;
 
 
@@ -1003,7 +1011,7 @@ void BM_mesh_decimate_collapse(BMesh *bm, const float factor, float *vweights, c
        bm_decim_build_edge_cost(bm, vquadrics, vweights, eheap, eheap_table);
 
        face_tot_target = bm->totface * factor;
-       bm->elem_index_dirty |= BM_FACE | BM_EDGE | BM_VERT;
+       bm->elem_index_dirty |= BM_ALL;
 
 
 #ifdef USE_CUSTOMDATA