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