openVRProvider.cpp 34 KB

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