=bmesh=
Multires interpolation now works on cases like simple cubes. (though it isn't perfect when bevelling sharp corners). Normal flipping is handled correctly, and multires interpolation now works on normal-inconsistent meshes (so long as they are manifold, at least).
This commit is contained in:
@@ -112,6 +112,7 @@ struct EditMesh;
|
||||
#define BM_ACTIVE (1<<6)
|
||||
#define BM_NONORMCALC (1<<7)
|
||||
#define BM_PINNED (1<<8)
|
||||
#define BM_FLIPPED (1<<9) /*internal flag, used for ensuring correct normals during multires interpolation*/
|
||||
|
||||
#include "bmesh_class.h"
|
||||
|
||||
@@ -149,6 +150,7 @@ struct BMFace *BM_Make_Ngon ( struct BMesh *bm, struct BMVert *v1, struct BMVert
|
||||
#define BM_TestHFlag(ele, f) (ele && (((BMHeader*)ele)->flag & (f)))
|
||||
#define BM_SetHFlag(ele, f) (((BMHeader*)ele)->flag = ((BMHeader*)ele)->flag | (f))
|
||||
#define BM_ClearHFlag(ele, f) (((BMHeader*)ele)->flag = ((BMHeader*)ele)->flag & ~(f))
|
||||
#define BM_ToggleHFlag(ele, f) (((BMHeader*)ele)->flag = ((BMHeader*)ele)->flag ^ (f))
|
||||
|
||||
/*stuff for setting indices in elements.*/
|
||||
#define BMINDEX_SET(ele, i) (((BMHeader*)ele)->index = i)
|
||||
|
||||
@@ -255,6 +255,8 @@ typedef struct BMesh {
|
||||
|
||||
ListBase errorstack;
|
||||
struct Object *ob; /*owner object*/
|
||||
|
||||
int opflag; /*current operator flag*/
|
||||
} BMesh;
|
||||
|
||||
BMFace *BM_Copy_Face(BMesh *bm, BMFace *f, int copyedges, int copyverts);
|
||||
|
||||
@@ -119,6 +119,12 @@ typedef struct BMOpDefine {
|
||||
/*BMOpDefine->flag*/
|
||||
#define BMOP_UNTAN_MULTIRES 1 /*switch from multires tangent space to absolute coordinates*/
|
||||
|
||||
/*ensures consistent normals before operator execution,
|
||||
restoring the original ones windings/normals afterwards.
|
||||
keep in mind, this won't work if the input mesh isn't
|
||||
manifold.*/
|
||||
#define BMOP_RATIONALIZE_NORMALS 2
|
||||
|
||||
/*------------- Operator API --------------*/
|
||||
|
||||
/*data types that use pointers (arrays, etc) should never
|
||||
@@ -147,6 +153,7 @@ void BMO_Finish_Op(struct BMesh *bm, struct BMOperator *op);
|
||||
#define BMO_TestFlag(bm, element, flag) (((BMHeader*)(element))->flags[bm->stackdepth-1].f & (flag))
|
||||
#define BMO_SetFlag(bm, element, flag) (((BMHeader*)(element))->flags[bm->stackdepth-1].f |= (flag))
|
||||
#define BMO_ClearFlag(bm, element, flag) (((BMHeader*)(element))->flags[bm->stackdepth-1].f &= ~(flag))
|
||||
#define BMO_ToggleFlag(bm, element, flag) (((BMHeader*)(element))->flags[bm->stackdepth-1].f ^= (flag))
|
||||
|
||||
/*profiling showed a significant amount of time spent in BMO_TestFlag
|
||||
void BMO_SetFlag(struct BMesh *bm, void *element, int flag);
|
||||
|
||||
@@ -457,9 +457,9 @@ double quad_coord(double aa[3], double bb[3], double cc[3], double dd[3], int a1
|
||||
|
||||
int quad_co(double *x, double *y, double v1[3], double v2[3], double v3[3], double v4[3], double p[3], float n[3])
|
||||
{
|
||||
float projverts[5][3];
|
||||
double xn, yn, zn, dprojverts[4][3], origin[3]={0.0f, 0.0f, 0.0f};
|
||||
int i, ax, ay;
|
||||
float projverts[5][3], n2[3];
|
||||
double dprojverts[4][3], origin[3]={0.0f, 0.0f, 0.0f};
|
||||
int i;
|
||||
|
||||
/*project points into 2d along normal*/
|
||||
VECCOPY(projverts[0], v1);
|
||||
@@ -467,7 +467,12 @@ int quad_co(double *x, double *y, double v1[3], double v2[3], double v3[3], doub
|
||||
VECCOPY(projverts[2], v3);
|
||||
VECCOPY(projverts[3], v4);
|
||||
VECCOPY(projverts[4], p);
|
||||
|
||||
|
||||
normal_quad_v3(n2, projverts[0], projverts[1], projverts[2], projverts[3]);
|
||||
|
||||
if (INPR(n, n2) < -FLT_EPSILON)
|
||||
return 0;
|
||||
|
||||
/*rotate*/
|
||||
poly_rotate_plane(n, projverts, 5);
|
||||
|
||||
@@ -494,8 +499,8 @@ int quad_co(double *x, double *y, double v1[3], double v2[3], double v3[3], doub
|
||||
}
|
||||
|
||||
|
||||
/*tl is loop to project onto, sl is loop whose internal displacement, co, is being
|
||||
projected. x and y are location in loop's mdisps grid of co.*/
|
||||
/*tl is loop to project onto, l is loop whose internal displacement, co, is being
|
||||
projected. x and y are location in loop's mdisps grid of point co.*/
|
||||
static int mdisp_in_mdispquad(BMesh *bm, BMLoop *l, BMLoop *tl, double p[3], double *x, double *y, int res)
|
||||
{
|
||||
double v1[3], v2[3], c[3], v3[3], v4[3], e1[3], e2[3];
|
||||
@@ -534,6 +539,10 @@ static void bmesh_loop_interp_mdisps(BMesh *bm, BMLoop *target, BMFace *source)
|
||||
double x, y, d, v1[3], v2[3], v3[3], v4[3] = {0.0f, 0.0f, 0.0f}, e1[3], e2[3], e3[3], e4[3];
|
||||
int ix, iy, res;
|
||||
|
||||
/*ignore 2-edged faces*/
|
||||
if (target->f->len < 3)
|
||||
return;
|
||||
|
||||
if (!CustomData_has_layer(&bm->ldata, CD_MDISPS))
|
||||
return;
|
||||
|
||||
|
||||
@@ -294,17 +294,46 @@ void BM_Compute_Normals(BMesh *bm)
|
||||
MEM_freeN(projectverts);
|
||||
}
|
||||
|
||||
/*
|
||||
* BMESH BEGIN/END EDIT
|
||||
*
|
||||
* Functions for setting up a mesh for editing and cleaning up after
|
||||
* the editing operations are done. These are called by the tools/operator
|
||||
* API for each time a tool is executed.
|
||||
*
|
||||
* Returns -
|
||||
* Nothing
|
||||
*
|
||||
/*
|
||||
This function ensures correct normals for the mesh, but
|
||||
sets the flag BM_FLIPPED in flipped faces, to allow restoration
|
||||
of original normals.
|
||||
|
||||
if undo is 0: calculate right normals
|
||||
if undo is 1: restore original normals
|
||||
*/
|
||||
//keep in sycn with utils.c!
|
||||
#define FACE_FLIP 8
|
||||
static void bmesh_rationalize_normals(BMesh *bm, int undo) {
|
||||
BMOperator bmop;
|
||||
BMFace *f;
|
||||
BMIter iter;
|
||||
|
||||
if (undo) {
|
||||
BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
|
||||
if (BM_TestHFlag(f, BM_FLIPPED)) {
|
||||
BM_flip_normal(bm, f);
|
||||
}
|
||||
BM_ClearHFlag(f, BM_FLIPPED);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
BMO_InitOpf(bm, &bmop, "righthandfaces faces=%af doflip=%d", 0);
|
||||
|
||||
BMO_push(bm, &bmop);
|
||||
bmesh_righthandfaces_exec(bm, &bmop);
|
||||
|
||||
BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
|
||||
if (BMO_TestFlag(bm, f, FACE_FLIP))
|
||||
BM_SetHFlag(f, BM_FLIPPED);
|
||||
else BM_ClearHFlag(f, BM_FLIPPED);
|
||||
}
|
||||
|
||||
BMO_pop(bm);
|
||||
BMO_Finish_Op(bm, &bmop);
|
||||
}
|
||||
|
||||
void bmesh_set_mdisps_space(BMesh *bm, int from, int to)
|
||||
{
|
||||
@@ -357,18 +386,45 @@ void bmesh_set_mdisps_space(BMesh *bm, int from, int to)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* BMESH BEGIN/END EDIT
|
||||
*
|
||||
* Functions for setting up a mesh for editing and cleaning up after
|
||||
* the editing operations are done. These are called by the tools/operator
|
||||
* API for each time a tool is executed.
|
||||
*
|
||||
* Returns -
|
||||
* Nothing
|
||||
*
|
||||
*/
|
||||
void bmesh_begin_edit(BMesh *bm, int flag) {
|
||||
bm->opflag = flag;
|
||||
|
||||
/*switch multires data out of tangent space*/
|
||||
if ((flag & BMOP_UNTAN_MULTIRES) && CustomData_has_layer(&bm->ldata, CD_MDISPS))
|
||||
if ((flag & BMOP_UNTAN_MULTIRES) && CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
|
||||
bmesh_set_mdisps_space(bm, MULTIRES_SPACE_TANGENT, MULTIRES_SPACE_ABSOLUTE);
|
||||
|
||||
/*ensure correct normals, if possible*/
|
||||
bmesh_rationalize_normals(bm, 0);
|
||||
BM_Compute_Normals(bm);
|
||||
} else if (flag & BMOP_RATIONALIZE_NORMALS) {
|
||||
bmesh_rationalize_normals(bm, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void bmesh_end_edit(BMesh *bm, int flag){
|
||||
/*switch multires data into tangent space*/
|
||||
if ((flag & BMOP_UNTAN_MULTIRES) && CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
|
||||
/*set normals to their previous winding*/
|
||||
bmesh_rationalize_normals(bm, 1);
|
||||
bmesh_set_mdisps_space(bm, MULTIRES_SPACE_ABSOLUTE, MULTIRES_SPACE_TANGENT);
|
||||
} else if (flag & BMOP_RATIONALIZE_NORMALS) {
|
||||
bmesh_rationalize_normals(bm, 1);
|
||||
}
|
||||
|
||||
bm->opflag = 0;
|
||||
|
||||
/*compute normals, clear temp flags and flush selections*/
|
||||
BM_Compute_Normals(bm);
|
||||
BM_SelectMode_Flush(bm);
|
||||
|
||||
/*switch multires data into tangent space*/
|
||||
if ((flag & BMOP_UNTAN_MULTIRES) && CustomData_has_layer(&bm->ldata, CD_MDISPS))
|
||||
bmesh_set_mdisps_space(bm, MULTIRES_SPACE_ABSOLUTE, MULTIRES_SPACE_TANGENT);
|
||||
}
|
||||
|
||||
@@ -665,15 +665,12 @@ int bmesh_loop_length(BMLoop *l)
|
||||
|
||||
int bmesh_loop_reverse_loop(BMesh *bm, BMFace *f, BMLoopList *lst){
|
||||
BMLoop *l = lst->first, *curloop, *oldprev, *oldnext;
|
||||
BMEdge *staticedar[64], **edar;
|
||||
int i, j, edok, len = 0;
|
||||
BMEdge **edar = NULL;
|
||||
MDisps *md;
|
||||
BLI_array_staticdeclare(edar, 64);
|
||||
int i, j, edok, len = 0, do_disps = CustomData_has_layer(&bm->ldata, CD_MDISPS);
|
||||
|
||||
len = bmesh_loop_length(l);
|
||||
if(len >= 64){
|
||||
edar = MEM_callocN(sizeof(BMEdge *)* len, "BM Edge pointer array");
|
||||
} else {
|
||||
edar = staticedar;
|
||||
}
|
||||
|
||||
for(i=0, curloop = l; i< len; i++, curloop= ((BMLoop*)(curloop->next)) ){
|
||||
curloop->e->head.eflag1 = 0;
|
||||
@@ -681,7 +678,7 @@ int bmesh_loop_reverse_loop(BMesh *bm, BMFace *f, BMLoopList *lst){
|
||||
bmesh_radial_remove_loop(curloop, curloop->e);
|
||||
/*in case of border edges we HAVE to zero out curloop->radial Next/Prev*/
|
||||
curloop->radial_next = curloop->radial_prev = NULL;
|
||||
edar[i] = curloop->e;
|
||||
BLI_array_append(edar, curloop->e);
|
||||
}
|
||||
|
||||
/*actually reverse the loop.*/
|
||||
@@ -691,6 +688,24 @@ int bmesh_loop_reverse_loop(BMesh *bm, BMFace *f, BMLoopList *lst){
|
||||
curloop->next = (BMLoop*)oldprev;
|
||||
curloop->prev = (BMLoop*)oldnext;
|
||||
curloop = oldnext;
|
||||
|
||||
if (do_disps) {
|
||||
float (*co)[3];
|
||||
int x, y, sides;
|
||||
|
||||
md = CustomData_bmesh_get(&bm->ldata, curloop->head.data, CD_MDISPS);
|
||||
if (!md->totdisp || !md->disps)
|
||||
continue;
|
||||
|
||||
sides=sqrt(md->totdisp);
|
||||
co = md->disps;
|
||||
|
||||
for (x=0; x<sides; x++) {
|
||||
for (y=0; y<x; y++) {
|
||||
swap_v3_v3(co[y*sides+x], co[sides*x + y]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(len == 2){ //two edged face
|
||||
@@ -722,8 +737,7 @@ int bmesh_loop_reverse_loop(BMesh *bm, BMFace *f, BMLoopList *lst){
|
||||
CHECK_ELEMENT(bm, curloop->f);
|
||||
}
|
||||
|
||||
if (edar != staticedar)
|
||||
MEM_freeN(edar);
|
||||
BLI_array_free(edar);
|
||||
|
||||
CHECK_ELEMENT(bm, f);
|
||||
|
||||
|
||||
@@ -93,10 +93,11 @@ BMOpDefine def_vertexsmooth = {
|
||||
BMOpDefine def_righthandfaces = {
|
||||
"righthandfaces",
|
||||
{{BMOP_OPSLOT_ELEMENT_BUF, "faces"},
|
||||
{BMOP_OPSLOT_INT, "doflip"}, //internal flag, used by bmesh_rationalize_normals
|
||||
{0} /*null-terminating sentinel*/,
|
||||
},
|
||||
bmesh_righthandfaces_exec,
|
||||
BMOP_UNTAN_MULTIRES
|
||||
BMOP_UNTAN_MULTIRES,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -150,7 +151,7 @@ BMOpDefine def_reversefaces = {
|
||||
{0} /*null-terminating sentinel*/,
|
||||
},
|
||||
bmesh_reversefaces_exec,
|
||||
BMOP_UNTAN_MULTIRES
|
||||
BMOP_UNTAN_MULTIRES,
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -1286,6 +1286,20 @@ int BMO_CallOpf(BMesh *bm, const char *fmt, ...) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* BMO_TOGGLEFLAG
|
||||
*
|
||||
* Toggles a flag for a certain element
|
||||
*
|
||||
*/
|
||||
#ifdef BMO_ToggleFlag
|
||||
#undef BMO_ToggleFlag
|
||||
#endif
|
||||
void BMO_ToggleFlag(BMesh *bm, void *element, int flag)
|
||||
{
|
||||
BMHeader *head = element;
|
||||
head->flags[bm->stackdepth-1].f ^= flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* BMO_SETFLAG
|
||||
|
||||
@@ -229,6 +229,7 @@ void bmesh_regionextend_exec(BMesh *bm, BMOperator *op)
|
||||
#define FACE_VIS 1
|
||||
#define FACE_FLAG 2
|
||||
#define FACE_MARK 4
|
||||
#define FACE_FLIP 8
|
||||
|
||||
/* NOTE: these are the original righthandfaces comment in editmesh_mods.c,
|
||||
copied here for reference.
|
||||
@@ -257,7 +258,7 @@ void bmesh_righthandfaces_exec(BMesh *bm, BMOperator *op)
|
||||
BLI_array_declare(fstack);
|
||||
BMLoop *l, *l2;
|
||||
float maxx, cent[3];
|
||||
int i, maxi;
|
||||
int i, maxi, flagflip = BMO_Get_Int(op, "doflip");
|
||||
|
||||
startf= NULL;
|
||||
maxx= -1.0e10;
|
||||
@@ -285,8 +286,13 @@ void bmesh_righthandfaces_exec(BMesh *bm, BMOperator *op)
|
||||
BM_Compute_Face_Center(bm, startf, cent);
|
||||
|
||||
/*make sure the starting face has the correct winding*/
|
||||
if (cent[0]*startf->no[0] + cent[1]*startf->no[1] + cent[2]*startf->no[2] < 0.0)
|
||||
if (cent[0]*startf->no[0] + cent[1]*startf->no[1] + cent[2]*startf->no[2] < 0.0) {
|
||||
BM_flip_normal(bm, startf);
|
||||
BMO_ToggleFlag(bm, startf, FACE_FLIP);
|
||||
|
||||
if (flagflip)
|
||||
BM_ToggleHFlag(startf, BM_FLIPPED);
|
||||
}
|
||||
|
||||
/*now that we've found our starting face, make all connected faces
|
||||
have the same winding. this is done recursively, using a manual
|
||||
@@ -312,9 +318,19 @@ void bmesh_righthandfaces_exec(BMesh *bm, BMOperator *op)
|
||||
BMO_SetFlag(bm, l2->f, FACE_VIS);
|
||||
i++;
|
||||
|
||||
if (l2->v == l->v)
|
||||
if (l2->v == l->v) {
|
||||
BM_flip_normal(bm, l2->f);
|
||||
|
||||
|
||||
BMO_ToggleFlag(bm, l2->f, FACE_FLIP);
|
||||
if (flagflip)
|
||||
BM_ToggleHFlag(l2->f, BM_FLIPPED);
|
||||
} else if (BM_TestHFlag(l2->f, BM_FLIPPED) || BM_TestHFlag(l->f, BM_FLIPPED)) {
|
||||
if (flagflip) {
|
||||
BM_ClearHFlag(l->f, BM_FLIPPED);
|
||||
BM_ClearHFlag(l2->f, BM_FLIPPED);
|
||||
}
|
||||
}
|
||||
|
||||
if (i == maxi) {
|
||||
BLI_array_growone(fstack);
|
||||
maxi++;
|
||||
|
||||
@@ -1710,11 +1710,13 @@ static int normals_make_consistent_exec(bContext *C, wmOperator *op)
|
||||
Object *obedit= CTX_data_edit_object(C);
|
||||
BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
|
||||
|
||||
if (!EDBM_CallOpf(em, op, "righthandfaces faces=%hf", BM_SELECT))
|
||||
/*doflip has to do with bmesh_rationalize_normals, it's an internal
|
||||
thing*/
|
||||
if (!EDBM_CallOpf(em, op, "righthandfaces faces=%hf doflip=%d", BM_SELECT, 1))
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
if (RNA_boolean_get(op->ptr, "inside"))
|
||||
EDBM_CallOpf(em, op, "reversefaces faces=%hf", BM_SELECT);
|
||||
EDBM_CallOpf(em, op, "reversefaces faces=%hf doflip=%d", BM_SELECT, 1);
|
||||
|
||||
DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
|
||||
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
|
||||
|
||||
Reference in New Issue
Block a user