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