2.5
authorMartin Poirier <theeth@yahoo.com>
Mon, 29 Dec 2008 01:41:28 +0000 (01:41 +0000)
committerMartin Poirier <theeth@yahoo.com>
Mon, 29 Dec 2008 01:41:28 +0000 (01:41 +0000)
Transform:
First working port of the transform code:
- Object mode only (other conversions need to be ported)
- Contraints (global and local only) working
- Snap (no edit mode, obviously) working
- Numinput working
- Gears (Ctrl and Shift) working
- Only grap, rotate, scale, shear, warp and to sphere have been added as hotkey, but the rest should work too once accessible
- No manipulator
- No drawn feedback other than moving stuff and header print (no constraint line, snap circle, ...)
- No NDOF support

I've only tested Scons support, though Makefil *should* work, I *think*.

Misc:
-QuatIsNull function in arith
-Exporting project_* and view[line|ray] functions from view3d

18 files changed:
source/blender/blenlib/BLI_arithb.h
source/blender/blenlib/intern/arithb.c
source/blender/editors/include/BIF_transform.h [new file with mode: 0644]
source/blender/editors/include/ED_view3d.h
source/blender/editors/space_view3d/view3d_intern.h
source/blender/editors/space_view3d/view3d_ops.c
source/blender/editors/transform/Makefile
source/blender/editors/transform/SConscript
source/blender/editors/transform/transform.c [new file with mode: 0644]
source/blender/editors/transform/transform.h [new file with mode: 0644]
source/blender/editors/transform/transform_constraints.c [new file with mode: 0644]
source/blender/editors/transform/transform_conversions.c [new file with mode: 0644]
source/blender/editors/transform/transform_generics.c [new file with mode: 0644]
source/blender/editors/transform/transform_manipulator.c [new file with mode: 0644]
source/blender/editors/transform/transform_ndofinput.c [new file with mode: 0644]
source/blender/editors/transform/transform_numinput.c [new file with mode: 0644]
source/blender/editors/transform/transform_orientations.c [new file with mode: 0644]
source/blender/editors/transform/transform_snap.c [new file with mode: 0644]

index 186681fad7d08457d3c3dc92dafca06dcf275216..8c55a83785b34c45721c9fcbc956e8d95b279039 100644 (file)
@@ -123,6 +123,7 @@ void Mat3ToCompatibleEul(float mat[][3], float *eul, float *oldrot);
  * @section Quaternion arithmetic routines
  */
 
+int  QuatIsNul(float *q);
 void QuatToEul(float *quat, float *eul);
 void QuatOne(float *);
 void QuatMul(float *, float *, float *);
index a47d37eb69a1ec50e7ced99469c6e0a884f3fdbc..4d555a009c591d1e15401feef5f8f64b29afe20e 100644 (file)
@@ -1087,6 +1087,10 @@ void printmatrix3( char *str,  float m[][3])
 
 /* **************** QUATERNIONS ********** */
 
+int QuatIsNul(float *q)
+{
+       return (q[0] == 0 && q[1] == 0 && q[2] == 0 && q[3] == 0);
+}
 
 void QuatMul(float *q, float *q1, float *q2)
 {
diff --git a/source/blender/editors/include/BIF_transform.h b/source/blender/editors/include/BIF_transform.h
new file mode 100644 (file)
index 0000000..ca8488e
--- /dev/null
@@ -0,0 +1,135 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_TRANSFORM_H
+#define BIF_TRANSFORM_H
+
+/* ******************* Registration Function ********************** */
+
+struct wmWindowManager;
+struct ListBase;
+struct wmEvent;
+struct bContext;
+
+void transform_keymap_for_space(struct wmWindowManager *wm, struct ListBase *keymap, int spaceid);
+void transform_operatortypes(void);
+
+/* ******************** Macros & Prototypes *********************** */
+
+/* MODE AND NUMINPUT FLAGS */
+#define TFM_INIT                       -1
+#define TFM_DUMMY                      0
+#define TFM_TRANSLATION                1
+#define TFM_ROTATION           2
+#define TFM_RESIZE                     3
+#define TFM_TOSPHERE           4
+#define TFM_SHEAR                      5
+#define TFM_WARP                       7
+#define TFM_SHRINKFATTEN       8
+#define TFM_TILT                       9
+#define TFM_LAMP_ENERGY                10
+#define TFM_TRACKBALL          11
+#define TFM_PUSHPULL           12
+#define TFM_CREASE                     13
+#define TFM_MIRROR                     14
+#define TFM_BONESIZE           15
+#define TFM_BONE_ENVELOPE      16
+#define TFM_CURVE_SHRINKFATTEN         17
+#define TFM_BONE_ROLL          18
+#define TFM_TIME_TRANSLATE     19      
+#define TFM_TIME_SLIDE         20
+#define        TFM_TIME_SCALE          21
+#define TFM_TIME_EXTEND                22
+#define TFM_BAKE_TIME          23
+#define TFM_BEVEL                      24
+#define TFM_BWEIGHT                    25
+#define TFM_ALIGN                      26
+
+/* TRANSFORM CONTEXTS */
+#define CTX_NONE                       0
+#define CTX_TEXTURE                    1
+#define CTX_EDGE                       2
+#define CTX_NO_PET                     4
+#define CTX_TWEAK                      8
+#define CTX_NO_MIRROR          16
+#define CTX_AUTOCONFIRM                32
+#define CTX_BMESH                      64
+#define CTX_NDOF                       128
+
+/* Standalone call to get the transformation center corresponding to the current situation
+ * returns 1 if successful, 0 otherwise (usually means there's no selection)
+ * (if 0 is returns, *vec is unmodified) 
+ * */
+int calculateTransformCenter(struct bContext *C, struct wmEvent *event, int centerMode, float *vec);
+
+struct TransInfo;
+struct ScrArea;
+struct Base;
+struct Scene;
+
+struct TransInfo * BIF_GetTransInfo(void);
+void BIF_setSingleAxisConstraint(float vec[3], char *text);
+void BIF_setDualAxisConstraint(float vec1[3], float vec2[3], char *text);
+void BIF_setLocalAxisConstraint(char axis, char *text);
+void BIF_setLocalLockConstraint(char axis, char *text);
+
+int BIF_snappingSupported(void);
+
+struct TransformOrientation;
+
+void BIF_clearTransformOrientation(void);
+void BIF_removeTransformOrientation(struct TransformOrientation *ts);
+void BIF_manageTransformOrientation(int confirm, int set);
+int BIF_menuselectTransformOrientation(void);
+void BIF_selectTransformOrientation(struct TransformOrientation *ts);
+void BIF_selectTransformOrientationFromIndex(int index);
+
+char * BIF_menustringTransformOrientation(char *title); /* the returned value was allocated and needs to be freed after use */
+int BIF_countTransformOrientation();
+
+/* Drawing callbacks */
+void BIF_drawConstraint(void);
+void BIF_drawPropCircle(void);
+void BIF_drawSnap(void);
+
+void BIF_getPropCenter(float *center);
+
+void BIF_TransformSetUndo(char *str);
+
+void BIF_selectOrientation(void);
+
+/* view3d manipulators */
+void initManipulator(int mode);
+void ManipulatorTransform();
+
+//int BIF_do_manipulator(struct ScrArea *sa);
+//void BIF_draw_manipulator(struct ScrArea *sa);
+
+#endif
+
index cd342b1da51c109c1771e350176f09db06369e53..9b0dec908a8e7a82c6abca3ed27c04cdfced3a08 100644 (file)
 #define ED_VIEW3D_H
 
 /* ********* exports for space_view3d/ module ********** */
+struct ARegion;
+struct View3D;
+
 
 float *give_cursor(Scene *scene, View3D *v3d);
 
+void initgrabz(struct View3D *v3d, float x, float y, float z);
+void window_to_3d(struct ARegion *ar, struct View3D *v3d, float *vec, short mx, short my);
+
+/* Projection */
+
+void project_short(struct ARegion *ar, struct View3D *v3d, float *vec, short *adr);
+void project_short_noclip(struct ARegion *ar, struct View3D *v3d, float *vec, short *adr);
+
+void project_int(struct ARegion *ar, struct View3D *v3d, float *vec, int *adr);
+void project_int_noclip(struct ARegion *ar, struct View3D *v3d, float *vec, int *adr);
+
+void project_float(struct ARegion *ar, struct View3D *v3d, float *vec, float *adr);
+void project_float_noclip(struct ARegion *ar, struct View3D *v3d, float *vec, float *adr);
+
+void viewline(struct ARegion *ar, struct View3D *v3d, short mval[2], float ray_start[3], float ray_end[3]);
+void viewray(struct ARegion *ar, struct View3D *v3d, short mval[2], float ray_start[3], float ray_normal[3]);
+
 #endif /* ED_VIEW3D_H */
 
index bb9a06443842762e59acc0efd1bace660df6ee72..1c4bae503b64ffb62e449087160f2217d288fa0e 100644 (file)
@@ -130,11 +130,7 @@ void VIEW3D_OT_circle_select(struct wmOperatorType *ot);
 void VIEW3D_OT_smoothview(struct wmOperatorType *ot);
 
 void view3d_operator_needs_opengl(const struct bContext *C);
-void viewline(ARegion *ar, View3D *v3d, short mval[2], float ray_start[3], float ray_end[3]);
-void viewray(ARegion *ar, View3D *v3d, short mval[2], float ray_start[3], float ray_normal[3]);
 
-void initgrabz(View3D *v3d, float x, float y, float z);
-void window_to_3d(ARegion *ar, View3D *v3d, float *vec, short mx, short my);
 int boundbox_clip(View3D *v3d, float obmat[][4], struct BoundBox *bb);
 
 void view3d_project_short_clip(ARegion *ar, View3D *v3d, float *vec, short *adr, float projmat[4][4], float wmat[4][4]);
@@ -143,13 +139,6 @@ void view3d_project_float(ARegion *a, float *vec, float *adr, float mat[4][4]);
 void view3d_get_object_project_mat(View3D *v3d, struct Object *ob, float pmat[4][4], float vmat[4][4]);
 void view3d_project_float(ARegion *ar, float *vec, float *adr, float mat[4][4]);
 
-void project_short(ARegion *ar, View3D *v3d, float *vec, short *adr);
-void project_int(ARegion *ar, View3D *v3d, float *vec, int *adr);
-void project_int_noclip(ARegion *ar, View3D *v3d, float *vec, int *adr);
-void project_short_noclip(ARegion *ar, View3D *v3d, float *vec, short *adr);
-void project_float(ARegion *ar, View3D *v3d, float *vec, float *adr);
-void project_float_noclip(ARegion *ar, View3D *v3d, float *vec, float *adr);
-
 int get_view3d_viewplane(View3D *v3d, int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize);
 void view_settings_from_ob(Object *ob, float *ofs, float *quat, float *dist, float *lens);
 void obmat_to_viewmat(View3D *v3d, Object *ob, short smooth);
index 52147bbd557868c6be3f739936218b3c0dd647c6..e20752e28a176070c8058800fefcaec2a0ae6aef 100644 (file)
@@ -46,6 +46,8 @@
 #include "BKE_global.h"
 #include "BKE_utildefines.h"
 
+#include "BIF_transform.h"
+
 #include "RNA_access.h"
 #include "RNA_define.h"
 
@@ -79,6 +81,8 @@ void view3d_operatortypes(void)
        WM_operatortype_append(VIEW3D_OT_smoothview);
        WM_operatortype_append(VIEW3D_OT_render_border);
        WM_operatortype_append(VIEW3D_OT_cursor3d);
+       
+       transform_operatortypes();
 }
 
 void view3d_keymap(wmWindowManager *wm)
@@ -136,5 +140,7 @@ void view3d_keymap(wmWindowManager *wm)
        /* TODO - this is just while we have no way to load a text datablock */
        RNA_string_set(WM_keymap_add_item(keymap, "SCRIPT_OT_run_pyfile", PKEY, KM_PRESS, 0, 0)->ptr, "filename", "test.py");
 
+       transform_keymap_for_space(wm, keymap, SPACE_VIEW3D);
+
 }
 
index b2aeaa145f7efd0668106c0b1c515cef34f55f05..71a75b9bda0ce10fa97b52b5616c363d64d59368 100644 (file)
@@ -28,7 +28,7 @@
 #
 # Makes module object directory and bounces make to subdirectories.
 
