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