Bretch's patch for 2D transform. Thanks
[blender.git] / source / blender / src / editsima.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL 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. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <math.h>
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #ifndef WIN32
42 #include <unistd.h>
43 #else
44 #include <io.h>
45 #endif   
46 #include "MEM_guardedalloc.h"
47
48 #include "BLI_blenlib.h"
49 #include "BLI_arithb.h"
50
51 #include "IMB_imbuf_types.h"
52
53 #include "DNA_mesh_types.h"
54 #include "DNA_meshdata_types.h"
55 #include "DNA_scene_types.h"
56 #include "DNA_screen_types.h"
57 #include "DNA_userdef_types.h"
58 #include "DNA_space_types.h"
59 #include "DNA_image_types.h"
60 #include "DNA_object_types.h" // only for uvedit_selectionCB() (struct Object)
61
62 #include "BKE_depsgraph.h"
63 #include "BKE_global.h"
64 #include "BKE_mesh.h"
65 #include "BKE_displist.h"
66 #include "BKE_object.h"
67 #include "BKE_utildefines.h"
68
69 #include "BIF_gl.h"
70 #include "BIF_interface.h"
71 #include "BIF_screen.h"
72 #include "BIF_drawimage.h"
73 #include "BIF_editview.h"
74 #include "BIF_space.h"
75 #include "BIF_editsima.h"
76 #include "BIF_toolbox.h"
77 #include "BIF_transform.h"
78 #include "BIF_mywindow.h"
79
80 #include "BSE_drawipo.h"
81 #include "BSE_edit.h"
82 #include "BSE_trans_types.h"
83
84 #include "BDR_editobject.h"
85 #include "BDR_unwrapper.h"
86
87 #include "blendef.h"
88 #include "mydevice.h"
89
90 struct uvvertsort {
91         unsigned int v, f;
92         unsigned char tf_sel;
93         char flag;
94 };
95
96 /* local prototypes */
97 void clever_numbuts_sima(void);
98 void sel_uvco_inside_radius(short , TFace *, int , float *, float *, short);
99 void uvedit_selectionCB(short , Object *, short *, float ); /* used in edit.c*/ 
100
101 static int compuvvert(const void *u1, const void *u2)
102 {
103         const struct uvvertsort *v1=u1, *v2=u2;
104         if (v1->v > v2->v) return 1;
105         else if (v1->v < v2->v) return -1;
106         return 0;
107 }
108
109 void object_uvs_changed(Object *ob)
110 {
111         DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
112
113         allqueue(REDRAWVIEW3D, 0);
114         allqueue(REDRAWIMAGE, 0);
115 }
116
117 void object_tface_flags_changed(Object *ob, int updateButtons)
118 {
119         if (updateButtons) allqueue(REDRAWBUTSEDIT, 0);
120         allqueue(REDRAWVIEW3D, 0);
121         allqueue(REDRAWIMAGE, 0);
122 }
123
124 int is_uv_tface_editing_allowed_silent(void)
125 {
126         Mesh *me;
127
128         if(G.obedit) return 0;
129         if(G.sima->mode!=SI_TEXTURE) return 0;
130         if(!(G.f & G_FACESELECT)) return 0;  
131         me= get_mesh(OBACT);
132         if(me==0 || me->tface==0) return 0;
133         
134         return 1;
135 }
136
137 int is_uv_tface_editing_allowed(void)
138 {
139         if(G.obedit) error("Unable to perform action in Edit Mode");
140
141         return is_uv_tface_editing_allowed_silent();
142 }
143
144 void get_connected_limit_tface_uv(float *limit)
145 {
146         if(G.sima->image && G.sima->image->ibuf && G.sima->image->ibuf->x > 0 &&
147            G.sima->image->ibuf->y > 0) {
148                 limit[0]= 0.05/(float)G.sima->image->ibuf->x;
149                 limit[1]= 0.05/(float)G.sima->image->ibuf->y;
150         }
151         else
152                 limit[0]= limit[1]= 0.05/256.0;
153 }
154
155 void clever_numbuts_sima(void)
156 {
157         float ocent[2], cent[2]= {0.0, 0.0};
158         int imx, imy;
159         int i, nactive= 0;
160         Mesh *me;
161         
162         if( is_uv_tface_editing_allowed()==0 ) return;
163         me= get_mesh(OBACT);
164         
165         if (G.sima->image && G.sima->image->ibuf) {
166                 imx= G.sima->image->ibuf->x;
167                 imy= G.sima->image->ibuf->y;
168         } else
169                 imx= imy= 256;
170         
171         for (i=0; i<me->totface; i++) {
172                 MFace *mf= &((MFace*) me->mface)[i];
173                 TFace *tf= &((TFace*) me->tface)[i];
174                 
175                 if (!(tf->flag & TF_SELECT))
176                         continue;
177                 
178                 if (tf->flag & TF_SEL1) {
179                         cent[0]+= tf->uv[0][0];
180                         cent[1]+= tf->uv[0][1];
181                         nactive++;
182                 }
183                 if (tf->flag & TF_SEL2) {
184                         cent[0]+= tf->uv[1][0];
185                         cent[1]+= tf->uv[1][1];
186                         nactive++;
187                 }
188                 if (tf->flag & TF_SEL3) {
189                         cent[0]+= tf->uv[2][0];
190                         cent[1]+= tf->uv[2][1];
191                         nactive++;
192                 }
193                 if (mf->v4 && (tf->flag & TF_SEL4)) {
194                         cent[0]+= tf->uv[3][0];
195                         cent[1]+= tf->uv[3][1];
196                         nactive++;
197                 }
198         }
199         
200         if (nactive) {
201                 cent[0]= (cent[0]*imx)/nactive;
202                 cent[1]= (cent[1]*imy)/nactive;
203
204                 add_numbut(0, NUM|FLO, "LocX:", -imx*20, imx*20, &cent[0], NULL);
205                 add_numbut(1, NUM|FLO, "LocY:", -imy*20, imy*20, &cent[1], NULL);
206                 
207                 ocent[0]= cent[0];
208                 ocent[1]= cent[1];
209                 if (do_clever_numbuts((nactive==1)?"Active Vertex":"Selected Center", 2, REDRAW)) {
210                         float delta[2];
211                         
212                         delta[0]= (cent[0]-ocent[0])/imx;
213                         delta[1]= (cent[1]-ocent[1])/imy;
214
215                         for (i=0; i<me->totface; i++) {
216                                 MFace *mf= &((MFace*) me->mface)[i];
217                                 TFace *tf= &((TFace*) me->tface)[i];
218                         
219                                 if (!(tf->flag & TF_SELECT))
220                                         continue;
221                         
222                                 if (tf->flag & TF_SEL1) {
223                                         tf->uv[0][0]+= delta[0];
224                                         tf->uv[0][1]+= delta[1];
225                                 }
226                                 if (tf->flag & TF_SEL2) {
227                                         tf->uv[1][0]+= delta[0];
228                                         tf->uv[1][1]+= delta[1];
229                                 }
230                                 if (tf->flag & TF_SEL3) {
231                                         tf->uv[2][0]+= delta[0];
232                                         tf->uv[2][1]+= delta[1];
233                                 }
234                                 if (mf->v4 && (tf->flag & TF_SEL4)) {
235                                         tf->uv[3][0]+= delta[0];
236                                         tf->uv[3][1]+= delta[1];
237                                 }
238                         }
239                         
240                         object_uvs_changed(OBACT);
241                 }
242         }
243 }
244
245 void be_square_tface_uv(Mesh *me)
246 {
247         TFace *tface;
248         MFace *mface;
249         int a;
250         
251         /* if 1 vertex selected: doit (with the selected vertex) */
252         mface= (MFace*)me->mface;
253         tface= (TFace*)me->tface;
254         for(a=me->totface; a>0; a--, tface++, mface++) {
255                 if(mface->v4) {
256                         if(tface->flag & TF_SELECT) {
257                                 if(tface->flag & TF_SEL1) {
258                                         if( tface->uv[1][0] == tface->uv[2][0] ) {
259                                                 tface->uv[1][1]= tface->uv[0][1];
260                                                 tface->uv[3][0]= tface->uv[0][0];
261                                         }
262                                         else {  
263                                                 tface->uv[1][0]= tface->uv[0][0];
264                                                 tface->uv[3][1]= tface->uv[0][1];
265                                         }
266                                         
267                                 }
268                                 if(tface->flag & TF_SEL2) {
269                                         if( tface->uv[2][1] == tface->uv[3][1] ) {
270                                                 tface->uv[2][0]= tface->uv[1][0];
271                                                 tface->uv[0][1]= tface->uv[1][1];
272                                         }
273                                         else {
274                                                 tface->uv[2][1]= tface->uv[1][1];
275                                                 tface->uv[0][0]= tface->uv[1][0];
276                                         }
277
278                                 }
279                                 if(tface->flag & TF_SEL3) {
280                                         if( tface->uv[3][0] == tface->uv[0][0] ) {
281                                                 tface->uv[3][1]= tface->uv[2][1];
282                                                 tface->uv[1][0]= tface->uv[2][0];
283                                         }
284                                         else {
285                                                 tface->uv[3][0]= tface->uv[2][0];
286                                                 tface->uv[1][1]= tface->uv[2][1];
287                                         }
288                                 }
289                                 if(tface->flag & TF_SEL4) {
290                                         if( tface->uv[0][1] == tface->uv[1][1] ) {
291                                                 tface->uv[0][0]= tface->uv[3][0];
292                                                 tface->uv[2][1]= tface->uv[3][1];
293                                         }
294                                         else  {
295                                                 tface->uv[0][1]= tface->uv[3][1];
296                                                 tface->uv[2][0]= tface->uv[3][0];
297                                         }
298
299                                 }
300                         }
301                 }
302         }
303 }
304
305 void transform_aspect_ratio_tface_uv(float *aspx, float *aspy)
306 {
307         int w, h;
308
309         transform_width_height_tface_uv(&w, &h);
310         *aspx= (float)w/256.0f;
311         *aspy= (float)h/256.0f;
312 }
313
314 void transform_width_height_tface_uv(int *width, int *height)
315 {
316         if(G.sima->image && G.sima->image->ibuf) {
317                 *width= G.sima->image->ibuf->x;
318                 *height= G.sima->image->ibuf->y;
319         }
320         else {
321                 *width= 256;
322                 *height= 256;
323         }
324 }
325
326 void mirror_tface_uv(char mirroraxis)
327 {
328         Mirror((short)mirroraxis);
329 }
330
331 void mirrormenu_tface_uv(void)
332 {
333         short mode= 0;
334
335         if( is_uv_tface_editing_allowed()==0 ) return;
336
337         mode= pupmenu("Mirror%t|X Axis%x1|Y Axis%x2|");
338
339         if(mode==-1) return;
340
341         if(mode==1) mirror_tface_uv('x');
342         else if(mode==2) mirror_tface_uv('y');
343
344         BIF_undo_push("Mirror UV");
345 }
346
347 void weld_align_tface_uv(char tool)
348 {
349         MFace *mface;
350         TFace *tface;
351         Mesh *me;
352         float min[2], max[2], cent[2];
353         int a;
354         
355         if( is_uv_tface_editing_allowed()==0 ) return;
356         me= get_mesh(OBACT);
357
358         if (!minmax_tface_uv(min, max))
359                 return;
360
361         cent[0]= (min[0]+max[0])/2.0;
362         cent[1]= (min[1]+max[1])/2.0;
363
364         if(tool == 'x' || tool == 'w') {
365                 tface= me->tface;
366                 mface= me->mface;
367                 for(a=me->totface; a>0; a--, tface++, mface++) {
368                         if(tface->flag & TF_SELECT) {
369                                 if(tface->flag & TF_SEL1)
370                                         tface->uv[0][0]= cent[0];
371                                 if(tface->flag & TF_SEL2)
372                                         tface->uv[1][0]= cent[0];
373                                 if(tface->flag & TF_SEL3)
374                                         tface->uv[2][0]= cent[0];
375                                 if(mface->v4 && (tface->flag & TF_SEL4))
376                                         tface->uv[3][0]= cent[0];
377                         }
378                 }
379         }
380
381         if(tool == 'y' || tool == 'w') {
382                 tface= me->tface;
383                 mface= me->mface;
384                 for(a=me->totface; a>0; a--, tface++, mface++) {
385                         if(tface->flag & TF_SELECT) {
386                                 if(tface->flag & TF_SEL1)
387                                         tface->uv[0][1]= cent[1];
388                                 if(tface->flag & TF_SEL2)
389                                         tface->uv[1][1]= cent[1];
390                                 if(tface->flag & TF_SEL3)
391                                         tface->uv[2][1]= cent[1];
392                                 if(mface->v4 && (tface->flag & TF_SEL4))
393                                         tface->uv[3][1]= cent[1];
394                         }
395                 }
396         }
397
398         object_uvs_changed(OBACT);
399 }
400
401 void weld_align_menu_tface_uv(void)
402 {
403         short mode= 0;
404
405         if( is_uv_tface_editing_allowed()==0 ) return;
406
407         mode= pupmenu("Weld/Align%t|Weld%x1|Align X%x2|Align Y%x3|");
408
409         if(mode==-1) return;
410
411         if(mode==1) weld_align_tface_uv('w');
412         else if(mode==2) weld_align_tface_uv('x');
413         else if(mode==3) weld_align_tface_uv('y');
414
415         if(mode==1) BIF_undo_push("Weld UV");
416         else if(mode==2 || mode==3) BIF_undo_push("Align UV");
417 }
418
419 void select_swap_tface_uv(void)
420 {
421         Mesh *me;
422         TFace *tface;
423         MFace *mface;
424         int a, sel=0;
425         
426         if( is_uv_tface_editing_allowed()==0 ) return;
427         me= get_mesh(OBACT);
428
429         for(a=me->totface, tface= me->tface; a>0; a--, tface++) {
430                 if(tface->flag & TF_SELECT) {   
431                         if(tface->flag & (TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4)) {
432                                 sel= 1;
433                                 break;
434                         }
435                 }
436         }
437         
438         mface= me->mface;
439         for(a=me->totface, tface= me->tface; a>0; a--, tface++, mface++) {
440                 if(tface->flag & TF_SELECT) {
441                         if(mface->v4) {
442                                 if(sel) tface->flag &= ~(TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4);
443                                 else tface->flag |= (TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4);
444                         }
445                         else {
446                                 if(sel) tface->flag &= ~(TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4);
447                                 else tface->flag |= (TF_SEL1+TF_SEL2+TF_SEL3);
448                         }
449                 }
450         }
451         
452         BIF_undo_push("Select swap UV");
453
454         allqueue(REDRAWIMAGE, 0);
455 }
456
457 static int msel_hit(float *limit, unsigned int *hitarray, unsigned int vertexid, float **uv, float *uv2)
458 {
459         int i;
460         for(i=0; i< 4; i++) {
461                 if(hitarray[i] == vertexid) {
462                         if(G.sima->flag & SI_LOCALSTICKY) {
463                                 if(fabs(uv[i][0]-uv2[0]) < limit[0] &&
464                             fabs(uv[i][1]-uv2[1]) < limit[1])
465                                         return 1;
466                         }
467                         else return 1;
468                 }
469         }
470         return 0;
471 }
472
473 static void find_nearest_tface(TFace **nearesttf, MFace **nearestmf)
474 {
475         Mesh *me;
476         TFace *tf;
477         MFace *mf;
478         int a, i, nverts, mindist, dist, fcenter[2], uval[2];
479         short mval[2];
480
481         getmouseco_areawin(mval);       
482
483         mindist= 0x7FFFFFF;
484         *nearesttf= NULL;
485         *nearestmf= NULL;
486
487         me= get_mesh(OBACT);
488         mf= (MFace*)me->mface;
489         tf= (TFace*)me->tface;
490
491         for(a=me->totface; a>0; a--, tf++, mf++) {
492                 if(tf->flag & TF_SELECT) {
493
494                         fcenter[0]= fcenter[1]= 0;
495                         nverts= mf->v4? 4: 3;
496                         for(i=0; i<nverts; i++) {
497                                 uvco_to_areaco_noclip(tf->uv[i], uval);
498                                 fcenter[0] += uval[0];
499                                 fcenter[1] += uval[1];
500                         }
501
502                         fcenter[0] /= nverts;
503                         fcenter[1] /= nverts;
504
505                         dist= abs(mval[0]- fcenter[0])+ abs(mval[1]- fcenter[1]);
506                         if (dist < mindist) {
507                                 *nearesttf= tf;
508                                 *nearestmf= mf;
509                                 mindist= dist;
510                         }
511                 }
512         }
513 }
514
515 static int nearest_uv_between(TFace *tf, int nverts, int id, short *mval, int *uval)
516 {
517         float m[3], v1[3], v2[3], c1, c2;
518         int id1, id2;
519
520         id1= (id+nverts-1)%nverts;
521         id2= (id+nverts+1)%nverts;
522
523         m[0] = (float)(mval[0]-uval[0]);
524         m[1] = (float)(mval[1]-uval[1]);
525         Vec2Subf(v1, tf->uv[id1], tf->uv[id]);
526         Vec2Subf(v2, tf->uv[id2], tf->uv[id]);
527
528         /* m and v2 on same side of v-v1? */
529         c1= v1[0]*m[1] - v1[1]*m[0];
530         c2= v1[0]*v2[1] - v1[1]*v2[0];
531
532         if (c1*c2 < 0.0f)
533                 return 0;
534
535         /* m and v1 on same side of v-v2? */
536         c1= v2[0]*m[1] - v2[1]*m[0];
537         c2= v2[0]*v1[1] - v2[1]*v1[0];
538
539         return (c1*c2 >= 0.0f);
540 }
541
542 static void find_nearest_uv(TFace **nearesttf, unsigned int *nearestv, int *nearestuv)
543 {
544         Mesh *me;
545         TFace *tf;
546         MFace *mf;
547         int a, i, nverts, mindist, dist, uval[2];
548         short mval[2];
549
550         getmouseco_areawin(mval);       
551
552         mindist= 0x7FFFFFF;
553         *nearesttf= NULL;
554
555         me= get_mesh(OBACT);
556         mf= (MFace*)me->mface;
557         tf= (TFace*)me->tface;
558
559         for(a=me->totface; a>0; a--, tf++, mf++) {
560                 if(tf->flag & TF_SELECT) {
561
562                         nverts= mf->v4? 4: 3;
563                         for(i=0; i<nverts; i++) {
564                                 uvco_to_areaco_noclip(tf->uv[i], uval);
565                                 dist= abs(mval[0]-uval[0]) + abs(mval[1]-uval[1]);
566
567                                 if(tf->flag & TF_SEL_MASK(i))
568                                         dist += 5;
569
570                                 if(dist<=mindist) {
571                                         if(dist==mindist)
572                                                 if (!nearest_uv_between(tf, nverts, i, mval, uval))
573                                                         continue;
574
575                                         mindist= dist; 
576
577                                         *nearesttf= tf;
578                                         *nearestuv= i;
579
580                                         if (i==0) *nearestv=  mf->v1;
581                                         else if (i==1) *nearestv=  mf->v2;
582                                         else if (i==2) *nearestv=  mf->v3;
583                                         else *nearestv=  mf->v4;
584                                 }
585                         }
586                 }
587         }
588 }
589
590 void mouse_select_sima(void)
591 {
592         Mesh *me;
593         TFace *tf, *nearesttf;
594         MFace *mf, *nearestmf;
595         int a, selectsticky, sticky, actface, nearestuv, i;
596         unsigned int hitv[4], nearestv;
597         float *hituv[4], limit[2];
598         
599         if( is_uv_tface_editing_allowed()==0 ) return;
600         me= get_mesh(OBACT);
601
602         get_connected_limit_tface_uv(limit);
603         actface= (G.qual & LR_ALTKEY || G.sima->flag & SI_SELACTFACE);
604         sticky= (G.qual & LR_CTRLKEY || G.sima->flag & SI_STICKYUVS ||
605                  G.sima->flag & SI_LOCALSTICKY);
606
607         if(actface) {
608                 find_nearest_tface(&nearesttf, &nearestmf);
609                 if(nearesttf==NULL)
610                         return;
611
612                 nearesttf->flag |= TF_ACTIVE;
613
614                 for (i=0; i<4; i++)
615                         hituv[i]= nearesttf->uv[i];
616
617                 hitv[0]= nearestmf->v1;
618                 hitv[1]= nearestmf->v2;
619                 hitv[2]= nearestmf->v3;
620                 hitv[3]= nearestmf->v4? nearestmf->v4: 0xFFFFFFFF;
621         }
622         else {
623                 find_nearest_uv(&nearesttf, &nearestv, &nearestuv);
624                 if(nearesttf==NULL)
625                         return;
626
627                 if(sticky) {
628                         for(i=0; i<4; i++)
629                                 hitv[i]= 0xFFFFFFFF;
630                         hitv[nearestuv]= nearestv;
631                         hituv[nearestuv]= nearesttf->uv[nearestuv];
632                 }
633         }
634
635         if(G.qual & LR_SHIFTKEY) {
636                 /* (de)select face */
637                 if(actface) {
638                         if(!(~nearesttf->flag & (TF_SEL1|TF_SEL2|TF_SEL3))
639                            && (!nearestmf->v4 || nearesttf->flag & TF_SEL4)) {
640                                 nearesttf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
641                                 selectsticky= 0;
642                         }
643                         else {
644                                 nearesttf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
645                                 selectsticky= 1;
646                         }
647                 }
648                 /* (de)select uv node */
649                 else {
650                         if(nearesttf->flag & TF_SEL_MASK(nearestuv)) {
651                                 nearesttf->flag &= ~TF_SEL_MASK(nearestuv);
652                                 selectsticky= 0;
653                         }
654                         else {
655                                 nearesttf->flag |= TF_SEL_MASK(nearestuv);
656                                 selectsticky= 1;
657                         }
658                 }
659
660                 /* (de)select sticky uv nodes */
661                 if(sticky || actface) {
662                         mf= (MFace*)me->mface;
663                         tf= (TFace*)me->tface;
664                         /* deselect */
665                         if(selectsticky==0) {
666                                 for(a=me->totface; a>0; a--, tf++, mf++) {
667                                         if(!(tf->flag & TF_SELECT)) continue;
668                                         if(nearesttf && tf!=nearesttf) tf->flag &=~ TF_ACTIVE;
669                                         if (!sticky) continue;
670
671                                         if(msel_hit(limit, hitv, mf->v1, hituv, tf->uv[0]))
672                                                 tf->flag &= ~TF_SEL1;
673                                         if(msel_hit(limit, hitv, mf->v2, hituv, tf->uv[1]))
674                                                 tf->flag &= ~TF_SEL2;
675                                         if(msel_hit(limit, hitv, mf->v3, hituv, tf->uv[2]))
676                                                 tf->flag &= ~TF_SEL3;
677                                         if (mf->v4)
678                                                 if(msel_hit(limit, hitv, mf->v4, hituv, tf->uv[3]))
679                                                         tf->flag &= ~TF_SEL4;
680                                 }
681                         }
682                         /* select */
683                         else {
684                                 for(a=me->totface; a>0; a--, tf++, mf++) {
685                                         if(!(tf->flag & TF_SELECT)) continue;
686                                         if(nearesttf && tf!=nearesttf)
687                                                 tf->flag &=~ TF_ACTIVE;
688                                         if (!sticky) continue;
689
690                                         if(msel_hit(limit, hitv, mf->v1, hituv, tf->uv[0]))
691                                                 tf->flag |= TF_SEL1;
692                                         if(msel_hit(limit, hitv, mf->v2, hituv, tf->uv[1]))
693                                                 tf->flag |= TF_SEL2;
694                                         if(msel_hit(limit, hitv, mf->v3, hituv, tf->uv[2]))
695                                                 tf->flag |= TF_SEL3;
696                                         if (mf->v4)
697                                                 if(msel_hit(limit, hitv, mf->v4, hituv, tf->uv[3]))
698                                                         tf->flag |= TF_SEL4;
699                                 }
700                         }
701                 }
702         }
703         else {
704                 /* select face and deselect other faces */ 
705                 if(actface) {
706                         mf= (MFace*)me->mface;
707                         tf= (TFace*)me->tface;
708                         for(a=me->totface; a>0; a--, tf++, mf++) {
709                                 tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
710                                 if(nearesttf && tf!=nearesttf)
711                                         tf->flag &= ~TF_ACTIVE;
712                         }
713                         if(nearesttf)
714                                 nearesttf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
715                 }
716
717                 /* deselect uvs, and select sticky uvs */
718                 mf= (MFace*)me->mface;
719                 tf= (TFace*)me->tface;
720                 for(a=me->totface; a>0; a--, tf++, mf++) {
721                         if(tf->flag & TF_SELECT) {
722                                 if(!actface) tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
723                                 if(!sticky) continue;
724
725                                 if(msel_hit(limit, hitv, mf->v1, hituv, tf->uv[0]))
726                                         tf->flag |= TF_SEL1;
727                                 if(msel_hit(limit, hitv, mf->v2, hituv, tf->uv[1]))
728                                         tf->flag |= TF_SEL2;
729                                 if(msel_hit(limit, hitv, mf->v3, hituv, tf->uv[2]))
730                                         tf->flag |= TF_SEL3;
731                                 if(mf->v4)
732                                         if(msel_hit(limit, hitv, mf->v4, hituv, tf->uv[3]))
733                                                 tf->flag |= TF_SEL4;
734                         }
735                 }
736                 
737                 if(!actface) 
738                         nearesttf->flag |= TF_SEL_MASK(nearestuv);
739         }
740         
741         force_draw(1);
742         
743         BIF_undo_push("Select UV");
744         rightmouse_transform();
745 }
746
747 void borderselect_sima(void)
748 {
749         Mesh *me;
750         TFace *tface;
751         MFace *mface;
752         rcti rect;
753         rctf rectf;
754         int a, val;
755         short mval[2];
756
757         if( is_uv_tface_editing_allowed()==0 ) return;
758         me= get_mesh(OBACT);
759
760         val= get_border(&rect, 3);
761
762         if(val) {
763                 mval[0]= rect.xmin;
764                 mval[1]= rect.ymin;
765                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
766                 mval[0]= rect.xmax;
767                 mval[1]= rect.ymax;
768                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
769
770                 mface= me->mface;
771                 for(a=me->totface, tface= me->tface; a>0; a--, tface++, mface++) {
772                 
773                         if(tface->flag & TF_SELECT) {
774                                 
775                                 if(BLI_in_rctf(&rectf, (float)tface->uv[0][0], (float)tface->uv[0][1])) {
776                                         if(val==LEFTMOUSE) tface->flag |= TF_SEL1;
777                                         else tface->flag &= ~TF_SEL1;
778                                 }
779                                 if(BLI_in_rctf(&rectf, (float)tface->uv[1][0], (float)tface->uv[1][1])) {
780                                         if(val==LEFTMOUSE) tface->flag |= TF_SEL2;
781                                         else tface->flag &= ~TF_SEL2;
782                                 }
783                                 if(BLI_in_rctf(&rectf, (float)tface->uv[2][0], (float)tface->uv[2][1])) {
784                                         if(val==LEFTMOUSE) tface->flag |= TF_SEL3;
785                                         else tface->flag &= ~TF_SEL3;
786                                 }
787                                 if(mface->v4 && BLI_in_rctf(&rectf, (float)tface->uv[3][0], (float)tface->uv[3][1])) {
788                                         if(val==LEFTMOUSE) tface->flag |= TF_SEL4;
789                                         else tface->flag &= ~TF_SEL4;
790                                 }
791                         }
792                                                         
793                 }
794                 BIF_undo_push("Border select UV");
795                 scrarea_queue_winredraw(curarea);
796         }
797 }
798
799 /** This is an ugly function to set the Tface selection flags depending
800   * on whether its UV coordinates are inside the normalized 
801   * area with radius rad and offset offset. These coordinates must be
802   * normalized to 1.0 
803   * Just for readability...
804   */
805
806 void sel_uvco_inside_radius(short sel, TFace *tface, int index, float *offset, float *ell, short select_mask)
807 {
808         // normalized ellipse: ell[0] = scaleX,
809         //                        [1] = scaleY
810
811         float *uv = tface->uv[index];
812         float x, y, r2;
813
814         x = (uv[0] - offset[0]) * ell[0];
815         y = (uv[1] - offset[1]) * ell[1];
816
817         r2 = x * x + y * y;
818         if (r2 < 1.0) {
819                 if (sel == LEFTMOUSE) tface->flag |= select_mask;
820                 else tface->flag &= ~select_mask;
821         }
822 }
823
824 // see below:
825 /** gets image dimensions of the 2D view 'v' */
826 static void getSpaceImageDimension(SpaceImage *sima, float *xy)
827 {
828         Image *img = sima->image;
829         float z;
830
831         z = sima->zoom;
832
833         if (img) {
834                 xy[0] = img->ibuf->x * z;
835                 xy[1] = img->ibuf->y * z;
836         } else {
837                 xy[0] = 256 * z;
838                 xy[1] = 256 * z;
839         }
840 }
841
842 /** Callback function called by circle_selectCB to enable 
843   * brush select in UV editor.
844   */
845
846 void uvedit_selectionCB(short selecting, Object *editobj, short *mval, float rad) 
847 {
848         float offset[2];
849         Mesh *me;
850         MFace *mface;
851         TFace *tface;
852         int i;
853
854         float ellipse[2]; // we need to deal with ellipses, as
855                           // non square textures require for circle
856                                           // selection. this ellipse is normalized; r = 1.0
857         
858         me = get_mesh(editobj);
859
860         getSpaceImageDimension(curarea->spacedata.first, ellipse);
861         ellipse[0] /= rad;
862         ellipse[1] /= rad;
863
864         areamouseco_to_ipoco(G.v2d, mval, &offset[0], &offset[1]);
865
866         mface= me->mface;
867         tface= me->tface;
868
869         if (selecting) {
870                 for(i = 0; i < me->totface; i++) {
871                         sel_uvco_inside_radius(selecting, tface, 0, offset, ellipse, TF_SEL1);
872                         sel_uvco_inside_radius(selecting, tface, 1, offset, ellipse, TF_SEL2);
873                         sel_uvco_inside_radius(selecting, tface, 2, offset, ellipse, TF_SEL3);
874                         if (mface->v4)
875                                 sel_uvco_inside_radius(selecting, tface, 3, offset, ellipse, TF_SEL4);
876                         
877                         tface++; mface++;
878
879                 }
880
881                 if(G.f & G_DRAWFACES) { /* full redraw only if necessary */
882                         draw_sel_circle(0, 0, 0, 0, 0); /* signal */
883                         force_draw(0);
884                 }
885                 else { /* force_draw() is no good here... */
886                         glDrawBuffer(GL_FRONT);
887                         draw_tfaces();
888                         glDrawBuffer(GL_BACK);
889                 }
890         }       
891 }
892
893
894 void mouseco_to_curtile(void)
895 {
896         float fx, fy;
897         short mval[2];
898         
899         if( is_uv_tface_editing_allowed()==0) return;
900
901         if(G.sima->image && G.sima->image->tpageflag & IMA_TILES) {
902                 
903                 G.sima->flag |= SI_EDITTILE;
904                 
905                 while(get_mbut()&L_MOUSE) {
906                         
907                         calc_image_view(G.sima, 'f');
908                         
909                         getmouseco_areawin(mval);
910                         areamouseco_to_ipoco(G.v2d, mval, &fx, &fy);
911
912                         if(fx>=0.0 && fy>=0.0 && fx<1.0 && fy<1.0) {
913                         
914                                 fx= (fx)*G.sima->image->xrep;
915                                 fy= (fy)*G.sima->image->yrep;
916                                 
917                                 mval[0]= fx;
918                                 mval[1]= fy;
919                                 
920                                 G.sima->curtile= mval[1]*G.sima->image->xrep + mval[0];
921                         }
922
923                         scrarea_do_windraw(curarea);
924                         screen_swapbuffers();
925                 }
926                 
927                 G.sima->flag &= ~SI_EDITTILE;
928
929                 image_changed(G.sima, 1);
930
931                 allqueue(REDRAWVIEW3D, 0);
932                 scrarea_queue_winredraw(curarea);
933         }
934 }
935
936 void hide_tface_uv(int swap)
937 {
938         Mesh *me;
939         TFace *tface;
940         MFace *mface;
941         int a;
942
943         if( is_uv_tface_editing_allowed()==0 ) return;
944         me= get_mesh(OBACT);
945
946         if(swap) {
947                 mface= me->mface;
948                 for(a=me->totface, tface= me->tface; a>0; a--, tface++, mface++) {
949                         if(tface->flag & TF_SELECT) {
950                                 if((tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3))==0) {
951                                         if(!mface->v4)
952                                                 tface->flag &= ~TF_SELECT;
953                                         else if(!(tface->flag & TF_SEL4))
954                                                 tface->flag &= ~TF_SELECT;
955                                 }
956                         }
957                 }
958         } else {
959                 mface= me->mface;
960                 for(a=me->totface, tface= me->tface; a>0; a--, tface++, mface++) {
961                         if(tface->flag & TF_SELECT) {
962                                 if(tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3))
963                                                 tface->flag &= ~TF_SELECT;
964                                 else if(mface->v4 && tface->flag & TF_SEL4)
965                                                 tface->flag &= ~TF_SELECT;
966                         }
967                 }
968         }
969
970         BIF_undo_push("Hide UV");
971
972         object_tface_flags_changed(OBACT, 0);
973 }
974
975 void reveal_tface_uv(void)
976 {
977         Mesh *me;
978         TFace *tface;
979         MFace *mface;
980         int a;
981
982         if( is_uv_tface_editing_allowed()==0 ) return;
983         me= get_mesh(OBACT);
984
985         mface= me->mface;
986         for(a=me->totface, tface= me->tface; a>0; a--, tface++, mface++)
987                 if(!(tface->flag & TF_HIDE))
988                         if(!(tface->flag & TF_SELECT))
989                                 tface->flag |= (TF_SELECT|TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
990         
991         BIF_undo_push("Reveal UV");
992
993         object_tface_flags_changed(OBACT, 0);
994 }
995
996 void stitch_uv_tface(int mode)
997 {
998         MFace *mf;
999         TFace *tf, *tface;
1000         Mesh *me;
1001         int a, b, c, tot, vtot, vtot2;
1002         float newuv[2], limit[2], *uv, *uv1;
1003         struct uvvertsort *sortblock, *sb, *sb1, *sb2;
1004         
1005         if( is_uv_tface_editing_allowed()==0 ) return;
1006
1007         limit[0]= limit[1]= 20.0;
1008         if(mode==1) {
1009                 add_numbut(0, NUM|FLO, "Limit:", 0.1, 1000.0, &limit[0], NULL);
1010                 if (!do_clever_numbuts("Stitch UVs", 1, REDRAW))
1011                         return;
1012         }
1013
1014         if(G.sima->image && G.sima->image->ibuf && G.sima->image->ibuf->x > 0 &&
1015            G.sima->image->ibuf->y > 0) {
1016                 limit[1]= limit[0]/(float)G.sima->image->ibuf->y;
1017                 limit[0]= limit[0]/(float)G.sima->image->ibuf->x;
1018         }
1019         else
1020                 limit[0]= limit[1]= limit[0]/256.0;
1021         
1022         me= get_mesh(OBACT);
1023         tface= (TFace*)me->tface;
1024         
1025         tot= 0;
1026         mf= (MFace*)me->mface;
1027         tf= (TFace*)me->tface;
1028         for(a=me->totface; a>0; a--, tf++, mf++) {
1029                 if((tf->flag & TF_SELECT)) {
1030                         if(tf->flag & TF_SEL1) tot++;
1031                         if(tf->flag & TF_SEL2) tot++;
1032                         if(tf->flag & TF_SEL3) tot++;
1033                         if(mf->v4 && tf->flag & TF_SEL4) tot++; 
1034                 }
1035         }
1036         if(tot==0) return;
1037
1038         sb= sortblock= MEM_callocN(sizeof(struct uvvertsort)*tot,"sortstitchuv");
1039
1040         mf= (MFace*)me->mface;
1041         tf= (TFace*)me->tface;
1042         for(a=0; a<me->totface; a++, tf++, mf++) {
1043                 if((tf->flag & TF_SELECT)) {
1044                         if(tf->flag & TF_SEL1) {
1045                                 sb->v= mf->v1;
1046                                 sb->f= a;
1047                                 sb->tf_sel= 0;
1048                                 sb++;
1049                         }
1050                         if(tf->flag & TF_SEL2) {
1051                                 sb->v= mf->v2;
1052                                 sb->f= a;
1053                                 sb->tf_sel= 1;
1054                                 sb++;
1055                         }
1056                         if(tf->flag & TF_SEL3) {
1057                                 sb->v= mf->v3;
1058                                 sb->f= a;
1059                                 sb->tf_sel= 2;
1060                                 sb++;
1061                         }
1062                         if(mf->v4 && tf->flag & TF_SEL4) {
1063                                 sb->v= mf->v4;
1064                                 sb->f= a;
1065                                 sb->tf_sel= 3;
1066                                 sb++;
1067                         }
1068                 }
1069         }
1070         
1071         /* sort by vertex */
1072         qsort(sortblock, tot, sizeof(struct uvvertsort), compuvvert);
1073
1074         if(mode==0) {
1075                 for (a=0, sb=sortblock; a<tot; a+=vtot, sb+=vtot) {
1076                         newuv[0]= 0; newuv[1]= 0;
1077                         vtot= 0;
1078
1079                         for (b=a, sb1=sb; b<tot && sb1->v==sb->v; b++, sb1++) {
1080                                 newuv[0] += tface[sb1->f].uv[sb1->tf_sel][0];
1081                                 newuv[1] += tface[sb1->f].uv[sb1->tf_sel][1];
1082                                 vtot++;
1083                         }
1084
1085                         newuv[0] /= vtot; newuv[1] /= vtot;
1086
1087                         for (b=a, sb1=sb; b<a+vtot; b++, sb1++) {
1088                                 tface[sb1->f].uv[sb1->tf_sel][0]= newuv[0];
1089                                 tface[sb1->f].uv[sb1->tf_sel][1]= newuv[1];
1090                         }
1091                 }
1092         } else if(mode==1) {
1093                 for (a=0, sb=sortblock; a<tot; a+=vtot, sb+=vtot) {
1094                         vtot= 0;
1095                         for (b=a, sb1=sb; b<tot && sb1->v==sb->v; b++, sb1++)
1096                                 vtot++;
1097
1098                         for (b=a, sb1=sb; b<a+vtot; b++, sb1++) {
1099                                 if(sb1->flag & 2) continue;
1100
1101                                 newuv[0]= 0; newuv[1]= 0;
1102                                 vtot2 = 0;
1103
1104                                 for (c=b, sb2=sb1; c<a+vtot; c++, sb2++) {
1105                                         uv = tface[sb2->f].uv[sb2->tf_sel];
1106                                         uv1 = tface[sb1->f].uv[sb1->tf_sel];
1107                                         if (fabs(uv[0]-uv1[0]) < limit[0] &&
1108                                             fabs(uv[1]-uv1[1]) < limit[1]) {
1109                                                 newuv[0] += uv[0];
1110                                                 newuv[1] += uv[1];
1111                                                 sb2->flag |= 2;
1112                                                 sb2->flag |= 4;
1113                                                 vtot2++;
1114                                         }
1115                                 }
1116
1117                                 newuv[0] /= vtot2; newuv[1] /= vtot2;
1118
1119                                 for (c=b, sb2=sb1; c<a+vtot; c++, sb2++) {
1120                                         if(sb2->flag & 4) {
1121                                                 tface[sb2->f].uv[sb2->tf_sel][0]= newuv[0];
1122                                                 tface[sb2->f].uv[sb2->tf_sel][1]= newuv[1];
1123                                                 sb2->flag &= ~4;
1124                                         }
1125                                 }
1126                         }
1127                 }
1128         }
1129         MEM_freeN(sortblock);
1130
1131         if(G.sima->flag & SI_BE_SQUARE) be_square_tface_uv(me);
1132
1133         BIF_undo_push("Stitch UV");
1134
1135         object_uvs_changed(OBACT);
1136 }
1137
1138 void select_linked_tface_uv(int mode)
1139 {
1140         MFace *mf;
1141         TFace *tface, *tf, *nearesttf=NULL;
1142         Mesh *me;
1143         char sel, *linkflag;
1144         int a, b, c, tot, vtot, nearestv, nearestuv, i, nverts;
1145         float limit[2], *uv, *uv1;
1146         struct uvvertsort *sortblock, *sb, *sb1, *sb2;
1147         
1148         if( is_uv_tface_editing_allowed()==0 ) return;
1149
1150         me= get_mesh(OBACT);
1151         get_connected_limit_tface_uv(limit);
1152
1153         tot= 0;
1154         mf= (MFace*)me->mface;
1155         tf= (TFace*)me->tface;
1156         for(a=me->totface; a>0; a--, tf++, mf++)
1157                 if(tf->flag & TF_SELECT)
1158                         tot += mf->v4? 4: 3;
1159
1160         if(tot==0) return;
1161
1162         if (mode!=2) {
1163                 find_nearest_uv(&nearesttf, &nearestv, &nearestuv);
1164
1165                 if(nearesttf==NULL)
1166                         return;
1167         }
1168         else {
1169                 nearesttf= NULL;
1170                 nearestuv= 0;
1171         }
1172
1173         sb= sortblock= MEM_callocN(sizeof(struct uvvertsort)*tot, "sortsellinkuv");
1174         linkflag= MEM_callocN(sizeof(char)*me->totface, "linkflaguv");
1175
1176         mf= (MFace*)me->mface;
1177         tf= (TFace*)me->tface;
1178         for(a=0; a<me->totface; a++, tf++, mf++) {
1179                 if(!(tf->flag & TF_HIDE) && (tf->flag & TF_SELECT)) {
1180                         sel= 0;
1181                         sb1= sb;
1182                         nverts= mf->v4? 4: 3;
1183                         for(i=0; i<nverts; i++) {
1184                                 if(tf->flag & TF_SEL_MASK(i))
1185                                         sel= 1;
1186                                 sb->f= a;
1187                                 sb->tf_sel= i;
1188                                 sb++;
1189                         }
1190
1191                         if(nearesttf==tf || ((sel && mode==2)))
1192                                 linkflag[a] = 1;
1193
1194                         (sb1)->v= mf->v1;
1195                         (sb1+1)->v= mf->v2;
1196                         (sb1+2)->v= mf->v3;
1197                         if(mf->v4) (sb1+3)->v= mf->v4;
1198                 }
1199         }
1200         
1201         /* sort by vertex */
1202         qsort(sortblock, tot, sizeof(struct uvvertsort), compuvvert);
1203
1204         tface= (TFace*)me->tface;
1205         sel= 1;
1206         while(sel) {
1207                 sel= 0;
1208
1209                 /* select all tex vertices that are near a selected tex vertex */
1210                 for (a=0, sb=sortblock; a<tot; a+=vtot, sb+=vtot) {
1211                         vtot= 0;
1212                         for (b=a, sb1=sb; b<tot && sb1->v==sb->v; b++, sb1++)
1213                                 vtot++;
1214                         for (b=a, sb1=sb; b<a+vtot; b++, sb1++) {
1215                                 if(linkflag[sb1->f]) continue;
1216
1217                                 for (c=a, sb2=sb; c<a+vtot; c++, sb2++) {
1218                                         if(!(linkflag[sb2->f])) continue;
1219                                         
1220                                         uv = tface[sb2->f].uv[sb2->tf_sel];
1221                                         uv1 = tface[sb1->f].uv[sb1->tf_sel];
1222                                         if (fabs(uv[0]-uv1[0]) < limit[0] &&
1223                                             fabs(uv[1]-uv1[1]) < limit[1]) {
1224                                                 linkflag[sb1->f] = 1;
1225                                                 sel= 1;
1226                                                 break;
1227                                         }
1228                                 }
1229                         }
1230                 }
1231         }
1232
1233         if(mode==0 || mode==2) {
1234                 for(a=0, tf=tface; a<me->totface; a++, tf++)
1235                         if(linkflag[a])
1236                                 tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
1237                         else
1238                                 tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
1239         }
1240         else if(mode==1) {
1241                 for(a=0, tf=tface; a<me->totface; a++, tf++) {
1242                         if(linkflag[a]) {
1243                                 if (mf->v4) {
1244                                         if((tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)))
1245                                                 break;
1246                                 }
1247                                 else if(tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3))
1248                                         break;
1249                         }
1250                 }
1251
1252                 if (a<me->totface) {
1253                         for(a=0, tf=tface; a<me->totface; a++, tf++)
1254                                 if(linkflag[a])
1255                                         tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
1256                 }
1257                 else {
1258                         for(a=0, tf=tface; a<me->totface; a++, tf++)
1259                                 if(linkflag[a])
1260                                         tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
1261                 }
1262         }
1263         
1264         MEM_freeN(sortblock);
1265         MEM_freeN(linkflag);
1266
1267         BIF_undo_push("Select linked UV");
1268         scrarea_queue_winredraw(curarea);
1269 }
1270
1271 void unlink_selection(void)
1272 {
1273         Mesh *me;
1274         TFace *tface;
1275         MFace *mface;
1276         int a;
1277
1278         if( is_uv_tface_editing_allowed()==0 ) return;
1279         me= get_mesh(OBACT);
1280
1281         mface= me->mface;
1282         for(a=me->totface, tface= me->tface; a>0; a--, tface++, mface++) {
1283                 if(tface->flag & TF_SELECT) {
1284                         if(mface->v4) {
1285                                 if(~tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4))
1286                                         tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
1287                         } else {
1288                                 if(~tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3))
1289                                         tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3);
1290                         }
1291                 }
1292         }
1293         
1294         BIF_undo_push("Unlink UV selection");
1295         scrarea_queue_winredraw(curarea);
1296 }
1297
1298 void toggle_uv_select(int mode)
1299 {
1300         switch(mode){
1301         case 'f':
1302                 G.sima->flag ^= SI_SELACTFACE;
1303                 break;
1304         case 's':
1305                 G.sima->flag ^= SI_STICKYUVS; 
1306                 if (G.sima->flag & SI_STICKYUVS) G.sima->flag &= ~SI_LOCALSTICKY;
1307                 break;
1308         case 'l': 
1309                  G.sima->flag ^= SI_LOCALSTICKY;
1310                  if (G.sima->flag & SI_LOCALSTICKY) G.sima->flag &= ~SI_STICKYUVS;
1311                 break;
1312         case 'o':
1313                 G.sima->flag &= ~SI_STICKYUVS; 
1314                 G.sima->flag &= ~SI_LOCALSTICKY;
1315                 break;
1316         }
1317         allqueue(REDRAWIMAGE, 0);
1318 }
1319
1320 void pin_tface_uv(int mode)
1321 {
1322         Mesh *me;
1323         TFace *tface;
1324         MFace *mface;
1325         int a;
1326         
1327         if( is_uv_tface_editing_allowed()==0 ) return;
1328         me= get_mesh(OBACT);
1329         
1330         mface= me->mface;
1331         tface= me->tface;
1332         for(a=me->totface; a>0; a--, tface++, mface++) {
1333                 if(tface->flag & TF_SELECT) {
1334                         if(mode ==1){
1335                                 if(tface->flag & TF_SEL1) tface->unwrap |= TF_PIN1;
1336                                 if(tface->flag & TF_SEL2) tface->unwrap |= TF_PIN2;
1337                                 if(tface->flag & TF_SEL3) tface->unwrap |= TF_PIN3;
1338                                 if(mface->v4)
1339                                         if(tface->flag & TF_SEL4) tface->unwrap |= TF_PIN4;
1340                         }
1341                         else if (mode ==0){
1342                                 if(tface->flag & TF_SEL1) tface->unwrap &= ~TF_PIN1;
1343                                 if(tface->flag & TF_SEL2) tface->unwrap &= ~TF_PIN2;
1344                                 if(tface->flag & TF_SEL3) tface->unwrap &= ~TF_PIN3;
1345                                 if(mface->v4)
1346                                 if(tface->flag & TF_SEL4) tface->unwrap &= ~TF_PIN4;
1347                         }
1348                 }
1349         }
1350         
1351         BIF_undo_push("Pin UV");
1352         scrarea_queue_winredraw(curarea);
1353 }
1354
1355 int minmax_tface_uv(float *min, float *max)
1356 {
1357         Mesh *me;
1358         TFace *tf;
1359         MFace *mf;
1360         int a, sel;
1361
1362         if( is_uv_tface_editing_allowed()==0 ) return 0;
1363         me= get_mesh(OBACT);
1364
1365         INIT_MINMAX2(min, max);
1366
1367         sel= 0;
1368         mf= (MFace*)me->mface;
1369         tf= (TFace*)me->tface;
1370         for(a=me->totface; a>0; a--, tf++, mf++) {
1371                 if(tf->flag & TF_HIDE);
1372                 else if(tf->flag & TF_SELECT) {
1373
1374                         if (tf->flag & TF_SEL1) {
1375                                 DO_MINMAX2(tf->uv[0], min, max);
1376                         }
1377                         if (tf->flag & TF_SEL2) {
1378                                 DO_MINMAX2(tf->uv[1], min, max);
1379                         }
1380                         if (tf->flag & TF_SEL3) {
1381                                 DO_MINMAX2(tf->uv[2], min, max);
1382                         }
1383                         if (mf->v4 && tf->flag & TF_SEL4) {
1384                                 DO_MINMAX2(tf->uv[3], min, max);
1385                         }
1386
1387                         sel = 1;
1388                 }
1389         }
1390
1391         return sel;
1392 }
1393