Pose Channels - changing settings in RNA updates them correctly again
[blender.git] / source / blender / editors / transform / transform.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <math.h>
34 #include <float.h>
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #ifndef WIN32
41 #include <unistd.h>
42 #else
43 #include <io.h>
44 #endif
45
46 #include "MEM_guardedalloc.h"
47
48 #include "DNA_armature_types.h"
49 #include "DNA_action_types.h"  /* for some special action-editor settings */
50 #include "DNA_constraint_types.h"
51 #include "DNA_ipo_types.h"              /* some silly ipo flag  */
52 #include "DNA_listBase.h"
53 #include "DNA_meshdata_types.h"
54 #include "DNA_mesh_types.h"
55 #include "DNA_object_types.h"
56 #include "DNA_scene_types.h"            /* PET modes                    */
57 #include "DNA_screen_types.h"   /* area dimensions              */
58 #include "DNA_texture_types.h"
59 #include "DNA_userdef_types.h"
60 #include "DNA_view3d_types.h"
61 #include "DNA_space_types.h"
62 #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->propsize*= 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->propsize*= 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->propsize*= 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->propsize*= 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, 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         short twmode= (t->spacetype==SPACE_VIEW3D)? ((View3D*)t->view)->twmode: V3D_MANIP_GLOBAL;
946
947         RNA_int_set(op->ptr, "mode", t->mode);
948         RNA_int_set(op->ptr, "options", t->options);
949         RNA_float_set_array(op->ptr, "values", t->values);
950
951         
952         RNA_int_set(op->ptr, "constraint_mode", t->con.mode);
953         RNA_int_set(op->ptr, "constraint_orientation", twmode);
954         RNA_float_set_array(op->ptr, "constraint_matrix", (float*)t->con.mtx);
955 }
956
957 void initTransform(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event)
958 {
959         int mode    = RNA_int_get(op->ptr, "mode");
960         int options = RNA_int_get(op->ptr, "options");
961
962         /* added initialize, for external calls to set stuff in TransInfo, like undo string */
963
964         t->state = TRANS_RUNNING;
965
966         t->options = options;
967         
968         t->mode = mode;
969
970         initTransInfo(C, t, event);                                     // internal data, mouse, vectors
971         
972         initTransformOrientation(C, t);
973
974         if(t->spacetype == SPACE_VIEW3D)
975         {
976                 RegionView3D *rv3d = t->ar->regiondata;
977                 //calc_manipulator_stats(curarea);
978                 Mat3CpyMat4(t->spacemtx, rv3d->twmat);
979                 Mat3Ortho(t->spacemtx);
980                 
981                 t->draw_handle = ED_region_draw_cb_activate(t->ar->type, drawTransform, t, REGION_DRAW_POST);
982         }
983         else if(t->spacetype == SPACE_IMAGE) {
984                 Mat3One(t->spacemtx);
985                 t->draw_handle = ED_region_draw_cb_activate(t->ar->type, drawTransform, t, REGION_DRAW_POST);
986         }
987         else
988                 Mat3One(t->spacemtx);
989
990         createTransData(C, t);                  // make TransData structs from selection
991
992         initSnapping(t); // Initialize snapping data AFTER mode flags
993
994         if (t->total == 0) {
995                 postTrans(t);
996                 return;
997         }
998
999         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
1000         /* EVIL2: we gave as argument also texture space context bit... was cleared */
1001         /* EVIL3: extend mode for animation editors also switches modes... but is best way to avoid duplicate code */
1002         mode = t->mode;
1003         
1004         calculatePropRatio(t);
1005         calculateCenter(t);
1006         
1007         initMouseInput(t, &t->mouse, t->center2d, t->imval);
1008
1009         switch (mode) {
1010         case TFM_TRANSLATION:
1011                 initTranslation(t);
1012                 break;
1013         case TFM_ROTATION:
1014                 initRotation(t);
1015                 break;
1016         case TFM_RESIZE:
1017                 initResize(t);
1018                 break;
1019         case TFM_TOSPHERE:
1020                 initToSphere(t);
1021                 break;
1022         case TFM_SHEAR:
1023                 initShear(t);
1024                 break;
1025         case TFM_WARP:
1026                 initWarp(t);
1027                 break;
1028         case TFM_SHRINKFATTEN:
1029                 initShrinkFatten(t);
1030                 break;
1031         case TFM_TILT:
1032                 initTilt(t);
1033                 break;
1034         case TFM_CURVE_SHRINKFATTEN:
1035                 initCurveShrinkFatten(t);
1036                 break;
1037         case TFM_TRACKBALL:
1038                 initTrackball(t);
1039                 break;
1040         case TFM_PUSHPULL:
1041                 initPushPull(t);
1042                 break;
1043         case TFM_CREASE:
1044                 initCrease(t);
1045                 break;
1046         case TFM_BONESIZE:
1047                 {       /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */
1048                         bArmature *arm= t->poseobj->data;
1049                         if(arm->drawtype==ARM_ENVELOPE)
1050                                 initBoneEnvelope(t);
1051                         else
1052                                 initBoneSize(t);
1053                 }
1054                 break;
1055         case TFM_BONE_ENVELOPE:
1056                 initBoneEnvelope(t);
1057                 break;
1058         case TFM_BONE_ROLL:
1059                 initBoneRoll(t);
1060                 break;
1061         case TFM_TIME_TRANSLATE:
1062                 initTimeTranslate(t);
1063                 break;
1064         case TFM_TIME_SLIDE:
1065                 initTimeSlide(t);
1066                 break;
1067         case TFM_TIME_SCALE:
1068                 initTimeScale(t);
1069                 break;
1070         case TFM_TIME_EXTEND: 
1071                 /* now that transdata has been made, do like for TFM_TIME_TRANSLATE (for most Animation
1072                  * Editors because they have only 1D transforms for time values) or TFM_TRANSLATION
1073                  * (for Graph Editor only since it uses 'standard' transforms to get 2D movement)
1074                  * depending on which editor this was called from 
1075                  */
1076                 if (t->spacetype == SPACE_IPO)
1077                         initTranslation(t);
1078                 else
1079                         initTimeTranslate(t);
1080                 break;
1081         case TFM_BAKE_TIME:
1082                 initBakeTime(t);
1083                 break;
1084         case TFM_MIRROR:
1085                 initMirror(t);
1086                 break;
1087         case TFM_BEVEL:
1088                 initBevel(t);
1089                 break;
1090         case TFM_BWEIGHT:
1091                 initBevelWeight(t);
1092                 break;
1093         case TFM_ALIGN:
1094                 initAlign(t);
1095                 break;
1096         }
1097         
1098         /* overwrite initial values if operator supplied a non-null vector */
1099         if (RNA_property_is_set(op->ptr, "values"))
1100         {
1101                 float values[4];
1102                 RNA_float_get_array(op->ptr, "values", values);
1103                 QUATCOPY(t->values, values);
1104         }
1105
1106         /* Constraint init from operator */
1107         {
1108                 t->con.mode = RNA_int_get(op->ptr, "constraint_mode");
1109                 
1110                 if (t->con.mode & CON_APPLY)
1111                 {
1112                         RNA_float_get_array(op->ptr, "constraint_matrix", (float*)t->spacemtx);
1113                         
1114                         setUserConstraint(t, t->con.mode, "%s");                
1115                 }
1116
1117         }
1118 }
1119
1120 void transformApply(bContext *C, TransInfo *t)
1121 {
1122         if (t->redraw)
1123         {
1124                 if (t->modifiers & MOD_CONSTRAINT_SELECT)
1125                         t->con.mode |= CON_SELECT;
1126
1127                 selectConstraint(t);
1128                 if (t->transform) {
1129                         t->transform(t, t->mval);  // calls recalcData()
1130                         viewRedrawForce(C, t);
1131                 }
1132                 t->redraw = 0;
1133         }
1134
1135         /* If auto confirm is on, break after one pass */               
1136         if (t->options & CTX_AUTOCONFIRM)
1137         {
1138                 t->state = TRANS_CONFIRM;
1139         }
1140
1141         if (BKE_ptcache_get_continue_physics())
1142         {
1143                 // TRANSFORM_FIX_ME
1144                 //do_screenhandlers(G.curscreen);
1145                 t->redraw = 1;
1146         }
1147 }
1148
1149 int transformEnd(bContext *C, TransInfo *t)
1150 {
1151         int exit_code = OPERATOR_RUNNING_MODAL;
1152         
1153         if (t->state != TRANS_RUNNING)
1154         {
1155                 /* handle restoring objects */
1156                 if(t->state == TRANS_CANCEL)
1157                 {
1158                         exit_code = OPERATOR_CANCELLED;
1159                         restoreTransObjects(t); // calls recalcData()
1160                 }
1161                 else
1162                 {
1163                         exit_code = OPERATOR_FINISHED;
1164                 }
1165                 
1166                 /* free data */
1167                 postTrans(t);
1168         
1169                 /* aftertrans does insert keyframes, and clears base flags, doesnt read transdata */
1170                 special_aftertrans_update(t);
1171         
1172                 /* send events out for redraws */
1173                 viewRedrawPost(t);
1174         
1175                 /*  Undo as last, certainly after special_trans_update! */
1176
1177                 if(t->state == TRANS_CANCEL) {
1178 //                      if(t->undostr) ED_undo_push(C, t->undostr);
1179                 }
1180                 else {
1181 //                      if(t->undostr) ED_undo_push(C, t->undostr);
1182 //                      else ED_undo_push(C, transform_to_undostr(t));
1183                 }
1184                 t->undostr= NULL;
1185
1186                 viewRedrawForce(C, t);
1187         }
1188         
1189         return exit_code;
1190 }
1191
1192 /* ************************** Manipulator init and main **************************** */
1193
1194 void initManipulator(int mode)
1195 {
1196 #if 0 // TRANSFORM_FIX_ME
1197         Trans.state = TRANS_RUNNING;
1198
1199         Trans.options = CTX_NONE;
1200         
1201         Trans.mode = mode;
1202         
1203         /* automatic switch to scaling bone envelopes */
1204         if(mode==TFM_RESIZE && t->obedit && t->obedit->type==OB_ARMATURE) {
1205                 bArmature *arm= t->obedit->data;
1206                 if(arm->drawtype==ARM_ENVELOPE)
1207                         mode= TFM_BONE_ENVELOPE;
1208         }
1209
1210         initTrans(&Trans);                                      // internal data, mouse, vectors
1211
1212         G.moving |= G_TRANSFORM_MANIP;          // signal to draw manipuls while transform
1213         createTransData(&Trans);                        // make TransData structs from selection
1214
1215         if (Trans.total == 0)
1216                 return;
1217
1218         initSnapping(&Trans); // Initialize snapping data AFTER mode flags
1219
1220         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
1221         /* EVIL2: we gave as argument also texture space context bit... was cleared */
1222         mode = Trans.mode;
1223         
1224         calculatePropRatio(&Trans);
1225         calculateCenter(&Trans);
1226
1227         switch (mode) {
1228         case TFM_TRANSLATION:
1229                 initTranslation(&Trans);
1230                 break;
1231         case TFM_ROTATION:
1232                 initRotation(&Trans);
1233                 break;
1234         case TFM_RESIZE:
1235                 initResize(&Trans);
1236                 break;
1237         case TFM_TRACKBALL:
1238                 initTrackball(&Trans);
1239                 break;
1240         }
1241
1242         Trans.flag |= T_USES_MANIPULATOR;
1243 #endif
1244 }
1245
1246 void ManipulatorTransform() 
1247 {
1248 #if 0 // TRANSFORM_FIX_ME
1249         int mouse_moved = 0;
1250         short pmval[2] = {0, 0}, mval[2], val;
1251         unsigned short event;
1252
1253         if (Trans.total == 0)
1254                 return;
1255
1256         Trans.redraw = 1; /* initial draw */
1257
1258         while (Trans.state == TRANS_RUNNING) {
1259                 
1260                 getmouseco_areawin(mval);
1261                 
1262                 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
1263                         Trans.redraw = 1;
1264                 }
1265                 if (Trans.redraw) {
1266                         pmval[0] = mval[0];
1267                         pmval[1] = mval[1];
1268
1269                         //selectConstraint(&Trans);  needed?
1270                         if (Trans.transform) {
1271                                 Trans.transform(&Trans, mval);
1272                         }
1273                         Trans.redraw = 0;
1274                 }
1275                 
1276                 /* essential for idling subloop */
1277                 if( qtest()==0) PIL_sleep_ms(2);
1278
1279                 while( qtest() ) {
1280                         event= extern_qread(&val);
1281
1282                         switch (event){
1283                         case MOUSEX:
1284                         case MOUSEY:
1285                                 mouse_moved = 1;
1286                                 break;
1287                         /* enforce redraw of transform when modifiers are used */
1288                         case LEFTCTRLKEY:
1289                         case RIGHTCTRLKEY:
1290                                 if(val) Trans.redraw = 1;
1291                                 break;
1292                         case LEFTSHIFTKEY:
1293                         case RIGHTSHIFTKEY:
1294                                 /* shift is modifier for higher resolution transform, works nice to store this mouse position */
1295                                 if(val) {
1296                                         getmouseco_areawin(Trans.shiftmval);
1297                                         Trans.flag |= T_SHIFT_MOD;
1298                                         Trans.redraw = 1;
1299                                 }
1300                                 else Trans.flag &= ~T_SHIFT_MOD; 
1301                                 break;
1302                                 
1303                         case ESCKEY:
1304                         case RIGHTMOUSE:
1305                                 Trans.state = TRANS_CANCEL;
1306                                 break;
1307                         case LEFTMOUSE:
1308                                 if(mouse_moved==0 && val==0) break;
1309                                 // else we pass on event to next, which cancels
1310                         case SPACEKEY:
1311                         case PADENTER:
1312                         case RETKEY:
1313                                 Trans.state = TRANS_CONFIRM;
1314                                 break;
1315    //         case NDOFMOTION:
1316      //           viewmoveNDOF(1);
1317      //           break;
1318                         }
1319                         if(val) {
1320                                 switch(event) {
1321                                 case PADPLUSKEY:
1322                                         if(G.qual & LR_ALTKEY && Trans.flag & T_PROP_EDIT) {
1323                                                 Trans.propsize*= 1.1f;
1324                                                 calculatePropRatio(&Trans);
1325                                         }
1326                                         Trans.redraw= 1;
1327                                         break;
1328                                 case PAGEUPKEY:
1329                                 case WHEELDOWNMOUSE:
1330                                         if (Trans.flag & T_AUTOIK) {
1331                                                 transform_autoik_update(&Trans, 1);
1332                                         }
1333                                         else if(Trans.flag & T_PROP_EDIT) {
1334                                                 Trans.propsize*= 1.1f;
1335                                                 calculatePropRatio(&Trans);
1336                                         }
1337                                         else view_editmove(event);
1338                                         Trans.redraw= 1;
1339                                         break;
1340                                 case PADMINUS:
1341                                         if(G.qual & LR_ALTKEY && Trans.flag & T_PROP_EDIT) {
1342                                                 Trans.propsize*= 0.90909090f;
1343                                                 calculatePropRatio(&Trans);
1344                                         }
1345                                         Trans.redraw= 1;
1346                                         break;
1347                                 case PAGEDOWNKEY:
1348                                 case WHEELUPMOUSE:
1349                                         if (Trans.flag & T_AUTOIK) {
1350                                                 transform_autoik_update(&Trans, -1);
1351                                         }
1352                                         else if (Trans.flag & T_PROP_EDIT) {
1353                                                 Trans.propsize*= 0.90909090f;
1354                                                 calculatePropRatio(&Trans);
1355                                         }
1356                                         else view_editmove(event);
1357                                         Trans.redraw= 1;
1358                                         break;
1359                                 }
1360                                                         
1361                                 // Numerical input events
1362                                 Trans.redraw |= handleNumInput(&(Trans.num), event);
1363                         }
1364                 }
1365         }
1366         
1367         if(Trans.state == TRANS_CANCEL) {
1368                 restoreTransObjects(&Trans);
1369         }
1370         
1371         /* free data, reset vars */
1372         postTrans(&Trans);
1373         
1374         /* aftertrans does insert ipos and action channels, and clears base flags */
1375         special_aftertrans_update(&Trans);
1376         
1377         /* send events out for redraws */
1378         viewRedrawPost(&Trans);
1379
1380         if(Trans.state != TRANS_CANCEL) {
1381                 BIF_undo_push(transform_to_undostr(&Trans));
1382         }
1383 #endif
1384 }
1385
1386 /* ************************** TRANSFORM LOCKS **************************** */
1387
1388 static void protectedTransBits(short protectflag, float *vec)
1389 {
1390         if(protectflag & OB_LOCK_LOCX)
1391                 vec[0]= 0.0f;
1392         if(protectflag & OB_LOCK_LOCY)
1393                 vec[1]= 0.0f;
1394         if(protectflag & OB_LOCK_LOCZ)
1395                 vec[2]= 0.0f;
1396 }
1397
1398 static void protectedSizeBits(short protectflag, float *size)
1399 {
1400         if(protectflag & OB_LOCK_SCALEX)
1401                 size[0]= 1.0f;
1402         if(protectflag & OB_LOCK_SCALEY)
1403                 size[1]= 1.0f;
1404         if(protectflag & OB_LOCK_SCALEZ)
1405                 size[2]= 1.0f;
1406 }
1407
1408 static void protectedRotateBits(short protectflag, float *eul, float *oldeul)
1409 {
1410         if(protectflag & OB_LOCK_ROTX)
1411                 eul[0]= oldeul[0];
1412         if(protectflag & OB_LOCK_ROTY)
1413                 eul[1]= oldeul[1];
1414         if(protectflag & OB_LOCK_ROTZ)
1415                 eul[2]= oldeul[2];
1416 }
1417
1418 static void protectedQuaternionBits(short protectflag, float *quat, float *oldquat)
1419 {
1420         /* quaternions get limited with euler... */
1421         /* this function only does the delta rotation */
1422         
1423         if(protectflag) {
1424                 float eul[3], oldeul[3], quat1[4];
1425                 
1426                 QUATCOPY(quat1, quat);
1427                 QuatToEul(quat, eul);
1428                 QuatToEul(oldquat, oldeul);
1429                 
1430                 if(protectflag & OB_LOCK_ROTX)
1431                         eul[0]= oldeul[0];
1432                 if(protectflag & OB_LOCK_ROTY)
1433                         eul[1]= oldeul[1];
1434                 if(protectflag & OB_LOCK_ROTZ)
1435                         eul[2]= oldeul[2];
1436                 
1437                 EulToQuat(eul, quat);
1438                 /* quaternions flip w sign to accumulate rotations correctly */
1439                 if( (quat1[0]<0.0f && quat[0]>0.0f) || (quat1[0]>0.0f && quat[0]<0.0f) ) {
1440                         QuatMulf(quat, -1.0f);
1441                 }
1442         }
1443 }
1444
1445 /* ******************* TRANSFORM LIMITS ********************** */
1446
1447 static void constraintTransLim(TransInfo *t, TransData *td)
1448 {
1449         if (td->con) {
1450                 bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT);
1451                 bConstraintOb cob;
1452                 bConstraint *con;
1453                 
1454                 /* Make a temporary bConstraintOb for using these limit constraints 
1455                  *      - they only care that cob->matrix is correctly set ;-)
1456                  *      - current space should be local
1457                  */
1458                 memset(&cob, 0, sizeof(bConstraintOb));
1459                 Mat4One(cob.matrix);
1460                 if (td->tdi) {
1461                         TransDataIpokey *tdi= td->tdi;
1462                         cob.matrix[3][0]= tdi->locx[0];
1463                         cob.matrix[3][1]= tdi->locy[0];
1464                         cob.matrix[3][2]= tdi->locz[0];
1465                 }
1466                 else {
1467                         VECCOPY(cob.matrix[3], td->loc);
1468                 }
1469                 
1470                 /* Evaluate valid constraints */
1471                 for (con= td->con; con; con= con->next) {
1472                         float tmat[4][4];
1473                         
1474                         /* only consider constraint if enabled */
1475                         if (con->flag & CONSTRAINT_DISABLE) continue;
1476                         if (con->enforce == 0.0f) continue;
1477                         
1478                         /* only use it if it's tagged for this purpose (and the right type) */
1479                         if (con->type == CONSTRAINT_TYPE_LOCLIMIT) {
1480                                 bLocLimitConstraint *data= con->data;
1481                                 
1482                                 if ((data->flag2 & LIMIT_TRANSFORM)==0) 
1483                                         continue;
1484                                 
1485                                 /* do space conversions */
1486                                 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1487                                         /* just multiply by td->mtx (this should be ok) */
1488                                         Mat4CpyMat4(tmat, cob.matrix);
1489                                         Mat4MulMat34(cob.matrix, td->mtx, tmat);
1490                                 }
1491                                 else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
1492                                         /* skip... incompatable spacetype */
1493                                         continue;
1494                                 }
1495                                 
1496                                 /* do constraint */
1497                                 cti->evaluate_constraint(con, &cob, NULL);
1498                                 
1499                                 /* convert spaces again */
1500                                 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1501                                         /* just multiply by td->mtx (this should be ok) */
1502                                         Mat4CpyMat4(tmat, cob.matrix);
1503                                         Mat4MulMat34(cob.matrix, td->smtx, tmat);
1504                                 }
1505                         }
1506                 }
1507                 
1508                 /* copy results from cob->matrix */
1509                 if (td->tdi) {
1510                         TransDataIpokey *tdi= td->tdi;
1511                         tdi->locx[0]= cob.matrix[3][0];
1512                         tdi->locy[0]= cob.matrix[3][1];
1513                         tdi->locz[0]= cob.matrix[3][2];
1514                 }
1515                 else {
1516                         VECCOPY(td->loc, cob.matrix[3]);
1517                 }
1518         }
1519 }
1520
1521 static void constraintRotLim(TransInfo *t, TransData *td)
1522 {
1523         if (td->con) {
1524                 bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_ROTLIMIT);
1525                 bConstraintOb cob;
1526                 bConstraint *con;
1527                 
1528                 /* Make a temporary bConstraintOb for using these limit constraints 
1529                  *      - they only care that cob->matrix is correctly set ;-)
1530                  *      - current space should be local
1531                  */
1532                 memset(&cob, 0, sizeof(bConstraintOb));
1533                 if (td->flag & TD_USEQUAT) {
1534                         /* quats */
1535                         if (td->ext)
1536                                 QuatToMat4(td->ext->quat, cob.matrix);
1537                         else
1538                                 return;
1539                 }
1540                 else if (td->tdi) {
1541                         /* ipo-keys eulers */
1542                         TransDataIpokey *tdi= td->tdi;
1543                         float eul[3];
1544                         
1545                         eul[0]= tdi->rotx[0];
1546                         eul[1]= tdi->roty[0];
1547                         eul[2]= tdi->rotz[0];
1548                         
1549                         EulToMat4(eul, cob.matrix);
1550                 }
1551                 else {
1552                         /* eulers */
1553                         if (td->ext)
1554                                 EulToMat4(td->ext->rot, cob.matrix);
1555                         else
1556                                 return;
1557                 }
1558                         
1559                 /* Evaluate valid constraints */
1560                 for (con= td->con; con; con= con->next) {
1561                         /* only consider constraint if enabled */
1562                         if (con->flag & CONSTRAINT_DISABLE) continue;
1563                         if (con->enforce == 0.0f) continue;
1564                         
1565                         /* we're only interested in Limit-Rotation constraints */
1566                         if (con->type == CONSTRAINT_TYPE_ROTLIMIT) {
1567                                 bRotLimitConstraint *data= con->data;
1568                                 float tmat[4][4];
1569                                 
1570                                 /* only use it if it's tagged for this purpose */
1571                                 if ((data->flag2 & LIMIT_TRANSFORM)==0) 
1572                                         continue;
1573                                         
1574                                 /* do space conversions */
1575                                 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1576                                         /* just multiply by td->mtx (this should be ok) */
1577                                         Mat4CpyMat4(tmat, cob.matrix);
1578                                         Mat4MulMat34(cob.matrix, td->mtx, tmat);
1579                                 }
1580                                 else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
1581                                         /* skip... incompatable spacetype */
1582                                         continue;
1583                                 }
1584                                 
1585                                 /* do constraint */
1586                                 cti->evaluate_constraint(con, &cob, NULL);
1587                                 
1588                                 /* convert spaces again */
1589                                 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1590                                         /* just multiply by td->mtx (this should be ok) */
1591                                         Mat4CpyMat4(tmat, cob.matrix);
1592                                         Mat4MulMat34(cob.matrix, td->smtx, tmat);
1593                                 }
1594                         }
1595                 }
1596                 
1597                 /* copy results from cob->matrix */
1598                 if (td->flag & TD_USEQUAT) {
1599                         /* quats */
1600                         Mat4ToQuat(cob.matrix, td->ext->quat);
1601                 }
1602                 else if (td->tdi) {
1603                         /* ipo-keys eulers */
1604                         TransDataIpokey *tdi= td->tdi;
1605                         float eul[3];
1606                         
1607                         Mat4ToEul(cob.matrix, eul);
1608                         
1609                         tdi->rotx[0]= eul[0];
1610                         tdi->roty[0]= eul[1];
1611                         tdi->rotz[0]= eul[2];
1612                 }
1613                 else {
1614                         /* eulers */
1615                         Mat4ToEul(cob.matrix, td->ext->rot);
1616                 }
1617         }
1618 }
1619
1620 static void constraintSizeLim(TransInfo *t, TransData *td)
1621 {
1622         if (td->con && td->ext) {
1623                 bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_SIZELIMIT);
1624                 bConstraintOb cob;
1625                 bConstraint *con;
1626                 
1627                 /* Make a temporary bConstraintOb for using these limit constraints 
1628                  *      - they only care that cob->matrix is correctly set ;-)
1629                  *      - current space should be local
1630                  */
1631                 memset(&cob, 0, sizeof(bConstraintOb));
1632                 if (td->tdi) {
1633                         TransDataIpokey *tdi= td->tdi;
1634                         float size[3];
1635                         
1636                         size[0]= tdi->sizex[0];
1637                         size[1]= tdi->sizey[0];
1638                         size[2]= tdi->sizez[0];
1639                         SizeToMat4(size, cob.matrix);
1640                 } 
1641                 else if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
1642                         /* scale val and reset size */
1643                         return; // TODO: fix this case
1644                 }
1645                 else {
1646                         /* Reset val if SINGLESIZE but using a constraint */
1647                         if (td->flag & TD_SINGLESIZE)
1648                                 return;
1649                         
1650                         SizeToMat4(td->ext->size, cob.matrix);
1651                 }
1652                         
1653                 /* Evaluate valid constraints */
1654                 for (con= td->con; con; con= con->next) {
1655                         /* only consider constraint if enabled */
1656                         if (con->flag & CONSTRAINT_DISABLE) continue;
1657                         if (con->enforce == 0.0f) continue;
1658                         
1659                         /* we're only interested in Limit-Scale constraints */
1660                         if (con->type == CONSTRAINT_TYPE_SIZELIMIT) {
1661                                 bSizeLimitConstraint *data= con->data;
1662                                 float tmat[4][4];
1663                                 
1664                                 /* only use it if it's tagged for this purpose */
1665                                 if ((data->flag2 & LIMIT_TRANSFORM)==0) 
1666                                         continue;
1667                                         
1668                                 /* do space conversions */
1669                                 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1670                                         /* just multiply by td->mtx (this should be ok) */
1671                                         Mat4CpyMat4(tmat, cob.matrix);
1672                                         Mat4MulMat34(cob.matrix, td->mtx, tmat);
1673                                 }
1674                                 else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
1675                                         /* skip... incompatable spacetype */
1676                                         continue;
1677                                 }
1678                                 
1679                                 /* do constraint */
1680                                 cti->evaluate_constraint(con, &cob, NULL);
1681                                 
1682                                 /* convert spaces again */
1683                                 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1684                                         /* just multiply by td->mtx (this should be ok) */
1685                                         Mat4CpyMat4(tmat, cob.matrix);
1686                                         Mat4MulMat34(cob.matrix, td->smtx, tmat);
1687                                 }
1688                         }
1689                 }
1690                 
1691                 /* copy results from cob->matrix */
1692                 if (td->tdi) {
1693                         TransDataIpokey *tdi= td->tdi;
1694                         float size[3];
1695                         
1696                         Mat4ToSize(cob.matrix, size);
1697                         
1698                         tdi->sizex[0]= size[0];
1699                         tdi->sizey[0]= size[1];
1700                         tdi->sizez[0]= size[2];
1701                 } 
1702                 else if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
1703                         /* scale val and reset size */
1704                         return; // TODO: fix this case
1705                 }
1706                 else {
1707                         /* Reset val if SINGLESIZE but using a constraint */
1708                         if (td->flag & TD_SINGLESIZE)
1709                                 return;
1710                                 
1711                         Mat4ToSize(cob.matrix, td->ext->size);
1712                 }
1713         }
1714 }
1715
1716 /* ************************** WARP *************************** */
1717
1718 void initWarp(TransInfo *t) 
1719 {
1720         float max[3], min[3];
1721         int i;
1722         
1723         t->mode = TFM_WARP;
1724         t->transform = Warp;
1725         t->handleEvent = handleEventWarp;
1726         
1727         initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO);
1728
1729         t->idx_max = 0;
1730         t->num.idx_max = 0;
1731         t->snap[0] = 0.0f;
1732         t->snap[1] = 5.0f;
1733         t->snap[2] = 1.0f;
1734         
1735         t->flag |= T_NO_CONSTRAINT;
1736
1737         /* we need min/max in view space */
1738         for(i = 0; i < t->total; i++) {
1739                 float center[3];
1740                 VECCOPY(center, t->data[i].center);
1741                 Mat3MulVecfl(t->data[i].mtx, center);
1742                 Mat4MulVecfl(t->viewmat, center);
1743                 VecSubf(center, center, t->viewmat[3]);
1744                 if (i)
1745                         MinMax3(min, max, center);
1746                 else {
1747                         VECCOPY(max, center);
1748                         VECCOPY(min, center);
1749                 }
1750         }
1751         
1752         t->center[0]= (min[0]+max[0])/2.0f;
1753         t->center[1]= (min[1]+max[1])/2.0f;
1754         t->center[2]= (min[2]+max[2])/2.0f;
1755         
1756         if (max[0] == min[0]) max[0] += 0.1; /* not optimal, but flipping is better than invalid garbage (i.e. division by zero!) */
1757         t->val= (max[0]-min[0])/2.0f; /* t->val is X dimension projected boundbox */
1758 }
1759
1760 int handleEventWarp(TransInfo *t, wmEvent *event)
1761 {
1762         int status = 0;
1763         
1764         if (event->type == MIDDLEMOUSE && event->val)
1765         {
1766                 // Use customData pointer to signal warp direction
1767                 if      (t->customData == 0)
1768                         t->customData = (void*)1;
1769                 else
1770                         t->customData = 0;
1771                         
1772                 status = 1;
1773         }
1774         
1775         return status;
1776 }
1777
1778 int Warp(TransInfo *t, short mval[2])
1779 {
1780         TransData *td = t->data;
1781         float vec[3], circumfac, dist, phi0, co, si, *curs, cursor[3], gcursor[3];
1782         int i;
1783         char str[50];
1784         
1785         curs= give_cursor(t->scene, t->view);
1786         /*
1787          * gcursor is the one used for helpline.
1788          * It has to be in the same space as the drawing loop
1789          * (that means it needs to be in the object's space when in edit mode and
1790          *  in global space in object mode)
1791          *
1792          * cursor is used for calculations.
1793          * It needs to be in view space, but we need to take object's offset
1794          * into account if in Edit mode.
1795          */
1796         VECCOPY(cursor, curs);
1797         VECCOPY(gcursor, cursor);       
1798         if (t->flag & T_EDIT) {
1799                 VecSubf(cursor, cursor, t->obedit->obmat[3]);
1800                 VecSubf(gcursor, gcursor, t->obedit->obmat[3]);
1801                 Mat3MulVecfl(t->data->smtx, gcursor);
1802         }
1803         Mat4MulVecfl(t->viewmat, cursor);
1804         VecSubf(cursor, cursor, t->viewmat[3]);
1805
1806         /* amount of degrees for warp */
1807         circumfac = 360.0f * t->values[0];
1808         
1809         if (t->customData) /* non-null value indicates reversed input */
1810         {
1811                 circumfac *= -1;
1812         }
1813
1814         snapGrid(t, &circumfac);
1815         applyNumInput(&t->num, &circumfac);
1816         
1817         /* header print for NumInput */
1818         if (hasNumInput(&t->num)) {
1819                 char c[20];
1820                 
1821                 outputNumInput(&(t->num), c);
1822                 
1823                 sprintf(str, "Warp: %s", c);
1824         }
1825         else {
1826                 /* default header print */
1827                 sprintf(str, "Warp: %.3f", circumfac);
1828         }
1829         
1830         circumfac*= (float)(-M_PI/360.0);
1831         
1832         for(i = 0; i < t->total; i++, td++) {
1833                 float loc[3];
1834                 if (td->flag & TD_NOACTION)
1835                         break;
1836
1837                 if (td->flag & TD_SKIP)
1838                         continue;
1839                 
1840                 /* translate point to center, rotate in such a way that outline==distance */
1841                 VECCOPY(vec, td->iloc);
1842                 Mat3MulVecfl(td->mtx, vec);
1843                 Mat4MulVecfl(t->viewmat, vec);
1844                 VecSubf(vec, vec, t->viewmat[3]);
1845                 
1846                 dist= vec[0]-cursor[0];
1847                 
1848                 /* t->val is X dimension projected boundbox */
1849                 phi0= (circumfac*dist/t->val);  
1850                 
1851                 vec[1]= (vec[1]-cursor[1]);
1852                 
1853                 co= (float)cos(phi0);
1854                 si= (float)sin(phi0);
1855                 loc[0]= -si*vec[1]+cursor[0];
1856                 loc[1]= co*vec[1]+cursor[1];
1857                 loc[2]= vec[2];
1858                 
1859                 Mat4MulVecfl(t->viewinv, loc);
1860                 VecSubf(loc, loc, t->viewinv[3]);
1861                 Mat3MulVecfl(td->smtx, loc);
1862                 
1863                 VecSubf(loc, loc, td->iloc);
1864                 VecMulf(loc, td->factor);
1865                 VecAddf(td->loc, td->iloc, loc);
1866         }
1867
1868         recalcData(t);
1869         
1870         ED_area_headerprint(t->sa, str);
1871         
1872         helpline(t, gcursor);
1873         
1874         return 1;
1875 }
1876
1877 /* ************************** SHEAR *************************** */
1878
1879 void initShear(TransInfo *t) 
1880 {
1881         t->mode = TFM_SHEAR;
1882         t->transform = Shear;
1883         t->handleEvent = handleEventShear;
1884         
1885         initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE);
1886         
1887         t->idx_max = 0;
1888         t->num.idx_max = 0;
1889         t->snap[0] = 0.0f;
1890         t->snap[1] = 0.1f;
1891         t->snap[2] = t->snap[1] * 0.1f;
1892         
1893         t->flag |= T_NO_CONSTRAINT;
1894 }
1895
1896 int handleEventShear(TransInfo *t, wmEvent *event)
1897 {
1898         int status = 0;
1899         
1900         if (event->type == MIDDLEMOUSE && event->val)
1901         {
1902                 // Use customData pointer to signal Shear direction
1903                 if      (t->customData == 0)
1904                 {
1905                         initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
1906                         t->customData = (void*)1;
1907                 }
1908                 else
1909                 {
1910                         initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE);
1911                         t->customData = 0;
1912                 }
1913                         
1914                 status = 1;
1915         }
1916         
1917         return status;
1918 }
1919
1920
1921 int Shear(TransInfo *t, short mval[2]) 
1922 {
1923         TransData *td = t->data;
1924         float vec[3];
1925         float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
1926         float value;
1927         int i;
1928         char str[50];
1929
1930         Mat3CpyMat4(persmat, t->viewmat);
1931         Mat3Inv(persinv, persmat);
1932
1933         value = 0.05f * t->values[0];
1934
1935         snapGrid(t, &value);
1936
1937         applyNumInput(&t->num, &value);
1938
1939         /* header print for NumInput */
1940         if (hasNumInput(&t->num)) {
1941                 char c[20];
1942
1943                 outputNumInput(&(t->num), c);
1944
1945                 sprintf(str, "Shear: %s %s", c, t->proptext);
1946         }
1947         else {
1948                 /* default header print */
1949                 sprintf(str, "Shear: %.3f %s", value, t->proptext);
1950         }
1951         
1952         Mat3One(smat);
1953         
1954         // Custom data signals shear direction
1955         if (t->customData == 0)
1956                 smat[1][0] = value;
1957         else
1958                 smat[0][1] = value;
1959         
1960         Mat3MulMat3(tmat, smat, persmat);
1961         Mat3MulMat3(totmat, persinv, tmat);
1962         
1963         for(i = 0 ; i < t->total; i++, td++) {
1964                 if (td->flag & TD_NOACTION)
1965                         break;
1966
1967                 if (td->flag & TD_SKIP)
1968                         continue;
1969
1970                 if (t->obedit) {
1971                         float mat3[3][3];
1972                         Mat3MulMat3(mat3, totmat, td->mtx);
1973                         Mat3MulMat3(tmat, td->smtx, mat3);
1974                 }
1975                 else {
1976                         Mat3CpyMat3(tmat, totmat);
1977                 }
1978                 VecSubf(vec, td->center, t->center);
1979
1980                 Mat3MulVecfl(tmat, vec);
1981
1982                 VecAddf(vec, vec, t->center);
1983                 VecSubf(vec, vec, td->center);
1984
1985                 VecMulf(vec, td->factor);
1986
1987                 VecAddf(td->loc, td->iloc, vec);
1988         }
1989
1990         recalcData(t);
1991
1992         ED_area_headerprint(t->sa, str);
1993
1994         helpline (t, t->center);
1995
1996         return 1;
1997 }
1998
1999 /* ************************** RESIZE *************************** */
2000
2001 void initResize(TransInfo *t) 
2002 {
2003         t->mode = TFM_RESIZE;
2004         t->transform = Resize;
2005         
2006         initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
2007         
2008         t->flag |= T_NULL_ONE;
2009         t->num.flag |= NUM_NULL_ONE;
2010         t->num.flag |= NUM_AFFECT_ALL;
2011         if (!t->obedit) {
2012                 t->flag |= T_NO_ZERO;
2013                 t->num.flag |= NUM_NO_ZERO;
2014         }
2015         
2016         t->idx_max = 2;
2017         t->num.idx_max = 2;
2018         t->snap[0] = 0.0f;
2019         t->snap[1] = 0.1f;
2020         t->snap[2] = t->snap[1] * 0.1f;
2021 }
2022
2023 static void headerResize(TransInfo *t, float vec[3], char *str) {
2024         char tvec[60];
2025         if (hasNumInput(&t->num)) {
2026                 outputNumInput(&(t->num), tvec);
2027         }
2028         else {
2029                 sprintf(&tvec[0], "%.4f", vec[0]);
2030                 sprintf(&tvec[20], "%.4f", vec[1]);
2031                 sprintf(&tvec[40], "%.4f", vec[2]);
2032         }
2033
2034         if (t->con.mode & CON_APPLY) {
2035                 switch(t->num.idx_max) {
2036                 case 0:
2037                         sprintf(str, "Scale: %s%s %s", &tvec[0], t->con.text, t->proptext);
2038                         break;
2039                 case 1:
2040                         sprintf(str, "Scale: %s : %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
2041                         break;
2042                 case 2:
2043                         sprintf(str, "Scale: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
2044                 }
2045         }
2046         else {
2047                 if (t->flag & T_2D_EDIT)
2048                         sprintf(str, "Scale X: %s   Y: %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
2049                 else
2050                         sprintf(str, "Scale X: %s   Y: %s  Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
2051         }
2052 }
2053
2054 #define SIGN(a)         (a<-FLT_EPSILON?1:a>FLT_EPSILON?2:3)
2055 #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)
2056
2057 /* smat is reference matrix, only scaled */
2058 static void TransMat3ToSize( float mat[][3], float smat[][3], float *size)
2059 {
2060         float vec[3];
2061         
2062         VecCopyf(vec, mat[0]);
2063         size[0]= Normalize(vec);
2064         VecCopyf(vec, mat[1]);
2065         size[1]= Normalize(vec);
2066         VecCopyf(vec, mat[2]);
2067         size[2]= Normalize(vec);
2068         
2069         /* first tried with dotproduct... but the sign flip is crucial */
2070         if( VECSIGNFLIP(mat[0], smat[0]) ) size[0]= -size[0]; 
2071         if( VECSIGNFLIP(mat[1], smat[1]) ) size[1]= -size[1]; 
2072         if( VECSIGNFLIP(mat[2], smat[2]) ) size[2]= -size[2]; 
2073 }
2074
2075
2076 static void ElementResize(TransInfo *t, TransData *td, float mat[3][3]) {
2077         float tmat[3][3], smat[3][3], center[3];
2078         float vec[3];
2079
2080         if (t->flag & T_EDIT) {
2081                 Mat3MulMat3(smat, mat, td->mtx);
2082                 Mat3MulMat3(tmat, td->smtx, smat);
2083         }
2084         else {
2085                 Mat3CpyMat3(tmat, mat);
2086         }
2087
2088         if (t->con.applySize) {
2089                 t->con.applySize(t, td, tmat);
2090         }
2091
2092         /* local constraint shouldn't alter center */
2093         if (t->around == V3D_LOCAL) {
2094                 if (t->flag & T_OBJECT) {
2095                         VECCOPY(center, td->center);
2096                 }
2097                 else if (t->flag & T_EDIT) {
2098                         
2099                         if(t->around==V3D_LOCAL && (t->scene->selectmode & SCE_SELECT_FACE)) {
2100                                 VECCOPY(center, td->center);
2101                         }
2102                         else {
2103                                 VECCOPY(center, t->center);
2104                         }
2105                 }
2106                 else {
2107                         VECCOPY(center, t->center);
2108                 }
2109         }
2110         else {
2111                 VECCOPY(center, t->center);
2112         }
2113
2114         if (td->ext) {
2115                 float fsize[3];
2116                 
2117                 if (t->flag & (T_OBJECT|T_TEXTURE|T_POSE)) {
2118                         float obsizemat[3][3];
2119                         // Reorient the size mat to fit the oriented object.
2120                         Mat3MulMat3(obsizemat, tmat, td->axismtx);
2121                         //printmatrix3("obsizemat", obsizemat);
2122                         TransMat3ToSize(obsizemat, td->axismtx, fsize);
2123                         //printvecf("fsize", fsize);
2124                 }
2125                 else {
2126                         Mat3ToSize(tmat, fsize);
2127                 }
2128                 
2129                 protectedSizeBits(td->protectflag, fsize);
2130                 
2131                 if ((t->flag & T_V3D_ALIGN)==0) {       // align mode doesn't resize objects itself
2132                         /* handle ipokeys? */
2133                         if(td->tdi) {
2134                                 TransDataIpokey *tdi= td->tdi;
2135                                 /* calculate delta size (equal for size and dsize) */
2136                                 
2137                                 vec[0]= (tdi->oldsize[0])*(fsize[0] -1.0f) * td->factor;
2138                                 vec[1]= (tdi->oldsize[1])*(fsize[1] -1.0f) * td->factor;
2139                                 vec[2]= (tdi->oldsize[2])*(fsize[2] -1.0f) * td->factor;
2140                                 
2141                                 add_tdi_poin(tdi->sizex, tdi->oldsize,   vec[0]);
2142                                 add_tdi_poin(tdi->sizey, tdi->oldsize+1, vec[1]);
2143                                 add_tdi_poin(tdi->sizez, tdi->oldsize+2, vec[2]);
2144                                 
2145                         } 
2146                         else if((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)){
2147                                 /* scale val and reset size */
2148                                 *td->val = td->ival * fsize[0] * td->factor;
2149                                 
2150                                 td->ext->size[0] = td->ext->isize[0];
2151                                 td->ext->size[1] = td->ext->isize[1];
2152                                 td->ext->size[2] = td->ext->isize[2];
2153                         }
2154                         else {
2155                                 /* Reset val if SINGLESIZE but using a constraint */
2156                                 if (td->flag & TD_SINGLESIZE)
2157                                         *td->val = td->ival;
2158                                 
2159                                 td->ext->size[0] = td->ext->isize[0] * (fsize[0]) * td->factor;
2160                                 td->ext->size[1] = td->ext->isize[1] * (fsize[1]) * td->factor;
2161                                 td->ext->size[2] = td->ext->isize[2] * (fsize[2]) * td->factor;
2162                         }
2163                 }
2164                 
2165                 constraintSizeLim(t, td);
2166         }
2167         
2168         /* For individual element center, Editmode need to use iloc */
2169         if (t->flag & T_POINTS)
2170                 VecSubf(vec, td->iloc, center);
2171         else
2172                 VecSubf(vec, td->center, center);
2173
2174         Mat3MulVecfl(tmat, vec);
2175
2176         VecAddf(vec, vec, center);
2177         if (t->flag & T_POINTS)
2178                 VecSubf(vec, vec, td->iloc);
2179         else
2180                 VecSubf(vec, vec, td->center);
2181
2182         VecMulf(vec, td->factor);
2183
2184         if (t->flag & (T_OBJECT|T_POSE)) {
2185                 Mat3MulVecfl(td->smtx, vec);
2186         }
2187
2188         protectedTransBits(td->protectflag, vec);
2189
2190         if(td->tdi) {
2191                 TransDataIpokey *tdi= td->tdi;
2192                 add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
2193                 add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
2194                 add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
2195         }
2196         else VecAddf(td->loc, td->iloc, vec);
2197         
2198         constraintTransLim(t, td);
2199 }
2200
2201 int Resize(TransInfo *t, short mval[2]) 
2202 {
2203         TransData *td;
2204         float size[3], mat[3][3];
2205         float ratio;
2206         int i;
2207         char str[200];
2208
2209         /* for manipulator, center handle, the scaling can't be done relative to center */
2210         if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0)
2211         {
2212                 ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f;
2213         }
2214         else
2215         {
2216                 ratio = t->values[0];
2217         }
2218         
2219         size[0] = size[1] = size[2] = ratio;
2220
2221         snapGrid(t, size);
2222
2223         if (hasNumInput(&t->num)) {
2224                 applyNumInput(&t->num, size);
2225                 constraintNumInput(t, size);
2226         }
2227
2228         applySnapping(t, size);
2229
2230         SizeToMat3(size, mat);
2231
2232         if (t->con.applySize) {
2233                 t->con.applySize(t, NULL, mat);
2234         }
2235
2236         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2237         
2238         headerResize(t, size, str);
2239
2240         for(i = 0, td=t->data; i < t->total; i++, td++) {
2241                 if (td->flag & TD_NOACTION)
2242                         break;
2243
2244                 if (td->flag & TD_SKIP)
2245                         continue;
2246                 
2247                 ElementResize(t, td, mat);
2248         }
2249
2250         /* evil hack - redo resize if cliping needed */
2251         if (t->flag & T_CLIP_UV && clipUVTransform(t, size, 1)) {
2252                 SizeToMat3(size, mat);
2253
2254                 if (t->con.applySize)
2255                         t->con.applySize(t, NULL, mat);
2256
2257                 for(i = 0, td=t->data; i < t->total; i++, td++)
2258                         ElementResize(t, td, mat);
2259         }
2260
2261         recalcData(t);
2262
2263         ED_area_headerprint(t->sa, str);
2264
2265         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
2266
2267         return 1;
2268 }
2269
2270 /* ************************** TOSPHERE *************************** */
2271
2272 void initToSphere(TransInfo *t) 
2273 {
2274         TransData *td = t->data;
2275         int i;
2276
2277         t->mode = TFM_TOSPHERE;
2278         t->transform = ToSphere;
2279         
2280         initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO);
2281
2282         t->idx_max = 0;
2283         t->num.idx_max = 0;
2284         t->snap[0] = 0.0f;
2285         t->snap[1] = 0.1f;
2286         t->snap[2] = t->snap[1] * 0.1f;
2287         
2288         t->num.flag |= NUM_NULL_ONE | NUM_NO_NEGATIVE;
2289         t->flag |= T_NO_CONSTRAINT;
2290
2291         // Calculate average radius
2292         for(i = 0 ; i < t->total; i++, td++) {
2293                 t->val += VecLenf(t->center, td->iloc);
2294         }
2295
2296         t->val /= (float)t->total;
2297 }
2298
2299 int ToSphere(TransInfo *t, short mval[2]) 
2300 {
2301         float vec[3];
2302         float ratio, radius;
2303         int i;
2304         char str[64];
2305         TransData *td = t->data;
2306
2307         ratio = t->values[0];
2308
2309         snapGrid(t, &ratio);
2310
2311         applyNumInput(&t->num, &ratio);
2312
2313         if (ratio < 0)
2314                 ratio = 0.0f;
2315         else if (ratio > 1)
2316                 ratio = 1.0f;
2317
2318         /* header print for NumInput */
2319         if (hasNumInput(&t->num)) {
2320                 char c[20];
2321
2322                 outputNumInput(&(t->num), c);
2323
2324                 sprintf(str, "To Sphere: %s %s", c, t->proptext);
2325         }
2326         else {
2327                 /* default header print */
2328                 sprintf(str, "To Sphere: %.4f %s", ratio, t->proptext);
2329         }
2330         
2331         
2332         for(i = 0 ; i < t->total; i++, td++) {
2333                 float tratio;
2334                 if (td->flag & TD_NOACTION)
2335                         break;
2336
2337                 if (td->flag & TD_SKIP)
2338                         continue;
2339
2340                 VecSubf(vec, td->iloc, t->center);
2341
2342                 radius = Normalize(vec);
2343
2344                 tratio = ratio * td->factor;
2345
2346                 VecMulf(vec, radius * (1.0f - tratio) + t->val * tratio);
2347
2348                 VecAddf(td->loc, t->center, vec);
2349         }
2350         
2351
2352         recalcData(t);
2353
2354         ED_area_headerprint(t->sa, str);
2355
2356         return 1;
2357 }
2358
2359 /* ************************** ROTATION *************************** */
2360
2361
2362 void initRotation(TransInfo *t) 
2363 {
2364         t->mode = TFM_ROTATION;
2365         t->transform = Rotation;
2366         
2367         initMouseInputMode(t, &t->mouse, INPUT_ANGLE);
2368         
2369         t->ndof.axis = 16;
2370         /* Scale down and flip input for rotation */
2371         t->ndof.factor[0] = -0.2f;
2372         
2373         t->idx_max = 0;
2374         t->num.idx_max = 0;
2375         t->snap[0] = 0.0f;
2376         t->snap[1] = (float)((5.0/180)*M_PI);
2377         t->snap[2] = t->snap[1] * 0.2f;
2378         
2379         if (t->flag & T_2D_EDIT)
2380                 t->flag |= T_NO_CONSTRAINT;
2381 }
2382
2383 static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short around) {
2384         float vec[3], totmat[3][3], smat[3][3];
2385         float eul[3], fmat[3][3], quat[4];
2386         float *center = t->center;
2387         
2388         /* local constraint shouldn't alter center */
2389         if (around == V3D_LOCAL) {
2390                 if (t->flag & (T_OBJECT|T_POSE)) {
2391                         center = td->center;
2392                 }
2393                 else {
2394                         /* !TODO! Make this if not rely on G */
2395                         if(around==V3D_LOCAL && (t->scene->selectmode & SCE_SELECT_FACE)) {
2396                                 center = td->center;
2397                         }
2398                 }
2399         }
2400                 
2401         if (t->flag & T_POINTS) {
2402                 Mat3MulMat3(totmat, mat, td->mtx);
2403                 Mat3MulMat3(smat, td->smtx, totmat);
2404                 
2405                 VecSubf(vec, td->iloc, center);
2406                 Mat3MulVecfl(smat, vec);
2407                 
2408                 VecAddf(td->loc, vec, center);
2409
2410                 VecSubf(vec,td->loc,td->iloc);
2411                 protectedTransBits(td->protectflag, vec);
2412                 VecAddf(td->loc, td->iloc, vec);
2413
2414                 if(td->flag & TD_USEQUAT) {
2415                         Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
2416                         Mat3ToQuat(fmat, quat); // Actual transform
2417                         
2418                         if(td->ext->quat){
2419                                 QuatMul(td->ext->quat, quat, td->ext->iquat);
2420                                 
2421                                 /* is there a reason not to have this here? -jahka */
2422                                 protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
2423                         }
2424                 }
2425         }
2426         /**
2427          * HACK WARNING
2428          * 
2429          * This is some VERY ugly special case to deal with pose mode.
2430          * 
2431          * The problem is that mtx and smtx include each bone orientation.
2432          * 
2433          * That is needed to rotate each bone properly, HOWEVER, to calculate
2434          * the translation component, we only need the actual armature object's
2435          * matrix (and inverse). That is not all though. Once the proper translation
2436          * has been computed, it has to be converted back into the bone's space.
2437          */
2438         else if (t->flag & T_POSE) {
2439                 float pmtx[3][3], imtx[3][3];
2440
2441                 // Extract and invert armature object matrix            
2442                 Mat3CpyMat4(pmtx, t->poseobj->obmat);
2443                 Mat3Inv(imtx, pmtx);
2444                 
2445                 if ((td->flag & TD_NO_LOC) == 0)
2446                 {
2447                         VecSubf(vec, td->center, center);
2448                         
2449                         Mat3MulVecfl(pmtx, vec);        // To Global space
2450                         Mat3MulVecfl(mat, vec);         // Applying rotation
2451                         Mat3MulVecfl(imtx, vec);        // To Local space
2452                         
2453                         VecAddf(vec, vec, center);
2454                         /* vec now is the location where the object has to be */
2455                         
2456                         VecSubf(vec, vec, td->center); // Translation needed from the initial location
2457                         
2458                         Mat3MulVecfl(pmtx, vec);        // To Global space
2459                         Mat3MulVecfl(td->smtx, vec);// To Pose space
2460                                 
2461                         protectedTransBits(td->protectflag, vec);
2462                         
2463                         VecAddf(td->loc, td->iloc, vec);
2464                         
2465                         constraintTransLim(t, td);
2466                 }
2467                 
2468                 /* rotation */
2469                 if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
2470                         /* euler or quaternion? */
2471                         if (td->flag & TD_USEQUAT) {
2472                                 Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
2473                                 
2474                                 Mat3ToQuat(fmat, quat); // Actual transform
2475                                 
2476                                 QuatMul(td->ext->quat, quat, td->ext->iquat);
2477                                 /* this function works on end result */
2478                                 protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
2479                         }
2480                         else {
2481                                 float eulmat[3][3];
2482                                 
2483                                 Mat3MulMat3(totmat, mat, td->mtx);
2484                                 Mat3MulMat3(smat, td->smtx, totmat);
2485                                 
2486                                 /* calculate the total rotatation in eulers */
2487                                 VECCOPY(eul, td->ext->irot);
2488                                 EulToMat3(eul, eulmat);
2489                                 
2490                                 /* mat = transform, obmat = bone rotation */
2491                                 Mat3MulMat3(fmat, smat, eulmat);
2492                                 
2493                                 Mat3ToCompatibleEul(fmat, eul, td->ext->rot);
2494                                 
2495                                 /* and apply (to end result only) */
2496                                 protectedRotateBits(td->protectflag, eul, td->ext->irot);
2497                                 VECCOPY(td->ext->rot, eul);
2498                         }
2499                         
2500                         constraintRotLim(t, td);
2501                 }
2502         }
2503         else {
2504                 if ((td->flag & TD_NO_LOC) == 0)
2505                 {
2506                         /* translation */
2507                         VecSubf(vec, td->center, center);
2508                         Mat3MulVecfl(mat, vec);
2509                         VecAddf(vec, vec, center);
2510                         /* vec now is the location where the object has to be */
2511                         VecSubf(vec, vec, td->center);
2512                         Mat3MulVecfl(td->smtx, vec);
2513                         
2514                         protectedTransBits(td->protectflag, vec);
2515                         
2516                         if(td->tdi) {
2517                                 TransDataIpokey *tdi= td->tdi;
2518                                 add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
2519                                 add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
2520                                 add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
2521                         }
2522                         else VecAddf(td->loc, td->iloc, vec);
2523                 }
2524                 
2525                 
2526                 constraintTransLim(t, td);
2527
2528                 /* rotation */
2529                 if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
2530                         /* euler or quaternion? */
2531                     if (td->flag & TD_USEQUAT) {
2532                                 Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
2533                                 Mat3ToQuat(fmat, quat); // Actual transform
2534                                 
2535                                 QuatMul(td->ext->quat, quat, td->ext->iquat);
2536                                 /* this function works on end result */
2537                                 protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
2538                         }
2539                         else {
2540                                 float obmat[3][3];
2541                                 
2542                                 /* are there ipo keys? */
2543                                 if(td->tdi) {
2544                                         TransDataIpokey *tdi= td->tdi;
2545                                         float current_rot[3];
2546                                         float rot[3];
2547                                         
2548                                         /* current IPO value for compatible euler */
2549                                         current_rot[0] = (tdi->rotx) ? tdi->rotx[0] : 0.0f;
2550                                         current_rot[1] = (tdi->roty) ? tdi->roty[0] : 0.0f;
2551                                         current_rot[2] = (tdi->rotz) ? tdi->rotz[0] : 0.0f;
2552                                         VecMulf(current_rot, (float)(M_PI_2 / 9.0));
2553                                         
2554                                         /* calculate the total rotatation in eulers */
2555                                         VecAddf(eul, td->ext->irot, td->ext->drot);
2556                                         EulToMat3(eul, obmat);
2557                                         /* mat = transform, obmat = object rotation */
2558                                         Mat3MulMat3(fmat, mat, obmat);
2559                                         
2560                                         Mat3ToCompatibleEul(fmat, eul, current_rot);
2561                                         
2562                                         /* correct back for delta rot */
2563                                         if(tdi->flag & TOB_IPODROT) {
2564                                                 VecSubf(rot, eul, td->ext->irot);
2565                                         }
2566                                         else {
2567                                                 VecSubf(rot, eul, td->ext->drot);
2568                                         }
2569                                         
2570                                         VecMulf(rot, (float)(9.0/M_PI_2));
2571                                         VecSubf(rot, rot, tdi->oldrot);
2572                                         
2573                                         protectedRotateBits(td->protectflag, rot, tdi->oldrot);
2574                                         
2575                                         add_tdi_poin(tdi->rotx, tdi->oldrot, rot[0]);
2576                                         add_tdi_poin(tdi->roty, tdi->oldrot+1, rot[1]);
2577                                         add_tdi_poin(tdi->rotz, tdi->oldrot+2, rot[2]);
2578                                 }
2579                                 else {
2580                                         Mat3MulMat3(totmat, mat, td->mtx);
2581                                         Mat3MulMat3(smat, td->smtx, totmat);
2582                                         
2583                                         /* calculate the total rotatation in eulers */
2584                                         VecAddf(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
2585                                         EulToMat3(eul, obmat);
2586                                         /* mat = transform, obmat = object rotation */
2587                                         Mat3MulMat3(fmat, smat, obmat);
2588                                         
2589                                         Mat3ToCompatibleEul(fmat, eul, td->ext->rot);
2590                                         
2591                                         /* correct back for delta rot */
2592                                         VecSubf(eul, eul, td->ext->drot);
2593                                         
2594                                         /* and apply */
2595                                         protectedRotateBits(td->protectflag, eul, td->ext->irot);
2596                                         VECCOPY(td->ext->rot, eul);
2597                                 }
2598                         }
2599                         
2600                         constraintRotLim(t, td);
2601                 }
2602         }
2603 }
2604
2605 static void applyRotation(TransInfo *t, float angle, float axis[3]) 
2606 {
2607         TransData *td = t->data;
2608         float mat[3][3];
2609         int i;
2610
2611         VecRotToMat3(axis, angle, mat);
2612         
2613         for(i = 0 ; i < t->total; i++, td++) {
2614
2615                 if (td->flag & TD_NOACTION)
2616                         break;
2617
2618                 if (td->flag & TD_SKIP)
2619                         continue;
2620                 
2621                 if (t->con.applyRot) {
2622                         t->con.applyRot(t, td, axis, NULL);
2623                         VecRotToMat3(axis, angle * td->factor, mat);
2624                 }
2625                 else if (t->flag & T_PROP_EDIT) {
2626                         VecRotToMat3(axis, angle * td->factor, mat);
2627                 }
2628
2629                 ElementRotation(t, td, mat, t->around);
2630         }
2631 }
2632
2633 int Rotation(TransInfo *t, short mval[2]) 
2634 {
2635         char str[64];
2636
2637         float final;
2638
2639         float axis[3];
2640         float mat[3][3];
2641
2642         VECCOPY(axis, t->viewinv[2]);
2643         VecMulf(axis, -1.0f);
2644         Normalize(axis);
2645
2646         final = t->values[0];
2647
2648         applyNDofInput(&t->ndof, &final);
2649         
2650         snapGrid(t, &final);
2651
2652         if (t->con.applyRot) {
2653                 t->con.applyRot(t, NULL, axis, &final);
2654         }
2655         
2656         applySnapping(t, &final);
2657
2658         if (hasNumInput(&t->num)) {
2659                 char c[20];
2660
2661                 applyNumInput(&t->num, &final);
2662
2663                 outputNumInput(&(t->num), c);
2664
2665                 sprintf(str, "Rot: %s %s %s", &c[0], t->con.text, t->proptext);
2666
2667                 /* Clamp between -180 and 180 */
2668                 while (final >= 180.0)
2669                         final -= 360.0;
2670                 
2671                 while (final <= -180.0)
2672                         final += 360.0;
2673
2674                 final *= (float)(M_PI / 180.0);
2675         }
2676         else {
2677                 sprintf(str, "Rot: %.2f%s %s", 180.0*final/M_PI, t->con.text, t->proptext);
2678         }
2679
2680         VecRotToMat3(axis, final, mat);
2681
2682         // TRANSFORM_FIX_ME
2683 //      t->values[0] = final;           // used in manipulator
2684 //      Mat3CpyMat3(t->mat, mat);       // used in manipulator
2685         
2686         applyRotation(t, final, axis);
2687         
2688         recalcData(t);
2689
2690         ED_area_headerprint(t->sa, str);
2691
2692         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
2693
2694         return 1;
2695 }
2696
2697
2698 /* ************************** TRACKBALL *************************** */
2699
2700 void initTrackball(TransInfo *t) 
2701 {
2702         t->mode = TFM_TRACKBALL;
2703         t->transform = Trackball;
2704         
2705         initMouseInputMode(t, &t->mouse, INPUT_TRACKBALL);
2706         
2707         t->ndof.axis = 40;
2708         /* Scale down input for rotation */
2709         t->ndof.factor[0] = 0.2f;
2710         t->ndof.factor[1] = 0.2f;
2711
2712         t->idx_max = 1;
2713         t->num.idx_max = 1;
2714         t->snap[0] = 0.0f;
2715         t->snap[1] = (float)((5.0/180)*M_PI);
2716         t->snap[2] = t->snap[1] * 0.2f;
2717         
2718         t->flag |= T_NO_CONSTRAINT;
2719 }
2720
2721 static void applyTrackball(TransInfo *t, float axis1[3], float axis2[3], float angles[2])
2722 {
2723         TransData *td = t->data;
2724         float mat[3][3], smat[3][3], totmat[3][3];
2725         int i;
2726
2727         VecRotToMat3(axis1, angles[0], smat);
2728         VecRotToMat3(axis2, angles[1], totmat);
2729         
2730         Mat3MulMat3(mat, smat, totmat);
2731
2732         for(i = 0 ; i < t->total; i++, td++) {
2733                 if (td->flag & TD_NOACTION)
2734                         break;
2735
2736                 if (td->flag & TD_SKIP)
2737                         continue;
2738                 
2739                 if (t->flag & T_PROP_EDIT) {
2740                         VecRotToMat3(axis1, td->factor * angles[0], smat);
2741                         VecRotToMat3(axis2, td->factor * angles[1], totmat);
2742                         
2743                         Mat3MulMat3(mat, smat, totmat);
2744                 }
2745                 
2746                 ElementRotation(t, td, mat, t->around);
2747         }
2748 }
2749
2750 int Trackball(TransInfo *t, short mval[2]) 
2751 {
2752         char str[128];
2753         float axis1[3], axis2[3];
2754         float mat[3][3], totmat[3][3], smat[3][3];
2755         float phi[2];
2756         
2757         VECCOPY(axis1, t->persinv[0]);
2758         VECCOPY(axis2, t->persinv[1]);
2759         Normalize(axis1);
2760         Normalize(axis2);
2761         
2762         phi[0] = t->values[0];
2763         phi[1] = t->values[1];
2764                 
2765         applyNDofInput(&t->ndof, phi);
2766         
2767         snapGrid(t, phi);
2768         
2769         if (hasNumInput(&t->num)) {
2770                 char c[40];
2771                 
2772                 applyNumInput(&t->num, phi);
2773                 
2774                 outputNumInput(&(t->num), c);
2775                 
2776                 sprintf(str, "Trackball: %s %s %s", &c[0], &c[20], t->proptext);
2777                 
2778                 phi[0] *= (float)(M_PI / 180.0);
2779                 phi[1] *= (float)(M_PI / 180.0);
2780         }
2781         else {
2782                 sprintf(str, "Trackball: %.2f %.2f %s", 180.0*phi[0]/M_PI, 180.0*phi[1]/M_PI, t->proptext);
2783         }
2784
2785         VecRotToMat3(axis1, phi[0], smat);
2786         VecRotToMat3(axis2, phi[1], totmat);
2787         
2788         Mat3MulMat3(mat, smat, totmat);
2789         
2790         // TRANSFORM_FIX_ME
2791         //Mat3CpyMat3(t->mat, mat);     // used in manipulator
2792         
2793         applyTrackball(t, axis1, axis2, phi);
2794         
2795         recalcData(t);
2796         
2797         ED_area_headerprint(t->sa, str);
2798         
2799         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
2800         
2801         return 1;
2802 }
2803
2804 /* ************************** TRANSLATION *************************** */
2805         
2806 void initTranslation(TransInfo *t) 
2807 {
2808         t->mode = TFM_TRANSLATION;
2809         t->transform = Translation;
2810         
2811         initMouseInputMode(t, &t->mouse, INPUT_VECTOR);
2812
2813         t->idx_max = (t->flag & T_2D_EDIT)? 1: 2;
2814         t->num.flag = 0;
2815         t->num.idx_max = t->idx_max;
2816         
2817         t->ndof.axis = (t->flag & T_2D_EDIT)? 1|2: 1|2|4;
2818
2819         if(t->spacetype == SPACE_VIEW3D) {
2820                 View3D *v3d = t->view;
2821
2822                 t->snap[0] = 0.0f;
2823                 t->snap[1] = v3d->gridview * 1.0f;
2824                 t->snap[2] = t->snap[1] * 0.1f;
2825         }
2826         else if(t->spacetype == SPACE_IMAGE) {
2827                 t->snap[0] = 0.0f;
2828                 t->snap[1] = 0.125f;
2829                 t->snap[2] = 0.0625f;
2830         }
2831         else {
2832                 t->snap[0] = 0.0f;
2833                 t->snap[1] = t->snap[2] = 1.0f;
2834         }
2835 }
2836
2837 static void headerTranslation(TransInfo *t, float vec[3], char *str) {
2838         char tvec[60];
2839         char distvec[20];
2840         char autoik[20];
2841         float dist;
2842         
2843         if (hasNumInput(&t->num)) {
2844                 outputNumInput(&(t->num), tvec);
2845                 dist = VecLength(t->num.val);
2846         }
2847         else {
2848                 float dvec[3];
2849
2850                 VECCOPY(dvec, vec);
2851                 applyAspectRatio(t, dvec);
2852
2853                 dist = VecLength(vec);
2854                 sprintf(&tvec[0], "%.4f", dvec[0]);
2855                 sprintf(&tvec[20], "%.4f", dvec[1]);
2856                 sprintf(&tvec[40], "%.4f", dvec[2]);
2857         }
2858
2859         if( dist > 1e10 || dist < -1e10 )       /* prevent string buffer overflow */
2860                 sprintf(distvec, "%.4e", dist);
2861         else
2862                 sprintf(distvec, "%.4f", dist);
2863                 
2864         if(t->flag & T_AUTOIK) {
2865                 short chainlen= t->scene->toolsettings->autoik_chainlen;
2866                 
2867                 if(chainlen)
2868                         sprintf(autoik, "AutoIK-Len: %d", chainlen);
2869                 else
2870                         strcpy(autoik, "");
2871         }
2872         else
2873                 strcpy(autoik, "");
2874
2875         if (t->con.mode & CON_APPLY) {
2876                 switch(t->num.idx_max) {
2877                 case 0:
2878                         sprintf(str, "D: %s (%s)%s %s  %s", &tvec[0], distvec, t->con.text, t->proptext, &autoik[0]);
2879                         break;
2880                 case 1:
2881                         sprintf(str, "D: %s   D: %s (%s)%s %s  %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext, &autoik[0]);
2882                         break;
2883                 case 2:
2884                         sprintf(str, "D: %s   D: %s  D: %s (%s)%s %s  %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext, &autoik[0]);
2885                 }
2886         }
2887         else {
2888                 if(t->flag & T_2D_EDIT)
2889                         sprintf(str, "Dx: %s   Dy: %s (%s)%s %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext);
2890                 else
2891                         sprintf(str, "Dx: %s   Dy: %s  Dz: %s (%s)%s %s  %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext, &autoik[0]);
2892         }
2893 }
2894
2895 static void applyTranslation(TransInfo *t, float vec[3]) {
2896         TransData *td = t->data;
2897         float tvec[3];
2898         int i;
2899
2900         for(i = 0 ; i < t->total; i++, td++) {
2901                 if (td->flag & TD_NOACTION)
2902                         break;
2903                 
2904                 if (td->flag & TD_SKIP)
2905                         continue;
2906                 
2907                 /* handle snapping rotation before doing the translation */
2908                 if (usingSnappingNormal(t))
2909                 {
2910                         if (validSnappingNormal(t))
2911                         {
2912                                 float *original_normal = td->axismtx[2];
2913                                 float axis[3];
2914                                 float quat[4];
2915                                 float mat[3][3];
2916                                 float angle;
2917                                 
2918                                 Crossf(axis, original_normal, t->tsnap.snapNormal);
2919                                 angle = saacos(Inpf(original_normal, t->tsnap.snapNormal));
2920                                 
2921                                 AxisAngleToQuat(quat, axis, angle);
2922         
2923                                 QuatToMat3(quat, mat);
2924                                 
2925                                 ElementRotation(t, td, mat, V3D_LOCAL);
2926                         }
2927                         else
2928                         {
2929                                 float mat[3][3];
2930                                 
2931                                 Mat3One(mat);
2932                                 
2933                                 ElementRotation(t, td, mat, V3D_LOCAL);
2934                         }
2935                 }
2936
2937                 if (t->con.applyVec) {
2938                         float pvec[3];
2939                         t->con.applyVec(t, td, vec, tvec, pvec);
2940                 }
2941                 else {
2942                         VECCOPY(tvec, vec);
2943                 }
2944                 
2945                 Mat3MulVecfl(td->smtx, tvec);
2946                 VecMulf(tvec, td->factor);
2947                 
2948                 protectedTransBits(td->protectflag, tvec);
2949                 
2950                 /* transdata ipokey */
2951                 if(td->tdi) {
2952                         TransDataIpokey *tdi= td->tdi;
2953                         add_tdi_poin(tdi->locx, tdi->oldloc, tvec[0]);
2954                         add_tdi_poin(tdi->locy, tdi->oldloc+1, tvec[1]);
2955                         add_tdi_poin(tdi->locz, tdi->oldloc+2, tvec[2]);
2956                 }
2957                 else VecAddf(td->loc, td->iloc, tvec);
2958                 
2959                 constraintTransLim(t, td);
2960         }
2961 }
2962
2963 /* uses t->vec to store actual translation in */
2964 int Translation(TransInfo *t, short mval[2]) 
2965 {
2966         float tvec[3];
2967         char str[250];
2968         
2969         if (t->con.mode & CON_APPLY) {
2970                 float pvec[3] = {0.0f, 0.0f, 0.0f};
2971                 applySnapping(t, t->values);
2972                 t->con.applyVec(t, NULL, t->values, tvec, pvec);
2973                 VECCOPY(t->values, tvec);
2974                 headerTranslation(t, pvec, str);
2975         }
2976         else {
2977                 applyNDofInput(&t->ndof, t->values);
2978                 snapGrid(t, t->values);
2979                 applyNumInput(&t->num, t->values);
2980                 if (hasNumInput(&t->num))
2981                 {
2982                         removeAspectRatio(t, t->values);
2983                 }
2984                 
2985                 applySnapping(t, t->values);
2986                 headerTranslation(t, t->values, str);
2987         }
2988         
2989         applyTranslation(t, t->values);
2990
2991         /* evil hack - redo translation if clipping needed */
2992         if (t->flag & T_CLIP_UV && clipUVTransform(t, t->values, 0))
2993                 applyTranslation(t, t->values);
2994
2995         recalcData(t);
2996
2997         ED_area_headerprint(t->sa, str);
2998
2999         drawSnapping(t);
3000
3001         return 1;
3002 }
3003
3004 /* ************************** SHRINK/FATTEN *************************** */
3005
3006 void initShrinkFatten(TransInfo *t) 
3007 {
3008         // If not in mesh edit mode, fallback to Resize
3009         if (t->obedit==NULL || t->obedit->type != OB_MESH) {