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