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