BMesh: face-flip, no need for temporary edge-array
[blender.git] / source / blender / bmesh / intern / bmesh_core.c
index 6abc52d75ef6eb4b9b5833b9e2abae443d2605d9..ac4eb2c33fd64e416dc85e549b8b41e64c4dfa92 100644 (file)
@@ -1019,18 +1019,12 @@ static int UNUSED_FUNCTION(bm_loop_length)(BMLoop *l)
  * \brief Loop Reverse
  *
  * Changes the winding order of a face from CW to CCW or vice versa.
- * This euler is a bit peculiar in comparison to others as it is its
- * own inverse.
- *
- * BMESH_TODO: reinsert validation code.
  *
  * \param cd_loop_mdisp_offset: Cached result of `CustomData_get_offset(&bm->ldata, CD_MDISPS)`.
  * \param use_loop_mdisp_flip: When set, flip the Z-depth of the mdisp,
  * (use when flipping normals, disable when mirroring, eg: symmetrize).
- *
- * \return Success
  */
-static bool bm_loop_reverse_loop(
+static void bm_loop_reverse_loop(
         BMesh *bm, BMFace *f,
 #ifdef USE_BMESH_HOLES
         BMLoopList *lst,
@@ -1044,39 +1038,62 @@ static bool bm_loop_reverse_loop(
        BMLoop *l_first = f->l_first;
 #endif
 
-       const int len = f->len;
-       BMLoop *l_iter;
-       BMEdge **edar = BLI_array_alloca(edar, len);
-       int i;
+       /* track previous cycles radial state */
+       BMEdge *e_prev = l_first->prev->e;
+       BMLoop *l_prev_radial_next = l_first->prev->radial_next;
+       BMLoop *l_prev_radial_prev = l_first->prev->radial_prev;
+       bool is_prev_boundary = l_prev_radial_next == l_prev_radial_next->radial_next;
 
-       for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) {
-               bmesh_radial_loop_remove((edar[i] = l_iter->e), l_iter);
-       }
+       BMLoop *l_iter = l_first;
+       do {
+               BMEdge *e_iter = l_iter->e;
+               BMLoop *l_iter_radial_next = l_iter->radial_next;
+               BMLoop *l_iter_radial_prev = l_iter->radial_prev;
+               bool is_iter_boundary = l_iter_radial_next == l_iter_radial_next->radial_next;
+
+#if 0
+               bmesh_radial_loop_remove(e_curr, l_iter);
+               bmesh_radial_loop_append(e_prev, l_iter);
+#else
+               /* inline loop reversal */
+               if (is_prev_boundary) {
+                       /* boundary */
+                       l_iter->radial_next = l_iter;
+                       l_iter->radial_prev = l_iter;
+               }
+               else {
+                       /* non-boundary, replace radial links */
+                       l_iter->radial_next = l_prev_radial_next;
+                       l_iter->radial_prev = l_prev_radial_prev;
+                       l_prev_radial_next->radial_prev = l_iter;
+                       l_prev_radial_prev->radial_next = l_iter;
+               }
+
+               if (e_iter->l == l_iter) {
+                       e_iter->l = l_iter->next;
+               }
+               l_iter->e = e_prev;
+#endif
+
+               SWAP(BMLoop *, l_iter->next, l_iter->prev);
 
-       /* actually reverse the loop */
-       for (i = 0, l_iter = l_first; i < len; i++) {
-               BMLoop *oldnext = l_iter->next;
-               BMLoop *oldprev = l_iter->prev;
-               l_iter->next = oldprev;
-               l_iter->prev = oldnext;
-               l_iter = oldnext;
-               
                if (cd_loop_mdisp_offset != -1) {
                        MDisps *md = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_mdisp_offset);
                        BKE_mesh_mdisp_flip(md, use_loop_mdisp_flip);
                }
-       }
 
-       /* rebuild radial */
-       for (i = 0, l_iter = l_first->prev; i < len; i++, l_iter = l_iter->prev) {
-               BLI_assert(BM_verts_in_edge(l_iter->v, l_iter->next->v, edar[i]));
-               l_iter->e = edar[i];
-               bmesh_radial_loop_append(l_iter->e, l_iter);
-       }
+               e_prev = e_iter;
+               l_prev_radial_next = l_iter_radial_next;
+               l_prev_radial_prev = l_iter_radial_prev;
+               is_prev_boundary = is_iter_boundary;
+
+               /* step to next (now swapped) */
+       } while ((l_iter = l_iter->prev) != l_first);
 
 #ifndef NDEBUG
        /* validate radial */
-       for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) {
+       int i;
+       for (i = 0, l_iter = l_first; i < f->len; i++, l_iter = l_iter->next) {
                BM_CHECK_ELEMENT(l_iter);
                BM_CHECK_ELEMENT(l_iter->e);
                BM_CHECK_ELEMENT(l_iter->v);
@@ -1088,21 +1105,19 @@ static bool bm_loop_reverse_loop(
 
        /* Loop indices are no more valid! */
        bm->elem_index_dirty |= BM_LOOP;
-
-       return true;
 }
 
 /**
  * \brief Flip the faces direction
  */
-bool bmesh_loop_reverse(
+void bmesh_loop_reverse(
         BMesh *bm, BMFace *f,
         const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip)
 {
 #ifdef USE_BMESH_HOLES
-       return bm_loop_reverse_loop(bm, f, f->loops.first, cd_loop_mdisp_offset, use_loop_mdisp_flip);
+       bm_loop_reverse_loop(bm, f, f->loops.first, cd_loop_mdisp_offset, use_loop_mdisp_flip);
 #else
-       return bm_loop_reverse_loop(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip);
+       bm_loop_reverse_loop(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip);
 #endif
 }