/* * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL LICENSE BLOCK ***** */ /** \file blender/editors/uvedit/uvedit_ops.c * \ingroup eduv */ #include #include #include #include #include "MEM_guardedalloc.h" #include "DNA_object_types.h" #include "DNA_meshdata_types.h" #include "DNA_image_types.h" #include "DNA_space_types.h" #include "DNA_scene_types.h" #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_editVert.h" #include "BLI_array.h" #include "BLI_utildefines.h" #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_depsgraph.h" #include "BKE_image.h" #include "BKE_library.h" #include "BKE_mesh.h" #include "BKE_report.h" #include "BKE_tessmesh.h" #include "ED_image.h" #include "ED_mesh.h" #include "ED_uvedit.h" #include "ED_object.h" #include "ED_screen.h" #include "ED_transform.h" #include "RNA_access.h" #include "RNA_define.h" #include "WM_api.h" #include "WM_types.h" #include "UI_view2d.h" #include "uvedit_intern.h" #define EFA_F1_FLAG 2 /************************* state testing ************************/ int ED_uvedit_test(Object *obedit) { BMEditMesh *em; int ret; if (!obedit) return 0; if(obedit->type != OB_MESH) return 0; em = ((Mesh*)obedit->data)->edit_btmesh; ret = EDBM_texFaceCheck(em); return ret; } /************************* assign image ************************/ void ED_uvedit_assign_image(Scene *scene, Object *obedit, Image *ima, Image *previma) { BMEditMesh *em; BMFace *efa; BMIter iter; MTexPoly *tf; int update= 0; /* skip assigning these procedural images... */ if(ima && (ima->type==IMA_TYPE_R_RESULT || ima->type==IMA_TYPE_COMPOSITE)) return; /* verify we have a mesh we can work with */ if(!obedit || (obedit->type != OB_MESH)) return; em= ((Mesh*)obedit->data)->edit_btmesh; if(!em || !em->bm->totface) { return; } /* ensure we have a uv layer */ if(!CustomData_has_layer(&em->bm->pdata, CD_MTEXPOLY)) { BM_add_data_layer(em->bm, &em->bm->pdata, CD_MTEXPOLY); BM_add_data_layer(em->bm, &em->bm->ldata, CD_MLOOPUV); update= 1; } /* now assign to all visible faces */ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); if(uvedit_face_visible(scene, previma, efa, tf)) { if(ima) { tf->tpage= ima; if(ima->id.us==0) id_us_plus(&ima->id); else id_lib_extern(&ima->id); } else { tf->tpage= NULL; } update = 1; } } /* and update depdency graph */ if(update) DAG_id_tag_update(obedit->data, 0); } /* dotile - 1, set the tile flag (from the space image) * 2, set the tile index for the faces. */ static int uvedit_set_tile(Object *obedit, Image *ima, int curtile) { BMEditMesh *em; BMFace *efa; BMIter iter; MTexPoly *tf; /* verify if we have something to do */ if(!ima || !ED_uvedit_test(obedit)) return 0; if((ima->tpageflag & IMA_TILES) == 0) return 0; /* skip assigning these procedural images... */ if(ima->type==IMA_TYPE_R_RESULT || ima->type==IMA_TYPE_COMPOSITE) return 0; em= ((Mesh*)obedit->data)->edit_btmesh; BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); if(!BM_TestHFlag(efa, BM_HIDDEN) && BM_TestHFlag(efa, BM_SELECT)) tf->tile= curtile; /* set tile index */ } DAG_id_tag_update(obedit->data, 0); return 1; } /*********************** space conversion *********************/ static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist) { int width, height; ED_space_image_size(sima, &width, &height); dist[0]= pixeldist/width; dist[1]= pixeldist/height; } /*************** visibility and selection utilities **************/ int uvedit_face_visible_nolocal(Scene *scene, BMFace *efa) { ToolSettings *ts= scene->toolsettings; if(ts->uv_flag & UV_SYNC_SELECTION) return (BM_TestHFlag(efa, BM_HIDDEN)==0); else return (BM_TestHFlag(efa, BM_HIDDEN)==0 && BM_TestHFlag(efa, BM_SELECT)); } int uvedit_face_visible(Scene *scene, Image *ima, BMFace *efa, MTexPoly *tf) { ToolSettings *ts= scene->toolsettings; if(ts->uv_flag & UV_SHOW_SAME_IMAGE) return (tf->tpage==ima)? uvedit_face_visible_nolocal(scene, efa): 0; else return uvedit_face_visible_nolocal(scene, efa); } int uvedit_face_selected(Scene *scene, BMEditMesh *em, BMFace *efa) { ToolSettings *ts= scene->toolsettings; if(ts->uv_flag & UV_SYNC_SELECTION) return (BM_TestHFlag(efa, BM_SELECT)); else { BMLoop *l; MLoopUV *luv; BMIter liter; BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); if (!(luv->flag & MLOOPUV_VERTSEL)) return 0; } return 1; } } int uvedit_face_select(Scene *scene, BMEditMesh *em, BMFace *efa) { ToolSettings *ts= scene->toolsettings; if(ts->uv_flag & UV_SYNC_SELECTION) BM_Select(em->bm, efa, 1); else { BMLoop *l; MLoopUV *luv; BMIter liter; BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); luv->flag |= MLOOPUV_VERTSEL; } return 1; } return 0; } int uvedit_face_deselect(Scene *scene, BMEditMesh *em, BMFace *efa) { ToolSettings *ts= scene->toolsettings; if(ts->uv_flag & UV_SYNC_SELECTION) BM_Select(em->bm, efa, 0); else { BMLoop *l; MLoopUV *luv; BMIter liter; BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); luv->flag &= ~MLOOPUV_VERTSEL; } return 1; } return 0; } int uvedit_edge_selected(BMEditMesh *em, Scene *scene, BMLoop *l) { ToolSettings *ts= scene->toolsettings; if(ts->uv_flag & UV_SYNC_SELECTION) { if(ts->selectmode & SCE_SELECT_FACE) return BM_TestHFlag(l->f, BM_SELECT); else if(ts->selectmode == SCE_SELECT_EDGE) { return BM_TestHFlag(l->e, BM_SELECT); } else return BM_TestHFlag(l->v, BM_SELECT) && BM_TestHFlag(l->next->v, BM_SELECT); } else { MLoopUV *luv1, *luv2; luv1 = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); luv2 = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV); return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL); } } void uvedit_edge_select(BMEditMesh *em, Scene *scene, BMLoop *l) { ToolSettings *ts= scene->toolsettings; if(ts->uv_flag & UV_SYNC_SELECTION) { if(ts->selectmode & SCE_SELECT_FACE) BM_Select(em->bm, l->f, 1); else if(ts->selectmode & SCE_SELECT_EDGE) BM_Select(em->bm, l->e, 1); else { BM_Select(em->bm, l->e->v1, 1); BM_Select(em->bm, l->e->v2, 1); } } else { MLoopUV *luv1, *luv2; luv1 = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); luv2 = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV); luv1->flag |= MLOOPUV_VERTSEL; luv2->flag |= MLOOPUV_VERTSEL; } } void uvedit_edge_deselect(BMEditMesh *em, Scene *scene, BMLoop *l) { ToolSettings *ts= scene->toolsettings; if(ts->uv_flag & UV_SYNC_SELECTION) { if(ts->selectmode & SCE_SELECT_FACE) BM_Select(em->bm, l->f, 0); else if(ts->selectmode & SCE_SELECT_EDGE) BM_Select(em->bm, l->e, 0); else { BM_Select(em->bm, l->e->v1, 0); BM_Select(em->bm, l->e->v2, 0); } } else { MLoopUV *luv1, *luv2; luv1 = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); luv2 = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV); luv1->flag &= ~MLOOPUV_VERTSEL; luv2->flag &= ~MLOOPUV_VERTSEL; } } int uvedit_uv_selected(BMEditMesh *em, Scene *scene, BMLoop *l) { ToolSettings *ts= scene->toolsettings; if(ts->uv_flag & UV_SYNC_SELECTION) { if(ts->selectmode & SCE_SELECT_FACE) return BM_TestHFlag(l->f, BM_SELECT); else return BM_TestHFlag(l->v, BM_SELECT); } else { MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); return luv->flag & MLOOPUV_VERTSEL; } } void uvedit_uv_select(BMEditMesh *em, Scene *scene, BMLoop *l) { ToolSettings *ts= scene->toolsettings; if(ts->uv_flag & UV_SYNC_SELECTION) { if(ts->selectmode & SCE_SELECT_FACE) BM_Select(em->bm, l->f, 1); else BM_Select(em->bm, l->v, 1); } else { MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); luv->flag |= MLOOPUV_VERTSEL; } } void uvedit_uv_deselect(BMEditMesh *em, Scene *scene, BMLoop *l) { ToolSettings *ts= scene->toolsettings; if(ts->uv_flag & UV_SYNC_SELECTION) { if(ts->selectmode & SCE_SELECT_FACE) BM_Select(em->bm, l->f, 0); else BM_Select(em->bm, l->v, 0); } else { MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); luv->flag &= ~MLOOPUV_VERTSEL; } } /*********************** live unwrap utilities ***********************/ static void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit) { if(sima && (sima->flag & SI_LIVE_UNWRAP)) { ED_uvedit_live_unwrap_begin(scene, obedit); ED_uvedit_live_unwrap_re_solve(); ED_uvedit_live_unwrap_end(0); } } /*********************** geometric utilities ***********************/ void poly_uv_center(BMEditMesh *em, BMFace *f, float cent[2]) { BMLoop *l; MLoopUV *luv; BMIter liter; cent[0] = cent[1] = 0.0f; BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) { luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); cent[0] += luv->uv[0]; cent[1] += luv->uv[1]; } cent[0] /= (float) f->len; cent[1] /= (float) f->len; } void uv_center(float uv[][2], float cent[2], int quad) { if(quad) { cent[0] = (uv[0][0] + uv[1][0] + uv[2][0] + uv[3][0]) / 4.0f; cent[1] = (uv[0][1] + uv[1][1] + uv[2][1] + uv[3][1]) / 4.0f; } else { cent[0] = (uv[0][0] + uv[1][0] + uv[2][0]) / 3.0f; cent[1] = (uv[0][1] + uv[1][1] + uv[2][1]) / 3.0f; } } float uv_area(float uv[][2], int quad) { if(quad) return area_tri_v2(uv[0], uv[1], uv[2]) + area_tri_v2(uv[0], uv[2], uv[3]); else return area_tri_v2(uv[0], uv[1], uv[2]); } float poly_uv_area(float uv[][2], int len) { //BMESH_TODO: make this not suck //maybe use scanfill? I dunno. if(len >= 4) return area_tri_v2(uv[0], uv[1], uv[2]) + area_tri_v2(uv[0], uv[2], uv[3]); else return area_tri_v2(uv[0], uv[1], uv[2]); return 1.0; } void poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len) { int i; for (i=0; idata)->edit_btmesh; BMFace *efa; BMLoop *l; BMIter iter, liter; MTexPoly *tf; MLoopUV *luv; int sel; INIT_MINMAX2(min, max); sel= 0; BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); if(!uvedit_face_visible(scene, ima, efa, tf)) continue; BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { if (uvedit_uv_selected(em, scene, l)) { luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); DO_MINMAX2(luv->uv, min, max); sel = 1; } } } return sel; } static int ED_uvedit_median(Scene *scene, Image *ima, Object *obedit, float co[3]) { BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; BMFace *efa; BMLoop *l; BMIter iter, liter; MTexPoly *tf; MLoopUV *luv; unsigned int sel= 0; zero_v3(co); BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); if(!uvedit_face_visible(scene, ima, efa, tf)) continue; BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); if (uvedit_uv_selected(em, scene, l)) { add_v2_v2(co, luv->uv); sel++; } } } mul_v3_fl(co, 1.0f/(float)sel); return (sel != 0); } static int uvedit_center(Scene *scene, Image *ima, Object *obedit, float *cent, char mode) { float min[2], max[2]; int change= 0; if(mode==V3D_CENTER) { /* bounding box */ if(ED_uvedit_minmax(scene, ima, obedit, min, max)) { change = 1; cent[0]= (min[0]+max[0])/2.0f; cent[1]= (min[1]+max[1])/2.0f; } } else { if(ED_uvedit_median(scene, ima, obedit, cent)) { change = 1; } } if(change) { return 1; } return 0; } /************************** find nearest ****************************/ typedef struct NearestHit { BMFace *efa; MTexPoly *tf; BMLoop *l, *nextl; MLoopUV *luv, *nextluv; int lindex; //index of loop within face int vert1, vert2; //index in mesh of edge vertices } NearestHit; static void find_nearest_uv_edge(Scene *scene, Image *ima, BMEditMesh *em, float co[2], NearestHit *hit) { MTexPoly *tf; BMFace *efa; BMLoop *l; BMVert *eve; BMIter iter, liter; MLoopUV *luv, *nextluv; float mindist, dist; int i; mindist= 1e10f; memset(hit, 0, sizeof(*hit)); eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL); for (i=0; eve; eve=BMIter_Step(&iter), i++) { BM_SetIndex(eve, i); } BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); if(!uvedit_face_visible(scene, ima, efa, tf)) continue; i = 0; BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); nextluv = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV); dist= dist_to_line_segment_v2(co, luv->uv, nextluv->uv); if(dist < mindist) { hit->tf= tf; hit->efa= efa; hit->l = l; hit->nextl = l->next; hit->luv = luv; hit->nextluv = nextluv; hit->lindex = i; hit->vert1 = BM_GetIndex(hit->l->v); hit->vert2 = BM_GetIndex(hit->l->next->v); mindist = dist; } i++; } } } static void find_nearest_uv_face(Scene *scene, Image *ima, BMEditMesh *em, float co[2], NearestHit *hit) { MTexPoly *tf; BMFace *efa; BMLoop *l; BMIter iter, liter; MLoopUV *luv; float mindist, dist, cent[2]; mindist= 1e10f; memset(hit, 0, sizeof(*hit)); /*this will fill in hit.vert1 and hit.vert2*/ find_nearest_uv_edge(scene, ima, em, co, hit); hit->l = hit->nextl = NULL; hit->luv = hit->nextluv = NULL; BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); if(!uvedit_face_visible(scene, ima, efa, tf)) continue; cent[0]= cent[1]= 0.0f; BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); cent[0] += luv->uv[0]; cent[1] += luv->uv[1]; } cent[0] /= efa->len; cent[1] /= efa->len; 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(BMEditMesh *em, BMFace *efa, int UNUSED(nverts), int id, float co[2], float uv[2]) { BMLoop *l; MLoopUV *luv; BMIter iter; float m[3], v1[3], v2[3], c1, c2, *uv1, *uv2, *uv3; int id1, id2, i; id1= (id+efa->len-1)%efa->len; id2= (id+efa->len+1)%efa->len; m[0]= co[0]-uv[0]; m[1]= co[1]-uv[1]; i = 0; BM_ITER(l, &iter, em->bm, BM_LOOPS_OF_FACE, efa) { luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); if (i == id1) uv1 = luv->uv; else if (i == id) uv2 = luv->uv; else if (i == id2) uv3 = luv->uv; i++; } sub_v3_v3v3(v1, uv1, uv); sub_v3_v3v3(v2, uv3, uv); /* 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, BMEditMesh *em, float co[2], float penalty[2], NearestHit *hit) { BMFace *efa; BMVert *eve; BMLoop *l; BMIter iter, liter; MTexPoly *tf; MLoopUV *luv; float mindist, dist; int i; /*this will fill in hit.vert1 and hit.vert2*/ find_nearest_uv_edge(scene, ima, em, co, hit); hit->l = hit->nextl = NULL; hit->luv = hit->nextluv = NULL; mindist= 1e10f; memset(hit, 0, sizeof(*hit)); eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL); for (i=0; eve; eve=BMIter_Step(&iter), i++) { BM_SetIndex(eve, i); } BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); if(!uvedit_face_visible(scene, ima, efa, tf)) continue; i = 0; BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); if(penalty && uvedit_uv_selected(em, scene, l)) dist= fabs(co[0]-luv->uv[0])+penalty[0] + fabs(co[1]-luv->uv[1])+penalty[1]; else dist= fabs(co[0]-luv->uv[0]) + fabs(co[1]-luv->uv[1]); if(dist<=mindist) { if(dist==mindist) if(!nearest_uv_between(em, efa, efa->len, i, co, luv->uv)) { i++; continue; } mindist= dist; hit->l = l; hit->nextl = l->next; hit->luv = luv; hit->nextluv = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV); hit->tf= tf; hit->efa= efa; hit->lindex = i; hit->vert1 = BM_GetIndex(hit->l->v); } i++; } } } int ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, float co[2], float uv[2]) { BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; BMFace *efa; BMLoop *l; BMIter iter, liter; MTexPoly *tf; MLoopUV *luv; float mindist, dist; int found= 0; mindist= 1e10f; uv[0]= co[0]; uv[1]= co[1]; BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); if(!uvedit_face_visible(scene, ima, efa, tf)) continue; BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); dist= fabs(co[0]-luv->uv[0]) + fabs(co[1]-luv->uv[1]); if(dist<=mindist) { mindist= dist; uv[0]= luv->uv[0]; uv[1]= luv->uv[1]; found= 1; } } } return found; } /*********************** 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, BMFace *efa, int a) { UvMapVert *iterv, *first; BMLoop *l; l = BMIter_AtIndex(NULL, BM_LOOPS_OF_FACE, efa, a); first= EDBM_get_uv_map_vert(vmap, BM_GetIndex(l->v)); for(iterv=first; iterv; iterv=iterv->next) { if(iterv->separate) first= iterv; if(iterv->f == BM_GetIndex(efa)) return first; } return NULL; } static int uv_edge_tag_faces(BMEditMesh *em, UvMapVert *first1, UvMapVert *first2, int *totface) { UvMapVert *iterv1, *iterv2; BMFace *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= EDBM_get_face_for_index(em, iterv1->f); if(BMO_TestFlag(em->bm, efa, EFA_F1_FLAG)) 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= EDBM_get_face_for_index(em, iterv1->f); BMO_SetFlag(em->bm, efa, EFA_F1_FLAG); break; } } } return 1; } static int select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestHit *hit, float limit[2], int extend) { BMVert *eve; BMFace *efa; BMIter iter, liter; BMLoop *l; MTexPoly *tf; UvVertMap *vmap; UvMapVert *iterv1, *iterv2; int a, count, looking, nverts, starttotf, select; /* setup */ EDBM_init_index_arrays(em, 0, 0, 1); vmap= EDBM_make_uv_vert_map(em, 0, 0, limit); count = 0; BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { BM_SetIndex(eve, count); count++; } count = 0; BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { if(!extend) { uvedit_face_deselect(scene, em, efa); } BMO_ClearFlag(em->bm, efa, EFA_F1_FLAG); BM_SetIndex(efa, count); count++; } /* set flags for first face and verts */ nverts= hit->efa->len; iterv1= uv_vertex_map_get(vmap, hit->efa, hit->lindex); iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->lindex+1)%nverts); uv_vertex_loop_flag(iterv1); uv_vertex_loop_flag(iterv2); starttotf= 0; uv_edge_tag_faces(em, 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 */ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); if(!BMO_TestFlag(em->bm, efa, EFA_F1_FLAG) && uvedit_face_visible(scene, ima, efa, tf)) { nverts= efa->len; for(a=0; a