brought back x-mirror editing, though it's currently buggy. also made tesselation face normals writable to disk.
This commit is contained in:
parent
b8b6fad640
commit
d6158a4019
|
@ -57,6 +57,10 @@ typedef struct BMEditMesh {
|
|||
/*Mesh structure this editmesh came from, if it came from one*/
|
||||
struct Mesh *me;
|
||||
struct Object *ob;
|
||||
|
||||
/*temp variables for x-mirror editing*/
|
||||
int mirror_cdlayer;
|
||||
int mirr_free_arrays;
|
||||
} BMEditMesh;
|
||||
|
||||
void BMEdit_RecalcTesselation(BMEditMesh *tm);
|
||||
|
|
|
@ -936,7 +936,7 @@ const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
|
|||
layerSwap_mcol, layerDefault_mcol},
|
||||
{sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
|
||||
/* 3 floats per normal vector */
|
||||
{sizeof(float)*3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
|
||||
{sizeof(float)*3, "vec3f", 1, NULL, NULL, NULL, NULL, NULL, NULL},
|
||||
{sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
|
||||
{sizeof(MFloatProperty), "MFloatProperty",1,"Float",NULL,NULL,NULL,NULL},
|
||||
{sizeof(MIntProperty), "MIntProperty",1,"Int",NULL,NULL,NULL,NULL},
|
||||
|
|
|
@ -316,6 +316,7 @@ void BM_Data_Interp_From_Verts(struct BMesh *bm, struct BMVert *v1, struct BMVer
|
|||
void BM_Data_Facevert_Edgeinterp(struct BMesh *bm, struct BMVert *v1, struct BMVert *v2, struct BMVert *v, struct BMEdge *e1, float fac);
|
||||
//void bmesh_data_interp_from_face(struct BMesh *bm, struct BMFace *source, struct BMFace *target);
|
||||
void BM_add_data_layer(BMesh *em, CustomData *data, int type);
|
||||
void BM_add_data_layer_named(BMesh *bm, CustomData *data, int type, char *name);
|
||||
void BM_free_data_layer(BMesh *em, CustomData *data, int type);
|
||||
|
||||
|
||||
|
|
|
@ -254,6 +254,18 @@ void BM_add_data_layer(BMesh *bm, CustomData *data, int type)
|
|||
if (olddata.layers) MEM_freeN(olddata.layers);
|
||||
}
|
||||
|
||||
void BM_add_data_layer_named(BMesh *bm, CustomData *data, int type, char *name)
|
||||
{
|
||||
CustomData olddata;
|
||||
|
||||
olddata= *data;
|
||||
olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL;
|
||||
CustomData_add_layer_named(data, type, CD_DEFAULT, NULL, 0, name);
|
||||
|
||||
update_data_blocks(bm, &olddata, data);
|
||||
if (olddata.layers) MEM_freeN(olddata.layers);
|
||||
}
|
||||
|
||||
void BM_free_data_layer(BMesh *bm, CustomData *data, int type)
|
||||
{
|
||||
CustomData olddata;
|
||||
|
|
|
@ -128,35 +128,14 @@ void BM_Select_Vert(BMesh *bm, BMVert *v, int select)
|
|||
if (BM_TestHFlag(v, BM_SELECT)) bm->totvertsel -= 1;
|
||||
BM_ClearHFlag(v, BM_SELECT);
|
||||
}
|
||||
|
||||
/*BMESH_TODO hrm, not sure if flushing here is such a good idea. . .
|
||||
but probably easier then calling a EDBM_Normalize_Selection after
|
||||
each tool?*/
|
||||
#if 0
|
||||
BM_ITER(e, &iter, bm, BM_EDGES_OF_VERT, v) {
|
||||
if (!BM_TestHFlag(e, BM_SELECT) && BM_TestHFlag(e->v1, BM_SELECT)
|
||||
&& BM_TestHFlag(e->v2, BM_SELECT)) {
|
||||
BM_SetHFlag(e, BM_SELECT);
|
||||
bm->totedgesel += 1;
|
||||
} else if (BM_TestHFlag(e, BM_SELECT) && (!BM_TestHFlag(e->v1, BM_SELECT)
|
||||
|| !BM_TestHFlag(e->v2, BM_SELECT))) {
|
||||
BM_ClearHFlag(e, BM_SELECT);
|
||||
bm->totedgesel -= 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* BMESH SELECT EDGE
|
||||
*
|
||||
* Changes selection state of a single edge
|
||||
* in a mesh. Note that this is actually not
|
||||
* 100 percent reliable. Deselecting an edge
|
||||
* will also deselect both its vertices
|
||||
* regardless of the selection state of
|
||||
* other edges incident upon it. Fixing this
|
||||
* issue breaks multi-select mode though...
|
||||
* in a mesh. Note that this may not be
|
||||
* 100 percent reliable.
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -165,7 +144,7 @@ void BM_Select_Edge(BMesh *bm, BMEdge *e, int select)
|
|||
int candesel;
|
||||
int testiso = 1;
|
||||
|
||||
/*I might move this logic to bmeshutils_mods.c, where it'd be invoked
|
||||
/*I might move this logic to editors/mesh/bmesh_select.c, where it'd be invoked
|
||||
by the selection tools. in that case, we'd still retain the checks
|
||||
for if an edge's verts can be deselected.*/
|
||||
|
||||
|
|
|
@ -85,6 +85,28 @@ struct rcti;
|
|||
|
||||
/* bmeshutils.c */
|
||||
|
||||
/*x-mirror editing api. usage:
|
||||
|
||||
EDBM_CacheMirrorVerts(em);
|
||||
...
|
||||
...
|
||||
BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
|
||||
mirrorv = EDBM_GetMirrorVert(em, v);
|
||||
}
|
||||
...
|
||||
...
|
||||
EDBM_EndMirrorCache(em);
|
||||
|
||||
note: why do we only allow x axis mirror editing?
|
||||
*/
|
||||
void EDBM_CacheMirrorVerts(struct BMEditMesh *em);
|
||||
|
||||
/*retrieves mirrored cache vert, or NULL if there isn't one.
|
||||
note: calling this without ensuring the mirror cache state
|
||||
is bad.*/
|
||||
struct BMVert *EDBM_GetMirrorVert(struct BMEditMesh *em, struct BMVert *v);
|
||||
void EDBM_EndMirrorCache(struct BMEditMesh *em);
|
||||
|
||||
void EDBM_RecalcNormals(struct BMEditMesh *em);
|
||||
|
||||
void EDBM_MakeEditBMesh(struct ToolSettings *ts, struct Scene *scene, struct Object *ob);
|
||||
|
|
|
@ -73,6 +73,8 @@
|
|||
#include "BKE_report.h"
|
||||
#include "BKE_tessmesh.h"
|
||||
|
||||
#include "bmesh.h"
|
||||
|
||||
#include "BIF_gl.h"
|
||||
#include "BIF_glutil.h"
|
||||
|
||||
|
@ -86,8 +88,8 @@
|
|||
|
||||
#include "UI_interface.h"
|
||||
|
||||
#include "editbmesh_bvh.h"
|
||||
#include "mesh_intern.h"
|
||||
#include "bmesh.h"
|
||||
|
||||
void EDBM_RecalcNormals(BMEditMesh *em)
|
||||
{
|
||||
|
@ -805,3 +807,91 @@ int EDBM_vertColorCheck(BMEditMesh *em)
|
|||
return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_MLOOPCOL);
|
||||
}
|
||||
|
||||
|
||||
void EDBM_CacheMirrorVerts(BMEditMesh *em)
|
||||
{
|
||||
BMBVHTree *tree = BMBVH_NewBVH(em);
|
||||
BMIter iter;
|
||||
BMVert *v;
|
||||
float invmat[4][4];
|
||||
int li, i;
|
||||
|
||||
if (!em->vert_index) {
|
||||
EDBM_init_index_arrays(em, 1, 0, 0);
|
||||
em->mirr_free_arrays = 1;
|
||||
}
|
||||
|
||||
if (!CustomData_get_layer_named(&em->bm->vdata, CD_PROP_INT, "__mirror_index")) {
|
||||
BM_add_data_layer_named(em->bm, &em->bm->vdata, CD_PROP_INT, "__mirror_index");
|
||||
}
|
||||
|
||||
li = CustomData_get_named_layer_index(&em->bm->vdata, CD_PROP_INT, "__mirror_index");
|
||||
em->bm->vdata.layers[li].flag |= CD_FLAG_TEMPORARY;
|
||||
|
||||
/*multiply verts by object matrix, temporarily*/
|
||||
|
||||
i = 0;
|
||||
BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
|
||||
BMINDEX_SET(v, i);
|
||||
i++;
|
||||
|
||||
if (em->ob)
|
||||
mul_m4_v3(em->ob->obmat, v->co);
|
||||
}
|
||||
|
||||
BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
|
||||
BMVert *mirr;
|
||||
int *idx = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, li);
|
||||
float co[3] = {-v->co[0], v->co[1], v->co[2]};
|
||||
|
||||
//temporary for testing, check for selection
|
||||
if (!BM_TestHFlag(v, BM_SELECT))
|
||||
continue;
|
||||
|
||||
mirr = BMBVH_FindClosestVertTopo(tree, co, BM_SEARCH_MAXDIST, v);
|
||||
if (mirr && mirr != v) {
|
||||
*idx = BMINDEX_GET(mirr);
|
||||
idx = CustomData_bmesh_get_layer_n(&em->bm->vdata,mirr->head.data, li);
|
||||
*idx = BMINDEX_GET(v);
|
||||
} else *idx = -1;
|
||||
}
|
||||
|
||||
/*unmultiply by object matrix*/
|
||||
if (em->ob) {
|
||||
i = 0;
|
||||
invert_m4_m4(invmat, em->ob->obmat);
|
||||
BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
|
||||
BMINDEX_SET(v, i);
|
||||
i++;
|
||||
|
||||
mul_m4_v3(invmat, v->co);
|
||||
}
|
||||
|
||||
BMBVH_FreeBVH(tree);
|
||||
}
|
||||
}
|
||||
|
||||
BMVert *EDBM_GetMirrorVert(BMEditMesh *em, BMVert *v)
|
||||
{
|
||||
int *mirr = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, em->mirror_cdlayer);
|
||||
|
||||
if (mirr && *mirr >=0 && *mirr < em->bm->totvert) {
|
||||
if (!em->vert_index) {
|
||||
printf("err: should only be called between "
|
||||
"EDBM_CacheMirrorVerts and EDBM_EndMirrorCache");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return em->vert_index[*mirr];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void EDBM_EndMirrorCache(BMEditMesh *em)
|
||||
{
|
||||
if (em->mirr_free_arrays) {
|
||||
MEM_freeN(em->vert_index);
|
||||
em->vert_index = NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -325,7 +325,7 @@ static float topo_compare(BMesh *bm, BMVert *v1, BMVert *v2, int tag)
|
|||
BLI_array_declare(stack2);
|
||||
float vec1[3], vec2[3], minangle=FLT_MAX, w;
|
||||
int lvl=1;
|
||||
static int maxlevel = 8;
|
||||
static int maxlevel = 3;
|
||||
|
||||
/*ok. see how similar v is to v2, based on topological similaritys in the local
|
||||
topological neighborhood*/
|
||||
|
@ -409,17 +409,65 @@ static float topo_compare(BMesh *bm, BMVert *v1, BMVert *v2, int tag)
|
|||
if (!s1->curl)
|
||||
s1->curl = s1->cure->loop;
|
||||
if (!s2->curl) {
|
||||
float no1[3], no2[3], angle;
|
||||
int wind1, wind2;
|
||||
|
||||
s2->curl = s2->cure->loop;
|
||||
|
||||
/*find which of two possible faces to use*/
|
||||
wind1 = winding(s1->v->co, s1->lastv->co,
|
||||
s1->v == s1->curl->v ? ((BMLoop*)s1->curl->head.prev->prev)->v->co : ((BMLoop*)s1->curl->head.next->next)->v->co);
|
||||
l1 = BM_OtherFaceLoop(s1->curl->e, s1->curl->f, s1->lastv);
|
||||
l2 = BM_OtherFaceLoop(s2->curl->e, s2->curl->f, s2->lastv);
|
||||
|
||||
wind2 = winding(s2->v->co, s2->lastv->co,
|
||||
s2->v == s2->curl->v ? ((BMLoop*)s2->curl->head.prev->prev)->v->co : ((BMLoop*)s2->curl->head.next->next)->v->co);
|
||||
if (l1->v == s2->lastv) {
|
||||
l1 = (BMLoop*) l1->head.next;
|
||||
if (l1->v == s2->v)
|
||||
l1 = (BMLoop*) l1->head.prev->prev;
|
||||
} else if (l1->v == s2->v) {
|
||||
l1 = (BMLoop*) l1->head.next;
|
||||
if (l1->v == s2->lastv)
|
||||
l1 = (BMLoop*) l1->head.prev->prev;
|
||||
}
|
||||
|
||||
if (l2->v == s2->lastv) {
|
||||
l2 = (BMLoop*) l2->head.next;
|
||||
if (l2->v == s2->v)
|
||||
l2 = (BMLoop*) l2->head.prev->prev;
|
||||
} else if (l2->v == s2->v) {
|
||||
l2 = (BMLoop*) l2->head.next;
|
||||
if (l2->v == s2->lastv)
|
||||
l2 = (BMLoop*) l2->head.prev->prev;
|
||||
}
|
||||
|
||||
wind1 = winding(s1->v->co, s1->lastv->co, l1->v->co);
|
||||
|
||||
wind2 = winding(s2->v->co, s2->lastv->co, l2->v->co);
|
||||
|
||||
/*if angle between the two adjacent faces is greater then 90 degrees,
|
||||
we need to flip wind2*/
|
||||
l1 = l2;
|
||||
l2 = s2->curl->radial.next->data;
|
||||
l2 = BM_OtherFaceLoop(l2->e, l2->f, s2->lastv);
|
||||
|
||||
if (l2->v == s2->lastv) {
|
||||
l2 = (BMLoop*) l2->head.next;
|
||||
if (l2->v == s2->v)
|
||||
l2 = (BMLoop*) l2->head.prev->prev;
|
||||
} else if (l2->v == s2->v) {
|
||||
l2 = (BMLoop*) l2->head.next;
|
||||
if (l2->v == s2->lastv)
|
||||
l2 = (BMLoop*) l2->head.prev->prev;
|
||||
}
|
||||
|
||||
normal_tri_v3(no1, s2->v->co, s2->lastv->co, l1->v->co);
|
||||
normal_tri_v3(no2, s2->v->co, s2->lastv->co, l2->v->co);
|
||||
|
||||
/*enforce identical winding as no1*/
|
||||
mul_v3_fl(no2, -1.0);
|
||||
|
||||
angle = angle_v3v3(no1, no2);
|
||||
if (angle > M_PI/2 - FLT_EPSILON*2)
|
||||
wind2 = !wind2;
|
||||
|
||||
if (wind1 == wind2)
|
||||
s2->curl = s2->curl->radial.next->data;
|
||||
}
|
||||
|
@ -444,10 +492,10 @@ static float topo_compare(BMesh *bm, BMVert *v1, BMVert *v2, int tag)
|
|||
/*repush the current stack item*/
|
||||
lvl++;
|
||||
|
||||
if (maxlevel % 2 == 0) {
|
||||
//if (maxlevel % 2 == 0) {
|
||||
BLI_ghash_insert(gh, v1, NULL);
|
||||
BLI_ghash_insert(gh, v2, NULL);
|
||||
}
|
||||
//}
|
||||
|
||||
/*now push the child node*/
|
||||
SPUSH(stack1, lvl, v1, lastv1, e1);
|
||||
|
@ -565,17 +613,13 @@ BMVert *BMBVH_FindClosestVertTopo(BMBVHTree *tree, float *co, float maxdist, BMV
|
|||
VECCOPY(hit.co, co);
|
||||
VECCOPY(tree->co, co);
|
||||
hit.index = -1;
|
||||
hit.dist = 10.0f;
|
||||
hit.dist = maxdist;
|
||||
|
||||
tree->curw = FLT_MAX;
|
||||
tree->curd = FLT_MAX;
|
||||
tree->curv = NULL;
|
||||
tree->curtag = 1;
|
||||
|
||||
BM_ITER(v, &iter, tree->bm, BM_VERTS_OF_MESH, NULL) {
|
||||
BMINDEX_SET(v, 0);
|
||||
}
|
||||
|
||||
tree->gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
|
||||
|
||||
tree->maxdist = maxdist;
|
||||
|
|
|
@ -17,6 +17,8 @@ struct BMFace *BMBVH_RayCast(struct BMBVHTree *tree, float *co, float *dir, floa
|
|||
int BMBVH_EdgeVisible(struct BMBVHTree *tree, struct BMEdge *e,
|
||||
struct RegionView3D *r3d, struct Object *obedit);
|
||||
|
||||
#define BM_SEARCH_MAXDIST 0.4f
|
||||
|
||||
/*find a vert closest to co in a sphere of radius maxdist*/
|
||||
struct BMVert *BMBVH_FindClosestVert(struct BMBVHTree *tree, float *co, float maxdist);
|
||||
struct BMVert *BMBVH_FindClosestVertTopo(struct BMBVHTree *tree, float *co,
|
||||
|
|
|
@ -2167,6 +2167,7 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
|
|||
|
||||
if (t->flag & T_MIRROR)
|
||||
{
|
||||
EDBM_CacheMirrorVerts(em);
|
||||
mirror = 1;
|
||||
}
|
||||
|
||||
|
@ -2359,12 +2360,12 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
|
|||
/* Mirror? */
|
||||
|
||||
//BMESH_TODO
|
||||
//if( (mirror>0 && tob->iloc[0]>0.0f) || (mirror<0 && tob->iloc[0]<0.0f)) {
|
||||
// BMVert *vmir= editmesh_get_x_mirror_vert(t->obedit, em, eve, tob->iloc, a); /* initializes octree on first call */
|
||||
// if(vmir != eve) {
|
||||
// tob->extra = vmir;
|
||||
// }
|
||||
//}
|
||||
if( (mirror>0 && tob->iloc[0]>0.0f) || (mirror<0 && tob->iloc[0]<0.0f)) {
|
||||
BMVert *vmir= EDBM_GetMirrorVert(em, eve); //t->obedit, em, eve, tob->iloc, a);
|
||||
if(vmir && vmir != eve) {
|
||||
tob->extra = vmir;
|
||||
}
|
||||
}
|
||||
tob++;
|
||||
}
|
||||
}
|
||||
|
@ -2390,6 +2391,12 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
|
|||
MEM_freeN(defmats);
|
||||
|
||||
BLI_array_free(selstate);
|
||||
|
||||
if (t->flag & T_MIRROR)
|
||||
{
|
||||
EDBM_EndMirrorCache(em);
|
||||
mirror = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* *** NODE EDITOR *** */
|
||||
|
|
|
@ -250,7 +250,6 @@ static void editbmesh_apply_to_mirror(TransInfo *t)
|
|||
{
|
||||
TransData *td = t->data;
|
||||
BMVert *eve;
|
||||
BMIter iter;
|
||||
int i;
|
||||
|
||||
for(i = 0 ; i < t->total; i++, td++) {
|
||||
|
|
Loading…
Reference in New Issue