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