ccOculus.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. //##########################################################################
  2. //# #
  3. //# CLOUDCOMPARE #
  4. //# #
  5. //# This program is free software; you can redistribute it and/or modify #
  6. //# it under the terms of the GNU General Public License as published by #
  7. //# the Free Software Foundation; version 2 of the License. #
  8. //# #
  9. //# This program is distributed in the hope that it will be useful, #
  10. //# but WITHOUT ANY WARRANTY; without even the implied warranty of #
  11. //# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
  12. //# GNU General Public License for more details. #
  13. //# #
  14. //# COPYRIGHT: CloudCompare project #
  15. //# #
  16. //##########################################################################
  17. //qCC_db
  18. #include <ccIncludeGL.h>
  19. #include <ccLog.h>
  20. //CCLib
  21. #include <CCGeom.h>
  22. //CCFbo
  23. #include <ccFrameBufferObject.h>
  24. //OVRlib
  25. #include <OVR_CAPI.h>
  26. #include <OVR_CAPI_GL.h>
  27. #include <Extras/OVR_Math.h>
  28. //system
  29. #include <vector>
  30. //Oculus SDK 'session'
  31. struct OculusHMD
  32. {
  33. OculusHMD()
  34. : session(nullptr)
  35. , fbo(nullptr)
  36. , hasTextureSet(false)
  37. , lastOVRPos(0, 0, 0)
  38. , hasLastOVRPos(false)
  39. {
  40. textureSize.w = textureSize.h = 0;
  41. }
  42. ~OculusHMD()
  43. {
  44. stop(true);
  45. }
  46. void setSesion(ovrSession s)
  47. {
  48. if (session && session != s)
  49. {
  50. //auto-stop
  51. stop(false);
  52. }
  53. session = s;
  54. if (session)
  55. {
  56. ovrHmdDesc hmdDesc = ovr_GetHmdDesc(session);
  57. eyeRenderDesc[0] = ovr_GetRenderDesc(session, ovrEye_Left, hmdDesc.DefaultEyeFov[0]);
  58. eyeRenderDesc[1] = ovr_GetRenderDesc(session, ovrEye_Right, hmdDesc.DefaultEyeFov[1]);
  59. hmdToEyeViewOffset[0] = eyeRenderDesc[0].HmdToEyeOffset;
  60. hmdToEyeViewOffset[1] = eyeRenderDesc[1].HmdToEyeOffset;
  61. }
  62. }
  63. bool initTextureSet(QOpenGLContext* context)
  64. {
  65. if (!session || !context)
  66. {
  67. assert(false);
  68. return false;
  69. }
  70. ovrHmdDesc hmdDesc = ovr_GetHmdDesc(session);
  71. ovrSizei recommendedTex0Size = ovr_GetFovTextureSize(session, ovrEye_Left, hmdDesc.DefaultEyeFov[0], 1.0f);
  72. ovrSizei recommendedTex1Size = ovr_GetFovTextureSize(session, ovrEye_Right, hmdDesc.DefaultEyeFov[1], 1.0f);
  73. //determine the rendering FOV and allocate the required ovrSwapTextureSet (see https://developer.oculus.com/documentation/pcsdk/latest/concepts/dg-render/)
  74. ovrSizei bufferSize;
  75. {
  76. bufferSize.w = recommendedTex0Size.w + recommendedTex1Size.w;
  77. bufferSize.h = std::max(recommendedTex0Size.h, recommendedTex1Size.h);
  78. }
  79. if ( !hasTextureSet
  80. || !fbo
  81. || textureSize.w != bufferSize.w
  82. || textureSize.h != bufferSize.h )
  83. {
  84. destroyTextureSet();
  85. ovrTextureSwapChainDesc desc = {};
  86. desc.Type = ovrTexture_2D;
  87. desc.ArraySize = 1;
  88. desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
  89. desc.Width = bufferSize.w;
  90. desc.Height = bufferSize.h;
  91. desc.MipLevels = 1;
  92. desc.SampleCount = 1;
  93. desc.StaticImage = ovrFalse;
  94. if (!ovr_CreateTextureSwapChainGL(session,
  95. &desc,
  96. &textureSwapChain) == ovrSuccess)
  97. {
  98. return false;
  99. }
  100. hasTextureSet = true;
  101. assert(!fbo);
  102. fbo = new ccFrameBufferObject;
  103. if ( !fbo->init( static_cast<unsigned>(bufferSize.w),
  104. static_cast<unsigned>(bufferSize.h) )
  105. //|| !fbo->initDepth()
  106. )
  107. {
  108. destroyTextureSet();
  109. return false;
  110. }
  111. QOpenGLFunctions_2_1* glFunc = context->versionFunctions<QOpenGLFunctions_2_1>();
  112. //we create a depth texture for each color texture
  113. assert(depthTextures.empty());
  114. int textureCount = 0;
  115. ovr_GetTextureSwapChainLength(session, textureSwapChain, &textureCount);
  116. depthTextures.resize(textureCount, 0);
  117. for (int i = 0; i < textureCount; ++i)
  118. {
  119. //set the color texture
  120. {
  121. unsigned int texId;
  122. ovr_GetTextureSwapChainBufferGL(session, textureSwapChain, 0, &texId);
  123. glFunc->glBindTexture(GL_TEXTURE_2D, texId);
  124. glFunc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
  125. glFunc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
  126. glFunc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR/*GL_LINEAR_MIPMAP_LINEAR*/);
  127. glFunc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  128. if (context->hasExtension(QByteArrayLiteral("GLE_EXT_texture_filter_anisotropic")))
  129. {
  130. glFunc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1);
  131. }
  132. glFunc->glBindTexture(GL_TEXTURE_2D, 0);
  133. }
  134. //create the depth texture
  135. {
  136. glFunc->glPushAttrib(GL_ENABLE_BIT);
  137. glFunc->glEnable(GL_TEXTURE_2D);
  138. GLuint texID = 0;
  139. glFunc->glGenTextures(1, &texID);
  140. glFunc->glBindTexture(GL_TEXTURE_2D, texID);
  141. glFunc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
  142. glFunc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
  143. glFunc->glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
  144. glFunc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
  145. glFunc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  146. glFunc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  147. glFunc->glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, bufferSize.w, bufferSize.h, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
  148. glFunc->glBindTexture(GL_TEXTURE_2D, 0);
  149. glFunc->glPopAttrib();
  150. depthTextures[i] = texID;
  151. }
  152. }
  153. //DGM: doesn't work :(
  154. //fbo->initDepth();
  155. textureSize = bufferSize;
  156. }
  157. // Initialize our single full screen Fov layer.
  158. layer.Header.Type = ovrLayerType_EyeFov;
  159. layer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft;
  160. layer.ColorTexture[0] = textureSwapChain;
  161. layer.ColorTexture[1] = textureSwapChain;
  162. layer.Fov[0] = eyeRenderDesc[0].Fov;
  163. layer.Fov[1] = eyeRenderDesc[1].Fov;
  164. layer.Viewport[0].Pos.x = 0;
  165. layer.Viewport[0].Pos.y = 0;
  166. layer.Viewport[0].Size = recommendedTex0Size;
  167. layer.Viewport[1].Pos.x = recommendedTex0Size.w;
  168. layer.Viewport[1].Pos.y = 0;
  169. layer.Viewport[1].Size = recommendedTex1Size;
  170. return true;
  171. }
  172. bool initMirrorTexture(int w, int h, QOpenGLExtension_ARB_framebuffer_object& glExt)
  173. {
  174. if (!session)
  175. {
  176. assert(false);
  177. return false;
  178. }
  179. //mirrorTexture
  180. if (!mirror.texture)
  181. {
  182. ovrMirrorTextureDesc desc;
  183. memset(&desc, 0, sizeof(desc));
  184. desc.Width = w;
  185. desc.Height = h;
  186. desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
  187. // Create mirror texture and an FBO used to copy mirror texture to back buffer
  188. ovrResult result = ovr_CreateMirrorTextureGL(session, &desc, &mirror.texture);
  189. if (OVR_SUCCESS(result))
  190. {
  191. // Configure the mirror read buffer
  192. ovr_GetMirrorTextureBufferGL(session, mirror.texture, &mirror.textureID);
  193. mirror.size = QSize(w, h);
  194. // And the FBO
  195. glExt.glGenFramebuffers(1, &mirror.fbo);
  196. glExt.glBindFramebuffer(GL_READ_FRAMEBUFFER, mirror.fbo);
  197. glExt.glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mirror.textureID, 0);
  198. glExt.glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
  199. glExt.glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
  200. }
  201. else
  202. {
  203. ccLog::Warning("[Oculus] Failed to create the mirror texture");
  204. return false;
  205. }
  206. }
  207. return true;
  208. }
  209. void releaseMirrorTexture(QOpenGLExtension_ARB_framebuffer_object& glExt)
  210. {
  211. if (mirror.fbo)
  212. {
  213. glExt.glDeleteFramebuffers(1, &mirror.fbo);
  214. mirror.fbo = 0;
  215. }
  216. if (mirror.texture)
  217. {
  218. ovr_DestroyMirrorTexture(session, mirror.texture);
  219. mirror.texture = nullptr;
  220. }
  221. }
  222. void stop(bool autoShutdown = true)
  223. {
  224. if (session)
  225. {
  226. //destroy the textures (if any)
  227. destroyTextureSet();
  228. //then destroy the session
  229. ovr_Destroy(session);
  230. session = 0;
  231. }
  232. if (autoShutdown)
  233. {
  234. ovr_Shutdown();
  235. }
  236. }
  237. //! Destroy the textures (if any)
  238. void destroyTextureSet(QOpenGLFunctions_2_1* glFunc = 0)
  239. {
  240. if (fbo)
  241. {
  242. delete fbo;
  243. fbo = 0;
  244. }
  245. if (hasTextureSet)
  246. {
  247. ovr_DestroyTextureSwapChain(session, textureSwapChain);
  248. hasTextureSet = false;
  249. }
  250. if (!depthTextures.empty())
  251. {
  252. QOpenGLContext* context = QOpenGLContext::currentContext();
  253. if (context)
  254. {
  255. QOpenGLFunctions_2_1* glFunc = context->versionFunctions<QOpenGLFunctions_2_1>();
  256. for (size_t i = 0; i < depthTextures.size(); ++i)
  257. {
  258. glFunc->glDeleteTextures(1, &(depthTextures[i]));
  259. }
  260. }
  261. depthTextures.clear();
  262. }
  263. textureSize.w = textureSize.h = 0;
  264. }
  265. //! Session handle
  266. ovrSession session;
  267. //! Dedicated FBO
  268. ccFrameBufferObject* fbo;
  269. //! Mirror texture
  270. struct Mirror
  271. {
  272. //! texture
  273. ovrMirrorTexture texture = nullptr;
  274. //! texture ID
  275. GLuint textureID = 0;
  276. //! texture size
  277. QSize size;
  278. //! FBO
  279. GLuint fbo = 0;
  280. };
  281. //! Mirror
  282. Mirror mirror;
  283. //! Color texture(s)
  284. ovrTextureSwapChain textureSwapChain;
  285. //! Whether color texture(s) are available
  286. bool hasTextureSet;
  287. //! Depth texture(s)
  288. std::vector<GLuint> depthTextures;
  289. //! Texture(s) size
  290. ovrSizei textureSize;
  291. //stereo pair rendering parameters
  292. ovrEyeRenderDesc eyeRenderDesc[2];
  293. ovrVector3f hmdToEyeViewOffset[2];
  294. ovrLayerEyeFov layer;
  295. //! Last sensor position
  296. CCVector3d lastOVRPos;
  297. //! Whether a position has been already recorded or not
  298. bool hasLastOVRPos;
  299. };
  300. static ccGLMatrixd FromOVRMat(const OVR::Matrix4f& ovrMat)
  301. {
  302. ccGLMatrixd ccMat;
  303. double* data = ccMat.data();
  304. data[0] = ovrMat.M[0][0]; data[4] = ovrMat.M[0][1]; data[8] = ovrMat.M[0][2]; data[12] = ovrMat.M[0][3];
  305. data[1] = ovrMat.M[1][0]; data[5] = ovrMat.M[1][1]; data[9] = ovrMat.M[1][2]; data[13] = ovrMat.M[1][3];
  306. data[2] = ovrMat.M[2][0]; data[6] = ovrMat.M[2][1]; data[10] = ovrMat.M[2][2]; data[14] = ovrMat.M[2][3];
  307. data[3] = ovrMat.M[3][0]; data[7] = ovrMat.M[3][1]; data[11] = ovrMat.M[3][2]; data[15] = ovrMat.M[3][3];
  308. return ccMat;
  309. }
  310. static OVR::Matrix4f ToOVRMat(const ccGLMatrixd& ccMat)
  311. {
  312. const double* M = ccMat.data();
  313. return OVR::Matrix4f( M[0], M[4], M[8], M[12],
  314. M[1], M[5], M[9], M[13],
  315. M[2], M[6], M[10], M[14],
  316. M[3], M[7], M[11], M[15]);
  317. }
  318. static void OVR_CDECL LogCallback(uintptr_t /*userData*/, int level, const char* message)
  319. {
  320. switch (level)
  321. {
  322. case ovrLogLevel_Debug:
  323. ccLog::PrintDebug(QString("[oculus] ") + message);
  324. break;
  325. case ovrLogLevel_Info:
  326. ccLog::Print(QString("[oculus] ") + message);
  327. break;
  328. case ovrLogLevel_Error:
  329. ccLog::Warning(QString("[oculus] ") + message);
  330. break;
  331. default:
  332. assert(false);
  333. break;
  334. }
  335. }