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