diff options
-rw-r--r-- | intern/ghost/GHOST_Types.h | 24 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_NDOFManager.cpp | 96 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_NDOFManager.h | 9 | ||||
-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 | ||||
-rw-r--r-- | source/blender/windowmanager/WM_types.h | 27 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_event_system.c | 2 |
8 files changed, 361 insertions, 131 deletions
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index bc731a43ae7..85f73a25b47 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -434,14 +434,24 @@ typedef struct { GHOST_TUns8 **strings; } GHOST_TStringArray; +typedef enum { + GHOST_kNotStarted, + GHOST_kStarting, + GHOST_kInProgress, + GHOST_kFinishing, + GHOST_kFinished + } GHOST_TProgress; + typedef struct { - /** N-degree of freedom device data v3 [GSoC 2010]*/ - /* Each component normally ranges from -1 to +1, but can exceed that. */ - float tx, ty, tz; /* translation: -x left, +y forward, -z up */ - float rx, ry, rz; /* rotation: - axis = (rx,ry,rz).normalized - amount = (rx,ry,rz).magnitude [in revolutions, 1.0 = 360 deg] */ - float dt; // time since previous NDOF Motion event (or zero if this is the first) + /** N-degree of freedom device data v3 [GSoC 2010] */ + // Each component normally ranges from -1 to +1, but can exceed that. + // These use blender standard view coordinates, with positive rotations being CCW about the axis. + float tx, ty, tz; // translation + float rx, ry, rz; // rotation: + // axis = (rx,ry,rz).normalized + // amount = (rx,ry,rz).magnitude [in revolutions, 1.0 = 360 deg] + float dt; // time since previous NDOF Motion event + GHOST_TProgress progress; // Starting, InProgress or Finishing (for modal handlers) } GHOST_TEventNDOFMotionData; typedef enum { GHOST_kPress, GHOST_kRelease } GHOST_TButtonAction; diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp index 4d2f06f8191..e001540aa95 100644 --- a/intern/ghost/intern/GHOST_NDOFManager.cpp +++ b/intern/ghost/intern/GHOST_NDOFManager.cpp @@ -29,6 +29,12 @@ #include <stdio.h> // for error/info reporting #include <math.h> +#ifdef DEBUG_NDOF_MOTION +// printable version of each GHOST_TProgress value +static const char* progress_string[] = + {"not started","starting","in progress","finishing","finished"}; +#endif + #ifdef DEBUG_NDOF_BUTTONS static const char* ndof_button_names[] = { // used internally, never sent @@ -139,9 +145,10 @@ GHOST_NDOFManager::GHOST_NDOFManager(GHOST_System& sys) , m_buttonCount(0) , m_buttonMask(0) , m_buttons(0) - , m_motionTime(1000) // one full second (operators should filter out such large time deltas) + , m_motionTime(0) , m_prevMotionTime(0) - , m_atRest(true) + , m_motionState(GHOST_kNotStarted) + , m_motionEventPending(false) { // to avoid the rare situation where one triple is updated and // the other is not, initialize them both here: @@ -179,10 +186,16 @@ void GHOST_NDOFManager::setDevice(unsigned short vendor_id, unsigned short produ break; // -- older devices -- - case 0xC623: puts("ndof: SpaceTraveler not supported, please file a bug report"); break; - // no buttons? - case 0xC625: puts("ndof: SpacePilot not supported, please file a bug report"); break; - // 21 buttons + // keep unknown device type so rogue button events will get discarded + // "mystery device" owners can help build another HID_map for their hardware + case 0xC623: + puts("ndof: SpaceTraveler not supported, please file a bug report"); + m_buttonCount = 8; + break; + case 0xC625: + puts("ndof: SpacePilot not supported, please file a bug report"); + m_buttonCount = 21; + break; default: printf("ndof: unknown Logitech product %04hx\n", product_id); } @@ -198,18 +211,41 @@ void GHOST_NDOFManager::setDevice(unsigned short vendor_id, unsigned short produ #endif } +void GHOST_NDOFManager::updateMotionState() + { + if (m_motionEventPending) + return; + + switch (m_motionState) + { + case GHOST_kFinished: + case GHOST_kNotStarted: + m_motionState = GHOST_kStarting; + break; + case GHOST_kStarting: + m_motionState = GHOST_kInProgress; + break; + default: + // InProgress remains InProgress + // should never be Finishing + break; + } + + m_motionEventPending = true; + } + void GHOST_NDOFManager::updateTranslation(short t[3], GHOST_TUns64 time) { memcpy(m_translation, t, sizeof(m_translation)); m_motionTime = time; - m_atRest = false; + updateMotionState(); } void GHOST_NDOFManager::updateRotation(short r[3], GHOST_TUns64 time) { memcpy(m_rotation, r, sizeof(m_rotation)); m_motionTime = time; - m_atRest = false; + updateMotionState(); } void GHOST_NDOFManager::sendButtonEvent(NDOF_ButtonT button, bool press, GHOST_TUns64 time, GHOST_IWindow* window) @@ -290,7 +326,7 @@ void GHOST_NDOFManager::updateButtons(int button_bits, GHOST_TUns64 time) int diff = m_buttons ^ button_bits; - for (int button_number = 0; button_number <= 31; ++button_number) + for (int button_number = 0; button_number < m_buttonCount; ++button_number) { int mask = 1 << button_number; @@ -302,15 +338,21 @@ void GHOST_NDOFManager::updateButtons(int button_bits, GHOST_TUns64 time) } } -static bool atHomePosition(GHOST_TEventNDOFMotionData* ndof, float threshold) +static bool atHomePosition(GHOST_TEventNDOFMotionData* ndof) { - #define HOME(foo) (fabsf(ndof->foo) < threshold) + #define HOME(foo) (ndof->foo == 0) return HOME(tx) && HOME(ty) && HOME(tz) && HOME(rx) && HOME(ry) && HOME(rz); } +static bool nearHomePosition(GHOST_TEventNDOFMotionData* ndof, float threshold) + { + #define HOME1(foo) (fabsf(ndof->foo) < threshold) + return HOME1(tx) && HOME1(ty) && HOME1(tz) && HOME1(rx) && HOME1(ry) && HOME1(rz); + } + bool GHOST_NDOFManager::sendMotionEvent() { - if (m_atRest) + if (m_motionState == GHOST_kFinished || m_motionState == GHOST_kNotStarted) return false; GHOST_IWindow* window = m_system.getWindowManager()->getActiveWindow(); @@ -320,7 +362,7 @@ bool GHOST_NDOFManager::sendMotionEvent() const float scale = 1.f / 350.f; // 3Dconnexion devices send +/- 350 usually - // possible future enhancement + // probable future enhancement // scale *= m_sensitivity; data->tx = scale * m_translation[0]; @@ -331,19 +373,35 @@ bool GHOST_NDOFManager::sendMotionEvent() data->ry = scale * m_rotation[1]; data->rz = scale * m_rotation[2]; - data->dt = 0.001f * (m_motionTime - m_prevMotionTime); // in seconds + if (m_motionState == GHOST_kStarting) + // prev motion time will be ancient, so just make up something reasonable + data->dt = 0.0125f; + else + data->dt = 0.001f * (m_motionTime - m_prevMotionTime); // in seconds m_prevMotionTime = m_motionTime; + // 'at rest' test goes at the end so that the first 'rest' event gets sent + if (atHomePosition(data)) +// if (nearHomePosition(data, 0.05f)) // Linux & Windows have trouble w/ calibration + { + data->progress = GHOST_kFinishing; + // for internal state, skip Finishing & jump to Finished + m_motionState = GHOST_kFinished; + } + else + data->progress = m_motionState; // Starting or InProgress + #ifdef DEBUG_NDOF_MOTION - printf("ndof: T=(%.2f,%.2f,%.2f) R=(%.2f,%.2f,%.2f) dt=%.3f\n", - data->tx, data->ty, data->tz, data->rx, data->ry, data->rz, data->dt); + printf("ndof %s: T=(%.2f,%.2f,%.2f) R=(%.2f,%.2f,%.2f) dt=%.3f\n", + progress_string[data->progress], + data->tx, data->ty, data->tz, + data->rx, data->ry, data->rz, + data->dt); #endif m_system.pushEvent(event); - - // 'at rest' test goes at the end so that the first 'rest' event gets sent - m_atRest = atHomePosition(data, 0.05f); + m_motionEventPending = false; return true; } diff --git a/intern/ghost/intern/GHOST_NDOFManager.h b/intern/ghost/intern/GHOST_NDOFManager.h index 155510d6d7f..cabff22fca7 100644 --- a/intern/ghost/intern/GHOST_NDOFManager.h +++ b/intern/ghost/intern/GHOST_NDOFManager.h @@ -27,9 +27,7 @@ #include "GHOST_System.h" -// --- the following type definitions will find a home somewhere else once finished --- - -//#define DEBUG_NDOF_MOTION +#define DEBUG_NDOF_MOTION #define DEBUG_NDOF_BUTTONS typedef enum { NDOF_UnknownDevice, NDOF_SpaceNavigator, NDOF_SpaceExplorer, NDOF_SpacePilotPro } NDOF_DeviceT; @@ -120,7 +118,7 @@ protected: private: void sendButtonEvent(NDOF_ButtonT, bool press, GHOST_TUns64 time, GHOST_IWindow*); void sendKeyEvent(GHOST_TKey, bool press, GHOST_TUns64 time, GHOST_IWindow*); - + void updateMotionState(); NDOF_DeviceT m_deviceType; int m_buttonCount; @@ -132,7 +130,8 @@ private: GHOST_TUns64 m_motionTime; // in milliseconds GHOST_TUns64 m_prevMotionTime; // time of most recent Motion event sent - bool m_atRest; + GHOST_TProgress m_motionState; + bool m_motionEventPending; }; #endif 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); diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 26c394a2ad3..7476410ec19 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -377,17 +377,24 @@ typedef struct wmTabletData { float Ytilt; /* as above */ } wmTabletData; -typedef struct { +typedef enum { // motion progress, for modal handlers + P_NOT_STARTED, + P_STARTING, // <-- + P_IN_PROGRESS, // <-- only these are sent for NDOF motion + P_FINISHING, // <-- + P_FINISHED + } wmProgress; + +typedef struct wmNDOFMotionData { /* awfully similar to GHOST_TEventNDOFMotionData... */ - - /* Each component normally ranges from -1 to +1, but can exceed that. */ - - float tx, ty, tz; /* translation: -x left, +y forward, -z up */ - float rx, ry, rz; /* rotation: - axis = (rx,ry,rz).normalized - amount = (rx,ry,rz).magnitude [in revolutions, 1.0 = 360 deg] */ - - float dt; // time since previous NDOF Motion event (or zero if this is the first) + // Each component normally ranges from -1 to +1, but can exceed that. + // These use blender standard view coordinates, with positive rotations being CCW about the axis. + float tx, ty, tz; // translation + float rx, ry, rz; // rotation: + // axis = (rx,ry,rz).normalized + // amount = (rx,ry,rz).magnitude [in revolutions, 1.0 = 360 deg] + float dt; // time since previous NDOF Motion event + wmProgress progress; // is this the first event, the last, or one of many in between? } wmNDOFMotionData; typedef struct wmTimer { diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index b41eebc5298..c2df53c9e91 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -2324,6 +2324,8 @@ static void attach_ndof_data(wmEvent* event, const GHOST_TEventNDOFMotionData* g data->dt = ghost->dt; + data->progress = (wmProgress) ghost->progress; + event->custom = EVT_DATA_NDOF_MOTION; event->customdata = data; event->customdatafree = 1; |