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