fly mode back as a modal operator view3d.fly
authorCampbell Barton <ideasman42@gmail.com>
Wed, 23 Sep 2009 11:26:16 +0000 (11:26 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 23 Sep 2009 11:26:16 +0000 (11:26 +0000)
- access with the F key, Ctrl+Alt+F in editmode, View->Navigation menu
- camera, perspective & 4split (perspective view only)
- uses modal keymap, (same as 2.4x).
- bugfix since 2.4x, when flying upside down, turning left/right was inverted.
- bugfix for "Align Camera To View", was using deprecated v3d->ofs rather then rv3d->ofs, fixed for NDof fly too. checked v3d->ofs is only used in readfile.c

Todo
- Warping the cursor removed in 2.5, no way to place the cursor in the middle of the view.
- Adding keyframes while in flymode to record the path is missing.
- Not getting MMB mouse release events (used for pan). need to look into why.

release/ui/space_view3d.py
source/blender/editors/mesh/mesh_ops.c
source/blender/editors/space_view3d/view3d_edit.c
source/blender/editors/space_view3d/view3d_intern.h
source/blender/editors/space_view3d/view3d_ops.c
source/blender/editors/space_view3d/view3d_view.c

index fd06853625e5e8ce416c09a2d42fba19ff33aeac..23f3b8a10ac3bc02ed6c8e3764c61cc03fa40b01 100644 (file)
@@ -136,6 +136,10 @@ class VIEW3D_MT_view_navigation(bpy.types.Menu):
                
                layout.item_floatO("view3d.zoom", "delta", 1.0, text="Zoom In")
                layout.item_floatO("view3d.zoom", "delta", -1.0, text="Zoom Out")
+               
+               layout.itemS()
+               
+               layout.itemO("view3d.fly")
 
 class VIEW3D_MT_view_align(bpy.types.Menu):
        __space_type__ = 'VIEW_3D'
index a79b42dcbb80b286d6e08e483a343002651ba164..96f5e7452d166ad6836612b9049e16eeb453463b 100644 (file)
@@ -429,7 +429,7 @@ void ED_keymap_mesh(wmWindowManager *wm)
        WM_keymap_add_item(keymap, "MESH_OT_edge_face_add", FKEY, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "MESH_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
        WM_keymap_add_item(keymap, "OBJECT_OT_mesh_add", AKEY, KM_PRESS, KM_SHIFT, 0);
-       WM_keymap_add_item(keymap, "MESH_OT_separate", PKEY, KM_PRESS, KM_SHIFT, 0);
+       WM_keymap_add_item(keymap, "MESH_OT_separate", PKEY, KM_PRESS, 0, 0);
                                                /* use KM_RELEASE because same key is used for tweaks */
        WM_keymap_add_item(keymap, "MESH_OT_dupli_extrude_cursor", LEFTMOUSE, KM_RELEASE, KM_CTRL, 0);
        
index b788dc28311ee944d80744dbf6a4c57766a8dbde..24ec0d124c662d94adf810af3b335c9974676776 100644 (file)
@@ -2338,7 +2338,7 @@ void viewmoveNDOF(Scene *scene, ARegion *ar, View3D *v3d, int mode)
 
     if (use_sel) {
         QuatConj(q1); /* conj == inv for unit quat */
-        VecSubf(v3d->ofs, v3d->ofs, obofs);
+        VecSubf(rv3d->ofs, rv3d->ofs, obofs);
         QuatMulVecf(q1, rv3d->ofs);
         VecAddf(rv3d->ofs, rv3d->ofs, obofs);
     }
index 52505fad521fa2b79b05e8fd11e7a71b7a9f3a08..d532d2b2cc8762db21ef89175734c7e1bf2a5aa4 100644 (file)
@@ -124,6 +124,7 @@ void VIEW3D_OT_smoothview(struct wmOperatorType *ot);
 void VIEW3D_OT_setcameratoview(struct wmOperatorType *ot);
 void VIEW3D_OT_localview(struct wmOperatorType *ot);
 void VIEW3D_OT_game_start(struct wmOperatorType *ot);
+void VIEW3D_OT_fly(struct wmOperatorType *ot);
 
 
 int boundbox_clip(RegionView3D *rv3d, float obmat[][4], struct BoundBox *bb);
@@ -135,6 +136,8 @@ void smooth_view(struct bContext *C, Object *, Object *, float *ofs, float *quat
 void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect); /* rect: for picking */
 void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d);
 
+void fly_modal_keymap(struct wmWindowManager *wm);
+
 /* view3d_buttons.c */
 void VIEW3D_OT_properties(struct wmOperatorType *ot);
 void view3d_buttons_register(struct ARegionType *art);
index 57176dc2592854ce3b454628ff76dce28ca047e2..06480d3e2db9faddbf3d8454eab6a073820ecf42 100644 (file)
@@ -85,6 +85,7 @@ void view3d_operatortypes(void)
        WM_operatortype_append(VIEW3D_OT_drawtype);
        WM_operatortype_append(VIEW3D_OT_localview);
        WM_operatortype_append(VIEW3D_OT_game_start);
+       WM_operatortype_append(VIEW3D_OT_fly);
        WM_operatortype_append(VIEW3D_OT_layers);
        
        WM_operatortype_append(VIEW3D_OT_properties);
@@ -123,6 +124,8 @@ void view3d_keymap(wmWindowManager *wm)
        WM_keymap_verify_item(keymap, "VIEW3D_OT_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0);
        WM_keymap_verify_item(keymap, "VIEW3D_OT_view_center", PADPERIOD, KM_PRESS, 0, 0);
        
+       WM_keymap_verify_item(keymap, "VIEW3D_OT_fly", FKEY, KM_PRESS, KM_ANY, 0);
+
        WM_keymap_verify_item(keymap, "VIEW3D_OT_smoothview", TIMER1, KM_ANY, KM_ANY, 0);
        
        RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", PADPLUSKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);
@@ -218,5 +221,6 @@ void view3d_keymap(wmWindowManager *wm)
 
        transform_keymap_for_space(wm, keymap, SPACE_VIEW3D);
 
+       fly_modal_keymap(wm);
 }
 
index b6b6f6549098e80216d3487295aca0c4e9f25431..f722a97963d50d6815eb78d92e80156802f7b343 100644 (file)
 #include "BKE_object.h"
 #include "BKE_global.h"
 #include "BKE_main.h"
+#include "BKE_report.h"
 #include "BKE_scene.h"
 #include "BKE_screen.h"
 #include "BKE_utildefines.h"
+#include "BKE_depsgraph.h" /* for fly mode updating */
 
 #include "RE_pipeline.h"       // make_stars
 
@@ -384,26 +386,31 @@ void VIEW3D_OT_smoothview(wmOperatorType *ot)
        ot->poll= ED_operator_view3d_active;
 }
 
