From c72ab0a39e2b0894c3ae0d27afeb0779b947853a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 17 Feb 2010 19:50:42 +0000 Subject: topology based mirror, (from apricot branch) - correct errors with non-mirrored meshes - mirror weight paint on asymmetrical meshes --- source/blender/editors/include/ED_mesh.h | 2 +- source/blender/editors/mesh/editmesh_mods.c | 10 +- source/blender/editors/mesh/meshtools.c | 299 ++++++++++++++++++++- .../blender/editors/space_view3d/view3d_buttons.c | 20 +- .../editors/transform/transform_conversions.c | 40 ++- 5 files changed, 344 insertions(+), 27 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index cf2d16574df..886da0820a2 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -78,7 +78,7 @@ struct rcti; /* meshtools.c */ intptr_t mesh_octree_table(struct Object *ob, struct EditMesh *em, float *co, char mode); -struct EditVert *editmesh_get_x_mirror_vert(struct Object *ob, struct EditMesh *em, float *co); +struct EditVert *editmesh_get_x_mirror_vert(struct Object *ob, struct EditMesh *em, struct EditVert *eve, float *co, int index); int mesh_get_x_mirror_vert(struct Object *ob, int index); int *mesh_get_x_mirror_faces(struct Object *ob, struct EditMesh *em); diff --git a/source/blender/editors/mesh/editmesh_mods.c b/source/blender/editors/mesh/editmesh_mods.c index b2ae7ddf7e0..c5ec1214be9 100644 --- a/source/blender/editors/mesh/editmesh_mods.c +++ b/source/blender/editors/mesh/editmesh_mods.c @@ -104,14 +104,15 @@ static int pupmenu() {return 0;} void EM_cache_x_mirror_vert(struct Object *ob, struct EditMesh *em) { EditVert *eve, *eve_mirror; + int index= 0; for(eve= em->verts.first; eve; eve= eve->next) { eve->tmp.v= NULL; } - for(eve= em->verts.first; eve; eve= eve->next) { + for(eve= em->verts.first; eve; eve= eve->next, index++) { if(eve->tmp.v==NULL) { - eve_mirror = editmesh_get_x_mirror_vert(ob, em, eve->co); + eve_mirror = editmesh_get_x_mirror_vert(ob, em, eve, eve->co, index); if(eve_mirror) { eve->tmp.v= eve_mirror; eve_mirror->tmp.v = eve; @@ -4239,6 +4240,7 @@ static int smooth_vertex(bContext *C, wmOperator *op) float fvec[3]; int teller=0; ModifierData *md; + int index; /* count */ eve= em->verts.first; @@ -4313,13 +4315,14 @@ static int smooth_vertex(bContext *C, wmOperator *op) eed= eed->next; } + index= 0; eve= em->verts.first; while(eve) { if(eve->f & SELECT) { if(eve->f1) { if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) { - eve_mir= editmesh_get_x_mirror_vert(obedit, em, eve->co); + eve_mir= editmesh_get_x_mirror_vert(obedit, em, eve, eve->co, index); } adr = eve->tmp.p; @@ -4352,6 +4355,7 @@ static int smooth_vertex(bContext *C, wmOperator *op) } eve->tmp.p= NULL; } + index++; eve= eve->next; } MEM_freeN(adror); diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index 55e8b55dcd5..e345d743172 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -989,7 +989,200 @@ intptr_t mesh_octree_table(Object *ob, EditMesh *em, float *co, char mode) return 0; } -int mesh_get_x_mirror_vert(Object *ob, int index) + +/* ********************* MESH VERTEX MIRR TOPO LOOKUP *************** */ + +#define MIRRHASH_TYPE int + +typedef struct MirrTopoPair { + long hash; + int vIndex; +} MirrTopoPair; + +static int MirrTopo_long_sort(const void *l1, const void *l2) +{ + if( (MIRRHASH_TYPE)(intptr_t)l1 > (MIRRHASH_TYPE)(intptr_t)l2 ) return 1; + else if( (MIRRHASH_TYPE)(intptr_t)l1 < (MIRRHASH_TYPE)(intptr_t)l2 ) return -1; + return 0; +} + +static int MirrTopo_item_sort(const void *v1, const void *v2) +{ + if( ((MirrTopoPair *)v1)->hash > ((MirrTopoPair *)v2)->hash ) return 1; + else if( ((MirrTopoPair *)v1)->hash < ((MirrTopoPair *)v2)->hash ) return -1; + return 0; +} + +static long *mesh_topo_lookup = NULL; +static int mesh_topo_lookup_tot = -1; +static int mesh_topo_lookup_mode = -1; + +/* mode is 's' start, or 'e' end, or 'u' use */ +/* if end, ob can be NULL */ +long mesh_mirrtopo_table(Object *ob, char mode) +{ + if(mode=='u') { /* use table */ + Mesh *me= ob->data; + if( (mesh_topo_lookup==NULL) || + (mesh_topo_lookup_mode != ob->mode) || + (me->edit_mesh && me->edit_mesh->totvert != mesh_topo_lookup_tot) || + (me->edit_mesh==NULL && me->totvert != mesh_topo_lookup_tot) + ) { + mesh_mirrtopo_table(ob, 's'); + } + } else if(mode=='s') { /* start table */ + Mesh *me= ob->data; + MEdge *medge; + EditMesh *em= me->edit_mesh; + + mesh_topo_lookup_mode= ob->mode; + + /* editmode*/ + EditEdge *eed; + + int a, last, totvert; + int totUnique= -1, totUniqueOld= -1; + + MIRRHASH_TYPE *MirrTopoHash = NULL; + MIRRHASH_TYPE *MirrTopoHash_Prev = NULL; + MirrTopoPair *MirrTopoPairs; + + /* reallocate if needed */ + if (mesh_topo_lookup) { + MEM_freeN(mesh_topo_lookup); + mesh_topo_lookup = NULL; + } + + if(em) { + EditVert *eve; + totvert= 0; + for(eve= em->verts.first; eve; eve= eve->next) { + eve->hash = totvert++; + } + } else { + totvert = me->totvert; + } + + MirrTopoHash = MEM_callocN( totvert * sizeof(MIRRHASH_TYPE), "TopoMirr" ); + + /* Initialize the vert-edge-user counts used to detect unique topology */ + if(em) { + for(eed=em->edges.first; eed; eed= eed->next) { + MirrTopoHash[eed->v1->hash]++; + MirrTopoHash[eed->v2->hash]++; + } + } else { + for(a=0, medge=me->medge; atotedge; a++, medge++) { + MirrTopoHash[medge->v1]++; + MirrTopoHash[medge->v2]++; + } + } + + MirrTopoHash_Prev = MEM_dupallocN( MirrTopoHash ); + + totUniqueOld = -1; + while(1) { + /* use the number of edges per vert to give verts unique topology IDs */ + + if(em) { + for(eed=em->edges.first; eed; eed= eed->next) { + MirrTopoHash[eed->v1->hash] += MirrTopoHash_Prev[eed->v2->hash]; + MirrTopoHash[eed->v2->hash] += MirrTopoHash_Prev[eed->v1->hash]; + } + } else { + for(a=0, medge=me->medge; atotedge; a++, medge++) { + /* This can make realy big numbers, wrapping around here is fine */ + MirrTopoHash[medge->v1] += MirrTopoHash_Prev[medge->v2]; + MirrTopoHash[medge->v2] += MirrTopoHash_Prev[medge->v1]; + } + } + memcpy(MirrTopoHash_Prev, MirrTopoHash, sizeof(MIRRHASH_TYPE) * totvert); + + /* sort so we can count unique values */ + qsort(MirrTopoHash_Prev, totvert, sizeof(MIRRHASH_TYPE), MirrTopo_long_sort); + + totUnique = 1; /* account for skiping the first value */ + for(a=1; a= 2) && (MirrTopoPairs[0].hash == MirrTopoPairs[1].hash)) ? 0 : 1; + + /* Get the pairs out of the sorted hashes, note, totvert+1 means we can use the previous 2, + * but you cant ever access the last 'a' index of MirrTopoPairs */ + for(a=2; a < totvert+1; a++) { + /* printf("I %d %ld %d\n", (a-last), MirrTopoPairs[a ].hash, MirrTopoPairs[a ].vIndex ); */ + if ((a==totvert) || (MirrTopoPairs[a-1].hash != MirrTopoPairs[a].hash)) { + if (a-last==2) { + if(em) { + mesh_topo_lookup[MirrTopoPairs[a-1].vIndex] = (long)EM_get_vert_for_index(MirrTopoPairs[a-2].vIndex); + mesh_topo_lookup[MirrTopoPairs[a-2].vIndex] = (long)EM_get_vert_for_index(MirrTopoPairs[a-1].vIndex); + } else { + mesh_topo_lookup[MirrTopoPairs[a-1].vIndex] = MirrTopoPairs[a-2].vIndex; + mesh_topo_lookup[MirrTopoPairs[a-2].vIndex] = MirrTopoPairs[a-1].vIndex; + } + } + last= a; + } + } + if(em) { + EM_free_index_arrays(); + } + + MEM_freeN( MirrTopoPairs ); + MirrTopoPairs = NULL; + + MEM_freeN( MirrTopoHash ); + MEM_freeN( MirrTopoHash_Prev ); + + mesh_topo_lookup_tot = totvert; + + } else if(mode=='e') { /* end table */ + if (mesh_topo_lookup) { + MEM_freeN(mesh_topo_lookup); + } + mesh_topo_lookup = NULL; + mesh_topo_lookup_tot= -1; + } + return 0; +} + +int mesh_get_x_mirror_vert_spacial(Object *ob, int index) { Mesh *me= ob->data; MVert *mvert; @@ -1003,7 +1196,24 @@ int mesh_get_x_mirror_vert(Object *ob, int index) return mesh_octree_table(ob, NULL, vec, 'u'); } -EditVert *editmesh_get_x_mirror_vert(Object *ob, EditMesh *em, float *co) +static int mesh_get_x_mirror_vert_topo(Object *ob, int index) +{ + if (mesh_mirrtopo_table(ob, 'u')==-1) + return -1; + + return mesh_topo_lookup[index]; +} + +int mesh_get_x_mirror_vert(Object *ob, int index) +{ + if (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_TOPO) { + return mesh_get_x_mirror_vert_topo(ob, index); + } else { + return mesh_get_x_mirror_vert_spacial(ob, index); + } +} + +static EditVert *editmesh_get_x_mirror_vert_spacial(Object *ob, EditMesh *em, float *co) { float vec[3]; intptr_t poinval; @@ -1025,6 +1235,91 @@ EditVert *editmesh_get_x_mirror_vert(Object *ob, EditMesh *em, float *co) return NULL; } +static EditVert *editmesh_get_x_mirror_vert_topo(Object *ob, struct EditMesh *em, EditVert *eve, int index) +{ + long poinval; + if (mesh_mirrtopo_table(ob, 'u')==-1) + return NULL; + + if (index!=-1) { + index = BLI_findindex(&em->verts, eve); + } + + if (index==-1) + return NULL; + + poinval= mesh_topo_lookup[ index ]; + + if(poinval != -1) + return (EditVert *)(poinval); + return NULL; +} + +EditVert *editmesh_get_x_mirror_vert(Object *ob, struct EditMesh *em, EditVert *eve, float *co, int index) +{ + if (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_TOPO) { + return editmesh_get_x_mirror_vert_topo(ob, em, eve, index); + } else { + return editmesh_get_x_mirror_vert_spacial(ob, em, eve->co); + } +} + + +#if 0 +float *editmesh_get_mirror_uv(int axis, float *uv, float *mirrCent, float *face_cent) +{ + float vec[2]; + float cent_vec[2]; + float cent[2]; + + /* ignore nan verts */ + if (isnan(uv[0]) || !finite(uv[0]) || + isnan(uv[1]) || !finite(uv[1]) + ) + return NULL; + + if (axis) { + vec[0]= uv[0]; + vec[1]= -((uv[1])-mirrCent[1]) + mirrCent[1]; + + cent_vec[0] = face_cent[0]; + cent_vec[1]= -((face_cent[1])-mirrCent[1]) + mirrCent[1]; + } else { + vec[0]= -((uv[0])-mirrCent[0]) + mirrCent[0]; + vec[1]= uv[1]; + + cent_vec[0]= -((face_cent[0])-mirrCent[0]) + mirrCent[0]; + cent_vec[1] = face_cent[1]; + } + + /* + G.v2d->cursor[0] = mirrCent[0]; + G.v2d->cursor[1] = mirrCent[1]; + */ + + /* TODO - Optimize */ + { + EditFace *efa; + int i, len; + for(efa=em->faces.first; efa; efa=efa->next) { + MTFace *tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + uv_center(tf->uv, cent, (void *)efa->v4); + + if ( (fabs(cent[0] - cent_vec[0]) < 0.001) && (fabs(cent[1] - cent_vec[1]) < 0.001) ) { + len = efa->v4 ? 4 : 3; + for (i=0; iuv[i][0] - vec[0]) < 0.001) && (fabs(tf->uv[i][1] - vec[1]) < 0.001) ) { + return tf->uv[i]; + } + } + } + } + } + + return NULL; +} +#endif + static unsigned int mirror_facehash(void *ptr) { MFace *mf= ptr; diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 1fc6ab2fc5b..f1668190ea8 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -502,13 +502,13 @@ static void act_vert_def(Object *ob, EditVert **eve, MDeformVert **dvert) *dvert= NULL; } -static void editvert_mirror_update(Object *ob, EditVert *eve, int def_nr) +static void editvert_mirror_update(Object *ob, EditVert *eve, int def_nr, int index) { Mesh *me= ob->data; EditMesh *em = BKE_mesh_get_editmesh(me); EditVert *eve_mirr; - eve_mirr= editmesh_get_x_mirror_vert(ob, em, eve->co); + eve_mirr= editmesh_get_x_mirror_vert(ob, em, eve, eve->co, index); if(eve_mirr && eve_mirr != eve) { MDeformVert *dvert_src= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); @@ -541,7 +541,7 @@ static void vgroup_adjust_active(Object *ob, int def_nr) if(dvert_act) { if(((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X) - editvert_mirror_update(ob, eve_act, def_nr); + editvert_mirror_update(ob, eve_act, def_nr, -1); } } @@ -560,15 +560,16 @@ static void vgroup_copy_active_to_sel(Object *ob) EditMesh *em = BKE_mesh_get_editmesh(me); EditVert *eve; MDeformVert *dvert; + int index= 0; - for(eve= em->verts.first; eve; eve= eve->next) { + for(eve= em->verts.first; eve; eve= eve->next, index++) { if(eve->f & SELECT && eve != eve_act) { dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); if(dvert) { defvert_copy(dvert, dvert_act); if(me->editflag & ME_EDIT_MIRROR_X) - editvert_mirror_update(ob, eve, -1); + editvert_mirror_update(ob, eve, -1, index); } } @@ -594,6 +595,7 @@ static void vgroup_copy_active_to_sel_single(Object *ob, int def_nr) MDeformWeight *dw; float act_weight = -1.0f; int i; + int index= 0; for(i=0, dw=dvert_act->dw; i < dvert_act->totweight; i++, dw++) { if(def_nr == dw->def_nr) { @@ -605,7 +607,7 @@ static void vgroup_copy_active_to_sel_single(Object *ob, int def_nr) if(act_weight < -0.5f) return; - for(eve= em->verts.first; eve; eve= eve->next) { + for(eve= em->verts.first; eve; eve= eve->next, index++) { if(eve->f & SELECT && eve != eve_act) { dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); if(dvert) { @@ -614,7 +616,7 @@ static void vgroup_copy_active_to_sel_single(Object *ob, int def_nr) dw->weight= act_weight; if(me->editflag & ME_EDIT_MIRROR_X) - editvert_mirror_update(ob, eve, -1); + editvert_mirror_update(ob, eve, -1, index); break; } @@ -624,7 +626,7 @@ static void vgroup_copy_active_to_sel_single(Object *ob, int def_nr) } if(me->editflag & ME_EDIT_MIRROR_X) - editvert_mirror_update(ob, eve_act, -1); + editvert_mirror_update(ob, eve_act, -1, -1); } } @@ -642,7 +644,7 @@ static void vgroup_normalize_active(Object *ob) defvert_normalize(dvert_act); if(((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X) - editvert_mirror_update(ob, eve_act, -1); + editvert_mirror_update(ob, eve_act, -1, -1); diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 7738299358a..8d01174ae2e 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -2272,8 +2272,10 @@ static void createTransEditVerts(bContext *C, TransInfo *t) /* Mirror? */ if( (mirror>0 && tob->iloc[0]>0.0f) || (mirror<0 && tob->iloc[0]<0.0f)) { - EditVert *vmir= editmesh_get_x_mirror_vert(t->obedit, em, tob->iloc); /* initializes octree on first call */ - if(vmir != eve) tob->extra = vmir; + EditVert *vmir= editmesh_get_x_mirror_vert(t->obedit, em, eve, tob->iloc, a); /* initializes octree on first call */ + if(vmir != eve) { + tob->extra = vmir; + } } tob++; } @@ -3283,7 +3285,7 @@ static void createTransActionData(bContext *C, TransInfo *t) /* Helper function for createTransGraphEditData, which is reponsible for associating * source data with transform data */ -static void bezt_to_transdata (TransData *td, TransData2D *td2d, AnimData *adt, float *loc, float *cent, short selected, short ishandle, short intvals) +static void bezt_to_transdata (TransData *td, TransData2D *td2d, AnimData *adt, float *loc, float *cent, short selected, short ishandle, short intvals, float iaspy) { /* New location from td gets dumped onto the old-location of td2d, which then * gets copied to the actual data at td2d->loc2d (bezt->vec[n]) @@ -3294,20 +3296,20 @@ static void bezt_to_transdata (TransData *td, TransData2D *td2d, AnimData *adt, if (adt) { td2d->loc[0] = BKE_nla_tweakedit_remap(adt, loc[0], NLATIME_CONVERT_MAP); - td2d->loc[1] = loc[1]; + td2d->loc[1] = loc[1] * iaspy; td2d->loc[2] = 0.0f; td2d->loc2d = loc; td->loc = td2d->loc; td->center[0] = BKE_nla_tweakedit_remap(adt, cent[0], NLATIME_CONVERT_MAP); - td->center[1] = cent[1]; + td->center[1] = cent[1] * iaspy; td->center[2] = 0.0f; VECCOPY(td->iloc, td->loc); } else { td2d->loc[0] = loc[0]; - td2d->loc[1] = loc[1]; + td2d->loc[1] = loc[1] * iaspy; td2d->loc[2] = 0.0f; td2d->loc2d = loc; @@ -3340,6 +3342,13 @@ static void bezt_to_transdata (TransData *td, TransData2D *td2d, AnimData *adt, unit_m3(td->smtx); } +static float UI_view2d_aspect_y(View2D *v2d) +{ + float viewx, viewy; + UI_view2d_region_to_view(v2d, 1, 1, &viewx, &viewy); + return -1.0 / (viewx / viewy); +} + static void createTransGraphEditData(bContext *C, TransInfo *t) { SpaceIpo *sipo= CTX_wm_space_graph(C); @@ -3444,7 +3453,13 @@ static void createTransGraphEditData(bContext *C, TransInfo *t) AnimData *adt= ANIM_nla_mapping_get(&ac, ale); FCurve *fcu= (FCurve *)ale->key_data; short intvals= (fcu->flag & FCURVE_INT_VALUES); - + + float iaspy; + if(intvals) + iaspy= 1.0f; + else + iaspy= 1.0f/UI_view2d_aspect_y(v2d); + /* convert current-frame to action-time (slightly less accurate, espcially under * higher scaling ratios, but is faster than converting all points) */ @@ -3468,14 +3483,14 @@ static void createTransGraphEditData(bContext *C, TransInfo *t) /* only include handles if selected, irrespective of the interpolation modes */ if (bezt->f1 & SELECT) { hdata = initTransDataCurveHandles(td, bezt); - bezt_to_transdata(td++, td2d++, adt, bezt->vec[0], bezt->vec[1], 1, 1, intvals); + bezt_to_transdata(td++, td2d++, adt, bezt->vec[0], bezt->vec[1], 1, 1, intvals, iaspy); } else h1= 0; if (bezt->f3 & SELECT) { if (hdata==NULL) hdata = initTransDataCurveHandles(td, bezt); - bezt_to_transdata(td++, td2d++, adt, bezt->vec[2], bezt->vec[1], 1, 1, intvals); + bezt_to_transdata(td++, td2d++, adt, bezt->vec[2], bezt->vec[1], 1, 1, intvals, iaspy); } else h2= 0; @@ -3490,7 +3505,7 @@ static void createTransGraphEditData(bContext *C, TransInfo *t) hdata = initTransDataCurveHandles(td, bezt); } - bezt_to_transdata(td++, td2d++, adt, bezt->vec[1], bezt->vec[1], 1, 0, intvals); + bezt_to_transdata(td++, td2d++, adt, bezt->vec[1], bezt->vec[1], 1, 0, intvals, iaspy); } /* special hack (must be done after initTransDataCurveHandles(), as that stores handle settings to restore...): @@ -3713,7 +3728,8 @@ void flushTransGraphData(TransInfo *t) Scene *scene= t->scene; double secf= FPS; int a; - + float aspy= UI_view2d_aspect_y(&t->ar->v2d); + /* flush to 2d vector from internally used 3d vector */ for (a=0, td= t->data, td2d=t->data2d; atotal; a++, td++, td2d++) { AnimData *adt= (AnimData *)td->extra; /* pointers to relevant AnimData blocks are stored in the td->extra pointers */ @@ -3747,7 +3763,7 @@ void flushTransGraphData(TransInfo *t) if (td->flag & TD_INTVALUES) td2d->loc2d[1]= (float)((int)td2d->loc[1]); else - td2d->loc2d[1]= td2d->loc[1]; + td2d->loc2d[1]= td2d->loc[1] * aspy; } } -- cgit v1.2.3