From f33ee6aa3e075ffb9d8649bf9fcd6649652c24d9 Mon Sep 17 00:00:00 2001 From: Christopher Bruns Date: Sun, 27 Oct 2013 08:24:47 -0400 Subject: [PATCH] Client|Renderer|Stereo 3D: Remove global VR::mode variable, in favor of Con_GetInteger("rend-vr-mode") Adjust link libraries for Win32 Oculus Rift SDK Adjust comments in vr.h --- doomsday/client/include/render/vr.h | 45 +++++---- doomsday/client/src/render/vr.cpp | 124 +++++++++++++++++++++++- doomsday/client/src/ui/clientwindow.cpp | 6 +- doomsday/dep_rift.pri | 5 +- 4 files changed, 154 insertions(+), 26 deletions(-) diff --git a/doomsday/client/include/render/vr.h b/doomsday/client/include/render/vr.h index 5a0bc8d615..351271c94d 100644 --- a/doomsday/client/include/render/vr.h +++ b/doomsday/client/include/render/vr.h @@ -3,8 +3,10 @@ namespace VR { -// The order shown here determines the integer value in the console. -/// @todo - Should rend-vr-mode console variable be a string instead of an int, for better semantics (but decreased discoverability)? +/// Menu of stereoscopic 3D modes available. Oculus Rift is the star player, but there +/// are many other options. +/// The order shown here determines the integer value in the console. +/// @todo - Add an additional console command to support symbolic versions of these mode settings enum Stereo3DMode { MODE_MONO = 0, MODE_GREEN_MAGENTA, @@ -16,23 +18,19 @@ enum Stereo3DMode { MODE_PARALLEL, MODE_CROSSEYE, MODE_OCULUS_RIFT, - MODE_ROW_INTERLEAVED, // 10 - MODE_COLUMN_INTERLEAVED, - MODE_CHECKERBOARD, + MODE_ROW_INTERLEAVED, // 10 // NOT IMPLEMENTED YET + MODE_COLUMN_INTERLEAVED, // NOT IMPLEMENTED YET + MODE_CHECKERBOARD, // NOT IMPLEMENTED YET MODE_QUAD_BUFFERED, // MODE_MAX_3D_MODE_PLUS_ONE }; // Console variables - -// Console variables -extern int mode; -// Interpupillary distance in meters -extern float ipd; -extern float playerHeight; -extern float dominantEye; -extern byte swapEyes; +extern float ipd; /// Interpupillary distance in meters +extern float playerHeight; /// Human player's real world height in meters +extern float dominantEye; /// Kludge for aim-down-weapon-sight modes +extern byte swapEyes; /// When true, inverts stereoscopic effect // Variables below are global, but not user visible // @@ -41,17 +39,30 @@ extern byte swapEyes; extern bool applyFrustumShift; // local viewpoint relative eye position in map units, -// vr::eyeshift is ordinarily set from vr::setEyeView() +// VR::eyeShift is ordinarily set from VR::getEyeShift() extern float eyeShift; -extern float hudDistance; // in map units -extern float weaponDistance; // in map units +extern float hudDistance; // Distance from player character to screen, in map units (not used in Rift mode, because it's used by frustum shift) +extern float weaponDistance; // (UNUSED) Distance from player character to weapon sprite, in map units -// -1 means left eye, +1 means right eye +/// @param eye: -1 means left eye, +1 means right eye +/// @return viewpoint eye shift in map units float getEyeShift(float eye); + // Register console variables void consoleRegister(); +// Head tracking API + +// True if Oculus Rift is enabled and can report head orientation. +bool hasHeadOrientation(); + +// Returns current pitch, roll, yaw angles, in radians, or empty vector if head tracking is not available. +std::vector getHeadOrientation(); + +// To release memory and resources when done, for tidiness. +void deleteOculusTracker(); + } // namespace VR #endif // CLIENT_RENDER_VR_H diff --git a/doomsday/client/src/render/vr.cpp b/doomsday/client/src/render/vr.cpp index 32199d6c24..e9b766c726 100644 --- a/doomsday/client/src/render/vr.cpp +++ b/doomsday/client/src/render/vr.cpp @@ -3,21 +3,23 @@ // Console variables -int VR::mode = 0; +static int vrMode = 0; // Interpupillary distance in meters float VR::ipd = 0.0622f; float VR::playerHeight = 1.70f; float VR::dominantEye = 0.0f; byte VR::swapEyes = 0; + // Global variables bool VR::applyFrustumShift = true; float VR::eyeShift = 0; float VR::hudDistance = 30.0f; float VR::weaponDistance = 10.0f; -// eye: -1 means left eye, +1 means right eye -// Returns viewpoint eye shift in map units + +/// @param eye: -1 means left eye, +1 means right eye +/// @return viewpoint eye shift in map units float VR::getEyeShift(float eye) { // 0.95 because eyes are not at top of head @@ -43,5 +45,119 @@ void VR::consoleRegister() C_VAR_FLOAT ("rend-vr-player-height", & VR::playerHeight, 0, 1.0f, 3.0f); C_VAR_FLOAT ("rend-vr-dominant-eye", & VR::dominantEye, 0, -1.0f, 1.0f); C_VAR_BYTE ("rend-vr-swap-eyes", & VR::swapEyes, 0, 0, 1); - C_VAR_INT2 ("rend-vr-mode", & VR::mode, 0, 0, (int)(VR::MODE_MAX_3D_MODE_PLUS_ONE - 1), vrModeChanged); + C_VAR_INT2 ("rend-vr-mode", & vrMode, 0, 0, (int)(VR::MODE_MAX_3D_MODE_PLUS_ONE - 1), vrModeChanged); +} + + +// Head tracking + +#ifdef DENG_HAVE_OCULUS_API +#include "OVR.h" + +class OculusTracker { +public: + OculusTracker() + : pitch(0) + , roll(0) + , yaw(0) + { + OVR::System::Init(); + pFusionResult = new OVR::SensorFusion(); + pManager = *OVR::DeviceManager::Create(); + pHMD = *pManager->EnumerateDevices().CreateDevice(); + if(pHMD) + { + InfoLoaded = pHMD->GetDeviceInfo(&Info); + pSensor = pHMD->GetSensor(); + } + else + { + pSensor = *pManager->EnumerateDevices().CreateDevice(); + } + + if (pSensor) + { + pFusionResult->AttachToSensor(pSensor); + } + } + + ~OculusTracker() + { + pSensor.Clear(); + pHMD.Clear(); + pManager.Clear(); + delete pFusionResult; + OVR::System::Destroy(); + } + + const OVR::HMDInfo& getInfo() const { + return Info; + } + + bool isGood() const { + return pSensor.GetPtr() != NULL; + } + + void update() + { + OVR::Quatf quaternion = pFusionResult->GetOrientation(); + quaternion.GetEulerAngles(&yaw, &pitch, &roll); + } + + // Head orientation state, refreshed by call to update(); + float pitch, roll, yaw; + +private: + OVR::Ptr pManager; + OVR::Ptr pHMD; + OVR::Ptr pSensor; + OVR::SensorFusion* pFusionResult; + OVR::HMDInfo Info; + bool InfoLoaded; +}; + +static OculusTracker* oculusTracker = NULL; +#endif + +// True if Oculus Rift is enabled and can report head orientation. +bool VR::hasHeadOrientation() +{ +#ifdef DENG_HAVE_OCULUS_API + if (oculusTracker == NULL) + oculusTracker = new OculusTracker(); + return oculusTracker->isGood(); +#else + // No API; No head tracking. + return false; +#endif +} + +// Returns current pitch, roll, yaw angles, in radians +std::vector VR::getHeadOrientation() +{ + std::vector result; +#ifdef DENG_HAVE_OCULUS_API + if (! VR::hasHeadOrientation()) + return result; // empty vector + oculusTracker->update(); + result.push_back(oculusTracker->pitch); + result.push_back(oculusTracker->roll); + result.push_back(oculusTracker->yaw); + return result; +#else + // No API; Return empty vector. You should have called VR::hasHeadOrientation() first... + return result; +#endif +} + +// To release memory and resources when done, for tidiness. +void VR::deleteOculusTracker() +{ +#ifdef DENG_HAVE_OCULUS_API + if (oculusTracker != NULL) + { + delete oculusTracker; + oculusTracker = NULL; + } +#endif } diff --git a/doomsday/client/src/ui/clientwindow.cpp b/doomsday/client/src/ui/clientwindow.cpp index fcd4a97d87..c18526b9cc 100644 --- a/doomsday/client/src/ui/clientwindow.cpp +++ b/doomsday/client/src/ui/clientwindow.cpp @@ -278,7 +278,7 @@ DENG2_OBSERVES(App, GameChange) { MouseEvent ev = event; - switch(VR::mode) + switch(Con_GetInteger("rend-vr-mode")) { // Left-right screen split modes case VR::MODE_SIDE_BY_SIDE: @@ -552,7 +552,7 @@ void ClientWindow::canvasGLDraw(Canvas &canvas) DENG_ASSERT_IN_MAIN_THREAD(); DENG_ASSERT_GL_CONTEXT_ACTIVE(); - switch(VR::mode) + switch(Con_GetInteger("rend-vr-mode")) { // A) Single view type stereo 3D modes here: case VR::MODE_MONO: @@ -853,7 +853,7 @@ void ClientWindow::updateRootSize() { Canvas::Size size = canvas().size(); - switch(VR::mode) + switch(Con_GetInteger("rend-vr-mode")) { // Left-right screen split modes case VR::MODE_CROSSEYE: diff --git a/doomsday/dep_rift.pri b/doomsday/dep_rift.pri index 11b273e664..bdeaea0734 100644 --- a/doomsday/dep_rift.pri +++ b/doomsday/dep_rift.pri @@ -4,9 +4,10 @@ exists($${LIBOVR_DIR}/Include/OVR.h) { INCLUDEPATH += $${LIBOVR_DIR}/Include # TODO - LIBS statement for Mac, Linux win32:LIBS += $${LIBOVR_DIR}/Lib/Win32/libovr.lib - DEFINES += HAVE_OCULUS_API + # Additional windows libraries needed to avoid link errors when using Rift + win32:LIBS += shell32.lib winmm.lib + DEFINES += DENG_HAVE_OCULUS_API # message("Found Oculus Rift SDK") } else { # message("Oculus Rift SDK not found") } -