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