Mesh elements sorting refactor.
authorBastien Montagne <montagne29@wanadoo.fr>
Sun, 6 May 2012 17:14:56 +0000 (17:14 +0000)
committerBastien Montagne <montagne29@wanadoo.fr>
Sun, 6 May 2012 17:14:56 +0000 (17:14 +0000)
Now only one operator. Same options for vertices, edges and faces (so adds edges sorting, and some options to vertices sorting).

Face sorting should behave as previously. However, XSortVerts won’t pack anymore selected vertices at the begining of the vert array (as it used to), if you want such behavior you’ll have to first run SortElements with Selected action.

Also added bug ref I forgot in r46354 (armature.c).

release/scripts/startup/bl_ui/space_view3d.py
source/blender/blenkernel/intern/armature.c
source/blender/editors/mesh/editmesh_tools.c
source/blender/editors/mesh/mesh_intern.h
source/blender/editors/mesh/mesh_ops.c

index 629a2ec323d074ea920ed0dbb2684c2f3502ed15..7e53cfed28218139a6b0024ff80bee31a9bb078d 100644 (file)
@@ -1675,6 +1675,7 @@ class VIEW3D_MT_edit_mesh_specials(Menu):
         layout.operator("mesh.blend_from_shape")
         layout.operator("mesh.shape_propagate_to_all")
         layout.operator("mesh.select_vertex_path")
+        layout.operator("mesh.sort_elements")
 
 
 class VIEW3D_MT_edit_mesh_select_mode(Menu):
@@ -1750,8 +1751,7 @@ class VIEW3D_MT_edit_mesh_vertices(Menu):
 
         layout.operator("mesh.vertices_smooth")
         layout.operator("mesh.remove_doubles")
-        layout.operator("mesh.vertices_sort")
-        layout.operator("mesh.vertices_randomize")
+        layout.operator("mesh.sort_elements", text="Sort Vertices").elements = {"VERT"}
 
         layout.operator("mesh.select_vertex_path")
 
@@ -1796,6 +1796,7 @@ class VIEW3D_MT_edit_mesh_edges(Menu):
         layout.operator("mesh.bevel")
         layout.operator("mesh.edge_split")
         layout.operator("mesh.bridge_edge_loops")
+        layout.operator("mesh.sort_elements", text="Sort Edges").elements = {"EDGE"}
 
         layout.separator()
 
@@ -1828,7 +1829,7 @@ class VIEW3D_MT_edit_mesh_faces(Menu):
         layout.operator("mesh.bevel")
         layout.operator("mesh.solidify")
         layout.operator("mesh.wireframe")
-        layout.operator("mesh.sort_faces")
+        layout.operator("mesh.sort_elements", text="Sort Faces").elements = {"FACE"}
 
         layout.separator()
 
