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