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