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_context.h"
83 #include "BKE_constraint.h"
84 #include "BKE_global.h"
85 #include "BKE_particle.h"
86 #include "BKE_pointcache.h"
87 #include "BKE_utildefines.h"
88 #include "BKE_context.h"
89
90 //#include "BSE_drawipo.h"
91 //#include "BSE_editnla_types.h"        /* for NLAWIDTH */
92 //#include "BSE_editaction_types.h"
93 //#include "BSE_time.h"
94 //#include "BSE_view.h"
95
96 #include "ED_view3d.h"
97 #include "ED_screen.h"
98 #include "ED_util.h"
99 #include "UI_view2d.h"
100 #include "WM_types.h"
101
102 #include "BLI_arithb.h"
103 #include "BLI_blenlib.h"
104 #include "BLI_editVert.h"
105
106 #include "PIL_time.h"                   /* sleep                                */
107
108 //#include "blendef.h"
109 //
110 //#include "mydevice.h"
111
112 #include "transform.h"
113
114 /******************************** Helper functions ************************************/
115
116 /* GLOBAL Wrapper Fonctions */
117
118 //void BIF_drawSnap()
119 //{
120 //      drawSnapping(&Trans);
121 //}
122
123 /* ************************** Dashed help line **************************** */
124
125
126 /* bad frontbuffer call... because it is used in transform after force_draw() */
127 static void helpline(TransInfo *t, float *vec)
128 {
129 #if 0 // TRANSFORM_FIX_ME
130         float vecrot[3], cent[2];
131         short mval[2];
132         
133         VECCOPY(vecrot, vec);
134         if(t->flag & T_EDIT) {
135                 Object *ob= t->obedit;
136                 if(ob) Mat4MulVecfl(ob->obmat, vecrot);
137         }
138         else if(t->flag & T_POSE) {
139                 Object *ob=t->poseobj;
140                 if(ob) Mat4MulVecfl(ob->obmat, vecrot);
141         }
142         
143         getmouseco_areawin(mval);
144         projectFloatView(t, vecrot, cent);      // no overflow in extreme cases
145
146         persp(PERSP_WIN);
147         
148         glDrawBuffer(GL_FRONT);
149         
150         BIF_ThemeColor(TH_WIRE);
151         
152         setlinestyle(3);
153         glBegin(GL_LINE_STRIP); 
154         glVertex2sv(mval); 
155         glVertex2fv(cent); 
156         glEnd();
157         setlinestyle(0);
158         
159         persp(PERSP_VIEW);
160         bglFlush(); // flush display for frontbuffer
161         glDrawBuffer(GL_BACK);
162 #endif
163 }
164
165 /* ************************** SPACE DEPENDANT CODE **************************** */
166
167 void setTransformViewMatrices(TransInfo *t)
168 {
169         if(t->spacetype==SPACE_VIEW3D) {
170                 View3D *v3d = t->view;
171                 
172                 Mat4CpyMat4(t->viewmat, v3d->viewmat);
173                 Mat4CpyMat4(t->viewinv, v3d->viewinv);
174                 Mat4CpyMat4(t->persmat, v3d->persmat);
175                 Mat4CpyMat4(t->persinv, v3d->persinv);
176                 t->persp = v3d->persp;
177         }
178         else {
179                 Mat4One(t->viewmat);
180                 Mat4One(t->viewinv);
181                 Mat4One(t->persmat);
182                 Mat4One(t->persinv);
183                 t->persp = V3D_ORTHO;
184         }
185         
186         calculateCenter2D(t);
187 }
188
189 void convertViewVec(TransInfo *t, float *vec, short dx, short dy)
190 {
191         if (t->spacetype==SPACE_VIEW3D) {
192                 window_to_3d(t->ar, t->view, vec, dx, dy);
193         }
194         else if(t->spacetype==SPACE_IMAGE) {
195                 View2D *v2d = t->view;
196                 float divx, divy, aspx, aspy;
197                 
198                 // TRANSFORM_FIX_ME
199                 //transform_aspect_ratio_tface_uv(&aspx, &aspy);
200                 
201                 divx= v2d->mask.xmax-v2d->mask.xmin;
202                 divy= v2d->mask.ymax-v2d->mask.ymin;
203                 
204                 vec[0]= aspx*(v2d->cur.xmax-v2d->cur.xmin)*(dx)/divx;
205                 vec[1]= aspy*(v2d->cur.ymax-v2d->cur.ymin)*(dy)/divy;
206                 vec[2]= 0.0f;
207         }
208         else if(t->spacetype==SPACE_IPO) {
209                 View2D *v2d = t->view;
210                 float divx, divy;
211                 
212                 divx= v2d->mask.xmax-v2d->mask.xmin;
213                 divy= v2d->mask.ymax-v2d->mask.ymin;
214                 
215                 vec[0]= (v2d->cur.xmax-v2d->cur.xmin)*(dx) / (divx);
216                 vec[1]= (v2d->cur.ymax-v2d->cur.ymin)*(dy) / (divy);
217                 vec[2]= 0.0f;
218         }
219 }
220
221 void projectIntView(TransInfo *t, float *vec, int *adr)
222 {
223         if (t->spacetype==SPACE_VIEW3D) {
224                 project_int_noclip(t->ar, t->view, vec, adr);
225         }
226         else if(t->spacetype==SPACE_IMAGE) {
227                 float aspx, aspy, v[2];
228                 
229                 // TRANSFORM_FIX_ME
230                 //transform_aspect_ratio_tface_uv(&aspx, &aspy);
231                 v[0]= vec[0]/aspx;
232                 v[1]= vec[1]/aspy;
233                 
234                 // TRANSFORM_FIX_ME
235                 //uvco_to_areaco_noclip(v, adr);
236         }
237         else if(t->spacetype==SPACE_IPO) {
238                 short out[2] = {0.0f, 0.0f};
239                 
240                 UI_view2d_view_to_region((View2D *)t->view, vec[0], vec[1], out, out+1); 
241                 adr[0]= out[0];
242                 adr[1]= out[1];
243         }
244 }
245
246 void projectFloatView(TransInfo *t, float *vec, float *adr)
247 {
248         if (t->spacetype==SPACE_VIEW3D) {
249                 project_float_noclip(t->ar, t->view, vec, adr);
250         }
251         else if(t->spacetype==SPACE_IMAGE) {
252                 int a[2];
253                 
254                 projectIntView(t, vec, a);
255                 adr[0]= a[0];
256                 adr[1]= a[1];
257         }
258         else if(t->spacetype==SPACE_IPO) {
259                 int a[2];
260                 
261                 projectIntView(t, vec, a);
262                 adr[0]= a[0];
263                 adr[1]= a[1];
264         }
265 }
266
267 void convertVecToDisplayNum(float *vec, float *num)
268 {
269         VECCOPY(num, vec);
270
271 #if 0 // TRANSFORM_FIX_ME
272         TransInfo *t = BIF_GetTransInfo();
273
274         if ((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) {
275                 float aspx, aspy;
276
277                 if((G.sima->flag & SI_COORDFLOATS)==0) {
278                         int width, height;
279                         transform_width_height_tface_uv(&width, &height);
280
281                         num[0] *= width;
282                         num[1] *= height;
283                 }
284
285                 transform_aspect_ratio_tface_uv(&aspx, &aspy);
286                 num[0] /= aspx;
287                 num[1] /= aspy;
288         }
289 #endif
290 }
291
292 void convertDisplayNumToVec(float *num, float *vec)
293 {
294         VECCOPY(vec, num);
295
296 #if 0 // TRANSFORM_FIX_ME
297         TransInfo *t = BIF_GetTransInfo();
298
299         if ((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) {
300                 float aspx, aspy;
301
302                 if((G.sima->flag & SI_COORDFLOATS)==0) {
303                         int width, height;
304                         transform_width_height_tface_uv(&width, &height);
305
306                         vec[0] /= width;
307                         vec[1] /= height;
308                 }
309
310                 transform_aspect_ratio_tface_uv(&aspx, &aspy);
311                 vec[0] *= aspx;
312                 vec[1] *= aspy;
313         }
314 #endif
315 }
316
317 static void viewRedrawForce(TransInfo *t)
318 {
319         if (t->spacetype == SPACE_VIEW3D)
320         {
321                 // TRANSFORM_FIX_ME
322                 // need to redraw ALL 3d view
323                 ED_area_tag_redraw(t->sa);
324         }
325         else if (t->spacetype == SPACE_ACTION) {
326                 SpaceAction *saction= (SpaceAction *)t->sa->spacedata.first;
327                 
328                 // TRANSFORM_FIX_ME
329                 if (saction->lock) {
330                         // whole window...
331                 }
332                 else 
333                         ED_area_tag_redraw(t->sa);
334         }
335 #if 0 // TRANSFORM_FIX_ME
336         else if (t->spacetype==SPACE_IMAGE) {
337                 if (G.sima->lock) force_draw_plus(SPACE_VIEW3D, 0);
338                 else force_draw(0);
339         }
340         else if (t->spacetype == SPACE_ACTION) {
341                 if (G.saction->lock) {
342                         short context;
343                         
344                         /* we ignore the pointer this function returns (not needed) */
345                         get_action_context(&context);
346                         
347                         if (context == ACTCONT_ACTION)
348                                 force_draw_plus(SPACE_VIEW3D, 0);
349                         else if (context == ACTCONT_SHAPEKEY) 
350                                 force_draw_all(0);
351                         else
352                                 force_draw(0);
353                 }
354                 else {
355                         force_draw(0);
356                 }
357         }
358         else if (t->spacetype == SPACE_NLA) {
359                 if (G.snla->lock)
360                         force_draw_all(0);
361                 else
362                         force_draw(0);
363         }
364         else if (t->spacetype == SPACE_IPO) {
365                 /* update realtime */
366                 if (G.sipo->lock) {
367                         if (G.sipo->blocktype==ID_MA || G.sipo->blocktype==ID_TE)
368                                 force_draw_plus(SPACE_BUTS, 0);
369                         else if (G.sipo->blocktype==ID_CA)
370                                 force_draw_plus(SPACE_VIEW3D, 0);
371                         else if (G.sipo->blocktype==ID_KE)
372                                 force_draw_plus(SPACE_VIEW3D, 0);
373                         else if (G.sipo->blocktype==ID_PO)
374                                 force_draw_plus(SPACE_VIEW3D, 0);
375                         else if (G.sipo->blocktype==ID_OB) 
376                                 force_draw_plus(SPACE_VIEW3D, 0);
377                         else if (G.sipo->blocktype==ID_SEQ) 
378                                 force_draw_plus(SPACE_SEQ, 0);
379                         else 
380                                 force_draw(0);
381                 }
382                 else {
383                         force_draw(0);
384                 }
385         }
386 #endif  
387 }
388
389 static void viewRedrawPost(TransInfo *t)
390 {
391         ED_area_headerprint(t->sa, NULL);
392         
393 #if 0 // TRANSFORM_FIX_ME
394         if(t->spacetype==SPACE_VIEW3D) {
395                 allqueue(REDRAWBUTSOBJECT, 0);
396                 allqueue(REDRAWVIEW3D, 0);
397         }
398         else if(t->spacetype==SPACE_IMAGE) {
399                 allqueue(REDRAWIMAGE, 0);
400                 allqueue(REDRAWVIEW3D, 0);
401         }
402         else if(ELEM3(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_IPO)) {
403                 allqueue(REDRAWVIEW3D, 0);
404                 allqueue(REDRAWACTION, 0);
405                 allqueue(REDRAWNLA, 0);
406                 allqueue(REDRAWIPO, 0);
407                 allqueue(REDRAWTIME, 0);
408                 allqueue(REDRAWBUTSOBJECT, 0);
409         }
410
411         scrarea_queue_headredraw(curarea);
412 #endif
413 }
414
415 /* ************************** TRANSFORMATIONS **************************** */
416
417 void BIF_selectOrientation() {
418 #if 0 // TRANSFORM_FIX_ME
419         short val;
420         char *str_menu = BIF_menustringTransformOrientation("Orientation");
421         val= pupmenu(str_menu);
422         MEM_freeN(str_menu);
423         
424         if(val >= 0) {
425                 G.vd->twmode = val;
426         }
427 #endif
428 }
429
430 static void view_editmove(unsigned short event)
431 {
432 #if 0 // TRANSFORM_FIX_ME
433         int refresh = 0;
434         /* Regular:   Zoom in */
435         /* Shift:     Scroll up */
436         /* Ctrl:      Scroll right */
437         /* Alt-Shift: Rotate up */
438         /* Alt-Ctrl:  Rotate right */
439         
440         /* only work in 3D window for now
441          * In the end, will have to send to event to a 2D window handler instead
442          */
443         if (Trans.flag & T_2D_EDIT)
444                 return;
445         
446         switch(event) {
447                 case WHEELUPMOUSE:
448                         
449                         if( G.qual & LR_SHIFTKEY ) {
450                                 if( G.qual & LR_ALTKEY ) { 
451                                         G.qual &= ~LR_SHIFTKEY;
452                                         persptoetsen(PAD2);
453                                         G.qual |= LR_SHIFTKEY;
454                                 } else {
455                                         persptoetsen(PAD2);
456                                 }
457                         } else if( G.qual & LR_CTRLKEY ) {
458                                 if( G.qual & LR_ALTKEY ) { 
459                                         G.qual &= ~LR_CTRLKEY;
460                                         persptoetsen(PAD4);
461                                         G.qual |= LR_CTRLKEY;
462                                 } else {
463                                         persptoetsen(PAD4);
464                                 }
465                         } else if(U.uiflag & USER_WHEELZOOMDIR) 
466                                 persptoetsen(PADMINUS);
467                         else
468                                 persptoetsen(PADPLUSKEY);
469                         
470                         refresh = 1;
471                         break;
472                 case WHEELDOWNMOUSE:
473                         if( G.qual & LR_SHIFTKEY ) {
474                                 if( G.qual & LR_ALTKEY ) { 
475                                         G.qual &= ~LR_SHIFTKEY;
476                                         persptoetsen(PAD8);
477                                         G.qual |= LR_SHIFTKEY;
478                                 } else {
479                                         persptoetsen(PAD8);
480                                 }
481                         } else if( G.qual & LR_CTRLKEY ) {
482                                 if( G.qual & LR_ALTKEY ) { 
483                                         G.qual &= ~LR_CTRLKEY;
484                                         persptoetsen(PAD6);
485                                         G.qual |= LR_CTRLKEY;
486                                 } else {
487                                         persptoetsen(PAD6);
488                                 }
489                         } else if(U.uiflag & USER_WHEELZOOMDIR) 
490                                 persptoetsen(PADPLUSKEY);
491                         else
492                                 persptoetsen(PADMINUS);
493                         
494                         refresh = 1;
495                         break;
496         }
497
498         if (refresh)
499                 setTransformViewMatrices(&Trans);
500 #endif
501 }
502
503 static char *transform_to_undostr(TransInfo *t)
504 {
505         switch (t->mode) {
506                 case TFM_TRANSLATION:
507                         return "Translate";
508                 case TFM_ROTATION:
509                         return "Rotate";
510                 case TFM_RESIZE:
511                         return "Scale";
512                 case TFM_TOSPHERE:
513                         return "To Sphere";
514                 case TFM_SHEAR:
515                         return "Shear";
516                 case TFM_WARP:
517                         return "Warp";
518                 case TFM_SHRINKFATTEN:
519                         return "Shrink/Fatten";
520                 case TFM_TILT:
521                         return "Tilt";
522                 case TFM_TRACKBALL:
523                         return "Trackball";
524                 case TFM_PUSHPULL:
525                         return "Push/Pull";
526                 case TFM_BEVEL:
527                         return "Bevel";
528                 case TFM_BWEIGHT:
529                         return "Bevel Weight";
530                 case TFM_CREASE:
531                         return "Crease";
532                 case TFM_BONESIZE:
533                         return "Bone Width";
534                 case TFM_BONE_ENVELOPE:
535                         return "Bone Envelope";
536                 case TFM_TIME_TRANSLATE:
537                         return "Translate Anim. Data";
538                 case TFM_TIME_SCALE:
539                         return "Scale Anim. Data";
540                 case TFM_TIME_SLIDE:
541                         return "Time Slide";
542                 case TFM_BAKE_TIME:
543                         return "Key Time";
544                 case TFM_MIRROR:
545                         return "Mirror";
546         }
547         return "Transform";
548 }
549
550 /* ************************************************* */
551
552 void transformEvent(TransInfo *t, wmEvent *event)
553 {
554         float mati[3][3] = {{1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}};
555         char cmode = constraintModeToChar(t);
556         
557         t->event = event;
558         
559         t->redraw |= handleMouseInput(t, &t->mouse, event);
560
561         if (event->type == MOUSEMOVE)
562         {
563                 t->mval[0] = event->x - t->ar->winrct.xmin;
564                 t->mval[1] = event->y - t->ar->winrct.ymin;
565                 
566                 applyMouseInput(t, &t->mouse, t->mval, t->values);
567         }
568         
569         if (event->val) {
570                 switch (event->type){
571                 /* enforce redraw of transform when modifiers are used */
572                 case LEFTCTRLKEY:
573                 case RIGHTCTRLKEY:
574                         t->redraw = 1;
575                         break;
576                         
577                 case SPACEKEY:
578                         if ((t->spacetype==SPACE_VIEW3D) && event->alt) {
579 #if 0 // TRANSFORM_FIX_ME
580                                 short mval[2];
581                                 
582                                 getmouseco_sc(mval);
583                                 BIF_selectOrientation();
584                                 calc_manipulator_stats(curarea);
585                                 Mat3CpyMat4(t->spacemtx, G.vd->twmat);
586                                 warp_pointer(mval[0], mval[1]);
587 #endif
588                         }
589                         else {
590                                 t->state = TRANS_CONFIRM;
591                         }
592                         break;
593                         
594                         
595                 case MIDDLEMOUSE:
596                         if ((t->flag & T_NO_CONSTRAINT)==0) {
597                                 /* exception for switching to dolly, or trackball, in camera view */
598                                 if (t->flag & T_CAMERA) {
599                                         if (t->mode==TFM_TRANSLATION)
600                                                 setLocalConstraint(t, (CON_AXIS2), "along local Z");
601                                         else if (t->mode==TFM_ROTATION) {
602                                                 restoreTransObjects(t);
603                                                 initTrackball(t);
604                                         }
605                                 }
606                                 else {
607                                         t->flag |= T_MMB_PRESSED;
608                                         if (t->con.mode & CON_APPLY) {
609                                                 stopConstraint(t);
610                                         }
611                                         else {
612                                                 if (event->shift) {
613                                                         initSelectConstraint(t, t->spacemtx);
614                                                 }
615                                                 else {
616                                                         /* bit hackish... but it prevents mmb select to print the orientation from menu */
617                                                         strcpy(t->spacename, "global");
618                                                         initSelectConstraint(t, mati);
619                                                 }
620                                                 postSelectConstraint(t);
621                                         }
622                                 }
623                                 t->redraw = 1;
624                         }
625                         break;
626                 case ESCKEY:
627                 case RIGHTMOUSE:
628                         printf("cancelled\n");
629                         t->state = TRANS_CANCEL;
630                         break;
631                 case LEFTMOUSE:
632                 case PADENTER:
633                 case RETKEY:
634                         t->state = TRANS_CONFIRM;
635                         break;
636                 case GKEY:
637                         /* only switch when... */
638                         if( ELEM3(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL) ) { 
639                                 resetTransRestrictions(t); 
640                                 restoreTransObjects(t);
641                                 initTranslation(t);
642                                 t->redraw = 1;
643                         }
644                         break;
645                 case SKEY:
646                         /* only switch when... */
647                         if( ELEM3(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) { 
648                                 resetTransRestrictions(t); 
649                                 restoreTransObjects(t);
650                                 initResize(t);
651                                 t->redraw = 1;
652                         }
653                         break;
654                 case RKEY:
655                         /* only switch when... */
656                         if( ELEM4(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) {
657                                 
658                                 resetTransRestrictions(t); 
659                                 
660                                 if (t->mode == TFM_ROTATION) {
661                                         restoreTransObjects(t);
662                                         initTrackball(t);
663                                 }
664                                 else {
665                                         restoreTransObjects(t);
666                                         initRotation(t);
667                                 }
668                                 t->redraw = 1;
669                         }
670                         break;
671                 case CKEY:
672                         if (event->alt) {
673                                 t->flag ^= T_PROP_CONNECTED;
674                                 sort_trans_data_dist(t);
675                                 calculatePropRatio(t);
676                                 t->redraw= 1;
677                         }
678                         else {
679                                 stopConstraint(t);
680                                 t->redraw = 1;
681                         }
682                         break;
683                 case XKEY:
684                         if ((t->flag & T_NO_CONSTRAINT)==0) {
685                                 if (cmode == 'X') {
686                                         if (t->flag & T_2D_EDIT) {
687                                                 stopConstraint(t);
688                                         }
689                                         else {
690                                                 if (t->con.mode & CON_USER) {
691                                                         stopConstraint(t);
692                                                 }
693                                                 else {
694                                                         if (event->keymodifier == 0)
695                                                                 setUserConstraint(t, (CON_AXIS0), "along %s X");
696                                                         else if (event->keymodifier == KM_SHIFT)
697                                                                 setUserConstraint(t, (CON_AXIS1|CON_AXIS2), "locking %s X");
698                                                 }
699                                         }
700                                 }
701                                 else {
702                                         if (t->flag & T_2D_EDIT) {
703                                                 setConstraint(t, mati, (CON_AXIS0), "along X axis");
704                                         }
705                                         else {
706                                                 if (event->keymodifier == 0)
707                                                         setConstraint(t, mati, (CON_AXIS0), "along global X");
708                                                 else if (event->keymodifier == KM_SHIFT)
709                                                         setConstraint(t, mati, (CON_AXIS1|CON_AXIS2), "locking global X");
710                                         }
711                                 }
712                                 t->redraw = 1;
713                         }
714                         break;
715                 case YKEY:
716                         if ((t->flag & T_NO_CONSTRAINT)==0) {
717                                 if (cmode == 'Y') {
718                                         if (t->flag & T_2D_EDIT) {
719                                                 stopConstraint(t);
720                                         }
721                                         else {
722                                                 if (t->con.mode & CON_USER) {
723                                                         stopConstraint(t);
724                                                 }
725                                                 else {
726                                                         if (event->keymodifier == 0)
727                                                                 setUserConstraint(t, (CON_AXIS1), "along %s Y");
728                                                         else if (event->keymodifier == KM_SHIFT)
729                                                                 setUserConstraint(t, (CON_AXIS0|CON_AXIS2), "locking %s Y");
730                                                 }
731                                         }
732                                 }
733                                 else {
734                                         if (t->flag & T_2D_EDIT) {
735                                                 setConstraint(t, mati, (CON_AXIS1), "along Y axis");
736                                         }
737                                         else {
738                                                 if (event->keymodifier == 0)
739                                                         setConstraint(t, mati, (CON_AXIS1), "along global Y");
740                                                 else if (event->keymodifier == KM_SHIFT)
741                                                         setConstraint(t, mati, (CON_AXIS0|CON_AXIS2), "locking global Y");
742                                         }
743                                 }
744                                 t->redraw = 1;
745                         }
746                         break;
747                 case ZKEY:
748                         if ((t->flag & T_NO_CONSTRAINT)==0) {
749                                 if (cmode == 'Z') {
750                                         if (t->con.mode & CON_USER) {
751                                                 stopConstraint(t);
752                                         }
753                                         else {
754                                                 if (event->keymodifier == 0)
755                                                         setUserConstraint(t, (CON_AXIS2), "along %s Z");
756                                                 else if ((event->keymodifier == KM_SHIFT) && ((t->flag & T_2D_EDIT)==0))
757                                                         setUserConstraint(t, (CON_AXIS0|CON_AXIS1), "locking %s Z");
758                                         }
759                                 }
760                                 else if ((t->flag & T_2D_EDIT)==0) {
761                                         if (event->keymodifier == 0)
762                                                 setConstraint(t, mati, (CON_AXIS2), "along global Z");
763                                         else if (event->keymodifier == KM_SHIFT)
764                                                 setConstraint(t, mati, (CON_AXIS0|CON_AXIS1), "locking global Z");
765                                 }
766                                 t->redraw = 1;
767                         }
768                         break;
769                 case OKEY:
770                         if (t->flag & T_PROP_EDIT && event->keymodifier == KM_SHIFT) {
771                                 G.scene->prop_mode = (G.scene->prop_mode+1)%6;
772                                 calculatePropRatio(t);
773                                 t->redraw= 1;
774                         }
775                         break;
776                 case PADPLUSKEY:
777                         if(event->keymodifier & KM_ALT && t->flag & T_PROP_EDIT) {
778                                 t->propsize*= 1.1f;
779                                 calculatePropRatio(t);
780                         }
781                         t->redraw= 1;
782                         break;
783                 case PAGEUPKEY:
784                 case WHEELDOWNMOUSE:
785                         if (t->flag & T_AUTOIK) {
786                                 transform_autoik_update(t, 1);
787                         }
788                         else if(t->flag & T_PROP_EDIT) {
789                                 t->propsize*= 1.1f;
790                                 calculatePropRatio(t);
791                         }
792                         else view_editmove(event->type);
793                         t->redraw= 1;
794                         break;
795                 case PADMINUS:
796                         if(event->keymodifier & KM_ALT && t->flag & T_PROP_EDIT) {
797                                 t->propsize*= 0.90909090f;
798                                 calculatePropRatio(t);
799                         }
800                         t->redraw= 1;
801                         break;
802                 case PAGEDOWNKEY:
803                 case WHEELUPMOUSE:
804                         if (t->flag & T_AUTOIK) {
805                                 transform_autoik_update(t, -1);
806                         }
807                         else if (t->flag & T_PROP_EDIT) {
808                                 t->propsize*= 0.90909090f;
809                                 calculatePropRatio(t);
810                         }
811                         else view_editmove(event->type);
812                         t->redraw= 1;
813                         break;
814 //              case NDOFMOTION:
815 //            viewmoveNDOF(1);
816   //         break;
817                 }
818                 
819                 // Numerical input events
820                 t->redraw |= handleNumInput(&(t->num), event);
821                 
822                 // NDof input events
823                 switch(handleNDofInput(&(t->ndof), event))
824                 {
825                         case NDOF_CONFIRM:
826                                 if ((t->options & CTX_NDOF) == 0)
827                                 {
828                                         /* Confirm on normal transform only */
829                                         t->state = TRANS_CONFIRM;
830                                 }
831                                 break;
832                         case NDOF_CANCEL:
833                                 if (t->options & CTX_NDOF)
834                                 {
835                                         /* Cancel on pure NDOF transform */
836                                         t->state = TRANS_CANCEL; 
837                                 }
838                                 else
839                                 {
840                                         /* Otherwise, just redraw, NDof input was cancelled */
841                                         t->redraw = 1;
842                                 }
843                                 break;
844                         case NDOF_NOMOVE:
845                                 if (t->options & CTX_NDOF)
846                                 {
847                                         /* Confirm on pure NDOF transform */
848                                         t->state = TRANS_CONFIRM;
849                                 }
850                                 break;
851                         case NDOF_REFRESH:
852                                 t->redraw = 1;
853                                 break;
854                         
855                 }
856                 
857                 // Snapping events
858                 t->redraw |= handleSnapping(t, event);
859                 
860                 //arrows_move_cursor(event->type);
861         }
862         else {
863                 switch (event->type){
864                 /* no redraw on release modifier keys! this makes sure you can assign the 'grid' still 
865                    after releasing modifer key */
866                 case MIDDLEMOUSE:
867                         if ((t->flag & T_NO_CONSTRAINT)==0) {
868                                 t->flag &= ~T_MMB_PRESSED;
869                                 postSelectConstraint(t);
870                                 t->redraw = 1;
871                         }
872                         break;
873                 case LEFTMOUSE:
874                 case RIGHTMOUSE:
875                         if (t->options & CTX_TWEAK)
876                                 t->state = TRANS_CONFIRM;
877                         break;
878                 }
879         }
880         
881         // Per transform event, if present
882         if (t->handleEvent)
883                 t->redraw |= t->handleEvent(t, event);
884 }
885
886 int calculateTransformCenter(bContext *C, wmEvent *event, int centerMode, float *vec)
887 {
888         TransInfo *t = MEM_callocN(sizeof(TransInfo), "TransInfo data");
889         int success = 1;
890
891         t->state = TRANS_RUNNING;
892
893         t->options = CTX_NONE;
894         
895         t->mode = TFM_DUMMY;
896
897         initTransInfo(C, t, event);                                     // internal data, mouse, vectors
898
899         createTransData(C, t);                  // make TransData structs from selection
900
901         t->around = centerMode;                         // override userdefined mode
902
903         if (t->total == 0) {
904                 success = 0;
905         }
906         else {
907                 success = 1;
908                 
909                 calculateCenter(t);
910         
911                 // Copy center from constraint center. Transform center can be local    
912                 VECCOPY(vec, t->con.center);
913         }
914
915         postTrans(t);
916
917         /* aftertrans does insert ipos and action channels, and clears base flags, doesnt read transdata */
918         special_aftertrans_update(t);
919         
920         MEM_freeN(t);
921         
922         return success;
923 }
924
925 void initTransform(bContext *C, TransInfo *t, int mode, int options, wmEvent *event)
926 {
927         /* added initialize, for external calls to set stuff in TransInfo, like undo string */
928
929         t->state = TRANS_RUNNING;
930
931         t->options = options;
932         
933         t->mode = mode;
934
935         initTransInfo(C, t, event);                                     // internal data, mouse, vectors
936
937         if(t->spacetype == SPACE_VIEW3D)
938         {
939                 View3D *v3d = t->view;
940                 //calc_manipulator_stats(curarea);
941                 Mat3CpyMat4(t->spacemtx, v3d->twmat);
942                 Mat3Ortho(t->spacemtx);
943         }
944         else
945                 Mat3One(t->spacemtx);
946
947         createTransData(C, t);                  // make TransData structs from selection
948
949         initSnapping(t); // Initialize snapping data AFTER mode flags
950
951         if (t->total == 0) {
952                 postTrans(t);
953                 return;
954         }
955
956         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
957         /* EVIL2: we gave as argument also texture space context bit... was cleared */
958         /* EVIL3: extend mode for animation editors also switches modes... but is best way to avoid duplicate code */
959         mode = t->mode;
960         
961         calculatePropRatio(t);
962         calculateCenter(t);
963         
964         initMouseInput(t, &t->mouse, t->center2d, t->imval);
965
966         switch (mode) {
967         case TFM_TRANSLATION:
968                 initTranslation(t);
969                 break;
970         case TFM_ROTATION:
971                 initRotation(t);
972                 break;
973         case TFM_RESIZE:
974                 initResize(t);
975                 break;
976         case TFM_TOSPHERE:
977                 initToSphere(t);
978                 break;
979         case TFM_SHEAR:
980                 initShear(t);
981                 break;
982         case TFM_WARP:
983                 initWarp(t);
984                 break;
985         case TFM_SHRINKFATTEN:
986                 initShrinkFatten(t);
987                 break;
988         case TFM_TILT:
989                 initTilt(t);
990                 break;
991         case TFM_CURVE_SHRINKFATTEN:
992                 initCurveShrinkFatten(t);
993                 break;
994         case TFM_TRACKBALL:
995                 initTrackball(t);
996                 break;
997         case TFM_PUSHPULL:
998                 initPushPull(t);
999                 break;
1000         case TFM_CREASE:
1001                 initCrease(t);
1002                 break;
1003         case TFM_BONESIZE:
1004                 {       /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */
1005                         bArmature *arm= t->poseobj->data;
1006                         if(arm->drawtype==ARM_ENVELOPE)
1007                                 initBoneEnvelope(t);
1008                         else
1009                                 initBoneSize(t);
1010                 }
1011                 break;
1012         case TFM_BONE_ENVELOPE:
1013                 initBoneEnvelope(t);
1014                 break;
1015         case TFM_BONE_ROLL:
1016                 initBoneRoll(t);
1017                 break;
1018         case TFM_TIME_TRANSLATE:
1019                 initTimeTranslate(t);
1020                 break;
1021         case TFM_TIME_SLIDE:
1022                 initTimeSlide(t);
1023                 break;
1024         case TFM_TIME_SCALE:
1025                 initTimeScale(t);
1026                 break;
1027         case TFM_TIME_EXTEND: 
1028                 /* now that transdata has been made, do like for TFM_TIME_TRANSLATE */
1029                 initTimeTranslate(t);
1030                 break;
1031         case TFM_BAKE_TIME:
1032                 initBakeTime(t);
1033                 break;
1034         case TFM_MIRROR:
1035                 initMirror(t);
1036                 break;
1037         case TFM_BEVEL:
1038                 initBevel(t);
1039                 break;
1040         case TFM_BWEIGHT:
1041                 initBevelWeight(t);
1042                 break;
1043         case TFM_ALIGN:
1044                 initAlign(t);
1045                 break;
1046         }
1047 }
1048
1049 void transformApply(TransInfo *t)
1050 {
1051         if (1) // MOUSE MOVE
1052         {
1053                 if (t->flag & T_MMB_PRESSED)
1054                         t->con.mode |= CON_SELECT;
1055                 t->redraw = 1;
1056         }
1057         if (t->redraw)
1058         {
1059                 // RESET MOUSE MOVE
1060
1061                 selectConstraint(t);
1062                 if (t->transform) {
1063                         t->transform(t, t->mval);  // calls recalcData()
1064                 }
1065                 t->redraw = 0;
1066         }
1067
1068         /* If auto confirm is on, break after one pass */               
1069         if (t->options & CTX_AUTOCONFIRM)
1070         {
1071                 t->state = TRANS_CONFIRM;
1072         }
1073
1074         if (BKE_ptcache_get_continue_physics())
1075         {
1076                 // TRANSFORM_FIX_ME
1077                 //do_screenhandlers(G.curscreen);
1078                 t->redraw = 1;
1079         }
1080 }
1081
1082 int transformEnd(bContext *C, TransInfo *t)
1083 {
1084         if (t->state != TRANS_RUNNING)
1085         {
1086                 /* handle restoring objects */
1087                 if(t->state == TRANS_CANCEL)
1088                         restoreTransObjects(t); // calls recalcData()
1089                 
1090                 /* free data */
1091                 postTrans(t);
1092         
1093                 /* aftertrans does insert ipos and action channels, and clears base flags, doesnt read transdata */
1094                 special_aftertrans_update(t);
1095         
1096                 /* send events out for redraws */
1097                 viewRedrawPost(t);
1098         
1099                 /*  Undo as last, certainly after special_trans_update! */
1100
1101                 if(t->state == TRANS_CANCEL) {
1102                         if(t->undostr) ED_undo_push(C, t->undostr);
1103                 }
1104                 else {
1105                         if(t->undostr) ED_undo_push(C, t->undostr);
1106                         else ED_undo_push(C, transform_to_undostr(t));
1107                 }
1108                 t->undostr= NULL;
1109
1110                 return 1;
1111         }
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 && t->obedit && t->obedit->type==OB_ARMATURE) {
1130                 bArmature *arm= t->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, t->obedit->obmat[3]);
1725                 VecSubf(gcursor, gcursor, t->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 (t->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 (!t->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 (t->obedit==NULL || t->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(