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