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