index 58264fb4175abbd34afe5b892d0d39b53cdb8650..1f4259c6d86a6f4df8304c391d1945bf13e595c4 100644 (file)
@@ -1464,7 +1464,7 @@ void vec_roll_to_mat3(const float vec[3], const float roll, float mat[][3])
         * was 0.000001, causes bug [#30438] (which is same as [#27675, imho).
         * Reseting it to org value seems to cause no more [#23954]...
         *
-        * was 0.0000000000001, caused bug [#], smaller values give unstable
+        * was 0.0000000000001, caused bug [#31333], smaller values give unstable
         * roll when toggling editmode again...
         * No good value here, trying 0.000000001 as best compromize. :/
         */
index 9c7ef7561475df06c41a06a12ec1818fb3e68b5e..af3d7f169272cbbc21b2eeef890b9447ed0a7423 100644 (file)
@@ -66,6 +66,8 @@
 
 #include "RE_render_ext.h"
 
+#include "UI_interface.h"
+
 #include "mesh_intern.h"
 
 /* allow accumulated normals to form a new direction but don't
@@ -3659,393 +3661,577 @@ void MESH_OT_select_mirror(wmOperatorType *ot)
        RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection");
 }
 
-/* qsort routines.  not sure how to make these
- * work, since we aren't using linked lists for
- * geometry anymore.  might need a sort of "swap"
- * function for bmesh elements. */
-
-/* TODO All this section could probably use a refresh...
- *      face code works in object mode, does everything in one op, while vert uses several...
- */
-
-typedef struct xvertsort {
-       int x; /* X screen-coordinate */
-       int org_idx; /* Original index of this vertex _in the mempool_ */
-} xvertsort;
+/******************************************************************************
+ * qsort routines.
+ * Now unified, for vertices/edges/faces. */
 
+enum {
+       SRT_VIEW_ZAXIS = 1,  /* Use view Z (deep) axis. */
+       SRT_VIEW_XAXIS,      /* Use view X (left to right) axis. */
+       SRT_CURSOR_DISTANCE, /* Use distance from element to 3D cursor. */
+       SRT_MATERIAL,        /* Face only: use mat number. */
+       SRT_SELECTED,        /* Move selected elements in first, without modifying 
+                             * relative order of selected and unselected elements. */
+       SRT_RANDOMIZE,       /* Randomize selected elements. */
+       SRT_REVERSE,         /* Reverse current order of selected elements. */
+};
 
-static int vergxco(const void *v1, const void *v2)
-{
-       const xvertsort *x1 = v1, *x2 = v2;
-
-       /* We move unchanged vertices (org_idx < 0) at the begining of the sorted list. */
-       if (x1->org_idx >= 0 && x2->org_idx >= 0)
-               return (x1->x > x2->x) - (x1->x < x2->x);
-       return (x2->org_idx < 0) - (x1->org_idx < 0);
-}
+typedef struct bmelemsort {
+       float srt; /* Sort factor */
+       int org_idx; /* Original index of this element _in its mempool_ */
+} bmelemsort;
 
-static void xsortvert_flag__doSetX(void *userData, BMVert *UNUSED(eve), int x, int UNUSED(y), int index)
+static int bmelemsort_comp(const void *v1, const void *v2)
 {
-       xvertsort *sortblock = userData;
+       const bmelemsort *x1 = v1, *x2 = v2;
 
-       sortblock[index].x = x;
+       return (x1->srt > x2->srt) - (x1->srt < x2->srt);
 }
 
-/* all verts with (flag & 'flag') are sorted */
-static void xsortvert_flag(bContext *C, int flag)
+/* Reorders vertices/edges/faces using a given methods. Loops are not supported. */
+static void sort_bmelem_flag(bContext *C, const int types, const int flag, const int action,
+                             const int reverse, const unsigned int seed)
 {
+       Scene *scene = CTX_data_scene(C);
+       Object *ob = CTX_data_edit_object(C);
        ViewContext vc;
        BMEditMesh *em;
        BMVert *ve;
+       BMEdge *ed;
+       BMFace *fa;
        BMIter iter;
-       xvertsort *sortblock;
-       int *unchangedblock, *vmap;
-       int totvert, sorted = 0, unchanged = 0, i;
+
+       /* In all five elements below, 0 = vertices, 1 = edges, 2 = faces. */
+       /* Just to mark protected elements. */
+       char *pblock[3] = {NULL, NULL, NULL}, *pb;
+       bmelemsort *sblock[3] = {NULL, NULL, NULL}, *sb;
+       int *map[3] = {NULL, NULL, NULL}, *mp;
+       int totelem[3] = {0, 0, 0}, tot;
+       int affected[3] = {0, 0, 0}, aff;
+       int i, j;
+
+       if (!(types && flag && action))
+               return;
 
        em_setup_viewcontext(C, &vc);
        em = vc.em;
 
-       totvert = em->bm->totvert;
+       if (types & BM_VERT)
+               totelem[0] = em->bm->totvert;
+       if (types & BM_EDGE)
+               totelem[1] = em->bm->totedge;
+       if (types & BM_FACE)
+               totelem[2] = em->bm->totface;
 
-       sortblock = MEM_callocN(sizeof(xvertsort) * totvert, "xsort sorted");
-       /* Stores unchanged verts, will be reused as final old2new vert mapping... */
-       unchangedblock = MEM_callocN(sizeof(int) * totvert, "xsort unchanged");
-       BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
-               if (BM_elem_flag_test(ve, flag)) {
-                       sortblock[i].org_idx = i;
-                       sorted++;
-               }
-               else {
-                       unchangedblock[unchanged++] = i;
-                       sortblock[i].org_idx = -1;
-               }
-       }
-/*     printf("%d verts: %d to be sorted, %d unchanged…\n", totvert, sorted, unchanged);*/
-       if (sorted == 0) {
-               MEM_freeN(sortblock);
-               MEM_freeN(unchangedblock);
-               return;
-       }
+       if (ELEM(action, SRT_VIEW_ZAXIS, SRT_VIEW_XAXIS)) {
+               RegionView3D *rv3d = ED_view3d_context_rv3d(C);
+               float mat[4][4];
+               float fact = reverse ? -1.0 : 1.0;
+               int coidx = (action == SRT_VIEW_ZAXIS) ? 2 : 0;
 
-       ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
-       mesh_foreachScreenVert(&vc, xsortvert_flag__doSetX, sortblock, V3D_CLIP_TEST_OFF);
+               mult_m4_m4m4(mat, rv3d->viewmat, ob->obmat);  /* Apply the view matrix to the object matrix. */
 
-       qsort(sortblock, totvert, sizeof(xvertsort), vergxco);
+               if (totelem[0]) {
+                       pb = pblock[0] = MEM_callocN(sizeof(char) * totelem[0], "sort_bmelem vert pblock");
+                       sb = sblock[0] = MEM_callocN(sizeof(bmelemsort) * totelem[0], "sort_bmelem vert sblock");
 
-       /* Convert sortblock into an array mapping old idx to new. */
-       vmap = unchangedblock;
-       unchangedblock = NULL;
-       if (unchanged) {
-               unchangedblock = MEM_mallocN(sizeof(int) * unchanged, "xsort unchanged");
-               memcpy(unchangedblock, vmap, unchanged * sizeof(int));
-       }
-       for (i = totvert; i--; ) {
-               if (i < unchanged)
-                       vmap[unchangedblock[i]] = i;
-               else
-                       vmap[sortblock[i].org_idx] = i;
-       }
+                       BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+                               if (BM_elem_flag_test(ve, flag)) {
+                                       float co[3];
+                                       mul_v3_m4v3(co, mat, ve->co);
 
-       MEM_freeN(sortblock);
-       if (unchangedblock)
-               MEM_freeN(unchangedblock);
+                                       pb[i] = FALSE;
+                                       sb[affected[0]].org_idx = i;
+                                       sb[affected[0]++].srt = co[coidx] * fact;
+                               }
+                               else {
+                                       pb[i] = TRUE;
+                               }
+                       }
+               }
 
-       BM_mesh_remap(em->bm, vmap, NULL, NULL);
+               if (totelem[1]) {
+                       pb = pblock[1] = MEM_callocN(sizeof(char) * totelem[1], "sort_bmelem edge pblock");
+                       sb = sblock[1] = MEM_callocN(sizeof(bmelemsort) * totelem[1], "sort_bmelem edge sblock");
 
-       MEM_freeN(vmap);
-}
+                       BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
+                               if (BM_elem_flag_test(ed, flag)) {
+                                       float co[3];
+                                       mid_v3_v3v3(co, ed->v1->co, ed->v2->co);
+                                       mul_m4_v3(mat, co);
 
-static int edbm_vertices_sort_exec(bContext *C, wmOperator *UNUSED(op))
-{
-       xsortvert_flag(C, BM_ELEM_SELECT);
-       return OPERATOR_FINISHED;
-}
+                                       pb[i] = FALSE;
+                                       sb[affected[1]].org_idx = i;
+                                       sb[affected[1]++].srt = co[coidx] * fact;
+                               }
+                               else {
+                                       pb[i] = TRUE;
+                               }
+                       }
+               }
 
-void MESH_OT_vertices_sort(wmOperatorType *ot)
-{
-       /* identifiers */
-       ot->name = "Vertex Sort";
-       ot->description = "Sort vertex order";
-       ot->idname = "MESH_OT_vertices_sort";
+               if (totelem[2]) {
+                       pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock");
+                       sb = sblock[2] = MEM_callocN(sizeof(bmelemsort) * totelem[2], "sort_bmelem face sblock");
 
-       /* api callbacks */
-       ot->exec = edbm_vertices_sort_exec;
+                       BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) {
+                               if (BM_elem_flag_test(fa, flag)) {
+                                       float co[3];
+                                       BM_face_calc_center_mean(fa, co);
+                                       mul_m4_v3(mat, co);
 
-       ot->poll = EM_view3d_poll; /* uses view relative X axis to sort verts */
+                                       pb[i] = FALSE;
+                                       sb[affected[2]].org_idx = i;
+                                       sb[affected[2]++].srt = co[coidx] * fact;
+                               }
+                               else {
+                                       pb[i] = TRUE;
+                               }
+                       }
+               }
+       }
 
-       /* flags */
-       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
+       else if (action == SRT_CURSOR_DISTANCE) {
+               View3D *v3d = CTX_wm_view3d(C);
+               float cur[3];
+               float mat[4][4];
+               float fact = reverse ? -1.0 : 1.0;
 
-/* ********************** SORT FACES ******************* */
+               if (v3d && v3d->localvd)
+                       copy_v3_v3(cur, v3d->cursor);
+               else
+                       copy_v3_v3(cur, scene->cursor);
+               invert_m4_m4(mat, ob->obmat);
+               mul_m4_v3(mat, cur);
+
+               if (totelem[0]) {
+                       pb = pblock[0] = MEM_callocN(sizeof(char) * totelem[0], "sort_bmelem vert pblock");
+                       sb = sblock[0] = MEM_callocN(sizeof(bmelemsort) * totelem[0], "sort_bmelem vert sblock");
+
+                       BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+                               if (BM_elem_flag_test(ve, flag)) {
+                                       pb[i] = FALSE;
+                                       sb[affected[0]].org_idx = i;
+                                       sb[affected[0]++].srt = len_squared_v3v3(cur, ve->co) * fact;
+                               }
+                               else {
+                                       pb[i] = TRUE;
+                               }
+                       }
+               }
 
-static void permutate(void *list, int num, int size, int *index)
-{
-       void *buf;
-       int len;
-       int i;
+               if (totelem[1]) {
+                       pb = pblock[1] = MEM_callocN(sizeof(char) * totelem[1], "sort_bmelem edge pblock");
+                       sb = sblock[1] = MEM_callocN(sizeof(bmelemsort) * totelem[1], "sort_bmelem edge sblock");
 
-       len = num * size;
+                       BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
+                               if (BM_elem_flag_test(ed, flag)) {
+                                       float co[3];
+                                       mid_v3_v3v3(co, ed->v1->co, ed->v2->co);
 
-       buf = MEM_mallocN(len, "permutate");
-       memcpy(buf, list, len);
-       
-       for (i = 0; i < num; i++) {
-               memcpy((char *)list + (i * size), (char *)buf + (index[i] * size), size);
-       }
-       MEM_freeN(buf);
-}
+                                       pb[i] = FALSE;
+                                       sb[affected[1]].org_idx = i;
+                                       sb[affected[1]++].srt = len_squared_v3v3(cur, co) * fact;
+                               }
+                               else {
+                                       pb[i] = TRUE;
+                               }
+                       }
+               }
 
