Merged changes in the trunk up to revision 46557.
Conflicts resolved: source/blender/blenkernel/intern/material.c source/blender/blenkernel/intern/subsurf_ccg.c source/blender/blenloader/intern/readfile.c source/blender/editors/animation/anim_channels_defines.c source/blender/makesrna/intern/rna_scene.c Additional changes: * Fix for recent changes of BKE_* function renaming. * Fix for an "attempt to free NULL pointer" in BlenderStrokeRenderer::RenderStrokeRepBasic().
This commit is contained in:
@@ -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
|
||||
@@ -485,7 +487,7 @@ static int edbm_extrude_mesh(Scene *scene, Object *obedit, BMEditMesh *em, wmOpe
|
||||
* automatically building this data if invalid. Or something.
|
||||
*/
|
||||
// DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
|
||||
object_handle_update(scene, obedit);
|
||||
BKE_object_handle_update(scene, obedit);
|
||||
|
||||
/* individual faces? */
|
||||
// BIF_TransformSetUndo("Extrude");
|
||||
@@ -614,7 +616,7 @@ static int edbm_extrude_faces_exec(bContext *C, wmOperator *op)
|
||||
|
||||
edbm_extrude_face_indiv(em, op, BM_ELEM_SELECT, nor);
|
||||
|
||||
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
|
||||
EDBM_update_generic(C, em, TRUE);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
@@ -1251,6 +1253,7 @@ void MESH_OT_edge_split(wmOperatorType *ot)
|
||||
/* identifiers */
|
||||
ot->name = "Edge Split";
|
||||
ot->idname = "MESH_OT_edge_split";
|
||||
ot->description = "Split selected edges so that each neighbor face gets its own copy";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = edbm_edge_split_exec;
|
||||
@@ -3060,6 +3063,7 @@ void MESH_OT_beautify_fill(wmOperatorType *ot)
|
||||
/* identifiers */
|
||||
ot->name = "Beautify Fill";
|
||||
ot->idname = "MESH_OT_beautify_fill";
|
||||
ot->description = "Rearrange some faces to try to get less degenerated geometry";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = edbm_beautify_fill_exec;
|
||||
@@ -3657,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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user