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