-/* sort faces on view axis */
-static float *face_sort_floats;
-static int float_sort(const void *v1, const void *v2)
-{
-       float x1, x2;
-       
-       x1 = face_sort_floats[((int *) v1)[0]];
-       x2 = face_sort_floats[((int *) v2)[0]];
-       
-       if      (x1 > x2) return  1;
-       else if (x1 < x2) return -1;
-       return 0;
-}
+               if (totelem[2]) {
+                       pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock");
+                       sb = sblock[2] = MEM_callocN(sizeof(bmelemsort) * totelem[2], "sort_bmelem face sblock");
 
-static int edbm_sort_faces_exec(bContext *C, wmOperator *op)
-{
-       RegionView3D *rv3d = ED_view3d_context_rv3d(C);
-       View3D *v3d = CTX_wm_view3d(C);
-       Object *ob = CTX_data_edit_object(C);
-       Scene *scene = CTX_data_scene(C);
-       Mesh *me;
-       CustomDataLayer *layer;
-       int i, j, *index;
-       int event;
-       float reverse = 1;
-       // XXX int ctrl = 0;
-       
-       if (!v3d) return OPERATOR_CANCELLED;
-
-       /* This operator work in Object Mode, not in edit mode.
-        * After talk with Campbell we agree that there is no point to port this to EditMesh right now.
-        * so for now, we just exit_editmode and enter_editmode at the end of this function.
-        */
-       ED_object_exit_editmode(C, EM_FREEDATA);
+                       BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) {
+                               if (BM_elem_flag_test(fa, flag)) {
+                                       float co[3];
+                                       BM_face_calc_center_mean(fa, co);
 
-       me = ob->data;
-       if (me->totpoly == 0) {
-               ED_object_enter_editmode(C, 0);
-               return OPERATOR_FINISHED;
+                                       pb[i] = FALSE;
+                                       sb[affected[2]].org_idx = i;
+                                       sb[affected[2]++].srt = len_squared_v3v3(cur, co) * fact;
+                               }
+                               else {
+                                       pb[i] = TRUE;
+                               }
+                       }
+               }
        }
 
