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