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