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