/* * Copyright 2011-2015 Branimir Karadzic. All rights reserved. * License: http://www.opensource.org/licenses/BSD-2-Clause */ #include "ovr.h" #if BGFX_CONFIG_USE_OVR namespace bgfx { #if OVR_VERSION <= OVR_VERSION_050 # define OVR_EYE_BUFFER 100 #else # define OVR_EYE_BUFFER 8 #endif // OVR_VERSION... OVR::OVR() : m_hmd(NULL) , m_isenabled(false) , m_debug(false) { } OVR::~OVR() { BX_CHECK(NULL == m_hmd, "OVR not shutdown properly."); } void OVR::init() { bool initialized = !!ovr_Initialize(); BX_WARN(initialized, "Unable to create OVR device."); if (!initialized) { return; } m_hmd = ovrHmd_Create(0); if (NULL == m_hmd) { m_hmd = ovrHmd_CreateDebug(ovrHmd_DK2); BX_WARN(NULL != m_hmd, "Unable to create OVR device."); if (NULL == m_hmd) { return; } } BX_TRACE("HMD: %s, %s, firmware: %d.%d" , m_hmd->ProductName , m_hmd->Manufacturer , m_hmd->FirmwareMajor , m_hmd->FirmwareMinor ); ovrSizei sizeL = ovrHmd_GetFovTextureSize(m_hmd, ovrEye_Left, m_hmd->DefaultEyeFov[0], 1.0f); ovrSizei sizeR = ovrHmd_GetFovTextureSize(m_hmd, ovrEye_Right, m_hmd->DefaultEyeFov[1], 1.0f); m_rtSize.w = sizeL.w + sizeR.w + OVR_EYE_BUFFER; m_rtSize.h = bx::uint32_max(sizeL.h, sizeR.h); m_warning = true; } void OVR::shutdown() { BX_CHECK(!m_isenabled, "HMD not disabled."); ovrHmd_Destroy(m_hmd); m_hmd = NULL; ovr_Shutdown(); } void OVR::getViewport(uint8_t _eye, Rect* _viewport) { _viewport->m_x = _eye * (m_rtSize.w + OVR_EYE_BUFFER + 1)/2; _viewport->m_y = 0; _viewport->m_width = (m_rtSize.w - OVR_EYE_BUFFER)/2; _viewport->m_height = m_rtSize.h; } bool OVR::postReset(void* _nwh, ovrRenderAPIConfig* _config, bool _debug) { if (_debug) { switch (_config->Header.API) { #if BGFX_CONFIG_RENDERER_DIRECT3D11 case ovrRenderAPI_D3D11: { ovrD3D11ConfigData* data = (ovrD3D11ConfigData*)_config; # if OVR_VERSION > OVR_VERSION_043 m_rtSize = data->Header.BackBufferSize; # else m_rtSize = data->Header.RTSize; # endif // OVR_VERSION > OVR_VERSION_043 } break; #endif // BGFX_CONFIG_RENDERER_DIRECT3D11 #if BGFX_CONFIG_RENDERER_OPENGL case ovrRenderAPI_OpenGL: { ovrGLConfigData* data = (ovrGLConfigData*)_config; # if OVR_VERSION > OVR_VERSION_043 m_rtSize = data->Header.BackBufferSize; # else m_rtSize = data->Header.RTSize; # endif // OVR_VERSION > OVR_VERSION_043 } break; #endif // BGFX_CONFIG_RENDERER_OPENGL case ovrRenderAPI_None: default: BX_CHECK(false, "You should not be here!"); break; } m_debug = true; return false; } if (NULL == m_hmd) { return false; } m_isenabled = true; ovrBool result; result = ovrHmd_AttachToWindow(m_hmd, _nwh, NULL, NULL); if (!result) { goto ovrError; } ovrFovPort eyeFov[2] = { m_hmd->DefaultEyeFov[0], m_hmd->DefaultEyeFov[1] }; result = ovrHmd_ConfigureRendering(m_hmd , _config , 0 #if OVR_VERSION < OVR_VERSION_050 | ovrDistortionCap_Chromatic // permanently enabled >= v5.0 #endif | ovrDistortionCap_Vignette | ovrDistortionCap_TimeWarp | ovrDistortionCap_Overdrive | ovrDistortionCap_NoRestore | ovrDistortionCap_HqDistortion , eyeFov , m_erd ); if (!result) { goto ovrError; } ovrHmd_SetEnabledCaps(m_hmd , 0 | ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction ); result = ovrHmd_ConfigureTracking(m_hmd , 0 | ovrTrackingCap_Orientation | ovrTrackingCap_MagYawCorrection | ovrTrackingCap_Position , 0 ); if (!result) { ovrError: BX_TRACE("Failed to initialize OVR."); m_isenabled = false; return false; } m_warning = true; return true; } void OVR::postReset(const ovrTexture& _texture) { if (NULL != m_hmd) { m_texture[0] = _texture; m_texture[1] = _texture; ovrRecti rect; rect.Pos.x = 0; rect.Pos.y = 0; rect.Size.w = (m_rtSize.w - OVR_EYE_BUFFER)/2; rect.Size.h = m_rtSize.h; m_texture[0].Header.RenderViewport = rect; rect.Pos.x += rect.Size.w + OVR_EYE_BUFFER; m_texture[1].Header.RenderViewport = rect; m_timing = ovrHmd_BeginFrame(m_hmd, 0); #if OVR_VERSION > OVR_VERSION_042 m_pose[0] = ovrHmd_GetHmdPosePerEye(m_hmd, ovrEye_Left); m_pose[1] = ovrHmd_GetHmdPosePerEye(m_hmd, ovrEye_Right); #else m_pose[0] = ovrHmd_GetEyePose(m_hmd, ovrEye_Left); m_pose[1] = ovrHmd_GetEyePose(m_hmd, ovrEye_Right); #endif // OVR_VERSION > OVR_VERSION_042 } } void OVR::preReset() { if (m_isenabled) { ovrHmd_EndFrame(m_hmd, m_pose, m_texture); ovrHmd_AttachToWindow(m_hmd, NULL, NULL, NULL); ovrHmd_ConfigureRendering(m_hmd, NULL, 0, NULL, NULL); m_isenabled = false; } m_debug = false; } bool OVR::swap(HMD& _hmd) { _hmd.flags = BGFX_HMD_NONE; if (NULL != m_hmd) { _hmd.flags |= BGFX_HMD_DEVICE_RESOLUTION; _hmd.deviceWidth = m_hmd->Resolution.w; _hmd.deviceHeight = m_hmd->Resolution.h; } if (!m_isenabled) { return false; } _hmd.flags |= BGFX_HMD_RENDERING; ovrHmd_EndFrame(m_hmd, m_pose, m_texture); if (m_warning) { m_warning = !ovrHmd_DismissHSWDisplay(m_hmd); } m_timing = ovrHmd_BeginFrame(m_hmd, 0); #if OVR_VERSION > OVR_VERSION_042 m_pose[0] = ovrHmd_GetHmdPosePerEye(m_hmd, ovrEye_Left); m_pose[1] = ovrHmd_GetHmdPosePerEye(m_hmd, ovrEye_Right); #else m_pose[0] = ovrHmd_GetEyePose(m_hmd, ovrEye_Left); m_pose[1] = ovrHmd_GetEyePose(m_hmd, ovrEye_Right); #endif // OVR_VERSION > OVR_VERSION_042 getEyePose(_hmd); return true; } void OVR::recenter() { if (NULL != m_hmd) { ovrHmd_RecenterPose(m_hmd); } } void OVR::getEyePose(HMD& _hmd) { if (NULL != m_hmd) { for (int ii = 0; ii < 2; ++ii) { const ovrPosef& pose = m_pose[ii]; HMD::Eye& eye = _hmd.eye[ii]; eye.rotation[0] = pose.Orientation.x; eye.rotation[1] = pose.Orientation.y; eye.rotation[2] = pose.Orientation.z; eye.rotation[3] = pose.Orientation.w; eye.translation[0] = pose.Position.x; eye.translation[1] = pose.Position.y; eye.translation[2] = pose.Position.z; const ovrEyeRenderDesc& erd = m_erd[ii]; eye.fov[0] = erd.Fov.UpTan; eye.fov[1] = erd.Fov.DownTan; eye.fov[2] = erd.Fov.LeftTan; eye.fov[3] = erd.Fov.RightTan; #if OVR_VERSION > OVR_VERSION_042 eye.viewOffset[0] = erd.HmdToEyeViewOffset.x; eye.viewOffset[1] = erd.HmdToEyeViewOffset.y; eye.viewOffset[2] = erd.HmdToEyeViewOffset.z; #else eye.viewOffset[0] = erd.ViewAdjust.x; eye.viewOffset[1] = erd.ViewAdjust.y; eye.viewOffset[2] = erd.ViewAdjust.z; #endif // OVR_VERSION > OVR_VERSION_042 eye.pixelsPerTanAngle[0] = erd.PixelsPerTanAngleAtCenter.x; eye.pixelsPerTanAngle[1] = erd.PixelsPerTanAngleAtCenter.y; } } else { for (int ii = 0; ii < 2; ++ii) { _hmd.eye[ii].rotation[0] = 0.0f; _hmd.eye[ii].rotation[1] = 0.0f; _hmd.eye[ii].rotation[2] = 0.0f; _hmd.eye[ii].rotation[3] = 1.0f; _hmd.eye[ii].translation[0] = 0.0f; _hmd.eye[ii].translation[1] = 0.0f; _hmd.eye[ii].translation[2] = 0.0f; _hmd.eye[ii].fov[0] = 1.32928634f; _hmd.eye[ii].fov[1] = 1.32928634f; _hmd.eye[ii].fov[2] = 0 == ii ? 1.05865765f : 1.09236801f; _hmd.eye[ii].fov[3] = 0 == ii ? 1.09236801f : 1.05865765f; _hmd.eye[ii].viewOffset[0] = 0 == ii ? 0.0355070010f : -0.0375000015f; _hmd.eye[ii].viewOffset[1] = 0.0f; _hmd.eye[ii].viewOffset[2] = 0 == ii ? 0.00150949787f : -0.00150949787f; _hmd.eye[ii].pixelsPerTanAngle[0] = 1; _hmd.eye[ii].pixelsPerTanAngle[1] = 1; } } _hmd.width = uint16_t(m_rtSize.w); _hmd.height = uint16_t(m_rtSize.h); } } // namespace bgfx #endif // BGFX_CONFIG_USE_OVR