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