Mesh elements sorting refactor.

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).
This commit is contained in:
Bastien Montagne 2012-05-06 17:14:56 +00:00
parent 9e3523b556
commit 1118b3fe3f
5 changed files with 532 additions and 349 deletions

@ -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()

@ -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. :/
*/

@ -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. */
/******************************************************************************
* qsort routines.
* Now unified, for vertices/edges/faces. */
/* TODO All this section could probably use a refresh...
* face code works in object mode, does everything in one op, while vert uses several...
*/
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. */
};
typedef struct xvertsort {
int x; /* X screen-coordinate */
int org_idx; /* Original index of this vertex _in the mempool_ */
} xvertsort;
typedef struct bmelemsort {
float srt; /* Sort factor */
int org_idx; /* Original index of this element _in its mempool_ */
} bmelemsort;
static int vergxco(const void *v1, const void *v2)
static int bmelemsort_comp(const void *v1, const void *v2)
{
const xvertsort *x1 = v1, *x2 = v2;
const bmelemsort *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);
return (x1->srt > x2->srt) - (x1->srt < x2->srt);
}
static void xsortvert_flag__doSetX(void *userData, BMVert *UNUSED(eve), int x, int UNUSED(y), int index)
{
xvertsort *sortblock = userData;
sortblock[index].x = x;
}
/* 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++;
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;
mult_m4_m4m4(mat, rv3d->viewmat, ob->obmat); /* Apply the view matrix to the object matrix. */
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)) {
float co[3];
mul_v3_m4v3(co, mat, ve->co);
pb[i] = FALSE;
sb[affected[0]].org_idx = i;
sb[affected[0]++].srt = co[coidx] * fact;
}
else {
pb[i] = TRUE;
}
}
}
else {
unchangedblock[unchanged++] = i;
sortblock[i].org_idx = -1;
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");
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);
pb[i] = FALSE;
sb[affected[1]].org_idx = i;
sb[affected[1]++].srt = co[coidx] * fact;
}
else {
pb[i] = TRUE;
}
}
}
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");
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);
pb[i] = FALSE;
sb[affected[2]].org_idx = i;
sb[affected[2]++].srt = co[coidx] * fact;
}
else {
pb[i] = TRUE;
}
}
}
}
/* printf("%d verts: %d to be sorted, %d unchanged…\n", totvert, sorted, unchanged);*/
if (sorted == 0) {
MEM_freeN(sortblock);
MEM_freeN(unchangedblock);
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;
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;
}
}
}
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");
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);
pb[i] = FALSE;
sb[affected[1]].org_idx = i;
sb[affected[1]++].srt = len_squared_v3v3(cur, co) * fact;
}
else {
pb[i] = TRUE;
}
}
}
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");
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);
pb[i] = FALSE;
sb[affected[2]].org_idx = i;
sb[affected[2]++].srt = len_squared_v3v3(cur, co) * fact;
}
else {
pb[i] = TRUE;
}
}
}
}
/* 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;
}
}
}
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++;
}
}
}
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 {
*tb = i;
tb++;
}
}
}
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;
}
if (reverse) {
memcpy(tb + (tot - aff), mp, aff * sizeof(int));
}
else {
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();
}
else {
pb[i] = TRUE;
}
}
}
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;
}
}
}
}
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");
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;
}
}
}
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");
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;
}
}
}
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");
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;
}
}
}
}
/* 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;
}
ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
mesh_foreachScreenVert(&vc, xsortvert_flag__doSetX, sortblock, V3D_CLIP_TEST_OFF);
/* 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(sortblock, totvert, sizeof(xvertsort), vergxco);
qsort(sb, aff, sizeof(bmelemsort), bmelemsort_comp);
/* 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;
}
MEM_freeN(sortblock);
if (unchangedblock)
MEM_freeN(unchangedblock);
BM_mesh_remap(em->bm, vmap, NULL, NULL);
MEM_freeN(vmap);
}
static int edbm_vertices_sort_exec(bContext *C, wmOperator *UNUSED(op))
{
xsortvert_flag(C, BM_ELEM_SELECT);
return OPERATOR_FINISHED;
}
void MESH_OT_vertices_sort(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Vertex Sort";
ot->description = "Sort vertex order";
ot->idname = "MESH_OT_vertices_sort";
/* api callbacks */
ot->exec = edbm_vertices_sort_exec;
ot->poll = EM_view3d_poll; /* uses view relative X axis to sort verts */
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ********************** SORT FACES ******************* */
static void permutate(void *list, int num, int size, int *index)
{
void *buf;
int len;
int i;
len = num * size;
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);
}
/* 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;
}
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);
me = ob->data;
if (me->totpoly == 0) {
ED_object_enter_editmode(C, 0);
return OPERATOR_FINISHED;
}
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;
}
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();
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--;
}
}
}
qsort(index, me->totpoly, sizeof(int), float_sort);
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]);
}
}
static int edbm_sort_elements_exec(bContext *C, wmOperator *op)
{
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);
}
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);
}
else {
copy_v3_v3(cur, scene->cursor);
}
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;
}
else if (event == 4) {
/* selected first */
if (mp->flag & ME_FACE_SEL)
face_sort_floats[i] = 0.0;
else
face_sort_floats[i] = reverse;
}
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);
}
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 if (event == 2) { /* distance from cursor */
face_sort_floats[i] = len_v3v3(cur, vec) * reverse; /* back to front */
}
}
}
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);
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);
}
MEM_freeN(index);
DAG_id_tag_update(ob->data, 0);
/* Return to editmode. */
ED_object_enter_editmode(C, 0);
sort_bmelem_flag(C, elem_types, BM_ELEM_SELECT, action, reverse, seed);
return OPERATOR_FINISHED;
}
void MESH_OT_sort_faces(wmOperatorType *ot)
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
return FALSE;
}
/* 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;
}
return TRUE;
}
static void edbm_sort_elements_ui(bContext *C, wmOperator *op)
{
uiLayout *layout = op->layout;
wmWindowManager *wm = CTX_wm_manager(C);
PointerRNA ptr;
RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
/* Main auto-draw call. */
uiDefAutoButsRNA(layout, &ptr, edbm_sort_elements_draw_check_prop, '\0');
}
void MESH_OT_sort_elements(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 }};
{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 = "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";
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->invoke = WM_menu_invoke;
ot->exec = edbm_sort_faces_exec;
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_enum(ot->srna, "type", type_items, 0, "Type", "");
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);
}
/* ******************************* Randomize verts ************************* */
static void hashvert_flag(BMEditMesh *em, int flag, unsigned int seed)
{
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;
}
}
/* 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;
}
/* 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;
else
*t_idx = *r_idx--;
}
MEM_freeN(randblock);
MEM_freeN(block);
BM_mesh_remap(em->bm, vmap, NULL, NULL);
MEM_freeN(vmap);
}
static int edbm_vertices_randomize_exec(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");
hashvert_flag(em, BM_ELEM_SELECT, seed);
return OPERATOR_FINISHED;
}
void MESH_OT_vertices_randomize(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Vertex Randomize";
ot->description = "Randomize vertex order";
ot->idname = "MESH_OT_vertices_randomize";
/* api callbacks */
ot->exec = edbm_vertices_randomize_exec;
ot->poll = ED_operator_editmesh;
/* 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);
}
/******end of qsort stuff ****/
/****** end of qsort stuff ****/
static int edbm_noise_exec(bContext *C, wmOperator *op)
{

@ -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 */

@ -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);