style cleanup: follow style guide for formatting of if/for/while loops, and else...
[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_texFaceCheck(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, 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[3])
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_v3(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_v3_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, char mode)
648 {
649         float min[2], max[2];
650         int change= 0;
651         
652         if (mode==V3D_CENTER) { /* bounding box */
653                 if (ED_uvedit_minmax(scene, ima, obedit, min, max)) {
654                         change = 1;
655
656                         cent[0]= (min[0]+max[0])/2.0f;
657                         cent[1]= (min[1]+max[1])/2.0f;
658                 }
659         }
660         else {
661                 if (ED_uvedit_median(scene, ima, obedit, cent)) {
662                         change = 1;
663                 }
664
665         }
666
667         if (change) {
668                 return 1;
669         }
670
671         return 0;
672 }
673
674 /************************** find nearest ****************************/
675
676 void uv_find_nearest_edge(Scene *scene, Image *ima, BMEditMesh *em, float co[2], NearestHit *hit)
677 {
678         MTexPoly *tf;
679         BMFace *efa;
680         BMLoop *l;
681         BMIter iter, liter;
682         MLoopUV *luv, *nextluv;
683         float mindist, dist;
684         int i;
685
686         mindist= 1e10f;
687         memset(hit, 0, sizeof(*hit));
688
689         BM_mesh_elem_index_ensure(em->bm, BM_VERT);
690         
691         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
692                 tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
693                 if (!uvedit_face_visible(scene, ima, efa, tf))
694                         continue;
695                 
696                 i = 0;
697                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
698                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
699                         nextluv = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
700
701                         dist= dist_to_line_segment_v2(co, luv->uv, nextluv->uv);
702
703                         if (dist < mindist) {
704                                 hit->tf= tf;
705                                 hit->efa= efa;
706                                 
707                                 hit->l = l;
708                                 hit->nextl = l->next;
709                                 hit->luv = luv;
710                                 hit->nextluv = nextluv;
711                                 hit->lindex = i;
712                                 hit->vert1 = BM_elem_index_get(hit->l->v);
713                                 hit->vert2 = BM_elem_index_get(hit->l->next->v);
714
715                                 mindist = dist;
716                         }
717
718                         i++;
719                 }
720         }
721 }
722
723 static void find_nearest_uv_face(Scene *scene, Image *ima, BMEditMesh *em, float co[2], NearestHit *hit)
724 {
725         MTexPoly *tf;
726         BMFace *efa;
727         BMLoop *l;
728         BMIter iter, liter;
729         MLoopUV *luv;
730         float mindist, dist, cent[2];
731
732         mindist= 1e10f;
733         memset(hit, 0, sizeof(*hit));
734
735         /*this will fill in hit.vert1 and hit.vert2*/
736         uv_find_nearest_edge(scene, ima, em, co, hit);
737         hit->l = hit->nextl = NULL;
738         hit->luv = hit->nextluv = NULL;
739
740         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
741                 tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
742                 if (!uvedit_face_visible(scene, ima, efa, tf))
743                         continue;
744                 
745                 cent[0]= cent[1]= 0.0f;
746                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
747                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
748
749                         add_v2_v2(cent, luv->uv);
750                 }
751
752                 cent[0] /= efa->len;
753                 cent[1] /= efa->len;
754                 dist= fabs(co[0]- cent[0]) + fabs(co[1]- cent[1]);
755
756                 if (dist < mindist) {
757                         hit->tf= tf;
758                         hit->efa= efa;
759                         mindist= dist;
760                 }
761         }
762 }
763
764 static int nearest_uv_between(BMEditMesh *em, BMFace *efa, int UNUSED(nverts), int id,
765                               float co[2], float uv[2])
766 {
767         BMLoop *l;
768         MLoopUV *luv;
769         BMIter iter;
770         float m[3], v1[3], v2[3], c1, c2, *uv1, /* *uv2, */ /* UNUSED */ *uv3;
771         int id1, id2, i;
772
773         id1= (id+efa->len-1)%efa->len;
774         id2= (id+efa->len+1)%efa->len;
775
776         m[0]= co[0]-uv[0];
777         m[1]= co[1]-uv[1];
778
779         i = 0;
780         BM_ITER(l, &iter, em->bm, BM_LOOPS_OF_FACE, efa) {
781                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
782                 
783                 if (i == id1)
784                         uv1 = luv->uv;
785                 else if (i == id)
786                         ; /* uv2 = luv->uv; */ /* UNUSED */
787                 else if (i == id2)
788                         uv3 = luv->uv;
789
790                 i++;
791         }
792
793         sub_v3_v3v3(v1, uv1, uv);
794         sub_v3_v3v3(v2, uv3, uv);
795
796         /* m and v2 on same side of v-v1? */
797         c1= v1[0]*m[1] - v1[1]*m[0];
798         c2= v1[0]*v2[1] - v1[1]*v2[0];
799
800         if (c1*c2 < 0.0f)
801                 return 0;
802
803         /* m and v1 on same side of v-v2? */
804         c1= v2[0]*m[1] - v2[1]*m[0];
805         c2= v2[0]*v1[1] - v2[1]*v1[0];
806
807         return (c1*c2 >= 0.0f);
808 }
809
810 void uv_find_nearest_vert(Scene *scene, Image *ima, BMEditMesh *em,
811                           float co[2], float penalty[2], NearestHit *hit)
812 {
813         BMFace *efa;
814         BMLoop *l;
815         BMIter iter, liter;
816         MTexPoly *tf;
817         MLoopUV *luv;
818         float mindist, dist;
819         int i;
820
821         /*this will fill in hit.vert1 and hit.vert2*/
822         uv_find_nearest_edge(scene, ima, em, co, hit);
823         hit->l = hit->nextl = NULL;
824         hit->luv = hit->nextluv = NULL;
825
826         mindist= 1e10f;
827         memset(hit, 0, sizeof(*hit));
828         
829         BM_mesh_elem_index_ensure(em->bm, BM_VERT);
830
831         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
832                 tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
833                 if (!uvedit_face_visible(scene, ima, efa, tf))
834                         continue;
835                 
836                 i = 0;
837                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
838                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
839
840                         if (penalty && uvedit_uv_selected(em, scene, l))
841                                 dist= fabs(co[0]-luv->uv[0])+penalty[0] + fabs(co[1]-luv->uv[1])+penalty[1];
842                         else
843                                 dist= fabs(co[0]-luv->uv[0]) + fabs(co[1]-luv->uv[1]);
844
845                         if (dist<=mindist) {
846                                 if (dist==mindist)
847                                         if (!nearest_uv_between(em, efa, efa->len, i, co, luv->uv)) {
848                                                 i++;
849                                                 continue;
850                                         }
851
852                                 mindist= dist;
853
854                                 hit->l = l;
855                                 hit->nextl = l->next;
856                                 hit->luv = luv;
857                                 hit->nextluv = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
858                                 hit->tf= tf;
859                                 hit->efa= efa;
860                                 hit->lindex = i;
861                                 hit->vert1 = BM_elem_index_get(hit->l->v);
862                         }
863
864                         i++;
865                 }
866         }
867 }
868
869 int ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, float co[2], float uv[2])
870 {
871         BMEditMesh *em = BMEdit_FromObject(obedit);
872         BMFace *efa;
873         BMLoop *l;
874         BMIter iter, liter;
875         MTexPoly *tf;
876         MLoopUV *luv;
877         float mindist, dist;
878         int found= 0;
879
880         mindist= 1e10f;
881         uv[0]= co[0];
882         uv[1]= co[1];
883         
884         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
885                 tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
886                 if (!uvedit_face_visible(scene, ima, efa, tf))
887                         continue;
888                 
889                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
890                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
891                         dist= fabs(co[0]-luv->uv[0]) + fabs(co[1]-luv->uv[1]);
892
893                         if (dist<=mindist) {
894                                 mindist= dist;
895
896                                 uv[0]= luv->uv[0];
897                                 uv[1]= luv->uv[1];
898                                 found= 1;
899                         }
900                 }
901         }
902
903         return found;
904 }
905
906 /*********************** loop select ***********************/
907
908 static void uv_vertex_loop_flag(UvMapVert *first)
909 {
910         UvMapVert *iterv;
911         int count= 0;
912
913         for (iterv=first; iterv; iterv=iterv->next) {
914                 if (iterv->separate && iterv!=first)
915                         break;
916
917                 count++;
918         }
919         
920         if (count < 5)
921                 first->flag= 1;
922 }
923
924 static UvMapVert *uv_vertex_map_get(UvVertMap *vmap, BMFace *efa, int a)
925 {
926         UvMapVert *iterv, *first;
927         BMLoop *l;
928
929         l = BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, a);
930         first= EDBM_get_uv_map_vert(vmap,  BM_elem_index_get(l->v));
931
932         for (iterv=first; iterv; iterv=iterv->next) {
933                 if (iterv->separate)
934                         first= iterv;
935                 if (iterv->f == BM_elem_index_get(efa))
936                         return first;
937         }
938         
939         return NULL;
940 }
941
942 UvElement *ED_get_uv_element(UvElementMap *map, BMFace *efa, BMLoop *l)
943 {
944         UvElement *element;
945
946         element = map->vert[BM_elem_index_get(l->v)];
947
948         for (; element; element = element->next)
949                 if (element->face == efa)
950                         return element;
951
952         return NULL;
953 }
954
955 static int uv_edge_tag_faces(BMEditMesh *em, UvMapVert *first1, UvMapVert *first2, int *totface)
956 {
957         UvMapVert *iterv1, *iterv2;
958         BMFace *efa;
959         int tot = 0;
960
961         /* count number of faces this edge has */
962         for (iterv1=first1; iterv1; iterv1=iterv1->next) {
963                 if (iterv1->separate && iterv1 != first1)
964                         break;
965
966                 for (iterv2=first2; iterv2; iterv2=iterv2->next) {
967                         if (iterv2->separate && iterv2 != first2)
968                                 break;
969
970                         if (iterv1->f == iterv2->f) {
971                                 /* if face already tagged, don't do this edge */
972                                 efa= EDBM_get_face_for_index(em, iterv1->f);
973                                 if (BMO_elem_flag_test(em->bm, efa, EFA_F1_FLAG))
974                                         return 0;
975
976                                 tot++;
977                                 break;
978                         }
979                 }
980         }
981
982         if (*totface == 0) /* start edge */
983                 *totface= tot;
984         else if (tot != *totface) /* check for same number of faces as start edge */
985                 return 0;
986
987         /* tag the faces */
988         for (iterv1=first1; iterv1; iterv1=iterv1->next) {
989                 if (iterv1->separate && iterv1 != first1)
990                         break;
991
992                 for (iterv2=first2; iterv2; iterv2=iterv2->next) {
993                         if (iterv2->separate && iterv2 != first2)
994                                 break;
995
996                         if (iterv1->f == iterv2->f) {
997                                 efa= EDBM_get_face_for_index(em, iterv1->f);
998                                 BMO_elem_flag_enable(em->bm, efa, EFA_F1_FLAG);
999                                 break;
1000                         }
1001                 }
1002         }
1003
1004         return 1;
1005 }
1006
1007 static int select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestHit *hit, float limit[2], int extend)
1008 {
1009         BMFace *efa;
1010         BMIter iter, liter;
1011         BMLoop *l;
1012         MTexPoly *tf;
1013         UvVertMap *vmap;
1014         UvMapVert *iterv1, *iterv2;
1015         int a, count, looking, nverts, starttotf, select;
1016
1017         /* setup */
1018         EDBM_init_index_arrays(em, 0, 0, 1);
1019         vmap= EDBM_make_uv_vert_map(em, 0, 0, limit);
1020
1021         BM_mesh_elem_index_ensure(em->bm, BM_VERT);
1022
1023         count = 0;
1024         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1025                 if (!extend) {
1026                         uvedit_face_deselect(scene, em, efa);
1027                 }
1028                 
1029                 BMO_elem_flag_disable(em->bm, efa, EFA_F1_FLAG);
1030
1031                 BM_elem_index_set(efa, count); /* set_inline */
1032
1033                 count++;
1034         }
1035         em->bm->elem_index_dirty &= ~BM_FACE;
1036
1037         /* set flags for first face and verts */
1038         nverts= hit->efa->len;
1039         iterv1= uv_vertex_map_get(vmap, hit->efa, hit->lindex);
1040         iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->lindex+1)%nverts);
1041         uv_vertex_loop_flag(iterv1);
1042         uv_vertex_loop_flag(iterv2);
1043
1044         starttotf= 0;
1045         uv_edge_tag_faces(em, iterv1, iterv2, &starttotf);
1046
1047         /* sorry, first edge isn't even ok */
1048         if (iterv1->flag==0 && iterv2->flag==0) looking= 0;
1049         else looking= 1;
1050
1051         /* iterate */
1052         while(looking) {
1053                 looking= 0;
1054
1055                 /* find correct valence edges which are not tagged yet, but connect to tagged one */
1056
1057                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1058                         tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1059
1060                         if (!BMO_elem_flag_test(em->bm, efa, EFA_F1_FLAG) && uvedit_face_visible(scene, ima, efa, tf)) {
1061                                 nverts= efa->len;
1062                                 for (a=0; a<nverts; a++) {
1063                                         /* check face not hidden and not tagged */
1064                                         iterv1= uv_vertex_map_get(vmap, efa, a);
1065                                         iterv2= uv_vertex_map_get(vmap, efa, (a+1)%nverts);
1066                                         
1067                                         if (!iterv1 || !iterv2)
1068                                                 continue;
1069
1070                                         /* check if vertex is tagged and has right valence */
1071                                         if (iterv1->flag || iterv2->flag) {
1072                                                 if (uv_edge_tag_faces(em, iterv1, iterv2, &starttotf)) {
1073                                                         looking= 1;
1074                                                         BMO_elem_flag_enable(em->bm, efa, EFA_F1_FLAG);
1075
1076                                                         uv_vertex_loop_flag(iterv1);
1077                                                         uv_vertex_loop_flag(iterv2);
1078                                                         break;
1079                                                 }
1080                                         }
1081                                 }
1082                         }
1083                 }
1084         }
1085
1086         /* do the actual select/deselect */
1087         nverts= hit->efa->len;
1088         iterv1= uv_vertex_map_get(vmap, hit->efa, hit->lindex);
1089         iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->lindex+1)%nverts);
1090         iterv1->flag= 1;
1091         iterv2->flag= 1;
1092
1093         if (extend) {
1094                 if (uvedit_uv_selected(em, scene, hit->l))
1095                         select= 0;
1096                 else
1097                         select= 1;
1098         }
1099         else
1100                 select= 1;
1101         
1102         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1103                 a = 0;
1104                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1105                         iterv1= uv_vertex_map_get(vmap, efa, a);
1106
1107                         if (iterv1->flag) {
1108                                 if (select) uvedit_uv_select(em, scene, l);
1109                                 else uvedit_uv_deselect(em, scene, l);
1110                         }
1111
1112                         a++;
1113                 }
1114         }
1115
1116         /* cleanup */
1117         EDBM_free_uv_vert_map(vmap);
1118         EDBM_free_index_arrays(em);
1119
1120         return (select)? 1: -1;
1121 }
1122
1123 /*********************** linked select ***********************/
1124
1125 static void select_linked(Scene *scene, Image *ima, BMEditMesh *em, float limit[2], NearestHit *hit, int extend)
1126 {
1127         BMFace *efa;
1128         BMLoop *l;
1129         BMIter iter, liter;
1130         MTexPoly *tf;
1131         MLoopUV *luv;
1132         UvVertMap *vmap;
1133         UvMapVert *vlist, *iterv, *startv;
1134         int i, stacksize= 0, *stack;
1135         unsigned int a;
1136         char *flag;
1137
1138         EDBM_init_index_arrays(em, 0, 0, 1); /* we can use this too */
1139         vmap= EDBM_make_uv_vert_map(em, 1, 1, limit);
1140
1141         if (vmap == NULL)
1142                 return;
1143
1144         stack= MEM_mallocN(sizeof(*stack)*(em->bm->totface+1), "UvLinkStack");
1145         flag= MEM_callocN(sizeof(*flag)*em->bm->totface, "UvLinkFlag");
1146
1147         if (!hit) {
1148                 BM_ITER_INDEX(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL, a) {
1149                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1150
1151                         if (uvedit_face_visible(scene, ima, efa, tf)) {
1152                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1153                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1154
1155                                         if (luv->flag & MLOOPUV_VERTSEL) {
1156                                                 stack[stacksize]= a;
1157                                                 stacksize++;
1158                                                 flag[a]= 1;
1159
1160                                                 break;
1161                                         }
1162                                 }
1163                         }
1164                 }
1165         }
1166         else {
1167                 a = 0;
1168                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1169                         if (efa == hit->efa) {
1170                                 stack[stacksize]= a;
1171                                 stacksize++;
1172                                 flag[a]= 1;
1173                                 break;
1174                         }
1175
1176                         a++;
1177                 }
1178         }
1179
1180         while(stacksize > 0) {
1181                 int j;
1182
1183                 stacksize--;
1184                 a= stack[stacksize];
1185                 
1186                 j = 0;
1187                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1188                         if (j==a)
1189                                 break;
1190
1191                         j++;
1192                 }
1193
1194                 i = 0;
1195                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1196
1197                         /* make_uv_vert_map_EM sets verts tmp.l to the indices */
1198                         vlist= EDBM_get_uv_map_vert(vmap, BM_elem_index_get(l->v));
1199                         
1200                         startv= vlist;
1201
1202                         for (iterv=vlist; iterv; iterv=iterv->next) {
1203                                 if (iterv->separate)
1204                                         startv= iterv;
1205                                 if (iterv->f == a)
1206                                         break;
1207                         }
1208
1209                         for (iterv=startv; iterv; iterv=iterv->next) {
1210                                 if ((startv != iterv) && (iterv->separate))
1211                                         break;
1212                                 else if (!flag[iterv->f]) {
1213                                         flag[iterv->f]= 1;
1214                                         stack[stacksize]= iterv->f;
1215                                         stacksize++;
1216                                 }
1217                         }
1218
1219                         i++;
1220                 }
1221         }
1222
1223         if (!extend) {
1224                 a = 0;
1225                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1226                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1227                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1228                                 
1229                                 if (flag[a])
1230                                         luv->flag |= MLOOPUV_VERTSEL;
1231                                 else
1232                                         luv->flag &= ~MLOOPUV_VERTSEL;
1233                         }
1234                         a++;
1235                 }
1236         }
1237         else {
1238                 a = 0;
1239                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1240                         if (!flag[a]) {
1241                                 a++;
1242                                 continue;
1243                         }
1244                         
1245                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1246                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1247                                                 
1248                                 if (luv->flag & MLOOPUV_VERTSEL)
1249                                         break;
1250                         }
1251                         
1252                         if (l)
1253                                 break;
1254                         
1255                         a++;
1256                 }
1257
1258                 if (efa) {
1259                         a = 0;
1260                         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1261                                 if (!flag[a]) {
1262                                         a++;
1263                                         continue;
1264                                 }
1265
1266                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1267                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1268                                         
1269                                         luv->flag &= ~MLOOPUV_VERTSEL;
1270                                 }
1271
1272                                 a++;
1273                         }
1274                 }
1275                 else {
1276                         a = 0;
1277                         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1278                                 if (!flag[a]) {
1279                                         a++;
1280                                         continue;
1281                                 }
1282
1283                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1284                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1285                                         
1286                                         luv->flag |= MLOOPUV_VERTSEL;
1287                                 }
1288
1289                                 a++;
1290                         }
1291                 }
1292         }
1293         
1294         MEM_freeN(stack);
1295         MEM_freeN(flag);
1296         EDBM_free_uv_vert_map(vmap);
1297         EDBM_free_index_arrays(em);
1298 }
1299
1300 /* WATCH IT: this returns first selected UV,
1301  * not ideal in many cases since there could be multiple */
1302 static float *uv_sel_co_from_eve(Scene *scene, Image *ima, BMEditMesh *em, BMVert *eve)
1303 {
1304         BMIter liter;
1305         BMLoop *l;
1306
1307         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_VERT, eve) {
1308                 MTexPoly *tf = CustomData_bmesh_get(&em->bm->pdata, l->f->head.data, CD_MTEXPOLY);
1309
1310                 if (!uvedit_face_visible(scene, ima, l->f, tf))
1311                         continue;
1312
1313                 if (uvedit_uv_selected(em, scene, l)) {
1314                         MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1315                         return luv->uv;
1316                 }
1317         }
1318
1319         return NULL;
1320 }
1321
1322 /* ******************** align operator **************** */
1323
1324 static void weld_align_uv(bContext *C, int tool)
1325 {
1326         SpaceImage *sima;
1327         Scene *scene;
1328         Object *obedit;
1329         Image *ima;
1330         BMEditMesh *em;
1331         BMIter iter, liter;
1332         MTexPoly *tf;
1333         MLoopUV *luv;
1334         float cent[2], min[2], max[2];
1335         
1336         scene = CTX_data_scene(C);
1337         obedit = CTX_data_edit_object(C);
1338         em = BMEdit_FromObject(obedit);
1339         ima = CTX_data_edit_image(C);
1340         sima = CTX_wm_space_image(C);
1341
1342         INIT_MINMAX2(min, max);
1343
1344         if (tool == 'a') {
1345                 BMFace *efa;
1346                 BMLoop *l;
1347
1348                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1349                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1350
1351                         if (!uvedit_face_visible(scene, ima, efa, tf))
1352                                 continue;
1353
1354                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1355                                 if (uvedit_uv_selected(em, scene, l)) {
1356                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1357                                         DO_MINMAX2(luv->uv, min, max);
1358                                 }
1359                         }
1360                 }
1361
1362                 tool= (max[0]-min[0] >= max[1]-min[1])? 'y': 'x';
1363         }
1364
1365         uvedit_center(scene, ima, obedit, cent, 0);
1366
1367         if (tool == 'x' || tool == 'w') {
1368                 BMFace *efa;
1369                 BMLoop *l;
1370
1371                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1372                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1373                         if (!uvedit_face_visible(scene, ima, efa, tf))
1374                                 continue;
1375
1376                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1377                                 if (uvedit_uv_selected(em, scene, l)) {
1378                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1379                                         luv->uv[0] = cent[0];
1380                                 }
1381
1382                         }
1383                 }
1384         }
1385
1386         if (tool == 'y' || tool == 'w') {
1387                 BMFace *efa;
1388                 BMLoop *l;
1389
1390                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1391                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1392                         if (!uvedit_face_visible(scene, ima, efa, tf))
1393                                 continue;
1394
1395                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1396                                 if (uvedit_uv_selected(em, scene, l)) {
1397                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1398                                         luv->uv[1] = cent[1];
1399                                 }
1400
1401                         }
1402                 }
1403         }
1404
1405         if (tool == 's' || tool == 't' || tool == 'u') {
1406                 BMEdge *eed;
1407                 BMLoop *l;
1408                 BMVert *eve;
1409                 BMVert *eve_start;
1410                 BMIter iter, liter, eiter;
1411
1412                 /* clear tag */
1413                 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
1414                         BM_elem_flag_disable(eve, BM_ELEM_TAG);
1415                 }
1416
1417                 /* tag verts with a selected UV */
1418                 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
1419                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_VERT, eve) {
1420                                 tf = CustomData_bmesh_get(&em->bm->pdata, l->f->head.data, CD_MTEXPOLY);
1421
1422                                 if (!uvedit_face_visible(scene, ima, l->f, tf))
1423                                         continue;
1424
1425                                 if (uvedit_uv_selected(em, scene, l)) {
1426                                         BM_elem_flag_enable(eve, BM_ELEM_TAG);
1427                                         break;
1428                                 }
1429                         }
1430                 }
1431
1432                 /* flush vertex tags to edges */
1433                 BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
1434                         BM_elem_flag_set(eed, BM_ELEM_TAG, (BM_elem_flag_test(eed->v1, BM_ELEM_TAG) &&
1435                                                             BM_elem_flag_test(eed->v2, BM_ELEM_TAG)));
1436                 }
1437
1438                 /* find a vertex with only one tagged edge */
1439                 eve_start = NULL;
1440                 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
1441                         int tot_eed_tag = 0;
1442                         BM_ITER(eed, &eiter, em->bm, BM_EDGES_OF_VERT, eve) {
1443                                 if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
1444                                         tot_eed_tag++;
1445                                 }
1446                         }
1447
1448                         if (tot_eed_tag == 1) {
1449                                 eve_start = eve;
1450                                 break;
1451                         }
1452                 }
1453
1454                 if (eve_start) {
1455                         BMVert **eve_line = NULL;
1456                         BMVert *eve_next = NULL;
1457                         BLI_array_declare(eve_line);
1458                         int i;
1459
1460                         eve = eve_start;
1461
1462                         /* walk over edges, building an array of verts in a line */
1463                         while (eve) {
1464                                 BLI_array_append(eve_line, eve);
1465                                 /* don't touch again */
1466                                 BM_elem_flag_disable(eve, BM_ELEM_TAG);
1467
1468                                 eve_next = NULL;
1469
1470                                 /* find next eve */
1471                                 BM_ITER(eed, &eiter, em->bm, BM_EDGES_OF_VERT, eve) {
1472                                         if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
1473                                                 BMVert *eve_other = BM_edge_other_vert(eed, eve);
1474                                                 if (BM_elem_flag_test(eve_other, BM_ELEM_TAG)) {
1475                                                         /* this is a tagged vert we didnt walk over yet, step onto it */
1476                                                         eve_next = eve_other;
1477                                                         break;
1478                                                 }
1479                                         }
1480                                 }
1481
1482                                 eve = eve_next;
1483                         }
1484
1485                         /* now we have all verts, make into a line */
1486                         if (BLI_array_count(eve_line) > 2) {
1487
1488                                 /* we know the returns from these must be valid */
1489                                 float *uv_start = uv_sel_co_from_eve(scene, ima, em, eve_line[0]);
1490                                 float *uv_end   = uv_sel_co_from_eve(scene, ima, em, eve_line[BLI_array_count(eve_line) - 1]);
1491
1492                                 if (tool == 't') {
1493                                         uv_start[0] = uv_end[0] = (uv_start[0] + uv_end[0]) * 0.5f;
1494                                 }
1495                                 else if (tool == 'u') {
1496                                         uv_start[1] = uv_end[1] = (uv_start[1] + uv_end[1]) * 0.5f;
1497                                 }
1498
1499                                 /* go over all verts except for endpoints */
1500                                 for (i = 0; i < BLI_array_count(eve_line); i++) {
1501                                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_VERT, eve_line[i]) {
1502                                                 tf = CustomData_bmesh_get(&em->bm->pdata, l->f->head.data, CD_MTEXPOLY);
1503
1504                                                 if (!uvedit_face_visible(scene, ima, l->f, tf))
1505                                                         continue;
1506
1507                                                 if (uvedit_uv_selected(em, scene, l)) {
1508                                                         MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1509                                                         closest_to_line_segment_v2(luv->uv, luv->uv, uv_start, uv_end);
1510                                                 }
1511                                         }
1512                                 }
1513                         }
1514                         else {
1515                                 /* error - not a line, needs 3+ points  */
1516                         }
1517
1518                         if (eve_line) {
1519                                 MEM_freeN(eve_line);
1520                         }
1521                 }
1522                 else {
1523                         /* error - cant find an endpoint */
1524                 }
1525         }
1526
1527
1528         uvedit_live_unwrap_update(sima, scene, obedit);
1529         DAG_id_tag_update(obedit->data, 0);
1530         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1531 }
1532
1533 static int align_exec(bContext *C, wmOperator *op)
1534 {
1535         weld_align_uv(C, RNA_enum_get(op->ptr, "axis"));
1536
1537         return OPERATOR_FINISHED;
1538 }
1539
1540 static void UV_OT_align(wmOperatorType *ot)
1541 {
1542         static EnumPropertyItem axis_items[] = {
1543                 {'s', "ALIGN_S", 0, "Straighten", "Align UVs along the line defined by the endpoints"},
1544                 {'t', "ALIGN_T", 0, "Straighten X", "Align UVs along the line defined by the endpoints along the X axis"},
1545                 {'u', "ALIGN_U", 0, "Straighten Y", "Align UVs along the line defined by the endpoints along the Y axis"},
1546                 {'a', "ALIGN_AUTO", 0, "Align Auto", "Automatically choose the axis on which there is most alignment already"},
1547                 {'x', "ALIGN_X", 0, "Align X", "Align UVs on X axis"},
1548                 {'y', "ALIGN_Y", 0, "Align Y", "Align UVs on Y axis"},
1549                 {0, NULL, 0, NULL, NULL}};
1550
1551         /* identifiers */
1552         ot->name = "Align";
1553         ot->description = "Align selected UV vertices to an axis";
1554         ot->idname = "UV_OT_align";
1555         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1556         
1557         /* api callbacks */
1558         ot->exec = align_exec;
1559         ot->poll = ED_operator_image_active;    /* requires space image */;
1560
1561         /* properties */
1562         RNA_def_enum(ot->srna, "axis", axis_items, 'a', "Axis", "Axis to align UV locations on");
1563 }
1564
1565 /* ******************** weld operator **************** */
1566
1567 static int weld_exec(bContext *C, wmOperator *UNUSED(op))
1568 {
1569         weld_align_uv(C, 'w');
1570
1571         return OPERATOR_FINISHED;
1572 }
1573
1574 static void UV_OT_weld(wmOperatorType *ot)
1575 {
1576         /* identifiers */
1577         ot->name = "Weld";
1578         ot->description = "Weld selected UV vertices together";
1579         ot->idname = "UV_OT_weld";
1580         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1581         
1582         /* api callbacks */
1583         ot->exec = weld_exec;
1584         ot->poll = ED_operator_uvedit;
1585 }
1586
1587
1588 /* ******************** (de)select all operator **************** */
1589
1590 static void select_all_perform(bContext *C, int action)
1591 {
1592         Scene *scene;
1593         ToolSettings *ts;
1594         Object *obedit;
1595         BMEditMesh *em;
1596         BMFace *efa;
1597         BMLoop *l;
1598         BMIter iter, liter;
1599         Image *ima;
1600         MTexPoly *tf;
1601         MLoopUV *luv;
1602         
1603         scene = CTX_data_scene(C);
1604         ts = CTX_data_tool_settings(C);
1605         obedit = CTX_data_edit_object(C);
1606         em = BMEdit_FromObject(obedit);
1607         ima = CTX_data_edit_image(C);
1608         
1609         if (ts->uv_flag & UV_SYNC_SELECTION) {
1610
1611                 switch (action) {
1612                 case SEL_TOGGLE:
1613                         EDBM_select_toggle_all(BMEdit_FromObject(obedit));
1614                         break;
1615                 case SEL_SELECT:
1616                         EDBM_flag_enable_all(em, BM_ELEM_SELECT);
1617                         break;
1618                 case SEL_DESELECT:
1619                         EDBM_flag_disable_all(em, BM_ELEM_SELECT);
1620                         break;
1621                 case SEL_INVERT:
1622                         EDBM_select_swap(em);
1623                         break;
1624                 }
1625         }
1626         else {
1627                 if (action == SEL_TOGGLE) {
1628                         action = SEL_SELECT;
1629                         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1630                                 tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1631         
1632                                 if (!uvedit_face_visible(scene, ima, efa, tf))
1633                                         continue;
1634
1635                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1636                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1637
1638                                         if (luv->flag & MLOOPUV_VERTSEL) {
1639                                                 action = SEL_DESELECT;
1640                                                 break;
1641                                         }
1642                                 }
1643                         }
1644                 }
1645         
1646                 
1647                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1648                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1649
1650                         if (!uvedit_face_visible(scene, ima, efa, tf))
1651                                 continue;
1652
1653                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1654                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1655
1656                                 switch (action) {
1657                                 case SEL_SELECT:
1658                                         luv->flag |= MLOOPUV_VERTSEL;
1659                                         break;
1660                                 case SEL_DESELECT:
1661                                         luv->flag &= ~MLOOPUV_VERTSEL;
1662                                         break;
1663                                 case SEL_INVERT:
1664                                         luv->flag ^= MLOOPUV_VERTSEL;
1665                                         break;
1666                                 }
1667                         }
1668                 }
1669         }
1670 }
1671
1672 static int select_all_exec(bContext *C, wmOperator *op)
1673 {
1674         Object *obedit= CTX_data_edit_object(C);
1675         int action= RNA_enum_get(op->ptr, "action");
1676
1677         select_all_perform(C, action);
1678
1679         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
1680
1681         return OPERATOR_FINISHED;
1682 }
1683
1684 static void UV_OT_select_all(wmOperatorType *ot)
1685 {
1686         /* identifiers */
1687         ot->name = "(De)select All";
1688         ot->description = "Change selection of all UV vertices";
1689         ot->idname = "UV_OT_select_all";
1690         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1691         
1692         /* api callbacks */
1693         ot->exec = select_all_exec;
1694         ot->poll = ED_operator_uvedit;
1695
1696         WM_operator_properties_select_all(ot);
1697 }
1698
1699 /* ******************** mouse select operator **************** */
1700
1701 static int sticky_select(float *limit, int hitv[4], int v, float *hituv[4], float *uv, int sticky, int hitlen)
1702 {
1703         int i;
1704
1705         /* this function test if some vertex needs to selected
1706          * in addition to the existing ones due to sticky select */
1707         if (sticky == SI_STICKY_DISABLE)
1708                 return 0;
1709
1710         for (i=0; i<hitlen; i++) {
1711                 if (hitv[i] == v) {
1712                         if (sticky == SI_STICKY_LOC) {
1713                                 if (fabsf(hituv[i][0]-uv[0]) < limit[0] && fabsf(hituv[i][1]-uv[1]) < limit[1])
1714                                         return 1;
1715                         }
1716                         else if (sticky == SI_STICKY_VERTEX)
1717                                 return 1;
1718                 }
1719         }
1720
1721         return 0;
1722 }
1723
1724 static int mouse_select(bContext *C, float co[2], int extend, int loop)
1725 {
1726         SpaceImage *sima = CTX_wm_space_image(C);
1727         Scene *scene = CTX_data_scene(C);
1728         ToolSettings *ts = CTX_data_tool_settings(C);
1729         Object *obedit = CTX_data_edit_object(C);
1730         Image *ima = CTX_data_edit_image(C);
1731         BMEditMesh *em = BMEdit_FromObject(obedit);
1732         BMFace *efa;
1733         BMLoop *l;
1734         BMIter iter, liter;
1735         MTexPoly *tf;
1736         MLoopUV *luv;
1737         NearestHit hit;
1738         int i, select = 1, selectmode, sticky, sync, *hitv=NULL, nvert;
1739         BLI_array_declare(hitv);
1740         int flush = 0, hitlen=0; /* 0 == don't flush, 1 == sel, -1 == desel;  only use when selection sync is enabled */
1741         float limit[2], **hituv = NULL;
1742         BLI_array_declare(hituv);
1743         float penalty[2];
1744
1745         /* notice 'limit' is the same no matter the zoom level, since this is like
1746          * remove doubles and could annoying if it joined points when zoomed out.
1747          * 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and
1748          * shift-selecting can consider an adjacent point close enough to add to
1749          * the selection rather than de-selecting the closest. */
1750
1751         uvedit_pixel_to_float(sima, limit, 0.05f);
1752         uvedit_pixel_to_float(sima, penalty, 5.0f / sima->zoom);
1753
1754         /* retrieve operation mode */
1755         if (ts->uv_flag & UV_SYNC_SELECTION) {
1756                 sync= 1;
1757
1758                 if (ts->selectmode & SCE_SELECT_FACE)
1759                         selectmode= UV_SELECT_FACE;
1760                 else if (ts->selectmode & SCE_SELECT_EDGE)
1761                         selectmode= UV_SELECT_EDGE;
1762                 else
1763                         selectmode= UV_SELECT_VERTEX;
1764
1765                 sticky= SI_STICKY_DISABLE;
1766         }
1767         else {
1768                 sync= 0;
1769                 selectmode= ts->uv_selectmode;
1770                 sticky= (sima)? sima->sticky: 1;
1771         }
1772
1773         /* find nearest element */
1774         if (loop) {
1775                 /* find edge */
1776                 uv_find_nearest_edge(scene, ima, em, co, &hit);
1777                 if (hit.efa == NULL) {
1778                         BLI_array_free(hitv);
1779                         BLI_array_free(hituv);
1780                         return OPERATOR_CANCELLED;
1781                 }
1782
1783                 hitlen = 0;
1784         }
1785         else if (selectmode == UV_SELECT_VERTEX) {
1786                 /* find vertex */
1787                 uv_find_nearest_vert(scene, ima, em, co, penalty, &hit);
1788                 if (hit.efa == NULL) {
1789                         BLI_array_free(hitv);
1790                         BLI_array_free(hituv);
1791                         return OPERATOR_CANCELLED;
1792                 }
1793
1794                 /* mark 1 vertex as being hit */
1795                 BLI_array_growitems(hitv, hit.efa->len);
1796                 BLI_array_growitems(hituv, hit.efa->len);
1797                 for (i=0; i<hit.efa->len; i++) {
1798                         hitv[i]= 0xFFFFFFFF;
1799                 }
1800
1801                 hitv[hit.lindex]= hit.vert1;
1802                 hituv[hit.lindex]= hit.luv->uv;
1803
1804                 hitlen = hit.efa->len;
1805         }
1806         else if (selectmode == UV_SELECT_EDGE) {
1807                 /* find edge */
1808                 uv_find_nearest_edge(scene, ima, em, co, &hit);
1809                 if (hit.efa == NULL) {
1810                         BLI_array_free(hitv);
1811                         BLI_array_free(hituv);
1812                         return OPERATOR_CANCELLED;
1813                 }
1814
1815                 /* mark 2 edge vertices as being hit */
1816                 BLI_array_growitems(hitv,  hit.efa->len);
1817                 BLI_array_growitems(hituv, hit.efa->len);
1818                 for (i=0; i < hit.efa->len; i++) {
1819                         hitv[i]= 0xFFFFFFFF;
1820                 }
1821
1822                 nvert= hit.efa->len;
1823
1824                 hitv[hit.lindex]= hit.vert1;
1825                 hitv[(hit.lindex+1)%nvert]= hit.vert2;
1826                 hituv[hit.lindex]= hit.luv->uv;
1827                 hituv[(hit.lindex+1)%nvert]= hit.nextluv->uv;
1828
1829                 hitlen = hit.efa->len;
1830         }
1831         else if (selectmode == UV_SELECT_FACE) {
1832                 /* find face */
1833                 find_nearest_uv_face(scene, ima, em, co, &hit);
1834                 if (hit.efa == NULL) {
1835                         BLI_array_free(hitv);
1836                         BLI_array_free(hituv);
1837                         return OPERATOR_CANCELLED;
1838                 }
1839                 
1840                 /* make active */
1841                 BM_active_face_set(em->bm, hit.efa);
1842
1843                 /* mark all face vertices as being hit */
1844
1845                 BLI_array_growitems(hitv,  hit.efa->len);
1846                 BLI_array_growitems(hituv, hit.efa->len);
1847                 i = 0;
1848                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, hit.efa) {
1849                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1850                         hituv[i]= luv->uv;
1851                         hitv[i] = BM_elem_index_get(l->v);
1852                         i++;
1853                 }
1854                 
1855                 hitlen = hit.efa->len;
1856         }
1857         else if (selectmode == UV_SELECT_ISLAND) {
1858                 uv_find_nearest_vert(scene, ima, em, co, NULL, &hit);
1859
1860                 if (hit.efa==NULL) {
1861                         BLI_array_free(hitv);
1862                         BLI_array_free(hituv);
1863                         return OPERATOR_CANCELLED;
1864                 }
1865
1866                 hitlen = 0;
1867         }
1868         else {
1869                 hitlen = 0;
1870                 BLI_array_free(hitv);
1871                 BLI_array_free(hituv);
1872                 return OPERATOR_CANCELLED;
1873         }
1874
1875         /* do selection */
1876         if (loop) {
1877                 flush= select_edgeloop(scene, ima, em, &hit, limit, extend);
1878         }
1879         else if (selectmode == UV_SELECT_ISLAND) {
1880                 select_linked(scene, ima, em, limit, &hit, extend);
1881         }
1882         else if (extend) {
1883                 if (selectmode == UV_SELECT_VERTEX) {
1884                         /* (de)select uv vertex */
1885                         if (uvedit_uv_selected(em, scene, hit.l)) {
1886                                 uvedit_uv_deselect(em, scene, hit.l);
1887                                 select= 0;
1888                         }
1889                         else {
1890                                 uvedit_uv_select(em, scene, hit.l);
1891                                 select= 1;
1892                         }
1893                         flush = 1;
1894                 }
1895                 else if (selectmode == UV_SELECT_EDGE) {
1896                         /* (de)select edge */
1897                         if (uvedit_edge_selected(em, scene, hit.l)) {
1898                                 uvedit_edge_deselect(em, scene, hit.l);
1899                                 select= 0;
1900                         }
1901                         else {
1902                                 uvedit_edge_select(em, scene, hit.l);
1903                                 select= 1;
1904                         }
1905                         flush = 1;
1906                 }
1907                 else if (selectmode == UV_SELECT_FACE) {
1908                         /* (de)select face */
1909                         if (uvedit_face_selected(scene, em, hit.efa)) {
1910                                 uvedit_face_deselect(scene, em, hit.efa);
1911                                 select= 0;
1912                         }
1913                         else {
1914                                 uvedit_face_select(scene, em, hit.efa);
1915                                 select= 1;
1916                         }
1917                         flush = -1;
1918                 }
1919
1920                 /* (de)select sticky uv nodes */
1921                 if (sticky != SI_STICKY_DISABLE) {
1922
1923                         BM_mesh_elem_index_ensure(em->bm, BM_VERT);
1924
1925                         /* deselect */
1926                         if (select==0) {
1927                                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1928                                         tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1929                                         if (!uvedit_face_visible(scene, ima, efa, tf))
1930                                                 continue;
1931
1932                                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1933                                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1934                                                 if (sticky_select(limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen))
1935                                                         uvedit_uv_deselect(em, scene, l);
1936                                         }
1937                                 }
1938                                 flush = -1;
1939                         }
1940                         /* select */
1941                         else {
1942                                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1943                                         tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1944                                         if (!uvedit_face_visible(scene, ima, efa, tf))
1945                                                 continue;
1946
1947                                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1948                                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1949                                                 if (sticky_select(limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen))
1950                                                         uvedit_uv_select(em, scene, l);
1951                                         }
1952                                 }
1953
1954                                 flush = 1;
1955                         }                       
1956                 }
1957         }
1958         else {
1959                 /* deselect all */
1960                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1961                         uvedit_face_deselect(scene, em, efa);
1962                 }
1963
1964                 if (selectmode == UV_SELECT_VERTEX) {
1965                         /* select vertex */
1966                         uvedit_uv_select(em, scene, hit.l);
1967                         flush= 1;
1968                 }
1969                 else if (selectmode == UV_SELECT_EDGE) {
1970                         /* select edge */
1971                         uvedit_edge_select(em, scene, hit.l);
1972                         flush= 1;
1973                 }
1974                 else if (selectmode == UV_SELECT_FACE) {
1975                         /* select face */
1976                         uvedit_face_select(scene, em, hit.efa);
1977                 }
1978
1979                 /* select sticky uvs */
1980                 if (sticky != SI_STICKY_DISABLE) {
1981                         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1982                                 tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1983                                 if (!uvedit_face_visible(scene, ima, efa, tf))
1984                                         continue;
1985                                 
1986                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1987                                         if (sticky == SI_STICKY_DISABLE) continue;
1988                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1989
1990                                         if (sticky_select(limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen))
1991                                                 uvedit_uv_select(em, scene, l);
1992
1993                                         flush= 1;
1994                                 }
1995                         }
1996                 }
1997         }
1998
1999 #if 0   /* BM_elem_select_set API handles all of this? */
2000
2001         if (sync) {
2002                 /* flush for mesh selection */
2003                 if (ts->selectmode != SCE_SELECT_FACE) {
2004                         if (flush==1)           EDBM_select_flush(em);
2005                         else if (flush==-1)     EDBM_deselect_flush(em);
2006                 }
2007         }
2008 #else
2009         (void)flush; /* flush is otherwise UNUSED */
2010         (void)sync; /* sync is otherwise UNUSED */
2011 #endif
2012
2013         DAG_id_tag_update(obedit->data, 0);
2014         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2015
2016         BLI_array_free(hitv);
2017         BLI_array_free(hituv);
2018
2019         return OPERATOR_PASS_THROUGH|OPERATOR_FINISHED;
2020 }
2021
2022 static int select_exec(bContext *C, wmOperator *op)
2023 {
2024         float co[2];
2025         int extend, loop;
2026
2027         RNA_float_get_array(op->ptr, "location", co);
2028         extend= RNA_boolean_get(op->ptr, "extend");
2029         loop= 0;
2030
2031         return mouse_select(C, co, extend, loop);
2032 }
2033
2034 static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
2035 {
2036         ARegion *ar= CTX_wm_region(C);
2037         float co[2];
2038
2039         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
2040         RNA_float_set_array(op->ptr, "location", co);
2041
2042         return select_exec(C, op);
2043 }
2044
2045 static void UV_OT_select(wmOperatorType *ot)
2046 {
2047         /* identifiers */
2048         ot->name = "Select";
2049         ot->description = "Select UV vertices";
2050         ot->idname = "UV_OT_select";
2051         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2052         
2053         /* api callbacks */
2054         ot->exec = select_exec;
2055         ot->invoke = select_invoke;
2056         ot->poll = ED_operator_image_active;    /* requires space image */;
2057
2058         /* properties */
2059         RNA_def_boolean(ot->srna, "extend", 0,
2060                 "Extend", "Extend selection rather than clearing the existing selection");
2061         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
2062                 "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
2063 }
2064
2065 /* ******************** loop select operator **************** */
2066
2067 static int select_loop_exec(bContext *C, wmOperator *op)
2068 {
2069         float co[2];
2070         int extend, loop;
2071
2072         RNA_float_get_array(op->ptr, "location", co);
2073         extend= RNA_boolean_get(op->ptr, "extend");
2074         loop= 1;
2075
2076         return mouse_select(C, co, extend, loop);
2077 }
2078
2079 static int select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
2080 {
2081         ARegion *ar= CTX_wm_region(C);
2082         float co[2];
2083
2084         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
2085         RNA_float_set_array(op->ptr, "location", co);
2086
2087         return select_loop_exec(C, op);
2088 }
2089
2090 static void UV_OT_select_loop(wmOperatorType *ot)
2091 {
2092         /* identifiers */
2093         ot->name = "Loop Select";
2094         ot->description = "Select a loop of connected UV vertices";
2095         ot->idname = "UV_OT_select_loop";
2096         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2097         
2098         /* api callbacks */
2099         ot->exec = select_loop_exec;
2100         ot->invoke = select_loop_invoke;
2101         ot->poll = ED_operator_image_active;    /* requires space image */;
2102
2103         /* properties */
2104         RNA_def_boolean(ot->srna, "extend", 0,
2105                 "Extend", "Extend selection rather than clearing the existing selection");
2106         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
2107                 "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
2108 }
2109
2110 /* ******************** linked select operator **************** */
2111
2112 static int select_linked_internal(bContext *C, wmOperator *op, wmEvent *event, int pick)
2113 {
2114         SpaceImage *sima = CTX_wm_space_image(C);
2115         Scene *scene = CTX_data_scene(C);
2116         ToolSettings *ts = CTX_data_tool_settings(C);
2117         Object *obedit = CTX_data_edit_object(C);
2118         Image *ima = CTX_data_edit_image(C);
2119         BMEditMesh *em = BMEdit_FromObject(obedit);
2120         float limit[2];
2121         int extend;
2122
2123         NearestHit hit, *hit_p= NULL;
2124
2125         if (ts->uv_flag & UV_SYNC_SELECTION) {
2126                 BKE_report(op->reports, RPT_ERROR, "Can't select linked when sync selection is enabled");
2127                 return OPERATOR_CANCELLED;
2128         }
2129
2130         extend= RNA_boolean_get(op->ptr, "extend");
2131         uvedit_pixel_to_float(sima, limit, 0.05f);
2132
2133         if (pick) {
2134                 float co[2];
2135
2136                 if (event) {
2137                         /* invoke */
2138                         ARegion *ar= CTX_wm_region(C);
2139
2140                         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
2141                         RNA_float_set_array(op->ptr, "location", co);
2142                 }
2143                 else {
2144                         /* exec */
2145                         RNA_float_get_array(op->ptr, "location", co);
2146                 }
2147
2148                 uv_find_nearest_vert(scene, ima, em, co, NULL, &hit);
2149                 hit_p= &hit;
2150         }
2151
2152         select_linked(scene, ima, em, limit, hit_p, extend);
2153
2154         DAG_id_tag_update(obedit->data, 0);
2155         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2156
2157         return OPERATOR_FINISHED;
2158 }
2159
2160 static int select_linked_exec(bContext *C, wmOperator *op)
2161 {
2162         return select_linked_internal(C, op, NULL, 0);
2163 }
2164
2165 static void UV_OT_select_linked(wmOperatorType *ot)
2166 {
2167         /* identifiers */
2168         ot->name = "Select Linked";
2169         ot->description = "Select all UV vertices linked to the active UV map";
2170         ot->idname = "UV_OT_select_linked";
2171         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2172         
2173         /* api callbacks */
2174         ot->exec = select_linked_exec;
2175         ot->poll = ED_operator_image_active;    /* requires space image */
2176
2177         /* properties */
2178         RNA_def_boolean(ot->srna, "extend", 0,
2179                 "Extend", "Extend selection rather than clearing the existing selection");
2180 }
2181
2182 static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
2183 {
2184         return select_linked_internal(C, op, event, 1);
2185 }
2186
2187 static int select_linked_pick_exec(bContext *C, wmOperator *op)
2188 {
2189         return select_linked_internal(C, op, NULL, 1);
2190 }
2191
2192 static void UV_OT_select_linked_pick(wmOperatorType *ot)
2193 {
2194         /* identifiers */
2195         ot->name = "Select Linked Pick";
2196         ot->description = "Select all UV vertices linked under the mouse";
2197         ot->idname = "UV_OT_select_linked_pick";
2198         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2199
2200         /* api callbacks */
2201         ot->invoke = select_linked_pick_invoke;
2202         ot->exec = select_linked_pick_exec;
2203         ot->poll = ED_operator_image_active;    /* requires space image */;
2204
2205         /* properties */
2206         RNA_def_boolean(ot->srna, "extend", 0,
2207                 "Extend", "Extend selection rather than clearing the existing selection");
2208
2209         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
2210                 "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
2211 }
2212
2213 /* ******************** unlink selection operator **************** */
2214
2215 static int unlink_selection_exec(bContext *C, wmOperator *op)
2216 {
2217         Scene *scene = CTX_data_scene(C);
2218         ToolSettings *ts = CTX_data_tool_settings(C);
2219         Object *obedit = CTX_data_edit_object(C);
2220         Image *ima = CTX_data_edit_image(C);
2221         BMEditMesh *em = BMEdit_FromObject(obedit);
2222         BMFace *efa;
2223         BMLoop *l;
2224         BMIter iter, liter;
2225         MTexPoly *tf;
2226         MLoopUV *luv;
2227
2228         if (ts->uv_flag & UV_SYNC_SELECTION) {
2229                 BKE_report(op->reports, RPT_ERROR, "Can't unlink selection when sync selection is enabled");
2230                 return OPERATOR_CANCELLED;
2231         }
2232         
2233         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2234                 int desel = 0;
2235
2236                 tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2237                 if (!uvedit_face_visible(scene, ima, efa, tf))
2238                         continue;
2239
2240                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2241                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2242                         
2243                         if (!(luv->flag & MLOOPUV_VERTSEL)) {
2244                                 desel = 1;
2245                                 break;
2246                         }
2247                 }
2248
2249                 if (desel) {
2250                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2251                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2252                                 luv->flag &= ~MLOOPUV_VERTSEL;
2253                         }
2254                 }
2255         }
2256         
2257         DAG_id_tag_update(obedit->data, 0);
2258         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2259
2260         return OPERATOR_FINISHED;
2261 }
2262
2263 static void UV_OT_unlink_selected(wmOperatorType *ot)
2264 {
2265         /* identifiers */
2266         ot->name = "Unlink Selection";
2267         ot->description = "Unlink selected UV vertices from active UV map";
2268         ot->idname = "UV_OT_unlink_selected";
2269         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2270         
2271         /* api callbacks */
2272         ot->exec = unlink_selection_exec;
2273         ot->poll = ED_operator_uvedit;
2274 }
2275
2276 /* ******************** border select operator **************** */
2277
2278 /* This function sets the selection on tagged faces, need because settings the
2279  * selection a face is done in a number of places but it also needs to respect
2280  * the sticky modes for the UV verts, so dealing with the sticky modes is best
2281  * done in a separate function.
2282  * 
2283  * De-selects faces that have been tagged on efa->tmp.l.  */
2284
2285 static void uv_faces_do_sticky(bContext *C, SpaceImage *sima, Scene *scene, Object *obedit, short select)
2286 {
2287         /* Selecting UV Faces with some modes requires us to change 
2288          * the selection in other faces (depending on the sticky mode).
2289          * 
2290          * This only needs to be done when the Mesh is not used for
2291          * selection (so for sticky modes, vertex or location based). */
2292         
2293         ToolSettings *ts = CTX_data_tool_settings(C);
2294         BMEditMesh *em = BMEdit_FromObject(obedit);
2295         BMFace *efa;
2296         BMLoop *l;
2297         BMIter iter, liter;
2298         /* MTexPoly *tf; */
2299         
2300         if ((ts->uv_flag & UV_SYNC_SELECTION)==0 && sima->sticky == SI_STICKY_VERTEX) {
2301                 /* Tag all verts as untouched, then touch the ones that have a face center
2302                  * in the loop and select all MLoopUV's that use a touched vert. */
2303                 BMVert *eve;
2304                 
2305                 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
2306                         BM_elem_flag_disable(eve, BM_ELEM_TAG);
2307                 }
2308                 
2309                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2310                         if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
2311                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2312                                         BM_elem_flag_enable(l->v, BM_ELEM_TAG);
2313                                 }
2314                         }
2315                 }
2316
2317                 /* now select tagged verts */
2318                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2319                         /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
2320
2321                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2322                                 if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
2323                                         if (select)
2324                                                 uvedit_uv_select(em, scene, l);
2325                                         else
2326                                                 uvedit_uv_deselect(em, scene, l);
2327                                 }
2328                         }
2329                 }
2330         }
2331         else if ((ts->uv_flag & UV_SYNC_SELECTION)==0 && sima->sticky == SI_STICKY_LOC) {
2332                 BMFace *efa_vlist;
2333                 /* MTexPoly *tf_vlist; */ /* UNUSED */
2334                 UvMapVert *start_vlist=NULL, *vlist_iter;
2335                 struct UvVertMap *vmap;
2336                 float limit[2];
2337                 unsigned int efa_index;
2338                 //BMVert *eve; /* removed vert counting for now */ 
2339                 //int a;
2340                 
2341                 uvedit_pixel_to_float(sima, limit, 0.05);
2342                 
2343                 EDBM_init_index_arrays(em, 0, 0, 1);
2344                 vmap= EDBM_make_uv_vert_map(em, 0, 0, limit);
2345                 
2346                 /* verts are numbered above in make_uv_vert_map_EM, make sure this stays true! */
2347                 /* BMESH_TODO - why keep this commented? - campbell */
2348 #if 0
2349                 for (a=0, eve= em->verts.first; eve; a++, eve= eve->next)
2350                         eve->tmp.l = a;
2351 #endif
2352                 if (vmap == NULL) {
2353                         return;
2354                 }
2355                 
2356                 efa = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL);
2357                 for (efa_index=0; efa; efa=BM_iter_step(&iter), efa_index++) {
2358                         if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
2359                                 /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
2360                                 
2361                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2362                                         if (select)
2363                                                 uvedit_uv_select(em, scene, l);
2364                                         else
2365                                                 uvedit_uv_deselect(em, scene, l);
2366                                         
2367                                         vlist_iter= EDBM_get_uv_map_vert(vmap, BM_elem_index_get(l->v));
2368                                         
2369                                         while (vlist_iter) {
2370                                                 if (vlist_iter->separate)
2371                                                         start_vlist = vlist_iter;
2372                                                 
2373                                                 if (efa_index == vlist_iter->f)
2374                                                         break;
2375
2376                                                 vlist_iter = vlist_iter->next;
2377                                         }
2378                                 
2379                                         vlist_iter = start_vlist;
2380                                         while (vlist_iter) {
2381                                                 
2382                                                 if (vlist_iter != start_vlist && vlist_iter->separate)
2383                                                         break;
2384                                                 
2385                                                 if (efa_index != vlist_iter->f) {
2386                                                         efa_vlist = EDBM_get_face_for_index(em, vlist_iter->f);
2387                                                         /* tf_vlist = CustomData_bmesh_get(&em->bm->pdata, efa_vlist->head.data, CD_MTEXPOLY); */ /* UNUSED */
2388                                                         
2389                                                         if (select)
2390                                                                 uvedit_uv_select(em, scene, BM_iter_at_index(em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->tfindex));
2391                                                         else
2392                                                                 uvedit_uv_deselect(em, scene, BM_iter_at_index(em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->tfindex));
2393                                                 }
2394                                                 vlist_iter = vlist_iter->next;
2395                                         }
2396                                 }
2397                         }
2398                 }
2399                 EDBM_free_index_arrays(em);
2400                 EDBM_free_uv_vert_map(vmap);
2401                 
2402         }
2403         else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
2404                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2405                         if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
2406                                 if (select)
2407                                         uvedit_face_select(scene, em, efa);
2408                                 else
2409                                         uvedit_face_deselect(scene, em, efa);
2410                         }
2411                 }
2412         }
2413 }
2414
2415 static int border_select_exec(bContext *C, wmOperator *op)
2416 {
2417         SpaceImage *sima = CTX_wm_space_image(C);
2418         Scene *scene = CTX_data_scene(C);
2419         ToolSettings *ts = CTX_data_tool_settings(C);
2420         Object *obedit = CTX_data_edit_object(C);
2421         Image *ima = CTX_data_edit_image(C);
2422         ARegion *ar = CTX_wm_region(C);
2423         BMEditMesh *em = BMEdit_FromObject(obedit);
2424         BMFace *efa;
2425         BMLoop *l;
2426         BMIter iter, liter;
2427         MTexPoly *tf;
2428         MLoopUV *luv;
2429         rcti rect;
2430         rctf rectf;
2431         int change, pinned, select, faces, extend;
2432
2433         /* get rectangle from operator */
2434         rect.xmin = RNA_int_get(op->ptr, "xmin");
2435         rect.ymin = RNA_int_get(op->ptr, "ymin");
2436         rect.xmax = RNA_int_get(op->ptr, "xmax");
2437         rect.ymax = RNA_int_get(op->ptr, "ymax");
2438                 
2439         UI_view2d_region_to_view(&ar->v2d, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
2440         UI_view2d_region_to_view(&ar->v2d, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
2441
2442         /* figure out what to select/deselect */
2443         select= (RNA_int_get(op->ptr, "gesture_mode") == GESTURE_MODAL_SELECT);
2444         pinned= RNA_boolean_get(op->ptr, "pinned");
2445         extend= RNA_boolean_get(op->ptr, "extend");
2446
2447         if (!extend)
2448                 select_all_perform(C, SEL_DESELECT);
2449         
2450         if (ts->uv_flag & UV_SYNC_SELECTION)
2451                 faces= (ts->selectmode == SCE_SELECT_FACE);
2452         else
2453                 faces= (ts->uv_selectmode == UV_SELECT_FACE);
2454
2455         /* do actual selection */
2456         if (faces && !pinned) {
2457                 /* handle face selection mode */
2458                 float cent[2];
2459
2460                 change= 0;
2461
2462                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2463                         /* assume not touched */
2464                         BM_elem_flag_disable(efa, BM_ELEM_TAG);
2465
2466                         tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2467                         if (uvedit_face_visible(scene, ima, efa, tf)) {
2468                                 poly_uv_center(em, efa, cent);
2469                                 if (BLI_in_rctf(&rectf, cent[0], cent[1])) {
2470                                         BM_elem_flag_enable(efa, BM_ELEM_TAG);
2471                                         change = 1;
2472                                 }
2473                         }
2474                 }
2475
2476                 /* (de)selects all tagged faces and deals with sticky modes */
2477                 if (change)
2478                         uv_faces_do_sticky(C, sima, scene, obedit, select);
2479         }
2480         else {
2481                 /* other selection modes */
2482                 change= 1;
2483                 
2484                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2485                         tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2486                         if (!uvedit_face_visible(scene, ima, efa, tf))
2487                                 continue;
2488                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2489                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2490
2491                                 if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION) ) {
2492
2493                                         /* UV_SYNC_SELECTION - can't do pinned selection */
2494                                         if (BLI_in_rctf(&rectf, luv->uv[0], luv->uv[1])) {
2495                                                 if (select)     uvedit_uv_select(em, scene, l);
2496                                                 else            uvedit_uv_deselect(em, scene, l);
2497                                         }
2498                                 }
2499                                 else if (pinned) {
2500                                         if ((luv->flag & MLOOPUV_PINNED) && 
2501                                             BLI_in_rctf(&rectf, luv->uv[0], luv->uv[1])) {
2502                                                 if (select)     uvedit_uv_select(em, scene, l);
2503                                                 else            uvedit_uv_deselect(em, scene, l);
2504                                         }
2505                                 }
2506                         }
2507                 }
2508         }
2509
2510         if (change) {
2511                 /* make sure newly selected vert selection is updated*/
2512 #if 0   /* BM_elem_select_set API handles all of this? */
2513                 if (ts->uv_flag & UV_SYNC_SELECTION) {
2514                         if (ts->selectmode != SCE_SELECT_FACE) {
2515                                 if (select)     EDBM_select_flush(em);
2516                                 else            EDBM_deselect_flush(em);
2517                         }
2518                 }
2519 #endif
2520
2521                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2522                 
2523                 return OPERATOR_FINISHED;
2524         }
2525
2526         return OPERATOR_CANCELLED;
2527
2528
2529 static void UV_OT_select_border(wmOperatorType *ot)
2530 {
2531         /* identifiers */
2532         ot->name = "Border Select";
2533         ot->description = "Select UV vertices using border selection";
2534         ot->idname = "UV_OT_select_border";
2535         
2536         /* api callbacks */
2537         ot->invoke = WM_border_select_invoke;
2538         ot->exec = border_select_exec;
2539         ot->modal = WM_border_select_modal;
2540         ot->poll = ED_operator_image_active;    /* requires space image */;
2541         ot->cancel = WM_border_select_cancel;
2542         
2543         /* flags */
2544         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2545         
2546         /* properties */
2547         RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only");
2548
2549         WM_operator_properties_gesture_border(ot, TRUE);
2550 }
2551
2552 /* ******************** circle select operator **************** */
2553
2554 static void select_uv_inside_ellipse(BMEditMesh *em, SpaceImage *UNUSED(sima), Scene *scene, int select,
2555                                                                          float *offset, float *ell, BMLoop *l, MLoopUV *luv)
2556 {
2557         /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
2558         float x, y, r2, *uv;
2559         
2560         
2561         uv= luv->uv;
2562
2563         x= (uv[0] - offset[0])*ell[0];
2564         y= (uv[1] - offset[1])*ell[1];
2565
2566         r2 = x*x + y*y;
2567         if (r2 < 1.0f) {
2568                 if (select) uvedit_uv_select(em, scene, l);
2569                 else uvedit_uv_deselect(em, scene, l);
2570         }
2571 }
2572
2573 static int circle_select_exec(bContext *C, wmOperator *op)
2574 {
2575         SpaceImage *sima = CTX_wm_space_image(C);
2576         Scene *scene = CTX_data_scene(C);
2577         Object *obedit = CTX_data_edit_object(C);
2578         BMEditMesh *em = BMEdit_FromObject(obedit);
2579         ARegion *ar = CTX_wm_region(C);
2580         BMFace *efa;
2581         BMLoop *l;
2582         BMIter iter, liter;
2583         MLoopUV *luv;
2584         int x, y, radius, width, height, select;
2585         float zoomx, zoomy, offset[2], ellipse[2];
2586         int gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
2587
2588         /* get operator properties */
2589         select= (gesture_mode == GESTURE_MODAL_SELECT);
2590         x= RNA_int_get(op->ptr, "x");
2591         y= RNA_int_get(op->ptr, "y");
2592         radius= RNA_int_get(op->ptr, "radius");
2593
2594         /* compute ellipse size and location, not a circle since we deal
2595          * with non square image. ellipse is normalized, r = 1.0. */
2596         ED_space_image_size(sima, &width, &height);
2597         ED_space_image_zoom(sima, ar, &zoomx, &zoomy);
2598
2599         ellipse[0]= width*zoomx/radius;
2600         ellipse[1]= height*zoomy/radius;
2601
2602         UI_view2d_region_to_view(&ar->v2d, x, y, &offset[0], &offset[1]);
2603         
2604         /* do selection */
2605         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2606                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2607                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2608                         select_uv_inside_ellipse(em, sima, scene, select, offset, ellipse, l, luv);
2609                 }
2610         }
2611
2612 #if 0 //I think the BM_elem_select_set api stuff handles all this as necessary?
2613         if (select) EM_select_flush(em);
2614         else EM_deselect_flush(em);
2615 #endif
2616         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2617
2618         return OPERATOR_FINISHED;
2619 }
2620
2621 static void UV_OT_circle_select(wmOperatorType *ot)
2622 {
2623         /* identifiers */
2624         ot->name = "Circle Select";
2625         ot->description = "Select UV vertices using circle selection";
2626         ot->idname = "UV_OT_circle_select";
2627         
2628         /* api callbacks */
2629         ot->invoke = WM_gesture_circle_invoke;
2630         ot->modal = WM_gesture_circle_modal;
2631         ot->exec = circle_select_exec;
2632         ot->poll = ED_operator_image_active;    /* requires space image */;
2633         ot->cancel = WM_gesture_circle_cancel;
2634         
2635         /* flags */
2636         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2637         
2638         /* properties */
2639         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
2640         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
2641         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
2642         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
2643 }
2644
2645 /* ******************** snap cursor operator **************** */
2646
2647 static void snap_uv_to_pixel(float *uvco, float w, float h)
2648 {
2649         uvco[0] = ((float)((int)((uvco[0]*w) + 0.5f)))/w;
2650         uvco[1] = ((float)((int)((uvco[1]*h) + 0.5f)))/h;
2651 }
2652
2653 static void snap_cursor_to_pixels(SpaceImage *sima)
2654 {
2655         int width= 0, height= 0;
2656
2657         ED_space_image_size(sima, &width, &height);
2658         snap_uv_to_pixel(sima->cursor, width, height);
2659 }
2660
2661 static int snap_cursor_to_selection(Scene *scene, Image *ima, Object *obedit, SpaceImage *sima)
2662 {
2663         return uvedit_center(scene, ima, obedit, sima->cursor, sima->around);
2664 }
2665
2666 static int snap_cursor_exec(bContext *C, wmOperator *op)
2667 {
2668         SpaceImage *sima= CTX_wm_space_image(C);
2669         Scene *scene= CTX_data_scene(C);
2670         Object *obedit= CTX_data_edit_object(C);
2671         Image *ima= CTX_data_edit_image(C);
2672         int change= 0;
2673
2674         switch(RNA_enum_get(op->ptr, "target")) {
2675                 case 0:
2676                         snap_cursor_to_pixels(sima);
2677                         change= 1;
2678                         break;
2679                 case 1:
2680                         change= snap_cursor_to_selection(scene, ima, obedit, sima);
2681                         break;
2682         }
2683
2684         if (!change)
2685                 return OPERATOR_CANCELLED;
2686         
2687         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_IMAGE, sima);
2688
2689         return OPERATOR_FINISHED;
2690 }
2691
2692 static void UV_OT_snap_cursor(wmOperatorType *ot)
2693 {
2694         static EnumPropertyItem target_items[] = {
2695                 {0, "PIXELS", 0, "Pixels", ""},
2696                 {1, "SELECTED", 0, "Selected", ""},
2697                 {0, NULL, 0, NULL, NULL}};
2698
2699         /* identifiers */
2700         ot->name = "Snap Cursor";
2701         ot->description = "Snap cursor to target type";
2702         ot->idname = "UV_OT_snap_cursor";
2703         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2704         
2705         /* api callbacks */
2706         ot->exec = snap_cursor_exec;
2707         ot->poll = ED_operator_image_active;    /* requires space image */;
2708
2709         /* properties */
2710         RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
2711 }
2712
2713 /* ******************** snap selection operator **************** */
2714
2715 static int snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, SpaceImage *sima)
2716 {
2717         BMEditMesh *em = BMEdit_FromObject(obedit);
2718         BMFace *efa;
2719         BMLoop *l;
2720         BMIter iter, liter;
2721         MTexPoly *tface;
2722         MLoopUV *luv;
2723         short change= 0;
2724
2725         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2726                 tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2727                 if (!uvedit_face_visible(scene, ima, efa, tface))
2728                         continue;
2729
2730                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2731                         if (uvedit_uv_selected(em, scene, l)) {
2732                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2733                                 copy_v2_v2(luv->uv, sima->cursor);
2734                                 change= 1;
2735                         }
2736                 }
2737         }
2738
2739         return change;
2740 }
2741
2742 static int snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obedit)
2743 {
2744         BMEditMesh *em = BMEdit_FromObject(obedit);
2745         BMFace *efa;
2746         BMLoop *l;
2747         BMIter iter, liter;
2748         BMVert *eve;
2749         MTexPoly *tface;
2750         MLoopUV *luv;
2751         short change = 0;
2752         int count = 0;
2753         float *coords;
2754         short *usercount, users;
2755
2756         /* BMESH_TODO - stop setting the index, bad juju
2757          * not totally simple because 3 states and because the count is not
2758          * based on the global vertex index :S - campbell */
2759
2760         /* set all verts to -1 : an unused index*/
2761         BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL)
2762                 BM_elem_index_set(eve, -1); /* set_dirty! */
2763         em->bm->elem_index_dirty |= BM_VERT;
2764         
2765         /* index every vert that has a selected UV using it, but only once so as to
2766          * get unique indices and to count how much to malloc */
2767         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2768                 tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2769                 if (!uvedit_face_visible(scene, ima, efa, tface)) {
2770                         BM_elem_flag_disable(efa, BM_ELEM_TAG);
2771                         continue;
2772                 }
2773                 else {
2774                         BM_elem_flag_enable(efa, BM_ELEM_TAG);
2775                 }
2776
2777                 change = 1;
2778                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2779                         if (uvedit_uv_selected(em, scene, l) && BM_elem_index_get(l->v) == -1) {
2780                                 BM_elem_index_set(l->v, count); /* set_dirty! */
2781                                 count++;
2782                         }
2783                 }
2784         }
2785         em->bm->elem_index_dirty |= BM_VERT; /* set above but include for completeness since they are made dirty again */
2786         
2787         coords = MEM_callocN(sizeof(float)*count*2, "snap to adjacent coords");
2788         usercount = MEM_callocN(sizeof(short)*count, "snap to adjacent counts");
2789         
2790         /* add all UV coords from visible, unselected UV coords as well as counting them to average later */
2791         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2792                 if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
2793                         continue;
2794
2795                 tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2796                 if (!uvedit_face_visible(scene, ima, efa, tface))
2797                         continue;
2798
2799                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2800                         if (BM_elem_index_get(l->v) >= 0 && 
2801                             (!uvedit_uv_selected(em, scene, l))) {
2802                                     luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2803                                         add_v2_v2(&coords[BM_elem_index_get(l->v) * 2], luv->uv);
2804                                     change = 1;
2805                         }
2806                 }
2807         }
2808         
2809         /* no other verts selected, bail out */
2810         if (!change) {
2811                 MEM_freeN(coords);
2812                 MEM_freeN(usercount);
2813                 return change;
2814         }
2815         
2816         /* copy the averaged unselected UVs back to the selected UVs */
2817         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2818                 if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
2819                         continue;
2820
2821                 tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2822                 if (!uvedit_face_visible(scene, ima, efa, tface))
2823                         continue;
2824
2825                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2826                         if (uvedit_uv_selected(em, scene, l) && BM_elem_index_get(l->v) >= 0
2827                             && (users = usercount[BM_elem_index_get(l->v)])) {
2828                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2829                                 copy_v2_v2(luv->uv, &coords[BM_elem_index_get(l->v) * 2]);
2830                         }
2831                 }
2832         }
2833         
2834         MEM_freeN(coords);
2835         MEM_freeN(usercount);
2836
2837         return change;
2838 }
2839
2840 static int snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit)
2841 {
2842         BMEditMesh *em = BMEdit_FromObject(obedit);
2843         Image *ima = sima->image;
2844         BMFace *efa;
2845         BMLoop *l;
2846         BMIter iter, liter;
2847         MTexPoly *tface;
2848         MLoopUV *luv;
2849         int width = 0, height = 0;
2850         float w, h;
2851         short change = 0;
2852
2853         ED_space_image_size(sima, &width, &height);
2854         w = (float)width;
2855         h = (float)height;
2856         
2857         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2858                 tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2859                 if (!uvedit_face_visible(scene, ima, efa, tface))
2860                         continue;
2861
2862                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2863                         if (uvedit_uv_selected(em, scene, l)) {
2864                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2865                                 snap_uv_to_pixel(luv->uv, w, h);
2866                         }
2867                 }
2868
2869                 change = 1;
2870         }
2871
2872         return change;
2873 }
2874
2875 static int snap_selection_exec(bContext *C, wmOperator *op)
2876 {
2877         SpaceImage *sima= CTX_wm_space_image(C);
2878         Scene *scene= CTX_data_scene(C);
2879         Object *obedit= CTX_data_edit_object(C);
2880         Image *ima= CTX_data_edit_image(C);
2881         int change= 0;
2882
2883         switch(RNA_enum_get(op->ptr, "target")) {
2884                 case 0:
2885                         change= snap_uvs_to_pixels(sima, scene, obedit);
2886                         break;
2887                 case 1:
2888                         change= snap_uvs_to_cursor(scene, ima, obedit, sima);
2889                         break;
2890                 case 2:
2891                         change= snap_uvs_to_adjacent_unselected(scene, ima, obedit);
2892                         break;
2893         }
2894
2895         if (!change)
2896                 return OPERATOR_CANCELLED;
2897
2898         uvedit_live_unwrap_update(sima, scene, obedit);
2899         DAG_id_tag_update(obedit->data, 0);
2900         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2901
2902         return OPERATOR_FINISHED;
2903 }
2904
2905 static void UV_OT_snap_selected(wmOperatorType *ot)
2906 {
2907         static EnumPropertyItem target_items[] = {
2908                 {0, "PIXELS", 0, "Pixels", ""},
2909                 {1, "CURSOR", 0, "Cursor", ""},
2910                 {2, "ADJACENT_UNSELECTED", 0, "Adjacent Unselected", ""},
2911                 {0, NULL, 0, NULL, NULL}};
2912
2913         /* identifiers */
2914         ot->name = "Snap Selection";
2915         ot->description = "Snap selected UV vertices to target type";
2916         ot->idname = "UV_OT_snap_selected";
2917         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2918         
2919         /* api callbacks */
2920         ot->exec = snap_selection_exec;
2921         ot->poll = ED_operator_image_active;    /* requires space image */;
2922
2923         /* properties */
2924         RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
2925 }
2926
2927 /* ******************** pin operator **************** */
2928
2929 static int pin_exec(bContext *C, wmOperator *op)
2930 {
2931         Scene *scene = CTX_data_scene(C);
2932         Object *obedit = CTX_data_edit_object(C);
2933         Image *ima = CTX_data_edit_image(C);
2934         BMEditMesh *em = BMEdit_FromObject(obedit);
2935         BMFace *efa;
2936         BMLoop *l;
2937         BMIter iter, liter;
2938         MTexPoly *tface;
2939         MLoopUV *luv;
2940         int clear = RNA_boolean_get(op->ptr, "clear");
2941         
2942         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2943                 tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2944                 if (!uvedit_face_visible(scene, ima, efa, tface))
2945                         continue;
2946
2947                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
2948                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
2949                         
2950                         if (!clear) {
2951                                 if (uvedit_uv_selected(em, scene, l))
2952                                         luv->flag |= MLOOPUV_PINNED;
2953                         }
2954                         else {
2955                                 if (uvedit_uv_selected(em, scene, l))
2956                                         luv->flag &= ~MLOOPUV_PINNED;
2957                         }
2958                 }
2959         }
2960         
2961         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2962
2963         return OPERATOR_FINISHED;
2964 }
2965
2966 static void UV_OT_pin(wmOperatorType *ot)
2967 {
2968         /* identifiers */
2969         ot->name = "Pin";
2970         ot->description = "Set/clear selected UV vertices as anchored between multiple unwrap operations";
2971         ot->idname = "UV_OT_pin";
2972         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2973         
2974         /* api callbacks */
2975         ot->exec = pin_exec;
2976         ot->poll = ED_operator_uvedit;
2977
2978         /* properties */
2979         RNA_def_boolean(ot->srna, "clear", 0, "Clear", "Clear pinning for the selection instead of setting it");
2980 }
2981
2982 /******************* select pinned operator ***************/
2983
2984 static int select_pinned_exec(bContext *C, wmOperator *UNUSED(op))
2985 {
2986         Scene *scene = CTX_data_scene(C);
2987         Object *obedit = CTX_data_edit_object(C);
2988         Image *ima = CTX_data_edit_image(C);
2989         BMEditMesh *em = BMEdit_FromObject(obedit);
2990         BMFace *efa;
2991         BMLoop *l;
2992         BMIter iter, liter;
2993         MTexPoly *tface;
2994         MLoopUV *luv;
2995         
2996         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
2997                 tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
2998                 if (!uvedit_face_visible(scene, ima, efa, tface))
2999                         continue;
3000
3001                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
3002                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
3003                         
3004                         if (luv->flag & MLOOPUV_PINNED)
3005                                 uvedit_uv_select(em, scene, l);
3006                 }
3007         }
3008         
3009         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
3010
3011         return OPERATOR_FINISHED;
3012 }
3013
3014 static void UV_OT_select_pinned(wmOperatorType *ot)
3015 {
3016         /* identifiers */
3017         ot->name = "Selected Pinned";
3018         ot->description = "Select all pinned UV vertices";
3019         ot->idname = "UV_OT_select_pinned";
3020         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
3021         
3022         /* api callbacks */
3023         ot->exec = select_pinned_exec;
3024         ot->poll = ED_operator_uvedit;
3025 }
3026
3027 /********************** hide operator *********************/
3028
3029 static int hide_exec(bContext *C, wmOperator *op)
3030 {
3031         SpaceImage *sima = CTX_wm_space_image(C);
3032         ToolSettings *ts = CTX_data_tool_settings(C);
3033         Object *obedit = CTX_data_edit_object(C);
3034         Scene *scene = CTX_data_scene(C);
3035         BMEditMesh *em = BMEdit_FromObject(obedit);
3036         BMFace *efa;
3037         BMLoop *l;
3038         BMIter iter, liter;
3039         MLoopUV *luv;
3040         int swap = RNA_boolean_get(op->ptr, "unselected");
3041         int facemode= sima ? sima->flag & SI_SELACTFACE : 0;
3042
3043         if (ts->uv_flag & UV_SYNC_SELECTION) {
3044                 EDBM_hide_mesh(em, swap);
3045                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
3046
3047                 return OPERATOR_FINISHED;
3048         }
3049         
3050         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
3051                 int hide = 0;
3052
3053                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
3054                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
3055
3056                         if (luv->flag & MLOOPUV_VERTSEL) {
3057                                 hide = 1;
3058                                 break;
3059                         }
3060                 }
3061
3062                 if (swap)
3063                         hide = !hide;
3064                 
3065                 if (hide) {
3066                         if (facemode) {
3067                                 /*check that every UV is selected*/
3068                                 luv = NULL;
3069                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
3070                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
3071                                         if (!(luv->flag & MLOOPUV_VERTSEL))
3072                                                 break;
3073                                 }
3074                                 
3075                                 if (!luv) {
3076                                         BM_elem_select_set(em->bm, efa, FALSE);
3077                                         uvedit_face_deselect(scene, em, efa);
3078                                 }
3079                         }
3080                         else if (em->selectmode == SCE_SELECT_FACE) {
3081                                 /*check if a UV is selected*/
3082                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
3083                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
3084                                         if (luv->flag & MLOOPUV_VERTSEL) {
3085                                                 BM_elem_select_set(em->bm, efa, FALSE);
3086                                         }
3087                                         luv->flag &= ~MLOOPUV_VERTSEL;
3088                                 }
3089                         }
3090                         else {
3091                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
3092                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
3093                                         if (luv->flag & MLOOPUV_VERTSEL) {
3094                                                 BM_elem_select_set(em->bm, l->v, FALSE);
3095                                                 luv->flag &= ~MLOOPUV_VERTSEL;
3096                                         }
3097                                 }
3098                         }
3099                 }
3100         }
3101         
3102         
3103         EDBM_validate_selections(em);
3104         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
3105
3106         return OPERATOR_FINISHED;
3107 }
3108
3109 static void UV_OT_hide(wmOperatorType *ot)
3110 {
3111         /* identifiers */
3112         ot->name = "Hide Selected";
3113         ot->description = "Hide (un)selected UV vertices";
3114         ot->idname = "UV_OT_hide";
3115         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
3116         
3117         /* api callbacks */
3118         ot->exec = hide_exec;
3119         ot->poll = ED_operator_uvedit;
3120
3121         /* props */
3122         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
3123 }
3124
3125 /****************** reveal operator ******************/
3126
3127 static int reveal_exec(bContext *C, wmOperator *UNUSED(op))
3128 {
3129         SpaceImage *sima= CTX_wm_space_image(C);
3130         ToolSettings *ts= CTX_data_tool_settings(C);
3131         Object *obedit= CTX_data_edit_object(C);
3132         /*Scene *scene = CTX_data_scene(C);*/ /*UNUSED*/
3133         BMEditMesh *em = BMEdit_FromObject(obedit);
3134         BMFace *efa;
3135         BMLoop *l;
3136         BMIter iter, liter;
3137         MLoopUV *luv;
3138         int facemode= sima ? sima->flag & SI_SELACTFACE : 0;
3139         int stickymode= sima ? (sima->sticky != SI_STICKY_DISABLE) : 1;
3140
3141         /* call the mesh function if we are in mesh sync sel */
3142         if (ts->uv_flag & UV_SYNC_SELECTION) {
3143                 EDBM_reveal_mesh(em);
3144                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
3145
3146                 return OPERATOR_FINISHED;
3147         }
3148         if (facemode) {
3149                 if (em->selectmode == SCE_SELECT_FACE) {
3150                         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
3151                                 if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
3152                                         BM_elem_select_set(em->bm, efa, TRUE);
3153                                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
3154                                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
3155                                                 luv->flag |= MLOOPUV_VERTSEL;
3156