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