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