OCULUS Scol plugin
 All Classes Functions Groups Pages
sOculus.cpp
1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OpenSpace3D
4 For the latest info, see http://www.openspace3d.com
5 
6 Copyright (c) 2013 I-maginer
7 
8 This program is free software; you can redistribute it and/or modify it under
9 the terms of the GNU Lesser General Public License as published by the Free Software
10 Foundation; either version 2 of the License, or (at your option) any later
11 version.
12 
13 This program is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
16 
17 You should have received a copy of the GNU Lesser General Public License along with
18 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
20 http://www.gnu.org/copyleft/lesser.txt
21 
22 -----------------------------------------------------------------------------
23 */
24 
25 #include "sOculus.h"
26 
27 extern HWND HScol;
28 extern int OCULUS_CONNECTED_CB;
29 extern int OCULUS_DISCONNECTED_CB;
30 
31 bool sOculus::isInitialized = false;
32 
34 {
35  mConnected = false;
36  mTerminate = false;
37  mDebug = false;
38  mUpdated = false;
39  mHmd = 0;
40  mTimeWarpOffset = 0.0;
41  mLastTime = 0.0;
42 
43  if(!isInitialized)
44  {
45  ovr_Initialize();
46  isInitialized = true;
47  }
48 
49  mThread = boost::thread(boost::bind(&sOculus::UpdateThread, this));
50 }
51 
53 {
54  mTerminate = true;
55  mThread.join();
56 
57  Disconnect();
58 
59  if(isInitialized)
60  {
61  ovr_Shutdown();
62  isInitialized = false;
63  }
64 }
65 
66 bool sOculus::IsConnected()
67 {
68  return mConnected;
69 }
70 
71 void sOculus::UpdateThread()
72 {
73  while (!mTerminate)
74  {
75  {
76  boost::mutex::scoped_lock l(mMutex);
77  int nbHmd = ovrHmd_Detect();
78  if (!mConnected)
79  {
80  if (nbHmd > 0)
81  {
82  for(int i = 0; (i < nbHmd) && (mHmd == 0); i++)
83  mHmd = ovrHmd_Create(i);
84  }
85  else if (mDebug)
86  {
87  mHmd = ovrHmd_CreateDebug(ovrHmd_DK2);
88  }
89 
90  if (mHmd != 0)
91  {
92  mConnected = true;
93  mUpdated = false;
94  ovrHmd_SetEnabledCaps(mHmd, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction);
95 
96  if ((mHmd->Type == ovrHmd_DK1) || (mHmd->Type == ovrHmd_DKHD))
97  ovrHmd_ConfigureTracking(mHmd, ovrTrackingCap_Orientation | ovrTrackingCap_MagYawCorrection, 0);
98  else
99  ovrHmd_ConfigureTracking(mHmd, ovrTrackingCap_Orientation | ovrTrackingCap_MagYawCorrection | ovrTrackingCap_Position, 0);
100 
101  //MMechostr(MSKDEBUG,"A new Oculus SENSOR has been connected.\n");
102  OBJpostEvent(OCULUS_CONNECTED_CB, (int)this, 0);
103  }
104  }
105 
106 
107  if (mConnected && (nbHmd < 1) && !mDebug)
108  {
109  /*int caps = ovrHmd_GetEnabledCaps(mHmd); // don't work
110  if ((caps != 0) && !(caps & ovrHmdCap_Present) && !mDebug) //unplugged
111  {
112  //MMechostr(MSKDEBUG,"Oculus SENSOR has been disconnected.\n");
113  }*/
114  Disconnect();
115  }
116  }
117 
118  // Sleep for 30ms so we don't eat the CPU
119  Sleep(30);
120  }
121 }
122 
123 ovrHmdType sOculus::GetType()
124 {
125  if (mHmd != 0)
126  {
127 
128  return mHmd->Type;
129  }
130 
131  return ovrHmd_None;
132 }
133 
134 bool sOculus::Connect()
135 {
136  boost::mutex::scoped_lock l(mMutex);
137  if (mConnected)
138  return false;
139 
140  int nbHmd = ovrHmd_Detect();
141  if (nbHmd > 0)
142  {
143  for(int i = 0; (i < nbHmd) && (mHmd == 0); i++)
144  mHmd = ovrHmd_Create(i);
145  }
146 
147  if (mHmd != 0)
148  {
149  ovrHmd_SetEnabledCaps(mHmd, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction);
150 
151  if ((mHmd->Type == ovrHmd_DK1) || (mHmd->Type == ovrHmd_DKHD))
152  ovrHmd_ConfigureTracking(mHmd, ovrTrackingCap_Orientation | ovrTrackingCap_MagYawCorrection, 0);
153  else
154  ovrHmd_ConfigureTracking(mHmd, ovrTrackingCap_Orientation | ovrTrackingCap_MagYawCorrection | ovrTrackingCap_Position, 0);
155 
156  mConnected = true;
157  mUpdated = false;
158  MMechostr(MSKDEBUG,"A new Oculus SENSOR has been connected.\n");
159  OBJpostEvent(OCULUS_CONNECTED_CB, (int)this, 0);
160  return true;
161  }
162 
163  return false;
164 }
165 
166 void sOculus::Disconnect()
167 {
168  if (mConnected)
169  {
170  if(mHmd)
171  ovrHmd_Destroy(mHmd);
172 
173  mHmd = 0;
174  mConnected = false;
175  OBJpostEvent(OCULUS_DISCONNECTED_CB, (int)this, 0);
176  }
177 }
178 
179 void sOculus::SetLowPersistance(bool state)
180 {
181  if (mHmd)
182  ovrHmd_SetEnabledCaps(mHmd, (state) ? ovrHmd_GetEnabledCaps(mHmd) | ovrHmdCap_LowPersistence : ovrHmd_GetEnabledCaps(mHmd) & (~ovrHmdCap_LowPersistence));
183 }
184 
185 bool sOculus::GetLowPersistance()
186 {
187  if (!mHmd)
188  return false;
189 
190  if (ovrHmd_GetEnabledCaps(mHmd) & ovrHmdCap_LowPersistence)
191  return true;
192  else
193  return false;
194 }
195 
196 void sOculus::ResetSensor()
197 {
198  boost::mutex::scoped_lock l(mMutex);
199  if (mHmd)
200  ovrHmd_RecenterPose(mHmd);
201 }
202 
203 Quatf sOculus::GetSensorOrientation()
204 {
205  if (!mConnected || !(mTrackingState.StatusFlags & ovrStatus_OrientationTracked))
206  return Quatf(0.0f, 0.0f, 0.0f, 1.0f);
207 
208  // Get acceleration
209  Posef pose = mTrackingState.HeadPose.ThePose;
210  return pose.Rotation;
211 }
212 
213 Vector3f sOculus::GetSensorYawPitchRoll()
214 {
215  if (!mConnected)
216  return Vector3f(0.0f, 0.0f, 0.0f);
217 
218  // Get acceleration
219  Posef pose = mTrackingState.HeadPose.ThePose;
220 
221  // Get orientation quaternion to control view
222  Quatf q = pose.Rotation;
223 
224  // Create a matrix from quaternion,
225  // where elements [0][0] through [3][3] contain rotation.
226  Matrix4f bodyFrameMatrix(q);
227 
228  // Get Euler angles from quaternion, in specified axis rotation order.
229  Vector3f ypr;
230  q.GetEulerAngles<Axis_Y, Axis_X, Axis_Z>(&ypr.x, &ypr.y, &ypr.z);
231  return ypr;
232 }
233 
234 Vector3f sOculus::GetSensorAcceleration()
235 {
236  if (!mConnected)
237  return Vector3f(0.0f, 0.0f, 0.0f);
238 
239  // Get acceleration
240  return mTrackingState.HeadPose.LinearAcceleration;
241 }
242 
243 Vector3f sOculus::GetSensorPosition()
244 {
245  if (!mConnected || !(mTrackingState.StatusFlags & ovrStatus_PositionTracked))
246  return Vector3f(0.0f, 0.0f, 0.0f);
247 
248  Posef pose = mTrackingState.HeadPose.ThePose;
249 
250  // Get acceleration
251  return pose.Translation;
252 }
253 
254 bool sOculus::GetStereoConfigDistortionMesh(ovrEyeType eye, ovrDistortionMesh &mesh)
255 {
256  boost::mutex::scoped_lock l(mMutex);
257  if (!mHmd)
258  return false;
259 
260  ovrEyeRenderDesc eyeRenderDesc = ovrHmd_GetRenderDesc(mHmd, eye, mHmd->DefaultEyeFov[eye]);
261  if (ovrHmd_CreateDistortionMesh(mHmd, eyeRenderDesc.Eye, eyeRenderDesc.Fov, ovrDistortionCap_Chromatic|ovrDistortionCap_TimeWarp|ovrDistortionCap_Vignette, &mesh))
262  return true;
263  else
264  return false;
265 }
266 
267 bool sOculus::GetProjectionMatrix(ovrEyeType eye, float nearclip, float farclip, ovrMatrix4f &mat)
268 {
269  boost::mutex::scoped_lock l(mMutex);
270  if (!mHmd)
271  return false;
272 
273  ovrFovPort fov = mHmd->DefaultEyeFov[eye];
274  mat = ovrMatrix4f_Projection(fov, nearclip, farclip, true);
275  return true;
276 }
277 
278 void sOculus::WaitForFrame()
279 {
280  if (mUpdated)
281  ovr_WaitTillTime(mFrameTiming.TimewarpPointSeconds);
282 }
283 
284 void sOculus::SetTimewarpOffset(double value)
285 {
286  mTimeWarpOffset = value;
287 }
288 
289 bool sOculus::GetTimeWarpMatrix(ovrEyeType eye, ovrMatrix4f* mat)
290 {
291  //boost::mutex::scoped_lock l(mMutex);
292  mat[0].M[0][0] = 1.0f;
293  mat[0].M[0][1] = 0.0f;
294  mat[0].M[0][2] = 0.0f;
295  mat[0].M[0][3] = 0.0f;
296  mat[0].M[1][0] = 0.0f;
297  mat[0].M[1][1] = 1.0f;
298  mat[0].M[1][2] = 0.0f;
299  mat[0].M[1][3] = 0.0f;
300  mat[0].M[2][0] = 0.0f;
301  mat[0].M[2][1] = 0.0f;
302  mat[0].M[2][2] = 1.0f;
303  mat[0].M[2][3] = 0.0f;
304  mat[0].M[3][0] = 0.0f;
305  mat[0].M[3][1] = 0.0f;
306  mat[0].M[3][2] = 0.0f;
307  mat[0].M[3][3] = 1.0f;
308 
309  mat[1].M[0][0] = 1.0f;
310  mat[1].M[0][1] = 0.0f;
311  mat[1].M[0][2] = 0.0f;
312  mat[1].M[0][3] = 0.0f;
313  mat[1].M[1][0] = 0.0f;
314  mat[1].M[1][1] = 1.0f;
315  mat[1].M[1][2] = 0.0f;
316  mat[1].M[1][3] = 0.0f;
317  mat[1].M[2][0] = 0.0f;
318  mat[1].M[2][1] = 0.0f;
319  mat[1].M[2][2] = 1.0f;
320  mat[1].M[2][3] = 0.0f;
321  mat[1].M[3][0] = 0.0f;
322  mat[1].M[3][1] = 0.0f;
323  mat[1].M[3][2] = 0.0f;
324  mat[1].M[3][3] = 1.0f;
325 
326  if (!mHmd || !mUpdated)
327  return false;
328 
329  ovrHmd_GetEyeTimewarpMatricesDebug(mHmd, eye, mEyepos[eye], mat, mTimeWarpOffset);
330 
331  return true;
332 }
333 
334 Sizei sOculus::GetStereoConfigFovTextureSize(ovrEyeType eye)
335 {
336  boost::mutex::scoped_lock l(mMutex);
337  if (!mHmd)
338  return Sizei(512, 512);
339 
340  return ovrHmd_GetFovTextureSize(mHmd, eye, mHmd->DefaultEyeFov[eye], 1.0f);
341 }
342 
343 bool sOculus::GetStereoConfigUvScaleOffset(ovrEyeType eye, Sizei textSize, Vector2f &scale, Vector2f &offset)
344 {
345  boost::mutex::scoped_lock l(mMutex);
346  if (!mHmd)
347  return false;
348 
349  ovrEyeRenderDesc eyeRenderDesc = ovrHmd_GetRenderDesc(mHmd, eye, mHmd->DefaultEyeFov[eye]);
350 
351  ovrRecti viewport;
352  viewport.Pos.x = 0;
353  viewport.Pos.y = 0;
354  viewport.Size.w = textSize.w;
355  viewport.Size.h = textSize.h;
356 
357  ovrVector2f UVScaleOffset[2];
358  ovrHmd_GetRenderScaleAndOffset(eyeRenderDesc.Fov, textSize, viewport, UVScaleOffset);
359  scale = UVScaleOffset[0];
360  offset = UVScaleOffset[1];
361  return true;
362 }
363 
364 bool sOculus::GetWindowPosAndSize(Vector2i &pos, Sizei &size, int &monitorIndex)
365 {
366  boost::mutex::scoped_lock l(mMutex);
367  if (!mHmd)
368  return false;
369 
370  if (mDebug)
371  pos = Vector2i(-1920, 0);
372  else
373  pos = mHmd->WindowsPos;
374  size = mHmd->Resolution;
375  monitorIndex = (mHmd->DisplayId < 0) ? 1 : mHmd->DisplayId;
376  return true;
377 }
378 
379 float sOculus::GetStereoConfigAspect()
380 {
381  boost::mutex::scoped_lock l(mMutex);
382  if (mHmd)
383  {
384  ovrFovPort fovLeft = mHmd->DefaultEyeFov[ovrEye_Left];
385  ovrFovPort fovRight = mHmd->DefaultEyeFov[ovrEye_Right];
386 
387  float combinedTanHalfFovHorizontal = std::max(fovLeft.LeftTan, fovLeft.RightTan);
388  float combinedTanHalfFovVertical = std::max(fovLeft.UpTan, fovLeft.DownTan);
389  return combinedTanHalfFovHorizontal / combinedTanHalfFovVertical;
390  }
391  else
392  return 0.8f;
393 }
394 
395 float sOculus::GetStereoConfigFovY()
396 {
397  boost::mutex::scoped_lock l(mMutex);
398  if (mHmd)
399  {
400  ovrFovPort fovLeft = mHmd->DefaultEyeFov[ovrEye_Left];
401  ovrFovPort fovRight = mHmd->DefaultEyeFov[ovrEye_Right];
402 
403  return (atanf(fovLeft.UpTan) + atanf(fovLeft.DownTan) + atanf(fovRight.UpTan) + atanf(fovRight.DownTan)) * 0.5f;
404  }
405  else
406  return 1.919862f;
407 }
408 
409 float sOculus::GetStereoIPD()
410 {
411  boost::mutex::scoped_lock l(mMutex);
412  if (mHmd)
413  {
414  return ovrHmd_GetFloat(mHmd, OVR_KEY_IPD, 0.064f);
415  }
416  else
417  return 0.064f;
418 }
419 
420 bool sOculus::UpdateStart()
421 {
422  if (mHmd)
423  {
424  mFrameTiming = ovrHmd_BeginFrameTiming(mHmd, 0);
425  mUpdated = true;
426 
427  ovrEyeRenderDesc eyeRenderDesc[2] = {ovrHmd_GetRenderDesc(mHmd, ovrEye_Left, mHmd->DefaultEyeFov[ovrEye_Left]), ovrHmd_GetRenderDesc(mHmd, ovrEye_Right, mHmd->DefaultEyeFov[ovrEye_Right])};
428  ovrVector3f useHmdToEyeViewOffset[2] = {eyeRenderDesc[0].HmdToEyeViewOffset, eyeRenderDesc[1].HmdToEyeViewOffset};
429 
430  //mEyepos[0] = Posef(mTrackingState.HeadPose.ThePose.Orientation, ((Posef)mTrackingState.HeadPose.ThePose).Apply(-((Vector3f)useHmdToEyeViewOffset[0])));
431  //mEyepos[1] = Posef(mTrackingState.HeadPose.ThePose.Orientation, ((Posef)mTrackingState.HeadPose.ThePose).Apply(-((Vector3f)useHmdToEyeViewOffset[1])));
432 
433  ovrHmd_GetEyePoses(mHmd, 0, useHmdToEyeViewOffset, mEyepos, &mTrackingState);
434 
435  return true;
436  }
437 
438  return false;
439 }
440 
441 void sOculus::UpdateEnd()
442 {
443  if (mHmd && mUpdated)
444  {
445  ovrHmd_EndFrameTiming(mHmd);
446  mUpdated = false;
447  }
448 }