ovr_sdk

annotate LibOVR/Src/OVR_CAPI.cpp @ 0:1b39a1b46319

initial 0.4.4
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 14 Jan 2015 06:51:16 +0200
parents
children
rev   line source
nuclear@0 1 /************************************************************************************
nuclear@0 2
nuclear@0 3 Filename : OVR_CAPI.cpp
nuclear@0 4 Content : Experimental simple C interface to the HMD - version 1.
nuclear@0 5 Created : November 30, 2013
nuclear@0 6 Authors : Michael Antonov
nuclear@0 7
nuclear@0 8 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
nuclear@0 9
nuclear@0 10 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
nuclear@0 11 you may not use the Oculus VR Rift SDK except in compliance with the License,
nuclear@0 12 which is provided at the time of installation or download, or which
nuclear@0 13 otherwise accompanies this software in either electronic or hard copy form.
nuclear@0 14
nuclear@0 15 You may obtain a copy of the License at
nuclear@0 16
nuclear@0 17 http://www.oculusvr.com/licenses/LICENSE-3.2
nuclear@0 18
nuclear@0 19 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
nuclear@0 20 distributed under the License is distributed on an "AS IS" BASIS,
nuclear@0 21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
nuclear@0 22 See the License for the specific language governing permissions and
nuclear@0 23 limitations under the License.
nuclear@0 24
nuclear@0 25 ************************************************************************************/
nuclear@0 26
nuclear@0 27 #include "OVR_CAPI.h"
nuclear@0 28 #include "Kernel/OVR_Timer.h"
nuclear@0 29 #include "Kernel/OVR_Math.h"
nuclear@0 30 #include "Kernel/OVR_System.h"
nuclear@0 31 #include "OVR_Stereo.h"
nuclear@0 32 #include "OVR_Profile.h"
nuclear@0 33 #include "../Include/OVR_Version.h"
nuclear@0 34
nuclear@0 35 #include "CAPI/CAPI_HMDState.h"
nuclear@0 36 #include "CAPI/CAPI_FrameTimeManager.h"
nuclear@0 37
nuclear@0 38 #include "Service/Service_NetClient.h"
nuclear@0 39 #ifdef OVR_SINGLE_PROCESS
nuclear@0 40 #include "Service/Service_NetServer.h"
nuclear@0 41 #endif
nuclear@0 42
nuclear@0 43 #ifdef OVR_OS_WIN32
nuclear@0 44 #include "Displays/OVR_Win32_ShimFunctions.h"
nuclear@0 45 #endif
nuclear@0 46
nuclear@0 47
nuclear@0 48 using namespace OVR;
nuclear@0 49 using namespace OVR::Util::Render;
nuclear@0 50 using namespace OVR::Tracking;
nuclear@0 51
nuclear@0 52 //-------------------------------------------------------------------------------------
nuclear@0 53 // Math
nuclear@0 54 namespace OVR {
nuclear@0 55
nuclear@0 56
nuclear@0 57 // ***** FovPort
nuclear@0 58
nuclear@0 59 // C-interop support: FovPort <-> ovrFovPort
nuclear@0 60 FovPort::FovPort(const ovrFovPort &src)
nuclear@0 61 : UpTan(src.UpTan), DownTan(src.DownTan), LeftTan(src.LeftTan), RightTan(src.RightTan)
nuclear@0 62 { }
nuclear@0 63
nuclear@0 64 FovPort::operator ovrFovPort () const
nuclear@0 65 {
nuclear@0 66 ovrFovPort result;
nuclear@0 67 result.LeftTan = LeftTan;
nuclear@0 68 result.RightTan = RightTan;
nuclear@0 69 result.UpTan = UpTan;
nuclear@0 70 result.DownTan = DownTan;
nuclear@0 71 return result;
nuclear@0 72 }
nuclear@0 73
nuclear@0 74 // Converts Fov Tan angle units to [-1,1] render target NDC space
nuclear@0 75 Vector2f FovPort::TanAngleToRendertargetNDC(Vector2f const &tanEyeAngle)
nuclear@0 76 {
nuclear@0 77 ScaleAndOffset2D eyeToSourceNDC = CreateNDCScaleAndOffsetFromFov(*this);
nuclear@0 78 return tanEyeAngle * eyeToSourceNDC.Scale + eyeToSourceNDC.Offset;
nuclear@0 79 }
nuclear@0 80
nuclear@0 81 // ***** SensorDataType
nuclear@0 82
nuclear@0 83 SensorDataType::SensorDataType(const ovrSensorData& s)
nuclear@0 84 {
nuclear@0 85 Acceleration = s.Accelerometer;
nuclear@0 86 RotationRate = s.Gyro;
nuclear@0 87 MagneticField = s.Magnetometer;
nuclear@0 88 Temperature = s.Temperature;
nuclear@0 89 AbsoluteTimeSeconds = s.TimeInSeconds;
nuclear@0 90 }
nuclear@0 91
nuclear@0 92 SensorDataType::operator ovrSensorData () const
nuclear@0 93 {
nuclear@0 94 ovrSensorData result;
nuclear@0 95 result.Accelerometer = Acceleration;
nuclear@0 96 result.Gyro = RotationRate;
nuclear@0 97 result.Magnetometer = MagneticField;
nuclear@0 98 result.Temperature = Temperature;
nuclear@0 99 result.TimeInSeconds = (float) AbsoluteTimeSeconds;
nuclear@0 100 return result;
nuclear@0 101 }
nuclear@0 102
nuclear@0 103
nuclear@0 104 // ***** SensorState
nuclear@0 105
nuclear@0 106 TrackingState::TrackingState(const ovrTrackingState& s)
nuclear@0 107 {
nuclear@0 108 HeadPose = s.HeadPose;
nuclear@0 109 CameraPose = s.CameraPose;
nuclear@0 110 LeveledCameraPose = s.LeveledCameraPose;
nuclear@0 111 RawSensorData = s.RawSensorData;
nuclear@0 112 StatusFlags = s.StatusFlags;
nuclear@0 113 LastVisionProcessingTime = s.LastVisionProcessingTime;
nuclear@0 114 LastVisionFrameLatency = s.LastVisionFrameLatency;
nuclear@0 115 LastCameraFrameCounter = s.LastCameraFrameCounter;
nuclear@0 116 }
nuclear@0 117
nuclear@0 118 TrackingState::operator ovrTrackingState() const
nuclear@0 119 {
nuclear@0 120 ovrTrackingState result;
nuclear@0 121 result.HeadPose = HeadPose;
nuclear@0 122 result.CameraPose = CameraPose;
nuclear@0 123 result.LeveledCameraPose = LeveledCameraPose;
nuclear@0 124 result.RawSensorData = RawSensorData;
nuclear@0 125 result.StatusFlags = StatusFlags;
nuclear@0 126 result.LastVisionProcessingTime = LastVisionProcessingTime;
nuclear@0 127 result.LastVisionFrameLatency = LastVisionFrameLatency;
nuclear@0 128 result.LastCameraFrameCounter = LastCameraFrameCounter;
nuclear@0 129 return result;
nuclear@0 130 }
nuclear@0 131
nuclear@0 132
nuclear@0 133 } // namespace OVR
nuclear@0 134
nuclear@0 135 //-------------------------------------------------------------------------------------
nuclear@0 136
nuclear@0 137 using namespace OVR::CAPI;
nuclear@0 138
nuclear@0 139 #ifdef __cplusplus
nuclear@0 140 extern "C" {
nuclear@0 141 #endif
nuclear@0 142
nuclear@0 143
nuclear@0 144 // Used to generate projection from ovrEyeDesc::Fov
nuclear@0 145 OVR_EXPORT ovrMatrix4f ovrMatrix4f_Projection(ovrFovPort fov, float znear, float zfar, ovrBool rightHanded)
nuclear@0 146 {
nuclear@0 147 return CreateProjection(rightHanded ? true : false, fov, znear, zfar);
nuclear@0 148 }
nuclear@0 149
nuclear@0 150
nuclear@0 151 OVR_EXPORT ovrMatrix4f ovrMatrix4f_OrthoSubProjection(ovrMatrix4f projection, ovrVector2f orthoScale,
nuclear@0 152 float orthoDistance, float hmdToEyeViewOffsetX)
nuclear@0 153 {
nuclear@0 154
nuclear@0 155 float orthoHorizontalOffset = hmdToEyeViewOffsetX / orthoDistance;
nuclear@0 156
nuclear@0 157 // Current projection maps real-world vector (x,y,1) to the RT.
nuclear@0 158 // We want to find the projection that maps the range [-FovPixels/2,FovPixels/2] to
nuclear@0 159 // the physical [-orthoHalfFov,orthoHalfFov]
nuclear@0 160 // Note moving the offset from M[0][2]+M[1][2] to M[0][3]+M[1][3] - this means
nuclear@0 161 // we don't have to feed in Z=1 all the time.
nuclear@0 162 // The horizontal offset math is a little hinky because the destination is
nuclear@0 163 // actually [-orthoHalfFov+orthoHorizontalOffset,orthoHalfFov+orthoHorizontalOffset]
nuclear@0 164 // So we need to first map [-FovPixels/2,FovPixels/2] to
nuclear@0 165 // [-orthoHalfFov+orthoHorizontalOffset,orthoHalfFov+orthoHorizontalOffset]:
nuclear@0 166 // x1 = x0 * orthoHalfFov/(FovPixels/2) + orthoHorizontalOffset;
nuclear@0 167 // = x0 * 2*orthoHalfFov/FovPixels + orthoHorizontalOffset;
nuclear@0 168 // But then we need the same mapping as the existing projection matrix, i.e.
nuclear@0 169 // x2 = x1 * Projection.M[0][0] + Projection.M[0][2];
nuclear@0 170 // = x0 * (2*orthoHalfFov/FovPixels + orthoHorizontalOffset) * Projection.M[0][0] + Projection.M[0][2];
nuclear@0 171 // = x0 * Projection.M[0][0]*2*orthoHalfFov/FovPixels +
nuclear@0 172 // orthoHorizontalOffset*Projection.M[0][0] + Projection.M[0][2];
nuclear@0 173 // So in the new projection matrix we need to scale by Projection.M[0][0]*2*orthoHalfFov/FovPixels and
nuclear@0 174 // offset by orthoHorizontalOffset*Projection.M[0][0] + Projection.M[0][2].
nuclear@0 175
nuclear@0 176 Matrix4f ortho;
nuclear@0 177 ortho.M[0][0] = projection.M[0][0] * orthoScale.x;
nuclear@0 178 ortho.M[0][1] = 0.0f;
nuclear@0 179 ortho.M[0][2] = 0.0f;
nuclear@0 180 ortho.M[0][3] = -projection.M[0][2] + ( orthoHorizontalOffset * projection.M[0][0] );
nuclear@0 181
nuclear@0 182 ortho.M[1][0] = 0.0f;
nuclear@0 183 ortho.M[1][1] = -projection.M[1][1] * orthoScale.y; // Note sign flip (text rendering uses Y=down).
nuclear@0 184 ortho.M[1][2] = 0.0f;
nuclear@0 185 ortho.M[1][3] = -projection.M[1][2];
nuclear@0 186
nuclear@0 187 /*
nuclear@0 188 if ( fabsf ( zNear - zFar ) < 0.001f )
nuclear@0 189 {
nuclear@0 190 ortho.M[2][0] = 0.0f;
nuclear@0 191 ortho.M[2][1] = 0.0f;
nuclear@0 192 ortho.M[2][2] = 0.0f;
nuclear@0 193 ortho.M[2][3] = zFar;
nuclear@0 194 }
nuclear@0 195 else
nuclear@0 196 {
nuclear@0 197 ortho.M[2][0] = 0.0f;
nuclear@0 198 ortho.M[2][1] = 0.0f;
nuclear@0 199 ortho.M[2][2] = zFar / (zNear - zFar);
nuclear@0 200 ortho.M[2][3] = (zFar * zNear) / (zNear - zFar);
nuclear@0 201 }
nuclear@0 202 */
nuclear@0 203
nuclear@0 204 // MA: Undo effect of sign
nuclear@0 205 ortho.M[2][0] = 0.0f;
nuclear@0 206 ortho.M[2][1] = 0.0f;
nuclear@0 207 //ortho.M[2][2] = projection.M[2][2] * projection.M[3][2] * -1.0f; // reverse right-handedness
nuclear@0 208 ortho.M[2][2] = 0.0f;
nuclear@0 209 ortho.M[2][3] = 0.0f;
nuclear@0 210 //projection.M[2][3];
nuclear@0 211
nuclear@0 212 // No perspective correction for ortho.
nuclear@0 213 ortho.M[3][0] = 0.0f;
nuclear@0 214 ortho.M[3][1] = 0.0f;
nuclear@0 215 ortho.M[3][2] = 0.0f;
nuclear@0 216 ortho.M[3][3] = 1.0f;
nuclear@0 217
nuclear@0 218 return ortho;
nuclear@0 219 }
nuclear@0 220
nuclear@0 221
nuclear@0 222 OVR_EXPORT double ovr_GetTimeInSeconds()
nuclear@0 223 {
nuclear@0 224 return Timer::GetSeconds();
nuclear@0 225 }
nuclear@0 226
nuclear@0 227 // Waits until the specified absolute time.
nuclear@0 228 OVR_EXPORT double ovr_WaitTillTime(double absTime)
nuclear@0 229 {
nuclear@0 230 double initialTime = ovr_GetTimeInSeconds();
nuclear@0 231 double newTime = initialTime;
nuclear@0 232
nuclear@0 233 while(newTime < absTime)
nuclear@0 234 {
nuclear@0 235 for (int j = 0; j < 5; j++)
nuclear@0 236 OVR_PROCESSOR_PAUSE();
nuclear@0 237
nuclear@0 238 newTime = ovr_GetTimeInSeconds();
nuclear@0 239 }
nuclear@0 240
nuclear@0 241 // How long we waited
nuclear@0 242 return newTime - initialTime;
nuclear@0 243 }
nuclear@0 244
nuclear@0 245
nuclear@0 246 //-------------------------------------------------------------------------------------
nuclear@0 247
nuclear@0 248 // 1. Init/shutdown.
nuclear@0 249
nuclear@0 250 static ovrBool CAPI_SystemInitCalled = 0;
nuclear@0 251 static ovrBool CAPI_ovrInitializeCalled = 0;
nuclear@0 252
nuclear@0 253 static OVR::Service::NetClient* CAPI_pNetClient = 0;
nuclear@0 254
nuclear@0 255 OVR_EXPORT ovrBool ovr_InitializeRenderingShim()
nuclear@0 256 {
nuclear@0 257 OVR::System::DirectDisplayInitialize();
nuclear@0 258 return OVR::System::DirectDisplayEnabled();
nuclear@0 259 }
nuclear@0 260
nuclear@0 261 OVR_EXPORT ovrBool ovr_Initialize()
nuclear@0 262 {
nuclear@0 263 if (CAPI_ovrInitializeCalled)
nuclear@0 264 return 1;
nuclear@0 265
nuclear@0 266 // We must set up the system for the plugin to work
nuclear@0 267 if (!OVR::System::IsInitialized())
nuclear@0 268 {
nuclear@0 269 OVR::System::Init(OVR::Log::ConfigureDefaultLog(OVR::LogMask_All));
nuclear@0 270 CAPI_SystemInitCalled = 1;
nuclear@0 271 }
nuclear@0 272
nuclear@0 273 if (!OVR::System::DirectDisplayEnabled() && !OVR::Display::InCompatibilityMode(false))
nuclear@0 274 {
nuclear@0 275 OVR_ASSERT(false);
nuclear@0 276 return 0;
nuclear@0 277 }
nuclear@0 278
nuclear@0 279 CAPI_pNetClient = NetClient::GetInstance();
nuclear@0 280
nuclear@0 281 #ifdef OVR_SINGLE_PROCESS
nuclear@0 282
nuclear@0 283 // If the server could not start running,
nuclear@0 284 if (Service::NetServer::GetInstance()->IsInitialized())
nuclear@0 285 {
nuclear@0 286 CAPI_pNetClient->Connect(true);
nuclear@0 287 }
nuclear@0 288 else
nuclear@0 289 {
nuclear@0 290 // This normally will happen if the OVRService is running in the background,
nuclear@0 291 // or another SingleProcess-mode app is running in the background.
nuclear@0 292 // In this case, it's using the hardware and we should not also attempt to use
nuclear@0 293 // the hardware.
nuclear@0 294 LogError("{ERR-079} [LibOVR] Server is already running");
nuclear@0 295 }
nuclear@0 296 #else
nuclear@0 297 CAPI_pNetClient->Connect(true);
nuclear@0 298 #endif
nuclear@0 299
nuclear@0 300 CAPI_ovrInitializeCalled = 1;
nuclear@0 301
nuclear@0 302 return 1;
nuclear@0 303 }
nuclear@0 304
nuclear@0 305 OVR_EXPORT void ovr_Shutdown()
nuclear@0 306 {
nuclear@0 307 // We should clean up the system to be complete
nuclear@0 308 if (OVR::System::IsInitialized() && CAPI_SystemInitCalled)
nuclear@0 309 {
nuclear@0 310 OVR::System::Destroy();
nuclear@0 311 }
nuclear@0 312
nuclear@0 313 CAPI_SystemInitCalled = 0;
nuclear@0 314 CAPI_ovrInitializeCalled = 0;
nuclear@0 315 }
nuclear@0 316
nuclear@0 317
nuclear@0 318 // There is a thread safety issue with ovrHmd_Detect in that multiple calls from different
nuclear@0 319 // threads can corrupt the global array state. This would lead to two problems:
nuclear@0 320 // a) Create(index) enumerator may miss or overshoot items. Probably not a big deal
nuclear@0 321 // as game logic can easily be written to only do Detect(s)/Creates in one place.
nuclear@0 322 // The alternative would be to return list handle.
nuclear@0 323 // b) TBD: Un-mutexed Detect access from two threads could lead to crash. We should
nuclear@0 324 // probably check this.
nuclear@0 325 //
nuclear@0 326
nuclear@0 327 OVR_EXPORT int ovrHmd_Detect()
nuclear@0 328 {
nuclear@0 329 if (!CAPI_ovrInitializeCalled)
nuclear@0 330 return 0;
nuclear@0 331
nuclear@0 332 return CAPI_pNetClient->Hmd_Detect();
nuclear@0 333 }
nuclear@0 334
nuclear@0 335
nuclear@0 336 // ovrHmd_Create us explicitly separated from ConfigureTracking and ConfigureRendering to allow creation of
nuclear@0 337 // a relatively light-weight handle that would reference the device going forward and would
nuclear@0 338 // survive future ovrHmd_Detect calls. That is once ovrHMD is returned, index is no longer
nuclear@0 339 // necessary and can be changed by a ovrHmd_Detect call.
nuclear@0 340 OVR_EXPORT ovrHmd ovrHmd_Create(int index)
nuclear@0 341 {
nuclear@0 342 if (!CAPI_ovrInitializeCalled)
nuclear@0 343 return 0;
nuclear@0 344
nuclear@0 345 double t0 = Timer::GetSeconds();
nuclear@0 346 HMDNetworkInfo netInfo;
nuclear@0 347
nuclear@0 348 // There may be some delay before the HMD is fully detected.
nuclear@0 349 // Since we are also trying to create the HMD immediately it may lose this race and
nuclear@0 350 // get "NO HMD DETECTED." Wait a bit longer to avoid this.
nuclear@0 351 while (!CAPI_pNetClient->Hmd_Create(index, &netInfo) ||
nuclear@0 352 netInfo.NetId == InvalidVirtualHmdId)
nuclear@0 353 {
nuclear@0 354 // If two seconds elapse and still no HMD detected,
nuclear@0 355 if (Timer::GetSeconds() - t0 > 2.)
nuclear@0 356 {
nuclear@0 357 if (!NetClient::GetInstance()->IsConnected(false, false))
nuclear@0 358 {
nuclear@0 359 NetClient::GetInstance()->SetLastError("Not connected to service");
nuclear@0 360 }
nuclear@0 361 else
nuclear@0 362 {
nuclear@0 363 NetClient::GetInstance()->SetLastError("No HMD Detected");
nuclear@0 364 }
nuclear@0 365
nuclear@0 366 return 0;
nuclear@0 367 }
nuclear@0 368 }
nuclear@0 369
nuclear@0 370 // Create HMD State object
nuclear@0 371 HMDState* hmds = HMDState::CreateHMDState(CAPI_pNetClient, netInfo);
nuclear@0 372 if (!hmds)
nuclear@0 373 {
nuclear@0 374 CAPI_pNetClient->Hmd_Release(netInfo.NetId);
nuclear@0 375
nuclear@0 376 NetClient::GetInstance()->SetLastError("Unable to create HMD state");
nuclear@0 377 return 0;
nuclear@0 378 }
nuclear@0 379
nuclear@0 380 // Reset frame timing so that FrameTimeManager values are properly initialized in AppRendered mode.
nuclear@0 381 ovrHmd_ResetFrameTiming(hmds->pHmdDesc, 0);
nuclear@0 382
nuclear@0 383 return hmds->pHmdDesc;
nuclear@0 384 }
nuclear@0 385
nuclear@0 386
nuclear@0 387 OVR_EXPORT ovrBool ovrHmd_AttachToWindow( ovrHmd hmd, void* window,
nuclear@0 388 const ovrRecti* destMirrorRect,
nuclear@0 389 const ovrRecti* sourceRenderTargetRect )
nuclear@0 390 {
nuclear@0 391 OVR_UNUSED( destMirrorRect );
nuclear@0 392 OVR_UNUSED( sourceRenderTargetRect );
nuclear@0 393
nuclear@0 394 if (!CAPI_ovrInitializeCalled)
nuclear@0 395 return false;
nuclear@0 396
nuclear@0 397 if (!hmd || !hmd->Handle)
nuclear@0 398 return false;
nuclear@0 399 #ifndef OVR_OS_MAC
nuclear@0 400 HMDState* hmds = (HMDState*)hmd->Handle;
nuclear@0 401 CAPI_pNetClient->Hmd_AttachToWindow(hmds->GetNetId(), window);
nuclear@0 402 hmds->pWindow = window;
nuclear@0 403 #endif
nuclear@0 404 #ifdef OVR_OS_WIN32
nuclear@0 405 Win32::DisplayShim::GetInstance().hWindow = (HWND)window;
nuclear@0 406 #endif
nuclear@0 407 #ifdef OVR_OS_MAC
nuclear@0 408 OVR_UNUSED(window);
nuclear@0 409 #endif
nuclear@0 410
nuclear@0 411 return true;
nuclear@0 412 }
nuclear@0 413
nuclear@0 414 OVR_EXPORT ovrHmd ovrHmd_CreateDebug(ovrHmdType type)
nuclear@0 415 {
nuclear@0 416 if (!CAPI_ovrInitializeCalled)
nuclear@0 417 return 0;
nuclear@0 418
nuclear@0 419 HMDState* hmds = HMDState::CreateHMDState(type);
nuclear@0 420
nuclear@0 421 return hmds->pHmdDesc;
nuclear@0 422 }
nuclear@0 423
nuclear@0 424 OVR_EXPORT void ovrHmd_Destroy(ovrHmd hmddesc)
nuclear@0 425 {
nuclear@0 426 if (!hmddesc || !hmddesc->Handle)
nuclear@0 427 return;
nuclear@0 428
nuclear@0 429 // TBD: Any extra shutdown?
nuclear@0 430 HMDState* hmds = (HMDState*)hmddesc->Handle;
nuclear@0 431
nuclear@0 432 { // Thread checker in its own scope, to avoid access after 'delete'.
nuclear@0 433 // Essentially just checks that no other RenderAPI function is executing.
nuclear@0 434 ThreadChecker::Scope checkScope(&hmds->RenderAPIThreadChecker, "ovrHmd_Destroy");
nuclear@0 435 }
nuclear@0 436
nuclear@0 437 #ifdef OVR_OS_WIN32
nuclear@0 438 if (hmds->pWindow)
nuclear@0 439 {
nuclear@0 440 // ? ok to call
nuclear@0 441 //CAPI_pNetClient->Hmd_AttachToWindow(hmds->GetNetId(), 0);
nuclear@0 442 hmds->pWindow = 0;
nuclear@0 443 Win32::DisplayShim::GetInstance().hWindow = (HWND)0;
nuclear@0 444 }
nuclear@0 445 #endif
nuclear@0 446
nuclear@0 447 delete (HMDState*)hmddesc->Handle;
nuclear@0 448 }
nuclear@0 449
nuclear@0 450
nuclear@0 451 OVR_EXPORT const char* ovrHmd_GetLastError(ovrHmd hmddesc)
nuclear@0 452 {
nuclear@0 453 if (!CAPI_ovrInitializeCalled)
nuclear@0 454 {
nuclear@0 455 return "System initialize not called";
nuclear@0 456 }
nuclear@0 457
nuclear@0 458 VirtualHmdId netId = InvalidVirtualHmdId;
nuclear@0 459
nuclear@0 460 if (hmddesc && hmddesc->Handle)
nuclear@0 461 {
nuclear@0 462 HMDState* p = (HMDState*)hmddesc->Handle;
nuclear@0 463 netId = p->GetNetId();
nuclear@0 464 }
nuclear@0 465
nuclear@0 466 return CAPI_pNetClient->Hmd_GetLastError(netId);
nuclear@0 467 }
nuclear@0 468
nuclear@0 469 #define OVR_VERSION_LIBOVR_PFX "libOVR:"
nuclear@0 470
nuclear@0 471 // Returns version string representing libOVR version. Static, so
nuclear@0 472 // string remains valid for app lifespan
nuclear@0 473 OVR_EXPORT const char* ovr_GetVersionString()
nuclear@0 474 {
nuclear@0 475 static const char* version = OVR_VERSION_LIBOVR_PFX OVR_VERSION_STRING;
nuclear@0 476 return version + sizeof(OVR_VERSION_LIBOVR_PFX) - 1;
nuclear@0 477 }
nuclear@0 478
nuclear@0 479
nuclear@0 480
nuclear@0 481 //-------------------------------------------------------------------------------------
nuclear@0 482
nuclear@0 483 // Returns capability bits that are enabled at this time; described by ovrHmdCapBits.
nuclear@0 484 // Note that this value is different font ovrHmdDesc::Caps, which describes what
nuclear@0 485 // capabilities are available.
nuclear@0 486 OVR_EXPORT unsigned int ovrHmd_GetEnabledCaps(ovrHmd hmddesc)
nuclear@0 487 {
nuclear@0 488 HMDState* p = (HMDState*)hmddesc->Handle;
nuclear@0 489 return p ? p->EnabledHmdCaps : 0;
nuclear@0 490 }
nuclear@0 491
nuclear@0 492 // Modifies capability bits described by ovrHmdCapBits that can be modified,
nuclear@0 493 // such as ovrHmdCap_LowPersistance.
nuclear@0 494 OVR_EXPORT void ovrHmd_SetEnabledCaps(ovrHmd hmddesc, unsigned int capsBits)
nuclear@0 495 {
nuclear@0 496 HMDState* p = (HMDState*)hmddesc->Handle;
nuclear@0 497 if (p)
nuclear@0 498 {
nuclear@0 499 p->SetEnabledHmdCaps(capsBits);
nuclear@0 500 }
nuclear@0 501 }
nuclear@0 502
nuclear@0 503
nuclear@0 504 //-------------------------------------------------------------------------------------
nuclear@0 505 // *** Sensor
nuclear@0 506
nuclear@0 507 // Sensor APIs are separated from Create & Configure for several reasons:
nuclear@0 508 // - They need custom parameters that control allocation of heavy resources
nuclear@0 509 // such as Vision tracking, which you don't want to create unless necessary.
nuclear@0 510 // - A game may want to switch some sensor settings based on user input,
nuclear@0 511 // or at lease enable/disable features such as Vision for debugging.
nuclear@0 512 // - The same or syntactically similar sensor interface is likely to be used if we
nuclear@0 513 // introduce controllers.
nuclear@0 514 //
nuclear@0 515 // - Sensor interface functions are all Thread-safe, unlike the frame/render API
nuclear@0 516 // functions that have different rules (all frame access functions
nuclear@0 517 // must be on render thread)
nuclear@0 518
nuclear@0 519 OVR_EXPORT ovrBool ovrHmd_ConfigureTracking(ovrHmd hmddesc, unsigned int supportedCaps,
nuclear@0 520 unsigned int requiredCaps)
nuclear@0 521 {
nuclear@0 522 if (hmddesc)
nuclear@0 523 {
nuclear@0 524 HMDState* p = (HMDState*)hmddesc->Handle;
nuclear@0 525 return p->ConfigureTracking(supportedCaps, requiredCaps);
nuclear@0 526 }
nuclear@0 527
nuclear@0 528 return 0;
nuclear@0 529 }
nuclear@0 530
nuclear@0 531 OVR_EXPORT void ovrHmd_RecenterPose(ovrHmd hmddesc)
nuclear@0 532 {
nuclear@0 533 if (hmddesc)
nuclear@0 534 {
nuclear@0 535 HMDState* p = (HMDState*)hmddesc->Handle;
nuclear@0 536 p->TheSensorStateReader.RecenterPose();
nuclear@0 537 }
nuclear@0 538 }
nuclear@0 539
nuclear@0 540 OVR_EXPORT ovrTrackingState ovrHmd_GetTrackingState(ovrHmd hmddesc, double absTime)
nuclear@0 541 {
nuclear@0 542 ovrTrackingState result;
nuclear@0 543
nuclear@0 544 if (hmddesc)
nuclear@0 545 {
nuclear@0 546 HMDState* p = (HMDState*)hmddesc->Handle;
nuclear@0 547 result = p->PredictedTrackingState(absTime);
nuclear@0 548
nuclear@0 549 // Instrument data from eye pose
nuclear@0 550 p->LagStats.InstrumentEyePose(result);
nuclear@0 551 }
nuclear@0 552 else
nuclear@0 553 memset(&result, 0, sizeof(result));
nuclear@0 554
nuclear@0 555 #ifdef OVR_OS_WIN32
nuclear@0 556 // Set up display code for Windows
nuclear@0 557 Win32::DisplayShim::GetInstance().Active = (result.StatusFlags & ovrStatus_HmdConnected) != 0;
nuclear@0 558 #endif
nuclear@0 559
nuclear@0 560 return result;
nuclear@0 561 }
nuclear@0 562
nuclear@0 563
nuclear@0 564 //-------------------------------------------------------------------------------------
nuclear@0 565 // *** General Setup
nuclear@0 566
nuclear@0 567 // Per HMD -> calculateIdealPixelSize
nuclear@0 568 OVR_EXPORT ovrSizei ovrHmd_GetFovTextureSize(ovrHmd hmddesc, ovrEyeType eye, ovrFovPort fov,
nuclear@0 569 float pixelsPerDisplayPixel)
nuclear@0 570 {
nuclear@0 571 ovrHmdStruct * hmd = hmddesc->Handle;
nuclear@0 572 if (!hmd) return Sizei(0);
nuclear@0 573
nuclear@0 574 HMDState* hmds = (HMDState*)hmd;
nuclear@0 575 return hmds->RenderState.GetFOVTextureSize(eye, fov, pixelsPerDisplayPixel);
nuclear@0 576 }
nuclear@0 577
nuclear@0 578
nuclear@0 579 //-------------------------------------------------------------------------------------
nuclear@0 580
nuclear@0 581
nuclear@0 582 OVR_EXPORT
nuclear@0 583 ovrBool ovrHmd_ConfigureRendering( ovrHmd hmddesc,
nuclear@0 584 const ovrRenderAPIConfig* apiConfig,
nuclear@0 585 unsigned int distortionCaps,
nuclear@0 586 const ovrFovPort eyeFovIn[2],
nuclear@0 587 ovrEyeRenderDesc eyeRenderDescOut[2] )
nuclear@0 588 {
nuclear@0 589 ovrHmdStruct * hmd = hmddesc->Handle;
nuclear@0 590 if (!hmd) return 0;
nuclear@0 591 return ((HMDState*)hmd)->ConfigureRendering(eyeRenderDescOut, eyeFovIn,
nuclear@0 592 apiConfig, distortionCaps);
nuclear@0 593 }
nuclear@0 594
nuclear@0 595
nuclear@0 596
nuclear@0 597 // TBD: MA - Deprecated, need alternative
nuclear@0 598 void ovrHmd_SetVsync(ovrHmd hmddesc, ovrBool vsync)
nuclear@0 599 {
nuclear@0 600 ovrHmdStruct * hmd = hmddesc->Handle;
nuclear@0 601 if (!hmd) return;
nuclear@0 602
nuclear@0 603 return ((HMDState*)hmd)->TimeManager.SetVsync(vsync? true : false);
nuclear@0 604 }
nuclear@0 605
nuclear@0 606
nuclear@0 607 OVR_EXPORT ovrFrameTiming ovrHmd_BeginFrame(ovrHmd hmddesc, unsigned int frameIndex)
nuclear@0 608 {
nuclear@0 609 HMDState* hmds = (HMDState*)hmddesc->Handle;
nuclear@0 610 if (!hmds)
nuclear@0 611 {
nuclear@0 612 ovrFrameTiming f;
nuclear@0 613 memset(&f, 0, sizeof(f));
nuclear@0 614 return f;
nuclear@0 615 }
nuclear@0 616
nuclear@0 617 // Check: Proper configure and threading state for the call.
nuclear@0 618 hmds->checkRenderingConfigured("ovrHmd_BeginFrame");
nuclear@0 619 OVR_DEBUG_LOG_COND(hmds->BeginFrameCalled, ("ovrHmd_BeginFrame called multiple times."));
nuclear@0 620 ThreadChecker::Scope checkScope(&hmds->RenderAPIThreadChecker, "ovrHmd_BeginFrame");
nuclear@0 621
nuclear@0 622 hmds->BeginFrameCalled = true;
nuclear@0 623 hmds->BeginFrameThreadId = OVR::GetCurrentThreadId();
nuclear@0 624
nuclear@0 625 return ovrHmd_BeginFrameTiming(hmddesc, frameIndex);
nuclear@0 626 }
nuclear@0 627
nuclear@0 628
nuclear@0 629 // Renders textures to frame buffer
nuclear@0 630 OVR_EXPORT void ovrHmd_EndFrame(ovrHmd hmddesc,
nuclear@0 631 const ovrPosef renderPose[2],
nuclear@0 632 const ovrTexture eyeTexture[2])
nuclear@0 633 {
nuclear@0 634 HMDState* hmds = (HMDState*)hmddesc->Handle;
nuclear@0 635 if (!hmds) return;
nuclear@0 636
nuclear@0 637 // Instrument when the EndFrame() call started
nuclear@0 638 hmds->LagStats.InstrumentEndFrameStart(ovr_GetTimeInSeconds());
nuclear@0 639
nuclear@0 640 hmds->SubmitEyeTextures(renderPose, eyeTexture);
nuclear@0 641
nuclear@0 642 // Debug state checks: Must be in BeginFrame, on the same thread.
nuclear@0 643 hmds->checkBeginFrameScope("ovrHmd_EndFrame");
nuclear@0 644 ThreadChecker::Scope checkScope(&hmds->RenderAPIThreadChecker, "ovrHmd_EndFrame");
nuclear@0 645
nuclear@0 646 hmds->pRenderer->SetLatencyTestColor(hmds->LatencyTestActive ? hmds->LatencyTestDrawColor : NULL);
nuclear@0 647
nuclear@0 648 ovrHmd_GetLatencyTest2DrawColor(hmddesc, NULL); // We don't actually need to draw color, so send NULL
nuclear@0 649
nuclear@0 650 if (hmds->pRenderer)
nuclear@0 651 {
nuclear@0 652 hmds->pRenderer->SaveGraphicsState();
nuclear@0 653
nuclear@0 654 // See if we need to show the HSWDisplay.
nuclear@0 655 if (hmds->pHSWDisplay) // Until we know that these are valid, assume any of them can't be.
nuclear@0 656 {
nuclear@0 657 ovrHSWDisplayState hswDisplayState;
nuclear@0 658 hmds->pHSWDisplay->TickState(&hswDisplayState, true); // This may internally call HASWarning::Display.
nuclear@0 659
nuclear@0 660 if (hswDisplayState.Displayed)
nuclear@0 661 {
nuclear@0 662 hmds->pHSWDisplay->Render(ovrEye_Left, &eyeTexture[ovrEye_Left]);
nuclear@0 663 hmds->pHSWDisplay->Render(ovrEye_Right, &eyeTexture[ovrEye_Right]);
nuclear@0 664 }
nuclear@0 665 }
nuclear@0 666
nuclear@0 667 hmds->pRenderer->EndFrame(true);
nuclear@0 668 hmds->pRenderer->RestoreGraphicsState();
nuclear@0 669 }
nuclear@0 670
nuclear@0 671 // Call after present
nuclear@0 672 ovrHmd_EndFrameTiming(hmddesc);
nuclear@0 673
nuclear@0 674 // Instrument latency tester
nuclear@0 675 hmds->LagStats.InstrumentLatencyTimings(hmds->TimeManager);
nuclear@0 676
nuclear@0 677 // Instrument when the EndFrame() call ended
nuclear@0 678 hmds->LagStats.InstrumentEndFrameEnd(ovr_GetTimeInSeconds());
nuclear@0 679
nuclear@0 680 // Out of BeginFrame
nuclear@0 681 hmds->BeginFrameThreadId = 0;
nuclear@0 682 hmds->BeginFrameCalled = false;
nuclear@0 683 }
nuclear@0 684
nuclear@0 685
nuclear@0 686 // Not exposed as part of public API
nuclear@0 687 OVR_EXPORT void ovrHmd_RegisterPostDistortionCallback(ovrHmd hmddesc, PostDistortionCallback callback)
nuclear@0 688 {
nuclear@0 689 HMDState* hmds = (HMDState*)hmddesc->Handle;
nuclear@0 690 if (!hmds) return;
nuclear@0 691
nuclear@0 692 if (hmds->pRenderer)
nuclear@0 693 {
nuclear@0 694 hmds->pRenderer->RegisterPostDistortionCallback(callback);
nuclear@0 695 }
nuclear@0 696 }
nuclear@0 697
nuclear@0 698
nuclear@0 699
nuclear@0 700 //-------------------------------------------------------------------------------------
nuclear@0 701 // ***** Frame Timing logic
nuclear@0 702
nuclear@0 703
nuclear@0 704 OVR_EXPORT ovrFrameTiming ovrHmd_GetFrameTiming(ovrHmd hmddesc, unsigned int frameIndex)
nuclear@0 705 {
nuclear@0 706 ovrHmdStruct * hmd = hmddesc->Handle;
nuclear@0 707 ovrFrameTiming f;
nuclear@0 708 memset(&f, 0, sizeof(f));
nuclear@0 709
nuclear@0 710 HMDState* hmds = (HMDState*)hmd;
nuclear@0 711 if (hmds)
nuclear@0 712 {
nuclear@0 713 FrameTimeManager::Timing frameTiming = hmds->TimeManager.GetFrameTiming(frameIndex);
nuclear@0 714
nuclear@0 715 f.ThisFrameSeconds = frameTiming.ThisFrameTime;
nuclear@0 716 f.NextFrameSeconds = frameTiming.NextFrameTime;
nuclear@0 717 f.TimewarpPointSeconds = frameTiming.TimewarpPointTime;
nuclear@0 718 f.ScanoutMidpointSeconds = frameTiming.MidpointTime;
nuclear@0 719 f.EyeScanoutSeconds[0] = frameTiming.EyeRenderTimes[0];
nuclear@0 720 f.EyeScanoutSeconds[1] = frameTiming.EyeRenderTimes[1];
nuclear@0 721
nuclear@0 722 // Compute DeltaSeconds.
nuclear@0 723 f.DeltaSeconds = (hmds->LastGetFrameTimeSeconds == 0.0f) ? 0.0f :
nuclear@0 724 (float) (f.ThisFrameSeconds - hmds->LastFrameTimeSeconds);
nuclear@0 725 hmds->LastGetFrameTimeSeconds = f.ThisFrameSeconds;
nuclear@0 726 if (f.DeltaSeconds > 1.0f)
nuclear@0 727 f.DeltaSeconds = 1.0f;
nuclear@0 728 }
nuclear@0 729
nuclear@0 730 return f;
nuclear@0 731 }
nuclear@0 732
nuclear@0 733 OVR_EXPORT ovrFrameTiming ovrHmd_BeginFrameTiming(ovrHmd hmddesc, unsigned int frameIndex)
nuclear@0 734 {
nuclear@0 735 ovrHmdStruct * hmd = hmddesc->Handle;
nuclear@0 736 ovrFrameTiming f;
nuclear@0 737 memset(&f, 0, sizeof(f));
nuclear@0 738
nuclear@0 739 HMDState* hmds = (HMDState*)hmd;
nuclear@0 740 if (!hmds) return f;
nuclear@0 741
nuclear@0 742 // Check: Proper state for the call.
nuclear@0 743 OVR_DEBUG_LOG_COND(hmds->BeginFrameTimingCalled,
nuclear@0 744 ("ovrHmd_BeginFrameTiming called multiple times."));
nuclear@0 745 hmds->BeginFrameTimingCalled = true;
nuclear@0 746
nuclear@0 747 double thisFrameTime = hmds->TimeManager.BeginFrame(frameIndex);
nuclear@0 748
nuclear@0 749 const FrameTimeManager::Timing &frameTiming = hmds->TimeManager.GetFrameTiming();
nuclear@0 750
nuclear@0 751 f.ThisFrameSeconds = thisFrameTime;
nuclear@0 752 f.NextFrameSeconds = frameTiming.NextFrameTime;
nuclear@0 753 f.TimewarpPointSeconds = frameTiming.TimewarpPointTime;
nuclear@0 754 f.ScanoutMidpointSeconds= frameTiming.MidpointTime;
nuclear@0 755 f.EyeScanoutSeconds[0] = frameTiming.EyeRenderTimes[0];
nuclear@0 756 f.EyeScanoutSeconds[1] = frameTiming.EyeRenderTimes[1];
nuclear@0 757
nuclear@0 758 // Compute DeltaSeconds.
nuclear@0 759 f.DeltaSeconds = (hmds->LastFrameTimeSeconds == 0.0f) ? 0.0f :
nuclear@0 760 (float) (thisFrameTime - hmds->LastFrameTimeSeconds);
nuclear@0 761 hmds->LastFrameTimeSeconds = thisFrameTime;
nuclear@0 762 if (f.DeltaSeconds > 1.0f)
nuclear@0 763 f.DeltaSeconds = 1.0f;
nuclear@0 764
nuclear@0 765 return f;
nuclear@0 766 }
nuclear@0 767
nuclear@0 768
nuclear@0 769 OVR_EXPORT void ovrHmd_EndFrameTiming(ovrHmd hmddesc)
nuclear@0 770 {
nuclear@0 771 HMDState* hmds = (HMDState*)hmddesc->Handle;
nuclear@0 772 if (!hmds) return;
nuclear@0 773
nuclear@0 774 // Debug state checks: Must be in BeginFrameTiming, on the same thread.
nuclear@0 775 hmds->checkBeginFrameTimingScope("ovrHmd_EndTiming");
nuclear@0 776 // MA TBD: Correct check or not?
nuclear@0 777 // ThreadChecker::Scope checkScope(&hmds->RenderAPIThreadChecker, "ovrHmd_EndFrame");
nuclear@0 778
nuclear@0 779 hmds->TimeManager.EndFrame();
nuclear@0 780 hmds->BeginFrameTimingCalled = false;
nuclear@0 781
nuclear@0 782 bool dk2LatencyTest = (hmds->EnabledHmdCaps & ovrHmdCap_DynamicPrediction) != 0;
nuclear@0 783 if (dk2LatencyTest)
nuclear@0 784 {
nuclear@0 785 Util::FrameTimeRecordSet recordset;
nuclear@0 786 hmds->TheLatencyTestStateReader.GetRecordSet(recordset);
nuclear@0 787 hmds->TimeManager.UpdateFrameLatencyTrackingAfterEndFrame( hmds->LatencyTest2DrawColor,
nuclear@0 788 recordset);
nuclear@0 789 }
nuclear@0 790 }
nuclear@0 791
nuclear@0 792
nuclear@0 793 OVR_EXPORT void ovrHmd_ResetFrameTiming(ovrHmd hmddesc, unsigned int frameIndex)
nuclear@0 794 {
nuclear@0 795 HMDState* hmds = (HMDState*)hmddesc->Handle;
nuclear@0 796 if (!hmds) return;
nuclear@0 797
nuclear@0 798 hmds->TimeManager.ResetFrameTiming(frameIndex,
nuclear@0 799 false,
nuclear@0 800 hmds->RenderingConfigured);
nuclear@0 801 hmds->LastFrameTimeSeconds = 0.0;
nuclear@0 802 hmds->LastGetFrameTimeSeconds = 0.0;
nuclear@0 803 }
nuclear@0 804
nuclear@0 805 OVR_EXPORT void ovrHmd_GetEyePoses(ovrHmd hmd, unsigned int frameIndex, ovrVector3f hmdToEyeViewOffset[2],
nuclear@0 806 ovrPosef outEyePoses[2], ovrTrackingState* outHmdTrackingState)
nuclear@0 807 {
nuclear@0 808 HMDState* hmds = (HMDState*)hmd->Handle;
nuclear@0 809 if (!hmds) return;
nuclear@0 810
nuclear@0 811 hmds->LatencyTestActive = hmds->ProcessLatencyTest(hmds->LatencyTestDrawColor);
nuclear@0 812
nuclear@0 813 ovrTrackingState hmdTrackingState = hmds->TimeManager.GetEyePredictionTracking(hmd, ovrEye_Count, frameIndex);
nuclear@0 814 ovrPosef hmdPose = hmdTrackingState.HeadPose.ThePose;
nuclear@0 815
nuclear@0 816 // caller passed in a valid pointer, so copy to output
nuclear@0 817 if(outHmdTrackingState)
nuclear@0 818 *outHmdTrackingState = hmdTrackingState;
nuclear@0 819
nuclear@0 820 // Currently HmdToEyeViewOffset is only a 3D vector
nuclear@0 821 // (Negate HmdToEyeViewOffset because offset is a view matrix offset and not a camera offset)
nuclear@0 822 outEyePoses[0] = Posef(hmdPose.Orientation, ((Posef)hmdPose).Apply(-((Vector3f)hmdToEyeViewOffset[0])));
nuclear@0 823 outEyePoses[1] = Posef(hmdPose.Orientation, ((Posef)hmdPose).Apply(-((Vector3f)hmdToEyeViewOffset[1])));
nuclear@0 824
nuclear@0 825 // Instrument data from eye pose
nuclear@0 826 hmds->LagStats.InstrumentEyePose(hmdTrackingState);
nuclear@0 827 }
nuclear@0 828
nuclear@0 829 ovrPosef ovrHmd_GetHmdPosePerEye(ovrHmd hmd, ovrEyeType eye)
nuclear@0 830 {
nuclear@0 831 HMDState* hmds = (HMDState*)hmd->Handle;
nuclear@0 832 if (!hmds) return ovrPosef();
nuclear@0 833
nuclear@0 834 // This isn't a great place, but since we removed ovrHmd_BeginEyeRender...
nuclear@0 835 // Only process latency tester for drawing the left eye (assumes left eye is drawn first)
nuclear@0 836 if (hmds->pRenderer && eye == 0)
nuclear@0 837 {
nuclear@0 838 hmds->LatencyTestActive = hmds->ProcessLatencyTest(hmds->LatencyTestDrawColor);
nuclear@0 839 }
nuclear@0 840
nuclear@0 841 hmds->checkBeginFrameTimingScope("ovrHmd_GetEyePose");
nuclear@0 842 return hmds->TimeManager.GetEyePredictionPose(hmd, eye);
nuclear@0 843 }
nuclear@0 844
nuclear@0 845 OVR_EXPORT void ovrHmd_AddDistortionTimeMeasurement(ovrHmd hmddesc, double distortionTimeSeconds)
nuclear@0 846 {
nuclear@0 847 if (!hmddesc)
nuclear@0 848 return;
nuclear@0 849 HMDState* hmds = (HMDState*)hmddesc->Handle;
nuclear@0 850
nuclear@0 851 hmds->checkBeginFrameTimingScope("ovrHmd_GetTimewarpEyeMatrices");
nuclear@0 852 hmds->TimeManager.AddDistortionTimeMeasurement(distortionTimeSeconds);
nuclear@0 853 }
nuclear@0 854
nuclear@0 855
nuclear@0 856
nuclear@0 857 OVR_EXPORT void ovrHmd_GetEyeTimewarpMatricesDebug(ovrHmd hmddesc, ovrEyeType eye,
nuclear@0 858 ovrPosef renderPose, ovrMatrix4f twmOut[2],double debugTimingOffsetInSeconds)
nuclear@0 859 {
nuclear@0 860 if (!hmddesc)
nuclear@0 861 return;
nuclear@0 862 HMDState* hmds = (HMDState*)hmddesc->Handle;
nuclear@0 863
nuclear@0 864 // Debug checks: BeginFrame was called, on the same thread.
nuclear@0 865 hmds->checkBeginFrameTimingScope("ovrHmd_GetTimewarpEyeMatrices");
nuclear@0 866
nuclear@0 867 hmds->TimeManager.GetTimewarpMatrices(hmddesc, eye, renderPose, twmOut, debugTimingOffsetInSeconds);
nuclear@0 868
nuclear@0 869 /*
nuclear@0 870 // MA: Took this out because new latency test approach just sames
nuclear@0 871 // the sample times in FrameTimeManager.
nuclear@0 872 // TODO: if no timewarp, then test latency in begin eye render
nuclear@0 873 if (eye == 0)
nuclear@0 874 {
nuclear@0 875 hmds->ProcessLatencyTest2(hmds->LatencyTest2DrawColor, -1.0f);
nuclear@0 876 }
nuclear@0 877 */
nuclear@0 878 }
nuclear@0 879
nuclear@0 880
nuclear@0 881 OVR_EXPORT void ovrHmd_GetEyeTimewarpMatrices(ovrHmd hmddesc, ovrEyeType eye,
nuclear@0 882 ovrPosef renderPose, ovrMatrix4f twmOut[2])
nuclear@0 883 {
nuclear@0 884 return(ovrHmd_GetEyeTimewarpMatricesDebug(hmddesc, eye, renderPose, twmOut, 0.0));
nuclear@0 885 }
nuclear@0 886
nuclear@0 887
nuclear@0 888
nuclear@0 889 OVR_EXPORT ovrEyeRenderDesc ovrHmd_GetRenderDesc(ovrHmd hmddesc,
nuclear@0 890 ovrEyeType eyeType, ovrFovPort fov)
nuclear@0 891 {
nuclear@0 892 HMDState* hmds = (HMDState*)hmddesc->Handle;
nuclear@0 893 ovrEyeRenderDesc erd;
nuclear@0 894
nuclear@0 895 if (!hmds)
nuclear@0 896 {
nuclear@0 897 memset(&erd, 0, sizeof(erd));
nuclear@0 898 return erd;
nuclear@0 899 }
nuclear@0 900
nuclear@0 901 return hmds->RenderState.CalcRenderDesc(eyeType, fov);
nuclear@0 902 }
nuclear@0 903
nuclear@0 904
nuclear@0 905
nuclear@0 906 #define OVR_OFFSET_OF(s, field) ((size_t)&((s*)0)->field)
nuclear@0 907
nuclear@0 908
nuclear@0 909
nuclear@0 910
nuclear@0 911 OVR_EXPORT ovrBool ovrHmd_CreateDistortionMeshDebug( ovrHmd hmddesc,
nuclear@0 912 ovrEyeType eyeType, ovrFovPort fov,
nuclear@0 913 unsigned int distortionCaps,
nuclear@0 914 ovrDistortionMesh *meshData,
nuclear@0 915 float debugEyeReliefOverrideInMetres)
nuclear@0 916 {
nuclear@0 917 // The 'internal' function below can be found in CAPI_HMDState.
nuclear@0 918 // Not ideal, but navigating the convolutions of what compiles
nuclear@0 919 // where, meant they are in the few places which actually lets these compile.
nuclear@0 920 // Please relocate (if you wish) to a more meaningful place if you can navigate the compiler gymnastics :)
nuclear@0 921 return(ovrHmd_CreateDistortionMeshInternal( hmddesc->Handle,
nuclear@0 922 eyeType, fov,
nuclear@0 923 distortionCaps,
nuclear@0 924 meshData,
nuclear@0 925 debugEyeReliefOverrideInMetres));
nuclear@0 926
nuclear@0 927 }
nuclear@0 928 OVR_EXPORT ovrBool ovrHmd_CreateDistortionMesh( ovrHmd hmddesc,
nuclear@0 929 ovrEyeType eyeType, ovrFovPort fov,
nuclear@0 930 unsigned int distortionCaps,
nuclear@0 931 ovrDistortionMesh *meshData)
nuclear@0 932 {
nuclear@0 933 return(ovrHmd_CreateDistortionMeshDebug( hmddesc, eyeType, fov, distortionCaps,meshData, 0));
nuclear@0 934 }
nuclear@0 935
nuclear@0 936
nuclear@0 937
nuclear@0 938 // Frees distortion mesh allocated by ovrHmd_GenerateDistortionMesh. meshData elements
nuclear@0 939 // are set to null and 0s after the call.
nuclear@0 940 OVR_EXPORT void ovrHmd_DestroyDistortionMesh(ovrDistortionMesh* meshData)
nuclear@0 941 {
nuclear@0 942 if (meshData->pVertexData)
nuclear@0 943 DistortionMeshDestroy((DistortionMeshVertexData*)meshData->pVertexData,
nuclear@0 944 meshData->pIndexData);
nuclear@0 945 meshData->pVertexData = 0;
nuclear@0 946 meshData->pIndexData = 0;
nuclear@0 947 meshData->VertexCount = 0;
nuclear@0 948 meshData->IndexCount = 0;
nuclear@0 949 }
nuclear@0 950
nuclear@0 951
nuclear@0 952
nuclear@0 953 // Computes updated 'uvScaleOffsetOut' to be used with a distortion if render target size or
nuclear@0 954 // viewport changes after the fact. This can be used to adjust render size every frame, if desired.
nuclear@0 955 OVR_EXPORT void ovrHmd_GetRenderScaleAndOffset( ovrFovPort fov,
nuclear@0 956 ovrSizei textureSize, ovrRecti renderViewport,
nuclear@0 957 ovrVector2f uvScaleOffsetOut[2] )
nuclear@0 958 {
nuclear@0 959 // Find the mapping from TanAngle space to target NDC space.
nuclear@0 960 ScaleAndOffset2D eyeToSourceNDC = CreateNDCScaleAndOffsetFromFov(fov);
nuclear@0 961 // Find the mapping from TanAngle space to textureUV space.
nuclear@0 962 ScaleAndOffset2D eyeToSourceUV = CreateUVScaleAndOffsetfromNDCScaleandOffset(
nuclear@0 963 eyeToSourceNDC,
nuclear@0 964 renderViewport, textureSize );
nuclear@0 965
nuclear@0 966 uvScaleOffsetOut[0] = eyeToSourceUV.Scale;
nuclear@0 967 uvScaleOffsetOut[1] = eyeToSourceUV.Offset;
nuclear@0 968 }
nuclear@0 969
nuclear@0 970
nuclear@0 971 //-------------------------------------------------------------------------------------
nuclear@0 972 // ***** Latency Test interface
nuclear@0 973
nuclear@0 974 OVR_EXPORT ovrBool ovrHmd_GetLatencyTestDrawColor(ovrHmd hmddesc, unsigned char rgbColorOut[3])
nuclear@0 975 {
nuclear@0 976 HMDState* p = (HMDState*)hmddesc->Handle;
nuclear@0 977 rgbColorOut[0] = p->LatencyTestDrawColor[0];
nuclear@0 978 rgbColorOut[1] = p->LatencyTestDrawColor[1];
nuclear@0 979 rgbColorOut[2] = p->LatencyTestDrawColor[2];
nuclear@0 980 return p->LatencyTestActive;
nuclear@0 981 }
nuclear@0 982
nuclear@0 983 OVR_EXPORT ovrBool ovrHmd_ProcessLatencyTest(ovrHmd hmddesc, unsigned char rgbColorOut[3])
nuclear@0 984 {
nuclear@0 985 OVR_UNUSED(hmddesc);
nuclear@0 986 return NetClient::GetInstance()->LatencyUtil_ProcessInputs(Timer::GetSeconds(), rgbColorOut);
nuclear@0 987 }
nuclear@0 988
nuclear@0 989 OVR_EXPORT const char* ovrHmd_GetLatencyTestResult(ovrHmd hmddesc)
nuclear@0 990 {
nuclear@0 991 OVR_UNUSED(hmddesc);
nuclear@0 992 return NetClient::GetInstance()->LatencyUtil_GetResultsString();
nuclear@0 993 }
nuclear@0 994
nuclear@0 995 OVR_EXPORT ovrBool ovrHmd_GetLatencyTest2DrawColor(ovrHmd hmddesc, unsigned char rgbColorOut[3])
nuclear@0 996 {
nuclear@0 997 HMDState* hmds = (HMDState*)hmddesc->Handle;
nuclear@0 998 if (!hmds) return false;
nuclear@0 999
nuclear@0 1000 // TBD: Move directly into renderer
nuclear@0 1001 bool dk2LatencyTest = (hmds->EnabledHmdCaps & ovrHmdCap_DynamicPrediction) != 0;
nuclear@0 1002 if (dk2LatencyTest)
nuclear@0 1003 {
nuclear@0 1004 hmds->TimeManager.GetFrameLatencyTestDrawColor(hmds->LatencyTest2DrawColor);
nuclear@0 1005 if(rgbColorOut != NULL)
nuclear@0 1006 {
nuclear@0 1007 rgbColorOut[0] = hmds->LatencyTest2DrawColor[0];
nuclear@0 1008 rgbColorOut[1] = hmds->LatencyTest2DrawColor[1];
nuclear@0 1009 rgbColorOut[2] = hmds->LatencyTest2DrawColor[2];
nuclear@0 1010 }
nuclear@0 1011
nuclear@0 1012 if(hmds->pRenderer != NULL)
nuclear@0 1013 hmds->pRenderer->SetLatencyTest2Color(hmds->LatencyTest2DrawColor);
nuclear@0 1014 }
nuclear@0 1015 else
nuclear@0 1016 {
nuclear@0 1017 if(hmds->pRenderer != NULL)
nuclear@0 1018 hmds->pRenderer->SetLatencyTest2Color(NULL);
nuclear@0 1019 }
nuclear@0 1020
nuclear@0 1021 return dk2LatencyTest;
nuclear@0 1022 }
nuclear@0 1023
nuclear@0 1024
nuclear@0 1025 OVR_EXPORT double ovrHmd_GetMeasuredLatencyTest2(ovrHmd hmddesc)
nuclear@0 1026 {
nuclear@0 1027 HMDState* p = (HMDState*)hmddesc->Handle;
nuclear@0 1028
nuclear@0 1029 // MA Test
nuclear@0 1030 float latencyRender, latencyTimewarp, latencyPostPresent;
nuclear@0 1031
nuclear@0 1032 p->TimeManager.GetLatencyTimings(latencyRender, latencyTimewarp, latencyPostPresent);
nuclear@0 1033 return latencyPostPresent;
nuclear@0 1034 }
nuclear@0 1035
nuclear@0 1036
nuclear@0 1037 //-------------------------------------------------------------------------------------
nuclear@0 1038 // ***** Health and Safety Warning Display interface
nuclear@0 1039 //
nuclear@0 1040
nuclear@0 1041 OVR_EXPORT void ovrHmd_GetHSWDisplayState(ovrHmd hmd, ovrHSWDisplayState *hswDisplayState)
nuclear@0 1042 {
nuclear@0 1043 OVR::CAPI::HMDState* pHMDState = (OVR::CAPI::HMDState*)hmd->Handle;
nuclear@0 1044
nuclear@0 1045 if (pHMDState)
nuclear@0 1046 {
nuclear@0 1047 OVR::CAPI::HSWDisplay* pHSWDisplay = pHMDState->pHSWDisplay;
nuclear@0 1048
nuclear@0 1049 if(pHSWDisplay)
nuclear@0 1050 pHSWDisplay->TickState(hswDisplayState); // This may internally call HSWDisplay::Display.
nuclear@0 1051 }
nuclear@0 1052 }
nuclear@0 1053
nuclear@0 1054 OVR_EXPORT ovrBool ovrHmd_DismissHSWDisplay(ovrHmd hmd)
nuclear@0 1055 {
nuclear@0 1056 OVR::CAPI::HMDState* pHMDState = (OVR::CAPI::HMDState*)hmd->Handle;
nuclear@0 1057
nuclear@0 1058 if (pHMDState)
nuclear@0 1059 {
nuclear@0 1060 OVR::CAPI::HSWDisplay* pHSWDisplay = pHMDState->pHSWDisplay;
nuclear@0 1061
nuclear@0 1062 if(pHSWDisplay)
nuclear@0 1063 return (pHSWDisplay->Dismiss() ? 1 : 0);
nuclear@0 1064 }
nuclear@0 1065
nuclear@0 1066 return false;
nuclear@0 1067 }
nuclear@0 1068
nuclear@0 1069
nuclear@0 1070 // -----------------------------------------------------------------------------------
nuclear@0 1071 // ***** Property Access
nuclear@0 1072 OVR_EXPORT ovrBool ovrHmd_GetBool(ovrHmd hmddesc,
nuclear@0 1073 const char* propertyName,
nuclear@0 1074 ovrBool defaultVal)
nuclear@0 1075 {
nuclear@0 1076 OVR_ASSERT(propertyName);
nuclear@0 1077 if (hmddesc)
nuclear@0 1078 {
nuclear@0 1079 HMDState* hmds = (HMDState*)hmddesc->Handle;
nuclear@0 1080 OVR_ASSERT(hmds);
nuclear@0 1081 if (hmds)
nuclear@0 1082 {
nuclear@0 1083 return hmds->getBoolValue(propertyName, (defaultVal != 0));
nuclear@0 1084 }
nuclear@0 1085 }
nuclear@0 1086
nuclear@0 1087 return NetClient::GetInstance()->GetBoolValue(InvalidVirtualHmdId, propertyName, (defaultVal != 0)) ? 1 : 0;
nuclear@0 1088 }
nuclear@0 1089
nuclear@0 1090 OVR_EXPORT ovrBool ovrHmd_SetBool(ovrHmd hmddesc,
nuclear@0 1091 const char* propertyName,
nuclear@0 1092 ovrBool value)
nuclear@0 1093 {
nuclear@0 1094 OVR_ASSERT(propertyName);
nuclear@0 1095 if (hmddesc)
nuclear@0 1096 {
nuclear@0 1097 HMDState* hmds = (HMDState*)hmddesc->Handle;
nuclear@0 1098 OVR_ASSERT(hmds);
nuclear@0 1099 if (hmds)
nuclear@0 1100 {
nuclear@0 1101 return hmds->setBoolValue(propertyName, value != 0) ? 1 : 0;
nuclear@0 1102 }
nuclear@0 1103 }
nuclear@0 1104
nuclear@0 1105 return NetClient::GetInstance()->SetBoolValue(InvalidVirtualHmdId, propertyName, (value != 0)) ? 1 : 0;
nuclear@0 1106 }
nuclear@0 1107
nuclear@0 1108 OVR_EXPORT int ovrHmd_GetInt(ovrHmd hmddesc,
nuclear@0 1109 const char* propertyName,
nuclear@0 1110 int defaultVal)
nuclear@0 1111 {
nuclear@0 1112 OVR_ASSERT(propertyName);
nuclear@0 1113 if (hmddesc)
nuclear@0 1114 {
nuclear@0 1115 HMDState* hmds = (HMDState*)hmddesc->Handle;
nuclear@0 1116 OVR_ASSERT(hmds);
nuclear@0 1117 if (hmds)
nuclear@0 1118 {
nuclear@0 1119 return hmds->getIntValue(propertyName, defaultVal);
nuclear@0 1120 }
nuclear@0 1121 }
nuclear@0 1122
nuclear@0 1123 return NetClient::GetInstance()->GetIntValue(InvalidVirtualHmdId, propertyName, defaultVal);
nuclear@0 1124 }
nuclear@0 1125
nuclear@0 1126 OVR_EXPORT ovrBool ovrHmd_SetInt(ovrHmd hmddesc,
nuclear@0 1127 const char* propertyName,
nuclear@0 1128 int value)
nuclear@0 1129 {
nuclear@0 1130 OVR_ASSERT(propertyName);
nuclear@0 1131 if (hmddesc)
nuclear@0 1132 {
nuclear@0 1133 HMDState* hmds = (HMDState*)hmddesc->Handle;
nuclear@0 1134 OVR_ASSERT(hmds);
nuclear@0 1135 if (hmds)
nuclear@0 1136 {
nuclear@0 1137 return hmds->setIntValue(propertyName, value) ? 1 : 0;
nuclear@0 1138 }
nuclear@0 1139 }
nuclear@0 1140
nuclear@0 1141 return NetClient::GetInstance()->SetIntValue(InvalidVirtualHmdId, propertyName, value) ? 1 : 0;
nuclear@0 1142 }
nuclear@0 1143
nuclear@0 1144 OVR_EXPORT float ovrHmd_GetFloat(ovrHmd hmddesc,
nuclear@0 1145 const char* propertyName,
nuclear@0 1146 float defaultVal)
nuclear@0 1147 {
nuclear@0 1148 OVR_ASSERT(propertyName);
nuclear@0 1149 if (hmddesc)
nuclear@0 1150 {
nuclear@0 1151 HMDState* hmds = (HMDState*)hmddesc->Handle;
nuclear@0 1152 OVR_ASSERT(hmds);
nuclear@0 1153 if (hmds)
nuclear@0 1154 {
nuclear@0 1155 return hmds->getFloatValue(propertyName, defaultVal);
nuclear@0 1156 }
nuclear@0 1157 }
nuclear@0 1158
nuclear@0 1159 return (float)NetClient::GetInstance()->GetNumberValue(InvalidVirtualHmdId, propertyName, defaultVal);
nuclear@0 1160 }
nuclear@0 1161
nuclear@0 1162 OVR_EXPORT ovrBool ovrHmd_SetFloat(ovrHmd hmddesc,
nuclear@0 1163 const char* propertyName,
nuclear@0 1164 float value)
nuclear@0 1165 {
nuclear@0 1166 OVR_ASSERT(propertyName);
nuclear@0 1167 if (hmddesc)
nuclear@0 1168 {
nuclear@0 1169 HMDState* hmds = (HMDState*)hmddesc->Handle;
nuclear@0 1170 OVR_ASSERT(hmds);
nuclear@0 1171 if (hmds)
nuclear@0 1172 {
nuclear@0 1173 return hmds->setFloatValue(propertyName, value) ? 1 : 0;
nuclear@0 1174 }
nuclear@0 1175 }
nuclear@0 1176
nuclear@0 1177 return NetClient::GetInstance()->SetNumberValue(InvalidVirtualHmdId, propertyName, value) ? 1 : 0;
nuclear@0 1178 }
nuclear@0 1179
nuclear@0 1180 OVR_EXPORT unsigned int ovrHmd_GetFloatArray(ovrHmd hmddesc,
nuclear@0 1181 const char* propertyName,
nuclear@0 1182 float values[],
nuclear@0 1183 unsigned int arraySize)
nuclear@0 1184 {
nuclear@0 1185 OVR_ASSERT(propertyName);
nuclear@0 1186 OVR_ASSERT(hmddesc);
nuclear@0 1187 if (hmddesc)
nuclear@0 1188 {
nuclear@0 1189 HMDState* hmds = (HMDState*)hmddesc->Handle;
nuclear@0 1190 OVR_ASSERT(hmds);
nuclear@0 1191 if (hmds)
nuclear@0 1192 {
nuclear@0 1193 return hmds->getFloatArray(propertyName, values, arraySize);
nuclear@0 1194 }
nuclear@0 1195 }
nuclear@0 1196
nuclear@0 1197 // FIXME: Currently it takes a few lines of code to do this, so just not supported for now.
nuclear@0 1198 return 0;
nuclear@0 1199 }
nuclear@0 1200
nuclear@0 1201 // Modify float[] property; false if property doesn't exist or is readonly.
nuclear@0 1202 OVR_EXPORT ovrBool ovrHmd_SetFloatArray(ovrHmd hmddesc,
nuclear@0 1203 const char* propertyName,
nuclear@0 1204 float values[],
nuclear@0 1205 unsigned int arraySize)
nuclear@0 1206 {
nuclear@0 1207 OVR_ASSERT(propertyName);
nuclear@0 1208 OVR_ASSERT(hmddesc);
nuclear@0 1209 if (hmddesc)
nuclear@0 1210 {
nuclear@0 1211 HMDState* hmds = (HMDState*)hmddesc->Handle;
nuclear@0 1212 OVR_ASSERT(hmds);
nuclear@0 1213 if (hmds)
nuclear@0 1214 {
nuclear@0 1215 return hmds->setFloatArray(propertyName, values, arraySize) ? 1 : 0;
nuclear@0 1216 }
nuclear@0 1217 }
nuclear@0 1218
nuclear@0 1219 // FIXME: Currently it takes a few lines of code to do this, so just not supported for now.
nuclear@0 1220 return 0;
nuclear@0 1221 }
nuclear@0 1222
nuclear@0 1223 OVR_EXPORT const char* ovrHmd_GetString(ovrHmd hmddesc,
nuclear@0 1224 const char* propertyName,
nuclear@0 1225 const char* defaultVal)
nuclear@0 1226 {
nuclear@0 1227 OVR_ASSERT(propertyName);
nuclear@0 1228 if (hmddesc)
nuclear@0 1229 {
nuclear@0 1230 HMDState* hmds = (HMDState*)hmddesc->Handle;
nuclear@0 1231 if (hmds)
nuclear@0 1232 {
nuclear@0 1233 return hmds->getString(propertyName, defaultVal);
nuclear@0 1234 }
nuclear@0 1235 }
nuclear@0 1236
nuclear@0 1237 return NetClient::GetInstance()->GetStringValue(InvalidVirtualHmdId, propertyName, defaultVal);
nuclear@0 1238 }
nuclear@0 1239
nuclear@0 1240 OVR_EXPORT ovrBool ovrHmd_SetString(ovrHmd hmddesc,
nuclear@0 1241 const char* propertyName,
nuclear@0 1242 const char* value)
nuclear@0 1243 {
nuclear@0 1244 OVR_ASSERT(propertyName);
nuclear@0 1245 if (hmddesc)
nuclear@0 1246 {
nuclear@0 1247 HMDState* hmds = (HMDState*)hmddesc->Handle;
nuclear@0 1248 if (hmds)
nuclear@0 1249 {
nuclear@0 1250 return hmds->setString(propertyName, value) ? 1 : 0;
nuclear@0 1251 }
nuclear@0 1252 }
nuclear@0 1253
nuclear@0 1254 return NetClient::GetInstance()->SetStringValue(InvalidVirtualHmdId, propertyName, value) ? 1 : 0;
nuclear@0 1255 }
nuclear@0 1256
nuclear@0 1257 // -----------------------------------------------------------------------------------
nuclear@0 1258 // ***** Logging
nuclear@0 1259
nuclear@0 1260 OVR_EXPORT ovrBool ovrHmd_StartPerfLog(ovrHmd hmd, const char* fileName, const char* userData1)
nuclear@0 1261 {
nuclear@0 1262 OVR_ASSERT(fileName && fileName[0]);
nuclear@0 1263
nuclear@0 1264 OVR::CAPI::HMDState* pHMDState = (OVR::CAPI::HMDState*)hmd->Handle;
nuclear@0 1265
nuclear@0 1266 if (pHMDState)
nuclear@0 1267 {
nuclear@0 1268 ovrBool started = pHMDState->LagStatsCSV.Start(fileName, userData1) ? 1 : 0;
nuclear@0 1269 if (started)
nuclear@0 1270 pHMDState->LagStats.AddResultsObserver(pHMDState->LagStatsCSV.GetObserver());
nuclear@0 1271 return started;
nuclear@0 1272 }
nuclear@0 1273 return 0;
nuclear@0 1274 }
nuclear@0 1275 OVR_EXPORT ovrBool ovrHmd_StopPerfLog(ovrHmd hmd)
nuclear@0 1276 {
nuclear@0 1277 OVR::CAPI::HMDState* pHMDState = (OVR::CAPI::HMDState*)hmd->Handle;
nuclear@0 1278
nuclear@0 1279 if (pHMDState)
nuclear@0 1280 {
nuclear@0 1281 return pHMDState->LagStatsCSV.Stop() ? 1 : 0;
nuclear@0 1282 }
nuclear@0 1283 return false;
nuclear@0 1284 }
nuclear@0 1285
nuclear@0 1286
nuclear@0 1287 #ifdef __cplusplus
nuclear@0 1288 } // extern "C"
nuclear@0 1289 #endif