ovr_sdk

annotate LibOVR/Src/CAPI/CAPI_HMDState.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 : CAPI_HMDState.cpp
nuclear@0 4 Content : State associated with a single HMD
nuclear@0 5 Created : January 24, 2014
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 "CAPI_HMDState.h"
nuclear@0 28 #include "../OVR_Profile.h"
nuclear@0 29 #include "../Service/Service_NetClient.h"
nuclear@0 30 #ifdef OVR_OS_WIN32
nuclear@0 31 #include "../Displays/OVR_Win32_ShimFunctions.h"
nuclear@0 32 #endif
nuclear@0 33
nuclear@0 34
nuclear@0 35 namespace OVR { namespace CAPI {
nuclear@0 36
nuclear@0 37
nuclear@0 38 // Accessed via HMDState::GetHMDStateList()
nuclear@0 39 static OVR::List<HMDState> hmdStateList; // List of all created HMDStates.
nuclear@0 40
nuclear@0 41
nuclear@0 42 //-------------------------------------------------------------------------------------
nuclear@0 43 // ***** HMDState
nuclear@0 44
nuclear@0 45 HMDState::HMDState(const OVR::Service::HMDNetworkInfo& netInfo,
nuclear@0 46 const OVR::HMDInfo& hmdInfo,
nuclear@0 47 Profile* profile,
nuclear@0 48 Service::NetClient* client) :
nuclear@0 49 pProfile(profile),
nuclear@0 50 pHmdDesc(0),
nuclear@0 51 pWindow(0),
nuclear@0 52 pClient(client),
nuclear@0 53 NetId(netInfo.NetId),
nuclear@0 54 NetInfo(netInfo),
nuclear@0 55 OurHMDInfo(hmdInfo),
nuclear@0 56 pLastError(NULL),
nuclear@0 57 EnabledHmdCaps(0),
nuclear@0 58 EnabledServiceHmdCaps(0),
nuclear@0 59 SharedStateReader(),
nuclear@0 60 TheSensorStateReader(),
nuclear@0 61 TheLatencyTestStateReader(),
nuclear@0 62 LatencyTestActive(false),
nuclear@0 63 //LatencyTestDrawColor(),
nuclear@0 64 LatencyTest2Active(false),
nuclear@0 65 //LatencyTest2DrawColor(),
nuclear@0 66 TimeManager(true),
nuclear@0 67 RenderState(),
nuclear@0 68 pRenderer(),
nuclear@0 69 pHSWDisplay(),
nuclear@0 70 LastFrameTimeSeconds(0.),
nuclear@0 71 LastGetFrameTimeSeconds(0.),
nuclear@0 72 //LastGetStringValue(),
nuclear@0 73 RenderingConfigured(false),
nuclear@0 74 BeginFrameCalled(false),
nuclear@0 75 BeginFrameThreadId(),
nuclear@0 76 RenderAPIThreadChecker(),
nuclear@0 77 BeginFrameTimingCalled(false)
nuclear@0 78 {
nuclear@0 79 sharedInit(profile);
nuclear@0 80 hmdStateList.PushBack(this);
nuclear@0 81 }
nuclear@0 82
nuclear@0 83
nuclear@0 84 HMDState::HMDState(const OVR::HMDInfo& hmdInfo, Profile* profile) :
nuclear@0 85 pProfile(profile),
nuclear@0 86 pHmdDesc(0),
nuclear@0 87 pWindow(0),
nuclear@0 88 pClient(0),
nuclear@0 89 NetId(InvalidVirtualHmdId),
nuclear@0 90 NetInfo(),
nuclear@0 91 OurHMDInfo(hmdInfo),
nuclear@0 92 pLastError(NULL),
nuclear@0 93 EnabledHmdCaps(0),
nuclear@0 94 EnabledServiceHmdCaps(0),
nuclear@0 95 SharedStateReader(),
nuclear@0 96 TheSensorStateReader(),
nuclear@0 97 TheLatencyTestStateReader(),
nuclear@0 98 LatencyTestActive(false),
nuclear@0 99 //LatencyTestDrawColor(),
nuclear@0 100 LatencyTest2Active(false),
nuclear@0 101 //LatencyTest2DrawColor(),
nuclear@0 102 TimeManager(true),
nuclear@0 103 RenderState(),
nuclear@0 104 pRenderer(),
nuclear@0 105 pHSWDisplay(),
nuclear@0 106 LastFrameTimeSeconds(0.),
nuclear@0 107 LastGetFrameTimeSeconds(0.),
nuclear@0 108 //LastGetStringValue(),
nuclear@0 109 RenderingConfigured(false),
nuclear@0 110 BeginFrameCalled(false),
nuclear@0 111 BeginFrameThreadId(),
nuclear@0 112 RenderAPIThreadChecker(),
nuclear@0 113 BeginFrameTimingCalled(false)
nuclear@0 114 {
nuclear@0 115 sharedInit(profile);
nuclear@0 116 hmdStateList.PushBack(this);
nuclear@0 117 }
nuclear@0 118
nuclear@0 119 HMDState::~HMDState()
nuclear@0 120 {
nuclear@0 121 hmdStateList.Remove(this);
nuclear@0 122
nuclear@0 123 if (pClient)
nuclear@0 124 {
nuclear@0 125 pClient->Hmd_Release(NetId);
nuclear@0 126 pClient = 0;
nuclear@0 127 }
nuclear@0 128
nuclear@0 129 ConfigureRendering(0,0,0,0);
nuclear@0 130
nuclear@0 131 if (pHmdDesc)
nuclear@0 132 {
nuclear@0 133 OVR_FREE(pHmdDesc);
nuclear@0 134 pHmdDesc = NULL;
nuclear@0 135 }
nuclear@0 136 }
nuclear@0 137
nuclear@0 138 void HMDState::sharedInit(Profile* profile)
nuclear@0 139 {
nuclear@0 140 // TBD: We should probably be looking up the default profile for the given
nuclear@0 141 // device type + user if profile == 0.
nuclear@0 142 pLastError = 0;
nuclear@0 143
nuclear@0 144 RenderState.OurHMDInfo = OurHMDInfo;
nuclear@0 145
nuclear@0 146 UpdateRenderProfile(profile);
nuclear@0 147
nuclear@0 148 OVR_ASSERT(!pHmdDesc);
nuclear@0 149 pHmdDesc = (ovrHmdDesc*)OVR_ALLOC(sizeof(ovrHmdDesc));
nuclear@0 150 *pHmdDesc = RenderState.GetDesc();
nuclear@0 151 pHmdDesc->Handle = this;
nuclear@0 152
nuclear@0 153 RenderState.ClearColor[0] = 0.0f;
nuclear@0 154 RenderState.ClearColor[1] = 0.0f;
nuclear@0 155 RenderState.ClearColor[2] = 0.0f;
nuclear@0 156 RenderState.ClearColor[3] = 0.0f;
nuclear@0 157
nuclear@0 158 RenderState.EnabledHmdCaps = 0;
nuclear@0 159
nuclear@0 160 TimeManager.Init(RenderState.RenderInfo);
nuclear@0 161
nuclear@0 162 /*
nuclear@0 163 LatencyTestDrawColor[0] = 0;
nuclear@0 164 LatencyTestDrawColor[1] = 0;
nuclear@0 165 LatencyTestDrawColor[2] = 0;
nuclear@0 166 */
nuclear@0 167
nuclear@0 168 RenderingConfigured = false;
nuclear@0 169 BeginFrameCalled = false;
nuclear@0 170 BeginFrameThreadId = 0;
nuclear@0 171 BeginFrameTimingCalled = false;
nuclear@0 172
nuclear@0 173 // Construct the HSWDisplay. We will later reconstruct it with a specific ovrRenderAPI type if the application starts using SDK-based rendering.
nuclear@0 174 if(!pHSWDisplay)
nuclear@0 175 {
nuclear@0 176 pHSWDisplay = *OVR::CAPI::HSWDisplay::Factory(ovrRenderAPI_None, pHmdDesc, RenderState);
nuclear@0 177 pHSWDisplay->Enable(pProfile->GetBoolValue("HSW", true));
nuclear@0 178 }
nuclear@0 179 }
nuclear@0 180
nuclear@0 181 static Vector3f GetNeckModelFromProfile(Profile* profile)
nuclear@0 182 {
nuclear@0 183 OVR_ASSERT(profile);
nuclear@0 184
nuclear@0 185 float neckeye[2] = { OVR_DEFAULT_NECK_TO_EYE_HORIZONTAL, OVR_DEFAULT_NECK_TO_EYE_VERTICAL };
nuclear@0 186 profile->GetFloatValues(OVR_KEY_NECK_TO_EYE_DISTANCE, neckeye, 2);
nuclear@0 187
nuclear@0 188 // Make sure these are vaguely sensible values.
nuclear@0 189 //OVR_ASSERT((neckeye[0] > 0.05f) && (neckeye[0] < 0.5f));
nuclear@0 190 //OVR_ASSERT((neckeye[1] > 0.05f) && (neckeye[1] < 0.5f));
nuclear@0 191
nuclear@0 192 // Named for clarity
nuclear@0 193 float NeckToEyeHorizontal = neckeye[0];
nuclear@0 194 float NeckToEyeVertical = neckeye[1];
nuclear@0 195
nuclear@0 196 // Store the neck model
nuclear@0 197 return Vector3f(0.0, NeckToEyeVertical, -NeckToEyeHorizontal);
nuclear@0 198 }
nuclear@0 199
nuclear@0 200 static float GetCenterPupilDepthFromRenderInfo(HmdRenderInfo* hmdRenderInfo)
nuclear@0 201 {
nuclear@0 202 OVR_ASSERT(hmdRenderInfo);
nuclear@0 203
nuclear@0 204 // Find the distance from the center of the screen to the "center eye"
nuclear@0 205 // This center eye is used by systems like rendering & audio to represent the player,
nuclear@0 206 // and they will handle the offsets needed from there to each actual eye.
nuclear@0 207
nuclear@0 208 // HACK HACK HACK
nuclear@0 209 // We know for DK1 the screen->lens surface distance is roughly 0.049f, and that the faceplate->lens is 0.02357f.
nuclear@0 210 // We're going to assume(!!!!) that all HMDs have the same screen->faceplate distance.
nuclear@0 211 // Crystal Cove was measured to be roughly 0.025 screen->faceplate which agrees with this assumption.
nuclear@0 212 // TODO: do this properly! Update: Measured this at 0.02733 with a CC prototype, CES era (PT7), on 2/19/14 -Steve
nuclear@0 213 float screenCenterToMidplate = 0.02733f;
nuclear@0 214 float centerEyeRelief = hmdRenderInfo->GetEyeCenter().ReliefInMeters;
nuclear@0 215 float CenterPupilDepth = screenCenterToMidplate + hmdRenderInfo->LensSurfaceToMidplateInMeters + centerEyeRelief;
nuclear@0 216
nuclear@0 217 return CenterPupilDepth;
nuclear@0 218 }
nuclear@0 219
nuclear@0 220 void HMDState::UpdateRenderProfile(Profile* profile)
nuclear@0 221 {
nuclear@0 222 // Apply the given profile to generate a render context
nuclear@0 223 RenderState.RenderInfo = GenerateHmdRenderInfoFromHmdInfo(RenderState.OurHMDInfo, profile);
nuclear@0 224 RenderState.Distortion[0] = CalculateDistortionRenderDesc(StereoEye_Left, RenderState.RenderInfo, 0);
nuclear@0 225 RenderState.Distortion[1] = CalculateDistortionRenderDesc(StereoEye_Right, RenderState.RenderInfo, 0);
nuclear@0 226
nuclear@0 227 if (pClient)
nuclear@0 228 {
nuclear@0 229 // Center pupil depth
nuclear@0 230 float centerPupilDepth = GetCenterPupilDepthFromRenderInfo(&RenderState.RenderInfo);
nuclear@0 231 pClient->SetNumberValue(GetNetId(), "CenterPupilDepth", centerPupilDepth);
nuclear@0 232
nuclear@0 233 // Neck model
nuclear@0 234 Vector3f neckModel = GetNeckModelFromProfile(profile);
nuclear@0 235 double neckModelArray[3] = {
nuclear@0 236 neckModel.x,
nuclear@0 237 neckModel.y,
nuclear@0 238 neckModel.z
nuclear@0 239 };
nuclear@0 240 pClient->SetNumberValues(GetNetId(), "NeckModelVector3f", neckModelArray, 3);
nuclear@0 241
nuclear@0 242 double camerastate[7];
nuclear@0 243 if (profile->GetDoubleValues(OVR_KEY_CAMERA_POSITION, camerastate, 7) == 0)
nuclear@0 244 {
nuclear@0 245 //there is no value, so we load the default
nuclear@0 246 for (int i = 0; i < 7; i++) camerastate[i] = 0;
nuclear@0 247 camerastate[3] = 1;//no offset. by default, give the quaternion w component value 1
nuclear@0 248 }
nuclear@0 249 else
nuclear@0 250
nuclear@0 251 TheSensorStateReader.setCenteredFromWorld(OVR::Posed::FromArray(camerastate));
nuclear@0 252 }
nuclear@0 253
nuclear@0 254
nuclear@0 255 }
nuclear@0 256
nuclear@0 257 HMDState* HMDState::CreateHMDState(NetClient* client, const HMDNetworkInfo& netInfo)
nuclear@0 258 {
nuclear@0 259 // HMDState works through a handle to service HMD....
nuclear@0 260 HMDInfo hinfo;
nuclear@0 261 if (!client->Hmd_GetHmdInfo(netInfo.NetId, &hinfo))
nuclear@0 262 {
nuclear@0 263 OVR_DEBUG_LOG(("[HMDState] Unable to get HMD info"));
nuclear@0 264 return NULL;
nuclear@0 265 }
nuclear@0 266
nuclear@0 267 #ifdef OVR_OS_WIN32
nuclear@0 268 OVR_DEBUG_LOG(("Setting up display shim"));
nuclear@0 269
nuclear@0 270 // Initialize the display shim before reporting the display to the user code
nuclear@0 271 // so that this will happen before the D3D display object is created.
nuclear@0 272 Win32::DisplayShim::GetInstance().Update(&hinfo.ShimInfo);
nuclear@0 273 #endif
nuclear@0 274
nuclear@0 275 Ptr<Profile> pDefaultProfile = *ProfileManager::GetInstance()->GetDefaultUserProfile(&hinfo);
nuclear@0 276 OVR_DEBUG_LOG(("Using profile %s", pDefaultProfile->GetValue(OVR_KEY_USER)));
nuclear@0 277
nuclear@0 278 HMDState* hmds = new HMDState(netInfo, hinfo, pDefaultProfile, client);
nuclear@0 279
nuclear@0 280 if (!hmds->SharedStateReader.Open(netInfo.SharedMemoryName.ToCStr()))
nuclear@0 281 {
nuclear@0 282 delete hmds;
nuclear@0 283 return NULL;
nuclear@0 284 }
nuclear@0 285
nuclear@0 286 hmds->TheSensorStateReader.SetUpdater(hmds->SharedStateReader.Get());
nuclear@0 287 hmds->TheLatencyTestStateReader.SetUpdater(hmds->SharedStateReader.Get());
nuclear@0 288
nuclear@0 289 return hmds;
nuclear@0 290 }
nuclear@0 291
nuclear@0 292 HMDState* HMDState::CreateHMDState(ovrHmdType hmdType)
nuclear@0 293 {
nuclear@0 294 HmdTypeEnum t = HmdType_None;
nuclear@0 295 if (hmdType == ovrHmd_DK1)
nuclear@0 296 t = HmdType_DK1;
nuclear@0 297 else if (hmdType == ovrHmd_DK2)
nuclear@0 298 t = HmdType_DK2;
nuclear@0 299
nuclear@0 300 // FIXME: This does not actually grab the right user..
nuclear@0 301 Ptr<Profile> pDefaultProfile = *ProfileManager::GetInstance()->GetDefaultProfile(t);
nuclear@0 302
nuclear@0 303 return new HMDState(CreateDebugHMDInfo(t), pDefaultProfile);
nuclear@0 304 }
nuclear@0 305
nuclear@0 306
nuclear@0 307 const OVR::List<HMDState>& HMDState::GetHMDStateList()
nuclear@0 308 {
nuclear@0 309 return hmdStateList;
nuclear@0 310 }
nuclear@0 311
nuclear@0 312
nuclear@0 313 //-------------------------------------------------------------------------------------
nuclear@0 314 // *** Sensor
nuclear@0 315
nuclear@0 316 bool HMDState::ConfigureTracking(unsigned supportedCaps, unsigned requiredCaps)
nuclear@0 317 {
nuclear@0 318 return pClient ? pClient->Hmd_ConfigureTracking(NetId, supportedCaps, requiredCaps) : true;
nuclear@0 319 }
nuclear@0 320
nuclear@0 321 void HMDState::ResetTracking()
nuclear@0 322 {
nuclear@0 323 if (pClient) pClient->Hmd_ResetTracking(NetId);
nuclear@0 324 }
nuclear@0 325
nuclear@0 326 // Re-center the orientation.
nuclear@0 327 void HMDState::RecenterPose()
nuclear@0 328 {
nuclear@0 329 TheSensorStateReader.RecenterPose();
nuclear@0 330 }
nuclear@0 331
nuclear@0 332 // Returns prediction for time.
nuclear@0 333 ovrTrackingState HMDState::PredictedTrackingState(double absTime)
nuclear@0 334 {
nuclear@0 335 Tracking::TrackingState ss;
nuclear@0 336 TheSensorStateReader.GetSensorStateAtTime(absTime, ss);
nuclear@0 337
nuclear@0 338 // Zero out the status flags
nuclear@0 339 if (!pClient || !pClient->IsConnected(false, false))
nuclear@0 340 {
nuclear@0 341 ss.StatusFlags = 0;
nuclear@0 342 }
nuclear@0 343
nuclear@0 344 return ss;
nuclear@0 345 }
nuclear@0 346
nuclear@0 347 void HMDState::SetEnabledHmdCaps(unsigned hmdCaps)
nuclear@0 348 {
nuclear@0 349 if (OurHMDInfo.HmdType < HmdType_DK2)
nuclear@0 350 {
nuclear@0 351 // disable low persistence and pentile.
nuclear@0 352 hmdCaps &= ~ovrHmdCap_LowPersistence;
nuclear@0 353 hmdCaps &= ~ovrHmdCap_DirectPentile;
nuclear@0 354
nuclear@0 355 // disable dynamic prediction using the internal latency tester
nuclear@0 356 hmdCaps &= ~ovrHmdCap_DynamicPrediction;
nuclear@0 357 }
nuclear@0 358
nuclear@0 359 if (OurHMDInfo.HmdType >= HmdType_DK2)
nuclear@0 360 {
nuclear@0 361 if ((EnabledHmdCaps ^ hmdCaps) & ovrHmdCap_DynamicPrediction)
nuclear@0 362 {
nuclear@0 363 // DynamicPrediction change
nuclear@0 364 TimeManager.ResetFrameTiming(TimeManager.GetFrameTiming().FrameIndex,
nuclear@0 365 (hmdCaps & ovrHmdCap_DynamicPrediction) ? true : false,
nuclear@0 366 RenderingConfigured);
nuclear@0 367 }
nuclear@0 368 }
nuclear@0 369
nuclear@0 370 // Pentile unsupported on everything right now.
nuclear@0 371 hmdCaps &= ~ovrHmdCap_DirectPentile;
nuclear@0 372
nuclear@0 373 if ((EnabledHmdCaps ^ hmdCaps) & ovrHmdCap_NoVSync)
nuclear@0 374 {
nuclear@0 375 TimeManager.SetVsync((hmdCaps & ovrHmdCap_NoVSync) ? false : true);
nuclear@0 376 }
nuclear@0 377
nuclear@0 378 if ((EnabledHmdCaps ^ hmdCaps) & ovrHmdCap_NoMirrorToWindow)
nuclear@0 379 {
nuclear@0 380 #ifdef OVR_OS_WIN32
nuclear@0 381 Win32::DisplayShim::GetInstance().UseMirroring = (hmdCaps & ovrHmdCap_NoMirrorToWindow) ?
nuclear@0 382 false : true;
nuclear@0 383 if (pWindow)
nuclear@0 384 { // Force window repaint so that stale mirrored image doesn't persist.
nuclear@0 385 ::InvalidateRect((HWND)pWindow, 0, true);
nuclear@0 386 }
nuclear@0 387 #endif
nuclear@0 388 }
nuclear@0 389
nuclear@0 390 // TBD: Should this include be only the rendering flags? Otherwise, bits that failed
nuclear@0 391 // modification in Hmd_SetEnabledCaps may mis-match...
nuclear@0 392 EnabledHmdCaps = hmdCaps & ovrHmdCap_Writable_Mask;
nuclear@0 393 RenderState.EnabledHmdCaps = EnabledHmdCaps;
nuclear@0 394
nuclear@0 395
nuclear@0 396 // If any of the modifiable service caps changed, call on the service.
nuclear@0 397 unsigned prevServiceCaps = EnabledServiceHmdCaps & ovrHmdCap_Writable_Mask;
nuclear@0 398 unsigned newServiceCaps = hmdCaps & ovrHmdCap_Writable_Mask & ovrHmdCap_Service_Mask;
nuclear@0 399
nuclear@0 400 if (prevServiceCaps ^ newServiceCaps)
nuclear@0 401 {
nuclear@0 402 EnabledServiceHmdCaps = pClient ? pClient->Hmd_SetEnabledCaps(NetId, newServiceCaps)
nuclear@0 403 : newServiceCaps;
nuclear@0 404 }
nuclear@0 405 }
nuclear@0 406
nuclear@0 407
nuclear@0 408 unsigned HMDState::SetEnabledHmdCaps()
nuclear@0 409 {
nuclear@0 410 unsigned serviceCaps = pClient ? pClient->Hmd_GetEnabledCaps(NetId) :
nuclear@0 411 EnabledServiceHmdCaps;
nuclear@0 412
nuclear@0 413 return serviceCaps & ((~ovrHmdCap_Service_Mask) | EnabledHmdCaps);
nuclear@0 414 }
nuclear@0 415
nuclear@0 416
nuclear@0 417 //-------------------------------------------------------------------------------------
nuclear@0 418 // ***** Property Access
nuclear@0 419
nuclear@0 420 // FIXME: Remove the EGetBoolValue stuff and do it with a "Server:" prefix, so we do not
nuclear@0 421 // need to keep a white-list of keys. This is also way cool because it allows us to add
nuclear@0 422 // new settings keys from outside CAPI that can modify internal server data.
nuclear@0 423
nuclear@0 424 bool HMDState::getBoolValue(const char* propertyName, bool defaultVal)
nuclear@0 425 {
nuclear@0 426 if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetBoolValue, propertyName))
nuclear@0 427 {
nuclear@0 428 return NetClient::GetInstance()->GetBoolValue(GetNetId(), propertyName, defaultVal);
nuclear@0 429 }
nuclear@0 430 else if (pProfile)
nuclear@0 431 {
nuclear@0 432 return pProfile->GetBoolValue(propertyName, defaultVal);
nuclear@0 433 }
nuclear@0 434 return defaultVal;
nuclear@0 435 }
nuclear@0 436
nuclear@0 437 bool HMDState::setBoolValue(const char* propertyName, bool value)
nuclear@0 438 {
nuclear@0 439 if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetBoolValue, propertyName))
nuclear@0 440 {
nuclear@0 441 return NetClient::GetInstance()->SetBoolValue(GetNetId(), propertyName, value);
nuclear@0 442 }
nuclear@0 443
nuclear@0 444 return false;
nuclear@0 445 }
nuclear@0 446
nuclear@0 447 int HMDState::getIntValue(const char* propertyName, int defaultVal)
nuclear@0 448 {
nuclear@0 449 if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetIntValue, propertyName))
nuclear@0 450 {
nuclear@0 451 return NetClient::GetInstance()->GetIntValue(GetNetId(), propertyName, defaultVal);
nuclear@0 452 }
nuclear@0 453 else if (pProfile)
nuclear@0 454 {
nuclear@0 455 return pProfile->GetIntValue(propertyName, defaultVal);
nuclear@0 456 }
nuclear@0 457 return defaultVal;
nuclear@0 458 }
nuclear@0 459
nuclear@0 460 bool HMDState::setIntValue(const char* propertyName, int value)
nuclear@0 461 {
nuclear@0 462 if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetIntValue, propertyName))
nuclear@0 463 {
nuclear@0 464 return NetClient::GetInstance()->SetIntValue(GetNetId(), propertyName, value);
nuclear@0 465 }
nuclear@0 466
nuclear@0 467 return false;
nuclear@0 468 }
nuclear@0 469
nuclear@0 470 float HMDState::getFloatValue(const char* propertyName, float defaultVal)
nuclear@0 471 {
nuclear@0 472 if (OVR_strcmp(propertyName, "LensSeparation") == 0)
nuclear@0 473 {
nuclear@0 474 return OurHMDInfo.LensSeparationInMeters;
nuclear@0 475 }
nuclear@0 476 else if (OVR_strcmp(propertyName, "VsyncToNextVsync") == 0)
nuclear@0 477 {
nuclear@0 478 return OurHMDInfo.Shutter.VsyncToNextVsync;
nuclear@0 479 }
nuclear@0 480 else if (OVR_strcmp(propertyName, "PixelPersistence") == 0)
nuclear@0 481 {
nuclear@0 482 return OurHMDInfo.Shutter.PixelPersistence;
nuclear@0 483 }
nuclear@0 484 else if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetNumberValue, propertyName))
nuclear@0 485 {
nuclear@0 486 return (float)NetClient::GetInstance()->GetNumberValue(GetNetId(), propertyName, defaultVal);
nuclear@0 487 }
nuclear@0 488 else if (pProfile)
nuclear@0 489 {
nuclear@0 490 return pProfile->GetFloatValue(propertyName, defaultVal);
nuclear@0 491 }
nuclear@0 492
nuclear@0 493 return defaultVal;
nuclear@0 494 }
nuclear@0 495
nuclear@0 496 bool HMDState::setFloatValue(const char* propertyName, float value)
nuclear@0 497 {
nuclear@0 498 if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetNumberValue, propertyName))
nuclear@0 499 {
nuclear@0 500 return NetClient::GetInstance()->SetNumberValue(GetNetId(), propertyName, value);
nuclear@0 501 }
nuclear@0 502
nuclear@0 503 return false;
nuclear@0 504 }
nuclear@0 505
nuclear@0 506 static unsigned CopyFloatArrayWithLimit(float dest[], unsigned destSize,
nuclear@0 507 float source[], unsigned sourceSize)
nuclear@0 508 {
nuclear@0 509 unsigned count = Alg::Min(destSize, sourceSize);
nuclear@0 510 for (unsigned i = 0; i < count; i++)
nuclear@0 511 dest[i] = source[i];
nuclear@0 512 return count;
nuclear@0 513 }
nuclear@0 514
nuclear@0 515 unsigned HMDState::getFloatArray(const char* propertyName, float values[], unsigned arraySize)
nuclear@0 516 {
nuclear@0 517 if (arraySize)
nuclear@0 518 {
nuclear@0 519 if (OVR_strcmp(propertyName, "ScreenSize") == 0)
nuclear@0 520 {
nuclear@0 521 float data[2] = { OurHMDInfo.ScreenSizeInMeters.w, OurHMDInfo.ScreenSizeInMeters.h };
nuclear@0 522
nuclear@0 523 return CopyFloatArrayWithLimit(values, arraySize, data, 2);
nuclear@0 524 }
nuclear@0 525 else if (OVR_strcmp(propertyName, "DistortionClearColor") == 0)
nuclear@0 526 {
nuclear@0 527 return CopyFloatArrayWithLimit(values, arraySize, RenderState.ClearColor, 4);
nuclear@0 528 }
nuclear@0 529 else if (OVR_strcmp(propertyName, "DK2Latency") == 0)
nuclear@0 530 {
nuclear@0 531 if (OurHMDInfo.HmdType != HmdType_DK2)
nuclear@0 532 {
nuclear@0 533 return 0;
nuclear@0 534 }
nuclear@0 535
nuclear@0 536 union {
nuclear@0 537 struct X {
nuclear@0 538 float latencyRender, latencyTimewarp, latencyPostPresent;
nuclear@0 539 } x;
nuclear@0 540 float data[3];
nuclear@0 541 } m;
nuclear@0 542
nuclear@0 543 static_assert(sizeof(m.x)==sizeof(m.data), "sizeof(struct X) failure");
nuclear@0 544
nuclear@0 545 TimeManager.GetLatencyTimings(m.x.latencyRender, m.x.latencyTimewarp, m.x.latencyPostPresent);
nuclear@0 546
nuclear@0 547 return CopyFloatArrayWithLimit(values, arraySize, m.data, 3);
nuclear@0 548 }
nuclear@0 549 else if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetNumberValues, propertyName))
nuclear@0 550 {
nuclear@0 551 // Convert floats to doubles
nuclear@0 552 double* da = new double[arraySize];
nuclear@0 553 for (int i = 0; i < (int)arraySize; ++i)
nuclear@0 554 {
nuclear@0 555 da[i] = values[i];
nuclear@0 556 }
nuclear@0 557
nuclear@0 558 int count = NetClient::GetInstance()->GetNumberValues(GetNetId(), propertyName, da, (int)arraySize);
nuclear@0 559
nuclear@0 560 for (int i = 0; i < count; ++i)
nuclear@0 561 {
nuclear@0 562 values[i] = (float)da[i];
nuclear@0 563 }
nuclear@0 564
nuclear@0 565 delete[] da;
nuclear@0 566
nuclear@0 567 return count;
nuclear@0 568 }
nuclear@0 569 else if (pProfile)
nuclear@0 570 {
nuclear@0 571 // TBD: Not quite right. Should update profile interface, so that
nuclear@0 572 // we can return 0 in all conditions if property doesn't exist.
nuclear@0 573
nuclear@0 574 return pProfile->GetFloatValues(propertyName, values, arraySize);
nuclear@0 575 }
nuclear@0 576 }
nuclear@0 577
nuclear@0 578 return 0;
nuclear@0 579 }
nuclear@0 580
nuclear@0 581 bool HMDState::setFloatArray(const char* propertyName, float values[], unsigned arraySize)
nuclear@0 582 {
nuclear@0 583 if (!arraySize)
nuclear@0 584 {
nuclear@0 585 return false;
nuclear@0 586 }
nuclear@0 587
nuclear@0 588 if (OVR_strcmp(propertyName, "DistortionClearColor") == 0)
nuclear@0 589 {
nuclear@0 590 CopyFloatArrayWithLimit(RenderState.ClearColor, 4, values, arraySize);
nuclear@0 591 return true;
nuclear@0 592 }
nuclear@0 593
nuclear@0 594 if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetNumberValues, propertyName))
nuclear@0 595 {
nuclear@0 596 double* da = new double[arraySize];
nuclear@0 597 for (int i = 0; i < (int)arraySize; ++i)
nuclear@0 598 {
nuclear@0 599 da[i] = values[i];
nuclear@0 600 }
nuclear@0 601
nuclear@0 602 bool result = NetClient::GetInstance()->SetNumberValues(GetNetId(), propertyName, da, arraySize);
nuclear@0 603
nuclear@0 604 delete[] da;
nuclear@0 605
nuclear@0 606 return result;
nuclear@0 607 }
nuclear@0 608
nuclear@0 609 return false;
nuclear@0 610 }
nuclear@0 611
nuclear@0 612 const char* HMDState::getString(const char* propertyName, const char* defaultVal)
nuclear@0 613 {
nuclear@0 614 if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetStringValue, propertyName))
nuclear@0 615 {
nuclear@0 616 return NetClient::GetInstance()->GetStringValue(GetNetId(), propertyName, defaultVal);
nuclear@0 617 }
nuclear@0 618
nuclear@0 619 if (pProfile)
nuclear@0 620 {
nuclear@0 621 LastGetStringValue[0] = 0;
nuclear@0 622 if (pProfile->GetValue(propertyName, LastGetStringValue, sizeof(LastGetStringValue)))
nuclear@0 623 {
nuclear@0 624 return LastGetStringValue;
nuclear@0 625 }
nuclear@0 626 }
nuclear@0 627
nuclear@0 628 return defaultVal;
nuclear@0 629 }
nuclear@0 630
nuclear@0 631 bool HMDState::setString(const char* propertyName, const char* value)
nuclear@0 632 {
nuclear@0 633 if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetStringValue, propertyName))
nuclear@0 634 {
nuclear@0 635 return NetClient::GetInstance()->SetStringValue(GetNetId(), propertyName, value);
nuclear@0 636 }
nuclear@0 637
nuclear@0 638 return false;
nuclear@0 639 }
nuclear@0 640
nuclear@0 641
nuclear@0 642 //-------------------------------------------------------------------------------------
nuclear@0 643 // *** Latency Test
nuclear@0 644
nuclear@0 645 bool HMDState::ProcessLatencyTest(unsigned char rgbColorOut[3])
nuclear@0 646 {
nuclear@0 647 return NetClient::GetInstance()->LatencyUtil_ProcessInputs(Timer::GetSeconds(), rgbColorOut);
nuclear@0 648 }
nuclear@0 649
nuclear@0 650 //-------------------------------------------------------------------------------------
nuclear@0 651 // *** Rendering
nuclear@0 652
nuclear@0 653 bool HMDState::ConfigureRendering(ovrEyeRenderDesc eyeRenderDescOut[2],
nuclear@0 654 const ovrFovPort eyeFovIn[2],
nuclear@0 655 const ovrRenderAPIConfig* apiConfig,
nuclear@0 656 unsigned distortionCaps)
nuclear@0 657 {
nuclear@0 658 ThreadChecker::Scope checkScope(&RenderAPIThreadChecker, "ovrHmd_ConfigureRendering");
nuclear@0 659
nuclear@0 660 // null -> shut down.
nuclear@0 661 if (!apiConfig)
nuclear@0 662 {
nuclear@0 663 if (pHSWDisplay)
nuclear@0 664 {
nuclear@0 665 pHSWDisplay->Shutdown();
nuclear@0 666 pHSWDisplay.Clear();
nuclear@0 667 }
nuclear@0 668
nuclear@0 669 if (pRenderer)
nuclear@0 670 pRenderer.Clear();
nuclear@0 671 RenderingConfigured = false;
nuclear@0 672 return true;
nuclear@0 673 }
nuclear@0 674
nuclear@0 675 if (pRenderer &&
nuclear@0 676 (apiConfig->Header.API != pRenderer->GetRenderAPI()))
nuclear@0 677 {
nuclear@0 678 // Shutdown old renderer.
nuclear@0 679 if (pHSWDisplay)
nuclear@0 680 {
nuclear@0 681 pHSWDisplay->Shutdown();
nuclear@0 682 pHSWDisplay.Clear();
nuclear@0 683 }
nuclear@0 684
nuclear@0 685 if (pRenderer)
nuclear@0 686 pRenderer.Clear();
nuclear@0 687 }
nuclear@0 688
nuclear@0 689 distortionCaps = distortionCaps & pHmdDesc->DistortionCaps;
nuclear@0 690
nuclear@0 691 // Step 1: do basic setup configuration
nuclear@0 692 RenderState.EnabledHmdCaps = EnabledHmdCaps; // This is a copy... Any cleaner way?
nuclear@0 693 RenderState.DistortionCaps = distortionCaps;
nuclear@0 694 RenderState.EyeRenderDesc[0] = RenderState.CalcRenderDesc(ovrEye_Left, eyeFovIn[0]);
nuclear@0 695 RenderState.EyeRenderDesc[1] = RenderState.CalcRenderDesc(ovrEye_Right, eyeFovIn[1]);
nuclear@0 696 eyeRenderDescOut[0] = RenderState.EyeRenderDesc[0];
nuclear@0 697 eyeRenderDescOut[1] = RenderState.EyeRenderDesc[1];
nuclear@0 698
nuclear@0 699 TimeManager.ResetFrameTiming(0,
nuclear@0 700 (EnabledHmdCaps & ovrHmdCap_DynamicPrediction) ? true : false,
nuclear@0 701 true);
nuclear@0 702
nuclear@0 703 LastFrameTimeSeconds = 0.0f;
nuclear@0 704
nuclear@0 705 // Set RenderingConfigured early to avoid ASSERTs in renderer initialization.
nuclear@0 706 RenderingConfigured = true;
nuclear@0 707
nuclear@0 708 if (!pRenderer)
nuclear@0 709 {
nuclear@0 710 pRenderer = *DistortionRenderer::APICreateRegistry
nuclear@0 711 [apiConfig->Header.API](pHmdDesc, TimeManager, RenderState);
nuclear@0 712 }
nuclear@0 713
nuclear@0 714 if (!pRenderer ||
nuclear@0 715 !pRenderer->Initialize(apiConfig))
nuclear@0 716 {
nuclear@0 717 RenderingConfigured = false;
nuclear@0 718 return false;
nuclear@0 719 }
nuclear@0 720
nuclear@0 721 // Setup the Health and Safety Warning display system.
nuclear@0 722 if(pHSWDisplay && (pHSWDisplay->GetRenderAPIType() != apiConfig->Header.API)) // If we need to reconstruct the HSWDisplay for a different graphics API type, delete the existing display.
nuclear@0 723 {
nuclear@0 724 pHSWDisplay->Shutdown();
nuclear@0 725 pHSWDisplay.Clear();
nuclear@0 726 }
nuclear@0 727
nuclear@0 728 if(!pHSWDisplay) // Use * below because that for of operator= causes it to inherit the refcount the factory gave the object.
nuclear@0 729 {
nuclear@0 730 pHSWDisplay = *OVR::CAPI::HSWDisplay::Factory(apiConfig->Header.API, pHmdDesc, RenderState);
nuclear@0 731 pHSWDisplay->Enable(pProfile->GetBoolValue("HSW", true));
nuclear@0 732 }
nuclear@0 733
nuclear@0 734 if (pHSWDisplay)
nuclear@0 735 pHSWDisplay->Initialize(apiConfig); // This is potentially re-initializing it with a new config.
nuclear@0 736
nuclear@0 737 return true;
nuclear@0 738 }
nuclear@0 739
nuclear@0 740
nuclear@0 741 void HMDState::SubmitEyeTextures(const ovrPosef renderPose[2],
nuclear@0 742 const ovrTexture eyeTexture[2])
nuclear@0 743 {
nuclear@0 744 RenderState.EyeRenderPoses[0] = renderPose[0];
nuclear@0 745 RenderState.EyeRenderPoses[1] = renderPose[1];
nuclear@0 746
nuclear@0 747 if (pRenderer)
nuclear@0 748 {
nuclear@0 749 pRenderer->SubmitEye(0, &eyeTexture[0]);
nuclear@0 750 pRenderer->SubmitEye(1, &eyeTexture[1]);
nuclear@0 751 }
nuclear@0 752 }
nuclear@0 753
nuclear@0 754
nuclear@0 755 // I appreciate this is not an idea place for this function, but it didn't seem to be
nuclear@0 756 // being linked properly when in OVR_CAPI.cpp.
nuclear@0 757 // Please relocate if you know of a better place
nuclear@0 758 ovrBool ovrHmd_CreateDistortionMeshInternal( ovrHmdStruct * hmd,
nuclear@0 759 ovrEyeType eyeType, ovrFovPort fov,
nuclear@0 760 unsigned int distortionCaps,
nuclear@0 761 ovrDistortionMesh *meshData,
nuclear@0 762 float overrideEyeReliefIfNonZero )
nuclear@0 763 {
nuclear@0 764 if (!meshData)
nuclear@0 765 return 0;
nuclear@0 766 HMDState* hmds = (HMDState*)hmd;
nuclear@0 767
nuclear@0 768 // Not used now, but Chromatic flag or others could possibly be checked for in the future.
nuclear@0 769 OVR_UNUSED1(distortionCaps);
nuclear@0 770
nuclear@0 771 #if defined (OVR_CC_MSVC)
nuclear@0 772 static_assert(sizeof(DistortionMeshVertexData) == sizeof(ovrDistortionVertex), "DistortionMeshVertexData size mismatch");
nuclear@0 773 #endif
nuclear@0 774
nuclear@0 775 // *** Calculate a part of "StereoParams" needed for mesh generation
nuclear@0 776
nuclear@0 777 // Note that mesh distortion generation is invariant of RenderTarget UVs, allowing
nuclear@0 778 // render target size and location to be changed after the fact dynamically.
nuclear@0 779 // eyeToSourceUV is computed here for convenience, so that users don't need
nuclear@0 780 // to call ovrHmd_GetRenderScaleAndOffset unless changing RT dynamically.
nuclear@0 781
nuclear@0 782 const HmdRenderInfo& hmdri = hmds->RenderState.RenderInfo;
nuclear@0 783 StereoEye stereoEye = (eyeType == ovrEye_Left) ? StereoEye_Left : StereoEye_Right;
nuclear@0 784
nuclear@0 785 DistortionRenderDesc& distortion = hmds->RenderState.Distortion[eyeType];
nuclear@0 786 if (overrideEyeReliefIfNonZero)
nuclear@0 787 {
nuclear@0 788 distortion.Lens = GenerateLensConfigFromEyeRelief(overrideEyeReliefIfNonZero,hmdri);
nuclear@0 789 }
nuclear@0 790
nuclear@0 791 // Find the mapping from TanAngle space to target NDC space.
nuclear@0 792 ScaleAndOffset2D eyeToSourceNDC = CreateNDCScaleAndOffsetFromFov(fov);
nuclear@0 793
nuclear@0 794 int triangleCount = 0;
nuclear@0 795 int vertexCount = 0;
nuclear@0 796
nuclear@0 797 DistortionMeshCreate((DistortionMeshVertexData**)&meshData->pVertexData,
nuclear@0 798 (uint16_t**)&meshData->pIndexData,
nuclear@0 799 &vertexCount, &triangleCount,
nuclear@0 800 (stereoEye == StereoEye_Right),
nuclear@0 801 hmdri, distortion, eyeToSourceNDC);
nuclear@0 802
nuclear@0 803 if (meshData->pVertexData)
nuclear@0 804 {
nuclear@0 805 // Convert to index
nuclear@0 806 meshData->IndexCount = triangleCount * 3;
nuclear@0 807 meshData->VertexCount = vertexCount;
nuclear@0 808 return 1;
nuclear@0 809 }
nuclear@0 810
nuclear@0 811 return 0;
nuclear@0 812 }
nuclear@0 813
nuclear@0 814
nuclear@0 815
nuclear@0 816 }} // namespace OVR::CAPI