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