From f5e386527c4a74e6e5733f4f1cfa55873851257e Mon Sep 17 00:00:00 2001 From: Steven Bennetts Date: Fri, 4 Apr 2008 01:22:03 +0000 Subject: QAR-427 merge 3dconnex-merge -r 84010 : 84039 -> release --- indra/llui/llfloater.cpp | 13 +- indra/llwindow/llwindow.cpp | 41 +- indra/llwindow/llwindow.h | 8 +- indra/llwindow/llwindowwin32.cpp | 139 +----- indra/newview/app_settings/settings.xml | 366 +++++++++++++- indra/newview/llagent.cpp | 38 +- indra/newview/llagent.h | 5 +- indra/newview/llappviewer.cpp | 30 +- indra/newview/llfloaterjoystick.cpp | 333 +++++++++++++ indra/newview/llfloaterjoystick.h | 78 +++ indra/newview/llfloatertools.cpp | 4 +- indra/newview/llmanip.cpp | 2 +- indra/newview/llmanip.h | 2 +- indra/newview/llselectmgr.cpp | 195 ++++++++ indra/newview/llselectmgr.h | 6 +- indra/newview/lltoolcomp.cpp | 2 +- indra/newview/lltoolmgr.cpp | 15 + indra/newview/lltoolmgr.h | 3 + indra/newview/llviewercamera.cpp | 9 + indra/newview/llviewercontrol.cpp | 54 ++- indra/newview/llviewerjoystick.cpp | 834 +++++++++++++++++++++++++++----- indra/newview/llviewerjoystick.h | 67 ++- indra/newview/llviewermenu.cpp | 82 +++- indra/newview/llviewermenu.h | 1 + indra/newview/llviewerwindow.cpp | 36 ++ indra/newview/llviewerwindow.h | 4 + indra/newview/viewer_manifest.py | 3 + 27 files changed, 2004 insertions(+), 366 deletions(-) create mode 100644 indra/newview/llfloaterjoystick.cpp create mode 100644 indra/newview/llfloaterjoystick.h (limited to 'indra') diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index b69ac30e9c..1eb3d169a5 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -656,7 +656,8 @@ void LLFloater::setTitle( const LLString& title ) { return; } - mDragHandle->setTitle( title ); + if (mDragHandle) + mDragHandle->setTitle( title ); } const LLString& LLFloater::getTitle() const @@ -934,7 +935,8 @@ void LLFloater::setIsChrome(BOOL is_chrome) } // no titles displayed on "chrome" floaters - mDragHandle->setTitleVisible(!is_chrome); + if (mDragHandle) + mDragHandle->setTitleVisible(!is_chrome); LLPanel::setIsChrome(is_chrome); } @@ -945,7 +947,8 @@ void LLFloater::setForeground(BOOL front) if (front != mForeground) { mForeground = front; - mDragHandle->setForeground( front ); + if (mDragHandle) + mDragHandle->setForeground( front ); if (!front) { @@ -1580,8 +1583,8 @@ void LLFloater::updateButtons() mButtons[i]->setVisible(FALSE); } } - - mDragHandle->setMaxTitleWidth(getRect().getWidth() - (button_count * (LLFLOATER_CLOSE_BOX_SIZE + 1))); + if (mDragHandle) + mDragHandle->setMaxTitleWidth(getRect().getWidth() - (button_count * (LLFLOATER_CLOSE_BOX_SIZE + 1))); } void LLFloater::buildButtons() diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp index 37f089e8be..c640a83328 100644 --- a/indra/llwindow/llwindow.cpp +++ b/indra/llwindow/llwindow.cpp @@ -143,6 +143,11 @@ BOOL LLWindowCallbacks::handleActivate(LLWindow *window, BOOL activated) return FALSE; } +BOOL LLWindowCallbacks::handleActivateApp(LLWindow *window, BOOL activating) +{ + return FALSE; +} + void LLWindowCallbacks::handleMouseMove(LLWindow *window, const LLCoordGL pos, MASK mask) { } @@ -190,6 +195,15 @@ void LLWindowCallbacks::handleDataCopy(LLWindow *window, S32 data_type, void *da { } +BOOL LLWindowCallbacks::handleTimerEvent(LLWindow *window) +{ + return FALSE; +} + +BOOL LLWindowCallbacks::handleDeviceChange(LLWindow *window) +{ + return FALSE; +} S32 OSMessageBox(const char* text, const char* caption, U32 type) { @@ -247,15 +261,6 @@ LLWindow::LLWindow(BOOL fullscreen, U32 flags) mFlags(flags), mHighSurrogate(0) { - for (U32 i = 0; i < 8; i++) - { - mJoyAxis[i] = 0; - } - - for (U32 i = 0; i < 16; i++) - { - mJoyButtonState[i] = 0; - } } // virtual @@ -273,24 +278,6 @@ void LLWindow::decBusyCount() } } -F32 LLWindow::getJoystickAxis(U32 axis) -{ - if (axis < 8) - { - return mJoyAxis[axis]; - } - return 0.f; -} - -U8 LLWindow::getJoystickButton(U32 button) -{ - if (button < 16) - { - return mJoyButtonState[button]; - } - return 0; -} - void LLWindow::setCallbacks(LLWindowCallbacks *callbacks) { mCallbacks = callbacks; diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index 6b9414a301..81adf8b13a 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -107,6 +107,7 @@ public: virtual BOOL handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); virtual BOOL handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); virtual BOOL handleActivate(LLWindow *window, BOOL activated); + virtual BOOL handleActivateApp(LLWindow *window, BOOL activating); virtual void handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask); virtual void handleScrollWheel(LLWindow *window, S32 clicks); virtual void handleResize(LLWindow *window, S32 width, S32 height); @@ -118,6 +119,8 @@ public: virtual void handleWindowBlock(LLWindow *window); // window is taking over CPU for a while virtual void handleWindowUnblock(LLWindow *window); // window coming back after taking over CPU for a while virtual void handleDataCopy(LLWindow *window, S32 data_type, void *data); + virtual BOOL handleTimerEvent(LLWindow *window); + virtual BOOL handleDeviceChange(LLWindow *window); }; // Refer to llwindow_test in test/common/llwindow for usage example @@ -214,9 +217,6 @@ public: virtual F32 getPixelAspectRatio() = 0; virtual void setNativeAspectRatio(F32 aspect) = 0; - F32 getJoystickAxis(U32 axis); - U8 getJoystickButton(U32 button); - void setCallbacks(LLWindowCallbacks *callbacks); virtual void beforeDialog() {}; // prepare to put up an OS dialog (if special measures are required, such as in fullscreen mode) @@ -260,8 +260,6 @@ protected: ESwapMethod mSwapMethod; BOOL mHideCursorPermanent; U32 mFlags; - F32 mJoyAxis[8]; - U8 mJoyButtonState[16]; U16 mHighSurrogate; // Handle a UTF-16 encoding unit received from keyboard. diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index f05397b058..61daacb567 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -46,7 +46,7 @@ #define DIRECTINPUT_VERSION 0x0800 #include - +#include #include "llkeyboardwin32.h" #include "llerror.h" @@ -359,14 +359,6 @@ LLWinImm::~LLWinImm() } -LPDIRECTINPUT8 g_pDI = NULL; -LPDIRECTINPUTDEVICE8 g_pJoystick = NULL; -BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, - VOID* pContext ); -BOOL CALLBACK EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, - VOID* pContext ); - - LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clearBg, @@ -666,38 +658,6 @@ LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width, // Initialize (boot strap) the Language text input management, // based on the system's (or user's) default settings. allowLanguageTextInput(NULL, FALSE); -} - -void LLWindowWin32::initInputDevices() -{ - // Direct Input - HRESULT hr; - - if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, - IID_IDirectInput8, (VOID**)&g_pDI, NULL ) ) ) - { - llwarns << "Direct8InputCreate failed!" << llendl; - } - else - { - while(1) - { - // Look for a simple joystick we can use for this sample program. - if (FAILED( hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL, - EnumJoysticksCallback, - NULL, DIEDFL_ATTACHEDONLY ) ) ) - break; - if (!g_pJoystick) - break; - if( FAILED( hr = g_pJoystick->SetDataFormat( &c_dfDIJoystick ) ) ) - break; - if( FAILED( hr = g_pJoystick->EnumObjects( EnumObjectsCallback, - (VOID*)mWindowHandle, DIDFT_ALL ) ) ) - break; - g_pJoystick->Acquire(); - break; - } - } SetTimer( mWindowHandle, 0, 1000 / 30, NULL ); // 30 fps timer } @@ -1438,8 +1398,6 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO SetWindowLong(mWindowHandle, GWL_USERDATA, (U32)this); show(); - initInputDevices(); - // ok to post quit messages now mPostQuit = TRUE; return TRUE; @@ -1730,7 +1688,22 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ S32 update_height; case WM_TIMER: - window_imp->updateJoystick( ); + window_imp->mCallbacks->handleTimerEvent(window_imp); + break; + + case WM_DEVICECHANGE: + if (gDebugWindowProc) + { + llinfos << " WM_DEVICECHANGE: wParam=" << w_param + << "; lParam=" << l_param << llendl; + } + if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL) + { + if (window_imp->mCallbacks->handleDeviceChange(window_imp)) + { + return 0; + } + } break; case WM_PAINT: @@ -1795,6 +1768,9 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->resetDisplayResolution(); } } + + window_imp->mCallbacks->handleActivateApp(window_imp, activating); + break; } @@ -2831,81 +2807,6 @@ void LLWindowWin32::swapBuffers() } -BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, - VOID* pContext ) -{ - HRESULT hr; - - // Obtain an interface to the enumerated joystick. - hr = g_pDI->CreateDevice( pdidInstance->guidInstance, &g_pJoystick, NULL ); - - // If it failed, then we can't use this joystick. (Maybe the user unplugged - // it while we were in the middle of enumerating it.) - if( FAILED(hr) ) - return DIENUM_CONTINUE; - - // Stop enumeration. Note: we're just taking the first joystick we get. You - // could store all the enumerated joysticks and let the user pick. - return DIENUM_STOP; -} - -BOOL CALLBACK EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, - VOID* pContext ) -{ - if( pdidoi->dwType & DIDFT_AXIS ) - { - DIPROPRANGE diprg; - diprg.diph.dwSize = sizeof(DIPROPRANGE); - diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); - diprg.diph.dwHow = DIPH_BYID; - diprg.diph.dwObj = pdidoi->dwType; // Specify the enumerated axis - diprg.lMin = -1000; - diprg.lMax = +1000; - - // Set the range for the axis - if( FAILED( g_pJoystick->SetProperty( DIPROP_RANGE, &diprg.diph ) ) ) - return DIENUM_STOP; - - } - return DIENUM_CONTINUE; -} - -void LLWindowWin32::updateJoystick( ) -{ - HRESULT hr; - DIJOYSTATE js; // DInput joystick state - - if (!g_pJoystick) - return; - hr = g_pJoystick->Poll(); - if ( hr == DIERR_INPUTLOST ) - { - hr = g_pJoystick->Acquire(); - return; - } - else if ( FAILED(hr) ) - return; - - // Get the input's device state - if( FAILED( hr = g_pJoystick->GetDeviceState( sizeof(DIJOYSTATE), &js ) ) ) - return; // The device should have been acquired during the Poll() - - mJoyAxis[0] = js.lX/1000.f; - mJoyAxis[1] = js.lY/1000.f; - mJoyAxis[2] = js.lZ/1000.f; - mJoyAxis[3] = js.lRx/1000.f; - mJoyAxis[4] = js.lRy/1000.f; - mJoyAxis[5] = js.lRz/1000.f; - mJoyAxis[6] = js.rglSlider[0]/1000.f; - mJoyAxis[7] = js.rglSlider[1]/1000.f; - - for (U32 i = 0; i < 16; i++) - { - mJoyButtonState[i] = js.rgbButtons[i]; - } -} - - // // LLSplashScreenImp // diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 1a26783623..2754b27234 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -2791,7 +2791,7 @@ Value 0 - FlycamAutoLeveling + AutoLeveling Comment Keep Flycam level. @@ -2802,7 +2802,40 @@ Value 1 - FlycamAxis0 + Cursor3D + + Comment + Tread Joystick values as absolute positions (not deltas). + Persist + 1 + Type + Boolean + Value + 1 + + ZoomDirect + + Comment + Map Joystick zoom axis directly to camera zoom. + Persist + 1 + Type + Boolean + Value + 0 + + JoystickInitialized + + Comment + Whether or not a joystick has been detected and initiailized. + Persist + 1 + Type + String + Value + + + JoystickAxis0 Comment Flycam hardware axis mapping for internal axis 0 ([0, 5]). @@ -2813,7 +2846,7 @@ Value 0 - FlycamAxis1 + JoystickAxis1 Comment Flycam hardware axis mapping for internal axis 1 ([0, 5]). @@ -2822,9 +2855,9 @@ Type S32 Value - 1 + 2 - FlycamAxis2 + JoystickAxis2 Comment Flycam hardware axis mapping for internal axis 2 ([0, 5]). @@ -2833,9 +2866,9 @@ Type S32 Value - 2 + 1 - FlycamAxis3 + JoystickAxis3 Comment Flycam hardware axis mapping for internal axis 3 ([0, 5]). @@ -2844,9 +2877,9 @@ Type S32 Value - 3 + 5 - FlycamAxis4 + JoystickAxis4 Comment Flycam hardware axis mapping for internal axis 4 ([0, 5]). @@ -2857,7 +2890,7 @@ Value 4 - FlycamAxis5 + JoystickAxis5 Comment Flycam hardware axis mapping for internal axis 5 ([0, 5]). @@ -2866,9 +2899,9 @@ Type S32 Value - 5 + 3 - FlycamAxis6 + JoystickAxis6 Comment Flycam hardware axis mapping for internal axis 6 ([0, 5]). @@ -2888,7 +2921,7 @@ Type F32 Value - 0.1000000014901161193847656 + 0.1 FlycamAxisDeadZone1 @@ -2899,7 +2932,7 @@ Type F32 Value - 0.1000000014901161193847656 + 0.1 FlycamAxisDeadZone2 @@ -2910,7 +2943,7 @@ Type F32 Value - 0.1000000014901161193847656 + 0.1 FlycamAxisDeadZone3 @@ -2921,7 +2954,7 @@ Type F32 Value - 0.1000000014901161193847656 + 0.1 FlycamAxisDeadZone4 @@ -2932,7 +2965,7 @@ Type F32 Value - 0.1000000014901161193847656 + 0.1 FlycamAxisDeadZone5 @@ -2943,7 +2976,7 @@ Type F32 Value - 0.1000000014901161193847656 + 0.1 FlycamAxisDeadZone6 @@ -2954,7 +2987,7 @@ Type F32 Value - 0.1000000014901161193847656 + 0.1 FlycamAxisScale0 @@ -6016,7 +6049,7 @@ Type F32 Value - 0.1000000014901161193847656 + 0.1 SelectionHighlightThickness @@ -6049,7 +6082,7 @@ Type F32 Value - 0.1000000014901161193847656 + 0.1 SelectionHighlightVAnim @@ -6606,7 +6639,7 @@ 1 0 - 0.1000000014901161193847656 + 0.1 SkyUseClassicClouds @@ -9748,5 +9781,294 @@ Value 1 + + AvatarAxisDeadZone0 + + Comment + Avatar axis 0 dead zone. + Persist + 1 + Type + F32 + Value + 0.1 + + AvatarAxisDeadZone1 + + Comment + Avatar axis 1 dead zone. + Persist + 1 + Type + F32 + Value + 0.1 + + AvatarAxisDeadZone2 + + Comment + Avatar axis 2 dead zone. + Persist + 1 + Type + F32 + Value + 0.1 + + AvatarAxisDeadZone3 + + Comment + Avatar axis 3 dead zone. + Persist + 1 + Type + F32 + Value + 0.1 + + AvatarAxisDeadZone4 + + Comment + Avatar axis 4 dead zone. + Persist + 1 + Type + F32 + Value + 0.1 + + AvatarAxisDeadZone5 + + Comment + Avatar axis 5 dead zone. + Persist + 1 + Type + F32 + Value + 0.1 + + AvatarAxisScale0 + + Comment + Avatar axis 0 scaler. + Persist + 1 + Type + F32 + Value + 1 + + AvatarAxisScale1 + + Comment + Avatar axis 1 scaler. + Persist + 1 + Type + F32 + Value + 1 + + AvatarAxisScale2 + + Comment + Avatar axis 2 scaler. + Persist + 1 + Type + F32 + Value + 1 + + AvatarAxisScale3 + + Comment + Avatar axis 3 scaler. + Persist + 1 + Type + F32 + Value + 1 + + AvatarAxisScale4 + + Comment + Avatar axis 4 scaler. + Persist + 1 + Type + F32 + Value + 1 + + AvatarAxisScale5 + + Comment + Avatar axis 5 scaler. + Persist + 1 + Type + F32 + Value + 1 + + AvatarFeathering + + Comment + Avatar feathering (less is softer) + Persist + 1 + Type + F32 + Value + 16 + + + BuildAxisDeadZone0 + + Comment + Build axis 0 dead zone. + Persist + 1 + Type + F32 + Value + 0.1 + + BuildAxisDeadZone1 + + Comment + Build axis 1 dead zone. + Persist + 1 + Type + F32 + Value + 0.1 + + BuildAxisDeadZone2 + + Comment + Build axis 2 dead zone. + Persist + 1 + Type + F32 + Value + 0.1 + + BuildAxisDeadZone3 + + Comment + Build axis 3 dead zone. + Persist + 1 + Type + F32 + Value + 0.1 + + BuildAxisDeadZone4 + + Comment + Build axis 4 dead zone. + Persist + 1 + Type + F32 + Value + 0.1 + + BuildAxisDeadZone5 + + Comment + Build axis 5 dead zone. + Persist + 1 + Type + F32 + Value + 0.1 + + BuildAxisScale0 + + Comment + Build axis 0 scaler. + Persist + 1 + Type + F32 + Value + 1 + + BuildAxisScale1 + + Comment + Build axis 1 scaler. + Persist + 1 + Type + F32 + Value + 1 + + BuildAxisScale2 + + Comment + Build axis 2 scaler. + Persist + 1 + Type + F32 + Value + 1 + + BuildAxisScale3 + + Comment + Build axis 3 scaler. + Persist + 1 + Type + F32 + Value + 1 + + BuildAxisScale4 + + Comment + Build axis 4 scaler. + Persist + 1 + Type + F32 + Value + 1 + + BuildAxisScale5 + + Comment + Build axis 5 scaler. + Persist + 1 + Type + F32 + Value + 1 + + BuildFeathering + + Comment + Build feathering (less is softer) + Persist + 1 + Type + F32 + Value + 16 + + diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 2f5589a966..dcea6b2957 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -581,7 +581,7 @@ void LLAgent::unlockView() //----------------------------------------------------------------------------- // moveAt() //----------------------------------------------------------------------------- -void LLAgent::moveAt(S32 direction) +void LLAgent::moveAt(S32 direction, bool reset) { // age chat timer so it fades more quickly when you are intentionally moving ageChat(); @@ -597,7 +597,10 @@ void LLAgent::moveAt(S32 direction) setControlFlags(AGENT_CONTROL_AT_NEG | AGENT_CONTROL_FAST_AT); } - resetView(); + if (reset) + { + resetView(); + } } //----------------------------------------------------------------------------- @@ -691,7 +694,7 @@ void LLAgent::moveUp(S32 direction) //----------------------------------------------------------------------------- // moveYaw() //----------------------------------------------------------------------------- -void LLAgent::moveYaw(F32 mag) +void LLAgent::moveYaw(F32 mag, bool reset_view) { mYawKey = mag; @@ -704,7 +707,10 @@ void LLAgent::moveYaw(F32 mag) setControlFlags(AGENT_CONTROL_YAW_NEG); } - resetView(); + if (reset_view) + { + resetView(); + } } //----------------------------------------------------------------------------- @@ -1216,7 +1222,16 @@ LLVector3 LLAgent::getReferenceUpVector() void LLAgent::pitch(F32 angle) { // don't let user pitch if pointed almost all the way down or up - + mFrameAgent.pitch(clampPitchToLimits(angle)); +} + + +// Radians, positive is forward into ground +//----------------------------------------------------------------------------- +// clampPitchToLimits() +//----------------------------------------------------------------------------- +F32 LLAgent::clampPitchToLimits(F32 angle) +{ // A dot B = mag(A) * mag(B) * cos(angle between A and B) // so... cos(angle between A and B) = A dot B / mag(A) / mag(B) // = A dot B for unit vectors @@ -1246,8 +1261,8 @@ void LLAgent::pitch(F32 angle) { angle = look_up_limit - angle_from_skyward; } - - mFrameAgent.pitch(angle); + + return angle; } @@ -2576,15 +2591,18 @@ void LLAgent::updateLookAt(const S32 mouse_x, const S32 mouse_y) LLVector3 headLookAxis; LLCoordFrame frameCamera = *((LLCoordFrame*)LLViewerCamera::getInstance()); - F32 x_from_center = ((F32) mouse_x / (F32) gViewerWindow->getWindowWidth() ) - 0.5f; - F32 y_from_center = ((F32) mouse_y / (F32) gViewerWindow->getWindowHeight() ) - 0.5f; - if (cameraMouselook()) { lookAtType = LOOKAT_TARGET_MOUSELOOK; } else if (cameraThirdPerson()) { + // range from -.5 to .5 + F32 x_from_center = + ((F32) mouse_x / (F32) gViewerWindow->getWindowWidth() ) - 0.5f; + F32 y_from_center = + ((F32) mouse_y / (F32) gViewerWindow->getWindowHeight() ) - 0.5f; + frameCamera.yaw( - x_from_center * gSavedSettings.getF32("YawFromMousePosition") * DEG_TO_RAD); frameCamera.pitch( - y_from_center * gSavedSettings.getF32("PitchFromMousePosition") * DEG_TO_RAD); lookAtType = LOOKAT_TARGET_FREELOOK; diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 1a7d239288..b50fb745ca 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -356,6 +356,7 @@ public: void roll(F32 angle); void yaw(F32 angle); LLVector3 getReferenceUpVector(); + F32 clampPitchToLimits(F32 angle); void setThirdPersonHeadOffset(LLVector3 offset) { mThirdPersonHeadOffset = offset; } // Flight management @@ -404,12 +405,12 @@ public: // Movement from user input. All set the appropriate animation flags. // All turn off autopilot and make sure the camera is behind the avatar. // direction is either positive, zero, or negative - void moveAt(S32 direction); + void moveAt(S32 direction, bool reset_view = true); void moveAtNudge(S32 direction); void moveLeft(S32 direction); void moveLeftNudge(S32 direction); void moveUp(S32 direction); - void moveYaw(F32 mag); + void moveYaw(F32 mag, bool reset_view = true); void movePitch(S32 direction); void setOrbitLeftKey(F32 mag) { mOrbitLeftKey = mag; } diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index fc092e5cba..3d10eda7fd 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -51,6 +51,7 @@ #include "llstartup.h" #include "llfocusmgr.h" #include "llviewerjoystick.h" +#include "llfloaterjoystick.h" #include "llares.h" #include "llcurl.h" #include "llfloatersnapshot.h" @@ -709,7 +710,7 @@ bool LLAppViewer::init() // Copy settings to globals. *TODO: Remove or move to appropriage class initializers - settings_to_globals(); + settings_to_globals(); // Setup settings listeners settings_setup_listeners(); // Modify settings based on system configuration and compile options @@ -858,6 +859,16 @@ bool LLAppViewer::init() gSimLastTime = gRenderStartTime.getElapsedTimeF32(); gSimFrames = (F32)gFrameCount; + LLViewerJoystick::getInstance()->init(); + if (LLViewerJoystick::getInstance()->isLikeSpaceNavigator()) + { + if (gSavedSettings.getString("JoystickInitialized") != "SpaceNavigator") + { + LLFloaterJoystick::setSNDefaults(); + gSavedSettings.setString("JoystickInitialized", "SpaceNavigator"); + } + } + return true; } @@ -880,7 +891,9 @@ bool LLAppViewer::mainLoop() LLMemType mt1(LLMemType::MTYPE_MAIN); LLTimer frameTimer,idleTimer; LLTimer debugTime; - + LLViewerJoystick* joystick(LLViewerJoystick::getInstance()); + joystick->setNeedsReset(true); + // Handle messages while (!LLApp::isExiting()) { @@ -921,8 +934,8 @@ bool LLAppViewer::mainLoop() && !gViewerWindow->getShowProgress() && !gFocusMgr.focusLocked()) { + joystick->scanJoystick(); gKeyboard->scanKeyboard(); - LLViewerJoystick::scanJoystick(); } // Update state based on messages, user input, object idle. @@ -3217,13 +3230,18 @@ void LLAppViewer::idle() } stop_glerror(); - if (!LLViewerJoystick::sOverrideCamera) + if (LLViewerJoystick::sOverrideCamera) { - gAgent.updateCamera(); + LLViewerJoystick::getInstance()->moveFlycam(); } else { - LLViewerJoystick::updateCamera(); + if (LLToolMgr::getInstance()->inBuildMode()) + { + LLViewerJoystick::getInstance()->moveObjects(); + } + + gAgent.updateCamera(); } // objects and camera should be in sync, do LOD calculations now diff --git a/indra/newview/llfloaterjoystick.cpp b/indra/newview/llfloaterjoystick.cpp new file mode 100644 index 0000000000..44abdd3cde --- /dev/null +++ b/indra/newview/llfloaterjoystick.cpp @@ -0,0 +1,333 @@ +/** + * @file llfloaterjoystick.cpp + * @brief Joystick preferences panel + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +// file include +#include "llfloaterjoystick.h" + +// linden library includes +#include "llerror.h" +#include "llrect.h" +#include "llstring.h" + +// project includes +#include "lluictrlfactory.h" +#include "llviewercontrol.h" +#include "llappviewer.h" +#include "llviewerjoystick.h" + +LLFloaterJoystick::LLFloaterJoystick(const LLSD& data) + : LLFloater("floater_joystick") +{ + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_joystick.xml"); + center(); +} + +void LLFloaterJoystick::draw() +{ + LLViewerJoystick* joystick(LLViewerJoystick::getInstance()); + for (U32 i = 0; i < 6; i++) + { + F32 value = joystick->getJoystickAxis(i); + mAxisStats[i]->addValue(value * gFrameIntervalSeconds); + + if (mAxisStatsBar[i]->mMinBar > value) + { + mAxisStatsBar[i]->mMinBar = value; + } + if (mAxisStatsBar[i]->mMaxBar < value) + { + mAxisStatsBar[i]->mMaxBar = value; + } + } + + LLFloater::draw(); +} + +BOOL LLFloaterJoystick::postBuild() +{ + F32 range = gSavedSettings.getBOOL("Cursor3D") ? 1024.f : 2.f; + LLUIString axis = getUIString("Axis"); + LLUIString joystick = getUIString("JoystickMonitor"); + + // use this child to get relative positioning info; we'll place the + // joystick monitor on its right, vertically aligned to it. + LLView* child = getChild("FlycamAxisScale1"); + LLRect rect; + + if (child) + { + LLRect r = child->getRect(); + LLRect f = getRect(); + rect = LLRect(350, r.mTop, r.mRight + 200, 0); + } + + mAxisStatsView = new LLStatView("axis values", joystick, "", rect); + mAxisStatsView->setDisplayChildren(TRUE); + + for (U32 i = 0; i < 6; i++) + { + axis.setArg("[NUM]", llformat("%d", i)); + mAxisStats[i] = new LLStat(4); + mAxisStatsBar[i] = mAxisStatsView->addStat(axis, mAxisStats[i]); + mAxisStatsBar[i]->mMinBar = -range; + mAxisStatsBar[i]->mMaxBar = range; + mAxisStatsBar[i]->mLabelSpacing = range * 0.5f; + mAxisStatsBar[i]->mTickSpacing = range * 0.25f; + } + + addChild(mAxisStatsView); + + childSetAction("SpaceNavigatorDefaults", onClickRestoreSNDefaults, this); + refresh(); + return TRUE; +} + +LLFloaterJoystick::~LLFloaterJoystick() +{ + // Children all cleaned up by default view destructor. +} + + +void LLFloaterJoystick::apply() +{ +} + +void LLFloaterJoystick::refresh() +{ + LLFloater::refresh(); + + mJoystickAxis[0] = gSavedSettings.getS32("JoystickAxis0"); + mJoystickAxis[1] = gSavedSettings.getS32("JoystickAxis1"); + mJoystickAxis[2] = gSavedSettings.getS32("JoystickAxis2"); + mJoystickAxis[3] = gSavedSettings.getS32("JoystickAxis3"); + mJoystickAxis[4] = gSavedSettings.getS32("JoystickAxis4"); + mJoystickAxis[5] = gSavedSettings.getS32("JoystickAxis5"); + mJoystickAxis[6] = gSavedSettings.getS32("JoystickAxis6"); + + m3DCursor = gSavedSettings.getBOOL("Cursor3D"); + mAutoLeveling = gSavedSettings.getBOOL("AutoLeveling"); + mZoomDirect = gSavedSettings.getBOOL("ZoomDirect"); + + mAvatarAxisScale[0] = gSavedSettings.getF32("AvatarAxisScale0"); + mAvatarAxisScale[1] = gSavedSettings.getF32("AvatarAxisScale1"); + mAvatarAxisScale[2] = gSavedSettings.getF32("AvatarAxisScale2"); + mAvatarAxisScale[3] = gSavedSettings.getF32("AvatarAxisScale3"); + mAvatarAxisScale[4] = gSavedSettings.getF32("AvatarAxisScale4"); + mAvatarAxisScale[5] = gSavedSettings.getF32("AvatarAxisScale5"); + + mBuildAxisScale[0] = gSavedSettings.getF32("BuildAxisScale0"); + mBuildAxisScale[1] = gSavedSettings.getF32("BuildAxisScale1"); + mBuildAxisScale[2] = gSavedSettings.getF32("BuildAxisScale2"); + mBuildAxisScale[3] = gSavedSettings.getF32("BuildAxisScale3"); + mBuildAxisScale[4] = gSavedSettings.getF32("BuildAxisScale4"); + mBuildAxisScale[5] = gSavedSettings.getF32("BuildAxisScale5"); + + mFlycamAxisScale[0] = gSavedSettings.getF32("FlycamAxisScale0"); + mFlycamAxisScale[1] = gSavedSettings.getF32("FlycamAxisScale1"); + mFlycamAxisScale[2] = gSavedSettings.getF32("FlycamAxisScale2"); + mFlycamAxisScale[3] = gSavedSettings.getF32("FlycamAxisScale3"); + mFlycamAxisScale[4] = gSavedSettings.getF32("FlycamAxisScale4"); + mFlycamAxisScale[5] = gSavedSettings.getF32("FlycamAxisScale5"); + mFlycamAxisScale[6] = gSavedSettings.getF32("FlycamAxisScale6"); + + mAvatarAxisDeadZone[0] = gSavedSettings.getF32("AvatarAxisDeadZone0"); + mAvatarAxisDeadZone[1] = gSavedSettings.getF32("AvatarAxisDeadZone1"); + mAvatarAxisDeadZone[2] = gSavedSettings.getF32("AvatarAxisDeadZone2"); + mAvatarAxisDeadZone[3] = gSavedSettings.getF32("AvatarAxisDeadZone3"); + mAvatarAxisDeadZone[4] = gSavedSettings.getF32("AvatarAxisDeadZone4"); + mAvatarAxisDeadZone[5] = gSavedSettings.getF32("AvatarAxisDeadZone5"); + + mBuildAxisDeadZone[0] = gSavedSettings.getF32("BuildAxisDeadZone0"); + mBuildAxisDeadZone[1] = gSavedSettings.getF32("BuildAxisDeadZone1"); + mBuildAxisDeadZone[2] = gSavedSettings.getF32("BuildAxisDeadZone2"); + mBuildAxisDeadZone[3] = gSavedSettings.getF32("BuildAxisDeadZone3"); + mBuildAxisDeadZone[4] = gSavedSettings.getF32("BuildAxisDeadZone4"); + mBuildAxisDeadZone[5] = gSavedSettings.getF32("BuildAxisDeadZone5"); + + mFlycamAxisDeadZone[0] = gSavedSettings.getF32("FlycamAxisDeadZone0"); + mFlycamAxisDeadZone[1] = gSavedSettings.getF32("FlycamAxisDeadZone1"); + mFlycamAxisDeadZone[2] = gSavedSettings.getF32("FlycamAxisDeadZone2"); + mFlycamAxisDeadZone[3] = gSavedSettings.getF32("FlycamAxisDeadZone3"); + mFlycamAxisDeadZone[4] = gSavedSettings.getF32("FlycamAxisDeadZone4"); + mFlycamAxisDeadZone[5] = gSavedSettings.getF32("FlycamAxisDeadZone5"); + mFlycamAxisDeadZone[6] = gSavedSettings.getF32("FlycamAxisDeadZone6"); + + mAvatarFeathering = gSavedSettings.getF32("AvatarFeathering"); + mBuildFeathering = gSavedSettings.getF32("BuildFeathering"); + mFlycamFeathering = gSavedSettings.getF32("FlycamFeathering"); +} + +void LLFloaterJoystick::cancel() +{ + llinfos << "reading from gSavedSettings->Cursor3D=" + << gSavedSettings.getBOOL("Cursor3D") << "; m3DCursor=" + << m3DCursor << llendl; + + gSavedSettings.setS32("JoystickAxis0", mJoystickAxis[0]); + gSavedSettings.setS32("JoystickAxis1", mJoystickAxis[1]); + gSavedSettings.setS32("JoystickAxis2", mJoystickAxis[2]); + gSavedSettings.setS32("JoystickAxis3", mJoystickAxis[3]); + gSavedSettings.setS32("JoystickAxis4", mJoystickAxis[4]); + gSavedSettings.setS32("JoystickAxis5", mJoystickAxis[5]); + gSavedSettings.setS32("JoystickAxis6", mJoystickAxis[6]); + + gSavedSettings.setBOOL("Cursor3D", m3DCursor); + gSavedSettings.setBOOL("AutoLeveling", mAutoLeveling); + gSavedSettings.setBOOL("ZoomDirect", mZoomDirect ); + + gSavedSettings.setF32("AvatarAxisScale0", mAvatarAxisScale[0]); + gSavedSettings.setF32("AvatarAxisScale1", mAvatarAxisScale[1]); + gSavedSettings.setF32("AvatarAxisScale2", mAvatarAxisScale[2]); + gSavedSettings.setF32("AvatarAxisScale3", mAvatarAxisScale[3]); + gSavedSettings.setF32("AvatarAxisScale4", mAvatarAxisScale[4]); + gSavedSettings.setF32("AvatarAxisScale5", mAvatarAxisScale[5]); + + gSavedSettings.setF32("BuildAxisScale0", mBuildAxisScale[0]); + gSavedSettings.setF32("BuildAxisScale1", mBuildAxisScale[1]); + gSavedSettings.setF32("BuildAxisScale2", mBuildAxisScale[2]); + gSavedSettings.setF32("BuildAxisScale3", mBuildAxisScale[3]); + gSavedSettings.setF32("BuildAxisScale4", mBuildAxisScale[4]); + gSavedSettings.setF32("BuildAxisScale5", mBuildAxisScale[5]); + + gSavedSettings.setF32("FlycamAxisScale0", mFlycamAxisScale[0]); + gSavedSettings.setF32("FlycamAxisScale1", mFlycamAxisScale[1]); + gSavedSettings.setF32("FlycamAxisScale2", mFlycamAxisScale[2]); + gSavedSettings.setF32("FlycamAxisScale3", mFlycamAxisScale[3]); + gSavedSettings.setF32("FlycamAxisScale4", mFlycamAxisScale[4]); + gSavedSettings.setF32("FlycamAxisScale5", mFlycamAxisScale[5]); + gSavedSettings.setF32("FlycamAxisScale6", mFlycamAxisScale[6]); + + gSavedSettings.setF32("AvatarAxisDeadZone0", mAvatarAxisDeadZone[0]); + gSavedSettings.setF32("AvatarAxisDeadZone1", mAvatarAxisDeadZone[1]); + gSavedSettings.setF32("AvatarAxisDeadZone2", mAvatarAxisDeadZone[2]); + gSavedSettings.setF32("AvatarAxisDeadZone3", mAvatarAxisDeadZone[3]); + gSavedSettings.setF32("AvatarAxisDeadZone4", mAvatarAxisDeadZone[4]); + gSavedSettings.setF32("AvatarAxisDeadZone5", mAvatarAxisDeadZone[5]); + + gSavedSettings.setF32("BuildAxisDeadZone0", mBuildAxisDeadZone[0]); + gSavedSettings.setF32("BuildAxisDeadZone1", mBuildAxisDeadZone[1]); + gSavedSettings.setF32("BuildAxisDeadZone2", mBuildAxisDeadZone[2]); + gSavedSettings.setF32("BuildAxisDeadZone3", mBuildAxisDeadZone[3]); + gSavedSettings.setF32("BuildAxisDeadZone4", mBuildAxisDeadZone[4]); + gSavedSettings.setF32("BuildAxisDeadZone5", mBuildAxisDeadZone[5]); + + gSavedSettings.setF32("FlycamAxisDeadZone0", mFlycamAxisDeadZone[0]); + gSavedSettings.setF32("FlycamAxisDeadZone1", mFlycamAxisDeadZone[1]); + gSavedSettings.setF32("FlycamAxisDeadZone2", mFlycamAxisDeadZone[2]); + gSavedSettings.setF32("FlycamAxisDeadZone3", mFlycamAxisDeadZone[3]); + gSavedSettings.setF32("FlycamAxisDeadZone4", mFlycamAxisDeadZone[4]); + gSavedSettings.setF32("FlycamAxisDeadZone5", mFlycamAxisDeadZone[5]); + gSavedSettings.setF32("FlycamAxisDeadZone6", mFlycamAxisDeadZone[6]); + + gSavedSettings.setF32("AvatarFeathering", mAvatarFeathering); + gSavedSettings.setF32("BuildFeathering", mBuildFeathering); + gSavedSettings.setF32("FlycamFeathering", mFlycamFeathering); +} + +void LLFloaterJoystick::onClickRestoreSNDefaults(void *joy_panel) +{ + setSNDefaults(); +} + +void LLFloaterJoystick::setSNDefaults() +{ +#if LL_DARWIN +#define kPlatformScale 20.f +#else +#define kPlatformScale 1.f +#endif + + //gViewerWindow->alertXml("CacheWillClear"); + llinfos << "restoring SpaceNavigator defaults..." << llendl; + + gSavedSettings.setS32("JoystickAxis1", 0); // x (slide) + gSavedSettings.setS32("JoystickAxis2", 2); // y (up) + gSavedSettings.setS32("JoystickAxis0", 1); // z (at) + gSavedSettings.setS32("JoystickAxis4", 3); // roll + gSavedSettings.setS32("JoystickAxis5", 5); // yaw + gSavedSettings.setS32("JoystickAxis3", 4); // pitch + gSavedSettings.setS32("JoystickAxis6", -1); + +#if LL_DARWIN + // The SpaceNavigator doesn't act as a 3D cursor on OS X. + gSavedSettings.setBOOL("Cursor3D", false); +#else + gSavedSettings.setBOOL("Cursor3D", true); +#endif + gSavedSettings.setBOOL("AutoLeveling", true); + gSavedSettings.setBOOL("ZoomDirect", false); + + gSavedSettings.setF32("AvatarAxisScale0", 1.f); + gSavedSettings.setF32("AvatarAxisScale1", 1.f); + gSavedSettings.setF32("AvatarAxisScale2", 1.f); + gSavedSettings.setF32("AvatarAxisScale4", .1f * kPlatformScale); + gSavedSettings.setF32("AvatarAxisScale5", .1f * kPlatformScale); + gSavedSettings.setF32("AvatarAxisScale3", 0.f * kPlatformScale); + gSavedSettings.setF32("BuildAxisScale1", .3f * kPlatformScale); + gSavedSettings.setF32("BuildAxisScale2", .3f * kPlatformScale); + gSavedSettings.setF32("BuildAxisScale0", .3f * kPlatformScale); + gSavedSettings.setF32("BuildAxisScale4", .3f * kPlatformScale); + gSavedSettings.setF32("BuildAxisScale5", .3f * kPlatformScale); + gSavedSettings.setF32("BuildAxisScale3", .3f * kPlatformScale); + gSavedSettings.setF32("FlycamAxisScale1", 2.f * kPlatformScale); + gSavedSettings.setF32("FlycamAxisScale2", 2.f * kPlatformScale); + gSavedSettings.setF32("FlycamAxisScale0", 2.1f * kPlatformScale); + gSavedSettings.setF32("FlycamAxisScale4", .1f * kPlatformScale); + gSavedSettings.setF32("FlycamAxisScale5", .15f * kPlatformScale); + gSavedSettings.setF32("FlycamAxisScale3", 0.f * kPlatformScale); + gSavedSettings.setF32("FlycamAxisScale6", 0.f * kPlatformScale); + + gSavedSettings.setF32("AvatarAxisDeadZone0", .1f); + gSavedSettings.setF32("AvatarAxisDeadZone1", .1f); + gSavedSettings.setF32("AvatarAxisDeadZone2", .1f); + gSavedSettings.setF32("AvatarAxisDeadZone3", 1.f); + gSavedSettings.setF32("AvatarAxisDeadZone4", .02f); + gSavedSettings.setF32("AvatarAxisDeadZone5", .01f); + gSavedSettings.setF32("BuildAxisDeadZone0", .01f); + gSavedSettings.setF32("BuildAxisDeadZone1", .01f); + gSavedSettings.setF32("BuildAxisDeadZone2", .01f); + gSavedSettings.setF32("BuildAxisDeadZone3", .01f); + gSavedSettings.setF32("BuildAxisDeadZone4", .01f); + gSavedSettings.setF32("BuildAxisDeadZone5", .01f); + gSavedSettings.setF32("FlycamAxisDeadZone0", .01f); + gSavedSettings.setF32("FlycamAxisDeadZone1", .01f); + gSavedSettings.setF32("FlycamAxisDeadZone2", .01f); + gSavedSettings.setF32("FlycamAxisDeadZone3", .01f); + gSavedSettings.setF32("FlycamAxisDeadZone4", .01f); + gSavedSettings.setF32("FlycamAxisDeadZone5", .01f); + gSavedSettings.setF32("FlycamAxisDeadZone6", 1.f); + + gSavedSettings.setF32("AvatarFeathering", 6.f); + gSavedSettings.setF32("BuildFeathering", 12.f); + gSavedSettings.setF32("FlycamFeathering", 5.f); +} diff --git a/indra/newview/llfloaterjoystick.h b/indra/newview/llfloaterjoystick.h new file mode 100644 index 0000000000..6dc40704f0 --- /dev/null +++ b/indra/newview/llfloaterjoystick.h @@ -0,0 +1,78 @@ +/** + * @file llfloaterjoystick.h + * @brief Joystick preferences panel + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERJOYSTICK_H +#define LL_LLFLOATERJOYSTICK_H + +#include "llfloater.h" +#include "llstatview.h" + +class LLFloaterJoystick : public LLFloater, public LLFloaterSingleton +{ +public: + LLFloaterJoystick(const LLSD& data); + virtual ~LLFloaterJoystick(); + + virtual BOOL postBuild(); + virtual void refresh(); + virtual void apply(); // Apply the changed values. + virtual void cancel(); // Cancel the changed values. + virtual void draw(); + static void setSNDefaults(); + +private: + static void onClickRestoreSNDefaults(void*); + +private: + // Device prefs + S32 mJoystickAxis[7]; + bool m3DCursor; + bool mAutoLeveling; + bool mZoomDirect; + + // Modes prefs + F32 mAvatarAxisScale[6]; + F32 mBuildAxisScale[6]; + F32 mFlycamAxisScale[7]; + F32 mAvatarAxisDeadZone[6]; + F32 mBuildAxisDeadZone[6]; + F32 mFlycamAxisDeadZone[7]; + F32 mAvatarFeathering; + F32 mBuildFeathering; + F32 mFlycamFeathering; + + // stats view + LLStatView* mAxisStatsView; + LLStat* mAxisStats[6]; + LLStatBar* mAxisStatsBar[6]; +}; + +#endif diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index 7777544a4c..0e58363de5 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -75,7 +75,7 @@ #include "llviewerparcelmgr.h" #include "llviewerwindow.h" #include "llviewercontrol.h" - +#include "llviewerjoystick.h" #include "lluictrlfactory.h" // Globals @@ -770,6 +770,8 @@ void LLFloaterTools::onClose(bool app_quitting) setVisible(FALSE); mTab->setVisible(FALSE); + LLViewerJoystick::getInstance()->moveAvatar(true); + // Different from handle_reset_view in that it doesn't actually // move the camera if EditCameraMovement is not set. gAgent.resetView(gSavedSettings.getBOOL("EditCameraMovement")); diff --git a/indra/newview/llmanip.cpp b/indra/newview/llmanip.cpp index af682508c9..887db4cf95 100644 --- a/indra/newview/llmanip.cpp +++ b/indra/newview/llmanip.cpp @@ -255,7 +255,7 @@ BOOL LLManip::getMousePointOnPlaneAgent(LLVector3& point, S32 x, S32 y, LLVector return result; } -BOOL LLManip::getMousePointOnPlaneGlobal(LLVector3d& point, S32 x, S32 y, LLVector3d origin, LLVector3 normal) +BOOL LLManip::getMousePointOnPlaneGlobal(LLVector3d& point, S32 x, S32 y, LLVector3d origin, LLVector3 normal) const { if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD) { diff --git a/indra/newview/llmanip.h b/indra/newview/llmanip.h index 2dd0eab8b0..a2ad464f3c 100644 --- a/indra/newview/llmanip.h +++ b/indra/newview/llmanip.h @@ -146,7 +146,7 @@ protected: void renderTickValue(const LLVector3& pos, F32 value, const char* suffix, const LLColor4 &color); void renderTickText(const LLVector3& pos, const char* suffix, const LLColor4 &color); void updateGridSettings(); - BOOL getMousePointOnPlaneGlobal(LLVector3d& point, S32 x, S32 y, LLVector3d origin, LLVector3 normal); + BOOL getMousePointOnPlaneGlobal(LLVector3d& point, S32 x, S32 y, LLVector3d origin, LLVector3 normal) const; BOOL getMousePointOnPlaneAgent(LLVector3& point, S32 x, S32 y, LLVector3 origin, LLVector3 normal); BOOL nearestPointOnLineFromMouse( S32 x, S32 y, const LLVector3& b1, const LLVector3& b2, F32 &a_param, F32 &b_param ); LLColor4 setupSnapGuideRenderPass(S32 pass); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index c2dfd779a3..cd59c8e300 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -6241,4 +6241,199 @@ LLViewerObject* LLObjectSelection::getFirstMoveableObject(BOOL get_parent) return getFirstSelectedObject(&func, get_parent); } +//----------------------------------------------------------------------------- +// Position + Rotation update methods called from LLViewerJoystick +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectionMove(const LLVector3& displ, + F32 roll, F32 pitch, F32 yaw, U32 update_type) +{ + if (update_type == UPD_NONE) + { + return false; + } + + LLVector3 displ_global; + bool update_success = true; + bool update_position = update_type & UPD_POSITION; + bool update_rotation = update_type & UPD_ROTATION; + const bool noedit_linked_parts = !gSavedSettings.getBOOL("EditLinkedParts"); + + if (update_position) + { + // calculate the distance of the object closest to the camera origin + F32 min_dist = 1e+30f; + LLVector3 obj_pos; + for (LLObjectSelection::root_iterator it = getSelection()->root_begin(); + it != getSelection()->root_end(); ++it) + { + obj_pos = (*it)->getObject()->getPositionEdit(); + + F32 obj_dist = dist_vec(obj_pos, LLViewerCamera::getInstance()->getOrigin()); + if (obj_dist < min_dist) + { + min_dist = obj_dist; + } + } + + // factor the distance inside the displacement vector. This will get us + // equally visible movements for both close and far away selections. + min_dist = sqrt(min_dist) / 2; + displ_global.setVec(displ.mV[0]*min_dist, + displ.mV[1]*min_dist, + displ.mV[2]*min_dist); + + // equates to: Displ_global = Displ * M_cam_axes_in_global_frame + displ_global = LLViewerCamera::getInstance()->rotateToAbsolute(displ_global); + } + + LLQuaternion new_rot; + if (update_rotation) + { + // let's calculate the rotation around each camera axes + LLQuaternion qx(roll, LLViewerCamera::getInstance()->getAtAxis()); + LLQuaternion qy(pitch, LLViewerCamera::getInstance()->getLeftAxis()); + LLQuaternion qz(yaw, LLViewerCamera::getInstance()->getUpAxis()); + new_rot.setQuat(qx * qy * qz); + } + + LLViewerObject *obj; + S32 obj_count = getSelection()->getObjectCount(); + for (LLObjectSelection::root_iterator it = getSelection()->root_begin(); + it != getSelection()->root_end(); ++it ) + { + obj = (*it)->getObject(); + bool enable_pos = false, enable_rot = false; + bool perm_move = obj->permMove(); + bool perm_mod = obj->permModify(); + + LLVector3d sel_center(getSelectionCenterGlobal()); + + if (update_rotation) + { + enable_rot = perm_move + && ((perm_mod && !obj->isAttachment()) || noedit_linked_parts); + + if (enable_rot) + { + int children_count = obj->getChildren().size(); + if (obj_count > 1 && children_count > 0) + { + // for linked sets, rotate around the group center + const LLVector3 t(obj->getPositionGlobal() - sel_center); + + // Ra = T x R x T^-1 + LLMatrix4 mt; mt.setTranslation(t); + const LLMatrix4 mnew_rot(new_rot); + LLMatrix4 mt_1; mt_1.setTranslation(-t); + mt *= mnew_rot; + mt *= mt_1; + + // Rfin = Rcur * Ra + obj->setRotation(obj->getRotationEdit() * mt.quaternion()); + displ_global += mt.getTranslation(); + } + else + { + obj->setRotation(obj->getRotationEdit() * new_rot); + } + } + else + { + update_success = false; + } + } + + if (update_position) + { + // establish if object can be moved or not + enable_pos = perm_move && !obj->isAttachment() + && (perm_mod || noedit_linked_parts); + + if (enable_pos) + { + obj->setPosition(obj->getPositionEdit() + displ_global); + } + else + { + update_success = false; + } + } + + if (enable_pos && enable_rot && obj->mDrawable.notNull()) + { + gPipeline.markMoved(obj->mDrawable, TRUE); + } + } + + if (update_position && update_success && obj_count > 1) + { + updateSelectionCenter(); + } + + return update_success; +} + +void LLSelectMgr::sendSelectionMove() +{ + LLSelectNode *node = mSelectedObjects->getFirstRootNode(); + if (node == NULL) + { + return; + } + + //saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); + + U32 update_type = UPD_POSITION | UPD_ROTATION; + LLViewerRegion *last_region, *curr_region = node->getObject()->getRegion(); + S32 objects_in_this_packet = 0; + + // apply to linked objects if unable to select their individual parts + if (!gSavedSettings.getBOOL("EditLinkedParts") && !getTEMode()) + { + // tell simulator to apply to whole linked sets + update_type |= UPD_LINKED_SETS; + } + + // prepare first bulk message + gMessageSystem->newMessage("MultipleObjectUpdate"); + packAgentAndSessionID(&update_type); + + LLViewerObject *obj = NULL; + for (LLObjectSelection::root_iterator it = getSelection()->root_begin(); + it != getSelection()->root_end(); ++it) + { + obj = (*it)->getObject(); + + // note: following code adapted from sendListToRegions() (@3924) + last_region = curr_region; + curr_region = obj->getRegion(); + // if not simulator or message too big + if (curr_region != last_region + || gMessageSystem->isSendFull(NULL) + || objects_in_this_packet >= MAX_OBJECTS_PER_PACKET) + { + // send sim the current message and start new one + gMessageSystem->sendReliable(last_region->getHost()); + objects_in_this_packet = 0; + gMessageSystem->newMessage("MultipleObjectUpdate"); + packAgentAndSessionID(&update_type); + } + + // add another instance of the body of data + packMultipleUpdate(*it, &update_type); + ++objects_in_this_packet; + } + + // flush remaining messages + if (gMessageSystem->getCurrentSendTotal() > 0) + { + gMessageSystem->sendReliable(curr_region->getHost()); + } + else + { + gMessageSystem->clearMessage(); + } + + //saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); +} diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 598a962b3c..4a8f99db1f 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -321,7 +321,7 @@ public: bool applyToRootNodes(LLSelectedNodeFunctor* func, bool firstonly = false); bool applyToNodes(LLSelectedNodeFunctor* func, bool firstonly = false); - ESelectType getSelectType() { return mSelectType; } + ESelectType getSelectType() const { return mSelectType; } private: const LLObjectSelection &operator=(const LLObjectSelection &); @@ -516,6 +516,10 @@ public: void selectionResetRotation(); // sets rotation quat to identity void selectionRotateAroundZ(F32 degrees); + bool selectionMove(const LLVector3& displ, F32 rx, F32 ry, F32 rz, + U32 update_type); + void sendSelectionMove(); + void sendGodlikeRequest(const LLString& request, const LLString& parameter); diff --git a/indra/newview/lltoolcomp.cpp b/indra/newview/lltoolcomp.cpp index 7865d8efe3..8d1faa850f 100644 --- a/indra/newview/lltoolcomp.cpp +++ b/indra/newview/lltoolcomp.cpp @@ -300,7 +300,7 @@ BOOL LLToolCompTranslate::handleDoubleClick(S32 x, S32 y, MASK mask) void LLToolCompTranslate::render() { - mCur->render(); + mCur->render(); // removing this will not draw the RGB arrows and guidelines if( mCur != mManip ) { diff --git a/indra/newview/lltoolmgr.cpp b/indra/newview/lltoolmgr.cpp index b20d4f9d28..a4c7856411 100644 --- a/indra/newview/lltoolmgr.cpp +++ b/indra/newview/lltoolmgr.cpp @@ -49,6 +49,8 @@ #include "lltoolselectland.h" #include "lltoolobjpicker.h" #include "lltoolpipette.h" +#include "llagent.h" +#include "llviewercontrol.h" // Used when app not active to avoid processing hover. @@ -227,6 +229,19 @@ BOOL LLToolMgr::inEdit() return mBaseTool != LLToolPie::getInstance() && mBaseTool != gToolNull; } +bool LLToolMgr::inBuildMode() +{ + // when entering mouselook inEdit() immediately returns true before + // cameraMouselook() actually starts returning true. Also, appearance edit + // sets build mode to true, so let's exclude that. + bool b=(inEdit() + && gSavedSettings.getBOOL("BuildBtnState") + && !gAgent.cameraMouselook() + && mCurrentToolset != gFaceEditToolset); + + return b; +} + void LLToolMgr::setTransientTool(LLTool* tool) { if (!tool) diff --git a/indra/newview/lltoolmgr.h b/indra/newview/lltoolmgr.h index 73b8a38c57..e4a4b80dcf 100644 --- a/indra/newview/lltoolmgr.h +++ b/indra/newview/lltoolmgr.h @@ -58,6 +58,9 @@ public: LLTool* getBaseTool(); // returns active tool when overrides are deactivated BOOL inEdit(); + + /* Determines if we are in Build mode or not. */ + bool inBuildMode(); void setTransientTool(LLTool* tool); void clearTransientTool(); diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp index 8657f59ccb..a1a2c34222 100644 --- a/indra/newview/llviewercamera.cpp +++ b/indra/newview/llviewercamera.cpp @@ -47,6 +47,8 @@ #include "llviewerwindow.h" #include "llvovolume.h" #include "llworld.h" +#include "lltoolmgr.h" +#include "llviewerjoystick.h" GLfloat gGLZFar; GLfloat gGLZNear; @@ -97,6 +99,13 @@ void LLViewerCamera::updateCameraLocation(const LLVector3 ¢er, const LLVector3 &up_direction, const LLVector3 &point_of_interest) { + // do not update if we are in build mode AND avatar didn't move + if (LLToolMgr::getInstance()->inBuildMode() + && !LLViewerJoystick::getInstance()->getCameraNeedsUpdate()) + { + return; + } + LLVector3 last_position; LLVector3 last_axis; last_position = getOrigin(); diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 2e76fe33a3..d40073b3e7 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -253,7 +253,7 @@ static void handleAudioVolumeChanged(const LLSD& newvalue) static bool handleJoystickChanged(const LLSD& newvalue) { - LLViewerJoystick::updateCamera(TRUE); + LLViewerJoystick::getInstance()->setCameraNeedsUpdate(TRUE); return true; } @@ -493,13 +493,51 @@ void settings_setup_listeners() gSavedSettings.getControl("WLSkyDetail")->getSignal()->connect(boost::bind(&handleWLSkyDetailChanged, _1)); gSavedSettings.getControl("RenderLightingDetail")->getSignal()->connect(boost::bind(&handleRenderLightingDetailChanged, _1)); gSavedSettings.getControl("NumpadControl")->getSignal()->connect(boost::bind(&handleNumpadControlChanged, _1)); - gSavedSettings.getControl("FlycamAxis0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("FlycamAxis1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("FlycamAxis2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("FlycamAxis3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("FlycamAxis4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("FlycamAxis5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("FlycamAxis6")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("JoystickAxis0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("JoystickAxis1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("JoystickAxis2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("JoystickAxis3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("JoystickAxis4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("JoystickAxis5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("JoystickAxis6")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("FlycamAxisScale0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("FlycamAxisScale1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("FlycamAxisScale2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("FlycamAxisScale3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("FlycamAxisScale4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("FlycamAxisScale5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("FlycamAxisScale6")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("FlycamAxisDeadZone0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("FlycamAxisDeadZone1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("FlycamAxisDeadZone2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("FlycamAxisDeadZone3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("FlycamAxisDeadZone4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("FlycamAxisDeadZone5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("FlycamAxisDeadZone6")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("AvatarAxisScale0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("AvatarAxisScale1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("AvatarAxisScale2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("AvatarAxisScale3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("AvatarAxisScale4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("AvatarAxisScale5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("AvatarAxisDeadZone0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("AvatarAxisDeadZone1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("AvatarAxisDeadZone2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("AvatarAxisDeadZone3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("AvatarAxisDeadZone4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("AvatarAxisDeadZone5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("BuildAxisScale0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("BuildAxisScale1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("BuildAxisScale2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("BuildAxisScale3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("BuildAxisScale4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("BuildAxisScale5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("BuildAxisDeadZone0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("BuildAxisDeadZone1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("BuildAxisDeadZone2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("BuildAxisDeadZone3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("BuildAxisDeadZone4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); + gSavedSettings.getControl("BuildAxisDeadZone5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); gSavedSettings.getControl("DebugViews")->getSignal()->connect(boost::bind(&handleDebugViewsChanged, _1)); gSavedSettings.getControl("UserLogFile")->getSignal()->connect(boost::bind(&handleLogFileChanged, _1)); gSavedSettings.getControl("RenderHideGroupTitle")->getSignal()->connect(boost::bind(handleHideGroupTitleChanged, _1)); diff --git a/indra/newview/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp index a8e898999a..cd4eddb5e1 100644 --- a/indra/newview/llviewerjoystick.cpp +++ b/indra/newview/llviewerjoystick.cpp @@ -1,6 +1,6 @@ /** * @file llviewerjoystick.cpp - * @brief Joystick functionality. + * @brief Joystick / NDOF device functionality. * * $LicenseInfo:firstyear=2002&license=viewergpl$ * @@ -30,39 +30,661 @@ */ #include "llviewerprecompiledheaders.h" + +#include "llviewerjoystick.h" + #include "llviewercontrol.h" #include "llviewerwindow.h" #include "llviewercamera.h" -#include "llviewerjoystick.h" #include "llappviewer.h" #include "llkeyboard.h" +#include "lltoolmgr.h" +#include "llselectmgr.h" +#include "llviewermenu.h" +#include "llagent.h" +#include "llfocusmgr.h" + + +// ---------------------------------------------------------------------------- +// Constants + +#define X_I 1 +#define Y_I 2 +#define Z_I 0 +#define RX_I 4 +#define RY_I 5 +#define RZ_I 3 + +// flycam translations in build mode should be reduced +const F32 BUILDMODE_FLYCAM_T_SCALE = 3.f; + +bool LLViewerJoystick::sOverrideCamera = false; +F32 LLViewerJoystick::sLastDelta[] = {0,0,0,0,0,0,0}; +F32 LLViewerJoystick::sDelta[] = {0,0,0,0,0,0,0}; + +// These constants specify the maximum absolute value coming in from the device. +// HACK ALERT! the value of MAX_JOYSTICK_INPUT_VALUE is not arbitrary as it +// should be. It has to be equal to 3000 because the SpaceNavigator on Windows +// refuses to respond to the DirectInput SetProperty call; it always returns +// values in the [-3000, 3000] range. +#define MAX_SPACENAVIGATOR_INPUT 3000.0f +#define MAX_JOYSTICK_INPUT_VALUE MAX_SPACENAVIGATOR_INPUT + +// ----------------------------------------------------------------------------- +#if LIB_NDOF +NDOF_HotPlugResult LLViewerJoystick::HotPlugAddCallback(NDOF_Device *dev) +{ + LLViewerJoystick* joystick(LLViewerJoystick::getInstance()); + if (joystick->mDriverState == JDS_UNINITIALIZED) + { + llinfos << "HotPlugAddCallback: will use device:" << llendl; + ndof_dump(dev); + joystick->mNdofDev = dev; + joystick->mDriverState = JDS_INITIALIZED; + return NDOF_KEEP_HOTPLUGGED; + } + return NDOF_DISCARD_HOTPLUGGED; +} +#endif + +// ----------------------------------------------------------------------------- +#if LIB_NDOF +void LLViewerJoystick::HotPlugRemovalCallback(NDOF_Device *dev) +{ + LLViewerJoystick* joystick(LLViewerJoystick::getInstance()); + if (joystick->mNdofDev == dev) + { + llinfos << "HotPlugRemovalCallback: joystick->mNdofDev=" + << joystick->mNdofDev << "; removed device:" << llendl; + ndof_dump(dev); + joystick->mDriverState = JDS_UNINITIALIZED; + } +} +#endif + +// ----------------------------------------------------------------------------- +LLViewerJoystick::LLViewerJoystick() +: mDriverState(JDS_UNINITIALIZED), + mNdofDev(NULL), + mResetFlag(false), + mCameraUpdated(true) +{ + for (int i = 0; i < 6; i++) + { + mAxes[i] = sDelta[i] = sLastDelta[i] = 0.0f; + } + + memset(mBtn, 0, sizeof(mBtn)); + + // factor in bandwidth? bandwidth = gViewerStats->mKBitStat + mPerfScale = 4000.f / gSysCPU.getMhz(); +} + +// ----------------------------------------------------------------------------- +LLViewerJoystick::~LLViewerJoystick() +{ + if (mDriverState == JDS_INITIALIZED) + { + terminate(); + } +} + +// ----------------------------------------------------------------------------- +void LLViewerJoystick::init() +{ +#if LIB_NDOF + static bool libinit = false; + mDriverState = JDS_INITIALIZING; + + if (libinit == false) + { + if (ndof_libinit(HotPlugAddCallback, + HotPlugRemovalCallback, + NULL)) + { + mDriverState = JDS_UNINITIALIZED; + } + else + { + // NB: ndof_libinit succeeds when there's no device + libinit = true; + + // allocate memory once for an eventual device + mNdofDev = ndof_create(); + } + } + + if (libinit) + { + if (mNdofDev) + { + // Different joysticks will return different ranges of raw values. + // Since we want to handle every device in the same uniform way, + // we initialize the mNdofDev struct and we set the range + // of values we would like to receive. + // + // HACK: On Windows, libndofdev passes our range to DI with a + // SetProperty call. This works but with one notable exception, the + // SpaceNavigator, who doesn't seem to care about the SetProperty + // call. In theory, we should handle this case inside libndofdev. + // However, the range we're setting here is arbitrary anyway, + // so let's just use the SpaceNavigator range for our purposes. + mNdofDev->axes_min = (long)-MAX_JOYSTICK_INPUT_VALUE; + mNdofDev->axes_max = (long)+MAX_JOYSTICK_INPUT_VALUE; + + // libndofdev could be used to return deltas. Here we choose to + // just have the absolute values instead. + mNdofDev->absolute = 1; + + // init & use the first suitable NDOF device found on the USB chain + if (ndof_init_first(mNdofDev, NULL)) + { + mDriverState = JDS_UNINITIALIZED; + llwarns << "ndof_init_first FAILED" << llendl; + } + else + { + mDriverState = JDS_INITIALIZED; + } + } + else + { + mDriverState = JDS_UNINITIALIZED; + } + } + + llinfos << "ndof: mDriverState=" << mDriverState << "; mNdofDev=" + << mNdofDev << "; libinit=" << libinit << llendl; +#endif +} + +// ----------------------------------------------------------------------------- +void LLViewerJoystick::terminate() +{ +#if LIB_NDOF + + ndof_libcleanup(); + llinfos << "Terminated connection with NDOF device." << llendl; + +#endif +} + +// ----------------------------------------------------------------------------- +void LLViewerJoystick::updateStatus() +{ +#if LIB_NDOF + + ndof_update(mNdofDev); + + for (int i=0; i<6; i++) + { + mAxes[i] = (F32) mNdofDev->axes[i] / mNdofDev->axes_max; + } + + for (int i=0; i<16; i++) + { + mBtn[i] = mNdofDev->buttons[i]; + } + +#endif +} + +// ----------------------------------------------------------------------------- +F32 LLViewerJoystick::getJoystickAxis(U32 axis) const +{ + if (axis < 6) + { + return mAxes[axis]; + } + return 0.f; +} + +// ----------------------------------------------------------------------------- +U32 LLViewerJoystick::getJoystickButton(U32 button) const +{ + if (button < 16) + { + return mBtn[button]; + } + return 0; +} + +// ----------------------------------------------------------------------------- +void LLViewerJoystick::agentJump() +{ + gAgent.moveUp(1); +} + +// ----------------------------------------------------------------------------- +void LLViewerJoystick::agentSlide(F32 inc) +{ + if (inc < 0) + { + gAgent.moveLeft(1); + } + else if (inc > 0) + { + gAgent.moveLeft(-1); + } +} + +// ----------------------------------------------------------------------------- +void LLViewerJoystick::agentPush(F32 inc) +{ + if (inc < 0) // forward + { + gAgent.moveAt(1, false); + } + else if (inc > 0) // backward + { + gAgent.moveAt(-1, false); + } +} + +// ----------------------------------------------------------------------------- +void LLViewerJoystick::agentFly(F32 inc) +{ + if (inc < 0) + { + if (gAgent.getFlying()) + { + gAgent.moveUp(1); + } + else + { + gAgent.setFlying(true); + } + } + else if (inc > 0) + { + // crouch + gAgent.moveUp(-1); + } +} + +// ----------------------------------------------------------------------------- +void LLViewerJoystick::agentRotate(F32 pitch_inc, F32 yaw_inc) +{ + LLQuaternion new_rot; + pitch_inc = gAgent.clampPitchToLimits(-pitch_inc); + const LLQuaternion qx(pitch_inc, gAgent.getLeftAxis()); + const LLQuaternion qy(-yaw_inc, gAgent.getReferenceUpVector()); + new_rot.setQuat(qx * qy); + gAgent.rotate(new_rot); +} + +// ----------------------------------------------------------------------------- +void LLViewerJoystick::resetDeltas(S32 axis[], bool flycam_and_build_mode) +{ + for (U32 i = 0; i < 6; i++) + { + sLastDelta[i] = -mAxes[axis[i]]; + sDelta[i] = 0.f; + } + + if (flycam_and_build_mode) + { + sLastDelta[X_I] /= BUILDMODE_FLYCAM_T_SCALE; + sLastDelta[Y_I] /= BUILDMODE_FLYCAM_T_SCALE; + sLastDelta[Z_I] /= BUILDMODE_FLYCAM_T_SCALE; + } + + sLastDelta[6] = sDelta[6] = 0.f; + mResetFlag = false; +} + +// ----------------------------------------------------------------------------- +void LLViewerJoystick::moveObjects(bool reset) +{ + static bool toggle_send_to_sim = false; + + if (!gFocusMgr.getAppHasFocus() || mDriverState != JDS_INITIALIZED) + { + return; + } + + S32 axis[] = + { + gSavedSettings.getS32("JoystickAxis0"), + gSavedSettings.getS32("JoystickAxis1"), + gSavedSettings.getS32("JoystickAxis2"), + gSavedSettings.getS32("JoystickAxis3"), + gSavedSettings.getS32("JoystickAxis4"), + gSavedSettings.getS32("JoystickAxis5"), + }; + + if (reset || mResetFlag) + { + resetDeltas(axis); + return; + } + + F32 axis_scale[] = + { + gSavedSettings.getF32("BuildAxisScale0"), + gSavedSettings.getF32("BuildAxisScale1"), + gSavedSettings.getF32("BuildAxisScale2"), + gSavedSettings.getF32("BuildAxisScale3"), + gSavedSettings.getF32("BuildAxisScale4"), + gSavedSettings.getF32("BuildAxisScale5"), + }; + + F32 dead_zone[] = + { + gSavedSettings.getF32("BuildAxisDeadZone0"), + gSavedSettings.getF32("BuildAxisDeadZone1"), + gSavedSettings.getF32("BuildAxisDeadZone2"), + gSavedSettings.getF32("BuildAxisDeadZone3"), + gSavedSettings.getF32("BuildAxisDeadZone4"), + gSavedSettings.getF32("BuildAxisDeadZone5"), + }; + + F32 cur_delta[6]; + F32 time = gFrameIntervalSeconds; + + // avoid making ridicously big movements if there's a big drop in fps + if (time > .2f) + { + time = .2f; + } + + // max feather is 32 + F32 feather = gSavedSettings.getF32("BuildFeathering"); + bool is_zero = true, absolute = gSavedSettings.getBOOL("Cursor3D"); + + for (U32 i = 0; i < 6; i++) + { + cur_delta[i] = -mAxes[axis[i]]; + F32 tmp = cur_delta[i]; + if (absolute) + { + cur_delta[i] = cur_delta[i] - sLastDelta[i]; + } + sLastDelta[i] = tmp; + is_zero = is_zero && (cur_delta[i] == 0.f); + + if (cur_delta[i] > 0) + { + cur_delta[i] = llmax(cur_delta[i]-dead_zone[i], 0.f); + } + else + { + cur_delta[i] = llmin(cur_delta[i]+dead_zone[i], 0.f); + } + cur_delta[i] *= axis_scale[i]; + + if (!absolute) + { + cur_delta[i] *= time; + } -static LLQuaternion sFlycamRotation; -static LLVector3 sFlycamPosition; -static F32 sFlycamZoom; + sDelta[i] = sDelta[i] + (cur_delta[i]-sDelta[i])*time*feather; + } -BOOL LLViewerJoystick::sOverrideCamera = FALSE; + U32 upd_type = UPD_NONE; + LLVector3 v; + + if (!is_zero) + { + if (sDelta[0] || sDelta[1] || sDelta[2]) + { + upd_type |= UPD_POSITION; + v.setVec(sDelta[0], sDelta[1], sDelta[2]); + } + + if (sDelta[3] || sDelta[4] || sDelta[5]) + { + upd_type |= UPD_ROTATION; + } + + // the selection update could fail, so we won't send + if (LLSelectMgr::getInstance()->selectionMove(v, sDelta[3],sDelta[4],sDelta[5], upd_type)) + { + toggle_send_to_sim = true; + } + } + else if (toggle_send_to_sim) + { + LLSelectMgr::getInstance()->sendSelectionMove(); + toggle_send_to_sim = false; + } +} -void LLViewerJoystick::updateCamera(BOOL reset) +// ----------------------------------------------------------------------------- +void LLViewerJoystick::moveAvatar(bool reset) { - static F32 last_delta[] = {0,0,0,0,0,0,0}; - static F32 delta[] = { 0,0,0,0,0,0,0 }; + if (!gFocusMgr.getAppHasFocus() || mDriverState != JDS_INITIALIZED) + { + return; + } + + S32 axis[] = + { + // [1 0 2 4 3 5] + // [Z X Y RZ RX RY] + gSavedSettings.getS32("JoystickAxis0"), + gSavedSettings.getS32("JoystickAxis1"), + gSavedSettings.getS32("JoystickAxis2"), + gSavedSettings.getS32("JoystickAxis3"), + gSavedSettings.getS32("JoystickAxis4"), + gSavedSettings.getS32("JoystickAxis5") + }; + + if (reset || mResetFlag) + { + resetDeltas(axis); + if (reset) + { + // Note: moving the agent triggers agent camera mode; + // don't do this every time we set mResetFlag (e.g. because we gained focus) + gAgent.moveAt(0, true); + } + return; + } + + if (mBtn[1] == 1) + { + agentJump(); + return; + } + + F32 axis_scale[] = + { + gSavedSettings.getF32("AvatarAxisScale0"), + gSavedSettings.getF32("AvatarAxisScale1"), + gSavedSettings.getF32("AvatarAxisScale2"), + gSavedSettings.getF32("AvatarAxisScale3"), + gSavedSettings.getF32("AvatarAxisScale4"), + gSavedSettings.getF32("AvatarAxisScale5") + }; - LLWindow* window = gViewerWindow->getWindow(); + F32 dead_zone[] = + { + gSavedSettings.getF32("AvatarAxisDeadZone0"), + gSavedSettings.getF32("AvatarAxisDeadZone1"), + gSavedSettings.getF32("AvatarAxisDeadZone2"), + gSavedSettings.getF32("AvatarAxisDeadZone3"), + gSavedSettings.getF32("AvatarAxisDeadZone4"), + gSavedSettings.getF32("AvatarAxisDeadZone5") + }; + // time interval in seconds between this frame and the previous F32 time = gFrameIntervalSeconds; + // avoid making ridicously big movements if there's a big drop in fps + if (time > .2f) + { + time = .2f; + } + + // note: max feather is 32.0 + F32 feather = gSavedSettings.getF32("AvatarFeathering"); + + F32 cur_delta[6]; + F32 val, dom_mov = 0.f; + U32 dom_axis = Z_I; +#if LIB_NDOF + bool absolute = (gSavedSettings.getBOOL("Cursor3D") && mNdofDev->absolute); +#else + bool absolute = false; +#endif + // remove dead zones and determine biggest movement on the joystick + for (U32 i = 0; i < 6; i++) + { + cur_delta[i] = -mAxes[axis[i]]; + if (absolute) + { + F32 tmp = cur_delta[i]; + cur_delta[i] = cur_delta[i] - sLastDelta[i]; + sLastDelta[i] = tmp; + } + + if (cur_delta[i] > 0) + { + cur_delta[i] = llmax(cur_delta[i]-dead_zone[i], 0.f); + } + else + { + cur_delta[i] = llmin(cur_delta[i]+dead_zone[i], 0.f); + } + + // we don't care about Roll (RZ) and Z is calculated after the loop + if (i != Z_I && i != RZ_I) + { + // find out the axis with the biggest joystick motion + val = fabs(cur_delta[i]); + if (val > dom_mov) + { + dom_axis = i; + dom_mov = val; + } + } + } + + // forward|backward movements overrule the real dominant movement if + // they're bigger than its 20%. This is what you want cos moving forward + // is what you do most. We also added a special (even more lenient) case + // for RX|RY to allow walking while pitching n' turning + if (fabs(cur_delta[Z_I]) > .2f * dom_mov + || ((dom_axis == RX_I || dom_axis == RY_I) + && fabs(cur_delta[Z_I]) > .05f * dom_mov)) + { + dom_axis = Z_I; + } + + sDelta[X_I] = -cur_delta[X_I] * axis_scale[X_I]; + sDelta[Y_I] = -cur_delta[Y_I] * axis_scale[Y_I]; + sDelta[Z_I] = -cur_delta[Z_I] * axis_scale[Z_I]; + cur_delta[RX_I] *= -axis_scale[RX_I] * mPerfScale; + cur_delta[RY_I] *= -axis_scale[RY_I] * mPerfScale; + + if (!absolute) + { + cur_delta[RX_I] *= time; + cur_delta[RY_I] *= time; + } + sDelta[RX_I] += (cur_delta[RX_I] - sDelta[RX_I]) * time * feather; + sDelta[RY_I] += (cur_delta[RY_I] - sDelta[RY_I]) * time * feather; + + switch (dom_axis) + { + case X_I: // move sideways + agentSlide(sDelta[X_I]); + break; + + case Z_I: // forward/back + { + agentPush(sDelta[Z_I]); + + if (fabs(sDelta[Y_I]) > .1f) + { + agentFly(sDelta[Y_I]); + } + + // too many rotations during walking can be confusing, so apply + // the deadzones one more time (quick & dirty), at 50%|30% power + F32 eff_rx = .3f * dead_zone[RX_I]; + F32 eff_ry = .3f * dead_zone[RY_I]; + + if (sDelta[RX_I] > 0) + { + eff_rx = llmax(sDelta[RX_I] - eff_rx, 0.f); + } + else + { + eff_rx = llmin(sDelta[RX_I] + eff_rx, 0.f); + } + + if (sDelta[RY_I] > 0) + { + eff_ry = llmax(sDelta[RY_I] - eff_ry, 0.f); + } + else + { + eff_ry = llmin(sDelta[RY_I] + eff_ry, 0.f); + } + + + if (fabs(eff_rx) > 0.f || fabs(eff_ry) > 0.f) + { + if (gAgent.getFlying()) + { + agentRotate(eff_rx, eff_ry); + } + else + { + agentRotate(eff_rx, 2.f * eff_ry); + } + } + break; + } + case Y_I: // up/crouch + agentFly(sDelta[Y_I]); + break; + + case RX_I: // pitch + case RY_I: // turn + agentRotate(sDelta[RX_I], sDelta[RY_I]); + break; + // case RZ_I: roll is unused in avatar mode + }// switch +} + +// ----------------------------------------------------------------------------- +void LLViewerJoystick::moveFlycam(bool reset) +{ + static LLQuaternion sFlycamRotation; + static LLVector3 sFlycamPosition; + static F32 sFlycamZoom; + + if (!gFocusMgr.getAppHasFocus() || mDriverState != JDS_INITIALIZED) + { + return; + } + S32 axis[] = { - gSavedSettings.getS32("FlycamAxis0"), - gSavedSettings.getS32("FlycamAxis1"), - gSavedSettings.getS32("FlycamAxis2"), - gSavedSettings.getS32("FlycamAxis3"), - gSavedSettings.getS32("FlycamAxis4"), - gSavedSettings.getS32("FlycamAxis5"), - gSavedSettings.getS32("FlycamAxis6") + gSavedSettings.getS32("JoystickAxis0"), + gSavedSettings.getS32("JoystickAxis1"), + gSavedSettings.getS32("JoystickAxis2"), + gSavedSettings.getS32("JoystickAxis3"), + gSavedSettings.getS32("JoystickAxis4"), + gSavedSettings.getS32("JoystickAxis5"), + gSavedSettings.getS32("JoystickAxis6") }; + bool in_build_mode = LLToolMgr::getInstance()->inBuildMode(); + if (reset || mResetFlag) + { + sFlycamPosition = LLViewerCamera::getInstance()->getOrigin(); + sFlycamRotation = LLViewerCamera::getInstance()->getQuaternion(); + sFlycamZoom = LLViewerCamera::getInstance()->getView(); + + resetDeltas(axis, in_build_mode); + + return; + } + F32 axis_scale[] = { gSavedSettings.getF32("FlycamAxisScale0"), @@ -85,33 +707,37 @@ void LLViewerJoystick::updateCamera(BOOL reset) gSavedSettings.getF32("FlycamAxisDeadZone6") }; - if (reset) - { - sFlycamPosition = LLViewerCamera::getInstance()->getOrigin(); - sFlycamRotation = LLViewerCamera::getInstance()->getQuaternion(); - sFlycamZoom = LLViewerCamera::getInstance()->getView(); + F32 time = gFrameIntervalSeconds; - for (U32 i = 0; i < 7; i++) - { - last_delta[i] = -window->getJoystickAxis(axis[i]); - delta[i] = 0.f; - } - return; + // avoid making ridicously big movements if there's a big drop in fps + if (time > .2f) + { + time = .2f; } F32 cur_delta[7]; F32 feather = gSavedSettings.getF32("FlycamFeathering"); - BOOL absolute = gSavedSettings.getBOOL("FlycamAbsolute"); + bool absolute = gSavedSettings.getBOOL("Cursor3D"); for (U32 i = 0; i < 7; i++) { - cur_delta[i] = -window->getJoystickAxis(axis[i]); + cur_delta[i] = -getJoystickAxis(axis[i]); + + // we need smaller camera movements in build mode + if (in_build_mode) + { + if (i == X_I || i == Y_I || i == Z_I) + { + cur_delta[i] /= BUILDMODE_FLYCAM_T_SCALE; + } + } + F32 tmp = cur_delta[i]; if (absolute) { - cur_delta[i] = cur_delta[i] - last_delta[i]; + cur_delta[i] = cur_delta[i] - sLastDelta[i]; } - last_delta[i] = tmp; + sLastDelta[i] = tmp; if (cur_delta[i] > 0) { @@ -128,18 +754,15 @@ void LLViewerJoystick::updateCamera(BOOL reset) cur_delta[i] *= time; } - delta[i] = delta[i] + (cur_delta[i]-delta[i])*time*feather; + sDelta[i] = sDelta[i] + (cur_delta[i]-sDelta[i])*time*feather; } - sFlycamPosition += LLVector3(delta) * sFlycamRotation; + sFlycamPosition += LLVector3(sDelta) * sFlycamRotation; - LLMatrix3 rot_mat(delta[3], - delta[4], - delta[5]); - + LLMatrix3 rot_mat(sDelta[3], sDelta[4], sDelta[5]); sFlycamRotation = LLQuaternion(rot_mat)*sFlycamRotation; - if (gSavedSettings.getBOOL("FlycamAutoLeveling")) + if (gSavedSettings.getBOOL("AutoLeveling")) { LLMatrix3 level(sFlycamRotation); @@ -153,17 +776,17 @@ void LLViewerJoystick::updateCamera(BOOL reset) level.setRows(x,y,z); level.orthogonalize(); - LLQuaternion quat = LLQuaternion(level); + LLQuaternion quat(level); sFlycamRotation = nlerp(llmin(feather*time,1.f), sFlycamRotation, quat); } - if (gSavedSettings.getBOOL("FlycamZoomDirect")) + if (gSavedSettings.getBOOL("ZoomDirect")) { - sFlycamZoom = last_delta[6]*axis_scale[6]+dead_zone[6]; + sFlycamZoom = sLastDelta[6]*axis_scale[6]+dead_zone[6]; } else { - sFlycamZoom += delta[6]; + sFlycamZoom += sDelta[6]; } LLMatrix3 mat(sFlycamRotation); @@ -175,101 +798,52 @@ void LLViewerJoystick::updateCamera(BOOL reset) LLViewerCamera::getInstance()->mZAxis = LLVector3(mat.mMatrix[2]); } - +// ----------------------------------------------------------------------------- void LLViewerJoystick::scanJoystick() { - if (!sOverrideCamera) + if (mDriverState != JDS_INITIALIZED) { - static U32 joystick_state = 0; - static U32 button_state = 0; + return; + } - F32 xval = gViewerWindow->getWindow()->getJoystickAxis(0); - F32 yval = gViewerWindow->getWindow()->getJoystickAxis(1); +#if LL_WINDOWS + // On windows, the flycam is updated syncronously with a timer, so there is + // no need to update the status of the joystick here. + if (!sOverrideCamera) +#endif + updateStatus(); - if (xval <= -0.5f) - { - if (!(joystick_state & 0x1)) - { - gKeyboard->handleTranslatedKeyDown(KEY_PAD_LEFT, 0); - joystick_state |= 0x1; - } - } - else - { - if (joystick_state & 0x1) - { - gKeyboard->handleTranslatedKeyUp(KEY_PAD_LEFT, 0); - joystick_state &= ~0x1; - } - } - if (xval >= 0.5f) - { - if (!(joystick_state & 0x2)) - { - gKeyboard->handleTranslatedKeyDown(KEY_PAD_RIGHT, 0); - joystick_state |= 0x2; - } - } - else - { - if (joystick_state & 0x2) - { - gKeyboard->handleTranslatedKeyUp(KEY_PAD_RIGHT, 0); - joystick_state &= ~0x2; - } - } - if (yval <= -0.5f) - { - if (!(joystick_state & 0x4)) - { - gKeyboard->handleTranslatedKeyDown(KEY_PAD_UP, 0); - joystick_state |= 0x4; - } - } - else - { - if (joystick_state & 0x4) - { - gKeyboard->handleTranslatedKeyUp(KEY_PAD_UP, 0); - joystick_state &= ~0x4; - } - } - if (yval >= 0.5f) - { - if (!(joystick_state & 0x8)) - { - gKeyboard->handleTranslatedKeyDown(KEY_PAD_DOWN, 0); - joystick_state |= 0x8; - } - } - else - { - if (joystick_state & 0x8) - { - gKeyboard->handleTranslatedKeyUp(KEY_PAD_DOWN, 0); - joystick_state &= ~0x8; - } - } + static long toggle_flycam = 0; - for( int i = 0; i < 15; i++ ) + if (mBtn[0] == 1) + { + if (mBtn[0] != toggle_flycam) { - if ( gViewerWindow->getWindow()->getJoystickButton(i) & 0x80 ) - { - if (!(button_state & (1<handleTranslatedKeyDown(KEY_BUTTON1+i, 0); - button_state |= (1<handleTranslatedKeyUp(KEY_BUTTON1+i, 0); - button_state &= ~(1<inBuildMode()) + { + moveAvatar(); + } } +// ----------------------------------------------------------------------------- +bool LLViewerJoystick::isLikeSpaceNavigator() const +{ +#if LIB_NDOF + return (isJoystickInitialized() + && (strncmp(mNdofDev->product, "SpaceNavigator", 14) == 0 + || strncmp(mNdofDev->product, "SpaceExplorer", 13) == 0 + || strncmp(mNdofDev->product, "SpaceTraveler", 13) == 0 + || strncmp(mNdofDev->product, "SpacePilot", 10) == 0)); +#else + return false; +#endif +} diff --git a/indra/newview/llviewerjoystick.h b/indra/newview/llviewerjoystick.h index f2fc24b813..47acf17f17 100644 --- a/indra/newview/llviewerjoystick.h +++ b/indra/newview/llviewerjoystick.h @@ -1,6 +1,6 @@ /** * @file llviewerjoystick.h - * @brief Viewer joystick functionality. + * @brief Viewer joystick / NDOF device functionality. * * $LicenseInfo:firstyear=2001&license=viewergpl$ * @@ -32,12 +32,69 @@ #ifndef LL_LLVIEWERJOYSTICK_H #define LL_LLVIEWERJOYSTICK_H -class LLViewerJoystick +#include "stdtypes.h" + +#define LIB_NDOF (LL_WINDOWS || LL_DARWIN) + +#if LIB_NDOF +#include "ndofdev_external.h" +#else +#define NDOF_Device void +#define NDOF_HotPlugResult S32 +#endif + +typedef enum e_joystick_driver_state +{ + JDS_UNINITIALIZED, + JDS_INITIALIZED, + JDS_INITIALIZING +} EJoystickDriverState; + +class LLViewerJoystick : public LLSingleton { public: - static BOOL sOverrideCamera; - static void scanJoystick(); - static void updateCamera(BOOL reset = FALSE); + static bool sOverrideCamera; + + void init(); + void updateStatus(); + void scanJoystick(); + void moveObjects(bool reset = false); + void moveAvatar(bool reset = false); + void moveFlycam(bool reset = false); + F32 getJoystickAxis(U32 axis) const; + U32 getJoystickButton(U32 button) const; + bool isJoystickInitialized() const {return (mDriverState==JDS_INITIALIZED);} + bool isLikeSpaceNavigator() const; + void setNeedsReset(bool reset = true) { mResetFlag = reset; } + void setCameraNeedsUpdate(bool b) { mCameraUpdated = b; } + bool getCameraNeedsUpdate() const { return mCameraUpdated; } + + LLViewerJoystick(); + virtual ~LLViewerJoystick(); + +protected: + void terminate(); + void agentSlide(F32 inc); + void agentPush(F32 inc); + void agentFly(F32 inc); + void agentRotate(F32 pitch_inc, F32 turn_inc); + void agentJump(); + void resetDeltas(S32 axis[], bool flycam_and_build = false); +#if LIB_NDOF + static NDOF_HotPlugResult HotPlugAddCallback(NDOF_Device *dev); + static void HotPlugRemovalCallback(NDOF_Device *dev); +#endif + +private: + F32 mAxes[6]; + long mBtn[16]; + EJoystickDriverState mDriverState; + NDOF_Device *mNdofDev; + bool mResetFlag; + F32 mPerfScale; + bool mCameraUpdated; + static F32 sLastDelta[7]; + static F32 sDelta[7]; }; #endif diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 4234d4862c..ec52118098 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -67,7 +67,6 @@ #include "llagentpilot.h" #include "llbox.h" #include "llcallingcard.h" -#include "llcameraview.h" #include "llclipboard.h" #include "llcompilequeue.h" #include "llconsole.h" @@ -466,8 +465,6 @@ void handle_dump_image_list(void*); void handle_crash(void*); void handle_dump_followcam(void*); -void handle_toggle_flycam(void*); -BOOL check_flycam(void*); void handle_viewer_enable_message_log(void*); void handle_viewer_disable_message_log(void*); void handle_send_postcard(void*); @@ -1082,9 +1079,6 @@ void init_client_menu(LLMenuGL* menu) &menu_check_control, (void*)"DisableCameraConstraints")); - menu->append(new LLMenuItemCheckGL("Joystick Flycam", - &handle_toggle_flycam,NULL,&check_flycam,NULL)); - menu->append(new LLMenuItemCheckGL("Mouse Smoothing", &menu_toggle_control, NULL, @@ -1825,9 +1819,17 @@ bool toggle_build_mode() { // just reset the view, will pull us out of edit mode handle_reset_view(); + + // avoid spurious avatar movements pulling out of edit mode + LLViewerJoystick::getInstance()->moveAvatar(true); } else { + if (LLViewerJoystick::sOverrideCamera) + { + handle_toggle_flycam(); + } + if (gAgent.getFocusOnAvatar() && gSavedSettings.getBOOL("EditCameraMovement") ) { // zoom in if we're looking at the avatar @@ -1855,6 +1857,46 @@ class LLViewBuildMode : public view_listener_t }; +class LLViewJoystickFlycam : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) + { + handle_toggle_flycam(); + return true; + } +}; + +class LLViewCheckJoystickFlycam : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) + { + bool new_val = LLViewerJoystick::sOverrideCamera; + gMenuHolder->findControl(userdata["control"].asString())->setValue(new_val); + return true; + } +}; + +void handle_toggle_flycam() +{ + LLViewerJoystick::sOverrideCamera = !LLViewerJoystick::sOverrideCamera; + if (LLViewerJoystick::sOverrideCamera) + { + LLViewerJoystick::getInstance()->moveFlycam(true); + } + else if (!LLToolMgr::getInstance()->inBuildMode()) + { + LLViewerJoystick::getInstance()->moveAvatar(true); + } + else + { + // we are in build mode, exiting from the flycam mode: since we are + // going to keep the flycam POV for the main camera until the avatar + // moves, we need to track this situation. + LLViewerJoystick::getInstance()->setCameraNeedsUpdate(false); + LLViewerJoystick::getInstance()->setNeedsReset(true); + } +} + class LLObjectBuild : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) @@ -1916,6 +1958,9 @@ class LLObjectEdit : public view_listener_t LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); gFloaterTools->setEditTool( LLToolCompTranslate::getInstance() ); + LLViewerJoystick::getInstance()->moveObjects(true); + LLViewerJoystick::getInstance()->setNeedsReset(true); + // Could be first use LLFirstUse::useBuild(); return true; @@ -3339,7 +3384,13 @@ void reset_view_final( BOOL proceed, void* ) if (LLViewerJoystick::sOverrideCamera) { - handle_toggle_flycam(NULL); + handle_toggle_flycam(); + } + + // reset avatar mode from eventual residual motion + if (LLToolMgr::getInstance()->inBuildMode()) + { + LLViewerJoystick::getInstance()->moveAvatar(true); } gAgent.resetView(!gFloaterTools->getVisible()); @@ -5252,21 +5303,6 @@ void handle_dump_followcam(void*) LLFollowCamMgr::dump(); } -BOOL check_flycam(void*) -{ - return LLViewerJoystick::sOverrideCamera; -} - -void handle_toggle_flycam(void*) -{ - LLViewerJoystick::sOverrideCamera = !LLViewerJoystick::sOverrideCamera; - if (LLViewerJoystick::sOverrideCamera) - { - LLViewerJoystick::updateCamera(TRUE); - LLFloaterJoystick::show(NULL); - } -} - void handle_viewer_enable_message_log(void*) { gMessageSystem->startLogging(); @@ -7715,6 +7751,7 @@ void initialize_menus() // View menu addMenu(new LLViewMouselook(), "View.Mouselook"); addMenu(new LLViewBuildMode(), "View.BuildMode"); + addMenu(new LLViewJoystickFlycam(), "View.JoystickFlycam"); addMenu(new LLViewResetView(), "View.ResetView"); addMenu(new LLViewLookAtLastChatter(), "View.LookAtLastChatter"); addMenu(new LLViewShowHoverTips(), "View.ShowHoverTips"); @@ -7733,6 +7770,7 @@ void initialize_menus() addMenu(new LLViewEnableLastChatter(), "View.EnableLastChatter"); addMenu(new LLViewCheckBuildMode(), "View.CheckBuildMode"); + addMenu(new LLViewCheckJoystickFlycam(), "View.CheckJoystickFlycam"); addMenu(new LLViewCheckShowHoverTips(), "View.CheckShowHoverTips"); addMenu(new LLViewCheckHighlightTransparent(), "View.CheckHighlightTransparent"); addMenu(new LLViewCheckBeaconEnabled(), "View.CheckBeaconEnabled"); diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index 21b2554ceb..98b08c4985 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -102,6 +102,7 @@ void handle_sit_down(void*); bool toggle_build_mode(); void handle_object_build(void*); void handle_save_snapshot(void *); +void handle_toggle_flycam(); bool handle_sit_or_stand(); bool handle_give_money_dialog(); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 697aea8582..696a2ad3c6 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -32,6 +32,7 @@ #include "llviewerprecompiledheaders.h" #include "llpanellogin.h" +#include "llviewerkeyboard.h" #include "llviewerwindow.h" // system library includes @@ -180,6 +181,7 @@ #include "llurlsimstring.h" #include "llviewerdisplay.h" #include "llspatialpartition.h" +#include "llviewerjoystick.h" #if LL_WINDOWS #include "llwindebug.h" @@ -514,6 +516,13 @@ public: addText(xpos, ypos, llformat("FOV: %2.1f deg", RAD_TO_DEG * LLViewerCamera::getInstance()->getView())); ypos += y_inc; } + + if (LLViewerJoystick::sOverrideCamera) + { + addText(xpos + 200, ypos, llformat("Flycam")); + ypos += y_inc; + } + if (gSavedSettings.getBOOL("DebugShowRenderInfo")) { if (gPipeline.getUseVertexShaders() == 0) @@ -1302,6 +1311,7 @@ BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key, MASK mask) void LLViewerWindow::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) { + LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true); return gViewerKeyboard.scanKey(key, key_down, key_up, key_level); } @@ -1364,6 +1374,12 @@ BOOL LLViewerWindow::handleActivate(LLWindow *window, BOOL activated) return TRUE; } +BOOL LLViewerWindow::handleActivateApp(LLWindow *window, BOOL activating) +{ + LLViewerJoystick::getInstance()->setNeedsReset(true); + return FALSE; +} + void LLViewerWindow::handleMenuSelect(LLWindow *window, S32 menu_item) { @@ -1450,6 +1466,26 @@ void LLViewerWindow::handleDataCopy(LLWindow *window, S32 data_type, void *data) } } +BOOL LLViewerWindow::handleTimerEvent(LLWindow *window) +{ + if (LLViewerJoystick::sOverrideCamera) + { + LLViewerJoystick::getInstance()->updateStatus(); + return TRUE; + } + return FALSE; +} + +BOOL LLViewerWindow::handleDeviceChange(LLWindow *window) +{ + // give a chance to use a joystick after startup (hot-plugging) + if (!LLViewerJoystick::getInstance()->isJoystickInitialized() ) + { + LLViewerJoystick::getInstance()->init(); + return TRUE; + } + return FALSE; +} // // Classes diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index ef3b5146e2..cad3bb031f 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -97,6 +97,7 @@ public: /*virtual*/ void handleFocus(LLWindow *window); /*virtual*/ void handleFocusLost(LLWindow *window); /*virtual*/ BOOL handleActivate(LLWindow *window, BOOL activated); + /*virtual*/ BOOL handleActivateApp(LLWindow *window, BOOL activating); /*virtual*/ void handleMenuSelect(LLWindow *window, S32 menu_item); /*virtual*/ BOOL handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S32 height); /*virtual*/ void handleScrollWheel(LLWindow *window, S32 clicks); @@ -104,6 +105,9 @@ public: /*virtual*/ void handleWindowBlock(LLWindow *window); /*virtual*/ void handleWindowUnblock(LLWindow *window); /*virtual*/ void handleDataCopy(LLWindow *window, S32 data_type, void *data); + /*virtual*/ BOOL handleTimerEvent(LLWindow *window); + /*virtual*/ BOOL handleDeviceChange(LLWindow *window); + // diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index e73d278043..edb7002584 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -342,6 +342,9 @@ class DarwinManifest(ViewerManifest): # /Contents/MacOS/ self.contents_of_tar('mozilla-universal-darwin.tgz', 'MacOS') + # copy additional libs in /Contents/MacOS/ + self.path("../../libraries/universal-darwin/lib_release/libndofdev.dylib", dst="MacOS/libndofdev.dylib") + # replace the default theme with our custom theme (so scrollbars work). if self.prefix(src="mozilla-theme", dst="MacOS/chrome"): self.path("classic.jar") -- cgit v1.2.3