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