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