76e6c7eaf51c12e70952c7ea73bf4a4173156617
[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_TRACKBALL:
790                 initTrackball(&Trans);
791                 break;
792         case TFM_PUSHPULL:
793                 initPushPull(&Trans);
794                 break;
795         case TFM_CREASE:
796                 initCrease(&Trans);
797                 break;
798         case TFM_BONESIZE:
799                 {       /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */
800                         bArmature *arm= Trans.poseobj->data;
801                         if(arm->drawtype==ARM_ENVELOPE)
802                                 initBoneEnvelope(&Trans);
803                         else
804                                 initBoneSize(&Trans);
805                 }
806                 break;
807         case TFM_BONE_ENVELOPE:
808                 initBoneEnvelope(&Trans);
809                 break;
810         }
811 }
812
813 void Transform() 
814 {
815         short pmval[2] = {0, 0}, mval[2], val;
816         unsigned short event;
817
818         if(Trans.total==0) return;      // added, can happen now! (ton)
819         
820         // Emptying event queue
821         while( qtest() ) {
822                 event= extern_qread(&val);
823         }
824
825         Trans.redraw = 1; /* initial draw */
826
827         while (Trans.state == TRANS_RUNNING) {
828
829                 getmouseco_areawin(mval);
830                 
831                 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
832                         if (Trans.flag & T_MMB_PRESSED)
833                                 Trans.con.mode |= CON_SELECT;
834                         Trans.redraw = 1;
835                 }
836                 if (Trans.redraw) {
837                         pmval[0] = mval[0];
838                         pmval[1] = mval[1];
839
840                         selectConstraint(&Trans);
841                         if (Trans.transform) {
842                                 Trans.transform(&Trans, mval);  // calls recalcData()
843                         }
844                         Trans.redraw = 0;
845                 }
846                 
847                 /* essential for idling subloop */
848                 if( qtest()==0) PIL_sleep_ms(2);
849
850                 while( qtest() ) {
851                         event= extern_qread(&val);
852                         transformEvent(event, val);
853                 }
854         }
855         
856         
857         /* handle restoring objects */
858         if(Trans.state == TRANS_CANCEL)
859                 restoreTransObjects(&Trans);    // calls recalcData()
860         
861         /* free data */
862         postTrans(&Trans);
863
864         /* aftertrans does insert ipos and action channels, and clears base flags, doesnt read transdata */
865         special_aftertrans_update(&Trans);
866
867         /* send events out for redraws */
868         viewRedrawPost(&Trans);
869
870         /*  Undo as last, certainly after special_trans_update! */
871         if(Trans.state == TRANS_CANCEL) {
872                 if(Trans.undostr) BIF_undo_push(Trans.undostr);
873         }
874         else {
875                 if(Trans.undostr) BIF_undo_push(Trans.undostr);
876                 else BIF_undo_push(transform_to_undostr(&Trans));
877         }
878         Trans.undostr= NULL;
879         
880 }
881
882 /* ************************** Manipulator init and main **************************** */
883
884 void initManipulator(int mode)
885 {
886         Trans.state = TRANS_RUNNING;
887
888         Trans.context = CTX_NONE;
889         
890         /* automatic switch to scaling bone envelopes */
891         if(mode==TFM_RESIZE && G.obedit && G.obedit->type==OB_ARMATURE) {
892                 bArmature *arm= G.obedit->data;
893                 if(arm->drawtype==ARM_ENVELOPE)
894                         mode= TFM_BONE_ENVELOPE;
895         }
896
897         initTrans(&Trans);                                      // internal data, mouse, vectors
898
899         initTransModeFlags(&Trans, mode);       // modal settings in struct Trans
900
901         G.moving |= G_TRANSFORM_MANIP;          // signal to draw manipuls while transform
902         createTransData(&Trans);                        // make TransData structs from selection
903
904         if (Trans.total == 0)
905                 return;
906
907         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
908         /* EVIL2: we gave as argument also texture space context bit... was cleared */
909         mode= Trans.mode;
910         
911         calculatePropRatio(&Trans);
912         calculateCenter(&Trans);
913
914         switch (mode) {
915         case TFM_TRANSLATION:
916                 initTranslation(&Trans);
917                 break;
918         case TFM_ROTATION:
919                 initRotation(&Trans);
920                 break;
921         case TFM_RESIZE:
922                 initResize(&Trans);
923                 break;
924         case TFM_TRACKBALL:
925                 initTrackball(&Trans);
926                 break;
927         }
928
929         Trans.flag |= T_USES_MANIPULATOR;
930 }
931
932 void ManipulatorTransform() 
933 {
934         int mouse_moved = 0;
935         short pmval[2] = {0, 0}, mval[2], val;
936         unsigned short event;
937
938         if (Trans.total == 0)
939                 return;
940
941         Trans.redraw = 1; /* initial draw */
942
943         while (Trans.state == TRANS_RUNNING) {
944                 
945                 getmouseco_areawin(mval);
946                 
947                 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
948                         Trans.redraw = 1;
949                 }
950                 if (Trans.redraw) {
951                         pmval[0] = mval[0];
952                         pmval[1] = mval[1];
953
954                         //selectConstraint(&Trans);  needed?
955                         if (Trans.transform) {
956                                 Trans.transform(&Trans, mval);
957                         }
958                         Trans.redraw = 0;
959                 }
960                 
961                 /* essential for idling subloop */
962                 if( qtest()==0) PIL_sleep_ms(2);
963
964                 while( qtest() ) {
965                         event= extern_qread(&val);
966
967                         switch (event){
968                         case MOUSEX:
969                         case MOUSEY:
970                                 mouse_moved = 1;
971                                 break;
972                         /* enforce redraw of transform when modifiers are used */
973                         case LEFTCTRLKEY:
974                         case RIGHTCTRLKEY:
975                                 if(val) Trans.redraw = 1;
976                                 break;
977                         case LEFTSHIFTKEY:
978                         case RIGHTSHIFTKEY:
979                                 /* shift is modifier for higher resolution transform, works nice to store this mouse position */
980                                 if(val) {
981                                         getmouseco_areawin(Trans.shiftmval);
982                                         Trans.flag |= T_SHIFT_MOD;
983                                         Trans.redraw = 1;
984                                 }
985                                 else Trans.flag &= ~T_SHIFT_MOD; 
986                                 break;
987                                 
988                         case ESCKEY:
989                         case RIGHTMOUSE:
990                                 Trans.state = TRANS_CANCEL;
991                                 break;
992                         case LEFTMOUSE:
993                                 if(mouse_moved==0 && val==0) break;
994                                 // else we pass on event to next, which cancels
995                         case SPACEKEY:
996                         case PADENTER:
997                         case RETKEY:
998                                 Trans.state = TRANS_CONFIRM;
999                                 break;
1000                         }
1001                         if(val) {
1002                                 switch(event) {
1003                                 case WHEELDOWNMOUSE:
1004                                 case PADPLUSKEY:
1005                                         if(Trans.flag & T_PROP_EDIT) {
1006                                                 Trans.propsize*= 1.1f;
1007                                                 calculatePropRatio(&Trans);
1008                                                 Trans.redraw= 1;
1009                                         }
1010                                         break;
1011                                 case WHEELUPMOUSE:
1012                                 case PADMINUS:
1013                                         if(Trans.flag & T_PROP_EDIT) {
1014                                                 Trans.propsize*= 0.90909090f;
1015                                                 calculatePropRatio(&Trans);
1016                                                 Trans.redraw= 1;
1017                                         }
1018                                         break;
1019                                 }                       
1020                         }
1021                 }
1022         }
1023         
1024         if(Trans.state == TRANS_CANCEL) {
1025                 restoreTransObjects(&Trans);
1026         }
1027         else {
1028                 BIF_undo_push(transform_to_undostr(&Trans));
1029         }
1030         
1031         /* free data, reset vars */
1032         postTrans(&Trans);
1033         
1034         /* aftertrans does insert ipos and action channels, and clears base flags */
1035         special_aftertrans_update(&Trans);
1036         
1037         /* send events out for redraws */
1038         viewRedrawPost(&Trans);
1039 }
1040
1041 /* ************************** TRANSFORMATIONS **************************** */
1042
1043 static void protectedTransBits(short protectflag, float *vec)
1044 {
1045         if(protectflag & OB_LOCK_LOCX)
1046                 vec[0]= 0.0f;
1047         if(protectflag & OB_LOCK_LOCY)
1048                 vec[1]= 0.0f;
1049         if(protectflag & OB_LOCK_LOCZ)
1050                 vec[2]= 0.0f;
1051 }
1052
1053 static void protectedSizeBits(short protectflag, float *size)
1054 {
1055         if(protectflag & OB_LOCK_SCALEX)
1056                 size[0]= 1.0f;
1057         if(protectflag & OB_LOCK_SCALEY)
1058                 size[1]= 1.0f;
1059         if(protectflag & OB_LOCK_SCALEZ)
1060                 size[2]= 1.0f;
1061 }
1062
1063 static void protectedRotateBits(short protectflag, float *eul, float *oldeul)
1064 {
1065         if(protectflag & OB_LOCK_ROTX)
1066                 eul[0]= oldeul[0];
1067         if(protectflag & OB_LOCK_ROTY)
1068                 eul[1]= oldeul[1];
1069         if(protectflag & OB_LOCK_ROTZ)
1070                 eul[2]= oldeul[2];
1071 }
1072
1073 static void protectedQuaternionBits(short protectflag, float *quat, float *oldquat)
1074 {
1075         /* quaternions get limited with euler... */
1076         /* this function only does the delta rotation */
1077         
1078         if(protectflag) {
1079                 float eul[3], oldeul[3], quat1[4];
1080                 
1081                 QUATCOPY(quat1, quat);
1082                 QuatToEul(quat, eul);
1083                 QuatToEul(oldquat, oldeul);
1084                 
1085                 if(protectflag & OB_LOCK_ROTX)
1086                         eul[0]= oldeul[0];
1087                 if(protectflag & OB_LOCK_ROTY)
1088                         eul[1]= oldeul[1];
1089                 if(protectflag & OB_LOCK_ROTZ)
1090                         eul[2]= oldeul[2];
1091                 
1092                 EulToQuat(eul, quat);
1093                 /* quaternions flip w sign to accumulate rotations correctly */
1094                 if( (quat1[0]<0.0f && quat[0]>0.0f) || (quat1[0]>0.0f && quat[0]<0.0f) ) {
1095                         QuatMulf(quat, -1.0f);
1096                 }
1097         }
1098 }
1099
1100 /* ************************** WARP *************************** */
1101
1102 /* warp is done fully in view space */
1103 void initWarp(TransInfo *t) 
1104 {
1105         float max[3], min[3];
1106         int i;
1107         
1108         calculateCenterCursor(t);
1109         t->idx_max = 0;
1110         t->num.idx_max = 0;
1111         t->transform = Warp;
1112         t->snap[0] = 0.0f;
1113         t->snap[1] = 5.0f;
1114         t->snap[2] = 1.0f;
1115         
1116         t->fac = (float)(t->center2d[0] - t->imval[0]);
1117         
1118         /* we need min/max in view space */
1119         for(i = 0; i < t->total; i++) {
1120                 float center[3];
1121                 VECCOPY(center, t->data[i].center);
1122                 Mat3MulVecfl(t->data[i].mtx, center);
1123                 Mat4MulVecfl(t->viewmat, center);
1124                 VecSubf(center, center, t->viewmat[3]);
1125                 if (i)
1126                         MinMax3(min, max, center);
1127                 else {
1128                         VECCOPY(max, center);
1129                         VECCOPY(min, center);
1130                 }
1131         }
1132
1133         t->center[0]= (min[0]+max[0])/2.0f;
1134         t->center[1]= (min[1]+max[1])/2.0f;
1135         t->center[2]= (min[2]+max[2])/2.0f;
1136         
1137         t->val= (max[0]-min[0])/2.0f;   // t->val is free variable
1138 }
1139
1140
1141 int Warp(TransInfo *t, short mval[2])
1142 {
1143         TransData *td = t->data;
1144         float vec[3], circumfac, dist, phi0, co, si, *curs, cursor[3], gcursor[3];
1145         int i;
1146         char str[50];
1147         
1148         curs= give_cursor();
1149         /*
1150          * gcursor is the one used for helpline.
1151          * It has to be in the same space as the drawing loop
1152          * (that means it needs to be in the object's space when in edit mode and
1153          *  in global space in object mode)
1154          *
1155          * cursor is used for calculations.
1156          * It needs to be in view space, but we need to take object's offset
1157          * into account if in Edit mode.
1158          */
1159         VECCOPY(cursor, curs);
1160         VECCOPY(gcursor, cursor);       
1161         if (t->flag & T_EDIT) {
1162                 VecSubf(cursor, cursor, G.obedit->obmat[3]);
1163                 VecSubf(gcursor, gcursor, G.obedit->obmat[3]);
1164                 Mat3MulVecfl(t->data->smtx, gcursor);
1165         }
1166         Mat4MulVecfl(t->viewmat, cursor);
1167         VecSubf(cursor, cursor, t->viewmat[3]);
1168
1169         // amount of degrees for warp, 450 = allow to create 360 degree warp
1170         circumfac= 450.0f*(mval[1] - t->imval[1]) / (float)(curarea->winy);
1171         circumfac+= 90.0f;
1172
1173         snapGrid(t, &circumfac);
1174         applyNumInput(&t->num, &circumfac);
1175         
1176         /* header print for NumInput */
1177         if (hasNumInput(&t->num)) {
1178                 char c[20];
1179                 
1180                 outputNumInput(&(t->num), c);
1181                 
1182                 sprintf(str, "Warp: %s", c);
1183         }
1184         else {
1185                 /* default header print */
1186                 sprintf(str, "Warp: %.3f", circumfac);
1187         }
1188         
1189         circumfac*= (float)(-M_PI/360.0);
1190         
1191         for(i = 0 ; i < t->total; i++, td++) {
1192                 float loc[3];
1193                 if (td->flag & TD_NOACTION)
1194                         break;
1195
1196                 /* translate point to centre, rotate in such a way that outline==distance */
1197                 
1198                 VECCOPY(vec, td->iloc);
1199                 Mat3MulVecfl(td->mtx, vec);
1200                 Mat4MulVecfl(t->viewmat, vec);
1201                 VecSubf(vec, vec, t->viewmat[3]);
1202                 
1203                 dist= vec[0]-cursor[0];
1204
1205                 phi0= (circumfac*dist/t->val);  // t->val is X dimension projected boundbox
1206                 
1207                 vec[1]= (vec[1]-cursor[1]);
1208                 
1209                 co= (float)cos(phi0);
1210                 si= (float)sin(phi0);
1211                 loc[0]= -si*vec[1]+cursor[0];
1212                 loc[1]= co*vec[1]+cursor[1];
1213                 loc[2]= vec[2];
1214                 
1215                 Mat4MulVecfl(t->viewinv, loc);
1216                 VecSubf(loc, loc, t->viewinv[3]);
1217                 Mat3MulVecfl(td->smtx, loc);
1218
1219                 VecSubf(loc, loc, td->iloc);
1220                 VecMulf(loc, td->factor);
1221                 VecAddf(td->loc, td->iloc, loc);
1222         }
1223
1224         recalcData(t);
1225         
1226         headerprint(str);
1227         
1228         viewRedrawForce(t);
1229         
1230         helpline(t, gcursor);
1231         
1232         return 1;
1233 }
1234
1235 /* ************************** SHEAR *************************** */
1236
1237 void initShear(TransInfo *t) 
1238 {
1239         t->idx_max = 0;
1240         t->num.idx_max = 0;
1241         t->snap[0] = 0.0f;
1242         t->snap[1] = 0.1f;
1243         t->snap[2] = t->snap[1] * 0.1f;
1244         t->transform = Shear;
1245 }
1246
1247 int Shear(TransInfo *t, short mval[2]) 
1248 {
1249         TransData *td = t->data;
1250         float vec[3];
1251         float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
1252         float value;
1253         int i;
1254         char str[50];
1255
1256         Mat3CpyMat4(persmat, t->viewmat);
1257         Mat3Inv(persinv, persmat);
1258
1259         value = 0.05f * InputHorizontalAbsolute(t, mval);
1260
1261         snapGrid(t, &value);
1262
1263         applyNumInput(&t->num, &value);
1264
1265         /* header print for NumInput */
1266         if (hasNumInput(&t->num)) {
1267                 char c[20];
1268
1269                 outputNumInput(&(t->num), c);
1270
1271                 sprintf(str, "Shear: %s %s", c, t->proptext);
1272         }
1273         else {
1274                 /* default header print */
1275                 sprintf(str, "Shear: %.3f %s", value, t->proptext);
1276         }
1277         
1278         Mat3One(smat);
1279         smat[1][0] = value;
1280         Mat3MulMat3(tmat, smat, persmat);
1281         Mat3MulMat3(totmat, persinv, tmat);
1282         
1283         for(i = 0 ; i < t->total; i++, td++) {
1284                 if (td->flag & TD_NOACTION)
1285                         break;
1286
1287                 if (G.obedit) {
1288                         float mat3[3][3];
1289                         Mat3MulMat3(mat3, totmat, td->mtx);
1290                         Mat3MulMat3(tmat, td->smtx, mat3);
1291                 }
1292                 else {
1293                         Mat3CpyMat3(tmat, totmat);
1294                 }
1295                 VecSubf(vec, td->center, t->center);
1296
1297                 Mat3MulVecfl(tmat, vec);
1298
1299                 VecAddf(vec, vec, t->center);
1300                 VecSubf(vec, vec, td->center);
1301
1302                 VecMulf(vec, td->factor);
1303
1304                 VecAddf(td->loc, td->iloc, vec);
1305         }
1306
1307         recalcData(t);
1308
1309         headerprint(str);
1310
1311         viewRedrawForce(t);
1312
1313         helpline (t, t->center);
1314
1315         return 1;
1316 }
1317
1318 /* ************************** RESIZE *************************** */
1319
1320 void initResize(TransInfo *t) 
1321 {
1322         t->fac = (float)sqrt(
1323                 (
1324                         ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
1325                 +
1326                         ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
1327                 ) );
1328
1329         if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
1330         
1331         t->idx_max = 2;
1332         t->num.idx_max = 2;
1333         t->snap[0] = 0.0f;
1334         t->snap[1] = 0.1f;
1335         t->snap[2] = t->snap[1] * 0.1f;
1336         t->transform = Resize;
1337 }
1338
1339 static void headerResize(TransInfo *t, float vec[3], char *str) {
1340         char tvec[60];
1341         if (hasNumInput(&t->num)) {
1342                 outputNumInput(&(t->num), tvec);
1343         }
1344         else {
1345                 sprintf(&tvec[0], "%.4f", vec[0]);
1346                 sprintf(&tvec[20], "%.4f", vec[1]);
1347                 sprintf(&tvec[40], "%.4f", vec[2]);
1348         }
1349
1350         if (t->con.mode & CON_APPLY) {
1351                 switch(t->num.idx_max) {
1352                 case 0:
1353                         sprintf(str, "Scale: %s%s %s", &tvec[0], t->con.text, t->proptext);
1354                         break;
1355                 case 1:
1356                         sprintf(str, "Scale: %s : %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
1357                         break;
1358                 case 2:
1359                         sprintf(str, "Scale: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
1360                 }
1361         }
1362         else {
1363                 if (t->flag & T_2D_EDIT)
1364                         sprintf(str, "Scale X: %s   Y: %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
1365                 else
1366                         sprintf(str, "Scale X: %s   Y: %s  Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
1367         }
1368 }
1369
1370 #define SIGN(a)         (a<-FLT_EPSILON?1:a>FLT_EPSILON?2:3)
1371 #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)
1372
1373 /* smat is reference matrix, only scaled */
1374 static void TransMat3ToSize( float mat[][3], float smat[][3], float *size)
1375 {
1376         float vec[3];
1377         
1378         VecCopyf(vec, mat[0]);
1379         size[0]= Normalise(vec);
1380         VecCopyf(vec, mat[1]);
1381         size[1]= Normalise(vec);
1382         VecCopyf(vec, mat[2]);
1383         size[2]= Normalise(vec);
1384         
1385         /* first tried with dotproduct... but the sign flip is crucial */
1386         if( VECSIGNFLIP(mat[0], smat[0]) ) size[0]= -size[0]; 
1387         if( VECSIGNFLIP(mat[1], smat[1]) ) size[1]= -size[1]; 
1388         if( VECSIGNFLIP(mat[2], smat[2]) ) size[2]= -size[2]; 
1389 }
1390
1391
1392 static void ElementResize(TransInfo *t, TransData *td, float mat[3][3]) {
1393         float tmat[3][3], smat[3][3], center[3];
1394         float vec[3];
1395
1396         if (t->flag & T_EDIT) {
1397                 Mat3MulMat3(smat, mat, td->mtx);
1398                 Mat3MulMat3(tmat, td->smtx, smat);
1399         }
1400         else {
1401                 Mat3CpyMat3(tmat, mat);
1402         }
1403
1404         if (t->con.applySize) {
1405                 t->con.applySize(t, td, tmat);
1406         }
1407
1408         /* local constraint shouldn't alter center */
1409         if (t->around == V3D_LOCAL) {
1410                 if (t->flag & T_OBJECT) {
1411                         VECCOPY(center, td->center);
1412                 }
1413                 else if (t->flag & T_EDIT) {
1414                         
1415                         if(G.vd->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
1416                                 VECCOPY(center, td->center);
1417                         }
1418                         else {
1419                                 VECCOPY(center, t->center);
1420                         }
1421                 }
1422                 else {
1423                         VECCOPY(center, t->center);
1424                 }
1425         }
1426         else {
1427                 VECCOPY(center, t->center);
1428         }
1429
1430         if (td->ext) {
1431                 float fsize[3];
1432
1433                 if (t->flag & (T_OBJECT|T_TEXTURE)) {
1434                         float obsizemat[3][3];
1435                         // Reorient the size mat to fit the oriented object.
1436                         Mat3MulMat3(obsizemat, tmat, td->axismtx);
1437                         //printmatrix3("obsizemat", obsizemat);
1438                         TransMat3ToSize(obsizemat, td->axismtx, fsize);
1439                         //printvecf("fsize", fsize);
1440                 }
1441                 else {
1442                         Mat3ToSize(tmat, fsize);
1443                 }
1444                 
1445                 protectedSizeBits(td->protectflag, fsize);
1446                 
1447                 if ((t->flag & T_V3D_ALIGN)==0) {       // align mode doesn't rotate objects itself
1448                         /* handle ipokeys? */
1449                         if(td->tdi) {
1450                                 TransDataIpokey *tdi= td->tdi;
1451                                 /* calculate delta size (equal for size and dsize) */
1452                                 
1453                                 vec[0]= (tdi->oldsize[0])*(fsize[0] -1.0f) * td->factor;
1454                                 vec[1]= (tdi->oldsize[1])*(fsize[1] -1.0f) * td->factor;
1455                                 vec[2]= (tdi->oldsize[2])*(fsize[2] -1.0f) * td->factor;
1456                                 
1457                                 add_tdi_poin(tdi->sizex, tdi->oldsize,   vec[0]);
1458                                 add_tdi_poin(tdi->sizey, tdi->oldsize+1, vec[1]);
1459                                 add_tdi_poin(tdi->sizez, tdi->oldsize+2, vec[2]);
1460                                 
1461                         }
1462                         else if((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)){
1463                                 /* scale val and reset size */
1464                                 *td->val = td->ival * fsize[0] * td->factor;
1465
1466                                 td->ext->size[0] = td->ext->isize[0];
1467                                 td->ext->size[1] = td->ext->isize[1];
1468                                 td->ext->size[2] = td->ext->isize[2];
1469                         }
1470                         else {
1471                                 /* Reset val if SINGLESIZE but using a constraint */
1472                                 if (td->flag & TD_SINGLESIZE)
1473                                         *td->val = td->ival;
1474
1475                                 td->ext->size[0] = td->ext->isize[0] * (fsize[0]) * td->factor;
1476                                 td->ext->size[1] = td->ext->isize[1] * (fsize[1]) * td->factor;
1477                                 td->ext->size[2] = td->ext->isize[2] * (fsize[2]) * td->factor;
1478                         }
1479                 }
1480         }
1481         /* For individual element center, Editmode need to use iloc */
1482         if (t->flag & T_POINTS)
1483                 VecSubf(vec, td->iloc, center);
1484         else
1485                 VecSubf(vec, td->center, center);
1486
1487         Mat3MulVecfl(tmat, vec);
1488
1489         VecAddf(vec, vec, center);
1490         if (t->flag & T_POINTS)
1491                 VecSubf(vec, vec, td->iloc);
1492         else
1493                 VecSubf(vec, vec, td->center);
1494
1495         VecMulf(vec, td->factor);
1496
1497         if (t->flag & T_OBJECT) {
1498                 Mat3MulVecfl(td->smtx, vec);
1499         }
1500
1501         protectedTransBits(td->protectflag, vec);
1502
1503         if(td->tdi) {
1504                 TransDataIpokey *tdi= td->tdi;
1505                 add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
1506                 add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
1507                 add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
1508         }
1509         else VecAddf(td->loc, td->iloc, vec);
1510 }
1511
1512 int Resize(TransInfo *t, short mval[2]) 
1513 {
1514         TransData *td;
1515         float size[3], mat[3][3];
1516         float ratio;
1517         int i;
1518         char str[200];
1519
1520         /* for manipulator, center handle, the scaling can't be done relative to center */
1521         if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) {
1522                 ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f;
1523         }
1524         else {
1525                 ratio = InputScaleRatio(t, mval);
1526                 
1527                 /* flip scale, but not for manipulator center handle */
1528                 if      ((t->center2d[0] - mval[0]) * (t->center2d[0] - t->imval[0]) + 
1529                          (t->center2d[1] - mval[1]) * (t->center2d[1] - t->imval[1]) < 0)
1530                                 ratio *= -1.0f;
1531         }
1532         
1533         size[0] = size[1] = size[2] = ratio;
1534
1535         snapGrid(t, size);
1536
1537         if (hasNumInput(&t->num)) {
1538                 applyNumInput(&t->num, size);
1539                 constraintNumInput(t, size);
1540         }
1541
1542         SizeToMat3(size, mat);
1543
1544         if (t->con.applySize) {
1545                 t->con.applySize(t, NULL, mat);
1546         }
1547
1548         Mat3CpyMat3(t->mat, mat);       // used in manipulator
1549         
1550         headerResize(t, size, str);
1551
1552         for(i = 0, td=t->data; i < t->total; i++, td++) {
1553                 if (td->flag & TD_NOACTION)
1554                         break;
1555                 
1556                 ElementResize(t, td, mat);
1557         }
1558
1559         /* evil hack - redo resize if cliiping needeed */
1560         if (t->flag & T_CLIP_UV && clipUVTransform(t, size, 1)) {
1561                 SizeToMat3(size, mat);
1562
1563                 if (t->con.applySize)
1564                         t->con.applySize(t, NULL, mat);
1565
1566                 for(i = 0, td=t->data; i < t->total; i++, td++)
1567                         ElementResize(t, td, mat);
1568         }
1569
1570         recalcData(t);
1571
1572         headerprint(str);
1573
1574         viewRedrawForce(t);
1575
1576         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
1577
1578         return 1;
1579 }
1580
1581 /* ************************** TOSPHERE *************************** */
1582
1583 void initToSphere(TransInfo *t) 
1584 {
1585         TransData *td = t->data;
1586         int i;
1587
1588         // Calculate average radius
1589         for(i = 0 ; i < t->total; i++, td++) {
1590                 t->val += VecLenf(t->center, td->iloc);
1591         }
1592
1593         t->val /= (float)t->total;
1594
1595         t->idx_max = 0;
1596         t->num.idx_max = 0;
1597         t->snap[0] = 0.0f;
1598         t->snap[1] = 0.1f;
1599         t->snap[2] = t->snap[1] * 0.1f;
1600         t->transform = ToSphere;
1601 }
1602
1603
1604
1605 int ToSphere(TransInfo *t, short mval[2]) 
1606 {
1607         float vec[3];
1608         float ratio, radius;
1609         int i;
1610         char str[50];
1611         TransData *td = t->data;
1612
1613         ratio = InputHorizontalRatio(t, mval);
1614
1615         snapGrid(t, &ratio);
1616
1617         applyNumInput(&t->num, &ratio);
1618
1619         if (ratio < 0)
1620                 ratio = 0.0f;
1621         else if (ratio > 1)
1622                 ratio = 1.0f;
1623
1624         /* header print for NumInput */
1625         if (hasNumInput(&t->num)) {
1626                 char c[20];
1627
1628                 outputNumInput(&(t->num), c);
1629
1630                 sprintf(str, "To Sphere: %s %s", c, t->proptext);
1631         }
1632         else {
1633                 /* default header print */
1634                 sprintf(str, "To Sphere: %.4f %s", ratio, t->proptext);
1635         }
1636         
1637         
1638         for(i = 0 ; i < t->total; i++, td++) {
1639                 float tratio;
1640                 if (td->flag & TD_NOACTION)
1641                         break;
1642
1643                 VecSubf(vec, td->iloc, t->center);
1644
1645                 radius = Normalise(vec);
1646
1647                 tratio = ratio * td->factor;
1648
1649                 VecMulf(vec, radius * (1.0f - tratio) + t->val * tratio);
1650
1651                 VecAddf(td->loc, t->center, vec);
1652         }
1653
1654         recalcData(t);
1655
1656         headerprint(str);
1657
1658         viewRedrawForce(t);
1659
1660         return 1;
1661 }
1662
1663 /* ************************** ROTATION *************************** */
1664
1665
1666 void initRotation(TransInfo *t) 
1667 {
1668         t->idx_max = 0;
1669         t->num.idx_max = 0;
1670         t->snap[0] = 0.0f;
1671         t->snap[1] = (float)((5.0/180)*M_PI);
1672         t->snap[2] = t->snap[1] * 0.2f;
1673         t->fac = 0;
1674         t->transform = Rotation;
1675 }
1676
1677 static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3]) {
1678         float vec[3], totmat[3][3], smat[3][3];
1679         float eul[3], fmat[3][3], quat[4];
1680
1681         if (t->flag & T_POINTS) {
1682                 Mat3MulMat3(totmat, mat, td->mtx);
1683                 Mat3MulMat3(smat, td->smtx, totmat);
1684                 
1685                 VecSubf(vec, td->iloc, t->center);
1686                 Mat3MulVecfl(smat, vec);
1687                 
1688                 VecAddf(td->loc, vec, t->center);
1689
1690                 if(td->flag & TD_USEQUAT) {
1691                         Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
1692                         Mat3ToQuat(fmat, quat); // Actual transform
1693                         QuatMul(td->ext->quat, quat, td->ext->iquat);
1694                 }
1695         }
1696         else {
1697                 /* translation */
1698                 
1699                 VecSubf(vec, td->center, t->center);
1700                 Mat3MulVecfl(mat, vec);
1701                 VecAddf(vec, vec, t->center);
1702                 /* vec now is the location where the object has to be */
1703                 VecSubf(vec, vec, td->center);
1704                 Mat3MulVecfl(td->smtx, vec);
1705
1706                 protectedTransBits(td->protectflag, vec);
1707
1708                 if(td->tdi) {
1709                         TransDataIpokey *tdi= td->tdi;
1710                         add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
1711                         add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
1712                         add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
1713                 }
1714                 else VecAddf(td->loc, td->iloc, vec);
1715
1716                 /* rotation */
1717                 
1718                 if(td->flag & TD_USEQUAT) {
1719                         Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
1720                         Mat3ToQuat(fmat, quat); // Actual transform
1721                         
1722                         QuatMul(td->ext->quat, quat, td->ext->iquat);
1723                         /* this function works on end result */
1724                         protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
1725                 }
1726                 else if ((t->flag & T_V3D_ALIGN)==0) {  // align mode doesn't rotate objects itself
1727                         float obmat[3][3];
1728                         
1729                         /* are there ipo keys? */
1730                         if(td->tdi) {
1731                                 TransDataIpokey *tdi= td->tdi;
1732                                 float rot[3];
1733                                 
1734                                 /* calculate the total rotatation in eulers */
1735                                 VecAddf(eul, td->ext->irot, td->ext->drot);
1736                                 EulToMat3(eul, obmat);
1737                                 /* mat = transform, obmat = object rotation */
1738                                 Mat3MulMat3(fmat, mat, obmat);
1739                                 Mat3ToEul(fmat, eul);
1740                                 compatible_eul(eul, td->ext->irot);
1741                                 
1742                                 /* correct back for delta rot */
1743                                 if(tdi->flag & TOB_IPODROT) {
1744                                         VecSubf(rot, eul, td->ext->irot);
1745                                 }
1746                                 else {
1747                                         VecSubf(rot, eul, td->ext->drot);
1748                                 }
1749                                 
1750                                 VecMulf(rot, (float)(9.0/M_PI_2));
1751                                 VecSubf(rot, rot, tdi->oldrot);
1752                                 
1753                                 protectedRotateBits(td->protectflag, rot, tdi->oldrot);
1754                                 
1755                                 add_tdi_poin(tdi->rotx, tdi->oldrot, rot[0]);
1756                                 add_tdi_poin(tdi->roty, tdi->oldrot+1, rot[1]);
1757                                 add_tdi_poin(tdi->rotz, tdi->oldrot+2, rot[2]);
1758                         }
1759                         else {
1760                                 Mat3MulMat3(totmat, mat, td->mtx);
1761                                 Mat3MulMat3(smat, td->smtx, totmat);
1762                                 
1763                                 /* calculate the total rotatation in eulers */
1764                                 VecAddf(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
1765                                 EulToMat3(eul, obmat);
1766                                 /* mat = transform, obmat = object rotation */
1767                                 Mat3MulMat3(fmat, smat, obmat);
1768                                 Mat3ToEul(fmat, eul);
1769                                 compatible_eul(eul, td->ext->irot);
1770                                 
1771                                 /* correct back for delta rot */
1772                                 VecSubf(eul, eul, td->ext->drot);
1773                                 
1774                                 /* and apply */
1775                                 protectedRotateBits(td->protectflag, eul, td->ext->irot);
1776                                 VECCOPY(td->ext->rot, eul);
1777                         }
1778                 }
1779         }
1780 }
1781
1782 static void applyRotation(TransInfo *t, float angle, float axis[3]) 
1783 {
1784         TransData *td = t->data;
1785         float mat[3][3], center[3];
1786         int i;
1787
1788         /* saving original center */
1789         if (t->around == V3D_LOCAL) {
1790                 VECCOPY(center, t->center);
1791         }
1792
1793         VecRotToMat3(axis, angle, mat);
1794
1795         for(i = 0 ; i < t->total; i++, td++) {
1796
1797                 if (td->flag & TD_NOACTION)
1798                         break;
1799                 
1800                 /* local constraint shouldn't alter center */
1801                 if (t->around == V3D_LOCAL) {
1802                         if (t->flag & (T_OBJECT|T_POSE)) {
1803                                 VECCOPY(t->center, td->center);
1804                         }
1805                         else {
1806                                 if(G.vd->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
1807                                         VECCOPY(t->center, td->center);
1808                                 }
1809                         }
1810                 }
1811                 
1812                 if (t->con.applyRot) {
1813                         t->con.applyRot(t, td, axis);
1814                         VecRotToMat3(axis, angle * td->factor, mat);
1815                 }
1816                 else if (t->flag & T_PROP_EDIT) {
1817                         VecRotToMat3(axis, angle * td->factor, mat);
1818                 }
1819
1820                 ElementRotation(t, td, mat);
1821         }
1822
1823         /* restoring original center */
1824         if (t->around == V3D_LOCAL) {
1825                 VECCOPY(t->center, center);
1826         }
1827 }
1828
1829 int Rotation(TransInfo *t, short mval[2]) 
1830 {
1831         TransData *td = t->data;
1832         char str[50];
1833
1834         float final;
1835
1836         int dx2 = t->center2d[0] - mval[0];
1837         int dy2 = t->center2d[1] - mval[1];
1838         double B = sqrt(dx2*dx2+dy2*dy2);
1839
1840         int dx1 = t->center2d[0] - t->imval[0];
1841         int dy1 = t->center2d[1] - t->imval[1];
1842         double A = sqrt(dx1*dx1+dy1*dy1);
1843
1844         int dx3 = mval[0] - t->imval[0];
1845         int dy3 = mval[1] - t->imval[1];
1846                 /* use doubles here, to make sure a "1.0" (no rotation) doesnt become 9.999999e-01, which gives 0.02 for acos */
1847         double deler= ((double)((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3) ))
1848                 / (2.0 * (A*B?A*B:1.0));
1849         /* (A*B?A*B:1.0f) this takes care of potential divide by zero errors */
1850
1851         float dphi;
1852
1853         float axis[3];
1854         float mat[3][3];
1855
1856         VECCOPY(axis, t->viewinv[2]);
1857         VecMulf(axis, -1.0f);
1858         Normalise(axis);
1859
1860         dphi = saacos((float)deler);
1861         if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
1862
1863         if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
1864         else t->fac += dphi;
1865
1866         /*
1867         clamping angle between -2 PI and 2 PI (not sure if useful so commented out - theeth)
1868         if (t->fac >= 2 * M_PI)
1869                 t->fac -= 2 * M_PI;
1870         else if (t->fac <= -2 * M_PI)
1871                 t->fac -= -2 * M_PI;
1872         */
1873
1874         final = t->fac;
1875
1876         snapGrid(t, &final);
1877
1878         t->imval[0] = mval[0];
1879         t->imval[1] = mval[1];
1880
1881         if (t->con.applyRot) {
1882                 t->con.applyRot(t, NULL, axis);
1883         }
1884
1885         if (hasNumInput(&t->num)) {
1886                 char c[20];
1887
1888                 applyNumInput(&t->num, &final);
1889
1890                 outputNumInput(&(t->num), c);
1891
1892                 sprintf(str, "Rot: %s %s", &c[0], t->proptext);
1893
1894                 final *= (float)(M_PI / 180.0);
1895         }
1896         else {
1897                 sprintf(str, "Rot: %.2f%s %s", 180.0*final/M_PI, t->con.text, t->proptext);
1898         }
1899
1900         VecRotToMat3(axis, final * td->factor, mat);
1901
1902         t->val = final;                         // used in manipulator
1903         Mat3CpyMat3(t->mat, mat);       // used in manipulator
1904         
1905         applyRotation(t, final, axis);
1906         
1907         recalcData(t);
1908
1909         headerprint(str);
1910
1911         viewRedrawForce(t);
1912
1913         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
1914
1915         return 1;
1916 }
1917
1918
1919 /* ************************** TRACKBALL *************************** */
1920
1921 void initTrackball(TransInfo *t) 
1922 {
1923         t->idx_max = 1;
1924         t->num.idx_max = 1;
1925         t->snap[0] = 0.0f;
1926         t->snap[1] = (float)((5.0/180)*M_PI);
1927         t->snap[2] = t->snap[1] * 0.2f;
1928         t->fac = 0;
1929         t->transform = Trackball;
1930         
1931         t->flag |= T_NO_CONSTRAINT; /* making sure the flag is always set */
1932 }
1933
1934 static void applyTrackball(TransInfo *t, float axis1[3], float axis2[3], float angles[2])
1935 {
1936         TransData *td = t->data;
1937         float mat[3][3], smat[3][3], totmat[3][3];
1938         int i;
1939
1940         VecRotToMat3(axis1, angles[0], smat);
1941         VecRotToMat3(axis2, angles[1], totmat);
1942         
1943         Mat3MulMat3(mat, smat, totmat);
1944
1945         for(i = 0 ; i < t->total; i++, td++) {
1946                 if (td->flag & TD_NOACTION)
1947                         break;
1948                 
1949                 if (t->around == V3D_LOCAL) {
1950                         if (t->flag & T_OBJECT)
1951                                 VECCOPY(t->center, td->center); // not supported in editmode yet
1952                 }
1953                 
1954                 if (t->flag & T_PROP_EDIT) {
1955                         VecRotToMat3(axis1, td->factor * angles[0], smat);
1956                         VecRotToMat3(axis2, td->factor * angles[1], totmat);
1957                         
1958                         Mat3MulMat3(mat, smat, totmat);
1959                 }
1960
1961                 ElementRotation(t, td, mat);
1962         }
1963 }
1964
1965 int Trackball(TransInfo *t, short mval[2]) 
1966 {
1967         char str[80];
1968         float axis1[3], axis2[3];
1969         float mat[3][3], totmat[3][3], smat[3][3];
1970         float phi[2];
1971         
1972         VECCOPY(axis1, t->persinv[0]);
1973         VECCOPY(axis2, t->persinv[1]);
1974         Normalise(axis1);
1975         Normalise(axis2);
1976         
1977         /* factore has to become setting or so */
1978         phi[0]= 0.01f*(float)( t->imval[1] - mval[1] );
1979         phi[1]= 0.01f*(float)( mval[0] - t->imval[0] );
1980         
1981         //if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
1982         //else t->fac += dphi;
1983         
1984         snapGrid(t, phi);
1985         
1986         if (hasNumInput(&t->num)) {
1987                 char c[40];
1988                 
1989                 applyNumInput(&t->num, phi);
1990                 
1991                 outputNumInput(&(t->num), c);
1992                 
1993                 sprintf(str, "Trackball: %s %s %s", &c[0], &c[20], t->proptext);
1994                 
1995                 phi[0] *= (float)(M_PI / 180.0);
1996                 phi[1] *= (float)(M_PI / 180.0);
1997         }
1998         else {
1999                 sprintf(str, "Trackball: %.2f %.2f %s", 180.0*phi[0]/M_PI, 180.0*phi[1]/M_PI, t->proptext);
2000         }
2001         
2002         VecRotToMat3(axis1, phi[0], smat);
2003         VecRotToMat3(axis2, phi[1], totmat);
2004         
2005         Mat3MulMat3(mat, smat, totmat);
2006         
2007         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2008         
2009         applyTrackball(t, axis1, axis2, phi);
2010         
2011         recalcData(t);
2012         
2013         headerprint(str);
2014         
2015         viewRedrawForce(t);
2016         
2017         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
2018         
2019         return 1;
2020 }
2021
2022 /* ************************** TRANSLATION *************************** */
2023         
2024 void initTranslation(TransInfo *t) 
2025 {
2026         t->idx_max = (t->flag & T_2D_EDIT)? 1: 2;
2027         t->num.idx_max = t->idx_max;
2028         t->transform = Translation;
2029         
2030         if(t->spacetype == SPACE_VIEW3D) {
2031                 /* initgrabz() defines a factor for perspective depth correction, used in window_to_3d() */
2032                 if(t->flag & (T_EDIT|T_POSE)) {
2033                         Object *ob= G.obedit?G.obedit:t->poseobj;
2034                         float vec[3];
2035                         
2036                         VECCOPY(vec, t->center);
2037                         Mat4MulVecfl(ob->obmat, vec);
2038                         initgrabz(vec[0], vec[1], vec[2]);
2039                 }
2040                 else initgrabz(t->center[0], t->center[1], t->center[2]); 
2041
2042                 t->snap[0] = 0.0f;
2043                 t->snap[1] = G.vd->gridview * 1.0f;
2044                 t->snap[2] = t->snap[1] * 0.1f;
2045         }
2046         else if(t->spacetype == SPACE_IMAGE) {
2047                 t->snap[0] = 0.0f;
2048                 t->snap[1] = 0.125f;
2049                 t->snap[2] = 0.0625f;
2050         }
2051         else {
2052                 t->snap[0] = 0.0f;
2053                 t->snap[1] = t->snap[2] = 1.0f;
2054         }
2055 }
2056
2057 static void headerTranslation(TransInfo *t, float vec[3], char *str) {
2058         char tvec[60];
2059         char distvec[20];
2060         float dvec[3];
2061         float dist;
2062         
2063         convertVecToDisplayNum(vec, dvec);
2064
2065         if (hasNumInput(&t->num)) {
2066                 outputNumInput(&(t->num), tvec);
2067                 dist = VecLength(t->num.val);
2068         }
2069         else {
2070                 dist = VecLength(vec);
2071                 sprintf(&tvec[0], "%.4f", dvec[0]);
2072                 sprintf(&tvec[20], "%.4f", dvec[1]);
2073                 sprintf(&tvec[40], "%.4f", dvec[2]);
2074         }
2075
2076         if( dist > 1e10 || dist < -1e10 )       /* prevent string buffer overflow */
2077                 sprintf(distvec, "%.4e", dist);
2078         else
2079                 sprintf(distvec, "%.4f", dist);
2080
2081         if (t->con.mode & CON_APPLY) {
2082                 switch(t->num.idx_max) {
2083                 case 0:
2084                         sprintf(str, "D: %s (%s)%s %s", &tvec[0], distvec, t->con.text, t->proptext);
2085                         break;
2086                 case 1:
2087                         sprintf(str, "D: %s   D: %s (%s)%s %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext);
2088                         break;
2089                 case 2:
2090                         sprintf(str, "D: %s   D: %s  D: %s (%s)%s %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext);
2091                 }
2092         }
2093         else {
2094                 if(t->flag & T_2D_EDIT)
2095                         sprintf(str, "Dx: %s   Dy: %s (%s)%s %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext);
2096                 else
2097                         sprintf(str, "Dx: %s   Dy: %s  Dz: %s (%s)%s %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext);
2098         }
2099 }
2100
2101 static void applyTranslation(TransInfo *t, float vec[3]) {
2102         TransData *td = t->data;
2103         float tvec[3];
2104         int i;
2105
2106         for(i = 0 ; i < t->total; i++, td++) {
2107                 if (td->flag & TD_NOACTION)
2108                         break;
2109
2110                 if (t->con.applyVec) {
2111                         float pvec[3];
2112                         t->con.applyVec(t, td, vec, tvec, pvec);
2113                 }
2114                 else {
2115                         VECCOPY(tvec, vec);
2116                 }
2117
2118                 Mat3MulVecfl(td->smtx, tvec);
2119                 VecMulf(tvec, td->factor);
2120                 
2121                 protectedTransBits(td->protectflag, tvec);
2122                 
2123                 /* transdata ipokey */
2124                 if(td->tdi) {
2125                         TransDataIpokey *tdi= td->tdi;
2126                         add_tdi_poin(tdi->locx, tdi->oldloc, tvec[0]);
2127                         add_tdi_poin(tdi->locy, tdi->oldloc+1, tvec[1]);
2128                         add_tdi_poin(tdi->locz, tdi->oldloc+2, tvec[2]);
2129                 }
2130                 else VecAddf(td->loc, td->iloc, tvec);
2131         }
2132 }
2133
2134 /* uses t->vec to store actual translation in */
2135 int Translation(TransInfo *t, short mval[2]) 
2136 {
2137         float tvec[3];
2138         char str[200];
2139         
2140         if(t->flag & T_SHIFT_MOD) {
2141                 float dvec[3];
2142                 /* calculate the main translation and the precise one separate */
2143                 convertViewVec(t, dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
2144                 VecMulf(dvec, 0.1f);
2145                 convertViewVec(t, t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
2146                 VecAddf(t->vec, t->vec, dvec);
2147         }
2148         else convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
2149
2150         if (t->con.mode & CON_APPLY) {
2151                 float pvec[3] = {0.0f, 0.0f, 0.0f};
2152                 t->con.applyVec(t, NULL, t->vec, tvec, pvec);
2153                 VECCOPY(t->vec, tvec);
2154                 headerTranslation(t, pvec, str);
2155         }
2156         else {
2157                 snapGrid(t, t->vec);
2158                 applyNumInput(&t->num, t->vec);
2159                 headerTranslation(t, t->vec, str);
2160         }
2161
2162         applyTranslation(t, t->vec);
2163
2164         /* evil hack - redo translation if cliiping needeed */
2165         if (t->flag & T_CLIP_UV && clipUVTransform(t, t->vec, 0))
2166                 applyTranslation(t, t->vec);
2167
2168         recalcData(t);
2169
2170         headerprint(str);
2171
2172         viewRedrawForce(t);
2173
2174         return 1;
2175 }
2176
2177 /* ************************** SHRINK/FATTEN *************************** */
2178
2179 void initShrinkFatten(TransInfo *t) 
2180 {
2181         if (G.obedit==NULL || G.obedit->type != OB_MESH) {
2182                 initTransModeFlags(t, TFM_RESIZE);
2183                 initResize(t);
2184                 return;
2185         }
2186
2187         t->idx_max = 0;
2188         t->num.idx_max = 0;
2189         t->snap[0] = 0.0f;
2190         t->snap[1] = 1.0f;
2191         t->snap[2] = t->snap[1] * 0.1f;
2192         t->transform = ShrinkFatten;
2193 }
2194
2195
2196
2197 int ShrinkFatten(TransInfo *t, short mval[2]) 
2198 {
2199         float vec[3];
2200         float distance;
2201         int i;
2202         char str[50];
2203         TransData *td = t->data;
2204
2205         distance = -InputVerticalAbsolute(t, mval);
2206
2207         snapGrid(t, &distance);
2208
2209         applyNumInput(&t->num, &distance);
2210
2211         /* header print for NumInput */
2212         if (hasNumInput(&t->num)) {
2213                 char c[20];
2214
2215                 outputNumInput(&(t->num), c);
2216
2217                 sprintf(str, "Shrink/Fatten: %s %s", c, t->proptext);
2218         }
2219         else {
2220                 /* default header print */
2221                 sprintf(str, "Shrink/Fatten: %.4f %s", distance, t->proptext);
2222         }
2223         
2224         
2225         for(i = 0 ; i < t->total; i++, td++) {
2226                 if (td->flag & TD_NOACTION)
2227                         break;
2228
2229                 VECCOPY(vec, td->axismtx[2]);
2230                 VecMulf(vec, distance);
2231                 VecMulf(vec, td->factor);
2232
2233                 VecAddf(td->loc, td->iloc, vec);
2234         }
2235
2236         recalcData(t);
2237
2238         headerprint(str);
2239
2240         viewRedrawForce(t);
2241
2242         return 1;
2243 }
2244
2245 /* ************************** TILT *************************** */
2246
2247 void initTilt(TransInfo *t) 
2248 {
2249         t->idx_max = 0;
2250         t->num.idx_max = 0;
2251         t->snap[0] = 0.0f;
2252         t->snap[1] = (float)((5.0/180)*M_PI);
2253         t->snap[2] = t->snap[1] * 0.2f;
2254         t->fac = 0;
2255         t->transform = Tilt;
2256 }
2257
2258
2259
2260 int Tilt(TransInfo *t, short mval[2]) 
2261 {
2262         TransData *td = t->data;
2263         int i;
2264         char str[50];
2265
2266         float final;
2267
2268         int dx2 = t->center2d[0] - mval[0];
2269         int dy2 = t->center2d[1] - mval[1];
2270         float B = (float)sqrt(dx2*dx2+dy2*dy2);
2271
2272         int dx1 = t->center2d[0] - t->imval[0];
2273         int dy1 = t->center2d[1] - t->imval[1];
2274         float A = (float)sqrt(dx1*dx1+dy1*dy1);
2275
2276         int dx3 = mval[0] - t->imval[0];
2277         int dy3 = mval[1] - t->imval[1];
2278
2279         float deler= ((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3))
2280                 / (2 * A * B);
2281
2282         float dphi;
2283
2284         dphi = saacos(deler);
2285         if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
2286
2287         if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
2288         else t->fac += dphi;
2289
2290         final = t->fac;
2291
2292         snapGrid(t, &final);
2293
2294         t->imval[0] = mval[0];
2295         t->imval[1] = mval[1];
2296
2297         if (hasNumInput(&t->num)) {
2298                 char c[20];
2299
2300                 applyNumInput(&t->num, &final);
2301
2302                 outputNumInput(&(t->num), c);
2303
2304                 sprintf(str, "Tilt: %s %s", &c[0], t->proptext);
2305
2306                 final *= (float)(M_PI / 180.0);
2307         }
2308         else {
2309                 sprintf(str, "Tilt: %.2f %s", 180.0*final/M_PI, t->proptext);
2310         }
2311
2312         for(i = 0 ; i < t->total; i++, td++) {
2313                 if (td->flag & TD_NOACTION)
2314                         break;
2315
2316                 if (td->val) {
2317                         *td->val = td->ival + final * td->factor;
2318                 }
2319         }
2320
2321         recalcData(t);
2322
2323         headerprint(str);
2324
2325         viewRedrawForce(t);
2326
2327         helpline (t, t->center);
2328
2329         return 1;
2330 }
2331
2332 /* ************************** PUSH/PULL *************************** */
2333
2334 void initPushPull(TransInfo *t) 
2335 {
2336         t->idx_max = 0;
2337         t->num.idx_max = 0;
2338         t->snap[0] = 0.0f;
2339         t->snap[1] = 1.0f;
2340         t->snap[2] = t->snap[1] * 0.1f;
2341         t->transform = PushPull;
2342 }
2343
2344
2345
2346 int PushPull(TransInfo *t, short mval[2]) 
2347 {
2348         float vec[3], axis[3];
2349         float distance;
2350         int i;
2351         char str[50];
2352         TransData *td = t->data;
2353
2354         distance = InputVerticalAbsolute(t, mval);
2355
2356         snapGrid(t, &distance);
2357
2358         applyNumInput(&t->num, &distance);
2359
2360         /* header print for NumInput */
2361         if (hasNumInput(&t->num)) {
2362                 char c[20];
2363
2364                 outputNumInput(&(t->num), c);
2365
2366                 sprintf(str, "Push/Pull: %s%s %s", c, t->con.text, t->proptext);
2367         }
2368         else {
2369                 /* default header print */
2370                 sprintf(str, "Push/Pull: %.4f%s %s", distance, t->con.text, t->proptext);
2371         }
2372         
2373         if (t->con.applyRot && t->con.mode & CON_APPLY) {
2374                 t->con.applyRot(t, NULL, axis);
2375         }
2376         
2377         for(i = 0 ; i < t->total; i++, td++) {
2378                 if (td->flag & TD_NOACTION)
2379                         break;
2380
2381                 VecSubf(vec, t->center, td->center);
2382                 if (t->con.applyRot && t->con.mode & CON_APPLY) {
2383                         t->con.applyRot(t, td, axis);
2384                         if (isLockConstraint(t)) {
2385                                 float dvec[3];
2386                                 Projf(dvec, vec, axis);
2387                                 VecSubf(vec, vec, dvec);
2388                         }
2389                         else {
2390                                 Projf(vec, vec, axis);
2391                         }
2392                 }
2393                 Normalise(vec);
2394                 VecMulf(vec, distance);
2395                 VecMulf(vec, td->factor);
2396
2397                 VecAddf(td->loc, td->iloc, vec);
2398         }
2399
2400         recalcData(t);
2401
2402         headerprint(str);
2403
2404         viewRedrawForce(t);
2405
2406         return 1;
2407 }
2408
2409 /* ************************** CREASE *************************** */
2410
2411 void initCrease(TransInfo *t) 
2412 {
2413         t->idx_max = 0;
2414         t->num.idx_max = 0;
2415         t->snap[0] = 0.0f;
2416         t->snap[1] = 0.1f;
2417         t->snap[2] = t->snap[1] * 0.1f;
2418         t->transform = Crease;
2419         t->fac = (float)sqrt(
2420                 (
2421                         ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
2422                 +
2423                         ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
2424                 ) );
2425
2426         if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
2427 }
2428
2429 int Crease(TransInfo *t, short mval[2]) 
2430 {
2431         TransData *td = t->data;
2432         float crease;
2433         int i;
2434         char str[50];
2435
2436                 
2437         if(t->flag & T_SHIFT_MOD) {
2438                 /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
2439                 float dx= (float)(t->center2d[0] - t->shiftmval[0]);
2440                 float dy= (float)(t->center2d[1] - t->shiftmval[1]);
2441                 crease = (float)sqrt( dx*dx + dy*dy)/t->fac;
2442                 
2443                 dx= (float)(t->center2d[0] - mval[0]);
2444                 dy= (float)(t->center2d[1] - mval[1]);
2445                 crease+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -crease);
2446                 
2447         }
2448         else {
2449                 float dx= (float)(t->center2d[0] - mval[0]);
2450                 float dy= (float)(t->center2d[1] - mval[1]);
2451                 crease = (float)sqrt( dx*dx + dy*dy)/t->fac;
2452         }
2453
2454         crease -= 1.0f;
2455         if (crease > 1.0f) crease = 1.0f;
2456
2457         snapGrid(t, &crease);
2458
2459         applyNumInput(&t->num, &crease);
2460
2461         /* header print for NumInput */
2462         if (hasNumInput(&t->num)) {
2463                 char c[20];
2464
2465                 outputNumInput(&(t->num), c);
2466
2467                 if (crease >= 0.0f)
2468                         sprintf(str, "Crease: +%s %s", c, t->proptext);
2469                 else
2470                         sprintf(str, "Crease: %s %s", c, t->proptext);
2471         }
2472         else {
2473                 /* default header print */
2474                 if (crease >= 0.0f)
2475                         sprintf(str, "Crease: +%.3f %s", crease, t->proptext);
2476                 else
2477                         sprintf(str, "Crease: %.3f %s", crease, t->proptext);
2478         }
2479         
2480         for(i = 0 ; i < t->total; i++, td++) {
2481                 if (td->flag & TD_NOACTION)
2482                         break;
2483
2484                 if (td->val) {
2485                         *td->val = td->ival + crease * td->factor;
2486                         if (*td->val < 0.0f) *td->val = 0.0f;
2487                         if (*td->val > 1.0f) *td->val = 1.0f;
2488                 }
2489         }
2490
2491         recalcData(t);
2492
2493         headerprint(str);
2494
2495         viewRedrawForce(t);
2496
2497         helpline (t, t->center);
2498
2499         return 1;
2500 }
2501
2502 /* ************************** MIRROR *************************** */
2503
2504 void Mirror(short mode) 
2505 {
2506         TransData *td;
2507         float mati[3][3], matview[3][3], mat[3][3];
2508         float size[3];
2509         int i;
2510
2511         Trans.context = CTX_NO_PET;
2512
2513         initTrans(&Trans);              // internal data, mouse, vectors
2514
2515         Mat3One(mati);
2516         Mat3CpyMat4(matview, Trans.viewinv); // t->viewinv was set in initTrans
2517         Mat3Ortho(matview);
2518
2519         initTransModeFlags(&Trans, TFM_MIRROR); // modal settings in struct Trans
2520
2521         createTransData(&Trans);        // make TransData structs from selection
2522
2523         calculatePropRatio(&Trans);
2524         calculateCenter(&Trans);
2525
2526         initResize(&Trans);
2527
2528         if (Trans.total == 0) {
2529                 postTrans(&Trans);
2530                 return;
2531         }
2532
2533         size[0] = size[1] = size[2] = 1.0f;
2534         td = Trans.data;
2535
2536         switch (mode) {
2537         case 1:
2538                 size[0] = -1.0f;
2539                 setConstraint(&Trans, mati, (CON_AXIS0), "");
2540                 break;
2541         case 2:
2542                 size[1] = -1.0f;
2543                 setConstraint(&Trans, mati, (CON_AXIS1), "");
2544                 break;
2545         case 3:
2546                 size[2] = -1.0f;
2547                 setConstraint(&Trans, mati, (CON_AXIS2), "");
2548                 break;
2549         case 4:
2550                 size[0] = -1.0f;
2551                 setLocalConstraint(&Trans, (CON_AXIS0), "");
2552                 break;
2553         case 5:
2554                 size[1] = -1.0f;
2555                 setLocalConstraint(&Trans, (CON_AXIS1), "");
2556                 break;
2557         case 6:
2558                 size[2] = -1.0f;
2559                 setLocalConstraint(&Trans, (CON_AXIS2), "");
2560                 break;
2561         case 7:
2562                 size[0] = -1.0f;
2563                 setConstraint(&Trans, matview, (CON_AXIS0), "");
2564                 break;
2565         case 8:
2566                 size[1] = -1.0f;
2567                 setConstraint(&Trans, matview, (CON_AXIS1), "");
2568                 break;
2569         case 9:
2570                 size[2] = -1.0f;
2571                 setConstraint(&Trans, matview, (CON_AXIS2), "");
2572                 break;
2573         default:
2574                 return;
2575         }
2576
2577         SizeToMat3(size, mat);
2578
2579         if (Trans.con.applySize) {
2580                 Trans.con.applySize(&Trans, NULL, mat);
2581         }
2582
2583         for(i = 0 ; i < Trans.total; i++, td++) {
2584                 if (td->flag & TD_NOACTION)
2585                         break;
2586                 
2587                 ElementResize(&Trans, td, mat);
2588         }
2589
2590         recalcData(&Trans);
2591         
2592         BIF_undo_push("Mirror");
2593
2594         /* free data, reset vars */
2595         postTrans(&Trans);
2596
2597         /* send events out for redraws */
2598         viewRedrawPost(&Trans);
2599 }
2600
2601 /* ******************** EditBone (B-bone) width scaling *************** */
2602
2603 static void ElementBoneSize(TransInfo *t, TransData *td, float mat[3][3]) 
2604 {
2605         float tmat[3][3], smat[3][3], oldy;
2606         float sizemat[3][3];
2607         
2608         Mat3MulMat3(smat, mat, td->mtx);
2609         Mat3MulMat3(tmat, td->smtx, smat);
2610         
2611         if (t->con.applySize) {
2612                 t->con.applySize(t, td, tmat);
2613         }
2614         
2615         /* we've tucked the scale in loc */
2616         oldy= td->iloc[1];
2617         SizeToMat3(td->iloc, sizemat);
2618         Mat3MulMat3(tmat, tmat, sizemat);
2619         Mat3ToSize(tmat, td->loc);
2620         td->loc[1]= oldy;
2621 }
2622
2623
2624 int BoneSize(TransInfo *t, short mval[2]) 
2625 {
2626         TransData *td = t->data;
2627         float size[3], mat[3][3];
2628         float ratio;
2629         int i;
2630         char str[50];
2631         
2632         /* for manipulator, center handle, the scaling can't be done relative to center */
2633         if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) {
2634                 ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f;
2635         }
2636         else {
2637                 
2638                 if(t->flag & T_SHIFT_MOD) {
2639                         /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
2640                         float dx= (float)(t->center2d[0] - t->shiftmval[0]);
2641                         float dy= (float)(t->center2d[1] - t->shiftmval[1]);
2642                         ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
2643                         
2644                         dx= (float)(t->center2d[0] - mval[0]);
2645                         dy= (float)(t->center2d[1] - mval[1]);
2646                         ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
2647                         
2648                 }
2649                 else {
2650                         float dx= (float)(t->center2d[0] - mval[0]);
2651                         float dy= (float)(t->center2d[1] - mval[1]);
2652                         ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
2653                 }
2654                 
2655                 /* flip scale, but not for manipulator center handle */
2656                 if      ((t->center2d[0] - mval[0]) * (t->center2d[0] - t->imval[0]) + 
2657                          (t->center2d[1] - mval[1]) * (t->center2d[1] - t->imval[1]) < 0)
2658                         ratio *= -1.0f;
2659         }
2660         
2661         size[0] = size[1] = size[2] = ratio;
2662         
2663         snapGrid(t, size);
2664         
2665         if (hasNumInput(&t->num)) {
2666                 applyNumInput(&t->num, size);
2667                 constraintNumInput(t, size);
2668         }
2669         
2670         SizeToMat3(size, mat);
2671         
2672         if (t->con.applySize) {
2673                 t->con.applySize(t, NULL, mat);
2674         }
2675         
2676         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2677         
2678         headerResize(t, size, str);
2679         
2680         for(i = 0 ; i < t->total; i++, td++) {
2681                 if (td->flag & TD_NOACTION)
2682                         break;
2683                 
2684                 ElementBoneSize(t, td, mat);
2685         }
2686         
2687         recalcData(t);
2688         
2689         headerprint(str);
2690         
2691         viewRedrawForce(t);
2692         
2693         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
2694         
2695         return 1;
2696 }
2697
2698 void initBoneSize(TransInfo *t)
2699 {
2700         t->idx_max = 0;
2701         t->num.idx_max = 0;
2702         t->snap[0] = 0.0f;
2703         t->snap[1] = 0.1f;
2704         t->snap[2] = t->snap[1] * 0.1f;
2705         t->transform = BoneSize;
2706         t->fac = (float)sqrt( (
2707                                            ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
2708                                            +
2709                                            ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
2710                                            ) );
2711         
2712         if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
2713 }
2714
2715 /* ******************** EditBone envelope *************** */
2716
2717 int BoneEnvelope(TransInfo *t, short mval[2]) 
2718 {
2719         TransData *td = t->data;
2720         float ratio;
2721         int i;
2722         char str[50];
2723         
2724         if(t->flag & T_SHIFT_MOD) {
2725                 /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
2726                 float dx= (float)(t->center2d[0] - t->shiftmval[0]);
2727                 float dy= (float)(t->center2d[1] - t->shiftmval[1]);
2728                 ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
2729                 
2730                 dx= (float)(t->center2d[0] - mval[0]);
2731                 dy= (float)(t->center2d[1] - mval[1]);
2732                 ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
2733                 
2734         }
2735         else {
2736                 float dx= (float)(t->center2d[0] - mval[0]);
2737                 float dy= (float)(t->center2d[1] - mval[1]);
2738                 ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
2739         }
2740         
2741         snapGrid(t, &ratio);
2742         
2743         applyNumInput(&t->num, &ratio);
2744         
2745         /* header print for NumInput */
2746         if (hasNumInput(&t->num)) {
2747                 char c[20];
2748                 
2749                 outputNumInput(&(t->num), c);
2750                 sprintf(str, "Envelope: %s", c);
2751         }
2752         else {
2753                 sprintf(str, "Envelope: %3f", ratio);
2754         }
2755         
2756         for(i = 0 ; i < t->total; i++, td++) {
2757                 if (td->flag & TD_NOACTION)
2758                         break;
2759                 
2760                 if(td->val) *td->val= td->ival*ratio;
2761         }
2762         
2763         recalcData(t);
2764         
2765         headerprint(str);
2766         
2767         force_draw(0);
2768         
2769         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
2770         
2771         return 1;
2772 }
2773
2774 void initBoneEnvelope(TransInfo *t)
2775 {
2776         t->idx_max = 0;
2777         t->num.idx_max = 0;
2778         t->snap[0] = 0.0f;
2779         t->snap[1] = 0.1f;
2780         t->snap[2] = t->snap[1] * 0.1f;
2781         t->transform = BoneEnvelope;
2782         t->fac = (float)sqrt( (
2783                                                    ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
2784                                                    +
2785                                                    ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
2786                                                    ) );
2787         
2788         if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
2789 }
2790
2791 /* ************************************ */
2792
2793 void BIF_TransformSetUndo(char *str)
2794 {
2795         Trans.undostr= str;
2796 }
2797
2798