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