diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2009-01-18 01:14:08 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2009-01-18 01:14:08 +0300 |
commit | 0f4f89f19a664ee300b1da0e71cbf87a3536ebee (patch) | |
tree | 0509b516e11365f5ec17563813c5e9505cc93bf0 /source/blender/editors/uvedit | |
parent | a6edbba8ec49f628259c61555e5f0b4ad27b6c09 (diff) |
2.5: uv editor
- mouse select, loop select, select linked, unlink selection operators.
- added edge selection mode.
- fix 2.45 bug with unitialized theme colors, which caused the active face
and face centers to be not drawn.
Diffstat (limited to 'source/blender/editors/uvedit')
-rw-r--r-- | source/blender/editors/uvedit/uvedit_draw.c | 101 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_intern.h | 4 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_ops.c | 1605 |
3 files changed, 987 insertions, 723 deletions
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index d363639acbc..ddb45bdd736 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -412,25 +412,26 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFac /* draws uv's in the image space */ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) { + ToolSettings *settings; EditMesh *em; EditFace *efa, *efa_act; MTFace *tf, *activetf = NULL; DerivedMesh *finaldm, *cagedm; char col1[4], col2[4]; float pointsize; - int drawfaces, lastsel, sel; + int drawfaces, interpedges, lastsel, sel; Image *ima= sima->image; em= ((Mesh*)obedit->data)->edit_mesh; activetf= EM_get_active_mtface(em, &efa_act, NULL, 0); /* will be set to NULL if hidden */ + settings= scene->toolsettings; + drawfaces= draw_uvs_face_check(scene); - -#if 0 - calc_image_view(G.sima, 'f'); /* float */ - myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax); - glLoadIdentity(); -#endif + if(settings->uv_flag & UV_SYNC_SELECTION) + interpedges= (scene->selectmode & SCE_SELECT_VERTEX); + else + interpedges= (settings->uv_selectmode == UV_SELECT_VERTEX); /* 1. draw shadow mesh */ @@ -442,7 +443,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) /* when sync selection is enabled, all faces are drawn (except for hidden) * so if cage is the same as the final, theres no point in drawing this */ - if(!((scene->toolsettings->uv_flag & UV_SYNC_SELECTION) && (cagedm == finaldm))) + if(!((settings->uv_flag & UV_SYNC_SELECTION) && (cagedm == finaldm))) draw_uvs_dm_shadow(finaldm); /* release derivedmesh again */ @@ -614,37 +615,75 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) glColor4ubv((unsigned char *)col2); if(G.f & G_DRAWEDGES) { - glShadeModel(GL_SMOOTH); UI_GetThemeColor4ubv(TH_VERTEX_SELECT, col1); lastsel = sel = 0; - for(efa= em->faces.first; efa; efa= efa->next) { - tf= (MTFace *)efa->tmp.p; /* visible faces cached */ + if(interpedges) { + glShadeModel(GL_SMOOTH); - if(tf) { - glBegin(GL_LINE_LOOP); - sel = (uvedit_uv_selected(scene, efa, tf, 0) ? 1 : 0); - if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; } - glVertex2fv(tf->uv[0]); - - sel = uvedit_uv_selected(scene, efa, tf, 1) ? 1 : 0; - if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; } - glVertex2fv(tf->uv[1]); - - sel = uvedit_uv_selected(scene, efa, tf, 2) ? 1 : 0; - if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; } - glVertex2fv(tf->uv[2]); - - if(efa->v4) { - sel = uvedit_uv_selected(scene, efa, tf, 3) ? 1 : 0; + for(efa= em->faces.first; efa; efa= efa->next) { + tf= (MTFace *)efa->tmp.p; /* visible faces cached */ + + if(tf) { + glBegin(GL_LINE_LOOP); + sel = (uvedit_uv_selected(scene, efa, tf, 0)? 1 : 0); + if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; } + glVertex2fv(tf->uv[0]); + + sel = uvedit_uv_selected(scene, efa, tf, 1)? 1 : 0; + if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; } + glVertex2fv(tf->uv[1]); + + sel = uvedit_uv_selected(scene, efa, tf, 2)? 1 : 0; if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; } - glVertex2fv(tf->uv[3]); + glVertex2fv(tf->uv[2]); + + if(efa->v4) { + sel = uvedit_uv_selected(scene, efa, tf, 3)? 1 : 0; + if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; } + glVertex2fv(tf->uv[3]); + } + + glEnd(); + } + } + + glShadeModel(GL_FLAT); + } + else { + for(efa= em->faces.first; efa; efa= efa->next) { + tf= (MTFace *)efa->tmp.p; /* visible faces cached */ + + if(tf) { + glBegin(GL_LINES); + sel = (uvedit_edge_selected(scene, efa, tf, 0)? 1 : 0); + if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; } + glVertex2fv(tf->uv[0]); + glVertex2fv(tf->uv[1]); + + sel = uvedit_edge_selected(scene, efa, tf, 1)? 1 : 0; + if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; } + glVertex2fv(tf->uv[1]); + glVertex2fv(tf->uv[2]); + + sel = uvedit_edge_selected(scene, efa, tf, 2)? 1 : 0; + if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; } + glVertex2fv(tf->uv[2]); + + if(efa->v4) { + glVertex2fv(tf->uv[3]); + + sel = uvedit_edge_selected(scene, efa, tf, 3)? 1 : 0; + if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; } + glVertex2fv(tf->uv[3]); + } + + glVertex2fv(tf->uv[0]); + + glEnd(); } - - glEnd(); } } - glShadeModel(GL_FLAT); } else { /* no nice edges */ diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index 99656bf9fbc..ea188848e1e 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -56,6 +56,10 @@ int uvedit_face_selected(struct Scene *scene, struct EditFace *efa, struct MTFac void uvedit_face_select(struct Scene *scene, struct EditFace *efa, struct MTFace *tf); void uvedit_face_deselect(struct Scene *scene, struct EditFace *efa, struct MTFace *tf); +int uvedit_edge_selected(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i); +void uvedit_edge_select(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i); +void uvedit_edge_deselect(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i); + int uvedit_uv_selected(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i); void uvedit_uv_select(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i); void uvedit_uv_deselect(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i); diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index e097511e466..2e5f64ad6c6 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -28,6 +28,7 @@ */ #include <stdlib.h> +#include <string.h> #include <math.h> #include "MEM_guardedalloc.h" @@ -50,6 +51,7 @@ #include "BKE_image.h" #include "BKE_library.h" #include "BKE_mesh.h" +#include "BKE_report.h" #include "BKE_utildefines.h" #include "IMB_imbuf_types.h" // XXX remove? @@ -64,13 +66,13 @@ #include "WM_api.h" #include "WM_types.h" +#include "UI_view2d.h" + #include "uvedit_intern.h" /* local prototypes */ static void sel_uvco_inside_radius(SpaceImage *sima, Scene *scene, short sel, EditFace *efa, MTFace *tface, int index, float *offset, float *ell, short select_index); void uvedit_selectionCB(SpaceImage *sima, Scene *scene, ARegion *ar, short selecting, Object *obedit, short *mval, float rad); /* used in edit.c */ -void select_edgeloop_tface_uv(bContext *C, Scene *scene, Image *ima, Object *obedit, EditFace *startefa, int starta, int shift, int *flush); -void select_linked_tface_uv(bContext *C, Scene *scene, Image *ima, Object *obedit, int mode); void uvface_setsel__internal(bContext *C, SpaceImage *sima, Scene *scene, Object *obedit, short select); /************************* state testing ************************/ @@ -187,9 +189,9 @@ void ED_uvedit_set_tile(Scene *scene, Object *obedit, Image *ima, int curtile, i // XXX WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); } -/*********************** connection testing *********************/ +/*********************** space conversion *********************/ -static void uvedit_connection_limit(bContext *C, float *limit, float pixellimit) +static void uvedit_pixel_to_float(bContext *C, float *dist, float pixeldist) { ImBuf *ibuf= CTX_data_edit_image_buffer(C); float width, height; @@ -203,8 +205,8 @@ static void uvedit_connection_limit(bContext *C, float *limit, float pixellimit) height= 256.0f; } - limit[0]= pixellimit/width; - limit[1]= pixellimit/height; + dist[0]= pixeldist/width; + dist[1]= pixeldist/height; } /*************** visibility and selection utilities **************/ @@ -249,6 +251,58 @@ void uvedit_face_deselect(Scene *scene, EditFace *efa, MTFace *tf) tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); } +int uvedit_edge_selected(Scene *scene, EditFace *efa, MTFace *tf, int i) +{ + int nvert= (efa->v4)? 4: 3; + + if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) { + if(scene->selectmode == SCE_SELECT_FACE) + return (efa->f & SELECT); + else if(scene->selectmode == SCE_SELECT_EDGE) + return (*(&efa->e1 + i))->f & SELECT; + else + return (((efa->v1 + i)->f & SELECT) && ((efa->v1 + (i+1)%nvert)->f & SELECT)); + } + else + return (tf->flag & TF_SEL_MASK(i)) && (tf->flag & TF_SEL_MASK((i+1)%nvert)); +} + +void uvedit_edge_select(Scene *scene, EditFace *efa, MTFace *tf, int i) +{ + int nvert= (efa->v4)? 4: 3; + + if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) { + if(scene->selectmode == SCE_SELECT_FACE) + EM_select_face(efa, 1); + else if(scene->selectmode == SCE_SELECT_EDGE) + EM_select_edge((*(&efa->e1 + i)), 1); + else { + (efa->v1 + i)->f |= SELECT; + (efa->v1 + (i+1)%nvert)->f |= SELECT; + } + } + else + tf->flag |= TF_SEL_MASK(i)|TF_SEL_MASK((i+1)%nvert); +} + +void uvedit_edge_deselect(Scene *scene, EditFace *efa, MTFace *tf, int i) +{ + int nvert= (efa->v4)? 4: 3; + + if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) { + if(scene->selectmode == SCE_SELECT_FACE) + EM_select_face(efa, 0); + else if(scene->selectmode == SCE_SELECT_EDGE) + EM_select_edge((*(&efa->e1 + i)), 0); + else { + (efa->v1 + i)->f &= ~SELECT; + (efa->v1 + (i+1)%nvert)->f &= ~SELECT; + } + } + else + tf->flag &= ~(TF_SEL_MASK(i)|TF_SEL_MASK((i+1)%nvert)); +} + int uvedit_uv_selected(Scene *scene, EditFace *efa, MTFace *tf, int i) { if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) { @@ -445,6 +499,477 @@ void uvedit_constrain_square(Scene *scene, Image *ima, EditMesh *em) } } +/************************** find nearest ****************************/ + +typedef struct NearestHit { + EditFace *efa; + MTFace *tf; + + int vert, uv; + int edge, vert2; +} NearestHit; + +static void find_nearest_uv_edge(Scene *scene, Image *ima, EditMesh *em, float co[2], NearestHit *hit) +{ + MTFace *tf; + EditFace *efa; + EditVert *eve; + float mindist, dist; + int i, nverts; + + mindist= 1e10f; + memset(hit, 0, sizeof(*hit)); + + for(i=0, eve=em->verts.first; eve; eve=eve->next, i++) + eve->tmp.l = i; + + for(efa= em->faces.first; efa; efa= efa->next) { + tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + + if(uvedit_face_visible(scene, ima, efa, tf)) { + nverts= efa->v4? 4: 3; + + for(i=0; i<nverts; i++) { + dist= PdistVL2Dfl(co, tf->uv[i], tf->uv[(i+1)%nverts]); + + if(dist < mindist) { + hit->tf= tf; + hit->efa= efa; + hit->edge= i; + mindist= dist; + + hit->vert= (*(&efa->v1 + i))->tmp.l; + hit->vert2= (*(&efa->v1 + ((i+1)%nverts)))->tmp.l; + } + } + } + } +} + +static void find_nearest_uv_face(Scene *scene, Image *ima, EditMesh *em, float co[2], NearestHit *hit) +{ + MTFace *tf; + EditFace *efa; + float mindist, dist, cent[2]; + int i, nverts; + + mindist= 1e10f; + memset(hit, 0, sizeof(*hit)); + + for(efa= em->faces.first; efa; efa= efa->next) { + tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + + if(uvedit_face_visible(scene, ima, efa, tf)) { + nverts= efa->v4? 4: 3; + cent[0]= cent[1]= 0.0f; + + for(i=0; i<nverts; i++) { + cent[0] += tf->uv[i][0]; + cent[1] += tf->uv[i][1]; + } + + cent[0] /= nverts; + cent[1] /= nverts; + dist= fabs(co[0]- cent[0]) + fabs(co[1]- cent[1]); + + if(dist < mindist) { + hit->tf= tf; + hit->efa= efa; + mindist= dist; + } + } + } +} + +static int nearest_uv_between(MTFace *tf, int nverts, int id, float co[2], float uv[2]) +{ + float m[3], v1[3], v2[3], c1, c2; + int id1, id2; + + id1= (id+nverts-1)%nverts; + id2= (id+nverts+1)%nverts; + + m[0]= co[0]-uv[0]; + m[1]= co[1]-uv[1]; + Vec2Subf(v1, tf->uv[id1], tf->uv[id]); + Vec2Subf(v2, tf->uv[id2], tf->uv[id]); + + /* m and v2 on same side of v-v1? */ + c1= v1[0]*m[1] - v1[1]*m[0]; + c2= v1[0]*v2[1] - v1[1]*v2[0]; + + if(c1*c2 < 0.0f) + return 0; + + /* m and v1 on same side of v-v2? */ + c1= v2[0]*m[1] - v2[1]*m[0]; + c2= v2[0]*v1[1] - v2[1]*v1[0]; + + return (c1*c2 >= 0.0f); +} + +static void find_nearest_uv_vert(Scene *scene, Image *ima, EditMesh *em, float co[2], float penalty[2], NearestHit *hit) +{ + EditFace *efa; + EditVert *eve; + MTFace *tf; + float mindist, dist; + int i, nverts; + + mindist= 1e10f; + memset(hit, 0, sizeof(*hit)); + + for(i=0, eve=em->verts.first; eve; eve=eve->next, i++) + eve->tmp.l = i; + + for(efa= em->faces.first; efa; efa= efa->next) { + tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + + if(uvedit_face_visible(scene, ima, efa, tf)) { + nverts= efa->v4? 4: 3; + + for(i=0; i<nverts; i++) { + if(penalty && uvedit_uv_selected(scene, efa, tf, i)) + dist= fabs(co[0]-tf->uv[i][0])+penalty[0] + fabs(co[1]-tf->uv[i][1])+penalty[1]; + else + dist= fabs(co[0]-tf->uv[i][0]) + fabs(co[1]-tf->uv[i][1]); + + if(dist<=mindist) { + if(dist==mindist) + if(!nearest_uv_between(tf, nverts, i, co, tf->uv[i])) + continue; + + mindist= dist; + + hit->uv= i; + hit->tf= tf; + hit->efa= efa; + + hit->vert= (*(&efa->v1 + i))->tmp.l; + } + } + } + } +} + +/*********************** loop select ***********************/ + +static void uv_vertex_loop_flag(UvMapVert *first) +{ + UvMapVert *iterv; + int count= 0; + + for(iterv=first; iterv; iterv=iterv->next) { + if(iterv->separate && iterv!=first) + break; + + count++; + } + + if(count < 5) + first->flag= 1; +} + +static UvMapVert *uv_vertex_map_get(UvVertMap *vmap, EditFace *efa, int a) +{ + UvMapVert *iterv, *first; + + first= EM_get_uv_map_vert(vmap, (*(&efa->v1 + a))->tmp.l); + + for(iterv=first; iterv; iterv=iterv->next) { + if(iterv->separate) + first= iterv; + if(iterv->f == efa->tmp.l) + return first; + } + + return NULL; +} + +static int uv_edge_tag_faces(UvMapVert *first1, UvMapVert *first2, int *totface) +{ + UvMapVert *iterv1, *iterv2; + EditFace *efa; + int tot = 0; + + /* count number of faces this edge has */ + for(iterv1=first1; iterv1; iterv1=iterv1->next) { + if(iterv1->separate && iterv1 != first1) + break; + + for(iterv2=first2; iterv2; iterv2=iterv2->next) { + if(iterv2->separate && iterv2 != first2) + break; + + if(iterv1->f == iterv2->f) { + /* if face already tagged, don't do this edge */ + efa= EM_get_face_for_index(iterv1->f); + if(efa->f1) + return 0; + + tot++; + break; + } + } + } + + if(*totface == 0) /* start edge */ + *totface= tot; + else if(tot != *totface) /* check for same number of faces as start edge */ + return 0; + + /* tag the faces */ + for(iterv1=first1; iterv1; iterv1=iterv1->next) { + if(iterv1->separate && iterv1 != first1) + break; + + for(iterv2=first2; iterv2; iterv2=iterv2->next) { + if(iterv2->separate && iterv2 != first2) + break; + + if(iterv1->f == iterv2->f) { + efa= EM_get_face_for_index(iterv1->f); + efa->f1= 1; + break; + } + } + } + + return 1; +} + +static int select_edgeloop(Scene *scene, Image *ima, EditMesh *em, NearestHit *hit, float limit[2], int extend) +{ + EditVert *eve; + EditFace *efa; + MTFace *tf; + UvVertMap *vmap; + UvMapVert *iterv1, *iterv2; + int a, count, looking, nverts, starttotf, select; + + /* setup */ + EM_init_index_arrays(em, 0, 0, 1); + vmap= EM_make_uv_vert_map(em, 0, 0, limit); + + for(count=0, eve=em->verts.first; eve; count++, eve= eve->next) + eve->tmp.l = count; + + for(count=0, efa= em->faces.first; efa; count++, efa= efa->next) { + if(!extend) { + tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + uvedit_face_deselect(scene, efa, tf); + } + + efa->tmp.l= count; + efa->f1= 0; + } + + /* set flags for first face and verts */ + nverts= (hit->efa->v4)? 4: 3; + iterv1= uv_vertex_map_get(vmap, hit->efa, hit->edge); + iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->edge+1)%nverts); + uv_vertex_loop_flag(iterv1); + uv_vertex_loop_flag(iterv2); + + starttotf= 0; + uv_edge_tag_faces(iterv1, iterv2, &starttotf); + + /* sorry, first edge isnt even ok */ + if(iterv1->flag==0 && iterv2->flag==0) looking= 0; + else looking= 1; + + /* iterate */ + while(looking) { + looking= 0; + + /* find correct valence edges which are not tagged yet, but connect to tagged one */ + for(efa= em->faces.first; efa; efa=efa->next) { + tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + + if(!efa->f1 && uvedit_face_visible(scene, ima, efa, tf)) { + nverts= (efa->v4)? 4: 3; + for(a=0; a<nverts; a++) { + /* check face not hidden and not tagged */ + iterv1= uv_vertex_map_get(vmap, efa, a); + iterv2= uv_vertex_map_get(vmap, efa, (a+1)%nverts); + + /* check if vertex is tagged and has right valence */ + if(iterv1->flag || iterv2->flag) { + if(uv_edge_tag_faces(iterv1, iterv2, &starttotf)) { + looking= 1; + efa->f1= 1; + + uv_vertex_loop_flag(iterv1); + uv_vertex_loop_flag(iterv2); + break; + } + } + } + } + } + } + + /* do the actual select/deselect */ + nverts= (hit->efa->v4)? 4: 3; + iterv1= uv_vertex_map_get(vmap, hit->efa, hit->edge); + iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->edge+1)%nverts); + iterv1->flag= 1; + iterv2->flag= 1; + + if(extend) { + tf= CustomData_em_get(&em->fdata, hit->efa->data, CD_MTFACE); + + if(uvedit_uv_selected(scene, hit->efa, tf, hit->edge) && uvedit_uv_selected(scene, hit->efa, tf, hit->edge)) + select= 0; + else + select= 1; + } + else + select= 1; + + for(efa= em->faces.first; efa; efa=efa->next) { + tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + + nverts= (efa->v4)? 4: 3; + for(a=0; a<nverts; a++) { + iterv1= uv_vertex_map_get(vmap, efa, a); + + if(iterv1->flag) { + if(select) uvedit_uv_select(scene, efa, tf, a); + else uvedit_uv_deselect(scene, efa, tf, a); + } + } + } + + /* cleanup */ + EM_free_uv_vert_map(vmap); + EM_free_index_arrays(); + + return (select)? 1: -1; +} + +/*********************** linked select ***********************/ + +static void select_linked(Scene *scene, Image *ima, EditMesh *em, float limit[2], NearestHit *hit, int extend) +{ + EditFace *efa; + MTFace *tf; + UvVertMap *vmap; + UvMapVert *vlist, *iterv, *startv; + int a, i, nverts, j, stacksize= 0, *stack; + char *flag; + + vmap= EM_make_uv_vert_map(em, 1, 1, limit); + if(vmap == NULL) + return; + + stack= MEM_mallocN(sizeof(*stack)* BLI_countlist(&em->faces), "UvLinkStack"); + flag= MEM_callocN(sizeof(*flag)*BLI_countlist(&em->faces), "UvLinkFlag"); + + if(!hit) { + for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) { + tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + + if(uvedit_face_visible(scene, ima, efa, tf)) { + if(tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) { + stack[stacksize]= a; + stacksize++; + flag[a]= 1; + } + } + } + } + else { + for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) { + if(efa == hit->efa) { + stack[stacksize]= a; + stacksize++; + flag[a]= 1; + break; + } + } + } + + while(stacksize > 0) { + stacksize--; + a= stack[stacksize]; + + for(j=0, efa= em->faces.first; efa; efa= efa->next, j++) + if(j==a) + break; + + nverts= efa->v4? 4: 3; + + for(i=0; i<nverts; i++) { + /* make_uv_vert_map_EM sets verts tmp.l to the indicies */ + vlist= EM_get_uv_map_vert(vmap, (*(&efa->v1 + i))->tmp.l); + + startv= vlist; + + for(iterv=vlist; iterv; iterv=iterv->next) { + if(iterv->separate) + startv= iterv; + if(iterv->f == a) + break; + } + + for(iterv=startv; iterv; iterv=iterv->next) { + if((startv != iterv) && (iterv->separate)) + break; + else if(!flag[iterv->f]) { + flag[iterv->f]= 1; + stack[stacksize]= iterv->f;; + stacksize++; + } + } + } + } + + if(!extend || hit) { + for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) { + tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + if(flag[a]) + tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); + else + tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); + } + } + else if(extend && hit) { + for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) { + if(flag[a]) { + tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + if(efa->v4) { + if((tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4))) + break; + } + else if(tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) + break; + } + } + + if(efa) { + for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) { + if(flag[a]) { + tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); + } + } + } + else { + for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) { + if(flag[a]) { + tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); + } + } + } + } + + MEM_freeN(stack); + MEM_freeN(flag); + EM_free_uv_vert_map(vmap); +} + /* ******************** mirror operator **************** */ /* XXX */ @@ -666,7 +1191,7 @@ static int stitch_exec(bContext *C, wmOperator *op) int a, vtot; pixels= RNA_float_get(op->ptr, "limit"); - uvedit_connection_limit(C, limit, pixels); + uvedit_pixel_to_float(C, limit, pixels); EM_init_index_arrays(em, 0, 0, 1); vmap= EM_make_uv_vert_map(em, 1, 0, limit); @@ -941,328 +1466,200 @@ void UV_OT_de_select_all(wmOperatorType *ot) /* ******************** mouse select operator **************** */ -static int msel_hit(float *limit, unsigned int *hitarray, unsigned int vertexid, float **uv, float *uv2, int sticky) +static int sticky_select(float *limit, int hitv[4], int v, float *hituv[4], float *uv, int sticky) { int i; - for(i=0; i< 4; i++) { - if(hitarray[i] == vertexid) { - if(sticky == 2) { - if(fabs(uv[i][0]-uv2[0]) < limit[0] && - fabs(uv[i][1]-uv2[1]) < limit[1]) + + /* this function test if some vertex needs to selected + * in addition to the existing ones due to sticky select */ + if(sticky == SI_STICKY_DISABLE) + return 0; + + for(i=0; i<4; i++) { + if(hitv[i] == v) { + if(sticky == SI_STICKY_LOC) { + if(fabs(hituv[i][0]-uv[0]) < limit[0] && fabs(hituv[i][1]-uv[1]) < limit[1]) return 1; } - else return 1; + else if(sticky == SI_STICKY_VERTEX) + return 1; } } + return 0; } -static void find_nearest_uv_edge(Scene *scene, Image *ima, Object *obedit, MTFace **nearesttf, EditFace **nearestefa, int *nearestedge) +static int mouse_select(bContext *C, float co[2], int extend, int loop) { + SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C); + Scene *scene= CTX_data_scene(C); + Object *obedit= CTX_data_edit_object(C); + Image *ima= CTX_data_edit_image(C); EditMesh *em= ((Mesh*)obedit->data)->edit_mesh; - MTFace *tf; EditFace *efa; - float mvalf[2], v1[2], v2[2]; - int i, nverts, mindist, dist, uval1[2], uval2[2]; - short mval[2]; - - mval[0]= mval[1]= 0; // XXX getmouseco_areawin(mval); - mvalf[0]= mval[0]; - mvalf[1]= mval[1]; - - mindist= 0x7FFFFFF; - *nearesttf= NULL; - *nearestefa= NULL; - *nearestedge= 0; + MTFace *tf; + NearestHit hit; + int a, i, select, selectmode, sticky, sync, hitv[4], nvert; + int flush = 0; /* 0 == dont flush, 1 == sel, -1 == desel; only use when selection sync is enabled */ + float limit[2], *hituv[4], penalty[2]; - for(efa= em->faces.first; efa; efa= efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + uvedit_pixel_to_float(C, limit, 0.05f); + uvedit_pixel_to_float(C, penalty, 5.0f); - if(uvedit_face_visible(scene, ima, efa, tf)) { - nverts= efa->v4? 4: 3; - for(i=0; i<nverts; i++) { - uval1[0]= uval1[1]= 0; // XXX uvco_to_areaco_noclip(tf->uv[i], uval1); - uval2[0]= uval2[1]= 0; // XXX uvco_to_areaco_noclip(tf->uv[(i+1)%nverts], uval2); + /* retrieve operation mode */ + if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) { + sync= 1; - v1[0]= uval1[0]; - v1[1]= uval1[1]; - v2[0]= uval2[0]; - v2[1]= uval2[1]; + if(scene->selectmode & SCE_SELECT_FACE) + selectmode= UV_SELECT_FACE; + else if(scene->selectmode & SCE_SELECT_EDGE) + selectmode= UV_SELECT_EDGE; + else + selectmode= UV_SELECT_VERTEX; - dist= PdistVL2Dfl(mvalf, v1, v2); - if(dist < mindist) { - *nearesttf= tf; - *nearestefa= efa; - *nearestedge= i; - mindist= dist; - } - } - } + sticky= SI_STICKY_DISABLE; } -} - -static void find_nearest_tface(Scene *scene, Image *ima, Object *obedit, MTFace **nearesttf, EditFace **nearestefa) -{ - EditMesh *em= ((Mesh*)obedit->data)->edit_mesh; - MTFace *tf; - EditFace *efa; - int i, nverts, mindist, dist, fcenter[2], uval[2]; - short mval[2]; - - mval[0]= mval[1]= 0; // XXX getmouseco_areawin(mval); - - mindist= 0x7FFFFFF; - *nearesttf= NULL; - *nearestefa= NULL; - - for(efa= em->faces.first; efa; efa= efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(uvedit_face_visible(scene, ima, efa, tf)) { - fcenter[0]= fcenter[1]= 0; - nverts= efa->v4? 4: 3; - for(i=0; i<nverts; i++) { - uval[0]= uval[0]= 0; // XXX uvco_to_areaco_noclip(tf->uv[i], uval); - fcenter[0] += uval[0]; - fcenter[1] += uval[1]; - } - - fcenter[0] /= nverts; - fcenter[1] /= nverts; + else { + sync= 0; + selectmode= scene->toolsettings->uv_selectmode; + sticky= sima->sticky; - dist= abs(mval[0]- fcenter[0])+ abs(mval[1]- fcenter[1]); - if(dist < mindist) { - *nearesttf= tf; - *nearestefa= efa; - mindist= dist; - } - } + /* XXX if(sticky == SI_STICKY_VERTEX && (G.qual & LR_CTRLKEY)) + sticky= SI_STICKY_DISABLE;*/ } -} - -static int nearest_uv_between(MTFace *tf, int nverts, int id, short *mval, int *uval) -{ - float m[3], v1[3], v2[3], c1, c2; - int id1, id2; - - id1= (id+nverts-1)%nverts; - id2= (id+nverts+1)%nverts; - - m[0] = (float)(mval[0]-uval[0]); - m[1] = (float)(mval[1]-uval[1]); - Vec2Subf(v1, tf->uv[id1], tf->uv[id]); - Vec2Subf(v2, tf->uv[id2], tf->uv[id]); - - /* m and v2 on same side of v-v1? */ - c1= v1[0]*m[1] - v1[1]*m[0]; - c2= v1[0]*v2[1] - v1[1]*v2[0]; - - if(c1*c2 < 0.0f) - return 0; - - /* m and v1 on same side of v-v2? */ - c1= v2[0]*m[1] - v2[1]*m[0]; - c2= v2[0]*v1[1] - v2[1]*v1[0]; - - return (c1*c2 >= 0.0f); -} -void find_nearest_uv(Scene *scene, Image *ima, Object *obedit, MTFace **nearesttf, EditFace **nearestefa, unsigned int *nearestv, int *nearestuv) -{ - EditMesh *em= ((Mesh*)obedit->data)->edit_mesh; - EditFace *efa; - MTFace *tf; - int i, nverts, mindist, dist, uval[2]; - short mval[2]; - - mval[0]= mval[1]= 0; // XXX getmouseco_areawin(mval); - - mindist= 0x7FFFFFF; - if(nearesttf) *nearesttf= NULL; - if(nearestefa) *nearestefa= NULL; - - if(nearestv) { - EditVert *ev; - for(i=0, ev=em->verts.first; ev; ev = ev->next, i++) - ev->tmp.l = i; + /* find nearest element */ + if(loop) { + /* find edge */ + find_nearest_uv_edge(scene, ima, em, co, &hit); + if(hit.efa == NULL) + return OPERATOR_CANCELLED; } - - for(efa= em->faces.first; efa; efa= efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(uvedit_face_visible(scene, ima, efa, tf)) { - nverts= efa->v4? 4: 3; - for(i=0; i<nverts; i++) { - uval[0]= uval[1]= 0; // XXX uvco_to_areaco_noclip(tf->uv[i], uval); - dist= abs(mval[0]-uval[0]) + abs(mval[1]-uval[1]); - - if(uvedit_uv_selected(scene, efa, tf, i)) - dist += 5; + else if(selectmode == UV_SELECT_VERTEX) { + /* find vertex */ + find_nearest_uv_vert(scene, ima, em, co, penalty, &hit); + if(hit.efa == NULL) + return OPERATOR_CANCELLED; - if(dist<=mindist) { - if(dist==mindist) - if(!nearest_uv_between(tf, nverts, i, mval, uval)) - continue; + /* mark 1 vertex as being hit */ + for(i=0; i<4; i++) + hitv[i]= 0xFFFFFFFF; - mindist= dist; - *nearestuv= i; - - if(nearesttf) *nearesttf= tf; - if(nearestefa) *nearestefa= efa; - if(nearestv) { - if(i==0) *nearestv= efa->v1->tmp.l; - else if(i==1) *nearestv= efa->v2->tmp.l; - else if(i==2) *nearestv= efa->v3->tmp.l; - else *nearestv= efa->v4->tmp.l; - } - } - } - } + hitv[hit.uv]= hit.vert; + hituv[hit.uv]= hit.tf->uv[hit.uv]; } -} - -void mouse_select_sima(bContext *C, SpaceImage *sima, Scene *scene, Image *ima, Object *obedit) -{ - EditMesh *em= ((Mesh*)obedit->data)->edit_mesh; - EditFace *efa; - MTFace *tf, *nearesttf; - EditFace *nearestefa=NULL; - int a, selectsticky, edgeloop, actface, nearestuv, nearestedge, i, shift, island=0; - char sticky= 0; - int flush = 0; /* 0 == dont flush, 1 == sel, -1 == desel; only use when selection sync is enabled */ - unsigned int hitv[4], nearestv; - float *hituv[4], limit[2]; - - if(!uvedit_test(obedit)) return; + else if(selectmode == UV_SELECT_EDGE) { + /* find edge */ + find_nearest_uv_edge(scene, ima, em, co, &hit); + if(hit.efa == NULL) + return OPERATOR_CANCELLED; - uvedit_connection_limit(C, limit, 0.05); - - edgeloop= 0; // XXX G.qual & LR_ALTKEY; - shift= 0; // XXX G.qual & LR_SHIFTKEY; - - if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) { - /* copy from mesh */ - if(scene->selectmode == SCE_SELECT_FACE) { - actface= 1; - sticky= 0; - } - else { - actface= scene->selectmode & SCE_SELECT_FACE; - sticky= 2; - } - } - else { - /* normal operation */ - actface= scene->toolsettings->uv_selectmode == UV_SELECT_FACE; - island= scene->toolsettings->uv_selectmode == UV_SELECT_ISLAND; - - switch(sima->sticky) { - case SI_STICKY_LOC: - sticky=2; - break; - case SI_STICKY_DISABLE: - sticky=0; - break; - case SI_STICKY_VERTEX: - if(0) // XXX G.qual & LR_CTRLKEY) - sticky=0; - else - sticky=1; - break; - } - } + /* mark 2 edge vertices as being hit */ + for(i=0; i<4; i++) + hitv[i]= 0xFFFFFFFF; - if(edgeloop) { - find_nearest_uv_edge(scene, ima, obedit, &nearesttf, &nearestefa, &nearestedge); - if(nearesttf==NULL) - return; + nvert= (hit.efa->v4)? 4: 3; - select_edgeloop_tface_uv(C, scene, ima, obedit, nearestefa, nearestedge, shift, &flush); + hitv[hit.edge]= hit.vert; + hitv[(hit.edge+1)%nvert]= hit.vert2; + hituv[hit.edge]= hit.tf->uv[hit.edge]; + hituv[(hit.edge+1)%nvert]= hit.tf->uv[(hit.edge+1)%nvert]; } - else if(actface) { - find_nearest_tface(scene, ima, obedit, &nearesttf, &nearestefa); - if(nearesttf==NULL) - return; + else if(selectmode == UV_SELECT_FACE) { + /* find face */ + find_nearest_uv_face(scene, ima, em, co, &hit); + if(hit.efa == NULL) + return OPERATOR_CANCELLED; - EM_set_actFace(em, nearestefa); + /* make active */ + EM_set_actFace(em, hit.efa); + /* mark all face vertices as being hit */ for(i=0; i<4; i++) - hituv[i]= nearesttf->uv[i]; + hituv[i]= hit.tf->uv[i]; - hitv[0]= nearestefa->v1->tmp.l; - hitv[1]= nearestefa->v2->tmp.l; - hitv[2]= nearestefa->v3->tmp.l; + hitv[0]= hit.efa->v1->tmp.l; + hitv[1]= hit.efa->v2->tmp.l; + hitv[2]= hit.efa->v3->tmp.l; - if(nearestefa->v4) hitv[3]= nearestefa->v4->tmp.l; - else hitv[3]= 0xFFFFFFFF; + if(hit.efa->v4) hitv[3]= hit.efa->v4->tmp.l; + else hitv[3]= 0xFFFFFFFF; } - else if(island) { + else if(selectmode == UV_SELECT_ISLAND) { + find_nearest_uv_vert(scene, ima, em, co, NULL, &hit); + if(hit.efa==NULL) + return OPERATOR_CANCELLED; } - else { - find_nearest_uv(scene, ima, obedit, &nearesttf, &nearestefa, &nearestv, &nearestuv); - if(nearesttf==NULL) - return; + else + return OPERATOR_CANCELLED; - if(sticky) { - for(i=0; i<4; i++) - hitv[i]= 0xFFFFFFFF; - hitv[nearestuv]= nearestv; - hituv[nearestuv]= nearesttf->uv[nearestuv]; - } + /* do selection */ + if(loop) { + flush= select_edgeloop(scene, ima, em, &hit, limit, extend); } - - if(island) { - if(shift) select_linked_tface_uv(C, scene, ima, obedit, 1); - else select_linked_tface_uv(C, scene, ima, obedit, 0); + else if(selectmode == UV_SELECT_ISLAND) { + select_linked(scene, ima, em, limit, &hit, extend); } - else if(!edgeloop && shift) { - /* (de)select face */ - if(actface) { - if(uvedit_face_selected(scene, nearestefa, nearesttf)) { - uvedit_face_deselect(scene, nearestefa, nearesttf); - selectsticky= 0; + else if(extend) { + if(selectmode == UV_SELECT_VERTEX) { + /* (de)select uv vertex */ + if(uvedit_uv_selected(scene, hit.efa, hit.tf, hit.uv)) { + uvedit_uv_deselect(scene, hit.efa, hit.tf, hit.uv); + select= 0; } else { - uvedit_face_select(scene, nearestefa, nearesttf); - selectsticky= 1; + uvedit_uv_select(scene, hit.efa, hit.tf, hit.uv); + select= 1; } - flush = -1; + flush = 1; } - /* (de)select uv node */ - else { - if(uvedit_uv_selected(scene, nearestefa, nearesttf, nearestuv)) { - uvedit_uv_deselect(scene, nearestefa, nearesttf, nearestuv); - selectsticky= 0; + else if(selectmode == UV_SELECT_EDGE) { + /* (de)select edge */ + if(uvedit_edge_selected(scene, hit.efa, hit.tf, hit.edge)) { + uvedit_edge_deselect(scene, hit.efa, hit.tf, hit.edge); + select= 0; } else { - uvedit_uv_select(scene, nearestefa, nearesttf, nearestuv); - selectsticky= 1; + uvedit_edge_select(scene, hit.efa, hit.tf, hit.edge); + select= 1; } flush = 1; } + else if(selectmode == UV_SELECT_FACE) { + /* (de)select face */ + if(uvedit_face_selected(scene, hit.efa, hit.tf)) { + uvedit_face_deselect(scene, hit.efa, hit.tf); + select= 0; + } + else { + uvedit_face_select(scene, hit.efa, hit.tf); + select= 1; + } + flush = -1; + } /* (de)select sticky uv nodes */ - if(sticky || actface) { + if(sticky != SI_STICKY_DISABLE) { EditVert *ev; for(a=0, ev=em->verts.first; ev; ev = ev->next, a++) ev->tmp.l = a; /* deselect */ - if(selectsticky==0) { + if(select==0) { for(efa= em->faces.first; efa; efa= efa->next) { tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + if(uvedit_face_visible(scene, ima, efa, tf)) { - /*if(nearesttf && tf!=nearesttf) tf->flag &=~ TF_ACTIVE;*/ /* TODO - deal with editmesh active face */ - if(!sticky) continue; - - if(msel_hit(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky)) + if(sticky_select(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky)) uvedit_uv_deselect(scene, efa, tf, 0); - if(msel_hit(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky)) + if(sticky_select(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky)) uvedit_uv_deselect(scene, efa, tf, 1); - if(msel_hit(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky)) + if(sticky_select(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky)) uvedit_uv_deselect(scene, efa, tf, 2); if(efa->v4) - if(msel_hit(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky)) + if(sticky_select(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky)) uvedit_uv_deselect(scene, efa, tf, 3); } } @@ -1272,82 +1669,274 @@ void mouse_select_sima(bContext *C, SpaceImage *sima, Scene *scene, Image *ima, else { for(efa= em->faces.first; efa; efa= efa->next) { tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + if(uvedit_face_visible(scene, ima, efa, tf)) { - if(!sticky) continue; - if(msel_hit(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky)) + if(sticky_select(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky)) uvedit_uv_select(scene, efa, tf, 0); - if(msel_hit(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky)) + if(sticky_select(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky)) uvedit_uv_select(scene, efa, tf, 1); - if(msel_hit(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky)) + if(sticky_select(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky)) uvedit_uv_select(scene, efa, tf, 2); if(efa->v4) - if(msel_hit(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky)) + if(sticky_select(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky)) uvedit_uv_select(scene, efa, tf, 3); } } - if(actface) - EM_set_actFace(em, nearestefa); - flush = 1; } } } - else if(!edgeloop) { - /* select face and deselect other faces */ - if(actface) { - for(efa= em->faces.first; efa; efa= efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - uvedit_face_deselect(scene, efa, tf); - } - if(nearesttf) { - uvedit_face_select(scene, nearestefa, nearesttf); - EM_set_actFace(em, nearestefa); - } - - } - - /* deselect uvs, and select sticky uvs */ + else { + /* deselect all */ for(efa= em->faces.first; efa; efa= efa->next) { tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(uvedit_face_visible(scene, ima, efa, tf)) { - if(!actface) uvedit_face_deselect(scene, efa, tf); - if(!sticky) continue; - - if(msel_hit(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky)) - uvedit_uv_select(scene, efa, tf, 0); - if(msel_hit(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky)) - uvedit_uv_select(scene, efa, tf, 1); - if(msel_hit(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky)) - uvedit_uv_select(scene, efa, tf, 2); - if(efa->v4) - if(msel_hit(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky)) - uvedit_uv_select(scene, efa, tf, 3); - flush= 1; - } + uvedit_face_deselect(scene, efa, tf); } - - if(!actface) { - uvedit_uv_select(scene, nearestefa, nearesttf, nearestuv); + + if(selectmode == UV_SELECT_VERTEX) { + /* select vertex */ + uvedit_uv_select(scene, hit.efa, hit.tf, hit.uv); flush= 1; } + else if(selectmode == UV_SELECT_EDGE) { + /* select edge */ + uvedit_edge_select(scene, hit.efa, hit.tf, hit.edge); + flush= 1; + } + else if(selectmode == UV_SELECT_FACE) { + /* select face */ + uvedit_face_select(scene, hit.efa, hit.tf); + } + + /* select sticky uvs */ + if(sticky != SI_STICKY_DISABLE) { + for(efa= em->faces.first; efa; efa= efa->next) { + tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + if(uvedit_face_visible(scene, ima, efa, tf)) { + if(sticky == SI_STICKY_DISABLE) continue; + + if(sticky_select(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky)) + uvedit_uv_select(scene, efa, tf, 0); + if(sticky_select(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky)) + uvedit_uv_select(scene, efa, tf, 1); + if(sticky_select(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky)) + uvedit_uv_select(scene, efa, tf, 2); + if(efa->v4) + if(sticky_select(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky)) + uvedit_uv_select(scene, efa, tf, 3); + + flush= 1; + } + } + } } - // XXX force_draw(1); - - if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) { + if(sync) { /* flush for mesh selection */ if(scene->selectmode != SCE_SELECT_FACE) { if(flush==1) EM_select_flush(em); else if(flush==-1) EM_deselect_flush(em); } - // XXX allqueue(REDRAWVIEW3D, 0); /* mesh selection has changed */ } + // XXX force_draw(1); // XXX BIF_undo_push("Select UV"); // XXX rightmouse_transform(); + + DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); + + return OPERATOR_FINISHED; +} + +static int select_exec(bContext *C, wmOperator *op) +{ + float co[2]; + int extend, loop; + + RNA_float_get_array(op->ptr, "location", co); + extend= RNA_boolean_get(op->ptr, "extend"); + loop= 0; + + return mouse_select(C, co, extend, loop); +} + +static int select_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + ARegion *ar= CTX_wm_region(C); + float co[2]; + int x, y; + + x= event->x - ar->winrct.xmin; + y= event->y - ar->winrct.ymin; + + UI_view2d_region_to_view(&ar->v2d, x, y, &co[0], &co[1]); + RNA_float_set_array(op->ptr, "location", co); + + return select_exec(C, op); +} + +void UV_OT_select(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select"; + ot->idname= "UV_OT_select"; + ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; + + /* api callbacks */ + ot->exec= select_exec; + ot->invoke= select_invoke; + ot->poll= ED_operator_uvedit; + + /* properties */ + RNA_def_boolean(ot->srna, "extend", 0, + "Extend", "Extend selection rather than clearing the existing selection."); + RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, + "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds.", -100.0f, 100.0f); +} + +/* ******************** loop select operator **************** */ + +static int loop_select_exec(bContext *C, wmOperator *op) +{ + float co[2]; + int extend, loop; + + RNA_float_get_array(op->ptr, "location", co); + extend= RNA_boolean_get(op->ptr, "extend"); + loop= 1; + + return mouse_select(C, co, extend, loop); +} + +static int loop_select_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + ARegion *ar= CTX_wm_region(C); + float co[2]; + int x, y; + + x= event->x - ar->winrct.xmin; + y= event->y - ar->winrct.ymin; + + UI_view2d_region_to_view(&ar->v2d, x, y, &co[0], &co[1]); + RNA_float_set_array(op->ptr, "location", co); + + return loop_select_exec(C, op); +} + +void UV_OT_loop_select(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Loop Select"; + ot->idname= "UV_OT_loop_select"; + ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; + + /* api callbacks */ + ot->exec= loop_select_exec; + ot->invoke= loop_select_invoke; + ot->poll= ED_operator_uvedit; + + /* properties */ + RNA_def_boolean(ot->srna, "extend", 0, + "Extend", "Extend selection rather than clearing the existing selection."); + RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, + "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds.", -100.0f, 100.0f); +} + +/* ******************** linked select operator **************** */ + +static int select_linked_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Object *obedit= CTX_data_edit_object(C); + Image *ima= CTX_data_edit_image(C); + EditMesh *em= ((Mesh*)obedit->data)->edit_mesh; + float limit[2]; + int extend; + + if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) { + BKE_report(op->reports, RPT_ERROR, "Can't select linked when sync selection is enabled."); + return OPERATOR_CANCELLED; + } + + extend= RNA_boolean_get(op->ptr, "extend"); + uvedit_pixel_to_float(C, limit, 0.05f); + select_linked(scene, ima, em, limit, NULL, extend); + + DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); + + return OPERATOR_FINISHED; } +void UV_OT_select_linked(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select Linked"; + ot->idname= "UV_OT_select_linked"; + ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; + + /* api callbacks */ + ot->exec= select_linked_exec; + ot->poll= ED_operator_uvedit; + + /* properties */ + RNA_def_boolean(ot->srna, "extend", 0, + "Extend", "Extend selection rather than clearing the existing selection."); +} + +/* ******************** unlink selection operator **************** */ + +static int unlink_selection_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Object *obedit= CTX_data_edit_object(C); + Image *ima= CTX_data_edit_image(C); + EditMesh *em= ((Mesh*)obedit->data)->edit_mesh; + EditFace *efa; + MTFace *tf; + + if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) { + BKE_report(op->reports, RPT_ERROR, "Can't unlink selection when sync selection is enabled."); + return OPERATOR_CANCELLED; + } + + for(efa= em->faces.first; efa; efa= efa->next) { + tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + + if(uvedit_face_visible(scene, ima, efa, tf)) { + if(efa->v4) { + if(~tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) + tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); + } + else { + if(~tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) + tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3); + } + } + } + + DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); + + return OPERATOR_FINISHED; +} + +void UV_OT_unlink_selection(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Unlink Selection"; + ot->idname= "UV_OT_unlink_selection"; + ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; + + /* api callbacks */ + ot->exec= unlink_selection_exec; + ot->poll= ED_operator_uvedit; +} + +/* ******************** border select operator **************** */ + void borderselect_sima(bContext *C, SpaceImage *sima, Scene *scene, Image *ima, Object *obedit, short whichuvs) { EditMesh *em= ((Mesh*)obedit->data)->edit_mesh; @@ -1780,184 +2369,6 @@ void uvedit_selectionCB(SpaceImage *sima, Scene *scene, ARegion *ar, short selec } } -void select_linked_tface_uv(bContext *C, Scene *scene, Image *ima, Object *obedit, int mode) /* TODO */ -{ - EditMesh *em= ((Mesh*)obedit->data)->edit_mesh; - EditFace *efa, *nearestefa=NULL; - MTFace *tf, *nearesttf=NULL; - UvVertMap *vmap; - UvMapVert *vlist, *iterv, *startv; - unsigned int *stack, stacksize= 0, nearestv; - char *flag; - int a, nearestuv, i, nverts, j; - float limit[2]; - - if(!uvedit_test(obedit)) return; - - if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) { - // XXX error("Can't select linked when Sync Mesh Selection is enabled"); - return; - } - - if(mode == 2) { - nearesttf= NULL; - nearestuv= 0; - } - if(mode!=2) { - find_nearest_uv(scene, ima, obedit, &nearesttf, &nearestefa, &nearestv, &nearestuv); - if(nearesttf==NULL) - return; - } - - uvedit_connection_limit(C, limit, 0.05); - vmap= EM_make_uv_vert_map(em, 1, 1, limit); - if(vmap == NULL) - return; - - stack= MEM_mallocN(sizeof(*stack)* BLI_countlist(&em->faces), "UvLinkStack"); - flag= MEM_callocN(sizeof(*flag)*BLI_countlist(&em->faces), "UvLinkFlag"); - - if(mode == 2) { - for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(uvedit_face_visible(scene, ima, efa, tf)) { - if(tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) { - stack[stacksize]= a; - stacksize++; - flag[a]= 1; - } - } - } - } - else { - for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(tf == nearesttf) { - stack[stacksize]= a; - stacksize++; - flag[a]= 1; - break; - } - } - } - - while(stacksize > 0) { - stacksize--; - a= stack[stacksize]; - - for(j=0, efa= em->faces.first; efa; efa= efa->next, j++) { - if(j==a) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - break; - } - } - - nverts= efa->v4? 4: 3; - - for(i=0; i<nverts; i++) { - /* make_uv_vert_map_EM sets verts tmp.l to the indicies */ - vlist= EM_get_uv_map_vert(vmap, (*(&efa->v1 + i))->tmp.l); - - startv= vlist; - - for(iterv=vlist; iterv; iterv=iterv->next) { - if(iterv->separate) - startv= iterv; - if(iterv->f == a) - break; - } - - for(iterv=startv; iterv; iterv=iterv->next) { - if((startv != iterv) && (iterv->separate)) - break; - else if(!flag[iterv->f]) { - flag[iterv->f]= 1; - stack[stacksize]= iterv->f;; - stacksize++; - } - } - } - } - - if(mode==0 || mode==2) { - for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(flag[a]) - tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); - else - tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); - } - } - else if(mode==1) { - for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) { - if(flag[a]) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(efa->v4) { - if((tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4))) - break; - } - else if(tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) - break; - } - } - - if(efa) { - for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) { - if(flag[a]) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); - } - } - } - else { - for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) { - if(flag[a]) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); - } - } - } - } - - MEM_freeN(stack); - MEM_freeN(flag); - EM_free_uv_vert_map(vmap); - - // XXX BIF_undo_push("Select linked UV"); - // XXX scrarea_queue_winredraw(curarea); -} - -void unlink_selection(Scene *scene, Image *ima, Object *obedit) -{ - EditMesh *em= ((Mesh*)obedit->data)->edit_mesh; - EditFace *efa; - MTFace *tface; - - if(!uvedit_test(obedit)) return; - - if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) { - ; // XXX error("Can't select unlinked when Sync Mesh Selection is enabled"); - return; - } - - for(efa= em->faces.first; efa; efa= efa->next) { - tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(uvedit_face_visible(scene, ima, efa, tface)) { - if(efa->v4) { - if(~tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) - tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); - } - else { - if(~tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) - tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3); - } - } - } - - // XXX BIF_undo_push("Unlink UV selection"); - // XXX scrarea_queue_winredraw(curarea); -} - /* this function sets the selection on tagged faces * This is needed because setting the selection on a face is done in * a number of places but it also needs to respect the sticky modes @@ -2026,7 +2437,7 @@ void uvface_setsel__internal(bContext *C, SpaceImage *sima, Scene *scene, Object //EditVert *eve; /* removed vert counting for now */ //int a; - uvedit_connection_limit(C, limit, 0.05); + uvedit_pixel_to_float(C, limit, 0.05); EM_init_index_arrays(em, 0, 0, 1); vmap= EM_make_uv_vert_map(em, 0, 0, limit); @@ -2159,214 +2570,16 @@ void select_pinned_tface_uv(Scene *scene, Image *ima, Object *obedit) // XXX scrarea_queue_winredraw(curarea); } -/* UV edge loop select, follows same rules as editmesh */ - -static void uv_vertex_loop_flag(UvMapVert *first) -{ - UvMapVert *iterv; - int count= 0; - - for(iterv=first; iterv; iterv=iterv->next) { - if(iterv->separate && iterv!=first) - break; - - count++; - } - - if(count < 5) - first->flag= 1; -} - -static UvMapVert *uv_vertex_map_get(UvVertMap *vmap, EditFace *efa, int a) -{ - UvMapVert *iterv, *first; - - first= EM_get_uv_map_vert(vmap, (*(&efa->v1 + a))->tmp.l); - - for(iterv=first; iterv; iterv=iterv->next) { - if(iterv->separate) - first= iterv; - if(iterv->f == efa->tmp.l) - return first; - } - - return NULL; -} - -static int uv_edge_tag_faces(UvMapVert *first1, UvMapVert *first2, int *totface) -{ - UvMapVert *iterv1, *iterv2; - EditFace *efa; - int tot = 0; - - /* count number of faces this edge has */ - for(iterv1=first1; iterv1; iterv1=iterv1->next) { - if(iterv1->separate && iterv1 != first1) - break; - - for(iterv2=first2; iterv2; iterv2=iterv2->next) { - if(iterv2->separate && iterv2 != first2) - break; - - if(iterv1->f == iterv2->f) { - /* if face already tagged, don't do this edge */ - efa= EM_get_face_for_index(iterv1->f); - if(efa->f1) - return 0; - - tot++; - break; - } - } - } - - if(*totface == 0) /* start edge */ - *totface= tot; - else if(tot != *totface) /* check for same number of faces as start edge */ - return 0; - - /* tag the faces */ - for(iterv1=first1; iterv1; iterv1=iterv1->next) { - if(iterv1->separate && iterv1 != first1) - break; - - for(iterv2=first2; iterv2; iterv2=iterv2->next) { - if(iterv2->separate && iterv2 != first2) - break; - - if(iterv1->f == iterv2->f) { - efa= EM_get_face_for_index(iterv1->f); - efa->f1= 1; - break; - } - } - } - - return 1; -} - -void select_edgeloop_tface_uv(bContext *C, Scene *scene, Image *ima, Object *obedit, EditFace *startefa, int starta, int shift, int *flush) -{ - EditMesh *em= ((Mesh*)obedit->data)->edit_mesh; - EditVert *eve; - EditFace *efa; - MTFace *tface; - UvVertMap *vmap; - UvMapVert *iterv1, *iterv2; - float limit[2]; - int a, count, looking, nverts, starttotface, select; - - if(!uvedit_test(obedit)) return; - - /* setup */ - EM_init_index_arrays(em, 0, 0, 1); - - uvedit_connection_limit(C, limit, 0.05); - vmap= EM_make_uv_vert_map(em, 0, 0, limit); - - for(count=0, eve=em->verts.first; eve; count++, eve= eve->next) - eve->tmp.l = count; - - for(count=0, efa= em->faces.first; efa; count++, efa= efa->next) { - if(!shift) { - tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - uvedit_face_deselect(scene, efa, tface); - } - - efa->tmp.l= count; - efa->f1= 0; - } - - /* set flags for first face and verts */ - nverts= (startefa->v4)? 4: 3; - iterv1= uv_vertex_map_get(vmap, startefa, starta); - iterv2= uv_vertex_map_get(vmap, startefa, (starta+1)%nverts); - uv_vertex_loop_flag(iterv1); - uv_vertex_loop_flag(iterv2); - - starttotface= 0; - uv_edge_tag_faces(iterv1, iterv2, &starttotface); - - /* sorry, first edge isnt even ok */ - if(iterv1->flag==0 && iterv2->flag==0) looking= 0; - else looking= 1; - - /* iterate */ - while(looking) { - looking= 0; - - /* find correct valence edges which are not tagged yet, but connect to tagged one */ - for(efa= em->faces.first; efa; efa=efa->next) { - tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - if(!efa->f1 && uvedit_face_visible(scene, ima, efa, tface)) { - nverts= (efa->v4)? 4: 3; - for(a=0; a<nverts; a++) { - /* check face not hidden and not tagged */ - iterv1= uv_vertex_map_get(vmap, efa, a); - iterv2= uv_vertex_map_get(vmap, efa, (a+1)%nverts); - - /* check if vertex is tagged and has right valence */ - if(iterv1->flag || iterv2->flag) { - if(uv_edge_tag_faces(iterv1, iterv2, &starttotface)) { - looking= 1; - efa->f1= 1; - - uv_vertex_loop_flag(iterv1); - uv_vertex_loop_flag(iterv2); - break; - } - } - } - } - } - } - - /* do the actual select/deselect */ - nverts= (startefa->v4)? 4: 3; - iterv1= uv_vertex_map_get(vmap, startefa, starta); - iterv2= uv_vertex_map_get(vmap, startefa, (starta+1)%nverts); - iterv1->flag= 1; - iterv2->flag= 1; - - if(shift) { - tface= CustomData_em_get(&em->fdata, startefa->data, CD_MTFACE); - if(uvedit_uv_selected(scene, startefa, tface, starta) && uvedit_uv_selected(scene, startefa, tface, starta)) - select= 0; - else - select= 1; - } - else - select= 1; - - if(select) *flush= 1; - else *flush= -1; - - for(efa= em->faces.first; efa; efa=efa->next) { - tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - nverts= (efa->v4)? 4: 3; - for(a=0; a<nverts; a++) { - iterv1= uv_vertex_map_get(vmap, efa, a); - - if(iterv1->flag) { - if(select) uvedit_uv_select(scene, efa, tface, a); - else uvedit_uv_deselect(scene, efa, tface, a); - } - } - } - - /* cleanup */ - EM_free_uv_vert_map(vmap); - EM_free_index_arrays(); -} - /* ************************** registration **********************************/ void ED_operatortypes_uvedit(void) { WM_operatortype_append(UV_OT_de_select_all); WM_operatortype_append(UV_OT_select_inverse); + WM_operatortype_append(UV_OT_select); + WM_operatortype_append(UV_OT_loop_select); + WM_operatortype_append(UV_OT_select_linked); + WM_operatortype_append(UV_OT_unlink_selection); WM_operatortype_append(UV_OT_align); WM_operatortype_append(UV_OT_mirror); @@ -2378,6 +2591,14 @@ void ED_keymap_uvedit(wmWindowManager *wm) { ListBase *keymap= WM_keymap_listbase(wm, "UVEdit", 0, 0); + WM_keymap_add_item(keymap, "UV_OT_select", SELECTMOUSE, KM_PRESS, 0, 0); + RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1); + WM_keymap_add_item(keymap, "UV_OT_loop_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0); + // XXX not working? + RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_loop_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, KM_ALT)->ptr, "extend", 1); + + WM_keymap_add_item(keymap, "UV_OT_select_linked", LKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "UV_OT_unlink_selection", LKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "UV_OT_de_select_all", AKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "UV_OT_select_inverse", IKEY, KM_PRESS, KM_CTRL, 0); |