ovr_sdk
diff 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 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/LibOVR/Src/CAPI/CAPI_HMDState.cpp Wed Jan 14 06:51:16 2015 +0200 1.3 @@ -0,0 +1,816 @@ 1.4 +/************************************************************************************ 1.5 + 1.6 +Filename : CAPI_HMDState.cpp 1.7 +Content : State associated with a single HMD 1.8 +Created : January 24, 2014 1.9 +Authors : Michael Antonov 1.10 + 1.11 +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. 1.12 + 1.13 +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); 1.14 +you may not use the Oculus VR Rift SDK except in compliance with the License, 1.15 +which is provided at the time of installation or download, or which 1.16 +otherwise accompanies this software in either electronic or hard copy form. 1.17 + 1.18 +You may obtain a copy of the License at 1.19 + 1.20 +http://www.oculusvr.com/licenses/LICENSE-3.2 1.21 + 1.22 +Unless required by applicable law or agreed to in writing, the Oculus VR SDK 1.23 +distributed under the License is distributed on an "AS IS" BASIS, 1.24 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.25 +See the License for the specific language governing permissions and 1.26 +limitations under the License. 1.27 + 1.28 +************************************************************************************/ 1.29 + 1.30 +#include "CAPI_HMDState.h" 1.31 +#include "../OVR_Profile.h" 1.32 +#include "../Service/Service_NetClient.h" 1.33 +#ifdef OVR_OS_WIN32 1.34 +#include "../Displays/OVR_Win32_ShimFunctions.h" 1.35 +#endif 1.36 + 1.37 + 1.38 +namespace OVR { namespace CAPI { 1.39 + 1.40 + 1.41 +// Accessed via HMDState::GetHMDStateList() 1.42 +static OVR::List<HMDState> hmdStateList; // List of all created HMDStates. 1.43 + 1.44 + 1.45 +//------------------------------------------------------------------------------------- 1.46 +// ***** HMDState 1.47 + 1.48 +HMDState::HMDState(const OVR::Service::HMDNetworkInfo& netInfo, 1.49 + const OVR::HMDInfo& hmdInfo, 1.50 + Profile* profile, 1.51 + Service::NetClient* client) : 1.52 + pProfile(profile), 1.53 + pHmdDesc(0), 1.54 + pWindow(0), 1.55 + pClient(client), 1.56 + NetId(netInfo.NetId), 1.57 + NetInfo(netInfo), 1.58 + OurHMDInfo(hmdInfo), 1.59 + pLastError(NULL), 1.60 + EnabledHmdCaps(0), 1.61 + EnabledServiceHmdCaps(0), 1.62 + SharedStateReader(), 1.63 + TheSensorStateReader(), 1.64 + TheLatencyTestStateReader(), 1.65 + LatencyTestActive(false), 1.66 + //LatencyTestDrawColor(), 1.67 + LatencyTest2Active(false), 1.68 + //LatencyTest2DrawColor(), 1.69 + TimeManager(true), 1.70 + RenderState(), 1.71 + pRenderer(), 1.72 + pHSWDisplay(), 1.73 + LastFrameTimeSeconds(0.), 1.74 + LastGetFrameTimeSeconds(0.), 1.75 + //LastGetStringValue(), 1.76 + RenderingConfigured(false), 1.77 + BeginFrameCalled(false), 1.78 + BeginFrameThreadId(), 1.79 + RenderAPIThreadChecker(), 1.80 + BeginFrameTimingCalled(false) 1.81 +{ 1.82 + sharedInit(profile); 1.83 + hmdStateList.PushBack(this); 1.84 +} 1.85 + 1.86 + 1.87 +HMDState::HMDState(const OVR::HMDInfo& hmdInfo, Profile* profile) : 1.88 + pProfile(profile), 1.89 + pHmdDesc(0), 1.90 + pWindow(0), 1.91 + pClient(0), 1.92 + NetId(InvalidVirtualHmdId), 1.93 + NetInfo(), 1.94 + OurHMDInfo(hmdInfo), 1.95 + pLastError(NULL), 1.96 + EnabledHmdCaps(0), 1.97 + EnabledServiceHmdCaps(0), 1.98 + SharedStateReader(), 1.99 + TheSensorStateReader(), 1.100 + TheLatencyTestStateReader(), 1.101 + LatencyTestActive(false), 1.102 + //LatencyTestDrawColor(), 1.103 + LatencyTest2Active(false), 1.104 + //LatencyTest2DrawColor(), 1.105 + TimeManager(true), 1.106 + RenderState(), 1.107 + pRenderer(), 1.108 + pHSWDisplay(), 1.109 + LastFrameTimeSeconds(0.), 1.110 + LastGetFrameTimeSeconds(0.), 1.111 + //LastGetStringValue(), 1.112 + RenderingConfigured(false), 1.113 + BeginFrameCalled(false), 1.114 + BeginFrameThreadId(), 1.115 + RenderAPIThreadChecker(), 1.116 + BeginFrameTimingCalled(false) 1.117 +{ 1.118 + sharedInit(profile); 1.119 + hmdStateList.PushBack(this); 1.120 +} 1.121 + 1.122 +HMDState::~HMDState() 1.123 +{ 1.124 + hmdStateList.Remove(this); 1.125 + 1.126 + if (pClient) 1.127 + { 1.128 + pClient->Hmd_Release(NetId); 1.129 + pClient = 0; 1.130 + } 1.131 + 1.132 + ConfigureRendering(0,0,0,0); 1.133 + 1.134 + if (pHmdDesc) 1.135 + { 1.136 + OVR_FREE(pHmdDesc); 1.137 + pHmdDesc = NULL; 1.138 + } 1.139 +} 1.140 + 1.141 +void HMDState::sharedInit(Profile* profile) 1.142 +{ 1.143 + // TBD: We should probably be looking up the default profile for the given 1.144 + // device type + user if profile == 0. 1.145 + pLastError = 0; 1.146 + 1.147 + RenderState.OurHMDInfo = OurHMDInfo; 1.148 + 1.149 + UpdateRenderProfile(profile); 1.150 + 1.151 + OVR_ASSERT(!pHmdDesc); 1.152 + pHmdDesc = (ovrHmdDesc*)OVR_ALLOC(sizeof(ovrHmdDesc)); 1.153 + *pHmdDesc = RenderState.GetDesc(); 1.154 + pHmdDesc->Handle = this; 1.155 + 1.156 + RenderState.ClearColor[0] = 0.0f; 1.157 + RenderState.ClearColor[1] = 0.0f; 1.158 + RenderState.ClearColor[2] = 0.0f; 1.159 + RenderState.ClearColor[3] = 0.0f; 1.160 + 1.161 + RenderState.EnabledHmdCaps = 0; 1.162 + 1.163 + TimeManager.Init(RenderState.RenderInfo); 1.164 + 1.165 + /* 1.166 + LatencyTestDrawColor[0] = 0; 1.167 + LatencyTestDrawColor[1] = 0; 1.168 + LatencyTestDrawColor[2] = 0; 1.169 + */ 1.170 + 1.171 + RenderingConfigured = false; 1.172 + BeginFrameCalled = false; 1.173 + BeginFrameThreadId = 0; 1.174 + BeginFrameTimingCalled = false; 1.175 + 1.176 + // Construct the HSWDisplay. We will later reconstruct it with a specific ovrRenderAPI type if the application starts using SDK-based rendering. 1.177 + if(!pHSWDisplay) 1.178 + { 1.179 + pHSWDisplay = *OVR::CAPI::HSWDisplay::Factory(ovrRenderAPI_None, pHmdDesc, RenderState); 1.180 + pHSWDisplay->Enable(pProfile->GetBoolValue("HSW", true)); 1.181 + } 1.182 +} 1.183 + 1.184 +static Vector3f GetNeckModelFromProfile(Profile* profile) 1.185 +{ 1.186 + OVR_ASSERT(profile); 1.187 + 1.188 + float neckeye[2] = { OVR_DEFAULT_NECK_TO_EYE_HORIZONTAL, OVR_DEFAULT_NECK_TO_EYE_VERTICAL }; 1.189 + profile->GetFloatValues(OVR_KEY_NECK_TO_EYE_DISTANCE, neckeye, 2); 1.190 + 1.191 + // Make sure these are vaguely sensible values. 1.192 + //OVR_ASSERT((neckeye[0] > 0.05f) && (neckeye[0] < 0.5f)); 1.193 + //OVR_ASSERT((neckeye[1] > 0.05f) && (neckeye[1] < 0.5f)); 1.194 + 1.195 + // Named for clarity 1.196 + float NeckToEyeHorizontal = neckeye[0]; 1.197 + float NeckToEyeVertical = neckeye[1]; 1.198 + 1.199 + // Store the neck model 1.200 + return Vector3f(0.0, NeckToEyeVertical, -NeckToEyeHorizontal); 1.201 +} 1.202 + 1.203 +static float GetCenterPupilDepthFromRenderInfo(HmdRenderInfo* hmdRenderInfo) 1.204 +{ 1.205 + OVR_ASSERT(hmdRenderInfo); 1.206 + 1.207 + // Find the distance from the center of the screen to the "center eye" 1.208 + // This center eye is used by systems like rendering & audio to represent the player, 1.209 + // and they will handle the offsets needed from there to each actual eye. 1.210 + 1.211 + // HACK HACK HACK 1.212 + // We know for DK1 the screen->lens surface distance is roughly 0.049f, and that the faceplate->lens is 0.02357f. 1.213 + // We're going to assume(!!!!) that all HMDs have the same screen->faceplate distance. 1.214 + // Crystal Cove was measured to be roughly 0.025 screen->faceplate which agrees with this assumption. 1.215 + // TODO: do this properly! Update: Measured this at 0.02733 with a CC prototype, CES era (PT7), on 2/19/14 -Steve 1.216 + float screenCenterToMidplate = 0.02733f; 1.217 + float centerEyeRelief = hmdRenderInfo->GetEyeCenter().ReliefInMeters; 1.218 + float CenterPupilDepth = screenCenterToMidplate + hmdRenderInfo->LensSurfaceToMidplateInMeters + centerEyeRelief; 1.219 + 1.220 + return CenterPupilDepth; 1.221 +} 1.222 + 1.223 +void HMDState::UpdateRenderProfile(Profile* profile) 1.224 +{ 1.225 + // Apply the given profile to generate a render context 1.226 + RenderState.RenderInfo = GenerateHmdRenderInfoFromHmdInfo(RenderState.OurHMDInfo, profile); 1.227 + RenderState.Distortion[0] = CalculateDistortionRenderDesc(StereoEye_Left, RenderState.RenderInfo, 0); 1.228 + RenderState.Distortion[1] = CalculateDistortionRenderDesc(StereoEye_Right, RenderState.RenderInfo, 0); 1.229 + 1.230 + if (pClient) 1.231 + { 1.232 + // Center pupil depth 1.233 + float centerPupilDepth = GetCenterPupilDepthFromRenderInfo(&RenderState.RenderInfo); 1.234 + pClient->SetNumberValue(GetNetId(), "CenterPupilDepth", centerPupilDepth); 1.235 + 1.236 + // Neck model 1.237 + Vector3f neckModel = GetNeckModelFromProfile(profile); 1.238 + double neckModelArray[3] = { 1.239 + neckModel.x, 1.240 + neckModel.y, 1.241 + neckModel.z 1.242 + }; 1.243 + pClient->SetNumberValues(GetNetId(), "NeckModelVector3f", neckModelArray, 3); 1.244 + 1.245 + double camerastate[7]; 1.246 + if (profile->GetDoubleValues(OVR_KEY_CAMERA_POSITION, camerastate, 7) == 0) 1.247 + { 1.248 + //there is no value, so we load the default 1.249 + for (int i = 0; i < 7; i++) camerastate[i] = 0; 1.250 + camerastate[3] = 1;//no offset. by default, give the quaternion w component value 1 1.251 + } 1.252 + else 1.253 + 1.254 + TheSensorStateReader.setCenteredFromWorld(OVR::Posed::FromArray(camerastate)); 1.255 + } 1.256 + 1.257 + 1.258 +} 1.259 + 1.260 +HMDState* HMDState::CreateHMDState(NetClient* client, const HMDNetworkInfo& netInfo) 1.261 +{ 1.262 + // HMDState works through a handle to service HMD.... 1.263 + HMDInfo hinfo; 1.264 + if (!client->Hmd_GetHmdInfo(netInfo.NetId, &hinfo)) 1.265 + { 1.266 + OVR_DEBUG_LOG(("[HMDState] Unable to get HMD info")); 1.267 + return NULL; 1.268 + } 1.269 + 1.270 +#ifdef OVR_OS_WIN32 1.271 + OVR_DEBUG_LOG(("Setting up display shim")); 1.272 + 1.273 + // Initialize the display shim before reporting the display to the user code 1.274 + // so that this will happen before the D3D display object is created. 1.275 + Win32::DisplayShim::GetInstance().Update(&hinfo.ShimInfo); 1.276 +#endif 1.277 + 1.278 + Ptr<Profile> pDefaultProfile = *ProfileManager::GetInstance()->GetDefaultUserProfile(&hinfo); 1.279 + OVR_DEBUG_LOG(("Using profile %s", pDefaultProfile->GetValue(OVR_KEY_USER))); 1.280 + 1.281 + HMDState* hmds = new HMDState(netInfo, hinfo, pDefaultProfile, client); 1.282 + 1.283 + if (!hmds->SharedStateReader.Open(netInfo.SharedMemoryName.ToCStr())) 1.284 + { 1.285 + delete hmds; 1.286 + return NULL; 1.287 + } 1.288 + 1.289 + hmds->TheSensorStateReader.SetUpdater(hmds->SharedStateReader.Get()); 1.290 + hmds->TheLatencyTestStateReader.SetUpdater(hmds->SharedStateReader.Get()); 1.291 + 1.292 + return hmds; 1.293 +} 1.294 + 1.295 +HMDState* HMDState::CreateHMDState(ovrHmdType hmdType) 1.296 +{ 1.297 + HmdTypeEnum t = HmdType_None; 1.298 + if (hmdType == ovrHmd_DK1) 1.299 + t = HmdType_DK1; 1.300 + else if (hmdType == ovrHmd_DK2) 1.301 + t = HmdType_DK2; 1.302 + 1.303 + // FIXME: This does not actually grab the right user.. 1.304 + Ptr<Profile> pDefaultProfile = *ProfileManager::GetInstance()->GetDefaultProfile(t); 1.305 + 1.306 + return new HMDState(CreateDebugHMDInfo(t), pDefaultProfile); 1.307 +} 1.308 + 1.309 + 1.310 +const OVR::List<HMDState>& HMDState::GetHMDStateList() 1.311 +{ 1.312 + return hmdStateList; 1.313 +} 1.314 + 1.315 + 1.316 +//------------------------------------------------------------------------------------- 1.317 +// *** Sensor 1.318 + 1.319 +bool HMDState::ConfigureTracking(unsigned supportedCaps, unsigned requiredCaps) 1.320 +{ 1.321 + return pClient ? pClient->Hmd_ConfigureTracking(NetId, supportedCaps, requiredCaps) : true; 1.322 +} 1.323 + 1.324 +void HMDState::ResetTracking() 1.325 +{ 1.326 + if (pClient) pClient->Hmd_ResetTracking(NetId); 1.327 +} 1.328 + 1.329 +// Re-center the orientation. 1.330 +void HMDState::RecenterPose() 1.331 +{ 1.332 + TheSensorStateReader.RecenterPose(); 1.333 +} 1.334 + 1.335 +// Returns prediction for time. 1.336 +ovrTrackingState HMDState::PredictedTrackingState(double absTime) 1.337 +{ 1.338 + Tracking::TrackingState ss; 1.339 + TheSensorStateReader.GetSensorStateAtTime(absTime, ss); 1.340 + 1.341 + // Zero out the status flags 1.342 + if (!pClient || !pClient->IsConnected(false, false)) 1.343 + { 1.344 + ss.StatusFlags = 0; 1.345 + } 1.346 + 1.347 + return ss; 1.348 +} 1.349 + 1.350 +void HMDState::SetEnabledHmdCaps(unsigned hmdCaps) 1.351 +{ 1.352 + if (OurHMDInfo.HmdType < HmdType_DK2) 1.353 + { 1.354 + // disable low persistence and pentile. 1.355 + hmdCaps &= ~ovrHmdCap_LowPersistence; 1.356 + hmdCaps &= ~ovrHmdCap_DirectPentile; 1.357 + 1.358 + // disable dynamic prediction using the internal latency tester 1.359 + hmdCaps &= ~ovrHmdCap_DynamicPrediction; 1.360 + } 1.361 + 1.362 + if (OurHMDInfo.HmdType >= HmdType_DK2) 1.363 + { 1.364 + if ((EnabledHmdCaps ^ hmdCaps) & ovrHmdCap_DynamicPrediction) 1.365 + { 1.366 + // DynamicPrediction change 1.367 + TimeManager.ResetFrameTiming(TimeManager.GetFrameTiming().FrameIndex, 1.368 + (hmdCaps & ovrHmdCap_DynamicPrediction) ? true : false, 1.369 + RenderingConfigured); 1.370 + } 1.371 + } 1.372 + 1.373 + // Pentile unsupported on everything right now. 1.374 + hmdCaps &= ~ovrHmdCap_DirectPentile; 1.375 + 1.376 + if ((EnabledHmdCaps ^ hmdCaps) & ovrHmdCap_NoVSync) 1.377 + { 1.378 + TimeManager.SetVsync((hmdCaps & ovrHmdCap_NoVSync) ? false : true); 1.379 + } 1.380 + 1.381 + if ((EnabledHmdCaps ^ hmdCaps) & ovrHmdCap_NoMirrorToWindow) 1.382 + { 1.383 +#ifdef OVR_OS_WIN32 1.384 + Win32::DisplayShim::GetInstance().UseMirroring = (hmdCaps & ovrHmdCap_NoMirrorToWindow) ? 1.385 + false : true; 1.386 + if (pWindow) 1.387 + { // Force window repaint so that stale mirrored image doesn't persist. 1.388 + ::InvalidateRect((HWND)pWindow, 0, true); 1.389 + } 1.390 +#endif 1.391 + } 1.392 + 1.393 + // TBD: Should this include be only the rendering flags? Otherwise, bits that failed 1.394 + // modification in Hmd_SetEnabledCaps may mis-match... 1.395 + EnabledHmdCaps = hmdCaps & ovrHmdCap_Writable_Mask; 1.396 + RenderState.EnabledHmdCaps = EnabledHmdCaps; 1.397 + 1.398 + 1.399 + // If any of the modifiable service caps changed, call on the service. 1.400 + unsigned prevServiceCaps = EnabledServiceHmdCaps & ovrHmdCap_Writable_Mask; 1.401 + unsigned newServiceCaps = hmdCaps & ovrHmdCap_Writable_Mask & ovrHmdCap_Service_Mask; 1.402 + 1.403 + if (prevServiceCaps ^ newServiceCaps) 1.404 + { 1.405 + EnabledServiceHmdCaps = pClient ? pClient->Hmd_SetEnabledCaps(NetId, newServiceCaps) 1.406 + : newServiceCaps; 1.407 + } 1.408 +} 1.409 + 1.410 + 1.411 +unsigned HMDState::SetEnabledHmdCaps() 1.412 +{ 1.413 + unsigned serviceCaps = pClient ? pClient->Hmd_GetEnabledCaps(NetId) : 1.414 + EnabledServiceHmdCaps; 1.415 + 1.416 + return serviceCaps & ((~ovrHmdCap_Service_Mask) | EnabledHmdCaps); 1.417 +} 1.418 + 1.419 + 1.420 +//------------------------------------------------------------------------------------- 1.421 +// ***** Property Access 1.422 + 1.423 +// FIXME: Remove the EGetBoolValue stuff and do it with a "Server:" prefix, so we do not 1.424 +// need to keep a white-list of keys. This is also way cool because it allows us to add 1.425 +// new settings keys from outside CAPI that can modify internal server data. 1.426 + 1.427 +bool HMDState::getBoolValue(const char* propertyName, bool defaultVal) 1.428 +{ 1.429 + if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetBoolValue, propertyName)) 1.430 + { 1.431 + return NetClient::GetInstance()->GetBoolValue(GetNetId(), propertyName, defaultVal); 1.432 + } 1.433 + else if (pProfile) 1.434 + { 1.435 + return pProfile->GetBoolValue(propertyName, defaultVal); 1.436 + } 1.437 + return defaultVal; 1.438 +} 1.439 + 1.440 +bool HMDState::setBoolValue(const char* propertyName, bool value) 1.441 +{ 1.442 + if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetBoolValue, propertyName)) 1.443 + { 1.444 + return NetClient::GetInstance()->SetBoolValue(GetNetId(), propertyName, value); 1.445 + } 1.446 + 1.447 + return false; 1.448 +} 1.449 + 1.450 +int HMDState::getIntValue(const char* propertyName, int defaultVal) 1.451 +{ 1.452 + if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetIntValue, propertyName)) 1.453 + { 1.454 + return NetClient::GetInstance()->GetIntValue(GetNetId(), propertyName, defaultVal); 1.455 + } 1.456 + else if (pProfile) 1.457 + { 1.458 + return pProfile->GetIntValue(propertyName, defaultVal); 1.459 + } 1.460 + return defaultVal; 1.461 +} 1.462 + 1.463 +bool HMDState::setIntValue(const char* propertyName, int value) 1.464 +{ 1.465 + if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetIntValue, propertyName)) 1.466 + { 1.467 + return NetClient::GetInstance()->SetIntValue(GetNetId(), propertyName, value); 1.468 + } 1.469 + 1.470 + return false; 1.471 +} 1.472 + 1.473 +float HMDState::getFloatValue(const char* propertyName, float defaultVal) 1.474 +{ 1.475 + if (OVR_strcmp(propertyName, "LensSeparation") == 0) 1.476 + { 1.477 + return OurHMDInfo.LensSeparationInMeters; 1.478 + } 1.479 + else if (OVR_strcmp(propertyName, "VsyncToNextVsync") == 0) 1.480 + { 1.481 + return OurHMDInfo.Shutter.VsyncToNextVsync; 1.482 + } 1.483 + else if (OVR_strcmp(propertyName, "PixelPersistence") == 0) 1.484 + { 1.485 + return OurHMDInfo.Shutter.PixelPersistence; 1.486 + } 1.487 + else if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetNumberValue, propertyName)) 1.488 + { 1.489 + return (float)NetClient::GetInstance()->GetNumberValue(GetNetId(), propertyName, defaultVal); 1.490 + } 1.491 + else if (pProfile) 1.492 + { 1.493 + return pProfile->GetFloatValue(propertyName, defaultVal); 1.494 + } 1.495 + 1.496 + return defaultVal; 1.497 +} 1.498 + 1.499 +bool HMDState::setFloatValue(const char* propertyName, float value) 1.500 +{ 1.501 + if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetNumberValue, propertyName)) 1.502 + { 1.503 + return NetClient::GetInstance()->SetNumberValue(GetNetId(), propertyName, value); 1.504 + } 1.505 + 1.506 + return false; 1.507 +} 1.508 + 1.509 +static unsigned CopyFloatArrayWithLimit(float dest[], unsigned destSize, 1.510 + float source[], unsigned sourceSize) 1.511 +{ 1.512 + unsigned count = Alg::Min(destSize, sourceSize); 1.513 + for (unsigned i = 0; i < count; i++) 1.514 + dest[i] = source[i]; 1.515 + return count; 1.516 +} 1.517 + 1.518 +unsigned HMDState::getFloatArray(const char* propertyName, float values[], unsigned arraySize) 1.519 +{ 1.520 + if (arraySize) 1.521 + { 1.522 + if (OVR_strcmp(propertyName, "ScreenSize") == 0) 1.523 + { 1.524 + float data[2] = { OurHMDInfo.ScreenSizeInMeters.w, OurHMDInfo.ScreenSizeInMeters.h }; 1.525 + 1.526 + return CopyFloatArrayWithLimit(values, arraySize, data, 2); 1.527 + } 1.528 + else if (OVR_strcmp(propertyName, "DistortionClearColor") == 0) 1.529 + { 1.530 + return CopyFloatArrayWithLimit(values, arraySize, RenderState.ClearColor, 4); 1.531 + } 1.532 + else if (OVR_strcmp(propertyName, "DK2Latency") == 0) 1.533 + { 1.534 + if (OurHMDInfo.HmdType != HmdType_DK2) 1.535 + { 1.536 + return 0; 1.537 + } 1.538 + 1.539 + union { 1.540 + struct X { 1.541 + float latencyRender, latencyTimewarp, latencyPostPresent; 1.542 + } x; 1.543 + float data[3]; 1.544 + } m; 1.545 + 1.546 + static_assert(sizeof(m.x)==sizeof(m.data), "sizeof(struct X) failure"); 1.547 + 1.548 + TimeManager.GetLatencyTimings(m.x.latencyRender, m.x.latencyTimewarp, m.x.latencyPostPresent); 1.549 + 1.550 + return CopyFloatArrayWithLimit(values, arraySize, m.data, 3); 1.551 + } 1.552 + else if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetNumberValues, propertyName)) 1.553 + { 1.554 + // Convert floats to doubles 1.555 + double* da = new double[arraySize]; 1.556 + for (int i = 0; i < (int)arraySize; ++i) 1.557 + { 1.558 + da[i] = values[i]; 1.559 + } 1.560 + 1.561 + int count = NetClient::GetInstance()->GetNumberValues(GetNetId(), propertyName, da, (int)arraySize); 1.562 + 1.563 + for (int i = 0; i < count; ++i) 1.564 + { 1.565 + values[i] = (float)da[i]; 1.566 + } 1.567 + 1.568 + delete[] da; 1.569 + 1.570 + return count; 1.571 + } 1.572 + else if (pProfile) 1.573 + { 1.574 + // TBD: Not quite right. Should update profile interface, so that 1.575 + // we can return 0 in all conditions if property doesn't exist. 1.576 + 1.577 + return pProfile->GetFloatValues(propertyName, values, arraySize); 1.578 + } 1.579 + } 1.580 + 1.581 + return 0; 1.582 +} 1.583 + 1.584 +bool HMDState::setFloatArray(const char* propertyName, float values[], unsigned arraySize) 1.585 +{ 1.586 + if (!arraySize) 1.587 + { 1.588 + return false; 1.589 + } 1.590 + 1.591 + if (OVR_strcmp(propertyName, "DistortionClearColor") == 0) 1.592 + { 1.593 + CopyFloatArrayWithLimit(RenderState.ClearColor, 4, values, arraySize); 1.594 + return true; 1.595 + } 1.596 + 1.597 + if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetNumberValues, propertyName)) 1.598 + { 1.599 + double* da = new double[arraySize]; 1.600 + for (int i = 0; i < (int)arraySize; ++i) 1.601 + { 1.602 + da[i] = values[i]; 1.603 + } 1.604 + 1.605 + bool result = NetClient::GetInstance()->SetNumberValues(GetNetId(), propertyName, da, arraySize); 1.606 + 1.607 + delete[] da; 1.608 + 1.609 + return result; 1.610 + } 1.611 + 1.612 + return false; 1.613 +} 1.614 + 1.615 +const char* HMDState::getString(const char* propertyName, const char* defaultVal) 1.616 +{ 1.617 + if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetStringValue, propertyName)) 1.618 + { 1.619 + return NetClient::GetInstance()->GetStringValue(GetNetId(), propertyName, defaultVal); 1.620 + } 1.621 + 1.622 + if (pProfile) 1.623 + { 1.624 + LastGetStringValue[0] = 0; 1.625 + if (pProfile->GetValue(propertyName, LastGetStringValue, sizeof(LastGetStringValue))) 1.626 + { 1.627 + return LastGetStringValue; 1.628 + } 1.629 + } 1.630 + 1.631 + return defaultVal; 1.632 +} 1.633 + 1.634 +bool HMDState::setString(const char* propertyName, const char* value) 1.635 +{ 1.636 + if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetStringValue, propertyName)) 1.637 + { 1.638 + return NetClient::GetInstance()->SetStringValue(GetNetId(), propertyName, value); 1.639 + } 1.640 + 1.641 + return false; 1.642 +} 1.643 + 1.644 + 1.645 +//------------------------------------------------------------------------------------- 1.646 +// *** Latency Test 1.647 + 1.648 +bool HMDState::ProcessLatencyTest(unsigned char rgbColorOut[3]) 1.649 +{ 1.650 + return NetClient::GetInstance()->LatencyUtil_ProcessInputs(Timer::GetSeconds(), rgbColorOut); 1.651 +} 1.652 + 1.653 +//------------------------------------------------------------------------------------- 1.654 +// *** Rendering 1.655 + 1.656 +bool HMDState::ConfigureRendering(ovrEyeRenderDesc eyeRenderDescOut[2], 1.657 + const ovrFovPort eyeFovIn[2], 1.658 + const ovrRenderAPIConfig* apiConfig, 1.659 + unsigned distortionCaps) 1.660 +{ 1.661 + ThreadChecker::Scope checkScope(&RenderAPIThreadChecker, "ovrHmd_ConfigureRendering"); 1.662 + 1.663 + // null -> shut down. 1.664 + if (!apiConfig) 1.665 + { 1.666 + if (pHSWDisplay) 1.667 + { 1.668 + pHSWDisplay->Shutdown(); 1.669 + pHSWDisplay.Clear(); 1.670 + } 1.671 + 1.672 + if (pRenderer) 1.673 + pRenderer.Clear(); 1.674 + RenderingConfigured = false; 1.675 + return true; 1.676 + } 1.677 + 1.678 + if (pRenderer && 1.679 + (apiConfig->Header.API != pRenderer->GetRenderAPI())) 1.680 + { 1.681 + // Shutdown old renderer. 1.682 + if (pHSWDisplay) 1.683 + { 1.684 + pHSWDisplay->Shutdown(); 1.685 + pHSWDisplay.Clear(); 1.686 + } 1.687 + 1.688 + if (pRenderer) 1.689 + pRenderer.Clear(); 1.690 + } 1.691 + 1.692 + distortionCaps = distortionCaps & pHmdDesc->DistortionCaps; 1.693 + 1.694 + // Step 1: do basic setup configuration 1.695 + RenderState.EnabledHmdCaps = EnabledHmdCaps; // This is a copy... Any cleaner way? 1.696 + RenderState.DistortionCaps = distortionCaps; 1.697 + RenderState.EyeRenderDesc[0] = RenderState.CalcRenderDesc(ovrEye_Left, eyeFovIn[0]); 1.698 + RenderState.EyeRenderDesc[1] = RenderState.CalcRenderDesc(ovrEye_Right, eyeFovIn[1]); 1.699 + eyeRenderDescOut[0] = RenderState.EyeRenderDesc[0]; 1.700 + eyeRenderDescOut[1] = RenderState.EyeRenderDesc[1]; 1.701 + 1.702 + TimeManager.ResetFrameTiming(0, 1.703 + (EnabledHmdCaps & ovrHmdCap_DynamicPrediction) ? true : false, 1.704 + true); 1.705 + 1.706 + LastFrameTimeSeconds = 0.0f; 1.707 + 1.708 + // Set RenderingConfigured early to avoid ASSERTs in renderer initialization. 1.709 + RenderingConfigured = true; 1.710 + 1.711 + if (!pRenderer) 1.712 + { 1.713 + pRenderer = *DistortionRenderer::APICreateRegistry 1.714 + [apiConfig->Header.API](pHmdDesc, TimeManager, RenderState); 1.715 + } 1.716 + 1.717 + if (!pRenderer || 1.718 + !pRenderer->Initialize(apiConfig)) 1.719 + { 1.720 + RenderingConfigured = false; 1.721 + return false; 1.722 + } 1.723 + 1.724 + // Setup the Health and Safety Warning display system. 1.725 + if(pHSWDisplay && (pHSWDisplay->GetRenderAPIType() != apiConfig->Header.API)) // If we need to reconstruct the HSWDisplay for a different graphics API type, delete the existing display. 1.726 + { 1.727 + pHSWDisplay->Shutdown(); 1.728 + pHSWDisplay.Clear(); 1.729 + } 1.730 + 1.731 + if(!pHSWDisplay) // Use * below because that for of operator= causes it to inherit the refcount the factory gave the object. 1.732 + { 1.733 + pHSWDisplay = *OVR::CAPI::HSWDisplay::Factory(apiConfig->Header.API, pHmdDesc, RenderState); 1.734 + pHSWDisplay->Enable(pProfile->GetBoolValue("HSW", true)); 1.735 + } 1.736 + 1.737 + if (pHSWDisplay) 1.738 + pHSWDisplay->Initialize(apiConfig); // This is potentially re-initializing it with a new config. 1.739 + 1.740 + return true; 1.741 +} 1.742 + 1.743 + 1.744 +void HMDState::SubmitEyeTextures(const ovrPosef renderPose[2], 1.745 + const ovrTexture eyeTexture[2]) 1.746 +{ 1.747 + RenderState.EyeRenderPoses[0] = renderPose[0]; 1.748 + RenderState.EyeRenderPoses[1] = renderPose[1]; 1.749 + 1.750 + if (pRenderer) 1.751 + { 1.752 + pRenderer->SubmitEye(0, &eyeTexture[0]); 1.753 + pRenderer->SubmitEye(1, &eyeTexture[1]); 1.754 + } 1.755 +} 1.756 + 1.757 + 1.758 +// I appreciate this is not an idea place for this function, but it didn't seem to be 1.759 +// being linked properly when in OVR_CAPI.cpp. 1.760 +// Please relocate if you know of a better place 1.761 +ovrBool ovrHmd_CreateDistortionMeshInternal( ovrHmdStruct * hmd, 1.762 + ovrEyeType eyeType, ovrFovPort fov, 1.763 + unsigned int distortionCaps, 1.764 + ovrDistortionMesh *meshData, 1.765 + float overrideEyeReliefIfNonZero ) 1.766 +{ 1.767 + if (!meshData) 1.768 + return 0; 1.769 + HMDState* hmds = (HMDState*)hmd; 1.770 + 1.771 + // Not used now, but Chromatic flag or others could possibly be checked for in the future. 1.772 + OVR_UNUSED1(distortionCaps); 1.773 + 1.774 +#if defined (OVR_CC_MSVC) 1.775 + static_assert(sizeof(DistortionMeshVertexData) == sizeof(ovrDistortionVertex), "DistortionMeshVertexData size mismatch"); 1.776 +#endif 1.777 + 1.778 + // *** Calculate a part of "StereoParams" needed for mesh generation 1.779 + 1.780 + // Note that mesh distortion generation is invariant of RenderTarget UVs, allowing 1.781 + // render target size and location to be changed after the fact dynamically. 1.782 + // eyeToSourceUV is computed here for convenience, so that users don't need 1.783 + // to call ovrHmd_GetRenderScaleAndOffset unless changing RT dynamically. 1.784 + 1.785 + const HmdRenderInfo& hmdri = hmds->RenderState.RenderInfo; 1.786 + StereoEye stereoEye = (eyeType == ovrEye_Left) ? StereoEye_Left : StereoEye_Right; 1.787 + 1.788 + DistortionRenderDesc& distortion = hmds->RenderState.Distortion[eyeType]; 1.789 + if (overrideEyeReliefIfNonZero) 1.790 + { 1.791 + distortion.Lens = GenerateLensConfigFromEyeRelief(overrideEyeReliefIfNonZero,hmdri); 1.792 + } 1.793 + 1.794 + // Find the mapping from TanAngle space to target NDC space. 1.795 + ScaleAndOffset2D eyeToSourceNDC = CreateNDCScaleAndOffsetFromFov(fov); 1.796 + 1.797 + int triangleCount = 0; 1.798 + int vertexCount = 0; 1.799 + 1.800 + DistortionMeshCreate((DistortionMeshVertexData**)&meshData->pVertexData, 1.801 + (uint16_t**)&meshData->pIndexData, 1.802 + &vertexCount, &triangleCount, 1.803 + (stereoEye == StereoEye_Right), 1.804 + hmdri, distortion, eyeToSourceNDC); 1.805 + 1.806 + if (meshData->pVertexData) 1.807 + { 1.808 + // Convert to index 1.809 + meshData->IndexCount = triangleCount * 3; 1.810 + meshData->VertexCount = vertexCount; 1.811 + return 1; 1.812 + } 1.813 + 1.814 + return 0; 1.815 +} 1.816 + 1.817 + 1.818 + 1.819 +}} // namespace OVR::CAPI