bool HMDState::setFloatArray(const char* propertyName, float values[], unsigned arraySize) { if (!arraySize) { return false; } if (OVR_strcmp(propertyName, "DistortionClearColor") == 0) { CopyFloatArrayWithLimit(RenderState.ClearColor, 4, values, arraySize); return true; } if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetNumberValues, propertyName)) { double* da = new double[arraySize]; for (int i = 0; i < (int)arraySize; ++i) { da[i] = values[i]; } bool result = NetClient::GetInstance()->SetNumberValues(GetNetId(), propertyName, da, arraySize); delete[] da; return result; } return false; }
float HMDState::getFloatValue(const char* propertyName, float defaultVal) { if (OVR_strcmp(propertyName, "LensSeparation") == 0) { return OurHMDInfo.LensSeparationInMeters; } else if (OVR_strcmp(propertyName, "VsyncToNextVsync") == 0) { return OurHMDInfo.Shutter.VsyncToNextVsync; } else if (OVR_strcmp(propertyName, "PixelPersistence") == 0) { return OurHMDInfo.Shutter.PixelPersistence; } else if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetNumberValue, propertyName)) { return (float)NetClient::GetInstance()->GetNumberValue(GetNetId(), propertyName, defaultVal); } else if (pProfile) { return pProfile->GetFloatValue(propertyName, defaultVal); } return defaultVal; }
bool HMDState::setString(const char* propertyName, const char* value) { if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetStringValue, propertyName)) { return NetClient::GetInstance()->SetStringValue(GetNetId(), propertyName, value); } return false; }
void HMDState::UpdateRenderProfile(Profile* profile) { // Apply the given profile to generate a render context RenderState.OurProfileRenderInfo = GenerateProfileRenderInfoFromProfile(RenderState.OurHMDInfo, profile); RenderState.RenderInfo = GenerateHmdRenderInfoFromHmdInfo(RenderState.OurHMDInfo, RenderState.OurProfileRenderInfo); RenderState.Distortion[0] = CalculateDistortionRenderDesc(StereoEye_Left, RenderState.RenderInfo, 0); RenderState.Distortion[1] = CalculateDistortionRenderDesc(StereoEye_Right, RenderState.RenderInfo, 0); if (pClient) { // Center pupil depth float centerPupilDepth = GetCenterPupilDepthFromRenderInfo(&RenderState.RenderInfo); pClient->SetNumberValue(GetNetId(), "CenterPupilDepth", centerPupilDepth); // Neck model Vector3f neckModel = GetNeckModelFromProfile(profile); double neckModelArray[3] = { neckModel.x, neckModel.y, neckModel.z }; pClient->SetNumberValues(GetNetId(), "NeckModelVector3f", neckModelArray, 3); // Camera position // OVR_KEY_CAMERA_POSITION is actually the *inverse* of a camera position. Posed centeredFromWorld; double values[7]; if (profile->GetDoubleValues(OVR_KEY_CAMERA_POSITION, values, 7) == 7) { centeredFromWorld = Posed::FromArray(values); } else { centeredFromWorld = TheTrackingStateReader.GetDefaultCenteredFromWorld(); } // ComputeCenteredFromWorld wants a worldFromCpf pose, so invert it. // FIXME: The stored centeredFromWorld doesn't have a neck model offset applied, but probably should. TheTrackingStateReader.ComputeCenteredFromWorld(centeredFromWorld.Inverted(), Vector3d(0, 0, 0)); } }
int HMDState::getIntValue(const char* propertyName, int defaultVal) { if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetIntValue, propertyName)) { return NetClient::GetInstance()->GetIntValue(GetNetId(), propertyName, defaultVal); } else if (pProfile) { return pProfile->GetIntValue(propertyName, defaultVal); } return defaultVal; }
void HMDState::UpdateRenderProfile(Profile* profile) { // Apply the given profile to generate a render context RenderState.RenderInfo = GenerateHmdRenderInfoFromHmdInfo(RenderState.OurHMDInfo, profile); RenderState.Distortion[0] = CalculateDistortionRenderDesc(StereoEye_Left, RenderState.RenderInfo, 0); RenderState.Distortion[1] = CalculateDistortionRenderDesc(StereoEye_Right, RenderState.RenderInfo, 0); if (pClient) { // Center pupil depth float centerPupilDepth = GetCenterPupilDepthFromRenderInfo(&RenderState.RenderInfo); pClient->SetNumberValue(GetNetId(), "CenterPupilDepth", centerPupilDepth); // Neck model Vector3f neckModel = GetNeckModelFromProfile(profile); double neckModelArray[3] = { neckModel.x, neckModel.y, neckModel.z }; pClient->SetNumberValues(GetNetId(), "NeckModelVector3f", neckModelArray, 3); double camerastate[7]; if (profile->GetDoubleValues(OVR_KEY_CAMERA_POSITION, camerastate, 7) == 0) { //there is no value, so we load the default for (int i = 0; i < 7; i++) camerastate[i] = 0; camerastate[3] = 1;//no offset. by default, give the quaternion w component value 1 } else TheSensorStateReader.setCenteredFromWorld(OVR::Posed::FromArray(camerastate)); } }
const char* HMDState::getString(const char* propertyName, const char* defaultVal) { if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetStringValue, propertyName)) { return NetClient::GetInstance()->GetStringValue(GetNetId(), propertyName, defaultVal); } if (pProfile) { LastGetStringValue[0] = 0; if (pProfile->GetValue(propertyName, LastGetStringValue, sizeof(LastGetStringValue))) { return LastGetStringValue; } } return defaultVal; }
unsigned HMDState::getFloatArray(const char* propertyName, float values[], unsigned arraySize) { if (arraySize) { if (OVR_strcmp(propertyName, "ScreenSize") == 0) { float data[2] = { OurHMDInfo.ScreenSizeInMeters.w, OurHMDInfo.ScreenSizeInMeters.h }; return CopyFloatArrayWithLimit(values, arraySize, data, 2); } else if (OVR_strcmp(propertyName, "DistortionClearColor") == 0) { return CopyFloatArrayWithLimit(values, arraySize, RenderState.ClearColor, 4); } else if (OVR_strcmp(propertyName, "DK2Latency") == 0) { if (OurHMDInfo.HmdType != HmdType_DK2) { return 0; } union { struct X { float latencyRender, latencyTimewarp, latencyPostPresent; } x; float data[3]; } m; static_assert(sizeof(m.x)==sizeof(m.data), "sizeof(struct X) failure"); TimeManager.GetLatencyTimings(m.x.latencyRender, m.x.latencyTimewarp, m.x.latencyPostPresent); return CopyFloatArrayWithLimit(values, arraySize, m.data, 3); } else if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetNumberValues, propertyName)) { // Convert floats to doubles double* da = new double[arraySize]; for (int i = 0; i < (int)arraySize; ++i) { da[i] = values[i]; } int count = NetClient::GetInstance()->GetNumberValues(GetNetId(), propertyName, da, (int)arraySize); for (int i = 0; i < count; ++i) { values[i] = (float)da[i]; } delete[] da; return count; } else if (pProfile) { // TBD: Not quite right. Should update profile interface, so that // we can return 0 in all conditions if property doesn't exist. return pProfile->GetFloatValues(propertyName, values, arraySize); } } return 0; }
bool HMDState::ConfigureRendering(ovrEyeRenderDesc eyeRenderDescOut[2], const ovrFovPort eyeFovIn[2], const ovrRenderAPIConfig* apiConfig, unsigned distortionCaps) { ThreadChecker::Scope checkScope(&RenderAPIThreadChecker, "ovrHmd_ConfigureRendering"); // null -> shut down. if (!apiConfig) { #if !defined(HEADLESS_APP) if (pHSWDisplay) { pHSWDisplay->Shutdown(); pHSWDisplay.Clear(); } #endif /* !defined(HEADLESS_APP) */ if (pRenderer) pRenderer.Clear(); RenderingConfigured = false; return true; } if (pRenderer && (apiConfig->Header.API != pRenderer->GetRenderAPI())) { // Shutdown old renderer. #if !defined(HEADLESS_APP) if (pHSWDisplay) { pHSWDisplay->Shutdown(); pHSWDisplay.Clear(); } #endif /* !defined(HEADLESS_APP) */ if (pRenderer) pRenderer.Clear(); } distortionCaps = distortionCaps & pHmdDesc->DistortionCaps; // Step 1: do basic setup configuration RenderState.EnabledHmdCaps = EnabledHmdCaps; // This is a copy... Any cleaner way? RenderState.DistortionCaps = distortionCaps; RenderState.EyeRenderDesc[0] = RenderState.CalcRenderDesc(ovrEye_Left, eyeFovIn[0]); RenderState.EyeRenderDesc[1] = RenderState.CalcRenderDesc(ovrEye_Right, eyeFovIn[1]); eyeRenderDescOut[0] = RenderState.EyeRenderDesc[0]; eyeRenderDescOut[1] = RenderState.EyeRenderDesc[1]; // Set RenderingConfigured early to avoid ASSERTs in renderer initialization. RenderingConfigured = true; if (!pRenderer) { #if !defined(HEADLESS_APP) pRenderer = *DistortionRenderer::APICreateRegistry [apiConfig->Header.API](); #endif /* !defined(HEADLESS_APP) */ } if (!pRenderer #if !defined(HEADLESS_APP) || !pRenderer->Initialize(apiConfig, &TheTrackingStateReader, &TimewarpTimer, &RenderState) #endif /* !defined(HEADLESS_APP) */ ) { RenderingConfigured = false; return false; } #if !defined(HEADLESS_APP) // Setup the Health and Safety Warning display system. if(pHSWDisplay && (pHSWDisplay->GetRenderAPIType() != apiConfig->Header.API)) // If we need to reconstruct the HSWDisplay for a different graphics API type, delete the existing display. { pHSWDisplay->Shutdown(); pHSWDisplay.Clear(); } if(!pHSWDisplay) // Use * below because that for of operator= causes it to inherit the refcount the factory gave the object. { pHSWDisplay = *OVR::CAPI::HSWDisplay::Factory(apiConfig->Header.API, pHmdDesc, RenderState); } if (pHSWDisplay) { pHSWDisplay->Initialize(apiConfig); // This is potentially re-initializing it with a new config. } #ifdef OVR_OS_WIN32 if (!pWindow) { // We can automatically populate the window to attach to by // pulling that information off the swap chain that the // application provides. If the application later calls the // ovrHmd_AttachToWindow() function these will get harmlessly // overwritten. The check above verifies that the window is // not set yet, and it insures that this default doesn't // overwrite the application setting. if (apiConfig->Header.API == ovrRenderAPI_D3D11) { ovrD3D11Config* d3d11Config = (ovrD3D11Config*)apiConfig; if (d3d11Config->D3D11.pSwapChain) { DXGI_SWAP_CHAIN_DESC desc = {}; HRESULT hr = d3d11Config->D3D11.pSwapChain->GetDesc(&desc); if (SUCCEEDED(hr)) { pWindow = (void*)desc.OutputWindow; } } } else if (apiConfig->Header.API == ovrRenderAPI_OpenGL) { ovrGLConfig* glConfig = (ovrGLConfig*)apiConfig; pWindow = (void*)glConfig->OGL.Window; } OVR_DISABLE_MSVC_WARNING(4996) // Disable deprecation warning else if (apiConfig->Header.API == ovrRenderAPI_D3D9) { ovrD3D9Config* dx9Config = (ovrD3D9Config*)apiConfig; if (dx9Config->D3D9.pDevice) { D3DDEVICE_CREATION_PARAMETERS params = {}; HRESULT hr = dx9Config->D3D9.pDevice->GetCreationParameters(¶ms); if (SUCCEEDED(hr)) { pWindow = (void*)params.hFocusWindow; } } } OVR_RESTORE_MSVC_WARNING() // If a window handle was implied by render configuration, if (pWindow) { // This is the same logic as ovrHmd_AttachToWindow() on Windows: if (pClient) pClient->Hmd_AttachToWindow(GetNetId(), pWindow); Win32::DisplayShim::GetInstance().hWindow = (HWND)pWindow; // On the server side it is updating the association of connection // to window handle. This is perfectly safe to update later to // a new window handle (verified). Also verified that if this // handle is garbage that it doesn't crash anything. } } #endif #endif /* !defined(HEADLESS_APP) */ return true; }
unsigned HMDState::getFloatArray(const char* propertyName, float values[], unsigned arraySize) { if (arraySize) { if (OVR_strcmp(propertyName, "ScreenSize") == 0) { float data[2] = { OurHMDInfo.ScreenSizeInMeters.w, OurHMDInfo.ScreenSizeInMeters.h }; return CopyFloatArrayWithLimit(values, arraySize, data, 2); } else if (OVR_strcmp(propertyName, "DistortionClearColor") == 0) { return CopyFloatArrayWithLimit(values, arraySize, RenderState.ClearColor, 4); } else if (OVR_strcmp(propertyName, "DK2Latency") == 0) { if (OurHMDInfo.HmdType < HmdType_DK2) { return 0; } OutputLatencyTimings timings; ScreenLatencyTracker.GetLatencyTimings(timings); if (arraySize > 0) { switch (arraySize) { default: values[4] = (float)timings.ErrorTimewarp; // Fall-thru case 4: values[3] = (float)timings.ErrorRender; // Fall-thru case 3: values[2] = (float)timings.LatencyPostPresent; // Fall-thru case 2: values[1] = (float)timings.LatencyTimewarp; // Fall-thru case 1: values[0] = (float)timings.LatencyRender; } } return arraySize > 5 ? 5 : arraySize; } else if (OVR_strcmp(propertyName, "NeckModelVector3f") == 0) { // Query the service to grab the HNM. double hnm[3] = {}; int count = NetClient::GetInstance()->GetNumberValues(GetNetId(), propertyName, hnm, (int)arraySize); // If the service is unavailable or returns zero data, if (count < 3 || (hnm[0] == 0.0 && hnm[1] == 0.0 && hnm[2] == 0.0)) { // These are the default values used if the server does not return any data, due to not // being reachable or other errors. OVR_ASSERT(pProfile.GetPtr()); if (pProfile.GetPtr()) { Vector3f neckModel = GetNeckModelFromProfile(pProfile); hnm[0] = neckModel.x; hnm[1] = neckModel.y; hnm[2] = neckModel.z; } } for (unsigned i = 0; i < 3 && i < arraySize; ++i) { values[i] = (float)hnm[i]; } return arraySize > 3 ? 3 : arraySize; } else if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetNumberValues, propertyName)) { // Convert floats to doubles double* da = new double[arraySize]; for (int i = 0; i < (int)arraySize; ++i) { da[i] = values[i]; } int count = NetClient::GetInstance()->GetNumberValues(GetNetId(), propertyName, da, (int)arraySize); for (int i = 0; i < count; ++i) { values[i] = (float)da[i]; } delete[] da; return count; } else if (pProfile) { // TBD: Not quite right. Should update profile interface, so that // we can return 0 in all conditions if property doesn't exist. return pProfile->GetFloatValues(propertyName, values, arraySize); } } return 0; }