6e4641a4d1207df9e18b814d034906e8386daae6
[blender.git] / source / blender / src / transform.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL 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.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <math.h>
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #ifndef WIN32
40 #include <unistd.h>
41 #else
42 #include <io.h>
43 #endif
44
45 #include "MEM_guardedalloc.h"
46
47 #include "DNA_armature_types.h"
48 #include "DNA_action_types.h"  /* for some special action-editor settings */
49 #include "DNA_constraint_types.h"
50 #include "DNA_ipo_types.h"              /* some silly ipo flag  */
51 #include "DNA_listBase.h"
52 #include "DNA_meshdata_types.h"
53 #include "DNA_mesh_types.h"
54 #include "DNA_object_types.h"
55 #include "DNA_scene_types.h"            /* PET modes                    */
56 #include "DNA_screen_types.h"   /* area dimensions              */
57 #include "DNA_texture_types.h"
58 #include "DNA_userdef_types.h"
59 #include "DNA_view3d_types.h"
60 #include "DNA_space_types.h"
61
62 #include "BIF_editview.h"               /* arrows_move_cursor   */
63 #include "BIF_gl.h"
64 #include "BIF_glutil.h"
65 #include "BIF_mywindow.h"
66 #include "BIF_resources.h"
67 #include "BIF_screen.h"
68 #include "BIF_space.h"                  /* undo                                 */
69 #include "BIF_toets.h"                  /* persptoetsen                 */
70 #include "BIF_mywindow.h"               /* warp_pointer                 */
71 #include "BIF_toolbox.h"                        /* notice                               */
72 #include "BIF_editmesh.h"
73 #include "BIF_editsima.h"
74 #include "BIF_editparticle.h"
75 #include "BIF_drawimage.h"              /* uvco_to_areaco_noclip */
76 #include "BIF_editaction.h" 
77
78 #include "BKE_action.h" /* get_action_frame */
79 #include "BKE_bad_level_calls.h"/* popmenu and error    */
80 #include "BKE_bmesh.h"
81 #include "BKE_constraint.h"
82 #include "BKE_global.h"
83 #include "BKE_particle.h"
84 #include "BKE_pointcache.h"
85 #include "BKE_utildefines.h"
86
87 #include "BSE_drawipo.h"
88 #include "BSE_editnla_types.h"  /* for NLAWIDTH */
89 #include "BSE_editaction_types.h"
90 #include "BSE_time.h"
91 #include "BSE_view.h"
92
93 #include "BLI_arithb.h"
94 #include "BLI_blenlib.h"
95 #include "BLI_editVert.h"
96
97 #include "PIL_time.h"                   /* sleep                                */
98
99 #include "blendef.h"
100
101 #include "mydevice.h"
102
103 #include "transform.h"
104
105 /* GLOBAL VARIABLE THAT SHOULD MOVED TO SCREEN MEMBER OR SOMETHING  */
106 TransInfo Trans = {TFM_INIT, 0};        // enforce init on first usage
107
108 /******************************** Helper functions ************************************/
109
110 /* GLOBAL Wrapper Fonctions */
111
112 void BIF_drawSnap()
113 {
114         drawSnapping(&Trans);
115 }
116
117 /* ************************** Dashed help line **************************** */
118
119
120 /* bad frontbuffer call... because it is used in transform after force_draw() */
121 static void helpline(TransInfo *t, float *vec)
122 {
123         float vecrot[3], cent[2];
124         short mval[2];
125         
126         VECCOPY(vecrot, vec);
127         if(t->flag & T_EDIT) {
128                 Object *ob=G.obedit;
129                 if(ob) Mat4MulVecfl(ob->obmat, vecrot);
130         }
131         else if(t->flag & T_POSE) {
132                 Object *ob=t->poseobj;
133                 if(ob) Mat4MulVecfl(ob->obmat, vecrot);
134         }
135         
136         getmouseco_areawin(mval);
137         projectFloatView(t, vecrot, cent);      // no overflow in extreme cases
138         if(cent[0]!=IS_CLIPPED) {
139                 persp(PERSP_WIN);
140                 
141                 glDrawBuffer(GL_FRONT);
142                 
143                 BIF_ThemeColor(TH_WIRE);
144                 
145                 setlinestyle(3);
146                 glBegin(GL_LINE_STRIP); 
147                 glVertex2sv(mval); 
148                 glVertex2fv(cent); 
149                 glEnd();
150                 setlinestyle(0);
151                 
152                 persp(PERSP_VIEW);
153                 bglFlush(); // flush display for frontbuffer
154                 glDrawBuffer(GL_BACK);
155         }
156 }
157
158
159   
160 /* ************************** INPUT FROM MOUSE *************************** */
161
162 float InputScaleRatio(TransInfo *t, short mval[2]) {
163         float ratio, dx, dy;
164         if(t->flag & T_SHIFT_MOD) {
165                 /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
166                 dx = (float)(t->center2d[0] - t->shiftmval[0]);
167                 dy = (float)(t->center2d[1] - t->shiftmval[1]);
168                 ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
169                 
170                 dx= (float)(t->center2d[0] - mval[0]);
171                 dy= (float)(t->center2d[1] - mval[1]);
172                 ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
173         }
174         else {
175                 dx = (float)(t->center2d[0] - mval[0]);
176                 dy = (float)(t->center2d[1] - mval[1]);
177                 ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
178         }
179         return ratio;
180 }
181
182 float InputHorizontalRatio(TransInfo *t, short mval[2]) {
183         float x, pad;
184
185         pad = curarea->winx / 10;
186
187         if (t->flag & T_SHIFT_MOD) {
188                 /* deal with Shift key by adding motion / 10 to motion before shift press */
189                 x = t->shiftmval[0] + (float)(mval[0] - t->shiftmval[0]) / 10.0f;
190         }
191         else {
192                 x = mval[0];
193         }
194         return (x - pad) / (curarea->winx - 2 * pad);
195 }
196
197 float InputHorizontalAbsolute(TransInfo *t, short mval[2]) {
198         float vec[3];
199         if(t->flag & T_SHIFT_MOD) {
200                 float dvec[3];
201                 /* calculate the main translation and the precise one separate */
202                 convertViewVec(t, dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
203                 VecMulf(dvec, 0.1f);
204                 convertViewVec(t, t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
205                 VecAddf(t->vec, t->vec, dvec);
206         }
207         else {
208                 convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
209         }
210         Projf(vec, t->vec, t->viewinv[0]);
211         return Inpf(t->viewinv[0], vec) * 2.0f;
212 }
213
214 float InputVerticalRatio(TransInfo *t, short mval[2]) {
215         float y, pad;
216
217         pad = curarea->winy / 10;
218
219         if (t->flag & T_SHIFT_MOD) {
220                 /* deal with Shift key by adding motion / 10 to motion before shift press */
221                 y = t->shiftmval[1] + (float)(mval[1] - t->shiftmval[1]) / 10.0f;
222         }
223         else {
224                 y = mval[0];
225         }
226         return (y - pad) / (curarea->winy - 2 * pad);
227 }
228
229 float InputVerticalAbsolute(TransInfo *t, short mval[2]) {
230         float vec[3];
231         if(t->flag & T_SHIFT_MOD) {
232                 float dvec[3];
233                 /* calculate the main translation and the precise one separate */
234                 convertViewVec(t, dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
235                 VecMulf(dvec, 0.1f);
236                 convertViewVec(t, t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
237                 VecAddf(t->vec, t->vec, dvec);
238         }
239         else {
240                 convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
241         }
242         Projf(vec, t->vec, t->viewinv[1]);
243         return Inpf(t->viewinv[1], vec) * 2.0f;
244 }
245
246 /* ************************** SPACE DEPENDANT CODE **************************** */
247
248 void setTransformViewMatrices(TransInfo *t)
249 {
250         if(t->spacetype==SPACE_VIEW3D) {
251                 Mat4CpyMat4(t->viewmat, G.vd->viewmat);
252                 Mat4CpyMat4(t->viewinv, G.vd->viewinv);
253                 Mat4CpyMat4(t->persmat, G.vd->persmat);
254                 Mat4CpyMat4(t->persinv, G.vd->persinv);
255                 t->persp= G.vd->persp;
256         }
257         else {
258                 Mat4One(t->viewmat);
259                 Mat4One(t->viewinv);
260                 Mat4One(t->persmat);
261                 Mat4One(t->persinv);
262                 t->persp = V3D_ORTHO;
263         }
264         
265         calculateCenter2D(t);
266         
267 }
268
269 void convertViewVec(TransInfo *t, float *vec, short dx, short dy)
270 {
271         if (t->spacetype==SPACE_VIEW3D) {
272                 window_to_3d(vec, dx, dy);
273         }
274         else if(t->spacetype==SPACE_IMAGE) {
275                 float divx, divy, aspx, aspy;
276                 
277                 transform_aspect_ratio_tface_uv(&aspx, &aspy);
278                 
279                 divx= G.v2d->mask.xmax-G.v2d->mask.xmin;
280                 divy= G.v2d->mask.ymax-G.v2d->mask.ymin;
281                 
282                 vec[0]= aspx*(G.v2d->cur.xmax-G.v2d->cur.xmin)*(dx)/divx;
283                 vec[1]= aspy*(G.v2d->cur.ymax-G.v2d->cur.ymin)*(dy)/divy;
284                 vec[2]= 0.0f;
285         }
286         else if(t->spacetype==SPACE_IPO) {
287                 float divx, divy;
288                 
289                 divx= G.v2d->mask.xmax-G.v2d->mask.xmin;
290                 divy= G.v2d->mask.ymax-G.v2d->mask.ymin;
291                 
292                 vec[0]= (G.v2d->cur.xmax-G.v2d->cur.xmin)*(dx) / (divx);
293                 vec[1]= (G.v2d->cur.ymax-G.v2d->cur.ymin)*(dy) / (divy);
294                 vec[2]= 0.0f;
295         }
296 }
297
298 void projectIntView(TransInfo *t, float *vec, int *adr)
299 {
300         if (t->spacetype==SPACE_VIEW3D)
301                 project_int(vec, adr);
302         else if(t->spacetype==SPACE_IMAGE) {
303                 float aspx, aspy, v[2];
304                 
305                 transform_aspect_ratio_tface_uv(&aspx, &aspy);
306                 v[0]= vec[0]/aspx;
307                 v[1]= vec[1]/aspy;
308                 
309                 uvco_to_areaco_noclip(v, adr);
310         }
311         else if(t->spacetype==SPACE_IPO) {
312                 short out[2] = {0.0f, 0.0f};
313                 
314                 ipoco_to_areaco(G.v2d, vec, out);
315                 adr[0]= out[0];
316                 adr[1]= out[1];
317         }
318 }
319
320 void projectFloatView(TransInfo *t, float *vec, float *adr)
321 {
322         if (t->spacetype==SPACE_VIEW3D)
323                 project_float(vec, adr);
324         else if(t->spacetype==SPACE_IMAGE) {
325                 int a[2];
326                 
327                 projectIntView(t, vec, a);
328                 adr[0]= a[0];
329                 adr[1]= a[1];
330         }
331         else if(t->spacetype==SPACE_IPO) {
332                 int a[2];
333                 
334                 projectIntView(t, vec, a);
335                 adr[0]= a[0];
336                 adr[1]= a[1];
337         }
338 }
339
340 void convertVecToDisplayNum(float *vec, float *num)
341 {
342         TransInfo *t= BIF_GetTransInfo();
343
344         VECCOPY(num, vec);
345
346         if ((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) {
347                 float aspx, aspy;
348
349                 if((G.sima->flag & SI_COORDFLOATS)==0) {
350                         int width, height;
351                         transform_width_height_tface_uv(&width, &height);
352
353                         num[0] *= width;
354                         num[1] *= height;
355                 }
356
357                 transform_aspect_ratio_tface_uv(&aspx, &aspy);
358                 num[0] /= aspx;
359                 num[1] /= aspy;
360         }
361 }
362
363 void convertDisplayNumToVec(float *num, float *vec)
364 {
365         TransInfo *t= BIF_GetTransInfo();
366
367         VECCOPY(vec, num);
368
369         if ((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) {
370                 float aspx, aspy;
371
372                 if((G.sima->flag & SI_COORDFLOATS)==0) {
373                         int width, height;
374                         transform_width_height_tface_uv(&width, &height);
375
376                         vec[0] /= width;
377                         vec[1] /= height;
378                 }
379
380                 transform_aspect_ratio_tface_uv(&aspx, &aspy);
381                 vec[0] *= aspx;
382                 vec[1] *= aspy;
383         }
384 }
385
386 static void viewRedrawForce(TransInfo *t)
387 {
388         if (t->spacetype == SPACE_VIEW3D)
389                 force_draw(0);
390         else if (t->spacetype==SPACE_IMAGE) {
391                 if (G.sima->lock) force_draw_plus(SPACE_VIEW3D, 0);
392                 else force_draw(0);
393         }
394         else if (t->spacetype == SPACE_ACTION) {
395                 if (G.saction->lock) {
396                         short context;
397                         
398                         /* we ignore the pointer this function returns (not needed) */
399                         get_action_context(&context);
400                         
401                         if (context == ACTCONT_ACTION)
402                                 force_draw_plus(SPACE_VIEW3D, 0);
403                         else if (context == ACTCONT_SHAPEKEY) 
404                                 force_draw_all(0);
405                         else
406                                 force_draw(0);
407                 }
408                 else {
409                         force_draw(0);
410                 }
411         }
412         else if (t->spacetype == SPACE_NLA) {
413                 if (G.snla->lock)
414                         force_draw_all(0);
415                 else
416                         force_draw(0);
417         }
418         else if (t->spacetype == SPACE_IPO) {
419                 /* update realtime */
420                 if (G.sipo->lock) {
421                         if (G.sipo->blocktype==ID_MA || G.sipo->blocktype==ID_TE)
422                                 force_draw_plus(SPACE_BUTS, 0);
423                         else if (G.sipo->blocktype==ID_CA)
424                                 force_draw_plus(SPACE_VIEW3D, 0);
425                         else if (G.sipo->blocktype==ID_KE)
426                                 force_draw_plus(SPACE_VIEW3D, 0);
427                         else if (G.sipo->blocktype==ID_PO)
428                                 force_draw_plus(SPACE_VIEW3D, 0);
429                         else if (G.sipo->blocktype==ID_OB) 
430                                 force_draw_plus(SPACE_VIEW3D, 0);
431                         else if (G.sipo->blocktype==ID_SEQ) 
432                                 force_draw_plus(SPACE_SEQ, 0);
433                         else 
434                                 force_draw(0);
435                 }
436                 else {
437                         force_draw(0);
438                 }
439         }
440 }
441
442 static void viewRedrawPost(TransInfo *t)
443 {
444         if(t->spacetype==SPACE_VIEW3D) {
445                 allqueue(REDRAWBUTSOBJECT, 0);
446                 allqueue(REDRAWVIEW3D, 0);
447         }
448         else if(t->spacetype==SPACE_IMAGE) {
449                 allqueue(REDRAWIMAGE, 0);
450                 allqueue(REDRAWVIEW3D, 0);
451         }
452         else if(ELEM3(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_IPO)) {
453                 allqueue(REDRAWVIEW3D, 0);
454                 allqueue(REDRAWACTION, 0);
455                 allqueue(REDRAWNLA, 0);
456                 allqueue(REDRAWIPO, 0);
457                 allqueue(REDRAWTIME, 0);
458                 allqueue(REDRAWBUTSOBJECT, 0);
459         }
460
461         scrarea_queue_headredraw(curarea);
462 }
463
464 /* ************************** TRANSFORMATIONS **************************** */
465
466 void BIF_selectOrientation() {
467         short val;
468         char *str_menu = BIF_menustringTransformOrientation("Orientation");
469         val= pupmenu(str_menu);
470         MEM_freeN(str_menu);
471         
472         if(val >= 0) {
473                 G.vd->twmode = val;
474         }
475 }
476
477 static void view_editmove(unsigned short event)
478 {
479         int refresh = 0;
480         /* Regular:   Zoom in */
481         /* Shift:     Scroll up */
482         /* Ctrl:      Scroll right */
483         /* Alt-Shift: Rotate up */
484         /* Alt-Ctrl:  Rotate right */
485         
486         /* only work in 3D window for now
487          * In the end, will have to send to event to a 2D window handler instead
488          */
489         if (Trans.flag & T_2D_EDIT)
490                 return;
491         
492         switch(event) {
493                 case WHEELUPMOUSE:
494                         
495                         if( G.qual & LR_SHIFTKEY ) {
496                                 if( G.qual & LR_ALTKEY ) { 
497                                         G.qual &= ~LR_SHIFTKEY;
498                                         persptoetsen(PAD2);
499                                         G.qual |= LR_SHIFTKEY;
500                                 } else {
501                                         persptoetsen(PAD2);
502                                 }
503                         } else if( G.qual & LR_CTRLKEY ) {
504                                 if( G.qual & LR_ALTKEY ) { 
505                                         G.qual &= ~LR_CTRLKEY;
506                                         persptoetsen(PAD4);
507                                         G.qual |= LR_CTRLKEY;
508                                 } else {
509                                         persptoetsen(PAD4);
510                                 }
511                         } else if(U.uiflag & USER_WHEELZOOMDIR) 
512                                 persptoetsen(PADMINUS);
513                         else
514                                 persptoetsen(PADPLUSKEY);
515                         
516                         refresh = 1;
517                         break;
518                 case WHEELDOWNMOUSE:
519                         if( G.qual & LR_SHIFTKEY ) {
520                                 if( G.qual & LR_ALTKEY ) { 
521                                         G.qual &= ~LR_SHIFTKEY;
522                                         persptoetsen(PAD8);
523                                         G.qual |= LR_SHIFTKEY;
524                                 } else {
525                                         persptoetsen(PAD8);
526                                 }
527                         } else if( G.qual & LR_CTRLKEY ) {
528                                 if( G.qual & LR_ALTKEY ) { 
529                                         G.qual &= ~LR_CTRLKEY;
530                                         persptoetsen(PAD6);
531                                         G.qual |= LR_CTRLKEY;
532                                 } else {
533                                         persptoetsen(PAD6);
534                                 }
535                         } else if(U.uiflag & USER_WHEELZOOMDIR) 
536                                 persptoetsen(PADPLUSKEY);
537                         else
538                                 persptoetsen(PADMINUS);
539                         
540                         refresh = 1;
541                         break;
542         }
543
544         if (refresh)
545                 setTransformViewMatrices(&Trans);
546 }
547
548 void checkFirstTime() {
549         if(Trans.mode==TFM_INIT) {
550                 memset(&Trans, 0, sizeof(TransInfo));
551                 Trans.propsize = 1.0;
552         }
553 }
554
555 static char *transform_to_undostr(TransInfo *t)
556 {
557         switch (t->mode) {
558                 case TFM_TRANSLATION:
559                         return "Translate";
560                 case TFM_ROTATION:
561                         return "Rotate";
562                 case TFM_RESIZE:
563                         return "Scale";
564                 case TFM_TOSPHERE:
565                         return "To Sphere";
566                 case TFM_SHEAR:
567                         return "Shear";
568                 case TFM_WARP:
569                         return "Warp";
570                 case TFM_SHRINKFATTEN:
571                         return "Shrink/Fatten";
572                 case TFM_TILT:
573                         return "Tilt";
574                 case TFM_TRACKBALL:
575                         return "Trackball";
576                 case TFM_PUSHPULL:
577                         return "Push/Pull";
578                 case TFM_BEVEL:
579                         return "Bevel";
580                 case TFM_BWEIGHT:
581                         return "Bevel Weight";
582                 case TFM_CREASE:
583                         return "Crease";
584                 case TFM_BONESIZE:
585                         return "Bone Width";
586                 case TFM_BONE_ENVELOPE:
587                         return "Bone Envelope";
588                 case TFM_TIME_TRANSLATE:
589                         return "Translate Anim. Data";
590                 case TFM_TIME_SCALE:
591                         return "Scale Anim. Data";
592                 case TFM_TIME_SLIDE:
593                         return "Time Slide";
594                 case TFM_BAKE_TIME:
595                         return "Key Time";
596                 case TFM_MIRROR:
597                         return "Mirror";
598         }
599         return "Transform";
600 }
601
602 /* ************************************************* */
603
604 static void transformEvent(unsigned short event, short val) {
605         float mati[3][3] = {{1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}};
606         char cmode = constraintModeToChar(&Trans);
607
608         if (val) {
609                 switch (event){
610                 /* enforce redraw of transform when modifiers are used */
611                 case LEFTCTRLKEY:
612                 case RIGHTCTRLKEY:
613                         Trans.redraw = 1;
614                         break;
615                 case LEFTSHIFTKEY:
616                 case RIGHTSHIFTKEY:
617                         /* shift is modifier for higher resolution transform, works nice to store this mouse position */
618                         getmouseco_areawin(Trans.shiftmval);
619                         Trans.flag |= T_SHIFT_MOD;
620                         Trans.redraw = 1;
621                         break;
622                         
623                 case SPACEKEY:
624                         if ((Trans.spacetype==SPACE_VIEW3D) && (G.qual & LR_ALTKEY)) {
625                                 short mval[2];
626                                 
627                                 getmouseco_sc(mval);
628                                 BIF_selectOrientation();
629                                 calc_manipulator_stats(curarea);
630                                 Mat3CpyMat4(Trans.spacemtx, G.vd->twmat);
631                                 warp_pointer(mval[0], mval[1]);
632                         }
633                         else {
634                                 Trans.state = TRANS_CONFIRM;
635                         }
636                         break;
637                         
638                         
639                 case MIDDLEMOUSE:
640                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
641                                 /* exception for switching to dolly, or trackball, in camera view */
642                                 if (Trans.flag & T_CAMERA) {
643                                         if (Trans.mode==TFM_TRANSLATION)
644                                                 setLocalConstraint(&Trans, (CON_AXIS2), "along local Z");
645                                         else if (Trans.mode==TFM_ROTATION) {
646                                                 restoreTransObjects(&Trans);
647                                                 initTrackball(&Trans);
648                                         }
649                                 }
650                                 else {
651                                         Trans.flag |= T_MMB_PRESSED;
652                                         if (Trans.con.mode & CON_APPLY) {
653                                                 stopConstraint(&Trans);
654                                         }
655                                         else {
656                                                 if (G.qual & LR_CTRLKEY) {
657                                                         initSelectConstraint(&Trans, Trans.spacemtx);
658                                                 }
659                                                 else {
660                                                         /* bit hackish... but it prevents mmb select to print the orientation from menu */
661                                                         strcpy(Trans.spacename, "global");
662                                                         initSelectConstraint(&Trans, mati);
663                                                 }
664                                                 postSelectConstraint(&Trans);
665                                         }
666                                 }
667                                 Trans.redraw = 1;
668                         }
669                         break;
670                 case ESCKEY:
671                 case RIGHTMOUSE:
672                         Trans.state = TRANS_CANCEL;
673                         break;
674                 case LEFTMOUSE:
675                 case PADENTER:
676                 case RETKEY:
677                         Trans.state = TRANS_CONFIRM;
678                         break;
679                 case GKEY:
680                         /* only switch when... */
681                         if( ELEM3(Trans.mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL) ) { 
682                                 restoreTransObjects(&Trans);
683                                 initTranslation(&Trans);
684                                 Trans.redraw = 1;
685                         }
686                         break;
687                 case SKEY:
688                         /* only switch when... */
689                         if( ELEM3(Trans.mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) { 
690                                 restoreTransObjects(&Trans);
691                                 initResize(&Trans);
692                                 Trans.redraw = 1;
693                         }
694                         break;
695                 case RKEY:
696                         /* only switch when... */
697                         if( ELEM4(Trans.mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) { 
698                                 
699                                 if (Trans.mode == TFM_ROTATION) {
700                                         restoreTransObjects(&Trans);
701                                         initTrackball(&Trans);
702                                 }
703                                 else {
704                                         restoreTransObjects(&Trans);
705                                         initRotation(&Trans);
706                                 }
707                                 Trans.redraw = 1;
708                         }
709                         break;
710                 case CKEY:
711                         if (G.qual & LR_ALTKEY) {
712                                 Trans.flag ^= T_PROP_CONNECTED;
713                                 sort_trans_data_dist(&Trans);
714                                 calculatePropRatio(&Trans);
715                                 Trans.redraw= 1;
716                         }
717                         else {
718                                 stopConstraint(&Trans);
719                                 Trans.redraw = 1;
720                         }
721                         break;
722                 case XKEY:
723                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
724                                 if (cmode == 'X') {
725                                         if (Trans.flag & T_2D_EDIT) {
726                                                 stopConstraint(&Trans);
727                                         }
728                                         else {
729                                                 if (Trans.con.mode & CON_USER) {
730                                                         stopConstraint(&Trans);
731                                                 }
732                                                 else {
733                                                         if (G.qual == 0)
734                                                                 setUserConstraint(&Trans, (CON_AXIS0), "along %s X");
735                                                         else if (G.qual == LR_SHIFTKEY)
736                                                                 setUserConstraint(&Trans, (CON_AXIS1|CON_AXIS2), "locking %s X");
737                                                 }
738                                         }
739                                 }
740                                 else {
741                                         if (Trans.flag & T_2D_EDIT) {
742                                                 setConstraint(&Trans, mati, (CON_AXIS0), "along X axis");
743                                         }
744                                         else {
745                                                 if (G.qual == 0)
746                                                         setConstraint(&Trans, mati, (CON_AXIS0), "along global X");
747                                                 else if (G.qual == LR_SHIFTKEY)
748                                                         setConstraint(&Trans, mati, (CON_AXIS1|CON_AXIS2), "locking global X");
749                                         }
750                                 }
751                                 Trans.redraw = 1;
752                         }
753                         break;
754                 case YKEY:
755                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
756                                 if (cmode == 'Y') {
757                                         if (Trans.flag & T_2D_EDIT) {
758                                                 stopConstraint(&Trans);
759                                         }
760                                         else {
761                                                 if (Trans.con.mode & CON_USER) {
762                                                         stopConstraint(&Trans);
763                                                 }
764                                                 else {
765                                                         if (G.qual == 0)
766                                                                 setUserConstraint(&Trans, (CON_AXIS1), "along %s Y");
767                                                         else if (G.qual == LR_SHIFTKEY)
768                                                                 setUserConstraint(&Trans, (CON_AXIS0|CON_AXIS2), "locking %s Y");
769                                                 }
770                                         }
771                                 }
772                                 else {
773                                         if (Trans.flag & T_2D_EDIT) {
774                                                 setConstraint(&Trans, mati, (CON_AXIS1), "along Y axis");
775                                         }
776                                         else {
777                                                 if (G.qual == 0)
778                                                         setConstraint(&Trans, mati, (CON_AXIS1), "along global Y");
779                                                 else if (G.qual == LR_SHIFTKEY)
780                                                         setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS2), "locking global Y");
781                                         }
782                                 }
783                                 Trans.redraw = 1;
784                         }
785                         break;
786                 case ZKEY:
787                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
788                                 if (cmode == 'Z') {
789                                         if (Trans.con.mode & CON_USER) {
790                                                 stopConstraint(&Trans);
791                                         }
792                                         else {
793                                                 if (G.qual == 0)
794                                                         setUserConstraint(&Trans, (CON_AXIS2), "along %s Z");
795                                                 else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
796                                                         setUserConstraint(&Trans, (CON_AXIS0|CON_AXIS1), "locking %s Z");
797                                         }
798                                 }
799                                 else if ((Trans.flag & T_2D_EDIT)==0) {
800                                         if (G.qual == 0)
801                                                 setConstraint(&Trans, mati, (CON_AXIS2), "along global Z");
802                                         else if (G.qual == LR_SHIFTKEY)
803                                                 setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS1), "locking global Z");
804                                 }
805                                 Trans.redraw = 1;
806                         }
807                         break;
808                 case OKEY:
809                         if (Trans.flag & T_PROP_EDIT && G.qual==LR_SHIFTKEY) {
810                                 G.scene->prop_mode = (G.scene->prop_mode+1)%6;
811                                 calculatePropRatio(&Trans);
812                                 Trans.redraw= 1;
813                         }
814                         break;
815                 case PADPLUSKEY:
816                         if(G.qual & LR_ALTKEY && Trans.flag & T_PROP_EDIT) {
817                                 Trans.propsize*= 1.1f;
818                                 calculatePropRatio(&Trans);
819                         }
820                         Trans.redraw= 1;
821                         break;
822                 case PAGEUPKEY:
823                 case WHEELDOWNMOUSE:
824                         if (Trans.flag & T_AUTOIK) {
825                                 transform_autoik_update(&Trans, 1);
826                         }
827                         else if(Trans.flag & T_PROP_EDIT) {
828                                 Trans.propsize*= 1.1f;
829                                 calculatePropRatio(&Trans);
830                         }
831                         else view_editmove(event);
832                         Trans.redraw= 1;
833                         break;
834                 case PADMINUS:
835                         if(G.qual & LR_ALTKEY && Trans.flag & T_PROP_EDIT) {
836                                 Trans.propsize*= 0.90909090f;
837                                 calculatePropRatio(&Trans);
838                         }
839                         Trans.redraw= 1;
840                         break;
841                 case PAGEDOWNKEY:
842                 case WHEELUPMOUSE:
843                         if (Trans.flag & T_AUTOIK) {
844                                 transform_autoik_update(&Trans, -1);
845                         }
846                         else if (Trans.flag & T_PROP_EDIT) {
847                                 Trans.propsize*= 0.90909090f;
848                                 calculatePropRatio(&Trans);
849                         }
850                         else view_editmove(event);
851                         Trans.redraw= 1;
852                         break;
853 //              case NDOFMOTION:
854 //            viewmoveNDOF(1);
855   //         break;
856                 }
857                 
858                 // Numerical input events
859                 Trans.redraw |= handleNumInput(&(Trans.num), event);
860                 
861                 // NDof input events
862                 switch(handleNDofInput(&(Trans.ndof), event, val))
863                 {
864                         case NDOF_CONFIRM:
865                                 if ((Trans.context & CTX_NDOF) == 0)
866                                 {
867                                         /* Confirm on normal transform only */
868                                         Trans.state = TRANS_CONFIRM;
869                                 }
870                                 break;
871                         case NDOF_CANCEL:
872                                 if (Trans.context & CTX_NDOF)
873                                 {
874                                         /* Cancel on pure NDOF transform */
875                                         Trans.state = TRANS_CANCEL; 
876                                 }
877                                 else
878                                 {
879                                         /* Otherwise, just redraw, NDof input was cancelled */
880                                         Trans.redraw = 1;
881                                 }
882                                 break;
883                         case NDOF_NOMOVE:
884                                 if (Trans.context & CTX_NDOF)
885                                 {
886                                         /* Confirm on pure NDOF transform */
887                                         Trans.state = TRANS_CONFIRM;
888                                 }
889                                 break;
890                         case NDOF_REFRESH:
891                                 Trans.redraw = 1;
892                                 break;
893                         
894                 }
895                 
896                 // Snapping events
897                 Trans.redraw |= handleSnapping(&Trans, event);
898                 
899                 arrows_move_cursor(event);
900         }
901         else {
902                 switch (event){
903                 /* no redraw on release modifier keys! this makes sure you can assign the 'grid' still 
904                    after releasing modifer key */
905                 case MIDDLEMOUSE:
906                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
907                                 Trans.flag &= ~T_MMB_PRESSED;
908                                 postSelectConstraint(&Trans);
909                                 Trans.redraw = 1;
910                         }
911                         break;
912                 case LEFTMOUSE:
913                 case RIGHTMOUSE:
914                         if (Trans.context & CTX_TWEAK)
915                                 Trans.state = TRANS_CONFIRM;
916                         break;
917                 case LEFTSHIFTKEY:
918                 case RIGHTSHIFTKEY:
919                         /* shift is modifier for higher resolution transform */
920                         Trans.flag &= ~T_SHIFT_MOD;
921                         break;
922                 }
923         }
924         
925         // Per transform event, if present
926         if (Trans.handleEvent)
927                 Trans.redraw |= Trans.handleEvent(&Trans, event, val);
928 }
929
930 int calculateTransformCenter(int centerMode, float *vec)
931 {
932         int success = 1;
933         checkFirstTime();
934
935         Trans.state = TRANS_RUNNING;
936
937         Trans.context = CTX_NONE;
938         
939         Trans.mode = TFM_DUMMY;
940
941         initTrans(&Trans);                                      // internal data, mouse, vectors
942
943         createTransData(&Trans);                        // make TransData structs from selection
944
945         Trans.around = centerMode;                      // override userdefined mode
946
947         if (Trans.total == 0) {
948                 success = 0;
949         }
950         else {
951                 success = 1;
952                 
953                 calculateCenter(&Trans);
954         
955                 // Copy center from constraint center. Transform center can be local    
956                 VECCOPY(vec, Trans.con.center);
957         }
958
959         postTrans(&Trans);
960
961         /* aftertrans does insert ipos and action channels, and clears base flags, doesnt read transdata */
962         special_aftertrans_update(&Trans);
963         
964         return success;
965 }
966
967 void initTransform(int mode, int context) {
968         /* added initialize, for external calls to set stuff in TransInfo, like undo string */
969         checkFirstTime();
970
971         Trans.state = TRANS_RUNNING;
972
973         Trans.context = context;
974         
975         Trans.mode = mode;
976
977         initTrans(&Trans);                                      // internal data, mouse, vectors
978
979         if(Trans.spacetype==SPACE_VIEW3D) {
980                 calc_manipulator_stats(curarea);
981                 Mat3CpyMat4(Trans.spacemtx, G.vd->twmat);
982                 Mat3Ortho(Trans.spacemtx);
983         }
984         else
985                 Mat3One(Trans.spacemtx);
986
987         createTransData(&Trans);                        // make TransData structs from selection
988
989         initSnapping(&Trans); // Initialize snapping data AFTER mode flags
990
991         if (Trans.total == 0) {
992                 postTrans(&Trans);
993                 return;
994         }
995
996         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
997         /* EVIL2: we gave as argument also texture space context bit... was cleared */
998         /* EVIL3: extend mode for animation editors also switches modes... but is best way to avoid duplicate code */
999         mode = Trans.mode;
1000         
1001         calculatePropRatio(&Trans);
1002         calculateCenter(&Trans);
1003
1004         switch (mode) {
1005         case TFM_TRANSLATION:
1006                 initTranslation(&Trans);
1007                 break;
1008         case TFM_ROTATION:
1009                 initRotation(&Trans);
1010                 break;
1011         case TFM_RESIZE:
1012                 initResize(&Trans);
1013                 break;
1014         case TFM_TOSPHERE:
1015                 initToSphere(&Trans);
1016                 break;
1017         case TFM_SHEAR:
1018                 initShear(&Trans);
1019                 break;
1020         case TFM_WARP:
1021                 initWarp(&Trans);
1022                 break;
1023         case TFM_SHRINKFATTEN:
1024                 initShrinkFatten(&Trans);
1025                 break;
1026         case TFM_TILT:
1027                 initTilt(&Trans);
1028                 break;
1029         case TFM_CURVE_SHRINKFATTEN:
1030                 initCurveShrinkFatten(&Trans);
1031                 break;
1032         case TFM_TRACKBALL:
1033                 initTrackball(&Trans);
1034                 break;
1035         case TFM_PUSHPULL:
1036                 initPushPull(&Trans);
1037                 break;
1038         case TFM_CREASE:
1039                 initCrease(&Trans);
1040                 break;
1041         case TFM_BONESIZE:
1042                 {       /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */
1043                         bArmature *arm= Trans.poseobj->data;
1044                         if(arm->drawtype==ARM_ENVELOPE)
1045                                 initBoneEnvelope(&Trans);
1046                         else
1047                                 initBoneSize(&Trans);
1048                 }
1049                 break;
1050         case TFM_BONE_ENVELOPE:
1051                 initBoneEnvelope(&Trans);
1052                 break;
1053         case TFM_BONE_ROLL:
1054                 initBoneRoll(&Trans);
1055                 break;
1056         case TFM_TIME_TRANSLATE:
1057                 initTimeTranslate(&Trans);
1058                 break;
1059         case TFM_TIME_SLIDE:
1060                 initTimeSlide(&Trans);
1061                 break;
1062         case TFM_TIME_SCALE:
1063                 initTimeScale(&Trans);
1064                 break;
1065         case TFM_TIME_EXTEND: 
1066                 /* now that transdata has been made, do like for TFM_TIME_TRANSLATE */
1067                 initTimeTranslate(&Trans);
1068                 break;
1069         case TFM_BAKE_TIME:
1070                 initBakeTime(&Trans);
1071                 break;
1072         case TFM_MIRROR:
1073                 initMirror(&Trans);
1074                 break;
1075         case TFM_BEVEL:
1076                 initBevel(&Trans);
1077                 break;
1078         case TFM_BWEIGHT:
1079                 initBevelWeight(&Trans);
1080                 break;
1081         case TFM_ALIGN:
1082                 initAlign(&Trans);
1083                 break;
1084         }
1085 }
1086
1087 void Transform() 
1088 {
1089         short pmval[2] = {0, 0}, mval[2], val;
1090         unsigned short event;
1091
1092         if(Trans.total==0) return;      // added, can happen now! (ton)
1093         
1094         // Emptying event queue
1095         while( qtest() ) {
1096                 event= extern_qread(&val);
1097         }
1098
1099         Trans.redraw = 1; /* initial draw */
1100
1101         while (Trans.state == TRANS_RUNNING) {
1102
1103                 getmouseco_areawin(mval);
1104                 
1105                 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
1106                         if (Trans.flag & T_MMB_PRESSED)
1107                                 Trans.con.mode |= CON_SELECT;
1108                         Trans.redraw = 1;
1109                 }
1110                 if (Trans.redraw) {
1111                         pmval[0] = mval[0];
1112                         pmval[1] = mval[1];
1113
1114                         selectConstraint(&Trans);
1115                         if (Trans.transform) {
1116                                 Trans.transform(&Trans, mval);  // calls recalcData()
1117                         }
1118                         Trans.redraw = 0;
1119                 }
1120
1121                 /* If auto confirm is on, break after one pass */               
1122                 if (Trans.context & CTX_AUTOCONFIRM)
1123                 {
1124                         Trans.state = TRANS_CONFIRM;
1125                         break;
1126                 }
1127                 
1128                 /* essential for idling subloop */
1129                 if( qtest()==0) PIL_sleep_ms(2);
1130
1131                 while( qtest() ) {
1132                         event= extern_qread(&val);
1133                         transformEvent(event, val);
1134                 }
1135
1136                 if(BKE_ptcache_get_continue_physics()) {
1137                         do_screenhandlers(G.curscreen);
1138                         Trans.redraw= 1;
1139                 }
1140         }
1141         
1142         
1143         /* handle restoring objects */
1144         if(Trans.state == TRANS_CANCEL)
1145                 restoreTransObjects(&Trans);    // calls recalcData()
1146         
1147         /* free data */
1148         postTrans(&Trans);
1149
1150         /* aftertrans does insert ipos and action channels, and clears base flags, doesnt read transdata */
1151         special_aftertrans_update(&Trans);
1152
1153         /* send events out for redraws */
1154         viewRedrawPost(&Trans);
1155
1156         /*  Undo as last, certainly after special_trans_update! */
1157         if(Trans.state == TRANS_CANCEL) {
1158                 if(Trans.undostr) BIF_undo_push(Trans.undostr);
1159         }
1160         else {
1161                 if(Trans.undostr) BIF_undo_push(Trans.undostr);
1162                 else BIF_undo_push(transform_to_undostr(&Trans));
1163         }
1164         Trans.undostr= NULL;
1165         
1166 }
1167
1168 /* ************************** Manipulator init and main **************************** */
1169
1170 void initManipulator(int mode)
1171 {
1172         Trans.state = TRANS_RUNNING;
1173
1174         Trans.context = CTX_NONE;
1175         
1176         Trans.mode = mode;
1177         
1178         /* automatic switch to scaling bone envelopes */
1179         if(mode==TFM_RESIZE && G.obedit && G.obedit->type==OB_ARMATURE) {
1180                 bArmature *arm= G.obedit->data;
1181                 if(arm->drawtype==ARM_ENVELOPE)
1182                         mode= TFM_BONE_ENVELOPE;
1183         }
1184
1185         initTrans(&Trans);                                      // internal data, mouse, vectors
1186
1187         G.moving |= G_TRANSFORM_MANIP;          // signal to draw manipuls while transform
1188         createTransData(&Trans);                        // make TransData structs from selection
1189
1190         if (Trans.total == 0)
1191                 return;
1192
1193         initSnapping(&Trans); // Initialize snapping data AFTER mode flags
1194
1195         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
1196         /* EVIL2: we gave as argument also texture space context bit... was cleared */
1197         mode = Trans.mode;
1198         
1199         calculatePropRatio(&Trans);
1200         calculateCenter(&Trans);
1201
1202         switch (mode) {
1203         case TFM_TRANSLATION:
1204                 initTranslation(&Trans);
1205                 break;
1206         case TFM_ROTATION:
1207                 initRotation(&Trans);
1208                 break;
1209         case TFM_RESIZE:
1210                 initResize(&Trans);
1211                 break;
1212         case TFM_TRACKBALL:
1213                 initTrackball(&Trans);
1214                 break;
1215         }
1216
1217         Trans.flag |= T_USES_MANIPULATOR;
1218 }
1219
1220 void ManipulatorTransform() 
1221 {
1222         int mouse_moved = 0;
1223         short pmval[2] = {0, 0}, mval[2], val;
1224         unsigned short event;
1225
1226         if (Trans.total == 0)
1227                 return;
1228
1229         Trans.redraw = 1; /* initial draw */
1230
1231         while (Trans.state == TRANS_RUNNING) {
1232                 
1233                 getmouseco_areawin(mval);
1234                 
1235                 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
1236                         Trans.redraw = 1;
1237                 }
1238                 if (Trans.redraw) {
1239                         pmval[0] = mval[0];
1240                         pmval[1] = mval[1];
1241
1242                         //selectConstraint(&Trans);  needed?
1243                         if (Trans.transform) {
1244                                 Trans.transform(&Trans, mval);
1245                         }
1246                         Trans.redraw = 0;
1247                 }
1248                 
1249                 /* essential for idling subloop */
1250                 if( qtest()==0) PIL_sleep_ms(2);
1251
1252                 while( qtest() ) {
1253                         event= extern_qread(&val);
1254
1255                         switch (event){
1256                         case MOUSEX:
1257                         case MOUSEY:
1258                                 mouse_moved = 1;
1259                                 break;
1260                         /* enforce redraw of transform when modifiers are used */
1261                         case LEFTCTRLKEY:
1262                         case RIGHTCTRLKEY:
1263                                 if(val) Trans.redraw = 1;
1264                                 break;
1265                         case LEFTSHIFTKEY:
1266                         case RIGHTSHIFTKEY:
1267                                 /* shift is modifier for higher resolution transform, works nice to store this mouse position */
1268                                 if(val) {
1269                                         getmouseco_areawin(Trans.shiftmval);
1270                                         Trans.flag |= T_SHIFT_MOD;
1271                                         Trans.redraw = 1;
1272                                 }
1273                                 else Trans.flag &= ~T_SHIFT_MOD; 
1274                                 break;
1275                                 
1276                         case ESCKEY:
1277                         case RIGHTMOUSE:
1278                                 Trans.state = TRANS_CANCEL;
1279                                 break;
1280                         case LEFTMOUSE:
1281                                 if(mouse_moved==0 && val==0) break;
1282                                 // else we pass on event to next, which cancels
1283                         case SPACEKEY:
1284                         case PADENTER:
1285                         case RETKEY:
1286                                 Trans.state = TRANS_CONFIRM;
1287                                 break;
1288    //         case NDOFMOTION:
1289      //           viewmoveNDOF(1);
1290      //           break;
1291                         }
1292                         if(val) {
1293                                 switch(event) {
1294                                 case PADPLUSKEY:
1295                                         if(G.qual & LR_ALTKEY && Trans.flag & T_PROP_EDIT) {
1296                                                 Trans.propsize*= 1.1f;
1297                                                 calculatePropRatio(&Trans);
1298                                         }
1299                                         Trans.redraw= 1;
1300                                         break;
1301                                 case PAGEUPKEY:
1302                                 case WHEELDOWNMOUSE:
1303                                         if (Trans.flag & T_AUTOIK) {
1304                                                 transform_autoik_update(&Trans, 1);
1305                                         }
1306                                         else if(Trans.flag & T_PROP_EDIT) {
1307                                                 Trans.propsize*= 1.1f;
1308                                                 calculatePropRatio(&Trans);
1309                                         }
1310                                         else view_editmove(event);
1311                                         Trans.redraw= 1;
1312                                         break;
1313                                 case PADMINUS:
1314                                         if(G.qual & LR_ALTKEY && Trans.flag & T_PROP_EDIT) {
1315                                                 Trans.propsize*= 0.90909090f;
1316                                                 calculatePropRatio(&Trans);
1317                                         }
1318                                         Trans.redraw= 1;
1319                                         break;
1320                                 case PAGEDOWNKEY:
1321                                 case WHEELUPMOUSE:
1322                                         if (Trans.flag & T_AUTOIK) {
1323                                                 transform_autoik_update(&Trans, -1);
1324                                         }
1325                                         else if (Trans.flag & T_PROP_EDIT) {
1326                                                 Trans.propsize*= 0.90909090f;
1327                                                 calculatePropRatio(&Trans);
1328                                         }
1329                                         else view_editmove(event);
1330                                         Trans.redraw= 1;
1331                                         break;
1332                                 }
1333                                                         
1334                                 // Numerical input events
1335                                 Trans.redraw |= handleNumInput(&(Trans.num), event);
1336                         }
1337                 }
1338         }
1339         
1340         if(Trans.state == TRANS_CANCEL) {
1341                 restoreTransObjects(&Trans);
1342         }
1343         
1344         /* free data, reset vars */
1345         postTrans(&Trans);
1346         
1347         /* aftertrans does insert ipos and action channels, and clears base flags */
1348         special_aftertrans_update(&Trans);
1349         
1350         /* send events out for redraws */
1351         viewRedrawPost(&Trans);
1352
1353         if(Trans.state != TRANS_CANCEL) {
1354                 BIF_undo_push(transform_to_undostr(&Trans));
1355         }
1356         
1357 }
1358
1359 /* ************************** TRANSFORM LOCKS **************************** */
1360
1361 static void protectedTransBits(short protectflag, float *vec)
1362 {
1363         if(protectflag & OB_LOCK_LOCX)
1364                 vec[0]= 0.0f;
1365         if(protectflag & OB_LOCK_LOCY)
1366                 vec[1]= 0.0f;
1367         if(protectflag & OB_LOCK_LOCZ)
1368                 vec[2]= 0.0f;
1369 }
1370
1371 static void protectedSizeBits(short protectflag, float *size)
1372 {
1373         if(protectflag & OB_LOCK_SCALEX)
1374                 size[0]= 1.0f;
1375         if(protectflag & OB_LOCK_SCALEY)
1376                 size[1]= 1.0f;
1377         if(protectflag & OB_LOCK_SCALEZ)
1378                 size[2]= 1.0f;
1379 }
1380
1381 static void protectedRotateBits(short protectflag, float *eul, float *oldeul)
1382 {
1383         if(protectflag & OB_LOCK_ROTX)
1384                 eul[0]= oldeul[0];
1385         if(protectflag & OB_LOCK_ROTY)
1386                 eul[1]= oldeul[1];
1387         if(protectflag & OB_LOCK_ROTZ)
1388                 eul[2]= oldeul[2];
1389 }
1390
1391 static void protectedQuaternionBits(short protectflag, float *quat, float *oldquat)
1392 {
1393         /* quaternions get limited with euler... */
1394         /* this function only does the delta rotation */
1395         
1396         if(protectflag) {
1397                 float eul[3], oldeul[3], quat1[4];
1398                 
1399                 QUATCOPY(quat1, quat);
1400                 QuatToEul(quat, eul);
1401                 QuatToEul(oldquat, oldeul);
1402                 
1403                 if(protectflag & OB_LOCK_ROTX)
1404                         eul[0]= oldeul[0];
1405                 if(protectflag & OB_LOCK_ROTY)
1406                         eul[1]= oldeul[1];
1407                 if(protectflag & OB_LOCK_ROTZ)
1408                         eul[2]= oldeul[2];
1409                 
1410                 EulToQuat(eul, quat);
1411                 /* quaternions flip w sign to accumulate rotations correctly */
1412                 if( (quat1[0]<0.0f && quat[0]>0.0f) || (quat1[0]>0.0f && quat[0]<0.0f) ) {
1413                         QuatMulf(quat, -1.0f);
1414                 }
1415         }
1416 }
1417
1418 /* ******************* TRANSFORM LIMITS ********************** */
1419
1420 static void constraintTransLim(TransInfo *t, TransData *td)
1421 {
1422         if (td->con) {
1423                 bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT);
1424                 bConstraintOb cob;
1425                 bConstraint *con;
1426                 
1427                 /* Make a temporary bConstraintOb for using these limit constraints 
1428                  *      - they only care that cob->matrix is correctly set ;-)
1429                  *      - current space should be local
1430                  */
1431                 memset(&cob, 0, sizeof(bConstraintOb));
1432                 Mat4One(cob.matrix);
1433                 if (td->tdi) {
1434                         TransDataIpokey *tdi= td->tdi;
1435                         cob.matrix[3][0]= tdi->locx[0];
1436                         cob.matrix[3][1]= tdi->locy[0];
1437                         cob.matrix[3][2]= tdi->locz[0];
1438                 }
1439                 else {
1440                         VECCOPY(cob.matrix[3], td->loc);
1441                 }
1442                 
1443                 /* Evaluate valid constraints */
1444                 for (con= td->con; con; con= con->next) {
1445                         float tmat[4][4];
1446                         
1447                         /* only use it if it's tagged for this purpose (and the right type) */
1448                         if (con->type == CONSTRAINT_TYPE_LOCLIMIT) {
1449                                 bLocLimitConstraint *data= con->data;
1450                                 
1451                                 if ((data->flag2 & LIMIT_TRANSFORM)==0) 
1452                                         continue;
1453                                 
1454                                 /* do space conversions */
1455                                 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1456                                         /* just multiply by td->mtx (this should be ok) */
1457                                         Mat4CpyMat4(tmat, cob.matrix);
1458                                         Mat4MulMat34(cob.matrix, td->mtx, tmat);
1459                                 }
1460                                 else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
1461                                         /* skip... incompatable spacetype */
1462                                         continue;
1463                                 }
1464                                 
1465                                 /* do constraint */
1466                                 cti->evaluate_constraint(con, &cob, NULL);
1467                                 
1468                                 /* convert spaces again */
1469                                 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1470                                         /* just multiply by td->mtx (this should be ok) */
1471                                         Mat4CpyMat4(tmat, cob.matrix);
1472                                         Mat4MulMat34(cob.matrix, td->smtx, tmat);
1473                                 }
1474                         }
1475                 }
1476                 
1477                 /* copy results from cob->matrix */
1478                 if (td->tdi) {
1479                         TransDataIpokey *tdi= td->tdi;
1480                         tdi->locx[0]= cob.matrix[3][0];
1481                         tdi->locy[0]= cob.matrix[3][1];
1482                         tdi->locz[0]= cob.matrix[3][2];
1483                 }
1484                 else {
1485                         VECCOPY(td->loc, cob.matrix[3]);
1486                 }
1487         }
1488 }
1489
1490 static void constraintRotLim(TransInfo *t, TransData *td)
1491 {
1492         if (td->con) {
1493                 bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_ROTLIMIT);
1494                 bConstraintOb cob;
1495                 bConstraint *con;
1496                 
1497                 /* Make a temporary bConstraintOb for using these limit constraints 
1498                  *      - they only care that cob->matrix is correctly set ;-)
1499                  *      - current space should be local
1500                  */
1501                 memset(&cob, 0, sizeof(bConstraintOb));
1502                 if (td->flag & TD_USEQUAT) {
1503                         /* quats */
1504                         if (td->ext)
1505                                 QuatToMat4(td->ext->quat, cob.matrix);
1506                         else
1507                                 return;
1508                 }
1509                 else if (td->tdi) {
1510                         /* ipo-keys eulers */
1511                         TransDataIpokey *tdi= td->tdi;
1512                         float eul[3];
1513                         
1514                         eul[0]= tdi->rotx[0];
1515                         eul[1]= tdi->roty[0];
1516                         eul[2]= tdi->rotz[0];
1517                         
1518                         EulToMat4(eul, cob.matrix);
1519                 }
1520                 else {
1521                         /* eulers */
1522                         if (td->ext)
1523                                 EulToMat4(td->ext->rot, cob.matrix);
1524                         else
1525                                 return;
1526                 }
1527                         
1528                 /* Evaluate valid constraints */
1529                 for (con= td->con; con; con= con->next) {
1530                         /* we're only interested in Limit-Scale constraints */
1531                         if (con->type == CONSTRAINT_TYPE_ROTLIMIT) {
1532                                 bRotLimitConstraint *data= con->data;
1533                                 float tmat[4][4];
1534                                 
1535                                 /* only use it if it's tagged for this purpose */
1536                                 if ((data->flag2 & LIMIT_TRANSFORM)==0) 
1537                                         continue;
1538                                         
1539                                 /* do space conversions */
1540                                 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1541                                         /* just multiply by td->mtx (this should be ok) */
1542                                         Mat4CpyMat4(tmat, cob.matrix);
1543                                         Mat4MulMat34(cob.matrix, td->mtx, tmat);
1544                                 }
1545                                 else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
1546                                         /* skip... incompatable spacetype */
1547                                         continue;
1548                                 }
1549                                 
1550                                 /* do constraint */
1551                                 cti->evaluate_constraint(con, &cob, NULL);
1552                                 
1553                                 /* convert spaces again */
1554                                 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1555                                         /* just multiply by td->mtx (this should be ok) */
1556                                         Mat4CpyMat4(tmat, cob.matrix);
1557                                         Mat4MulMat34(cob.matrix, td->smtx, tmat);
1558                                 }
1559                         }
1560                 }
1561                 
1562                 /* copy results from cob->matrix */
1563                 if (td->flag & TD_USEQUAT) {
1564                         /* quats */
1565                         Mat4ToQuat(cob.matrix, td->ext->quat);
1566                 }
1567                 else if (td->tdi) {
1568                         /* ipo-keys eulers */
1569                         TransDataIpokey *tdi= td->tdi;
1570                         float eul[3];
1571                         
1572                         Mat4ToEul(cob.matrix, eul);
1573                         
1574                         tdi->rotx[0]= eul[0];
1575                         tdi->roty[0]= eul[1];
1576                         tdi->rotz[0]= eul[2];
1577                 }
1578                 else {
1579                         /* eulers */
1580                         Mat4ToEul(cob.matrix, td->ext->rot);
1581                 }
1582         }
1583 }
1584
1585 static void constraintSizeLim(TransInfo *t, TransData *td)
1586 {
1587         if (td->con && td->ext) {
1588                 bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_SIZELIMIT);
1589                 bConstraintOb cob;
1590                 bConstraint *con;
1591                 
1592                 /* Make a temporary bConstraintOb for using these limit constraints 
1593                  *      - they only care that cob->matrix is correctly set ;-)
1594                  *      - current space should be local
1595                  */
1596                 memset(&cob, 0, sizeof(bConstraintOb));
1597                 if (td->tdi) {
1598                         TransDataIpokey *tdi= td->tdi;
1599                         float size[3];
1600                         
1601                         size[0]= tdi->sizex[0];
1602                         size[1]= tdi->sizey[0];
1603                         size[2]= tdi->sizez[0];
1604                         SizeToMat4(size, cob.matrix);
1605                 } 
1606                 else if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
1607                         /* scale val and reset size */
1608                         return; // TODO: fix this case
1609                 }
1610                 else {
1611                         /* Reset val if SINGLESIZE but using a constraint */
1612                         if (td->flag & TD_SINGLESIZE)
1613                                 return;
1614                         
1615                         SizeToMat4(td->ext->size, cob.matrix);
1616                 }
1617                         
1618                 /* Evaluate valid constraints */
1619                 for (con= td->con; con; con= con->next) {
1620                         /* we're only interested in Limit-Scale constraints */
1621                         if (con->type == CONSTRAINT_TYPE_SIZELIMIT) {
1622                                 bSizeLimitConstraint *data= con->data;
1623                                 float tmat[4][4];
1624                                 
1625                                 /* only use it if it's tagged for this purpose */
1626                                 if ((data->flag2 & LIMIT_TRANSFORM)==0) 
1627                                         continue;
1628                                         
1629                                 /* do space conversions */
1630                                 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1631                                         /* just multiply by td->mtx (this should be ok) */
1632                                         Mat4CpyMat4(tmat, cob.matrix);
1633                                         Mat4MulMat34(cob.matrix, td->mtx, tmat);
1634                                 }
1635                                 else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
1636                                         /* skip... incompatable spacetype */
1637                                         continue;
1638                                 }
1639                                 
1640                                 /* do constraint */
1641                                 cti->evaluate_constraint(con, &cob, NULL);
1642                                 
1643                                 /* convert spaces again */
1644                                 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1645                                         /* just multiply by td->mtx (this should be ok) */
1646                                         Mat4CpyMat4(tmat, cob.matrix);
1647                                         Mat4MulMat34(cob.matrix, td->smtx, tmat);
1648                                 }
1649                         }
1650                 }
1651                 
1652                 /* copy results from cob->matrix */
1653                 if (td->tdi) {
1654                         TransDataIpokey *tdi= td->tdi;
1655                         float size[3];
1656                         
1657                         Mat4ToSize(cob.matrix, size);
1658                         
1659                         tdi->sizex[0]= size[0];
1660                         tdi->sizey[0]= size[1];
1661                         tdi->sizez[0]= size[2];
1662                 } 
1663                 else if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
1664                         /* scale val and reset size */
1665                         return; // TODO: fix this case
1666                 }
1667                 else {
1668                         /* Reset val if SINGLESIZE but using a constraint */
1669                         if (td->flag & TD_SINGLESIZE)
1670                                 return;
1671                                 
1672                         Mat4ToSize(cob.matrix, td->ext->size);
1673                 }
1674         }
1675 }
1676
1677 /* ************************** WARP *************************** */
1678
1679 void initWarp(TransInfo *t) 
1680 {
1681         float max[3], min[3];
1682         int i;
1683         
1684         t->mode = TFM_WARP;
1685         t->transform = Warp;
1686         t->handleEvent = handleEventWarp;
1687         
1688         t->idx_max = 0;
1689         t->num.idx_max = 0;
1690         t->snap[0] = 0.0f;
1691         t->snap[1] = 5.0f;
1692         t->snap[2] = 1.0f;
1693         
1694         t->flag |= T_NO_CONSTRAINT;
1695
1696 /* warp is done fully in view space */
1697         calculateCenterCursor(t);
1698         t->fac = (float)(t->center2d[0] - t->imval[0]);
1699         
1700         /* we need min/max in view space */
1701         for(i = 0; i < t->total; i++) {
1702                 float center[3];
1703                 VECCOPY(center, t->data[i].center);
1704                 Mat3MulVecfl(t->data[i].mtx, center);
1705                 Mat4MulVecfl(t->viewmat, center);
1706                 VecSubf(center, center, t->viewmat[3]);
1707                 if (i)
1708                         MinMax3(min, max, center);
1709                 else {
1710                         VECCOPY(max, center);
1711                         VECCOPY(min, center);
1712                 }
1713         }
1714         
1715         t->center[0]= (min[0]+max[0])/2.0f;
1716         t->center[1]= (min[1]+max[1])/2.0f;
1717         t->center[2]= (min[2]+max[2])/2.0f;
1718         
1719         if (max[0] == min[0]) max[0] += 0.1; /* not optimal, but flipping is better than invalid garbage (i.e. division by zero!) */
1720         t->val= (max[0]-min[0])/2.0f; /* t->val is X dimension projected boundbox */
1721 }
1722
1723 int handleEventWarp(TransInfo *t, unsigned short event, short val)
1724 {
1725         int status = 0;
1726         
1727         if (event == MIDDLEMOUSE && val)
1728         {
1729                 // Use customData pointer to signal warp direction
1730                 if      (t->customData == 0)
1731                         t->customData = (void*)1;
1732                 else
1733                         t->customData = 0;
1734                         
1735                 status = 1;
1736         }
1737         
1738         return status;
1739 }
1740
1741 int Warp(TransInfo *t, short mval[2])
1742 {
1743         TransData *td = t->data;
1744         float vec[3], circumfac, dist, phi0, co, si, *curs, cursor[3], gcursor[3];
1745         int i;
1746         char str[50];
1747         
1748         curs= give_cursor();
1749         /*
1750          * gcursor is the one used for helpline.
1751          * It has to be in the same space as the drawing loop
1752          * (that means it needs to be in the object's space when in edit mode and
1753          *  in global space in object mode)
1754          *
1755          * cursor is used for calculations.
1756          * It needs to be in view space, but we need to take object's offset
1757          * into account if in Edit mode.
1758          */
1759         VECCOPY(cursor, curs);
1760         VECCOPY(gcursor, cursor);       
1761         if (t->flag & T_EDIT) {
1762                 VecSubf(cursor, cursor, G.obedit->obmat[3]);
1763                 VecSubf(gcursor, gcursor, G.obedit->obmat[3]);
1764                 Mat3MulVecfl(t->data->smtx, gcursor);
1765         }
1766         Mat4MulVecfl(t->viewmat, cursor);
1767         VecSubf(cursor, cursor, t->viewmat[3]);
1768
1769         /* amount of degrees for warp */
1770         circumfac= 360.0f * InputHorizontalRatio(t, mval);
1771         
1772         if (t->customData) /* non-null value indicates reversed input */
1773         {
1774                 circumfac *= -1;
1775         }
1776
1777         snapGrid(t, &circumfac);
1778         applyNumInput(&t->num, &circumfac);
1779         
1780         /* header print for NumInput */
1781         if (hasNumInput(&t->num)) {
1782                 char c[20];
1783                 
1784                 outputNumInput(&(t->num), c);
1785                 
1786                 sprintf(str, "Warp: %s", c);
1787         }
1788         else {
1789                 /* default header print */
1790                 sprintf(str, "Warp: %.3f", circumfac);
1791         }
1792         
1793         circumfac*= (float)(-M_PI/360.0);
1794         
1795         for(i = 0; i < t->total; i++, td++) {
1796                 float loc[3];
1797                 if (td->flag & TD_NOACTION)
1798                         break;
1799
1800                 if (td->flag & TD_SKIP)
1801                         continue;
1802                 
1803                 /* translate point to center, rotate in such a way that outline==distance */
1804                 VECCOPY(vec, td->iloc);
1805                 Mat3MulVecfl(td->mtx, vec);
1806                 Mat4MulVecfl(t->viewmat, vec);
1807                 VecSubf(vec, vec, t->viewmat[3]);
1808                 
1809                 dist= vec[0]-cursor[0];
1810                 
1811                 /* t->val is X dimension projected boundbox */
1812                 phi0= (circumfac*dist/t->val);  
1813                 
1814                 vec[1]= (vec[1]-cursor[1]);
1815                 
1816                 co= (float)cos(phi0);
1817                 si= (float)sin(phi0);
1818                 loc[0]= -si*vec[1]+cursor[0];
1819                 loc[1]= co*vec[1]+cursor[1];
1820                 loc[2]= vec[2];
1821                 
1822                 Mat4MulVecfl(t->viewinv, loc);
1823                 VecSubf(loc, loc, t->viewinv[3]);
1824                 Mat3MulVecfl(td->smtx, loc);
1825                 
1826                 VecSubf(loc, loc, td->iloc);
1827                 VecMulf(loc, td->factor);
1828                 VecAddf(td->loc, td->iloc, loc);
1829         }
1830
1831         recalcData(t);
1832         
1833         headerprint(str);
1834         
1835         viewRedrawForce(t);
1836         
1837         helpline(t, gcursor);
1838         
1839         return 1;
1840 }
1841
1842 /* ************************** SHEAR *************************** */
1843
1844 void initShear(TransInfo *t) 
1845 {
1846         t->mode = TFM_SHEAR;
1847         t->transform = Shear;
1848         t->handleEvent = handleEventShear;
1849         
1850         t->idx_max = 0;
1851         t->num.idx_max = 0;
1852         t->snap[0] = 0.0f;
1853         t->snap[1] = 0.1f;
1854         t->snap[2] = t->snap[1] * 0.1f;
1855         
1856         t->flag |= T_NO_CONSTRAINT;
1857 }
1858
1859 int handleEventShear(TransInfo *t, unsigned short event, short val)
1860 {
1861         int status = 0;
1862         
1863         if (event == MIDDLEMOUSE && val)
1864         {
1865                 // Use customData pointer to signal Shear direction
1866                 if      (t->customData == 0)
1867                         t->customData = (void*)1;
1868                 else
1869                         t->customData = 0;
1870                         
1871                 status = 1;
1872         }
1873         
1874         return status;
1875 }
1876
1877
1878 int Shear(TransInfo *t, short mval[2]) 
1879 {
1880         TransData *td = t->data;
1881         float vec[3];
1882         float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
1883         float value;
1884         int i;
1885         char str[50];
1886
1887         Mat3CpyMat4(persmat, t->viewmat);
1888         Mat3Inv(persinv, persmat);
1889
1890         // Custom data signals shear direction
1891         if (t->customData == 0)
1892                 value = 0.05f * InputHorizontalAbsolute(t, mval);
1893         else
1894                 value = 0.05f * InputVerticalAbsolute(t, mval);
1895
1896         snapGrid(t, &value);
1897
1898         applyNumInput(&t->num, &value);
1899
1900         /* header print for NumInput */
1901         if (hasNumInput(&t->num)) {
1902                 char c[20];
1903
1904                 outputNumInput(&(t->num), c);
1905
1906                 sprintf(str, "Shear: %s %s", c, t->proptext);
1907         }
1908         else {
1909                 /* default header print */
1910                 sprintf(str, "Shear: %.3f %s", value, t->proptext);
1911         }
1912         
1913         Mat3One(smat);
1914         
1915         // Custom data signals shear direction
1916         if (t->customData == 0)
1917                 smat[1][0] = value;
1918         else
1919                 smat[0][1] = value;
1920         
1921         Mat3MulMat3(tmat, smat, persmat);
1922         Mat3MulMat3(totmat, persinv, tmat);
1923         
1924         for(i = 0 ; i < t->total; i++, td++) {
1925                 if (td->flag & TD_NOACTION)
1926                         break;
1927
1928                 if (td->flag & TD_SKIP)
1929                         continue;
1930
1931                 if (G.obedit) {
1932                         float mat3[3][3];
1933                         Mat3MulMat3(mat3, totmat, td->mtx);
1934                         Mat3MulMat3(tmat, td->smtx, mat3);
1935                 }
1936                 else {
1937                         Mat3CpyMat3(tmat, totmat);
1938                 }
1939                 VecSubf(vec, td->center, t->center);
1940
1941                 Mat3MulVecfl(tmat, vec);
1942
1943                 VecAddf(vec, vec, t->center);
1944                 VecSubf(vec, vec, td->center);
1945
1946                 VecMulf(vec, td->factor);
1947
1948                 VecAddf(td->loc, td->iloc, vec);
1949         }
1950
1951         recalcData(t);
1952
1953         headerprint(str);
1954
1955         viewRedrawForce(t);
1956
1957         helpline (t, t->center);
1958
1959         return 1;
1960 }
1961
1962 /* ************************** RESIZE *************************** */
1963
1964 void initResize(TransInfo *t) 
1965 {
1966         t->mode = TFM_RESIZE;
1967         t->transform = Resize;
1968         
1969         t->flag |= T_NULL_ONE;
1970         t->num.flag |= NUM_NULL_ONE;
1971         t->num.flag |= NUM_AFFECT_ALL;
1972         if (!G.obedit) {
1973                 t->flag |= T_NO_ZERO;
1974                 t->num.flag |= NUM_NO_ZERO;
1975         }
1976         
1977         t->idx_max = 2;
1978         t->num.idx_max = 2;
1979         t->snap[0] = 0.0f;
1980         t->snap[1] = 0.1f;
1981         t->snap[2] = t->snap[1] * 0.1f;
1982
1983         t->fac = (float)sqrt(
1984                 (
1985                         ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
1986                 +
1987                         ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
1988                 ) );
1989
1990         if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
1991 }
1992
1993 static void headerResize(TransInfo *t, float vec[3], char *str) {
1994         char tvec[60];
1995         if (hasNumInput(&t->num)) {
1996                 outputNumInput(&(t->num), tvec);
1997         }
1998         else {
1999                 sprintf(&tvec[0], "%.4f", vec[0]);
2000                 sprintf(&tvec[20], "%.4f", vec[1]);
2001                 sprintf(&tvec[40], "%.4f", vec[2]);
2002         }
2003
2004         if (t->con.mode & CON_APPLY) {
2005                 switch(t->num.idx_max) {
2006                 case 0:
2007                         sprintf(str, "Scale: %s%s %s", &tvec[0], t->con.text, t->proptext);
2008                         break;
2009                 case 1:
2010                         sprintf(str, "Scale: %s : %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
2011                         break;
2012                 case 2:
2013                         sprintf(str, "Scale: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
2014                 }
2015         }
2016         else {
2017                 if (t->flag & T_2D_EDIT)
2018                         sprintf(str, "Scale X: %s   Y: %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
2019                 else
2020                         sprintf(str, "Scale X: %s   Y: %s  Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
2021         }
2022 }
2023
2024 #define SIGN(a)         (a<-FLT_EPSILON?1:a>FLT_EPSILON?2:3)
2025 #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)
2026
2027 /* smat is reference matrix, only scaled */
2028 static void TransMat3ToSize( float mat[][3], float smat[][3], float *size)
2029 {
2030         float vec[3];
2031         
2032         VecCopyf(vec, mat[0]);
2033         size[0]= Normalize(vec);
2034         VecCopyf(vec, mat[1]);
2035         size[1]= Normalize(vec);
2036         VecCopyf(vec, mat[2]);
2037         size[2]= Normalize(vec);
2038         
2039         /* first tried with dotproduct... but the sign flip is crucial */
2040         if( VECSIGNFLIP(mat[0], smat[0]) ) size[0]= -size[0]; 
2041         if( VECSIGNFLIP(mat[1], smat[1]) ) size[1]= -size[1]; 
2042         if( VECSIGNFLIP(mat[2], smat[2]) ) size[2]= -size[2]; 
2043 }
2044
2045
2046 static void ElementResize(TransInfo *t, TransData *td, float mat[3][3]) {
2047         float tmat[3][3], smat[3][3], center[3];
2048         float vec[3];
2049
2050         if (t->flag & T_EDIT) {
2051                 Mat3MulMat3(smat, mat, td->mtx);
2052                 Mat3MulMat3(tmat, td->smtx, smat);
2053         }
2054         else {
2055                 Mat3CpyMat3(tmat, mat);
2056         }
2057
2058         if (t->con.applySize) {
2059                 t->con.applySize(t, td, tmat);
2060         }
2061
2062         /* local constraint shouldn't alter center */
2063         if (t->around == V3D_LOCAL) {
2064                 if (t->flag & T_OBJECT) {
2065                         VECCOPY(center, td->center);
2066                 }
2067                 else if (t->flag & T_EDIT) {
2068                         
2069                         if(G.vd->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
2070                                 VECCOPY(center, td->center);
2071                         }
2072                         else {
2073                                 VECCOPY(center, t->center);
2074                         }
2075                 }
2076                 else {
2077                         VECCOPY(center, t->center);
2078                 }
2079         }
2080         else {
2081                 VECCOPY(center, t->center);
2082         }
2083
2084         if (td->ext) {
2085                 float fsize[3];
2086                 
2087                 if (t->flag & (T_OBJECT|T_TEXTURE|T_POSE)) {
2088                         float obsizemat[3][3];
2089                         // Reorient the size mat to fit the oriented object.
2090                         Mat3MulMat3(obsizemat, tmat, td->axismtx);
2091                         //printmatrix3("obsizemat", obsizemat);
2092                         TransMat3ToSize(obsizemat, td->axismtx, fsize);
2093                         //printvecf("fsize", fsize);
2094                 }
2095                 else {
2096                         Mat3ToSize(tmat, fsize);
2097                 }
2098                 
2099                 protectedSizeBits(td->protectflag, fsize);
2100                 
2101                 if ((t->flag & T_V3D_ALIGN)==0) {       // align mode doesn't resize objects itself
2102                         /* handle ipokeys? */
2103                         if(td->tdi) {
2104                                 TransDataIpokey *tdi= td->tdi;
2105                                 /* calculate delta size (equal for size and dsize) */
2106                                 
2107                                 vec[0]= (tdi->oldsize[0])*(fsize[0] -1.0f) * td->factor;
2108                                 vec[1]= (tdi->oldsize[1])*(fsize[1] -1.0f) * td->factor;
2109                                 vec[2]= (tdi->oldsize[2])*(fsize[2] -1.0f) * td->factor;
2110                                 
2111                                 add_tdi_poin(tdi->sizex, tdi->oldsize,   vec[0]);
2112                                 add_tdi_poin(tdi->sizey, tdi->oldsize+1, vec[1]);
2113                                 add_tdi_poin(tdi->sizez, tdi->oldsize+2, vec[2]);
2114                                 
2115                         } 
2116                         else if((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)){
2117                                 /* scale val and reset size */
2118                                 *td->val = td->ival * fsize[0] * td->factor;
2119                                 
2120                                 td->ext->size[0] = td->ext->isize[0];
2121                                 td->ext->size[1] = td->ext->isize[1];
2122                                 td->ext->size[2] = td->ext->isize[2];
2123                         }
2124                         else {
2125                                 /* Reset val if SINGLESIZE but using a constraint */
2126                                 if (td->flag & TD_SINGLESIZE)
2127                                         *td->val = td->ival;
2128                                 
2129                                 td->ext->size[0] = td->ext->isize[0] * (fsize[0]) * td->factor;
2130                                 td->ext->size[1] = td->ext->isize[1] * (fsize[1]) * td->factor;
2131                                 td->ext->size[2] = td->ext->isize[2] * (fsize[2]) * td->factor;
2132                         }
2133                 }
2134                 
2135                 constraintSizeLim(t, td);
2136         }
2137         
2138         /* For individual element center, Editmode need to use iloc */
2139         if (t->flag & T_POINTS)
2140                 VecSubf(vec, td->iloc, center);
2141         else
2142                 VecSubf(vec, td->center, center);
2143
2144         Mat3MulVecfl(tmat, vec);
2145
2146         VecAddf(vec, vec, center);
2147         if (t->flag & T_POINTS)
2148                 VecSubf(vec, vec, td->iloc);
2149         else
2150                 VecSubf(vec, vec, td->center);
2151
2152         VecMulf(vec, td->factor);
2153
2154         if (t->flag & (T_OBJECT|T_POSE)) {
2155                 Mat3MulVecfl(td->smtx, vec);
2156         }
2157
2158         protectedTransBits(td->protectflag, vec);
2159
2160         if(td->tdi) {
2161                 TransDataIpokey *tdi= td->tdi;
2162                 add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
2163                 add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
2164                 add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
2165         }
2166         else VecAddf(td->loc, td->iloc, vec);
2167         
2168         constraintTransLim(t, td);
2169 }
2170
2171 int Resize(TransInfo *t, short mval[2]) 
2172 {
2173         TransData *td;
2174         float size[3], mat[3][3];
2175         float ratio;
2176         int i;
2177         char str[200];
2178
2179         /* for manipulator, center handle, the scaling can't be done relative to center */
2180         if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) {
2181                 ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f;
2182         }
2183         else {
2184                 ratio = InputScaleRatio(t, mval);
2185                 
2186                 /* flip scale, but not for manipulator center handle */
2187                 if      ((t->center2d[0] - mval[0]) * (t->center2d[0] - t->imval[0]) + 
2188                          (t->center2d[1] - mval[1]) * (t->center2d[1] - t->imval[1]) < 0)
2189                                 ratio *= -1.0f;
2190         }
2191         
2192         size[0] = size[1] = size[2] = ratio;
2193
2194         snapGrid(t, size);
2195
2196         if (hasNumInput(&t->num)) {
2197                 applyNumInput(&t->num, size);
2198                 constraintNumInput(t, size);
2199         }
2200
2201         applySnapping(t, size);
2202
2203         SizeToMat3(size, mat);
2204
2205         if (t->con.applySize) {
2206                 t->con.applySize(t, NULL, mat);
2207         }
2208
2209         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2210         
2211         headerResize(t, size, str);
2212
2213         for(i = 0, td=t->data; i < t->total; i++, td++) {
2214                 if (td->flag & TD_NOACTION)
2215                         break;
2216
2217                 if (td->flag & TD_SKIP)
2218                         continue;
2219                 
2220                 ElementResize(t, td, mat);
2221         }
2222
2223         /* evil hack - redo resize if cliping needed */
2224         if (t->flag & T_CLIP_UV && clipUVTransform(t, size, 1)) {
2225                 SizeToMat3(size, mat);
2226
2227                 if (t->con.applySize)
2228                         t->con.applySize(t, NULL, mat);
2229
2230                 for(i = 0, td=t->data; i < t->total; i++, td++)
2231                         ElementResize(t, td, mat);
2232         }
2233
2234         recalcData(t);
2235
2236         headerprint(str);
2237
2238         viewRedrawForce(t);
2239
2240         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
2241
2242         return 1;
2243 }
2244
2245 /* ************************** TOSPHERE *************************** */
2246
2247 void initToSphere(TransInfo *t) 
2248 {
2249         TransData *td = t->data;
2250         int i;
2251
2252         t->mode = TFM_TOSPHERE;
2253         t->transform = ToSphere;
2254
2255         t->idx_max = 0;
2256         t->num.idx_max = 0;
2257         t->snap[0] = 0.0f;
2258         t->snap[1] = 0.1f;
2259         t->snap[2] = t->snap[1] * 0.1f;
2260         
2261         t->num.flag |= NUM_NULL_ONE | NUM_NO_NEGATIVE;
2262         t->flag |= T_NO_CONSTRAINT;
2263
2264         // Calculate average radius
2265         for(i = 0 ; i < t->total; i++, td++) {
2266                 t->val += VecLenf(t->center, td->iloc);
2267         }
2268
2269         t->val /= (float)t->total;
2270 }
2271
2272 int ToSphere(TransInfo *t, short mval[2]) 
2273 {
2274         float vec[3];
2275         float ratio, radius;
2276         int i;
2277         char str[64];
2278         TransData *td = t->data;
2279
2280         ratio = InputHorizontalRatio(t, mval);
2281
2282         snapGrid(t, &ratio);
2283
2284         applyNumInput(&t->num, &ratio);
2285
2286         if (ratio < 0)
2287                 ratio = 0.0f;
2288         else if (ratio > 1)
2289                 ratio = 1.0f;
2290
2291         /* header print for NumInput */
2292         if (hasNumInput(&t->num)) {
2293                 char c[20];
2294
2295                 outputNumInput(&(t->num), c);
2296
2297                 sprintf(str, "To Sphere: %s %s", c, t->proptext);
2298         }
2299         else {
2300                 /* default header print */
2301                 sprintf(str, "To Sphere: %.4f %s", ratio, t->proptext);
2302         }
2303         
2304         
2305         for(i = 0 ; i < t->total; i++, td++) {
2306                 float tratio;
2307                 if (td->flag & TD_NOACTION)
2308                         break;
2309
2310                 if (td->flag & TD_SKIP)
2311                         continue;
2312
2313                 VecSubf(vec, td->iloc, t->center);
2314
2315                 radius = Normalize(vec);
2316
2317                 tratio = ratio * td->factor;
2318
2319                 VecMulf(vec, radius * (1.0f - tratio) + t->val * tratio);
2320
2321                 VecAddf(td->loc, t->center, vec);
2322         }
2323         
2324
2325         recalcData(t);
2326
2327         headerprint(str);
2328
2329         viewRedrawForce(t);
2330
2331         return 1;
2332 }
2333
2334 /* ************************** ROTATION *************************** */
2335
2336
2337 void initRotation(TransInfo *t) 
2338 {
2339         t->mode = TFM_ROTATION;
2340         t->transform = Rotation;
2341         
2342         t->ndof.axis = 16;
2343         /* Scale down and flip input for rotation */
2344         t->ndof.factor[0] = -0.2f;
2345         
2346         t->idx_max = 0;
2347         t->num.idx_max = 0;
2348         t->snap[0] = 0.0f;
2349         t->snap[1] = (float)((5.0/180)*M_PI);
2350         t->snap[2] = t->snap[1] * 0.2f;
2351         t->fac = 0;
2352         
2353         if (t->flag & T_2D_EDIT)
2354                 t->flag |= T_NO_CONSTRAINT;
2355 }
2356
2357 static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3]) {
2358         float vec[3], totmat[3][3], smat[3][3];
2359         float eul[3], fmat[3][3], quat[4];
2360
2361         if (t->flag & T_POINTS) {
2362                 Mat3MulMat3(totmat, mat, td->mtx);
2363                 Mat3MulMat3(smat, td->smtx, totmat);
2364                 
2365                 VecSubf(vec, td->iloc, t->center);
2366                 Mat3MulVecfl(smat, vec);
2367                 
2368                 VecAddf(td->loc, vec, t->center);
2369
2370                 VecSubf(vec,td->loc,td->iloc);
2371                 protectedTransBits(td->protectflag, vec);
2372                 VecAddf(td->loc, td->iloc, vec);
2373
2374                 if(td->flag & TD_USEQUAT) {
2375                         Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
2376                         Mat3ToQuat(fmat, quat); // Actual transform
2377                         
2378                         if(td->ext->quat){
2379                                 QuatMul(td->ext->quat, quat, td->ext->iquat);
2380                                 
2381                                 /* is there a reason not to have this here? -jahka */
2382                                 protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
2383                         }
2384                 }
2385         }
2386         /**
2387          * HACK WARNING
2388          * 
2389          * This is some VERY ugly special case to deal with pose mode.
2390          * 
2391          * The problem is that mtx and smtx include each bone orientation.
2392          * 
2393          * That is needed to rotate each bone properly, HOWEVER, to calculate
2394          * the translation component, we only need the actual armature object's
2395          * matrix (and inverse). That is not all though. Once the proper translation
2396          * has been computed, it has to be converted back into the bone's space.
2397          */
2398         else if (t->flag & T_POSE) {
2399                 float pmtx[3][3], imtx[3][3];
2400
2401                 // Extract and invert armature object matrix            
2402                 Mat3CpyMat4(pmtx, t->poseobj->obmat);
2403                 Mat3Inv(imtx, pmtx);
2404                 
2405                 VecSubf(vec, td->center, t->center);
2406                 
2407                 Mat3MulVecfl(pmtx, vec);        // To Global space
2408                 Mat3MulVecfl(mat, vec);         // Applying rotation
2409                 Mat3MulVecfl(imtx, vec);        // To Local space
2410
2411                 VecAddf(vec, vec, t->center);
2412                 /* vec now is the location where the object has to be */
2413                 
2414                 VecSubf(vec, vec, td->center); // Translation needed from the initial location
2415                 
2416                 Mat3MulVecfl(pmtx, vec);        // To Global space
2417                 Mat3MulVecfl(td->smtx, vec);// To Pose space
2418
2419                 protectedTransBits(td->protectflag, vec);
2420
2421                 VecAddf(td->loc, td->iloc, vec);
2422                 
2423                 constraintTransLim(t, td);
2424                 
2425                 /* rotation */
2426                 if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
2427                         Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
2428                         
2429                         Mat3ToQuat(fmat, quat); // Actual transform
2430                         
2431                         QuatMul(td->ext->quat, quat, td->ext->iquat);
2432                         /* this function works on end result */
2433                         protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
2434                         
2435                         constraintRotLim(t, td);
2436                 }
2437         }
2438         else {
2439                 /* translation */
2440                 VecSubf(vec, td->center, t->center);
2441                 Mat3MulVecfl(mat, vec);
2442                 VecAddf(vec, vec, t->center);
2443                 /* vec now is the location where the object has to be */
2444                 VecSubf(vec, vec, td->center);
2445                 Mat3MulVecfl(td->smtx, vec);
2446                 
2447                 protectedTransBits(td->protectflag, vec);
2448                 
2449                 if(td->tdi) {
2450                         TransDataIpokey *tdi= td->tdi;
2451                         add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
2452                         add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
2453                         add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
2454                 }
2455                 else VecAddf(td->loc, td->iloc, vec);
2456                 
2457                 constraintTransLim(t, td);
2458
2459                 /* rotation */
2460                 if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
2461                         if(td->flag & TD_USEQUAT) {
2462                                 Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
2463                                 Mat3ToQuat(fmat, quat); // Actual transform
2464                                 
2465                                 QuatMul(td->ext->quat, quat, td->ext->iquat);
2466                                 /* this function works on end result */
2467                                 protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
2468                         }
2469                         else {
2470                                 float obmat[3][3];
2471                                 
2472                                 /* are there ipo keys? */
2473                                 if(td->tdi) {
2474                                         TransDataIpokey *tdi= td->tdi;
2475                                         float rot[3];
2476                                         
2477                                         /* calculate the total rotatation in eulers */
2478                                         VecAddf(eul, td->ext->irot, td->ext->drot);
2479                                         EulToMat3(eul, obmat);
2480                                         /* mat = transform, obmat = object rotation */
2481                                         Mat3MulMat3(fmat, mat, obmat);
2482                                         
2483                                         Mat3ToCompatibleEul(fmat, eul, td->ext->irot);
2484                                         
2485                                         /* correct back for delta rot */
2486                                         if(tdi->flag & TOB_IPODROT) {
2487                                                 VecSubf(rot, eul, td->ext->irot);
2488                                         }
2489                                         else {
2490                                                 VecSubf(rot, eul, td->ext->drot);
2491                                         }
2492                                         
2493                                         VecMulf(rot, (float)(9.0/M_PI_2));
2494                                         VecSubf(rot, rot, tdi->oldrot);
2495                                         
2496                                         protectedRotateBits(td->protectflag, rot, tdi->oldrot);
2497                                         
2498                                         add_tdi_poin(tdi->rotx, tdi->oldrot, rot[0]);
2499                                         add_tdi_poin(tdi->roty, tdi->oldrot+1, rot[1]);
2500                                         add_tdi_poin(tdi->rotz, tdi->oldrot+2, rot[2]);
2501                                 }
2502                                 else {
2503                                         Mat3MulMat3(totmat, mat, td->mtx);
2504                                         Mat3MulMat3(smat, td->smtx, totmat);
2505                                         
2506                                         /* calculate the total rotatation in eulers */
2507                                         VecAddf(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
2508                                         EulToMat3(eul, obmat);
2509                                         /* mat = transform, obmat = object rotation */
2510                                         Mat3MulMat3(fmat, smat, obmat);
2511                                         
2512                                         Mat3ToCompatibleEul(fmat, eul, td->ext->irot);
2513                                         
2514                                         /* correct back for delta rot */
2515                                         VecSubf(eul, eul, td->ext->drot);
2516                                         
2517                                         /* and apply */
2518                                         protectedRotateBits(td->protectflag, eul, td->ext->irot);
2519                                         VECCOPY(td->ext->rot, eul);
2520                                 }
2521                         }
2522                         
2523                         constraintRotLim(t, td);
2524                 }
2525         }
2526 }
2527
2528 static void applyRotation(TransInfo *t, float angle, float axis[3]) 
2529 {
2530         TransData *td = t->data;
2531         float mat[3][3], center[3];
2532         int i;
2533
2534         /* saving original center */
2535         if (t->around == V3D_LOCAL) {
2536                 VECCOPY(center, t->center);
2537         }
2538         else {
2539                 center[0] = center[1] = center[2] = 0.0f;
2540         }
2541
2542         VecRotToMat3(axis, angle, mat);
2543         
2544         for(i = 0 ; i < t->total; i++, td++) {
2545
2546                 if (td->flag & TD_NOACTION)
2547                         break;
2548
2549                 if (td->flag & TD_SKIP)
2550                         continue;
2551                 
2552                 /* local constraint shouldn't alter center */
2553                 if (t->around == V3D_LOCAL) {
2554                         if (t->flag & (T_OBJECT|T_POSE)) {
2555                                 VECCOPY(t->center, td->center);
2556                         }
2557                         else {
2558                                 if(G.vd->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
2559                                         VECCOPY(t->center, td->center);
2560                                 }
2561                         }
2562                 }
2563                 
2564                 if (t->con.applyRot) {
2565                         t->con.applyRot(t, td, axis);
2566                         VecRotToMat3(axis, angle * td->factor, mat);
2567                 }
2568                 else if (t->flag & T_PROP_EDIT) {
2569                         VecRotToMat3(axis, angle * td->factor, mat);
2570                 }
2571
2572                 ElementRotation(t, td, mat);
2573         }
2574
2575         /* restoring original center */
2576         if (t->around == V3D_LOCAL) {
2577                 VECCOPY(t->center, center);
2578         }
2579 }
2580
2581 int Rotation(TransInfo *t, short mval[2]) 
2582 {
2583         char str[64];
2584
2585         float final;
2586
2587         double dx2 = t->center2d[0] - mval[0];
2588         double dy2 = t->center2d[1] - mval[1];
2589         double B = sqrt(dx2*dx2+dy2*dy2);
2590
2591         double dx1 = t->center2d[0] - t->imval[0];
2592         double dy1 = t->center2d[1] - t->imval[1];
2593         double A = sqrt(dx1*dx1+dy1*dy1);
2594
2595         double dx3 = mval[0] - t->imval[0];
2596         double dy3 = mval[1] - t->imval[1];
2597                 /* use doubles here, to make sure a "1.0" (no rotation) doesnt become 9.999999e-01, which gives 0.02 for acos */
2598         double deler= ((double)((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3) ))
2599                 / (2.0 * (A*B?A*B:1.0));
2600         /* (A*B?A*B:1.0f) this takes care of potential divide by zero errors */
2601
2602         float dphi;
2603
2604         float axis[3];
2605         float mat[3][3];
2606
2607         VECCOPY(axis, t->viewinv[2]);
2608         VecMulf(axis, -1.0f);
2609         Normalize(axis);
2610
2611         dphi = saacos((float)deler);
2612         if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
2613
2614         if(t->flag & T_SHIFT_MOD) t->fac += dphi/30.0f;
2615         else t->fac += dphi;
2616
2617         /*
2618         clamping angle between -2 PI and 2 PI (not sure if useful so commented out - theeth)
2619         if (t->fac >= 2 * M_PI)
2620                 t->fac -= 2 * M_PI;
2621         else if (t->fac <= -2 * M_PI)
2622                 t->fac -= -2 * M_PI;
2623         */
2624
2625         final = t->fac;
2626
2627         applyNDofInput(&t->ndof, &final);
2628         
2629         snapGrid(t, &final);
2630
2631         t->imval[0] = mval[0];
2632         t->imval[1] = mval[1];
2633
2634         if (t->con.applyRot) {
2635                 t->con.applyRot(t, NULL, axis);
2636         }
2637         
2638         applySnapping(t, &final);
2639
2640         if (hasNumInput(&t->num)) {
2641                 char c[20];
2642
2643                 applyNumInput(&t->num, &final);
2644
2645                 outputNumInput(&(t->num), c);
2646
2647                 sprintf(str, "Rot: %s %s %s", &c[0], t->con.text, t->proptext);
2648
2649                 /* Clamp between -180 and 180 */
2650                 while (final >= 180.0)
2651                         final -= 360.0;
2652                 
2653                 while (final <= -180.0)
2654                         final += 360.0;
2655
2656                 final *= (float)(M_PI / 180.0);
2657         }
2658         else {
2659                 sprintf(str, "Rot: %.2f%s %s", 180.0*final/M_PI, t->con.text, t->proptext);
2660         }
2661
2662         VecRotToMat3(axis, final, mat);
2663
2664         t->val = final;                         // used in manipulator
2665         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2666         
2667         applyRotation(t, final, axis);
2668         
2669         recalcData(t);
2670
2671         headerprint(str);
2672
2673         viewRedrawForce(t);
2674
2675         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
2676
2677         return 1;
2678 }
2679
2680
2681 /* ************************** TRACKBALL *************************** */
2682
2683 void initTrackball(TransInfo *t) 
2684 {
2685         t->mode = TFM_TRACKBALL;
2686         t->transform = Trackball;
2687         
2688         t->ndof.axis = 40;
2689         /* Scale down input for rotation */
2690         t->ndof.factor[0] = 0.2f;
2691         t->ndof.factor[1] = 0.2f;
2692
2693         t->idx_max = 1;
2694         t->num.idx_max = 1;
2695         t->snap[0] = 0.0f;
2696         t->snap[1] = (float)((5.0/180)*M_PI);
2697         t->snap[2] = t->snap[1] * 0.2f;
2698         t->fac = 0;
2699         
2700         t->flag |= T_NO_CONSTRAINT;
2701 }
2702
2703 static void applyTrackball(TransInfo *t, float axis1[3], float axis2[3], float angles[2])
2704 {
2705         TransData *td = t->data;
2706         float mat[3][3], smat[3][3], totmat[3][3];
2707         float center[3];
2708         int i;
2709
2710         VecRotToMat3(axis1, angles[0], smat);
2711         VecRotToMat3(axis2, angles[1], totmat);
2712         
2713         Mat3MulMat3(mat, smat, totmat);
2714
2715         for(i = 0 ; i < t->total; i++, td++) {
2716                 if (td->flag & TD_NOACTION)
2717                         break;
2718
2719                 if (td->flag & TD_SKIP)
2720                         continue;
2721                 
2722                 VECCOPY(center, t->center);
2723                 
2724                 if (t->around == V3D_LOCAL) {
2725                         /* local-mode shouldn't change center */
2726                         if (t->flag & (T_OBJECT|T_POSE)) {
2727                                 VECCOPY(t->center, td->center);
2728                         }
2729                         else {
2730                                 if(G.vd->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
2731                                         VECCOPY(t->center, td->center);
2732                                 }
2733                         }
2734                 }
2735                 
2736                 if (t->flag & T_PROP_EDIT) {
2737                         VecRotToMat3(axis1, td->factor * angles[0], smat);
2738                         VecRotToMat3(axis2, td->factor * angles[1], totmat);
2739                         
2740                         Mat3MulMat3(mat, smat, totmat);
2741                 }
2742                 
2743                 ElementRotation(t, td, mat);
2744                 
2745                 VECCOPY(t->center, center);
2746         }
2747 }
2748
2749 int Trackball(TransInfo *t, short mval[2]) 
2750 {
2751         char str[128];
2752         float axis1[3], axis2[3];
2753         float mat[3][3], totmat[3][3], smat[3][3];
2754         float phi[2];
2755         
2756         VECCOPY(axis1, t->persinv[0]);
2757         VECCOPY(axis2, t->persinv[1]);
2758         Normalize(axis1);
2759         Normalize(axis2);
2760         
2761         /* factore has to become setting or so */
2762         phi[0]= 0.01f*(float)( t->imval[1] - mval[1] );
2763         phi[1]= 0.01f*(float)( mval[0] - t->imval[0] );
2764                 
2765         applyNDofInput(&t->ndof, phi);
2766         
2767         snapGrid(t, phi);
2768         
2769         if (hasNumInput(&t->num)) {
2770                 char c[40];
2771                 
2772                 applyNumInput(&t->num, phi);
2773                 
2774                 outputNumInput(&(t->num), c);
2775                 
2776                 sprintf(str, "Trackball: %s %s %s", &c[0], &c[20], t->proptext);
2777                 
2778                 phi[0] *= (float)(M_PI / 180.0);
2779                 phi[1] *= (float)(M_PI / 180.0);
2780         }
2781         else {
2782                 sprintf(str, "Trackball: %.2f %.2f %s", 180.0*phi[0]/M_PI, 180.0*phi[1]/M_PI, t->proptext);
2783         
2784                 if(t->flag & T_SHIFT_MOD) {
2785                         if(phi[0] != 0.0) phi[0]/= 5.0f;
2786                         if(phi[1] != 0.0) phi[1]/= 5.0f;
2787                 }
2788         }
2789
2790         VecRotToMat3(axis1, phi[0], smat);
2791         VecRotToMat3(axis2, phi[1], totmat);
2792         
2793         Mat3MulMat3(mat, smat, totmat);
2794         
2795         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2796         
2797         applyTrackball(t, axis1, axis2, phi);
2798         
2799         recalcData(t);
2800         
2801         headerprint(str);
2802         
2803         viewRedrawForce(t);
2804         
2805         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
2806         
2807         return 1;
2808 }
2809
2810 /* ************************** TRANSLATION *************************** */
2811         
2812 void initTranslation(TransInfo *t) 
2813 {
2814         t->mode = TFM_TRANSLATION;
2815         t->transform = Translation;
2816
2817         t->idx_max = (t->flag & T_2D_EDIT)? 1: 2;
2818         t->num.flag = 0;
2819         t->num.idx_max = t->idx_max;
2820         
2821         t->ndof.axis = 7;
2822
2823         if(t->spacetype == SPACE_VIEW3D) {
2824                 /* initgrabz() defines a factor for perspective depth correction, used in window_to_3d() */
2825                 if(t->flag & (T_EDIT|T_POSE)) {
2826                         Object *ob= G.obedit?G.obedit:t->poseobj;
2827                         float vec[3];
2828                         
2829                         VECCOPY(vec, t->center);
2830                         Mat4MulVecfl(ob->obmat, vec);
2831                         initgrabz(vec[0], vec[1], vec[2]);
2832                 }
2833                 else {
2834                         initgrabz(t->center[0], t->center[1], t->center[2]);
2835                 } 
2836
2837                 t->snap[0] = 0.0f;
2838                 t->snap[1] = G.vd->gridview * 1.0f;
2839                 t->snap[2] = t->snap[1] * 0.1f;
2840         }
2841         else if(t->spacetype == SPACE_IMAGE) {
2842                 t->snap[0] = 0.0f;
2843                 t->snap[1] = 0.125f;
2844                 t->snap[2] = 0.0625f;
2845         }
2846         else {
2847                 t->snap[0] = 0.0f;
2848                 t->snap[1] = t->snap[2] = 1.0f;
2849         }
2850 }
2851
2852 static void headerTranslation(TransInfo *t, float vec[3], char *str) {
2853         char tvec[60];
2854         char distvec[20];
2855         char autoik[20];
2856         float dvec[3];
2857         float dist;
2858         
2859         convertVecToDisplayNum(vec, dvec);
2860
2861         if (hasNumInput(&t->num)) {
2862                 outputNumInput(&(t->num), tvec);
2863                 dist = VecLength(t->num.val);
2864         }
2865         else {
2866                 dist = VecLength(vec);
2867                 sprintf(&tvec[0], "%.4f", dvec[0]);
2868                 sprintf(&tvec[20], "%.4f", dvec[1]);
2869                 sprintf(&tvec[40], "%.4f", dvec[2]);
2870         }
2871
2872         if( dist > 1e10 || dist < -1e10 )       /* prevent string buffer overflow */
2873                 sprintf(distvec, "%.4e", dist);
2874         else
2875                 sprintf(distvec, "%.4f", dist);
2876                 
2877         if(t->flag & T_AUTOIK) {
2878                 short chainlen= G.scene->toolsettings->autoik_chainlen;
2879                 
2880                 if(chainlen)
2881                         sprintf(autoik, "AutoIK-Len: %d", chainlen);
2882                 else
2883                         strcpy(autoik, "");
2884         }
2885         else
2886                 strcpy(autoik, "");
2887
2888         if (t->con.mode & CON_APPLY) {
2889                 switch(t->num.idx_max) {
2890                 case 0:
2891                         sprintf(str, "D: %s (%s)%s %s  %s", &tvec[0], distvec, t->con.text, t->proptext, &autoik[0]);
2892                         break;
2893                 case 1:
2894                         sprintf(str, "D: %s   D: %s (%s)%s %s  %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext, &autoik[0]);
2895                         break;
2896                 case 2:
2897                         sprintf(str, "D: %s   D: %s  D: %s (%s)%s %s  %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext, &autoik[0]);
2898                 }
2899         }
2900         else {
2901                 if(t->flag & T_2D_EDIT)
2902                         sprintf(str, "Dx: %s   Dy: %s (%s)%s %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext);
2903                 else
2904                         sprintf(str, "Dx: %s   Dy: %s  Dz: %s (%s)%s %s  %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext, &autoik[0]);
2905         }
2906 }
2907
2908 static void applyTranslation(TransInfo *t, float vec[3]) {
2909         TransData *td = t->data;
2910         float tvec[3];
2911         int i;
2912
2913         for(i = 0 ; i < t->total; i++, td++) {
2914                 if (td->flag & TD_NOACTION)
2915                         break;
2916                 
2917                 if (td->flag & TD_SKIP)
2918                         continue;
2919                 
2920                 if (t->con.applyVec) {
2921                         float pvec[3];
2922                         t->con.applyVec(t, td, vec, tvec, pvec);
2923                 }
2924                 else {
2925                         VECCOPY(tvec, vec);
2926                 }
2927                 
2928                 Mat3MulVecfl(td->smtx, tvec);
2929                 VecMulf(tvec, td->factor);
2930                 
2931                 protectedTransBits(td->protectflag, tvec);
2932                 
2933                 /* transdata ipokey */
2934                 if(td->tdi) {
2935                         TransDataIpokey *tdi= td->tdi;
2936                         add_tdi_poin(tdi->locx, tdi->oldloc, tvec[0]);
2937                         add_tdi_poin(tdi->locy, tdi->oldloc+1, tvec[1]);
2938                         add_tdi_poin(tdi->locz, tdi->oldloc+2, tvec[2]);
2939                 }
2940                 else VecAddf(td->loc, td->iloc, tvec);
2941                 
2942                 constraintTransLim(t, td);
2943         }
2944 }
2945
2946 /* uses t->vec to store actual translation in */
2947 int Translation(TransInfo *t, short mval[2]) 
2948 {
2949         float tvec[3];
2950         char str[250];
2951         
2952         if(t->flag & T_SHIFT_MOD) {
2953                 float dvec[3];
2954                 /* calculate the main translation and the precise one separate */
2955                 convertViewVec(t, dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
2956                 VecMulf(dvec, 0.1f);
2957                 convertViewVec(t, t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
2958                 VecAddf(t->vec, t->vec, dvec);
2959         }
2960         else convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
2961
2962         if (t->con.mode & CON_APPLY) {
2963                 float pvec[3] = {0.0f, 0.0f, 0.0f};
2964                 applySnapping(t, t->vec);
2965                 t->con.applyVec(t, NULL, t->vec, tvec, pvec);
2966                 VECCOPY(t->vec, tvec);
2967                 headerTranslation(t, pvec, str);
2968         }
2969         else {
2970                 applyNDofInput(&t->ndof, t->vec);
2971                 snapGrid(t, t->vec);
2972                 applyNumInput(&t->num, t->vec);
2973                 applySnapping(t, t->vec);
2974                 headerTranslation(t, t->vec, str);
2975         }
2976         
2977         applyTranslation(t, t->vec);
2978
2979         /* evil hack - redo translation if cliiping needeed */
2980         if (t->flag & T_CLIP_UV && clipUVTransform(t, t->vec, 0))
2981                 applyTranslation(t, t->vec);
2982
2983         recalcData(t);
2984
2985         headerprint(str);
2986         
2987         viewRedrawForce(t);
2988
2989         drawSnapping(t);
2990
2991         return 1;
2992 }
2993
2994 /* ************************** SHRINK/FATTEN *************************** */
2995
2996 void initShrinkFatten(TransInfo *t) 
2997 {
2998         // If not in mesh edit mode, fallback to Resize
2999         if (G.obedit==NULL || G.obedit->type != OB_MESH) {
3000                 initResize(t);
3001         }
3002         else {
3003                 t->mode = TFM_SHRINKFATTEN;
3004                 t->transform = ShrinkFatten;
3005         
3006                 t->idx_max = 0;
3007                 t->num.idx_max = 0;
3008                 t->snap[0] = 0.0f;
3009                 t->snap[1] = 1.0f;
3010                 t->snap[2] = t->snap[1] * 0.1f;
3011                 
3012                 t->flag |= T_NO_CONSTRAINT;
3013         }
3014 }
3015
3016
3017
3018 int ShrinkFatten(TransInfo *t, short mval[2]) 
3019 {
3020         float vec[3];
3021         float distance;
3022         int i;
3023         char str[64];
3024         TransData *td = t->data;
3025
3026         distance = -InputVerticalAbsolute(t, mval);
3027
3028         snapGrid(t, &distance);
3029
3030         applyNumInput(&t->num, &distance);
3031
3032         /* header print for NumInput */
3033         if (hasNumInput(&t->num)) {
3034                 char c[20];
3035
3036                 outputNumInput(&(t->num), c);
3037
3038                 sprintf(str, "Shrink/Fatten: %s %s", c, t->proptext);
3039         }
3040         else {
3041                 /* default header print */
3042                 sprintf(str, "Shrink/Fatten: %.4f %s", distance, t->proptext);
3043         }
3044         
3045         
3046         for(i = 0 ; i < t->total; i++, td++) {
3047                 if (td->flag & TD_NOACTION)
3048                         break;
3049
3050                 if (td->flag & TD_SKIP)
3051                         continue;
3052
3053                 VECCOPY(vec, td->axismtx[2]);
3054                 VecMulf(vec, distance);
3055                 VecMulf(vec, td->factor);
3056
3057                 VecAddf(td->loc, td->iloc, vec);
3058         }
3059
3060         recalcData(t);
3061
3062         headerprint(str);
3063
3064         viewRedrawForce(t);
3065
3066         return 1;
3067 }
3068
3069 /* ************************** TILT *************************** */
3070
3071 void initTilt(TransInfo *t) 
3072 {
3073         t->mode = TFM_TILT;
3074         t->transform = Tilt;
3075
3076         t->ndof.axis = 16;
3077         /* Scale down and flip input for rotation */
3078         t->ndof.factor[0] = -0.2f;
3079
3080         t->idx_max = 0;
3081         t->num.idx_max = 0;
3082         t->snap[0] = 0.0f;
3083         t->snap[1] = (float)((5.0/180)*M_PI);
3084         t->snap[2] = t->snap[1] * 0.2f;
3085         t->fac = 0;
3086         
3087         t->flag |= T_NO_CONSTRAINT;
3088 }
3089
3090
3091
3092 int Tilt(TransInfo *t, short mval[2]) 
3093 {
3094         TransData *td = t->data;
3095         int i;
3096         char str[50];
3097
3098         float final;
3099
3100         double dx2 = t->center2d[0] - mval[0];
3101         double dy2 = t->center2d[1] - mval[1];
3102         double B = (float)sqrt(dx2*dx2+dy2*dy2);
3103
3104         double dx1 = t->center2d[0] - t->imval[0];
3105         double dy1 = t->center2d[1] - t->imval[1];
3106         double A = (float)sqrt(dx1*dx1+dy1*dy1);
3107
3108         double dx3 = mval[0] - t->imval[0];
3109         double dy3 = mval[1] - t->imval[1];
3110
3111         double deler= ((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3))
3112                 / (2 * A * B);
3113
3114         float dphi;
3115
3116         dphi = saacos((float)deler);
3117         if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
3118
3119         if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
3120         else t->fac += dphi;
3121
3122         final = t->fac;
3123         
3124         applyNDofInput(&t->ndof, &final);
3125
3126         snapGrid(t, &final);
3127
3128         t->imval[0] = mval[0];
3129         t->imval[1] = mval[1];
3130
3131         if (hasNumInput(&t->num)) {
3132                 char c[20];
3133
3134                 applyNumInput(&t->num, &final);
3135
3136                 outputNumInput(&(t->num), c);
3137
3138                 sprintf(str, "Tilt: %s %s", &c[0], t->proptext);
3139
3140                 final *= (float)(M_PI / 180.0);
3141         }
3142         else {
3143                 sprintf(str, "Tilt: %.2f %s", 180.0*final/M_PI, t->proptext);
3144         }
3145
3146         for(i = 0 ; i < t->total; i++, td++) {
3147                 if (td->flag & TD_NOACTION)
3148                         break;
3149
3150                 if (td->flag & TD_SKIP)
3151                         continue;
3152
3153                 if (td->val) {
3154                         *td->val = td->ival + final * td->factor;
3155                 }
3156         }
3157
3158         recalcData(t);
3159
3160         headerprint(str);
3161
3162         viewRedrawForce(t);
3163
3164         helpline (t, t->center);
3165
3166         return 1;
3167 }
3168
3169
3170 /* ******************** Curve Shrink/Fatten *************** */
3171
3172 int CurveShrinkFatten(TransInfo *t, short mval[2]) 
3173 {
3174         TransData *td = t->data;
3175         float ratio;
3176         int i;
3177         char str[50];