-       event = RNA_enum_get(op->ptr, "type");
-
-       // XXX
-       //if (ctrl)
-       //      reverse = -1;
-       
-       /* create index list */
-       index = (int *)MEM_mallocN(sizeof(int) * me->totpoly, "sort faces");
-       for (i = 0; i < me->totpoly; i++) {
-               index[i] = i;
+       /* Faces only! */
+       else if (action == SRT_MATERIAL && totelem[2]) {
+               pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock");
+               sb = sblock[2] = MEM_callocN(sizeof(bmelemsort) * totelem[2], "sort_bmelem face sblock");
+
+               BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) {
+                       if (BM_elem_flag_test(fa, flag)) {
+                               /* Reverse materials' order, not order of faces inside each mat! */
+                               /* Note: cannot use totcol, as mat_nr may sometimes be greater... */
+                               float srt = reverse ? (float)(MAXMAT - fa->mat_nr) : (float)fa->mat_nr;
+                               pb[i] = FALSE;
+                               sb[affected[2]].org_idx = i;
+                               /* Multiplying with totface and adding i ensures us we keep current order for all faces of same mat. */
+                               sb[affected[2]++].srt = srt * ((float)totelem[2]) + ((float)i);
+/*                             printf("e: %d; srt: %f; final: %f\n", i, srt, srt * ((float)totface) + ((float)i));*/
+                       }
+                       else {
+                               pb[i] = TRUE;
+                       }
+               }
        }
-       
-       face_sort_floats = (float *) MEM_mallocN(sizeof(float) * me->totpoly, "sort faces float");
 
