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