Bretch's patch for 2D transform. Thanks
[blender.git] / source / blender / src / transform.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 <stdio.h>
35 #include <string.h>
36 #include <math.h>
37
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #ifndef WIN32
43 #include <unistd.h>
44 #else
45 #include <io.h>
46 #endif
47
48 #include "MEM_guardedalloc.h"
49
50 #include "DNA_armature_types.h"
51 #include "DNA_ipo_types.h"              /* some silly ipo flag  */
52 #include "DNA_listBase.h"
53 #include "DNA_meshdata_types.h"
54 #include "DNA_mesh_types.h"
55 #include "DNA_object_types.h"
56 #include "DNA_scene_types.h"    /* PET modes                    */
57 #include "DNA_screen_types.h"   /* area dimensions              */
58 #include "DNA_scene_types.h"
59 #include "DNA_screen_types.h"
60 #include "DNA_texture_types.h"
61 #include "DNA_userdef_types.h"
62 #include "DNA_view3d_types.h"
63 #include "DNA_space_types.h"
64
65 #include "BIF_editview.h"               /* arrows_move_cursor   */
66 #include "BIF_gl.h"
67 #include "BIF_mywindow.h"
68 #include "BIF_resources.h"
69 #include "BIF_screen.h"
70 #include "BIF_space.h"                  /* undo                                 */
71 #include "BIF_toets.h"                  /* persptoetsen                 */
72 #include "BIF_mywindow.h"               /* warp_pointer                 */
73 #include "BIF_toolbox.h"                /* notice                               */
74 #include "BIF_editmesh.h"
75 #include "BIF_editsima.h"
76 #include "BIF_drawimage.h"              /* uvco_to_areaco_noclip */
77
78 #include "BKE_global.h"
79 #include "BKE_utildefines.h"
80 #include "BKE_bad_level_calls.h"/* popmenu and error    */
81
82 #include "BDR_editobject.h"             /* compatible_eul               */
83
84 #include "BSE_view.h"
85
86 #include "BLI_arithb.h"
87 #include "BLI_blenlib.h"
88 #include "BLI_editVert.h"
89
90 #include "PIL_time.h"                   /* sleep                                */
91
92 #include "blendef.h"
93
94 #include "mydevice.h"
95
96 #include "transform.h"
97
98 /* GLOBAL VARIABLE THAT SHOULD MOVED TO SCREEN MEMBER OR SOMETHING  */
99 TransInfo Trans = {TFM_INIT, 0};        // enforce init on first usage
100
101 /******************************** Helper functions ************************************/
102 /* ************************** Dashed help line **************************** */
103
104
105 /* bad frontbuffer call... because it is used in transform after force_draw() */
106 static void helpline(TransInfo *t, float *vec)
107 {
108         float vecrot[3], cent[2];
109         short mval[2];
110         
111         VECCOPY(vecrot, vec);
112         if(t->flag & T_EDIT) {
113                 Object *ob=G.obedit;
114                 if(ob) Mat4MulVecfl(ob->obmat, vecrot);
115         }
116         else if(t->flag & T_POSE) {
117                 Object *ob=t->poseobj;
118                 if(ob) Mat4MulVecfl(ob->obmat, vecrot);
119         }
120         
121         getmouseco_areawin(mval);
122         projectFloatView(t, vecrot, cent);      // no overflow in extreme cases
123         if(cent[0]!=IS_CLIPPED) {
124                 persp(PERSP_WIN);
125                 
126                 glDrawBuffer(GL_FRONT);
127                 
128                 BIF_ThemeColor(TH_WIRE);
129                 
130                 setlinestyle(3);
131                 glBegin(GL_LINE_STRIP); 
132                 glVertex2sv(mval); 
133                 glVertex2fv(cent); 
134                 glEnd();
135                 setlinestyle(0);
136                 
137                 persp(PERSP_VIEW);
138                 glFlush(); // flush display for frontbuffer
139                 glDrawBuffer(GL_BACK);
140         }
141 }
142 /* ************************** INPUT FROM MOUSE *************************** */
143
144 float InputScaleRatio(TransInfo *t, short mval[2]) {
145         float ratio, dx, dy;
146         if(t->flag & T_SHIFT_MOD) {
147                 /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
148                 float dx = (float)(t->center2d[0] - t->shiftmval[0]);
149                 float dy = (float)(t->center2d[1] - t->shiftmval[1]);
150                 ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
151                 
152                 dx= (float)(t->center2d[0] - mval[0]);
153                 dy= (float)(t->center2d[1] - mval[1]);
154                 ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
155         }
156         else {
157                 dx = (float)(t->center2d[0] - mval[0]);
158                 dy = (float)(t->center2d[1] - mval[1]);
159                 ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
160         }
161         return ratio;
162 }
163
164 float InputHorizontalRatio(TransInfo *t, short mval[2]) {
165         int y, pad;
166
167         pad = curarea->winx / 10;
168
169         if (t->flag & T_SHIFT_MOD) {
170                 /* deal with Shift key by adding motion / 10 to motion before shift press */
171                 y = t->shiftmval[0] + (mval[0] - t->shiftmval[0]) / 10;
172         }
173         else {
174                 y = mval[0];
175         }
176         return (float)(y - pad) / (float)(curarea->winx - 2 * pad);
177 }
178
179 /* ************************** SPACE DEPENDANT CODE **************************** */
180
181 void setTransformViewMatrices(TransInfo *t)
182 {
183         if(t->spacetype==SPACE_VIEW3D) {
184                 Mat4CpyMat4(t->viewmat, G.vd->viewmat);
185                 Mat4CpyMat4(t->viewinv, G.vd->viewinv);
186                 Mat4CpyMat4(t->persmat, G.vd->persmat);
187                 Mat4CpyMat4(t->persinv, G.vd->persinv);
188                 t->persp= G.vd->persp;
189         }
190         else {
191                 Mat4One(t->viewmat);
192                 Mat4One(t->viewinv);
193                 Mat4One(t->persmat);
194                 Mat4One(t->persinv);
195                 t->persp = 0; // ortho
196         }
197 }
198
199 void convertViewVec(TransInfo *t, float *vec, short dx, short dy)
200 {
201         if (t->spacetype==SPACE_VIEW3D)
202                 window_to_3d(vec, dx, dy);
203         else if(t->spacetype==SPACE_IMAGE) {
204                 float divx, divy, aspx, aspy;
205
206                 transform_aspect_ratio_tface_uv(&aspx, &aspy);
207
208                 divx= G.v2d->mask.xmax-G.v2d->mask.xmin;
209                 divy= G.v2d->mask.ymax-G.v2d->mask.ymin;
210
211                 vec[0]= aspx*(G.v2d->cur.xmax-G.v2d->cur.xmin)*(dx)/divx;
212                 vec[1]= aspy*(G.v2d->cur.ymax-G.v2d->cur.ymin)*(dy)/divy;
213                 vec[2]= 0.0f;
214         }
215 }
216
217 void projectIntView(TransInfo *t, float *vec, int *adr)
218 {
219         if (t->spacetype==SPACE_VIEW3D)
220                 project_int(vec, adr);
221         else if(t->spacetype==SPACE_IMAGE) {
222                 float aspx, aspy, v[2];
223
224                 transform_aspect_ratio_tface_uv(&aspx, &aspy);
225                 v[0]= vec[0]/aspx;
226                 v[1]= vec[1]/aspy;
227
228                 uvco_to_areaco_noclip(v, adr);
229         }
230 }
231
232 void projectFloatView(TransInfo *t, float *vec, float *adr)
233 {
234         if (t->spacetype==SPACE_VIEW3D)
235                 project_float(vec, adr);
236         else if(t->spacetype==SPACE_IMAGE) {
237                 int a[2];
238
239                 projectIntView(t, vec, a);
240                 adr[0]= a[0];
241                 adr[1]= a[1];
242         }
243 }
244
245 void convertVecToDisplayNum(float *vec, float *num)
246 {
247         TransInfo *t= BIF_GetTransInfo();
248
249         VECCOPY(num, vec);
250
251         if ((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) {
252                 float aspx, aspy;
253
254                 if((G.sima->flag & SI_COORDFLOATS)==0) {
255                         int width, height;
256                         transform_width_height_tface_uv(&width, &height);
257
258                         num[0] *= width;
259                         num[1] *= height;
260                 }
261
262                 transform_aspect_ratio_tface_uv(&aspx, &aspy);
263                 num[0] /= aspx;
264                 num[1] /= aspy;
265         }
266 }
267
268 void convertDisplayNumToVec(float *num, float *vec)
269 {
270         TransInfo *t= BIF_GetTransInfo();
271
272         VECCOPY(vec, num);
273
274         if ((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) {
275                 float aspx, aspy;
276
277                 if((G.sima->flag & SI_COORDFLOATS)==0) {
278                         int width, height;
279                         transform_width_height_tface_uv(&width, &height);
280
281                         vec[0] /= width;
282                         vec[1] /= height;
283                 }
284
285                 transform_aspect_ratio_tface_uv(&aspx, &aspy);
286                 vec[0] *= aspx;
287                 vec[1] *= aspy;
288         }
289 }
290
291 static void viewRedrawForce(TransInfo *t)
292 {
293         if(t->spacetype==SPACE_VIEW3D)
294                 force_draw(0);
295         else if(t->spacetype==SPACE_IMAGE) {
296                 if(G.sima->lock) force_draw_plus(SPACE_VIEW3D, 0);
297                 else force_draw(0);
298         }
299 }
300
301 static void viewRedrawPost(TransInfo *t)
302 {
303         if(t->spacetype==SPACE_VIEW3D) {
304                 allqueue(REDRAWBUTSOBJECT, 0);
305                 allqueue(REDRAWVIEW3D, 0);
306         }
307         else if(t->spacetype==SPACE_IMAGE) {
308                 allqueue(REDRAWIMAGE, 0);
309                 allqueue(REDRAWVIEW3D, 0);
310         }
311
312         scrarea_queue_headredraw(curarea);
313 }
314
315 /* ************************** TRANSFORMATIONS **************************** */
316
317 void BIF_selectOrientation() {
318         short val;
319         val= pupmenu("Orientation%t|Global|Local|Normal|View");
320         if(val>0) {
321                 if(val==1) G.vd->twmode= V3D_MANIP_GLOBAL;
322                 else if(val==2) G.vd->twmode= V3D_MANIP_LOCAL;
323                 else if(val==3) G.vd->twmode= V3D_MANIP_NORMAL;
324                 else if(val==4) G.vd->twmode= V3D_MANIP_VIEW;
325         }
326 }
327
328 static void view_editmove(unsigned short event)
329 {
330         int refresh = 0;
331         /* Regular:   Zoom in */
332         /* Shift:     Scroll up */
333         /* Ctrl:      Scroll right */
334         /* Alt-Shift: Rotate up */
335         /* Alt-Ctrl:  Rotate right */
336         
337         switch(event) {
338                 case WHEELUPMOUSE:
339                         
340                         if( G.qual & LR_SHIFTKEY ) {
341                                 if( G.qual & LR_ALTKEY ) { 
342                                         G.qual &= ~LR_SHIFTKEY;
343                                         persptoetsen(PAD2);
344                                         G.qual |= LR_SHIFTKEY;
345                                 } else {
346                                         persptoetsen(PAD2);
347                                 }
348                         } else if( G.qual & LR_CTRLKEY ) {
349                                 if( G.qual & LR_ALTKEY ) { 
350                                         G.qual &= ~LR_CTRLKEY;
351                                         persptoetsen(PAD4);
352                                         G.qual |= LR_CTRLKEY;
353                                 } else {
354                                         persptoetsen(PAD4);
355                                 }
356                         } else if(U.uiflag & USER_WHEELZOOMDIR) 
357                                 persptoetsen(PADMINUS);
358                         else
359                                 persptoetsen(PADPLUSKEY);
360                         
361                         refresh = 1;
362                         break;
363                 case WHEELDOWNMOUSE:
364                         if( G.qual & LR_SHIFTKEY ) {
365                                 if( G.qual & LR_ALTKEY ) { 
366                                         G.qual &= ~LR_SHIFTKEY;
367                                         persptoetsen(PAD8);
368                                         G.qual |= LR_SHIFTKEY;
369                                 } else {
370                                         persptoetsen(PAD8);
371                                 }
372                         } else if( G.qual & LR_CTRLKEY ) {
373                                 if( G.qual & LR_ALTKEY ) { 
374                                         G.qual &= ~LR_CTRLKEY;
375                                         persptoetsen(PAD6);
376                                         G.qual |= LR_CTRLKEY;
377                                 } else {
378                                         persptoetsen(PAD6);
379                                 }
380                         } else if(U.uiflag & USER_WHEELZOOMDIR) 
381                                 persptoetsen(PADPLUSKEY);
382                         else
383                                 persptoetsen(PADMINUS);
384                         
385                         refresh = 1;
386                         break;
387         }
388
389         if (refresh)
390                 setTransformViewMatrices(&Trans);
391 }
392
393 void checkFirstTime() {
394         if(Trans.mode==TFM_INIT) {
395                 memset(&Trans, 0, sizeof(TransInfo));
396                 Trans.propsize = 1.0;
397         }
398 }
399
400 static char *transform_to_undostr(TransInfo *t)
401 {
402         switch (t->mode) {
403                 case TFM_TRANSLATION:
404                         return "Translate";
405                 case TFM_ROTATION:
406                         return "Rotate";
407                 case TFM_RESIZE:
408                         return "Scale";
409                 case TFM_TOSPHERE:
410                         return "To Sphere";
411                 case TFM_SHEAR:
412                         return "Shear";
413                 case TFM_WARP:
414                         return "Warp";
415                 case TFM_SHRINKFATTEN:
416                         return "Shrink/Fatten";
417                 case TFM_TILT:
418                         return "Tilt";
419                 case TFM_TRACKBALL:
420                         return "Trackball";
421                 case TFM_PUSHPULL:
422                         return "Push/Pull";
423                 case TFM_CREASE:
424                         return "Crease";
425                 case TFM_BONESIZE:
426                         return "Bone Width";
427                 case TFM_BONE_ENVELOPE:
428                         return "Bone Envelope";
429         }
430         return "Transform";
431 }
432
433 /* ************************************************* */
434
435 static void transformEvent(unsigned short event, short val) {
436         float mati[3][3] = {{1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}};
437         char cmode = constraintModeToChar(&Trans);
438
439         if (val) {
440                 switch (event){
441                 /* enforce redraw of transform when modifiers are used */
442                 case LEFTCTRLKEY:
443                 case RIGHTCTRLKEY:
444                         Trans.redraw = 1;
445                         break;
446                 case LEFTSHIFTKEY:
447                 case RIGHTSHIFTKEY:
448                         /* shift is modifier for higher resolution transform, works nice to store this mouse position */
449                         getmouseco_areawin(Trans.shiftmval);
450                         Trans.flag |= T_SHIFT_MOD;
451                         Trans.redraw = 1;
452                         break;
453
454                 case SPACEKEY:
455                         if ((Trans.spacetype==SPACE_VIEW3D) && (G.qual & LR_ALTKEY)) {
456                                 short mval[2];
457
458                                 getmouseco_sc(mval);
459                                 BIF_selectOrientation();
460                                 calc_manipulator_stats(curarea);
461                                 Mat3CpyMat4(Trans.spacemtx, G.vd->twmat);
462                                 warp_pointer(mval[0], mval[1]);
463                         }
464                         else {
465                                 Trans.state = TRANS_CONFIRM;
466                         }
467                         break;
468
469                         
470                 case MIDDLEMOUSE:
471                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
472                                 /* exception for switching to dolly, or trackball, in camera view */
473                                 if (Trans.flag & T_CAMERA) {
474                                         if (Trans.mode==TFM_TRANSLATION)
475                                                 setLocalConstraint(&Trans, (CON_AXIS2), "along local Z");
476                                         else if (Trans.mode==TFM_ROTATION) {
477                                                 restoreTransObjects(&Trans);
478                                                 initTransModeFlags(&Trans, TFM_TRACKBALL);
479                                                 initTrackball(&Trans);
480                                         }
481                                 }
482                                 else {
483                                         Trans.flag |= T_MMB_PRESSED;
484                                         if (Trans.con.mode & CON_APPLY) {
485                                                 stopConstraint(&Trans);
486                                         }
487                                         else {
488                                                 initSelectConstraint(&Trans, Trans.spacemtx);
489                                                 postSelectConstraint(&Trans);
490                                         }
491                                 }
492                                 Trans.redraw = 1;
493                         }
494                         break;
495                 case ESCKEY:
496                 case RIGHTMOUSE:
497                         Trans.state = TRANS_CANCEL;
498                         break;
499                 case LEFTMOUSE:
500                 case PADENTER:
501                 case RETKEY:
502                         Trans.state = TRANS_CONFIRM;
503                         break;
504                 case GKEY:
505                         /* only switch when... */
506                         if( ELEM3(Trans.mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL) ) { 
507                                 restoreTransObjects(&Trans);
508                                 initTransModeFlags(&Trans, TFM_TRANSLATION);
509                                 initTranslation(&Trans);
510                                 Trans.redraw = 1;
511                         }
512                         break;
513                 case SKEY:
514                         /* only switch when... */
515                         if( ELEM3(Trans.mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) { 
516                                 restoreTransObjects(&Trans);
517                                 initTransModeFlags(&Trans, TFM_RESIZE);
518                                 initResize(&Trans);
519                                 Trans.redraw = 1;
520                         }
521                         break;
522                 case RKEY:
523                         /* only switch when... */
524                         if( ELEM4(Trans.mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) { 
525                                 
526                                 if (Trans.mode == TFM_ROTATION) {
527                                         restoreTransObjects(&Trans);
528                                         initTransModeFlags(&Trans, TFM_TRACKBALL);
529                                         initTrackball(&Trans);
530                                 }
531                                 else {
532                                         restoreTransObjects(&Trans);
533                                         initTransModeFlags(&Trans, TFM_ROTATION);
534                                         initRotation(&Trans);
535                                 }
536                                 Trans.redraw = 1;
537                         }
538                         break;
539                 case CKEY:
540                         if (G.qual & LR_ALTKEY) {
541                                 Trans.flag ^= T_PROP_CONNECTED;
542                                 sort_trans_data_dist(&Trans);
543                                 calculatePropRatio(&Trans);
544                                 Trans.redraw= 1;
545                         }
546                         else {
547                                 stopConstraint(&Trans);
548                                 Trans.redraw = 1;
549                         }
550                         break;
551                 case XKEY:
552                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
553                                 if (cmode == 'X') {
554                                         if (Trans.con.mode & CON_USER) {
555                                                 stopConstraint(&Trans);
556                                         }
557                                         else {
558                                                 if (G.qual == 0)
559                                                         setUserConstraint(&Trans, (CON_AXIS0), "along %s X");
560                                                 else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
561                                                         setUserConstraint(&Trans, (CON_AXIS1|CON_AXIS2), "locking %s X");
562                                         }
563                                 }
564                                 else {
565                                         if (G.qual == 0)
566                                                 setConstraint(&Trans, mati, (CON_AXIS0), "along global X");
567                                         else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
568                                                 setConstraint(&Trans, mati, (CON_AXIS1|CON_AXIS2), "locking global X");
569                                 }
570                                 Trans.redraw = 1;
571                         }
572                         break;
573                 case YKEY:
574                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
575                                 if (cmode == 'Y') {
576                                         if (Trans.con.mode & CON_USER) {
577                                                 stopConstraint(&Trans);
578                                         }
579                                         else {
580                                                 if (G.qual == 0)
581                                                         setUserConstraint(&Trans, (CON_AXIS1), "along %s Y");
582                                                 else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
583                                                         setUserConstraint(&Trans, (CON_AXIS0|CON_AXIS2), "locking %s Y");
584                                         }
585                                 }
586                                 else {
587                                         if (G.qual == 0)
588                                                 setConstraint(&Trans, mati, (CON_AXIS1), "along global Y");
589                                         else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
590                                                 setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS2), "locking global Y");
591                                 }
592                                 Trans.redraw = 1;
593                         }
594                         break;
595                 case ZKEY:
596                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
597                                 if (cmode == 'Z') {
598                                         if (Trans.con.mode & CON_USER) {
599                                                 stopConstraint(&Trans);
600                                         }
601                                         else {
602                                                 if (G.qual == 0)
603                                                         setUserConstraint(&Trans, (CON_AXIS2), "along %s Z");
604                                                 else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
605                                                         setUserConstraint(&Trans, (CON_AXIS0|CON_AXIS1), "locking %s Z");
606                                         }
607                                 }
608                                 else if ((Trans.flag & T_2D_EDIT)==0) {
609                                         if (G.qual == 0)
610                                                 setConstraint(&Trans, mati, (CON_AXIS2), "along global Z");
611                                         else if (G.qual == LR_SHIFTKEY)
612                                                 setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS1), "locking global Z");
613                                 }
614                                 Trans.redraw = 1;
615                         }
616                         break;
617                 case OKEY:
618                         if (Trans.flag & T_PROP_EDIT && G.qual==LR_SHIFTKEY) {
619                                 G.scene->prop_mode = (G.scene->prop_mode+1)%6;
620                                 calculatePropRatio(&Trans);
621                                 Trans.redraw= 1;
622                         }
623                         break;
624                 case PADPLUSKEY:
625                         if(G.qual & LR_ALTKEY && Trans.flag & T_PROP_EDIT) {
626                                 Trans.propsize*= 1.1f;
627                                 calculatePropRatio(&Trans);
628                         }
629                         Trans.redraw= 1;
630                         break;
631                 case PAGEUPKEY:
632                 case WHEELDOWNMOUSE:
633                         if(Trans.flag & T_PROP_EDIT) {
634                                 Trans.propsize*= 1.1f;
635                                 calculatePropRatio(&Trans);
636                         }
637                         else view_editmove(event);
638                         Trans.redraw= 1;
639                         break;
640                 case PADMINUS:
641                         if(G.qual & LR_ALTKEY && Trans.flag & T_PROP_EDIT) {
642                                 Trans.propsize*= 0.90909090f;
643                                 calculatePropRatio(&Trans);
644                         }
645                         Trans.redraw= 1;
646                         break;
647                 case PAGEDOWNKEY:
648                 case WHEELUPMOUSE:
649                         if(Trans.flag & T_PROP_EDIT) {
650                                 Trans.propsize*= 0.90909090f;
651                                 calculatePropRatio(&Trans);
652                         }
653                         else view_editmove(event);
654                         Trans.redraw= 1;
655                         break;
656                 }
657                 Trans.redraw |= handleNumInput(&(Trans.num), event);
658                 arrows_move_cursor(event);
659         }
660         else {
661                 switch (event){
662                 /* no redraw on release modifier keys! this makes sure you can assign the 'grid' still 
663                    after releasing modifer key */
664                 case MIDDLEMOUSE:
665                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
666                                 Trans.flag &= ~T_MMB_PRESSED;
667                                 postSelectConstraint(&Trans);
668                                 Trans.redraw = 1;
669                         }
670                         break;
671                 case LEFTMOUSE:
672                 case RIGHTMOUSE:
673                         if (Trans.context & CTX_TWEAK)
674                                 Trans.state = TRANS_CONFIRM;
675                         break;
676                 case LEFTSHIFTKEY:
677                 case RIGHTSHIFTKEY:
678                         /* shift is modifier for higher resolution transform */
679                         Trans.flag &= ~T_SHIFT_MOD;
680                         break;
681                 }
682         }
683 }
684
685 void initTransform(int mode, int context) {
686         /* added initialize, for external calls to set stuff in TransInfo, like undo string */
687         checkFirstTime();
688
689         Trans.state = TRANS_RUNNING;
690
691         Trans.context = context;
692
693         initTrans(&Trans);                                      // internal data, mouse, vectors
694
695         if(Trans.spacetype==SPACE_VIEW3D) {
696                 calc_manipulator_stats(curarea);
697                 Mat3CpyMat4(Trans.spacemtx, G.vd->twmat);
698         }
699         else
700                 Mat3One(Trans.spacemtx);
701
702         initTransModeFlags(&Trans, mode);       // modal settings in struct Trans
703
704         createTransData(&Trans);                        // make TransData structs from selection
705
706         if (Trans.total == 0) {
707                 postTrans(&Trans);
708                 return;
709         }
710
711         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
712         /* EVIL2: we gave as argument also texture space context bit... was cleared */
713         mode= Trans.mode;
714         
715         calculatePropRatio(&Trans);
716         calculateCenter(&Trans);
717
718         switch (mode) {
719         case TFM_TRANSLATION:
720                 initTranslation(&Trans);
721                 break;
722         case TFM_ROTATION:
723                 initRotation(&Trans);
724                 break;
725         case TFM_RESIZE:
726                 initResize(&Trans);
727                 break;
728         case TFM_TOSPHERE:
729                 initToSphere(&Trans);
730                 break;
731         case TFM_SHEAR:
732                 initShear(&Trans);
733                 break;
734         case TFM_WARP:
735                 initWarp(&Trans);
736                 break;
737         case TFM_SHRINKFATTEN:
738                 initShrinkFatten(&Trans);
739                 break;
740         case TFM_TILT:
741                 initTilt(&Trans);
742                 break;
743         case TFM_TRACKBALL:
744                 initTrackball(&Trans);
745                 break;
746         case TFM_PUSHPULL:
747                 initPushPull(&Trans);
748                 break;
749         case TFM_CREASE:
750                 initCrease(&Trans);
751                 break;
752         case TFM_BONESIZE:
753                 {       /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */
754                         bArmature *arm= Trans.poseobj->data;
755                         if(arm->drawtype==ARM_ENVELOPE)
756                                 initBoneEnvelope(&Trans);
757                         else
758                                 initBoneSize(&Trans);
759                 }
760                 break;
761         case TFM_BONE_ENVELOPE:
762                 initBoneEnvelope(&Trans);
763                 break;
764         }
765 }
766
767 void Transform() 
768 {
769         short pmval[2] = {0, 0}, mval[2], val;
770         unsigned short event;
771
772         if(Trans.total==0) return;      // added, can happen now! (ton)
773         
774         // Emptying event queue
775         while( qtest() ) {
776                 event= extern_qread(&val);
777         }
778
779         Trans.redraw = 1; /* initial draw */
780
781         while (Trans.state == TRANS_RUNNING) {
782
783                 getmouseco_areawin(mval);
784                 
785                 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
786                         if (Trans.flag & T_MMB_PRESSED) {
787                                 initSelectConstraint(&Trans, Trans.spacemtx);
788                         }
789                         Trans.redraw = 1;
790                 }
791                 if (Trans.redraw) {
792                         pmval[0] = mval[0];
793                         pmval[1] = mval[1];
794
795                         selectConstraint(&Trans);
796                         if (Trans.transform) {
797                                 Trans.transform(&Trans, mval);  // calls recalcData()
798                         }
799                         Trans.redraw = 0;
800                 }
801                 
802                 /* essential for idling subloop */
803                 if( qtest()==0) PIL_sleep_ms(2);
804
805                 while( qtest() ) {
806                         event= extern_qread(&val);
807                         transformEvent(event, val);
808                 }
809         }
810         
811         
812         /* handle restoring objects and Undo */
813         if(Trans.state == TRANS_CANCEL) {
814                 restoreTransObjects(&Trans);    // calls recalcData()
815                 if(Trans.undostr) BIF_undo_push(Trans.undostr);
816         }
817         else {
818                 if(Trans.undostr) BIF_undo_push(Trans.undostr);
819                 else BIF_undo_push(transform_to_undostr(&Trans));
820         }
821         Trans.undostr= NULL;
822         
823         /* free data */
824         postTrans(&Trans);
825
826         /* aftertrans does insert ipos and action channels, and clears base flags, doesnt read transdata */
827         special_aftertrans_update(&Trans);
828
829         /* send events out for redraws */
830         viewRedrawPost(&Trans);
831 }
832
833 /* ************************** Manipulator init and main **************************** */
834
835 void initManipulator(int mode)
836 {
837         Trans.state = TRANS_RUNNING;
838
839         Trans.context = CTX_NONE;
840         
841         /* automatic switch to scaling bone envelopes */
842         if(mode==TFM_RESIZE && G.obedit && G.obedit->type==OB_ARMATURE) {
843                 bArmature *arm= G.obedit->data;
844                 if(arm->drawtype==ARM_ENVELOPE)
845                         mode= TFM_BONE_ENVELOPE;
846         }
847
848         initTrans(&Trans);                                      // internal data, mouse, vectors
849
850         initTransModeFlags(&Trans, mode);       // modal settings in struct Trans
851
852         G.moving |= G_TRANSFORM_MANIP;          // signal to draw manipuls while transform
853         createTransData(&Trans);                        // make TransData structs from selection
854
855         if (Trans.total == 0)
856                 return;
857
858         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
859         /* EVIL2: we gave as argument also texture space context bit... was cleared */
860         mode= Trans.mode;
861         
862         calculatePropRatio(&Trans);
863         calculateCenter(&Trans);
864
865         switch (mode) {
866         case TFM_TRANSLATION:
867                 initTranslation(&Trans);
868                 break;
869         case TFM_ROTATION:
870                 initRotation(&Trans);
871                 break;
872         case TFM_RESIZE:
873                 initResize(&Trans);
874                 break;
875         case TFM_TRACKBALL:
876                 initTrackball(&Trans);
877                 break;
878         }
879
880         Trans.flag |= T_USES_MANIPULATOR;
881 }
882
883 void ManipulatorTransform() 
884 {
885         int mouse_moved = 0;
886         short pmval[2] = {0, 0}, mval[2], val;
887         unsigned short event;
888
889         if (Trans.total == 0)
890                 return;
891
892         Trans.redraw = 1; /* initial draw */
893
894         while (Trans.state == TRANS_RUNNING) {
895                 
896                 getmouseco_areawin(mval);
897                 
898                 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
899                         Trans.redraw = 1;
900                 }
901                 if (Trans.redraw) {
902                         pmval[0] = mval[0];
903                         pmval[1] = mval[1];
904
905                         //selectConstraint(&Trans);  needed?
906                         if (Trans.transform) {
907                                 Trans.transform(&Trans, mval);
908                         }
909                         Trans.redraw = 0;
910                 }
911                 
912                 /* essential for idling subloop */
913                 if( qtest()==0) PIL_sleep_ms(2);
914
915                 while( qtest() ) {
916                         event= extern_qread(&val);
917
918                         switch (event){
919                         case MOUSEX:
920                         case MOUSEY:
921                                 mouse_moved = 1;
922                                 break;
923                         /* enforce redraw of transform when modifiers are used */
924                         case LEFTCTRLKEY:
925                         case RIGHTCTRLKEY:
926                                 if(val) Trans.redraw = 1;
927                                 break;
928                         case LEFTSHIFTKEY:
929                         case RIGHTSHIFTKEY:
930                                 /* shift is modifier for higher resolution transform, works nice to store this mouse position */
931                                 if(val) {
932                                         getmouseco_areawin(Trans.shiftmval);
933                                         Trans.flag |= T_SHIFT_MOD;
934                                         Trans.redraw = 1;
935                                 }
936                                 else Trans.flag &= ~T_SHIFT_MOD; 
937                                 break;
938                                 
939                         case ESCKEY:
940                         case RIGHTMOUSE:
941                                 Trans.state = TRANS_CANCEL;
942                                 break;
943                         case LEFTMOUSE:
944                                 if(mouse_moved==0 && val==0) break;
945                                 // else we pass on event to next, which cancels
946                         case SPACEKEY:
947                         case PADENTER:
948                         case RETKEY:
949                                 Trans.state = TRANS_CONFIRM;
950                                 break;
951                         }
952                         if(val) {
953                                 switch(event) {
954                                 case WHEELDOWNMOUSE:
955                                 case PADPLUSKEY:
956                                         if(Trans.flag & T_PROP_EDIT) {
957                                                 Trans.propsize*= 1.1f;
958                                                 calculatePropRatio(&Trans);
959                                                 Trans.redraw= 1;
960                                         }
961                                         break;
962                                 case WHEELUPMOUSE:
963                                 case PADMINUS:
964                                         if(Trans.flag & T_PROP_EDIT) {
965                                                 Trans.propsize*= 0.90909090f;
966                                                 calculatePropRatio(&Trans);
967                                                 Trans.redraw= 1;
968                                         }
969                                         break;
970                                 }                       
971                         }
972                 }
973         }
974         
975         if(Trans.state == TRANS_CANCEL) {
976                 restoreTransObjects(&Trans);
977         }
978         else {
979                 BIF_undo_push(transform_to_undostr(&Trans));
980         }
981         
982         /* free data, reset vars */
983         postTrans(&Trans);
984         
985         /* aftertrans does insert ipos and action channels, and clears base flags */
986         special_aftertrans_update(&Trans);
987         
988         /* send events out for redraws */
989         viewRedrawPost(&Trans);
990 }
991
992 /* ************************** TRANSFORMATIONS **************************** */
993
994 /* ************************** WRAP *************************** */
995
996 /* warp is done fully in view space */
997 void initWarp(TransInfo *t) 
998 {
999         float max[3], min[3];
1000         int i;
1001         
1002         calculateCenterCursor(t);
1003         t->idx_max = 0;
1004         t->num.idx_max = 0;
1005         t->transform = Warp;
1006         t->snap[0] = 0.0f;
1007         t->snap[1] = 5.0f;
1008         t->snap[2] = 1.0f;
1009         
1010         t->fac = (float)(t->center2d[0] - t->imval[0]);
1011         
1012         /* we need min/max in view space */
1013         for(i = 0; i < t->total; i++) {
1014                 float center[3];
1015                 VECCOPY(center, t->data[i].center);
1016                 Mat3MulVecfl(t->data[i].mtx, center);
1017                 Mat4MulVecfl(t->viewmat, center);
1018                 VecSubf(center, center, t->viewmat[3]);
1019                 if (i)
1020                         MinMax3(min, max, center);
1021                 else {
1022                         VECCOPY(max, center);
1023                         VECCOPY(min, center);
1024                 }
1025         }
1026
1027         t->center[0]= (min[0]+max[0])/2.0f;
1028         t->center[1]= (min[1]+max[1])/2.0f;
1029         t->center[2]= (min[2]+max[2])/2.0f;
1030         
1031         t->val= (max[0]-min[0])/2.0f;   // t->val is free variable
1032 }
1033
1034
1035 int Warp(TransInfo *t, short mval[2])
1036 {
1037         TransData *td = t->data;
1038         float vec[3], circumfac, dist, phi0, co, si, *curs, cursor[3], gcursor[3];
1039         int i;
1040         char str[50];
1041         
1042         curs= give_cursor();
1043         /*
1044          * gcursor is the one used for helpline.
1045          * It has to be in the same space as the drawing loop
1046          * (that means it needs to be in the object's space when in edit mode and
1047          *  in global space in object mode)
1048          *
1049          * cursor is used for calculations.
1050          * It needs to be in view space, but we need to take object's offset
1051          * into account if in Edit mode.
1052          */
1053         VECCOPY(cursor, curs);
1054         VECCOPY(gcursor, cursor);       
1055         if (t->flag & T_EDIT) {
1056                 VecSubf(cursor, cursor, G.obedit->obmat[3]);
1057                 VecSubf(gcursor, gcursor, G.obedit->obmat[3]);
1058                 Mat3MulVecfl(t->data->smtx, gcursor);
1059         }
1060         Mat4MulVecfl(t->viewmat, cursor);
1061         VecSubf(cursor, cursor, t->viewmat[3]);
1062
1063         // amount of degrees for warp, 450 = allow to create 360 degree warp
1064         circumfac= 450.0f*(mval[1] - t->imval[1]) / (float)(curarea->winy);
1065         circumfac+= 90.0f;
1066
1067         snapGrid(t, &circumfac);
1068         applyNumInput(&t->num, &circumfac);
1069         
1070         /* header print for NumInput */
1071         if (hasNumInput(&t->num)) {
1072                 char c[20];
1073                 
1074                 outputNumInput(&(t->num), c);
1075                 
1076                 sprintf(str, "Warp: %s", c);
1077         }
1078         else {
1079                 /* default header print */
1080                 sprintf(str, "Warp: %.3f", circumfac);
1081         }
1082         
1083         circumfac*= (float)(-M_PI/360.0);
1084         
1085         for(i = 0 ; i < t->total; i++, td++) {
1086                 float loc[3];
1087                 if (td->flag & TD_NOACTION)
1088                         break;
1089
1090                 /* translate point to centre, rotate in such a way that outline==distance */
1091                 
1092                 VECCOPY(vec, td->iloc);
1093                 Mat3MulVecfl(td->mtx, vec);
1094                 Mat4MulVecfl(t->viewmat, vec);
1095                 VecSubf(vec, vec, t->viewmat[3]);
1096                 
1097                 dist= vec[0]-cursor[0];
1098
1099                 phi0= (circumfac*dist/t->val);  // t->val is X dimension projected boundbox
1100                 
1101                 vec[1]= (vec[1]-cursor[1]);
1102                 
1103                 co= (float)cos(phi0);
1104                 si= (float)sin(phi0);
1105                 loc[0]= -si*vec[1]+cursor[0];
1106                 loc[1]= co*vec[1]+cursor[1];
1107                 loc[2]= vec[2];
1108                 
1109                 Mat4MulVecfl(t->viewinv, loc);
1110                 VecSubf(loc, loc, t->viewinv[3]);
1111                 Mat3MulVecfl(td->smtx, loc);
1112
1113                 VecSubf(loc, loc, td->iloc);
1114                 VecMulf(loc, td->factor);
1115                 VecAddf(td->loc, td->iloc, loc);
1116         }
1117
1118         recalcData(t);
1119         
1120         headerprint(str);
1121         
1122         viewRedrawForce(t);
1123         
1124         helpline(t, gcursor);
1125         
1126         return 1;
1127 }
1128
1129 /* ************************** SHEAR *************************** */
1130
1131 void initShear(TransInfo *t) 
1132 {
1133         t->idx_max = 0;
1134         t->num.idx_max = 0;
1135         t->snap[0] = 0.0f;
1136         t->snap[1] = 0.1f;
1137         t->snap[2] = t->snap[1] * 0.1f;
1138         t->transform = Shear;
1139         t->fac = (float)(t->center2d[0] - t->imval[0]);
1140 }
1141
1142 int Shear(TransInfo *t, short mval[2]) 
1143 {
1144         TransData *td = t->data;
1145         float vec[3];
1146         float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
1147         float value;
1148         int i;
1149         char str[50];
1150
1151         Mat3CpyMat4(persmat, t->viewmat);
1152         Mat3Inv(persinv, persmat);
1153
1154         value = -0.005f * ((float)(t->center2d[0] - mval[0]) - t->fac);
1155
1156         snapGrid(t, &value);
1157
1158         applyNumInput(&t->num, &value);
1159
1160         /* header print for NumInput */
1161         if (hasNumInput(&t->num)) {
1162                 char c[20];
1163
1164                 outputNumInput(&(t->num), c);
1165
1166                 sprintf(str, "Shear: %s %s", c, t->proptext);
1167         }
1168         else {
1169                 /* default header print */
1170                 sprintf(str, "Shear: %.3f %s", value, t->proptext);
1171         }
1172         
1173         Mat3One(smat);
1174         smat[1][0] = value;
1175         Mat3MulMat3(tmat, smat, persmat);
1176         Mat3MulMat3(totmat, persinv, tmat);
1177         
1178         for(i = 0 ; i < t->total; i++, td++) {
1179                 if (td->flag & TD_NOACTION)
1180                         break;
1181
1182                 if (G.obedit) {
1183                         float mat3[3][3];
1184                         Mat3MulMat3(mat3, totmat, td->mtx);
1185                         Mat3MulMat3(tmat, td->smtx, mat3);
1186                 }
1187                 else {
1188                         Mat3CpyMat3(tmat, totmat);
1189                 }
1190                 VecSubf(vec, td->center, t->center);
1191
1192                 Mat3MulVecfl(tmat, vec);
1193
1194                 VecAddf(vec, vec, t->center);
1195                 VecSubf(vec, vec, td->center);
1196
1197                 VecMulf(vec, td->factor);
1198
1199                 VecAddf(td->loc, td->iloc, vec);
1200         }
1201
1202         recalcData(t);
1203
1204         headerprint(str);
1205
1206         viewRedrawForce(t);
1207
1208         helpline (t, t->center);
1209
1210         return 1;
1211 }
1212
1213 /* ************************** RESIZE *************************** */
1214
1215 void initResize(TransInfo *t) 
1216 {
1217         t->fac = (float)sqrt( (float)
1218                 (
1219                         (t->center2d[1] - t->imval[1])*(t->center2d[1] - t->imval[1])
1220                 +
1221                         (t->center2d[0] - t->imval[0])*(t->center2d[0] - t->imval[0])
1222                 ) );
1223
1224         if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
1225         
1226         t->idx_max = 2;
1227         t->num.idx_max = 2;
1228         t->snap[0] = 0.0f;
1229         t->snap[1] = 0.1f;
1230         t->snap[2] = t->snap[1] * 0.1f;
1231         t->transform = Resize;
1232 }
1233
1234 static void headerResize(TransInfo *t, float vec[3], char *str) {
1235         char tvec[60];
1236         if (hasNumInput(&t->num)) {
1237                 outputNumInput(&(t->num), tvec);
1238         }
1239         else {
1240                 sprintf(&tvec[0], "%.4f", vec[0]);
1241                 sprintf(&tvec[20], "%.4f", vec[1]);
1242                 sprintf(&tvec[40], "%.4f", vec[2]);
1243         }
1244
1245         if (t->con.mode & CON_APPLY) {
1246                 switch(t->num.idx_max) {
1247                 case 0:
1248                         sprintf(str, "Size: %s%s %s", &tvec[0], t->con.text, t->proptext);
1249                         break;
1250                 case 1:
1251                         sprintf(str, "Size: %s : %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
1252                         break;
1253                 case 2:
1254                         sprintf(str, "Size: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
1255                 }
1256         }
1257         else {
1258                 if (t->flag & T_2D_EDIT)
1259                         sprintf(str, "Size X: %s   Y: %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
1260                 else
1261                         sprintf(str, "Size X: %s   Y: %s  Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
1262         }
1263 }
1264
1265 #define SIGN(a)         (a<-FLT_EPSILON?1:a>FLT_EPSILON?2:3)
1266 #define VECSIGNFLIP(a, b) ((SIGN(a[0]) & SIGN(b[0]))==0 || (SIGN(a[1]) & SIGN(b[1]))==0 || (SIGN(a[2]) & SIGN(b[2]))==0)
1267
1268 /* smat is reference matrix, only scaled */
1269 static void TransMat3ToSize( float mat[][3], float smat[][3], float *size)
1270 {
1271         float vec[3];
1272         
1273         VecCopyf(vec, mat[0]);
1274         size[0]= Normalise(vec);
1275         VecCopyf(vec, mat[1]);
1276         size[1]= Normalise(vec);
1277         VecCopyf(vec, mat[2]);
1278         size[2]= Normalise(vec);
1279         
1280         /* first tried with dotproduct... but the sign flip is crucial */
1281         if( VECSIGNFLIP(mat[0], smat[0]) ) size[0]= -size[0]; 
1282         if( VECSIGNFLIP(mat[1], smat[1]) ) size[1]= -size[1]; 
1283         if( VECSIGNFLIP(mat[2], smat[2]) ) size[2]= -size[2]; 
1284 }
1285
1286
1287 static void ElementResize(TransInfo *t, TransData *td, float mat[3][3]) {
1288         float tmat[3][3], smat[3][3], center[3];
1289         float vec[3];
1290
1291         if (t->flag & T_EDIT) {
1292                 Mat3MulMat3(smat, mat, td->mtx);
1293                 Mat3MulMat3(tmat, td->smtx, smat);
1294         }
1295         else {
1296                 Mat3CpyMat3(tmat, mat);
1297         }
1298
1299         if (t->con.applySize) {
1300                 t->con.applySize(t, td, tmat);
1301         }
1302
1303         /* local constraint shouldn't alter center */
1304         if (t->around == V3D_LOCAL) {
1305                 if (t->flag & T_OBJECT) {
1306                         VECCOPY(center, td->center);    // not supported in editmode yet
1307                 }
1308                 else {
1309                         VECCOPY(center, t->center);             // Editmode needs to define center too...
1310                 }
1311         }
1312         else {
1313                 VECCOPY(center, t->center);
1314         }
1315
1316         if (td->ext) {
1317                 float fsize[3];
1318
1319                 if (t->flag & T_OBJECT) {
1320                         float obsizemat[3][3];
1321                         // Reorient the size mat to fit the oriented object.
1322                         Mat3MulMat3(obsizemat, tmat, td->axismtx);
1323                         //printmatrix3("obsizemat", obsizemat);
1324                         TransMat3ToSize(obsizemat, td->axismtx, fsize);
1325                         //printvecf("fsize", fsize);
1326                 }
1327                 else {
1328                         Mat3ToSize(tmat, fsize);
1329                 }
1330                 
1331                 if ((t->flag & T_V3D_ALIGN)==0) {       // align mode doesn't rotate objects itself
1332                         /* handle ipokeys? */
1333                         if(td->tdi) {
1334                                 TransDataIpokey *tdi= td->tdi;
1335                                 /* calculate delta size (equal for size and dsize) */
1336                                 
1337                                 vec[0]= (tdi->oldsize[0])*(fsize[0] -1.0f) * td->factor;
1338                                 vec[1]= (tdi->oldsize[1])*(fsize[1] -1.0f) * td->factor;
1339                                 vec[2]= (tdi->oldsize[2])*(fsize[2] -1.0f) * td->factor;
1340                                 
1341                                 add_tdi_poin(tdi->sizex, tdi->oldsize,   vec[0]);
1342                                 add_tdi_poin(tdi->sizey, tdi->oldsize+1, vec[1]);
1343                                 add_tdi_poin(tdi->sizez, tdi->oldsize+2, vec[2]);
1344                                 
1345                         }
1346                         else if((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)){
1347                                 /* scale val and reset size */
1348                                 *td->val = td->ival * fsize[0] * td->factor;
1349
1350                                 td->ext->size[0] = td->ext->isize[0];
1351                                 td->ext->size[1] = td->ext->isize[1];
1352                                 td->ext->size[2] = td->ext->isize[2];
1353                         }
1354                         else {
1355                                 /* Reset val if SINGLESIZE but using a constraint */
1356                                 if (td->flag & TD_SINGLESIZE)
1357                                         *td->val = td->ival;
1358
1359                                 td->ext->size[0] = td->ext->isize[0] * (fsize[0]) * td->factor;
1360                                 td->ext->size[1] = td->ext->isize[1] * (fsize[1]) * td->factor;
1361                                 td->ext->size[2] = td->ext->isize[2] * (fsize[2]) * td->factor;
1362                         }
1363                 }
1364         }
1365         /* For individual element center, Editmode need to use iloc */
1366         if (t->flag & T_POINTS)
1367                 VecSubf(vec, td->iloc, center);
1368         else
1369                 VecSubf(vec, td->center, center);
1370
1371         Mat3MulVecfl(tmat, vec);
1372
1373         VecAddf(vec, vec, center);
1374         if (t->flag & T_POINTS)
1375                 VecSubf(vec, vec, td->iloc);
1376         else
1377                 VecSubf(vec, vec, td->center);
1378
1379         VecMulf(vec, td->factor);
1380
1381         if (t->flag & T_OBJECT) {
1382                 Mat3MulVecfl(td->smtx, vec);
1383         }
1384
1385         if(td->tdi) {
1386                 TransDataIpokey *tdi= td->tdi;
1387                 add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
1388                 add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
1389                 add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
1390         }
1391         else VecAddf(td->loc, td->iloc, vec);
1392 }
1393
1394 int Resize(TransInfo *t, short mval[2]) 
1395 {
1396         TransData *td;
1397         float size[3], mat[3][3];
1398         float ratio;
1399         int i;
1400         char str[50];
1401
1402         /* for manipulator, center handle, the scaling can't be done relative to center */
1403         if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) {
1404                 ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f;
1405         }
1406         else {
1407                 ratio = InputScaleRatio(t, mval);
1408                 
1409                 /* flip scale, but not for manipulator center handle */
1410                 if      ((t->center2d[0] - mval[0]) * (t->center2d[0] - t->imval[0]) + 
1411                          (t->center2d[1] - mval[1]) * (t->center2d[1] - t->imval[1]) < 0)
1412                                 ratio *= -1.0f;
1413         }
1414         
1415         size[0] = size[1] = size[2] = ratio;
1416
1417         snapGrid(t, size);
1418
1419         if (hasNumInput(&t->num)) {
1420                 applyNumInput(&t->num, size);
1421                 constraintNumInput(t, size);
1422         }
1423
1424         SizeToMat3(size, mat);
1425
1426         if (t->con.applySize) {
1427                 t->con.applySize(t, NULL, mat);
1428         }
1429
1430         Mat3CpyMat3(t->mat, mat);       // used in manipulator
1431         
1432         headerResize(t, size, str);
1433
1434         for(i = 0, td=t->data; i < t->total; i++, td++) {
1435                 if (td->flag & TD_NOACTION)
1436                         break;
1437                 
1438                 ElementResize(t, td, mat);
1439         }
1440
1441         /* evil hack - redo resize if cliiping needeed */
1442         if (t->flag & T_CLIP_UV && clipUVTransform(t, size, 1)) {
1443                 SizeToMat3(size, mat);
1444
1445                 if (t->con.applySize)
1446                         t->con.applySize(t, NULL, mat);
1447
1448                 for(i = 0, td=t->data; i < t->total; i++, td++)
1449                         ElementResize(t, td, mat);
1450         }
1451
1452         recalcData(t);
1453
1454         headerprint(str);
1455
1456         viewRedrawForce(t);
1457
1458         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
1459
1460         return 1;
1461 }
1462
1463 /* ************************** TOSPHERE *************************** */
1464
1465 void initToSphere(TransInfo *t) 
1466 {
1467         TransData *td = t->data;
1468         int i;
1469
1470         // Calculate average radius
1471         for(i = 0 ; i < t->total; i++, td++) {
1472                 t->val += VecLenf(t->center, td->iloc);
1473         }
1474
1475         t->val /= (float)t->total;
1476
1477         t->idx_max = 0;
1478         t->num.idx_max = 0;
1479         t->snap[0] = 0.0f;
1480         t->snap[1] = 0.1f;
1481         t->snap[2] = t->snap[1] * 0.1f;
1482         t->transform = ToSphere;
1483 }
1484
1485
1486
1487 int ToSphere(TransInfo *t, short mval[2]) 
1488 {
1489         float vec[3];
1490         float ratio, radius;
1491         int i;
1492         char str[50];
1493         TransData *td = t->data;
1494
1495         ratio = InputHorizontalRatio(t, mval);
1496
1497         snapGrid(t, &ratio);
1498
1499         applyNumInput(&t->num, &ratio);
1500
1501         if (ratio < 0)
1502                 ratio = 0.0f;
1503         else if (ratio > 1)
1504                 ratio = 1.0f;
1505
1506         /* header print for NumInput */
1507         if (hasNumInput(&t->num)) {
1508                 char c[20];
1509
1510                 outputNumInput(&(t->num), c);
1511
1512                 sprintf(str, "To Sphere: %s %s", c, t->proptext);
1513         }
1514         else {
1515                 /* default header print */
1516                 sprintf(str, "To Sphere: %.4f %s", ratio, t->proptext);
1517         }
1518         
1519         
1520         for(i = 0 ; i < t->total; i++, td++) {
1521                 float tratio;
1522                 if (td->flag & TD_NOACTION)
1523                         break;
1524
1525                 VecSubf(vec, td->iloc, t->center);
1526
1527                 radius = Normalise(vec);
1528
1529                 tratio = ratio * td->factor;
1530
1531                 VecMulf(vec, radius * (1.0f - tratio) + t->val * tratio);
1532
1533                 VecAddf(td->loc, t->center, vec);
1534         }
1535
1536         recalcData(t);
1537
1538         headerprint(str);
1539
1540         viewRedrawForce(t);
1541
1542         return 1;
1543 }
1544
1545 /* ************************** ROTATION *************************** */
1546
1547
1548 void initRotation(TransInfo *t) 
1549 {
1550         t->idx_max = 0;
1551         t->num.idx_max = 0;
1552         t->snap[0] = 0.0f;
1553         t->snap[1] = (float)((5.0/180)*M_PI);
1554         t->snap[2] = t->snap[1] * 0.2f;
1555         t->fac = 0;
1556         t->transform = Rotation;
1557 }
1558
1559 static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3]) {
1560         float vec[3], totmat[3][3], smat[3][3];
1561         float eul[3], fmat[3][3], quat[4];
1562
1563         if (t->flag & T_POINTS) {
1564                 Mat3MulMat3(totmat, mat, td->mtx);
1565                 Mat3MulMat3(smat, td->smtx, totmat);
1566                 
1567                 VecSubf(vec, td->iloc, t->center);
1568                 Mat3MulVecfl(smat, vec);
1569                 
1570                 VecAddf(td->loc, vec, t->center);
1571
1572                 if(td->flag & TD_USEQUAT) {
1573                         Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
1574                         Mat3ToQuat(fmat, quat); // Actual transform
1575                         QuatMul(td->ext->quat, quat, td->ext->iquat);
1576                 }
1577         }
1578         else {
1579                 /* translation */
1580                 
1581                 VecSubf(vec, td->center, t->center);
1582                 Mat3MulVecfl(mat, vec);
1583                 VecAddf(vec, vec, t->center);
1584                 /* vec now is the location where the object has to be */
1585                 VecSubf(vec, vec, td->center);
1586                 Mat3MulVecfl(td->smtx, vec);
1587
1588                 if(td->tdi) {
1589                         TransDataIpokey *tdi= td->tdi;
1590                         add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
1591                         add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
1592                         add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
1593                 }
1594                 else VecAddf(td->loc, td->iloc, vec);
1595
1596                 if(td->flag & TD_USEQUAT) {
1597                         Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
1598                         Mat3ToQuat(fmat, quat); // Actual transform
1599                         QuatMul(td->ext->quat, quat, td->ext->iquat);
1600                 }
1601                 else if ((t->flag & T_V3D_ALIGN)==0) {  // align mode doesn't rotate objects itself
1602                         float obmat[3][3];
1603                         
1604                         /* are there ipo keys? */
1605                         if(td->tdi) {
1606                                 TransDataIpokey *tdi= td->tdi;
1607                                 float rot[3];
1608                                 
1609                                 /* calculate the total rotatation in eulers */
1610                                 VecAddf(eul, td->ext->irot, td->ext->drot);
1611                                 EulToMat3(eul, obmat);
1612                                 /* mat = transform, obmat = object rotation */
1613                                 Mat3MulMat3(fmat, mat, obmat);
1614                                 Mat3ToEul(fmat, eul);
1615                                 compatible_eul(eul, td->ext->irot);
1616                                 
1617                                 /* correct back for delta rot */
1618                                 if(tdi->flag & TOB_IPODROT) {
1619                                         VecSubf(rot, eul, td->ext->irot);
1620                                 }
1621                                 else {
1622                                         VecSubf(rot, eul, td->ext->drot);
1623                                 }
1624                                 
1625                                 VecMulf(rot, (float)(9.0/M_PI_2));
1626                                 VecSubf(rot, rot, tdi->oldrot);
1627                                 
1628                                 add_tdi_poin(tdi->rotx, tdi->oldrot, rot[0]);
1629                                 add_tdi_poin(tdi->roty, tdi->oldrot+1, rot[1]);
1630                                 add_tdi_poin(tdi->rotz, tdi->oldrot+2, rot[2]);
1631                         }
1632                         else {
1633                                 Mat3MulMat3(totmat, mat, td->mtx);
1634                                 Mat3MulMat3(smat, td->smtx, totmat);
1635                                 
1636                                 /* calculate the total rotatation in eulers */
1637                                 VecAddf(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
1638                                 EulToMat3(eul, obmat);
1639                                 /* mat = transform, obmat = object rotation */
1640                                 Mat3MulMat3(fmat, smat, obmat);
1641                                 Mat3ToEul(fmat, eul);
1642                                 compatible_eul(eul, td->ext->irot);
1643                                 
1644                                 /* correct back for delta rot */
1645                                 VecSubf(eul, eul, td->ext->drot);
1646                                 /* and apply */
1647                                 VECCOPY(td->ext->rot, eul);
1648                         }
1649                 }
1650         }
1651 }
1652
1653 static void applyRotation(TransInfo *t, float angle, float axis[3]) 
1654 {
1655         TransData *td = t->data;
1656         float mat[3][3], center[3];
1657         int i;
1658
1659         /* saving original center */
1660         if (t->around == V3D_LOCAL) {
1661                 VECCOPY(center, t->center);
1662         }
1663
1664         VecRotToMat3(axis, angle, mat);
1665
1666         for(i = 0 ; i < t->total; i++, td++) {
1667
1668                 if (td->flag & TD_NOACTION)
1669                         break;
1670                 
1671                 /* local constraint shouldn't alter center */
1672                 if (t->around == V3D_LOCAL) {
1673                         if (t->flag & T_OBJECT)
1674                                 VECCOPY(t->center, td->center);         // not supported in editmode yet
1675                 }
1676                 
1677                 if (t->con.applyRot) {
1678                         t->con.applyRot(t, td, axis);
1679                         VecRotToMat3(axis, angle * td->factor, mat);
1680                 }
1681                 else if (t->flag & T_PROP_EDIT) {
1682                         VecRotToMat3(axis, angle * td->factor, mat);
1683                 }
1684
1685                 ElementRotation(t, td, mat);
1686         }
1687
1688         /* restoring original center */
1689         if (t->around == V3D_LOCAL) {
1690                 VECCOPY(t->center, center);
1691         }
1692 }
1693
1694 int Rotation(TransInfo *t, short mval[2]) 
1695 {
1696         TransData *td = t->data;
1697         char str[50];
1698
1699         float final;
1700
1701         int dx2 = t->center2d[0] - mval[0];
1702         int dy2 = t->center2d[1] - mval[1];
1703         double B = sqrt(dx2*dx2+dy2*dy2);
1704
1705         int dx1 = t->center2d[0] - t->imval[0];
1706         int dy1 = t->center2d[1] - t->imval[1];
1707         double A = sqrt(dx1*dx1+dy1*dy1);
1708
1709         int dx3 = mval[0] - t->imval[0];
1710         int dy3 = mval[1] - t->imval[1];
1711                 /* use doubles here, to make sure a "1.0" (no rotation) doesnt become 9.999999e-01, which gives 0.02 for acos */
1712         double deler= ((double)((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3) ))
1713                 / (2.0 * (A*B?A*B:1.0));
1714         /* (A*B?A*B:1.0f) this takes care of potential divide by zero errors */
1715
1716         float dphi;
1717
1718         float axis[3];
1719         float mat[3][3];
1720
1721         VECCOPY(axis, t->viewinv[2]);
1722         VecMulf(axis, -1.0f);
1723         Normalise(axis);
1724
1725         dphi = saacos((float)deler);
1726         if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
1727
1728         if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
1729         else t->fac += dphi;
1730
1731         /*
1732         clamping angle between -2 PI and 2 PI (not sure if useful so commented out - theeth)
1733         if (t->fac >= 2 * M_PI)
1734                 t->fac -= 2 * M_PI;
1735         else if (t->fac <= -2 * M_PI)
1736                 t->fac -= -2 * M_PI;
1737         */
1738
1739         final = t->fac;
1740
1741         snapGrid(t, &final);
1742
1743         t->imval[0] = mval[0];
1744         t->imval[1] = mval[1];
1745
1746         if (t->con.applyRot) {
1747                 t->con.applyRot(t, NULL, axis);
1748         }
1749
1750         if (hasNumInput(&t->num)) {
1751                 char c[20];
1752
1753                 applyNumInput(&t->num, &final);
1754
1755                 outputNumInput(&(t->num), c);
1756
1757                 sprintf(str, "Rot: %s %s", &c[0], t->proptext);
1758
1759                 final *= (float)(M_PI / 180.0);
1760         }
1761         else {
1762                 sprintf(str, "Rot: %.2f%s %s", 180.0*final/M_PI, t->con.text, t->proptext);
1763         }
1764
1765         VecRotToMat3(axis, final * td->factor, mat);
1766
1767         t->val = final;                         // used in manipulator
1768         Mat3CpyMat3(t->mat, mat);       // used in manipulator
1769         
1770         applyRotation(t, final, axis);
1771         
1772         recalcData(t);
1773
1774         headerprint(str);
1775
1776         viewRedrawForce(t);
1777
1778         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
1779
1780         return 1;
1781 }
1782
1783
1784 /* ************************** TRACKBALL *************************** */
1785
1786 void initTrackball(TransInfo *t) 
1787 {
1788         t->idx_max = 1;
1789         t->num.idx_max = 1;
1790         t->snap[0] = 0.0f;
1791         t->snap[1] = (float)((5.0/180)*M_PI);
1792         t->snap[2] = t->snap[1] * 0.2f;
1793         t->fac = 0;
1794         t->transform = Trackball;
1795 }
1796
1797 static void applyTrackball(TransInfo *t, float axis1[3], float axis2[3], float angles[2])
1798 {
1799         TransData *td = t->data;
1800         float mat[3][3], smat[3][3], totmat[3][3];
1801         int i;
1802
1803         VecRotToMat3(axis1, angles[0], smat);
1804         VecRotToMat3(axis2, angles[1], totmat);
1805         
1806         Mat3MulMat3(mat, smat, totmat);
1807
1808         for(i = 0 ; i < t->total; i++, td++) {
1809                 if (td->flag & TD_NOACTION)
1810                         break;
1811                 
1812                 if (t->around == V3D_LOCAL) {
1813                         if (t->flag & T_OBJECT)
1814                                 VECCOPY(t->center, td->center); // not supported in editmode yet
1815                 }
1816                 
1817                 if (t->flag & T_PROP_EDIT) {
1818                         VecRotToMat3(axis1, td->factor * angles[0], smat);
1819                         VecRotToMat3(axis2, td->factor * angles[1], totmat);
1820                         
1821                         Mat3MulMat3(mat, smat, totmat);
1822                 }
1823
1824                 ElementRotation(t, td, mat);
1825         }
1826 }
1827
1828 int Trackball(TransInfo *t, short mval[2]) 
1829 {
1830         char str[80];
1831         float axis1[3], axis2[3];
1832         float mat[3][3], totmat[3][3], smat[3][3];
1833         float phi[2];
1834         
1835         VECCOPY(axis1, t->persinv[0]);
1836         VECCOPY(axis2, t->persinv[1]);
1837         Normalise(axis1);
1838         Normalise(axis2);
1839         
1840         /* factore has to become setting or so */
1841         phi[0]= 0.01f*(float)( t->imval[1] - mval[1] );
1842         phi[1]= 0.01f*(float)( mval[0] - t->imval[0] );
1843         
1844         //if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
1845         //else t->fac += dphi;
1846         
1847         snapGrid(t, phi);
1848         
1849         if (hasNumInput(&t->num)) {
1850                 char c[40];
1851                 
1852                 applyNumInput(&t->num, phi);
1853                 
1854                 outputNumInput(&(t->num), c);
1855                 
1856                 sprintf(str, "Trackball: %s %s %s", &c[0], &c[20], t->proptext);
1857                 
1858                 phi[0] *= (float)(M_PI / 180.0);
1859                 phi[1] *= (float)(M_PI / 180.0);
1860         }
1861         else {
1862                 sprintf(str, "Trackball: %.2f %.2f %s", 180.0*phi[0]/M_PI, 180.0*phi[1]/M_PI, t->proptext);
1863         }
1864         
1865         VecRotToMat3(axis1, phi[0], smat);
1866         VecRotToMat3(axis2, phi[1], totmat);
1867         
1868         Mat3MulMat3(mat, smat, totmat);
1869         
1870         Mat3CpyMat3(t->mat, mat);       // used in manipulator
1871         
1872         applyTrackball(t, axis1, axis2, phi);
1873         
1874         recalcData(t);
1875         
1876         headerprint(str);
1877         
1878         viewRedrawForce(t);
1879         
1880         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
1881         
1882         return 1;
1883 }
1884
1885 /* ************************** TRANSLATION *************************** */
1886         
1887 void initTranslation(TransInfo *t) 
1888 {
1889         t->idx_max = (t->flag & T_2D_EDIT)? 1: 2;
1890         t->num.idx_max = t->idx_max;
1891         t->transform = Translation;
1892         
1893         if(t->spacetype == SPACE_VIEW3D) {
1894                 /* initgrabz() defines a factor for perspective depth correction, used in window_to_3d() */
1895                 if(G.obedit) {
1896                         float vec[3];
1897                         
1898                         VECCOPY(vec, t->center);
1899                         Mat4MulVecfl(G.obedit->obmat, vec);
1900                         initgrabz(vec[0], vec[1], vec[2]);
1901                 }
1902                 else initgrabz(t->center[0], t->center[1], t->center[2]); 
1903
1904                 t->snap[0] = 0.0f;
1905                 t->snap[1] = G.vd->gridview * 1.0f;
1906                 t->snap[2] = t->snap[1] * 0.1f;
1907         }
1908         else if(t->spacetype == SPACE_IMAGE) {
1909                 t->snap[0] = 0.0f;
1910                 t->snap[1] = 0.125f;
1911                 t->snap[2] = 0.0625f;
1912         }
1913         else {
1914                 t->snap[0] = 0.0f;
1915                 t->snap[1] = t->snap[2] = 1.0f;
1916         }
1917 }
1918
1919 static void headerTranslation(TransInfo *t, float vec[3], char *str) {
1920         char tvec[60];
1921         float dvec[3];
1922
1923         convertVecToDisplayNum(vec, dvec);
1924
1925         if (hasNumInput(&t->num)) {
1926                 outputNumInput(&(t->num), tvec);
1927         }
1928         else {
1929                 sprintf(&tvec[0], "%.4f", dvec[0]);
1930                 sprintf(&tvec[20], "%.4f", dvec[1]);
1931                 sprintf(&tvec[40], "%.4f", dvec[2]);
1932         }
1933
1934         if (t->con.mode & CON_APPLY) {
1935                 switch(t->num.idx_max) {
1936                 case 0:
1937                         sprintf(str, "D: %s%s %s", &tvec[0], t->con.text, t->proptext);
1938                         break;
1939                 case 1:
1940                         sprintf(str, "D: %s   D: %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
1941                         break;
1942                 case 2:
1943                         sprintf(str, "D: %s   D: %s  D: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
1944                 }
1945         }
1946         else {
1947                 if(t->flag & T_2D_EDIT)
1948                         sprintf(str, "Dx: %s   Dy: %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
1949                 else
1950                         sprintf(str, "Dx: %s   Dy: %s  Dz: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
1951         }
1952 }
1953
1954 static void applyTranslation(TransInfo *t, float vec[3]) {
1955         TransData *td = t->data;
1956         float tvec[3];
1957         int i;
1958
1959         for(i = 0 ; i < t->total; i++, td++) {
1960                 if (td->flag & TD_NOACTION)
1961                         break;
1962
1963                 if (t->con.applyVec) {
1964                         float pvec[3];
1965                         t->con.applyVec(t, td, vec, tvec, pvec);
1966                 }
1967                 else {
1968                         VECCOPY(tvec, vec);
1969                 }
1970
1971                 Mat3MulVecfl(td->smtx, tvec);
1972                 VecMulf(tvec, td->factor);
1973                 
1974                 /* transdata ipokey */
1975                 if(td->tdi) {
1976                         TransDataIpokey *tdi= td->tdi;
1977                         add_tdi_poin(tdi->locx, tdi->oldloc, tvec[0]);
1978                         add_tdi_poin(tdi->locy, tdi->oldloc+1, tvec[1]);
1979                         add_tdi_poin(tdi->locz, tdi->oldloc+2, tvec[2]);
1980                 }
1981                 else VecAddf(td->loc, td->iloc, tvec);
1982         }
1983 }
1984
1985 /* uses t->vec to store actual translation in */
1986 int Translation(TransInfo *t, short mval[2]) 
1987 {
1988         float tvec[3];
1989         char str[200];
1990         
1991         if(t->flag & T_SHIFT_MOD) {
1992                 float dvec[3];
1993                 /* calculate the main translation and the precise one separate */
1994                 convertViewVec(t, dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
1995                 VecMulf(dvec, 0.1f);
1996                 convertViewVec(t, t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
1997                 VecAddf(t->vec, t->vec, dvec);
1998         }
1999         else convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
2000
2001         if (t->con.mode & CON_APPLY) {
2002                 float pvec[3] = {0.0f, 0.0f, 0.0f};
2003                 t->con.applyVec(t, NULL, t->vec, tvec, pvec);
2004                 VECCOPY(t->vec, tvec);
2005                 headerTranslation(t, pvec, str);
2006         }
2007         else {
2008                 snapGrid(t, t->vec);
2009                 applyNumInput(&t->num, t->vec);
2010                 headerTranslation(t, t->vec, str);
2011         }
2012
2013         applyTranslation(t, t->vec);
2014
2015         /* evil hack - redo translation if cliiping needeed */
2016         if (t->flag & T_CLIP_UV && clipUVTransform(t, t->vec, 0))
2017                 applyTranslation(t, t->vec);
2018
2019         recalcData(t);
2020
2021         headerprint(str);
2022
2023         viewRedrawForce(t);
2024
2025         return 1;
2026 }
2027
2028 /* ************************** SHRINK/FATTEN *************************** */
2029
2030 void initShrinkFatten(TransInfo *t) 
2031 {
2032         if (G.obedit==NULL || G.obedit->type != OB_MESH) {
2033                 initTransModeFlags(t, TFM_RESIZE);
2034                 initResize(t);
2035                 return;
2036         }
2037
2038         t->idx_max = 0;
2039         t->num.idx_max = 0;
2040         t->snap[0] = 0.0f;
2041         t->snap[1] = 1.0f;
2042         t->snap[2] = t->snap[1] * 0.1f;
2043         t->transform = ShrinkFatten;
2044 }
2045
2046
2047
2048 int ShrinkFatten(TransInfo *t, short mval[2]) 
2049 {
2050         float vec[3];
2051         float ratio;
2052         int i;
2053         char str[50];
2054         TransData *td = t->data;
2055
2056         convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
2057         Projf(vec, t->vec, t->viewinv[1]);
2058         ratio = Inpf(t->viewinv[1], vec) * -2.0f;
2059
2060         snapGrid(t, &ratio);
2061
2062         applyNumInput(&t->num, &ratio);
2063
2064         /* header print for NumInput */
2065         if (hasNumInput(&t->num)) {
2066                 char c[20];
2067
2068                 outputNumInput(&(t->num), c);
2069
2070                 sprintf(str, "Shrink/Fatten: %s %s", c, t->proptext);
2071         }
2072         else {
2073                 /* default header print */
2074                 sprintf(str, "Shrink/Fatten: %.4f %s", ratio, t->proptext);
2075         }
2076         
2077         
2078         for(i = 0 ; i < t->total; i++, td++) {
2079                 if (td->flag & TD_NOACTION)
2080                         break;
2081
2082                 VECCOPY(vec, td->axismtx[2]);
2083                 VecMulf(vec, ratio);
2084                 VecMulf(vec, td->factor);
2085
2086                 VecAddf(td->loc, td->iloc, vec);
2087         }
2088
2089         recalcData(t);
2090
2091         headerprint(str);
2092
2093         viewRedrawForce(t);
2094
2095         return 1;
2096 }
2097
2098 /* ************************** TILT *************************** */
2099
2100 void initTilt(TransInfo *t) 
2101 {
2102         t->idx_max = 0;
2103         t->num.idx_max = 0;
2104         t->snap[0] = 0.0f;
2105         t->snap[1] = (float)((5.0/180)*M_PI);
2106         t->snap[2] = t->snap[1] * 0.2f;
2107         t->fac = 0;
2108         t->transform = Tilt;
2109 }
2110
2111
2112
2113 int Tilt(TransInfo *t, short mval[2]) 
2114 {
2115         TransData *td = t->data;
2116         int i;
2117         char str[50];
2118
2119         float final;
2120
2121         int dx2 = t->center2d[0] - mval[0];
2122         int dy2 = t->center2d[1] - mval[1];
2123         float B = (float)sqrt(dx2*dx2+dy2*dy2);
2124
2125         int dx1 = t->center2d[0] - t->imval[0];
2126         int dy1 = t->center2d[1] - t->imval[1];
2127         float A = (float)sqrt(dx1*dx1+dy1*dy1);
2128
2129         int dx3 = mval[0] - t->imval[0];
2130         int dy3 = mval[1] - t->imval[1];
2131
2132         float deler= ((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3))
2133                 / (2 * A * B);
2134
2135         float dphi;
2136
2137         dphi = saacos(deler);
2138         if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
2139
2140         if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
2141         else t->fac += dphi;
2142
2143         final = t->fac;
2144
2145         snapGrid(t, &final);
2146
2147         t->imval[0] = mval[0];
2148         t->imval[1] = mval[1];
2149
2150         if (hasNumInput(&t->num)) {
2151                 char c[20];
2152
2153                 applyNumInput(&t->num, &final);
2154
2155                 outputNumInput(&(t->num), c);
2156
2157                 sprintf(str, "Tilt: %s %s", &c[0], t->proptext);
2158
2159                 final *= (float)(M_PI / 180.0);
2160         }
2161         else {
2162                 sprintf(str, "Tilt: %.2f %s", 180.0*final/M_PI, t->proptext);
2163         }
2164
2165         for(i = 0 ; i < t->total; i++, td++) {
2166                 if (td->flag & TD_NOACTION)
2167                         break;
2168
2169                 if (td->val) {
2170                         *td->val = td->ival + final * td->factor;
2171                 }
2172         }
2173
2174         recalcData(t);
2175
2176         headerprint(str);
2177
2178         viewRedrawForce(t);
2179
2180         helpline (t, t->center);
2181
2182         return 1;
2183 }
2184
2185 /* ************************** PUSH/PULL *************************** */
2186
2187 void initPushPull(TransInfo *t) 
2188 {
2189         t->idx_max = 0;
2190         t->num.idx_max = 0;
2191         t->snap[0] = 0.0f;
2192         t->snap[1] = 1.0f;
2193         t->snap[2] = t->snap[1] * 0.1f;
2194         t->transform = PushPull;
2195 }
2196
2197
2198
2199 int PushPull(TransInfo *t, short mval[2]) 
2200 {
2201         float vec[3], axis[3];
2202         float distance;
2203         int i;
2204         char str[50];
2205         TransData *td = t->data;
2206
2207         convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
2208         Projf(vec, t->vec, t->viewinv[1]);
2209         distance = Inpf(t->viewinv[1], vec) * 2.0f;
2210
2211         snapGrid(t, &distance);
2212
2213         applyNumInput(&t->num, &distance);
2214
2215         /* header print for NumInput */
2216         if (hasNumInput(&t->num)) {
2217                 char c[20];
2218
2219                 outputNumInput(&(t->num), c);
2220
2221                 sprintf(str, "Push/Pull: %s%s %s", c, t->con.text, t->proptext);
2222         }
2223         else {
2224                 /* default header print */
2225                 sprintf(str, "Push/Pull: %.4f%s %s", distance, t->con.text, t->proptext);
2226         }
2227         
2228         if (t->con.applyRot && t->con.mode & CON_APPLY) {
2229                 t->con.applyRot(t, NULL, axis);
2230         }
2231         
2232         for(i = 0 ; i < t->total; i++, td++) {
2233                 if (td->flag & TD_NOACTION)
2234                         break;
2235
2236                 VecSubf(vec, t->center, td->center);
2237                 if (t->con.applyRot && t->con.mode & CON_APPLY) {
2238                         t->con.applyRot(t, td, axis);
2239                         if (isLockConstraint(t)) {
2240                                 float dvec[3];
2241                                 Projf(dvec, vec, axis);
2242                                 VecSubf(vec, vec, dvec);
2243                         }
2244                         else {
2245                                 Projf(vec, vec, axis);
2246                         }
2247                 }
2248                 Normalise(vec);
2249                 VecMulf(vec, distance);
2250                 VecMulf(vec, td->factor);
2251
2252                 VecAddf(td->loc, td->iloc, vec);
2253         }
2254
2255         recalcData(t);
2256
2257         headerprint(str);
2258
2259         viewRedrawForce(t);
2260
2261         return 1;
2262 }
2263
2264 /* ************************** CREASE *************************** */
2265
2266 void initCrease(TransInfo *t) 
2267 {
2268         t->idx_max = 0;
2269         t->num.idx_max = 0;
2270         t->snap[0] = 0.0f;
2271         t->snap[1] = 0.1f;
2272         t->snap[2] = t->snap[1] * 0.1f;
2273         t->transform = Crease;
2274         t->fac = (float)sqrt( (float)
2275                 (
2276                         (t->center2d[1] - t->imval[1])*(t->center2d[1] - t->imval[1])
2277                 +
2278                         (t->center2d[0] - t->imval[0])*(t->center2d[0] - t->imval[0])
2279                 ) );
2280
2281         if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
2282 }
2283
2284 int Crease(TransInfo *t, short mval[2]) 
2285 {
2286         TransData *td = t->data;
2287         float crease;
2288         int i;
2289         char str[50];
2290
2291                 
2292         if(t->flag & T_SHIFT_MOD) {
2293                 /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
2294                 float dx= (float)(t->center2d[0] - t->shiftmval[0]);
2295                 float dy= (float)(t->center2d[1] - t->shiftmval[1]);
2296                 crease = (float)sqrt( dx*dx + dy*dy)/t->fac;
2297                 
2298                 dx= (float)(t->center2d[0] - mval[0]);
2299                 dy= (float)(t->center2d[1] - mval[1]);
2300                 crease+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -crease);
2301                 
2302         }
2303         else {
2304                 float dx= (float)(t->center2d[0] - mval[0]);
2305                 float dy= (float)(t->center2d[1] - mval[1]);
2306                 crease = (float)sqrt( dx*dx + dy*dy)/t->fac;
2307         }
2308
2309         crease -= 1.0f;
2310         if (crease > 1.0f) crease = 1.0f;
2311
2312         snapGrid(t, &crease);
2313
2314         applyNumInput(&t->num, &crease);
2315
2316         /* header print for NumInput */
2317         if (hasNumInput(&t->num)) {
2318                 char c[20];
2319
2320                 outputNumInput(&(t->num), c);
2321
2322                 if (crease >= 0.0f)
2323                         sprintf(str, "Crease: +%s %s", c, t->proptext);
2324                 else
2325                         sprintf(str, "Crease: %s %s", c, t->proptext);
2326         }
2327         else {
2328                 /* default header print */
2329                 if (crease >= 0.0f)
2330                         sprintf(str, "Crease: +%.3f %s", crease, t->proptext);
2331                 else
2332                         sprintf(str, "Crease: %.3f %s", crease, t->proptext);
2333         }
2334         
2335         for(i = 0 ; i < t->total; i++, td++) {
2336                 if (td->flag & TD_NOACTION)
2337                         break;
2338
2339                 if (td->val) {
2340                         *td->val = td->ival + crease * td->factor;
2341                         if (*td->val < 0.0f) *td->val = 0.0f;
2342                         if (*td->val > 1.0f) *td->val = 1.0f;
2343                 }
2344         }
2345
2346         recalcData(t);
2347
2348         headerprint(str);
2349
2350         viewRedrawForce(t);
2351
2352         helpline (t, t->center);
2353
2354         return 1;
2355 }
2356
2357 /* ************************** MIRROR *************************** */
2358
2359 void Mirror(short mode) 
2360 {
2361         TransData *td;
2362         float mati[3][3], matview[3][3], mat[3][3];
2363         float size[3];
2364         int i;
2365
2366         Trans.context = CTX_NO_PET;
2367
2368         initTrans(&Trans);                                      // internal data, mouse, vectors
2369
2370         Mat3One(mati);
2371         Mat3CpyMat4(matview, Trans.viewinv); // t->viewinv was set in initTrans
2372         Mat3Ortho(matview);
2373
2374         initTransModeFlags(&Trans, TFM_MIRROR); // modal settings in struct Trans
2375
2376         createTransData(&Trans);                        // make TransData structs from selection
2377
2378         calculatePropRatio(&Trans);
2379         calculateCenter(&Trans);
2380
2381         initResize(&Trans);
2382
2383         if (Trans.total == 0) {
2384                 postTrans(&Trans);
2385                 return;
2386         }
2387
2388         size[0] = size[1] = size[2] = 1.0f;
2389         td = Trans.data;
2390
2391         switch (mode) {
2392         case 1:
2393                 size[0] = -1.0f;
2394                 setConstraint(&Trans, mati, (CON_AXIS0), "");
2395                 break;
2396         case 2:
2397                 size[1] = -1.0f;
2398                 setConstraint(&Trans, mati, (CON_AXIS1), "");
2399                 break;
2400         case 3:
2401                 size[2] = -1.0f;
2402                 setConstraint(&Trans, mati, (CON_AXIS2), "");
2403                 break;
2404         case 4:
2405                 size[0] = -1.0f;
2406                 setLocalConstraint(&Trans, (CON_AXIS0), "");
2407                 break;
2408         case 5:
2409                 size[1] = -1.0f;
2410                 setLocalConstraint(&Trans, (CON_AXIS1), "");
2411                 break;
2412         case 6:
2413                 size[2] = -1.0f;
2414                 setLocalConstraint(&Trans, (CON_AXIS2), "");
2415                 break;
2416         case 7:
2417                 size[0] = -1.0f;
2418                 setConstraint(&Trans, matview, (CON_AXIS0), "");
2419                 break;
2420         case 8:
2421                 size[1] = -1.0f;
2422                 setConstraint(&Trans, matview, (CON_AXIS1), "");
2423                 break;
2424         case 9:
2425                 size[2] = -1.0f;
2426                 setConstraint(&Trans, matview, (CON_AXIS2), "");
2427                 break;
2428         default:
2429                 return;
2430         }
2431
2432         SizeToMat3(size, mat);
2433
2434         if (Trans.con.applySize) {
2435                 Trans.con.applySize(&Trans, NULL, mat);
2436         }
2437
2438         for(i = 0 ; i < Trans.total; i++, td++) {
2439                 if (td->flag & TD_NOACTION)
2440                         break;
2441                 
2442                 ElementResize(&Trans, td, mat);
2443         }
2444
2445         recalcData(&Trans);
2446         
2447         BIF_undo_push("Mirror");
2448
2449         /* free data, reset vars */
2450         postTrans(&Trans);
2451
2452         /* send events out for redraws */
2453         viewRedrawPost(&Trans);
2454 }
2455
2456 /* ******************** EditBone (B-bone) width scaling *************** */
2457
2458 static void ElementBoneSize(TransInfo *t, TransData *td, float mat[3][3]) 
2459 {
2460         float tmat[3][3], smat[3][3], oldy;
2461         float sizemat[3][3];
2462         
2463         Mat3MulMat3(smat, mat, td->mtx);
2464         Mat3MulMat3(tmat, td->smtx, smat);
2465         
2466         if (t->con.applySize) {
2467                 t->con.applySize(t, td, tmat);
2468         }
2469         
2470         /* we've tucked the scale in loc */
2471         oldy= td->iloc[1];
2472         SizeToMat3(td->iloc, sizemat);
2473         Mat3MulMat3(tmat, tmat, sizemat);
2474         Mat3ToSize(tmat, td->loc);
2475         td->loc[1]= oldy;
2476 }
2477
2478
2479 int BoneSize(TransInfo *t, short mval[2]) 
2480 {
2481         TransData *td = t->data;
2482         float size[3], mat[3][3];
2483         float ratio;
2484         int i;
2485         char str[50];
2486         
2487         /* for manipulator, center handle, the scaling can't be done relative to center */
2488         if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) {
2489                 ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f;
2490         }
2491         else {
2492                 
2493                 if(t->flag & T_SHIFT_MOD) {
2494                         /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
2495                         float dx= (float)(t->center2d[0] - t->shiftmval[0]);
2496                         float dy= (float)(t->center2d[1] - t->shiftmval[1]);
2497                         ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
2498                         
2499                         dx= (float)(t->center2d[0] - mval[0]);
2500                         dy= (float)(t->center2d[1] - mval[1]);
2501                         ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
2502                         
2503                 }
2504                 else {
2505                         float dx= (float)(t->center2d[0] - mval[0]);
2506                         float dy= (float)(t->center2d[1] - mval[1]);
2507                         ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
2508                 }
2509                 
2510                 /* flip scale, but not for manipulator center handle */
2511                 if      ((t->center2d[0] - mval[0]) * (t->center2d[0] - t->imval[0]) + 
2512                          (t->center2d[1] - mval[1]) * (t->center2d[1] - t->imval[1]) < 0)
2513                         ratio *= -1.0f;
2514         }
2515         
2516         size[0] = size[1] = size[2] = ratio;
2517         
2518         snapGrid(t, size);
2519         
2520         if (hasNumInput(&t->num)) {
2521                 applyNumInput(&t->num, size);
2522                 constraintNumInput(t, size);
2523         }
2524         
2525         SizeToMat3(size, mat);
2526         
2527         if (t->con.applySize) {
2528                 t->con.applySize(t, NULL, mat);
2529         }
2530         
2531         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2532         
2533         headerResize(t, size, str);
2534         
2535         for(i = 0 ; i < t->total; i++, td++) {
2536                 if (td->flag & TD_NOACTION)
2537                         break;
2538                 
2539                 ElementBoneSize(t, td, mat);
2540         }
2541         
2542         recalcData(t);
2543         
2544         headerprint(str);
2545         
2546         viewRedrawForce(t);
2547         
2548         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
2549         
2550         return 1;
2551 }
2552
2553 void initBoneSize(TransInfo *t)
2554 {
2555         t->idx_max = 0;
2556         t->num.idx_max = 0;
2557         t->snap[0] = 0.0f;
2558         t->snap[1] = 0.1f;
2559         t->snap[2] = t->snap[1] * 0.1f;
2560         t->transform = BoneSize;
2561         t->fac = (float)sqrt( (float)(
2562                                                                   (t->center2d[1] - t->imval[1])*(t->center2d[1] - t->imval[1])
2563                                                                   +
2564                                                                   (t->center2d[0] - t->imval[0])*(t->center2d[0] - t->imval[0])
2565                                                                   ) );
2566         
2567         if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
2568 }
2569
2570 /* ******************** EditBone envelope *************** */
2571
2572 int BoneEnvelope(TransInfo *t, short mval[2]) 
2573 {
2574         TransData *td = t->data;
2575         float ratio;
2576         int i;
2577         char str[50];
2578         
2579         if(t->flag & T_SHIFT_MOD) {
2580                 /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
2581                 float dx= (float)(t->center2d[0] - t->shiftmval[0]);
2582                 float dy= (float)(t->center2d[1] - t->shiftmval[1]);
2583                 ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
2584                 
2585                 dx= (float)(t->center2d[0] - mval[0]);
2586                 dy= (float)(t->center2d[1] - mval[1]);
2587                 ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
2588                 
2589         }
2590         else {
2591                 float dx= (float)(t->center2d[0] - mval[0]);
2592                 float dy= (float)(t->center2d[1] - mval[1]);
2593                 ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
2594         }
2595         
2596         snapGrid(t, &ratio);
2597         
2598         applyNumInput(&t->num, &ratio);
2599         
2600         /* header print for NumInput */
2601         if (hasNumInput(&t->num)) {
2602                 char c[20];
2603                 
2604                 outputNumInput(&(t->num), c);
2605                 sprintf(str, "Envelope: %s", c);
2606         }
2607         else {
2608                 sprintf(str, "Envelope: %3f", ratio);
2609         }
2610         
2611         for(i = 0 ; i < t->total; i++, td++) {
2612                 if (td->flag & TD_NOACTION)
2613                         break;
2614                 
2615                 if(td->val) *td->val= td->ival*ratio;
2616         }
2617         
2618         recalcData(t);
2619         
2620         headerprint(str);
2621         
2622         force_draw(0);
2623         
2624         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
2625         
2626         return 1;
2627 }
2628
2629 void initBoneEnvelope(TransInfo *t)
2630 {
2631         t->idx_max = 0;
2632         t->num.idx_max = 0;
2633         t->snap[0] = 0.0f;
2634         t->snap[1] = 0.1f;
2635         t->snap[2] = t->snap[1] * 0.1f;
2636         t->transform = BoneEnvelope;
2637         t->fac = (float)sqrt( (float)(
2638                                                                   (t->center2d[1] - t->imval[1])*(t->center2d[1] - t->imval[1])
2639                                                                   +
2640                                                                   (t->center2d[0] - t->imval[0])*(t->center2d[0] - t->imval[0])
2641                                                                   ) );
2642         
2643         if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
2644 }
2645
2646 /* ************************************ */
2647
2648 void BIF_TransformSetUndo(char *str)
2649 {
2650         Trans.undostr= str;
2651 }
2652
2653