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