4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): none yet.
27 * ***** END GPL LICENSE BLOCK *****
34 #include "MEM_guardedalloc.h"
36 #include "DNA_object_types.h"
37 #include "DNA_meshdata_types.h"
38 #include "DNA_scene_types.h"
41 #include "BLI_blenlib.h"
42 #include "BLI_editVert.h"
43 #include "BLI_utildefines.h"
45 #include "BKE_context.h"
46 #include "BKE_customdata.h"
47 #include "BKE_depsgraph.h"
48 #include "BKE_image.h"
49 #include "BKE_library.h"
51 #include "BKE_report.h"
55 #include "ED_uvedit.h"
56 #include "ED_object.h"
57 #include "ED_screen.h"
58 #include "ED_transform.h"
60 #include "RNA_access.h"
61 #include "RNA_define.h"
66 #include "UI_view2d.h"
68 #include "uvedit_intern.h"
70 /************************* state testing ************************/
72 int ED_uvedit_test(Object *obedit)
77 if(!obedit || obedit->type != OB_MESH)
80 em = BKE_mesh_get_editmesh(obedit->data);
81 ret = EM_texFaceCheck(em);
82 BKE_mesh_end_editmesh(obedit->data, em);
87 /************************* assign image ************************/
89 void ED_uvedit_assign_image(Scene *scene, Object *obedit, Image *ima, Image *previma)
96 /* skip assigning these procedural images... */
97 if(ima && (ima->type==IMA_TYPE_R_RESULT || ima->type==IMA_TYPE_COMPOSITE))
100 /* verify we have a mesh we can work with */
101 if(!obedit || (obedit->type != OB_MESH))
104 em= BKE_mesh_get_editmesh(((Mesh*)obedit->data));
105 if(!em || !em->faces.first) {
106 BKE_mesh_end_editmesh(obedit->data, em);
110 /* ensure we have a uv layer */
111 if(!CustomData_has_layer(&em->fdata, CD_MTFACE)) {
112 EM_add_data_layer(em, &em->fdata, CD_MTFACE, NULL);
116 /* now assign to all visible faces */
117 for(efa= em->faces.first; efa; efa= efa->next) {
118 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
120 if(uvedit_face_visible(scene, previma, efa, tf)) {
125 if(ima->id.us==0) id_us_plus(&ima->id);
126 else id_lib_extern(&ima->id);
137 /* and update depdency graph */
139 DAG_id_tag_update(obedit->data, 0);
141 BKE_mesh_end_editmesh(obedit->data, em);
144 /* dotile - 1, set the tile flag (from the space image)
145 * 2, set the tile index for the faces. */
146 static int uvedit_set_tile(Object *obedit, Image *ima, int curtile)
152 /* verify if we have something to do */
153 if(!ima || !ED_uvedit_test(obedit))
156 if((ima->tpageflag & IMA_TILES) == 0)
159 /* skip assigning these procedural images... */
160 if(ima->type==IMA_TYPE_R_RESULT || ima->type==IMA_TYPE_COMPOSITE)
163 em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
165 for(efa= em->faces.first; efa; efa= efa->next) {
166 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
168 if(efa->h==0 && efa->f & SELECT)
169 tf->tile= curtile; /* set tile index */
172 DAG_id_tag_update(obedit->data, 0);
173 BKE_mesh_end_editmesh(obedit->data, em);
178 /*********************** space conversion *********************/
180 static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist)
185 ED_space_image_size(sima, &width, &height);
192 dist[0]= pixeldist/width;
193 dist[1]= pixeldist/height;
196 /*************** visibility and selection utilities **************/
198 int uvedit_face_visible_nolocal(Scene *scene, EditFace *efa)
200 ToolSettings *ts= scene->toolsettings;
202 if(ts->uv_flag & UV_SYNC_SELECTION)
205 return (efa->h==0 && (efa->f & SELECT));
208 int uvedit_face_visible(Scene *scene, Image *ima, EditFace *efa, MTFace *tf)
210 ToolSettings *ts= scene->toolsettings;
212 if(ts->uv_flag & UV_SHOW_SAME_IMAGE)
213 return (tf->tpage==ima)? uvedit_face_visible_nolocal(scene, efa): 0;
215 return uvedit_face_visible_nolocal(scene, efa);
218 int uvedit_face_selected(Scene *scene, EditFace *efa, MTFace *tf)
220 ToolSettings *ts= scene->toolsettings;
222 if(ts->uv_flag & UV_SYNC_SELECTION)
223 return (efa->f & SELECT);
225 return (!(~tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) &&(!efa->v4 || tf->flag & TF_SEL4));
228 void uvedit_face_select(Scene *scene, EditFace *efa, MTFace *tf)
230 ToolSettings *ts= scene->toolsettings;
232 if(ts->uv_flag & UV_SYNC_SELECTION)
233 EM_select_face(efa, 1);
235 tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
238 void uvedit_face_deselect(Scene *scene, EditFace *efa, MTFace *tf)
240 ToolSettings *ts= scene->toolsettings;
242 if(ts->uv_flag & UV_SYNC_SELECTION)
243 EM_select_face(efa, 0);
245 tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
248 int uvedit_edge_selected(Scene *scene, EditFace *efa, MTFace *tf, int i)
250 ToolSettings *ts= scene->toolsettings;
251 int nvert= (efa->v4)? 4: 3;
253 if(ts->uv_flag & UV_SYNC_SELECTION) {
254 if(ts->selectmode & SCE_SELECT_FACE)
255 return (efa->f & SELECT);
256 else if(ts->selectmode & SCE_SELECT_EDGE)
257 return (*(&efa->e1 + i))->f & SELECT;
259 return (((efa->v1 + i)->f & SELECT) && ((efa->v1 + (i+1)%nvert)->f & SELECT));
262 return (tf->flag & TF_SEL_MASK(i)) && (tf->flag & TF_SEL_MASK((i+1)%nvert));
265 void uvedit_edge_select(Scene *scene, EditFace *efa, MTFace *tf, int i)
267 ToolSettings *ts= scene->toolsettings;
268 int nvert= (efa->v4)? 4: 3;
270 if(ts->uv_flag & UV_SYNC_SELECTION) {
271 if(ts->selectmode & SCE_SELECT_FACE)
272 EM_select_face(efa, 1);
273 else if(ts->selectmode & SCE_SELECT_EDGE)
274 EM_select_edge((*(&efa->e1 + i)), 1);
276 (efa->v1 + i)->f |= SELECT;
277 (efa->v1 + (i+1)%nvert)->f |= SELECT;
281 tf->flag |= TF_SEL_MASK(i)|TF_SEL_MASK((i+1)%nvert);
284 void uvedit_edge_deselect(Scene *scene, EditFace *efa, MTFace *tf, int i)
286 ToolSettings *ts= scene->toolsettings;
287 int nvert= (efa->v4)? 4: 3;
289 if(ts->uv_flag & UV_SYNC_SELECTION) {
290 if(ts->selectmode & SCE_SELECT_FACE)
291 EM_select_face(efa, 0);
292 else if(ts->selectmode & SCE_SELECT_EDGE)
293 EM_select_edge((*(&efa->e1 + i)), 0);
295 (efa->v1 + i)->f &= ~SELECT;
296 (efa->v1 + (i+1)%nvert)->f &= ~SELECT;
300 tf->flag &= ~(TF_SEL_MASK(i)|TF_SEL_MASK((i+1)%nvert));
303 int uvedit_uv_selected(Scene *scene, EditFace *efa, MTFace *tf, int i)
305 ToolSettings *ts= scene->toolsettings;
307 if(ts->uv_flag & UV_SYNC_SELECTION) {
308 if(ts->selectmode & SCE_SELECT_FACE)
309 return (efa->f & SELECT);
311 return (*(&efa->v1 + i))->f & SELECT;
314 return tf->flag & TF_SEL_MASK(i);
317 void uvedit_uv_select(Scene *scene, EditFace *efa, MTFace *tf, int i)
319 ToolSettings *ts= scene->toolsettings;
321 if(ts->uv_flag & UV_SYNC_SELECTION) {
322 if(ts->selectmode & SCE_SELECT_FACE)
323 EM_select_face(efa, 1);
325 (*(&efa->v1 + i))->f |= SELECT;
328 tf->flag |= TF_SEL_MASK(i);
331 void uvedit_uv_deselect(Scene *scene, EditFace *efa, MTFace *tf, int i)
333 ToolSettings *ts= scene->toolsettings;
335 if(ts->uv_flag & UV_SYNC_SELECTION) {
336 if(ts->selectmode & SCE_SELECT_FACE)
337 EM_select_face(efa, 0);
339 (*(&efa->v1 + i))->f &= ~SELECT;
342 tf->flag &= ~TF_SEL_MASK(i);
345 /*********************** geometric utilities ***********************/
347 void uv_center(float uv[][2], float cent[2], int quad)
350 cent[0] = (uv[0][0] + uv[1][0] + uv[2][0] + uv[3][0]) / 4.0;
351 cent[1] = (uv[0][1] + uv[1][1] + uv[2][1] + uv[3][1]) / 4.0;
354 cent[0] = (uv[0][0] + uv[1][0] + uv[2][0]) / 3.0;
355 cent[1] = (uv[0][1] + uv[1][1] + uv[2][1]) / 3.0;
359 float uv_area(float uv[][2], int quad)
362 return area_tri_v2(uv[0], uv[1], uv[2]) + area_tri_v2(uv[0], uv[2], uv[3]);
364 return area_tri_v2(uv[0], uv[1], uv[2]);
367 void uv_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy)
369 uv[0][0] = uv_orig[0][0]*aspx;
370 uv[0][1] = uv_orig[0][1]*aspy;
372 uv[1][0] = uv_orig[1][0]*aspx;
373 uv[1][1] = uv_orig[1][1]*aspy;
375 uv[2][0] = uv_orig[2][0]*aspx;
376 uv[2][1] = uv_orig[2][1]*aspy;
378 uv[3][0] = uv_orig[3][0]*aspx;
379 uv[3][1] = uv_orig[3][1]*aspy;
382 int ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float *min, float *max)
384 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
389 INIT_MINMAX2(min, max);
392 for(efa= em->faces.first; efa; efa= efa->next) {
393 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
394 if(uvedit_face_visible(scene, ima, efa, tf)) {
395 if(uvedit_uv_selected(scene, efa, tf, 0)) { DO_MINMAX2(tf->uv[0], min, max); sel = 1; }
396 if(uvedit_uv_selected(scene, efa, tf, 1)) { DO_MINMAX2(tf->uv[1], min, max); sel = 1; }
397 if(uvedit_uv_selected(scene, efa, tf, 2)) { DO_MINMAX2(tf->uv[2], min, max); sel = 1; }
398 if(efa->v4 && (uvedit_uv_selected(scene, efa, tf, 3))) { DO_MINMAX2(tf->uv[3], min, max); sel = 1; }
402 BKE_mesh_end_editmesh(obedit->data, em);
406 int uvedit_center(Scene *scene, Image *ima, Object *obedit, float *cent, int mode)
408 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
411 float min[2], max[2];
415 if(ED_uvedit_minmax(scene, ima, obedit, min, max))
419 INIT_MINMAX2(min, max);
421 for(efa= em->faces.first; efa; efa= efa->next) {
422 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
424 if(uvedit_face_visible(scene, ima, efa, tf)) {
425 if(uvedit_uv_selected(scene, efa, tf, 0)) { DO_MINMAX2(tf->uv[0], min, max); change= 1;}
426 if(uvedit_uv_selected(scene, efa, tf, 1)) { DO_MINMAX2(tf->uv[1], min, max); change= 1;}
427 if(uvedit_uv_selected(scene, efa, tf, 2)) { DO_MINMAX2(tf->uv[2], min, max); change= 1;}
428 if(efa->v4 && (uvedit_uv_selected(scene, efa, tf, 3))) { DO_MINMAX2(tf->uv[3], min, max); change= 1;}
434 cent[0]= (min[0]+max[0])/2.0;
435 cent[1]= (min[1]+max[1])/2.0;
437 BKE_mesh_end_editmesh(obedit->data, em);
441 BKE_mesh_end_editmesh(obedit->data, em);
445 /************************** find nearest ****************************/
447 typedef struct NearestHit {
455 static void find_nearest_uv_edge(Scene *scene, Image *ima, EditMesh *em, float co[2], NearestHit *hit)
464 memset(hit, 0, sizeof(*hit));
466 for(i=0, eve=em->verts.first; eve; eve=eve->next, i++)
469 for(efa= em->faces.first; efa; efa= efa->next) {
470 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
472 if(uvedit_face_visible(scene, ima, efa, tf)) {
473 nverts= efa->v4? 4: 3;
475 for(i=0; i<nverts; i++) {
476 dist= dist_to_line_segment_v2(co, tf->uv[i], tf->uv[(i+1)%nverts]);
484 hit->vert= (*(&efa->v1 + i))->tmp.l;
485 hit->vert2= (*(&efa->v1 + ((i+1)%nverts)))->tmp.l;
492 static void find_nearest_uv_face(Scene *scene, Image *ima, EditMesh *em, float co[2], NearestHit *hit)
496 float mindist, dist, cent[2];
500 memset(hit, 0, sizeof(*hit));
502 for(efa= em->faces.first; efa; efa= efa->next) {
503 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
505 if(uvedit_face_visible(scene, ima, efa, tf)) {
506 nverts= efa->v4? 4: 3;
507 cent[0]= cent[1]= 0.0f;
509 for(i=0; i<nverts; i++) {
510 cent[0] += tf->uv[i][0];
511 cent[1] += tf->uv[i][1];
516 dist= fabs(co[0]- cent[0]) + fabs(co[1]- cent[1]);
527 static int nearest_uv_between(MTFace *tf, int nverts, int id, float co[2], float uv[2])
529 float m[3], v1[3], v2[3], c1, c2;
532 id1= (id+nverts-1)%nverts;
533 id2= (id+nverts+1)%nverts;
537 sub_v2_v2v2(v1, tf->uv[id1], tf->uv[id]);
538 sub_v2_v2v2(v2, tf->uv[id2], tf->uv[id]);
540 /* m and v2 on same side of v-v1? */
541 c1= v1[0]*m[1] - v1[1]*m[0];
542 c2= v1[0]*v2[1] - v1[1]*v2[0];
547 /* m and v1 on same side of v-v2? */
548 c1= v2[0]*m[1] - v2[1]*m[0];
549 c2= v2[0]*v1[1] - v2[1]*v1[0];
551 return (c1*c2 >= 0.0f);
554 static void find_nearest_uv_vert(Scene *scene, Image *ima, EditMesh *em, float co[2], float penalty[2], NearestHit *hit)
563 memset(hit, 0, sizeof(*hit));
565 for(i=0, eve=em->verts.first; eve; eve=eve->next, i++)
568 for(efa= em->faces.first; efa; efa= efa->next) {
569 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
571 if(uvedit_face_visible(scene, ima, efa, tf)) {
572 nverts= efa->v4? 4: 3;
574 for(i=0; i<nverts; i++) {
575 if(penalty && uvedit_uv_selected(scene, efa, tf, i))
576 dist= fabs(co[0]-tf->uv[i][0])+penalty[0] + fabs(co[1]-tf->uv[i][1])+penalty[1];
578 dist= fabs(co[0]-tf->uv[i][0]) + fabs(co[1]-tf->uv[i][1]);
582 if(!nearest_uv_between(tf, nverts, i, co, tf->uv[i]))
591 hit->vert= (*(&efa->v1 + i))->tmp.l;
598 int ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, float co[2], float uv[2])
600 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
604 int i, nverts, found= 0;
610 for(efa= em->faces.first; efa; efa= efa->next) {
611 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
613 if(uvedit_face_visible(scene, ima, efa, tf)) {
614 nverts= efa->v4? 4: 3;
616 for(i=0; i<nverts; i++) {
617 dist= fabs(co[0]-tf->uv[i][0]) + fabs(co[1]-tf->uv[i][1]);
630 BKE_mesh_end_editmesh(obedit->data, em);
634 /*********************** loop select ***********************/
636 static void uv_vertex_loop_flag(UvMapVert *first)
641 for(iterv=first; iterv; iterv=iterv->next) {
642 if(iterv->separate && iterv!=first)
652 static UvMapVert *uv_vertex_map_get(UvVertMap *vmap, EditFace *efa, int a)
654 UvMapVert *iterv, *first;
656 first= EM_get_uv_map_vert(vmap, (*(&efa->v1 + a))->tmp.l);
658 for(iterv=first; iterv; iterv=iterv->next) {
661 if(iterv->f == efa->tmp.l)
668 static int uv_edge_tag_faces(UvMapVert *first1, UvMapVert *first2, int *totface)
670 UvMapVert *iterv1, *iterv2;
674 /* count number of faces this edge has */
675 for(iterv1=first1; iterv1; iterv1=iterv1->next) {
676 if(iterv1->separate && iterv1 != first1)
679 for(iterv2=first2; iterv2; iterv2=iterv2->next) {
680 if(iterv2->separate && iterv2 != first2)
683 if(iterv1->f == iterv2->f) {
684 /* if face already tagged, don't do this edge */
685 efa= EM_get_face_for_index(iterv1->f);
695 if(*totface == 0) /* start edge */
697 else if(tot != *totface) /* check for same number of faces as start edge */
701 for(iterv1=first1; iterv1; iterv1=iterv1->next) {
702 if(iterv1->separate && iterv1 != first1)
705 for(iterv2=first2; iterv2; iterv2=iterv2->next) {
706 if(iterv2->separate && iterv2 != first2)
709 if(iterv1->f == iterv2->f) {
710 efa= EM_get_face_for_index(iterv1->f);
720 static int select_edgeloop(Scene *scene, Image *ima, EditMesh *em, NearestHit *hit, float limit[2], int extend)
726 UvMapVert *iterv1, *iterv2;
727 int a, count, looking, nverts, starttotf, select;
730 EM_init_index_arrays(em, 0, 0, 1);
731 vmap= EM_make_uv_vert_map(em, 0, 0, limit);
733 for(count=0, eve=em->verts.first; eve; count++, eve= eve->next)
736 for(count=0, efa= em->faces.first; efa; count++, efa= efa->next) {
738 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
739 uvedit_face_deselect(scene, efa, tf);
746 /* set flags for first face and verts */
747 nverts= (hit->efa->v4)? 4: 3;
748 iterv1= uv_vertex_map_get(vmap, hit->efa, hit->edge);
749 iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->edge+1)%nverts);
750 uv_vertex_loop_flag(iterv1);
751 uv_vertex_loop_flag(iterv2);
754 uv_edge_tag_faces(iterv1, iterv2, &starttotf);
756 /* sorry, first edge isnt even ok */
757 if(iterv1->flag==0 && iterv2->flag==0) looking= 0;
764 /* find correct valence edges which are not tagged yet, but connect to tagged one */
765 for(efa= em->faces.first; efa; efa=efa->next) {
766 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
768 if(!efa->f1 && uvedit_face_visible(scene, ima, efa, tf)) {
769 nverts= (efa->v4)? 4: 3;
770 for(a=0; a<nverts; a++) {
771 /* check face not hidden and not tagged */
772 iterv1= uv_vertex_map_get(vmap, efa, a);
773 iterv2= uv_vertex_map_get(vmap, efa, (a+1)%nverts);
775 /* check if vertex is tagged and has right valence */
776 if(iterv1->flag || iterv2->flag) {
777 if(uv_edge_tag_faces(iterv1, iterv2, &starttotf)) {
781 uv_vertex_loop_flag(iterv1);
782 uv_vertex_loop_flag(iterv2);
791 /* do the actual select/deselect */
792 nverts= (hit->efa->v4)? 4: 3;
793 iterv1= uv_vertex_map_get(vmap, hit->efa, hit->edge);
794 iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->edge+1)%nverts);
799 tf= CustomData_em_get(&em->fdata, hit->efa->data, CD_MTFACE);
801 if(uvedit_uv_selected(scene, hit->efa, tf, hit->edge) && uvedit_uv_selected(scene, hit->efa, tf, hit->edge))
809 for(efa= em->faces.first; efa; efa=efa->next) {
810 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
812 nverts= (efa->v4)? 4: 3;
813 for(a=0; a<nverts; a++) {
814 iterv1= uv_vertex_map_get(vmap, efa, a);
817 if(select) uvedit_uv_select(scene, efa, tf, a);
818 else uvedit_uv_deselect(scene, efa, tf, a);
824 EM_free_uv_vert_map(vmap);
825 EM_free_index_arrays();
827 return (select)? 1: -1;
830 /*********************** linked select ***********************/
832 static void select_linked(Scene *scene, Image *ima, EditMesh *em, float limit[2], NearestHit *hit, int extend)
837 UvMapVert *vlist, *iterv, *startv;
838 int a, i, nverts, stacksize= 0, *stack;
841 EM_init_index_arrays(em, 0, 0, 1); /* we can use this too */
842 vmap= EM_make_uv_vert_map(em, 1, 0, limit);
846 stack= MEM_mallocN(sizeof(*stack) * em->totface, "UvLinkStack");
847 flag= MEM_callocN(sizeof(*flag) * em->totface, "UvLinkFlag");
850 for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
851 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
853 if(uvedit_face_visible(scene, ima, efa, tf)) {
854 const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
855 if(tf->flag & select_flag) {
864 for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
865 if(efa == hit->efa) {
874 while(stacksize > 0) {
878 efa = EM_get_face_for_index(a);
880 nverts= efa->v4? 4: 3;
882 for(i=0; i<nverts; i++) {
883 /* make_uv_vert_map_EM sets verts tmp.l to the indices */
884 vlist= EM_get_uv_map_vert(vmap, (*(&efa->v1 + i))->tmp.l);
888 for(iterv=vlist; iterv; iterv=iterv->next) {
895 for(iterv=startv; iterv; iterv=iterv->next) {
896 if((startv != iterv) && (iterv->separate))
898 else if(!flag[iterv->f]) {
900 stack[stacksize]= iterv->f;
908 for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
909 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
911 tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
913 tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
917 for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
919 const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
920 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
921 if((tf->flag & select_flag))
927 for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
929 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
930 tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
935 for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
937 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
938 tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
946 EM_free_uv_vert_map(vmap);
947 EM_free_index_arrays();
950 /* ******************** align operator **************** */
952 static void weld_align_uv(bContext *C, int tool)
960 float cent[2], min[2], max[2];
962 scene= CTX_data_scene(C);
963 obedit= CTX_data_edit_object(C);
964 em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
965 ima= CTX_data_edit_image(C);
967 INIT_MINMAX2(min, max);
970 for(efa= em->faces.first; efa; efa= efa->next) {
971 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
973 if(uvedit_face_visible(scene, ima, efa, tf)) {
974 if(uvedit_uv_selected(scene, efa, tf, 0))
975 DO_MINMAX2(tf->uv[0], min, max)
976 if(uvedit_uv_selected(scene, efa, tf, 1))
977 DO_MINMAX2(tf->uv[1], min, max)
978 if(uvedit_uv_selected(scene, efa, tf, 2))
979 DO_MINMAX2(tf->uv[2], min, max)
980 if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3))
981 DO_MINMAX2(tf->uv[3], min, max)
985 tool= (max[0]-min[0] >= max[1]-min[1])? 'y': 'x';
988 uvedit_center(scene, ima, obedit, cent, 0);
990 if(tool == 'x' || tool == 'w') {
991 for(efa= em->faces.first; efa; efa= efa->next) {
992 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
993 if(uvedit_face_visible(scene, ima, efa, tf)) {
994 if(uvedit_uv_selected(scene, efa, tf, 0))
995 tf->uv[0][0]= cent[0];
996 if(uvedit_uv_selected(scene, efa, tf, 1))
997 tf->uv[1][0]= cent[0];
998 if(uvedit_uv_selected(scene, efa, tf, 2))
999 tf->uv[2][0]= cent[0];
1000 if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3))
1001 tf->uv[3][0]= cent[0];
1006 if(tool == 'y' || tool == 'w') {
1007 for(efa= em->faces.first; efa; efa= efa->next) {
1008 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1009 if(uvedit_face_visible(scene, ima, efa, tf)) {
1010 if(uvedit_uv_selected(scene, efa, tf, 0))
1011 tf->uv[0][1]= cent[1];
1012 if(uvedit_uv_selected(scene, efa, tf, 1))
1013 tf->uv[1][1]= cent[1];
1014 if(uvedit_uv_selected(scene, efa, tf, 2))
1015 tf->uv[2][1]= cent[1];
1016 if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3))
1017 tf->uv[3][1]= cent[1];
1022 DAG_id_tag_update(obedit->data, 0);
1023 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1025 BKE_mesh_end_editmesh(obedit->data, em);
1028 static int align_exec(bContext *C, wmOperator *op)
1030 weld_align_uv(C, RNA_enum_get(op->ptr, "axis"));
1032 return OPERATOR_FINISHED;
1035 void UV_OT_align(wmOperatorType *ot)
1037 static EnumPropertyItem axis_items[] = {
1038 {'a', "ALIGN_AUTO", 0, "Align Auto", "Automatically choose the axis on which there is most alignment already"},
1039 {'x', "ALIGN_X", 0, "Align X", "Align UVs on X axis"},
1040 {'y', "ALIGN_Y", 0, "Align Y", "Align UVs on Y axis"},
1041 {0, NULL, 0, NULL, NULL}};
1045 ot->description= "Align selected UV vertices to an axis";
1046 ot->idname= "UV_OT_align";
1047 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1050 ot->exec= align_exec;
1051 ot->poll= ED_operator_uvedit;
1054 RNA_def_enum(ot->srna, "axis", axis_items, 'a', "Axis", "Axis to align UV locations on.");
1057 /* ******************** weld operator **************** */
1059 static int weld_exec(bContext *C, wmOperator *UNUSED(op))
1061 weld_align_uv(C, 'w');
1063 return OPERATOR_FINISHED;
1066 void UV_OT_weld(wmOperatorType *ot)
1070 ot->description= "Weld selected UV vertices together";
1071 ot->idname= "UV_OT_weld";
1072 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1075 ot->exec= weld_exec;
1076 ot->poll= ED_operator_uvedit;
1079 /* ******************** stitch operator **************** */
1081 /* just for averaging UVs */
1082 typedef struct UVVertAverage {
1087 static int stitch_exec(bContext *C, wmOperator *op)
1097 scene= CTX_data_scene(C);
1098 obedit= CTX_data_edit_object(C);
1099 em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
1100 ima= CTX_data_edit_image(C);
1102 if(RNA_boolean_get(op->ptr, "use_limit")) {
1104 UvMapVert *vlist, *iterv;
1105 float newuv[2], limit[2];
1108 limit[0]= RNA_float_get(op->ptr, "limit");
1111 EM_init_index_arrays(em, 0, 0, 1);
1112 vmap= EM_make_uv_vert_map(em, 1, 0, limit);
1115 BKE_mesh_end_editmesh(obedit->data, em);
1116 return OPERATOR_CANCELLED;
1119 for(a=0, eve= em->verts.first; eve; a++, eve= eve->next) {
1120 vlist= EM_get_uv_map_vert(vmap, a);
1123 newuv[0]= 0; newuv[1]= 0;
1126 for(iterv=vlist; iterv; iterv=iterv->next) {
1127 if((iterv != vlist) && iterv->separate)
1130 efa = EM_get_face_for_index(iterv->f);
1131 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1133 if(uvedit_uv_selected(scene, efa, tf, iterv->tfindex)) {
1134 newuv[0] += tf->uv[iterv->tfindex][0];
1135 newuv[1] += tf->uv[iterv->tfindex][1];
1141 newuv[0] /= vtot; newuv[1] /= vtot;
1143 for(iterv=vlist; iterv; iterv=iterv->next) {
1144 if((iterv != vlist) && iterv->separate)
1147 efa = EM_get_face_for_index(iterv->f);
1148 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1150 if(uvedit_uv_selected(scene, efa, tf, iterv->tfindex)) {
1151 tf->uv[iterv->tfindex][0]= newuv[0];
1152 tf->uv[iterv->tfindex][1]= newuv[1];
1161 EM_free_uv_vert_map(vmap);
1162 EM_free_index_arrays();
1165 UVVertAverage *uv_average, *uvav;
1168 // index and count verts
1169 for(count=0, eve=em->verts.first; eve; count++, eve= eve->next)
1172 uv_average= MEM_callocN(sizeof(UVVertAverage)*count, "Stitch");
1174 // gather uv averages per vert
1175 for(efa= em->faces.first; efa; efa= efa->next) {
1176 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1178 if(uvedit_face_visible(scene, ima, efa, tf)) {
1179 if(uvedit_uv_selected(scene, efa, tf, 0)) {
1180 uvav = uv_average + efa->v1->tmp.l;
1182 uvav->uv[0] += tf->uv[0][0];
1183 uvav->uv[1] += tf->uv[0][1];
1186 if(uvedit_uv_selected(scene, efa, tf, 1)) {
1187 uvav = uv_average + efa->v2->tmp.l;
1189 uvav->uv[0] += tf->uv[1][0];
1190 uvav->uv[1] += tf->uv[1][1];
1193 if(uvedit_uv_selected(scene, efa, tf, 2)) {
1194 uvav = uv_average + efa->v3->tmp.l;
1196 uvav->uv[0] += tf->uv[2][0];
1197 uvav->uv[1] += tf->uv[2][1];
1200 if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) {
1201 uvav = uv_average + efa->v4->tmp.l;
1203 uvav->uv[0] += tf->uv[3][0];
1204 uvav->uv[1] += tf->uv[3][1];
1210 for(efa= em->faces.first; efa; efa= efa->next) {
1211 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1213 if(uvedit_face_visible(scene, ima, efa, tf)) {
1214 if(uvedit_uv_selected(scene, efa, tf, 0)) {
1215 uvav = uv_average + efa->v1->tmp.l;
1216 tf->uv[0][0] = uvav->uv[0]/uvav->count;
1217 tf->uv[0][1] = uvav->uv[1]/uvav->count;
1220 if(uvedit_uv_selected(scene, efa, tf, 1)) {
1221 uvav = uv_average + efa->v2->tmp.l;
1222 tf->uv[1][0] = uvav->uv[0]/uvav->count;
1223 tf->uv[1][1] = uvav->uv[1]/uvav->count;
1226 if(uvedit_uv_selected(scene, efa, tf, 2)) {
1227 uvav = uv_average + efa->v3->tmp.l;
1228 tf->uv[2][0] = uvav->uv[0]/uvav->count;
1229 tf->uv[2][1] = uvav->uv[1]/uvav->count;
1232 if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) {
1233 uvav = uv_average + efa->v4->tmp.l;
1234 tf->uv[3][0] = uvav->uv[0]/uvav->count;
1235 tf->uv[3][1] = uvav->uv[1]/uvav->count;
1240 MEM_freeN(uv_average);
1243 DAG_id_tag_update(obedit->data, 0);
1244 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1246 BKE_mesh_end_editmesh(obedit->data, em);
1247 return OPERATOR_FINISHED;
1250 void UV_OT_stitch(wmOperatorType *ot)
1254 ot->description= "Stitch selected UV vertices by proximity";
1255 ot->idname= "UV_OT_stitch";
1256 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1259 ot->exec= stitch_exec;
1260 ot->poll= ED_operator_uvedit;
1263 RNA_def_boolean(ot->srna, "use_limit", 1, "Use Limit", "Stitch UVs within a specified limit distance.");
1264 RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, FLT_MAX, "Limit", "Limit distance in normalized coordinates.", -FLT_MAX, FLT_MAX);
1267 /* ******************** (de)select all operator **************** */
1269 static int select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
1279 scene= CTX_data_scene(C);
1280 ts= CTX_data_tool_settings(C);
1281 obedit= CTX_data_edit_object(C);
1282 em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
1283 ima= CTX_data_edit_image(C);
1285 if(ts->uv_flag & UV_SYNC_SELECTION) {
1289 for(efa= em->faces.first; efa; efa= efa->next) {
1290 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1292 if(uvedit_face_visible(scene, ima, efa, tf)) {
1293 tf->flag ^= TF_SEL1;
1294 tf->flag ^= TF_SEL2;
1295 tf->flag ^= TF_SEL3;
1296 if(efa->v4) tf->flag ^= TF_SEL4;
1301 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1303 BKE_mesh_end_editmesh(obedit->data, em);
1304 return OPERATOR_FINISHED;
1307 void UV_OT_select_inverse(wmOperatorType *ot)
1310 ot->name= "Select Inverse";
1311 ot->description= "Select inverse of (un)selected UV vertices";
1312 ot->idname= "UV_OT_select_inverse";
1313 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1316 ot->exec= select_inverse_exec;
1317 ot->poll= ED_operator_uvedit;
1320 /* ******************** (de)select all operator **************** */
1322 static int select_all_exec(bContext *C, wmOperator *op)
1331 int action = RNA_enum_get(op->ptr, "action");
1333 scene= CTX_data_scene(C);
1334 ts= CTX_data_tool_settings(C);
1335 obedit= CTX_data_edit_object(C);
1336 em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
1337 ima= CTX_data_edit_image(C);
1339 if(ts->uv_flag & UV_SYNC_SELECTION) {
1342 EM_toggle_select_all(em);
1348 EM_deselect_all(em);
1357 if (action == SEL_TOGGLE) {
1358 action = SEL_SELECT;
1359 for(efa= em->faces.first; efa; efa= efa->next) {
1360 const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
1361 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1363 if(uvedit_face_visible(scene, ima, efa, tf)) {
1364 if(tf->flag & select_flag) {
1365 action = SEL_DESELECT;
1372 for(efa= em->faces.first; efa; efa= efa->next) {
1373 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1375 if(uvedit_face_visible(scene, ima, efa, tf)) {
1376 const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
1380 tf->flag |= select_flag;
1383 tf->flag &= ~select_flag;
1386 if ((tf->flag & select_flag) == select_flag) {
1387 tf->flag &= ~select_flag;
1389 tf->flag &= ~select_flag;
1397 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
1399 BKE_mesh_end_editmesh(obedit->data, em);
1400 return OPERATOR_FINISHED;
1403 void UV_OT_select_all(wmOperatorType *ot)
1406 ot->name= "Select or Deselect All";
1407 ot->description= "Change selection of all UV vertices";
1408 ot->idname= "UV_OT_select_all";
1409 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1412 ot->exec= select_all_exec;
1413 ot->poll= ED_operator_uvedit;
1415 WM_operator_properties_select_all(ot);
1418 /* ******************** mouse select operator **************** */
1420 static int sticky_select(float *limit, int hitv[4], int v, float *hituv[4], float *uv, int sticky)
1424 /* this function test if some vertex needs to selected
1425 * in addition to the existing ones due to sticky select */
1426 if(sticky == SI_STICKY_DISABLE)
1429 for(i=0; i<4; i++) {
1431 if(sticky == SI_STICKY_LOC) {
1432 if(fabs(hituv[i][0]-uv[0]) < limit[0] && fabs(hituv[i][1]-uv[1]) < limit[1])
1435 else if(sticky == SI_STICKY_VERTEX)
1443 static int mouse_select(bContext *C, float co[2], int extend, int loop)
1445 SpaceImage *sima= CTX_wm_space_image(C);
1446 Scene *scene= CTX_data_scene(C);
1447 ToolSettings *ts= CTX_data_tool_settings(C);
1448 Object *obedit= CTX_data_edit_object(C);
1449 Image *ima= CTX_data_edit_image(C);
1450 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
1454 int a, i, select = 1, selectmode, sticky, sync, hitv[4], nvert;
1455 int flush = 0; /* 0 == dont flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
1456 float limit[2], *hituv[4], penalty[2];
1458 uvedit_pixel_to_float(sima, limit, 0.05f);
1459 uvedit_pixel_to_float(sima, penalty, 5.0f);
1461 /* retrieve operation mode */
1462 if(ts->uv_flag & UV_SYNC_SELECTION) {
1465 if(ts->selectmode & SCE_SELECT_FACE)
1466 selectmode= UV_SELECT_FACE;
1467 else if(ts->selectmode & SCE_SELECT_EDGE)
1468 selectmode= UV_SELECT_EDGE;
1470 selectmode= UV_SELECT_VERTEX;
1472 sticky= SI_STICKY_DISABLE;
1476 selectmode= ts->uv_selectmode;
1477 sticky= (sima)? sima->sticky: 1;
1480 /* find nearest element */
1483 find_nearest_uv_edge(scene, ima, em, co, &hit);
1484 if(hit.efa == NULL) {
1485 BKE_mesh_end_editmesh(obedit->data, em);
1486 return OPERATOR_CANCELLED;
1489 else if(selectmode == UV_SELECT_VERTEX) {
1491 find_nearest_uv_vert(scene, ima, em, co, penalty, &hit);
1492 if(hit.efa == NULL) {
1493 BKE_mesh_end_editmesh(obedit->data, em);
1494 return OPERATOR_CANCELLED;
1497 /* mark 1 vertex as being hit */
1499 hitv[i]= 0xFFFFFFFF;
1501 hitv[hit.uv]= hit.vert;
1502 hituv[hit.uv]= hit.tf->uv[hit.uv];
1504 else if(selectmode == UV_SELECT_EDGE) {
1506 find_nearest_uv_edge(scene, ima, em, co, &hit);
1507 if(hit.efa == NULL) {
1508 BKE_mesh_end_editmesh(obedit->data, em);
1509 return OPERATOR_CANCELLED;
1512 /* mark 2 edge vertices as being hit */
1514 hitv[i]= 0xFFFFFFFF;
1516 nvert= (hit.efa->v4)? 4: 3;
1518 hitv[hit.edge]= hit.vert;
1519 hitv[(hit.edge+1)%nvert]= hit.vert2;
1520 hituv[hit.edge]= hit.tf->uv[hit.edge];
1521 hituv[(hit.edge+1)%nvert]= hit.tf->uv[(hit.edge+1)%nvert];
1523 else if(selectmode == UV_SELECT_FACE) {
1525 find_nearest_uv_face(scene, ima, em, co, &hit);
1526 if(hit.efa == NULL) {
1527 BKE_mesh_end_editmesh(obedit->data, em);
1528 return OPERATOR_CANCELLED;
1532 EM_set_actFace(em, hit.efa);
1534 /* mark all face vertices as being hit */
1536 hituv[i]= hit.tf->uv[i];
1538 hitv[0]= hit.efa->v1->tmp.l;
1539 hitv[1]= hit.efa->v2->tmp.l;
1540 hitv[2]= hit.efa->v3->tmp.l;
1542 if(hit.efa->v4) hitv[3]= hit.efa->v4->tmp.l;
1543 else hitv[3]= 0xFFFFFFFF;
1545 else if(selectmode == UV_SELECT_ISLAND) {
1546 find_nearest_uv_vert(scene, ima, em, co, NULL, &hit);
1549 BKE_mesh_end_editmesh(obedit->data, em);
1550 return OPERATOR_CANCELLED;
1554 BKE_mesh_end_editmesh(obedit->data, em);
1555 return OPERATOR_CANCELLED;
1560 flush= select_edgeloop(scene, ima, em, &hit, limit, extend);
1562 else if(selectmode == UV_SELECT_ISLAND) {
1563 select_linked(scene, ima, em, limit, &hit, extend);
1566 if(selectmode == UV_SELECT_VERTEX) {
1567 /* (de)select uv vertex */
1568 if(uvedit_uv_selected(scene, hit.efa, hit.tf, hit.uv)) {
1569 uvedit_uv_deselect(scene, hit.efa, hit.tf, hit.uv);
1573 uvedit_uv_select(scene, hit.efa, hit.tf, hit.uv);
1578 else if(selectmode == UV_SELECT_EDGE) {
1579 /* (de)select edge */
1580 if(uvedit_edge_selected(scene, hit.efa, hit.tf, hit.edge)) {
1581 uvedit_edge_deselect(scene, hit.efa, hit.tf, hit.edge);
1585 uvedit_edge_select(scene, hit.efa, hit.tf, hit.edge);
1590 else if(selectmode == UV_SELECT_FACE) {
1591 /* (de)select face */
1592 if(uvedit_face_selected(scene, hit.efa, hit.tf)) {
1593 uvedit_face_deselect(scene, hit.efa, hit.tf);
1597 uvedit_face_select(scene, hit.efa, hit.tf);
1603 /* (de)select sticky uv nodes */
1604 if(sticky != SI_STICKY_DISABLE) {
1607 for(a=0, ev=em->verts.first; ev; ev = ev->next, a++)
1612 for(efa= em->faces.first; efa; efa= efa->next) {
1613 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1615 if(uvedit_face_visible(scene, ima, efa, tf)) {
1616 if(sticky_select(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
1617 uvedit_uv_deselect(scene, efa, tf, 0);
1618 if(sticky_select(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
1619 uvedit_uv_deselect(scene, efa, tf, 1);
1620 if(sticky_select(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
1621 uvedit_uv_deselect(scene, efa, tf, 2);
1623 if(sticky_select(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
1624 uvedit_uv_deselect(scene, efa, tf, 3);
1631 for(efa= em->faces.first; efa; efa= efa->next) {
1632 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1634 if(uvedit_face_visible(scene, ima, efa, tf)) {
1635 if(sticky_select(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
1636 uvedit_uv_select(scene, efa, tf, 0);
1637 if(sticky_select(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
1638 uvedit_uv_select(scene, efa, tf, 1);
1639 if(sticky_select(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
1640 uvedit_uv_select(scene, efa, tf, 2);
1642 if(sticky_select(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
1643 uvedit_uv_select(scene, efa, tf, 3);
1653 for(efa= em->faces.first; efa; efa= efa->next) {
1654 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1655 uvedit_face_deselect(scene, efa, tf);
1658 if(selectmode == UV_SELECT_VERTEX) {
1660 uvedit_uv_select(scene, hit.efa, hit.tf, hit.uv);
1663 else if(selectmode == UV_SELECT_EDGE) {
1665 uvedit_edge_select(scene, hit.efa, hit.tf, hit.edge);
1668 else if(selectmode == UV_SELECT_FACE) {
1670 uvedit_face_select(scene, hit.efa, hit.tf);
1673 /* select sticky uvs */
1674 if(sticky != SI_STICKY_DISABLE) {
1675 for(efa= em->faces.first; efa; efa= efa->next) {
1676 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1677 if(uvedit_face_visible(scene, ima, efa, tf)) {
1678 if(sticky == SI_STICKY_DISABLE) continue;
1680 if(sticky_select(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
1681 uvedit_uv_select(scene, efa, tf, 0);
1682 if(sticky_select(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
1683 uvedit_uv_select(scene, efa, tf, 1);
1684 if(sticky_select(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
1685 uvedit_uv_select(scene, efa, tf, 2);
1687 if(sticky_select(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
1688 uvedit_uv_select(scene, efa, tf, 3);
1697 /* flush for mesh selection */
1698 if(ts->selectmode != SCE_SELECT_FACE) {
1699 if(flush==1) EM_select_flush(em);
1700 else if(flush==-1) EM_deselect_flush(em);
1704 DAG_id_tag_update(obedit->data, 0);
1705 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
1707 BKE_mesh_end_editmesh(obedit->data, em);
1708 return OPERATOR_PASS_THROUGH|OPERATOR_FINISHED;
1711 static int select_exec(bContext *C, wmOperator *op)
1716 RNA_float_get_array(op->ptr, "location", co);
1717 extend= RNA_boolean_get(op->ptr, "extend");
1720 return mouse_select(C, co, extend, loop);
1723 static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1725 ARegion *ar= CTX_wm_region(C);
1729 x= event->x - ar->winrct.xmin;
1730 y= event->y - ar->winrct.ymin;
1732 UI_view2d_region_to_view(&ar->v2d, x, y, &co[0], &co[1]);
1733 RNA_float_set_array(op->ptr, "location", co);
1735 return select_exec(C, op);
1738 void UV_OT_select(wmOperatorType *ot)
1742 ot->description= "Select UV vertice";
1743 ot->idname= "UV_OT_select";
1744 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1747 ot->exec= select_exec;
1748 ot->invoke= select_invoke;
1749 ot->poll= ED_operator_uvedit;
1752 RNA_def_boolean(ot->srna, "extend", 0,
1753 "Extend", "Extend selection rather than clearing the existing selection.");
1754 RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
1755 "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds.", -100.0f, 100.0f);
1758 /* ******************** loop select operator **************** */
1760 static int select_loop_exec(bContext *C, wmOperator *op)
1765 RNA_float_get_array(op->ptr, "location", co);
1766 extend= RNA_boolean_get(op->ptr, "extend");
1769 return mouse_select(C, co, extend, loop);
1772 static int select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
1774 ARegion *ar= CTX_wm_region(C);
1778 x= event->x - ar->winrct.xmin;
1779 y= event->y - ar->winrct.ymin;
1781 UI_view2d_region_to_view(&ar->v2d, x, y, &co[0], &co[1]);
1782 RNA_float_set_array(op->ptr, "location", co);
1784 return select_loop_exec(C, op);
1787 void UV_OT_select_loop(wmOperatorType *ot)
1790 ot->name= "Loop Select";
1791 ot->description= "Select a loop of connected UV vertices";
1792 ot->idname= "UV_OT_select_loop";
1793 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1796 ot->exec= select_loop_exec;
1797 ot->invoke= select_loop_invoke;
1798 ot->poll= ED_operator_uvedit;
1801 RNA_def_boolean(ot->srna, "extend", 0,
1802 "Extend", "Extend selection rather than clearing the existing selection.");
1803 RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
1804 "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds.", -100.0f, 100.0f);
1807 /* ******************** linked select operator **************** */
1809 static int select_linked_internal(bContext *C, wmOperator *op, wmEvent *event, int pick)
1811 SpaceImage *sima= CTX_wm_space_image(C);
1812 Scene *scene= CTX_data_scene(C);
1813 ToolSettings *ts= CTX_data_tool_settings(C);
1814 Object *obedit= CTX_data_edit_object(C);
1815 Image *ima= CTX_data_edit_image(C);
1816 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
1820 NearestHit hit, *hit_p= NULL;
1822 if(ts->uv_flag & UV_SYNC_SELECTION) {
1823 BKE_report(op->reports, RPT_ERROR, "Can't select linked when sync selection is enabled.");
1824 BKE_mesh_end_editmesh(obedit->data, em);
1825 return OPERATOR_CANCELLED;
1828 extend= RNA_boolean_get(op->ptr, "extend");
1829 uvedit_pixel_to_float(sima, limit, 0.05f);
1836 ARegion *ar= CTX_wm_region(C);
1839 x= event->x - ar->winrct.xmin;
1840 y= event->y - ar->winrct.ymin;
1842 UI_view2d_region_to_view(&ar->v2d, x, y, &co[0], &co[1]);
1843 RNA_float_set_array(op->ptr, "location", co);
1847 RNA_float_get_array(op->ptr, "location", co);
1850 find_nearest_uv_vert(scene, ima, em, co, NULL, &hit);
1854 select_linked(scene, ima, em, limit, hit_p, extend);
1856 DAG_id_tag_update(obedit->data, 0);
1857 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
1859 BKE_mesh_end_editmesh(obedit->data, em);
1860 return OPERATOR_FINISHED;
1863 static int select_linked_exec(bContext *C, wmOperator *op)
1865 return select_linked_internal(C, op, NULL, 0);
1868 void UV_OT_select_linked(wmOperatorType *ot)
1871 ot->name= "Select Linked";
1872 ot->description= "Select all UV vertices linked to the active UV map";
1873 ot->idname= "UV_OT_select_linked";
1874 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1877 ot->exec= select_linked_exec;
1878 ot->poll= ED_operator_uvedit;
1881 RNA_def_boolean(ot->srna, "extend", 0,
1882 "Extend", "Extend selection rather than clearing the existing selection.");
1885 static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
1887 return select_linked_internal(C, op, event, 1);
1890 static int select_linked_pick_exec(bContext *C, wmOperator *op)
1892 return select_linked_internal(C, op, NULL, 1);
1895 void UV_OT_select_linked_pick(wmOperatorType *ot)
1898 ot->name= "Select Linked Pick";
1899 ot->description= "Select all UV vertices linked under the mouse";
1900 ot->idname= "UV_OT_select_linked_pick";
1901 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1904 ot->invoke= select_linked_pick_invoke;
1905 ot->exec= select_linked_pick_exec;
1906 ot->poll= ED_operator_uvedit;
1909 RNA_def_boolean(ot->srna, "extend", 0,
1910 "Extend", "Extend selection rather than clearing the existing selection.");
1912 RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
1913 "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds.", -100.0f, 100.0f);
1916 /* ******************** unlink selection operator **************** */
1918 static int unlink_selection_exec(bContext *C, wmOperator *op)
1920 Scene *scene= CTX_data_scene(C);
1921 ToolSettings *ts= CTX_data_tool_settings(C);
1922 Object *obedit= CTX_data_edit_object(C);
1923 Image *ima= CTX_data_edit_image(C);
1924 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
1928 if(ts->uv_flag & UV_SYNC_SELECTION) {
1929 BKE_report(op->reports, RPT_ERROR, "Can't unlink selection when sync selection is enabled.");
1930 BKE_mesh_end_editmesh(obedit->data, em);
1931 return OPERATOR_CANCELLED;
1934 for(efa= em->faces.first; efa; efa= efa->next) {
1935 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1937 if(uvedit_face_visible(scene, ima, efa, tf)) {
1938 const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
1939 if(~tf->flag & select_flag)
1940 tf->flag &= ~select_flag;
1945 DAG_id_tag_update(obedit->data, 0);
1946 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
1948 BKE_mesh_end_editmesh(obedit->data, em);
1949 return OPERATOR_FINISHED;
1952 void UV_OT_unlink_selection(wmOperatorType *ot)
1955 ot->name= "Unlink Selection";
1956 ot->description= "Unlink selected UV vertices from active UV map";
1957 ot->idname= "UV_OT_unlink_selection";
1958 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1961 ot->exec= unlink_selection_exec;
1962 ot->poll= ED_operator_uvedit;
1965 /* ******************** border select operator **************** */
1967 /* This function sets the selection on tagged faces, need because settings the
1968 * selection a face is done in a number of places but it also needs to respect
1969 * the sticky modes for the UV verts, so dealing with the sticky modes is best
1970 * done in a separate function.
1972 * De-selects faces that have been tagged on efa->tmp.l. */
1974 static void uv_faces_do_sticky(bContext *C, SpaceImage *sima, Scene *scene, Object *obedit, short select)
1976 /* Selecting UV Faces with some modes requires us to change
1977 * the selection in other faces (depending on the sticky mode).
1979 * This only needs to be done when the Mesh is not used for
1980 * selection (so for sticky modes, vertex or location based). */
1982 ToolSettings *ts= CTX_data_tool_settings(C);
1983 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
1988 if((ts->uv_flag & UV_SYNC_SELECTION)==0 && sima->sticky == SI_STICKY_VERTEX) {
1989 /* Tag all verts as untouched, then touch the ones that have a face center
1990 * in the loop and select all MTFace UV's that use a touched vert. */
1993 for(eve= em->verts.first; eve; eve= eve->next)
1996 for(efa= em->faces.first; efa; efa= efa->next) {
1999 efa->v1->tmp.l= efa->v2->tmp.l= efa->v3->tmp.l= efa->v4->tmp.l=1;
2001 efa->v1->tmp.l= efa->v2->tmp.l= efa->v3->tmp.l= 1;
2005 /* now select tagged verts */
2006 for(efa= em->faces.first; efa; efa= efa->next) {
2007 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2008 nverts= efa->v4? 4: 3;
2009 for(i=0; i<nverts; i++) {
2010 if((*(&efa->v1 + i))->tmp.l) {
2012 uvedit_uv_select(scene, efa, tf, i);
2014 uvedit_uv_deselect(scene, efa, tf, i);
2019 else if((ts->uv_flag & UV_SYNC_SELECTION)==0 && sima->sticky == SI_STICKY_LOC) {
2020 EditFace *efa_vlist;
2022 UvMapVert *start_vlist=NULL, *vlist_iter;
2023 struct UvVertMap *vmap;
2026 //EditVert *eve; /* removed vert counting for now */
2029 uvedit_pixel_to_float(sima, limit, 0.05);
2031 EM_init_index_arrays(em, 0, 0, 1);
2032 vmap= EM_make_uv_vert_map(em, 0, 0, limit);
2034 /* verts are numbered above in make_uv_vert_map_EM, make sure this stays true! */
2035 /*for(a=0, eve= em->verts.first; eve; a++, eve= eve->next)
2039 BKE_mesh_end_editmesh(obedit->data, em);
2043 for(efa_index=0, efa= em->faces.first; efa; efa_index++, efa= efa->next) {
2045 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2046 nverts= efa->v4? 4: 3;
2048 for(i=0; i<nverts; i++) {
2050 uvedit_uv_select(scene, efa, tf, i);
2052 uvedit_uv_deselect(scene, efa, tf, i);
2054 vlist_iter= EM_get_uv_map_vert(vmap, (*(&efa->v1 + i))->tmp.l);
2056 while (vlist_iter) {
2057 if(vlist_iter->separate)
2058 start_vlist = vlist_iter;
2060 if(efa_index == vlist_iter->f)
2063 vlist_iter = vlist_iter->next;
2066 vlist_iter = start_vlist;
2067 while (vlist_iter) {
2069 if(vlist_iter != start_vlist && vlist_iter->separate)
2072 if(efa_index != vlist_iter->f) {
2073 efa_vlist = EM_get_face_for_index(vlist_iter->f);
2074 tf_vlist = CustomData_em_get(&em->fdata, efa_vlist->data, CD_MTFACE);
2077 uvedit_uv_select(scene, efa_vlist, tf_vlist, vlist_iter->tfindex);
2079 uvedit_uv_deselect(scene, efa_vlist, tf_vlist, vlist_iter->tfindex);
2081 vlist_iter = vlist_iter->next;
2086 EM_free_index_arrays();
2087 EM_free_uv_vert_map(vmap);
2090 else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
2091 for(efa= em->faces.first; efa; efa= efa->next) {
2093 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2095 uvedit_face_select(scene, efa, tf);
2097 uvedit_face_deselect(scene, efa, tf);
2101 BKE_mesh_end_editmesh(obedit->data, em);
2104 static int border_select_exec(bContext *C, wmOperator *op)
2106 SpaceImage *sima= CTX_wm_space_image(C);
2107 Scene *scene= CTX_data_scene(C);
2108 ToolSettings *ts= CTX_data_tool_settings(C);
2109 Object *obedit= CTX_data_edit_object(C);
2110 Image *ima= CTX_data_edit_image(C);
2111 ARegion *ar= CTX_wm_region(C);
2112 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
2117 int change, pinned, select, faces;
2119 /* get rectangle from operator */
2120 rect.xmin= RNA_int_get(op->ptr, "xmin");
2121 rect.ymin= RNA_int_get(op->ptr, "ymin");
2122 rect.xmax= RNA_int_get(op->ptr, "xmax");
2123 rect.ymax= RNA_int_get(op->ptr, "ymax");
2125 UI_view2d_region_to_view(&ar->v2d, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
2126 UI_view2d_region_to_view(&ar->v2d, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
2128 /* figure out what to select/deselect */
2129 select= (RNA_int_get(op->ptr, "gesture_mode") == GESTURE_MODAL_SELECT);
2130 pinned= RNA_boolean_get(op->ptr, "pinned");
2132 if(ts->uv_flag & UV_SYNC_SELECTION)
2133 faces= (ts->selectmode == SCE_SELECT_FACE);
2135 faces= (ts->uv_selectmode == UV_SELECT_FACE);
2137 /* do actual selection */
2138 if(faces && !pinned) {
2139 /* handle face selection mode */
2144 for(efa= em->faces.first; efa; efa= efa->next) {
2145 /* assume not touched */
2147 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2148 if(uvedit_face_visible(scene, ima, efa, tface)) {
2149 uv_center(tface->uv, cent, efa->v4 != NULL);
2150 if(BLI_in_rctf(&rectf, cent[0], cent[1])) {
2151 efa->tmp.l = change = 1;
2156 /* (de)selects all tagged faces and deals with sticky modes */
2158 uv_faces_do_sticky(C, sima, scene, obedit, select);
2161 /* other selection modes */
2164 for(efa= em->faces.first; efa; efa= efa->next) {
2165 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2166 if(uvedit_face_visible(scene, ima, efa, tface)) {
2167 if(!pinned || (ts->uv_flag & UV_SYNC_SELECTION) ) {
2168 /* UV_SYNC_SELECTION - can't do pinned selection */
2169 if(BLI_in_rctf(&rectf, tface->uv[0][0], tface->uv[0][1])) {
2170 if(select) uvedit_uv_select(scene, efa, tface, 0);
2171 else uvedit_uv_deselect(scene, efa, tface, 0);
2173 if(BLI_in_rctf(&rectf, tface->uv[1][0], tface->uv[1][1])) {
2174 if(select) uvedit_uv_select(scene, efa, tface, 1);
2175 else uvedit_uv_deselect(scene, efa, tface, 1);
2177 if(BLI_in_rctf(&rectf, tface->uv[2][0], tface->uv[2][1])) {
2178 if(select) uvedit_uv_select(scene, efa, tface, 2);
2179 else uvedit_uv_deselect(scene, efa, tface, 2);
2181 if(efa->v4 && BLI_in_rctf(&rectf, tface->uv[3][0], tface->uv[3][1])) {
2182 if(select) uvedit_uv_select(scene, efa, tface, 3);
2183 else uvedit_uv_deselect(scene, efa, tface, 3);
2187 if((tface->unwrap & TF_PIN1) &&
2188 BLI_in_rctf(&rectf, tface->uv[0][0], tface->uv[0][1])) {
2190 if(select) uvedit_uv_select(scene, efa, tface, 0);
2191 else uvedit_uv_deselect(scene, efa, tface, 0);
2193 if((tface->unwrap & TF_PIN2) &&
2194 BLI_in_rctf(&rectf, tface->uv[1][0], tface->uv[1][1])) {
2196 if(select) uvedit_uv_select(scene, efa, tface, 1);
2197 else uvedit_uv_deselect(scene, efa, tface, 1);
2199 if((tface->unwrap & TF_PIN3) &&
2200 BLI_in_rctf(&rectf, tface->uv[2][0], tface->uv[2][1])) {
2202 if(select) uvedit_uv_select(scene, efa, tface, 2);
2203 else uvedit_uv_deselect(scene, efa, tface, 2);
2205 if((efa->v4) && (tface->unwrap & TF_PIN4) && BLI_in_rctf(&rectf, tface->uv[3][0], tface->uv[3][1])) {
2206 if(select) uvedit_uv_select(scene, efa, tface, 3);
2207 else uvedit_uv_deselect(scene, efa, tface, 3);
2215 /* make sure newly selected vert selection is updated*/
2216 if(ts->uv_flag & UV_SYNC_SELECTION) {
2217 if(ts->selectmode != SCE_SELECT_FACE) {
2218 if(select) EM_select_flush(em);
2219 else EM_deselect_flush(em);
2223 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2225 BKE_mesh_end_editmesh(obedit->data, em);
2226 return OPERATOR_FINISHED;
2229 BKE_mesh_end_editmesh(obedit->data, em);
2230 return OPERATOR_CANCELLED;
2233 void UV_OT_select_border(wmOperatorType *ot)
2236 ot->name= "Border Select";
2237 ot->description= "Select UV vertices using border selection";
2238 ot->idname= "UV_OT_select_border";
2241 ot->invoke= WM_border_select_invoke;
2242 ot->exec= border_select_exec;
2243 ot->modal= WM_border_select_modal;
2244 ot->poll= ED_operator_uvedit;
2247 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2250 RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only.");
2252 WM_operator_properties_gesture_border(ot, FALSE);
2255 /* ******************** circle select operator **************** */
2257 static void select_uv_inside_ellipse(Scene *scene, int select, EditFace *efa, MTFace *tface, int index, float *offset, float *ell, int select_index)
2259 /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
2260 float x, y, r2, *uv;
2262 uv= tface->uv[index];
2264 x= (uv[0] - offset[0])*ell[0];
2265 y= (uv[1] - offset[1])*ell[1];
2269 if(select) uvedit_uv_select(scene, efa, tface, select_index);
2270 else uvedit_uv_deselect(scene, efa, tface, select_index);
2274 int circle_select_exec(bContext *C, wmOperator *op)
2276 SpaceImage *sima= CTX_wm_space_image(C);
2277 Scene *scene= CTX_data_scene(C);
2278 Object *obedit= CTX_data_edit_object(C);
2279 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
2280 ARegion *ar= CTX_wm_region(C);
2283 int x, y, radius, width, height, select;
2284 float zoomx, zoomy, offset[2], ellipse[2];
2285 int gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
2287 /* get operator properties */
2288 select= (gesture_mode == GESTURE_MODAL_SELECT);
2289 x= RNA_int_get(op->ptr, "x");
2290 y= RNA_int_get(op->ptr, "y");
2291 radius= RNA_int_get(op->ptr, "radius");
2293 /* compute ellipse size and location, not a circle since we deal
2294 * with non square image. ellipse is normalized, r = 1.0. */
2295 ED_space_image_size(sima, &width, &height);
2296 ED_space_image_zoom(sima, ar, &zoomx, &zoomy);
2298 ellipse[0]= width*zoomx/radius;
2299 ellipse[1]= height*zoomy/radius;
2301 UI_view2d_region_to_view(&ar->v2d, x, y, &offset[0], &offset[1]);
2304 for(efa= em->faces.first; efa; efa= efa->next) {
2305 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2306 select_uv_inside_ellipse(scene, select, efa, tface, 0, offset, ellipse, 0);
2307 select_uv_inside_ellipse(scene, select, efa, tface, 1, offset, ellipse, 1);
2308 select_uv_inside_ellipse(scene, select, efa, tface, 2, offset, ellipse, 2);
2310 select_uv_inside_ellipse(scene, select, efa, tface, 3, offset, ellipse, 3);
2313 if(select) EM_select_flush(em);
2314 else EM_deselect_flush(em);
2316 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2318 BKE_mesh_end_editmesh(obedit->data, em);
2319 return OPERATOR_FINISHED;
2322 void UV_OT_circle_select(wmOperatorType *ot)
2325 ot->name= "Circle Select";
2326 ot->description= "Select UV vertices using circle selection";
2327 ot->idname= "UV_OT_circle_select";
2330 ot->invoke= WM_gesture_circle_invoke;
2331 ot->modal= WM_gesture_circle_modal;
2332 ot->exec= circle_select_exec;
2333 ot->poll= ED_operator_uvedit;
2336 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2339 RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
2340 RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
2341 RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
2342 RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
2345 /* ******************** snap cursor operator **************** */
2347 static void snap_uv_to_pixel(float *uvco, float w, float h)
2349 uvco[0] = ((float)((int)((uvco[0]*w) + 0.5f)))/w;
2350 uvco[1] = ((float)((int)((uvco[1]*h) + 0.5f)))/h;
2353 static void snap_cursor_to_pixels(SpaceImage *sima)
2355 int width= 0, height= 0;
2357 ED_space_image_size(sima, &width, &height);
2358 snap_uv_to_pixel(sima->cursor, width, height);
2361 static int snap_cursor_to_selection(Scene *scene, Image *ima, Object *obedit, SpaceImage *sima)
2363 return uvedit_center(scene, ima, obedit, sima->cursor, 0);
2366 static int snap_cursor_exec(bContext *C, wmOperator *op)
2368 SpaceImage *sima= CTX_wm_space_image(C);
2369 Scene *scene= CTX_data_scene(C);
2370 Object *obedit= CTX_data_edit_object(C);
2371 Image *ima= CTX_data_edit_image(C);
2374 switch(RNA_boolean_get(op->ptr, "target")) {
2376 snap_cursor_to_pixels(sima);
2380 change= snap_cursor_to_selection(scene, ima, obedit, sima);
2385 return OPERATOR_CANCELLED;
2387 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_IMAGE, sima);
2389 return OPERATOR_FINISHED;
2392 void UV_OT_snap_cursor(wmOperatorType *ot)
2394 static EnumPropertyItem target_items[] = {
2395 {0, "PIXELS", 0, "Pixels", ""},
2396 {1, "SELECTION", 0, "Selection", ""},
2397 {0, NULL, 0, NULL, NULL}};
2400 ot->name= "Snap Cursor";
2401 ot->description= "Snap cursor to target type";
2402 ot->idname= "UV_OT_snap_cursor";
2403 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2406 ot->exec= snap_cursor_exec;
2407 ot->poll= ED_operator_uvedit;
2410 RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UV's to.");
2413 /* ******************** snap selection operator **************** */
2415 static int snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, SpaceImage *sima)
2417 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
2422 for(efa= em->faces.first; efa; efa= efa->next) {
2423 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2424 if(uvedit_face_visible(scene, ima, efa, tface)) {
2425 if(uvedit_uv_selected(scene, efa, tface, 0)) VECCOPY2D(tface->uv[0], sima->cursor);
2426 if(uvedit_uv_selected(scene, efa, tface, 1)) VECCOPY2D(tface->uv[1], sima->cursor);
2427 if(uvedit_uv_selected(scene, efa, tface, 2)) VECCOPY2D(tface->uv[2], sima->cursor);
2429 if(uvedit_uv_selected(scene, efa, tface, 3)) VECCOPY2D(tface->uv[3], sima->cursor);
2435 BKE_mesh_end_editmesh(obedit->data, em);
2439 static int snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obedit)
2441 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
2448 short *usercount, users;
2450 /* set all verts to -1 : an unused index*/
2451 for(eve= em->verts.first; eve; eve= eve->next)
2454 /* index every vert that has a selected UV using it, but only once so as to
2455 * get unique indices and to count how much to malloc */
2456 for(efa= em->faces.first; efa; efa= efa->next) {
2457 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2459 if(uvedit_face_visible(scene, ima, efa, tface)) {
2460 if(uvedit_uv_selected(scene, efa, tface, 0) && efa->v1->tmp.l==-1) efa->v1->tmp.l= count++;
2461 if(uvedit_uv_selected(scene, efa, tface, 1) && efa->v2->tmp.l==-1) efa->v2->tmp.l= count++;
2462 if(uvedit_uv_selected(scene, efa, tface, 2) && efa->v3->tmp.l==-1) efa->v3->tmp.l= count++;
2464 if(uvedit_uv_selected(scene, efa, tface, 3) && efa->v4->tmp.l==-1) efa->v4->tmp.l= count++;
2468 /* optional speedup */
2475 coords = MEM_callocN(sizeof(float)*count*2, "snap to adjacent coords");
2476 usercount = MEM_callocN(sizeof(short)*count, "snap to adjacent counts");
2478 /* add all UV coords from visible, unselected UV coords as well as counting them to average later */
2479 for(efa= em->faces.first; efa; efa= efa->next) {
2480 if((tface=(MTFace *)efa->tmp.p)) {
2481 /* is this an unselected UV we can snap to? */
2482 if(efa->v1->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 0))) {
2483 coords[efa->v1->tmp.l*2] += tface->uv[0][0];
2484 coords[(efa->v1->tmp.l*2)+1] += tface->uv[0][1];
2485 usercount[efa->v1->tmp.l]++;
2488 if(efa->v2->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 1))) {
2489 coords[efa->v2->tmp.l*2] += tface->uv[1][0];
2490 coords[(efa->v2->tmp.l*2)+1] += tface->uv[1][1];
2491 usercount[efa->v2->tmp.l]++;
2494 if(efa->v3->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 2))) {
2495 coords[efa->v3->tmp.l*2] += tface->uv[2][0];
2496 coords[(efa->v3->tmp.l*2)+1] += tface->uv[2][1];
2497 usercount[efa->v3->tmp.l]++;
2502 if(efa->v4->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 3))) {
2503 coords[efa->v4->tmp.l*2] += tface->uv[3][0];
2504 coords[(efa->v4->tmp.l*2)+1] += tface->uv[3][1];
2505 usercount[efa->v4->tmp.l]++;
2512 /* no other verts selected, bail out */
2515 MEM_freeN(usercount);
2516 BKE_mesh_end_editmesh(obedit->data, em);
2520 /* copy the averaged unselected UVs back to the selected UVs */
2521 for(efa= em->faces.first; efa; efa= efa->next) {
2522 if((tface=(MTFace *)efa->tmp.p)) {
2524 if( uvedit_uv_selected(scene, efa, tface, 0) &&
2525 efa->v1->tmp.l >= 0 &&
2526 (users = usercount[efa->v1->tmp.l])
2528 tface->uv[0][0] = coords[efa->v1->tmp.l*2] / users;
2529 tface->uv[0][1] = coords[(efa->v1->tmp.l*2)+1] / users;
2532 if( uvedit_uv_selected(scene, efa, tface, 1) &&
2533 efa->v2->tmp.l >= 0 &&
2534 (users = usercount[efa->v2->tmp.l])
2536 tface->uv[1][0] = coords[efa->v2->tmp.l*2] / users;
2537 tface->uv[1][1] = coords[(efa->v2->tmp.l*2)+1] / users;
2540 if( uvedit_uv_selected(scene, efa, tface, 2) &&
2541 efa->v3->tmp.l >= 0 &&
2542 (users = usercount[efa->v3->tmp.l])
2544 tface->uv[2][0] = coords[efa->v3->tmp.l*2] / users;
2545 tface->uv[2][1] = coords[(efa->v3->tmp.l*2)+1] / users;
2549 if( uvedit_uv_selected(scene, efa, tface, 3) &&
2550 efa->v4->tmp.l >= 0 &&
2551 (users = usercount[efa->v4->tmp.l])
2553 tface->uv[3][0] = coords[efa->v4->tmp.l*2] / users;
2554 tface->uv[3][1] = coords[(efa->v4->tmp.l*2)+1] / users;
2561 MEM_freeN(usercount);
2563 BKE_mesh_end_editmesh(obedit->data, em);
2567 static int snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit)
2569 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
2573 int width= 0, height= 0;
2582 ED_space_image_size(sima, &width, &height);
2586 for(efa= em->faces.first; efa; efa= efa->next) {
2587 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2588 if(uvedit_face_visible(scene, ima, efa, tface)) {
2589 if(uvedit_uv_selected(scene, efa, tface, 0)) snap_uv_to_pixel(tface->uv[0], w, h);
2590 if(uvedit_uv_selected(scene, efa, tface, 1)) snap_uv_to_pixel(tface->uv[1], w, h);
2591 if(uvedit_uv_selected(scene, efa, tface, 2)) snap_uv_to_pixel(tface->uv[2], w, h);
2593 if(uvedit_uv_selected(scene, efa, tface, 3)) snap_uv_to_pixel(tface->uv[3], w, h);
2599 BKE_mesh_end_editmesh(obedit->data, em);
2603 static int snap_selection_exec(bContext *C, wmOperator *op)
2605 SpaceImage *sima= CTX_wm_space_image(C);
2606 Scene *scene= CTX_data_scene(C);
2607 Object *obedit= CTX_data_edit_object(C);
2608 Image *ima= CTX_data_edit_image(C);
2611 switch(RNA_boolean_get(op->ptr, "target")) {
2613 change= snap_uvs_to_pixels(sima, scene, obedit);
2616 change= snap_uvs_to_cursor(scene, ima, obedit, sima);
2619 change= snap_uvs_to_adjacent_unselected(scene, ima, obedit);
2624 return OPERATOR_CANCELLED;
2626 DAG_id_tag_update(obedit->data, 0);
2627 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2629 return OPERATOR_FINISHED;
2632 void UV_OT_snap_selection(wmOperatorType *ot)
2634 static EnumPropertyItem target_items[] = {
2635 {0, "PIXELS", 0, "Pixels", ""},
2636 {1, "CURSOR", 0, "Cursor", ""},
2637 {2, "ADJACENT_UNSELECTED", 0, "Adjacent Unselected", ""},
2638 {0, NULL, 0, NULL, NULL}};
2641 ot->name= "Snap Selection";
2642 ot->description= "Snap selected UV vertices to target type";
2643 ot->idname= "UV_OT_snap_selection";
2644 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2647 ot->exec= snap_selection_exec;
2648 ot->poll= ED_operator_uvedit;
2651 RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UV's to.");
2654 /* ******************** pin operator **************** */
2656 static int pin_exec(bContext *C, wmOperator *op)
2658 Scene *scene= CTX_data_scene(C);
2659 Object *obedit= CTX_data_edit_object(C);
2660 Image *ima= CTX_data_edit_image(C);
2661 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
2664 int clear= RNA_boolean_get(op->ptr, "clear");
2666 for(efa= em->faces.first; efa; efa= efa->next) {
2667 tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2669 if(uvedit_face_visible(scene, ima, efa, tface)) {
2671 if(uvedit_uv_selected(scene, efa, tface, 0)) tface->unwrap |= TF_PIN1;
2672 if(uvedit_uv_selected(scene, efa, tface, 1)) tface->unwrap |= TF_PIN2;
2673 if(uvedit_uv_selected(scene, efa, tface, 2)) tface->unwrap |= TF_PIN3;
2675 if(uvedit_uv_selected(scene, efa, tface, 3)) tface->unwrap |= TF_PIN4;
2678 if(uvedit_uv_selected(scene, efa, tface, 0)) tface->unwrap &= ~TF_PIN1;
2679 if(uvedit_uv_selected(scene, efa, tface, 1)) tface->unwrap &= ~TF_PIN2;
2680 if(uvedit_uv_selected(scene, efa, tface, 2)) tface->unwrap &= ~TF_PIN3;
2682 if(uvedit_uv_selected(scene, efa, tface, 3)) tface->unwrap &= ~TF_PIN4;
2687 WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2689 BKE_mesh_end_editmesh(obedit->data, em);
2690 return OPERATOR_FINISHED;
2693 void UV_OT_pin(wmOperatorType *ot)
2697 ot->description= "Set/clear selected UV vertices as anchored between multiple unwrap operations";
2698 ot->idname= "UV_OT_pin";
2699 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2703 ot->poll= ED_operator_uvedit;
2706 RNA_def_boolean(ot->srna, "clear", 0, "Clear", "Clear pinning for the selection instead of setting it.");
2709 /******************* select pinned operator ***************/
2711 static int select_pinned_exec(bContext *C, wmOperator *UNUSED(op))
2713 Scene *scene= CTX_data_scene(C);
2714 Object *obedit= CTX_data_edit_object(C);
2715 Image *ima= CTX_data_edit_image(C);
2716 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
2720 for(efa= em->faces.first; efa; efa= efa->next) {
2721 tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2723 if(uvedit_face_visible(scene, ima, efa, tface)) {
2724 if(tface->unwrap & TF_PIN1) uvedit_uv_select(scene, efa, tface, 0);
2725 if(tface->unwrap & TF_PIN2) uvedit_uv_select(scene, efa, tface, 1);
2726 if(tface->unwrap & TF_PIN3) uvedit_uv_select(scene, efa, tface, 2);
2728 if(tface->unwrap & TF_PIN4) uvedit_uv_select(scene, efa, tface, 3);
2733 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2735 BKE_mesh_end_editmesh(obedit->data, em);
2736 return OPERATOR_FINISHED;
2739 void UV_OT_select_pinned(wmOperatorType *ot)
2742 ot->name= "Selected Pinned";
2743 ot->description= "Select all pinned UV vertices";
2744 ot->idname= "UV_OT_select_pinned";
2745 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2748 ot->exec= select_pinned_exec;
2749 ot->poll= ED_operator_uvedit;
2752 /********************** hide operator *********************/
2754 static int hide_exec(bContext *C, wmOperator *op)
2756 SpaceImage *sima= CTX_wm_space_image(C);
2757 ToolSettings *ts= CTX_data_tool_settings(C);
2758 Object *obedit= CTX_data_edit_object(C);
2759 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
2762 int swap= RNA_boolean_get(op->ptr, "unselected");
2763 int facemode= sima ? sima->flag & SI_SELACTFACE : 0;
2765 if(ts->uv_flag & UV_SYNC_SELECTION) {
2766 EM_hide_mesh(em, swap);
2767 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2769 BKE_mesh_end_editmesh(obedit->data, em);
2770 return OPERATOR_FINISHED;
2774 for(efa= em->faces.first; efa; efa= efa->next) {
2775 if(efa->f & SELECT) {
2776 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2778 /* Pretend face mode */
2779 if(( (efa->v4==NULL &&
2780 ( tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) == (TF_SEL1|TF_SEL2|TF_SEL3) ) ||
2781 ( tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) == (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) ) == 0) {
2783 if(em->selectmode == SCE_SELECT_FACE) {
2785 /* must re-select after */
2786 efa->e1->f &= ~SELECT;
2787 efa->e2->f &= ~SELECT;
2788 efa->e3->f &= ~SELECT;
2789 if(efa->e4) efa->e4->f &= ~SELECT;
2792 EM_select_face(efa, 0);
2794 tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2796 else if(em->selectmode == SCE_SELECT_FACE) {
2797 const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
2798 if((tf->flag & select_flag)==0) {
2799 EM_select_face(efa, 0);
2800 tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2804 /* EM_deselect_flush will deselect the face */
2805 if((tf->flag & TF_SEL1)==0) efa->v1->f &= ~SELECT;
2806 if((tf->flag & TF_SEL2)==0) efa->v2->f &= ~SELECT;
2807 if((tf->flag & TF_SEL3)==0) efa->v3->f &= ~SELECT;
2808 if((efa->v4) && (tf->flag & TF_SEL4)==0) efa->v4->f &= ~SELECT;
2810 tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2816 for(efa= em->faces.first; efa; efa= efa->next) {
2817 if(efa->f & SELECT) {
2818 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2821 if( (efa->v4==NULL &&
2822 ( tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) == (TF_SEL1|TF_SEL2|TF_SEL3) ) ||
2823 ( tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) == (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) ) {
2825 if(em->selectmode == SCE_SELECT_FACE) {
2827 /* must re-select after */
2828 efa->e1->f &= ~SELECT;
2829 efa->e2->f &= ~SELECT;
2830 efa->e3->f &= ~SELECT;
2831 if(efa->e4) efa->e4->f &= ~SELECT;
2834 EM_select_face(efa, 0);
2837 tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2839 else if(em->selectmode == SCE_SELECT_FACE) {
2840 const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
2841 if(tf->flag & select_flag)
2842 EM_select_face(efa, 0);
2844 tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2847 /* EM_deselect_flush will deselect the face */
2848 if(tf->flag & TF_SEL1) efa->v1->f &= ~SELECT;
2849 if(tf->flag & TF_SEL2) efa->v2->f &= ~SELECT;
2850 if(tf->flag & TF_SEL3) efa->v3->f &= ~SELECT;
2851 if((efa->v4) && tf->flag & TF_SEL4) efa->v4->f &= ~SELECT;
2853 tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2859 /*deselects too many but ok for now*/
2860 if(em->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_VERTEX))
2861 EM_deselect_flush(em);
2863 if(em->selectmode==SCE_SELECT_FACE) {
2864 /* de-selected all edges from faces that were de-selected.
2865 * now make sure all faces that are selected also have selected edges */
2866 for(efa= em->faces.first; efa; efa= efa->next)
2868 EM_select_face(efa, 1);
2871 EM_validate_selections(em);
2872 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2874 BKE_mesh_end_editmesh(obedit->data, em);
2875 return OPERATOR_FINISHED;
2878 void UV_OT_hide(wmOperatorType *ot)
2881 ot->name= "Hide Selected";
2882 ot->description= "Hide (un)selected UV vertices";
2883 ot->idname= "UV_OT_hide";
2884 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2887 ot->exec= hide_exec;
2888 ot->poll= ED_operator_uvedit;
2891 RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
2894 /****************** reveal operator ******************/
2896 static int reveal_exec(bContext *C, wmOperator *UNUSED(op))
2898 SpaceImage *sima= CTX_wm_space_image(C);
2899 ToolSettings *ts= CTX_data_tool_settings(C);
2900 Object *obedit= CTX_data_edit_object(C);
2901 EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
2904 int facemode= sima ? sima->flag & SI_SELACTFACE : 0;
2905 int stickymode= sima ? (sima->sticky != SI_STICKY_DISABLE) : 1;
2907 /* call the mesh function if we are in mesh sync sel */
2908 if(ts->uv_flag & UV_SYNC_SELECTION) {
2910 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2912 BKE_mesh_end_editmesh(obedit->data, em);
2913 return OPERATOR_FINISHED;
2917 if(em->selectmode == SCE_SELECT_FACE) {
2918 for(efa= em->faces.first; efa; efa= efa->next) {
2919 if(!(efa->h) && !(efa->f & SELECT)) {
2920 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2921 EM_select_face(efa, 1);
2922 tf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
2927 /* enable adjacent faces to have disconnected UV selections if sticky is disabled */
2929 for(efa= em->faces.first; efa; efa= efa->next) {
2930 if(!(efa->h) && !(efa->f & SELECT)) {
2931 /* All verts must be unselected for the face to be selected in the UV view */
2932 if((efa->v1->f&SELECT)==0 && (efa->v2->f&SELECT)==0 && (efa->v3->f&SELECT)==0 && (efa->v4==0 || (efa->v4->f&SELECT)==0)) {
2933 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2935 tf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
2936 /* Cant use EM_select_face here because it unselects the verts
2937 * and we cant tell if the face was totally unselected or not */
2938 /*EM_select_face(efa, 1);
2940 * See Loop with EM_select_face() below... */
2947 for(efa= em->faces.first; efa; efa= efa->next) {
2948 if(!(efa->h) && !(efa->f & SELECT)) {
2949 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2951 if((efa->v1->f & SELECT)==0) {tf->flag |= TF_SEL1;}
2952 if((efa->v2->f & SELECT)==0) {tf->flag |