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