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