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