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