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