//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
# include "cbase.h"
# include "sourcevirtualreality.h"
# include "icommandline.h"
# include "filesystem.h"
# include "materialsystem/imaterial.h"
# include "materialsystem/imesh.h"
# include "materialsystem/imaterialvar.h"
# include "renderparm.h"
# include "openvr/openvr.h"
using namespace vr ;
CSourceVirtualReality g_SourceVirtualReality ;
EXPOSE_SINGLE_INTERFACE_GLOBALVAR ( CSourceVirtualReality , ISourceVirtualReality ,
SOURCE_VIRTUAL_REALITY_INTERFACE_VERSION , g_SourceVirtualReality ) ;
static VMatrix VMatrixFrom44 ( const float v [ 4 ] [ 4 ] ) ;
static VMatrix VMatrixFrom34 ( const float v [ 3 ] [ 4 ] ) ;
static VMatrix OpenVRToSourceCoordinateSystem ( const VMatrix & vortex ) ;
// --------------------------------------------------------------------
// Purpose: Set the current HMD pose as the zero pose
// --------------------------------------------------------------------
void CC_VR_Reset_Home_Pos ( const CCommand & args )
{
g_SourceVirtualReality . AcquireNewZeroPose ( ) ;
}
static ConCommand vr_reset_home_pos ( " vr_reset_home_pos " , CC_VR_Reset_Home_Pos , " Sets the current HMD position as the zero point " ) ;
// --------------------------------------------------------------------
// Purpose: Reinitialize the IHeadtrack object
// --------------------------------------------------------------------
void CC_VR_Track_Reinit ( const CCommand & args )
{
if ( g_SourceVirtualReality . ResetTracking ( ) )
{
// Tracker can't be restarted: show a message, but don't quit.
Warning ( " Can't reset HMD tracker " ) ;
}
}
static ConCommand vr_track_reinit ( " vr_track_reinit " , CC_VR_Track_Reinit , " Reinitializes HMD tracking " ) ;
// Disable distortion processing altogether.
ConVar vr_distortion_enable ( " vr_distortion_enable " , " 1 " ) ;
// Disable distortion by changing the distortion texture itself, so that the rendering path is otherwise identical.
// This won't take effect until the texture is refresed.
ConVar vr_debug_nodistortion ( " vr_debug_nodistortion " , " 0 " ) ;
// Disable just the chromatic aberration correction in the distortion texture, to make undistort quality/artifacts
// easier to see and debug. As above, won't take effect until the texture is refreshed.
ConVar vr_debug_nochromatic ( " vr_debug_nochromatic " , " 0 " ) ;
// Resolution of the undistort map.
static const int distortionTextureSize = 128 ;
void CC_vr_refresh_distortion_texture ( const CCommand & args )
{
g_SourceVirtualReality . RefreshDistortionTexture ( ) ;
}
ConCommand vr_refresh_distortion_texture ( " vr_refresh_distortion_texture " , CC_vr_refresh_distortion_texture ) ;
ConVar vr_use_offscreen_render_target ( " vr_use_offscreen_render_target " , " 0 " , 0 , " Experimental: Use larger offscreen render target for pre-distorted scene in VR " ) ;
// --------------------------------------------------------------------
// construction/destruction
// --------------------------------------------------------------------
CSourceVirtualReality : : CSourceVirtualReality ( )
: m_textureGeneratorLeft ( vr : : Eye_Left ) ,
m_textureGeneratorRight ( vr : : Eye_Right )
{
m_bActive = false ;
m_bUsingOffscreenRenderTarget = true ;
m_pHmd = NULL ;
}
CSourceVirtualReality : : ~ CSourceVirtualReality ( )
{
}
// --------------------------------------------------------------------
// Purpose:
// --------------------------------------------------------------------
bool CSourceVirtualReality : : Connect ( CreateInterfaceFn factory )
{
if ( ! factory )
return false ;
if ( ! BaseClass : : Connect ( factory ) )
return false ;
if ( ! g_pFullFileSystem )
{
Warning ( " The head tracker requires the filesystem to run! \n " ) ;
return false ;
}
return true ;
}
// --------------------------------------------------------------------
// Purpose:
// --------------------------------------------------------------------
void CSourceVirtualReality : : Disconnect ( )
{
BaseClass : : Disconnect ( ) ;
}
// --------------------------------------------------------------------
// Purpose:
// --------------------------------------------------------------------
void * CSourceVirtualReality : : QueryInterface ( const char * pInterfaceName )
{
CreateInterfaceFn factory = Sys_GetFactoryThis ( ) ; // This silly construction is necessary
return factory ( pInterfaceName , NULL ) ; // to prevent the LTCG compiler from crashing.
}
// --------------------------------------------------------------------
// Purpose:
// --------------------------------------------------------------------
InitReturnVal_t CSourceVirtualReality : : Init ( )
{
InitReturnVal_t nRetVal = BaseClass : : Init ( ) ;
if ( nRetVal ! = INIT_OK )
return nRetVal ;
MathLib_Init ( 2.2f , 2.2f , 0.0f , 2.0f ) ;
// if our tracker expects to use the texture base distortion shader,
// make the procedural textures for that shader now
m_pDistortionTextureLeft . Init ( materials - > CreateProceduralTexture ( " vr_distort_map_left " , TEXTURE_GROUP_PIXEL_SHADERS ,
distortionTextureSize , distortionTextureSize , IMAGE_FORMAT_RGBA16161616 ,
TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_NOLOD | TEXTUREFLAGS_NODEBUGOVERRIDE |
TEXTUREFLAGS_SINGLECOPY | TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT ) ) ;
m_pDistortionTextureRight . Init ( materials - > CreateProceduralTexture ( " vr_distort_map_right " , TEXTURE_GROUP_PIXEL_SHADERS ,
distortionTextureSize , distortionTextureSize , IMAGE_FORMAT_RGBA16161616 ,
TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_NOLOD | TEXTUREFLAGS_NODEBUGOVERRIDE |
TEXTUREFLAGS_SINGLECOPY | TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT ) ) ;
m_pDistortionTextureLeft - > SetTextureRegenerator ( & m_textureGeneratorLeft ) ;
m_pDistortionTextureRight - > SetTextureRegenerator ( & m_textureGeneratorRight ) ;
return INIT_OK ;
}
void CSourceVirtualReality : : RefreshDistortionTexture ( )
{
m_pDistortionTextureLeft - > Download ( ) ;
m_pDistortionTextureRight - > Download ( ) ;
}
void CDistortionTextureRegen : : RegenerateTextureBits ( ITexture * pTexture , IVTFTexture * pVTFTexture , Rect_t * pSubRect )
{
// only do this if we have an HMD
if ( ! g_SourceVirtualReality . GetHmd ( ) )
return ;
unsigned short * imageData = ( unsigned short * ) pVTFTexture - > ImageData ( 0 , 0 , 0 ) ;
enum ImageFormat imageFormat = pVTFTexture - > Format ( ) ;
if ( imageFormat ! = IMAGE_FORMAT_RGBA16161616 )
{
return ;
}
// we use different UVs for the full FB source texture
float fUScale ;
float fUOffset ;
if ( g_SourceVirtualReality . UsingOffscreenRenderTarget ( ) )
{
fUScale = 1.f ;
fUOffset = 0.f ;
}
else
{
fUScale = 0.5f ;
fUOffset = m_eEye = = Eye_Left ? 0.f : 0.5f ;
}
// optimize
int width = pVTFTexture - > Width ( ) ;
int height = pVTFTexture - > Height ( ) ;
float fHeight = height ;
float fWidth = width ;
int x , y ;
for ( y = 0 ; y < height ; y + + )
{
for ( x = 0 ; x < width ; x + + )
{
int offset = 4 * ( x + y * width ) ;
assert ( offset < width * height * 4 ) ;
float u = ( ( float ) x + 0.5f ) / fWidth ;
float v = ( ( float ) y + 0.5f ) / fHeight ;
DistortionCoordinates_t coords ;
if ( ! g_SourceVirtualReality . GetHmd ( ) - > ComputeDistortion ( m_eEye , u , v , & coords ) )
{
Warning ( " ComputeDistortion failed " ) ;
}
coords . rfRed [ 0 ] = Clamp ( coords . rfRed [ 0 ] , 0.f , 1.f ) * fUScale + fUOffset ;
coords . rfGreen [ 0 ] = Clamp ( coords . rfGreen [ 0 ] , 0.f , 1.f ) * fUScale + fUOffset ;
coords . rfBlue [ 0 ] = Clamp ( coords . rfBlue [ 0 ] , 0.f , 1.f ) * fUScale + fUOffset ;
if ( vr_debug_nodistortion . GetBool ( ) )
{
coords . rfRed [ 0 ] = coords . rfGreen [ 0 ] = coords . rfBlue [ 0 ] = u * fUScale + fUOffset ;
coords . rfRed [ 1 ] = coords . rfGreen [ 1 ] = coords . rfBlue [ 1 ] = v ;
}
if ( vr_debug_nochromatic . GetBool ( ) )
{
coords . rfRed [ 0 ] = coords . rfBlue [ 0 ] = coords . rfGreen [ 0 ] ;
coords . rfRed [ 1 ] = coords . rfBlue [ 1 ] = coords . rfGreen [ 1 ] ;
}
imageData [ offset + 0 ] = ( unsigned short ) ( Clamp ( coords . rfRed [ 0 ] , 0.f , 1.f ) * 65535.f ) ;
imageData [ offset + 1 ] = ( unsigned short ) ( Clamp ( coords . rfRed [ 1 ] , 0.f , 1.f ) * 65535.f ) ;
imageData [ offset + 2 ] = ( unsigned short ) ( Clamp ( coords . rfBlue [ 0 ] , 0.f , 1.f ) * 65535.f ) ;
imageData [ offset + 3 ] = ( unsigned short ) ( Clamp ( coords . rfBlue [ 1 ] , 0.f , 1.f ) * 65535.f ) ;
}
}
}
// --------------------------------------------------------------------
// Purpose:
// --------------------------------------------------------------------
void CSourceVirtualReality : : Shutdown ( )
{
BaseClass : : Shutdown ( ) ;
if ( m_pHmd )
VR_Shutdown ( ) ;
m_pDistortionTextureLeft . Shutdown ( ) ;
m_pDistortionTextureRight . Shutdown ( ) ;
}
// --------------------------------------------------------------------
// Purpose: Let the caller know if we're in VR mode
// --------------------------------------------------------------------
bool CSourceVirtualReality : : ShouldRunInVR ( )
{
return m_bActive & & m_pHmd ;
}
// --------------------------------------------------------------------
// Purpose: Returns true if there's an Hmd connected and everything
// started up.
// --------------------------------------------------------------------
bool CSourceVirtualReality : : IsHmdConnected ( )
{
// we really just care if OpenVR init was successful
return EnsureOpenVRInited ( ) ;
}
// --------------------------------------------------------------------
// Purpose: Let the caller know how big to make the window and where
// to put it.
// --------------------------------------------------------------------
bool CSourceVirtualReality : : GetDisplayBounds ( VRRect_t * pRect )
{
if ( m_pHmd )
{
int32_t x = 0 , y = 0 ;
uint32_t width = 1024 , height = 1024 ;
m_pExtDisplay - > GetWindowBounds ( & x , & y , & width , & height ) ;
pRect - > nX = x ;
pRect - > nY = y ;
pRect - > nWidth = width ;
pRect - > nHeight = height ;
return true ;
}
else
{
return false ;
}
}
// --------------------------------------------------------------------
// Purpose: Allocates the pre-distortion render targets.
// --------------------------------------------------------------------
void CSourceVirtualReality : : CreateRenderTargets ( IMaterialSystem * pMaterialSystem )
{
if ( ! m_pHmd | | ! m_bActive )
return ;
g_StereoGuiTexture . Init ( materials - > CreateNamedRenderTargetTextureEx2 (
" _rt_gui " ,
640 , 480 , RT_SIZE_OFFSCREEN ,
materials - > GetBackBufferFormat ( ) ,
MATERIAL_RT_DEPTH_SHARED ,
TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT ,
CREATERENDERTARGETFLAGS_HDR )
) ;
if ( UsingOffscreenRenderTarget ( ) )
{
uint32_t nWidth , nHeight ;
m_pHmd - > GetRecommendedRenderTargetSize ( & nWidth , & nHeight ) ;
m_pPredistortRT . Init ( pMaterialSystem - > CreateNamedRenderTargetTextureEx2 (
" _rt_vr_predistort " ,
nWidth , nHeight , RT_SIZE_LITERAL ,
IMAGE_FORMAT_RGBA8888 ,
MATERIAL_RT_DEPTH_SEPARATE ,
TEXTUREFLAGS_RENDERTARGET | TEXTUREFLAGS_NOMIP /*TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT */ ,
0 ) ) ;
//TODO: Figure out what I really want for the depth texture format
m_pPredistortRTDepth . Init ( pMaterialSystem - > CreateNamedRenderTargetTextureEx2 ( " _rt_vr_predistort_depth " , nWidth , nHeight ,
RT_SIZE_LITERAL , IMAGE_FORMAT_NV_DST24 , MATERIAL_RT_DEPTH_NONE ,
TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_NOMIP ,
0 ) ) ;
}
}
void CSourceVirtualReality : : ShutdownRenderTargets ( )
{
g_StereoGuiTexture . Shutdown ( ) ;
m_pPredistortRT . Shutdown ( ) ;
m_pPredistortRTDepth . Shutdown ( ) ;
}
// Returns the (possibly overridden) framebuffer size for render target sizing.
void CSourceVirtualReality : : GetRenderTargetFrameBufferDimensions ( int & nWidth , int & nHeight )
{
if ( m_pHmd & & UsingOffscreenRenderTarget ( ) )
{
uint32_t w , h ;
m_pHmd - > GetRecommendedRenderTargetSize ( & w , & h ) ;
nWidth = w ;
nHeight = h ;
}
else
{
// this will cause material system to fall back to the
// actual size of the frame buffer
nWidth = nHeight = 0 ;
}
}
// --------------------------------------------------------------------
// Purpose: fetches the render target for the specified eye
// --------------------------------------------------------------------
ITexture * CSourceVirtualReality : : GetRenderTarget ( ISourceVirtualReality : : VREye eEye , ISourceVirtualReality : : EWhichRenderTarget eWhich )
{
// we don't use any render targets if distortion is disabled
// Just let the game render to the frame buffer.
if ( ! vr_distortion_enable . GetBool ( ) )
return NULL ;
if ( ! m_bActive | | ! m_pHmd )
return NULL ;
if ( ! UsingOffscreenRenderTarget ( ) )
return NULL ;
switch ( eWhich )
{
case ISourceVirtualReality : : RT_Color :
return m_pPredistortRT ;
case ISourceVirtualReality : : RT_Depth :
return m_pPredistortRTDepth ;
}
return NULL ;
}
vr : : Hmd_Eye SourceEyeToHmdEye ( ISourceVirtualReality : : VREye eEye )
{
if ( eEye = = ISourceVirtualReality : : VREye_Left )
return vr : : Eye_Left ;
else
return vr : : Eye_Right ;
}
// --------------------------------------------------------------------
// Purpose: Let the caller know if we're in VR mode
// --------------------------------------------------------------------
void CSourceVirtualReality : : GetViewportBounds ( VREye eEye , int * pnX , int * pnY , int * pnWidth , int * pnHeight )
{
if ( ! m_pHmd | | ! m_bActive )
{
* pnWidth = 0 ;
* pnHeight = 0 ;
return ;
}
// if there are textures, use those
if ( m_pPredistortRT & & vr_distortion_enable . GetBool ( ) )
{
if ( pnX & & pnY )
{
* pnX = 0 ;
* pnY = 0 ;
}
* pnWidth = m_pPredistortRT - > GetActualWidth ( ) ;
* pnHeight = m_pPredistortRT - > GetActualHeight ( ) ;
}
else
{
uint32_t x = 0 , y = 0 , w = 640 , h = 480 ;
// m_pHmd->GetEyeOutputViewport( SourceEyeToHmdEye( eEye ), &x, &y, &w, &h );
m_pExtDisplay - > GetEyeOutputViewport ( SourceEyeToHmdEye ( eEye ) , & x , & y , & w , & h ) ;
if ( pnX & & pnY )
{
* pnX = x ;
* pnY = y ;
}
* pnWidth = w ;
* pnHeight = h ;
}
}
// --------------------------------------------------------------------
// Purpose: Returns the current pose
// --------------------------------------------------------------------
VMatrix CSourceVirtualReality : : GetMideyePose ( )
{
return m_ZeroFromHeadPose ;
}
// ----------------------------------------------------------------------
// Purpose: Create a 4x4 projection transform from eye projection and distortion parameters
// ----------------------------------------------------------------------
inline static void ComposeProjectionTransform ( float fLeft , float fRight , float fTop , float fBottom , float zNear , float zFar , float fovScale , VMatrix * pmProj )
{
/*if( fovScale != 1.0f && fovScale > 0.f )
{
float fFovScaleAdjusted = tan ( atan ( fTop ) / fovScale ) / fTop ;
fRight * = fFovScaleAdjusted ;
fLeft * = fFovScaleAdjusted ;
fTop * = fFovScaleAdjusted ;
fBottom * = fFovScaleAdjusted ;
} */
float idx = 1.0f / ( fRight - fLeft ) ;
float idy = 1.0f / ( fBottom - fTop ) ;
float idz = 1.0f / ( zFar - zNear ) ;
float sx = fRight + fLeft ;
float sy = fBottom + fTop ;
float ( * p ) [ 4 ] = pmProj - > m ;
p [ 0 ] [ 0 ] = 2 * idx ; p [ 0 ] [ 1 ] = 0 ; p [ 0 ] [ 2 ] = sx * idx ; p [ 0 ] [ 3 ] = 0 ;
p [ 1 ] [ 0 ] = 0 ; p [ 1 ] [ 1 ] = 2 * idy ; p [ 1 ] [ 2 ] = sy * idy ; p [ 1 ] [ 3 ] = 0 ;
p [ 2 ] [ 0 ] = 0 ; p [ 2 ] [ 1 ] = 0 ; p [ 2 ] [ 2 ] = - zFar * idz ; p [ 2 ] [ 3 ] = - zFar * zNear * idz ;
p [ 3 ] [ 0 ] = 0 ; p [ 3 ] [ 1 ] = 0 ; p [ 3 ] [ 2 ] = - 1.0f ; p [ 3 ] [ 3 ] = 0 ;
}
// ----------------------------------------------------------------------
// Purpose: Computes and returns the projection matrix for the eye
// ----------------------------------------------------------------------
bool CSourceVirtualReality : : GetEyeProjectionMatrix ( VMatrix * pResult , VREye eEye , float zNear , float zFar , float fovScale )
{
Assert ( pResult ! = NULL ) ;
if ( ! pResult | | ! m_pHmd | | ! m_bActive )
return false ;
float fLeft , fRight , fTop , fBottom ;
m_pHmd - > GetProjectionRaw ( SourceEyeToHmdEye ( eEye ) , & fLeft , & fRight , & fTop , & fBottom ) ;
ComposeProjectionTransform ( fLeft , fRight , fTop , fBottom , zNear , zFar , fovScale , pResult ) ;
return true ;
}
// ----------------------------------------------------------------------
// Purpose: Returns the mid eye from left/right eye part of the view
// matrix transform chain.
// ----------------------------------------------------------------------
VMatrix CSourceVirtualReality : : GetMidEyeFromEye ( VREye eEye )
{
if ( m_pHmd )
{
vr : : HmdMatrix34_t matMidEyeFromEye = m_pHmd - > GetEyeToHeadTransform ( SourceEyeToHmdEye ( eEye ) ) ;
return OpenVRToSourceCoordinateSystem ( VMatrixFrom34 ( matMidEyeFromEye . m ) ) ;
}
else
{
VMatrix mat ;
mat . Identity ( ) ;
return mat ;
}
}
// returns the adapter index to use for VR mode
int CSourceVirtualReality : : GetVRModeAdapter ( )
{
if ( EnsureOpenVRInited ( ) )
{
Assert ( m_pHmd ) ;
return m_pHmd - > GetD3D9AdapterIndex ( ) ;
}
else
{
return - 1 ;
}
}
bool CSourceVirtualReality : : WillDriftInYaw ( )
{
if ( m_pHmd )
return m_pHmd - > GetBoolTrackedDeviceProperty ( vr : : k_unTrackedDeviceIndex_Hmd , Prop_WillDriftInYaw_Bool ) ;
else
return false ;
}
void CSourceVirtualReality : : AcquireNewZeroPose ( )
{
// just let the next tracker update re-zero us
if ( m_pChap )
m_pChap - > ResetZeroPose ( TrackingUniverseSeated ) ;
}
bool CSourceVirtualReality : : SampleTrackingState ( float PlayerGameFov , float fPredictionSeconds )
{
if ( ! m_pHmd | | ! m_bActive )
return false ;
vr : : VREvent_t event ;
while ( m_pHmd - > PollNextEvent ( & event , sizeof ( event ) ) )
{
//ProcessVREvent( event );
}
vr : : TrackedDevicePose_t m_rTrackedDevicePose [ vr : : k_unMaxTrackedDeviceCount ] ;
vr : : VRCompositor ( ) - > WaitGetPoses ( m_rTrackedDevicePose , vr : : k_unMaxTrackedDeviceCount , NULL , 0 ) ;
// If tracker can't return a pose (it's possibly recalibrating itself)
// then we will freeze tracking at its current state, rather than
// snapping it back to the zero position
vr : : TrackedDevicePose_t pose ;
if ( m_pHmd - > IsTrackedDeviceConnected ( k_unTrackedDeviceIndex_Hmd ) )
{
float fSecondsSinceLastVsync ;
m_pHmd - > GetTimeSinceLastVsync ( & fSecondsSinceLastVsync , NULL ) ;
float fFrameDuration = 1.f / m_pHmd - > GetFloatTrackedDeviceProperty ( vr : : k_unTrackedDeviceIndex_Hmd ,
vr : : Prop_DisplayFrequency_Float ) ;
float fPredictedSecondsFromNow = fFrameDuration - fSecondsSinceLastVsync \
+ m_pHmd - > GetFloatTrackedDeviceProperty ( vr : : k_unTrackedDeviceIndex_Hmd ,
vr : : Prop_SecondsFromVsyncToPhotons_Float ) ;
// Use Seated here because everything using this interface or older is expecting a seated experience
m_pHmd - > GetDeviceToAbsoluteTrackingPose ( vr : : TrackingUniverseSeated , fPredictedSecondsFromNow , & pose , 1 ) ;
m_bHaveValidPose = pose . bPoseIsValid ;
}
else
{
m_bHaveValidPose = false ;
}
if ( ! m_bHaveValidPose )
return false ;
m_ZeroFromHeadPose = OpenVRToSourceCoordinateSystem ( VMatrixFrom34 ( pose . mDeviceToAbsoluteTracking . m ) ) ;
return true ;
}
# include "togl/rendermechanism.h"
// ----------------------------------------------------------------------
// Purpose: Performs the distortion required for the HMD display
// ----------------------------------------------------------------------
bool CSourceVirtualReality : : DoDistortionProcessing ( VREye eEye )
{
if ( ! ShouldRunInVR ( ) )
return false ;
if ( ! vr_distortion_enable . GetBool ( ) )
{
return false ;
}
CMatRenderContextPtr pRenderContext ( materials ) ;
IMaterial * pDistortMaterial ;
ITexture * pDistortTexture ;
if ( eEye = = VREye_Left )
pDistortMaterial = m_DistortLeftMaterial ;
else
pDistortMaterial = m_DistortRightMaterial ;
if ( eEye = = VREye_Left )
pDistortTexture = m_pDistortionTextureLeft ;
else
pDistortTexture = m_pDistortionTextureRight ;
if ( ! UsingOffscreenRenderTarget ( ) )
{
// copy the frame buffer to the source texture
ITexture * pFullFrameFB1 = materials - > FindTexture ( " _rt_FullFrameFB1 " , TEXTURE_GROUP_RENDER_TARGET ) ;
if ( ! pFullFrameFB1 )
return false ;
Rect_t r ;
r . x = ! eEye ? 0 : 640 ;
r . y = 0 ;
r . width = 640 ;
r . height = 480 ;
this - > GetViewportBounds ( eEye , & r . x , & r . y , & r . width , & r . height ) ;
pRenderContext - > CopyRenderTargetToTextureEx ( pFullFrameFB1 , 0 , & r , & r ) ;
}
// This is where we are rendering to
uint32_t x , y , w , h ;
x = ! eEye ? 0 : 640 ;
y = 0 ;
w = 640 ;
h = 480 ;
//m_pExtDisplay->GetEyeOutputViewport( SourceEyeToHmdEye( eEye ), &x, &y, &w, &h );
// pRenderContext->DrawScreenSpaceRectangle ( pDistortMaterial,
// x, y, w, h,
// 0, 0, distortionTextureSize-1,distortionTextureSize-1,distortionTextureSize,distortionTextureSize);
static int id = - 1 ;
//static CDynamicFunctionOpenGL< true, GLvoid ( APIENTRY *)(GLenum pname, GLint *params), GLvoid > glGetIntegerv("glGetIntegerv");
// pRenderContext->Bind(pDistortMaterial);
// pRenderContext->Flush( true );
// ShaderAPITextureHandle_t hndl = materials->GetShaderAPITextureBindHandle(pDistortTexture,0,0);
//if(id < 0)
id = materials - > GetShaderAPIGLTexture ( m_pPredistortRT , 0 , 0 ) ;
static int last_tex [ 2 ] = { - 1 , - 1 } ;
// glGetIntegerv(GL_TEXTURE_BINDING_2D, &id);
if ( id > 0 )
last_tex [ eEye ! = VREye_Left ] = id ;
// Msg("tex %d\n", id);
const vr : : VRTextureBounds_t bounds = { 0.0f , 1.0f , 1.0f , 0.0f } ;
vr : : Texture_t eyeTexture = { ( void * ) ( uintptr_t ) last_tex [ eEye ! = VREye_Left ] , vr : : TextureType_OpenGL , vr : : ColorSpace_Gamma } ;
if ( last_tex [ eEye ! = VREye_Left ] < = 0 )
return true ;
materials - > Flush ( ) ;
// if(eEye != VREye_Left)
// return 0;
glFinish ( ) ;
vr : : VRCompositor ( ) - > Submit ( SourceEyeToHmdEye ( eEye ) , & eyeTexture , & bounds ) ;
return true ;
}
// --------------------------------------------------------------------
// Pastes the HUD directly onto the backbuffer / render target, including
// applying the undistort.
// --------------------------------------------------------------------
bool CSourceVirtualReality : : CompositeHud ( VREye eEye , float ndcHudBounds [ 4 ] , bool bDoUndistort , bool bBlackout , bool bTranslucent )
{
// run away if we're not doing VR at all
if ( ! ShouldRunInVR ( ) )
return false ;
bDoUndistort = bDoUndistort & & vr_distortion_enable . GetBool ( ) ;
IMaterial * pDistortHUDMaterial = ( eEye = = VREye_Left ) ? m_DistortHUDLeftMaterial : m_DistortHUDRightMaterial ;
// The translucency flag will enable/disable both blending and alpha test. The only case where we don't want them enabled
// is when we're blacking out the entire screen (we use blending to smooth the edges of the HUD, and we use alpha test to kill
// the pixels outside the HUD). Note that right now I'm not expecting to see a mode with bTranslucent and bBlackout
// both true (maybe happens in sniper mode?).
pDistortHUDMaterial - > SetMaterialVarFlag ( MATERIAL_VAR_TRANSLUCENT , ! bBlackout ) ;
// The ndcHudBounds are the min x, min y, max x, max y of where we want to paste the HUD texture in NDC coordinates
// of the main 3D view. We conver to UV (0->1) space here for the shader.
float huduvs [ 4 ] ;
huduvs [ 0 ] = ndcHudBounds [ 0 ] * 0.5 + 0.5 ;
huduvs [ 1 ] = ndcHudBounds [ 1 ] * 0.5 + 0.5 ;
huduvs [ 2 ] = ndcHudBounds [ 2 ] * 0.5 + 0.5 ;
huduvs [ 3 ] = ndcHudBounds [ 3 ] * 0.5 + 0.5 ;
// Fix up coordinates depending on whether we're rendering to a buffer sized for one eye or two.
// (note that disabling distortion also disables use of the offscreen render target)
if ( vr_distortion_enable . GetBool ( ) & & ! UsingOffscreenRenderTarget ( ) )
{
huduvs [ 0 ] * = 0.5 ;
huduvs [ 2 ] * = 0.5 ;
if ( eEye = = VREye_Right )
{
huduvs [ 0 ] + = 0.5 ;
huduvs [ 2 ] + = 0.5 ;
}
}
IMaterialVar * pVar ;
pVar = pDistortHUDMaterial - > FindVar ( " $distortbounds " , NULL ) ;
if ( pVar )
{
pVar - > SetVecValue ( huduvs , 4 ) ;
}
pVar = pDistortHUDMaterial - > FindVar ( " $hudtranslucent " , NULL ) ;
if ( pVar )
{
pVar - > SetIntValue ( bTranslucent ) ;
}
pVar = pDistortHUDMaterial - > FindVar ( " $hudundistort " , NULL ) ;
if ( pVar )
{
pVar - > SetIntValue ( bDoUndistort ) ;
}
CMatRenderContextPtr pRenderContext ( materials ) ;
uint32_t x , y , w , h ;
x = ! eEye ? 0 : 640 ;
y = 0 ;
w = 640 ;
h = 480 ;
m_pExtDisplay - > GetEyeOutputViewport ( SourceEyeToHmdEye ( eEye ) , & x , & y , & w , & h ) ;
int id = materials - > GetShaderAPIGLTexture ( g_StereoGuiTexture , 0 , 0 ) ;
vr : : Texture_t guiTexture = { ( void * ) ( uintptr_t ) id , vr : : TextureType_OpenGL , vr : : ColorSpace_Gamma } ;
const vr : : VRTextureBounds_t bounds = { 0.0f , 1.0f , 1.0f , 0.0f } ;
vr : : VROverlay ( ) - > SetOverlayTextureBounds ( m_GuiOverlay , & bounds ) ;
vr : : VROverlay ( ) - > SetOverlayTexture ( m_GuiOverlay , & guiTexture ) ;
// pRenderContext->DrawScreenSpaceRectangle ( pDistortHUDMaterial,
// x, y, w, h,
// 0, 0, distortionTextureSize-1,distortionTextureSize-1,distortionTextureSize,distortionTextureSize);
return true ;
}
bool CSourceVirtualReality : : EnsureOpenVRInited ( )
{
if ( m_pHmd )
return true ;
return StartTracker ( ) ;
}
bool CSourceVirtualReality : : StartTracker ( )
{
Assert ( m_pHmd = = NULL ) ;
// Initialize SteamVR
vr : : HmdError err ;
m_pHmd = vr : : VR_Init ( & err , vr : : VRApplication_Scene ) ;
m_pExtDisplay = vr : : VRExtendedDisplay ( ) ;
m_pChap = vr : : VRChaperone ( ) ;
if ( err ! = vr : : VRInitError_None )
{
Msg ( " Unable to initialize HMD tracker. Error code %d \n " , err ) ;
return false ;
}
if ( ! vr : : VRCompositor ( ) )
{
Msg ( " Compositor initialization failed. See log file for details " ) ;
}
vr : : VROverlay ( ) - > CreateOverlay ( " GuiOverlayKey " , " GuiOverlay " , & m_GuiOverlay ) ;
vr : : VROverlay ( ) - > ShowOverlay ( m_GuiOverlay ) ;
m_pChap - > ResetZeroPose ( TrackingUniverseSeated ) ;
m_bHaveValidPose = false ;
m_ZeroFromHeadPose . Identity ( ) ;
return true ;
}
void CSourceVirtualReality : : StopTracker ( )
{
if ( m_pHmd )
{
VR_Shutdown ( ) ;
m_pHmd = NULL ;
}
}
bool CSourceVirtualReality : : ResetTracking ( )
{
StopTracker ( ) ;
return StartTracker ( ) ;
}
bool CSourceVirtualReality : : Activate ( )
{
// init the HMD itself
if ( ! ResetTracking ( ) )
return false ;
m_bActive = true ;
m_bUsingOffscreenRenderTarget = vr_use_offscreen_render_target . GetBool ( ) ;
m_warpMaterial . Init ( " dev/warp " , " Other " ) ;
if ( UsingOffscreenRenderTarget ( ) )
{
m_DistortLeftMaterial . Init ( " vr/vr_distort_texture_left " , " Other " ) ;
m_DistortRightMaterial . Init ( " vr/vr_distort_texture_right " , " Other " ) ;
}
else
{
m_DistortLeftMaterial . Init ( " vr/vr_distort_texture_left_nort " , " Other " ) ;
m_DistortRightMaterial . Init ( " vr/vr_distort_texture_right_nort " , " Other " ) ;
}
m_InWorldUIMaterial . Init ( " vgui/inworldui " , " Other " ) ;
m_InWorldUIOpaqueMaterial . Init ( " vgui/inworldui_opaque " , " Other " ) ;
m_blackMaterial . Init ( " vgui/black " , " Other " ) ;
m_DistortHUDLeftMaterial . Init ( " vr/vr_distort_hud_left " , " Other " ) ;
m_DistortHUDRightMaterial . Init ( " vr/vr_distort_hud_right " , " Other " ) ;
RefreshDistortionTexture ( ) ;
return true ;
}
void CSourceVirtualReality : : Deactivate ( )
{
m_bActive = false ;
m_bShouldForceVRMode = false ;
m_warpMaterial . Shutdown ( ) ;
m_DistortLeftMaterial . Shutdown ( ) ;
m_DistortRightMaterial . Shutdown ( ) ;
m_DistortHUDLeftMaterial . Shutdown ( ) ;
m_DistortHUDRightMaterial . Shutdown ( ) ;
m_InWorldUIMaterial . Shutdown ( ) ;
m_InWorldUIOpaqueMaterial . Shutdown ( ) ;
m_blackMaterial . Shutdown ( ) ;
}
bool CSourceVirtualReality : : ShouldForceVRMode ( )
{
return m_bShouldForceVRMode ;
}
void CSourceVirtualReality : : SetShouldForceVRMode ( )
{
m_bShouldForceVRMode = true ;
}
static VMatrix OpenVRToSourceCoordinateSystem ( const VMatrix & vortex )
{
const float inchesPerMeter = ( float ) ( 39.3700787 ) ;
// From Vortex: X=right, Y=up, Z=backwards, scale is meters.
// To Source: X=forwards, Y=left, Z=up, scale is inches.
//
// s_from_v = [ 0 0 -1 0
// -1 0 0 0
// 0 1 0 0
// 0 0 0 1];
//
// We want to compute vmatrix = s_from_v * vortex * v_from_s; v_from_s = s_from_v'
// Given vortex =
// [00 01 02 03
// 10 11 12 13
// 20 21 22 23
// 30 31 32 33]
//
// s_from_v * vortex * s_from_v' =
// 22 20 -21 -23
// 02 00 -01 -03
// -12 -10 11 13
// -32 -30 31 33
//
const vec_t ( * v ) [ 4 ] = vortex . m ;
VMatrix result (
v [ 2 ] [ 2 ] , v [ 2 ] [ 0 ] , - v [ 2 ] [ 1 ] , - v [ 2 ] [ 3 ] * inchesPerMeter ,
v [ 0 ] [ 2 ] , v [ 0 ] [ 0 ] , - v [ 0 ] [ 1 ] , - v [ 0 ] [ 3 ] * inchesPerMeter ,
- v [ 1 ] [ 2 ] , - v [ 1 ] [ 0 ] , v [ 1 ] [ 1 ] , v [ 1 ] [ 3 ] * inchesPerMeter ,
- v [ 3 ] [ 2 ] , - v [ 3 ] [ 0 ] , v [ 3 ] [ 1 ] , v [ 3 ] [ 3 ] ) ;
return result ;
}
static VMatrix VMatrixFrom44 ( const float v [ 4 ] [ 4 ] )
{
return VMatrix (
v [ 0 ] [ 0 ] , v [ 0 ] [ 1 ] , v [ 0 ] [ 2 ] , v [ 0 ] [ 3 ] ,
v [ 1 ] [ 0 ] , v [ 1 ] [ 1 ] , v [ 1 ] [ 2 ] , v [ 1 ] [ 3 ] ,
v [ 2 ] [ 0 ] , v [ 2 ] [ 1 ] , v [ 2 ] [ 2 ] , v [ 2 ] [ 3 ] ,
v [ 3 ] [ 0 ] , v [ 3 ] [ 1 ] , v [ 3 ] [ 2 ] , v [ 3 ] [ 3 ] ) ;
}
static VMatrix VMatrixFrom34 ( const float v [ 3 ] [ 4 ] )
{
return VMatrix (
v [ 0 ] [ 0 ] , v [ 0 ] [ 1 ] , v [ 0 ] [ 2 ] , v [ 0 ] [ 3 ] ,
v [ 1 ] [ 0 ] , v [ 1 ] [ 1 ] , v [ 1 ] [ 2 ] , v [ 1 ] [ 3 ] ,
v [ 2 ] [ 0 ] , v [ 2 ] [ 1 ] , v [ 2 ] [ 2 ] , v [ 2 ] [ 3 ] ,
0 , 0 , 0 , 1 ) ;
}
static VMatrix VMatrixFrom33 ( const float v [ 3 ] [ 3 ] )
{
return VMatrix (
v [ 0 ] [ 0 ] , v [ 0 ] [ 1 ] , v [ 0 ] [ 2 ] , 0 ,
v [ 1 ] [ 0 ] , v [ 1 ] [ 1 ] , v [ 1 ] [ 2 ] , 0 ,
v [ 2 ] [ 0 ] , v [ 2 ] [ 1 ] , v [ 2 ] [ 2 ] , 0 ,
0 , 0 , 0 , 1 ) ;
}