- added DerivedMesh.drawUVEdges function & implementations
[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_mywindow.h"
78
79 #include "BSE_drawipo.h"
80 #include "BSE_edit.h"
81 #include "BSE_trans_types.h"
82
83 #include "BDR_editobject.h"
84 #include "BDR_unwrapper.h"
85
86 #include "blendef.h"
87 #include "mydevice.h"
88
89 struct uvvertsort {
90         unsigned int v, f;
91         unsigned char tf_sel;
92         char flag;
93 };
94
95 /* local prototypes */
96 void clever_numbuts_sima(void);
97 void sel_uvco_inside_radius(short , TFace *, int , float *, float *, short);
98 void uvedit_selectionCB(short , Object *, short *, float ); /* used in edit.c*/ 
99
100 static int compuvvert(const void *u1, const void *u2)
101 {
102         const struct uvvertsort *v1=u1, *v2=u2;
103         if (v1->v > v2->v) return 1;
104         else if (v1->v < v2->v) return -1;
105         return 0;
106 }
107
108 void object_uvs_changed(Object *ob)
109 {
110                 /* Unfortunately we also have to force an eval 
111                  * here because otherwise the modifier UVs might 
112                  * not be updated. Goes back to sillyness that 
113                  * recalc is done as part of view3d draw loop!
114                  *
115                  * Technically should scan all SpaceImas here.
116                  */
117         DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
118         if(G.sima && (G.sima->flag & SI_DRAWSHADOW)) {
119                 object_handle_update(ob);
120         }
121
122         allqueue(REDRAWVIEW3D, 0);
123         allqueue(REDRAWIMAGE, 0);
124 }
125
126 void object_tface_flags_changed(Object *ob, int updateButtons)
127 {
128         if (G.f&G_FACESELECT) {
129                 DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
130                 object_handle_update(ob);
131         }
132
133         if (updateButtons) allqueue(REDRAWBUTSEDIT, 0);
134         allqueue(REDRAWVIEW3D, 0);
135         allqueue(REDRAWIMAGE, 0);
136 }
137
138 int is_uv_tface_editing_allowed_silent(void)
139 {
140         Mesh *me;
141
142         if(G.obedit) return 0;
143         if(G.sima->mode!=SI_TEXTURE) return 0;
144         if(!(G.f & G_FACESELECT)) return 0;  
145         me= get_mesh(OBACT);
146         if(me==0 || me->tface==0) return 0;
147         
148         return 1;
149 }
150
151 int is_uv_tface_editing_allowed(void)
152 {
153         if(G.obedit) error("Unable to perform action in Edit Mode");
154
155         return is_uv_tface_editing_allowed_silent();
156 }
157
158 void get_connected_limit_tface_uv(float *limit)
159 {
160         if(G.sima->image && G.sima->image->ibuf && G.sima->image->ibuf->x > 0 &&
161            G.sima->image->ibuf->y > 0) {
162                 limit[0]= 0.05/(float)G.sima->image->ibuf->x;
163                 limit[1]= 0.05/(float)G.sima->image->ibuf->y;
164         }
165         else
166                 limit[0]= limit[1]= 0.05/256.0;
167 }
168
169 void clever_numbuts_sima(void)
170 {
171         float ocent[2], cent[2]= {0.0, 0.0};
172         int imx, imy;
173         int i, nactive= 0;
174         Mesh *me;
175         
176         if( is_uv_tface_editing_allowed()==0 ) return;
177         me= get_mesh(OBACT);
178         
179         if (G.sima->image && G.sima->image->ibuf) {
180                 imx= G.sima->image->ibuf->x;
181                 imy= G.sima->image->ibuf->y;
182         } else
183                 imx= imy= 256;
184         
185         for (i=0; i<me->totface; i++) {
186                 MFace *mf= &((MFace*) me->mface)[i];
187                 TFace *tf= &((TFace*) me->tface)[i];
188                 
189                 if (!mf->v3 || !(tf->flag & TF_SELECT))
190                         continue;
191                 
192                 if (tf->flag & TF_SEL1) {
193                         cent[0]+= tf->uv[0][0];
194                         cent[1]+= tf->uv[0][1];
195                         nactive++;
196                 }
197                 if (tf->flag & TF_SEL2) {
198                         cent[0]+= tf->uv[1][0];
199                         cent[1]+= tf->uv[1][1];
200                         nactive++;
201                 }
202                 if (tf->flag & TF_SEL3) {
203                         cent[0]+= tf->uv[2][0];
204                         cent[1]+= tf->uv[2][1];
205                         nactive++;
206                 }
207                 if (mf->v4 && (tf->flag & TF_SEL4)) {
208                         cent[0]+= tf->uv[3][0];
209                         cent[1]+= tf->uv[3][1];
210                         nactive++;
211                 }
212         }
213         
214         if (nactive) {
215                 cent[0]= (cent[0]*imx)/nactive;
216                 cent[1]= (cent[1]*imy)/nactive;
217
218                 add_numbut(0, NUM|FLO, "LocX:", -imx*20, imx*20, &cent[0], NULL);
219                 add_numbut(1, NUM|FLO, "LocY:", -imy*20, imy*20, &cent[1], NULL);
220                 
221                 ocent[0]= cent[0];
222                 ocent[1]= cent[1];
223                 if (do_clever_numbuts((nactive==1)?"Active Vertex":"Selected Center", 2, REDRAW)) {
224                         float delta[2];
225                         
226                         delta[0]= (cent[0]-ocent[0])/imx;
227                         delta[1]= (cent[1]-ocent[1])/imy;
228
229                         for (i=0; i<me->totface; i++) {
230                                 MFace *mf= &((MFace*) me->mface)[i];
231                                 TFace *tf= &((TFace*) me->tface)[i];
232                         
233                                 if (!mf->v3 || !(tf->flag & TF_SELECT))
234                                         continue;
235                         
236                                 if (tf->flag & TF_SEL1) {
237                                         tf->uv[0][0]+= delta[0];
238                                         tf->uv[0][1]+= delta[1];
239                                 }
240                                 if (tf->flag & TF_SEL2) {
241                                         tf->uv[1][0]+= delta[0];
242                                         tf->uv[1][1]+= delta[1];
243                                 }
244                                 if (tf->flag & TF_SEL3) {
245                                         tf->uv[2][0]+= delta[0];
246                                         tf->uv[2][1]+= delta[1];
247                                 }
248                                 if (mf->v4 && (tf->flag & TF_SEL4)) {
249                                         tf->uv[3][0]+= delta[0];
250                                         tf->uv[3][1]+= delta[1];
251                                 }
252                         }
253                         
254                         object_uvs_changed(OBACT);
255                 }
256         }
257 }
258
259 static void sima_pixelgrid(float *loc, float sx, float sy)
260 {
261         float y;
262         float x;
263
264         if(G.sima->flag & SI_PIXELSNAP) {
265                 if(G.sima->image && G.sima->image->ibuf) {
266                         x= G.sima->image->ibuf->x;
267                         y= G.sima->image->ibuf->y;
268                 
269                         sx= floor(x*sx)/x;
270                         if(G.sima->flag & SI_CLIP_UV) {
271                                 CLAMP(sx, 0, 1.0);
272                         }
273                         loc[0]= sx;
274                         
275                         sy= floor(y*sy)/y;
276                         if(G.sima->flag & SI_CLIP_UV) {
277                                 CLAMP(sy, 0, 1.0);
278                         }
279                         loc[1]= sy;
280                 }
281                 else {
282                         loc[0]= sx;
283                         loc[1]= sy;
284                 }
285         }
286         else {
287                 loc[0]= sx;
288                 loc[1]= sy;
289         }
290 }
291
292
293 static void be_square_tface_uv(Mesh *me)
294 {
295         TFace *tface;
296         MFace *mface;
297         int a;
298         
299         /* if 1 vertex selected: doit (with the selected vertex) */
300         mface= (MFace*)me->mface;
301         tface= (TFace*)me->tface;
302         for(a=me->totface; a>0; a--, tface++, mface++) {
303                 if(mface->v4) {
304                         if(tface->flag & TF_SELECT) {
305                                 if(tface->flag & TF_SEL1) {
306                                         if( tface->uv[1][0] == tface->uv[2][0] ) {
307                                                 tface->uv[1][1]= tface->uv[0][1];
308                                                 tface->uv[3][0]= tface->uv[0][0];
309                                         }
310                                         else {  
311                                                 tface->uv[1][0]= tface->uv[0][0];
312                                                 tface->uv[3][1]= tface->uv[0][1];
313                                         }
314                                         
315                                 }
316                                 if(tface->flag & TF_SEL2) {
317                                         if( tface->uv[2][1] == tface->uv[3][1] ) {
318                                                 tface->uv[2][0]= tface->uv[1][0];
319                                                 tface->uv[0][1]= tface->uv[1][1];
320                                         }
321                                         else {
322                                                 tface->uv[2][1]= tface->uv[1][1];
323                                                 tface->uv[0][0]= tface->uv[1][0];
324                                         }
325
326                                 }
327                                 if(tface->flag & TF_SEL3) {
328                                         if( tface->uv[3][0] == tface->uv[0][0] ) {
329                                                 tface->uv[3][1]= tface->uv[2][1];
330                                                 tface->uv[1][0]= tface->uv[2][0];
331                                         }
332                                         else {
333                                                 tface->uv[3][0]= tface->uv[2][0];
334                                                 tface->uv[1][1]= tface->uv[2][1];
335                                         }
336                                 }
337                                 if(tface->flag & TF_SEL4) {
338                                         if( tface->uv[0][1] == tface->uv[1][1] ) {
339                                                 tface->uv[0][0]= tface->uv[3][0];
340                                                 tface->uv[2][1]= tface->uv[3][1];
341                                         }
342                                         else  {
343                                                 tface->uv[0][1]= tface->uv[3][1];
344                                                 tface->uv[2][0]= tface->uv[3][0];
345                                         }
346
347                                 }
348                         }
349                 }
350         }
351
352 }
353
354 void tface_do_clip(void)
355 {
356         Mesh *me;
357         TFace *tface;
358         int a, b;
359         
360         if( is_uv_tface_editing_allowed()==0 ) return;
361         me= get_mesh(OBACT);
362         tface= me->tface;
363         
364         for(a=0; a<me->totface; a++, tface++) {
365                 if(tface->flag & TF_SELECT) {
366                         for(b=0; b<4; b++) {
367                                 CLAMP(tface->uv[b][0], 0.0, 1.0);
368                                 CLAMP(tface->uv[b][1], 0.0, 1.0);
369                         }
370                 }
371         }
372         
373 }
374
375 void transform_tface_uv(int mode, int context)  // 2 args, for callback
376 {
377         MFace *mface;
378         TFace *tface;
379         Mesh *me;
380         TransVert *transmain, *tv;
381
382         float dist, xdist, ydist, aspx, aspy;
383         float asp, dx1, dx2, dy1, dy2, phi, dphi, co, si;
384         float size[2], sizefac;
385         float dx, dy, dvec2[2], dvec[2], div, cent[2];
386         float x, y, min[2], max[2], vec[2], xtra[2], ivec[2];
387         int xim, yim, tot=0, a, b, firsttime=1, afbreek=0;
388         int propmode= 0, proptot= 0, midtog= 0, proj= 0, prop_recalc= 1;
389         unsigned short event = 0;
390         short mval[2], val, xo, yo, xn, yn, xc, yc;
391         char str[80];
392         extern float prop_size, prop_cent[3]; 
393         
394         if( is_uv_tface_editing_allowed()==0 ) return;
395         me= get_mesh(OBACT);
396         
397         if(G.scene->proportional) propmode= 1;
398         
399         min[0]= min[1]= 10000.0;
400         max[0]= max[1]= -10000.0;
401         
402         calc_image_view(G.sima, 'f');
403         
404         if(G.sima->image && G.sima->image->ibuf) {
405                 xim= G.sima->image->ibuf->x;
406                 yim= G.sima->image->ibuf->y;
407         }
408         else {
409                 xim= yim= 256;
410         }
411         aspx = (float)xim/256.0;
412         aspy = (float)yim/256.0;
413
414         /* which vertices are involved? */
415         tface= me->tface;
416         mface= me->mface;
417         for(a=me->totface; a>0; a--, tface++, mface++) {
418                 if(mface->v3 && tface->flag & TF_SELECT) {
419                         if(tface->flag & TF_SEL1) tot++;
420                         if(tface->flag & TF_SEL2) tot++;
421                         if(tface->flag & TF_SEL3) tot++;
422                         if(mface->v4 && (tface->flag & TF_SEL4)) tot++;
423                         if(propmode) {
424                                 if(mface->v4) proptot+=4;
425                                 else proptot+=3;
426                         }
427                 }
428         }
429         if(tot==0) return;
430         if(propmode) tot= proptot;
431
432         G.moving= 1;
433         prop_size/= 3;
434         
435         tv=transmain= MEM_callocN(tot*sizeof(TransVert), "transmain");
436
437         tface= me->tface;
438         mface= me->mface;
439         for(a=me->totface; a>0; a--, tface++, mface++) {
440                 if(mface->v3 && tface->flag & TF_SELECT) {
441                         if (tface->flag & TF_SEL1 || propmode) {
442                                 tv->loc= tface->uv[0];
443                                 if(tface->flag & TF_SEL1) tv->flag= 1;
444                                 tv++;
445                         }
446                         if (tface->flag & TF_SEL2 || propmode) {
447                                 tv->loc= tface->uv[1];
448                                 if(tface->flag & TF_SEL2) tv->flag= 1;
449                                 tv++;
450                         }
451                         if (tface->flag & TF_SEL3 || propmode) {
452                                 tv->loc= tface->uv[2];
453                                 if(tface->flag & TF_SEL3) tv->flag= 1;
454                                 tv++;
455                         }
456                         if(mface->v4) {
457                                 if (tface->flag & TF_SEL4 || propmode) {
458                                         tv->loc= tface->uv[3];
459                                         if(tface->flag & TF_SEL4) tv->flag= 1;
460                                         tv++;
461                                 }
462                         }
463                 }
464         }
465         
466         a= tot;
467         tv= transmain;
468         while(a--) {
469                 tv->oldloc[0]= tv->loc[0];
470                 tv->oldloc[1]= tv->loc[1];
471                 if(tv->flag) {
472                         DO_MINMAX2(tv->loc, min, max);
473                 }
474                 tv++;
475         }
476
477         cent[0]= (min[0]+max[0])/2.0;
478         cent[1]= (min[1]+max[1])/2.0;
479         prop_cent[0]= cent[0];
480         prop_cent[1]= cent[1];
481
482         ipoco_to_areaco_noclip(G.v2d, cent, mval);
483         xc= mval[0];
484         yc= mval[1];
485         
486         getmouseco_areawin(mval);
487         xo= xn= mval[0];
488         yo= yn= mval[1];
489         dvec[0]= dvec[1]= 0.0;
490         dx1= xc-xn; 
491         dy1= yc-yn;
492         phi= 0.0;
493         
494         
495         sizefac= sqrt( (float)((yc-yn)*(yc-yn)+(xn-xc)*(xn-xc)) );
496         if(sizefac<2.0) sizefac= 2.0;
497
498         while(afbreek==0) {
499                 getmouseco_areawin(mval);
500                 if((mval[0]!=xo || mval[1]!=yo) || firsttime) {
501                         if(propmode && prop_recalc && transmain) {
502                                 a= tot;
503                                 tv= transmain;
504
505                                 while(a--) {
506                                         if(tv->oldloc[0]<min[0]) xdist= tv->oldloc[0]-min[0];
507                                         else if(tv->oldloc[0]>max[0]) xdist= tv->oldloc[0]-max[0];
508                                         else xdist= 0.0;
509                                         xdist*= aspx;
510
511                                         if(tv->oldloc[1]<min[1]) ydist= tv->oldloc[1]-min[1];
512                                         else if(tv->oldloc[1]>max[1]) ydist= tv->oldloc[1]-max[1];
513                                         else ydist= 0.0;
514                                         ydist*= aspy;
515
516                                         dist= sqrt(xdist*xdist + ydist*ydist);
517                                         if(dist==0.0) tv->fac= 1.0;
518                                         else if(dist > prop_size) tv->fac= 0.0;
519                                         else {
520                                                 dist= (prop_size-dist)/prop_size;
521
522                                                 switch(G.scene->prop_mode) {
523                                                 case PROP_SHARP:
524                                                         tv->fac= dist*dist;
525                                                         break;
526                                                 case PROP_SMOOTH:
527                                                         tv->fac= 3.0f*dist*dist - 2.0f*dist*dist*dist;
528                                                         break;
529                                                 case PROP_ROOT:
530                                                         tv->fac= (float)sqrt(dist);
531                                                         break;
532                                                 case PROP_LIN:
533                                                         tv->fac= dist;
534                                                         break;
535                                                 case PROP_CONST:
536                                                         tv->fac= 1.0f;
537                                                         break;
538                                                 case PROP_SPHERE:
539                                                         tv->fac= (float)sqrt(2*dist - dist * dist);
540                                                         break;
541                                                 default:
542                                                         tv->fac= 1;
543                                                 }
544                                         }
545                                         tv++;
546                                 }
547                                 prop_recalc= 0;
548                         }
549                         if(mode=='g') {
550                         
551                                 dx= mval[0]- xo;
552                                 dy= mval[1]- yo;
553         
554                                 div= G.v2d->mask.xmax-G.v2d->mask.xmin;
555                                 dvec[0]+= (G.v2d->cur.xmax-G.v2d->cur.xmin)*(dx)/div;
556         
557                                 div= G.v2d->mask.ymax-G.v2d->mask.ymin;
558                                 dvec[1]+= (G.v2d->cur.ymax-G.v2d->cur.ymin)*(dy)/div;
559                                 
560                                 if(midtog) dvec[proj]= 0.0;
561                                 
562                                 dvec2[0]= dvec[0];
563                                 dvec2[1]= dvec[1];
564                                 apply_keyb_grid(dvec2, 0.0, 1.0/8.0, 1.0/16.0, U.flag & USER_AUTOGRABGRID);
565                                 apply_keyb_grid(dvec2+1, 0.0, 1.0/8.0, 1.0/16.0, U.flag & USER_AUTOGRABGRID);
566
567                                 vec[0]= dvec2[0];
568                                 vec[1]= dvec2[1];
569                                 
570                                 if(G.sima->flag & SI_CLIP_UV) {
571                                         if(vec[0]< -min[0]) vec[0]= -min[0];
572                                         if(vec[1]< -min[1]) vec[1]= -min[1];
573                                         if(vec[0]> 1.0-max[0]) vec[0]= 1.0-max[0];
574                                         if(vec[1]> 1.0-max[1]) vec[1]= 1.0-max[1];
575                                 }
576                                 tv= transmain;
577                                 if (propmode) {
578                                         for(a=0; a<tot; a++, tv++) {
579                                                 x= tv->oldloc[0]+tv->fac*vec[0];
580                                                 y= tv->oldloc[1]+tv->fac*vec[1];
581                                                 
582                                                 sima_pixelgrid(tv->loc, x, y);
583                                         }
584                                 } else {
585                                         for(a=0; a<tot; a++, tv++) {
586                                                 x= tv->oldloc[0]+vec[0];
587                                                 y= tv->oldloc[1]+vec[1];
588                                                 
589                                                 sima_pixelgrid(tv->loc, x, y);
590                                         }
591                                 }
592                                         
593                                 if(G.sima->flag & SI_BE_SQUARE) be_square_tface_uv(me);
594         
595                                 if (G.sima->flag & SI_COORDFLOATS) {
596                                         ivec[0]= vec[0];
597                                         ivec[1]= vec[1];
598                                 }
599                                 else {
600                                         ivec[0]= (vec[0]*xim);
601                                         ivec[1]= (vec[1]*yim);
602                                 }
603                 
604                                 sprintf(str, "X: %.4f   Y: %.4f  ", ivec[0], ivec[1]);
605                                 headerprint(str);
606                         }
607                         else if(mode=='r') {
608
609                                 dx2= xc-mval[0];
610                                 dy2= yc-mval[1];
611                                 
612                                 div= sqrt( (dx1*dx1+dy1*dy1)*(dx2*dx2+dy2*dy2));
613                                 if(div>1.0) {
614                                 
615                                         dphi= (dx1*dx2+dy1*dy2)/div;
616                                         dphi= saacos(dphi);
617                                         if( (dx1*dy2-dx2*dy1)<0.0 ) dphi= -dphi;
618                                         
619                                         if(G.qual & LR_SHIFTKEY) phi+= dphi/30.0;
620                                         else phi+= dphi;
621
622                                         apply_keyb_grid(&phi, 0.0, (5.0/180)*M_PI, (1.0/180)*M_PI, U.flag & USER_AUTOROTGRID);
623                                         
624                                         dx1= dx2; 
625                                         dy1= dy2;
626                                         
627                                         co= cos(phi);
628                                         si= sin(phi);
629                                         asp= (float)yim/(float)xim;
630
631                                         tv= transmain;
632                                         for(a=0; a<tot; a++, tv++) {
633                                                 if(propmode) {
634                                                         co= cos(phi*tv->fac);
635                                                         si= sin(phi*tv->fac);
636                                                 }
637                                                 x= ( co*( tv->oldloc[0]-cent[0]) - si*asp*(tv->oldloc[1]-cent[1]) ) +cent[0];
638                                                 y= ( si*( tv->oldloc[0]-cent[0])/asp + co*(tv->oldloc[1]-cent[1]) ) +cent[1];
639                                                 sima_pixelgrid(tv->loc, x, y);
640                                                 
641                                                 if(G.sima->flag & SI_CLIP_UV) {
642                                                         if(tv->loc[0]<0.0) tv->loc[0]= 0.0;
643                                                         else if(tv->loc[0]>1.0) tv->loc[0]= 1.0;
644                                                         if(tv->loc[1]<0.0) tv->loc[1]= 0.0;
645                                                         else if(tv->loc[1]>1.0) tv->loc[1]= 1.0;
646                                                 }
647                                         }                                       
648                                         
649                                         sprintf(str, "Rot: %.3f  ", phi*180.0/M_PI);
650                                         headerprint(str);
651                                 }
652                         }
653                         else if(mode=='s') {
654                                 size[0]= size[1]= (sqrt((float)((yc-mval[1])*(yc-mval[1])+(mval[0]-xc)*(mval[0]-xc))))/sizefac;
655                                 if(midtog) size[proj]= 1.0;
656                                 
657                                 apply_keyb_grid(size, 0.0, 0.1, 0.01, U.flag & USER_AUTOSIZEGRID);
658                                 apply_keyb_grid(size+1, 0.0, 0.1, 0.01, U.flag & USER_AUTOSIZEGRID);
659
660                                 xtra[0]= xtra[1]= 0;
661
662                                 if(G.sima->flag & SI_CLIP_UV) {
663                                         /* boundbox limit: four step plan: XTRA X */
664         
665                                         a=b= 0;
666                                         if(size[0]*(min[0]-cent[0]) + cent[0] + xtra[0] < 0) 
667                                                 a= -size[0]*(min[0]-cent[0]) - cent[0];
668                                         if(size[0]*(max[0]-cent[0]) + cent[0] + xtra[0] > 1.0) 
669                                                 b= 1.0 - size[0]*(max[0]-cent[0]) - cent[0];
670                                         xtra[0]= (a+b)/2;
671                                         
672                                         /* SIZE X */
673                                         if(size[0]*(min[0]-cent[0]) + cent[0] + xtra[0] < 0) 
674                                                 size[0]= (-cent[0]-xtra[0])/(min[0]-cent[0]);
675                                         if(size[0]*(max[0]-cent[0]) + cent[0] +xtra[0] > 1.0) 
676                                                 size[0]= (1.0-cent[0]-xtra[0])/(max[0]-cent[0]);
677                                                 
678                                         /* XTRA Y */
679                                         a=b= 0;
680                                         if(size[1]*(min[1]-cent[1]) + cent[1] + xtra[1] < 0) 
681                                                 a= -size[1]*(min[1]-cent[1]) - cent[1];
682                                         if(size[1]*(max[1]-cent[1]) + cent[1] + xtra[1] > 1.0) 
683                                                 b= 1.0 - size[1]*(max[1]-cent[1]) - cent[1];
684                                         xtra[1]= (a+b)/2;
685                                         
686                                         /* SIZE Y */
687                                         if(size[1]*(min[1]-cent[1]) + cent[1] +xtra[1] < 0) 
688                                                 size[1]= (-cent[1]-xtra[1])/(min[1]-cent[1]);
689                                         if(size[1]*(max[1]-cent[1]) + cent[1] + xtra[1]> 1.0) 
690                                                 size[1]= (1.0-cent[1]-xtra[1])/(max[1]-cent[1]);
691                                 }
692
693                                 /* if(midtog==0) { */
694                                 /*      if(size[1]>size[0]) size[1]= size[0]; */
695                                 /*      else if(size[0]>size[1]) size[0]= size[1]; */
696                                 /* } */
697
698                                 tv= transmain;
699                                 if (propmode) {
700                                         for(a=0; a<tot; a++, tv++) {
701                                         
702                                                 x= (tv->fac*size[0] + 1.00-tv->fac)*(tv->oldloc[0]-cent[0])+ cent[0] + xtra[0];
703                                                 y= (tv->fac*size[1] + 1.00-tv->fac)*(tv->oldloc[1]-cent[1])+ cent[1] + xtra[1];
704                                                 sima_pixelgrid(tv->loc, x, y);
705                                         }
706
707                                 } else {
708                                         for(a=0; a<tot; a++, tv++) {
709                                         
710                                                 x= size[0]*(tv->oldloc[0]-cent[0])+ cent[0] + xtra[0];
711                                                 y= size[1]*(tv->oldloc[1]-cent[1])+ cent[1] + xtra[1];
712                                                 sima_pixelgrid(tv->loc, x, y);
713                                         }
714                                 }
715                                 
716                                 sprintf(str, "sizeX: %.3f   sizeY: %.3f", size[0], size[1]);
717                                 headerprint(str);
718                         }
719
720                         xo= mval[0];
721                         yo= mval[1];
722                         
723                                 /* Need to force a recalculate since we may be 
724                                  * drawing modified UVs.
725                                  */
726                         if(G.sima->flag & SI_DRAWSHADOW){
727                                 DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);        
728                                 object_handle_update(OBACT);
729                         }
730
731                         if(G.sima->lock) {
732                                 force_draw_plus(SPACE_VIEW3D, 0);
733                         }
734                         else force_draw(0);
735                         
736                         firsttime= 0;
737                         
738                 }
739                 else BIF_wait_for_statechange();
740                 
741                 while(qtest()) {
742                         event= extern_qread(&val);
743                         if(val) {
744                                 switch(event) {
745                                 case ESCKEY:
746                                 case RIGHTMOUSE:
747                                 case LEFTMOUSE:
748                                 case SPACEKEY:
749                                 case RETKEY:
750                                         afbreek= 1;
751                                         break;
752                                 case MIDDLEMOUSE:
753                                         midtog= ~midtog;
754                                         if(midtog) {
755                                                 if( abs(mval[0]-xn) > abs(mval[1]-yn)) proj= 1;
756                                                 else proj= 0;
757                                                 firsttime= 1;
758                                         }
759                                         break;
760                                 case WHEELDOWNMOUSE:
761                                 case PADPLUSKEY:
762                                         if(propmode) {
763                                                 prop_size*= 1.1;
764                                                 prop_recalc= 1;
765                                                 firsttime= 1;
766                                         }
767                                         break;
768                                 case WHEELUPMOUSE:
769                                 case PADMINUS:
770                                         if(propmode) {
771                                                 prop_size*= 0.90909090;
772                                                 prop_recalc= 1;
773                                                 firsttime= 1;
774                                         }
775                                         break;
776                                 case WKEY:
777                                 case XKEY:
778                                 case YKEY:
779                                         if(midtog) {
780                                                 if(event==XKEY) {
781                                                         if(proj==1) midtog= ~midtog;
782                                                         else if(proj==0) proj= 1;
783                                                 }
784                                                 else if(event==YKEY) {
785                                                         if(proj==0) midtog= ~midtog;
786                                                         else if(proj==1) proj= 0;
787                                                 }
788                                         }
789                                         else {
790                                                 if(event==XKEY) {
791                                                         midtog= ~midtog;
792                                                         proj= 1;
793                                                 }
794                                                 else if(event==YKEY) {
795                                                         midtog= ~midtog;
796                                                         proj= 0;
797                                                 }
798                                         }
799                                         firsttime= 1;
800                                         break;
801                                 default:
802                                         arrows_move_cursor(event);
803                                 }
804                         }
805
806                         if(afbreek) break;
807                 }
808         }
809         
810         if(event==ESCKEY || event == RIGHTMOUSE) {
811                 tv= transmain;
812                 for(a=0; a<tot; a++, tv++) {
813                         tv->loc[0]= tv->oldloc[0];
814                         tv->loc[1]= tv->oldloc[1];
815                 }
816         }
817
818         MEM_freeN(transmain);
819         
820         if(mode=='g') if(G.sima->flag & SI_BE_SQUARE) be_square_tface_uv(me);
821
822         G.moving= 0;
823         prop_size*= 3;
824         
825         object_uvs_changed(OBACT);
826
827         if(event!=ESCKEY && event!=RIGHTMOUSE)
828                 BIF_undo_push("Transform UV");
829 }
830
831 void mirror_tface_uv(char mirroraxis)
832 {
833         MFace *mface;
834         TFace *tface;
835         Mesh *me;
836         float min[2], max[2], cent[2];
837         int a, axis;
838         
839         if( is_uv_tface_editing_allowed()==0 ) return;
840         me= get_mesh(OBACT);
841         
842         if (!minmax_tface_uv(min, max))
843                 return;
844
845         cent[0]= min[0]+max[0];
846         cent[1]= min[1]+max[1];
847
848         if(mirroraxis=='x') axis= 0;
849         else axis= 1;
850
851         tface= me->tface;
852         mface= me->mface;
853         for(a=me->totface; a>0; a--, tface++, mface++) {
854                 if(tface->flag & TF_SELECT) {
855                         if(tface->flag & TF_SEL1)
856                                 tface->uv[0][axis]= cent[axis] - tface->uv[0][axis];
857                         if(tface->flag & TF_SEL2)
858                                 tface->uv[1][axis]= cent[axis] - tface->uv[1][axis];
859                         if(tface->flag & TF_SEL3)
860                                 tface->uv[2][axis]= cent[axis] - tface->uv[2][axis];
861                         if(mface->v4 && (tface->flag & TF_SEL4))
862                                 tface->uv[3][axis]= cent[axis] - tface->uv[3][axis];
863                 }
864         }
865
866         object_uvs_changed(OBACT);
867 }
868
869 void mirrormenu_tface_uv(void)
870 {
871         short mode= 0;
872
873         if( is_uv_tface_editing_allowed()==0 ) return;
874
875         mode= pupmenu("Mirror%t|X Axis%x1|Y Axis%x2|");
876
877         if(mode==-1) return;
878
879         if(mode==1) mirror_tface_uv('x');
880         else if(mode==2) mirror_tface_uv('y');
881
882         BIF_undo_push("Mirror UV");
883 }
884
885 void weld_align_tface_uv(char tool)
886 {
887         MFace *mface;
888         TFace *tface;
889         Mesh *me;
890         float min[2], max[2], cent[2];
891         int a;
892         
893         if( is_uv_tface_editing_allowed()==0 ) return;
894         me= get_mesh(OBACT);
895
896         if (!minmax_tface_uv(min, max))
897                 return;
898
899         cent[0]= (min[0]+max[0])/2.0;
900         cent[1]= (min[1]+max[1])/2.0;
901
902         if(tool == 'x' || tool == 'w') {
903                 tface= me->tface;
904                 mface= me->mface;
905                 for(a=me->totface; a>0; a--, tface++, mface++) {
906                         if(tface->flag & TF_SELECT) {
907                                 if(tface->flag & TF_SEL1)
908                                         tface->uv[0][0]= cent[0];
909                                 if(tface->flag & TF_SEL2)
910                                         tface->uv[1][0]= cent[0];
911                                 if(tface->flag & TF_SEL3)
912                                         tface->uv[2][0]= cent[0];
913                                 if(mface->v4 && (tface->flag & TF_SEL4))
914                                         tface->uv[3][0]= cent[0];
915                         }
916                 }
917         }
918
919         if(tool == 'y' || tool == 'w') {
920                 tface= me->tface;
921                 mface= me->mface;
922                 for(a=me->totface; a>0; a--, tface++, mface++) {
923                         if(tface->flag & TF_SELECT) {
924                                 if(tface->flag & TF_SEL1)
925                                         tface->uv[0][1]= cent[1];
926                                 if(tface->flag & TF_SEL2)
927                                         tface->uv[1][1]= cent[1];
928                                 if(tface->flag & TF_SEL3)
929                                         tface->uv[2][1]= cent[1];
930                                 if(mface->v4 && (tface->flag & TF_SEL4))
931                                         tface->uv[3][1]= cent[1];
932                         }
933                 }
934         }
935
936         object_uvs_changed(OBACT);
937 }
938
939 void weld_align_menu_tface_uv(void)
940 {
941         short mode= 0;
942
943         if( is_uv_tface_editing_allowed()==0 ) return;
944
945         mode= pupmenu("Weld/Align%t|Weld%x1|Align X%x2|Align Y%x3|");
946
947         if(mode==-1) return;
948
949         if(mode==1) weld_align_tface_uv('w');
950         else if(mode==2) weld_align_tface_uv('x');
951         else if(mode==3) weld_align_tface_uv('y');
952
953         if(mode==1) BIF_undo_push("Weld UV");
954         else if(mode==2 || mode==3) BIF_undo_push("Align UV");
955 }
956 void select_swap_tface_uv(void)
957 {
958         Mesh *me;
959         TFace *tface;
960         MFace *mface;
961         int a, sel=0;
962         
963         if( is_uv_tface_editing_allowed()==0 ) return;
964         me= get_mesh(OBACT);
965
966         for(a=me->totface, tface= me->tface; a>0; a--, tface++) {
967                 if(tface->flag & TF_SELECT) {   
968                         if(tface->flag & (TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4)) {
969                                 sel= 1;
970                                 break;
971                         }
972                 }
973         }
974         
975         mface= me->mface;
976         for(a=me->totface, tface= me->tface; a>0; a--, tface++, mface++) {
977                 if(tface->flag & TF_SELECT) {
978                         if(mface->v4) {
979                                 if(sel) tface->flag &= ~(TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4);
980                                 else tface->flag |= (TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4);
981                         }
982                         else if(mface->v3) {
983                                 if(sel) tface->flag &= ~(TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4);
984                                 else tface->flag |= (TF_SEL1+TF_SEL2+TF_SEL3);
985                         }
986                 }
987         }
988         
989         BIF_undo_push("Select swap UV");
990
991         allqueue(REDRAWIMAGE, 0);
992 }
993
994 static int msel_hit(float *limit, unsigned int *hitarray, unsigned int vertexid, float **uv, float *uv2)
995 {
996         int i;
997         for(i=0; i< 4; i++) {
998                 if(hitarray[i] == vertexid) {
999                         if(G.sima->flag & SI_LOCALSTICKY) {
1000                                 if(fabs(uv[i][0]-uv2[0]) < limit[0] &&
1001                             fabs(uv[i][1]-uv2[1]) < limit[1])
1002                                         return 1;
1003                         }
1004                         else return 1;
1005                 }
1006         }
1007         return 0;
1008 }
1009
1010 static void find_nearest_tface(TFace **nearesttf, MFace **nearestmf)
1011 {
1012         Mesh *me;
1013         TFace *tf;
1014         MFace *mf;
1015         int a, i, nverts, mindist, dist, fcenter[2];
1016         short mval[2], uval[2];
1017
1018         getmouseco_areawin(mval);       
1019
1020         mindist= 0x7FFFFFF;
1021         *nearesttf= NULL;
1022         *nearestmf= NULL;
1023
1024         me= get_mesh(OBACT);
1025         mf= (MFace*)me->mface;
1026         tf= (TFace*)me->tface;
1027
1028         for(a=me->totface; a>0; a--, tf++, mf++) {
1029                 if(tf->flag & TF_SELECT && mf->v3) {
1030
1031                         fcenter[0]= fcenter[1]= 0;
1032                         nverts= mf->v4? 4: 3;
1033                         for(i=0; i<nverts; i++) {
1034                                 uvco_to_areaco_noclip(tf->uv[i], uval);
1035                                 fcenter[0] += uval[0];
1036                                 fcenter[1] += uval[1];
1037                         }
1038
1039                         fcenter[0] /= nverts;
1040                         fcenter[1] /= nverts;
1041
1042                         dist= abs(mval[0]- fcenter[0])+ abs(mval[1]- fcenter[1]);
1043                         if (dist < mindist) {
1044                                 *nearesttf= tf;
1045                                 *nearestmf= mf;
1046                                 mindist= dist;
1047                         }
1048                 }
1049         }
1050 }
1051
1052 static int nearest_uv_between(TFace *tf, int nverts, int id, short *mval, short *uval)
1053 {
1054         float m[3], v1[3], v2[3], c1, c2;
1055         int id1, id2;
1056
1057         id1= (id+nverts-1)%nverts;
1058         id2= (id+nverts+1)%nverts;
1059
1060         m[0] = (float)(mval[0]-uval[0]);
1061         m[1] = (float)(mval[1]-uval[1]);
1062         Vec2Subf(v1, tf->uv[id1], tf->uv[id]);
1063         Vec2Subf(v2, tf->uv[id2], tf->uv[id]);
1064
1065         /* m and v2 on same side of v-v1? */
1066         c1= v1[0]*m[1] - v1[1]*m[0];
1067         c2= v1[0]*v2[1] - v1[1]*v2[0];
1068
1069         if (c1*c2 < 0.0f)
1070                 return 0;
1071
1072         /* m and v1 on same side of v-v2? */
1073         c1= v2[0]*m[1] - v2[1]*m[0];
1074         c2= v2[0]*v1[1] - v2[1]*v1[0];
1075
1076         return (c1*c2 >= 0.0f);
1077 }
1078
1079 static void find_nearest_uv(TFace **nearesttf, unsigned int *nearestv, int *nearestuv)
1080 {
1081         Mesh *me;
1082         TFace *tf;
1083         MFace *mf;
1084         int a, i, nverts, mindist, dist;
1085         short mval[2], uval[2];
1086
1087         getmouseco_areawin(mval);       
1088
1089         mindist= 0x7FFFFFF;
1090         *nearesttf= NULL;
1091
1092         me= get_mesh(OBACT);
1093         mf= (MFace*)me->mface;
1094         tf= (TFace*)me->tface;
1095
1096         for(a=me->totface; a>0; a--, tf++, mf++) {
1097                 if(tf->flag & TF_SELECT && mf->v3) {
1098
1099                         nverts= mf->v4? 4: 3;
1100                         for(i=0; i<nverts; i++) {
1101                                 uvco_to_areaco_noclip(tf->uv[i], uval);
1102                                 dist= abs(mval[0]-uval[0]) + abs(mval[1]-uval[1]);
1103
1104                                 if(tf->flag & TF_SEL_MASK(i))
1105                                         dist += 5;
1106
1107                                 if(dist<=mindist) {
1108                                         if(dist==mindist)
1109                                                 if (!nearest_uv_between(tf, nverts, i, mval, uval))
1110                                                         continue;
1111
1112                                         mindist= dist; 
1113
1114                                         *nearesttf= tf;
1115                                         *nearestuv= i;
1116
1117                                         if (i==0) *nearestv=  mf->v1;
1118                                         else if (i==1) *nearestv=  mf->v2;
1119                                         else if (i==2) *nearestv=  mf->v3;
1120                                         else *nearestv=  mf->v4;
1121                                 }
1122                         }
1123                 }
1124         }
1125 }
1126
1127 void mouse_select_sima(void)
1128 {
1129         Mesh *me;
1130         TFace *tf, *nearesttf;
1131         MFace *mf, *nearestmf;
1132         int a, selectsticky, sticky, actface, nearestuv, i;
1133         unsigned int hitv[4], nearestv;
1134         float *hituv[4], limit[2];
1135         
1136         if( is_uv_tface_editing_allowed()==0 ) return;
1137         me= get_mesh(OBACT);
1138
1139         get_connected_limit_tface_uv(limit);
1140         actface= (G.qual & LR_ALTKEY || G.sima->flag & SI_SELACTFACE);
1141         sticky= (G.qual & LR_CTRLKEY || G.sima->flag & SI_STICKYUVS ||
1142                  G.sima->flag & SI_LOCALSTICKY);
1143
1144         if(actface) {
1145                 find_nearest_tface(&nearesttf, &nearestmf);
1146                 if(nearesttf==NULL)
1147                         return;
1148
1149                 nearesttf->flag |= TF_ACTIVE;
1150
1151                 for (i=0; i<4; i++)
1152                         hituv[i]= nearesttf->uv[i];
1153
1154                 hitv[0]= nearestmf->v1;
1155                 hitv[1]= nearestmf->v2;
1156                 hitv[2]= nearestmf->v3;
1157                 hitv[3]= nearestmf->v4? nearestmf->v4: 0xFFFFFFFF;
1158         }
1159         else {
1160                 find_nearest_uv(&nearesttf, &nearestv, &nearestuv);
1161                 if(nearesttf==NULL)
1162                         return;
1163
1164                 if(sticky) {
1165                         for(i=0; i<4; i++)
1166                                 hitv[i]= 0xFFFFFFFF;
1167                         hitv[nearestuv]= nearestv;
1168                         hituv[nearestuv]= nearesttf->uv[nearestuv];
1169                 }
1170         }
1171
1172         if(G.qual & LR_SHIFTKEY) {
1173                 /* (de)select face */
1174                 if(actface) {
1175                         if(!(~nearesttf->flag & (TF_SEL1|TF_SEL2|TF_SEL3))
1176                            && (!nearestmf->v4 || nearesttf->flag & TF_SEL4)) {
1177                                 nearesttf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
1178                                 selectsticky= 0;
1179                         }
1180                         else {
1181                                 nearesttf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
1182                                 selectsticky= 1;
1183                         }
1184                 }
1185                 /* (de)select uv node */
1186                 else {
1187                         if(nearesttf->flag & TF_SEL_MASK(nearestuv)) {
1188                                 nearesttf->flag &= ~TF_SEL_MASK(nearestuv);
1189                                 selectsticky= 0;
1190                         }
1191                         else {
1192                                 nearesttf->flag |= TF_SEL_MASK(nearestuv);
1193                                 selectsticky= 1;
1194                         }
1195                 }
1196
1197                 /* (de)select sticky uv nodes */
1198                 if(sticky || actface) {
1199                         mf= (MFace*)me->mface;
1200                         tf= (TFace*)me->tface;
1201                         /* deselect */
1202                         if(selectsticky==0) {
1203                                 for(a=me->totface; a>0; a--, tf++, mf++) {
1204                                         if(!(tf->flag & TF_SELECT && mf->v3)) continue;
1205                                         if(nearesttf && tf!=nearesttf) tf->flag &=~ TF_ACTIVE;
1206                                         if (!sticky) continue;
1207
1208                                         if(msel_hit(limit, hitv, mf->v1, hituv, tf->uv[0]))
1209                                                 tf->flag &= ~TF_SEL1;
1210                                         if(msel_hit(limit, hitv, mf->v2, hituv, tf->uv[1]))
1211                                                 tf->flag &= ~TF_SEL2;
1212                                         if(msel_hit(limit, hitv, mf->v3, hituv, tf->uv[2]))
1213                                                 tf->flag &= ~TF_SEL3;
1214                                         if (mf->v4)
1215                                                 if(msel_hit(limit, hitv, mf->v4, hituv, tf->uv[3]))
1216                                                         tf->flag &= ~TF_SEL4;
1217                                 }
1218                         }
1219                         /* select */
1220                         else {
1221                                 for(a=me->totface; a>0; a--, tf++, mf++) {
1222                                         if(!(tf->flag & TF_SELECT && mf->v3)) continue;
1223                                         if(nearesttf && tf!=nearesttf)
1224                                                 tf->flag &=~ TF_ACTIVE;
1225                                         if (!sticky) continue;
1226
1227                                         if(msel_hit(limit, hitv, mf->v1, hituv, tf->uv[0]))
1228                                                 tf->flag |= TF_SEL1;
1229                                         if(msel_hit(limit, hitv, mf->v2, hituv, tf->uv[1]))
1230                                                 tf->flag |= TF_SEL2;
1231                                         if(msel_hit(limit, hitv, mf->v3, hituv, tf->uv[2]))
1232                                                 tf->flag |= TF_SEL3;
1233                                         if (mf->v4)
1234                                                 if(msel_hit(limit, hitv, mf->v4, hituv, tf->uv[3]))
1235                                                         tf->flag |= TF_SEL4;
1236                                 }
1237                         }
1238                 }
1239         }
1240         else {
1241                 /* select face and deselect other faces */ 
1242                 if(actface) {
1243                         mf= (MFace*)me->mface;
1244                         tf= (TFace*)me->tface;
1245                         for(a=me->totface; a>0; a--, tf++, mf++) {
1246                                 tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
1247                                 if(nearesttf && tf!=nearesttf)
1248                                         tf->flag &= ~TF_ACTIVE;
1249                         }
1250                         if(nearesttf)
1251                                 nearesttf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
1252                 }
1253
1254                 /* deselect uvs, and select sticky uvs */
1255                 mf= (MFace*)me->mface;
1256                 tf= (TFace*)me->tface;
1257                 for(a=me->totface; a>0; a--, tf++, mf++) {
1258                         if(tf->flag & TF_SELECT && mf->v3) {
1259                                 if(!actface) tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
1260                                 if(!sticky) continue;
1261
1262                                 if(msel_hit(limit, hitv, mf->v1, hituv, tf->uv[0]))
1263                                         tf->flag |= TF_SEL1;
1264                                 if(msel_hit(limit, hitv, mf->v2, hituv, tf->uv[1]))
1265                                         tf->flag |= TF_SEL2;
1266                                 if(msel_hit(limit, hitv, mf->v3, hituv, tf->uv[2]))
1267                                         tf->flag |= TF_SEL3;
1268                                 if(mf->v4)
1269                                         if(msel_hit(limit, hitv, mf->v4, hituv, tf->uv[3]))
1270                                                 tf->flag |= TF_SEL4;
1271                         }
1272                 }
1273                 
1274                 if(!actface) 
1275                         nearesttf->flag |= TF_SEL_MASK(nearestuv);
1276         }
1277         
1278         force_draw(1);
1279         
1280         BIF_undo_push("Select UV");
1281         std_rmouse_transform(transform_tface_uv);
1282 }
1283
1284 void borderselect_sima(void)
1285 {
1286         Mesh *me;
1287         TFace *tface;
1288         MFace *mface;
1289         rcti rect;
1290         rctf rectf;
1291         int a, val;
1292         short mval[2];
1293
1294         if( is_uv_tface_editing_allowed()==0 ) return;
1295         me= get_mesh(OBACT);
1296
1297         val= get_border(&rect, 3);
1298
1299         if(val) {
1300                 mval[0]= rect.xmin;
1301                 mval[1]= rect.ymin;
1302                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1303                 mval[0]= rect.xmax;
1304                 mval[1]= rect.ymax;
1305                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1306
1307                 mface= me->mface;
1308                 for(a=me->totface, tface= me->tface; a>0; a--, tface++, mface++) {
1309                 
1310                         if(tface->flag & TF_SELECT) {
1311                                 
1312                                 if(BLI_in_rctf(&rectf, (float)tface->uv[0][0], (float)tface->uv[0][1])) {
1313                                         if(val==LEFTMOUSE) tface->flag |= TF_SEL1;
1314                                         else tface->flag &= ~TF_SEL1;
1315                                 }
1316                                 if(BLI_in_rctf(&rectf, (float)tface->uv[1][0], (float)tface->uv[1][1])) {
1317                                         if(val==LEFTMOUSE) tface->flag |= TF_SEL2;
1318                                         else tface->flag &= ~TF_SEL2;
1319                                 }
1320                                 if(BLI_in_rctf(&rectf, (float)tface->uv[2][0], (float)tface->uv[2][1])) {
1321                                         if(val==LEFTMOUSE) tface->flag |= TF_SEL3;
1322                                         else tface->flag &= ~TF_SEL3;
1323                                 }
1324                                 if(mface->v4 && BLI_in_rctf(&rectf, (float)tface->uv[3][0], (float)tface->uv[3][1])) {
1325                                         if(val==LEFTMOUSE) tface->flag |= TF_SEL4;
1326                                         else tface->flag &= ~TF_SEL4;
1327                                 }
1328                         }
1329                                                         
1330                 }
1331                 BIF_undo_push("Border select UV");
1332                 scrarea_queue_winredraw(curarea);
1333         }
1334 }
1335
1336 /** This is an ugly function to set the Tface selection flags depending
1337   * on whether its UV coordinates are inside the normalized 
1338   * area with radius rad and offset offset. These coordinates must be
1339   * normalized to 1.0 
1340   * Just for readability...
1341   */
1342
1343 void sel_uvco_inside_radius(short sel, TFace *tface, int index, float *offset, float *ell, short select_mask)
1344 {
1345         // normalized ellipse: ell[0] = scaleX,
1346         //                        [1] = scaleY
1347
1348         float *uv = tface->uv[index];
1349         float x, y, r2;
1350
1351         x = (uv[0] - offset[0]) * ell[0];
1352         y = (uv[1] - offset[1]) * ell[1];
1353
1354         r2 = x * x + y * y;
1355         if (r2 < 1.0) {
1356                 if (sel == LEFTMOUSE) tface->flag |= select_mask;
1357                 else tface->flag &= ~select_mask;
1358         }
1359 }
1360
1361 // see below:
1362 /** gets image dimensions of the 2D view 'v' */
1363 static void getSpaceImageDimension(SpaceImage *sima, float *xy)
1364 {
1365         Image *img = sima->image;
1366         float z;
1367
1368         z = sima->zoom;
1369
1370         if (img) {
1371                 xy[0] = img->ibuf->x * z;
1372                 xy[1] = img->ibuf->y * z;
1373         } else {
1374                 xy[0] = 256 * z;
1375                 xy[1] = 256 * z;
1376         }
1377 }
1378
1379 /** Callback function called by circle_selectCB to enable 
1380   * brush select in UV editor.
1381   */
1382
1383 void uvedit_selectionCB(short selecting, Object *editobj, short *mval, float rad) 
1384 {
1385         float offset[2];
1386         Mesh *me;
1387         MFace *mface;
1388         TFace *tface;
1389         int i;
1390
1391         float ellipse[2]; // we need to deal with ellipses, as
1392                           // non square textures require for circle
1393                                           // selection. this ellipse is normalized; r = 1.0
1394         
1395         me = get_mesh(editobj);
1396
1397         getSpaceImageDimension(curarea->spacedata.first, ellipse);
1398         ellipse[0] /= rad;
1399         ellipse[1] /= rad;
1400
1401         areamouseco_to_ipoco(G.v2d, mval, &offset[0], &offset[1]);
1402
1403         mface= me->mface;
1404         tface= me->tface;
1405
1406         if (selecting) {
1407                 for(i = 0; i < me->totface; i++) {
1408                         sel_uvco_inside_radius(selecting, tface, 0, offset, ellipse, TF_SEL1);
1409                         sel_uvco_inside_radius(selecting, tface, 1, offset, ellipse, TF_SEL2);
1410                         sel_uvco_inside_radius(selecting, tface, 2, offset, ellipse, TF_SEL3);
1411                         if (mface->v4)
1412                                 sel_uvco_inside_radius(selecting, tface, 3, offset, ellipse, TF_SEL4);
1413                         
1414                         tface++; mface++;
1415
1416                 }
1417
1418                 if(G.f & G_DRAWFACES) { /* full redraw only if necessary */
1419                         draw_sel_circle(0, 0, 0, 0, 0); /* signal */
1420                         force_draw(0);
1421                 }
1422                 else { /* force_draw() is no good here... */
1423                         glDrawBuffer(GL_FRONT);
1424                         draw_tfaces();
1425                         glDrawBuffer(GL_BACK);
1426                 }
1427         }       
1428 }
1429
1430
1431 void mouseco_to_curtile(void)
1432 {
1433         float fx, fy;
1434         short mval[2];
1435         
1436         if( is_uv_tface_editing_allowed()==0) return;
1437
1438         if(G.sima->image && G.sima->image->tpageflag & IMA_TILES) {
1439                 
1440                 G.sima->flag |= SI_EDITTILE;
1441                 
1442                 while(get_mbut()&L_MOUSE) {
1443                         
1444                         calc_image_view(G.sima, 'f');
1445                         
1446                         getmouseco_areawin(mval);
1447                         areamouseco_to_ipoco(G.v2d, mval, &fx, &fy);
1448
1449                         if(fx>=0.0 && fy>=0.0 && fx<1.0 && fy<1.0) {
1450                         
1451                                 fx= (fx)*G.sima->image->xrep;
1452                                 fy= (fy)*G.sima->image->yrep;
1453                                 
1454                                 mval[0]= fx;
1455                                 mval[1]= fy;
1456                                 
1457                                 G.sima->curtile= mval[1]*G.sima->image->xrep + mval[0];
1458                         }
1459
1460                         scrarea_do_windraw(curarea);
1461                         screen_swapbuffers();
1462                 }
1463                 
1464                 G.sima->flag &= ~SI_EDITTILE;
1465
1466                 image_changed(G.sima, 1);
1467
1468                 allqueue(REDRAWVIEW3D, 0);
1469                 scrarea_queue_winredraw(curarea);
1470         }
1471 }
1472
1473 void hide_tface_uv(int swap)
1474 {
1475         Mesh *me;
1476         TFace *tface;
1477         MFace *mface;
1478         int a;
1479
1480         if( is_uv_tface_editing_allowed()==0 ) return;
1481         me= get_mesh(OBACT);
1482
1483         if(swap) {
1484                 mface= me->mface;
1485                 for(a=me->totface, tface= me->tface; a>0; a--, tface++, mface++) {
1486                         if(mface->v3 && tface->flag & TF_SELECT) {
1487                                 if((tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3))==0) {
1488                                         if(!mface->v4)
1489                                                 tface->flag &= ~TF_SELECT;
1490                                         else if(!(tface->flag & TF_SEL4))
1491                                                 tface->flag &= ~TF_SELECT;
1492                                 }
1493                         }
1494                 }
1495         } else {
1496                 mface= me->mface;
1497                 for(a=me->totface, tface= me->tface; a>0; a--, tface++, mface++) {
1498                         if(mface->v3 && tface->flag & TF_SELECT) {
1499                                 if(tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3))
1500                                                 tface->flag &= ~TF_SELECT;
1501                                 else if(mface->v4 && tface->flag & TF_SEL4)
1502                                                 tface->flag &= ~TF_SELECT;
1503                         }
1504                 }
1505         }
1506
1507         BIF_undo_push("Hide UV");
1508
1509         object_tface_flags_changed(OBACT, 0);
1510 }
1511
1512 void reveal_tface_uv(void)
1513 {
1514         Mesh *me;
1515         TFace *tface;
1516         MFace *mface;
1517         int a;
1518
1519         if( is_uv_tface_editing_allowed()==0 ) return;
1520         me= get_mesh(OBACT);
1521
1522         mface= me->mface;
1523         for(a=me->totface, tface= me->tface; a>0; a--, tface++, mface++)
1524                 if(mface->v3 && !(tface->flag & TF_HIDE))
1525                         if(!(tface->flag & TF_SELECT))
1526                                 tface->flag |= (TF_SELECT|TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
1527         
1528         BIF_undo_push("Reveal UV");
1529
1530         object_tface_flags_changed(OBACT, 0);
1531 }
1532
1533 void stitch_uv_tface(int mode)
1534 {
1535         MFace *mf;
1536         TFace *tf, *tface;
1537         Mesh *me;
1538         int a, b, c, tot, vtot, vtot2;
1539         float newuv[2], limit[2], *uv, *uv1;
1540         struct uvvertsort *sortblock, *sb, *sb1, *sb2;
1541         
1542         if( is_uv_tface_editing_allowed()==0 ) return;
1543
1544         limit[0]= limit[1]= 20.0;
1545         if(mode==1) {
1546                 add_numbut(0, NUM|FLO, "Limit:", 0.1, 1000.0, &limit[0], NULL);
1547                 if (!do_clever_numbuts("Stitch UVs", 1, REDRAW))
1548                         return;
1549         }
1550
1551         if(G.sima->image && G.sima->image->ibuf && G.sima->image->ibuf->x > 0 &&
1552            G.sima->image->ibuf->y > 0) {
1553                 limit[1]= limit[0]/(float)G.sima->image->ibuf->y;
1554                 limit[0]= limit[0]/(float)G.sima->image->ibuf->x;
1555         }
1556         else
1557                 limit[0]= limit[1]= limit[0]/256.0;
1558         
1559         me= get_mesh(OBACT);
1560         tface= (TFace*)me->tface;
1561         
1562         tot= 0;
1563         mf= (MFace*)me->mface;
1564         tf= (TFace*)me->tface;
1565         for(a=me->totface; a>0; a--, tf++, mf++) {
1566                 if((tf->flag & TF_SELECT) && mf->v3) {
1567                         if(tf->flag & TF_SEL1) tot++;
1568                         if(tf->flag & TF_SEL2) tot++;
1569                         if(tf->flag & TF_SEL3) tot++;
1570                         if(mf->v4 && tf->flag & TF_SEL4) tot++; 
1571                 }
1572         }
1573         if(tot==0) return;
1574
1575         sb= sortblock= MEM_callocN(sizeof(struct uvvertsort)*tot,"sortstitchuv");
1576
1577         mf= (MFace*)me->mface;
1578         tf= (TFace*)me->tface;
1579         for(a=0; a<me->totface; a++, tf++, mf++) {
1580                 if((tf->flag & TF_SELECT) && mf->v3) {
1581                         if(tf->flag & TF_SEL1) {
1582                                 sb->v= mf->v1;
1583                                 sb->f= a;
1584                                 sb->tf_sel= 0;
1585                                 sb++;
1586                         }
1587                         if(tf->flag & TF_SEL2) {
1588                                 sb->v= mf->v2;
1589                                 sb->f= a;
1590                                 sb->tf_sel= 1;
1591                                 sb++;
1592                         }
1593                         if(tf->flag & TF_SEL3) {
1594                                 sb->v= mf->v3;
1595                                 sb->f= a;
1596                                 sb->tf_sel= 2;
1597                                 sb++;
1598                         }
1599                         if(mf->v4 && tf->flag & TF_SEL4) {
1600                                 sb->v= mf->v4;
1601                                 sb->f= a;
1602                                 sb->tf_sel= 3;
1603                                 sb++;
1604                         }
1605                 }
1606         }
1607         
1608         /* sort by vertex */
1609         qsort(sortblock, tot, sizeof(struct uvvertsort), compuvvert);
1610
1611         if(mode==0) {
1612                 for (a=0, sb=sortblock; a<tot; a+=vtot, sb+=vtot) {
1613                         newuv[0]= 0; newuv[1]= 0;
1614                         vtot= 0;
1615
1616                         for (b=a, sb1=sb; b<tot && sb1->v==sb->v; b++, sb1++) {
1617                                 newuv[0] += tface[sb1->f].uv[sb1->tf_sel][0];
1618                                 newuv[1] += tface[sb1->f].uv[sb1->tf_sel][1];
1619                                 vtot++;
1620                         }
1621
1622                         newuv[0] /= vtot; newuv[1] /= vtot;
1623
1624                         for (b=a, sb1=sb; b<a+vtot; b++, sb1++) {
1625                                 tface[sb1->f].uv[sb1->tf_sel][0]= newuv[0];
1626                                 tface[sb1->f].uv[sb1->tf_sel][1]= newuv[1];
1627                         }
1628                 }
1629         } else if(mode==1) {
1630                 for (a=0, sb=sortblock; a<tot; a+=vtot, sb+=vtot) {
1631                         vtot= 0;
1632                         for (b=a, sb1=sb; b<tot && sb1->v==sb->v; b++, sb1++)
1633                                 vtot++;
1634
1635                         for (b=a, sb1=sb; b<a+vtot; b++, sb1++) {
1636                                 if(sb1->flag & 2) continue;
1637
1638                                 newuv[0]= 0; newuv[1]= 0;
1639                                 vtot2 = 0;
1640
1641                                 for (c=b, sb2=sb1; c<a+vtot; c++, sb2++) {
1642                                         uv = tface[sb2->f].uv[sb2->tf_sel];
1643                                         uv1 = tface[sb1->f].uv[sb1->tf_sel];
1644                                         if (fabs(uv[0]-uv1[0]) < limit[0] &&
1645                                             fabs(uv[1]-uv1[1]) < limit[1]) {
1646                                                 newuv[0] += uv[0];
1647                                                 newuv[1] += uv[1];
1648                                                 sb2->flag |= 2;
1649                                                 sb2->flag |= 4;
1650                                                 vtot2++;
1651                                         }
1652                                 }
1653
1654                                 newuv[0] /= vtot2; newuv[1] /= vtot2;
1655
1656                                 for (c=b, sb2=sb1; c<a+vtot; c++, sb2++) {
1657                                         if(sb2->flag & 4) {
1658                                                 tface[sb2->f].uv[sb2->tf_sel][0]= newuv[0];
1659                                                 tface[sb2->f].uv[sb2->tf_sel][1]= newuv[1];
1660                                                 sb2->flag &= ~4;
1661                                         }
1662                                 }
1663                         }
1664                 }
1665         }
1666         MEM_freeN(sortblock);
1667
1668         if(G.sima->flag & SI_BE_SQUARE) be_square_tface_uv(me);
1669         if(G.sima->flag & SI_CLIP_UV) tface_do_clip();
1670
1671         BIF_undo_push("Stitch UV");
1672
1673         object_uvs_changed(OBACT);
1674 }
1675
1676 void select_linked_tface_uv(int mode)
1677 {
1678         MFace *mf;
1679         TFace *tface, *tf, *nearesttf=NULL;
1680         Mesh *me;
1681         char sel, *linkflag;
1682         int a, b, c, tot, vtot, nearestv, nearestuv, i, nverts;
1683         float limit[2], *uv, *uv1;
1684         struct uvvertsort *sortblock, *sb, *sb1, *sb2;
1685         
1686         if( is_uv_tface_editing_allowed()==0 ) return;
1687
1688         me= get_mesh(OBACT);
1689         get_connected_limit_tface_uv(limit);
1690
1691         tot= 0;
1692         mf= (MFace*)me->mface;
1693         tf= (TFace*)me->tface;
1694         for(a=me->totface; a>0; a--, tf++, mf++)
1695                 if((tf->flag & TF_SELECT) && mf->v3)
1696                         tot += mf->v4? 4: 3;
1697
1698         if(tot==0) return;
1699
1700         if (mode!=2) {
1701                 find_nearest_uv(&nearesttf, &nearestv, &nearestuv);
1702
1703                 if(nearesttf==NULL)
1704                         return;
1705         }
1706         else {
1707                 nearesttf= NULL;
1708                 nearestuv= 0;
1709         }
1710
1711         sb= sortblock= MEM_callocN(sizeof(struct uvvertsort)*tot, "sortsellinkuv");
1712         linkflag= MEM_callocN(sizeof(char)*me->totface, "linkflaguv");
1713
1714         mf= (MFace*)me->mface;
1715         tf= (TFace*)me->tface;
1716         for(a=0; a<me->totface; a++, tf++, mf++) {
1717                 if(!(tf->flag & TF_HIDE) && (tf->flag & TF_SELECT) && mf->v3) {
1718                         sel= 0;
1719                         sb1= sb;
1720                         nverts= mf->v4? 4: 3;
1721                         for(i=0; i<nverts; i++) {
1722                                 if(tf->flag & TF_SEL_MASK(i))
1723                                         sel= 1;
1724                                 sb->f= a;
1725                                 sb->tf_sel= i;
1726                                 sb++;
1727                         }
1728
1729                         if(nearesttf==tf || ((sel && mode==2)))
1730                                 linkflag[a] = 1;
1731
1732                         (sb1)->v= mf->v1;
1733                         (sb1+1)->v= mf->v2;
1734                         (sb1+2)->v= mf->v3;
1735                         if(mf->v4) (sb1+3)->v= mf->v4;
1736                 }
1737         }
1738         
1739         /* sort by vertex */
1740         qsort(sortblock, tot, sizeof(struct uvvertsort), compuvvert);
1741
1742         tface= (TFace*)me->tface;
1743         sel= 1;
1744         while(sel) {
1745                 sel= 0;
1746
1747                 /* select all tex vertices that are near a selected tex vertex */
1748                 for (a=0, sb=sortblock; a<tot; a+=vtot, sb+=vtot) {
1749                         vtot= 0;
1750                         for (b=a, sb1=sb; b<tot && sb1->v==sb->v; b++, sb1++)
1751                                 vtot++;
1752                         for (b=a, sb1=sb; b<a+vtot; b++, sb1++) {
1753                                 if(linkflag[sb1->f]) continue;
1754
1755                                 for (c=a, sb2=sb; c<a+vtot; c++, sb2++) {
1756                                         if(!(linkflag[sb2->f])) continue;
1757                                         
1758                                         uv = tface[sb2->f].uv[sb2->tf_sel];
1759                                         uv1 = tface[sb1->f].uv[sb1->tf_sel];
1760                                         if (fabs(uv[0]-uv1[0]) < limit[0] &&
1761                                             fabs(uv[1]-uv1[1]) < limit[1]) {
1762                                                 linkflag[sb1->f] = 1;
1763                                                 sel= 1;
1764                                                 break;
1765                                         }
1766                                 }
1767                         }
1768                 }
1769         }
1770
1771         if(mode==0 || mode==2) {
1772                 for(a=0, tf=tface; a<me->totface; a++, tf++)
1773                         if(linkflag[a])
1774                                 tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
1775                         else
1776                                 tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
1777         }
1778         else if(mode==1) {
1779                 for(a=0, tf=tface; a<me->totface; a++, tf++) {
1780                         if(linkflag[a]) {
1781                                 if (mf->v4) {
1782                                         if((tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)))
1783                                                 break;
1784                                 }
1785                                 else if(tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3))
1786                                         break;
1787                         }
1788                 }
1789
1790                 if (a<me->totface) {
1791                         for(a=0, tf=tface; a<me->totface; a++, tf++)
1792                                 if(linkflag[a])
1793                                         tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
1794                 }
1795                 else {
1796                         for(a=0, tf=tface; a<me->totface; a++, tf++)
1797                                 if(linkflag[a])
1798                                         tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
1799                 }
1800         }
1801         
1802         MEM_freeN(sortblock);
1803         MEM_freeN(linkflag);
1804
1805         BIF_undo_push("Select linked UV");
1806         scrarea_queue_winredraw(curarea);
1807 }
1808
1809 void unlink_selection(void)
1810 {
1811         Mesh *me;
1812         TFace *tface;
1813         MFace *mface;
1814         int a;
1815
1816         if( is_uv_tface_editing_allowed()==0 ) return;
1817         me= get_mesh(OBACT);
1818
1819         mface= me->mface;
1820         for(a=me->totface, tface= me->tface; a>0; a--, tface++, mface++) {
1821                 if(mface->v3 && tface->flag & TF_SELECT) {
1822                         if(mface->v4) {
1823                                 if(~tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4))
1824                                         tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
1825                         } else {
1826                                 if(~tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3))
1827                                         tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3);
1828                         }
1829                 }
1830         }
1831         
1832         BIF_undo_push("Unlink UV selection");
1833         scrarea_queue_winredraw(curarea);
1834 }
1835
1836 void toggle_uv_select(int mode)
1837 {
1838         switch(mode){
1839         case 'f':
1840                 G.sima->flag ^= SI_SELACTFACE;
1841                 break;
1842         case 's':
1843                 G.sima->flag ^= SI_STICKYUVS; 
1844                 if (G.sima->flag & SI_STICKYUVS) G.sima->flag &= ~SI_LOCALSTICKY;
1845                 break;
1846         case 'l': 
1847                  G.sima->flag ^= SI_LOCALSTICKY;
1848                  if (G.sima->flag & SI_LOCALSTICKY) G.sima->flag &= ~SI_STICKYUVS;
1849                 break;
1850         case 'o':
1851                 G.sima->flag &= ~SI_STICKYUVS; 
1852                 G.sima->flag &= ~SI_LOCALSTICKY;
1853                 break;
1854         }
1855         allqueue(REDRAWIMAGE, 0);
1856 }
1857
1858 void pin_tface_uv(int mode)
1859 {
1860         Mesh *me;
1861         TFace *tface;
1862         MFace *mface;
1863         int a;
1864         
1865         if( is_uv_tface_editing_allowed()==0 ) return;
1866         me= get_mesh(OBACT);
1867         
1868         mface= me->mface;
1869         tface= me->tface;
1870         for(a=me->totface; a>0; a--, tface++, mface++) {
1871                 if(mface->v3 && tface->flag & TF_SELECT) {
1872                         if(mode ==1){
1873                                 if(tface->flag & TF_SEL1) tface->unwrap |= TF_PIN1;
1874                                 if(tface->flag & TF_SEL2) tface->unwrap |= TF_PIN2;
1875                                 if(tface->flag & TF_SEL3) tface->unwrap |= TF_PIN3;
1876                                 if(mface->v4)
1877                                         if(tface->flag & TF_SEL4) tface->unwrap |= TF_PIN4;
1878                         }
1879                         else if (mode ==0){
1880                                 if(tface->flag & TF_SEL1) tface->unwrap &= ~TF_PIN1;
1881                                 if(tface->flag & TF_SEL2) tface->unwrap &= ~TF_PIN2;
1882                                 if(tface->flag & TF_SEL3) tface->unwrap &= ~TF_PIN3;
1883                                 if(mface->v4)
1884                                 if(tface->flag & TF_SEL4) tface->unwrap &= ~TF_PIN4;
1885                         }
1886                 }
1887         }
1888         
1889         BIF_undo_push("Pin UV");
1890         scrarea_queue_winredraw(curarea);
1891 }
1892
1893 int minmax_tface_uv(float *min, float *max)
1894 {
1895         Mesh *me;
1896         TFace *tf;
1897         MFace *mf;
1898         int a, sel;
1899
1900         if( is_uv_tface_editing_allowed()==0 ) return 0;
1901         me= get_mesh(OBACT);
1902
1903         INIT_MINMAX2(min, max);
1904
1905         sel= 0;
1906         mf= (MFace*)me->mface;
1907         tf= (TFace*)me->tface;
1908         for(a=me->totface; a>0; a--, tf++, mf++) {
1909                 if(tf->flag & TF_HIDE);
1910                 else if(mf->v3 && (tf->flag & TF_SELECT)) {
1911
1912                         if (tf->flag & TF_SEL1) {
1913                                 DO_MINMAX2(tf->uv[0], min, max);
1914                         }
1915                         if (tf->flag & TF_SEL2) {
1916                                 DO_MINMAX2(tf->uv[1], min, max);
1917                         }
1918                         if (tf->flag & TF_SEL3) {
1919                                 DO_MINMAX2(tf->uv[2], min, max);
1920                         }
1921                         if (mf->v4 && tf->flag & TF_SEL4) {
1922                                 DO_MINMAX2(tf->uv[3], min, max);
1923                         }
1924
1925                         sel = 1;
1926                 }
1927         }
1928
1929         return sel;
1930 }
1931