-       /* sort index list instead of faces itself 
-        * and apply this permutation to all face layers
-        */
-       if (event == 5) {
-               /* Random */
-               for (i = 0; i < me->totpoly; i++) {
-                       face_sort_floats[i] = BLI_frand();
+       else if (action == SRT_SELECTED) {
+               int *tbuf[3] = {NULL, NULL, NULL}, *tb;
+
+               if (totelem[0]) {
+                       tb = tbuf[0] = MEM_callocN(sizeof(int) * totelem[0], "sort_bmelem vert tbuf");
+                       mp = map[0] = MEM_callocN(sizeof(int) * totelem[0], "sort_bmelem vert map");
+
+                       BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+                       if (BM_elem_flag_test(ve, flag)) {
+                               mp[affected[0]++] = i;
+                       }
+                       else {
+                               *tb = i;
+                               tb++;
+                               }
+                       }
                }
-               qsort(index, me->totpoly, sizeof(int), float_sort);
-       }
-       else {
-               MPoly *mp;
-               MLoop *ml;
-               MVert *mv;
-               float vec[3];
-               float mat[4][4];
-               float cur[3];
-               
-               if (event == 1)
-                       mult_m4_m4m4(mat, rv3d->viewmat, OBACT->obmat);  /* apply the view matrix to the object matrix */
-               else if (event == 2) { /* sort from cursor */
-                       if (v3d && v3d->localvd) {
-                               copy_v3_v3(cur, v3d->cursor);
+
+               if (totelem[1]) {
+                       tb = tbuf[1] = MEM_callocN(sizeof(int) * totelem[1], "sort_bmelem edge tbuf");
+                       mp = map[1] = MEM_callocN(sizeof(int) * totelem[1], "sort_bmelem edge map");
+
+                       BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
+                       if (BM_elem_flag_test(ed, flag)) {
+                               mp[affected[1]++] = i;
+                       }
+                       else {
+                               *tb = i;
+                               tb++;
+                               }
+                       }
+               }
+
+               if (totelem[2]) {
+                       tb = tbuf[2] = MEM_callocN(sizeof(int) * totelem[2], "sort_bmelem face tbuf");
+                       mp = map[2] = MEM_callocN(sizeof(int) * totelem[2], "sort_bmelem face map");
+
+                       BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) {
+                       if (BM_elem_flag_test(fa, flag)) {
+                               mp[affected[2]++] = i;
                        }
                        else {
-                               copy_v3_v3(cur, scene->cursor);
+                               *tb = i;
+                               tb++;
+                               }
                        }
-                       invert_m4_m4(mat, OBACT->obmat);
-                       mul_m4_v3(mat, cur);
                }
-               
-               mp = me->mpoly;
 
-               for (i = 0; i < me->totpoly; i++, mp++) {
-                       if (event == 3) {
-                               face_sort_floats[i] = ((float)mp->mat_nr) * reverse;
+               for (j = 3; j--;) {
+                       int tot = totelem[j];
+                       int aff = affected[j];
+                       tb = tbuf[j];
+                       mp = map[j];
+                       if (!(tb && mp))
+                               continue;
+                       if (ELEM(aff, 0, tot)) {
+                               MEM_freeN(tb);
+                               MEM_freeN(mp);
+                               map[j] = NULL;
+                               continue;
                        }
-                       else if (event == 4) {
-                               /* selected first */
-                               if (mp->flag & ME_FACE_SEL)
-                                       face_sort_floats[i] = 0.0;
-                               else
-                                       face_sort_floats[i] = reverse;
+                       if (reverse) {
+                               memcpy(tb + (tot - aff), mp, aff * sizeof(int));
                        }
                        else {
-                               /* find the face's center */
-                               ml = me->mloop + mp->loopstart;
-                               zero_v3(vec);
-                               for (j = 0; j < mp->totloop; j++, ml++) {
-                                       mv = me->mvert + ml->v;
-                                       add_v3_v3(vec, mv->co);
+                               memcpy(mp + aff, tb, (tot - aff) * sizeof(int));
+                               tb = mp;
+                               mp = map[j] = tbuf[j];
+                               tbuf[j] = tb;
+                       }
+
+                       /* Reverse mapping, we want an org2new one! */
+                       for (i = tot, tb = tbuf[j] + tot - 1; i--; tb--) {
+                               mp[*tb] = i;
+                       }
+                       MEM_freeN(tbuf[j]);
+               }
+       }
+
+       else if (action == SRT_RANDOMIZE) {
+               if (totelem[0]) {
+                       /* Re-init random generator for each element type, to get consistant random when
+                        * enabling/disabling an element type. */
+                       BLI_srandom(seed);
+                       pb = pblock[0] = MEM_callocN(sizeof(char) * totelem[0], "sort_bmelem vert pblock");
+                       sb = sblock[0] = MEM_callocN(sizeof(bmelemsort) * totelem[0], "sort_bmelem vert sblock");
+
+                       BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+                               if (BM_elem_flag_test(ve, flag)) {
+                                       pb[i] = FALSE;
+                                       sb[affected[0]].org_idx = i;
+                                       sb[affected[0]++].srt = BLI_frand();
                                }
-                               mul_v3_fl(vec, 1.0f / (float)mp->totloop);
-                               
-                               if (event == 1) { /* sort on view axis */
-                                       mul_m4_v3(mat, vec);
-                                       face_sort_floats[i] = vec[2] * reverse;
+                               else {
+                                       pb[i] = TRUE;
                                }
-                               else if (event == 2) { /* distance from cursor */
-                                       face_sort_floats[i] = len_v3v3(cur, vec) * reverse; /* back to front */
+                       }
+               }
+
+               if (totelem[1]) {
+                       BLI_srandom(seed);
+                       pb = pblock[1] = MEM_callocN(sizeof(char) * totelem[1], "sort_bmelem edge pblock");
+                       sb = sblock[1] = MEM_callocN(sizeof(bmelemsort) * totelem[1], "sort_bmelem edge sblock");
+
+                       BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
+                               if (BM_elem_flag_test(ed, flag)) {
+                                       pb[i] = FALSE;
+                                       sb[affected[1]].org_idx = i;
+                                       sb[affected[1]++].srt = BLI_frand();
+                               }
+                               else {
+                                       pb[i] = TRUE;
+                               }
+                       }
+               }
+
+               if (totelem[2]) {
+                       BLI_srandom(seed);
+                       pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock");
+                       sb = sblock[2] = MEM_callocN(sizeof(bmelemsort) * totelem[2], "sort_bmelem face sblock");
+
+                       BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) {
+                               if (BM_elem_flag_test(fa, flag)) {
+                                       pb[i] = FALSE;
+                                       sb[affected[2]].org_idx = i;
+                                       sb[affected[2]++].srt = BLI_frand();
+                               }
+                               else {
+                                       pb[i] = TRUE;
                                }
                        }
                }
-               qsort(index, me->totpoly, sizeof(int), float_sort);
-       }
-       
-       MEM_freeN(face_sort_floats);
-       for (i = 0; i < me->pdata.totlayer; i++) {
-               layer = &me->pdata.layers[i];
-               permutate(layer->data, me->totpoly, CustomData_sizeof(layer->type), index);
        }
 
-       MEM_freeN(index);
-       DAG_id_tag_update(ob->data, 0);
+       else if (action == SRT_REVERSE) {
+               if (totelem[0]) {
+                       pb = pblock[0] = MEM_callocN(sizeof(char) * totelem[0], "sort_bmelem vert pblock");
+                       sb = sblock[0] = MEM_callocN(sizeof(bmelemsort) * totelem[0], "sort_bmelem vert sblock");
 
-       /* Return to editmode. */
-       ED_object_enter_editmode(C, 0);
+                       BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+                               if (BM_elem_flag_test(ve, flag)) {
+                                       pb[i] = FALSE;
+                                       sb[affected[0]].org_idx = i;
+                                       sb[affected[0]++].srt = (float)-i;
+                               }
+                               else {
+                                       pb[i] = TRUE;
+                               }
+                       }
+               }
 
-       return OPERATOR_FINISHED;
-}
+               if (totelem[1]) {
+                       pb = pblock[1] = MEM_callocN(sizeof(char) * totelem[1], "sort_bmelem edge pblock");
+                       sb = sblock[1] = MEM_callocN(sizeof(bmelemsort) * totelem[1], "sort_bmelem edge sblock");
 
-void MESH_OT_sort_faces(wmOperatorType *ot)
-{
-       static EnumPropertyItem type_items[] = {
-               { 1, "VIEW_AXIS", 0, "View Axis", "" },
-               { 2, "CURSOR_DISTANCE", 0, "Cursor Distance", "" },
-               { 3, "MATERIAL", 0, "Material", "" },
-               { 4, "SELECTED", 0, "Selected", "" },
-               { 5, "RANDOMIZE", 0, "Randomize", "" },
-               { 0, NULL, 0, NULL, NULL }};
+                       BM_ITER_MESH_INDEX (ed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
+                               if (BM_elem_flag_test(ed, flag)) {
+                                       pb[i] = FALSE;
+                                       sb[affected[1]].org_idx = i;
+                                       sb[affected[1]++].srt = (float)-i;
+                               }
+                               else {
+                                       pb[i] = TRUE;
+                               }
+                       }
+               }
 
-       /* identifiers */
-       ot->name = "Sort Faces"; // XXX (Ctrl to reverse)%t|
-       ot->description = "The faces of the active Mesh Object are sorted, based on the current view";
-       ot->idname = "MESH_OT_sort_faces";
+               if (totelem[2]) {
+                       pb = pblock[2] = MEM_callocN(sizeof(char) * totelem[2], "sort_bmelem face pblock");
+                       sb = sblock[2] = MEM_callocN(sizeof(bmelemsort) * totelem[2], "sort_bmelem face sblock");
 
-       /* api callbacks */
-       ot->invoke = WM_menu_invoke;
-       ot->exec = edbm_sort_faces_exec;
-       ot->poll = ED_operator_editmesh;
+                       BM_ITER_MESH_INDEX (fa, &iter, em->bm, BM_FACES_OF_MESH, i) {
+                               if (BM_elem_flag_test(fa, flag)) {
+                                       pb[i] = FALSE;
+                                       sb[affected[2]].org_idx = i;
+                                       sb[affected[2]++].srt = (float)-i;
+                               }
+                               else {
+                                       pb[i] = TRUE;
+                               }
+                       }
+               }
+       }
 
-       /* flags */
-       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+/*     printf("%d vertices: %d to be affected…\n", totelem[0], affected[0]);*/
+/*     printf("%d edges: %d to be affected…\n", totelem[1], affected[1]);*/
+/*     printf("%d faces: %d to be affected…\n", totelem[2], affected[2]);*/
+       if (affected[0] == 0 && affected[1] == 0 && affected[2] == 0) {
+               for (j = 3; j--;) {
+                       if (pblock[j])
+                               MEM_freeN(pblock[j]);
+                       if (sblock[j])
+                               MEM_freeN(sblock[j]);
+                       if (map[j])
+                               MEM_freeN(map[j]);
+               }
+               return;
+       }
 
-       /* properties */
-       ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
+       /* Sort affected elements, and populate mapping arrays, if needed. */
+       for (j = 3; j--;) {
+               pb = pblock[j];
+               sb = sblock[j];
+               if (pb && sb && !map[j]) {
+                       char *p_blk;
+                       bmelemsort *s_blk;
+                       tot = totelem[j];
+                       aff = affected[j];
+
+                       qsort(sb, aff, sizeof(bmelemsort), bmelemsort_comp);
+
+                       mp = map[j] = MEM_mallocN(sizeof(int) * tot, "sort_bmelem map");
+                       p_blk = pb + tot - 1;
+                       s_blk = sb + aff - 1;
+                       for (i = tot; i--; p_blk--) {
+                               if (*p_blk) { /* Protected! */
+                                       mp[i] = i;
+                               }
+                               else {
+                                       mp[s_blk->org_idx] = i;
+                                       s_blk--;
+                               }
+                       }
+               }
+               if (pb)
+                       MEM_freeN(pb);
+               if (sb)
+                       MEM_freeN(sb);
+       }
+
+       BM_mesh_remap(em->bm, map[0], map[1], map[2]);
+/*     DAG_id_tag_update(ob->data, 0);*/
+
+       for (j = 3; j--;) {
+               if (map[j])
+                       MEM_freeN(map[j]);
+       }
 }
 
-/* ******************************* Randomize verts ************************* */
-static void hashvert_flag(BMEditMesh *em, int flag, unsigned int seed)
+static int edbm_sort_elements_exec(bContext *C, wmOperator *op)
 {
-       BMVert *ve;
-       BMIter iter;
-       char *block /* Just to mark protected vertices */, *t_blk;
-       int *randblock, *vmap, *t_idx, *r_idx;
-       int totvert, randomized = 0, /*protected = 0, */ i;
-
-       totvert = em->bm->totvert;
-
-       block = MEM_callocN(sizeof(char) * totvert, "randvert block");
-       randblock = MEM_callocN(sizeof(int) * totvert, "randvert randblock");
-       BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
-               if (BM_elem_flag_test(ve, flag)) {
-                       block[i] = FALSE;
-                       randblock[randomized++] = i;
-               }
-               else {
-                       block[i] = TRUE;
-               }
+       int action = RNA_enum_get(op->ptr, "type");
+       PropertyRNA *prop_elem_types = RNA_struct_find_property(op->ptr, "elements");
+       int elem_types = 0;
+       int reverse = RNA_boolean_get(op->ptr, "reverse");
+       unsigned int seed = RNA_int_get(op->ptr, "seed");
+
+       /* If no elem_types set, use current selection mode to set it! */
+       if (RNA_property_is_set(op->ptr, prop_elem_types)) {
+               elem_types = RNA_property_enum_get(op->ptr, prop_elem_types);
        }
-/*     protected = totvert - randomized;*/
-/*     printf("%d verts: %d to be randomized, %d protected…\n", totvert, randomized, protected);*/
-       if (randomized == 0) {
-               MEM_freeN(block);
-               MEM_freeN(randblock);
-               return;
+       else {
+               BMEditMesh *em = BMEdit_FromObject(CTX_data_edit_object(C));
+               if (em->selectmode & SCE_SELECT_VERTEX)
+                       elem_types |= BM_VERT;
+               if (em->selectmode & SCE_SELECT_EDGE)
+                       elem_types |= BM_EDGE;
+               if (em->selectmode & SCE_SELECT_FACE)
+                       elem_types |= BM_FACE;
+               RNA_enum_set(op->ptr, "elements", elem_types);
        }
 
-       
-       /* Randomize non-protected vertices indices, and create an array mapping old idx to new
-        *  from both blocks, keeping protected vertices at the same indices. */
-       vmap = randblock;
-       randblock = MEM_mallocN(sizeof(int) * randomized, "randvert randblock");
-       memcpy(randblock, vmap, randomized * sizeof(int));
-       BLI_array_randomize((void *)randblock, sizeof(int), randomized, seed);
-       t_blk = block + totvert - 1;
-       t_idx = vmap + totvert - 1;
-       r_idx = randblock + randomized - 1;
-       for (i = totvert; i--; t_blk--, t_idx--) {
-               if (*t_blk) /* Protected! */
-                       *t_idx = i;
+       sort_bmelem_flag(C, elem_types, BM_ELEM_SELECT, action, reverse, seed);
+       return OPERATOR_FINISHED;
+}
+
+static int edbm_sort_elements_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop)
+{
+       const char *prop_id = RNA_property_identifier(prop);
+       int action = RNA_enum_get(ptr, "type");
+
+       /* Only show seed for randomize action! */
+       if (strcmp(prop_id, "seed") == 0) {
+               if (action == SRT_RANDOMIZE)
+                       return TRUE;
                else
-                       *t_idx = *r_idx--;
+                       return FALSE;
        }
 
-       MEM_freeN(randblock);
-       MEM_freeN(block);
-
-       BM_mesh_remap(em->bm, vmap, NULL, NULL);
+       /* Hide seed for reverse and randomize actions! */
+       if (strcmp(prop_id, "reverse") == 0) {
+               if (ELEM(action, SRT_RANDOMIZE, SRT_REVERSE))
+                       return FALSE;
+               else
+                       return TRUE;
+       }
 
-       MEM_freeN(vmap);
+       return TRUE;
 }
 
-static int edbm_vertices_randomize_exec(bContext *C, wmOperator *op)
+static void edbm_sort_elements_ui(bContext *C, wmOperator *op)
 {
-       Object *obedit = CTX_data_edit_object(C);
-       BMEditMesh *em = BMEdit_FromObject(obedit);
-       unsigned int seed = RNA_int_get(op->ptr, "seed");
+       uiLayout *layout = op->layout;
+       wmWindowManager *wm = CTX_wm_manager(C);
+       PointerRNA ptr;
 
-       hashvert_flag(em, BM_ELEM_SELECT, seed);
+       RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
 
-       return OPERATOR_FINISHED;
+       /* Main auto-draw call. */
+       uiDefAutoButsRNA(layout, &ptr, edbm_sort_elements_draw_check_prop, '\0');
 }
 
-void MESH_OT_vertices_randomize(wmOperatorType *ot)
+void MESH_OT_sort_elements(wmOperatorType *ot)
 {
+       static EnumPropertyItem type_items[] = {
+               {SRT_VIEW_ZAXIS, "VIEW_ZAXIS", 0, "View Z Axis",
+                                "Sort selected elements from farest to nearest one in current view"},
+               {SRT_VIEW_XAXIS, "VIEW_XAXIS", 0, "View X Axis",
+                                "Sort selected elements from left to right one in current view"},
+               {SRT_CURSOR_DISTANCE, "CURSOR_DISTANCE", 0, "Cursor Distance",
+                                     "Sort selected elements from nearest to farest from 3D cursor"},
+               {SRT_MATERIAL, "MATERIAL", 0, "Material",
+                              "Sort selected elements from smallest to greatest material index (faces only!)"},
+               {SRT_SELECTED, "SELECTED", 0, "Selected",
+                              "Move all selected elements in first places, preserving their relative order "
+                              "(WARNING: this will affect unselected elements' indices as well!)"},
+               {SRT_RANDOMIZE, "RANDOMIZE", 0, "Randomize", "Randomize order of selected elements"},
+               {SRT_REVERSE, "REVERSE", 0, "Reverse", "Reverse current order of selected elements"},
+               {0, NULL, 0, NULL, NULL},
+       };
+
+       static EnumPropertyItem elem_items[] = {
+               {BM_VERT, "VERT", 0, "Vertices", ""},
+               {BM_EDGE, "EDGE", 0, "Edges", ""},
+               {BM_FACE, "FACE", 0, "Faces", ""},
+               {0, NULL, 0, NULL, NULL},
+       };
+
        /* identifiers */
-       ot->name = "Vertex Randomize";
-       ot->description = "Randomize vertex order";
-       ot->idname = "MESH_OT_vertices_randomize";
+       ot->name = "Sort Mesh Elements";
+       ot->description = "The order of selected vertices/edges/faces is modified, based on a given method";
+       ot->idname = "MESH_OT_sort_elements";
 
        /* api callbacks */
-       ot->exec = edbm_vertices_randomize_exec;
-
+       ot->invoke = WM_menu_invoke;
+       ot->exec = edbm_sort_elements_exec;
        ot->poll = ED_operator_editmesh;
+       ot->ui = edbm_sort_elements_ui;
 
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
-       /* Properties */
-       ot->prop = RNA_def_int(ot->srna, "seed", 0, 0, INT_MAX, "Seed", "Seed for the random generator", 0, 255);
+       /* properties */
+       ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Type of re-ordering operation to apply");
+       RNA_def_enum_flag(ot->srna, "elements", elem_items, 0, "Elements",
+                         "Which elements to affect (vertices, edges and/or faces)");
+       RNA_def_boolean(ot->srna, "reverse", FALSE, "Reverse", "Reverse the sorting effect");
+       RNA_def_int(ot->srna, "seed", 0, 0, INT_MAX, "Seed", "Seed for random-based operations", 0, 255);
 }
 
-/******end of qsort stuff ****/
-
+/****** end of qsort stuff ****/
 
 static int edbm_noise_exec(bContext *C, wmOperator *op)
 {
index 31c130d20c9102ec095a33e6baa2d347dfbc446a..cf17fce29716629773a5748149efec060778df70 100644 (file)
@@ -147,8 +147,6 @@ extern struct EnumPropertyItem *corner_type_items;
 void MESH_OT_merge(struct wmOperatorType *ot);
 void MESH_OT_subdivide(struct wmOperatorType *ot);
 void MESH_OT_remove_doubles(struct wmOperatorType *ot);
-void MESH_OT_vertices_randomize(struct wmOperatorType *ot);
-void MESH_OT_vertices_sort(struct wmOperatorType *ot);
 void MESH_OT_spin(struct wmOperatorType *ot);
 void MESH_OT_screw(struct wmOperatorType *ot);
 
@@ -183,7 +181,7 @@ void MESH_OT_rip(struct wmOperatorType *ot);
 
 void MESH_OT_shape_propagate_to_all(struct wmOperatorType *ot);
 void MESH_OT_blend_from_shape(struct wmOperatorType *ot);
-void MESH_OT_sort_faces(struct wmOperatorType *ot);
+void MESH_OT_sort_elements(struct wmOperatorType *ot);
 
 /* ******************* mesh_data.c */
 
index 9789fd03222ca79b3ada42895b0412594240a664..98dce10779fedede1c2eed0a8cf81604620ed594 100644 (file)
@@ -87,8 +87,6 @@ void ED_operatortypes_mesh(void)
        WM_operatortype_append(MESH_OT_primitive_ico_sphere_add);
        WM_operatortype_append(MESH_OT_duplicate);
        WM_operatortype_append(MESH_OT_remove_doubles);
-       WM_operatortype_append(MESH_OT_vertices_sort);
-       WM_operatortype_append(MESH_OT_vertices_randomize);
        WM_operatortype_append(MESH_OT_spin);
        WM_operatortype_append(MESH_OT_screw);
 
@@ -118,7 +116,7 @@ void ED_operatortypes_mesh(void)
        WM_operatortype_append(MESH_OT_dissolve_limited);
        WM_operatortype_append(MESH_OT_faces_shade_smooth);
        WM_operatortype_append(MESH_OT_faces_shade_flat);
-       WM_operatortype_append(MESH_OT_sort_faces);
+       WM_operatortype_append(MESH_OT_sort_elements);
 
        WM_operatortype_append(MESH_OT_delete);
        WM_operatortype_append(MESH_OT_edge_collapse);