diff options
author | Mike Erwin <significant.bit@gmail.com> | 2011-07-19 02:42:09 +0400 |
---|---|---|
committer | Mike Erwin <significant.bit@gmail.com> | 2011-07-19 02:42:09 +0400 |
commit | 5f47123fded84fed85d6a0713f814c99f68c1ce7 (patch) | |
tree | 7e9aa67a80fa72317d52ef47e49015885779ac1b /intern/ghost | |
parent | 3ad978ea8ec425e000fd1d79944b47b037f2f3f6 (diff) |
consistent Starting/InProgress/Finishing ndof events with dead-zone filtering
Diffstat (limited to 'intern/ghost')
-rw-r--r-- | intern/ghost/intern/GHOST_NDOFManager.cpp | 117 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_NDOFManager.h | 18 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_NDOFManagerX11.cpp | 2 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_SystemX11.cpp | 5 |
4 files changed, 91 insertions, 51 deletions
diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp index e001540aa95..06c792128cd 100644 --- a/intern/ghost/intern/GHOST_NDOFManager.cpp +++ b/intern/ghost/intern/GHOST_NDOFManager.cpp @@ -149,6 +149,7 @@ GHOST_NDOFManager::GHOST_NDOFManager(GHOST_System& sys) , m_prevMotionTime(0) , m_motionState(GHOST_kNotStarted) , m_motionEventPending(false) + , m_deadZone(0.f) { // to avoid the rare situation where one triple is updated and // the other is not, initialize them both here: @@ -201,7 +202,7 @@ void GHOST_NDOFManager::setDevice(unsigned short vendor_id, unsigned short produ } break; default: - printf("ndof: unknown vendor %04hx\n", vendor_id); + printf("ndof: unknown device %04hx:%04hx\n", vendor_id, product_id); } m_buttonMask = ~(-1 << m_buttonCount); @@ -211,41 +212,18 @@ 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; - updateMotionState(); + m_motionEventPending = true; } void GHOST_NDOFManager::updateRotation(short r[3], GHOST_TUns64 time) { memcpy(m_rotation, r, sizeof(m_rotation)); m_motionTime = time; - updateMotionState(); + m_motionEventPending = true; } void GHOST_NDOFManager::sendButtonEvent(NDOF_ButtonT button, bool press, GHOST_TUns64 time, GHOST_IWindow* window) @@ -338,6 +316,20 @@ void GHOST_NDOFManager::updateButtons(int button_bits, GHOST_TUns64 time) } } +void GHOST_NDOFManager::setDeadZone(float dz) + { + if (dz < 0.f) + // negative values don't make sense, so clamp at zero + dz = 0.f; + else if (dz > 0.5f) + // warn the rogue user/programmer, but allow it + printf("ndof: dead zone of %.2f is rather high...\n", dz); + + m_deadZone = dz; + + printf("ndof: dead zone set to %.2f\n", dz); + } + static bool atHomePosition(GHOST_TEventNDOFMotionData* ndof) { #define HOME(foo) (ndof->foo == 0) @@ -346,16 +338,25 @@ static bool atHomePosition(GHOST_TEventNDOFMotionData* ndof) 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); + if (threshold == 0.f) + return atHomePosition(ndof); + else + { + #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_motionState == GHOST_kFinished || m_motionState == GHOST_kNotStarted) + if (!m_motionEventPending) return false; + m_motionEventPending = false; // any pending motion is handled right now + GHOST_IWindow* window = m_system.getWindowManager()->getActiveWindow(); + if (window == NULL) + return false; // delivery will fail, so don't bother sending GHOST_EventNDOFMotion* event = new GHOST_EventNDOFMotion(m_motionTime, window); GHOST_TEventNDOFMotionData* data = (GHOST_TEventNDOFMotionData*) event->getData(); @@ -363,7 +364,7 @@ bool GHOST_NDOFManager::sendMotionEvent() const float scale = 1.f / 350.f; // 3Dconnexion devices send +/- 350 usually // probable future enhancement - // scale *= m_sensitivity; + // scale *= U.ndof_sensitivity; data->tx = scale * m_translation[0]; data->ty = scale * m_translation[1]; @@ -373,35 +374,57 @@ bool GHOST_NDOFManager::sendMotionEvent() data->ry = scale * m_rotation[1]; data->rz = scale * m_rotation[2]; - 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 + data->dt = 0.001f * (m_motionTime - m_prevMotionTime); // in seconds - m_prevMotionTime = m_motionTime; + bool handMotion = !nearHomePosition(data, m_deadZone); - // '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 + // determine what kind of motion event to send (Starting, InProgress, Finishing) + // and where that leaves this NDOF manager (NotStarted, InProgress, Finished) + switch (m_motionState) { - data->progress = GHOST_kFinishing; - // for internal state, skip Finishing & jump to Finished - m_motionState = GHOST_kFinished; + case GHOST_kNotStarted: + case GHOST_kFinished: + if (handMotion) + { + data->progress = GHOST_kStarting; + m_motionState = GHOST_kInProgress; + // prev motion time will be ancient, so just make up something reasonable + data->dt = 0.0125f; + } + else + { + // send no event and keep current state + delete event; + return false; + } + break; + case GHOST_kInProgress: + if (handMotion) + { + data->progress = GHOST_kInProgress; + // keep InProgress state + } + else + { + data->progress = GHOST_kFinishing; + m_motionState = GHOST_kFinished; + } + break; } - else - data->progress = m_motionState; // Starting or InProgress #ifdef DEBUG_NDOF_MOTION - printf("ndof %s: T=(%.2f,%.2f,%.2f) R=(%.2f,%.2f,%.2f) dt=%.3f\n", - progress_string[data->progress], + printf("ndof motion sent -- %s\n", progress_string[data->progress]); + + // show details about this motion event + printf(" 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); #endif m_system.pushEvent(event); - m_motionEventPending = false; + + m_prevMotionTime = m_motionTime; return true; } diff --git a/intern/ghost/intern/GHOST_NDOFManager.h b/intern/ghost/intern/GHOST_NDOFManager.h index 79e3a4eb4c8..9c67daa4412 100644 --- a/intern/ghost/intern/GHOST_NDOFManager.h +++ b/intern/ghost/intern/GHOST_NDOFManager.h @@ -30,7 +30,12 @@ // #define DEBUG_NDOF_MOTION #define DEBUG_NDOF_BUTTONS -typedef enum { NDOF_UnknownDevice, NDOF_SpaceNavigator, NDOF_SpaceExplorer, NDOF_SpacePilotPro } NDOF_DeviceT; +typedef enum { + NDOF_UnknownDevice, // <-- motion will work fine, buttons are ignored + NDOF_SpaceNavigator, + NDOF_SpaceExplorer, + NDOF_SpacePilotPro + } NDOF_DeviceT; // NDOF device button event types typedef enum { @@ -50,6 +55,7 @@ typedef enum { NDOF_BUTTON_ISO1, NDOF_BUTTON_ISO2, // 90 degree rotations + // these don't all correspond to physical buttons NDOF_BUTTON_ROLL_CW, NDOF_BUTTON_ROLL_CCW, NDOF_BUTTON_SPIN_CW, @@ -63,6 +69,7 @@ typedef enum { NDOF_BUTTON_PLUS, NDOF_BUTTON_MINUS, // general-purpose buttons + // TODO: expose these to keymap editor so users can assign functions NDOF_BUTTON_1, NDOF_BUTTON_2, NDOF_BUTTON_3, @@ -90,6 +97,12 @@ public: // use standard USB/HID identifiers void setDevice(unsigned short vendor_id, unsigned short product_id); + // filter out small/accidental/uncalibrated motions by + // setting up a "dead zone" around home position + // set to 0 to disable + // 0.1 is a safe and reasonable value + void setDeadZone(float); + // the latest raw axis data from the device // NOTE: axis data should be in blender view coordinates // +X is to the right @@ -118,7 +131,6 @@ 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; @@ -130,8 +142,10 @@ private: GHOST_TUns64 m_motionTime; // in milliseconds GHOST_TUns64 m_prevMotionTime; // time of most recent Motion event sent + GHOST_TProgress m_motionState; bool m_motionEventPending; + float m_deadZone; // discard motion with each component < this }; #endif diff --git a/intern/ghost/intern/GHOST_NDOFManagerX11.cpp b/intern/ghost/intern/GHOST_NDOFManagerX11.cpp index cc2b2f785ea..a823c3c8a81 100644 --- a/intern/ghost/intern/GHOST_NDOFManagerX11.cpp +++ b/intern/ghost/intern/GHOST_NDOFManagerX11.cpp @@ -34,6 +34,8 @@ GHOST_NDOFManagerX11::GHOST_NDOFManagerX11(GHOST_System& sys) { m_available = true; + setDeadZone(0.1f); // how to calibrate on Linux? throw away slight motion! + // determine exactly which device is plugged in #define MAX_LINE_LENGTH 100 diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index 4c62e5e62b4..f9b365fd62e 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -597,7 +597,8 @@ GHOST_SystemX11::processEvent(XEvent *xe) { XFocusChangeEvent &xfe = xe->xfocus; - printf("X: focus %s for window %d\n", xfe.type == FocusIn ? "in" : "out", (int) xfe.window); + // TODO: make sure this is the correct place for activate/deactivate + // printf("X: focus %s for window %d\n", xfe.type == FocusIn ? "in" : "out", (int) xfe.window); // May have to look at the type of event and filter some // out. @@ -687,7 +688,7 @@ GHOST_SystemX11::processEvent(XEvent *xe) ); } - printf("X: %s window %d\n", xce.type == EnterNotify ? "entering" : "leaving", (int) xce.window); + // printf("X: %s window %d\n", xce.type == EnterNotify ? "entering" : "leaving", (int) xce.window); if (xce.type == EnterNotify) m_windowManager->setActiveWindow(window); |