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