-LIBNAME = ed_screen
+LIBNAME = ed_transform
 DIR = $(OCGDIR)/blender/$(LIBNAME)
 
 include nan_compile.mk
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2c44204afa9852f724d6dbd788fd20a6bec423cc 100644 (file)
@@ -0,0 +1,11 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = env.Glob('*.c')
+
+incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
+incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
+incs += ' ../../render/extern/include #/intern/guardedalloc #intern/bmfont'
+incs += ' ../../gpu ../../makesrna'
+
+env.BlenderLib ( 'bf_editors_transform', sources, Split(incs), [], libtype=['core'], priority=[40] )
\ No newline at end of file
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
new file mode 100644 (file)
index 0000000..d3c5303
--- /dev/null
@@ -0,0 +1,4827 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <float.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_action_types.h"  /* for some special action-editor settings */
+#include "DNA_constraint_types.h"
+#include "DNA_ipo_types.h"             /* some silly ipo flag  */
+#include "DNA_listBase.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"           /* PET modes                    */
+#include "DNA_screen_types.h"  /* area dimensions              */
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_space_types.h"
+
+//#include "BIF_editview.h"            /* arrows_move_cursor   */
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+//#include "BIF_mywindow.h"
+//#include "BIF_resources.h"
+//#include "BIF_screen.h"
+//#include "BIF_space.h"                       /* undo                                 */
+//#include "BIF_toets.h"                       /* persptoetsen                 */
+//#include "BIF_mywindow.h"            /* warp_pointer                 */
+//#include "BIF_toolbox.h"                     /* notice                               */
+//#include "BIF_editmesh.h"
+//#include "BIF_editsima.h"
+//#include "BIF_editparticle.h"
+//#include "BIF_drawimage.h"           /* uvco_to_areaco_noclip */
+//#include "BIF_editaction.h" 
+
+#include "BKE_action.h" /* get_action_frame */
+//#include "BKE_bad_level_calls.h"/* popmenu and error */
+#include "BKE_bmesh.h"
+#include "BKE_constraint.h"
+#include "BKE_global.h"
+#include "BKE_particle.h"
+#include "BKE_pointcache.h"
+#include "BKE_utildefines.h"
+#include "BKE_context.h"
+
+//#include "BSE_drawipo.h"
+//#include "BSE_editnla_types.h"       /* for NLAWIDTH */
+//#include "BSE_editaction_types.h"
+//#include "BSE_time.h"
+//#include "BSE_view.h"
+
+#include "ED_view3d.h"
+#include "ED_screen.h"
+#include "WM_types.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+
+#include "PIL_time.h"                  /* sleep                                */
+
+//#include "blendef.h"
+//
+//#include "mydevice.h"
+
+#include "transform.h"
+
+/******************************** Helper functions ************************************/
+
+/* GLOBAL Wrapper Fonctions */
+
+//void BIF_drawSnap()
+//{
+//     drawSnapping(&Trans);
+//}
+
+/* ************************** Dashed help line **************************** */
+
+
+/* bad frontbuffer call... because it is used in transform after force_draw() */
+static void helpline(TransInfo *t, float *vec)
+{
+#if 0 // TRANSFORM_FIX_ME
+       float vecrot[3], cent[2];
+       short mval[2];
+       
+       VECCOPY(vecrot, vec);
+       if(t->flag & T_EDIT) {
+               Object *ob=G.obedit;
+               if(ob) Mat4MulVecfl(ob->obmat, vecrot);
+       }
+       else if(t->flag & T_POSE) {
+               Object *ob=t->poseobj;
+               if(ob) Mat4MulVecfl(ob->obmat, vecrot);
+       }
+       
+       getmouseco_areawin(mval);
+       projectFloatView(t, vecrot, cent);      // no overflow in extreme cases
+
+       persp(PERSP_WIN);
+       
+       glDrawBuffer(GL_FRONT);
+       
+       BIF_ThemeColor(TH_WIRE);
+       
+       setlinestyle(3);
+       glBegin(GL_LINE_STRIP); 
+       glVertex2sv(mval); 
+       glVertex2fv(cent); 
+       glEnd();
+       setlinestyle(0);
+       
+       persp(PERSP_VIEW);
+       bglFlush(); // flush display for frontbuffer
+       glDrawBuffer(GL_BACK);
+#endif
+}
+
+
+  
+/* ************************** INPUT FROM MOUSE *************************** */
+
+float InputScaleRatio(TransInfo *t, short mval[2]) {
+       float ratio, dx, dy;
+       if(t->flag & T_SHIFT_MOD) {
+               /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
+               dx = (float)(t->center2d[0] - t->shiftmval[0]);
+               dy = (float)(t->center2d[1] - t->shiftmval[1]);
+               ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
+               
+               dx= (float)(t->center2d[0] - mval[0]);
+               dy= (float)(t->center2d[1] - mval[1]);
+               ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
+       }
+       else {
+               dx = (float)(t->center2d[0] - mval[0]);
+               dy = (float)(t->center2d[1] - mval[1]);
+               ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
+       }
+       return ratio;
+}
+
+float InputHorizontalRatio(TransInfo *t, short mval[2]) {
+       float x, pad;
+
+       pad = t->ar->winx / 10;
+
+       if (t->flag & T_SHIFT_MOD) {
+               /* deal with Shift key by adding motion / 10 to motion before shift press */
+               x = t->shiftmval[0] + (float)(mval[0] - t->shiftmval[0]) / 10.0f;
+       }
+       else {
+               x = mval[0];
+       }
+       return (x - pad) / (t->ar->winx - 2 * pad);
+}
+
+float InputHorizontalAbsolute(TransInfo *t, short mval[2]) {
+       float vec[3];
+       if(t->flag & T_SHIFT_MOD) {
+               float dvec[3];
+               /* calculate the main translation and the precise one separate */
+               convertViewVec(t, dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
+               VecMulf(dvec, 0.1f);
+               convertViewVec(t, t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
+               VecAddf(t->vec, t->vec, dvec);
+       }
+       else {
+               convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
+       }
+       Projf(vec, t->vec, t->viewinv[0]);
+       return Inpf(t->viewinv[0], vec) * 2.0f;
+}
+
+float InputVerticalRatio(TransInfo *t, short mval[2]) {
+       float y, pad;
+
+       pad = t->ar->winy / 10;
+
+       if (t->flag & T_SHIFT_MOD) {
+               /* deal with Shift key by adding motion / 10 to motion before shift press */
+               y = t->shiftmval[1] + (float)(mval[1] - t->shiftmval[1]) / 10.0f;
+       }
+       else {
+               y = mval[0];
+       }
+       return (y - pad) / (t->ar->winy - 2 * pad);
+}
+
+float InputVerticalAbsolute(TransInfo *t, short mval[2]) {
+       float vec[3];
+       if(t->flag & T_SHIFT_MOD) {
+               float dvec[3];
+               /* calculate the main translation and the precise one separate */
+               convertViewVec(t, dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
+               VecMulf(dvec, 0.1f);
+               convertViewVec(t, t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
+               VecAddf(t->vec, t->vec, dvec);
+       }
+       else {
+               convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
+       }
+       Projf(vec, t->vec, t->viewinv[1]);
+       return Inpf(t->viewinv[1], vec) * 2.0f;
+}
+
+float InputDeltaAngle(TransInfo *t, short mval[2])
+{
+       double dx2 = mval[0] - t->center2d[0];
+       double dy2 = mval[1] - t->center2d[1];
+       double B = sqrt(dx2*dx2+dy2*dy2);
+
+       double dx1 = t->imval[0] - t->center2d[0];
+       double dy1 = t->imval[1] - t->center2d[1];
+       double A = sqrt(dx1*dx1+dy1*dy1);
+
+       double dx3 = mval[0] - t->imval[0];
+       double dy3 = mval[1] - t->imval[1];
+
+       /* use doubles here, to make sure a "1.0" (no rotation) doesnt become 9.999999e-01, which gives 0.02 for acos */
+       double deler = ((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3))
+               / (2.0 * (A*B?A*B:1.0));
+       /* (A*B?A*B:1.0f) this takes care of potential divide by zero errors */
+
+       float dphi;
+       
+       dphi = saacos((float)deler);
+       if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
+
+       /* If the angle is zero, because of lack of precision close to the 1.0 value in acos
+        * approximate the angle with the oposite side of the normalized triangle
+        * This is a good approximation here since the smallest acos value seems to be around
+        * 0.02 degree and lower values don't even have a 0.01% error compared to the approximation
+        * */   
+       if (dphi == 0)
+       {
+               double dx, dy;
+               
+               dx2 /= A;
+               dy2 /= A;
+               
+               dx1 /= B;
+               dy1 /= B;
+               
+               dx = dx1 - dx2;
+               dy = dy1 - dy2;
+               
+               dphi = sqrt(dx*dx + dy*dy);
+               if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
+       }
+       
+       if(t->flag & T_SHIFT_MOD) dphi = dphi/30.0f;
+       
+       /* if no delta angle, don't update initial position */
+       if (dphi != 0)
+       {
+               t->imval[0] = mval[0];
+               t->imval[1] = mval[1];
+       }
+       
+       return dphi;
+}
+
+/* ************************** SPACE DEPENDANT CODE **************************** */
+
+void setTransformViewMatrices(TransInfo *t)
+{
+       if(t->spacetype==SPACE_VIEW3D) {
+               View3D *v3d = t->view;
+               
+               Mat4CpyMat4(t->viewmat, v3d->viewmat);
+               Mat4CpyMat4(t->viewinv, v3d->viewinv);
+               Mat4CpyMat4(t->persmat, v3d->persmat);
+               Mat4CpyMat4(t->persinv, v3d->persinv);
+               t->persp = v3d->persp;
+       }
+       else {
+               Mat4One(t->viewmat);
+               Mat4One(t->viewinv);
+               Mat4One(t->persmat);
+               Mat4One(t->persinv);
+               t->persp = V3D_ORTHO;
+       }
+       
+       calculateCenter2D(t);
+}
+
+void convertViewVec(TransInfo *t, float *vec, short dx, short dy)
+{
+       if (t->spacetype==SPACE_VIEW3D) {
+               window_to_3d(t->ar, t->view, vec, dx, dy);
+       }
+       else if(t->spacetype==SPACE_IMAGE) {
+               View2D *v2d = t->view;
+               float divx, divy, aspx, aspy;
+               
+               // TRANSFORM_FIX_ME
+               //transform_aspect_ratio_tface_uv(&aspx, &aspy);
+               
+               divx= v2d->mask.xmax-v2d->mask.xmin;
+               divy= v2d->mask.ymax-v2d->mask.ymin;
+               
+               vec[0]= aspx*(v2d->cur.xmax-v2d->cur.xmin)*(dx)/divx;
+               vec[1]= aspy*(v2d->cur.ymax-v2d->cur.ymin)*(dy)/divy;
+               vec[2]= 0.0f;
+       }
+       else if(t->spacetype==SPACE_IPO) {
+               View2D *v2d = t->view;
+               float divx, divy;
+               
+               divx= v2d->mask.xmax-v2d->mask.xmin;
+               divy= v2d->mask.ymax-v2d->mask.ymin;
+               
+               vec[0]= (v2d->cur.xmax-v2d->cur.xmin)*(dx) / (divx);
+               vec[1]= (v2d->cur.ymax-v2d->cur.ymin)*(dy) / (divy);
+               vec[2]= 0.0f;
+       }
+}
+
+void projectIntView(TransInfo *t, float *vec, int *adr)
+{
+       if (t->spacetype==SPACE_VIEW3D) {
+               project_int_noclip(t->ar, t->view, vec, adr);
+       }
+       else if(t->spacetype==SPACE_IMAGE) {
+               float aspx, aspy, v[2];
+               
+               // TRANSFORM_FIX_ME
+               //transform_aspect_ratio_tface_uv(&aspx, &aspy);
+               v[0]= vec[0]/aspx;
+               v[1]= vec[1]/aspy;
+               
+               // TRANSFORM_FIX_ME
+               //uvco_to_areaco_noclip(v, adr);
+       }
+       else if(t->spacetype==SPACE_IPO) {
+               short out[2] = {0.0f, 0.0f};
+               
+               // TRANSFORM_FIX_ME
+               //ipoco_to_areaco(G.v2d, vec, out);
+               adr[0]= out[0];
+               adr[1]= out[1];
+       }
+}
+
+void projectFloatView(TransInfo *t, float *vec, float *adr)
+{
+       if (t->spacetype==SPACE_VIEW3D) {
+               project_float_noclip(t->ar, t->view, vec, adr);
+       }
+       else if(t->spacetype==SPACE_IMAGE) {
+               int a[2];
+               
+               projectIntView(t, vec, a);
+               adr[0]= a[0];
+               adr[1]= a[1];
+       }
+       else if(t->spacetype==SPACE_IPO) {
+               int a[2];
+               
+               projectIntView(t, vec, a);
+               adr[0]= a[0];
+               adr[1]= a[1];
+       }
+}
+
+void convertVecToDisplayNum(float *vec, float *num)
+{
+       // TRANSFORM_FIX_ME
+       TransInfo *t = NULL; //BIF_GetTransInfo();
+
+       VECCOPY(num, vec);
+
+       if ((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) {
+#if 0 // TRANSFORM_FIX_ME
+               float aspx, aspy;
+
+               if((G.sima->flag & SI_COORDFLOATS)==0) {
+                       int width, height;
+                       transform_width_height_tface_uv(&width, &height);
+
+                       num[0] *= width;
+                       num[1] *= height;
+               }
+
+               transform_aspect_ratio_tface_uv(&aspx, &aspy);
+               num[0] /= aspx;
+               num[1] /= aspy;
+#endif
+       }
+}
+
+void convertDisplayNumToVec(float *num, float *vec)
+{
+       // TRANSFORM_FIX_ME
+       TransInfo *t = NULL; //BIF_GetTransInfo();
+
+       VECCOPY(vec, num);
+
+       if ((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) {
+#if 0 // TRANSFORM_FIX_ME
+               float aspx, aspy;
+
+               if((G.sima->flag & SI_COORDFLOATS)==0) {
+                       int width, height;
+                       transform_width_height_tface_uv(&width, &height);
+
+                       vec[0] /= width;
+                       vec[1] /= height;
+               }
+
+               transform_aspect_ratio_tface_uv(&aspx, &aspy);
+               vec[0] *= aspx;
+               vec[1] *= aspy;
+#endif
+       }
+}
+
+static void viewRedrawForce(TransInfo *t)
+{
+       if (t->spacetype == SPACE_VIEW3D)
+       {
+               // TRANSFORM_FIX_ME
+               // need to redraw ALL 3d view
+               ED_area_tag_redraw(t->sa);
+       }
+#if 0 // TRANSFORM_FIX_ME
+       else if (t->spacetype==SPACE_IMAGE) {
+               if (G.sima->lock) force_draw_plus(SPACE_VIEW3D, 0);
+               else force_draw(0);
+       }
+       else if (t->spacetype == SPACE_ACTION) {
+               if (G.saction->lock) {
+                       short context;
+                       
+                       /* we ignore the pointer this function returns (not needed) */
+                       get_action_context(&context);
+                       
+                       if (context == ACTCONT_ACTION)
+                               force_draw_plus(SPACE_VIEW3D, 0);
+                       else if (context == ACTCONT_SHAPEKEY) 
+                               force_draw_all(0);
+                       else
+                               force_draw(0);
+               }
+               else {
+                       force_draw(0);
+               }
+       }
+       else if (t->spacetype == SPACE_NLA) {
+               if (G.snla->lock)
+                       force_draw_all(0);
+               else
+                       force_draw(0);
+       }
+       else if (t->spacetype == SPACE_IPO) {
+               /* update realtime */
+               if (G.sipo->lock) {
+                       if (G.sipo->blocktype==ID_MA || G.sipo->blocktype==ID_TE)
+                               force_draw_plus(SPACE_BUTS, 0);
+                       else if (G.sipo->blocktype==ID_CA)
+                               force_draw_plus(SPACE_VIEW3D, 0);
+                       else if (G.sipo->blocktype==ID_KE)
+                               force_draw_plus(SPACE_VIEW3D, 0);
+                       else if (G.sipo->blocktype==ID_PO)
+                               force_draw_plus(SPACE_VIEW3D, 0);
+                       else if (G.sipo->blocktype==ID_OB) 
+                               force_draw_plus(SPACE_VIEW3D, 0);
+                       else if (G.sipo->blocktype==ID_SEQ) 
+                               force_draw_plus(SPACE_SEQ, 0);
+                       else 
+                               force_draw(0);
+               }
+               else {
+                       force_draw(0);
+               }
+       }
+#endif 
+}
+
+static void viewRedrawPost(TransInfo *t)
+{
+       ED_area_headerprint(t->sa, NULL);
+       
+#if 0 // TRANSFORM_FIX_ME
+       if(t->spacetype==SPACE_VIEW3D) {
+               allqueue(REDRAWBUTSOBJECT, 0);
+               allqueue(REDRAWVIEW3D, 0);
+       }
+       else if(t->spacetype==SPACE_IMAGE) {
+               allqueue(REDRAWIMAGE, 0);
+               allqueue(REDRAWVIEW3D, 0);
+       }
+       else if(ELEM3(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_IPO)) {
+               allqueue(REDRAWVIEW3D, 0);
+               allqueue(REDRAWACTION, 0);
+               allqueue(REDRAWNLA, 0);
+               allqueue(REDRAWIPO, 0);
+               allqueue(REDRAWTIME, 0);
+               allqueue(REDRAWBUTSOBJECT, 0);
+       }
+
+       scrarea_queue_headredraw(curarea);
+#endif
+}
+
+/* ************************** TRANSFORMATIONS **************************** */
+
+void BIF_selectOrientation() {
+#if 0 // TRANSFORM_FIX_ME
+       short val;
+       char *str_menu = BIF_menustringTransformOrientation("Orientation");
+       val= pupmenu(str_menu);
+       MEM_freeN(str_menu);
+       
+       if(val >= 0) {
+               G.vd->twmode = val;
+       }
+#endif
+}
+
+static void view_editmove(unsigned short event)
+{
+#if 0 // TRANSFORM_FIX_ME
+       int refresh = 0;
+       /* Regular:   Zoom in */
+       /* Shift:     Scroll up */
+       /* Ctrl:      Scroll right */
+       /* Alt-Shift: Rotate up */
+       /* Alt-Ctrl:  Rotate right */
+       
+       /* only work in 3D window for now
+        * In the end, will have to send to event to a 2D window handler instead
+        */
+       if (Trans.flag & T_2D_EDIT)
+               return;
+       
+       switch(event) {
+               case WHEELUPMOUSE:
+                       
+                       if( G.qual & LR_SHIFTKEY ) {
+                               if( G.qual & LR_ALTKEY ) { 
+                                       G.qual &= ~LR_SHIFTKEY;
+                                       persptoetsen(PAD2);
+                                       G.qual |= LR_SHIFTKEY;
+                               } else {
+                                       persptoetsen(PAD2);
+                               }
+                       } else if( G.qual & LR_CTRLKEY ) {
+                               if( G.qual & LR_ALTKEY ) { 
+                                       G.qual &= ~LR_CTRLKEY;
+                                       persptoetsen(PAD4);
+                                       G.qual |= LR_CTRLKEY;
+                               } else {
+                                       persptoetsen(PAD4);
+                               }
+                       } else if(U.uiflag & USER_WHEELZOOMDIR) 
+                               persptoetsen(PADMINUS);
+                       else
+                               persptoetsen(PADPLUSKEY);
+                       
+                       refresh = 1;
+                       break;
+               case WHEELDOWNMOUSE:
+                       if( G.qual & LR_SHIFTKEY ) {
+                               if( G.qual & LR_ALTKEY ) { 
+                                       G.qual &= ~LR_SHIFTKEY;
+                                       persptoetsen(PAD8);
+                                       G.qual |= LR_SHIFTKEY;
+                               } else {
+                                       persptoetsen(PAD8);
+                               }
+                       } else if( G.qual & LR_CTRLKEY ) {
+                               if( G.qual & LR_ALTKEY ) { 
+                                       G.qual &= ~LR_CTRLKEY;
+                                       persptoetsen(PAD6);
+                                       G.qual |= LR_CTRLKEY;
+                               } else {
+                                       persptoetsen(PAD6);
+                               }
+                       } else if(U.uiflag & USER_WHEELZOOMDIR) 
+                               persptoetsen(PADPLUSKEY);
+                       else
+                               persptoetsen(PADMINUS);
+                       
+                       refresh = 1;
+                       break;
+       }
+
+       if (refresh)
+               setTransformViewMatrices(&Trans);
+#endif
+}
+
+static char *transform_to_undostr(TransInfo *t)
+{
+       switch (t->mode) {
+               case TFM_TRANSLATION:
+                       return "Translate";
+               case TFM_ROTATION:
+                       return "Rotate";
+               case TFM_RESIZE:
+                       return "Scale";
+               case TFM_TOSPHERE:
+                       return "To Sphere";
+               case TFM_SHEAR:
+                       return "Shear";
+               case TFM_WARP:
+                       return "Warp";
+               case TFM_SHRINKFATTEN:
+                       return "Shrink/Fatten";
+               case TFM_TILT:
+                       return "Tilt";
+               case TFM_TRACKBALL:
+                       return "Trackball";
+               case TFM_PUSHPULL:
+                       return "Push/Pull";
+               case TFM_BEVEL:
+                       return "Bevel";
+               case TFM_BWEIGHT:
+                       return "Bevel Weight";
+               case TFM_CREASE:
+                       return "Crease";
+               case TFM_BONESIZE:
+                       return "Bone Width";
+               case TFM_BONE_ENVELOPE:
+                       return "Bone Envelope";
+               case TFM_TIME_TRANSLATE:
+                       return "Translate Anim. Data";
+               case TFM_TIME_SCALE:
+                       return "Scale Anim. Data";
+               case TFM_TIME_SLIDE:
+                       return "Time Slide";
+               case TFM_BAKE_TIME:
+                       return "Key Time";
+               case TFM_MIRROR:
+                       return "Mirror";
+       }
+       return "Transform";
+}
+
+/* ************************************************* */
+
+void transformEvent(TransInfo *t, wmEvent *event)
+{
+       float mati[3][3] = {{1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}};
+       char cmode = constraintModeToChar(t);
+       
+       t->event = event;
+       
+       if (event->type == MOUSEMOVE)
+       {
+               t->mval[0] = event->x - t->ar->winrct.xmin;
+               t->mval[1] = event->y - t->ar->winrct.ymin;
+       }
+
+       if (event->val) {
+               switch (event->type){
+               /* enforce redraw of transform when modifiers are used */
+               case LEFTCTRLKEY:
+               case RIGHTCTRLKEY:
+                       t->redraw = 1;
+                       break;
+               case LEFTSHIFTKEY:
+               case RIGHTSHIFTKEY:
+                       /* shift is modifier for higher resolution transform, works nice to store this mouse position */
+                       t->shiftmval[0] = event->x - t->ar->winrct.xmin;
+                       t->shiftmval[1] = event->y - t->ar->winrct.ymin;
+                       t->flag |= T_SHIFT_MOD;
+                       t->redraw = 1;
+                       break;
+                       
+               case SPACEKEY:
+                       if ((t->spacetype==SPACE_VIEW3D) && event->alt) {
+#if 0 // TRANSFORM_FIX_ME
+                               short mval[2];
+                               
+                               getmouseco_sc(mval);
+                               BIF_selectOrientation();
+                               calc_manipulator_stats(curarea);
+                               Mat3CpyMat4(t->spacemtx, G.vd->twmat);
+                               warp_pointer(mval[0], mval[1]);
+#endif
+                       }
+                       else {
+                               t->state = TRANS_CONFIRM;
+                       }
+                       break;
+                       
+                       
+               case MIDDLEMOUSE:
+                       if ((t->flag & T_NO_CONSTRAINT)==0) {
+                               /* exception for switching to dolly, or trackball, in camera view */
+                               if (t->flag & T_CAMERA) {
+                                       if (t->mode==TFM_TRANSLATION)
+                                               setLocalConstraint(t, (CON_AXIS2), "along local Z");
+                                       else if (t->mode==TFM_ROTATION) {
+                                               restoreTransObjects(t);
+                                               initTrackball(t);
+                                       }
+                               }
+                               else {
+                                       t->flag |= T_MMB_PRESSED;
+                                       if (t->con.mode & CON_APPLY) {
+                                               stopConstraint(t);
+                                       }
+                                       else {
+                                               if (event->shift) {
+                                                       initSelectConstraint(t, t->spacemtx);
+                                               }
+                                               else {
+                                                       /* bit hackish... but it prevents mmb select to print the orientation from menu */
+                                                       strcpy(t->spacename, "global");
+                                                       initSelectConstraint(t, mati);
+                                               }
+                                               postSelectConstraint(t);
+                                       }
+                               }
+                               t->redraw = 1;
+                       }
+                       break;
+               case ESCKEY:
+               case RIGHTMOUSE:
+                       t->state = TRANS_CANCEL;
+                       break;
+               case LEFTMOUSE:
+               case PADENTER:
+               case RETKEY:
+                       t->state = TRANS_CONFIRM;
+                       break;
+               case GKEY:
+                       /* only switch when... */
+                       if( ELEM3(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL) ) { 
+                               resetTransRestrictions(t); 
+                               restoreTransObjects(t);
+                               initTranslation(t);
+                               t->redraw = 1;
+                       }
+                       break;
+               case SKEY:
+                       /* only switch when... */
+                       if( ELEM3(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) { 
+                               resetTransRestrictions(t); 
+                               restoreTransObjects(t);
+                               initResize(t);
+                               t->redraw = 1;
+                       }
+                       break;
+               case RKEY:
+                       /* only switch when... */
+                       if( ELEM4(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) {
+                               
+                               resetTransRestrictions(t); 
+                               
+                               if (t->mode == TFM_ROTATION) {
+                                       restoreTransObjects(t);
+                                       initTrackball(t);
+                               }
+                               else {
+                                       restoreTransObjects(t);
+                                       initRotation(t);
+                               }
+                               t->redraw = 1;
+                       }
+                       break;
+               case CKEY:
+                       if (event->alt) {
+                               t->flag ^= T_PROP_CONNECTED;
+                               sort_trans_data_dist(t);
+                               calculatePropRatio(t);
+                               t->redraw= 1;
+                       }
+                       else {
+                               stopConstraint(t);
+                               t->redraw = 1;
+                       }
+                       break;
+               case XKEY:
+                       if ((t->flag & T_NO_CONSTRAINT)==0) {
+                               if (cmode == 'X') {
+                                       if (t->flag & T_2D_EDIT) {
+                                               stopConstraint(t);
+                                       }
+                                       else {
+                                               if (t->con.mode & CON_USER) {
+                                                       stopConstraint(t);
+                                               }
+                                               else {
+                                                       if (event->keymodifier == 0)
+                                                               setUserConstraint(t, (CON_AXIS0), "along %s X");
+                                                       else if (event->keymodifier == KM_SHIFT)
+                                                               setUserConstraint(t, (CON_AXIS1|CON_AXIS2), "locking %s X");
+                                               }
+                                       }
+                               }
+                               else {
+                                       if (t->flag & T_2D_EDIT) {
+                                               setConstraint(t, mati, (CON_AXIS0), "along X axis");
+                                       }
+                                       else {
+                                               if (event->keymodifier == 0)
+                                                       setConstraint(t, mati, (CON_AXIS0), "along global X");
+                                               else if (event->keymodifier == KM_SHIFT)
+                                                       setConstraint(t, mati, (CON_AXIS1|CON_AXIS2), "locking global X");
+                                       }
+                               }
+                               t->redraw = 1;
+                       }
+                       break;
+               case YKEY:
+                       if ((t->flag & T_NO_CONSTRAINT)==0) {
+                               if (cmode == 'Y') {
+                                       if (t->flag & T_2D_EDIT) {
+                                               stopConstraint(t);
+                                       }
+                                       else {
+                                               if (t->con.mode & CON_USER) {
+                                                       stopConstraint(t);
+                                               }
+                                               else {
+                                                       if (event->keymodifier == 0)
+                                                               setUserConstraint(t, (CON_AXIS1), "along %s Y");
+                                                       else if (event->keymodifier == KM_SHIFT)
+                                                               setUserConstraint(t, (CON_AXIS0|CON_AXIS2), "locking %s Y");
+                                               }
+                                       }
+                               }
+                               else {
+                                       if (t->flag & T_2D_EDIT) {
+                                               setConstraint(t, mati, (CON_AXIS1), "along Y axis");
+                                       }
+                                       else {
+                                               if (event->keymodifier == 0)
+                                                       setConstraint(t, mati, (CON_AXIS1), "along global Y");
+                                               else if (event->keymodifier == KM_SHIFT)
+                                                       setConstraint(t, mati, (CON_AXIS0|CON_AXIS2), "locking global Y");
+                                       }
+                               }
+                               t->redraw = 1;
+                       }
+                       break;
+               case ZKEY:
+                       if ((t->flag & T_NO_CONSTRAINT)==0) {
+                               if (cmode == 'Z') {
+                                       if (t->con.mode & CON_USER) {
+                                               stopConstraint(t);
+                                       }
+                                       else {
+                                               if (event->keymodifier == 0)
+                                                       setUserConstraint(t, (CON_AXIS2), "along %s Z");
+                                               else if ((event->keymodifier == KM_SHIFT) && ((t->flag & T_2D_EDIT)==0))
+                                                       setUserConstraint(t, (CON_AXIS0|CON_AXIS1), "locking %s Z");
+                                       }
+                               }
+                               else if ((t->flag & T_2D_EDIT)==0) {
+                                       if (event->keymodifier == 0)
+                                               setConstraint(t, mati, (CON_AXIS2), "along global Z");
+                                       else if (event->keymodifier == KM_SHIFT)
+                                               setConstraint(t, mati, (CON_AXIS0|CON_AXIS1), "locking global Z");
+                               }
+                               t->redraw = 1;
+                       }
+                       break;
+               case OKEY:
+                       if (t->flag & T_PROP_EDIT && event->keymodifier == KM_SHIFT) {
+                               G.scene->prop_mode = (G.scene->prop_mode+1)%6;
+                               calculatePropRatio(t);
+                               t->redraw= 1;
+                       }
+                       break;
+               case PADPLUSKEY:
+                       if(event->keymodifier & KM_ALT && t->flag & T_PROP_EDIT) {
+                               t->propsize*= 1.1f;
+                               calculatePropRatio(t);
+                       }
+                       t->redraw= 1;
+                       break;
+               case PAGEUPKEY:
+               case WHEELDOWNMOUSE:
+                       if (t->flag & T_AUTOIK) {
+                               transform_autoik_update(t, 1);
+                       }
+                       else if(t->flag & T_PROP_EDIT) {
+                               t->propsize*= 1.1f;
+                               calculatePropRatio(t);
+                       }
+                       else view_editmove(event->type);
+                       t->redraw= 1;
+                       break;
+               case PADMINUS:
+                       if(event->keymodifier & KM_ALT && t->flag & T_PROP_EDIT) {
+                               t->propsize*= 0.90909090f;
+                               calculatePropRatio(t);
+                       }
+                       t->redraw= 1;
+                       break;
+               case PAGEDOWNKEY:
+               case WHEELUPMOUSE:
+                       if (t->flag & T_AUTOIK) {
+                               transform_autoik_update(t, -1);
+                       }
+                       else if (t->flag & T_PROP_EDIT) {
+                               t->propsize*= 0.90909090f;
+                               calculatePropRatio(t);
+                       }
+                       else view_editmove(event->type);
+                       t->redraw= 1;
+                       break;
+//             case NDOFMOTION:
+//            viewmoveNDOF(1);
+  //         break;
+               }
+               
+               // Numerical input events
+               t->redraw |= handleNumInput(&(t->num), event);
+               
+               // NDof input events
+               switch(handleNDofInput(&(t->ndof), event))
+               {
+                       case NDOF_CONFIRM:
+                               if ((t->context & CTX_NDOF) == 0)
+                               {
+                                       /* Confirm on normal transform only */
+                                       t->state = TRANS_CONFIRM;
+                               }
+                               break;
+                       case NDOF_CANCEL:
+                               if (t->context & CTX_NDOF)
+                               {
+                                       /* Cancel on pure NDOF transform */
+                                       t->state = TRANS_CANCEL; 
+                               }
+                               else
+                               {
+                                       /* Otherwise, just redraw, NDof input was cancelled */
+                                       t->redraw = 1;
+                               }
+                               break;
+                       case NDOF_NOMOVE:
+                               if (t->context & CTX_NDOF)
+                               {
+                                       /* Confirm on pure NDOF transform */
+                                       t->state = TRANS_CONFIRM;
+                               }
+                               break;
+                       case NDOF_REFRESH:
+                               t->redraw = 1;
+                               break;
+                       
+               }
+               
+               // Snapping events
+               t->redraw |= handleSnapping(t, event);
+               
+               //arrows_move_cursor(event->type);
+       }
+       else {
+               switch (event->type){
+               /* no redraw on release modifier keys! this makes sure you can assign the 'grid' still 
+                  after releasing modifer key */
+               case MIDDLEMOUSE:
+                       if ((t->flag & T_NO_CONSTRAINT)==0) {
+                               t->flag &= ~T_MMB_PRESSED;
+                               postSelectConstraint(t);
+                               t->redraw = 1;
+                       }
+                       break;
+               case LEFTMOUSE:
+               case RIGHTMOUSE:
+                       if (t->context & CTX_TWEAK)
+                               t->state = TRANS_CONFIRM;
+                       break;
+               case LEFTSHIFTKEY:
+               case RIGHTSHIFTKEY:
+                       /* shift is modifier for higher resolution transform */
+                       t->flag &= ~T_SHIFT_MOD;
+                       break;
+               }
+       }
+       
+       // Per transform event, if present
+       if (t->handleEvent)
+               t->redraw |= t->handleEvent(t, event);
+}
+
+int calculateTransformCenter(bContext *C, wmEvent *event, int centerMode, float *vec)
+{
+       TransInfo *t = MEM_callocN(sizeof(TransInfo), "TransInfo data");
+       int success = 1;
+
+       t->state = TRANS_RUNNING;
+
+       t->context = CTX_NONE;
+       
+       t->mode = TFM_DUMMY;
+
+       initTransInfo(C, t, event);                                     // internal data, mouse, vectors
+
+       createTransData(C, t);                  // make TransData structs from selection
+
+       t->around = centerMode;                         // override userdefined mode
+
+       if (t->total == 0) {
+               success = 0;
+       }
+       else {
+               success = 1;
+               
+               calculateCenter(t);
+       
+               // Copy center from constraint center. Transform center can be local    
+               VECCOPY(vec, t->con.center);
+       }
+
+       postTrans(t);
+
+       /* aftertrans does insert ipos and action channels, and clears base flags, doesnt read transdata */
+       special_aftertrans_update(t);
+       
+       MEM_freeN(t);
+       
+       return success;
+}
+
+void initTransform(bContext *C, TransInfo *t, int mode, int context, wmEvent *event)
+{
+       /* added initialize, for external calls to set stuff in TransInfo, like undo string */
+
+       t->state = TRANS_RUNNING;
+
+       t->context = context;
+       
+       t->mode = mode;
+
+       initTransInfo(C, t, event);                                     // internal data, mouse, vectors
+
+       if(t->spacetype == SPACE_VIEW3D)
+       {
+               View3D *v3d = t->view;
+               //calc_manipulator_stats(curarea);
+               Mat3CpyMat4(t->spacemtx, v3d->twmat);
+               Mat3Ortho(t->spacemtx);
+       }
+       else
+               Mat3One(t->spacemtx);
+
+       createTransData(C, t);                  // make TransData structs from selection
+
+       initSnapping(t); // Initialize snapping data AFTER mode flags
+
+       if (t->total == 0) {
+               postTrans(t);
+               return;
+       }
+
+       /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
+       /* EVIL2: we gave as argument also texture space context bit... was cleared */
+       /* EVIL3: extend mode for animation editors also switches modes... but is best way to avoid duplicate code */
+       mode = t->mode;
+       
+       calculatePropRatio(t);
+       calculateCenter(t);
+
+       switch (mode) {
+       case TFM_TRANSLATION:
+               initTranslation(t);
+               break;
+       case TFM_ROTATION:
+               initRotation(t);
+               break;
+       case TFM_RESIZE:
+               initResize(t);
+               break;
+       case TFM_TOSPHERE:
+               initToSphere(t);
+               break;
+       case TFM_SHEAR:
+               initShear(t);
+               break;
+       case TFM_WARP:
+               initWarp(t);
+               break;
+       case TFM_SHRINKFATTEN:
+               initShrinkFatten(t);
+               break;
+       case TFM_TILT:
+               initTilt(t);
+               break;
+       case TFM_CURVE_SHRINKFATTEN:
+               initCurveShrinkFatten(t);
+               break;
+       case TFM_TRACKBALL:
+               initTrackball(t);
+               break;
+       case TFM_PUSHPULL:
+               initPushPull(t);
+               break;
+       case TFM_CREASE:
+               initCrease(t);
+               break;
+       case TFM_BONESIZE:
+               {       /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */
+                       bArmature *arm= t->poseobj->data;
+                       if(arm->drawtype==ARM_ENVELOPE)
+                               initBoneEnvelope(t);
+                       else
+                               initBoneSize(t);
+               }
+               break;
+       case TFM_BONE_ENVELOPE:
+               initBoneEnvelope(t);
+               break;
+       case TFM_BONE_ROLL:
+               initBoneRoll(t);
+               break;
+       case TFM_TIME_TRANSLATE:
+               initTimeTranslate(t);
+               break;
+       case TFM_TIME_SLIDE:
+               initTimeSlide(t);
+               break;
+       case TFM_TIME_SCALE:
+               initTimeScale(t);
+               break;
+       case TFM_TIME_EXTEND: 
+               /* now that transdata has been made, do like for TFM_TIME_TRANSLATE */
+               initTimeTranslate(t);
+               break;
+       case TFM_BAKE_TIME:
+               initBakeTime(t);
+               break;
+       case TFM_MIRROR:
+               initMirror(t);
+               break;
+       case TFM_BEVEL:
+               initBevel(t);
+               break;
+       case TFM_BWEIGHT:
+               initBevelWeight(t);
+               break;
+       case TFM_ALIGN:
+               initAlign(t);
+               break;
+       }
+}
+
+void transformApply(TransInfo *t)
+{
+       if (1) // MOUSE MOVE
+       {
+               if (t->flag & T_MMB_PRESSED)
+                       t->con.mode |= CON_SELECT;
+               t->redraw = 1;
+       }
+       if (t->redraw)
+       {
+               // RESET MOUSE MOVE
+
+               selectConstraint(t);
+               if (t->transform) {
+                       t->transform(t, t->mval);  // calls recalcData()
+               }
+               t->redraw = 0;
+       }
+
+       /* If auto confirm is on, break after one pass */               
+       if (t->context & CTX_AUTOCONFIRM)
+       {
+               t->state = TRANS_CONFIRM;
+       }
+
+       if (BKE_ptcache_get_continue_physics())
+       {
+               // TRANSFORM_FIX_ME
+               //do_screenhandlers(G.curscreen);
+               t->redraw = 1;
+       }
+}
+
+int transformEnd(TransInfo *t)
+{
+       if (t->state != TRANS_RUNNING)
+       {
+               /* handle restoring objects */
+               if(t->state == TRANS_CANCEL)
+                       restoreTransObjects(t); // calls recalcData()
+               
+               /* free data */
+               postTrans(t);
+       
+               /* aftertrans does insert ipos and action channels, and clears base flags, doesnt read transdata */
+               special_aftertrans_update(t);
+       
+               /* send events out for redraws */
+               viewRedrawPost(t);
+       
+               /*  Undo as last, certainly after special_trans_update! */
+#if 0 // TRANSFORM_FIX_ME              
+               if(t->state == TRANS_CANCEL) {
+                       if(t->undostr) BIF_undo_push(t->undostr);
+               }
+               else {
+                       if(t->undostr) BIF_undo_push(t->undostr);
+                       else BIF_undo_push(transform_to_undostr(t));
+               }
+               t->undostr= NULL;
+#endif
+               return 1;
+       }
+
+       t->event = NULL;
+       
+       return 0;
+}
+
+/* ************************** Manipulator init and main **************************** */
+
+void initManipulator(int mode)
+{
+#if 0 // TRANSFORM_FIX_ME
+       Trans.state = TRANS_RUNNING;
+
+       Trans.context = CTX_NONE;
+       
+       Trans.mode = mode;
+       
+       /* automatic switch to scaling bone envelopes */
+       if(mode==TFM_RESIZE && G.obedit && G.obedit->type==OB_ARMATURE) {
+               bArmature *arm= G.obedit->data;
+               if(arm->drawtype==ARM_ENVELOPE)
+                       mode= TFM_BONE_ENVELOPE;
+       }
+
+       initTrans(&Trans);                                      // internal data, mouse, vectors
+
+       G.moving |= G_TRANSFORM_MANIP;          // signal to draw manipuls while transform
+       createTransData(&Trans);                        // make TransData structs from selection
+
+       if (Trans.total == 0)
+               return;
+
+       initSnapping(&Trans); // Initialize snapping data AFTER mode flags
+
+       /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
+       /* EVIL2: we gave as argument also texture space context bit... was cleared */
+       mode = Trans.mode;
+       
+       calculatePropRatio(&Trans);
+       calculateCenter(&Trans);
+
+       switch (mode) {
+       case TFM_TRANSLATION:
+               initTranslation(&Trans);
+               break;
+       case TFM_ROTATION:
+               initRotation(&Trans);
+               break;
+       case TFM_RESIZE:
+               initResize(&Trans);
+               break;
+       case TFM_TRACKBALL:
+               initTrackball(&Trans);
+               break;
+       }
+
+       Trans.flag |= T_USES_MANIPULATOR;
+#endif
+}
+
+void ManipulatorTransform() 
+{
+#if 0 // TRANSFORM_FIX_ME
+       int mouse_moved = 0;
+       short pmval[2] = {0, 0}, mval[2], val;
+       unsigned short event;
+
+       if (Trans.total == 0)
+               return;
+
+       Trans.redraw = 1; /* initial draw */
+
+       while (Trans.state == TRANS_RUNNING) {
+               
+               getmouseco_areawin(mval);
+               
+               if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
+                       Trans.redraw = 1;
+               }
+               if (Trans.redraw) {
+                       pmval[0] = mval[0];
+                       pmval[1] = mval[1];
+
+                       //selectConstraint(&Trans);  needed?
+                       if (Trans.transform) {
+                               Trans.transform(&Trans, mval);
+                       }
+                       Trans.redraw = 0;
+               }
+               
+               /* essential for idling subloop */
+               if( qtest()==0) PIL_sleep_ms(2);
+
+               while( qtest() ) {
+                       event= extern_qread(&val);
+
+                       switch (event){
+                       case MOUSEX:
+                       case MOUSEY:
+                               mouse_moved = 1;
+                               break;
+                       /* enforce redraw of transform when modifiers are used */
+                       case LEFTCTRLKEY:
+                       case RIGHTCTRLKEY:
+                               if(val) Trans.redraw = 1;
+                               break;
+                       case LEFTSHIFTKEY:
+                       case RIGHTSHIFTKEY:
+                               /* shift is modifier for higher resolution transform, works nice to store this mouse position */
+                               if(val) {
+                                       getmouseco_areawin(Trans.shiftmval);
+                                       Trans.flag |= T_SHIFT_MOD;
+                                       Trans.redraw = 1;
+                               }
+                               else Trans.flag &= ~T_SHIFT_MOD; 
+                               break;
+                               
+                       case ESCKEY:
+                       case RIGHTMOUSE:
+                               Trans.state = TRANS_CANCEL;
+                               break;
+                       case LEFTMOUSE:
+                               if(mouse_moved==0 && val==0) break;
+                               // else we pass on event to next, which cancels
+                       case SPACEKEY:
+                       case PADENTER:
+                       case RETKEY:
+                               Trans.state = TRANS_CONFIRM;
+                               break;
+   //         case NDOFMOTION:
+     //           viewmoveNDOF(1);
+     //           break;
+                       }
+                       if(val) {
+                               switch(event) {
+                               case PADPLUSKEY:
+                                       if(G.qual & LR_ALTKEY && Trans.flag & T_PROP_EDIT) {
+                                               Trans.propsize*= 1.1f;
+                                               calculatePropRatio(&Trans);
+                                       }
+                                       Trans.redraw= 1;
+                                       break;
+                               case PAGEUPKEY:
+                               case WHEELDOWNMOUSE:
+                                       if (Trans.flag & T_AUTOIK) {
+                                               transform_autoik_update(&Trans, 1);
+                                       }
+                                       else if(Trans.flag & T_PROP_EDIT) {
+                                               Trans.propsize*= 1.1f;
+                                               calculatePropRatio(&Trans);
+                                       }
+                                       else view_editmove(event);
+                                       Trans.redraw= 1;
+                                       break;
+                               case PADMINUS:
+                                       if(G.qual & LR_ALTKEY && Trans.flag & T_PROP_EDIT) {
+                                               Trans.propsize*= 0.90909090f;
+                                               calculatePropRatio(&Trans);
+                                       }
+                                       Trans.redraw= 1;
+                                       break;
+                               case PAGEDOWNKEY:
+                               case WHEELUPMOUSE:
+                                       if (Trans.flag & T_AUTOIK) {
+                                               transform_autoik_update(&Trans, -1);
+                                       }
+                                       else if (Trans.flag & T_PROP_EDIT) {
+                                               Trans.propsize*= 0.90909090f;
+                                               calculatePropRatio(&Trans);
+                                       }
+                                       else view_editmove(event);
+                                       Trans.redraw= 1;
+                                       break;
+                               }
+                                                       
+                               // Numerical input events
+                               Trans.redraw |= handleNumInput(&(Trans.num), event);
+                       }
+               }
+       }
+       
+       if(Trans.state == TRANS_CANCEL) {
+               restoreTransObjects(&Trans);
+       }
+       
+       /* free data, reset vars */
+       postTrans(&Trans);
+       
+       /* aftertrans does insert ipos and action channels, and clears base flags */
+       special_aftertrans_update(&Trans);
+       
+       /* send events out for redraws */
+       viewRedrawPost(&Trans);
+
+       if(Trans.state != TRANS_CANCEL) {
+               BIF_undo_push(transform_to_undostr(&Trans));
+       }
+#endif
+}
+
+/* ************************** TRANSFORM LOCKS **************************** */
+
+static void protectedTransBits(short protectflag, float *vec)
+{
+       if(protectflag & OB_LOCK_LOCX)
+               vec[0]= 0.0f;
+       if(protectflag & OB_LOCK_LOCY)
+               vec[1]= 0.0f;
+       if(protectflag & OB_LOCK_LOCZ)
+               vec[2]= 0.0f;
+}
+
+static void protectedSizeBits(short protectflag, float *size)
+{
+       if(protectflag & OB_LOCK_SCALEX)
+               size[0]= 1.0f;
+       if(protectflag & OB_LOCK_SCALEY)
+               size[1]= 1.0f;
+       if(protectflag & OB_LOCK_SCALEZ)
+               size[2]= 1.0f;
+}
+
+static void protectedRotateBits(short protectflag, float *eul, float *oldeul)
+{
+       if(protectflag & OB_LOCK_ROTX)
+               eul[0]= oldeul[0];
+       if(protectflag & OB_LOCK_ROTY)
+               eul[1]= oldeul[1];
+       if(protectflag & OB_LOCK_ROTZ)
+               eul[2]= oldeul[2];
+}
+
+static void protectedQuaternionBits(short protectflag, float *quat, float *oldquat)
+{
+       /* quaternions get limited with euler... */
+       /* this function only does the delta rotation */
+       
+       if(protectflag) {
+               float eul[3], oldeul[3], quat1[4];
+               
+               QUATCOPY(quat1, quat);
+               QuatToEul(quat, eul);
+               QuatToEul(oldquat, oldeul);
+               
+               if(protectflag & OB_LOCK_ROTX)
+                       eul[0]= oldeul[0];
+               if(protectflag & OB_LOCK_ROTY)
+                       eul[1]= oldeul[1];
+               if(protectflag & OB_LOCK_ROTZ)
+                       eul[2]= oldeul[2];
+               
+               EulToQuat(eul, quat);
+               /* quaternions flip w sign to accumulate rotations correctly */
+               if( (quat1[0]<0.0f && quat[0]>0.0f) || (quat1[0]>0.0f && quat[0]<0.0f) ) {
+                       QuatMulf(quat, -1.0f);
+               }
+       }
+}
+
+/* ******************* TRANSFORM LIMITS ********************** */
+
+static void constraintTransLim(TransInfo *t, TransData *td)
+{
+       if (td->con) {
+               bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT);
+               bConstraintOb cob;
+               bConstraint *con;
+               
+               /* Make a temporary bConstraintOb for using these limit constraints 
+                *      - they only care that cob->matrix is correctly set ;-)
+                *      - current space should be local
+                */
+               memset(&cob, 0, sizeof(bConstraintOb));
+               Mat4One(cob.matrix);
+               if (td->tdi) {
+                       TransDataIpokey *tdi= td->tdi;
+                       cob.matrix[3][0]= tdi->locx[0];
+                       cob.matrix[3][1]= tdi->locy[0];
+                       cob.matrix[3][2]= tdi->locz[0];
+               }
+               else {
+                       VECCOPY(cob.matrix[3], td->loc);
+               }
+               
+               /* Evaluate valid constraints */
+               for (con= td->con; con; con= con->next) {
+                       float tmat[4][4];
+                       
+                       /* only consider constraint if enabled */
+                       if (con->flag & CONSTRAINT_DISABLE) continue;
+                       if (con->enforce == 0.0f) continue;
+                       
+                       /* only use it if it's tagged for this purpose (and the right type) */
+                       if (con->type == CONSTRAINT_TYPE_LOCLIMIT) {
+                               bLocLimitConstraint *data= con->data;
+                               
+                               if ((data->flag2 & LIMIT_TRANSFORM)==0) 
+                                       continue;
+                               
+                               /* do space conversions */
+                               if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
+                                       /* just multiply by td->mtx (this should be ok) */
+                                       Mat4CpyMat4(tmat, cob.matrix);
+                                       Mat4MulMat34(cob.matrix, td->mtx, tmat);
+                               }
+                               else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
+                                       /* skip... incompatable spacetype */
+                                       continue;
+                               }
+                               
+                               /* do constraint */
+                               cti->evaluate_constraint(con, &cob, NULL);
+                               
+                               /* convert spaces again */
+                               if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
+                                       /* just multiply by td->mtx (this should be ok) */
+                                       Mat4CpyMat4(tmat, cob.matrix);
+                                       Mat4MulMat34(cob.matrix, td->smtx, tmat);
+                               }
+                       }
+               }
+               
+               /* copy results from cob->matrix */
+               if (td->tdi) {
+                       TransDataIpokey *tdi= td->tdi;
+                       tdi->locx[0]= cob.matrix[3][0];
+                       tdi->locy[0]= cob.matrix[3][1];
+                       tdi->locz[0]= cob.matrix[3][2];
+               }
+               else {
+                       VECCOPY(td->loc, cob.matrix[3]);
+               }
+       }
+}
+
+static void constraintRotLim(TransInfo *t, TransData *td)
+{
+       if (td->con) {
+               bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_ROTLIMIT);
+               bConstraintOb cob;
+               bConstraint *con;
+               
+               /* Make a temporary bConstraintOb for using these limit constraints 
+                *      - they only care that cob->matrix is correctly set ;-)
+                *      - current space should be local
+                */
+               memset(&cob, 0, sizeof(bConstraintOb));
+               if (td->flag & TD_USEQUAT) {
+                       /* quats */
+                       if (td->ext)
+                               QuatToMat4(td->ext->quat, cob.matrix);
+                       else
+                               return;
+               }
+               else if (td->tdi) {
+                       /* ipo-keys eulers */
+                       TransDataIpokey *tdi= td->tdi;
+                       float eul[3];
+                       
+                       eul[0]= tdi->rotx[0];
+                       eul[1]= tdi->roty[0];
+                       eul[2]= tdi->rotz[0];
+                       
+                       EulToMat4(eul, cob.matrix);
+               }
+               else {
+                       /* eulers */
+                       if (td->ext)
+                               EulToMat4(td->ext->rot, cob.matrix);
+                       else
+                               return;
+               }
+                       
+               /* Evaluate valid constraints */
+               for (con= td->con; con; con= con->next) {
+                       /* only consider constraint if enabled */
+                       if (con->flag & CONSTRAINT_DISABLE) continue;
+                       if (con->enforce == 0.0f) continue;
+                       
+                       /* we're only interested in Limit-Rotation constraints */
+                       if (con->type == CONSTRAINT_TYPE_ROTLIMIT) {
+                               bRotLimitConstraint *data= con->data;
+                               float tmat[4][4];
+                               
+                               /* only use it if it's tagged for this purpose */
+                               if ((data->flag2 & LIMIT_TRANSFORM)==0) 
+                                       continue;
+                                       
+                               /* do space conversions */
+                               if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
+                                       /* just multiply by td->mtx (this should be ok) */
+                                       Mat4CpyMat4(tmat, cob.matrix);
+                                       Mat4MulMat34(cob.matrix, td->mtx, tmat);
+                               }
+                               else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
+                                       /* skip... incompatable spacetype */
+                                       continue;
+                               }
+                               
+                               /* do constraint */
+                               cti->evaluate_constraint(con, &cob, NULL);
+                               
+                               /* convert spaces again */
+                               if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
+                                       /* just multiply by td->mtx (this should be ok) */
+                                       Mat4CpyMat4(tmat, cob.matrix);
+                                       Mat4MulMat34(cob.matrix, td->smtx, tmat);
+                               }
+                       }
+               }
+               
+               /* copy results from cob->matrix */
+               if (td->flag & TD_USEQUAT) {
+                       /* quats */
+                       Mat4ToQuat(cob.matrix, td->ext->quat);
+               }
+               else if (td->tdi) {
+                       /* ipo-keys eulers */
+                       TransDataIpokey *tdi= td->tdi;
+                       float eul[3];
+                       
+                       Mat4ToEul(cob.matrix, eul);
+                       
+                       tdi->rotx[0]= eul[0];
+                       tdi->roty[0]= eul[1];
+                       tdi->rotz[0]= eul[2];
+               }
+               else {
+                       /* eulers */
+                       Mat4ToEul(cob.matrix, td->ext->rot);
+               }
+       }
+}
+
+static void constraintSizeLim(TransInfo *t, TransData *td)
+{
+       if (td->con && td->ext) {
+               bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_SIZELIMIT);
+               bConstraintOb cob;
+               bConstraint *con;
+               
+               /* Make a temporary bConstraintOb for using these limit constraints 
+                *      - they only care that cob->matrix is correctly set ;-)
+                *      - current space should be local
+                */
+               memset(&cob, 0, sizeof(bConstraintOb));
+               if (td->tdi) {
+                       TransDataIpokey *tdi= td->tdi;
+                       float size[3];
+                       
+                       size[0]= tdi->sizex[0];
+                       size[1]= tdi->sizey[0];
+                       size[2]= tdi->sizez[0];
+                       SizeToMat4(size, cob.matrix);
+               } 
+               else if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
+                       /* scale val and reset size */
+                       return; // TODO: fix this case
+               }
+               else {
+                       /* Reset val if SINGLESIZE but using a constraint */
+                       if (td->flag & TD_SINGLESIZE)
+                               return;
+                       
+                       SizeToMat4(td->ext->size, cob.matrix);
+               }
+                       
+               /* Evaluate valid constraints */
+               for (con= td->con; con; con= con->next) {
+                       /* only consider constraint if enabled */
+                       if (con->flag & CONSTRAINT_DISABLE) continue;
+                       if (con->enforce == 0.0f) continue;
+                       
+                       /* we're only interested in Limit-Scale constraints */
+                       if (con->type == CONSTRAINT_TYPE_SIZELIMIT) {
+                               bSizeLimitConstraint *data= con->data;
+                               float tmat[4][4];
+                               
+                               /* only use it if it's tagged for this purpose */
+                               if ((data->flag2 & LIMIT_TRANSFORM)==0) 
+                                       continue;
+                                       
+                               /* do space conversions */
+                               if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
+                                       /* just multiply by td->mtx (this should be ok) */
+                                       Mat4CpyMat4(tmat, cob.matrix);
+                                       Mat4MulMat34(cob.matrix, td->mtx, tmat);
+                               }
+                               else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
+                                       /* skip... incompatable spacetype */
+                                       continue;
+                               }
+                               
+                               /* do constraint */
+                               cti->evaluate_constraint(con, &cob, NULL);
+                               
+                               /* convert spaces again */
+                               if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
+                                       /* just multiply by td->mtx (this should be ok) */
+                                       Mat4CpyMat4(tmat, cob.matrix);
+                                       Mat4MulMat34(cob.matrix, td->smtx, tmat);
+                               }
+                       }
+               }
+               
+               /* copy results from cob->matrix */
+               if (td->tdi) {
+                       TransDataIpokey *tdi= td->tdi;
+                       float size[3];
+                       
+                       Mat4ToSize(cob.matrix, size);
+                       
+                       tdi->sizex[0]= size[0];
+                       tdi->sizey[0]= size[1];
+                       tdi->sizez[0]= size[2];
+               } 
+               else if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
+                       /* scale val and reset size */
+                       return; // TODO: fix this case
+               }
+               else {
+                       /* Reset val if SINGLESIZE but using a constraint */
+                       if (td->flag & TD_SINGLESIZE)
+                               return;
+                               
+                       Mat4ToSize(cob.matrix, td->ext->size);
+               }
+       }
+}
+
+/* ************************** WARP *************************** */
+
+void initWarp(TransInfo *t) 
+{
+       float max[3], min[3];
+       int i;
+       
+       t->mode = TFM_WARP;
+       t->transform = Warp;
+       t->handleEvent = handleEventWarp;
+       
+       t->idx_max = 0;
+       t->num.idx_max = 0;
+       t->snap[0] = 0.0f;
+       t->snap[1] = 5.0f;
+       t->snap[2] = 1.0f;
+       
+       t->flag |= T_NO_CONSTRAINT;
+
+/* warp is done fully in view space */
+       calculateCenterCursor(t);
+       t->fac = (float)(t->center2d[0] - t->imval[0]);
+       
+       /* we need min/max in view space */
+       for(i = 0; i < t->total; i++) {
+               float center[3];
+               VECCOPY(center, t->data[i].center);
+               Mat3MulVecfl(t->data[i].mtx, center);
+               Mat4MulVecfl(t->viewmat, center);
+               VecSubf(center, center, t->viewmat[3]);
+               if (i)
+                       MinMax3(min, max, center);
+               else {
+                       VECCOPY(max, center);
+                       VECCOPY(min, center);
+               }
+       }
+       
+       t->center[0]= (min[0]+max[0])/2.0f;
+       t->center[1]= (min[1]+max[1])/2.0f;
+       t->center[2]= (min[2]+max[2])/2.0f;
+       
+       if (max[0] == min[0]) max[0] += 0.1; /* not optimal, but flipping is better than invalid garbage (i.e. division by zero!) */
+       t->val= (max[0]-min[0])/2.0f; /* t->val is X dimension projected boundbox */
+}
+
+int handleEventWarp(TransInfo *t, wmEvent *event)
+{
+       int status = 0;
+       
+       if (event->type == MIDDLEMOUSE && event->val)
+       {
+               // Use customData pointer to signal warp direction
+               if      (t->customData == 0)
+                       t->customData = (void*)1;
+               else
+                       t->customData = 0;
+                       
+               status = 1;
+       }
+       
+       return status;
+}
+
+int Warp(TransInfo *t, short mval[2])
+{
+       TransData *td = t->data;
+       float vec[3], circumfac, dist, phi0, co, si, *curs, cursor[3], gcursor[3];
+       int i;
+       char str[50];
+       
+       curs= give_cursor(t->scene, t->view);
+       /*
+        * gcursor is the one used for helpline.
+        * It has to be in the same space as the drawing loop
+        * (that means it needs to be in the object's space when in edit mode and
+        *  in global space in object mode)
+        *
+        * cursor is used for calculations.
+        * It needs to be in view space, but we need to take object's offset
+        * into account if in Edit mode.
+        */
+       VECCOPY(cursor, curs);
+       VECCOPY(gcursor, cursor);       
+       if (t->flag & T_EDIT) {
+               VecSubf(cursor, cursor, G.obedit->obmat[3]);
+               VecSubf(gcursor, gcursor, G.obedit->obmat[3]);
+               Mat3MulVecfl(t->data->smtx, gcursor);
+       }
+       Mat4MulVecfl(t->viewmat, cursor);
+       VecSubf(cursor, cursor, t->viewmat[3]);
+
+       /* amount of degrees for warp */
+       circumfac= 360.0f * InputHorizontalRatio(t, mval);
+       
+       if (t->customData) /* non-null value indicates reversed input */
+       {
+               circumfac *= -1;
+       }
+
+       snapGrid(t, &circumfac);
+       applyNumInput(&t->num, &circumfac);
+       
+       /* header print for NumInput */
+       if (hasNumInput(&t->num)) {
+               char c[20];
+               
+               outputNumInput(&(t->num), c);
+               
+               sprintf(str, "Warp: %s", c);
+       }
+       else {
+               /* default header print */
+               sprintf(str, "Warp: %.3f", circumfac);
+       }
+       
+       circumfac*= (float)(-M_PI/360.0);
+       
+       for(i = 0; i < t->total; i++, td++) {
+               float loc[3];
+               if (td->flag & TD_NOACTION)
+                       break;
+
+               if (td->flag & TD_SKIP)
+                       continue;
+               
+               /* translate point to center, rotate in such a way that outline==distance */
+               VECCOPY(vec, td->iloc);
+               Mat3MulVecfl(td->mtx, vec);
+               Mat4MulVecfl(t->viewmat, vec);
+               VecSubf(vec, vec, t->viewmat[3]);
+               
+               dist= vec[0]-cursor[0];
+               
+               /* t->val is X dimension projected boundbox */
+               phi0= (circumfac*dist/t->val);  
+               
+               vec[1]= (vec[1]-cursor[1]);
+               
+               co= (float)cos(phi0);
+               si= (float)sin(phi0);
+               loc[0]= -si*vec[1]+cursor[0];
+               loc[1]= co*vec[1]+cursor[1];
+               loc[2]= vec[2];
+               
+               Mat4MulVecfl(t->viewinv, loc);
+               VecSubf(loc, loc, t->viewinv[3]);
+               Mat3MulVecfl(td->smtx, loc);
+               
+               VecSubf(loc, loc, td->iloc);
+               VecMulf(loc, td->factor);
+               VecAddf(td->loc, td->iloc, loc);
+       }
+
+       recalcData(t);
+       
+       ED_area_headerprint(t->sa, str);
+       
+       viewRedrawForce(t);
+       
+       helpline(t, gcursor);
+       
+       return 1;
+}
+
+/* ************************** SHEAR *************************** */
+
+void initShear(TransInfo *t) 
+{
+       t->mode = TFM_SHEAR;
+       t->transform = Shear;
+       t->handleEvent = handleEventShear;
+       
+       t->idx_max = 0;
+       t->num.idx_max = 0;
+       t->snap[0] = 0.0f;
+       t->snap[1] = 0.1f;
+       t->snap[2] = t->snap[1] * 0.1f;
+       
+       t->flag |= T_NO_CONSTRAINT;
+}
+
+int handleEventShear(TransInfo *t, wmEvent *event)
+{
+       int status = 0;
+       
+       if (event->type == MIDDLEMOUSE && event->val)
+       {
+               // Use customData pointer to signal Shear direction
+               if      (t->customData == 0)
+                       t->customData = (void*)1;
+               else
+                       t->customData = 0;
+                       
+               status = 1;
+       }
+       
+       return status;
+}
+
+
+int Shear(TransInfo *t, short mval[2]) 
+{
+       TransData *td = t->data;
+       float vec[3];
+       float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
+       float value;
+       int i;
+       char str[50];
+
+       Mat3CpyMat4(persmat, t->viewmat);
+       Mat3Inv(persinv, persmat);
+
+       // Custom data signals shear direction
+       if (t->customData == 0)
+               value = 0.05f * InputHorizontalAbsolute(t, mval);
+       else
+               value = 0.05f * InputVerticalAbsolute(t, mval);
+
+       snapGrid(t, &value);
+
+       applyNumInput(&t->num, &value);
+
+       /* header print for NumInput */
+       if (hasNumInput(&t->num)) {
+               char c[20];
+
+               outputNumInput(&(t->num), c);
+
+               sprintf(str, "Shear: %s %s", c, t->proptext);
+       }
+       else {
+               /* default header print */
+               sprintf(str, "Shear: %.3f %s", value, t->proptext);
+       }
+       
+       Mat3One(smat);
+       
+       // Custom data signals shear direction
+       if (t->customData == 0)
+               smat[1][0] = value;
+       else
+               smat[0][1] = value;
+       
+       Mat3MulMat3(tmat, smat, persmat);
+       Mat3MulMat3(totmat, persinv, tmat);
+       
+       for(i = 0 ; i < t->total; i++, td++) {
+               if (td->flag & TD_NOACTION)
+                       break;
+
+               if (td->flag & TD_SKIP)
+                       continue;
+
+               if (G.obedit) {
+                       float mat3[3][3];
+                       Mat3MulMat3(mat3, totmat, td->mtx);
+                       Mat3MulMat3(tmat, td->smtx, mat3);
+               }
+               else {
+                       Mat3CpyMat3(tmat, totmat);
+               }
+               VecSubf(vec, td->center, t->center);
+
+               Mat3MulVecfl(tmat, vec);
+
+               VecAddf(vec, vec, t->center);
+               VecSubf(vec, vec, td->center);
+
+               VecMulf(vec, td->factor);
+
+               VecAddf(td->loc, td->iloc, vec);
+       }
+
+       recalcData(t);
+
+       ED_area_headerprint(t->sa, str);
+
+       viewRedrawForce(t);
+
+       helpline (t, t->center);
+
+       return 1;
+}
+
+/* ************************** RESIZE *************************** */
+
+void initResize(TransInfo *t) 
+{
+       t->mode = TFM_RESIZE;
+       t->transform = Resize;
+       
+       t->flag |= T_NULL_ONE;
+       t->num.flag |= NUM_NULL_ONE;
+       t->num.flag |= NUM_AFFECT_ALL;
+       if (!G.obedit) {
+               t->flag |= T_NO_ZERO;
+               t->num.flag |= NUM_NO_ZERO;
+       }
+       
+       t->idx_max = 2;
+       t->num.idx_max = 2;
+       t->snap[0] = 0.0f;
+       t->snap[1] = 0.1f;
+       t->snap[2] = t->snap[1] * 0.1f;
+
+       t->fac = (float)sqrt(
+               (
+                       ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
+               +
+                       ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
+               ) );
+
+       if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
+}
+
+static void headerResize(TransInfo *t, float vec[3], char *str) {
+       char tvec[60];
+       if (hasNumInput(&t->num)) {
+               outputNumInput(&(t->num), tvec);
+       }
+       else {
+               sprintf(&tvec[0], "%.4f", vec[0]);
+               sprintf(&tvec[20], "%.4f", vec[1]);
+               sprintf(&tvec[40], "%.4f", vec[2]);
+       }
+
+       if (t->con.mode & CON_APPLY) {
+               switch(t->num.idx_max) {
+               case 0:
+                       sprintf(str, "Scale: %s%s %s", &tvec[0], t->con.text, t->proptext);
+                       break;
+               case 1:
+                       sprintf(str, "Scale: %s : %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
+                       break;
+               case 2:
+                       sprintf(str, "Scale: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
+               }
+       }
+       else {
+               if (t->flag & T_2D_EDIT)
+                       sprintf(str, "Scale X: %s   Y: %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
+               else
+                       sprintf(str, "Scale X: %s   Y: %s  Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
+       }
+}
+
+#define SIGN(a)                (a<-FLT_EPSILON?1:a>FLT_EPSILON?2:3)
+#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)
+
+/* smat is reference matrix, only scaled */
+static void TransMat3ToSize( float mat[][3], float smat[][3], float *size)
+{
+       float vec[3];
+       
+       VecCopyf(vec, mat[0]);
+       size[0]= Normalize(vec);
+       VecCopyf(vec, mat[1]);
+       size[1]= Normalize(vec);
+       VecCopyf(vec, mat[2]);
+       size[2]= Normalize(vec);
+       
+       /* first tried with dotproduct... but the sign flip is crucial */
+       if( VECSIGNFLIP(mat[0], smat[0]) ) size[0]= -size[0]; 
+       if( VECSIGNFLIP(mat[1], smat[1]) ) size[1]= -size[1]; 
+       if( VECSIGNFLIP(mat[2], smat[2]) ) size[2]= -size[2]; 
+}
+
+
+static void ElementResize(TransInfo *t, TransData *td, float mat[3][3]) {
+       float tmat[3][3], smat[3][3], center[3];
+       float vec[3];
+
+       if (t->flag & T_EDIT) {
+               Mat3MulMat3(smat, mat, td->mtx);
+               Mat3MulMat3(tmat, td->smtx, smat);
+       }
+       else {
+               Mat3CpyMat3(tmat, mat);
+       }
+
+       if (t->con.applySize) {
+               t->con.applySize(t, td, tmat);
+       }
+
+       /* local constraint shouldn't alter center */
+       if (t->around == V3D_LOCAL) {
+               if (t->flag & T_OBJECT) {
+                       VECCOPY(center, td->center);
+               }
+               else if (t->flag & T_EDIT) {
+                       
+                       if(t->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
+                               VECCOPY(center, td->center);
+                       }
+                       else {
+                               VECCOPY(center, t->center);
+                       }
+               }
+               else {
+                       VECCOPY(center, t->center);
+               }
+       }
+       else {
+               VECCOPY(center, t->center);
+       }
+
+       if (td->ext) {
+               float fsize[3];
+               
+               if (t->flag & (T_OBJECT|T_TEXTURE|T_POSE)) {
+                       float obsizemat[3][3];
+                       // Reorient the size mat to fit the oriented object.
+                       Mat3MulMat3(obsizemat, tmat, td->axismtx);
+                       //printmatrix3("obsizemat", obsizemat);
+                       TransMat3ToSize(obsizemat, td->axismtx, fsize);
+                       //printvecf("fsize", fsize);
+               }
+               else {
+                       Mat3ToSize(tmat, fsize);
+               }
+               
+               protectedSizeBits(td->protectflag, fsize);
+               
+               if ((t->flag & T_V3D_ALIGN)==0) {       // align mode doesn't resize objects itself
+                       /* handle ipokeys? */
+                       if(td->tdi) {
+                               TransDataIpokey *tdi= td->tdi;
+                               /* calculate delta size (equal for size and dsize) */
+                               
+                               vec[0]= (tdi->oldsize[0])*(fsize[0] -1.0f) * td->factor;
+                               vec[1]= (tdi->oldsize[1])*(fsize[1] -1.0f) * td->factor;
+                               vec[2]= (tdi->oldsize[2])*(fsize[2] -1.0f) * td->factor;
+                               
+                               add_tdi_poin(tdi->sizex, tdi->oldsize,   vec[0]);
+                               add_tdi_poin(tdi->sizey, tdi->oldsize+1, vec[1]);
+                               add_tdi_poin(tdi->sizez, tdi->oldsize+2, vec[2]);
+                               
+                       } 
+                       else if((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)){
+                               /* scale val and reset size */
+                               *td->val = td->ival * fsize[0] * td->factor;
+                               
+                               td->ext->size[0] = td->ext->isize[0];
+                               td->ext->size[1] = td->ext->isize[1];
+                               td->ext->size[2] = td->ext->isize[2];
+                       }
+                       else {
+                               /* Reset val if SINGLESIZE but using a constraint */
+                               if (td->flag & TD_SINGLESIZE)
+                                       *td->val = td->ival;
+                               
+                               td->ext->size[0] = td->ext->isize[0] * (fsize[0]) * td->factor;
+                               td->ext->size[1] = td->ext->isize[1] * (fsize[1]) * td->factor;
+                               td->ext->size[2] = td->ext->isize[2] * (fsize[2]) * td->factor;
+                       }
+               }
+               
+               constraintSizeLim(t, td);
+       }
+       
+       /* For individual element center, Editmode need to use iloc */
+       if (t->flag & T_POINTS)
+               VecSubf(vec, td->iloc, center);
+       else
+               VecSubf(vec, td->center, center);
+
+       Mat3MulVecfl(tmat, vec);
+
+       VecAddf(vec, vec, center);
+       if (t->flag & T_POINTS)
+               VecSubf(vec, vec, td->iloc);
+       else
+               VecSubf(vec, vec, td->center);
+
+       VecMulf(vec, td->factor);
+
+       if (t->flag & (T_OBJECT|T_POSE)) {
+               Mat3MulVecfl(td->smtx, vec);
+       }
+
+       protectedTransBits(td->protectflag, vec);
+
+       if(td->tdi) {
+               TransDataIpokey *tdi= td->tdi;
+               add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
+               add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
+               add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
+       }
+       else VecAddf(td->loc, td->iloc, vec);
+       
+       constraintTransLim(t, td);
+}
+
+int Resize(TransInfo *t, short mval[2]) 
+{
+       TransData *td;
+       float size[3], mat[3][3];
+       float ratio;
+       int i;
+       char str[200];
+
+       /* for manipulator, center handle, the scaling can't be done relative to center */
+       if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) {
+               ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f;
+       }
+       else {
+               ratio = InputScaleRatio(t, mval);
+               
+               /* flip scale, but not for manipulator center handle */
+               if      ((t->center2d[0] - mval[0]) * (t->center2d[0] - t->imval[0]) + 
+                        (t->center2d[1] - mval[1]) * (t->center2d[1] - t->imval[1]) < 0)
+                               ratio *= -1.0f;
+       }
+       
+       size[0] = size[1] = size[2] = ratio;
+
+       snapGrid(t, size);
+
+       if (hasNumInput(&t->num)) {
+               applyNumInput(&t->num, size);
+               constraintNumInput(t, size);
+       }
+
+       applySnapping(t, size);
+
+       SizeToMat3(size, mat);
+
+       if (t->con.applySize) {
+               t->con.applySize(t, NULL, mat);
+       }
+
+       Mat3CpyMat3(t->mat, mat);       // used in manipulator
+       
+       headerResize(t, size, str);
+
+       for(i = 0, td=t->data; i < t->total; i++, td++) {
+               if (td->flag & TD_NOACTION)
+                       break;
+
+               if (td->flag & TD_SKIP)
+                       continue;
+               
+               ElementResize(t, td, mat);
+       }
+
+       /* evil hack - redo resize if cliping needed */
+       if (t->flag & T_CLIP_UV && clipUVTransform(t, size, 1)) {
+               SizeToMat3(size, mat);
+
+               if (t->con.applySize)
+                       t->con.applySize(t, NULL, mat);
+
+               for(i = 0, td=t->data; i < t->total; i++, td++)
+                       ElementResize(t, td, mat);
+       }
+
+       recalcData(t);
+
+       ED_area_headerprint(t->sa, str);
+
+       viewRedrawForce(t);
+
+       if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
+
+       return 1;
+}
+
+/* ************************** TOSPHERE *************************** */
+
+void initToSphere(TransInfo *t) 
+{
+       TransData *td = t->data;
+       int i;
+
+       t->mode = TFM_TOSPHERE;
+       t->transform = ToSphere;
+
+       t->idx_max = 0;
+       t->num.idx_max = 0;
+       t->snap[0] = 0.0f;
+       t->snap[1] = 0.1f;
+       t->snap[2] = t->snap[1] * 0.1f;
+       
+       t->num.flag |= NUM_NULL_ONE | NUM_NO_NEGATIVE;
+       t->flag |= T_NO_CONSTRAINT;
+
+       // Calculate average radius
+       for(i = 0 ; i < t->total; i++, td++) {
+               t->val += VecLenf(t->center, td->iloc);
+       }
+
+       t->val /= (float)t->total;
+}
+
+int ToSphere(TransInfo *t, short mval[2]) 
+{
+       float vec[3];
+       float ratio, radius;
+       int i;
+       char str[64];
+       TransData *td = t->data;
+
+       ratio = InputHorizontalRatio(t, mval);
+
+       snapGrid(t, &ratio);
+
+       applyNumInput(&t->num, &ratio);
+
+       if (ratio < 0)
+               ratio = 0.0f;
+       else if (ratio > 1)
+               ratio = 1.0f;
+
+       /* header print for NumInput */
+       if (hasNumInput(&t->num)) {
+               char c[20];
+
+               outputNumInput(&(t->num), c);
+
+               sprintf(str, "To Sphere: %s %s", c, t->proptext);
+       }
+       else {
+               /* default header print */
+               sprintf(str, "To Sphere: %.4f %s", ratio, t->proptext);
+       }
+       
+       
+       for(i = 0 ; i < t->total; i++, td++) {
+               float tratio;
+               if (td->flag & TD_NOACTION)
+                       break;
+
+               if (td->flag & TD_SKIP)
+                       continue;
+
+               VecSubf(vec, td->iloc, t->center);
+
+               radius = Normalize(vec);
+
+               tratio = ratio * td->factor;
+
+               VecMulf(vec, radius * (1.0f - tratio) + t->val * tratio);
+
+               VecAddf(td->loc, t->center, vec);
+       }
+       
+
+       recalcData(t);
+
+       ED_area_headerprint(t->sa, str);
+
+       viewRedrawForce(t);
+
+       return 1;
+}
+
+/* ************************** ROTATION *************************** */
+
+
+void initRotation(TransInfo *t) 
+{
+       t->mode = TFM_ROTATION;
+       t->transform = Rotation;
+       
+       t->ndof.axis = 16;
+       /* Scale down and flip input for rotation */
+       t->ndof.factor[0] = -0.2f;
+       
+       t->idx_max = 0;
+       t->num.idx_max = 0;
+       t->snap[0] = 0.0f;
+       t->snap[1] = (float)((5.0/180)*M_PI);
+       t->snap[2] = t->snap[1] * 0.2f;
+       t->fac = 0;
+       
+       if (t->flag & T_2D_EDIT)
+               t->flag |= T_NO_CONSTRAINT;
+}
+
+static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short around) {
+       float vec[3], totmat[3][3], smat[3][3];
+       float eul[3], fmat[3][3], quat[4];
+       float *center = t->center;
+       
+       /* local constraint shouldn't alter center */
+       if (around == V3D_LOCAL) {
+               if (t->flag & (T_OBJECT|T_POSE)) {
+                       center = td->center;
+               }
+               else {
+                       /* !TODO! Make this if not rely on G */
+                       if(around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
+                               center = td->center;
+                       }
+               }
+       }
+               
+       if (t->flag & T_POINTS) {
+               Mat3MulMat3(totmat, mat, td->mtx);
+               Mat3MulMat3(smat, td->smtx, totmat);
+               
+               VecSubf(vec, td->iloc, center);
+               Mat3MulVecfl(smat, vec);
+               
+               VecAddf(td->loc, vec, center);
+
+               VecSubf(vec,td->loc,td->iloc);
+               protectedTransBits(td->protectflag, vec);
+               VecAddf(td->loc, td->iloc, vec);
+
+               if(td->flag & TD_USEQUAT) {
+                       Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
+                       Mat3ToQuat(fmat, quat); // Actual transform
+                       
+                       if(td->ext->quat){
+                               QuatMul(td->ext->quat, quat, td->ext->iquat);
+                               
+                               /* is there a reason not to have this here? -jahka */
+                               protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
+                       }
+               }
+       }
+       /**
+        * HACK WARNING
+        * 
+        * This is some VERY ugly special case to deal with pose mode.
+        * 
+        * The problem is that mtx and smtx include each bone orientation.
+        * 
+        * That is needed to rotate each bone properly, HOWEVER, to calculate
+        * the translation component, we only need the actual armature object's
+        * matrix (and inverse). That is not all though. Once the proper translation
+        * has been computed, it has to be converted back into the bone's space.
+        */
+       else if (t->flag & T_POSE) {
+               float pmtx[3][3], imtx[3][3];
+
+               // Extract and invert armature object matrix            
+               Mat3CpyMat4(pmtx, t->poseobj->obmat);
+               Mat3Inv(imtx, pmtx);
+               
+               if ((td->flag & TD_NO_LOC) == 0)
+               {
+                       VecSubf(vec, td->center, center);
+                       
+                       Mat3MulVecfl(pmtx, vec);        // To Global space
+                       Mat3MulVecfl(mat, vec);         // Applying rotation
+                       Mat3MulVecfl(imtx, vec);        // To Local space
+       
+                       VecAddf(vec, vec, center);
+                       /* vec now is the location where the object has to be */
+                       
+                       VecSubf(vec, vec, td->center); // Translation needed from the initial location
+                       
+                       Mat3MulVecfl(pmtx, vec);        // To Global space
+                       Mat3MulVecfl(td->smtx, vec);// To Pose space
+       
+                       protectedTransBits(td->protectflag, vec);
+       
+                       VecAddf(td->loc, td->iloc, vec);
+                       
+                       constraintTransLim(t, td);
+               }
+               
+               /* rotation */
+               if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
+                       Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
+                       
+                       Mat3ToQuat(fmat, quat); // Actual transform
+                       
+                       QuatMul(td->ext->quat, quat, td->ext->iquat);
+                       /* this function works on end result */
+                       protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
+                       
+                       constraintRotLim(t, td);
+               }
+       }
+       else {
+               
+               if ((td->flag & TD_NO_LOC) == 0)
+               {
+                       /* translation */
+                       VecSubf(vec, td->center, center);
+                       Mat3MulVecfl(mat, vec);
+                       VecAddf(vec, vec, center);
+                       /* vec now is the location where the object has to be */
+                       VecSubf(vec, vec, td->center);
+                       Mat3MulVecfl(td->smtx, vec);
+                       
+                       protectedTransBits(td->protectflag, vec);
+                       
+                       if(td->tdi) {
+                               TransDataIpokey *tdi= td->tdi;
+                               add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
+                               add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
+                               add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
+                       }
+                       else VecAddf(td->loc, td->iloc, vec);
+               }
+               
+               
+               constraintTransLim(t, td);
+
+               /* rotation */
+               if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
+                       if(td->flag & TD_USEQUAT) {
+                               Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
+                               Mat3ToQuat(fmat, quat); // Actual transform
+                               
+                               QuatMul(td->ext->quat, quat, td->ext->iquat);
+                               /* this function works on end result */
+                               protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
+                       }
+                       else {
+                               float obmat[3][3];
+                               
+                               /* are there ipo keys? */
+                               if(td->tdi) {
+                                       TransDataIpokey *tdi= td->tdi;
+                                       float current_rot[3];
+                                       float rot[3];
+                                       
+                                       /* current IPO value for compatible euler */
+                                       current_rot[0] = (tdi->rotx) ? tdi->rotx[0] : 0.0f;
+                                       current_rot[1] = (tdi->roty) ? tdi->roty[0] : 0.0f;
+                                       current_rot[2] = (tdi->rotz) ? tdi->rotz[0] : 0.0f;
+                                       VecMulf(current_rot, (float)(M_PI_2 / 9.0));
+                                       
+                                       /* calculate the total rotatation in eulers */
+                                       VecAddf(eul, td->ext->irot, td->ext->drot);
+                                       EulToMat3(eul, obmat);
+                                       /* mat = transform, obmat = object rotation */
+                                       Mat3MulMat3(fmat, mat, obmat);
+                                       
+                                       Mat3ToCompatibleEul(fmat, eul, current_rot);
+                                       
+                                       /* correct back for delta rot */
+                                       if(tdi->flag & TOB_IPODROT) {
+                                               VecSubf(rot, eul, td->ext->irot);
+                                       }
+                                       else {
+                                               VecSubf(rot, eul, td->ext->drot);
+                                       }
+                                       
+                                       VecMulf(rot, (float)(9.0/M_PI_2));
+                                       VecSubf(rot, rot, tdi->oldrot);
+                                       
+                                       protectedRotateBits(td->protectflag, rot, tdi->oldrot);
+                                       
+                                       add_tdi_poin(tdi->rotx, tdi->oldrot, rot[0]);
+                                       add_tdi_poin(tdi->roty, tdi->oldrot+1, rot[1]);
+                                       add_tdi_poin(tdi->rotz, tdi->oldrot+2, rot[2]);
+                               }
+                               else {
+                                       Mat3MulMat3(totmat, mat, td->mtx);
+                                       Mat3MulMat3(smat, td->smtx, totmat);
+                                       
+                                       /* calculate the total rotatation in eulers */
+                                       VecAddf(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
+                                       EulToMat3(eul, obmat);
+                                       /* mat = transform, obmat = object rotation */
+                                       Mat3MulMat3(fmat, smat, obmat);
+                                       
+                                       Mat3ToCompatibleEul(fmat, eul, td->ext->rot);
+                                       
+                                       /* correct back for delta rot */
+                                       VecSubf(eul, eul, td->ext->drot);
+                                       
+                                       /* and apply */
+                                       protectedRotateBits(td->protectflag, eul, td->ext->irot);
+                                       VECCOPY(td->ext->rot, eul);
+                               }
+                       }
+                       
+                       constraintRotLim(t, td);
+               }
+       }
+}
+
+static void applyRotation(TransInfo *t, float angle, float axis[3]) 
+{
+       TransData *td = t->data;
+       float mat[3][3];
+       int i;
+
+       VecRotToMat3(axis, angle, mat);
+       
+       for(i = 0 ; i < t->total; i++, td++) {
+
+               if (td->flag & TD_NOACTION)
+                       break;
+
+               if (td->flag & TD_SKIP)
+                       continue;
+               
+               if (t->con.applyRot) {
+                       t->con.applyRot(t, td, axis, NULL);
+                       VecRotToMat3(axis, angle * td->factor, mat);
+               }
+               else if (t->flag & T_PROP_EDIT) {
+                       VecRotToMat3(axis, angle * td->factor, mat);
+               }
+
+               ElementRotation(t, td, mat, t->around);
+       }
+}
+
+int Rotation(TransInfo *t, short mval[2]) 
+{
+       char str[64];
+
+       float final;
+
+       float axis[3];
+       float mat[3][3];
+
+       VECCOPY(axis, t->viewinv[2]);
+       VecMulf(axis, -1.0f);
+       Normalize(axis);
+
+       t->fac += InputDeltaAngle(t, mval);
+
+       final = t->fac;
+
+       applyNDofInput(&t->ndof, &final);
+       
+       snapGrid(t, &final);
+
+       if (t->con.applyRot) {
+               t->con.applyRot(t, NULL, axis, &final);
+       }
+       
+       applySnapping(t, &final);
+
+       if (hasNumInput(&t->num)) {
+               char c[20];
+
+               applyNumInput(&t->num, &final);
+
+               outputNumInput(&(t->num), c);
+
+               sprintf(str, "Rot: %s %s %s", &c[0], t->con.text, t->proptext);
+
+               /* Clamp between -180 and 180 */
+               while (final >= 180.0)
+                       final -= 360.0;
+               
+               while (final <= -180.0)
+                       final += 360.0;
+
+               final *= (float)(M_PI / 180.0);
+       }
+       else {
+               sprintf(str, "Rot: %.2f%s %s", 180.0*final/M_PI, t->con.text, t->proptext);
+       }
+
+       VecRotToMat3(axis, final, mat);
+
+       t->val = final;                         // used in manipulator
+       Mat3CpyMat3(t->mat, mat);       // used in manipulator
+       
+       applyRotation(t, final, axis);
+       
+       recalcData(t);
+
+       ED_area_headerprint(t->sa, str);
+
+       viewRedrawForce(t);
+
+       if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
+
+       return 1;
+}
+
+
+/* ************************** TRACKBALL *************************** */
+
+void initTrackball(TransInfo *t) 
+{
+       t->mode = TFM_TRACKBALL;
+       t->transform = Trackball;
+       
+       t->ndof.axis = 40;
+       /* Scale down input for rotation */
+       t->ndof.factor[0] = 0.2f;
+       t->ndof.factor[1] = 0.2f;
+
+       t->idx_max = 1;
+       t->num.idx_max = 1;
+       t->snap[0] = 0.0f;
+       t->snap[1] = (float)((5.0/180)*M_PI);
+       t->snap[2] = t->snap[1] * 0.2f;
+       t->fac = 0;
+       
+       t->flag |= T_NO_CONSTRAINT;
+}
+
+static void applyTrackball(TransInfo *t, float axis1[3], float axis2[3], float angles[2])
+{
+       TransData *td = t->data;
+       float mat[3][3], smat[3][3], totmat[3][3];
+       int i;
+
+       VecRotToMat3(axis1, angles[0], smat);
+       VecRotToMat3(axis2, angles[1], totmat);
+       
+       Mat3MulMat3(mat, smat, totmat);
+
+       for(i = 0 ; i < t->total; i++, td++) {
+               if (td->flag & TD_NOACTION)
+                       break;
+
+               if (td->flag & TD_SKIP)
+                       continue;
+               
+               if (t->flag & T_PROP_EDIT) {
+                       VecRotToMat3(axis1, td->factor * angles[0], smat);
+                       VecRotToMat3(axis2, td->factor * angles[1], totmat);
+                       
+                       Mat3MulMat3(mat, smat, totmat);
+               }
+               
+               ElementRotation(t, td, mat, t->around);
+       }
+}
+
+int Trackball(TransInfo *t, short mval[2]) 
+{
+       char str[128];
+       float axis1[3], axis2[3];
+       float mat[3][3], totmat[3][3], smat[3][3];
+       float phi[2];
+       
+       VECCOPY(axis1, t->persinv[0]);
+       VECCOPY(axis2, t->persinv[1]);
+       Normalize(axis1);
+       Normalize(axis2);
+       
+       /* factore has to become setting or so */
+       phi[0]= 0.01f*(float)( t->imval[1] - mval[1] );
+       phi[1]= 0.01f*(float)( mval[0] - t->imval[0] );
+               
+       applyNDofInput(&t->ndof, phi);
+       
+       snapGrid(t, phi);
+       
+       if (hasNumInput(&t->num)) {
+               char c[40];
+               
+               applyNumInput(&t->num, phi);
+               
+               outputNumInput(&(t->num), c);
+               
+               sprintf(str, "Trackball: %s %s %s", &c[0], &c[20], t->proptext);
+               
+               phi[0] *= (float)(M_PI / 180.0);
+               phi[1] *= (float)(M_PI / 180.0);
+       }
+       else {
+               sprintf(str, "Trackball: %.2f %.2f %s", 180.0*phi[0]/M_PI, 180.0*phi[1]/M_PI, t->proptext);
+       
+               if(t->flag & T_SHIFT_MOD) {
+                       if(phi[0] != 0.0) phi[0]/= 5.0f;
+                       if(phi[1] != 0.0) phi[1]/= 5.0f;
+               }
+       }
+
+       VecRotToMat3(axis1, phi[0], smat);
+       VecRotToMat3(axis2, phi[1], totmat);
+       
+       Mat3MulMat3(mat, smat, totmat);
+       
+       Mat3CpyMat3(t->mat, mat);       // used in manipulator
+       
+       applyTrackball(t, axis1, axis2, phi);
+       
+       recalcData(t);
+       
+       ED_area_headerprint(t->sa, str);
+       
+       viewRedrawForce(t);
+       
+       if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
+       
+       return 1;
+}
+
+/* ************************** TRANSLATION *************************** */
+       
+void initTranslation(TransInfo *t) 
+{
+       t->mode = TFM_TRANSLATION;
+       t->transform = Translation;
+
+       t->idx_max = (t->flag & T_2D_EDIT)? 1: 2;
+       t->num.flag = 0;
+       t->num.idx_max = t->idx_max;
+       
+       t->ndof.axis = 7;
+
+       if(t->spacetype == SPACE_VIEW3D) {
+               View3D *v3d = t->view;
+               
+               /* initgrabz() defines a factor for perspective depth correction, used in window_to_3d() */
+               if(t->flag & (T_EDIT|T_POSE)) {
+                       Object *ob= G.obedit?G.obedit:t->poseobj;
+                       float vec[3];
+                       
+                       VECCOPY(vec, t->center);
+                       Mat4MulVecfl(ob->obmat, vec);
+                       initgrabz(v3d, vec[0], vec[1], vec[2]);
+               }
+               else {
+                       initgrabz(v3d, t->center[0], t->center[1], t->center[2]);
+               } 
+
+               t->snap[0] = 0.0f;
+               t->snap[1] = v3d->gridview * 1.0f;
+               t->snap[2] = t->snap[1] * 0.1f;
+       }
+       else if(t->spacetype == SPACE_IMAGE) {
+               t->snap[0] = 0.0f;
+               t->snap[1] = 0.125f;
+               t->snap[2] = 0.0625f;
+       }
+       else {
+               t->snap[0] = 0.0f;
+               t->snap[1] = t->snap[2] = 1.0f;
+       }
+}
+
+static void headerTranslation(TransInfo *t, float vec[3], char *str) {
+       char tvec[60];
+       char distvec[20];
+       char autoik[20];
+       float dvec[3];
+       float dist;
+       
+       convertVecToDisplayNum(vec, dvec);
+
+       if (hasNumInput(&t->num)) {
+               outputNumInput(&(t->num), tvec);
+               dist = VecLength(t->num.val);
+       }
+       else {
+               dist = VecLength(vec);
+               sprintf(&tvec[0], "%.4f", dvec[0]);
+               sprintf(&tvec[20], "%.4f", dvec[1]);
+               sprintf(&tvec[40], "%.4f", dvec[2]);
+       }
+
+       if( dist > 1e10 || dist < -1e10 )       /* prevent string buffer overflow */
+               sprintf(distvec, "%.4e", dist);
+       else
+               sprintf(distvec, "%.4f", dist);
+               
+       if(t->flag & T_AUTOIK) {
+               short chainlen= G.scene->toolsettings->autoik_chainlen;
+               
+               if(chainlen)
+                       sprintf(autoik, "AutoIK-Len: %d", chainlen);
+               else
+                       strcpy(autoik, "");
+       }
+       else
+               strcpy(autoik, "");
+
+       if (t->con.mode & CON_APPLY) {
+               switch(t->num.idx_max) {
+               case 0:
+                       sprintf(str, "D: %s (%s)%s %s  %s", &tvec[0], distvec, t->con.text, t->proptext, &autoik[0]);
+                       break;
+               case 1:
+                       sprintf(str, "D: %s   D: %s (%s)%s %s  %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext, &autoik[0]);
+                       break;
+               case 2:
+                       sprintf(str, "D: %s   D: %s  D: %s (%s)%s %s  %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext, &autoik[0]);
+               }
+       }
+       else {
+               if(t->flag & T_2D_EDIT)
+                       sprintf(str, "Dx: %s   Dy: %s (%s)%s %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext);
+               else
+                       sprintf(str, "Dx: %s   Dy: %s  Dz: %s (%s)%s %s  %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext, &autoik[0]);
+       }
+}
+
+static void applyTranslation(TransInfo *t, float vec[3]) {
+       TransData *td = t->data;
+       float tvec[3];
+       int i;
+
+       for(i = 0 ; i < t->total; i++, td++) {
+               if (td->flag & TD_NOACTION)
+                       break;
+               
+               if (td->flag & TD_SKIP)
+                       continue;
+               
+               /* handle snapping rotation before doing the translation */
+               if (usingSnappingNormal(t))
+               {
+                       if (validSnappingNormal(t))
+                       {
+                               float *original_normal = td->axismtx[2];
+                               float axis[3];
+                               float quat[4];
+                               float mat[3][3];
+                               float angle;
+                               
+                               Crossf(axis, original_normal, t->tsnap.snapNormal);
+                               angle = saacos(Inpf(original_normal, t->tsnap.snapNormal));
+                               
+                               AxisAngleToQuat(quat, axis, angle);
+       
+                               QuatToMat3(quat, mat);
+                               
+                               ElementRotation(t, td, mat, V3D_LOCAL);
+                       }
+                       else
+                       {
+                               float mat[3][3];
+                               
+                               Mat3One(mat);
+                               
+                               ElementRotation(t, td, mat, V3D_LOCAL);
+                       }
+               }
+
+               if (t->con.applyVec) {
+                       float pvec[3];
+                       t->con.applyVec(t, td, vec, tvec, pvec);
+               }
+               else {
+                       VECCOPY(tvec, vec);
+               }
+               
+               Mat3MulVecfl(td->smtx, tvec);
+               VecMulf(tvec, td->factor);
+               
+               protectedTransBits(td->protectflag, tvec);
+               
+               /* transdata ipokey */
+               if(td->tdi) {
+                       TransDataIpokey *tdi= td->tdi;
+                       add_tdi_poin(tdi->locx, tdi->oldloc, tvec[0]);
+                       add_tdi_poin(tdi->locy, tdi->oldloc+1, tvec[1]);
+                       add_tdi_poin(tdi->locz, tdi->oldloc+2, tvec[2]);
+               }
+               else VecAddf(td->loc, td->iloc, tvec);
+               
+               constraintTransLim(t, td);
+       }
+}
+
+/* uses t->vec to store actual translation in */
+int Translation(TransInfo *t, short mval[2]) 
+{
+       float tvec[3];
+       char str[250];
+       
+       if(t->flag & T_SHIFT_MOD) {
+               float dvec[3];
+               /* calculate the main translation and the precise one separate */
+               convertViewVec(t, dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
+               VecMulf(dvec, 0.1f);
+               convertViewVec(t, t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
+               VecAddf(t->vec, t->vec, dvec);
+       }
+       else convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
+
+       if (t->con.mode & CON_APPLY) {
+               float pvec[3] = {0.0f, 0.0f, 0.0f};
+               applySnapping(t, t->vec);
+               t->con.applyVec(t, NULL, t->vec, tvec, pvec);
+               VECCOPY(t->vec, tvec);
+               headerTranslation(t, pvec, str);
+       }
+       else {
+               applyNDofInput(&t->ndof, t->vec);
+               snapGrid(t, t->vec);
+               applyNumInput(&t->num, t->vec);
+               applySnapping(t, t->vec);
+               headerTranslation(t, t->vec, str);
+       }
+       
+       applyTranslation(t, t->vec);
+
+       /* evil hack - redo translation if cliiping needeed */
+       if (t->flag & T_CLIP_UV && clipUVTransform(t, t->vec, 0))
+               applyTranslation(t, t->vec);
+
+       recalcData(t);
+
+       ED_area_headerprint(t->sa, str);
+       
+       viewRedrawForce(t);
+
+       drawSnapping(t);
+
+       return 1;
+}
+
+/* ************************** SHRINK/FATTEN *************************** */
+
+void initShrinkFatten(TransInfo *t) 
+{
+       // If not in mesh edit mode, fallback to Resize
+       if (G.obedit==NULL || G.obedit->type != OB_MESH) {
+               initResize(t);
+       }
+       else {
+               t->mode = TFM_SHRINKFATTEN;
+               t->transform = ShrinkFatten;
+       
+               t->idx_max = 0;
+               t->num.idx_max = 0;
+               t->snap[0] = 0.0f;
+               t->snap[1] = 1.0f;
+               t->snap[2] = t->snap[1] * 0.1f;
+               
+               t->flag |= T_NO_CONSTRAINT;
+       }
+}
+
+
+
+int ShrinkFatten(TransInfo *t, short mval[2]) 
+{
+       float vec[3];
+       float distance;
+       int i;
+       char str[64];
+       TransData *td = t->data;
+
+       distance = -InputVerticalAbsolute(t, mval);
+
+       snapGrid(t, &distance);
+
+       applyNumInput(&t->num, &distance);
+
+       /* header print for NumInput */
+       if (hasNumInput(&t->num)) {
+               char c[20];
+
+               outputNumInput(&(t->num), c);
+
+               sprintf(str, "Shrink/Fatten: %s %s", c, t->proptext);
+       }
+       else {
+               /* default header print */
+               sprintf(str, "Shrink/Fatten: %.4f %s", distance, t->proptext);
+       }
+       
+       
+       for(i = 0 ; i < t->total; i++, td++) {
+               if (td->flag & TD_NOACTION)
+                       break;
+
+               if (td->flag & TD_SKIP)
+                       continue;
+
+               VECCOPY(vec, td->axismtx[2]);
+               VecMulf(vec, distance);
+               VecMulf(vec, td->factor);
+
+               VecAddf(td->loc, td->iloc, vec);
+       }
+
+       recalcData(t);
+
+       ED_area_headerprint(t->sa, str);
+
+       viewRedrawForce(t);
+
+       return 1;
+}
+
+/* ************************** TILT *************************** */
+
+void initTilt(TransInfo *t) 
+{
+       t->mode = TFM_TILT;
+       t->transform = Tilt;
+
+       t->ndof.axis = 16;
+       /* Scale down and flip input for rotation */
+       t->ndof.factor[0] = -0.2f;
+
+       t->idx_max = 0;
+       t->num.idx_max = 0;
+       t->snap[0] = 0.0f;
+       t->snap[1] = (float)((5.0/180)*M_PI);
+       t->snap[2] = t->snap[1] * 0.2f;
+       t->fac = 0;
+       
+       t->flag |= T_NO_CONSTRAINT;
+}
+
+
+
+int Tilt(TransInfo *t, short mval[2]) 
+{
+       TransData *td = t->data;
+       int i;
+       char str[50];
+
+       float final;
+
+       t->fac += InputDeltaAngle(t, mval);
+
+       final = t->fac;
+       
+       applyNDofInput(&t->ndof, &final);
+
+       snapGrid(t, &final);
+
+       if (hasNumInput(&t->num)) {
+               char c[20];
+
+               applyNumInput(&t->num, &final);
+
+               outputNumInput(&(t->num), c);
+
+               sprintf(str, "Tilt: %s %s", &c[0], t->proptext);
+
+               final *= (float)(M_PI / 180.0);
+       }
+       else {
+               sprintf(str, "Tilt: %.2f %s", 180.0*final/M_PI, t->proptext);
+       }
+
+       for(i = 0 ; i < t->total; i++, td++) {
+               if (td->flag & TD_NOACTION)
+                       break;
+
+               if (td->flag & TD_SKIP)
+                       continue;
+
+               if (td->val) {
+                       *td->val = td->ival + final * td->factor;
+               }
+       }
+
+       recalcData(t);
+
+       ED_area_headerprint(t->sa, str);
+
+       viewRedrawForce(t);
+
+       helpline (t, t->center);
+
+       return 1;
+}
+
+
+/* ******************** Curve Shrink/Fatten *************** */
+
+int CurveShrinkFatten(TransInfo *t, short mval[2]) 
+{
+       TransData *td = t->data;
+       float ratio;
+       int i;
+       char str[50];
+       
+       if(t->flag & T_SHIFT_MOD) {
+               /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
+               float dx= (float)(t->center2d[0] - t->shiftmval[0]);
+               float dy= (float)(t->center2d[1] - t->shiftmval[1]);
+               ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
+               
+               dx= (float)(t->center2d[0] - mval[0]);
+               dy= (float)(t->center2d[1] - mval[1]);
+               ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
+               
+       }
+       else {
+               float dx= (float)(t->center2d[0] - mval[0]);
+               float dy= (float)(t->center2d[1] - mval[1]);
+               ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
+       }
+       
+       snapGrid(t, &ratio);
+       
+       applyNumInput(&t->num, &ratio);
+       
+       /* header print for NumInput */
+       if (hasNumInput(&t->num)) {
+               char c[20];
+               
+               outputNumInput(&(t->num), c);
+               sprintf(str, "Shrink/Fatten: %s", c);
+       }
+       else {
+               sprintf(str, "Shrink/Fatten: %3f", ratio);
+       }
+       
+       for(i = 0 ; i < t->total; i++, td++) {
+               if (td->flag & TD_NOACTION)
+                       break;
+
+               if (td->flag & TD_SKIP)
+                       continue;
+               
+               if(td->val) {
+                       //*td->val= ratio;
+                       *td->val= td->ival*ratio;
+                       if (*td->val <= 0.0f) *td->val = 0.0001f;
+               }
+       }
+       
+       recalcData(t);
+       
+       ED_area_headerprint(t->sa, str);
+       
+       viewRedrawForce(t);
+       
+       if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
+       
+       return 1;
+}
+
+void initCurveShrinkFatten(TransInfo *t)
+{
+       t->mode = TFM_CURVE_SHRINKFATTEN;
+       t->transform = CurveShrinkFatten;
+       
+       t->idx_max = 0;
+       t->num.idx_max = 0;
+       t->snap[0] = 0.0f;
+       t->snap[1] = 0.1f;
+       t->snap[2] = t->snap[1] * 0.1f;
+       
+       t->flag |= T_NO_CONSTRAINT;
+
+       t->fac = (float)sqrt( (
+                  ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
+                  +
+                  ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
+                  ) );
+}
+
+/* ************************** PUSH/PULL *************************** */
+
+void initPushPull(TransInfo *t) 
+{
+       t->mode = TFM_PUSHPULL;
+       t->transform = PushPull;
+       
+       t->ndof.axis = 4;
+       /* Flip direction */
+       t->ndof.factor[0] = -1.0f;
+
+       t->idx_max = 0;
+       t->num.idx_max = 0;
+       t->snap[0] = 0.0f;
+       t->snap[1] = 1.0f;
+       t->snap[2] = t->snap[1] * 0.1f;
+}
+
+
+int PushPull(TransInfo *t, short mval[2]) 
+{
+       float vec[3], axis[3];
+       float distance;
+       int i;
+       char str[128];
+       TransData *td = t->data;
+
+       distance = InputVerticalAbsolute(t, mval);
+       
+       applyNDofInput(&t->ndof, &distance);
+
+       snapGrid(t, &distance);
+
+       applyNumInput(&t->num, &distance);
+
+       /* header print for NumInput */
+       if (hasNumInput(&t->num)) {
+               char c[20];
+
+               outputNumInput(&(t->num), c);
+
+               sprintf(str, "Push/Pull: %s%s %s", c, t->con.text, t->proptext);
+       }
+       else {
+               /* default header print */
+               sprintf(str, "Push/Pull: %.4f%s %s", distance, t->con.text, t->proptext);
+       }
+       
+       if (t->con.applyRot && t->con.mode & CON_APPLY) {
+               t->con.applyRot(t, NULL, axis, NULL);
+       }
+       
+       for(i = 0 ; i < t->total; i++, td++) {
+               if (td->flag & TD_NOACTION)
+                       break;
+
+               if (td->flag & TD_SKIP)
+                       continue;
+
+               VecSubf(vec, t->center, td->center);
+               if (t->con.applyRot && t->con.mode & CON_APPLY) {
+                       t->con.applyRot(t, td, axis, NULL);
+                       if (isLockConstraint(t)) {
+                               float dvec[3];
+                               Projf(dvec, vec, axis);
+                               VecSubf(vec, vec, dvec);
+                       }
+                       else {
+                               Projf(vec, vec, axis);
+                       }
+               }
+               Normalize(vec);
+               VecMulf(vec, distance);
+               VecMulf(vec, td->factor);
+
+               VecAddf(td->loc, td->iloc, vec);
+       }
+
+       recalcData(t);
+
+       ED_area_headerprint(t->sa, str);
+
+       viewRedrawForce(t);
+
+       return 1;
+}
+
+/* ************************** BEVEL **************************** */
+
+void initBevel(TransInfo *t) 
+{
+       t->mode = TFM_BEVEL;
+       t->flag |= T_NO_CONSTRAINT;
+       t->num.flag |= NUM_NO_NEGATIVE;
+       t->transform = Bevel;
+       t->handleEvent = handleEventBevel;
+
+       t->idx_max = 0;
+       t->num.idx_max = 0;
+       t->snap[0] = 0.0f;
+       t->snap[1] = 0.1f;
+       t->snap[2] = t->snap[1] * 0.1f;
+
+       /* DON'T KNOW WHY THIS IS NEEDED */
+       if (G.editBMesh->imval[0] == 0 && G.editBMesh->imval[1] == 0) {
+               /* save the initial mouse co */
+               G.editBMesh->imval[0] = t->imval[0];
+               G.editBMesh->imval[1] = t->imval[1];
+       }
+       else {
+               /* restore the mouse co from a previous call to initTransform() */
+               t->imval[0] = G.editBMesh->imval[0];
+               t->imval[1] = G.editBMesh->imval[1];
+       }
+}
+
+int handleEventBevel(TransInfo *t, wmEvent *event)
+{
+       if (event->val) {
+               if(!G.editBMesh) return 0;
+
+               switch (event->type) {
+               case MIDDLEMOUSE:
+                       G.editBMesh->options ^= BME_BEVEL_VERT;
+                       t->state = TRANS_CANCEL;
+                       return 1;
+               //case PADPLUSKEY:
+               //      G.editBMesh->options ^= BME_BEVEL_RES;
+               //      G.editBMesh->res += 1;
+               //      if (G.editBMesh->res > 4) {
+               //              G.editBMesh->res = 4;
+               //      }
+               //      t->state = TRANS_CANCEL;
+               //      return 1;
+               //case PADMINUS:
+               //      G.editBMesh->options ^= BME_BEVEL_RES;
+               //      G.editBMesh->res -= 1;
+               //      if (G.editBMesh->res < 0) {
+               //              G.editBMesh->res = 0;
+               //      }
+               //      t->state = TRANS_CANCEL;
+               //      return 1;
+               default:
+                       return 0;
+               }
+       }
+       return 0;
+}
+
+int Bevel(TransInfo *t, short mval[2])
+{
+       float distance,d;
+       int i;
+       char str[128];
+       char *mode;
+       TransData *td = t->data;
+
+       mode = (G.editBMesh->options & BME_BEVEL_VERT) ? "verts only" : "normal";
+       distance = InputHorizontalAbsolute(t, mval)/4; /* 4 just seemed a nice value to me, nothing special */
+       
+       distance = fabs(distance);
+
+       snapGrid(t, &distance);
+
+       applyNumInput(&t->num, &distance);
+
+       /* header print for NumInput */
+       if (hasNumInput(&t->num)) {
+               char c[20];
+
+               outputNumInput(&(t->num), c);
+
+               sprintf(str, "Bevel - Dist: %s, Mode: %s (MMB to toggle))", c, mode);
+       }
+       else {
+               /* default header print */
+               sprintf(str, "Bevel - Dist: %.4f, Mode: %s (MMB to toggle))", distance, mode);
+       }
+       
+       if (distance < 0) distance = -distance;
+       for(i = 0 ; i < t->total; i++, td++) {
+               if (td->axismtx[1][0] > 0 && distance > td->axismtx[1][0]) {
+                       d = td->axismtx[1][0];
+               }
+               else {
+                       d = distance;
+               }
+               VECADDFAC(td->loc,td->center,td->axismtx[0],(*td->val)*d);
+       }
+
+       recalcData(t);
+
+       ED_area_headerprint(t->sa, str);
+
+       viewRedrawForce(t);
+
+       return 1;
+}
+
+/* ************************** BEVEL WEIGHT *************************** */
+
+void initBevelWeight(TransInfo *t) 
+{
+       t->mode = TFM_BWEIGHT;
+       t->transform = BevelWeight;
+       
+       t->idx_max = 0;
+       t->num.idx_max = 0;
+       t->snap[0] = 0.0f;
+       t->snap[1] = 0.1f;
+       t->snap[2] = t->snap[1] * 0.1f;
+       
+       t->flag |= T_NO_CONSTRAINT;
+
+       t->fac = (float)sqrt(
+               (
+                       ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
+               +
+                       ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
+               ) );
+
+       if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
+}
+
+int BevelWeight(TransInfo *t, short mval[2]) 
+{
+       TransData *td = t->data;
+       float weight;
+       int i;
+       char str[50];
+
+               
+       if(t->flag & T_SHIFT_MOD) {
+               /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
+               float dx= (float)(t->center2d[0] - t->shiftmval[0]);
+               float dy= (float)(t->center2d[1] - t->shiftmval[1]);
+               weight = (float)sqrt( dx*dx + dy*dy)/t->fac;
+               
+               dx= (float)(t->center2d[0] - mval[0]);
+               dy= (float)(t->center2d[1] - mval[1]);
+               weight+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -weight);
+               
+       }
+       else {
+               float dx= (float)(t->center2d[0] - mval[0]);
+               float dy= (float)(t->center2d[1] - mval[1]);
+               weight = (float)sqrt( dx*dx + dy*dy)/t->fac;
+       }
+
+       weight -= 1.0f;
+       if (weight > 1.0f) weight = 1.0f;
+
+       snapGrid(t, &weight);
+
+       applyNumInput(&t->num, &weight);
+
+       /* header print for NumInput */
+       if (hasNumInput(&t->num)) {
+               char c[20];
+
+               outputNumInput(&(t->num), c);
+
+               if (weight >= 0.0f)
+                       sprintf(str, "Bevel Weight: +%s %s", c, t->proptext);
+               else
+                       sprintf(str, "Bevel Weight: %s %s", c, t->proptext);
+       }
+       else {
+               /* default header print */
+               if (weight >= 0.0f)
+                       sprintf(str, "Bevel Weight: +%.3f %s", weight, t->proptext);
+               else
+                       sprintf(str, "Bevel Weight: %.3f %s", weight, t->proptext);
+       }
+       
+       for(i = 0 ; i < t->total; i++, td++) {
+               if (td->flag & TD_NOACTION)
+                       break;
+
+               if (td->val) {
+                       *td->val = td->ival + weight * td->factor;
+                       if (*td->val < 0.0f) *td->val = 0.0f;
+                       if (*td->val > 1.0f) *td->val = 1.0f;
+               }
+       }
+
+       recalcData(t);
+
+       ED_area_headerprint(t->sa, str);
+
+       viewRedrawForce(t);
+
+       helpline (t, t->center);
+
+       return 1;
+}
+
+/* ************************** CREASE *************************** */
+
+void initCrease(TransInfo *t) 
+{
+       t->mode = TFM_CREASE;
+       t->transform = Crease;
+       
+       t->idx_max = 0;
+       t->num.idx_max = 0;
+       t->snap[0] = 0.0f;
+       t->snap[1] = 0.1f;
+       t->snap[2] = t->snap[1] * 0.1f;
+       
+       t->flag |= T_NO_CONSTRAINT;
+
+       t->fac = (float)sqrt(
+               (
+                       ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
+               +
+                       ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
+               ) );
+
+       if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
+}
+
+int Crease(TransInfo *t, short mval[2]) 
+{
+       TransData *td = t->data;
+       float crease;
+       int i;
+       char str[50];
+
+               
+       if(t->flag & T_SHIFT_MOD) {
+               /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
+               float dx= (float)(t->center2d[0] - t->shiftmval[0]);
+               float dy= (float)(t->center2d[1] - t->shiftmval[1]);
+               crease = (float)sqrt( dx*dx + dy*dy)/t->fac;
+               
+               dx= (float)(t->center2d[0] - mval[0]);
+               dy= (float)(t->center2d[1] - mval[1]);
+               crease+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -crease);
+               
+       }
+       else {
+               float dx= (float)(t->center2d[0] - mval[0]);
+               float dy= (float)(t->center2d[1] - mval[1]);
+               crease = (float)sqrt( dx*dx + dy*dy)/t->fac;
+       }
+
+       crease -= 1.0f;
+       if (crease > 1.0f) crease = 1.0f;
+
+       snapGrid(t, &crease);
+
+       applyNumInput(&t->num, &crease);
+
+       /* header print for NumInput */
+       if (hasNumInput(&t->num)) {
+               char c[20];
+
+               outputNumInput(&(t->num), c);
+
+               if (crease >= 0.0f)
+                       sprintf(str, "Crease: +%s %s", c, t->proptext);
+               else
+                       sprintf(str, "Crease: %s %s", c, t->proptext);
+       }
+       else {
+               /* default header print */
+               if (crease >= 0.0f)
+                       sprintf(str, "Crease: +%.3f %s", crease, t->proptext);
+               else
+                       sprintf(str, "Crease: %.3f %s", crease, t->proptext);
+       }
+       
+       for(i = 0 ; i < t->total; i++, td++) {
+               if (td->flag & TD_NOACTION)
+                       break;
+
+               if (td->flag & TD_SKIP)
+                       continue;
+
+               if (td->val) {
+                       *td->val = td->ival + crease * td->factor;
+                       if (*td->val < 0.0f) *td->val = 0.0f;
+                       if (*td->val > 1.0f) *td->val = 1.0f;
+               }
+       }
+
+       recalcData(t);
+
+       ED_area_headerprint(t->sa, str);
+
+       viewRedrawForce(t);
+
+       helpline (t, t->center);
+
+       return 1;
+}
+
+/* ******************** EditBone (B-bone) width scaling *************** */
+
+void initBoneSize(TransInfo *t)
+{
+       t->mode = TFM_BONESIZE;
+       t->transform = BoneSize;
+       
+       t->idx_max = 2;
+       t->num.idx_max = 2;
+       t->num.flag |= NUM_NULL_ONE;
+       t->snap[0] = 0.0f;
+       t->snap[1] = 0.1f;
+       t->snap[2] = t->snap[1] * 0.1f;
+       
+       t->fac = (float)sqrt( (
+                                          ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
+                                          +
+                                          ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
+                                          ) );
+       
+       if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
+}
+
+static void headerBoneSize(TransInfo *t, float vec[3], char *str) {
+       char tvec[60];
+       if (hasNumInput(&t->num)) {
+               outputNumInput(&(t->num), tvec);
+       }
+       else {
+               sprintf(&tvec[0], "%.4f", vec[0]);
+               sprintf(&tvec[20], "%.4f", vec[1]);
+               sprintf(&tvec[40], "%.4f", vec[2]);
+       }
+
+       /* hmm... perhaps the y-axis values don't need to be shown? */
+       if (t->con.mode & CON_APPLY) {
+               if (t->num.idx_max == 0)
+                       sprintf(str, "ScaleB: %s%s %s", &tvec[0], t->con.text, t->proptext);
+               else 
+                       sprintf(str, "ScaleB: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
+       }
+       else {
+               sprintf(str, "ScaleB X: %s  Y: %s  Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
+       }
+}
+
+static void ElementBoneSize(TransInfo *t, TransData *td, float mat[3][3]) 
+{
+       float tmat[3][3], smat[3][3], oldy;
+       float sizemat[3][3];
+       
+       Mat3MulMat3(smat, mat, td->mtx);
+       Mat3MulMat3(tmat, td->smtx, smat);
+       
+       if (t->con.applySize) {
+               t->con.applySize(t, td, tmat);
+       }
+       
+       /* we've tucked the scale in loc */
+       oldy= td->iloc[1];
+       SizeToMat3(td->iloc, sizemat);
+       Mat3MulMat3(tmat, tmat, sizemat);
+       Mat3ToSize(tmat, td->loc);
+       td->loc[1]= oldy;
+}
+
+int BoneSize(TransInfo *t, short mval[2]) 
+{
+       TransData *td = t->data;
+       float size[3], mat[3][3];
+       float ratio;
+       int i;
+       char str[60];
+       
+       /* for manipulator, center handle, the scaling can't be done relative to center */
+       if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) {
+               ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f;
+       }
+       else {
+               
+               if(t->flag & T_SHIFT_MOD) {
+                       /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
+                       float dx= (float)(t->center2d[0] - t->shiftmval[0]);
+                       float dy= (float)(t->center2d[1] - t->shiftmval[1]);
+                       ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
+                       
+                       dx= (float)(t->center2d[0] - mval[0]);
+                       dy= (float)(t->center2d[1] - mval[1]);
+                       ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
+                       
+               }
+               else {
+                       float dx= (float)(t->center2d[0] - mval[0]);
+                       float dy= (float)(t->center2d[1] - mval[1]);
+                       ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
+               }
+               
+               /* flip scale, but not for manipulator center handle */
+               if      ((t->center2d[0] - mval[0]) * (t->center2d[0] - t->imval[0]) + 
+                        (t->center2d[1] - mval[1]) * (t->center2d[1] - t->imval[1]) < 0)
+                       ratio *= -1.0f;
+       }
+       
+       size[0] = size[1] = size[2] = ratio;
+       
+       snapGrid(t, size);
+       
+       if (hasNumInput(&t->num)) {
+               applyNumInput(&t->num, size);
+               constraintNumInput(t, size);
+       }
+       
+       SizeToMat3(size, mat);
+       
+       if (t->con.applySize) {
+               t->con.applySize(t, NULL, mat);
+       }
+       
+       Mat3CpyMat3(t->mat, mat);       // used in manipulator
+       
+       headerBoneSize(t, size, str);
+       
+       for(i = 0 ; i < t->total; i++, td++) {
+               if (td->flag & TD_NOACTION)
+                       break;
+
+               if (td->flag & TD_SKIP)
+                       continue;
+               
+               ElementBoneSize(t, td, mat);
+       }
+       
+       recalcData(t);
+       
+       ED_area_headerprint(t->sa, str);
+       
+       viewRedrawForce(t);
+       
+       if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
+       
+       return 1;
+}
+
+
+/* ******************** EditBone envelope *************** */
+
+void initBoneEnvelope(TransInfo *t)
+{
+       t->mode = TFM_BONE_ENVELOPE;
+       t->transform = BoneEnvelope;
+       
+       t->idx_max = 0;
+       t->num.idx_max = 0;
+       t->snap[0] = 0.0f;
+       t->snap[1] = 0.1f;
+       t->snap[2] = t->snap[1] * 0.1f;
+
+       t->flag |= T_NO_CONSTRAINT;
+
+       t->fac = (float)sqrt( (
+                                                  ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
+                                                  +
+                                                  ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
+                                                  ) );
+       
+       if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
+}
+
+int BoneEnvelope(TransInfo *t, short mval[2]) 
+{
+       TransData *td = t->data;
+       float ratio;
+       int i;
+       char str[50];
+       
+       if(t->flag & T_SHIFT_MOD) {
+               /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
+               float dx= (float)(t->center2d[0] - t->shiftmval[0]);
+               float dy= (float)(t->center2d[1] - t->shiftmval[1]);
+               ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
+               
+               dx= (float)(t->center2d[0] - mval[0]);
+               dy= (float)(t->center2d[1] - mval[1]);
+               ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
+               
+       }
+       else {
+               float dx= (float)(t->center2d[0] - mval[0]);
+               float dy= (float)(t->center2d[1] - mval[1]);
+               ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
+       }
+       
+       snapGrid(t, &ratio);
+       
+       applyNumInput(&t->num, &ratio);
+       
+       /* header print for NumInput */
+       if (hasNumInput(&t->num)) {
+               char c[20];
+               
+               outputNumInput(&(t->num), c);
+               sprintf(str, "Envelope: %s", c);
+       }
+       else {
+               sprintf(str, "Envelope: %3f", ratio);
+       }
+       
+       for(i = 0 ; i < t->total; i++, td++) {
+               if (td->flag & TD_NOACTION)
+                       break;
+
+               if (td->flag & TD_SKIP)
+                       continue;
+               
+               if (td->val) {
+                       /* if the old/original value was 0.0f, then just use ratio */
+                       if (td->ival)
+                               *td->val= td->ival*ratio;
+                       else
+                               *td->val= ratio;
+               }
+       }
+       
+       recalcData(t);
+       
+       ED_area_headerprint(t->sa, str);
+       
+       viewRedrawForce(t);
+       
+       if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
+       
+       return 1;
+}
+
+
+/* ******************** EditBone roll *************** */
+
+void initBoneRoll(TransInfo *t)
+{
+       t->mode = TFM_BONE_ROLL;
+       t->transform = BoneRoll;
+
+       t->idx_max = 0;
+       t->num.idx_max = 0;
+       t->snap[0] = 0.0f;
+       t->snap[1] = (float)((5.0/180)*M_PI);
+       t->snap[2] = t->snap[1] * 0.2f;
+       
+       t->fac = 0.0f;
+       
+       t->flag |= T_NO_CONSTRAINT;
+}
+
+int BoneRoll(TransInfo *t, short mval[2]) 
+{
+       TransData *td = t->data;
+       int i;
+       char str[50];
+
+       float final;
+
+       t->fac += InputDeltaAngle(t, mval);
+
+       final = t->fac;
+
+       snapGrid(t, &final);
+
+       if (hasNumInput(&t->num)) {
+               char c[20];
+
+               applyNumInput(&t->num, &final);
+
+               outputNumInput(&(t->num), c);
+
+               sprintf(str, "Roll: %s", &c[0]);
+
+               final *= (float)(M_PI / 180.0);
+       }
+       else {
+               sprintf(str, "Roll: %.2f", 180.0*final/M_PI);
+       }
+       
+       /* set roll values */
+       for (i = 0; i < t->total; i++, td++) {  
+               if (td->flag & TD_NOACTION)
+                       break;
+
+               if (td->flag & TD_SKIP)
+                       continue;
+               
+               *(td->val) = td->ival - final;
+       }
+               
+       recalcData(t);
+
+       ED_area_headerprint(t->sa, str);
+
+       viewRedrawForce(t);
+
+       if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
+
+       return 1;
+}
+
+/* ************************** BAKE TIME ******************* */
+
+void initBakeTime(TransInfo *t) 
+{
+       t->idx_max = 0;
+       t->num.idx_max = 0;
+       t->snap[0] = 0.0f;
+       t->snap[1] = 1.0f;
+       t->snap[2] = t->snap[1] * 0.1f;
+       t->transform = BakeTime;
+       t->fac = 0.1f;
+}
+
+int BakeTime(TransInfo *t, short mval[2]) 
+{
+       TransData *td = t->data;
+       float time;
+       int i;
+       char str[50];
+
+               
+       if(t->flag & T_SHIFT_MOD) {
+               /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
+               time= (float)(t->center2d[0] - t->shiftmval[0])*t->fac;
+               time+= 0.1f*((float)(t->center2d[0]*t->fac - mval[0]) -time);
+       }
+       else {
+               time = (float)(t->center2d[0] - mval[0])*t->fac;
+       }
+
+       snapGrid(t, &time);
+
+       applyNumInput(&t->num, &time);
+
+       /* header print for NumInput */
+       if (hasNumInput(&t->num)) {
+               char c[20];
+
+               outputNumInput(&(t->num), c);
+
+               if (time >= 0.0f)
+                       sprintf(str, "Time: +%s %s", c, t->proptext);
+               else
+                       sprintf(str, "Time: %s %s", c, t->proptext);
+       }
+       else {
+               /* default header print */
+               if (time >= 0.0f)
+                       sprintf(str, "Time: +%.3f %s", time, t->proptext);
+               else
+                       sprintf(str, "Time: %.3f %s", time, t->proptext);
+       }
+       
+       for(i = 0 ; i < t->total; i++, td++) {
+               if (td->flag & TD_NOACTION)
+                       break;
+
+               if (td->flag & TD_SKIP)
+                       continue;
+
+               if (td->val) {
+                       *td->val = td->ival + time * td->factor;
+                       if (td->ext->size && *td->val < *td->ext->size) *td->val = *td->ext->size;
+                       if (td->ext->quat && *td->val > *td->ext->quat) *td->val = *td->ext->quat;
+               }
+       }
+
+       recalcData(t);
+
+       ED_area_headerprint(t->sa, str);
+
+       viewRedrawForce(t);
+
+       helpline (t, t->center);
+
+       return 1;
+}
+
+/* ************************** MIRROR *************************** */
+
+void initMirror(TransInfo *t) 
+{
+       t->flag |= T_NULL_ONE;
+       if (!G.obedit) {
+               t->flag |= T_NO_ZERO;
+       }
+       
+       t->transform = Mirror;
+}
+
+int Mirror(TransInfo *t, short mval[2]) 
+{
+       TransData *td;
+       float size[3], mat[3][3];
+       int i;
+       char str[200];
+
+       /*
+        * OPTIMISATION:
+        * This still recalcs transformation on mouse move
+        * while it should only recalc on constraint change
+        * */
+
+       /* if an axis has been selected */
+       if (t->con.mode & CON_APPLY) {
+               size[0] = size[1] = size[2] = -1;
+       
+               SizeToMat3(size, mat);
+               
+               if (t->con.applySize) {
+                       t->con.applySize(t, NULL, mat);
+               }
+               
+               sprintf(str, "Mirror%s", t->con.text);
+       
+               for(i = 0, td=t->data; i < t->total; i++, td++) {
+                       if (td->flag & TD_NOACTION)
+                               break;
+       
+                       if (td->flag & TD_SKIP)
+                               continue;
+                       
+                       ElementResize(t, td, mat);
+               }
+       
+               recalcData(t);
+       
+               ED_area_headerprint(t->sa, str);
+       
+               viewRedrawForce(t);
+       }
+       else
+       {
+               size[0] = size[1] = size[2] = 1;
+       
+               SizeToMat3(size, mat);
+               
+               for(i = 0, td=t->data; i < t->total; i++, td++) {
+                       if (td->flag & TD_NOACTION)
+                               break;
+       
+                       if (td->flag & TD_SKIP)
+                               continue;
+                       
+                       ElementResize(t, td, mat);
+               }
+       
+               recalcData(t);
+       
+               ED_area_headerprint(t->sa, "Select a mirror axis (X, Y, Z)");
+       
+               viewRedrawForce(t);
+       }
+
+       return 1;
+}
+
+/* ************************** ALIGN *************************** */
+
+void initAlign(TransInfo *t) 
+{
+       t->flag |= T_NO_CONSTRAINT;
+       
+       t->transform = Align;
+}
+
+int Align(TransInfo *t, short mval[2])
+{
+       TransData *td = t->data;
+       float center[3];
+       int i;
+
+       /* saving original center */
+       VECCOPY(center, t->center);
+
+       for(i = 0 ; i < t->total; i++, td++)
+       {
+               float mat[3][3], invmat[3][3];
+               
+               if (td->flag & TD_NOACTION)
+                       break;
+
+               if (td->flag & TD_SKIP)
+                       continue;
+               
+               /* around local centers */
+               if (t->flag & (T_OBJECT|T_POSE)) {
+                       VECCOPY(t->center, td->center);
+               }
+               else {
+                       if(G.scene->selectmode & SCE_SELECT_FACE) {
+                               VECCOPY(t->center, td->center);
+                       }
+               }
+
+               Mat3Inv(invmat, td->axismtx);
+               
+               Mat3MulMat3(mat, t->spacemtx, invmat);  
+
+               ElementRotation(t, td, mat, t->around);
+       }
+
+       /* restoring original center */
+       VECCOPY(t->center, center);
+               
+       recalcData(t);
+
+       ED_area_headerprint(t->sa, "Align");
+       
+       return 1;
+}
+
+/* ************************** ANIM EDITORS - TRANSFORM TOOLS *************************** */
+
+/* ---------------- Special Helpers for Various Settings ------------- */
+
+/* This function returns the snapping 'mode' for Animation Editors only 
+ * We cannot use the standard snapping due to NLA-strip scaling complexities.
+ */
+static short getAnimEdit_SnapMode(TransInfo *t)
+{
+       short autosnap= SACTSNAP_OFF;
+#if 0 // TRANSFORM_FIX_ME      
+       /* currently, some of these are only for the action editor */
+       if (t->spacetype == SPACE_ACTION && G.saction) {
+               switch (G.saction->autosnap) {
+               case SACTSNAP_OFF:
+                       if (G.qual == LR_CTRLKEY) 
+                               autosnap= SACTSNAP_STEP;
+                       else if (G.qual == LR_SHIFTKEY)
+                               autosnap= SACTSNAP_FRAME;
+                       else if (G.qual == LR_ALTKEY)
+                               autosnap= SACTSNAP_MARKER;
+                       else
+                               autosnap= SACTSNAP_OFF;
+                       break;
+               case SACTSNAP_STEP:
+                       autosnap= (G.qual==LR_CTRLKEY)? SACTSNAP_OFF: SACTSNAP_STEP;
+                       break;
+               case SACTSNAP_FRAME:
+                       autosnap= (G.qual==LR_SHIFTKEY)? SACTSNAP_OFF: SACTSNAP_FRAME;
+                       break;
+               case SACTSNAP_MARKER:
+                       autosnap= (G.qual==LR_ALTKEY)? SACTSNAP_OFF: SACTSNAP_MARKER;
+                       break;
+               }
+       }
+       else if (t->spacetype == SPACE_NLA && G.snla) {
+               switch (G.snla->autosnap) {
+               case SACTSNAP_OFF:
+                       if (G.qual == LR_CTRLKEY) 
+                               autosnap= SACTSNAP_STEP;
+                       else if (G.qual == LR_SHIFTKEY)
+                               autosnap= SACTSNAP_FRAME;
+                       else if (G.qual == LR_ALTKEY)
+                               autosnap= SACTSNAP_MARKER;
+                       else
+                               autosnap= SACTSNAP_OFF;
+                       break;
+               case SACTSNAP_STEP:
+                       autosnap= (G.qual==LR_CTRLKEY)? SACTSNAP_OFF: SACTSNAP_STEP;
+                       break;
+               case SACTSNAP_FRAME:
+                       autosnap= (G.qual==LR_SHIFTKEY)? SACTSNAP_OFF: SACTSNAP_FRAME;
+                       break;
+               case SACTSNAP_MARKER:
+                       autosnap= (G.qual==LR_ALTKEY)? SACTSNAP_OFF: SACTSNAP_MARKER;
+                       break;
+               }
+       }
+       else {
+               if (G.qual == LR_CTRLKEY) 
+                       autosnap= SACTSNAP_STEP;
+               else if (G.qual == LR_SHIFTKEY)
+                       autosnap= SACTSNAP_FRAME;
+               else if (G.qual == LR_ALTKEY)
+                       autosnap= SACTSNAP_MARKER;
+               else
+                       autosnap= SACTSNAP_OFF;
+       }
+#endif 
+       return autosnap;
+}
+
+/* This function is used for testing if an Animation Editor is displaying
+ * its data in frames or seconds (and the data needing to be edited as such).
+ * Returns 1 if in seconds, 0 if in frames 
+ */
+static short getAnimEdit_DrawTime(TransInfo *t)
+{
+#if 0 // TRANSFORM_FIX_ME      
+       short drawtime;
+       
+       /* currently, some of these are only for the action editor */
+       if (t->spacetype == SPACE_ACTION && G.saction) {
+               drawtime = (G.saction->flag & SACTION_DRAWTIME)? 1 : 0;
+       }
+       else if (t->spacetype == SPACE_NLA && G.snla) {
+               drawtime = (G.snla->flag & SNLA_DRAWTIME)? 1 : 0;
+       }
+       else {
+               drawtime = 0;
+       }
+       
+       return drawtime;
+#endif
+return 0;
+}      
+
+
+/* This function is used by Animation Editor specific transform functions to do 
+ * the Snap Keyframe to Nearest Frame/Marker
+ */
+static void doAnimEdit_SnapFrame(TransInfo *t, TransData *td, Object *ob, short autosnap)
+{
+#if 0 // TRANSFORM_FIX_ME      
+       /* snap key to nearest frame? */
+       if (autosnap == SACTSNAP_FRAME) {
+               short doTime= getAnimEdit_DrawTime(t);
+               double secf= FPS;
+               double val;
+               
+               /* convert frame to nla-action time (if needed) */
+               if (ob) 
+                       val= get_action_frame_inv(ob, *(td->val));
+               else
+                       val= *(td->val);
+               
+               /* do the snapping to nearest frame/second */
+               if (doTime)
+                       val= (float)( floor((val/secf) + 0.5f) * secf );
+               else
+                       val= (float)( floor(val+0.5f) );
+                       
+               /* convert frame out of nla-action time */
+               if (ob)
+                       *(td->val)= get_action_frame(ob, val);
+               else
+                       *(td->val)= val;
+       }
+       /* snap key to nearest marker? */
+       else if (autosnap == SACTSNAP_MARKER) {
+               float val;
+               
+               /* convert frame to nla-action time (if needed) */
+               if (ob) 
+                       val= get_action_frame_inv(ob, *(td->val));
+               else
+                       val= *(td->val);
+               
+               /* snap to nearest marker */
+               val= (float)find_nearest_marker_time(val);
+                       
+               /* convert frame out of nla-action time */
+               if (ob)
+                       *(td->val)= get_action_frame(ob, val);
+               else
+                       *(td->val)= val;
+       }
+#endif
+}
+
+/* ----------------- Translation ----------------------- */
+
+void initTimeTranslate(TransInfo *t) 
+{
+       t->mode = TFM_TIME_TRANSLATE;
+       t->transform = TimeTranslate;
+
+       /* num-input has max of (n-1) */
+       t->idx_max = 0;
+       t->num.flag = 0;
+       t->num.idx_max = t->idx_max;
+       
+       /* initialise snap like for everything else */
+       t->snap[0] = 0.0f; 
+       t->snap[1] = t->snap[2] = 1.0f;
+}
+
+static void headerTimeTranslate(TransInfo *t, char *str) 
+{
+       char tvec[60];
+       
+       /* if numeric input is active, use results from that, otherwise apply snapping to result */
+       if (hasNumInput(&t->num)) {
+               outputNumInput(&(t->num), tvec);
+       }
+       else {
+               Scene *scene = t->scene;
+               short autosnap= getAnimEdit_SnapMode(t);
+               short doTime = getAnimEdit_DrawTime(t);
+               double secf= FPS;
+               float val= t->fac;
+               
+               /* apply snapping + frame->seconds conversions */
+               if (autosnap == SACTSNAP_STEP) {
+                       if (doTime)
+                               val= floor(val/secf + 0.5f);
+                       else
+                               val= floor(val + 0.5f);
+               }
+               else {
+                       if (doTime)
+                               val= val / secf;
+               }
+               
+               sprintf(&tvec[0], "%.4f", val);
+       }
+               
+       sprintf(str, "DeltaX: %s", &tvec[0]);
+}
+
+static void applyTimeTranslate(TransInfo *t, float sval) 
+{
+       TransData *td = t->data;
+       Scene *scene = t->scene;
+       int i;
+       
+       short doTime= getAnimEdit_DrawTime(t);
+       double secf= FPS;
+       
+       short autosnap= getAnimEdit_SnapMode(t);
+       
+       float deltax, val;
+       
+       /* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */
+       for (i = 0 ; i < t->total; i++, td++) {
+               /* it is assumed that td->ob is a pointer to the object,
+                * whose active action is where this keyframe comes from 
+                */
+               Object *ob= td->ob;
+               
+               /* check if any need to apply nla-scaling */
+               if (ob) {
+                       deltax = t->fac;
+                       
+                       if (autosnap == SACTSNAP_STEP) {
+                               if (doTime) 
+                                       deltax= (float)( floor((deltax/secf) + 0.5f) * secf );
+                               else
+                                       deltax= (float)( floor(deltax + 0.5f) );
+                       }
+                       
+                       val = get_action_frame_inv(ob, td->ival);
+                       val += deltax;
+                       *(td->val) = get_action_frame(ob, val);
+               }
+               else {
+                       deltax = val = t->fac;
+                       
+                       if (autosnap == SACTSNAP_STEP) {
+                               if (doTime)
+                                       val= (float)( floor((deltax/secf) + 0.5f) * secf );
+                               else
+                                       val= (float)( floor(val + 0.5f) );
+                       }
+                       
+                       *(td->val) = td->ival + val;
+               }
+               
+               /* apply nearest snapping */
+               doAnimEdit_SnapFrame(t, td, ob, autosnap);
+       }
+}
+
+int TimeTranslate(TransInfo *t, short mval[2]) 
+{
+       View2D *v2d = t->view;
+       float cval[2], sval[2];
+       char str[200];
+
+#if 0 // TRANSFORM_FIX_ME      
+       /* calculate translation amount from mouse movement - in 'time-grid space' */
+       areamouseco_to_ipoco(v2d, mval, &cval[0], &cval[1]);
+       areamouseco_to_ipoco(v2d, t->imval, &sval[0], &sval[1]);
+       
+       /* we only need to calculate effect for time (applyTimeTranslate only needs that) */
+       t->fac= cval[0] - sval[0];
+       
+       /* handle numeric-input stuff */
+       t->vec[0] = t->fac;
+       applyNumInput(&t->num, &t->vec[0]);
+       t->fac = t->vec[0];
+       headerTimeTranslate(t, str);
+       
+       applyTimeTranslate(t, sval[0]);
+
+       recalcData(t);
+
+       ED_area_headerprint(t->sa, str);
+       
+       viewRedrawForce(t);
+#endif
+
+       return 1;
+}
+
+/* ----------------- Time Slide ----------------------- */
+
+void initTimeSlide(TransInfo *t) 
+{
+       /* this tool is only really available in the Action Editor... */
+       if (t->spacetype == SPACE_ACTION) {
+               /* set flag for drawing stuff*/
+               // TRANSFORM_FIX_ME
+               //G.saction->flag |= SACTION_MOVING;
+       }
+       
+       t->mode = TFM_TIME_SLIDE;
+       t->transform = TimeSlide;
+       t->flag |= T_FREE_CUSTOMDATA;
+
+       /* num-input has max of (n-1) */
+       t->idx_max = 0;
+       t->num.flag = 0;
+       t->num.idx_max = t->idx_max;
+       
+       /* initialise snap like for everything else */
+       t->snap[0] = 0.0f; 
+       t->snap[1] = t->snap[2] = 1.0f;
+}
+
+static void headerTimeSlide(TransInfo *t, float sval, char *str) 
+{
+       char tvec[60];
+       
+       if (hasNumInput(&t->num)) {
+               outputNumInput(&(t->num), tvec);
+       }
+       else {
+               float minx= *((float *)(t->customData));
+               float maxx= *((float *)(t->customData) + 1);
+               float cval= t->fac;
+               float val;
+                       
+               val= 2.0*(cval-sval) / (maxx-minx);
+               CLAMP(val, -1.0f, 1.0f);
+               
+               sprintf(&tvec[0], "%.4f", val);
+       }
+               
+       sprintf(str, "TimeSlide: %s", &tvec[0]);
+}
+
+static void applyTimeSlide(TransInfo *t, float sval) 
+{
+       TransData *td = t->data;
+       int i;
+       
+       float minx= *((float *)(t->customData));
+       float maxx= *((float *)(t->customData) + 1);
+       
+       
+       /* set value for drawing black line */
+       if (t->spacetype == SPACE_ACTION) {
+               float cvalf = t->fac;
+
+#if 0 // TRANSFORM_FIX_ME              
+               if (NLA_ACTION_SCALED)
+                       cvalf= get_action_frame(OBACT, cvalf);
+                       
+               G.saction->timeslide= cvalf;
+#endif
+       }
+       
+       /* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */
+       for (i = 0 ; i < t->total; i++, td++) {
+               /* it is assumed that td->ob is a pointer to the object,
+                * whose active action is where this keyframe comes from 
+                */
+               Object *ob= td->ob;
+               float cval = t->fac;
+               
+               /* apply scaling to necessary values */
+               if (ob)
+                       cval= get_action_frame(ob, cval);
+               
+               /* only apply to data if in range */
+               if ((sval > minx) && (sval < maxx)) {
+                       float cvalc= CLAMPIS(cval, minx, maxx);
+                       float timefac;
+                       
+                       /* left half? */
+                       if (td->ival < sval) {
+                               timefac= (sval - td->ival) / (sval - minx);
+                               *(td->val)= cvalc - timefac * (cvalc - minx);
+                       }
+                       else {
+                               timefac= (td->ival - sval) / (maxx - sval);
+                               *(td->val)= cvalc + timefac * (maxx - cvalc);
+                       }
+               }
+       }
+}
+
+int TimeSlide(TransInfo *t, short mval[2]) 
+{
+       View2D *v2d = t->view;
+       float cval[2], sval[2];
+       float minx= *((float *)(t->customData));
+       float maxx= *((float *)(t->customData) + 1);
+       char str[200];
+       
+       /* calculate mouse co-ordinates */
+#if 0 // TRANSFORM_FIX_ME      
+       areamouseco_to_ipoco(v2d, mval, &cval[0], &cval[1]);
+       areamouseco_to_ipoco(v2d, t->imval, &sval[0], &sval[1]);
+#endif
+       
+       /* t->fac stores cval[0], which is the current mouse-pointer location (in frames) */
+       t->fac= cval[0];
+       
+       /* handle numeric-input stuff */
+       t->vec[0] = 2.0*(cval[0]-sval[0]) / (maxx-minx);
+       applyNumInput(&t->num, &t->vec[0]);
+       t->fac = (maxx-minx) * t->vec[0] / 2.0 + sval[0];
+       
+       headerTimeSlide(t, sval[0], str);
+       applyTimeSlide(t, sval[0]);
+
+       recalcData(t);
+
+       ED_area_headerprint(t->sa, str);
+       
+       viewRedrawForce(t);
+
+       return 1;
+}
+
+/* ----------------- Scaling ----------------------- */
+
+void initTimeScale(TransInfo *t) 
+{
+       t->mode = TFM_TIME_SCALE;
+       t->transform = TimeScale;
+
+       t->flag |= T_NULL_ONE;
+       t->num.flag |= NUM_NULL_ONE;
+       
+       /* num-input has max of (n-1) */
+       t->idx_max = 0;
+       t->num.flag = 0;
+       t->num.idx_max = t->idx_max;
+       
+       /* initialise snap like for everything else */
+       t->snap[0] = 0.0f; 
+       t->snap[1] = t->snap[2] = 1.0f;
+}
+
+static void headerTimeScale(TransInfo *t, char *str) {
+       char tvec[60];
+       
+       if (hasNumInput(&t->num))
+               outputNumInput(&(t->num), tvec);
+       else
+               sprintf(&tvec[0], "%.4f", t->fac);
+               
+       sprintf(str, "ScaleX: %s", &tvec[0]);
+}
+
+static void applyTimeScale(TransInfo *t) {
+       Scene *scene = t->scene;
+       TransData *td = t->data;
+       int i;
+       
+       short autosnap= getAnimEdit_SnapMode(t);
+       short doTime= getAnimEdit_DrawTime(t);
+       double secf= FPS;
+       
+       
+       for (i = 0 ; i < t->total; i++, td++) {
+               /* it is assumed that td->ob is a pointer to the object,
+                * whose active action is where this keyframe comes from 
+                */
+               Object *ob= td->ob;
+               float startx= CFRA;
+               float fac= t->fac;
+               
+               if (autosnap == SACTSNAP_STEP) {
+                       if (doTime)
+                               fac= (float)( floor(fac/secf + 0.5f) * secf );
+                       else
+                               fac= (float)( floor(fac + 0.5f) );
+               }
+               
+               /* check if any need to apply nla-scaling */
+               if (ob)
+                       startx= get_action_frame(ob, startx);
+                       
+               /* now, calculate the new value */
+               *(td->val) = td->ival - startx;
+               *(td->val) *= fac;
+               *(td->val) += startx;
+               
+               /* apply nearest snapping */
+               doAnimEdit_SnapFrame(t, td, ob, autosnap);
+       }
+}
+
+int TimeScale(TransInfo *t, short mval[2]) 
+{
+       float cval, sval;
+       float deltax, startx;
+       float width= 0.0f;
+       char str[200];
+       
+       sval= t->imval[0];
+       cval= mval[0];
+       
+#if 0 // TRANSFORM_FIX_ME              
+       switch (t->spacetype) {
+               case SPACE_ACTION:
+                       width= ACTWIDTH;
+                       break;
+               case SPACE_NLA:
+                       width= NLAWIDTH;
+                       break;
+       }
+#endif
+       
+       /* calculate scaling factor */
+       startx= sval-(width/2+(t->ar->winx)/2);
+       deltax= cval-(width/2+(t->ar->winx)/2);
+       t->fac = deltax / startx;
+       
+       /* handle numeric-input stuff */
+       t->vec[0] = t->fac;
+       applyNumInput(&t->num, &t->vec[0]);
+       t->fac = t->vec[0];
+       headerTimeScale(t, str);
+       
+       applyTimeScale(t);
+
+       recalcData(t);
+
+       ED_area_headerprint(t->sa, str);
+       
+       viewRedrawForce(t);
+
+       return 1;
+}
+
+/* ************************************ */
+
+void BIF_TransformSetUndo(char *str)
+{
+       // TRANSFORM_FIX_ME
+       //Trans.undostr= str;
+}
+
+
+void NDofTransform()
+{
+#if 0 // TRANSFORM_FIX_ME
+    float fval[7];
+    float maxval = 50.0f; // also serves as threshold
+    int axis = -1;
+    int mode = 0;
+    int i;
+
+       getndof(fval);
+
+       for(i = 0; i < 6; i++)
+       {
+               float val = fabs(fval[i]);
+               if (val > maxval)
+               {
+                       axis = i;
+                       maxval = val;
+               }
+       }
+       
+       switch(axis)
+       {
+               case -1:
+                       /* No proper axis found */
+                       break;
+               case 0:
+               case 1:
+               case 2:
+                       mode = TFM_TRANSLATION;
+                       break;
+               case 4:
+                       mode = TFM_ROTATION;
+                       break;
+               case 3:
+               case 5:
+                       mode = TFM_TRACKBALL;
+                       break;
+               default:
+                       printf("ndof: what we are doing here ?");
+       }
+       
+       if (mode != 0)
+       {
+               initTransform(mode, CTX_NDOF);
+               Transform();
+       }
+#endif
+}
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
new file mode 100644 (file)
index 0000000..b8e439f
--- /dev/null
@@ -0,0 +1,569 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef TRANSFORM_H
+#define TRANSFORM_H
+
+#include "BIF_transform.h"
+
+/* ************************** Types ***************************** */
+
+struct TransInfo;
+struct TransData;
+struct TransSnap;
+struct NumInput;
+struct Object;
+struct View3D;
+struct ScrArea;
+struct Scene;
+struct bPose;
+struct bConstraint;
+struct BezTriple;
+struct wmOperatorType;
+struct bContext;
+struct wmEvent;
+struct ARegion;
+
+typedef struct NDofInput {
+       int             flag;
+       int             axis;
+       float   fval[7];
+       float   factor[3];
+} NDofInput;
+
+typedef struct NumInput {
+    short  idx;
+    short  idx_max;
+    short  flag;        /* Different flags to indicate different behaviors                                */
+    float  val[3];       /* Direct value of the input                                                      */
+    int  ctrl[3];      /* Control to indicate what to do with the numbers that are typed                 */
+} NumInput ;
+
+/*
+       The ctrl value has different meaning:
+               0                       : No value has been typed
+               
+               otherwise, |value| - 1 is where the cursor is located after the period
+               Positive        : number is positive
+               Negative        : number is negative
+*/
+
+typedef struct TransSnap {
+       short   modePoint;
+       short   modeTarget;
+       int     status;
+       float   snapPoint[3];
+       float   snapTarget[3];
+       float   snapNormal[3];
+       float   snapTangent[3];
+       float   dist; // Distance from snapPoint to snapTarget
+       double  last;
+       void  (*applySnap)(struct TransInfo *, float *);
+       void  (*calcSnap)(struct TransInfo *, float *);
+       void  (*targetSnap)(struct TransInfo *);
+       float  (*distance)(struct TransInfo *, float p1[3], float p2[3]); // Get the transform distance between two points (used by Closest snap)
+} TransSnap;
+
+typedef struct TransCon {
+    char  text[50];      /* Description of the Constraint for header_print                            */
+    float mtx[3][3];     /* Matrix of the Constraint space                                            */
+    float imtx[3][3];    /* Inverse Matrix of the Constraint space                                    */
+    float pmtx[3][3];    /* Projection Constraint Matrix (same as imtx with some axis == 0)           */
+    float center[3];     /* transformation center to define where to draw the view widget             
+                            ALWAYS in global space. Unlike the transformation center                  */
+       short imval[2];      /* initial mouse value for visual calculation                                */
+                            /* the one in TransInfo is not garanty to stay the same (Rotates change it)  */
+    int   mode;          /* Mode flags of the Constraint                                              */
+       void  (*drawExtra)(struct TransInfo *);
+                                                /* For constraints that needs to draw differently from the other
+                                                       uses this instead of the generic draw function                                                    */
+    void  (*applyVec)(struct TransInfo *, struct TransData *, float *, float *, float *);
+                         /* Apply function pointer for linear vectorial transformation                */
+                         /* The last three parameters are pointers to the in/out/printable vectors    */
+    void  (*applySize)(struct TransInfo *, struct TransData *, float [3][3]);
+                         /* Apply function pointer for size transformation */
+    void  (*applyRot)(struct TransInfo *, struct TransData *, float [3], float *);
+                         /* Apply function pointer for rotation transformation */
+} TransCon;
+
+typedef struct TransDataIpokey {
+       int flag;                                       /* which keys */
+       float *locx, *locy, *locz;      /* channel pointers */
+       float *rotx, *roty, *rotz;
+       float *quatx, *quaty, *quatz, *quatw;
+       float *sizex, *sizey, *sizez;
+       float oldloc[9];                        /* storage old values */
+       float oldrot[9];
+       float oldsize[9];
+       float oldquat[12];
+} TransDataIpokey;
+
+typedef struct TransDataExtension {
+       float drot[3];           /* Initial object drot */
+       float dsize[3];          /* Initial object dsize */
+    float *rot;          /* Rotation of the data to transform (Faculative)                                 */
+    float  irot[3];      /* Initial rotation                                                               */
+    float *quat;         /* Rotation quaternion of the data to transform (Faculative)                      */
+    float  iquat[4];    /* Initial rotation quaternion                                                    */
+    float *size;         /* Size of the data to transform (Faculative)                                     */
+    float  isize[3];    /* Initial size                                                                   */
+       float  obmat[4][4];      /* Object matrix */  
+} TransDataExtension;
+
+typedef struct TransData2D {
+       float loc[3];           /* Location of data used to transform (x,y,0) */
+       float *loc2d;           /* Pointer to real 2d location of data */
+} TransData2D;
+
+/* we need to store 2 handles for each transdata incase the other handle wasnt selected */
+typedef struct TransDataCurveHandleFlags {
+       char ih1, ih2;
+       char *h1, *h2;
+} TransDataCurveHandleFlags;
+
+
+typedef struct TransData {
+       float  dist;         /* Distance needed to affect element (for Proportionnal Editing)                  */
+       float  rdist;        /* Distance to the nearest element (for Proportionnal Editing)                    */
+       float  factor;       /* Factor of the transformation (for Proportionnal Editing)                       */
+    float *loc;          /* Location of the data to transform                                              */
+    float  iloc[3];      /* Initial location                                                               */
+       float *val;          /* Value pointer for special transforms */
+       float  ival;         /* Old value*/
+    float  center[3];   /* Individual data center                                                         */
+    float  mtx[3][3];    /* Transformation matrix from data space to global space                          */
+    float  smtx[3][3];   /* Transformation matrix from global space to data space                          */
+       float  axismtx[3][3];/* Axis orientation matrix of the data                                            */
+       struct Object *ob;
+       struct bConstraint *con;        /* for objects/bones, the first constraint in its constraint stack */
+       TransDataExtension *ext;        /* for objects, poses. 1 single malloc per TransInfo! */
+       TransDataIpokey *tdi;           /* for objects, ipo keys. per transdata a malloc */
+       TransDataCurveHandleFlags *hdata; /* for curves, stores handle flags for modification/cancel */
+       void  *extra;            /* extra data (mirrored element pointer, in editmode mesh to EditVert) (editbone for roll fixing) (...) */
+    short  flag;         /* Various flags */
+       short  protectflag;      /* If set, copy of Object or PoseChannel protection */
+/*#ifdef WITH_VERSE*/
+       void *verse;                    /* pointer at verse data struct (VerseVert, etc.) */
+/*#endif*/
+} TransData;
+
+typedef struct TransInfo {
+    int         mode;           /* current mode                         */
+    int                flag;           /* generic flags for special behaviors  */
+       short           state;                  /* current state (running, canceled,...)*/
+    int         context;        /* current context                      */
+    float       val;            /* init value for some transformations (and rotation angle)  */
+    float       fac;            /* factor for distance based transform  */
+    int       (*transform)(struct TransInfo *, short *);
+                                /* transform function pointer           */
+       int       (*handleEvent)(struct TransInfo *, struct wmEvent *event);
+                                                               /* event handler function pointer  RETURN 1 if redraw is needed */
+    int         total;          /* total number of transformed data     */
+    TransData  *data;           /* transformed data (array)             */
+       TransDataExtension *ext;        /* transformed data extension (array)   */
+       TransData2D *data2d;            /* transformed data for 2d (array)      */
+    TransCon    con;            /* transformed constraint               */
+    TransSnap  tsnap;
+    NumInput    num;            /* numerical input                      */
+    NDofInput   ndof;           /* ndof input                           */
+    char        redraw;         /* redraw flag                          */
+       float           propsize;               /* proportional circle radius           */
+       char            proptext[20];   /* proportional falloff text                    */
+    float       center[3];      /* center of transformation             */
+    int         center2d[2];    /* center in screen coordinates         */
+    short       imval[2];       /* initial mouse position               */
+       short           shiftmval[2];   /* mouse position when shift was pressed */
+       short       idx_max;            /* maximum index on the input vector    */
+       float           snap[3];                /* Snapping Gears                                               */
+       
+       float           viewmat[4][4];  /* copy from G.vd, prevents feedback,   */
+       float           viewinv[4][4];  /* and to make sure we don't have to    */
+       float           persmat[4][4];  /* access G.vd from other space types   */
+       float           persinv[4][4];
+       short           persp;
+       short           around;
+       char            spacetype;              /* spacetype where transforming is      */
+       
+       float           vec[3];                 /* translation, to show for widget      */
+       float           mat[3][3];              /* rot/rescale, to show for widget      */
+       
+       char            *undostr;               /* if set, uses this string for undo            */
+       float           spacemtx[3][3]; /* orientation matrix of the current space      */
+       char            spacename[32];  /* name of the current space                            */
+       
+       struct Object *poseobj;         /* if t->flag & T_POSE, this denotes pose object */
+       
+       void       *customData;         /* Per Transform custom data */
+
+       /*************** NEW STUFF *********************/
+
+       float           values[4];
+       void            *view;
+       struct ScrArea  *sa;
+       struct ARegion  *ar;
+       struct Scene    *scene;
+       struct wmEvent  *event; /* last event, reset at the start of each transformApply and nulled at the transformEnd */
+    short       mval[2];       /* current mouse position               */
+} TransInfo;
+
+
+/* ******************** Macros & Prototypes *********************** */
+
+/* NUMINPUT FLAGS */
+#define NUM_NULL_ONE           2
+#define NUM_NO_NEGATIVE                4
+#define        NUM_NO_ZERO                     8
+#define NUM_NO_FRACTION                16
+#define        NUM_AFFECT_ALL          32
+
+/* NDOFINPUT FLAGS */
+#define NDOF_INIT                      1
+
+/* transinfo->state */
+#define TRANS_RUNNING  0
+#define TRANS_CONFIRM  1
+#define TRANS_CANCEL   2
+
+/* transinfo->flag */
+#define T_OBJECT               (1 << 0)
+#define T_EDIT                 (1 << 1)
+#define T_POSE                 (1 << 2)
+#define T_TEXTURE              (1 << 3)
+#define T_CAMERA               (1 << 4)
+               // when shift pressed, higher resolution transform. cannot rely on G.qual, need event!
+#define T_SHIFT_MOD            (1 << 5)
+               // trans on points, having no rotation/scale 
+#define T_POINTS               (1 << 6)
+               // for manipulator exceptions, like scaling using center point, drawing help lines
+#define T_USES_MANIPULATOR     (1 << 7)
+
+       /* restrictions flags */
+#define T_ALL_RESTRICTIONS     ((1 << 8)|(1 << 9)|(1 << 10))
+#define T_NO_CONSTRAINT                (1 << 8)
+#define T_NULL_ONE                     (1 << 9)
+#define T_NO_ZERO                      (1 << 10)
+
+#define T_PROP_EDIT                    (1 << 11)
+#define T_PROP_CONNECTED       (1 << 12)
+
+       /* if MMB is pressed or not */
+#define        T_MMB_PRESSED           (1 << 13)
+
+#define T_V3D_ALIGN                    (1 << 14)
+       /* for 2d views like uv or ipo */
+#define T_2D_EDIT                      (1 << 15) 
+#define T_CLIP_UV                      (1 << 16)
+
+#define T_FREE_CUSTOMDATA      (1 << 17)
+       /* auto-ik is on */
+#define T_AUTOIK                       (1 << 18)
+
+/* ******************************************************************************** */
+
+/* transinfo->con->mode */
+#define CON_APPLY              1
+#define CON_AXIS0              2
+#define CON_AXIS1              4
+#define CON_AXIS2              8
+#define CON_SELECT             16
+#define CON_NOFLIP             32      /* does not reorient vector to face viewport when on */
+#define CON_LOCAL              64
+#define CON_USER               128
+
+/* transdata->flag */
+#define TD_SELECTED                    1
+#define TD_ACTIVE                      (1 << 1)
+#define        TD_NOACTION                     (1 << 2)
+#define        TD_USEQUAT                      (1 << 3)
+#define TD_NOTCONNECTED                (1 << 4)
+#define TD_SINGLESIZE          (1 << 5)        /* used for scaling of MetaElem->rad */
+#ifdef WITH_VERSE
+       #define TD_VERSE_OBJECT         (1 << 6)
+       #define TD_VERSE_VERT           (1 << 7)
+#endif
+#define TD_TIMEONLY                    (1 << 8)
+#define TD_NOCENTER                    (1 << 9)
+#define TD_NO_EXT                      (1 << 10)       /* ext abused for particle key timing */
+#define TD_SKIP                                (1 << 11)       /* don't transform this data */
+#define TD_BEZTRIPLE           (1 << 12)       /* if this is a bez triple, we need to restore the handles, if this is set transdata->misc.hdata needs freeing */
+#define TD_NO_LOC                      (1 << 13)       /* when this is set, don't apply translation changes to this element */
+
+/* transsnap->status */
+#define SNAP_ON                        1
+#define TARGET_INIT            2
+#define POINT_INIT             4
+
+/* transsnap->modePoint */
+#define SNAP_GRID                      0
+#define SNAP_GEO                       1
+
+/* transsnap->modeTarget */
+#define SNAP_CLOSEST           0
+#define SNAP_CENTER                    1
+#define SNAP_MEDIAN                    2
+#define SNAP_ACTIVE                    3
+
+
+void TFM_OT_transform(struct wmOperatorType *ot);
+
+void initTransform(struct bContext *C, struct TransInfo *t, int mode, int context, struct wmEvent *event);
+void transformEvent(TransInfo *t, struct wmEvent *event);
+void transformApply(TransInfo *t);
+int  transformEnd(TransInfo *t);
+
+void setTransformViewMatrices(TransInfo *t);
+void convertViewVec(TransInfo *t, float *vec, short dx, short dy);
+void projectIntView(TransInfo *t, float *vec, int *adr);
+void projectFloatView(TransInfo *t, float *vec, float *adr);
+
+void convertVecToDisplayNum(float *vec, float *num);
+void convertDisplayNumToVec(float *num, float *vec);
+
+void initWarp(TransInfo *t);
+int handleEventWarp(TransInfo *t, struct wmEvent *event);
+int Warp(TransInfo *t, short mval[2]);
+
+void initShear(TransInfo *t);
+int handleEventShear(TransInfo *t, struct wmEvent *event);
+int Shear(TransInfo *t, short mval[2]);
+
+void initResize(TransInfo *t);
+int Resize(TransInfo *t, short mval[2]);
+
+void initTranslation(TransInfo *t);
+int Translation(TransInfo *t, short mval[2]);
+
+void initToSphere(TransInfo *t);
+int ToSphere(TransInfo *t, short mval[2]);
+
+void initRotation(TransInfo *t);
+int Rotation(TransInfo *t, short mval[2]);
+
+void initShrinkFatten(TransInfo *t);
+int ShrinkFatten(TransInfo *t, short mval[2]);
+
+void initTilt(TransInfo *t);
+int Tilt(TransInfo *t, short mval[2]);
+
+void initCurveShrinkFatten(TransInfo *t);
+int CurveShrinkFatten(TransInfo *t, short mval[2]);
+
+void initTrackball(TransInfo *t);
+int Trackball(TransInfo *t, short mval[2]);
+
+void initPushPull(TransInfo *t);
+int PushPull(TransInfo *t, short mval[2]);
+
+void initBevel(TransInfo *t);
+int handleEventBevel(TransInfo *t, struct wmEvent *event);
+int Bevel(TransInfo *t, short mval[2]);
+
+void initBevelWeight(TransInfo *t);
+int BevelWeight(TransInfo *t, short mval[2]);
+
+void initCrease(TransInfo *t);
+int Crease(TransInfo *t, short mval[2]);
+
+void initBoneSize(TransInfo *t);
+int BoneSize(TransInfo *t, short mval[2]);
+
+void initBoneEnvelope(TransInfo *t);
+int BoneEnvelope(TransInfo *t, short mval[2]);
+
+void initBoneRoll(TransInfo *t);
+int BoneRoll(TransInfo *t, short mval[2]);
+
+void initTimeTranslate(TransInfo *t);
+int TimeTranslate(TransInfo *t, short mval[2]);
+
+void initTimeSlide(TransInfo *t);
+int TimeSlide(TransInfo *t, short mval[2]);
+
+void initTimeScale(TransInfo *t);
+int TimeScale(TransInfo *t, short mval[2]);
+
+void initBakeTime(TransInfo *t);
+int BakeTime(TransInfo *t, short mval[2]);
+
+void initMirror(TransInfo *t);
+int Mirror(TransInfo *t, short mval[2]);
+
+void initAlign(TransInfo *t);
+int Align(TransInfo *t, short mval[2]);
+
+/*********************** transform_conversions.c ********** */
+struct ListBase;
+void flushTransGPactionData(TransInfo *t);
+void flushTransIpoData(TransInfo *t);
+void flushTransUVs(TransInfo *t);
+void flushTransParticles(TransInfo *t);
+int clipUVTransform(TransInfo *t, float *vec, int resize);
+
+/*********************** exported from transform_manipulator.c ********** */
+void draw_manipulator_ext(struct ScrArea *sa, int type, char axis, int col, float vec[3], float mat[][3]);
+int calc_manipulator_stats(struct ScrArea *sa);
+float get_drawsize(struct View3D *v3d, struct ScrArea *sa, float *co);
+
+/*********************** TransData Creation and General Handling *********** */
+void createTransData(struct bContext *C, TransInfo *t);
+void sort_trans_data_dist(TransInfo *t);
+void add_tdi_poin(float *poin, float *old, float delta);
+void special_aftertrans_update(TransInfo *t);
+
+void transform_autoik_update(TransInfo *t, short mode);
+
+/* auto-keying stuff used by special_aftertrans_update */
+short autokeyframe_cfra_can_key(struct Object *ob);
+void autokeyframe_ob_cb_func(struct Object *ob, int tmode);
+void autokeyframe_pose_cb_func(struct Object *ob, int tmode, short targetless_ik);
+
+/*********************** Constraints *****************************/
+
+void getConstraintMatrix(TransInfo *t);
+void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]);
+void setLocalConstraint(TransInfo *t, int mode, const char text[]);
+void setUserConstraint(TransInfo *t, int mode, const char text[]);
+
+void constraintNumInput(TransInfo *t, float vec[3]);
+
+void getConstraintMatrix(TransInfo *t);
+int isLockConstraint(TransInfo *t);
+int getConstraintSpaceDimension(TransInfo *t);
+char constraintModeToChar(TransInfo *t);
+
+void startConstraint(TransInfo *t);
+void stopConstraint(TransInfo *t);
+
+void initSelectConstraint(TransInfo *t, float mtx[3][3]);
+void selectConstraint(TransInfo *t);
+void postSelectConstraint(TransInfo *t);
+
+void setNearestAxis(TransInfo *t);
+
+/*********************** Snapping ********************************/
+
+typedef enum {
+       NO_GEARS        = 0,
+       BIG_GEARS       = 1,
+       SMALL_GEARS     = 2
+} GearsType;
+
+void snapGrid(TransInfo *t, float *val);
+void snapGridAction(TransInfo *t, float *val, GearsType action);
+
+void initSnapping(struct TransInfo *t);
+void applySnapping(TransInfo *t, float *vec);
+void resetSnapping(TransInfo *t);
+int  handleSnapping(TransInfo *t, struct wmEvent *event);
+void drawSnapping(TransInfo *t);
+int usingSnappingNormal(TransInfo *t);
+int validSnappingNormal(TransInfo *t);
+
+/*********************** Generics ********************************/
+
+void initTransInfo(struct bContext *C, TransInfo *t, struct wmEvent *event);
+void postTrans (TransInfo *t);
+void resetTransRestrictions(TransInfo *t);
+
+void drawLine(float *center, float *dir, char axis, short options);
+
+TransDataCurveHandleFlags *initTransDataCurveHandes(TransData *td, struct BezTriple *bezt);
+
+/* DRAWLINE options flags */
+#define DRAWLIGHT      1
+#define DRAWDASHED     2
+#define DRAWBOLD       4
+
+void applyTransObjects(TransInfo *t);
+void restoreTransObjects(TransInfo *t);
+void recalcData(TransInfo *t);
+
+void calculateCenter(TransInfo *t);
+void calculateCenter2D(TransInfo *t);
+void calculateCenterBound(TransInfo *t);
+void calculateCenterMedian(TransInfo *t);
+void calculateCenterCursor(TransInfo *t);
+
+void calculateCenterCursor2D(TransInfo *t);
+void calculatePropRatio(TransInfo *t);
+
+void getViewVector(TransInfo *t, float coord[3], float vec[3]);
+
+TransInfo * BIF_GetTransInfo(void);
+
+/*********************** NumInput ********************************/
+
+void initNumInput(NumInput *n);
+void outputNumInput(NumInput *n, char *str);
+short hasNumInput(NumInput *n);
+void applyNumInput(NumInput *n, float *vec);
+char handleNumInput(NumInput *n, struct wmEvent *event);
+
+/*********************** NDofInput ********************************/
+
+void initNDofInput(NDofInput *n);
+int hasNDofInput(NDofInput *n);
+void applyNDofInput(NDofInput *n, float *vec);
+int handleNDofInput(NDofInput *n, struct wmEvent *event);
+
+/* handleNDofInput return values */
+#define NDOF_REFRESH   1
+#define NDOF_NOMOVE            2
+#define NDOF_CONFIRM   3
+#define NDOF_CANCEL            4
+
+
+/*********************** TransSpace ******************************/
+
+int manageObjectSpace(int confirm, int set);
+int manageMeshSpace(int confirm, int set);
+int manageBoneSpace(int confirm, int set);
+
+/* Those two fill in mat and return non-zero on success */
+int createSpaceNormal(float mat[3][3], float normal[3]);
+int createSpaceNormalTangent(float mat[3][3], float normal[3], float tangent[3]);
+
+int addMatrixSpace(float mat[3][3], char name[]);
+int addObjectSpace(struct Object *ob);
+void applyTransformOrientation(void);
+
+
+#define ORIENTATION_NONE       0
+#define ORIENTATION_NORMAL     1
+#define ORIENTATION_VERT       2
+#define ORIENTATION_EDGE       3
+#define ORIENTATION_FACE       4
+
+int getTransformOrientation(struct bContext *C, float normal[3], float plane[3], int activeOnly);
+int createSpaceNormal(float mat[3][3], float normal[3]);
+int createSpaceNormalTangent(float mat[3][3], float normal[3], float tangent[3]);
+
+#endif
+
+
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
new file mode 100644 (file)
index 0000000..94c4ffa
--- /dev/null
@@ -0,0 +1,1070 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_image_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+
+//#include "BIF_screen.h"
+//#include "BIF_resources.h"
+//#include "BIF_mywindow.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
+
+#include "ED_view3d.h"
+
+#include "BLI_arithb.h"
+
+//#include "BDR_drawobject.h"  /* drawcircball */
+//
+//#include "blendef.h"
+//
+//#include "mydevice.h"
+
+#include "WM_types.h"
+
+#include "transform.h"
+
+static void drawObjectConstraint(TransInfo *t);
+
+/* ************************** CONSTRAINTS ************************* */
+void constraintNumInput(TransInfo *t, float vec[3])
+{
+       int mode = t->con.mode;
+       if (mode & CON_APPLY) {
+               float nval = (t->flag & T_NULL_ONE)?1.0f:0.0f;
+
+               if (getConstraintSpaceDimension(t) == 2) {
+                       int axis = mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
+                       if (axis == (CON_AXIS0|CON_AXIS1)) {
+                               vec[2] = nval;
+                       }
+                       else if (axis == (CON_AXIS1|CON_AXIS2)) {
+                               vec[2] = vec[1];
+                               vec[1] = vec[0];
+                               vec[0] = nval;
+                       }
+                       else if (axis == (CON_AXIS0|CON_AXIS2)) {
+                               vec[2] = vec[1];
+                               vec[1] = nval;
+                       }
+               }
+               else if (getConstraintSpaceDimension(t) == 1) {
+                       if (mode & CON_AXIS0) {
+                               vec[1] = nval;
+                               vec[2] = nval;
+                       }
+                       else if (mode & CON_AXIS1) {
+                               vec[1] = vec[0];
+                               vec[0] = nval;
+                               vec[2] = nval;
+                       }
+                       else if (mode & CON_AXIS2) {
+                               vec[2] = vec[0];
+                               vec[0] = nval;
+                               vec[1] = nval;
+                       }
+               }
+       }
+}
+
+static void postConstraintChecks(TransInfo *t, float vec[3], float pvec[3]) {
+       int i = 0;
+
+       Mat3MulVecfl(t->con.imtx, vec);
+
+       snapGrid(t, vec);
+
+       if (t->num.flag & T_NULL_ONE) {
+               if (!(t->con.mode & CON_AXIS0))
+                       vec[0] = 1.0f;
+
+               if (!(t->con.mode & CON_AXIS1))
+                       vec[1] = 1.0f;
+
+               if (!(t->con.mode & CON_AXIS2))
+                       vec[2] = 1.0f;
+       }
+
+       if (hasNumInput(&t->num)) {
+               applyNumInput(&t->num, vec);
+               constraintNumInput(t, vec);
+       }
+       
+       if (t->con.mode & CON_AXIS0) {
+               pvec[i++] = vec[0];
+       }
+       if (t->con.mode & CON_AXIS1) {
+               pvec[i++] = vec[1];
+       }
+       if (t->con.mode & CON_AXIS2) {
+               pvec[i++] = vec[2];
+       }
+
+       Mat3MulVecfl(t->con.mtx, vec);
+}
+
+static void axisProjection(TransInfo *t, float axis[3], float in[3], float out[3]) {
+       float norm[3], vec[3], factor;
+       
+       if(in[0]==0.0f && in[1]==0.0f && in[2]==0.0f)
+               return;
+       
+       /* For when view is parallel to constraint... will cause NaNs otherwise
+          So we take vertical motion in 3D space and apply it to the
+          constraint axis. Nice for camera grab + MMB */
+       if(1.0f - fabs(Inpf(axis, t->viewinv[2])) < 0.000001f) {
+               Projf(vec, in, t->viewinv[1]);
+               factor = Inpf(t->viewinv[1], vec) * 2.0f;
+               /* since camera distance is quite relative, use quadratic relationship. holding shift can compensate */
+               if(factor<0.0f) factor*= -factor;
+               else factor*= factor;
+               
+               VECCOPY(out, axis);
+               Normalize(out);
+               VecMulf(out, -factor);  /* -factor makes move down going backwards */
+       }
+       else {
+               float cb[3], ab[3];
+               
+               VECCOPY(out, axis);
+               
+               /* Get view vector on axis to define a plane */
+               VecAddf(vec, t->con.center, in);
+               getViewVector(t, vec, norm);
+               
+               Crossf(vec, norm, axis);
+               
+               /* Project input vector on the plane passing on axis */
+               Projf(vec, in, vec);
+               VecSubf(vec, in, vec);
+               
+               /* intersect the two lines: axis and norm */
+               Crossf(cb, vec, norm);
+               Crossf(ab, axis, norm);
+               
+               VecMulf(out, Inpf(cb, ab) / Inpf(ab, ab));
+       }
+}
+
+static void planeProjection(TransInfo *t, float in[3], float out[3]) {
+       float vec[3], factor, norm[3];
+
+       VecAddf(vec, in, t->con.center);
+       getViewVector(t, vec, norm);
+
+       VecSubf(vec, out, in);
+
+       factor = Inpf(vec, norm);
+       if (fabs(factor) <= 0.001) {
+               return; /* prevent divide by zero */
+       }
+       factor = Inpf(vec, vec) / factor;
+
+       VECCOPY(vec, norm);
+       VecMulf(vec, factor);
+
+       VecAddf(out, in, vec);
+}
+
+/*
+ * Generic callback for constant spacial constraints applied to linear motion
+ * 
+ * The IN vector in projected into the constrained space and then further
+ * projected along the view vector.
+ * (in perspective mode, the view vector is relative to the position on screen)
+ *
+ */
+
+static void applyAxisConstraintVec(TransInfo *t, TransData *td, float in[3], float out[3], float pvec[3])
+{
+       VECCOPY(out, in);
+       if (!td && t->con.mode & CON_APPLY) {
+               Mat3MulVecfl(t->con.pmtx, out);
+               
+               // With snap, a projection is alright, no need to correct for view alignment
+               if ((t->tsnap.status & SNAP_ON) == 0) {
+                       if (getConstraintSpaceDimension(t) == 2) {
+                               if (out[0] != 0.0f || out[1] != 0.0f || out[2] != 0.0f) {
+                                       planeProjection(t, in, out);
+                               }
+                       }
+                       else if (getConstraintSpaceDimension(t) == 1) {
+                               float c[3];
+       
+                               if (t->con.mode & CON_AXIS0) {
+                                       VECCOPY(c, t->con.mtx[0]);
+                               }
+                               else if (t->con.mode & CON_AXIS1) {
+                                       VECCOPY(c, t->con.mtx[1]);
+                               }
+                               else if (t->con.mode & CON_AXIS2) {
+                                       VECCOPY(c, t->con.mtx[2]);
+                               }
+                               axisProjection(t, c, in, out);
+                       }
+               }
+               postConstraintChecks(t, out, pvec);
+       }
+}
+
+/*
+ * Generic callback for object based spacial constraints applied to linear motion
+ * 
+ * At first, the following is applied to the first data in the array
+ * The IN vector in projected into the constrained space and then further
+ * projected along the view vector.
+ * (in perspective mode, the view vector is relative to the position on screen)
+ *
+ * Further down, that vector is mapped to each data's space.
+ */
+
+static void applyObjectConstraintVec(TransInfo *t, TransData *td, float in[3], float out[3], float pvec[3])
+{
+       VECCOPY(out, in);
+       if (t->con.mode & CON_APPLY) {
+               if (!td) {
+                       Mat3MulVecfl(t->con.pmtx, out);
+                       if (getConstraintSpaceDimension(t) == 2) {
+                               if (out[0] != 0.0f || out[1] != 0.0f || out[2] != 0.0f) {
+                                       planeProjection(t, in, out);
+                               }
+                       }
+                       else if (getConstraintSpaceDimension(t) == 1) {
+                               float c[3];
+
+                               if (t->con.mode & CON_AXIS0) {
+                                       VECCOPY(c, t->con.mtx[0]);
+                               }
+                               else if (t->con.mode & CON_AXIS1) {
+                                       VECCOPY(c, t->con.mtx[1]);
+                               }
+                               else if (t->con.mode & CON_AXIS2) {
+                                       VECCOPY(c, t->con.mtx[2]);
+                               }
+                               axisProjection(t, c, in, out);
+                       }
+                       postConstraintChecks(t, out, pvec);
+                       VECCOPY(out, pvec);
+               }
+               else {
+                       int i=0;
+
+                       out[0] = out[1] = out[2] = 0.0f;
+                       if (t->con.mode & CON_AXIS0) {
+                               out[0] = in[i++];
+                       }
+                       if (t->con.mode & CON_AXIS1) {
+                               out[1] = in[i++];
+                       }
+                       if (t->con.mode & CON_AXIS2) {
+                               out[2] = in[i++];
+                       }
+                       Mat3MulVecfl(td->axismtx, out);
+               }
+       }
+}
+
+/*
+ * Generic callback for constant spacial constraints applied to resize motion
+ * 
+ *
+ */
+
+static void applyAxisConstraintSize(TransInfo *t, TransData *td, float smat[3][3])
+{
+       if (!td && t->con.mode & CON_APPLY) {
+               float tmat[3][3];
+
+               if (!(t->con.mode & CON_AXIS0)) {
+                       smat[0][0] = 1.0f;
+               }
+               if (!(t->con.mode & CON_AXIS1)) {
+                       smat[1][1] = 1.0f;
+               }
+               if (!(t->con.mode & CON_AXIS2)) {
+                       smat[2][2] = 1.0f;
+               }
+
+               Mat3MulMat3(tmat, smat, t->con.imtx);
+               Mat3MulMat3(smat, t->con.mtx, tmat);
+       }
+}
+
+/*
+ * Callback for object based spacial constraints applied to resize motion
+ * 
+ *
+ */
+
+static void applyObjectConstraintSize(TransInfo *t, TransData *td, float smat[3][3])
+{
+       if (td && t->con.mode & CON_APPLY) {
+               float tmat[3][3];
+               float imat[3][3];
+
+               Mat3Inv(imat, td->axismtx);
+
+               if (!(t->con.mode & CON_AXIS0)) {
+                       smat[0][0] = 1.0f;
+               }
+               if (!(t->con.mode & CON_AXIS1)) {
+                       smat[1][1] = 1.0f;
+               }
+               if (!(t->con.mode & CON_AXIS2)) {
+                       smat[2][2] = 1.0f;
+               }
+
+               Mat3MulMat3(tmat, smat, imat);
+               Mat3MulMat3(smat, td->axismtx, tmat);
+       }
+}
+
+/*
+ * Generic callback for constant spacial constraints applied to rotations
+ * 
+ * The rotation axis is copied into VEC.
+ *
+ * In the case of single axis constraints, the rotation axis is directly the one constrained to.
+ * For planar constraints (2 axis), the rotation axis is the normal of the plane.
+ *
+ * The following only applies when CON_NOFLIP is not set.
+ * The vector is then modified to always point away from the screen (in global space)
+ * This insures that the rotation is always logically following the mouse.
+ * (ie: not doing counterclockwise rotations when the mouse moves clockwise).
+ */
+
+static void applyAxisConstraintRot(TransInfo *t, TransData *td, float vec[3], float *angle)
+{
+       if (!td && t->con.mode & CON_APPLY) {
+               int mode = t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
+
+               switch(mode) {
+               case CON_AXIS0:
+               case (CON_AXIS1|CON_AXIS2):
+                       VECCOPY(vec, t->con.mtx[0]);
+                       break;
+               case CON_AXIS1:
+               case (CON_AXIS0|CON_AXIS2):
+                       VECCOPY(vec, t->con.mtx[1]);
+                       break;
+               case CON_AXIS2:
+               case (CON_AXIS0|CON_AXIS1):
+                       VECCOPY(vec, t->con.mtx[2]);
+                       break;
+               }
+               /* don't flip axis if asked to or if num input */
+               if (angle && (mode & CON_NOFLIP) == 0 && hasNumInput(&t->num) == 0) {
+                       if (Inpf(vec, t->viewinv[2]) > 0.0f) {
+                               *angle = -(*angle);
+                       }
+               }
+       }
+}
+
+/*
+ * Callback for object based spacial constraints applied to rotations
+ * 
+ * The rotation axis is copied into VEC.
+ *
+ * In the case of single axis constraints, the rotation axis is directly the one constrained to.
+ * For planar constraints (2 axis), the rotation axis is the normal of the plane.
+ *
+ * The following only applies when CON_NOFLIP is not set.
+ * The vector is then modified to always point away from the screen (in global space)
+ * This insures that the rotation is always logically following the mouse.
+ * (ie: not doing counterclockwise rotations when the mouse moves clockwise).
+ */
+
+static void applyObjectConstraintRot(TransInfo *t, TransData *td, float vec[3], float *angle)
+{
+       if (t->con.mode & CON_APPLY) {
+               int mode = t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
+               
+               /* on setup call, use first object */
+               if (td == NULL) {
+                       td= t->data;
+               }
+
+               switch(mode) {
+               case CON_AXIS0:
+               case (CON_AXIS1|CON_AXIS2):
+                       VECCOPY(vec, td->axismtx[0]);
+                       break;
+               case CON_AXIS1:
+               case (CON_AXIS0|CON_AXIS2):
+                       VECCOPY(vec, td->axismtx[1]);
+                       break;
+               case CON_AXIS2:
+               case (CON_AXIS0|CON_AXIS1):
+                       VECCOPY(vec, td->axismtx[2]);
+                       break;
+               }
+               if (angle && (mode & CON_NOFLIP) == 0 && hasNumInput(&t->num) == 0) {
+                       if (Inpf(vec, t->viewinv[2]) > 0.0f) {
+                               *angle = -(*angle);
+                       }
+               }
+       }
+}
+
+/*--------------------- INTERNAL SETUP CALLS ------------------*/
+
+void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]) {
+       strncpy(t->con.text + 1, text, 48);
+       Mat3CpyMat3(t->con.mtx, space);
+       t->con.mode = mode;
+       getConstraintMatrix(t);
+
+       startConstraint(t);
+
+       t->con.drawExtra = NULL;
+       t->con.applyVec = applyAxisConstraintVec;
+       t->con.applySize = applyAxisConstraintSize;
+       t->con.applyRot = applyAxisConstraintRot;
+       t->redraw = 1;
+}
+
+void setLocalConstraint(TransInfo *t, int mode, const char text[]) {
+       if (t->flag & T_EDIT) {
+               float obmat[3][3];
+               Mat3CpyMat4(obmat, G.obedit->obmat);
+               setConstraint(t, obmat, mode|CON_LOCAL, text);
+       }
+       else {
+               if (t->total == 1) {
+                       setConstraint(t, t->data->axismtx, mode|CON_LOCAL, text);
+               }
+               else {
+                       strncpy(t->con.text + 1, text, 48);
+                       Mat3CpyMat3(t->con.mtx, t->data->axismtx);
+                       t->con.mode = mode|CON_LOCAL;
+                       getConstraintMatrix(t);
+
+                       startConstraint(t);
+
+                       t->con.drawExtra = drawObjectConstraint;
+                       t->con.applyVec = applyObjectConstraintVec;
+                       t->con.applySize = applyObjectConstraintSize;
+                       t->con.applyRot = applyObjectConstraintRot;
+                       t->redraw = 1;
+               }
+       }
+}
+
+/*
+       Set the constraint according to the user defined orientation
+
+       ftext is a format string passed to sprintf. It will add the name of
+       the orientation where %s is (logically).
+*/
+void setUserConstraint(TransInfo *t, int mode, const char ftext[]) {
+       char text[40];
+       short twmode= (t->spacetype==SPACE_VIEW3D)? ((View3D*)t->view)->twmode: V3D_MANIP_GLOBAL;
+
+       switch(twmode) {
+       case V3D_MANIP_GLOBAL:
+       /*
+               sprintf(text, ftext, "global");
+               Mat3One(mtx);
+               setConstraint(t, mtx, mode, text);
+               break;
+       */
+       case V3D_MANIP_LOCAL:
+               sprintf(text, ftext, "local");
+               setLocalConstraint(t, mode, text);
+               break;
+       case V3D_MANIP_NORMAL:
+               sprintf(text, ftext, "normal");
+               setConstraint(t, t->spacemtx, mode, text);
+               break;
+       case V3D_MANIP_VIEW:
+               sprintf(text, ftext, "view");
+               setConstraint(t, t->spacemtx, mode, text);
+               break;
+       default: /* V3D_MANIP_CUSTOM */
+               sprintf(text, ftext, t->spacename);
+               setConstraint(t, t->spacemtx, mode, text);
+               break;
+       }
+
+       t->con.mode |= CON_USER;
+}
+
+/*--------------------- EXTERNAL SETUP CALLS ------------------*/
+
+void BIF_setLocalLockConstraint(char axis, char *text) {
+       TransInfo *t = BIF_GetTransInfo();
+
+       if (t->total == 0) {
+               return;
+       }
+       
+       switch (axis) {
+       case 'x':
+               setLocalConstraint(t, (CON_AXIS1|CON_AXIS2), text);
+               break;
+       case 'y':
+               setLocalConstraint(t, (CON_AXIS0|CON_AXIS2), text);
+               break;
+       case 'z':
+               setLocalConstraint(t, (CON_AXIS0|CON_AXIS1), text);
+               break;
+       }
+}
+
+void BIF_setLocalAxisConstraint(char axis, char *text) {
+       TransInfo *t = BIF_GetTransInfo();
+
+       if (t->total == 0) {
+               return;
+       }
+       
+       switch (axis) {
+       case 'X':
+               setLocalConstraint(t, CON_AXIS0, text);
+               break;
+       case 'Y':
+               setLocalConstraint(t, CON_AXIS1, text);
+               break;
+       case 'Z':
+               setLocalConstraint(t, CON_AXIS2, text);
+               break;
+       }
+}
+
+/* text is optional, for header print */
+void BIF_setSingleAxisConstraint(float vec[3], char *text) {
+       TransInfo *t = BIF_GetTransInfo();
+       float space[3][3], v[3];
+       
+       if (t->total == 0) {
+               return;
+       }
+       
+       VECCOPY(space[0], vec);
+
+       v[0] = vec[2];
+       v[1] = vec[0];
+       v[2] = vec[1];
+
+       Crossf(space[1], vec, v);
+       Crossf(space[2], vec, space[1]);
+       Mat3Ortho(space);
+
+       Mat3CpyMat3(t->con.mtx, space);
+       t->con.mode = CON_AXIS0;
+       
+       getConstraintMatrix(t);
+
+       startConstraint(t);
+       
+       /* start copying with an offset of 1, to reserve a spot for the SPACE char */
+       if(text)
+       {
+               strncpy(t->con.text+1, text, 48);       /* 50 in struct */
+       }
+       else
+       {
+               t->con.text[1] = '\0'; /* No text */
+       }
+       
+       t->con.drawExtra = NULL;
+       t->con.applyVec = applyAxisConstraintVec;
+       t->con.applySize = applyAxisConstraintSize;
+       t->con.applyRot = applyAxisConstraintRot;
+       t->redraw = 1;
+}
+
+void BIF_setDualAxisConstraint(float vec1[3], float vec2[3], char *text) {
+       TransInfo *t = BIF_GetTransInfo();
+       float space[3][3];
+       
+       if (t->total == 0) {
+               return;
+       }
+
+       VECCOPY(space[0], vec1);
+       VECCOPY(space[1], vec2);
+       Crossf(space[2], space[0], space[1]);
+       Mat3Ortho(space);
+       
+       Mat3CpyMat3(t->con.mtx, space);
+       t->con.mode = CON_AXIS0|CON_AXIS1;
+
+       getConstraintMatrix(t);
+
+       startConstraint(t);
+       
+       /* start copying with an offset of 1, to reserve a spot for the SPACE char */
+       if(text)
+       {
+               strncpy(t->con.text+1, text, 48);       /* 50 in struct */
+       }
+       else
+       {
+               t->con.text[1] = '\0'; /* No text */
+       }
+
+       t->con.drawExtra = NULL;
+       t->con.applyVec = applyAxisConstraintVec;
+       t->con.applySize = applyAxisConstraintSize;
+       t->con.applyRot = applyAxisConstraintRot;
+       t->redraw = 1;
+}
+
+/*----------------- DRAWING CONSTRAINTS -------------------*/
+
+void BIF_drawConstraint(void)
+{
+       TransInfo *t = BIF_GetTransInfo();
+       TransCon *tc = &(t->con);
+
+       if (t->spacetype!=SPACE_VIEW3D)
+               return;
+       if (!(tc->mode & CON_APPLY))
+               return;
+       if (t->flag & T_USES_MANIPULATOR)
+               return;
+       if (t->flag & T_NO_CONSTRAINT)
+               return;
+       
+       /* nasty exception for Z constraint in camera view */
+       // TRANSFORM_FIX_ME
+//     if((t->flag & T_OBJECT) && G.vd->camera==OBACT && G.vd->persp==V3D_CAMOB) 
+//             return;
+
+       if (tc->drawExtra) {
+               tc->drawExtra(t);
+       }
+       else {
+               if (tc->mode & CON_SELECT) {
+                       float vec[3];
+                       char col2[3] = {255,255,255};
+                       convertViewVec(t, vec, (short)(t->mval[0] - t->con.imval[0]), (short)(t->mval[1] - t->con.imval[1]));
+                       VecAddf(vec, vec, tc->center);
+
+                       drawLine(tc->center, tc->mtx[0], 'x', 0);
+                       drawLine(tc->center, tc->mtx[1], 'y', 0);
+                       drawLine(tc->center, tc->mtx[2], 'z', 0);
+
+                       glColor3ubv((GLubyte *)col2);
+                       
+                       glDisable(GL_DEPTH_TEST);
+                       setlinestyle(1);
+                       glBegin(GL_LINE_STRIP); 
+                               glVertex3fv(tc->center); 
+                               glVertex3fv(vec); 
+                       glEnd();
+                       setlinestyle(0);
+                       // TRANSFORM_FIX_ME
+                       //if(G.vd->zbuf)
+                               glEnable(GL_DEPTH_TEST);        
+               }
+
+               if (tc->mode & CON_AXIS0) {
+                       drawLine(tc->center, tc->mtx[0], 'x', DRAWLIGHT);
+               }
+               if (tc->mode & CON_AXIS1) {
+                       drawLine(tc->center, tc->mtx[1], 'y', DRAWLIGHT);
+               }
+               if (tc->mode & CON_AXIS2) {
+                       drawLine(tc->center, tc->mtx[2], 'z', DRAWLIGHT);
+               }
+       }
+}
+
+/* called from drawview.c, as an extra per-window draw option */
+void BIF_drawPropCircle()
+{
+       TransInfo *t = BIF_GetTransInfo();
+
+       if (t->flag & T_PROP_EDIT) {
+               // TRANSFORM_FIX_ME
+#if 0
+               float tmat[4][4], imat[4][4];
+
+               BIF_ThemeColor(TH_GRID);
+               
+               /* if editmode we need to go into object space */
+               if(G.obedit && t->spacetype == SPACE_VIEW3D)
+                       mymultmatrix(G.obedit->obmat);
+               
+               mygetmatrix(tmat);
+               Mat4Invert(imat, tmat);
+
+               set_inverted_drawing(1);
+               drawcircball(GL_LINE_LOOP, t->center, t->propsize, imat);
+               set_inverted_drawing(0);
+               
+               /* if editmode we restore */
+               if(G.obedit && t->spacetype == SPACE_VIEW3D)
+                       myloadmatrix(G.vd->viewmat);
+#endif
+       }
+}
+
+void BIF_getPropCenter(float *center)
+{
+       TransInfo *t = BIF_GetTransInfo();
+
+       if (t && t->flag & T_PROP_EDIT) {
+               VECCOPY(center, t->center);
+       }
+       else
+               center[0] = center[1] = center[2] = 0.0f;
+}
+static void drawObjectConstraint(TransInfo *t) {
+       int i;
+       TransData * td = t->data;
+
+       /* Draw the first one lighter because that's the one who controls the others.
+          Meaning the transformation is projected on that one and just copied on the others
+          constraint space.
+          In a nutshell, the object with light axis is controlled by the user and the others follow.
+          Without drawing the first light, users have little clue what they are doing.
+        */
+       if (t->con.mode & CON_AXIS0) {
+               drawLine(td->ob->obmat[3], td->axismtx[0], 'x', DRAWLIGHT);
+       }
+       if (t->con.mode & CON_AXIS1) {
+               drawLine(td->ob->obmat[3], td->axismtx[1], 'y', DRAWLIGHT);
+       }
+       if (t->con.mode & CON_AXIS2) {
+               drawLine(td->ob->obmat[3], td->axismtx[2], 'z', DRAWLIGHT);
+       }
+       
+       td++;
+
+       for(i=1;i<t->total;i++,td++) {
+               if (t->con.mode & CON_AXIS0) {
+                       drawLine(td->ob->obmat[3], td->axismtx[0], 'x', 0);
+               }
+               if (t->con.mode & CON_AXIS1) {
+                       drawLine(td->ob->obmat[3], td->axismtx[1], 'y', 0);
+               }
+               if (t->con.mode & CON_AXIS2) {
+                       drawLine(td->ob->obmat[3], td->axismtx[2], 'z', 0);
+               }
+       }
+}
+
+/*--------------------- START / STOP CONSTRAINTS ---------------------- */
+
+void startConstraint(TransInfo *t) {
+       t->con.mode |= CON_APPLY;
+       *t->con.text = ' ';
+       t->num.idx_max = MIN2(getConstraintSpaceDimension(t) - 1, t->idx_max);
+}
+
+void stopConstraint(TransInfo *t) {
+       t->con.mode &= ~(CON_APPLY|CON_SELECT);
+       *t->con.text = '\0';
+       t->num.idx_max = t->idx_max;
+}
+
+void getConstraintMatrix(TransInfo *t)
+{
+       float mat[3][3];
+       Mat3Inv(t->con.imtx, t->con.mtx);
+       Mat3One(t->con.pmtx);
+
+       if (!(t->con.mode & CON_AXIS0)) {
+               t->con.pmtx[0][0]               =
+                       t->con.pmtx[0][1]       =
+                       t->con.pmtx[0][2]       = 0.0f;
+       }
+
+       if (!(t->con.mode & CON_AXIS1)) {
+               t->con.pmtx[1][0]               =
+                       t->con.pmtx[1][1]       =
+                       t->con.pmtx[1][2]       = 0.0f;
+       }
+
+       if (!(t->con.mode & CON_AXIS2)) {
+               t->con.pmtx[2][0]               =
+                       t->con.pmtx[2][1]       =
+                       t->con.pmtx[2][2]       = 0.0f;
+       }
+
+       Mat3MulMat3(mat, t->con.pmtx, t->con.imtx);
+       Mat3MulMat3(t->con.pmtx, t->con.mtx, mat);
+}
+
+/*------------------------- MMB Select -------------------------------*/
+
+void initSelectConstraint(TransInfo *t, float mtx[3][3])
+{
+       Mat3CpyMat3(t->con.mtx, mtx);
+       t->con.mode |= CON_APPLY;
+       t->con.mode |= CON_SELECT;
+       t->con.mode &= ~CON_LOCAL;
+
+       setNearestAxis(t);
+       t->con.drawExtra = NULL;
+       t->con.applyVec = applyAxisConstraintVec;
+       t->con.applySize = applyAxisConstraintSize;
+       t->con.applyRot = applyAxisConstraintRot;
+}
+
+void selectConstraint(TransInfo *t) {
+       if (t->con.mode & CON_SELECT) {
+               setNearestAxis(t);
+               startConstraint(t);
+       }
+}
+
+void postSelectConstraint(TransInfo *t)
+{
+       if (!(t->con.mode & CON_SELECT))
+               return;
+
+       t->con.mode &= ~CON_AXIS0;
+       t->con.mode &= ~CON_AXIS1;
+       t->con.mode &= ~CON_AXIS2;
+       t->con.mode &= ~CON_SELECT;
+
+       setNearestAxis(t);
+
+       startConstraint(t);
+       t->redraw = 1;
+}
+
+static void setNearestAxis2d(TransInfo *t)
+{
+       /* no correction needed... just use whichever one is lower */
+       if ( abs(t->mval[0]-t->con.imval[0]) < abs(t->mval[1]-t->con.imval[1]) ) {
+               t->con.mode |= CON_AXIS1;
+               sprintf(t->con.text, " along Y axis");
+       }
+       else {
+               t->con.mode |= CON_AXIS0;
+               sprintf(t->con.text, " along X axis");
+       }
+}
+
+static void setNearestAxis3d(TransInfo *t)
+{
+       wmEvent *event = t->event;
+       float zfac;
+       float mvec[3], axis[3], proj[3];
+       float len[3];
+       int i, icoord[2];
+       
+       /* calculate mouse movement */
+       mvec[0] = (float)(t->mval[0] - t->con.imval[0]);
+       mvec[1] = (float)(t->mval[1] - t->con.imval[1]);
+       mvec[2] = 0.0f;
+       
+       /* we need to correct axis length for the current zoomlevel of view,
+          this to prevent projected values to be clipped behind the camera
+          and to overflow the short integers.
+          The formula used is a bit stupid, just a simplification of the substraction
+          of two 2D points 30 pixels apart (that's the last factor in the formula) after
+          projecting them with window_to_3d and then get the length of that vector.
+       */
+       zfac= t->persmat[0][3]*t->center[0]+ t->persmat[1][3]*t->center[1]+ t->persmat[2][3]*t->center[2]+ t->persmat[3][3];
+       zfac = VecLength(t->persinv[0]) * 2.0f/t->ar->winx * zfac * 30.0f;
+
+       for (i = 0; i<3; i++) {
+               VECCOPY(axis, t->con.mtx[i]);
+               
+               VecMulf(axis, zfac);
+               /* now we can project to get window coordinate */
+               VecAddf(axis, axis, t->con.center);
+               projectIntView(t, axis, icoord);
+               
+               axis[0] = (float)(icoord[0] - t->center2d[0]);
+               axis[1] = (float)(icoord[1] - t->center2d[1]);
+               axis[2] = 0.0f;
+
+               if (Normalize(axis) != 0.0f) {
+                       Projf(proj, mvec, axis);
+                       VecSubf(axis, mvec, proj);
+                       len[i] = Normalize(axis);
+               }
+               else {
+                       len[i] = 10000000000.0f;
+               }
+       }
+
+       if (len[0] <= len[1] && len[0] <= len[2]) {
+               if (event->shift) {
+                       t->con.mode |= (CON_AXIS1|CON_AXIS2);
+                       sprintf(t->con.text, " locking %s X axis", t->spacename);
+               }
+               else {
+                       t->con.mode |= CON_AXIS0;
+                       sprintf(t->con.text, " along %s X axis", t->spacename);
+               }
+       }
+       else if (len[1] <= len[0] && len[1] <= len[2]) {
+               if (event->shift) {
+                       t->con.mode |= (CON_AXIS0|CON_AXIS2);
+                       sprintf(t->con.text, " locking %s Y axis", t->spacename);
+               }
+               else {
+                       t->con.mode |= CON_AXIS1;
+                       sprintf(t->con.text, " along %s Y axis", t->spacename);
+               }
+       }
+       else if (len[2] <= len[1] && len[2] <= len[0]) {
+               if (event->shift) {
+                       t->con.mode |= (CON_AXIS0|CON_AXIS1);
+                       sprintf(t->con.text, " locking %s Z axis", t->spacename);
+               }
+               else {
+                       t->con.mode |= CON_AXIS2;
+                       sprintf(t->con.text, " along %s Z axis", t->spacename);
+               }
+       }
+}
+
+void setNearestAxis(TransInfo *t)
+{
+       /* clear any prior constraint flags */
+       t->con.mode &= ~CON_AXIS0;
+       t->con.mode &= ~CON_AXIS1;
+       t->con.mode &= ~CON_AXIS2;
+
+       /* constraint setting - depends on spacetype */
+       if (t->spacetype == SPACE_VIEW3D) {
+               /* 3d-view */
+               setNearestAxis3d(t);    
+       }
+       else {
+               /* assume that this means a 2D-Editor */
+               setNearestAxis2d(t);
+       }
+       
+       getConstraintMatrix(t);
+}
+
+/*-------------- HELPER FUNCTIONS ----------------*/
+
+char constraintModeToChar(TransInfo *t) {
+       if ((t->con.mode & CON_APPLY)==0) {
+               return '\0';
+       }
+       switch (t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2)) {
+       case (CON_AXIS0):
+       case (CON_AXIS1|CON_AXIS2):
+               return 'X';
+       case (CON_AXIS1):
+       case (CON_AXIS0|CON_AXIS2):
+               return 'Y';
+       case (CON_AXIS2):
+       case (CON_AXIS0|CON_AXIS1):
+               return 'Z';
+       default:
+               return '\0';
+       }
+}
+
+
+int isLockConstraint(TransInfo *t) {
+       int mode = t->con.mode;
+
+       if ( (mode & (CON_AXIS0|CON_AXIS1)) == (CON_AXIS0|CON_AXIS1))
+               return 1;
+
+       if ( (mode & (CON_AXIS1|CON_AXIS2)) == (CON_AXIS1|CON_AXIS2))
+               return 1;
+
+       if ( (mode & (CON_AXIS0|CON_AXIS2)) == (CON_AXIS0|CON_AXIS2))
+               return 1;
+
+       return 0;
+}
+
+/*
+ * Returns the dimension of the constraint space.
+ * 
+ * For that reason, the flags always needs to be set to properly evaluate here,
+ * even if they aren't actually used in the callback function. (Which could happen
+ * for weird constraints not yet designed. Along a path for example.)
+ */
+
+int getConstraintSpaceDimension(TransInfo *t)
+{
+       int n = 0;
+
+       if (t->con.mode & CON_AXIS0)
+               n++;
+
+       if (t->con.mode & CON_AXIS1)
+               n++;
+
+       if (t->con.mode & CON_AXIS2)
+               n++;
+
+       return n;
+/*
+  Someone willing to do it criptically could do the following instead:
+
+  return t->con & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
+       
+  Based on the assumptions that the axis flags are one after the other and start at 1
+*/
+}
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
new file mode 100644 (file)
index 0000000..cfc9a61
--- /dev/null
@@ -0,0 +1,4461 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_image_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_particle_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_property_types.h"
+#include "DNA_vfont_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_listBase.h"
+#include "DNA_gpencil_types.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_blender.h"
+#include "BKE_cloth.h"
+#include "BKE_curve.h"
+#include "BKE_constraint.h"
+#include "BKE_depsgraph.h"
+#include "BKE_displist.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_effect.h"
+#include "BKE_font.h"
+#include "BKE_global.h"
+#include "BKE_ipo.h"
+#include "BKE_lattice.h"
+#include "BKE_key.h"
+#include "BKE_main.h"
+#include "BKE_mball.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_pointcache.h"
+#include "BKE_softbody.h"
+#include "BKE_utildefines.h"
+#include "BKE_bmesh.h"
+#include "BKE_context.h"
+
+//#include "BIF_editaction.h"
+//#include "BIF_editview.h"
+//#include "BIF_editlattice.h"
+//#include "BIF_editconstraint.h"
+#include "BIF_editarmature.h"
+//#include "BIF_editmesh.h"
+//#include "BIF_editnla.h"
+//#include "BIF_editsima.h"
+//#include "BIF_editparticle.h"
+#include "BIF_gl.h"
+//#include "BIF_keyframing.h"
+//#include "BIF_poseobject.h"
+//#include "BIF_meshtools.h"
+//#include "BIF_mywindow.h"
+//#include "BIF_resources.h"
+#include "BIF_retopo.h"
+//#include "BIF_screen.h"
+//#include "BIF_space.h"
+//#include "BIF_toolbox.h"
+
+#include "ED_types.h"
+#include "ED_view3d.h"
+
+//#include "BSE_drawipo.h"
+//#include "BSE_edit.h"
+//#include "BSE_editipo.h"
+//#include "BSE_editipo_types.h"
+//#include "BSE_editaction_types.h"
+
+//#include "BDR_drawaction.h"          // list of keyframes in action
+//#include "BDR_editobject.h"          // reset_slowparents()
+//#include "BDR_gpencil.h"
+//#include "BDR_unwrapper.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+
+//#include "editmesh.h"
+//
+//#include "blendef.h"
+//
+//#include "mydevice.h"
+
+extern ListBase editNurb;
+extern ListBase editelems;
+
+#include "transform.h"
+
+#include "BLO_sys_types.h" // for intptr_t support
+
+/************ STUBS TO GET COMPILE ************/
+void transform_aspect_ratio_tface_uv(float *a1, float *a2) {}
+
+
+
+/* local function prototype - for Object/Bone Constraints */
+static short constraints_list_needinv(TransInfo *t, ListBase *list);
+/* local function prototype - for finding number of keyframes that are selected for editing */
+static int count_ipo_keys(Ipo *ipo, char side, float cfra);
+
+/* ************************** Functions *************************** */
+
+static void qsort_trans_data(TransInfo *t, TransData *head, TransData *tail) {
+       TransData pivot = *head;
+       TransData *ihead = head;
+       TransData *itail = tail;
+       short connected = t->flag & T_PROP_CONNECTED;
+
+       while (head < tail)
+       {
+               if (connected) {
+                       while ((tail->dist >= pivot.dist) && (head < tail))
+                               tail--;
+               }
+               else {
+                       while ((tail->rdist >= pivot.rdist) && (head < tail))
+                               tail--;
+               }
+
+               if (head != tail)
+               {
+                       *head = *tail;
+                       head++;
+               }
+
+               if (connected) {
+                       while ((head->dist <= pivot.dist) && (head < tail))
+                               head++;
+               }
+               else {
+                       while ((head->rdist <= pivot.rdist) && (head < tail))
+                               head++;
+               }
+
+               if (head != tail)
+               {
+                       *tail = *head;
+                       tail--;
+               }
+       }
+
+       *head = pivot;
+       if (ihead < head) {
+               qsort_trans_data(t, ihead, head-1);
+       }
+       if (itail > head) {
+               qsort_trans_data(t, head+1, itail);
+       }
+}
+
+void sort_trans_data_dist(TransInfo *t) {
+       TransData *start = t->data;
+       int i = 1;
+
+       while(i < t->total && start->flag & TD_SELECTED) {
+               start++;
+               i++;
+       }
+       qsort_trans_data(t, start, t->data + t->total - 1);
+}
+
+static void sort_trans_data(TransInfo *t) 
+{
+       TransData *sel, *unsel;
+       TransData temp;
+       unsel = t->data;
+       sel = t->data;
+       sel += t->total - 1;
+       while (sel > unsel) {
+               while (unsel->flag & TD_SELECTED) {
+                       unsel++;
+                       if (unsel == sel) {
+                               return;
+                       }
+               }
+               while (!(sel->flag & TD_SELECTED)) {
+                       sel--;
+                       if (unsel == sel) {
+                               return;
+                       }
+               }
+               temp = *unsel;
+               *unsel = *sel;
+               *sel = temp;
+               sel--;
+               unsel++;
+       }
+}
+
+/* distance calculated from not-selected vertex to nearest selected vertex
+   warning; this is loops inside loop, has minor N^2 issues, but by sorting list it is OK */
+static void set_prop_dist(TransInfo *t, short with_dist)
+{
+       TransData *tob;
+       int a;
+
+       for(a=0, tob= t->data; a<t->total; a++, tob++) {
+               
+               tob->rdist= 0.0f; // init, it was mallocced
+               
+               if((tob->flag & TD_SELECTED)==0) {
+                       TransData *td;
+                       int i;
+                       float dist, vec[3];
+
+                       tob->rdist = -1.0f; // signal for next loop
+                               
+                       for (i = 0, td= t->data; i < t->total; i++, td++) {
+                               if(td->flag & TD_SELECTED) {
+                                       VecSubf(vec, tob->center, td->center);
+                                       Mat3MulVecfl(tob->mtx, vec);
+                                       dist = Normalize(vec);
+                                       if (tob->rdist == -1.0f) {
+                                               tob->rdist = dist;
+                                       }
+                                       else if (dist < tob->rdist) {
+                                               tob->rdist = dist;
+                                       }
+                               }
+                               else break;     // by definition transdata has selected items in beginning
+                       }
+                       if (with_dist) {
+                               tob->dist = tob->rdist;
+                       }
+               }       
+       }
+}
+
+/* ************************** CONVERSIONS ************************* */
+
+/* ********************* texture space ********* */
+
+static void createTransTexspace(bContext *C, TransInfo *t)
+{
+       Scene *scene = CTX_data_scene(C);
+       TransData *td;
+       Object *ob;
+       ID *id;
+       int *texflag;
+       
+       ob = OBACT;
+       
+       if (ob == NULL) { // Shouldn't logically happen, but still...
+               t->total = 0;
+               return;
+       }
+
+       id = ob->data;
+       if(id == NULL || !ELEM3( GS(id->name), ID_ME, ID_CU, ID_MB )) {
+               t->total = 0;
+               return;
+       }
+
+       t->total = 1;
+       td= t->data= MEM_callocN(sizeof(TransData), "TransTexspace");
+       td->ext= t->ext= MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
+       
+       td->flag= TD_SELECTED;
+       VECCOPY(td->center, ob->obmat[3]);
+       td->ob = ob;
+       
+       Mat3CpyMat4(td->mtx, ob->obmat);
+       Mat3CpyMat4(td->axismtx, ob->obmat);
+       Mat3Ortho(td->axismtx);
+       Mat3Inv(td->smtx, td->mtx);
+       
+       if (give_obdata_texspace(ob, &texflag, &td->loc, &td->ext->size, &td->ext->rot)) {
+               *texflag &= ~AUTOSPACE;
+       }
+       
+       VECCOPY(td->iloc, td->loc);
+       VECCOPY(td->ext->irot, td->ext->rot);
+       VECCOPY(td->ext->isize, td->ext->size);
+}
+
+/* ********************* edge (for crease) ***** */
+
+static void createTransEdge(bContext *C, TransInfo *t) {
+#if 0  // TRANSFORM_FIX_ME
+       TransData *td = NULL;
+       EditMesh *em = G.editMesh;
+       EditEdge *eed;
+       float mtx[3][3], smtx[3][3];
+       int count=0, countsel=0;
+       int propmode = t->flag & T_PROP_EDIT;
+
+       for(eed= em->edges.first; eed; eed= eed->next) {
+               if(eed->h==0) {
+                       if (eed->f & SELECT) countsel++;
+                       if (propmode) count++;
+               }
+       }
+
+       if (countsel == 0)
+               return;
+
+       if(propmode) {
+               t->total = count;
+       }
+       else {
+               t->total = countsel;
+       }
+
+       td= t->data= MEM_callocN(t->total * sizeof(TransData), "TransCrease");
+
+       Mat3CpyMat4(mtx, G.obedit->obmat);
+       Mat3Inv(smtx, mtx);
+
+       for(eed= em->edges.first; eed; eed= eed->next) {
+               if(eed->h==0 && (eed->f & SELECT || propmode)) {
+                       /* need to set center for center calculations */
+                       VecAddf(td->center, eed->v1->co, eed->v2->co);
+                       VecMulf(td->center, 0.5f);
+
+                       td->loc= NULL;
+                       if (eed->f & SELECT)
+                               td->flag= TD_SELECTED;
+                       else 
+                               td->flag= 0;
+
+
+                       Mat3CpyMat3(td->smtx, smtx);
+                       Mat3CpyMat3(td->mtx, mtx);
+
+                       td->ext = NULL;
+                       td->tdi = NULL;
+                       if (t->mode == TFM_BWEIGHT) {
+                               td->val = &(eed->bweight);
+                               td->ival = eed->bweight;
+                       }
+                       else {
+                               td->val = &(eed->crease);
+                               td->ival = eed->crease;
+                       }
+
+                       td++;
+               }
+       }
+#endif
+}
+
+/* ********************* pose mode ************* */
+
+static bKinematicConstraint *has_targetless_ik(bPoseChannel *pchan)
+{
+       bConstraint *con= pchan->constraints.first;
+       
+       for(;con; con= con->next) {
+               if(con->type==CONSTRAINT_TYPE_KINEMATIC && (con->enforce!=0.0)) {
+                       bKinematicConstraint *data= con->data;
+                       
+                       if(data->tar==NULL) 
+                               return data;
+                       if(data->tar->type==OB_ARMATURE && data->subtarget[0]==0) 
+                               return data;
+               }
+       }
+       return NULL;
+}
+
+static short apply_targetless_ik(Object *ob)
+{
+       bPoseChannel *pchan, *parchan, *chanlist[256];
+       bKinematicConstraint *data;
+       int segcount, apply= 0;
+       
+       /* now we got a difficult situation... we have to find the
+          target-less IK pchans, and apply transformation to the all 
+          pchans that were in the chain */
+       
+       for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) {
+               data= has_targetless_ik(pchan);
+               if(data && (data->flag & CONSTRAINT_IK_AUTO)) {
+                       
+                       /* fill the array with the bones of the chain (armature.c does same, keep it synced) */
+                       segcount= 0;
+                       
+                       /* exclude tip from chain? */
+                       if(!(data->flag & CONSTRAINT_IK_TIP))
+                               parchan= pchan->parent;
+                       else
+                               parchan= pchan;
+                       
+                       /* Find the chain's root & count the segments needed */
+                       for (; parchan; parchan=parchan->parent){
+                               chanlist[segcount]= parchan;
+                               segcount++;
+                               
+                               if(segcount==data->rootbone || segcount>255) break; // 255 is weak
+                       }
+                       for(;segcount;segcount--) {
+                               Bone *bone;
+                               float rmat[4][4], tmat[4][4], imat[4][4];
+                               
+                               /* pose_mat(b) = pose_mat(b-1) * offs_bone * channel * constraint * IK  */
+                               /* we put in channel the entire result of rmat= (channel * constraint * IK) */
+                               /* pose_mat(b) = pose_mat(b-1) * offs_bone * rmat  */
+                               /* rmat = pose_mat(b) * inv( pose_mat(b-1) * offs_bone ) */
+                               
+                               parchan= chanlist[segcount-1];
+                               bone= parchan->bone;
+                               bone->flag |= BONE_TRANSFORM;   /* ensures it gets an auto key inserted */
+                               
+                               if(parchan->parent) {
+                                       Bone *parbone= parchan->parent->bone;
+                                       float offs_bone[4][4];
+                                       
+                                       /* offs_bone =  yoffs(b-1) + root(b) + bonemat(b) */
+                                       Mat4CpyMat3(offs_bone, bone->bone_mat);
+                                       
+                                       /* The bone's root offset (is in the parent's coordinate system) */
+                                       VECCOPY(offs_bone[3], bone->head);
+                                       
+                                       /* Get the length translation of parent (length along y axis) */
+                                       offs_bone[3][1]+= parbone->length;
+                                       
+                                       /* pose_mat(b-1) * offs_bone */
+                                       if(parchan->bone->flag & BONE_HINGE) {
+                                               /* the rotation of the parent restposition */
+                                               Mat4CpyMat4(rmat, parbone->arm_mat);    /* rmat used as temp */
+                                               
+                                               /* the location of actual parent transform */
+                                               VECCOPY(rmat[3], offs_bone[3]);
+                                               offs_bone[3][0]= offs_bone[3][1]= offs_bone[3][2]= 0.0f;
+                                               Mat4MulVecfl(parchan->parent->pose_mat, rmat[3]);
+                                               
+                                               Mat4MulMat4(tmat, offs_bone, rmat);
+                                       }
+                                       else if(parchan->bone->flag & BONE_NO_SCALE) {
+                                               Mat4MulMat4(tmat, offs_bone, parchan->parent->pose_mat);
+                                               Mat4Ortho(tmat);
+                                       }
+                                       else
+                                               Mat4MulMat4(tmat, offs_bone, parchan->parent->pose_mat);
+                                       
+                                       Mat4Invert(imat, tmat);
+                               }
+                               else {
+                                       Mat4CpyMat3(tmat, bone->bone_mat);
+
+                                       VECCOPY(tmat[3], bone->head);
+                                       Mat4Invert(imat, tmat);
+                               }
+                               /* result matrix */
+                               Mat4MulMat4(rmat, parchan->pose_mat, imat);
+                               
+                               /* apply and decompose, doesn't work for constraints or non-uniform scale well */
+                               {
+                                       float rmat3[3][3], qmat[3][3], imat[3][3], smat[3][3];
+                                       
+                                       Mat3CpyMat4(rmat3, rmat);
+                                       
+                                       /* quaternion */
+                                       Mat3ToQuat(rmat3, parchan->quat);
+                                       
+                                       /* for size, remove rotation */
+                                       /* causes problems with some constraints (so apply only if needed) */
+                                       if (data->flag & CONSTRAINT_IK_STRETCH) {
+                                               QuatToMat3(parchan->quat, qmat);
+                                               Mat3Inv(imat, qmat);
+                                               Mat3MulMat3(smat, rmat3, imat);
+                                               Mat3ToSize(smat, parchan->size);
+                                       }
+                                       
+                                       /* causes problems with some constraints (e.g. childof), so disable this */
+                                       /* as it is IK shouldn't affect location directly */
+                                       /* VECCOPY(parchan->loc, rmat[3]); */
+                               }
+                               
+                       }
+                       
+                       apply= 1;
+                       data->flag &= ~CONSTRAINT_IK_AUTO;
+               }
+       }               
+       
+       return apply;
+}
+
+static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, TransData *td)
+{
+       Bone *bone= pchan->bone;
+       float pmat[3][3], omat[3][3];
+       float cmat[3][3], tmat[3][3];
+       float vec[3];
+
+       VECCOPY(vec, pchan->pose_mat[3]);
+       VECCOPY(td->center, vec);
+       
+       td->ob = ob;
+       td->flag= TD_SELECTED|TD_USEQUAT;
+       if (bone->flag & BONE_HINGE_CHILD_TRANSFORM)
+       {
+               td->flag |= TD_NOCENTER;
+       }
+       
+       if (bone->flag & BONE_TRANSFORM_CHILD)
+       {
+               td->flag |= TD_NOCENTER;
+               td->flag |= TD_NO_LOC;
+       }
+       
+       td->protectflag= pchan->protectflag;
+       
+       td->loc = pchan->loc;
+       VECCOPY(td->iloc, pchan->loc);
+       
+       td->ext->rot= NULL;
+       td->ext->quat= pchan->quat;
+       td->ext->size= pchan->size;
+
+       QUATCOPY(td->ext->iquat, pchan->quat);
+       VECCOPY(td->ext->isize, pchan->size);
+
+       /* proper way to get parent transform + own transform + constraints transform */
+       Mat3CpyMat4(omat, ob->obmat);
+       
+       if(pchan->parent) {      
+               if(pchan->bone->flag & BONE_HINGE)       
+                       Mat3CpyMat4(pmat, pchan->parent->bone->arm_mat);         
+               else     
+                       Mat3CpyMat4(pmat, pchan->parent->pose_mat);
+               
+               if (constraints_list_needinv(t, &pchan->constraints)) {
+                       Mat3CpyMat4(tmat, pchan->constinv);
+                       Mat3Inv(cmat, tmat);
+                       Mat3MulSerie(td->mtx, pchan->bone->bone_mat, pmat, omat, cmat, 0,0,0,0);    // dang mulserie swaps args
+               }
+               else
+                       Mat3MulSerie(td->mtx, pchan->bone->bone_mat, pmat, omat, 0,0,0,0,0);    // dang mulserie swaps args
+       }
+       else {
+               if (constraints_list_needinv(t, &pchan->constraints)) {
+                       Mat3CpyMat4(tmat, pchan->constinv);
+                       Mat3Inv(cmat, tmat);
+                       Mat3MulSerie(td->mtx, pchan->bone->bone_mat, omat, cmat, 0,0,0,0,0);    // dang mulserie swaps args
+               }
+               else 
+                       Mat3MulMat3(td->mtx, omat, pchan->bone->bone_mat);  // Mat3MulMat3 has swapped args! 
+       }
+       
+       Mat3Inv(td->smtx, td->mtx);
+       
+       /* for axismat we use bone's own transform */
+       Mat3CpyMat4(pmat, pchan->pose_mat);
+       Mat3MulMat3(td->axismtx, omat, pmat);
+       Mat3Ortho(td->axismtx);
+       
+       if(t->mode==TFM_BONESIZE) {
+               bArmature *arm= t->poseobj->data;
+               
+               if(arm->drawtype==ARM_ENVELOPE) {
+                       td->loc= NULL;
+                       td->val= &bone->dist;
+                       td->ival= bone->dist;
+               }
+               else {
+                       // abusive storage of scale in the loc pointer :)
+                       td->loc= &bone->xwidth;
+                       VECCOPY (td->iloc, td->loc);
+                       td->val= NULL;
+               }
+       }
+       
+       /* in this case we can do target-less IK grabbing */
+       if(t->mode==TFM_TRANSLATION) {
+               bKinematicConstraint *data= has_targetless_ik(pchan);
+               if(data) {
+                       if(data->flag & CONSTRAINT_IK_TIP) {
+                               VECCOPY(data->grabtarget, pchan->pose_tail);
+                       }
+                       else {
+                               VECCOPY(data->grabtarget, pchan->pose_head);
+                       }
+                       td->loc = data->grabtarget;
+                       VECCOPY(td->iloc, td->loc);
+                       data->flag |= CONSTRAINT_IK_AUTO;
+                       
+                       /* only object matrix correction */
+                       Mat3CpyMat3 (td->mtx, omat);
+                       Mat3Inv (td->smtx, td->mtx);
+               }
+       }
+       
+       /* store reference to first constraint */
+       td->con= pchan->constraints.first;
+}
+
+static void bone_children_clear_transflag(TransInfo *t, ListBase *lb)
+{
+       Bone *bone= lb->first;
+       
+       for(;bone;bone= bone->next) {
+               if((bone->flag & BONE_HINGE) && (bone->flag & BONE_CONNECTED))
+               {
+                       bone->flag |= BONE_HINGE_CHILD_TRANSFORM;
+               }
+               else if (bone->flag & BONE_TRANSFORM && (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL)) 
+               {
+                       bone->flag |= BONE_TRANSFORM_CHILD;
+               }
+               else
+               {
+                       bone->flag &= ~BONE_TRANSFORM;
+               }
+
+               bone_children_clear_transflag(t, &bone->childbase);
+       }
+}
+
+/* sets transform flags in the bones, returns total */
+static void set_pose_transflags(TransInfo *t, Object *ob)
+{
+       bArmature *arm= ob->data;
+       bPoseChannel *pchan;
+       Bone *bone;
+       int hastranslation;
+       
+       t->total= 0;
+       
+       for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+               bone= pchan->bone;
+               if(bone->layer & arm->layer) {
+                       if(bone->flag & BONE_SELECTED)
+                               bone->flag |= BONE_TRANSFORM;
+                       else
+                               bone->flag &= ~BONE_TRANSFORM;
+
+                       bone->flag &= ~BONE_HINGE_CHILD_TRANSFORM;
+                       bone->flag &= ~BONE_TRANSFORM_CHILD;
+               }
+       }
+       
+       /* make sure no bone can be transformed when a parent is transformed */
+       /* since pchans are depsgraph sorted, the parents are in beginning of list */
+       if(t->mode!=TFM_BONESIZE) {
+               for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+                       bone= pchan->bone;
+                       if(bone->flag & BONE_TRANSFORM)
+                               bone_children_clear_transflag(t, &bone->childbase);
+               }
+       }       
+       /* now count, and check if we have autoIK or have to switch from translate to rotate */
+       hastranslation= 0;
+
+       for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+               bone= pchan->bone;
+               if(bone->flag & BONE_TRANSFORM) {
+
+                       t->total++;
+                       
+                       if(t->mode==TFM_TRANSLATION) {
+                               if( has_targetless_ik(pchan)==NULL ) {
+                                       if(pchan->parent && (pchan->bone->flag & BONE_CONNECTED)) {
+                                               if(pchan->bone->flag & BONE_HINGE_CHILD_TRANSFORM)
+                                                       hastranslation= 1;
+                                       }
+                                       else if((pchan->protectflag & OB_LOCK_LOC)!=OB_LOCK_LOC)
+                                               hastranslation= 1;
+                               }
+                               else
+                                       hastranslation= 1;
+                       }
+               }
+       }
+
+       /* if there are no translatable bones, do rotation */
+       if(t->mode==TFM_TRANSLATION && !hastranslation)
+               t->mode= TFM_ROTATION;
+}
+
+
+/* -------- Auto-IK ---------- */
+
+/* adjust pose-channel's auto-ik chainlen */
+static void pchan_autoik_adjust (bPoseChannel *pchan, short chainlen)
+{
+       bConstraint *con;
+       
+       /* don't bother to search if no valid constraints */
+       if ((pchan->constflag & (PCHAN_HAS_IK|PCHAN_HAS_TARGET))==0)
+               return;
+       
+       /* check if pchan has ik-constraint */
+       for (con= pchan->constraints.first; con; con= con->next) {
+               if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce!=0.0)) {
+                       bKinematicConstraint *data= con->data;
+                       
+                       /* only accept if a temporary one (for auto-ik) */
+                       if (data->flag & CONSTRAINT_IK_TEMP) {
+                               /* chainlen is new chainlen, but is limited by maximum chainlen */
+                               if ((chainlen==0) || (chainlen > data->max_rootbone))
+                                       data->rootbone= data->max_rootbone;
+                               else
+                                       data->rootbone= chainlen;
+                       }
+               }
+       }
+}
+
+/* change the chain-length of auto-ik */
+void transform_autoik_update (TransInfo *t, short mode)
+{
+       short *chainlen= &G.scene->toolsettings->autoik_chainlen;
+       bPoseChannel *pchan;
+       
+       /* mode determines what change to apply to chainlen */
+       if (mode == 1) {
+               /* mode=1 is from WHEELMOUSEDOWN... increases len */
+               (*chainlen)++;
+       }
+       else if (mode == -1) {
+               /* mode==-1 is from WHEELMOUSEUP... decreases len */
+               if (*chainlen > 0) (*chainlen)--;
+       }
+       
+       /* sanity checks (don't assume t->poseobj is set, or that it is an armature) */
+       if (ELEM(NULL, t->poseobj, t->poseobj->pose))
+               return;
+       
+       /* apply to all pose-channels */
+       for&nb