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