Oculus Rift.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. #define SUPPORT_OCULUS (WINDOWS_OLD && DX11)
  4. #if SUPPORT_OCULUS
  5. #include "../../../ThirdPartyLibs/begin.h"
  6. //#include "../../../ThirdPartyLibs/Oculus/LibOVR/Include/OVR.h"
  7. #include "../../../ThirdPartyLibs/Oculus/LibOVR/Include/OVR_CAPI.h"
  8. #if DX11
  9. #include "../../../ThirdPartyLibs/Oculus/LibOVR/Include/OVR_CAPI_D3D.h"
  10. #elif GL
  11. #include "../../../ThirdPartyLibs/Oculus/LibOVR/Include/OVR_CAPI_GL.h"
  12. #endif
  13. #include "../../../ThirdPartyLibs/end.h"
  14. #endif
  15. /******************************************************************************/
  16. namespace EE{
  17. /******************************************************************************/
  18. static struct OculusRiftApi : VirtualRealityApi
  19. {
  20. virtual Bool init()override;
  21. virtual void shut()override;
  22. virtual Bool active ()C override;
  23. virtual Matrix matrixCur ()C override;
  24. virtual void recenter () override;
  25. virtual void changedGuiDepth() override;
  26. virtual void changedGuiSize () override;
  27. virtual void update () override;
  28. virtual void draw () override;
  29. virtual void delImages()override;
  30. virtual Bool createGuiImage ()override;
  31. virtual Bool createRenderImage ()override;
  32. virtual ImageRC* getNewRender ()override;
  33. virtual ImageRC* getNewGui ()override;
  34. virtual ImageRC* getLastRender()override;
  35. virtual ImageRC* getLastGui ()override;
  36. Bool connect();
  37. void disconnect();
  38. void setGuiSizeX();
  39. void setGuiSize ();
  40. OculusRiftApi();
  41. #if SUPPORT_OCULUS
  42. //private:
  43. Bool _initialized;
  44. ovrSession _session;
  45. ovrLayerEyeFov _layer_render;
  46. ovrLayerQuad _layer_gui;
  47. #endif
  48. }OculusRift;
  49. /******************************************************************************/
  50. #if SUPPORT_OCULUS
  51. static struct ovrTexture
  52. {
  53. ImageRC image;
  54. ovrSwapTextureSet *texture_set;
  55. #if DX11
  56. ID3D11RenderTargetView *rtv[3];
  57. ID3D11ShaderResourceView *srv[3];
  58. #endif
  59. ~ovrTexture() {del();}
  60. ovrTexture()
  61. {
  62. texture_set=null;
  63. #if DX11
  64. REPAO(rtv)=null;
  65. REPAO(srv)=null;
  66. #endif
  67. }
  68. void del()
  69. {
  70. image.zero(); // !! zero without deleting, because members were just copied !!
  71. #if DX11
  72. if(D.created())
  73. {
  74. REPA(rtv)RELEASE(rtv[i]);
  75. REPA(srv)RELEASE(srv[i]);
  76. }else
  77. {
  78. REPAO(rtv)=null;
  79. REPAO(srv)=null;
  80. }
  81. #endif
  82. if(OculusRift._session)ovr_DestroySwapTextureSet(OculusRift._session, texture_set); texture_set=null;
  83. }
  84. Bool create(Int w, Int h)
  85. {
  86. del();
  87. // TODO: support gamma correct sRGB rendering
  88. image._size=image._hw_size.set(w, h, 1);
  89. image._type=image._hw_type=IMAGE_R8G8B8A8;
  90. image._mode=IMAGE_RT;
  91. image._mms=1;
  92. image._samples=1;
  93. image._byte_pp=ImageTI[image.type()].byte_pp;
  94. image. setPartial();
  95. #if DX11
  96. D3D11_TEXTURE2D_DESC desc;
  97. desc.Width =image.w();
  98. desc.Height =image.h();
  99. desc.MipLevels =1;
  100. desc.Format =DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
  101. desc.Usage =D3D11_USAGE_DEFAULT;
  102. desc.BindFlags =D3D11_BIND_RENDER_TARGET|D3D11_BIND_SHADER_RESOURCE;
  103. desc.MiscFlags =0;
  104. desc.CPUAccessFlags =0;
  105. desc.SampleDesc.Count =1;
  106. desc.SampleDesc.Quality=0;
  107. desc.ArraySize =1;
  108. //SyncLockerEx locker(D._lock); lock not needed for DX11 'D3D'
  109. if(ovr_CreateSwapTextureSetD3D11(OculusRift._session, D3D, &desc, ovrSwapTextureSetD3D11_Typeless, &texture_set)==ovrSuccess)
  110. {
  111. if (texture_set->TextureCount>Elms(rtv))Exit("Oculus Rift Swap Chain has too many textures");
  112. FREP(texture_set->TextureCount)
  113. {
  114. ovrD3D11Texture &tex=(ovrD3D11Texture&)texture_set->Textures[i];
  115. D3D11_RENDER_TARGET_VIEW_DESC rtvd; Zero(rtvd);
  116. rtvd.Format =DXGI_FORMAT_R8G8B8A8_UNORM;
  117. rtvd.ViewDimension=D3D11_RTV_DIMENSION_TEXTURE2D;
  118. if(!OK(D3D->CreateRenderTargetView(tex.D3D11.pTexture, &rtvd, &rtv[i])))goto error;
  119. D3D11_SHADER_RESOURCE_VIEW_DESC srvd; Zero(srvd);
  120. srvd.Format =DXGI_FORMAT_R8G8B8A8_UNORM;
  121. srvd.ViewDimension =D3D11_SRV_DIMENSION_TEXTURE2D;
  122. srvd.Texture2D.MipLevels=1;
  123. if(!OK(D3D->CreateShaderResourceView(tex.D3D11.pTexture, &srvd, &srv[i])))goto error;
  124. }
  125. return true;
  126. }
  127. #endif
  128. error:
  129. del(); return false;
  130. }
  131. ImageRC* getImage()
  132. {
  133. if(texture_set)
  134. {
  135. if( ++texture_set->CurrentIndex>=texture_set->TextureCount)texture_set->CurrentIndex=0;
  136. Int i=texture_set->CurrentIndex;
  137. image.unlock(); // unlock if it was locked by the user
  138. #if DX11
  139. ovrD3D11Texture &tex=(ovrD3D11Texture&)texture_set->Textures[i];
  140. image._txtr=tex.D3D11.pTexture;
  141. image._rtv =rtv[i];
  142. image._srv =srv[i];
  143. #endif
  144. return ℑ
  145. }
  146. return null;
  147. }
  148. }RenderTexture, GuiTexture;
  149. static void SetPose(Matrix &m, C ovrPosef &pose)
  150. {
  151. ASSERT(SIZE(pose.Orientation)==SIZE(Quaternion)); Quaternion q=(Quaternion&)pose.Orientation; CHS(q.z); m.orn()=q;
  152. ASSERT(SIZE(pose.Position )==SIZE(Vec )); m.pos.set(pose.Position.x, pose.Position.y, -pose.Position.z); // Oculus is right-handed
  153. }
  154. static void SetPose(ovrPosef &pose, C Matrix &m)
  155. {
  156. ASSERT(SIZE(pose.Orientation)==SIZE(Quaternion)); (Quaternion&)pose.Orientation=Quaternion(m); CHS(pose.Orientation.z);
  157. ASSERT(SIZE(pose.Position )==SIZE(Vec )); ((Vec&)pose.Position).set(m.pos.x, m.pos.y, -m.pos.z); // Oculus is right-handed
  158. }
  159. void OculusRiftApi::disconnect()
  160. {
  161. VR.delImages(); // !! need to call 'VR.delImages' and not 'T.delImages' !!
  162. if(_session)
  163. {
  164. ovr_Destroy(_session); _session=null;
  165. VR.disconnected(); // call 'disconnected' after clearing '_session' so 'VR.active' is false (needed for some things including 'D.setSync')
  166. }
  167. }
  168. Bool OculusRiftApi::connect()
  169. {
  170. disconnect();
  171. ASSERT(SIZE(VR._adapter_id)==SIZE(ovrGraphicsLuid));
  172. if(ovr_Create(&_session, (ovrGraphicsLuid*)&VR._adapter_id)==ovrSuccess)
  173. {
  174. D.clearFade();
  175. ovrHmdDesc desc=ovr_GetHmdDesc(_session);
  176. Set(VR._name, desc.ProductName);
  177. VR._refresh=desc.DisplayRefreshRate;
  178. VR._res.set(desc.Resolution.w, desc.Resolution.h);
  179. VR.setFOVTan(desc.DefaultEyeFov[0].LeftTan, desc.DefaultEyeFov[0].RightTan, desc.DefaultEyeFov[0].UpTan, desc.DefaultEyeFov[0].DownTan);
  180. ovrEyeRenderDesc eye_render_desc[2]; REPAO(eye_render_desc)=ovr_GetRenderDesc(_session, ovrEyeType(i), desc.DefaultEyeFov[i]);
  181. ASSERT(SIZE(eye_render_desc[0].HmdToEyeViewOffset)==SIZE(Vec));
  182. VR._eye_dist=Dist((Vec&)eye_render_desc[0].HmdToEyeViewOffset,
  183. (Vec&)eye_render_desc[1].HmdToEyeViewOffset);
  184. REP(2)_layer_render.Fov[i]=desc.DefaultEyeFov[i]; // eyes
  185. return VR.connected(); // call 'connected' after having set '_session' so 'VR.active' is true (needed for some things including 'D.setSync')
  186. }
  187. return false;
  188. }
  189. #endif
  190. /******************************************************************************/
  191. OculusRiftApi::OculusRiftApi()
  192. {
  193. #if SUPPORT_OCULUS
  194. _initialized=false;
  195. _session=null;
  196. Zero(_layer_render);
  197. _layer_render.Header.Type =ovrLayerType_EyeFov;
  198. _layer_render.Header.Flags=0;
  199. Zero(_layer_gui);
  200. _layer_gui.Header.Type =ovrLayerType_Quad;
  201. _layer_gui.Header.Flags=ovrLayerFlag_HeadLocked;
  202. Matrix m; m.identity(); SetPose(_layer_gui.QuadPoseCenter, m);
  203. _layer_gui.QuadPoseCenter.Position.z=-1; // Oculus is right-handed
  204. _layer_gui.QuadSize.y=1;
  205. #endif
  206. }
  207. /******************************************************************************/
  208. Bool VirtualReality::OculusRiftInit () {return VR.init(OculusRift);}
  209. Bool VirtualReality::OculusRiftDetected()C
  210. {
  211. #if SUPPORT_OCULUS
  212. return ovr_Detect(0).IsOculusHMDConnected!=ovrFalse; // according to headers, this can be called before 'ovr_Initialize'
  213. #else
  214. return false;
  215. #endif
  216. }
  217. Bool OculusRiftApi::active()C
  218. {
  219. #if SUPPORT_OCULUS
  220. return _session!=null;
  221. #else
  222. return false;
  223. #endif
  224. }
  225. /******************************************************************************/
  226. Bool OculusRiftApi::init()
  227. {
  228. #if SUPPORT_OCULUS
  229. if(!_initialized && ovr_Initialize(null)==ovrSuccess)
  230. {
  231. _initialized=true;
  232. connect();
  233. }
  234. return _initialized;
  235. #endif
  236. return false;
  237. }
  238. void OculusRiftApi::shut()
  239. {
  240. #if SUPPORT_OCULUS
  241. if(_initialized)
  242. {
  243. disconnect();
  244. _initialized=false;
  245. ovr_Shutdown();
  246. }
  247. #endif
  248. }
  249. /******************************************************************************/
  250. Matrix OculusRiftApi::matrixCur()C
  251. {
  252. #if SUPPORT_OCULUS
  253. if(_session)
  254. {
  255. ovrTrackingState ts=ovr_GetTrackingState(_session, 0, ovrFalse); // according to headers, "time 0" will get "the most recent sensor reading"
  256. if(ts.StatusFlags&(ovrStatus_OrientationTracked|ovrStatus_PositionTracked))
  257. {
  258. Matrix m; SetPose(m, ts.HeadPose.ThePose);
  259. return m;
  260. }
  261. }
  262. #endif
  263. return VR._matrix; // return last known matrix
  264. }
  265. /******************************************************************************/
  266. void OculusRiftApi::setGuiSizeX()
  267. {
  268. #if SUPPORT_OCULUS
  269. _layer_gui.QuadSize.x=_layer_gui.QuadSize.y*GuiTexture.image.aspect();
  270. #endif
  271. }
  272. void OculusRiftApi::setGuiSize()
  273. {
  274. #if SUPPORT_OCULUS
  275. _layer_gui.QuadSize.y=VR._gui_size*-_layer_gui.QuadPoseCenter.Position.z; // Oculus is right-handed
  276. #endif
  277. setGuiSizeX();
  278. }
  279. void OculusRiftApi::changedGuiDepth()
  280. {
  281. #if SUPPORT_OCULUS
  282. _layer_gui.QuadPoseCenter.Position.z=-VR.guiDepth(); // Oculus is right-handed
  283. setGuiSize();
  284. #endif
  285. }
  286. void OculusRiftApi::changedGuiSize()
  287. {
  288. #if SUPPORT_OCULUS
  289. setGuiSize();
  290. #endif
  291. }
  292. /******************************************************************************/
  293. void OculusRiftApi::delImages()
  294. {
  295. #if SUPPORT_OCULUS
  296. RenderTexture.del();
  297. GuiTexture.del();
  298. #endif
  299. }
  300. Bool OculusRiftApi::createGuiImage()
  301. {
  302. #if SUPPORT_OCULUS
  303. if(GuiTexture.create(VR.guiRes().x, VR.guiRes().y))
  304. {
  305. _layer_gui.ColorTexture=GuiTexture.texture_set;
  306. _layer_gui.Viewport.Pos .x=_layer_gui.Viewport.Pos.y=0;
  307. _layer_gui.Viewport.Size.w=GuiTexture.image.w();
  308. _layer_gui.Viewport.Size.h=GuiTexture.image.h();
  309. setGuiSizeX();
  310. return true;
  311. }
  312. #endif
  313. return false;
  314. }
  315. Bool OculusRiftApi::createRenderImage()
  316. {
  317. #if SUPPORT_OCULUS
  318. ovrHmdDesc desc=ovr_GetHmdDesc(_session);
  319. ovrSizei size=ovr_GetFovTextureSize(_session, ovrEye_Left, desc.DefaultEyeFov[0], VR.pixelDensity());
  320. Clamp(size.w*=2, 2, D.maxTexSize()); // *2 also makes sure that both eyes have the same width
  321. Clamp(size.h , 1, D.maxTexSize());
  322. if(RenderTexture.create(size.w, size.h))
  323. {
  324. _layer_render.ColorTexture[0]=RenderTexture.texture_set; // setting only to 0 means that texture contains data for both eyes
  325. _layer_render.ColorTexture[1]=null;
  326. _layer_render.Viewport[0].Pos .x=_layer_render.Viewport[0].Pos .y=_layer_render.Viewport[1].Pos .y=0;
  327. _layer_render.Viewport[1].Pos .x=_layer_render.Viewport[0].Size.w=_layer_render.Viewport[1].Size.w=RenderTexture.image.w()/2;
  328. _layer_render.Viewport[0].Size.h=_layer_render.Viewport[1].Size.h=RenderTexture.image.h();
  329. return true;
  330. }
  331. #endif
  332. return false;
  333. }
  334. /******************************************************************************/
  335. ImageRC* OculusRiftApi::getNewRender()
  336. {
  337. #if SUPPORT_OCULUS
  338. return RenderTexture.getImage();
  339. #endif
  340. return null;
  341. }
  342. ImageRC* OculusRiftApi::getNewGui()
  343. {
  344. #if SUPPORT_OCULUS
  345. return GuiTexture.getImage();
  346. #endif
  347. return null;
  348. }
  349. ImageRC* OculusRiftApi::getLastRender()
  350. {
  351. #if SUPPORT_OCULUS
  352. return &RenderTexture.image;
  353. #endif
  354. return null;
  355. }
  356. ImageRC* OculusRiftApi::getLastGui()
  357. {
  358. #if SUPPORT_OCULUS
  359. return &GuiTexture.image;
  360. #endif
  361. return null;
  362. }
  363. /******************************************************************************/
  364. void OculusRiftApi::recenter()
  365. {
  366. #if SUPPORT_OCULUS
  367. if(_session)ovr_RecenterPose(_session);
  368. #endif
  369. }
  370. /******************************************************************************/
  371. void OculusRiftApi::update()
  372. {
  373. #if SUPPORT_OCULUS
  374. if(_initialized)
  375. {
  376. VR._has_render=false;
  377. if(_session)
  378. {
  379. _layer_render.SensorSampleTime=ovr_GetTimeInSeconds(); // needs to be set at the same time when obtaining sensor data
  380. ovrTrackingState ts=ovr_GetTrackingState(_session, ovr_GetPredictedDisplayTime(_session, 0), ovrTrue);
  381. if(ts.StatusFlags&ovrStatus_HmdConnected)
  382. {
  383. C ovrVector3f &a=ts.RawSensorData.Accelerometer; AccelerometerValue.set(-a.x, -a.y, a.z);
  384. C ovrVector3f &g=ts.RawSensorData.Gyro ; GyroscopeValue.set( g.x, g.y, -g.z);
  385. C ovrVector3f &m=ts.RawSensorData.Magnetometer ; MagnetometerValue.set( m.x, m.y, -m.z);
  386. if(ts.HandStatusFlags[0]&(ovrStatus_OrientationTracked|ovrStatus_PositionTracked))SetPose(VR._left , ts.HandPoses[0].ThePose);
  387. if(ts.HandStatusFlags[1]&(ovrStatus_OrientationTracked|ovrStatus_PositionTracked))SetPose(VR._right, ts.HandPoses[1].ThePose);
  388. if(ts.StatusFlags &(ovrStatus_OrientationTracked|ovrStatus_PositionTracked))
  389. {
  390. SetPose(VR._matrix, ts.HeadPose.ThePose);
  391. #if 0 // slower
  392. ovrVector3f HmdToEyeViewOffset[2]=
  393. {
  394. {D.eyeDistance()*-0.5f, 0, 0},
  395. {D.eyeDistance()* 0.5f, 0, 0},
  396. };
  397. ovr_CalcEyePoses(ts.HeadPose.ThePose, HmdToEyeViewOffset, _layer_render.RenderPose);
  398. #else
  399. Vec eye_offset=VR._matrix.x*D.eyeDistance(); CHS(eye_offset.z); // need to change z because Oculus is right-handed
  400. ASSERT(SIZE(ts.HeadPose.ThePose.Position)==SIZE(Vec));
  401. (Vec&)ts.HeadPose.ThePose.Position-=eye_offset*0.5f; _layer_render.RenderPose[0]=ts.HeadPose.ThePose;
  402. (Vec&)ts.HeadPose.ThePose.Position+=eye_offset ; _layer_render.RenderPose[1]=ts.HeadPose.ThePose;
  403. #endif
  404. }
  405. }else disconnect(); // lost connection
  406. }else
  407. if(VR.OculusRiftDetected()) // try to connect
  408. {
  409. connect();
  410. }
  411. }
  412. #endif
  413. }
  414. void OculusRiftApi::draw()
  415. {
  416. #if SUPPORT_OCULUS
  417. if(active())
  418. {
  419. #if 0 // this made absolutely no difference, TODO: test in the future with a newer SDK
  420. FlagSet(_layer_render.Header.Flags, ovrLayerFlag_HighQuality, Ms.b(0));
  421. FlagSet(_layer_gui .Header.Flags, ovrLayerFlag_HighQuality, Ms.b(1));
  422. #endif
  423. ovrLayerHeader *layer[2]; Int layers=0;
  424. if(VR._has_render)layer[layers++]=&_layer_render.Header;
  425. if(VR. draw_2d )layer[layers++]=&_layer_gui .Header;
  426. ovr_SubmitFrame(_session, 0, null, layer, layers);
  427. }
  428. #endif
  429. }
  430. /******************************************************************************/
  431. }
  432. /******************************************************************************/