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:
2012-05-11 22:48:41 +00:00
631 changed files with 52120 additions and 48222 deletions

View 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
@@ -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)
{