fd868f1c935ddd817e067ed71bec98a83f6fa45d
[blender.git] / source / blender / editors / uvedit / uvedit_ops.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Antony Riakiotakis.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/uvedit/uvedit_ops.c
29  *  \ingroup eduv
30  */
31
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <math.h>
36 #include <string.h>
37
38 #include "MEM_guardedalloc.h"
39
40 #include "DNA_object_types.h"
41 #include "DNA_material_types.h"
42 #include "DNA_meshdata_types.h"
43 #include "DNA_node_types.h"
44 #include "DNA_image_types.h"
45 #include "DNA_space_types.h"
46 #include "DNA_scene_types.h"
47
48 #include "BLI_math.h"
49 #include "BLI_blenlib.h"
50 #include "BLI_editVert.h"
51 #include "BLI_array.h"
52 #include "BLI_utildefines.h"
53
54 #include "BKE_context.h"
55 #include "BKE_customdata.h"
56 #include "BKE_depsgraph.h"
57 #include "BKE_image.h"
58 #include "BKE_library.h"
59 #include "BKE_main.h"
60 #include "BKE_material.h"
61 #include "BKE_mesh.h"
62 #include "BKE_node.h"
63 #include "BKE_report.h"
64 #include "BKE_scene.h"
65 #include "BKE_tessmesh.h"
66
67 #include "ED_image.h"
68 #include "ED_mesh.h"
69 #include "ED_node.h"
70 #include "ED_uvedit.h"
71 #include "ED_object.h"
72 #include "ED_screen.h"
73 #include "ED_transform.h"
74
75 #include "RNA_access.h"
76 #include "RNA_define.h"
77
78 #include "WM_api.h"
79 #include "WM_types.h"
80
81 #include "UI_view2d.h"
82
83 #include "uvedit_intern.h"
84
85 #define EFA_F1_FLAG     2
86
87 /************************* state testing ************************/
88
89 int ED_uvedit_test(Object *obedit)
90 {
91         BMEditMesh *em;
92         int ret;
93
94         if (!obedit)
95                 return 0;
96         
97         if(obedit->type != OB_MESH)
98                 return 0;
99
100         em = ((Mesh*)obedit->data)->edit_btmesh;
101         ret = EDBM_texFaceCheck(em);
102         
103         return ret;
104 }
105
106 static int ED_operator_uvedit_can_uv_sculpt(struct bContext *C)
107 {
108         SpaceImage *sima= CTX_wm_space_image(C);
109         ToolSettings *toolsettings = CTX_data_tool_settings(C);
110         Object *obedit= CTX_data_edit_object(C);
111
112         return ED_space_image_show_uvedit(sima, obedit) && !(toolsettings->use_uv_sculpt);
113 }
114
115 static int UNUSED_FUNCTION(ED_operator_uvmap_mesh)(bContext *C)
116 {
117         Object *ob= CTX_data_active_object(C);
118
119         if(ob && ob->type==OB_MESH) {
120                 Mesh *me = ob->data;
121
122                 if(CustomData_get_layer(&me->fdata, CD_MTFACE) != NULL)
123                         return 1;
124         }
125
126         return 0;
127 }
128 /**************************** object active image *****************************/
129
130 static int is_image_texture_node(bNode *node)
131 {
132         return ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT);
133 }
134
135 int ED_object_get_active_image(Object *ob, int mat_nr, Image **ima, ImageUser **iuser, bNode **node_r)
136 {
137         Material *ma= give_current_material(ob, mat_nr);
138         bNode *node= (ma && ma->use_nodes)? nodeGetActiveTexture(ma->nodetree): NULL;
139
140         if(node && is_image_texture_node(node)) {
141                 if(ima) *ima= (Image*)node->id;
142                 if(iuser) *iuser= NULL;
143                 if(node_r) *node_r= node;
144                 return TRUE;
145         }
146         
147         if(ima) *ima= NULL;
148         if(iuser) *iuser= NULL;
149         if(node_r) *node_r= node;
150
151         return FALSE;
152 }
153
154 void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *ima)
155 {
156         Material *ma= give_current_material(ob, mat_nr);
157         bNode *node= (ma && ma->use_nodes)? nodeGetActiveTexture(ma->nodetree): NULL;
158
159         if(node && is_image_texture_node(node)) {
160                 node->id= &ima->id;
161                 ED_node_generic_update(bmain, ma->nodetree, node);
162         }
163 }
164
165 /************************* assign image ************************/
166
167 void ED_uvedit_assign_image(Main *bmain, Scene *scene, Object *obedit, Image *ima, Image *previma)
168 {
169         BMEditMesh *em;
170         BMFace *efa;
171         BMIter iter;
172         MTexPoly *tf;
173         int update= 0;
174         
175         /* skip assigning these procedural images... */
176         if(ima && (ima->type==IMA_TYPE_R_RESULT || ima->type==IMA_TYPE_COMPOSITE))
177                 return;
178
179         /* verify we have a mesh we can work with */
180         if(!obedit || (obedit->type != OB_MESH))
181                 return;
182
183         em= ((Mesh*)obedit->data)->edit_btmesh;
184         if(!em || !em->bm->totface) {
185                 return;
186         }
187
188         if(scene_use_new_shading_nodes(scene)) {
189                 /* new shading system, assign image in material */
190                 int sloppy= 1;
191                 BMFace *efa= BM_get_actFace(em->bm, sloppy);
192
193                 if(efa)
194                         ED_object_assign_active_image(bmain, obedit, efa->mat_nr, ima);
195         }
196         else {
197                 /* old shading system, assign image to selected faces */
198                 
199                 /* ensure we have a uv map */
200                 if(!CustomData_has_layer(&em->bm->pdata, CD_MTEXPOLY)) {
201                         BM_add_data_layer(em->bm, &em->bm->pdata, CD_MTEXPOLY);
202                         BM_add_data_layer(em->bm, &em->bm->ldata, CD_MLOOPUV);
203                         update= 1;
204                 }
205
206                 /* now assign to all visible faces */
207                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
208                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
209
210                         if(uvedit_face_visible(scene, previma, efa, tf)) {
211                                 if(ima) {
212                                         tf->tpage= ima;
213                                         
214                                         if(ima->id.us==0) id_us_plus(&ima->id);
215                                         else id_lib_extern(&ima->id);
216                                 }
217                                 else {
218                                         tf->tpage= NULL;
219                                 }
220
221                                 update = 1;
222                         }
223                 }
224
225                 /* and update depdency graph */
226                 if(update)
227                         DAG_id_tag_update(obedit->data, 0);
228         }
229
230 }
231
232 /* dotile -     1, set the tile flag (from the space image)
233  *                      2, set the tile index for the faces. */
234 static int uvedit_set_tile(Object *obedit, Image *ima, int curtile)
235 {
236         BMEditMesh *em;
237         BMFace *efa;
238         BMIter iter;
239         MTexPoly *tf;
240         
241         /* verify if we have something to do */
242         if(!ima || !ED_uvedit_test(obedit))
243                 return 0;
244
245         if((ima->tpageflag & IMA_TILES) == 0)
246                 return 0;
247
248         /* skip assigning these procedural images... */
249         if(ima->type==IMA_TYPE_R_RESULT || ima->type==IMA_TYPE_COMPOSITE)
250                 return 0;
251         
252         em= ((Mesh*)obedit->data)->edit_btmesh;
253
254         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
255                 tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
256
257                 if(!BM_TestHFlag(efa, BM_HIDDEN) && BM_TestHFlag(efa, BM_SELECT))
258                         tf->tile= curtile; /* set tile index */
259         }
260
261         DAG_id_tag_update(obedit->data, 0);
262
263         return 1;
264 }
265
266 /*********************** space conversion *********************/
267
268 static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist)
269 {
270         int width, height;
271
272         if(sima) {
273                 ED_space_image_size(sima, &width, &height);
274         }
275         else {
276                 width= 256;
277                 height= 256;
278         }
279
280         dist[0]= pixeldist/width;
281         dist[1]= pixeldist/height;
282 }
283
284 /*************** visibility and selection utilities **************/
285
286 int uvedit_face_visible_nolocal(Scene *scene, BMFace *efa)
287 {
288         ToolSettings *ts= scene->toolsettings;
289
290         if(ts->uv_flag & UV_SYNC_SELECTION)
291                 return (BM_TestHFlag(efa, BM_HIDDEN)==0);
292         else
293                 return (BM_TestHFlag(efa, BM_HIDDEN)==0 && BM_TestHFlag(efa, BM_SELECT));
294 }
295
296 int uvedit_face_visible(Scene *scene, Image *ima, BMFace *efa, MTexPoly *tf) {
297         ToolSettings *ts= scene->toolsettings;
298
299         if(ts->uv_flag & UV_SHOW_SAME_IMAGE)
300                 return (tf->tpage==ima)? uvedit_face_visible_nolocal(scene, efa): 0;
301         else
302                 return uvedit_face_visible_nolocal(scene, efa);
303 }
304
305 int uvedit_face_selected(Scene *scene, BMEditMesh *em, BMFace *efa)
306 {
307         ToolSettings *ts= scene->toolsettings;
308
309         if(ts->uv_flag & UV_SYNC_SELECTION)
310                 return (BM_TestHFlag(efa, BM_SELECT));
311         else {
312                 BMLoop *l;
313                 MLoopUV *luv;
314                 BMIter liter;
315
316                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
317                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
318                         if (!(luv->flag & MLOOPUV_VERTSEL))
319                                 return 0;
320                 }
321
322                 return 1;
323         }
324 }
325
326 int uvedit_face_select(Scene *scene, BMEditMesh *em, BMFace *efa)
327 {
328         ToolSettings *ts= scene->toolsettings;
329
330         if(ts->uv_flag & UV_SYNC_SELECTION)
331                 BM_Select(em->bm, efa, TRUE);
332         else {
333                 BMLoop *l;
334                 MLoopUV *luv;
335                 BMIter liter;
336
337                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
338                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
339                         luv->flag |= MLOOPUV_VERTSEL;
340                 }
341
342                 return 1;
343         }
344
345         return 0;
346 }
347
348 int uvedit_face_deselect(Scene *scene, BMEditMesh *em, BMFace *efa)
349 {
350         ToolSettings *ts= scene->toolsettings;
351
352         if(ts->uv_flag & UV_SYNC_SELECTION) {
353                 BM_Select(em->bm, efa, FALSE);
354         }
355         else {
356                 BMLoop *l;
357                 MLoopUV *luv;
358                 BMIter liter;
359
360                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
361                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
362                         luv->flag &= ~MLOOPUV_VERTSEL;
363                 }
364
365                 return 1;
366         }
367
368         return 0;
369 }
370
371 int uvedit_edge_selected(BMEditMesh *em, Scene *scene, BMLoop *l)
372 {
373         ToolSettings *ts= scene->toolsettings;
374
375         if(ts->uv_flag & UV_SYNC_SELECTION) {
376                 if(ts->selectmode & SCE_SELECT_FACE)
377                         return BM_TestHFlag(l->f, BM_SELECT);
378                 else if(ts->selectmode == SCE_SELECT_EDGE) {
379                         return BM_TestHFlag(l->e, BM_SELECT);
380                 } else
381                         return BM_TestHFlag(l->v, BM_SELECT) && 
382                                BM_TestHFlag(l->next->v, BM_SELECT);
383         }
384         else {
385                 MLoopUV *luv1, *luv2;
386
387                 luv1 = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
388                 luv2 = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
389
390                 return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL);
391         }
392 }
393
394 void uvedit_edge_select(BMEditMesh *em, Scene *scene, BMLoop *l)
395
396 {
397         ToolSettings *ts= scene->toolsettings;
398
399         if(ts->uv_flag & UV_SYNC_SELECTION) {
400                 if(ts->selectmode & SCE_SELECT_FACE)
401                         BM_Select(em->bm, l->f, TRUE);
402                 else if(ts->selectmode & SCE_SELECT_EDGE)
403                         BM_Select(em->bm, l->e, TRUE);
404                 else {
405                         BM_Select(em->bm, l->e->v1, TRUE);
406                         BM_Select(em->bm, l->e->v2, TRUE);
407                 }
408         }
409         else {
410                 MLoopUV *luv1, *luv2;
411
412                 luv1 = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
413                 luv2 = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
414                 
415                 luv1->flag |= MLOOPUV_VERTSEL;
416                 luv2->flag |= MLOOPUV_VERTSEL;
417         }
418 }
419
420 void uvedit_edge_deselect(BMEditMesh *em, Scene *scene, BMLoop *l)
421
422 {
423         ToolSettings *ts= scene->toolsettings;
424
425         if(ts->uv_flag & UV_SYNC_SELECTION) {
426                 if(ts->selectmode & SCE_SELECT_FACE)
427                         BM_Select(em->bm, l->f, FALSE);
428                 else if(ts->selectmode & SCE_SELECT_EDGE)
429                         BM_Select(em->bm, l->e, FALSE);
430                 else {
431                         BM_Select(em->bm, l->e->v1, FALSE);
432                         BM_Select(em->bm, l->e->v2, FALSE);
433                 }
434         }
435         else {
436                 MLoopUV *luv1, *luv2;
437
438                 luv1 = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
439                 luv2 = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
440                 
441                 luv1->flag &= ~MLOOPUV_VERTSEL;
442                 luv2->flag &= ~MLOOPUV_VERTSEL;
443         }
444 }
445
446 int uvedit_uv_selected(BMEditMesh *em, Scene *scene, BMLoop *l)
447 {
448         ToolSettings *ts= scene->toolsettings;
449
450         if(ts->uv_flag & UV_SYNC_SELECTION) {
451                 if(ts->selectmode & SCE_SELECT_FACE)
452                         return BM_TestHFlag(l->f, BM_SELECT);
453                 else
454                         return BM_TestHFlag(l->v, BM_SELECT);
455         }
456         else {
457                 MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
458
459                 return luv->flag & MLOOPUV_VERTSEL;
460         }
461 }
462
463 void uvedit_uv_select(BMEditMesh *em, Scene *scene, BMLoop *l)
464 {
465         ToolSettings *ts= scene->toolsettings;
466
467         if(ts->uv_flag & UV_SYNC_SELECTION) {
468                 if(ts->selectmode & SCE_SELECT_FACE)
469                         BM_Select(em->bm, l->f, TRUE);
470                 else
471                         BM_Select(em->bm, l->v, TRUE);
472         }
473         else {
474                 MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
475                 
476                 luv->flag |= MLOOPUV_VERTSEL;
477         }
478 }
479
480 void uvedit_uv_deselect(BMEditMesh *em, Scene *scene, BMLoop *l)
481 {
482         ToolSettings *ts= scene->toolsettings;
483
484         if(ts->uv_flag & UV_SYNC_SELECTION) {
485                 if(ts->selectmode & SCE_SELECT_FACE)
486                         BM_Select(em->bm, l->f, FALSE);
487                 else
488                         BM_Select(em->bm, l->v, FALSE);
489         }
490         else {
491                 MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
492                 
493                 luv->flag &= ~MLOOPUV_VERTSEL;
494         }
495 }
496
497 /*********************** live unwrap utilities ***********************/
498
499 void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit)
500 {
501         if(sima && (sima->flag & SI_LIVE_UNWRAP)) {
502                 ED_uvedit_live_unwrap_begin(scene, obedit);
503                 ED_uvedit_live_unwrap_re_solve();
504                 ED_uvedit_live_unwrap_end(0);
505         }
506 }
507
508 /*********************** geometric utilities ***********************/
509 void poly_uv_center(BMEditMesh *em, BMFace *f, float cent[2])
510 {
511         BMLoop *l;
512         MLoopUV *luv;
513         BMIter liter;
514
515         cent[0] = cent[1] = 0.0f;
516
517         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
518                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
519                 cent[0] += luv->uv[0];
520                 cent[1] += luv->uv[1];
521         }
522
523         cent[0] /= (float) f->len;
524         cent[1] /= (float) f->len;
525 }
526
527
528 void uv_center(float uv[][2], float cent[2], int quad)
529 {
530         if(quad) {
531                 cent[0] = (uv[0][0] + uv[1][0] + uv[2][0] + uv[3][0]) / 4.0f;
532                 cent[1] = (uv[0][1] + uv[1][1] + uv[2][1] + uv[3][1]) / 4.0f;
533         }
534         else {
535                 cent[0] = (uv[0][0] + uv[1][0] + uv[2][0]) / 3.0f;
536                 cent[1] = (uv[0][1] + uv[1][1] + uv[2][1]) / 3.0f;
537         }
538 }
539
540 float uv_area(float uv[][2], int quad)
541 {
542         if(quad)
543                 return area_tri_v2(uv[0], uv[1], uv[2]) + area_tri_v2(uv[0], uv[2], uv[3]); 
544         else
545                 return area_tri_v2(uv[0], uv[1], uv[2]); 
546 }
547
548 float poly_uv_area(float uv[][2], int len)
549 {
550         //BMESH_TODO: make this not suck
551         //maybe use scanfill? I dunno.
552
553         if(len >= 4)
554                 return area_tri_v2(uv[0], uv[1], uv[2]) + area_tri_v2(uv[0], uv[2], uv[3]); 
555         else
556                 return area_tri_v2(uv[0], uv[1], uv[2]); 
557
558         return 1.0;
559 }
560
561 void poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len)
562 {
563         int i;
564         for (i=0; i<len; i++) {
565                 uv[i][0] = uv_orig[i][0]*aspx;
566                 uv[i][1] = uv_orig[i][1]*aspy;
567         }
568 }
569
570 void uv_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy)
571 {
572         uv[0][0] = uv_orig[0][0]*aspx;
573         uv[0][1] = uv_orig[0][1]*aspy;
574         
575         uv[1][0] = uv_orig[1][0]*aspx;
576         uv[1][1] = uv_orig[1][1]*aspy;
577         
578         uv[2][0] = uv_orig[2][0]*aspx;
579         uv[2][1] = uv_orig[2][1]*aspy;
580         
581         uv[3][0] = uv_orig[3][0]*aspx;
582         uv[3][1] = uv_orig[3][1]*aspy;
583 }
584
585 int ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float *min, float *max)
586 {
587         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
588         BMFace *efa;
589         BMLoop *l;
590         BMIter iter, liter;
591         MTexPoly *tf;
592         MLoopUV *luv;
593         int sel;
594
595         INIT_MINMAX2(min, max);
596
597         sel= 0;
598         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
599                 tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
600                 if(!uvedit_face_visible(scene, ima, efa, tf))
601                         continue;
602                 
603                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
604                         if (uvedit_uv_selected(em, scene, l)) {
605                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
606                                 DO_MINMAX2(luv->uv, min, max); 
607                                 sel = 1;
608                         }
609                 }
610         }
611
612         return sel;
613 }
614
615 static int ED_uvedit_median(Scene *scene, Image *ima, Object *obedit, float co[3])
616 {
617         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
618         BMFace *efa;
619         BMLoop *l;
620         BMIter iter, liter;
621         MTexPoly *tf;
622         MLoopUV *luv;
623         unsigned int sel= 0;
624
625         zero_v3(co);
626         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
627                 tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
628                 if(!uvedit_face_visible(scene, ima, efa, tf))
629                         continue;
630                 
631                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
632                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
633                         if (uvedit_uv_selected(em, scene, l)) {
634                                 add_v2_v2(co, luv->uv);
635                                 sel++;
636                         }
637                 }
638         }
639
640         mul_v3_fl(co, 1.0f/(float)sel);
641
642         return (sel != 0);
643 }
644
645 static int uvedit_center(Scene *scene, Image *ima, Object *obedit, float *cent, char mode)
646 {
647         float min[2], max[2];
648         int change= 0;
649         
650         if(mode==V3D_CENTER) { /* bounding box */
651                 if(ED_uvedit_minmax(scene, ima, obedit, min, max)) {
652                         change = 1;
653
654                         cent[0]= (min[0]+max[0])/2.0f;
655                         cent[1]= (min[1]+max[1])/2.0f;
656                 }
657         }
658         else {
659                 if(ED_uvedit_median(scene, ima, obedit, cent)) {
660                         change = 1;
661                 }
662
663         }
664
665         if(change) {
666                 return 1;
667         }
668
669         return 0;
670 }
671
672 /************************** find nearest ****************************/
673
674 void uv_find_nearest_edge(Scene *scene, Image *ima, BMEditMesh *em, float co[2], NearestHit *hit)
675 {
676         MTexPoly *tf;
677         BMFace *efa;
678         BMLoop *l;
679         BMIter iter, liter;
680         MLoopUV *luv, *nextluv;
681         float mindist, dist;
682         int i;
683
684         mindist= 1e10f;
685         memset(hit, 0, sizeof(*hit));
686
687         BM_ElemIndex_Ensure(em->bm, BM_VERT);
688         
689         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
690                 tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
691                 if(!uvedit_face_visible(scene, ima, efa, tf))
692                         continue;
693                 
694                 i = 0;
695                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
696                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
697                         nextluv = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
698
699                         dist= dist_to_line_segment_v2(co, luv->uv, nextluv->uv);
700
701                         if(dist < mindist) {
702                                 hit->tf= tf;
703                                 hit->efa= efa;
704                                 
705                                 hit->l = l;
706                                 hit->nextl = l->next;
707                                 hit->luv = luv;
708                                 hit->nextluv = nextluv;
709                                 hit->lindex = i;
710                                 hit->vert1 = BM_GetIndex(hit->l->v);
711                                 hit->vert2 = BM_GetIndex(hit->l->next->v);
712
713                                 mindist = dist;
714                         }
715
716                         i++;
717                 }
718         }
719 }
720
721 static void find_nearest_uv_face(Scene *scene, Image *ima, BMEditMesh *em, float co[2], NearestHit *hit)
722 {
723         MTexPoly *tf;
724         BMFace *efa;
725         BMLoop *l;
726         BMIter iter, liter;
727         MLoopUV *luv;
728         float mindist, dist, cent[2];
729
730         mindist= 1e10f;
731         memset(hit, 0, sizeof(*hit));
732
733         /*this will fill in hit.vert1 and hit.vert2*/
734         uv_find_nearest_edge(scene, ima, em, co, hit);
735         hit->l = hit->nextl = NULL;
736         hit->luv = hit->nextluv = NULL;
737
738         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
739                 tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
740                 if(!uvedit_face_visible(scene, ima, efa, tf))
741                         continue;
742                 
743                 cent[0]= cent[1]= 0.0f;
744                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
745                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
746
747                         add_v2_v2(cent, luv->uv);
748                 }
749
750                 cent[0] /= efa->len;
751                 cent[1] /= efa->len;
752                 dist= fabs(co[0]- cent[0]) + fabs(co[1]- cent[1]);
753
754                 if(dist < mindist) {
755                         hit->tf= tf;
756                         hit->efa= efa;
757                         mindist= dist;
758                 }
759         }
760 }
761
762 static int nearest_uv_between(BMEditMesh *em, BMFace *efa, int UNUSED(nverts), int id,
763                               float co[2], float uv[2])
764 {
765         BMLoop *l;
766         MLoopUV *luv;
767         BMIter iter;
768         float m[3], v1[3], v2[3], c1, c2, *uv1, *uv2, *uv3;
769         int id1, id2, i;
770
771         id1= (id+efa->len-1)%efa->len;
772         id2= (id+efa->len+1)%efa->len;
773
774         m[0]= co[0]-uv[0];
775         m[1]= co[1]-uv[1];
776
777         i = 0;
778         BM_ITER(l, &iter, em->bm, BM_LOOPS_OF_FACE, efa) {
779                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
780                 
781                 if (i == id1)
782                         uv1 = luv->uv;
783                 else if (i == id)
784                         uv2 = luv->uv;
785                 else if (i == id2)
786                         uv3 = luv->uv;
787
788                 i++;
789         }
790
791         sub_v3_v3v3(v1, uv1, uv);
792         sub_v3_v3v3(v2, uv3, uv);
793
794         /* m and v2 on same side of v-v1? */
795         c1= v1[0]*m[1] - v1[1]*m[0];
796         c2= v1[0]*v2[1] - v1[1]*v2[0];
797
798         if(c1*c2 < 0.0f)
799                 return 0;
800
801         /* m and v1 on same side of v-v2? */
802         c1= v2[0]*m[1] - v2[1]*m[0];
803         c2= v2[0]*v1[1] - v2[1]*v1[0];
804
805         return (c1*c2 >= 0.0f);
806 }
807
808 void uv_find_nearest_vert(Scene *scene, Image *ima, BMEditMesh *em,
809                           float co[2], float penalty[2], NearestHit *hit)
810 {
811         BMFace *efa;
812         BMLoop *l;
813         BMIter iter, liter;
814         MTexPoly *tf;
815         MLoopUV *luv;
816         float mindist, dist;
817         int i;
818
819         /*this will fill in hit.vert1 and hit.vert2*/
820         uv_find_nearest_edge(scene, ima, em, co, hit);
821         hit->l = hit->nextl = NULL;
822         hit->luv = hit->nextluv = NULL;
823
824         mindist= 1e10f;
825         memset(hit, 0, sizeof(*hit));
826         
827         BM_ElemIndex_Ensure(em->bm, BM_VERT);
828
829         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
830                 tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
831                 if(!uvedit_face_visible(scene, ima, efa, tf))
832                         continue;
833                 
834                 i = 0;
835                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
836                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
837
838                         if(penalty && uvedit_uv_selected(em, scene, l))
839                                 dist= fabs(co[0]-luv->uv[0])+penalty[0] + fabs(co[1]-luv->uv[1])+penalty[1];
840                         else
841                                 dist= fabs(co[0]-luv->uv[0]) + fabs(co[1]-luv->uv[1]);
842
843                         if(dist<=mindist) {
844                                 if(dist==mindist)
845                                         if(!nearest_uv_between(em, efa, efa->len, i, co, luv->uv)) {
846                                                 i++;
847                                                 continue;
848                                         }
849
850                                 mindist= dist;
851
852                                 hit->l = l;
853                                 hit->nextl = l->next;
854                                 hit->luv = luv;
855                                 hit->nextluv = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
856                                 hit->tf= tf;
857                                 hit->efa= efa;
858                                 hit->lindex = i;
859                                 hit->vert1 = BM_GetIndex(hit->l->v);
860                         }
861
862                         i++;
863                 }
864         }
865 }
866
867 int ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, float co[2], float uv[2])
868 {
869         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
870         BMFace *efa;
871         BMLoop *l;
872         BMIter iter, liter;
873         MTexPoly *tf;
874         MLoopUV *luv;
875         float mindist, dist;
876         int found= 0;
877
878         mindist= 1e10f;
879         uv[0]= co[0];
880         uv[1]= co[1];
881         
882         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
883                 tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
884                 if(!uvedit_face_visible(scene, ima, efa, tf))
885                         continue;
886                 
887                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
888                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
889                         dist= fabs(co[0]-luv->uv[0]) + fabs(co[1]-luv->uv[1]);
890
891                         if(dist<=mindist) {
892                                 mindist= dist;
893
894                                 uv[0]= luv->uv[0];
895                                 uv[1]= luv->uv[1];
896                                 found= 1;
897                         }
898                 }
899         }
900
901         return found;
902 }
903
904 /*********************** loop select ***********************/
905
906 static void uv_vertex_loop_flag(UvMapVert *first)
907 {
908         UvMapVert *iterv;
909         int count= 0;
910
911         for(iterv=first; iterv; iterv=iterv->next) {
912                 if(iterv->separate && iterv!=first)
913                         break;
914
915                 count++;
916         }
917         
918         if(count < 5)
919                 first->flag= 1;
920 }
921
922 static UvMapVert *uv_vertex_map_get(UvVertMap *vmap, BMFace *efa, int a)
923 {
924         UvMapVert *iterv, *first;
925         BMLoop *l;
926
927         l = BMIter_AtIndex(NULL, BM_LOOPS_OF_FACE, efa, a);
928         first= EDBM_get_uv_map_vert(vmap,  BM_GetIndex(l->v));
929
930         for(iterv=first; iterv; iterv=iterv->next) {
931                 if(iterv->separate)
932                         first= iterv;
933                 if(iterv->f == BM_GetIndex(efa))
934                         return first;
935         }
936         
937         return NULL;
938 }
939
940 /* BMESH_TODO - in some cases we already know the loop so looking up the index isnt needed */
941
942 UvElement *ED_get_uv_element(UvElementMap *map, BMFace *efa, int index)
943 {
944         BMLoop *loop = efa->loops.first;
945         UvElement *element;
946
947         while (index >= 0) {
948                 loop = loop->next;
949                 index--;
950         }
951
952         element = map->vert[BM_GetIndex(loop->v)];
953
954         for(; element; element = element->next)
955                 if(element->face == efa)
956                         return element;
957
958         return NULL;
959 }
960
961 static int uv_edge_tag_faces(BMEditMesh *em, UvMapVert *first1, UvMapVert *first2, int *totface)
962 {
963         UvMapVert *iterv1, *iterv2;
964         BMFace *efa;
965         int tot = 0;
966
967         /* count number of faces this edge has */
968         for(iterv1=first1; iterv1; iterv1=iterv1->next) {
969                 if(iterv1->separate && iterv1 != first1)
970                         break;
971
972                 for(iterv2=first2; iterv2; iterv2=iterv2->next) {
973                         if(iterv2->separate && iterv2 != first2)
974                                 break;
975
976                         if(iterv1->f == iterv2->f) {
977                                 /* if face already tagged, don't do this edge */
978                                 efa= EDBM_get_face_for_index(em, iterv1->f);
979                                 if(BMO_TestFlag(em->bm, efa, EFA_F1_FLAG))
980                                         return 0;
981
982                                 tot++;
983                                 break;
984                         }
985                 }
986         }
987
988         if(*totface == 0) /* start edge */
989                 *totface= tot;
990         else if(tot != *totface) /* check for same number of faces as start edge */
991                 return 0;
992
993         /* tag the faces */
994         for(iterv1=first1; iterv1; iterv1=iterv1->next) {
995                 if(iterv1->separate && iterv1 != first1)
996                         break;
997
998                 for(iterv2=first2; iterv2; iterv2=iterv2->next) {
999                         if(iterv2->separate && iterv2 != first2)
1000                                 break;
1001
1002                         if(iterv1->f == iterv2->f) {
1003                                 efa= EDBM_get_face_for_index(em, iterv1->f);
1004                                 BMO_SetFlag(em->bm, efa, EFA_F1_FLAG);
1005                                 break;
1006                         }
1007                 }
1008         }
1009
1010         return 1;
1011 }
1012
1013 static int select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestHit *hit, float limit[2], int extend)
1014 {
1015         BMFace *efa;
1016         BMIter iter, liter;
1017         BMLoop *l;
1018         MTexPoly *tf;
1019         UvVertMap *vmap;
1020         UvMapVert *iterv1, *iterv2;
1021         int a, count, looking, nverts, starttotf, select;
1022
1023         /* setup */
1024         EDBM_init_index_arrays(em, 0, 0, 1);
1025         vmap= EDBM_make_uv_vert_map(em, 0, 0, limit);
1026
1027         BM_ElemIndex_Ensure(em->bm, BM_VERT);
1028
1029         count = 0;
1030         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1031                 if(!extend) {
1032                         uvedit_face_deselect(scene, em, efa);
1033                 }
1034                 
1035                 BMO_ClearFlag(em->bm, efa, EFA_F1_FLAG);
1036
1037                 BM_SetIndex(efa, count); /* set_inline */
1038
1039                 count++;
1040         }
1041         em->bm->elem_index_dirty &= ~BM_FACE;
1042
1043         /* set flags for first face and verts */
1044         nverts= hit->efa->len;
1045         iterv1= uv_vertex_map_get(vmap, hit->efa, hit->lindex);
1046         iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->lindex+1)%nverts);
1047         uv_vertex_loop_flag(iterv1);
1048         uv_vertex_loop_flag(iterv2);
1049
1050         starttotf= 0;
1051         uv_edge_tag_faces(em, iterv1, iterv2, &starttotf);
1052
1053         /* sorry, first edge isnt even ok */
1054         if(iterv1->flag==0 && iterv2->flag==0) looking= 0;
1055         else looking= 1;
1056
1057         /* iterate */
1058         while(looking) {
1059                 looking= 0;
1060
1061                 /* find correct valence edges which are not tagged yet, but connect to tagged one */
1062
1063                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1064                         tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1065
1066                         if(!BMO_TestFlag(em->bm, efa, EFA_F1_FLAG) && uvedit_face_visible(scene, ima, efa, tf)) {
1067                                 nverts= efa->len;
1068                                 for(a=0; a<nverts; a++) {
1069                                         /* check face not hidden and not tagged */
1070                                         iterv1= uv_vertex_map_get(vmap, efa, a);
1071                                         iterv2= uv_vertex_map_get(vmap, efa, (a+1)%nverts);
1072                                         
1073                                         if (!iterv1 || !iterv2)
1074                                                 continue;
1075
1076                                         /* check if vertex is tagged and has right valence */
1077                                         if(iterv1->flag || iterv2->flag) {
1078                                                 if(uv_edge_tag_faces(em, iterv1, iterv2, &starttotf)) {
1079                                                         looking= 1;
1080                                                         BMO_SetFlag(em->bm, efa, EFA_F1_FLAG);
1081
1082                                                         uv_vertex_loop_flag(iterv1);
1083                                                         uv_vertex_loop_flag(iterv2);
1084                                                         break;
1085                                                 }
1086                                         }
1087                                 }
1088                         }
1089                 }
1090         }
1091
1092         /* do the actual select/deselect */
1093         nverts= hit->efa->len;
1094         iterv1= uv_vertex_map_get(vmap, hit->efa, hit->lindex);
1095         iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->lindex+1)%nverts);
1096         iterv1->flag= 1;
1097         iterv2->flag= 1;
1098
1099         if(extend) {
1100                 if(uvedit_uv_selected(em, scene, hit->l))
1101                         select= 0;
1102                 else
1103                         select= 1;
1104         }
1105         else
1106                 select= 1;
1107         
1108         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1109                 tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1110
1111                 a = 0;
1112                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1113                         iterv1= uv_vertex_map_get(vmap, efa, a);
1114
1115                         if(iterv1->flag) {
1116                                 if(select) uvedit_uv_select(em, scene, l);
1117                                 else uvedit_uv_deselect(em, scene, l);
1118                         }
1119
1120                         a++;
1121                 }
1122         }
1123
1124         /* cleanup */
1125         EDBM_free_uv_vert_map(vmap);
1126         EDBM_free_index_arrays(em);
1127
1128         return (select)? 1: -1;
1129 }
1130
1131 /*********************** linked select ***********************/
1132
1133 static void select_linked(Scene *scene, Image *ima, BMEditMesh *em, float limit[2], NearestHit *hit, int extend)
1134 {
1135         BMFace *efa;
1136         BMLoop *l;
1137         BMIter iter, liter;
1138         MTexPoly *tf;
1139         MLoopUV *luv;
1140         UvVertMap *vmap;
1141         UvMapVert *vlist, *iterv, *startv;
1142         int i, nverts, stacksize= 0, *stack;
1143         unsigned int a;
1144         char *flag;
1145
1146         EDBM_init_index_arrays(em, 0, 0, 1); /* we can use this too */
1147         vmap= EDBM_make_uv_vert_map(em, 1, 1, limit);
1148
1149         if(vmap == NULL)
1150                 return;
1151
1152         stack= MEM_mallocN(sizeof(*stack)*(em->bm->totface+1), "UvLinkStack");
1153         flag= MEM_callocN(sizeof(*flag)*em->bm->totface, "UvLinkFlag");
1154
1155         if(!hit) {
1156                 a = 0;
1157                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1158                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1159
1160                         if(uvedit_face_visible(scene, ima, efa, tf)) { 
1161                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1162                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1163
1164                                         if (luv->flag & MLOOPUV_VERTSEL) {
1165                                                 stack[stacksize]= a;
1166                                                 stacksize++;
1167                                                 flag[a]= 1;
1168
1169                                                 break;
1170                                         }
1171                                 }
1172                         }
1173                 }
1174                 a++;
1175         }
1176         else {
1177                 a = 0;
1178                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1179                         if(efa == hit->efa) {
1180                                 stack[stacksize]= a;
1181                                 stacksize++;
1182                                 flag[a]= 1;
1183                                 break;
1184                         }
1185
1186                         a++;
1187                 }
1188         }
1189
1190         while(stacksize > 0) {
1191                 int j;
1192
1193                 stacksize--;
1194                 a= stack[stacksize];
1195                 
1196                 j = 0;
1197                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1198                         if(j==a)
1199                                 break;
1200
1201                         j++;
1202                 }
1203
1204                 nverts= efa->len;
1205
1206                 i = 0;
1207                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1208
1209                         /* make_uv_vert_map_EM sets verts tmp.l to the indices */
1210                         vlist= EDBM_get_uv_map_vert(vmap, BM_GetIndex(l->v));
1211                         
1212                         startv= vlist;
1213
1214                         for(iterv=vlist; iterv; iterv=iterv->next) {
1215                                 if(iterv->separate)
1216                                         startv= iterv;
1217                                 if(iterv->f == a)
1218                                         break;
1219                         }
1220
1221                         for(iterv=startv; iterv; iterv=iterv->next) {
1222                                 if((startv != iterv) && (iterv->separate))
1223                                         break;
1224                                 else if(!flag[iterv->f]) {
1225                                         flag[iterv->f]= 1;
1226                                         stack[stacksize]= iterv->f;
1227                                         stacksize++;
1228                                 }
1229                         }
1230
1231                         i++;
1232                 }
1233         }
1234
1235         if(!extend) {           
1236                 a = 0;
1237                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1238                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1239                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1240                                 
1241                                 if (flag[a])
1242                                         luv->flag |= MLOOPUV_VERTSEL;
1243                                 else
1244                                         luv->flag &= ~MLOOPUV_VERTSEL;
1245                         }
1246                         a++;
1247                 }
1248         }
1249         else {
1250                 a = 0;
1251                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1252                         if (!flag[a]) {
1253                                 a++;
1254                                 continue;
1255                         }
1256                         
1257                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1258                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1259                                                 
1260                                 if (luv->flag & MLOOPUV_VERTSEL)
1261                                         break;
1262                         }
1263                         
1264                         if (l)
1265                                 break;
1266                         
1267                         a++;
1268                 }
1269
1270                 if(efa) {
1271                         a = 0;
1272                         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1273                                 if (!flag[a]) {
1274                                         a++;
1275                                         continue;
1276                                 }
1277
1278                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1279                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1280                                         
1281                                         luv->flag &= ~MLOOPUV_VERTSEL;
1282                                 }
1283
1284                                 a++;
1285                         }
1286                 }
1287                 else {
1288                         a = 0;
1289                         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1290                                 if (!flag[a]) {
1291                                         a++;
1292                                         continue;
1293                                 }
1294
1295                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1296                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1297                                         
1298                                         luv->flag |= MLOOPUV_VERTSEL;
1299                                 }
1300
1301                                 a++;
1302                         }
1303                 }
1304         }
1305         
1306         MEM_freeN(stack);
1307         MEM_freeN(flag);
1308         EDBM_free_uv_vert_map(vmap);
1309         EDBM_free_index_arrays(em);
1310 }
1311
1312 /* ******************** align operator **************** */
1313
1314 static void weld_align_uv(bContext *C, int tool)
1315 {
1316         SpaceImage *sima;
1317         Scene *scene;
1318         Object *obedit;
1319         Image *ima;
1320         BMEditMesh *em;
1321         BMFace *efa;
1322         BMLoop *l;
1323         BMIter iter, liter;
1324         MTexPoly *tf;
1325         MLoopUV *luv;
1326         float cent[2], min[2], max[2];
1327         
1328         scene= CTX_data_scene(C);
1329         obedit= CTX_data_edit_object(C);
1330         em= ((Mesh*)obedit->data)->edit_btmesh;
1331         ima= CTX_data_edit_image(C);
1332         sima= CTX_wm_space_image(C);
1333
1334         INIT_MINMAX2(min, max);
1335
1336         if(tool == 'a') {
1337                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1338                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1339
1340                         if(!uvedit_face_visible(scene, ima, efa, tf))
1341                                 continue;
1342
1343                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1344                                 if (uvedit_uv_selected(em, scene, l)) {
1345                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1346                                         DO_MINMAX2(luv->uv, min, max)
1347                                 }
1348                         }
1349                 }
1350
1351                 tool= (max[0]-min[0] >= max[1]-min[1])? 'y': 'x';
1352         }
1353
1354         uvedit_center(scene, ima, obedit, cent, 0);
1355
1356         if(tool == 'x' || tool == 'w') {
1357                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1358                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1359                         if(!uvedit_face_visible(scene, ima, efa, tf))
1360                                 continue;
1361
1362                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1363                                 if (uvedit_uv_selected(em, scene, l)) {
1364                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1365                                         luv->uv[0] = cent[0];
1366                                 }
1367
1368                         }
1369                 }
1370         }
1371
1372         if(tool == 'y' || tool == 'w') {
1373                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1374                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1375                         if(!uvedit_face_visible(scene, ima, efa, tf))
1376                                 continue;
1377
1378                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1379                                 if (uvedit_uv_selected(em, scene, l)) {
1380                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1381                                         luv->uv[1] = cent[1];
1382                                 }
1383
1384                         }
1385                 }
1386         }
1387
1388 #if 0   // BMESH_TODO
1389
1390         if(tool == 's' || tool == 't' || tool == 'u') {
1391                  /* pass 1&2 variables */
1392                 int i, j;
1393                 int starttmpl= -1, connectedtostarttmpl= -1, startcorner;
1394                 int endtmpl= -1,   connectedtoendtmpl= -1,   endcorner;
1395                 MTFace *startface, *endface;
1396                 int itmpl, jtmpl;
1397                 EditVert *eve;
1398                 int pass; /* first 2 passes find endpoints, 3rd pass moves middle points, 4th pass is fail-on-face-selected */
1399                 EditFace *startefa, *endefa= NULL; /* endefa shouldnt need to be initialized but just incase */
1400
1401                  /* pass 3 variables */
1402                 float startx, starty, firstm,  firstb,  midx,      midy;
1403                 float endx,   endy,   secondm, secondb, midmovedx, midmovedy;
1404                 float IsVertical_check= -1;
1405                 float IsHorizontal_check= -1;
1406
1407                 for(i= 0, eve= em->verts.first; eve; eve= eve->next, i++) /* give each point a unique name */
1408                         eve->tmp.l= i;
1409                 for(pass= 1; pass <= 3; pass++) { /* do this for each endpoint */
1410                         if(pass == 3){ /* calculate */
1411                                 startx= startface->uv[startcorner][0];
1412                                 starty= startface->uv[startcorner][1];
1413                                 endx= endface->uv[endcorner][0];
1414                                 endy= endface->uv[endcorner][1];
1415                                 firstm= (endy-starty)/(endx-startx);
1416                                 firstb= starty-(firstm*startx);
1417                                 secondm= -1.0f/firstm;
1418                                 if(startx == endx) IsVertical_check= startx;
1419                                 if(starty == endy) IsHorizontal_check= starty;
1420                         }
1421                         for(efa= em->faces.first; efa; efa= efa->next) { /* for each face */
1422                                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); /* get face */
1423                                 if(uvedit_face_visible(scene, ima, efa, tf)) { /* if you can see it */
1424                                         if(uvedit_face_selected(scene, efa, tf)) { /* if the face is selected, get out now! */
1425                                                 pass= 4;
1426                                                 break;
1427                                         }
1428                                         for(i= 0; (i < 3 || (i == 3 && efa->v4)); i++) { /* for each point of the face */
1429                                                 itmpl= (*(&efa->v1 + i))->tmp.l; /* get unique name for points */
1430                                                 if(pass == 3) { /* move */
1431                                                         if(uvedit_uv_selected(scene, efa, tf, i)) {
1432                                                                 if(!(itmpl == starttmpl || itmpl == endtmpl)) {
1433                                                                         if(IsVertical_check != -1) tf->uv[i][0]= IsVertical_check;
1434                                                                         if(IsHorizontal_check != -1) tf->uv[i][1]= IsHorizontal_check;
1435                                                                         if((IsVertical_check == -1) && (IsHorizontal_check == -1)) {
1436                                                                                 midx= tf->uv[i][0];
1437                                                                                 midy= tf->uv[i][1];
1438                                                                                 if(tool == 's') {
1439                                                                                         secondb= midy-(secondm*midx);
1440                                                                                         midmovedx= (secondb-firstb)/(firstm-secondm);
1441                                                                                         midmovedy= (secondm*midmovedx)+secondb;
1442                                                                                         tf->uv[i][0]= midmovedx;
1443                                                                                         tf->uv[i][1]= midmovedy;
1444                                                                                 }
1445                                                                                 else if(tool == 't') {
1446                                                                                         tf->uv[i][0]= (midy-firstb)/firstm; /* midmovedx */
1447                                                                                 }
1448                                                                                 else if(tool == 'u') {
1449                                                                                         tf->uv[i][1]= (firstm*midx)+firstb; /* midmovedy */
1450                                                                                 }
1451                                                                         }
1452                                                                 }
1453                                                         }
1454                                                 }
1455                                                 else {
1456                                                         for(j= 0; (j < 3 || (j == 3 && efa->v4)); j++) { /* also for each point on the face */
1457                                                                 jtmpl= (*(&efa->v1 + j))->tmp.l;
1458                                                                 if(i != j && (!efa->v4 || ABS(i-j) !=  2)) { /* if the points are connected */
1459                                                                         /* quad   (0,1,2,3) 0,1 0,3 1,0 1,2 2,1 2,3 3,0 3,2
1460                                                                          * triangle (0,1,2) 0,1 0,2 1,0 1,2 2,0 2,1 */
1461                                                                         if(uvedit_uv_selected(scene, efa, tf, i) && uvedit_uv_selected(scene, efa, tf, j)) {
1462                                                                                  /* if the edge is selected */
1463                                                                                 if(pass == 1) { /* if finding first endpoint */
1464                                                                                         if(starttmpl == -1) { /* if the first endpoint isn't found yet */
1465                                                                                                 starttmpl= itmpl; /* set unique name for endpoint */
1466                                                                                                 connectedtostarttmpl= jtmpl;
1467                                                                                                  /* get point that endpoint is connected to */
1468                                                                                                 startface= tf; /* get face it's on */
1469                                                                                                 startcorner= i; /* what corner of the face? */
1470                                                                                                 startefa= efa;
1471                                                                                                 efa= em->faces.first;
1472                                                                                                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1473                                                                                                 i= -1;
1474                                                                                                 break;
1475                                                                                         }
1476                                                                                         if(starttmpl == itmpl && jtmpl != connectedtostarttmpl) {
1477                                                                                                 starttmpl= -1; /* not an endpoint */
1478                                                                                                 efa= startefa;
1479                                                                                                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1480                                                                                                 i= startcorner;
1481                                                                                                 break;
1482                                                                                         }
1483                                                                                 }
1484                                                                                 else if(pass == 2) { /* if finding second endpoint */
1485                                                                                         if(endtmpl == -1 && itmpl != starttmpl) {
1486                                                                                                 endtmpl= itmpl;
1487                                                                                                 connectedtoendtmpl= jtmpl;
1488                                                                                                 endface= tf;
1489                                                                                                 endcorner= i;
1490                                                                                                 endefa= efa;
1491                                                                                                 efa= em->faces.first;
1492                                                                                                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1493                                                                                                 i= -1;
1494                                                                                                 break;
1495                                                                                         }
1496                                                                                         if(endtmpl == itmpl && jtmpl != connectedtoendtmpl) {
1497                                                                                                 endtmpl= -1;
1498                                                                                                 efa= endefa;
1499                                                                                                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1500                                                                                                 i= endcorner;
1501                                                                                                 break;
1502                                                                                         }
1503                                                                                 }
1504                                                                         }
1505                                                                 }
1506                                                         }
1507                                                 }
1508                                         }
1509                                 }
1510                         }
1511                         if(pass == 2 && (starttmpl == -1 || endtmpl == -1)) {
1512                                 /* if endpoints aren't found */
1513                                 pass=4;
1514                         }
1515                 }
1516         }
1517
1518 #endif
1519
1520         uvedit_live_unwrap_update(sima, scene, obedit);
1521         DAG_id_tag_update(obedit->data, 0);
1522         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1523 }
1524
1525 static int align_exec(bContext *C, wmOperator *op)
1526 {
1527         weld_align_uv(C, RNA_enum_get(op->ptr, "axis"));
1528
1529         return OPERATOR_FINISHED;
1530 }
1531
1532 static void UV_OT_align(wmOperatorType *ot)
1533 {
1534         static EnumPropertyItem axis_items[] = {
1535                 {'s', "ALIGN_S", 0, "Straighten", "Align UVs along the line defined by the endpoints"},
1536                 {'t', "ALIGN_T", 0, "Straighten X", "Align UVs along the line defined by the endpoints along the X axis"},
1537                 {'u', "ALIGN_U", 0, "Straighten Y", "Align UVs along the line defined by the endpoints along the Y axis"},
1538                 {'a', "ALIGN_AUTO", 0, "Align Auto", "Automatically choose the axis on which there is most alignment already"},
1539                 {'x', "ALIGN_X", 0, "Align X", "Align UVs on X axis"},
1540                 {'y', "ALIGN_Y", 0, "Align Y", "Align UVs on Y axis"},
1541                 {0, NULL, 0, NULL, NULL}};
1542
1543         /* identifiers */
1544         ot->name= "Align";
1545         ot->description= "Align selected UV vertices to an axis";
1546         ot->idname= "UV_OT_align";
1547         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1548         
1549         /* api callbacks */
1550         ot->exec= align_exec;
1551         ot->poll= ED_operator_image_active;     /* requires space image */;
1552
1553         /* properties */
1554         RNA_def_enum(ot->srna, "axis", axis_items, 'a', "Axis", "Axis to align UV locations on");
1555 }
1556
1557 /* ******************** weld operator **************** */
1558
1559 static int weld_exec(bContext *C, wmOperator *UNUSED(op))
1560 {
1561         weld_align_uv(C, 'w');
1562
1563         return OPERATOR_FINISHED;
1564 }
1565
1566 static void UV_OT_weld(wmOperatorType *ot)
1567 {
1568         /* identifiers */
1569         ot->name= "Weld";
1570         ot->description= "Weld selected UV vertices together";
1571         ot->idname= "UV_OT_weld";
1572         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1573         
1574         /* api callbacks */
1575         ot->exec= weld_exec;
1576         ot->poll= ED_operator_uvedit;
1577 }
1578
1579 #if 0 // BMESH_TODO --- this function has been moved elsewhere
1580 /* ******************** stitch operator **************** */
1581
1582 /* just for averaging UVs */
1583 typedef struct UVVertAverage {
1584         float uv[2];
1585         int count;
1586 } UVVertAverage;
1587
1588 static int stitch_exec(bContext *C, wmOperator *op)
1589 {
1590         Scene *scene;
1591         Object *obedit;
1592         BMEditMesh *em;
1593         BMFace *efa;
1594         BMLoop *l;
1595         BMIter iter, liter;
1596         BMVert *eve;
1597         Image *ima;
1598         SpaceImage *sima= CTX_wm_space_image(C);
1599         MTexPoly *tf;
1600         MLoopUV *luv;
1601
1602         scene= CTX_data_scene(C);
1603         obedit= CTX_data_edit_object(C);
1604         em= ((Mesh*)obedit->data)->edit_btmesh;
1605         ima= CTX_data_edit_image(C);
1606         sima= CTX_wm_space_image(C);
1607         
1608         if(RNA_boolean_get(op->ptr, "use_limit")) {
1609                 UvVertMap *vmap;
1610                 UvMapVert *vlist, *iterv;
1611                 float newuv[2], limit[2], pixels;
1612                 int a, vtot;
1613
1614                 pixels= RNA_float_get(op->ptr, "limit");
1615                 uvedit_pixel_to_float(sima, limit, pixels);
1616
1617                 EDBM_init_index_arrays(em, 0, 0, 1);
1618                 vmap= EDBM_make_uv_vert_map(em, 1, 0, limit);
1619
1620                 if(vmap == NULL) {
1621                         return OPERATOR_CANCELLED;
1622                 }
1623                 
1624                 a = 0;
1625                 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
1626                         vlist= EDBM_get_uv_map_vert(vmap, a);
1627
1628                         while(vlist) {
1629                                 newuv[0]= 0; newuv[1]= 0;
1630                                 vtot= 0;
1631
1632                                 for(iterv=vlist; iterv; iterv=iterv->next) {
1633                                         if((iterv != vlist) && iterv->separate)
1634                                                 break;
1635
1636                                         efa = EDBM_get_face_for_index(em, iterv->f);
1637                                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1638                                         
1639                                         l = BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex);
1640                                         if (uvedit_uv_selected(em, scene, l)) {
1641                                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1642
1643                                                 newuv[0] += luv->uv[0];
1644                                                 newuv[1] += luv->uv[1];
1645                                                 vtot++;
1646                                         }
1647                                 }
1648
1649                                 if(vtot > 1) {
1650                                         newuv[0] /= vtot; newuv[1] /= vtot;
1651
1652                                         for(iterv=vlist; iterv; iterv=iterv->next) {
1653                                                 if((iterv != vlist) && iterv->separate)
1654                                                         break;
1655
1656                                                 efa = EDBM_get_face_for_index(em, iterv->f);
1657                                                 tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1658                                                 
1659                                                 l = BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex);
1660                                                 if (uvedit_uv_selected(em, scene, l)) {
1661                                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1662
1663                                                         luv->uv[0] = newuv[0];
1664                                                         luv->uv[1] = newuv[1];
1665                                                         vtot++;
1666                                                 }
1667                                         }
1668                                 }
1669
1670                                 vlist= iterv;
1671                         }
1672
1673                         a++;
1674                 }
1675
1676                 EDBM_free_uv_vert_map(vmap);
1677                 EDBM_free_index_arrays(em);
1678         }
1679         else {
1680                 UVVertAverage *uv_average, *uvav;
1681
1682                 BM_ElemIndex_Ensure(em->bm, BM_VERT);
1683
1684                 uv_average= MEM_callocN(sizeof(UVVertAverage)*em->bm->totvert, "Stitch");
1685                 
1686                 // gather uv averages per vert
1687                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1688                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1689                         if(!uvedit_face_visible(scene, ima, efa, tf))
1690                                 continue;
1691                         
1692                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1693                                 if(uvedit_uv_selected(em, scene, l)) {
1694                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1695                                         uvav = uv_average + BM_GetIndex(l->v);
1696
1697                                         uvav->count++;
1698                                         uvav->uv[0] += luv->uv[0];
1699                                         uvav->uv[1] += luv->uv[1];
1700                                 }
1701                         }
1702                 }
1703                 
1704                 // apply uv welding
1705                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1706                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1707                         if(!uvedit_face_visible(scene, ima, efa, tf))
1708                                 continue;
1709                         
1710                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1711                                 if(uvedit_uv_selected(em, scene, l)) {
1712                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1713                                         uvav = uv_average + BM_GetIndex(l->v);
1714                                         luv->uv[0] = uvav->uv[0]/uvav->count;
1715                                         luv->uv[1] = uvav->uv[1]/uvav->count;
1716                                 }
1717                         }
1718                 }
1719
1720                 MEM_freeN(uv_average);
1721         }
1722
1723         uvedit_live_unwrap_update(sima, scene, obedit);
1724         DAG_id_tag_update(obedit->data, 0);
1725         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1726
1727         return OPERATOR_FINISHED;
1728 }
1729
1730 static void UV_OT_stitch(wmOperatorType *ot)
1731 {
1732         /* identifiers */
1733         ot->name= "Stitch";
1734         ot->description= "Stitch selected UV vertices by proximity";
1735         ot->idname= "UV_OT_stitch";
1736         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1737         
1738         /* api callbacks */
1739         ot->exec= stitch_exec;
1740         ot->poll= ED_operator_uvedit;
1741
1742         /* properties */
1743         RNA_def_boolean(ot->srna, "use_limit", 1, "Use Limit", "Stitch UVs within a specified limit distance");
1744         RNA_def_float(ot->srna, "limit", 20.0, 0.0f, FLT_MAX, "Limit", "Limit distance in image pixels", -FLT_MAX, FLT_MAX);
1745 }
1746
1747 #endif
1748
1749 /* ******************** (de)select all operator **************** */
1750
1751 static void select_all_perform(bContext *C, int action)
1752 {
1753         Scene *scene;
1754         ToolSettings *ts;
1755         Object *obedit;
1756         BMEditMesh *em;
1757         BMFace *efa;
1758         BMLoop *l;
1759         BMIter iter, liter;
1760         Image *ima;
1761         MTexPoly *tf;
1762         MLoopUV *luv;
1763         
1764         scene= CTX_data_scene(C);
1765         ts= CTX_data_tool_settings(C);
1766         obedit= CTX_data_edit_object(C);
1767         em= ((Mesh*)obedit->data)->edit_btmesh;
1768         ima= CTX_data_edit_image(C);
1769         
1770         if(ts->uv_flag & UV_SYNC_SELECTION) {
1771
1772                 switch (action) {
1773                 case SEL_TOGGLE:
1774                         EDBM_toggle_select_all(((Mesh*)obedit->data)->edit_btmesh);
1775                         break;
1776                 case SEL_SELECT:
1777                         EDBM_set_flag_all(em, BM_SELECT);
1778                         break;
1779                 case SEL_DESELECT:
1780                         EDBM_clear_flag_all(em, BM_SELECT);
1781                         break;
1782                 case SEL_INVERT:
1783                         EDBM_select_swap(em);
1784                         break;
1785                 }
1786         }
1787         else {
1788                 if (action == SEL_TOGGLE) {
1789                         action = SEL_SELECT;
1790                         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1791                                 tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1792         
1793                                 if(!uvedit_face_visible(scene, ima, efa, tf))
1794                                         continue;
1795
1796                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1797                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1798
1799                                         if (luv->flag & MLOOPUV_VERTSEL) {
1800                                                 action = SEL_DESELECT;
1801                                                 break;
1802                                         }
1803                                 }
1804                         }
1805                 }
1806         
1807                 
1808                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1809                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1810
1811                         if(!uvedit_face_visible(scene, ima, efa, tf))
1812                                 continue;
1813
1814                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1815                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1816
1817                                 switch (action) {
1818                                 case SEL_SELECT:
1819                                         luv->flag |= MLOOPUV_VERTSEL;
1820                                         break;
1821                                 case SEL_DESELECT:
1822                                         luv->flag &= ~MLOOPUV_VERTSEL;
1823                                         break;
1824                                 case SEL_INVERT:
1825                                         luv->flag ^= MLOOPUV_VERTSEL;
1826                                         break;
1827                                 }
1828                         }
1829                 }
1830         }
1831 }
1832
1833 static int select_all_exec(bContext *C, wmOperator *op)
1834 {
1835         Object *obedit= CTX_data_edit_object(C);
1836         int action= RNA_enum_get(op->ptr, "action");
1837
1838         select_all_perform(C, action);
1839
1840         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
1841
1842         return OPERATOR_FINISHED;
1843 }
1844
1845 static void UV_OT_select_all(wmOperatorType *ot)
1846 {
1847         /* identifiers */
1848         ot->name= "Select or Deselect All";
1849         ot->description= "Change selection of all UV vertices";
1850         ot->idname= "UV_OT_select_all";
1851         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1852         
1853         /* api callbacks */
1854         ot->exec= select_all_exec;
1855         ot->poll= ED_operator_uvedit;
1856
1857         WM_operator_properties_select_all(ot);
1858 }
1859
1860 /* ******************** mouse select operator **************** */
1861
1862 static int sticky_select(float *limit, int hitv[4], int v, float *hituv[4], float *uv, int sticky, int hitlen)
1863 {
1864         int i;
1865
1866         /* this function test if some vertex needs to selected
1867          * in addition to the existing ones due to sticky select */
1868         if(sticky == SI_STICKY_DISABLE)
1869                 return 0;
1870
1871         for(i=0; i<hitlen; i++) {
1872                 if(hitv[i] == v) {
1873                         if(sticky == SI_STICKY_LOC) {
1874                                 if(fabsf(hituv[i][0]-uv[0]) < limit[0] && fabsf(hituv[i][1]-uv[1]) < limit[1])
1875                                         return 1;
1876                         }
1877                         else if(sticky == SI_STICKY_VERTEX)
1878                                 return 1;
1879                 }
1880         }
1881
1882         return 0;
1883 }
1884
1885 static int mouse_select(bContext *C, float co[2], int extend, int loop)
1886 {
1887         SpaceImage *sima= CTX_wm_space_image(C);
1888         Scene *scene= CTX_data_scene(C);
1889         ToolSettings *ts= CTX_data_tool_settings(C);
1890         Object *obedit= CTX_data_edit_object(C);
1891         Image *ima= CTX_data_edit_image(C);
1892         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
1893         BMFace *efa;
1894         BMLoop *l;
1895         BMIter iter, liter;
1896         MTexPoly *tf;
1897         MLoopUV *luv;
1898         NearestHit hit;
1899         int i, select = 1, selectmode, sticky, sync, *hitv=NULL, nvert;
1900         BLI_array_declare(hitv);
1901         int flush = 0, hitlen=0; /* 0 == dont flush, 1 == sel, -1 == desel;  only use when selection sync is enabled */
1902         float limit[2], **hituv = NULL;
1903         BLI_array_declare(hituv);
1904         float penalty[2];
1905
1906         /* notice 'limit' is the same no matter the zoom level, since this is like
1907          * remove doubles and could annoying if it joined points when zoomed out.
1908          * 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and
1909          * shift-selecting can consider an adjacent point close enough to add to
1910          * the selection rather than de-selecting the closest. */
1911
1912         uvedit_pixel_to_float(sima, limit, 0.05f);
1913         uvedit_pixel_to_float(sima, penalty, 5.0f / sima->zoom);
1914
1915         /* retrieve operation mode */
1916         if(ts->uv_flag & UV_SYNC_SELECTION) {
1917                 sync= 1;
1918
1919                 if(ts->selectmode & SCE_SELECT_FACE)
1920                         selectmode= UV_SELECT_FACE;
1921                 else if(ts->selectmode & SCE_SELECT_EDGE)
1922                         selectmode= UV_SELECT_EDGE;
1923                 else
1924                         selectmode= UV_SELECT_VERTEX;
1925
1926                 sticky= SI_STICKY_DISABLE;
1927         }
1928         else {
1929                 sync= 0;
1930                 selectmode= ts->uv_selectmode;
1931                 sticky= (sima)? sima->sticky: 1;
1932         }
1933
1934         /* find nearest element */
1935         if(loop) {
1936                 /* find edge */
1937                 uv_find_nearest_edge(scene, ima, em, co, &hit);
1938                 if(hit.efa == NULL) {
1939                         BLI_array_free(hitv);
1940                         BLI_array_free(hituv);
1941                         return OPERATOR_CANCELLED;
1942                 }
1943
1944                 hitlen = 0;
1945         }
1946         else if(selectmode == UV_SELECT_VERTEX) {
1947                 /* find vertex */
1948                 uv_find_nearest_vert(scene, ima, em, co, penalty, &hit);
1949                 if(hit.efa == NULL) {
1950                         BLI_array_free(hitv);
1951                         BLI_array_free(hituv);
1952                         return OPERATOR_CANCELLED;
1953                 }
1954
1955                 /* mark 1 vertex as being hit */
1956                 for(i=0; i<hit.efa->len; i++) {
1957                         BLI_array_growone(hitv);
1958                         BLI_array_growone(hituv);
1959                         hitv[i]= 0xFFFFFFFF;
1960                 }
1961
1962                 hitv[hit.lindex]= hit.vert1;
1963                 hituv[hit.lindex]= hit.luv->uv;
1964
1965                 hitlen = hit.efa->len;
1966         }
1967         else if(selectmode == UV_SELECT_EDGE) {
1968                 /* find edge */
1969                 uv_find_nearest_edge(scene, ima, em, co, &hit);
1970                 if(hit.efa == NULL) {
1971                         BLI_array_free(hitv);
1972                         BLI_array_free(hituv);
1973                         return OPERATOR_CANCELLED;
1974                 }
1975
1976                 /* mark 2 edge vertices as being hit */
1977                 for(i=0; i<hit.efa->len; i++) {
1978                         BLI_array_growone(hitv);
1979                         BLI_array_growone(hituv);
1980                         hitv[i]= 0xFFFFFFFF;
1981                 }
1982
1983                 nvert= hit.efa->len;
1984
1985                 hitv[hit.lindex]= hit.vert1;
1986                 hitv[(hit.lindex+1)%nvert]= hit.vert2;
1987                 hituv[hit.lindex]= hit.luv->uv;
1988                 hituv[(hit.lindex+1)%nvert]= hit.nextluv->uv;
1989
1990                 hitlen = hit.efa->len;
1991         }
1992         else if(selectmode == UV_SELECT_FACE) {
1993                 /* find face */
1994                 find_nearest_uv_face(scene, ima, em, co, &hit);
1995                 if(hit.efa == NULL) {
1996                         BLI_array_free(hitv);
1997                         BLI_array_free(hituv);
1998                         return OPERATOR_CANCELLED;
1999                 }
2000                 
2001                 /* make active */
2002                 BM_set_actFace(em->bm, hit.efa);
2003
2004                 /* mark all face vertices as being hit */
2005                 i = 0;
2006                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, hit.efa) {
2007                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2008
2009                         BLI_array_growone(hitv);
2010                         BLI_array_growone(hituv);
2011                         hituv[i]= luv->uv;
2012                         hitv[i] = BM_GetIndex(l->v);
2013                         i++;
2014                 }
2015                 
2016                 hitlen = hit.efa->len;
2017         }
2018         else if(selectmode == UV_SELECT_ISLAND) {
2019                 uv_find_nearest_vert(scene, ima, em, co, NULL, &hit);
2020
2021                 if(hit.efa==NULL) {
2022                         BLI_array_free(hitv);
2023                         BLI_array_free(hituv);
2024                         return OPERATOR_CANCELLED;
2025                 }
2026
2027                 hitlen = 0;
2028         }
2029         else {
2030                 hitlen = 0;
2031                 BLI_array_free(hitv);
2032                 BLI_array_free(hituv);
2033                 return OPERATOR_CANCELLED;
2034         }
2035
2036         /* do selection */
2037         if(loop) {
2038                 flush= select_edgeloop(scene, ima, em, &hit, limit, extend);
2039         }
2040         else if(selectmode == UV_SELECT_ISLAND) {
2041                 select_linked(scene, ima, em, limit, &hit, extend);
2042         }
2043         else if(extend) {
2044                 if(selectmode == UV_SELECT_VERTEX) {
2045                         /* (de)select uv vertex */
2046                         if(uvedit_uv_selected(em, scene, hit.l)) {
2047                                 uvedit_uv_deselect(em, scene, hit.l);
2048                                 select= 0;
2049                         }
2050                         else {
2051                                 uvedit_uv_select(em, scene, hit.l);
2052                                 select= 1;
2053                         }
2054                         flush = 1;
2055                 }
2056                 else if(selectmode == UV_SELECT_EDGE) {
2057                         /* (de)select edge */
2058                         if(uvedit_edge_selected(em, scene, hit.l)) {
2059                                 uvedit_edge_deselect(em, scene, hit.l);
2060                                 select= 0;
2061                         }
2062                         else {
2063                                 uvedit_edge_select(em, scene, hit.l);
2064                                 select= 1;
2065                         }
2066                         flush = 1;
2067                 }
2068                 else if(selectmode == UV_SELECT_FACE) {
2069                         /* (de)select face */
2070                         if(uvedit_face_selected(scene, em, hit.efa)) {
2071                                 uvedit_face_deselect(scene, em, hit.efa);
2072                                 select= 0;
2073                         }
2074                         else {
2075                                 uvedit_face_select(scene, em, hit.efa);
2076                                 select= 1;
2077                         }
2078                         flush = -1;
2079                 }
2080
2081                 /* (de)select sticky uv nodes */
2082                 if(sticky != SI_STICKY_DISABLE) {
2083
2084                         BM_ElemIndex_Ensure(em->bm, BM_VERT);
2085
2086                         /* deselect */
2087                         if(select==0) {
2088                                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2089                                         tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2090                                         if(!uvedit_face_visible(scene, ima, efa, tf))
2091                                                 continue;
2092
2093                                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2094                                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2095                                                 if(sticky_select(limit, hitv, BM_GetIndex(l->v), hituv, luv->uv, sticky, hitlen))
2096                                                         uvedit_uv_deselect(em, scene, l);
2097                                         }
2098                                 }
2099                                 flush = -1;
2100                         }
2101                         /* select */
2102                         else {
2103                                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2104                                         tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2105                                         if(!uvedit_face_visible(scene, ima, efa, tf))
2106                                                 continue;
2107
2108                                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2109                                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2110                                                 if(sticky_select(limit, hitv, BM_GetIndex(l->v), hituv, luv->uv, sticky, hitlen))
2111                                                         uvedit_uv_select(em, scene, l);
2112                                         }
2113                                 }
2114
2115                                 flush = 1;
2116                         }                       
2117                 }
2118         }
2119         else {
2120                 /* deselect all */
2121                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2122                         uvedit_face_deselect(scene, em, efa);
2123                 }
2124
2125                 if(selectmode == UV_SELECT_VERTEX) {
2126                         /* select vertex */
2127                         uvedit_uv_select(em, scene, hit.l);
2128                         flush= 1;
2129                 }
2130                 else if(selectmode == UV_SELECT_EDGE) {
2131                         /* select edge */
2132                         uvedit_edge_select(em, scene, hit.l);
2133                         flush= 1;
2134                 }
2135                 else if(selectmode == UV_SELECT_FACE) {
2136                         /* select face */
2137                         uvedit_face_select(scene, em, hit.efa);
2138                 }
2139
2140                 /* select sticky uvs */
2141                 if(sticky != SI_STICKY_DISABLE) {
2142                         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2143                                 tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2144                                 if(!uvedit_face_visible(scene, ima, efa, tf))
2145                                         continue;
2146                                 
2147                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2148                                         if(sticky == SI_STICKY_DISABLE) continue;
2149                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2150
2151                                         if(sticky_select(limit, hitv, BM_GetIndex(l->v), hituv, luv->uv, sticky, hitlen))
2152                                                 uvedit_uv_select(em, scene, l);
2153
2154                                         flush= 1;
2155                                 }
2156                         }
2157                 }
2158         }
2159
2160         if(sync) {
2161                 /* flush for mesh selection */
2162                 if(ts->selectmode != SCE_SELECT_FACE) {
2163                         if(flush==1)            EDBM_select_flush(em, ts->selectmode);
2164                         //else if(flush==-1)    EDBM_deselect_flush(em); <-- I think this takes care of itself. . .
2165                 }
2166         }
2167
2168         DAG_id_tag_update(obedit->data, 0);
2169         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2170
2171         BLI_array_free(hitv);
2172         BLI_array_free(hituv);
2173
2174         return OPERATOR_PASS_THROUGH|OPERATOR_FINISHED;
2175 }
2176
2177 static int select_exec(bContext *C, wmOperator *op)
2178 {
2179         float co[2];
2180         int extend, loop;
2181
2182         RNA_float_get_array(op->ptr, "location", co);
2183         extend= RNA_boolean_get(op->ptr, "extend");
2184         loop= 0;
2185
2186         return mouse_select(C, co, extend, loop);
2187 }
2188
2189 static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
2190 {
2191         ARegion *ar= CTX_wm_region(C);
2192         float co[2];
2193
2194         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
2195         RNA_float_set_array(op->ptr, "location", co);
2196
2197         return select_exec(C, op);
2198 }
2199
2200 static void UV_OT_select(wmOperatorType *ot)
2201 {
2202         /* identifiers */
2203         ot->name= "Select";
2204         ot->description= "Select UV vertices";
2205         ot->idname= "UV_OT_select";
2206         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2207         
2208         /* api callbacks */
2209         ot->exec= select_exec;
2210         ot->invoke= select_invoke;
2211         ot->poll= ED_operator_image_active;     /* requires space image */;
2212
2213         /* properties */
2214         RNA_def_boolean(ot->srna, "extend", 0,
2215                 "Extend", "Extend selection rather than clearing the existing selection");
2216         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
2217                 "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
2218 }
2219
2220 /* ******************** loop select operator **************** */
2221
2222 static int select_loop_exec(bContext *C, wmOperator *op)
2223 {
2224         float co[2];
2225         int extend, loop;
2226
2227         RNA_float_get_array(op->ptr, "location", co);
2228         extend= RNA_boolean_get(op->ptr, "extend");
2229         loop= 1;
2230
2231         return mouse_select(C, co, extend, loop);
2232 }
2233
2234 static int select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
2235 {
2236         ARegion *ar= CTX_wm_region(C);
2237         float co[2];
2238
2239         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
2240         RNA_float_set_array(op->ptr, "location", co);
2241
2242         return select_loop_exec(C, op);
2243 }
2244
2245 static void UV_OT_select_loop(wmOperatorType *ot)
2246 {
2247         /* identifiers */
2248         ot->name= "Loop Select";
2249         ot->description= "Select a loop of connected UV vertices";
2250         ot->idname= "UV_OT_select_loop";
2251         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2252         
2253         /* api callbacks */
2254         ot->exec= select_loop_exec;
2255         ot->invoke= select_loop_invoke;
2256         ot->poll= ED_operator_image_active;     /* requires space image */;
2257
2258         /* properties */
2259         RNA_def_boolean(ot->srna, "extend", 0,
2260                 "Extend", "Extend selection rather than clearing the existing selection");
2261         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
2262                 "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
2263 }
2264
2265 /* ******************** linked select operator **************** */
2266
2267 static int select_linked_internal(bContext *C, wmOperator *op, wmEvent *event, int pick)
2268 {
2269         SpaceImage *sima= CTX_wm_space_image(C);
2270         Scene *scene= CTX_data_scene(C);
2271         ToolSettings *ts= CTX_data_tool_settings(C);
2272         Object *obedit= CTX_data_edit_object(C);
2273         Image *ima= CTX_data_edit_image(C);
2274         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
2275         float limit[2];
2276         int extend;
2277
2278         NearestHit hit, *hit_p= NULL;
2279
2280         if(ts->uv_flag & UV_SYNC_SELECTION) {
2281                 BKE_report(op->reports, RPT_ERROR, "Can't select linked when sync selection is enabled");
2282                 return OPERATOR_CANCELLED;
2283         }
2284
2285         extend= RNA_boolean_get(op->ptr, "extend");
2286         uvedit_pixel_to_float(sima, limit, 0.05f);
2287
2288         if(pick) {
2289                 float co[2];
2290
2291                 if(event) {
2292                         /* invoke */
2293                         ARegion *ar= CTX_wm_region(C);
2294
2295                         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
2296                         RNA_float_set_array(op->ptr, "location", co);
2297                 }
2298                 else {
2299                         /* exec */
2300                         RNA_float_get_array(op->ptr, "location", co);
2301                 }
2302
2303                 uv_find_nearest_vert(scene, ima, em, co, NULL, &hit);
2304                 hit_p= &hit;
2305         }
2306
2307         select_linked(scene, ima, em, limit, hit_p, extend);
2308
2309         DAG_id_tag_update(obedit->data, 0);
2310         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2311
2312         return OPERATOR_FINISHED;
2313 }
2314
2315 static int select_linked_exec(bContext *C, wmOperator *op)
2316 {
2317         return select_linked_internal(C, op, NULL, 0);
2318 }
2319
2320 static void UV_OT_select_linked(wmOperatorType *ot)
2321 {
2322         /* identifiers */
2323         ot->name= "Select Linked";
2324         ot->description= "Select all UV vertices linked to the active UV map";
2325         ot->idname= "UV_OT_select_linked";
2326         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2327         
2328         /* api callbacks */
2329         ot->exec= select_linked_exec;
2330         ot->poll= ED_operator_image_active;     /* requires space image */
2331
2332         /* properties */
2333         RNA_def_boolean(ot->srna, "extend", 0,
2334                 "Extend", "Extend selection rather than clearing the existing selection");
2335 }
2336
2337 static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
2338 {
2339         return select_linked_internal(C, op, event, 1);
2340 }
2341
2342 static int select_linked_pick_exec(bContext *C, wmOperator *op)
2343 {
2344         return select_linked_internal(C, op, NULL, 1);
2345 }
2346
2347 static void UV_OT_select_linked_pick(wmOperatorType *ot)
2348 {
2349         /* identifiers */
2350         ot->name= "Select Linked Pick";
2351         ot->description= "Select all UV vertices linked under the mouse";
2352         ot->idname= "UV_OT_select_linked_pick";
2353         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2354
2355         /* api callbacks */
2356         ot->invoke= select_linked_pick_invoke;
2357         ot->exec= select_linked_pick_exec;
2358         ot->poll= ED_operator_image_active;     /* requires space image */;
2359
2360         /* properties */
2361         RNA_def_boolean(ot->srna, "extend", 0,
2362                 "Extend", "Extend selection rather than clearing the existing selection");
2363
2364         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
2365                 "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
2366 }
2367
2368 /* ******************** unlink selection operator **************** */
2369
2370 static int unlink_selection_exec(bContext *C, wmOperator *op)
2371 {
2372         Scene *scene= CTX_data_scene(C);
2373         ToolSettings *ts= CTX_data_tool_settings(C);
2374         Object *obedit= CTX_data_edit_object(C);
2375         Image *ima= CTX_data_edit_image(C);
2376         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
2377         BMFace *efa;
2378         BMLoop *l;
2379         BMIter iter, liter;
2380         MTexPoly *tf;
2381         MLoopUV *luv;
2382
2383         if(ts->uv_flag & UV_SYNC_SELECTION) {
2384                 BKE_report(op->reports, RPT_ERROR, "Can't unlink selection when sync selection is enabled");
2385                 return OPERATOR_CANCELLED;
2386         }
2387         
2388         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2389                 int desel = 0;
2390
2391                 tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2392                 if(!uvedit_face_visible(scene, ima, efa, tf))
2393                         continue;
2394
2395                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2396                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2397                         
2398                         if (!(luv->flag & MLOOPUV_VERTSEL)) {
2399                                 desel = 1;
2400                                 break;
2401                         }
2402                 }
2403
2404                 if (desel) {
2405                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2406                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2407                                 luv->flag &= ~MLOOPUV_VERTSEL;
2408                         }
2409                 }
2410         }
2411         
2412         DAG_id_tag_update(obedit->data, 0);
2413         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2414
2415         return OPERATOR_FINISHED;
2416 }
2417
2418 static void UV_OT_unlink_selected(wmOperatorType *ot)
2419 {
2420         /* identifiers */
2421         ot->name= "Unlink Selection";
2422         ot->description= "Unlink selected UV vertices from active UV map";
2423         ot->idname= "UV_OT_unlink_selected";
2424         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2425         
2426         /* api callbacks */
2427         ot->exec= unlink_selection_exec;
2428         ot->poll= ED_operator_uvedit;
2429 }
2430
2431 /* ******************** border select operator **************** */
2432
2433 /* This function sets the selection on tagged faces, need because settings the
2434  * selection a face is done in a number of places but it also needs to respect
2435  * the sticky modes for the UV verts, so dealing with the sticky modes is best
2436  * done in a separate function.
2437  * 
2438  * De-selects faces that have been tagged on efa->tmp.l.  */
2439
2440 static void uv_faces_do_sticky(bContext *C, SpaceImage *sima, Scene *scene, Object *obedit, short select)
2441 {
2442         /* Selecting UV Faces with some modes requires us to change 
2443          * the selection in other faces (depending on the sticky mode).
2444          * 
2445          * This only needs to be done when the Mesh is not used for
2446          * selection (so for sticky modes, vertex or location based). */
2447         
2448         ToolSettings *ts= CTX_data_tool_settings(C);
2449         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
2450         BMFace *efa;
2451         BMLoop *l;
2452         BMIter iter, liter;
2453         /* MTexPoly *tf; */
2454         
2455         if((ts->uv_flag & UV_SYNC_SELECTION)==0 && sima->sticky == SI_STICKY_VERTEX) {
2456                 /* Tag all verts as untouched, then touch the ones that have a face center
2457                  * in the loop and select all MLoopUV's that use a touched vert. */
2458                 BMVert *eve;
2459                 
2460                 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2461                         BM_ClearHFlag(eve, BM_TMP_TAG);
2462                 }
2463                 
2464                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2465                         if (BM_TestHFlag(efa, BM_TMP_TAG)) {
2466                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2467                                         BM_SetHFlag(l->v, BM_TMP_TAG);
2468                                 }
2469                         }
2470                 }
2471
2472                 /* now select tagged verts */
2473                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2474                         /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
2475
2476                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2477                                 if (BM_TestHFlag(l->v, BM_TMP_TAG)) {
2478                                         if (select)
2479                                                 uvedit_uv_select(em, scene, l);
2480                                         else
2481                                                 uvedit_uv_deselect(em, scene, l);
2482                                 }
2483                         }
2484                 }
2485         }
2486         else if((ts->uv_flag & UV_SYNC_SELECTION)==0 && sima->sticky == SI_STICKY_LOC) {
2487                 BMFace *efa_vlist;
2488                 /* MTexPoly *tf_vlist; */ /* UNUSED */
2489                 UvMapVert *start_vlist=NULL, *vlist_iter;
2490                 struct UvVertMap *vmap;
2491                 float limit[2];
2492                 unsigned int efa_index;
2493                 //BMVert *eve; /* removed vert counting for now */ 
2494                 //int a;
2495                 
2496                 uvedit_pixel_to_float(sima, limit, 0.05);
2497                 
2498                 EDBM_init_index_arrays(em, 0, 0, 1);
2499                 vmap= EDBM_make_uv_vert_map(em, 0, 0, limit);
2500                 
2501                 /* verts are numbered above in make_uv_vert_map_EM, make sure this stays true! */
2502                 /*for(a=0, eve= em->verts.first; eve; a++, eve= eve->next)
2503                         eve->tmp.l = a; */
2504                 
2505                 if(vmap == NULL) {
2506                         return;
2507                 }
2508                 
2509                 efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
2510                 for (efa_index=0; efa; efa=BMIter_Step(&iter), efa_index++) {
2511                         if (BM_TestHFlag(efa, BM_TMP_TAG)) {
2512                                 /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
2513                                 
2514                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2515                                         if(select)
2516                                                 uvedit_uv_select(em, scene, l);
2517                                         else
2518                                                 uvedit_uv_deselect(em, scene, l);
2519                                         
2520                                         vlist_iter= EDBM_get_uv_map_vert(vmap, BM_GetIndex(l->v));
2521                                         
2522                                         while (vlist_iter) {
2523                                                 if(vlist_iter->separate)
2524                                                         start_vlist = vlist_iter;
2525                                                 
2526                                                 if(efa_index == vlist_iter->f)
2527                                                         break;
2528
2529                                                 vlist_iter = vlist_iter->next;
2530                                         }
2531                                 
2532                                         vlist_iter = start_vlist;
2533                                         while (vlist_iter) {
2534                                                 
2535                                                 if(vlist_iter != start_vlist && vlist_iter->separate)
2536                                                         break;
2537                                                 
2538                                                 if(efa_index != vlist_iter->f) {
2539                                                         efa_vlist = EDBM_get_face_for_index(em, vlist_iter->f);
2540                                                         /* tf_vlist = CustomData_bmesh_get(&em->bm->pdata, efa_vlist->head.data, CD_MTEXPOLY); */ /* UNUSED */
2541                                                         
2542                                                         if(select)
2543                                                                 uvedit_uv_select(em, scene, BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->tfindex));
2544                                                         else
2545                                                                 uvedit_uv_deselect(em, scene, BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->tfindex));
2546                                                 }
2547                                                 vlist_iter = vlist_iter->next;
2548                                         }
2549                                 }
2550                         }
2551                 }
2552                 EDBM_free_index_arrays(em);
2553                 EDBM_free_uv_vert_map(vmap);
2554                 
2555         }
2556         else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
2557                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2558                         if (BM_TestHFlag(efa, BM_TMP_TAG)) {
2559                                 if(select)
2560                                         uvedit_face_select(scene, em, efa);
2561                                 else
2562                                         uvedit_face_deselect(scene, em, efa);
2563                         }
2564                 }
2565         }
2566 }
2567
2568 static int border_select_exec(bContext *C, wmOperator *op)
2569 {
2570         SpaceImage *sima= CTX_wm_space_image(C);
2571         Scene *scene= CTX_data_scene(C);
2572         ToolSettings *ts= CTX_data_tool_settings(C);
2573         Object *obedit= CTX_data_edit_object(C);
2574         Image *ima= CTX_data_edit_image(C);
2575         ARegion *ar= CTX_wm_region(C);
2576         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
2577         BMFace *efa;
2578         BMLoop *l;
2579         BMIter iter, liter;
2580         MTexPoly *tf;
2581         MLoopUV *luv;
2582         rcti rect;
2583         rctf rectf;
2584         int change, pinned, select, faces, extend;
2585
2586         /* get rectangle from operator */
2587         rect.xmin= RNA_int_get(op->ptr, "xmin");
2588         rect.ymin= RNA_int_get(op->ptr, "ymin");
2589         rect.xmax= RNA_int_get(op->ptr, "xmax");
2590         rect.ymax= RNA_int_get(op->ptr, "ymax");
2591                 
2592         UI_view2d_region_to_view(&ar->v2d, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
2593         UI_view2d_region_to_view(&ar->v2d, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
2594
2595         /* figure out what to select/deselect */
2596         select= (RNA_int_get(op->ptr, "gesture_mode") == GESTURE_MODAL_SELECT);
2597         pinned= RNA_boolean_get(op->ptr, "pinned");
2598         extend= RNA_boolean_get(op->ptr, "extend");
2599
2600         if(!extend)
2601                 select_all_perform(C, SEL_DESELECT);
2602         
2603         if(ts->uv_flag & UV_SYNC_SELECTION)
2604                 faces= (ts->selectmode == SCE_SELECT_FACE);
2605         else
2606                 faces= (ts->uv_selectmode == UV_SELECT_FACE);
2607
2608         /* do actual selection */
2609         if(faces && !pinned) {
2610                 /* handle face selection mode */
2611                 float cent[2];
2612
2613                 change= 0;
2614
2615                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2616                         /* assume not touched */
2617                         BM_ClearHFlag(efa, BM_TMP_TAG);
2618
2619                         tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2620                         if(uvedit_face_visible(scene, ima, efa, tf)) {
2621                                 poly_uv_center(em, efa, cent);
2622                                 if(BLI_in_rctf(&rectf, cent[0], cent[1])) {
2623                                         BM_SetHFlag(efa, BM_TMP_TAG);
2624                                         change = 1;
2625                                 }
2626                         }
2627                 }
2628
2629                 /* (de)selects all tagged faces and deals with sticky modes */
2630                 if(change)
2631                         uv_faces_do_sticky(C, sima, scene, obedit, select);
2632         }
2633         else {
2634                 /* other selection modes */
2635                 change= 1;
2636                 
2637                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2638                         tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2639                         if(!uvedit_face_visible(scene, ima, efa, tf))
2640                                 continue;
2641                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2642                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2643
2644                                 if(!pinned || (ts->uv_flag & UV_SYNC_SELECTION) ) {
2645
2646                                         /* UV_SYNC_SELECTION - can't do pinned selection */
2647                                         if(BLI_in_rctf(&rectf, luv->uv[0], luv->uv[1])) {
2648                                                 if(select)      uvedit_uv_select(em, scene, l);
2649                                                 else            uvedit_uv_deselect(em, scene, l);
2650                                         }
2651                                 } else if(pinned) {
2652                                         if ((luv->flag & MLOOPUV_PINNED) && 
2653                                             BLI_in_rctf(&rectf, luv->uv[0], luv->uv[1])) {
2654                                                 if(select)      uvedit_uv_select(em, scene, l);
2655                                                 else            uvedit_uv_deselect(em, scene, l);
2656                                         }
2657                                 }
2658                         }
2659                 }
2660         }
2661
2662         if(change) {
2663                 /* make sure newly selected vert selection is updated*/
2664 #if 0 //ok, I think the BM_Select API handles all of this?
2665                 if(ts->uv_flag & UV_SYNC_SELECTION) {
2666                         if(ts->selectmode != SCE_SELECT_FACE) {
2667                                 if(select)      EM_select_flush(em);
2668                                 else            EM_deselect_flush(em);
2669                         }
2670                 }
2671 #endif
2672
2673                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2674                 
2675                 return OPERATOR_FINISHED;
2676         }
2677
2678         return OPERATOR_CANCELLED;
2679
2680
2681 static void UV_OT_select_border(wmOperatorType *ot)
2682 {
2683         /* identifiers */
2684         ot->name= "Border Select";
2685         ot->description= "Select UV vertices using border selection";
2686         ot->idname= "UV_OT_select_border";
2687         
2688         /* api callbacks */
2689         ot->invoke= WM_border_select_invoke;
2690         ot->exec= border_select_exec;
2691         ot->modal= WM_border_select_modal;
2692         ot->poll= ED_operator_image_active;     /* requires space image */;
2693         ot->cancel= WM_border_select_cancel;
2694         
2695         /* flags */
2696         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2697         
2698         /* properties */
2699         RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only");
2700
2701         WM_operator_properties_gesture_border(ot, TRUE);
2702 }
2703
2704 /* ******************** circle select operator **************** */
2705
2706 static void select_uv_inside_ellipse(BMEditMesh *em, SpaceImage *UNUSED(sima), Scene *scene, int select,
2707                                                                          float *offset, float *ell, BMLoop *l, MLoopUV *luv)
2708 {
2709         /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
2710         float x, y, r2, *uv;
2711         
2712         
2713         uv= luv->uv;
2714
2715         x= (uv[0] - offset[0])*ell[0];
2716         y= (uv[1] - offset[1])*ell[1];
2717
2718         r2 = x*x + y*y;
2719         if(r2 < 1.0f) {
2720                 if(select) uvedit_uv_select(em, scene, l);
2721                 else uvedit_uv_deselect(em, scene, l);
2722         }
2723 }
2724
2725 static int circle_select_exec(bContext *C, wmOperator *op)
2726 {
2727         SpaceImage *sima= CTX_wm_space_image(C);
2728         Scene *scene= CTX_data_scene(C);
2729         Object *obedit= CTX_data_edit_object(C);
2730         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
2731         ARegion *ar= CTX_wm_region(C);
2732         BMFace *efa;
2733         BMLoop *l;
2734         BMIter iter, liter;
2735         MLoopUV *luv;
2736         int x, y, radius, width, height, select;
2737         float zoomx, zoomy, offset[2], ellipse[2];
2738         int gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
2739
2740         /* get operator properties */
2741         select= (gesture_mode == GESTURE_MODAL_SELECT);
2742         x= RNA_int_get(op->ptr, "x");
2743         y= RNA_int_get(op->ptr, "y");
2744         radius= RNA_int_get(op->ptr, "radius");
2745
2746         /* compute ellipse size and location, not a circle since we deal
2747          * with non square image. ellipse is normalized, r = 1.0. */
2748         ED_space_image_size(sima, &width, &height);
2749         ED_space_image_zoom(sima, ar, &zoomx, &zoomy);
2750
2751         ellipse[0]= width*zoomx/radius;
2752         ellipse[1]= height*zoomy/radius;
2753
2754         UI_view2d_region_to_view(&ar->v2d, x, y, &offset[0], &offset[1]);
2755         
2756         /* do selection */
2757         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2758                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2759                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2760                         select_uv_inside_ellipse(em, sima, scene, select, offset, ellipse, l, luv);
2761                 }
2762         }
2763
2764 #if 0 //I think the BM_Select api stuff handles all this as necassary?
2765         if(select) EM_select_flush(em);
2766         else EM_deselect_flush(em);
2767 #endif
2768         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2769
2770         return OPERATOR_FINISHED;
2771 }
2772
2773 static void UV_OT_circle_select(wmOperatorType *ot)
2774 {
2775         /* identifiers */
2776         ot->name= "Circle Select";
2777         ot->description= "Select UV vertices using circle selection";
2778         ot->idname= "UV_OT_circle_select";
2779         
2780         /* api callbacks */
2781         ot->invoke= WM_gesture_circle_invoke;
2782         ot->modal= WM_gesture_circle_modal;
2783         ot->exec= circle_select_exec;
2784         ot->poll= ED_operator_image_active;     /* requires space image */;
2785         ot->cancel= WM_gesture_circle_cancel;
2786         
2787         /* flags */
2788         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2789         
2790         /* properties */
2791         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
2792         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
2793         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
2794         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
2795 }
2796
2797 /* ******************** snap cursor operator **************** */
2798
2799 static void snap_uv_to_pixel(float *uvco, float w, float h)
2800 {
2801         uvco[0] = ((float)((int)((uvco[0]*w) + 0.5f)))/w;
2802         uvco[1] = ((float)((int)((uvco[1]*h) + 0.5f)))/h;
2803 }
2804
2805 static void snap_cursor_to_pixels(SpaceImage *sima)
2806 {
2807         int width= 0, height= 0;
2808
2809         ED_space_image_size(sima, &width, &height);
2810         snap_uv_to_pixel(sima->cursor, width, height);
2811 }
2812
2813 static int snap_cursor_to_selection(Scene *scene, Image *ima, Object *obedit, SpaceImage *sima)
2814 {
2815         return uvedit_center(scene, ima, obedit, sima->cursor, sima->around);
2816 }
2817
2818 static int snap_cursor_exec(bContext *C, wmOperator *op)
2819 {
2820         SpaceImage *sima= CTX_wm_space_image(C);
2821         Scene *scene= CTX_data_scene(C);
2822         Object *obedit= CTX_data_edit_object(C);
2823         Image *ima= CTX_data_edit_image(C);
2824         int change= 0;
2825
2826         switch(RNA_enum_get(op->ptr, "target")) {
2827                 case 0:
2828                         snap_cursor_to_pixels(sima);
2829                         change= 1;
2830                         break;
2831                 case 1:
2832                         change= snap_cursor_to_selection(scene, ima, obedit, sima);
2833                         break;
2834         }
2835
2836         if(!change)
2837                 return OPERATOR_CANCELLED;
2838         
2839         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_IMAGE, sima);
2840
2841         return OPERATOR_FINISHED;
2842 }
2843
2844 static void UV_OT_snap_cursor(wmOperatorType *ot)
2845 {
2846         static EnumPropertyItem target_items[] = {
2847                 {0, "PIXELS", 0, "Pixels", ""},
2848                 {1, "SELECTED", 0, "Selected", ""},
2849                 {0, NULL, 0, NULL, NULL}};
2850
2851         /* identifiers */
2852         ot->name= "Snap Cursor";
2853         ot->description= "Snap cursor to target type";
2854         ot->idname= "UV_OT_snap_cursor";
2855         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2856         
2857         /* api callbacks */
2858         ot->exec= snap_cursor_exec;
2859         ot->poll= ED_operator_image_active;     /* requires space image */;
2860
2861         /* properties */
2862         RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
2863 }
2864
2865 /* ******************** snap selection operator **************** */
2866
2867 static int snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, SpaceImage *sima)
2868 {
2869         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
2870         BMFace *efa;
2871         BMLoop *l;
2872         BMIter iter, liter;
2873         MTexPoly *tface;
2874         MLoopUV *luv;
2875         short change= 0;
2876
2877         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2878                 tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2879                 if(!uvedit_face_visible(scene, ima, efa, tface))
2880                         continue;
2881
2882                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2883                         if(uvedit_uv_selected(em, scene, l)) {
2884                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2885                                 copy_v2_v2(luv->uv, sima->cursor);
2886                                 change= 1;
2887                         }
2888                 }
2889         }
2890
2891         return change;
2892 }
2893
2894 static int snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obedit)
2895 {
2896         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
2897         BMFace *efa;
2898         BMLoop *l;
2899         BMIter iter, liter;
2900         BMVert *eve;
2901         MTexPoly *tface;
2902         MLoopUV *luv;
2903         short change = 0;
2904         int count = 0;
2905         float *coords;
2906         short *usercount, users;
2907
2908         /* BMESH_TODO - stop setting the index, bad juju
2909          * not totally simple because 3 states and because the count is not
2910          * based on the global vertex index :S - campbell */
2911
2912         /* set all verts to -1 : an unused index*/
2913         BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL)
2914                 BM_SetIndex(eve, -1); /* set_dirty! */
2915         em->bm->elem_index_dirty |= BM_VERT;
2916         
2917         /* index every vert that has a selected UV using it, but only once so as to
2918          * get unique indices and to count how much to malloc */
2919         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2920                 tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2921                 if(!uvedit_face_visible(scene, ima, efa, tface)) {
2922                         BM_ClearHFlag(efa, BM_TMP_TAG);
2923                         continue;
2924                 } else {
2925                         BM_SetHFlag(efa, BM_TMP_TAG);
2926                 }
2927
2928                 change = 1;
2929                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2930                         if (uvedit_uv_selected(em, scene, l) && BM_GetIndex(l->v) == -1) {
2931                                 BM_SetIndex(l->v, count); /* set_dirty! */
2932                                 count++;
2933                         }
2934                 }
2935         }
2936         em->bm->elem_index_dirty |= BM_VERT; /* set above but include for completeness since they are made dirty again */
2937         
2938         coords = MEM_callocN(sizeof(float)*count*2, "snap to adjacent coords");
2939         usercount = MEM_callocN(sizeof(short)*count, "snap to adjacent counts");
2940         
2941         /* add all UV coords from visible, unselected UV coords as well as counting them to average later */
2942         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2943                 if (!BM_TestHFlag(efa, BM_TMP_TAG))
2944                         continue;
2945
2946                 tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2947                 if(!uvedit_face_visible(scene, ima, efa, tface))
2948                         continue;
2949
2950                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2951                         if (BM_GetIndex(l->v) >= 0 && 
2952                             (!uvedit_uv_selected(em, scene, l))) {
2953                                     luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2954                                     coords[BM_GetIndex(l->v)*2] += luv->uv[0];
2955                                     coords[BM_GetIndex(l->v)*2+1] += luv->uv[1];
2956                                     change = 1;
2957                         }
2958                 }
2959         }
2960         
2961         /* no other verts selected, bail out */
2962         if(!change) {
2963                 MEM_freeN(coords);
2964                 MEM_freeN(usercount);
2965                 return change;
2966         }
2967         
2968         /* copy the averaged unselected UVs back to the selected UVs */
2969         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2970                 if (!BM_TestHFlag(efa, BM_TMP_TAG))
2971                         continue;
2972
2973                 tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2974                 if(!uvedit_face_visible(scene, ima, efa, tface))
2975                         continue;
2976
2977                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2978                         if (uvedit_uv_selected(em, scene, l) && BM_GetIndex(l->v) >= 0
2979                             && (users = usercount[BM_GetIndex(l->v)])) {
2980                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2981                                 luv->uv[0] = coords[BM_GetIndex(l->v)*2];
2982                                 luv->uv[1] = coords[BM_GetIndex(l->v)*2+1];
2983                         }
2984                 }
2985         }
2986         
2987         MEM_freeN(coords);
2988         MEM_freeN(usercount);
2989
2990         return change;
2991 }
2992
2993 static int snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit)
2994 {
2995         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
2996         Image *ima= sima->image;
2997         BMFace *efa;
2998         BMLoop *l;
2999         BMIter iter, liter;
3000         MTexPoly *tface;
3001         MLoopUV *luv;
3002         int width= 0, height= 0;
3003         float w, h;
3004         short change = 0;
3005
3006         ED_space_image_size(sima, &width, &height);
3007         w = (float)width;
3008         h = (float)height;
3009         
3010         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
3011                 tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
3012                 if(!uvedit_face_visible(scene, ima, efa, tface))
3013                         continue;
3014
3015                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
3016                         if (uvedit_uv_selected(em, scene, l)) {
3017                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
3018                                 snap_uv_to_pixel(luv->uv, w, h);
3019                         }
3020                 }
3021
3022                 change = 1;
3023         }
3024
3025         return change;
3026 }
3027
3028 static int snap_selection_exec(bContext *C, wmOperator *op)
3029 {
3030         SpaceImage *sima= CTX_wm_space_image(C);
3031         Scene *scene= CTX_data_scene(C);
3032         Object *obedit= CTX_data_edit_object(C);
3033         Image *ima= CTX_data_edit_image(C);
3034         int change= 0;
3035
3036         switch(RNA_enum_get(op->ptr, "target")) {
3037                 case 0:
3038                         change= snap_uvs_to_pixels(sima, scene, obedit);
3039                         break;
3040                 case 1:
3041                         change= snap_uvs_to_cursor(scene, ima, obedit, sima);
3042                         break;
3043                 case 2:
3044                         change= snap_uvs_to_adjacent_unselected(scene, ima, obedit);
3045                         break;
3046         }
3047
3048         if(!change)
3049                 return OPERATOR_CANCELLED;
3050
3051         uvedit_live_unwrap_update(sima, scene, obedit);
3052         DAG_id_tag_update(obedit->data, 0);