openVRProvider.cpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121
  1. #include "platform/input/openVR/openVRProvider.h"
  2. #include "platform/platformInput.h"
  3. #include "core/module.h"
  4. #include "console/engineAPI.h"
  5. #include "T3D/gameBase/gameConnection.h"
  6. #include "gui/core/guiCanvas.h"
  7. #include "postFx/postEffectCommon.h"
  8. #include "gfx/D3D11/gfxD3D11Device.h"
  9. #include "gfx/D3D11/gfxD3D11TextureObject.h"
  10. #include "gfx/D3D11/gfxD3D11EnumTranslate.h"
  11. #include "gfx/gfxStringEnumTranslate.h"
  12. #include "gfx/D3D9/gfxD3D9Device.h"
  13. #include "gfx/D3D9/gfxD3D9TextureObject.h"
  14. #include "gfx/D3D9/gfxD3D9EnumTranslate.h"
  15. #ifdef TORQUE_OPENGL
  16. #include "gfx/gl/gfxGLDevice.h"
  17. #include "gfx/gl/gfxGLTextureObject.h"
  18. #include "gfx/gl/gfxGLEnumTranslate.h"
  19. #endif
  20. namespace OpenVRUtil
  21. {
  22. void convertTransformFromOVR(const MatrixF &inRotTMat, MatrixF& outRotation)
  23. {
  24. Point4F col0; inRotTMat.getColumn(0, &col0);
  25. Point4F col1; inRotTMat.getColumn(1, &col1);
  26. Point4F col2; inRotTMat.getColumn(2, &col2);
  27. Point4F col3; inRotTMat.getColumn(3, &col3);
  28. // Set rotation. We need to convert from sensor coordinates to
  29. // Torque coordinates. The sensor matrix is stored row-major.
  30. // The conversion is:
  31. //
  32. // Sensor Torque
  33. // a b c a b c a -c b
  34. // d e f --> -g -h -i --> -g i -h
  35. // g h i d e f d -f e
  36. outRotation.setColumn(0, Point4F( col0.x, -col2.x, col1.x, 0.0f));
  37. outRotation.setColumn(1, Point4F(-col0.z, col2.z, -col1.z, 0.0f));
  38. outRotation.setColumn(2, Point4F( col0.y, -col2.y, col1.y, 0.0f));
  39. outRotation.setColumn(3, Point4F(-col3.x, col3.z, -col3.y, 1.0f));
  40. }
  41. void convertTransformToOVR(const MatrixF& inRotation, MatrixF& outRotation)
  42. {
  43. Point4F col0; inRotation.getColumn(0, &col0);
  44. Point4F col1; inRotation.getColumn(1, &col1);
  45. Point4F col2; inRotation.getColumn(2, &col2);
  46. Point4F col3; inRotation.getColumn(3, &col3);
  47. // This is basically a reverse of what is in convertTransformFromOVR
  48. outRotation.setColumn(0, Point4F(col0.x, col2.x, -col1.x, 0.0f));
  49. outRotation.setColumn(1, Point4F(col0.z, col2.z, -col1.z, 0.0f));
  50. outRotation.setColumn(2, Point4F(-col0.y, -col2.y, col1.y, 0.0f));
  51. outRotation.setColumn(3, Point4F(-col3.x, -col3.z, col3.y, 1.0f));
  52. }
  53. MatrixF convertSteamVRAffineMatrixToMatrixFPlain(const vr::HmdMatrix34_t &mat)
  54. {
  55. MatrixF outMat(1);
  56. outMat.setColumn(0, Point4F(mat.m[0][0], mat.m[1][0], mat.m[2][0], 0.0));
  57. outMat.setColumn(1, Point4F(mat.m[0][1], mat.m[1][1], mat.m[2][1], 0.0));
  58. outMat.setColumn(2, Point4F(mat.m[0][2], mat.m[1][2], mat.m[2][2], 0.0));
  59. outMat.setColumn(3, Point4F(mat.m[0][3], mat.m[1][3], mat.m[2][3], 1.0f)); // pos
  60. return outMat;
  61. }
  62. void convertMatrixFPlainToSteamVRAffineMatrix(const MatrixF &inMat, vr::HmdMatrix34_t &outMat)
  63. {
  64. Point4F row0; inMat.getRow(0, &row0);
  65. Point4F row1; inMat.getRow(1, &row1);
  66. Point4F row2; inMat.getRow(2, &row2);
  67. outMat.m[0][0] = row0.x;
  68. outMat.m[0][1] = row0.y;
  69. outMat.m[0][2] = row0.z;
  70. outMat.m[0][3] = row0.w;
  71. outMat.m[1][0] = row1.x;
  72. outMat.m[1][1] = row1.y;
  73. outMat.m[1][2] = row1.z;
  74. outMat.m[1][3] = row1.w;
  75. outMat.m[2][0] = row2.x;
  76. outMat.m[2][1] = row2.y;
  77. outMat.m[2][2] = row2.z;
  78. outMat.m[2][3] = row2.w;
  79. }
  80. vr::VRTextureBounds_t TorqueRectToBounds(const RectI &rect, const Point2I &widthHeight)
  81. {
  82. vr::VRTextureBounds_t bounds;
  83. F32 xRatio = 1.0 / (F32)widthHeight.x;
  84. F32 yRatio = 1.0 / (F32)widthHeight.y;
  85. bounds.uMin = rect.point.x * xRatio;
  86. bounds.vMin = rect.point.y * yRatio;
  87. bounds.uMax = (rect.point.x + rect.extent.x) * xRatio;
  88. bounds.vMax = (rect.point.y + rect.extent.y) * yRatio;
  89. return bounds;
  90. }
  91. }
  92. //------------------------------------------------------------
  93. DECLARE_SCOPE(OpenVR);
  94. IMPLEMENT_SCOPE(OpenVR, OpenVRProvider, , "");
  95. ConsoleDoc(
  96. "@class OpenVRProvider\n"
  97. "@brief This class is the interface between TorqueScript and OpenVR.\n\n"
  98. "@ingroup OpenVR\n"
  99. );
  100. // Enum impls
  101. ImplementEnumType(OpenVROverlayInputMethod,
  102. "Types of input supported by VR Overlays. .\n\n"
  103. "@ingroup OpenVR")
  104. { vr::VROverlayInputMethod_None, "None" },
  105. { vr::VROverlayInputMethod_Mouse, "Mouse" },
  106. EndImplementEnumType;
  107. ImplementEnumType(OpenVROverlayTransformType,
  108. "Allows the caller to figure out which overlay transform getter to call. .\n\n"
  109. "@ingroup OpenVR")
  110. { vr::VROverlayTransform_Absolute, "Absolute" },
  111. { vr::VROverlayTransform_TrackedDeviceRelative, "TrackedDeviceRelative" },
  112. { vr::VROverlayTransform_SystemOverlay, "SystemOverlay" },
  113. { vr::VROverlayTransform_TrackedComponent, "TrackedComponent" },
  114. EndImplementEnumType;
  115. ImplementEnumType(OpenVRGamepadTextInputMode,
  116. "Types of input supported by VR Overlays. .\n\n"
  117. "@ingroup OpenVR")
  118. { vr::k_EGamepadTextInputModeNormal, "Normal", },
  119. { vr::k_EGamepadTextInputModePassword, "Password", },
  120. { vr::k_EGamepadTextInputModeSubmit, "Submit" },
  121. EndImplementEnumType;
  122. ImplementEnumType(OpenVRGamepadTextInputLineMode,
  123. "Types of input supported by VR Overlays. .\n\n"
  124. "@ingroup OpenVR")
  125. { vr::k_EGamepadTextInputLineModeSingleLine, "SingleLine" },
  126. { vr::k_EGamepadTextInputLineModeMultipleLines, "MultipleLines" },
  127. EndImplementEnumType;
  128. ImplementEnumType(OpenVRTrackingResult,
  129. ". .\n\n"
  130. "@ingroup OpenVR")
  131. { vr::TrackingResult_Uninitialized, "None" },
  132. { vr::TrackingResult_Calibrating_InProgress, "Calibrating_InProgress" },
  133. { vr::TrackingResult_Calibrating_OutOfRange, "Calibrating_OutOfRange" },
  134. { vr::TrackingResult_Running_OK, "Running_Ok" },
  135. { vr::TrackingResult_Running_OutOfRange, "Running_OutOfRange" },
  136. EndImplementEnumType;
  137. ImplementEnumType(OpenVRTrackingUniverseOrigin,
  138. "Identifies which style of tracking origin the application wants to use for the poses it is requesting. .\n\n"
  139. "@ingroup OpenVR")
  140. { vr::TrackingUniverseSeated, "Seated" },
  141. { vr::TrackingUniverseStanding, "Standing" },
  142. { vr::TrackingUniverseRawAndUncalibrated, "RawAndUncalibrated" },
  143. EndImplementEnumType;
  144. ImplementEnumType(OpenVROverlayDirection,
  145. "Directions for changing focus between overlays with the gamepad. .\n\n"
  146. "@ingroup OpenVR")
  147. { vr::OverlayDirection_Up, "Up" },
  148. { vr::OverlayDirection_Down, "Down" },
  149. { vr::OverlayDirection_Left, "Left" },
  150. { vr::OverlayDirection_Right, "Right" },
  151. EndImplementEnumType;
  152. ImplementEnumType(OpenVRState,
  153. "Status of the overall system or tracked objects. .\n\n"
  154. "@ingroup OpenVR")
  155. { vr::VRState_Undefined, "Undefined" },
  156. { vr::VRState_Off, "Off" },
  157. { vr::VRState_Searching, "Searching" },
  158. { vr::VRState_Searching_Alert, "Searching_Alert" },
  159. { vr::VRState_Ready, "Ready" },
  160. { vr::VRState_Ready_Alert, "Ready_Alert" },
  161. { vr::VRState_NotReady, "NotReady" },
  162. EndImplementEnumType;
  163. //------------------------------------------------------------
  164. U32 OpenVRProvider::OVR_SENSORROT[vr::k_unMaxTrackedDeviceCount] = { 0 };
  165. U32 OpenVRProvider::OVR_SENSORROTANG[vr::k_unMaxTrackedDeviceCount] = { 0 };
  166. U32 OpenVRProvider::OVR_SENSORVELOCITY[vr::k_unMaxTrackedDeviceCount] = { 0 };
  167. U32 OpenVRProvider::OVR_SENSORANGVEL[vr::k_unMaxTrackedDeviceCount] = { 0 };
  168. U32 OpenVRProvider::OVR_SENSORMAGNETOMETER[vr::k_unMaxTrackedDeviceCount] = { 0 };
  169. U32 OpenVRProvider::OVR_SENSORPOSITION[vr::k_unMaxTrackedDeviceCount] = { 0 };
  170. U32 OpenVRProvider::OVR_BUTTONPRESSED[vr::k_unMaxTrackedDeviceCount];
  171. U32 OpenVRProvider::OVR_BUTTONTOUCHED[vr::k_unMaxTrackedDeviceCount];
  172. U32 OpenVRProvider::OVR_AXISNONE[vr::k_unMaxTrackedDeviceCount] = { 0 };
  173. U32 OpenVRProvider::OVR_AXISTRACKPAD[vr::k_unMaxTrackedDeviceCount] = { 0 };
  174. U32 OpenVRProvider::OVR_AXISJOYSTICK[vr::k_unMaxTrackedDeviceCount] = { 0 };
  175. U32 OpenVRProvider::OVR_AXISTRIGGER[vr::k_unMaxTrackedDeviceCount] = { 0 };
  176. static String GetTrackedDeviceString(vr::IVRSystem *pHmd, vr::TrackedDeviceIndex_t unDevice, vr::TrackedDeviceProperty prop, vr::TrackedPropertyError *peError = NULL)
  177. {
  178. uint32_t unRequiredBufferLen = pHmd->GetStringTrackedDeviceProperty(unDevice, prop, NULL, 0, peError);
  179. if (unRequiredBufferLen == 0)
  180. return "";
  181. char *pchBuffer = new char[unRequiredBufferLen];
  182. unRequiredBufferLen = pHmd->GetStringTrackedDeviceProperty(unDevice, prop, pchBuffer, unRequiredBufferLen, peError);
  183. String sResult = pchBuffer;
  184. delete[] pchBuffer;
  185. return sResult;
  186. }
  187. MODULE_BEGIN(OpenVRProvider)
  188. MODULE_INIT_AFTER(InputEventManager)
  189. MODULE_SHUTDOWN_BEFORE(InputEventManager)
  190. MODULE_INIT
  191. {
  192. OpenVRProvider::staticInit();
  193. ManagedSingleton< OpenVRProvider >::createSingleton();
  194. }
  195. MODULE_SHUTDOWN
  196. {
  197. ManagedSingleton< OpenVRProvider >::deleteSingleton();
  198. }
  199. MODULE_END;
  200. bool OpenVRRenderState::setupRenderTargets(GFXDevice::GFXDeviceRenderStyles mode)
  201. {
  202. if (!mHMD)
  203. return false;
  204. if (mRenderMode == mode)
  205. return true;
  206. mRenderMode = mode;
  207. if (mode == GFXDevice::RS_Standard)
  208. {
  209. reset(mHMD);
  210. return true;
  211. }
  212. U32 sizeX, sizeY;
  213. Point2I newRTSize;
  214. mHMD->GetRecommendedRenderTargetSize(&sizeX, &sizeY);
  215. if (mode == GFXDevice::RS_StereoSeparate)
  216. {
  217. mEyeViewport[0] = RectI(Point2I(0, 0), Point2I(sizeX, sizeY));
  218. mEyeViewport[1] = RectI(Point2I(0, 0), Point2I(sizeX, sizeY));
  219. newRTSize.x = sizeX;
  220. newRTSize.y = sizeY;
  221. }
  222. else
  223. {
  224. mEyeViewport[0] = RectI(Point2I(0, 0), Point2I(sizeX, sizeY));
  225. mEyeViewport[1] = RectI(Point2I(sizeX, 0), Point2I(sizeX, sizeY));
  226. newRTSize.x = sizeX * 2;
  227. newRTSize.y = sizeY;
  228. }
  229. GFXTexHandle stereoTexture;
  230. stereoTexture.set(newRTSize.x, newRTSize.y, GFXFormatR8G8B8A8, &VRTextureProfile, "OpenVR Stereo RT Color");
  231. mStereoRenderTexture = stereoTexture;
  232. GFXTexHandle stereoDepthTexture;
  233. stereoDepthTexture.set(newRTSize.x, newRTSize.y, GFXFormatD24S8, &VRDepthProfile, "OpenVR Depth");
  234. mStereoDepthTexture = stereoDepthTexture;
  235. mStereoRT = GFX->allocRenderToTextureTarget();
  236. mStereoRT->attachTexture(GFXTextureTarget::Color0, stereoTexture);
  237. mStereoRT->attachTexture(GFXTextureTarget::DepthStencil, stereoDepthTexture);
  238. mOutputEyeTextures.init(newRTSize.x, newRTSize.y, GFXFormatR8G8B8A8, &VRTextureProfile, "OpenVR Stereo RT Color OUTPUT");
  239. return true;
  240. }
  241. void OpenVRRenderState::renderPreview()
  242. {
  243. }
  244. void OpenVRRenderState::reset(vr::IVRSystem* hmd)
  245. {
  246. mHMD = hmd;
  247. mStereoRT = NULL;
  248. mStereoRenderTexture = NULL;
  249. mStereoDepthTexture = NULL;
  250. mOutputEyeTextures.clear();
  251. if (!mHMD)
  252. return;
  253. vr::HmdMatrix34_t mat = mHMD->GetEyeToHeadTransform(vr::Eye_Left);
  254. mEyePose[0] = OpenVRUtil::convertSteamVRAffineMatrixToMatrixFPlain(mat);
  255. mEyePose[0].inverse();
  256. mat = mHMD->GetEyeToHeadTransform(vr::Eye_Right);
  257. mEyePose[1] = OpenVRUtil::convertSteamVRAffineMatrixToMatrixFPlain(mat);
  258. mEyePose[1].inverse();
  259. mHMD->GetProjectionRaw(vr::Eye_Left, &mEyeFov[0].leftTan, &mEyeFov[0].rightTan, &mEyeFov[0].upTan, &mEyeFov[0].downTan);
  260. mHMD->GetProjectionRaw(vr::Eye_Right, &mEyeFov[1].leftTan, &mEyeFov[1].rightTan, &mEyeFov[1].upTan, &mEyeFov[1].downTan);
  261. mEyeFov[0].upTan = -mEyeFov[0].upTan;
  262. mEyeFov[0].leftTan = -mEyeFov[0].leftTan;
  263. mEyeFov[1].upTan = -mEyeFov[1].upTan;
  264. mEyeFov[1].leftTan = -mEyeFov[1].leftTan;
  265. }
  266. OpenVRProvider::OpenVRProvider() :
  267. mHMD(NULL),
  268. mRenderModels(NULL),
  269. mDrawCanvas(NULL),
  270. mGameConnection(NULL)
  271. {
  272. dStrcpy(mName, "openvr");
  273. mDeviceType = INPUTMGR->getNextDeviceType();
  274. buildInputCodeTable();
  275. GFXDevice::getDeviceEventSignal().notify(this, &OpenVRProvider::_handleDeviceEvent);
  276. INPUTMGR->registerDevice(this);
  277. dMemset(&mLUID, '\0', sizeof(mLUID));
  278. mTrackingSpace = vr::TrackingUniverseStanding;
  279. }
  280. OpenVRProvider::~OpenVRProvider()
  281. {
  282. }
  283. void OpenVRProvider::staticInit()
  284. {
  285. // Overlay flags
  286. Con::setIntVariable("$OpenVR::OverlayFlags_None", 1 << (U32)vr::VROverlayFlags_None);
  287. Con::setIntVariable("$OpenVR::OverlayFlags_Curved", 1 << (U32)vr::VROverlayFlags_Curved);
  288. Con::setIntVariable("$OpenVR::OverlayFlags_RGSS4X", 1 << (U32)vr::VROverlayFlags_RGSS4X);
  289. Con::setIntVariable("$OpenVR::OverlayFlags_NoDashboardTab", 1 << (U32)vr::VROverlayFlags_NoDashboardTab);
  290. Con::setIntVariable("$OpenVR::OverlayFlags_AcceptsGamepadEvents", 1 << (U32)vr::VROverlayFlags_AcceptsGamepadEvents);
  291. Con::setIntVariable("$OpenVR::OverlayFlags_ShowGamepadFocus", 1 << (U32)vr::VROverlayFlags_ShowGamepadFocus);
  292. Con::setIntVariable("$OpenVR::OverlayFlags_SendVRScrollEvents", 1 << (U32)vr::VROverlayFlags_SendVRScrollEvents);
  293. Con::setIntVariable("$OpenVR::OverlayFlags_SendVRTouchpadEvents", 1 << (U32)vr::VROverlayFlags_SendVRTouchpadEvents);
  294. Con::setIntVariable("$OpenVR::OverlayFlags_ShowTouchPadScrollWheel", 1 << (U32)vr::VROverlayFlags_ShowTouchPadScrollWheel);
  295. }
  296. bool OpenVRProvider::enable()
  297. {
  298. disable();
  299. // Load openvr runtime
  300. vr::EVRInitError eError = vr::VRInitError_None;
  301. mHMD = vr::VR_Init(&eError, vr::VRApplication_Scene);
  302. dMemset(mDeviceClassChar, '\0', sizeof(mDeviceClassChar));
  303. if (eError != vr::VRInitError_None)
  304. {
  305. mHMD = NULL;
  306. char buf[1024];
  307. sprintf_s(buf, sizeof(buf), "Unable to init VR runtime: %s", vr::VR_GetVRInitErrorAsEnglishDescription(eError));
  308. Con::printf(buf);
  309. return false;
  310. }
  311. dMemset(&mLUID, '\0', sizeof(mLUID));
  312. #ifdef TORQUE_OS_WIN32
  313. // For windows we need to lookup the DXGI record for this and grab the LUID for the display adapter. We need the LUID since
  314. // T3D uses EnumAdapters1 not EnumAdapters whereas openvr uses EnumAdapters.
  315. int32_t AdapterIdx;
  316. IDXGIAdapter* EnumAdapter;
  317. IDXGIFactory1* DXGIFactory;
  318. mHMD->GetDXGIOutputInfo(&AdapterIdx);
  319. // Get the LUID of the device
  320. HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&DXGIFactory));
  321. if (FAILED(hr))
  322. AssertFatal(false, "OpenVRProvider::enable -> CreateDXGIFactory1 call failure");
  323. hr = DXGIFactory->EnumAdapters(AdapterIdx, &EnumAdapter);
  324. if (FAILED(hr))
  325. {
  326. Con::warnf("VR: HMD device has an invalid adapter.");
  327. }
  328. else
  329. {
  330. DXGI_ADAPTER_DESC desc;
  331. hr = EnumAdapter->GetDesc(&desc);
  332. if (FAILED(hr))
  333. {
  334. Con::warnf("VR: HMD device has an invalid adapter.");
  335. }
  336. else
  337. {
  338. dMemcpy(&mLUID, &desc.AdapterLuid, sizeof(mLUID));
  339. }
  340. SAFE_RELEASE(EnumAdapter);
  341. }
  342. SAFE_RELEASE(DXGIFactory);
  343. #endif
  344. mRenderModels = (vr::IVRRenderModels *)vr::VR_GetGenericInterface(vr::IVRRenderModels_Version, &eError);
  345. if (!mRenderModels)
  346. {
  347. mHMD = NULL;
  348. vr::VR_Shutdown();
  349. char buf[1024];
  350. sprintf_s(buf, sizeof(buf), "Unable to get render model interface: %s", vr::VR_GetVRInitErrorAsEnglishDescription(eError));
  351. Con::printf(buf);
  352. return false;
  353. }
  354. mDriver = GetTrackedDeviceString(mHMD, vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_TrackingSystemName_String);
  355. mDisplay = GetTrackedDeviceString(mHMD, vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_SerialNumber_String);
  356. mHMDRenderState.reset(mHMD);
  357. mHMD->ResetSeatedZeroPose();
  358. dMemset(mPreviousInputTrackedDevicePose, '\0', sizeof(mPreviousInputTrackedDevicePose));
  359. mEnabled = true;
  360. return true;
  361. }
  362. bool OpenVRProvider::disable()
  363. {
  364. if (mHMD)
  365. {
  366. mHMD = NULL;
  367. mRenderModels = NULL;
  368. mHMDRenderState.reset(NULL);
  369. vr::VR_Shutdown();
  370. }
  371. mEnabled = false;
  372. return true;
  373. }
  374. void OpenVRProvider::buildInputCodeTable()
  375. {
  376. // Obtain all of the device codes
  377. for (U32 i = 0; i < vr::k_unMaxTrackedDeviceCount; ++i)
  378. {
  379. OVR_SENSORROT[i] = INPUTMGR->getNextDeviceCode();
  380. OVR_SENSORROTANG[i] = INPUTMGR->getNextDeviceCode();
  381. OVR_SENSORVELOCITY[i] = INPUTMGR->getNextDeviceCode();
  382. OVR_SENSORANGVEL[i] = INPUTMGR->getNextDeviceCode();
  383. OVR_SENSORMAGNETOMETER[i] = INPUTMGR->getNextDeviceCode();
  384. OVR_SENSORPOSITION[i] = INPUTMGR->getNextDeviceCode();
  385. OVR_BUTTONPRESSED[i] = INPUTMGR->getNextDeviceCode();
  386. OVR_BUTTONTOUCHED[i] = INPUTMGR->getNextDeviceCode();
  387. OVR_AXISNONE[i] = INPUTMGR->getNextDeviceCode();
  388. OVR_AXISTRACKPAD[i] = INPUTMGR->getNextDeviceCode();
  389. OVR_AXISJOYSTICK[i] = INPUTMGR->getNextDeviceCode();
  390. OVR_AXISTRIGGER[i] = INPUTMGR->getNextDeviceCode();
  391. }
  392. // Build out the virtual map
  393. char buffer[64];
  394. for (U32 i = 0; i < vr::k_unMaxTrackedDeviceCount; ++i)
  395. {
  396. dSprintf(buffer, 64, "opvr_sensorrot%d", i);
  397. INPUTMGR->addVirtualMap(buffer, SI_ROT, OVR_SENSORROT[i]);
  398. dSprintf(buffer, 64, "opvr_sensorrotang%d", i);
  399. INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_SENSORROTANG[i]);
  400. dSprintf(buffer, 64, "opvr_sensorvelocity%d", i);
  401. INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_SENSORVELOCITY[i]);
  402. dSprintf(buffer, 64, "opvr_sensorangvel%d", i);
  403. INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_SENSORANGVEL[i]);
  404. dSprintf(buffer, 64, "opvr_sensormagnetometer%d", i);
  405. INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_SENSORMAGNETOMETER[i]);
  406. dSprintf(buffer, 64, "opvr_sensorpos%d", i);
  407. INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_SENSORPOSITION[i]);
  408. dSprintf(buffer, 64, "opvr_buttonpressed%d", i);
  409. INPUTMGR->addVirtualMap(buffer, SI_INT, OVR_BUTTONPRESSED[i]);
  410. dSprintf(buffer, 64, "opvr_buttontouched%d", i);
  411. INPUTMGR->addVirtualMap(buffer, SI_INT, OVR_BUTTONTOUCHED[i]);
  412. dSprintf(buffer, 64, "opvr_axis_none%d", i);
  413. INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_AXISNONE[i]);
  414. dSprintf(buffer, 64, "opvr_axis_trackpad%d", i);
  415. INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_AXISTRACKPAD[i]);
  416. dSprintf(buffer, 64, "opvr_axis_joystick%d", i);
  417. INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_AXISJOYSTICK[i]);
  418. dSprintf(buffer, 64, "opvr_axis_trigger%d", i);
  419. INPUTMGR->addVirtualMap(buffer, SI_INT, OVR_AXISTRIGGER[i]);
  420. }
  421. }
  422. bool OpenVRProvider::process()
  423. {
  424. if (!mHMD)
  425. return true;
  426. if (!vr::VRCompositor())
  427. return true;
  428. // Process SteamVR events
  429. vr::VREvent_t event;
  430. while (mHMD->PollNextEvent(&event, sizeof(event)))
  431. {
  432. processVREvent(event);
  433. }
  434. // Process SteamVR controller state
  435. for (vr::TrackedDeviceIndex_t unDevice = 0; unDevice < vr::k_unMaxTrackedDeviceCount; unDevice++)
  436. {
  437. vr::VRControllerState_t state;
  438. if (mHMD->GetControllerState(unDevice, &state))
  439. {
  440. // TODO
  441. }
  442. }
  443. // Update input poses
  444. updateTrackedPoses();
  445. submitInputChanges();
  446. return true;
  447. }
  448. bool OpenVRProvider::providesFrameEyePose() const
  449. {
  450. return mHMD != NULL;
  451. }
  452. inline Point3F OpenVRVecToTorqueVec(vr::HmdVector3_t vec)
  453. {
  454. return Point3F(-vec.v[0], vec.v[2], -vec.v[1]);
  455. }
  456. void OpenVRTransformToRotPos(MatrixF mat, QuatF &outRot, Point3F &outPos)
  457. {
  458. // Directly set the rotation and position from the eye transforms
  459. MatrixF torqueMat(1);
  460. OpenVRUtil::convertTransformFromOVR(mat, torqueMat);
  461. Point3F pos = torqueMat.getPosition();
  462. outRot = QuatF(torqueMat);
  463. outPos = pos;// Point3F(-pos.x, pos.z, -pos.y);
  464. }
  465. void OpenVRProvider::getFrameEyePose(IDevicePose *pose, U32 eye) const
  466. {
  467. AssertFatal(eye >= 0 && eye < 2, "Out of bounds eye");
  468. MatrixF mat = mHMDRenderState.mEyePose[eye] * mHMDRenderState.mHMDPose; // same order as in the openvr example
  469. OpenVRTransformToRotPos(mat, pose->orientation, pose->position);
  470. pose->velocity = Point3F(0);
  471. pose->angularVelocity = Point3F(0);
  472. }
  473. bool OpenVRProvider::providesEyeOffsets() const
  474. {
  475. return mHMD != NULL;
  476. }
  477. /// Returns eye offset not taking into account any position tracking info
  478. void OpenVRProvider::getEyeOffsets(Point3F *dest) const
  479. {
  480. dest[0] = mHMDRenderState.mEyePose[0].getPosition();
  481. dest[1] = mHMDRenderState.mEyePose[1].getPosition();
  482. dest[0] = Point3F(-dest[0].x, dest[0].y, dest[0].z); // convert from vr-space
  483. dest[1] = Point3F(-dest[1].x, dest[1].y, dest[1].z);
  484. }
  485. bool OpenVRProvider::providesFovPorts() const
  486. {
  487. return mHMD != NULL;
  488. }
  489. void OpenVRProvider::getFovPorts(FovPort *out) const
  490. {
  491. dMemcpy(out, mHMDRenderState.mEyeFov, sizeof(mHMDRenderState.mEyeFov));
  492. }
  493. bool OpenVRProvider::providesProjectionOffset() const
  494. {
  495. return mHMD != NULL;
  496. }
  497. const Point2F& OpenVRProvider::getProjectionOffset() const
  498. {
  499. return Point2F(0, 0);
  500. }
  501. void OpenVRProvider::getStereoViewports(RectI *out) const
  502. {
  503. out[0] = mHMDRenderState.mEyeViewport[0];
  504. out[1] = mHMDRenderState.mEyeViewport[1];
  505. }
  506. void OpenVRProvider::getStereoTargets(GFXTextureTarget **out) const
  507. {
  508. out[0] = mHMDRenderState.mStereoRT;
  509. out[1] = mHMDRenderState.mStereoRT;
  510. }
  511. void OpenVRProvider::setDrawCanvas(GuiCanvas *canvas)
  512. {
  513. vr::EVRInitError peError = vr::VRInitError_None;
  514. if (!vr::VRCompositor())
  515. {
  516. Con::errorf("VR: Compositor initialization failed. See log file for details\n");
  517. return;
  518. }
  519. if (mDrawCanvas != canvas || mHMDRenderState.mHMD == NULL)
  520. {
  521. mHMDRenderState.setupRenderTargets(GFXDevice::RS_Standard);
  522. }
  523. mDrawCanvas = canvas;
  524. }
  525. void OpenVRProvider::setDrawMode(GFXDevice::GFXDeviceRenderStyles style)
  526. {
  527. mHMDRenderState.setupRenderTargets(style);
  528. }
  529. void OpenVRProvider::setCurrentConnection(GameConnection *connection)
  530. {
  531. mGameConnection = connection;
  532. }
  533. GameConnection* OpenVRProvider::getCurrentConnection()
  534. {
  535. return mGameConnection;
  536. }
  537. GFXTexHandle OpenVRProvider::getPreviewTexture()
  538. {
  539. return mHMDRenderState.mStereoRenderTexture; // TODO: render distortion preview
  540. }
  541. void OpenVRProvider::onStartFrame()
  542. {
  543. if (!mHMD)
  544. return;
  545. }
  546. void OpenVRProvider::onEndFrame()
  547. {
  548. if (!mHMD)
  549. return;
  550. }
  551. void OpenVRProvider::onEyeRendered(U32 index)
  552. {
  553. if (!mHMD)
  554. return;
  555. vr::EVRCompositorError err = vr::VRCompositorError_None;
  556. vr::VRTextureBounds_t bounds;
  557. U32 textureIdxToSubmit = index;
  558. GFXTexHandle eyeTex = mHMDRenderState.mOutputEyeTextures.getTextureHandle();
  559. if (mHMDRenderState.mRenderMode == GFXDevice::RS_StereoSeparate)
  560. {
  561. mHMDRenderState.mStereoRT->resolveTo(eyeTex);
  562. mHMDRenderState.mOutputEyeTextures.advance();
  563. }
  564. else
  565. {
  566. // assuming side-by-side, so the right eye will be next
  567. if (index == 1)
  568. {
  569. mHMDRenderState.mStereoRT->resolveTo(eyeTex);
  570. mHMDRenderState.mOutputEyeTextures.advance();
  571. }
  572. else
  573. {
  574. return;
  575. }
  576. }
  577. if (GFX->getAdapterType() == Direct3D11)
  578. {
  579. vr::Texture_t eyeTexture;
  580. if (mHMDRenderState.mRenderMode == GFXDevice::RS_StereoSeparate)
  581. {
  582. // whatever eye we are on
  583. eyeTexture = { (void*)static_cast<GFXD3D11TextureObject*>(eyeTex.getPointer())->get2DTex(), vr::API_DirectX, vr::ColorSpace_Gamma };
  584. bounds = OpenVRUtil::TorqueRectToBounds(mHMDRenderState.mEyeViewport[index], mHMDRenderState.mStereoRenderTexture.getWidthHeight());
  585. err = vr::VRCompositor()->Submit((vr::EVREye)(vr::Eye_Left + index), &eyeTexture, &bounds);
  586. }
  587. else
  588. {
  589. // left & right at the same time
  590. eyeTexture = { (void*)static_cast<GFXD3D11TextureObject*>(eyeTex.getPointer())->get2DTex(), vr::API_DirectX, vr::ColorSpace_Gamma };
  591. bounds = OpenVRUtil::TorqueRectToBounds(mHMDRenderState.mEyeViewport[0], mHMDRenderState.mStereoRenderTexture.getWidthHeight());
  592. err = vr::VRCompositor()->Submit((vr::EVREye)(vr::Eye_Left), &eyeTexture, &bounds);
  593. bounds = OpenVRUtil::TorqueRectToBounds(mHMDRenderState.mEyeViewport[1], mHMDRenderState.mStereoRenderTexture.getWidthHeight());
  594. err = vr::VRCompositor()->Submit((vr::EVREye)(vr::Eye_Right), &eyeTexture, &bounds);
  595. }
  596. }
  597. else if (GFX->getAdapterType() == Direct3D9)
  598. {
  599. //vr::Texture_t eyeTexture = { (void*)static_cast<GFXD3D9TextureObject*>(mHMDRenderState.mStereoRenderTextures[index].getPointer())->get2DTex(), vr::API_DirectX, vr::ColorSpace_Gamma };
  600. //err = vr::VRCompositor()->Submit((vr::EVREye)(vr::Eye_Left + index), &eyeTexture);
  601. }
  602. #ifdef TORQUE_OPENGL
  603. else if (GFX->getAdapterType() == OpenGL)
  604. {
  605. vr::Texture_t eyeTexture;
  606. if (mHMDRenderState.mRenderMode == GFXDevice::RS_StereoSeparate)
  607. {
  608. // whatever eye we are on
  609. eyeTexture = { (void*)static_cast<GFXGLTextureObject*>(eyeTex.getPointer())->getHandle(), vr::API_OpenGL, vr::ColorSpace_Gamma };
  610. bounds = OpenVRUtil::TorqueRectToBounds(mHMDRenderState.mEyeViewport[index], mHMDRenderState.mStereoRenderTexture.getWidthHeight());
  611. err = vr::VRCompositor()->Submit((vr::EVREye)(vr::Eye_Left + index), &eyeTexture, &bounds);
  612. }
  613. else
  614. {
  615. // left & right at the same time
  616. eyeTexture = { (void*)static_cast<GFXGLTextureObject*>(eyeTex.getPointer())->getHandle(), vr::API_OpenGL, vr::ColorSpace_Gamma };
  617. bounds = OpenVRUtil::TorqueRectToBounds(mHMDRenderState.mEyeViewport[0], mHMDRenderState.mStereoRenderTexture.getWidthHeight());
  618. err = vr::VRCompositor()->Submit((vr::EVREye)(vr::Eye_Left), &eyeTexture, &bounds);
  619. bounds = OpenVRUtil::TorqueRectToBounds(mHMDRenderState.mEyeViewport[1], mHMDRenderState.mStereoRenderTexture.getWidthHeight());
  620. err = vr::VRCompositor()->Submit((vr::EVREye)(vr::Eye_Right), &eyeTexture, &bounds);
  621. }
  622. }
  623. #endif
  624. AssertFatal(err == vr::VRCompositorError_None, "VR compositor error!");
  625. }
  626. void OpenVRProvider::setRoomTracking(bool room)
  627. {
  628. vr::IVRCompositor* compositor = vr::VRCompositor();
  629. mTrackingSpace = room ? vr::TrackingUniverseStanding : vr::TrackingUniverseSeated;
  630. if (compositor) compositor->SetTrackingSpace(mTrackingSpace);
  631. }
  632. bool OpenVRProvider::_handleDeviceEvent(GFXDevice::GFXDeviceEventType evt)
  633. {
  634. if (!ManagedSingleton<OpenVRProvider>::instanceOrNull())
  635. {
  636. return true;
  637. }
  638. switch (evt)
  639. {
  640. case GFXDevice::deStartOfFrame:
  641. // Start of frame
  642. onStartFrame();
  643. break;
  644. case GFXDevice::dePostFrame:
  645. // End of frame
  646. onEndFrame();
  647. break;
  648. case GFXDevice::deDestroy:
  649. // Need to reinit rendering
  650. break;
  651. case GFXDevice::deLeftStereoFrameRendered:
  652. //
  653. onEyeRendered(0);
  654. break;
  655. case GFXDevice::deRightStereoFrameRendered:
  656. //
  657. onEyeRendered(1);
  658. break;
  659. default:
  660. break;
  661. }
  662. return true;
  663. }
  664. S32 OpenVRProvider::getDisplayDeviceId() const
  665. {
  666. #if defined(TORQUE_OS_WIN64) || defined(TORQUE_OS_WIN32)
  667. if (GFX && GFX->getAdapterType() == Direct3D11)
  668. {
  669. Vector<GFXAdapter*> adapterList;
  670. GFXD3D11Device::enumerateAdapters(adapterList);
  671. for (U32 i = 0, sz = adapterList.size(); i < sz; i++)
  672. {
  673. GFXAdapter* adapter = adapterList[i];
  674. if (dMemcmp(&adapter->mLUID, &mLUID, sizeof(mLUID)) == 0)
  675. {
  676. return adapter->mIndex;
  677. }
  678. }
  679. }
  680. #endif
  681. return -1;
  682. }
  683. void OpenVRProvider::processVREvent(const vr::VREvent_t & event)
  684. {
  685. switch (event.eventType)
  686. {
  687. case vr::VREvent_TrackedDeviceActivated:
  688. {
  689. // Setup render model
  690. }
  691. break;
  692. case vr::VREvent_TrackedDeviceDeactivated:
  693. {
  694. // Deactivated
  695. }
  696. break;
  697. case vr::VREvent_TrackedDeviceUpdated:
  698. {
  699. // Updated
  700. }
  701. break;
  702. }
  703. }
  704. void OpenVRProvider::updateTrackedPoses()
  705. {
  706. if (!mHMD)
  707. return;
  708. vr::IVRCompositor* compositor = vr::VRCompositor();
  709. if (!compositor)
  710. return;
  711. if (compositor->GetTrackingSpace() != mTrackingSpace)
  712. {
  713. compositor->SetTrackingSpace(mTrackingSpace);
  714. }
  715. compositor->WaitGetPoses(mTrackedDevicePose, vr::k_unMaxTrackedDeviceCount, NULL, 0);
  716. mValidPoseCount = 0;
  717. for (int nDevice = 0; nDevice < vr::k_unMaxTrackedDeviceCount; ++nDevice)
  718. {
  719. IDevicePose &inPose = mCurrentDevicePose[nDevice];
  720. if (mTrackedDevicePose[nDevice].bPoseIsValid)
  721. {
  722. mValidPoseCount++;
  723. MatrixF mat = OpenVRUtil::convertSteamVRAffineMatrixToMatrixFPlain(mTrackedDevicePose[nDevice].mDeviceToAbsoluteTracking);
  724. mat.inverse();
  725. if (nDevice == vr::k_unTrackedDeviceIndex_Hmd)
  726. {
  727. mHMDRenderState.mHMDPose = mat;
  728. }
  729. vr::TrackedDevicePose_t &outPose = mTrackedDevicePose[nDevice];
  730. OpenVRTransformToRotPos(mat, inPose.orientation, inPose.position);
  731. inPose.state = outPose.eTrackingResult;
  732. inPose.valid = outPose.bPoseIsValid;
  733. inPose.connected = outPose.bDeviceIsConnected;
  734. inPose.velocity = OpenVRVecToTorqueVec(outPose.vVelocity);
  735. inPose.angularVelocity = OpenVRVecToTorqueVec(outPose.vAngularVelocity);
  736. }
  737. else
  738. {
  739. inPose.valid = false;
  740. }
  741. }
  742. }
  743. void OpenVRProvider::submitInputChanges()
  744. {
  745. // Diff current frame with previous frame
  746. for (U32 i = 0; i < vr::k_unMaxTrackedDeviceCount; i++)
  747. {
  748. IDevicePose curPose = mCurrentDevicePose[i];
  749. IDevicePose prevPose = mPreviousInputTrackedDevicePose[i];
  750. if (!curPose.valid || !curPose.connected)
  751. continue;
  752. if (curPose.orientation != prevPose.orientation)
  753. {
  754. AngAxisF axisAA(curPose.orientation);
  755. INPUTMGR->buildInputEvent(mDeviceType, 0, SI_ROT, OVR_SENSORROT[i], SI_MOVE, axisAA);
  756. }
  757. if (curPose.position != prevPose.position)
  758. {
  759. INPUTMGR->buildInputEvent(mDeviceType, 0, SI_POS, OVR_SENSORPOSITION[i], SI_MOVE, curPose.position);
  760. }
  761. if (curPose.velocity != prevPose.velocity)
  762. {
  763. // Convert angles to degrees
  764. VectorF angles;
  765. angles.x = curPose.velocity.x;
  766. angles.y = curPose.velocity.y;
  767. angles.z = curPose.velocity.z;
  768. INPUTMGR->buildInputEvent(mDeviceType, 0, SI_POS, OVR_SENSORVELOCITY[i], SI_MOVE, angles);
  769. }
  770. if (curPose.angularVelocity != prevPose.angularVelocity)
  771. {
  772. // Convert angles to degrees
  773. VectorF angles;
  774. angles[0] = mRadToDeg(curPose.velocity.x);
  775. angles[1] = mRadToDeg(curPose.velocity.y);
  776. angles[2] = mRadToDeg(curPose.velocity.z);
  777. INPUTMGR->buildInputEvent(mDeviceType, 0, SI_POS, OVR_SENSORANGVEL[i], SI_MOVE, angles);
  778. }
  779. /*
  780. if (curPose.connected != prevPose.connected)
  781. {
  782. if (Con::isFunction("onOVRConnectionChanged"))
  783. {
  784. Con::executef("onOVRConnectionStatus", curPose.connected);
  785. }
  786. }*/
  787. if (curPose.state != prevPose.state)
  788. {
  789. if (Con::isFunction("onOVRStateChanged"))
  790. {
  791. Con::executef("onOVRStateChanged", curPose.state);
  792. }
  793. }
  794. }
  795. dMemcpy(mPreviousInputTrackedDevicePose, mCurrentDevicePose, sizeof(mPreviousInputTrackedDevicePose));
  796. }
  797. void OpenVRProvider::resetSensors()
  798. {
  799. if (mHMD)
  800. {
  801. mHMD->ResetSeatedZeroPose();
  802. }
  803. }
  804. OpenVROverlay *OpenVRProvider::getGamepadFocusOverlay()
  805. {
  806. return NULL;
  807. }
  808. void OpenVRProvider::setOverlayNeighbour(vr::EOverlayDirection dir, OpenVROverlay *overlay)
  809. {
  810. }
  811. bool OpenVRProvider::isDashboardVisible()
  812. {
  813. return false;
  814. }
  815. void OpenVRProvider::showDashboard(const char *overlayToShow)
  816. {
  817. }
  818. vr::TrackedDeviceIndex_t OpenVRProvider::getPrimaryDashboardDevice()
  819. {
  820. return -1;
  821. }
  822. void OpenVRProvider::setKeyboardTransformAbsolute(const MatrixF &xfm)
  823. {
  824. // mTrackingSpace
  825. }
  826. void OpenVRProvider::setKeyboardPositionForOverlay(OpenVROverlay *overlay, const RectI &rect)
  827. {
  828. }
  829. DefineEngineStaticMethod(OpenVR, isDeviceActive, bool, (), ,
  830. "@brief Used to determine if the OpenVR input device is active\n\n"
  831. "The OpenVR device is considered active when the library has been "
  832. "initialized and either a real of simulated HMD is present.\n\n"
  833. "@return True if the OpenVR input device is active.\n"
  834. "@ingroup Game")
  835. {
  836. if (!ManagedSingleton<OpenVRProvider>::instanceOrNull())
  837. {
  838. return false;
  839. }
  840. return OPENVR->getActive();
  841. }
  842. DefineEngineStaticMethod(OpenVR, setEnabled, bool, (bool value), ,
  843. "@brief Used to determine if the OpenVR input device is active\n\n"
  844. "The OpenVR device is considered active when the library has been "
  845. "initialized and either a real of simulated HMD is present.\n\n"
  846. "@return True if the OpenVR input device is active.\n"
  847. "@ingroup Game")
  848. {
  849. if (!ManagedSingleton<OpenVRProvider>::instanceOrNull())
  850. {
  851. return false;
  852. }
  853. return value ? OPENVR->enable() : OPENVR->disable();
  854. }
  855. DefineEngineStaticMethod(OpenVR, setHMDAsGameConnectionDisplayDevice, bool, (GameConnection* conn), ,
  856. "@brief Sets the first HMD to be a GameConnection's display device\n\n"
  857. "@param conn The GameConnection to set.\n"
  858. "@return True if the GameConnection display device was set.\n"
  859. "@ingroup Game")
  860. {
  861. if (!ManagedSingleton<OpenVRProvider>::instanceOrNull())
  862. {
  863. Con::errorf("setOVRHMDAsGameConnectionDisplayDevice(): No Oculus VR Device present.");
  864. return false;
  865. }
  866. if (!conn)
  867. {
  868. Con::errorf("setOVRHMDAsGameConnectionDisplayDevice(): Invalid GameConnection.");
  869. return false;
  870. }
  871. conn->setDisplayDevice(OPENVR);
  872. return true;
  873. }
  874. DefineEngineStaticMethod(OpenVR, getDisplayDeviceId, S32, (), ,
  875. "@brief MacOS display ID.\n\n"
  876. "@param index The HMD index.\n"
  877. "@return The ID of the HMD display device, if any.\n"
  878. "@ingroup Game")
  879. {
  880. if (!ManagedSingleton<OpenVRProvider>::instanceOrNull())
  881. {
  882. return -1;
  883. }
  884. return OPENVR->getDisplayDeviceId();
  885. }
  886. DefineEngineStaticMethod(OpenVR, resetSensors, void, (), ,
  887. "@brief Resets all Oculus VR sensors.\n\n"
  888. "This resets all sensor orientations such that their 'normal' rotation "
  889. "is defined when this function is called. This defines an HMD's forwards "
  890. "and up direction, for example."
  891. "@ingroup Game")
  892. {
  893. if (!ManagedSingleton<OpenVRProvider>::instanceOrNull())
  894. {
  895. return;
  896. }
  897. OPENVR->resetSensors();
  898. }
  899. // Overlay stuff