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