-static int view3d_setcameratoview_exec(bContext *C, wmOperator *op)
+static void setcameratoview3d(View3D *v3d, RegionView3D *rv3d, Object *ob)
 {
-       View3D *v3d = CTX_wm_view3d(C);
-       RegionView3D *rv3d= CTX_wm_region_view3d(C);
-       Object *ob;
        float dvec[3];
        
-       ob= v3d->camera;
        dvec[0]= rv3d->dist*rv3d->viewinv[2][0];
        dvec[1]= rv3d->dist*rv3d->viewinv[2][1];
        dvec[2]= rv3d->dist*rv3d->viewinv[2][2];
        
        VECCOPY(ob->loc, dvec);
-       VecSubf(ob->loc, ob->loc, v3d->ofs);
+       VecSubf(ob->loc, ob->loc, rv3d->ofs);
        rv3d->viewquat[0]= -rv3d->viewquat[0];
 
        QuatToEul(rv3d->viewquat, ob->rot);
        rv3d->viewquat[0]= -rv3d->viewquat[0];
        
        ob->recalc= OB_RECALC_OB;
+}
+
+
+static int view3d_setcameratoview_exec(bContext *C, wmOperator *op)
+{
+       View3D *v3d = CTX_wm_view3d(C);
+       RegionView3D *rv3d= CTX_wm_region_view3d(C);
+
+       setcameratoview3d(v3d, rv3d, v3d->camera);
        
        WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, CTX_data_scene(C));
        
@@ -1572,6 +1579,802 @@ void VIEW3D_OT_game_start(wmOperatorType *ot)
        ot->poll= game_engine_poll;
 }
 
