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