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