+
+/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
+#define FLY_MODAL_CANCEL                       1
+#define FLY_MODAL_CONFIRM                      2
+#define FLY_MODAL_ACCELERATE           3
+#define FLY_MODAL_DECELERATE           4
+#define FLY_MODAL_PAN_ENABLE           5
+#define FLY_MODAL_PAN_DISABLE          6
+#define FLY_MODAL_DIR_FORWARD          7
+#define FLY_MODAL_DIR_BACKWARD         8
+#define FLY_MODAL_DIR_LEFT                     9
+#define FLY_MODAL_DIR_RIGHT                    10
+#define FLY_MODAL_DIR_UP                       11
+#define FLY_MODAL_DIR_DOWN                     12
+#define FLY_MODAL_AXIS_LOCK_X          13
+#define FLY_MODAL_AXIS_LOCK_Z          14
+#define FLY_MODAL_PRECISION_ENABLE     15
+#define FLY_MODAL_PRECISION_DISABLE    16
+
+/* called in transform_ops.c, on each regeneration of keymaps  */
+void fly_modal_keymap(wmWindowManager *wm)
+{
+       static EnumPropertyItem modal_items[] = {
+       {FLY_MODAL_CANCEL,      "CANCEL", 0, "Cancel", ""},
+       {FLY_MODAL_CONFIRM,     "CONFIRM", 0, "Confirm", ""},
+       {FLY_MODAL_ACCELERATE, "ACCELERATE", 0, "Accelerate", ""},
+       {FLY_MODAL_DECELERATE, "DECELERATE", 0, "Decelerate", ""},
+
+       {FLY_MODAL_PAN_ENABLE,  "PAN_ENABLE", 0, "Pan Enable", ""},
+       {FLY_MODAL_PAN_DISABLE, "PAN_DISABLE", 0, "Pan Disable", ""},
+
+       {FLY_MODAL_DIR_FORWARD, "FORWARD", 0, "Fly Forward", ""},
+       {FLY_MODAL_DIR_BACKWARD,"BACKWARD", 0, "Fly Backward", ""},
+       {FLY_MODAL_DIR_LEFT,    "LEFT", 0, "Fly Left", ""},
+       {FLY_MODAL_DIR_RIGHT,   "RIGHT", 0, "Fly Right", ""},
+       {FLY_MODAL_DIR_UP,              "UP", 0, "Fly Up", ""},
+       {FLY_MODAL_DIR_DOWN,    "DOWN", 0, "Fly Down", ""},
+
+       {FLY_MODAL_AXIS_LOCK_X, "AXIS_LOCK_X", 0, "X Axis Correction", "X axis correction (toggle)"},
+       {FLY_MODAL_AXIS_LOCK_Z, "AXIS_LOCK_Z", 0, "X Axis Correction", "Z axis correction (toggle)"},
+
+       {FLY_MODAL_PRECISION_ENABLE,    "PRECISION_ENABLE", 0, "Precision Enable", ""},
+       {FLY_MODAL_PRECISION_DISABLE,   "PRECISION_DISABLE", 0, "Precision Disable", ""},
+
+       {0, NULL, 0, NULL, NULL}};
+
+       wmKeyMap *keymap= WM_modalkeymap_get(wm, "View3D Fly Modal");
+
+       /* this function is called for each spacetype, only needs to add map once */
+       if(keymap) return;
+
+       keymap= WM_modalkeymap_add(wm, "View3D Fly Modal", modal_items);
+
+       /* items for modal map */
+       WM_modalkeymap_add_item(keymap, ESCKEY,    KM_PRESS, KM_ANY, 0, FLY_MODAL_CANCEL);
+       WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, FLY_MODAL_CANCEL);
+
+       WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, FLY_MODAL_CONFIRM);
+       WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_CONFIRM);
+       WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, FLY_MODAL_CONFIRM);
+
+       WM_modalkeymap_add_item(keymap, PADPLUSKEY, KM_PRESS, 0, 0, FLY_MODAL_ACCELERATE);
+       WM_modalkeymap_add_item(keymap, PADMINUS, KM_PRESS, 0, 0, FLY_MODAL_DECELERATE);
+       WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, FLY_MODAL_ACCELERATE);
+       WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, FLY_MODAL_DECELERATE);
+
+       WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, KM_ANY, 0, FLY_MODAL_PAN_ENABLE);
+       WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, FLY_MODAL_PAN_DISABLE); /* XXX - Bug in the event system, middle mouse release doesnt work */
+
+       /* WASD */
+       WM_modalkeymap_add_item(keymap, WKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_FORWARD);
+       WM_modalkeymap_add_item(keymap, SKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_BACKWARD);
+       WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_LEFT);
+       WM_modalkeymap_add_item(keymap, DKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_RIGHT);
+       WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_UP);
+       WM_modalkeymap_add_item(keymap, FKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_DOWN);
+
+       WM_modalkeymap_add_item(keymap, XKEY, KM_PRESS, 0, 0, FLY_MODAL_AXIS_LOCK_X);
+       WM_modalkeymap_add_item(keymap, ZKEY, KM_PRESS, 0, 0, FLY_MODAL_AXIS_LOCK_Z);
+
+       WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_PRECISION_ENABLE);
+       WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, FLY_MODAL_PRECISION_DISABLE);
+
+       /* assign map to operators */
+       WM_modalkeymap_assign(keymap, "VIEW3D_OT_fly");
+
+}
+
+typedef struct FlyInfo {
+       /* context stuff */
+       RegionView3D *rv3d;
+       View3D *v3d;
+       ARegion *ar;
+       Scene *scene;
+
+       wmTimer *timer; /* needed for redraws */
+
+       short state;
+       short use_precision;
+       short redraw;
+       short mval[2];
+
+       /* fly state state */
+       float speed; /* the speed the view is moving per redraw */
+       short axis; /* Axis index to move allong by default Z to move allong the view */
+       short pan_view; /* when true, pan the view instead of rotating */
+
+       /* relative view axis locking - xlock, zlock
+       0; disabled
+       1; enabled but not checking because mouse hasnt moved outside the margin since locking was checked an not needed
+          when the mouse moves, locking is set to 2 so checks are done.
+       2; mouse moved and checking needed, if no view altering is donem its changed back to 1 */
+       short xlock, zlock;
+       float xlock_momentum, zlock_momentum; /* nicer dynamics */
+       float grid; /* world scale 1.0 default */
+
+       /* backup values */
+       float dist_backup; /* backup the views distance since we use a zero dist for fly mode */
+       float ofs_backup[3]; /* backup the views offset incase the user cancels flying in non camera mode */
+       float rot_backup[4]; /* backup the views quat incase the user cancels flying in non camera mode. (quat for view, eul for camera) */
+       short persp_backup; /* remember if were ortho or not, only used for restoring the view if it was a ortho view */
+
+       /* compare between last state */
+       double time_lastwheel; /* used to accelerate when using the mousewheel a lot */
+       double time_lastdraw; /* time between draws */
+
+       /* use for some lag */
+       float dvec_prev[3]; /* old for some lag */
+
+} FlyInfo;
+
+/* FlyInfo->state */
+#define FLY_RUNNING            0
+#define FLY_CANCEL             1
+#define FLY_CONFIRM            2
+
+int initFlyInfo (bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *event)
+{
+       float upvec[3]; // tmp
+       float mat[3][3];
+
+       fly->rv3d= CTX_wm_region_view3d(C);
+       fly->v3d = CTX_wm_view3d(C);
+       fly->ar = CTX_wm_region(C);
+       fly->scene= CTX_data_scene(C);
+
+       if(fly->rv3d->persp==V3D_CAMOB && fly->v3d->camera->id.lib) {
+               BKE_report(op->reports, RPT_ERROR, "Cannot fly a camera from an external library");
+               return FALSE;
+       }
+
+       if(fly->v3d->ob_centre) {
+               BKE_report(op->reports, RPT_ERROR, "Cannot fly when the view is locked to an object");
+               return FALSE;
+       }
+
+       if(fly->rv3d->persp==V3D_CAMOB && fly->v3d->camera->constraints.first) {
+               BKE_report(op->reports, RPT_ERROR, "Cannot fly an object with constraints");
+               return FALSE;
+       }
+
+       fly->state= FLY_RUNNING;
+       fly->speed= 0.0f;
+       fly->axis= 2;
+       fly->pan_view= FALSE;
+       fly->xlock= FALSE;
+       fly->zlock= TRUE;
+       fly->xlock_momentum=0.0f;
+       fly->zlock_momentum=0.0f;
+       fly->grid= 1.0f;
+       fly->use_precision= 0;
+
+       fly->dvec_prev[0]= fly->dvec_prev[1]= fly->dvec_prev[2]= 0.0f;
+
+       fly->timer= WM_event_add_window_timer(CTX_wm_window(C), TIMER, 0.01f);
+
+
+       /* we have to rely on events to give proper mousecoords after a warp_pointer */
+//XXX2.5       warp_pointer(cent_orig[0], cent_orig[1]);
+       //fly->mval[0]= (fly->sa->winx)/2;
+       //fly->mval[1]= (fly->sa->winy)/2;
+
+       fly->mval[0] = event->x - fly->ar->winrct.xmin;
+       fly->mval[1] = event->y - fly->ar->winrct.ymin;
+
+
+       fly->time_lastdraw= fly->time_lastwheel= PIL_check_seconds_timer();
+
+       fly->rv3d->rflag |= RV3D_FLYMODE; /* so we draw the corner margins */
+
+       /* detect weather to start with Z locking */
+       upvec[0]=1.0f; upvec[1]=0.0f; upvec[2]=0.0f;
+       Mat3CpyMat4(mat, fly->rv3d->viewinv);
+       Mat3MulVecfl(mat, upvec);
+       if (fabs(upvec[2]) < 0.1)
+               fly->zlock = 1;
+       upvec[0]=0; upvec[1]=0; upvec[2]=0;
+
+       fly->persp_backup= fly->rv3d->persp;
+       fly->dist_backup= fly->rv3d->dist;
+       if (fly->rv3d->persp==V3D_CAMOB) {
+               /* store the origoinal camera loc and rot */
+               VECCOPY(fly->ofs_backup, fly->v3d->camera->loc);
+               VECCOPY(fly->rot_backup, fly->v3d->camera->rot);
+
+               where_is_object(fly->scene, fly->v3d->camera);
+               VECCOPY(fly->rv3d->ofs, fly->v3d->camera->obmat[3]);
+               VecMulf(fly->rv3d->ofs, -1.0f); /*flip the vector*/
+
+               fly->rv3d->dist=0.0;
+               fly->rv3d->viewbut=0;
+
+               /* used for recording */
+//XXX2.5               if(v3d->camera->ipoflag & OB_ACTION_OB)
+//XXX2.5                       actname= "Object";
+
+       } else {
+               /* perspective or ortho */
+               if (fly->rv3d->persp==V3D_ORTHO)
+                       fly->rv3d->persp= V3D_PERSP; /*if ortho projection, make perspective */
+               QUATCOPY(fly->rot_backup, fly->rv3d->viewquat);
+               VECCOPY(fly->ofs_backup, fly->rv3d->ofs);
+               fly->rv3d->dist= 0.0;
+
+               upvec[2]= fly->dist_backup; /*x and y are 0*/
+               Mat3MulVecfl(mat, upvec);
+               VecSubf(fly->rv3d->ofs, fly->rv3d->ofs, upvec);
+               /*Done with correcting for the dist*/
+       }
+
+       return 1;
+}
+
+static int flyEnd(bContext *C, FlyInfo *fly)
+{
+       RegionView3D *rv3d= fly->rv3d;
+       View3D *v3d = fly->v3d;
+
+       float upvec[3];
+
+       if(fly->state == FLY_RUNNING)
+               return OPERATOR_RUNNING_MODAL;
+
+       WM_event_remove_window_timer(CTX_wm_window(C), fly->timer);
+
+       rv3d->dist= fly->dist_backup;
+
+       if (fly->state == FLY_CANCEL) {
+       /* Revert to original view? */
+               if (fly->persp_backup==V3D_CAMOB) { /* a camera view */
+                       rv3d->viewbut=1;
+                       VECCOPY(v3d->camera->loc, fly->ofs_backup);
+                       VECCOPY(v3d->camera->rot, fly->rot_backup);
+                       DAG_id_flush_update(&v3d->camera->id, OB_RECALC_OB);
+               } else {
+                       /* Non Camera we need to reset the view back to the original location bacause the user canceled*/
+                       QUATCOPY(rv3d->viewquat, fly->rot_backup);
+                       VECCOPY(rv3d->ofs, fly->ofs_backup);
+                       rv3d->persp= fly->persp_backup;
+               }
+       }
+       else if (fly->persp_backup==V3D_CAMOB) {        /* camera */
+               float mat3[3][3];
+               Mat3CpyMat4(mat3, v3d->camera->obmat);
+               Mat3ToCompatibleEul(mat3, v3d->camera->rot, fly->rot_backup);
+
+               DAG_id_flush_update(&v3d->camera->id, OB_RECALC_OB);
+#if 0 //XXX2.5
+               if (IS_AUTOKEY_MODE(NORMAL)) {
+                       allqueue(REDRAWIPO, 0);
+                       allspace(REMAKEIPO, 0);
+                       allqueue(REDRAWNLA, 0);
+                       allqueue(REDRAWTIME, 0);
+               }
+#endif
+       }
+       else { /* not camera */
+               /* Apply the fly mode view */
+               /*restore the dist*/
+               float mat[3][3];
+               upvec[0]= upvec[1]= 0;
+               upvec[2]= fly->dist_backup; /*x and y are 0*/
+               Mat3CpyMat4(mat, rv3d->viewinv);
+               Mat3MulVecfl(mat, upvec);
+               VecAddf(rv3d->ofs, rv3d->ofs, upvec);
+               /*Done with correcting for the dist */
+       }
+
+       rv3d->rflag &= ~RV3D_FLYMODE;
+//XXX2.5       BIF_view3d_previewrender_signal(fly->sa, PR_DBASE|PR_DISPRECT); /* not working at the moment not sure why */
+
+
+       if(fly->state == FLY_CONFIRM) {
+               MEM_freeN(fly);
+               return OPERATOR_FINISHED;
+       }
+
+       MEM_freeN(fly);
+       return OPERATOR_CANCELLED;
+}
+
+void flyEvent(FlyInfo *fly, wmEvent *event)
+{
+       if (event->type == TIMER) {
+               fly->redraw = 1;
+       }
+       else if (event->type == MOUSEMOVE) {
+               fly->mval[0] = event->x - fly->ar->winrct.xmin;
+               fly->mval[1] = event->y - fly->ar->winrct.ymin;
+       } /* handle modal keymap first */
+       else if (event->type == EVT_MODAL_MAP) {
+               switch (event->val) {
+                       case FLY_MODAL_CANCEL:
+                               fly->state = FLY_CANCEL;
+                               break;
+                       case FLY_MODAL_CONFIRM:
+                               fly->state = FLY_CONFIRM;
+                               break;
+
+                       case FLY_MODAL_ACCELERATE:
+                       {
+                               double time_currwheel;
+                               float time_wheel;
+
+                               time_currwheel= PIL_check_seconds_timer();
+                               time_wheel = (float)(time_currwheel - fly->time_lastwheel);
+                               fly->time_lastwheel = time_currwheel;
+                               /*printf("Wheel %f\n", time_wheel);*/
+                               /*Mouse wheel delays range from 0.5==slow to 0.01==fast*/
+                               time_wheel = 1+ (10 - (20*MIN2(time_wheel, 0.5))); /* 0-0.5 -> 0-5.0 */
+
+                               if (fly->speed<0.0f) fly->speed= 0.0f;
+                               else {
+                                       if (event->shift)
+                                               fly->speed+= fly->grid*time_wheel*0.1;
+                                       else
+                                               fly->speed+= fly->grid*time_wheel;
+                               }
+                               break;
+                       }
+                       case FLY_MODAL_DECELERATE:
+                       {
+                               double time_currwheel;
+                               float time_wheel;
+
+                               time_currwheel= PIL_check_seconds_timer();
+                               time_wheel = (float)(time_currwheel - fly->time_lastwheel);
+                               fly->time_lastwheel = time_currwheel;
+                               time_wheel = 1+ (10 - (20*MIN2(time_wheel, 0.5))); /* 0-0.5 -> 0-5.0 */
+
+                               if (fly->speed>0) fly->speed=0;
+                               else {
+                                       if (event->shift)
+                                               fly->speed-= fly->grid*time_wheel*0.1;
+                                       else
+                                               fly->speed-= fly->grid*time_wheel;
+                               }
+                               break;
+                       }
+                       case FLY_MODAL_PAN_ENABLE:
+                               fly->pan_view= TRUE;
+                               break;
+                       case FLY_MODAL_PAN_DISABLE:
+//XXX2.5               warp_pointer(cent_orig[0], cent_orig[1]);
+                               fly->pan_view= FALSE;
+                               break;
+
+                               /* impliment WASD keys */
+                       case FLY_MODAL_DIR_FORWARD:
+                               if (fly->speed < 0.0f) fly->speed= -fly->speed; /* flip speed rather then stopping, game like motion */
+                               else fly->speed += fly->grid; /* increse like mousewheel if were alredy moving in that difection*/
+                               fly->axis= 2;
+                               break;
+                       case FLY_MODAL_DIR_BACKWARD:
+                               if (fly->speed>0) fly->speed= -fly->speed;
+                               else fly->speed -= fly->grid;
+                               fly->axis= 2;
+                               break;
+                       case FLY_MODAL_DIR_LEFT:
+                               if (fly->speed < 0.0f) fly->speed= -fly->speed;
+                               fly->axis= 0;
+                               break;
+                       case FLY_MODAL_DIR_RIGHT:
+                               if (fly->speed > 0.0f) fly->speed= -fly->speed;
+                               fly->axis= 0;
+                               break;
+
+                       case FLY_MODAL_DIR_UP:
+                               if (fly->speed < 0.0f) fly->speed= -fly->speed;
+                               fly->axis= 1;
+                               break;
+
+                       case FLY_MODAL_DIR_DOWN:
+                               if (fly->speed > 0.0f) fly->speed= -fly->speed;
+                               fly->axis= 1;
+                               break;
+
+                       case FLY_MODAL_AXIS_LOCK_X:
+                               if (fly->xlock) fly->xlock=0;
+                               else {
+                                       fly->xlock = 2;
+                                       fly->xlock_momentum = 0.0;
+                               }
+                               break;
+                       case FLY_MODAL_AXIS_LOCK_Z:
+                               if (fly->zlock) fly->zlock=0;
+                               else {
+                                       fly->zlock = 2;
+                                       fly->zlock_momentum = 0.0;
+                               }
+                               break;
+
+                       case FLY_MODAL_PRECISION_ENABLE:
+                               fly->use_precision= TRUE;
+                               break;
+                       case FLY_MODAL_PRECISION_DISABLE:
+                               fly->use_precision= FALSE;
+                               break;
+
+               }
+       }
+}
+
+//int fly_exec(bContext *C, wmOperator *op)
+int flyApply(FlyInfo *fly)
+{
+       /*
+       fly mode - Shift+F
+       a fly loop where the user can move move the view as if they are flying
+       */
+       RegionView3D *rv3d= fly->rv3d;
+       View3D *v3d = fly->v3d;
+       ARegion *ar = fly->ar;
+       Scene *scene= fly->scene;
+
+       float mat[3][3], /* 3x3 copy of the view matrix so we can move allong the view axis */
+       dvec[3]={0,0,0}, /* this is the direction thast added to the view offset per redraw */
+
+       /* Camera Uprighting variables */
+       upvec[3]={0,0,0}, /* stores the view's up vector */
+
+       moffset[2], /* mouse offset from the views center */
+       tmp_quat[4]; /* used for rotating the view */
+
+       int cent_orig[2], /* view center */
+//XXX- can avoid using //      cent[2], /* view center modified */
+       xmargin, ymargin; /* x and y margin are define the safe area where the mouses movement wont rotate the view */
+       unsigned char
+       apply_rotation= 1; /* if the user presses shift they can look about without movinf the direction there looking*/
+
+       /* for recording */
+#if 0 //XXX2.5 todo, get animation recording working again.
+       int playing_anim = 0; //XXX has_screenhandler(G.curscreen, SCREEN_HANDLER_ANIM);
+       int cfra = -1; /*so the first frame always has a key added */
+       char *actname="";
+#endif
+       /* the dist defines a vector that is infront of the offset
+       to rotate the view about.
+       this is no good for fly mode because we
+       want to rotate about the viewers center.
+       but to correct the dist removal we must
+       alter offset so the view doesn't jump. */
+
+       xmargin= ar->winx/20.0f;
+       ymargin= ar->winy/20.0f;
+
+       cent_orig[0]= ar->winrct.xmin + ar->winx/2;
+       cent_orig[1]= ar->winrct.ymin + ar->winy/2;
+
+       {
+
+               /* mouse offset from the center */
+               moffset[0]= fly->mval[0]- ar->winx/2;
+               moffset[1]= fly->mval[1]- ar->winy/2;
+
+               /* enforce a view margin */
+               if (moffset[0]>xmargin)                 moffset[0]-=xmargin;
+               else if (moffset[0] < -xmargin) moffset[0]+=xmargin;
+               else                                                    moffset[0]=0;
+
+               if (moffset[1]>ymargin)                 moffset[1]-=ymargin;
+               else if (moffset[1] < -ymargin) moffset[1]+=ymargin;
+               else                                                    moffset[1]=0;
+
+
+               /* scale the mouse movement by this value - scales mouse movement to the view size
+                * moffset[0]/(ar->winx-xmargin*2) - window size minus margin (same for y)
+                *
+                * the mouse moves isnt linear */
+
+               if(moffset[0]) {
+                       moffset[0] /= ar->winx - (xmargin*2);
+                       moffset[0] *= fabs(moffset[0]);
+               }
+
+               if(moffset[1]) {
+                       moffset[1] /= ar->winy - (ymargin*2);
+                       moffset[1] *= fabs(moffset[1]);
+               }
+
+               /* Should we redraw? */
+               if(fly->speed != 0.0f || moffset[0] || moffset[1] || fly->zlock || fly->xlock || dvec[0] || dvec[1] || dvec[2] ) {
+                       float dvec_tmp[3];
+                       double time_current, time_redraw; /*time how fast it takes for us to redraw, this is so simple scenes dont fly too fast */
+                       float time_redraw_clamped;
+
+                       time_current= PIL_check_seconds_timer();
+                       time_redraw= (float)(time_current - fly->time_lastdraw);
+                       time_redraw_clamped= MIN2(0.05f, time_redraw); /* clamt the redraw time to avoid jitter in roll correction */
+                       fly->time_lastdraw= time_current;
+                       /*fprintf(stderr, "%f\n", time_redraw);*/ /* 0.002 is a small redraw 0.02 is larger */
+
+                       /* Scale the time to use shift to scale the speed down- just like
+                       shift slows many other areas of blender down */
+                       if (fly->use_precision)
+                               fly->speed= fly->speed * (1.0f-time_redraw_clamped);
+
+                       Mat3CpyMat4(mat, rv3d->viewinv);
+
+                       if (fly->pan_view==TRUE) {
+                               /* pan only */
+                               dvec_tmp[0]= -moffset[0];
+                               dvec_tmp[1]= -moffset[1];
+                               dvec_tmp[2]= 0;
+
+                               if (fly->use_precision) {
+                                       dvec_tmp[0] *= 0.1;
+                                       dvec_tmp[1] *= 0.1;
+                               }
+
+                               Mat3MulVecfl(mat, dvec_tmp);
+                               VecMulf(dvec_tmp, time_redraw*200.0 * fly->grid);
+
+                       } else {
+                               float roll; /* similar to the angle between the camera's up and the Z-up, but its very rough so just roll*/
+
+                               /* rotate about the X axis- look up/down */
+                               if (moffset[1]) {
+                                       upvec[0]=1;
+                                       upvec[1]=0;
+                                       upvec[2]=0;
+                                       Mat3MulVecfl(mat, upvec);
+                                       VecRotToQuat( upvec, (float)moffset[1]*-time_redraw*20, tmp_quat); /* Rotate about the relative up vec */
+                                       QuatMul(rv3d->viewquat, rv3d->viewquat, tmp_quat);
+
+                                       if (fly->xlock) fly->xlock = 2; /*check for rotation*/
+                                       if (fly->zlock) fly->zlock = 2;
+                                       fly->xlock_momentum= 0.0f;
+                               }
+
+                               /* rotate about the Y axis- look left/right */
+                               if (moffset[0]) {
+
+                                       /* if we're upside down invert the moffset */
+                                       upvec[0]=0;
+                                       upvec[1]=1;
+                                       upvec[2]=0;
+                                       Mat3MulVecfl(mat, upvec);
+
+                                       if(upvec[2] < 0.0f)
+                                               moffset[0]= -moffset[0];
+
+                                       /* make the lock vectors */
+                                       if (fly->zlock) {
+                                               upvec[0]=0;
+                                               upvec[1]=0;
+                                               upvec[2]=1;
+                                       } else {
+                                               upvec[0]=0;
+                                               upvec[1]=1;
+                                               upvec[2]=0;
+                                               Mat3MulVecfl(mat, upvec);
+                                       }
+
+                                       VecRotToQuat( upvec, (float)moffset[0]*time_redraw*20, tmp_quat); /* Rotate about the relative up vec */
+                                       QuatMul(rv3d->viewquat, rv3d->viewquat, tmp_quat);
+
+                                       if (fly->xlock) fly->xlock = 2;/*check for rotation*/
+                                       if (fly->zlock) fly->zlock = 2;
+                               }
+
+                               if (fly->zlock==2) {
+                                       upvec[0]=1;
+                                       upvec[1]=0;
+                                       upvec[2]=0;
+                                       Mat3MulVecfl(mat, upvec);
+
+                                       /*make sure we have some z rolling*/
+                                       if (fabs(upvec[2]) > 0.00001f) {
+                                               roll= upvec[2]*5;
+                                               upvec[0]=0; /*rotate the view about this axis*/
+                                               upvec[1]=0;
+                                               upvec[2]=1;
+
+                                               Mat3MulVecfl(mat, upvec);
+                                               VecRotToQuat( upvec, roll*time_redraw_clamped*fly->zlock_momentum*0.1, tmp_quat); /* Rotate about the relative up vec */
+                                               QuatMul(rv3d->viewquat, rv3d->viewquat, tmp_quat);
+
+                                               fly->zlock_momentum += 0.05f;
+                                       } else {
+                                               fly->zlock=1; /* dont check until the view rotates again */
+                                               fly->zlock_momentum= 0.0f;
+                                       }
+                               }
+
+                               if (fly->xlock==2 && moffset[1]==0) { /*only apply xcorrect when mouse isnt applying x rot*/
+                                       upvec[0]=0;
+                                       upvec[1]=0;
+                                       upvec[2]=1;
+                                       Mat3MulVecfl(mat, upvec);
+                                       /*make sure we have some z rolling*/
+                                       if (fabs(upvec[2]) > 0.00001) {
+                                               roll= upvec[2] * -5;
+
+                                               upvec[0]= 1.0f; /*rotate the view about this axis*/
+                                               upvec[1]= 0.0f;
+                                               upvec[2]= 0.0f;
+
+                                               Mat3MulVecfl(mat, upvec);
+
+                                               VecRotToQuat( upvec, roll*time_redraw_clamped*fly->xlock_momentum*0.1f, tmp_quat); /* Rotate about the relative up vec */
+                                               QuatMul(rv3d->viewquat, rv3d->viewquat, tmp_quat);
+
+                                               fly->xlock_momentum += 0.05f;
+                                       } else {
+                                               fly->xlock=1; /* see above */
+                                               fly->xlock_momentum= 0.0f;
+                                       }
+                               }
+
+
+                               if (apply_rotation) {
+                                       /* Normal operation */
+                                       /* define dvec, view direction vector */
+                                       dvec_tmp[0]= dvec_tmp[1]= dvec_tmp[2]= 0.0f;
+                                       /* move along the current axis */
+                                       dvec_tmp[fly->axis]= 1.0f;
+
+                                       Mat3MulVecfl(mat, dvec_tmp);
+
+                                       VecMulf(dvec_tmp, fly->speed * time_redraw * 0.25f);
+                               }
+                       }
+
+                       /* impose a directional lag */
+                       VecLerpf(dvec, dvec_tmp, fly->dvec_prev, (1.0f/(1.0f+(time_redraw*5.0f))));
+
+                       if (rv3d->persp==V3D_CAMOB) {
+                               if (v3d->camera->protectflag & OB_LOCK_LOCX)
+                                       dvec[0] = 0.0;
+                               if (v3d->camera->protectflag & OB_LOCK_LOCY)
+                                       dvec[1] = 0.0;
+                               if (v3d->camera->protectflag & OB_LOCK_LOCZ)
+                                       dvec[2] = 0.0;
+                       }
+
+                       VecAddf(rv3d->ofs, rv3d->ofs, dvec);
+#if 0 //XXX2.5
+                       if (fly->zlock && fly->xlock)
+                               headerprint("FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X  on/Z on,   Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
+                       else if (fly->zlock)
+                               headerprint("FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X off/Z on,   Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
+                       else if (fly->xlock)
+                               headerprint("FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X  on/Z off,  Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
+                       else
+                               headerprint("FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X off/Z off,  Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
+#endif
+
+//XXX2.5                       do_screenhandlers(G.curscreen); /* advance the next frame */
+
+                       /* we are in camera view so apply the view ofs and quat to the view matrix and set the camera to the view */
+                       if (rv3d->persp==V3D_CAMOB) {
+                               rv3d->persp= V3D_PERSP; /*set this so setviewmatrixview3d uses the ofs and quat instead of the camera */
+                               setviewmatrixview3d(scene, v3d, rv3d);
+
+                               setcameratoview3d(v3d, rv3d, v3d->camera);
+
+                               {       //XXX - some reason setcameratoview3d doesnt copy, shouldnt not be needed!
+                                       VECCOPY(v3d->camera->loc, rv3d->ofs);
+                                       VecNegf(v3d->camera->loc);
+                               }
+
+                               rv3d->persp= V3D_CAMOB;
+#if 0 //XXX2.5
+                               /* record the motion */
+                               if (IS_AUTOKEY_MODE(NORMAL) && (!playing_anim || cfra != G.scene->r.cfra)) {
+                                       cfra = G.scene->r.cfra;
+
+                                       if (fly->xlock || fly->zlock || moffset[0] || moffset[1]) {
+                                               insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_ROT_X, 0);
+                                               insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_ROT_Y, 0);
+                                               insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_ROT_Z, 0);
+                                       }
+                                       if (fly->speed) {
+                                               insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_LOC_X, 0);
+                                               insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_LOC_Y, 0);
+                                               insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_LOC_Z, 0);
+                                       }
+                               }
+#endif
+                       }
+//XXX2.5                       scrarea_do_windraw(curarea);
+//XXX2.5                       screen_swapbuffers();
+               } else
+                       /*were not redrawing but we need to update the time else the view will jump */
+                       fly->time_lastdraw= PIL_check_seconds_timer();
+               /* end drawing */
+               VECCOPY(fly->dvec_prev, dvec);
+       }
+
+/* moved to flyEnd() */
+
+       return OPERATOR_FINISHED;
+}
+
+
+
+static int fly_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       RegionView3D *rv3d= CTX_wm_region_view3d(C);
+       FlyInfo *fly;
+
+       if(rv3d->viewlock)
+               return OPERATOR_CANCELLED;
+
+       fly= MEM_callocN(sizeof(FlyInfo), "FlyOperation");
+
+       op->customdata= fly;
+
+       if(initFlyInfo(C, fly, op, event)==FALSE) {
+               MEM_freeN(op->customdata);
+               return OPERATOR_CANCELLED;
+       }
+
+       flyEvent(fly, event);
+
+       WM_event_add_modal_handler(C, op);
+
+       return OPERATOR_RUNNING_MODAL;
+}
+
+static int fly_cancel(bContext *C, wmOperator *op)
+{
+       FlyInfo *fly = op->customdata;
+
+       fly->state = FLY_CANCEL;
+       flyEnd(C, fly);
+       op->customdata= NULL;
+
+       return OPERATOR_CANCELLED;
+}
+
+static int fly_modal(bContext *C, wmOperator *op, wmEvent *event)
+{
+       int exit_code;
+
+       FlyInfo *fly = op->customdata;
+
+       fly->redraw= 0;
+
+       flyEvent(fly, event);
+
+       if(event->type==TIMER)
+               flyApply(fly);
+
+       if(fly->redraw) {;
+               ED_region_tag_redraw(CTX_wm_region(C));
+       }
+
+       exit_code = flyEnd(C, fly);
+
+       if(exit_code!=OPERATOR_RUNNING_MODAL)
+               ED_region_tag_redraw(CTX_wm_region(C));
+
+       return exit_code;
+}
+
+void VIEW3D_OT_fly(wmOperatorType *ot)
+{
+
+       /* identifiers */
+       ot->name= "Fly Navigation";
+       ot->description= "Interactively fly around the scene.";
+       ot->idname= "VIEW3D_OT_fly";
+
+       /* api callbacks */
+       ot->invoke= fly_invoke;
+       ot->cancel= fly_cancel;
+       ot->modal= fly_modal;
+       ot->poll= ED_operator_view3d_active;
+
+       /* flags */
+       ot->flag= OPTYPE_BLOCKING;
+
+}
+
 /* ************************************** */
 
 void view3d_align_axis_to_vector(View3D *v3d, RegionView3D *rv3d, int axisidx, float vec[3])