fly mode back as a modal operator view3d.fly

- 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.
This commit is contained in:
2009-09-23 11:26:16 +00:00
parent 9e110a6d00
commit e2a7168e96
6 changed files with 822 additions and 8 deletions

View 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'

View 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);

View 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);
}

View 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);

View 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);
}

View File

@@ -56,9 +56,11 @@
#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])