diff options
author | Mike Erwin <significant.bit@gmail.com> | 2011-07-15 01:20:45 +0400 |
---|---|---|
committer | Mike Erwin <significant.bit@gmail.com> | 2011-07-15 01:20:45 +0400 |
commit | cc1ba4569ccdb77a9371140def316caecac71da5 (patch) | |
tree | cc1329237f33e5c586177f60e46000943ebc99f6 /source/blender/editors/space_view3d | |
parent | 44d2e6eb109889f49fb9935d05ef201127d15805 (diff) |
more consistent and modal-friendly ndof events, fly mode v1
Diffstat (limited to 'source/blender/editors/space_view3d')
-rw-r--r-- | source/blender/editors/space_view3d/view3d_edit.c | 182 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/view3d_fly.c | 149 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/view3d_intern.h | 3 |
3 files changed, 244 insertions, 90 deletions
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index fc84944da02..bfbff8a4906 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -929,10 +929,30 @@ void VIEW3D_OT_rotate(wmOperatorType *ot) ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER; } -#if 0 // NDOF utility functions +// NDOF utility functions +// (should these functions live in this file?) +float ndof_to_angle_axis(struct wmNDOFMotionData* ndof, float axis[3]) + { + const float x = ndof->rx; + const float y = ndof->ry; + const float z = ndof->rz; + + float angular_velocity = sqrtf(x*x + y*y + z*z); + float angle = ndof->dt * angular_velocity; + + float scale = 1.f / angular_velocity; + + // normalize + axis[0] = scale * x; + axis[1] = scale * y; + axis[2] = scale * z; + + return angle; + } + +#if 0 // unused utility functions // returns angular velocity (0..1), fills axis of rotation -// (shouldn't live in this file!) -static float ndof_to_angle_axis(const float ndof[3], float axis[3]) +float ndof_to_angle_axis(const float ndof[3], float axis[3]) { const float x = ndof[0]; const float y = ndof[1]; @@ -960,7 +980,7 @@ static float ndof_to_angular_velocity(wmNDOFMotionData* ndof) } #endif -static void ndof_to_quat(wmNDOFMotionData* ndof, float q[4]) +void ndof_to_quat(struct wmNDOFMotionData* ndof, float q[4]) { const float x = ndof->rx; const float y = ndof->ry; @@ -988,6 +1008,8 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, wmEvent *event) RegionView3D* rv3d = CTX_wm_region_view3d(C); wmNDOFMotionData* ndof = (wmNDOFMotionData*) event->customdata; + const float dt = ndof->dt; + // tune these until everything feels right const float rot_sensitivity = 1.f; const float zoom_sensitivity = 1.f; @@ -996,12 +1018,6 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, wmEvent *event) // rather have bool, but... int has_rotation = rv3d->viewlock != RV3D_LOCKED && (ndof->rx || ndof->ry || ndof->rz); - float dt = ndof->dt; - if (dt > 0.25f) - /* this is probably the first event for this motion, so set dt to something reasonable */ - /* TODO: replace such guesswork with a flag or field from the NDOF manager */ - ndof->dt = dt = 0.0125f; - //#define DEBUG_NDOF_MOTION #ifdef DEBUG_NDOF_MOTION printf("ndof: T=(%.2f,%.2f,%.2f) R=(%.2f,%.2f,%.2f) dt=%.3f delivered to 3D view\n", @@ -1086,41 +1102,109 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_FINISHED; } -#if 0 // not ready +#if 0 +// statics for controlling rv3d->dist corrections. +// viewmoveNDOF zeros and adjusts rv3d->ofs. +// viewmove restores based on dz_flag state. + +static int dz_flag = 0; +static float m_dist; + +static void mouse_rotation_workaround_push(RegionView3D* rv3d) +{ + // This is due to a side effect of the original + // mouse view rotation code. The rotation point is + // set a distance in front of the viewport to + // make rotating with the mouse look better. + // The distance effect is written at a low level + // in the view management instead of the mouse + // view function. This means that all other view + // movement devices must subtract this from their + // view transformations. + + float mat[3][3]; + float upvec[3]; + + if(rv3d->dist != 0.0) { + dz_flag = 1; + m_dist = rv3d->dist; + upvec[0] = upvec[1] = 0; + upvec[2] = rv3d->dist; + copy_m3_m4(mat, rv3d->viewinv); + mul_m3_v3(mat, upvec); + sub_v3_v3(rv3d->ofs, upvec); + rv3d->dist = 0.0; + } + + // this is still needed in version 2.5 [mce] + // warning! current viewmove does not look at dz_flag or m_dist + // don't expect 2D mouse to work properly right after using 3D mouse +} + +static void mouse_rotation_workaround_pop(RegionView3D* rv3d) +{ + if (dz_flag) { + dz_flag = 0; + rv3d->dist = m_dist; + } +} + static int ndof_fly_invoke(bContext *C, wmOperator *op, wmEvent *event) { RegionView3D* rv3d = CTX_wm_region_view3d(C); wmNDOFMotionData* ndof = (wmNDOFMotionData*) event->customdata; - const int shouldRotate = 0, shouldMove = 1; + const int shouldRotate = 1, shouldTranslate = 0; + + const float dt = ndof->dt; - float dt = ndof->dt; - if (dt > 0.25f) - /* this is probably the first event for this motion, so set dt to something reasonable */ - /* TODO: replace such guesswork with a flag or field from the NDOF manager */ - ndof->dt = dt = 0.0125f; + float view_inv[4]; + invert_qt_qt(view_inv, rv3d->viewquat); if (shouldRotate) { const float turn_sensitivity = 1.f; float rot[4]; + float view_inv_conj[4]; + mouse_rotation_workaround_push(rv3d); + ndof_to_quat(ndof, rot); + copy_qt_qt(view_inv_conj, view_inv); + conjugate_qt(view_inv_conj); + + // transform rotation from view to world coordinates + mul_qt_qtqt(rot, view_inv, rot); + mul_qt_qtqt(rot, rot, view_inv_conj); + + // apply rotation to view offset (focal point) + mul_qt_v3(rot, rv3d->ofs); +// mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot); + rv3d->view = RV3D_VIEW_USER; } - if (shouldMove) + if (shouldTranslate) { const float forward_sensitivity = 1.f; const float vertical_sensitivity = 1.f; const float lateral_sensitivity = 1.f; - + float trans[3] = { - lateral_sensitivity * dt * ndof->tx, - vertical_sensitivity * dt * ndof->ty, - forward_sensitivity * rv3d->dist * dt * ndof->tz + lateral_sensitivity * ndof->tx, + vertical_sensitivity * ndof->ty, + forward_sensitivity * ndof->tz }; + +// mul_v3_fl(trans, rv3d->dist * dt); + mul_v3_fl(trans, dt); + + /* transform motion from view to world coordinates */ + mul_qt_v3(view_inv, trans); + + /* move center of view opposite of hand motion (this is camera mode, not object mode) */ + sub_v3_v3(rv3d->ofs, trans); } ED_region_tag_redraw(CTX_wm_region(C)); @@ -1141,9 +1225,7 @@ static void getndof(wmNDOFMotionData* indof, float* outdof) const float vertical_sensitivity = 1.6f; const float lateral_sensitivity = 2.5f; - const float dt = (indof->dt < 0.25f) ? indof->dt : 0.0125f; - // this is probably the first event for this motion, so set dt to something reasonable - // TODO: replace such guesswork with a flag or field from the NDOF manager + const float dt = indof->dt; outdof[0] = lateral_sensitivity * dt * indof->tx; outdof[1] = vertical_sensitivity * dt * indof->ty; @@ -1154,51 +1236,6 @@ static void getndof(wmNDOFMotionData* indof, float* outdof) outdof[5] = turn_sensitivity * dt * indof->rz; } -// statics for controlling rv3d->dist corrections. -// viewmoveNDOF zeros and adjusts rv3d->ofs. -// viewmove restores based on dz_flag state. - -static int dz_flag = 0; -static float m_dist; - -static void mouse_rotation_workaround_push(RegionView3D* rv3d) -{ - // This is due to a side effect of the original - // mouse view rotation code. The rotation point is - // set a distance in front of the viewport to - // make rotating with the mouse look better. - // The distance effect is written at a low level - // in the view management instead of the mouse - // view function. This means that all other view - // movement devices must subtract this from their - // view transformations. - - float mat[3][3]; - float upvec[3]; - - if(rv3d->dist != 0.0) { - dz_flag = 1; - m_dist = rv3d->dist; - upvec[0] = upvec[1] = 0; - upvec[2] = rv3d->dist; - copy_m3_m4(mat, rv3d->viewinv); - mul_m3_v3(mat, upvec); - sub_v3_v3(rv3d->ofs, upvec); - rv3d->dist = 0.0; - } - - // this is still needed in version 2.5 [mce] - // warning! current viewmove does not look at dz_flag or m_dist - // don't expect 2D mouse to work properly right after using 3D mouse -} - -static void mouse_rotation_workaround_pop(RegionView3D* rv3d) -{ - if (dz_flag) { - dz_flag = 0; - rv3d->dist = m_dist; - } -} static int ndof_oldfly_invoke(bContext *C, wmOperator *op, wmEvent *event) { @@ -1254,7 +1291,7 @@ static int ndof_oldfly_invoke(bContext *C, wmOperator *op, wmEvent *event) // translate the view sub_v3_v3(rv3d->ofs, tvec); - mouse_rotation_workaround_pop(rv3d); +// mouse_rotation_workaround_pop(rv3d); // back to 2.5 land! ED_region_tag_redraw(CTX_wm_region(C)); @@ -1272,8 +1309,9 @@ void VIEW3D_OT_ndof(struct wmOperatorType *ot) ot->idname = "VIEW3D_OT_ndof"; /* api callbacks */ -// ot->invoke = ndof_oldfly_invoke; ot->invoke = ndof_orbit_invoke; +// ot->invoke = ndof_fly_invoke; +// ot->invoke = ndof_oldfly_invoke; ot->poll = ED_operator_view3d_active; /* flags */ diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c index ed1ed5b3881..00adfa13e28 100644 --- a/source/blender/editors/space_view3d/view3d_fly.c +++ b/source/blender/editors/space_view3d/view3d_fly.c @@ -158,7 +158,9 @@ typedef struct FlyInfo { short state; short use_precision; short redraw; - int mval[2]; + + int mval[2]; /* latest 2D mouse values */ + wmNDOFMotionData* ndof; /* latest 3D mouse values */ /* fly state state */ float speed; /* the speed the view is moving per redraw */ @@ -257,6 +259,8 @@ static int initFlyInfo (bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *even fly->ar = CTX_wm_region(C); fly->scene= CTX_data_scene(C); + puts("\n-- fly begin --"); + if(fly->rv3d->persp==RV3D_CAMOB && fly->v3d->camera->id.lib) { BKE_report(op->reports, RPT_ERROR, "Cannot fly a camera from an external library"); return FALSE; @@ -282,12 +286,14 @@ static int initFlyInfo (bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *even fly->zlock_momentum=0.0f; fly->grid= 1.0f; fly->use_precision= 0; + fly->redraw= 1; fly->dvec_prev[0]= fly->dvec_prev[1]= fly->dvec_prev[2]= 0.0f; fly->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f); VECCOPY2D(fly->mval, event->mval) + fly->ndof = NULL; fly->time_lastdraw= fly->time_lastwheel= PIL_check_seconds_timer(); @@ -329,8 +335,17 @@ static int initFlyInfo (bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *even /* perspective or ortho */ if (fly->rv3d->persp==RV3D_ORTHO) fly->rv3d->persp= RV3D_PERSP; /*if ortho projection, make perspective */ + copy_qt_qt(fly->rot_backup, fly->rv3d->viewquat); copy_v3_v3(fly->ofs_backup, fly->rv3d->ofs); + + /* 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. */ + fly->rv3d->dist= 0.0f; upvec[2]= fly->dist_backup; /*x and y are 0*/ @@ -338,7 +353,6 @@ static int initFlyInfo (bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *even sub_v3_v3(fly->rv3d->ofs, upvec); /*Done with correcting for the dist*/ } - /* center the mouse, probably the UI mafia are against this but without its quite annoying */ WM_cursor_warp(CTX_wm_window(C), fly->ar->winrct.xmin + fly->ar->winx/2, fly->ar->winrct.ymin + fly->ar->winy/2); @@ -356,6 +370,8 @@ static int flyEnd(bContext *C, FlyInfo *fly) if(fly->state == FLY_RUNNING) return OPERATOR_RUNNING_MODAL; + puts("\n-- fly end --"); + WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), fly->timer); ED_region_draw_cb_exit(fly->ar->type, fly->draw_handle_pixel); @@ -401,6 +417,9 @@ static int flyEnd(bContext *C, FlyInfo *fly) if(fly->obtfm) MEM_freeN(fly->obtfm); + if(fly->ndof) + MEM_freeN(fly->ndof); + if(fly->state == FLY_CONFIRM) { MEM_freeN(fly); return OPERATOR_FINISHED; @@ -412,12 +431,46 @@ static int flyEnd(bContext *C, FlyInfo *fly) static void flyEvent(FlyInfo *fly, wmEvent *event) { - if (event->type == TIMER && event->customdata == fly->timer) { - fly->redraw = 1; - } - else if (event->type == MOUSEMOVE) { + if (event->type == MOUSEMOVE) { VECCOPY2D(fly->mval, event->mval); - } /* handle modal keymap first */ + } + else if (event->type == NDOF_MOTION) { + // do these automagically get delivered? yes. + // puts("ndof motion detected in fly mode!"); + // static const char* tag_name = "3D mouse position"; + + wmNDOFMotionData* incoming_ndof = (wmNDOFMotionData*) event->customdata; + switch (incoming_ndof->progress) + { + case P_STARTING: + // start keeping track of 3D mouse position + puts("start keeping track of 3D mouse position"); + // fall through... + case P_IN_PROGRESS: + // update 3D mouse position + putchar('.'); fflush(stdout); + if (fly->ndof == NULL) + // fly->ndof = MEM_mallocN(sizeof(wmNDOFMotionData), tag_name); + fly->ndof = MEM_dupallocN(incoming_ndof); + // fly->ndof = malloc(sizeof(wmNDOFMotionData)); + else + memcpy(fly->ndof, incoming_ndof, sizeof(wmNDOFMotionData)); + break; + case P_FINISHING: + // stop keeping track of 3D mouse position + puts("stop keeping track of 3D mouse position"); + if (fly->ndof) + { + MEM_freeN(fly->ndof); + // free(fly->ndof); + fly->ndof = NULL; + } + break; + default: + ; // should always be one of the above 3 + } + } + /* handle modal keymap first */ else if (event->type == EVT_MODAL_MAP) { switch (event->val) { case FLY_MODAL_CANCEL: @@ -528,7 +581,6 @@ static void flyEvent(FlyInfo *fly, wmEvent *event) case FLY_MODAL_PRECISION_DISABLE: fly->use_precision= FALSE; break; - } } } @@ -567,16 +619,12 @@ static int flyApply(bContext *C, FlyInfo *fly) unsigned char apply_rotation= 1; /* if the user presses shift they can look about without movinf the direction there looking*/ + static unsigned int iteration = 1; + printf("fly timer %d\n", iteration++); + if(fly->root_parent) ED_view3d_to_m4(prev_view_mat, fly->rv3d->ofs, fly->rv3d->viewquat, fly->rv3d->dist); - /* 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; @@ -622,6 +670,8 @@ static int flyApply(bContext *C, FlyInfo *fly) float time_redraw; float time_redraw_clamped; + fly->redraw= 1; + 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 */ @@ -854,11 +904,69 @@ static int flyApply(bContext *C, FlyInfo *fly) copy_v3_v3(fly->dvec_prev, dvec); } -/* moved to flyEnd() */ - return OPERATOR_FINISHED; } +static int flyApply_ndof(bContext *C, FlyInfo *fly) +{ + // shorthand for oft-used variables + wmNDOFMotionData* ndof = fly->ndof; + const float dt = ndof->dt; + RegionView3D* rv3d = fly->rv3d; + + const int shouldRotate = 1, shouldTranslate = 1; + + float view_inv[4]; + invert_qt_qt(view_inv, rv3d->viewquat); + + if (shouldRotate) + { + const float turn_sensitivity = 1.f; + + float rotation[4]; + float axis[3]; + float angle = turn_sensitivity * ndof_to_angle_axis(ndof, axis); + + // transform rotation axis from view to world coordinates + mul_qt_v3(view_inv, axis); + + // apply rotation to view + axis_angle_to_quat(rotation, axis, angle); + mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rotation); + + rv3d->view = RV3D_VIEW_USER; + + fly->redraw = 1; + } + + if (shouldTranslate) + { + const float forward_sensitivity = 1.f; + const float vertical_sensitivity = 0.4f; + const float lateral_sensitivity = 0.6f; + + float speed = 10.f; // blender units per second + // ^^ this is ok for default cube scene, but should scale with.. something + + float trans[3] = { + lateral_sensitivity * ndof->tx, + vertical_sensitivity * ndof->ty, + forward_sensitivity * ndof->tz + }; + + mul_v3_fl(trans, speed * dt); + + // transform motion from view to world coordinates + mul_qt_v3(view_inv, trans); + + // move center of view opposite of hand motion (this is camera mode, not object mode) + sub_v3_v3(rv3d->ofs, trans); + + fly->redraw = 1; + } + + return OPERATOR_FINISHED; +} static int fly_invoke(bContext *C, wmOperator *op, wmEvent *event) @@ -908,7 +1016,12 @@ static int fly_modal(bContext *C, wmOperator *op, wmEvent *event) flyEvent(fly, event); - if(event->type==TIMER && event->customdata == fly->timer) + if (fly->ndof) // 3D mouse overrules [2D mouse + timer] + { + if (event->type==NDOF_MOTION) + flyApply_ndof(C, fly); + } + else if (event->type==TIMER && event->customdata == fly->timer) flyApply(C, fly); do_draw |= fly->redraw; diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 1a148481031..3658a481bdf 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -51,6 +51,7 @@ struct ARegionType; struct bPoseChannel; struct bAnimVizSettings; struct bMotionPath; +struct wmNDOFMotionData; #define BL_NEAR_CLIP 0.001 @@ -92,6 +93,8 @@ void VIEW3D_OT_zoom_border(struct wmOperatorType *ot); void VIEW3D_OT_drawtype(struct wmOperatorType *ot); void view3d_boxview_copy(ScrArea *sa, ARegion *ar); +void ndof_to_quat(struct wmNDOFMotionData* ndof, float q[4]); +float ndof_to_angle_axis(struct wmNDOFMotionData* ndof, float axis[3]); /* view3d_fly.c */ void view3d_keymap(struct wmKeyConfig *keyconf); |