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