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