我主要也是看了各个主要函数调用关系,特别是和显示有关的,因为改代码基本就是在这些地方该。
https://github.com/ValveSoftware/openvr/blob/master/samples/hellovr_opengl/hellovr_opengl_main.cpp
//========= Copyright Valve Corporation ============//
#include
#include
#include
#if defined( OSX )
#include
#include
#include
// Apple's version of glut.h #undef's APIENTRY, redefine it
#define APIENTRY
#else
#include
#endif
#include
#include
#include
#include
#include "shared/lodepng.h"
#include "shared/Matrices.h"
#include "shared/pathtools.h"
#if defined(POSIX)
#include "unistd.h"
#endif
#ifndef _WIN32
#define APIENTRY
#endif
#ifndef _countof
#define _countof(x) (sizeof(x)/sizeof((x)[0]))
#endif
void ThreadSleep( unsigned long nMilliseconds )
{
#if defined(_WIN32)
::Sleep( nMilliseconds );
#elif defined(POSIX)
usleep( nMilliseconds * 1000 );
#endif
}
class CGLRenderModel
{
public:
CGLRenderModel( const std::string & sRenderModelName );
~CGLRenderModel();
bool BInit( const vr::RenderModel_t & vrModel, const vr::RenderModel_TextureMap_t & vrDiffuseTexture );
void Cleanup();
void Draw();
const std::string & GetName() const { return m_sModelName; }
private:
GLuint m_glVertBuffer;
GLuint m_glIndexBuffer;
GLuint m_glVertArray;
GLuint m_glTexture;
GLsizei m_unVertexCount;
std::string m_sModelName;
};
static bool g_bPrintf = true;
//-----------------------------------------------------------------------------
// Purpose:
//------------------------------------------------------------------------------
class CMainApplication
{
public:
CMainApplication( int argc, char *argv[] );
virtual ~CMainApplication();
bool BInit();
bool BInitGL();
bool BInitCompositor();
void SetupRenderModels();
void Shutdown();
void RunMainLoop();
bool HandleInput();
void ProcessVREvent( const vr::VREvent_t & event );
void RenderFrame();
bool SetupTexturemaps();
void SetupScene();
void AddCubeToScene( Matrix4 mat, std::vector &vertdata );
void AddCubeVertex( float fl0, float fl1, float fl2, float fl3, float fl4, std::vector &vertdata );
void RenderControllerAxes();
bool SetupStereoRenderTargets();
void SetupCompanionWindow();
void SetupCameras();
void RenderStereoTargets();
void RenderCompanionWindow();
void RenderScene( vr::Hmd_Eye nEye );
Matrix4 GetHMDMatrixProjectionEye( vr::Hmd_Eye nEye );
Matrix4 GetHMDMatrixPoseEye( vr::Hmd_Eye nEye );
Matrix4 GetCurrentViewProjectionMatrix( vr::Hmd_Eye nEye );
void UpdateHMDMatrixPose();
Matrix4 ConvertSteamVRMatrixToMatrix4( const vr::HmdMatrix34_t &matPose );
GLuint CompileGLShader( const char *pchShaderName, const char *pchVertexShader, const char *pchFragmentShader );
bool CreateAllShaders();
void SetupRenderModelForTrackedDevice( vr::TrackedDeviceIndex_t unTrackedDeviceIndex );
CGLRenderModel *FindOrLoadRenderModel( const char *pchRenderModelName );
private:
bool m_bDebugOpenGL;
bool m_bVerbose;
bool m_bPerf;
bool m_bVblank;
bool m_bGlFinishHack;
vr::IVRSystem *m_pHMD;
vr::IVRRenderModels *m_pRenderModels;
std::string m_strDriver;
std::string m_strDisplay;
vr::TrackedDevicePose_t m_rTrackedDevicePose[ vr::k_unMaxTrackedDeviceCount ];
Matrix4 m_rmat4DevicePose[ vr::k_unMaxTrackedDeviceCount ];
bool m_rbShowTrackedDevice[ vr::k_unMaxTrackedDeviceCount ];
private: // SDL bookkeeping
SDL_Window *m_pCompanionWindow;
uint32_t m_nCompanionWindowWidth;
uint32_t m_nCompanionWindowHeight;
SDL_GLContext m_pContext;
private: // OpenGL bookkeeping
int m_iTrackedControllerCount;
int m_iTrackedControllerCount_Last;
int m_iValidPoseCount;
int m_iValidPoseCount_Last;
bool m_bShowCubes;
std::string m_strPoseClasses; // what classes we saw poses for this frame
char m_rDevClassChar[ vr::k_unMaxTrackedDeviceCount ]; // for each device, a character representing its class
int m_iSceneVolumeWidth;
int m_iSceneVolumeHeight;
int m_iSceneVolumeDepth;
float m_fScaleSpacing;
float m_fScale;
int m_iSceneVolumeInit; // if you want something other than the default 20x20x20
float m_fNearClip;
float m_fFarClip;
GLuint m_iTexture;
unsigned int m_uiVertcount;
GLuint m_glSceneVertBuffer;
GLuint m_unSceneVAO;
GLuint m_unCompanionWindowVAO;
GLuint m_glCompanionWindowIDVertBuffer;
GLuint m_glCompanionWindowIDIndexBuffer;
unsigned int m_uiCompanionWindowIndexSize;
GLuint m_glControllerVertBuffer;
GLuint m_unControllerVAO;
unsigned int m_uiControllerVertcount;
Matrix4 m_mat4HMDPose;
Matrix4 m_mat4eyePosLeft;
Matrix4 m_mat4eyePosRight;
Matrix4 m_mat4ProjectionCenter;
Matrix4 m_mat4ProjectionLeft;
Matrix4 m_mat4ProjectionRight;
struct VertexDataScene
{
Vector3 position;
Vector2 texCoord;
};
struct VertexDataWindow
{
Vector2 position;
Vector2 texCoord;
VertexDataWindow( const Vector2 & pos, const Vector2 tex ) : position(pos), texCoord(tex) { }
};
GLuint m_unSceneProgramID;
GLuint m_unCompanionWindowProgramID;
GLuint m_unControllerTransformProgramID;
GLuint m_unRenderModelProgramID;
GLint m_nSceneMatrixLocation;
GLint m_nControllerMatrixLocation;
GLint m_nRenderModelMatrixLocation;
struct FramebufferDesc
{
GLuint m_nDepthBufferId;
GLuint m_nRenderTextureId;
GLuint m_nRenderFramebufferId;
GLuint m_nResolveTextureId;
GLuint m_nResolveFramebufferId;
};
FramebufferDesc leftEyeDesc;
FramebufferDesc rightEyeDesc;
bool CreateFrameBuffer( int nWidth, int nHeight, FramebufferDesc &framebufferDesc );
uint32_t m_nRenderWidth;
uint32_t m_nRenderHeight;
std::vector< CGLRenderModel * > m_vecRenderModels;
CGLRenderModel *m_rTrackedDeviceToRenderModel[ vr::k_unMaxTrackedDeviceCount ];
};
//-----------------------------------------------------------------------------
// Purpose: Outputs a set of optional arguments to debugging output, using
// the printf format setting specified in fmt*.
//-----------------------------------------------------------------------------
void dprintf( const char *fmt, ... )
{
va_list args;
char buffer[ 2048 ];
va_start( args, fmt );
vsprintf_s( buffer, fmt, args );
va_end( args );
if ( g_bPrintf )
printf( "%s", buffer );
OutputDebugStringA( buffer );
}
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CMainApplication::CMainApplication( int argc, char *argv[] )
: m_pCompanionWindow(NULL)
, m_pContext(NULL)
, m_nCompanionWindowWidth( 640 )
, m_nCompanionWindowHeight( 320 )
, m_unSceneProgramID( 0 )
, m_unCompanionWindowProgramID( 0 )
, m_unControllerTransformProgramID( 0 )
, m_unRenderModelProgramID( 0 )
, m_pHMD( NULL )
, m_pRenderModels( NULL )
, m_bDebugOpenGL( false )
, m_bVerbose( false )
, m_bPerf( false )
, m_bVblank( false )
, m_bGlFinishHack( true )
, m_glControllerVertBuffer( 0 )
, m_unControllerVAO( 0 )
, m_unSceneVAO( 0 )
, m_nSceneMatrixLocation( -1 )
, m_nControllerMatrixLocation( -1 )
, m_nRenderModelMatrixLocation( -1 )
, m_iTrackedControllerCount( 0 )
, m_iTrackedControllerCount_Last( -1 )
, m_iValidPoseCount( 0 )
, m_iValidPoseCount_Last( -1 )
, m_iSceneVolumeInit( 20 )
, m_strPoseClasses("")
, m_bShowCubes( true )
{
for( int i = 1; i < argc; i++ )
{
if( !stricmp( argv[i], "-gldebug" ) )
{
m_bDebugOpenGL = true;
}
else if( !stricmp( argv[i], "-verbose" ) )
{
m_bVerbose = true;
}
else if( !stricmp( argv[i], "-novblank" ) )
{
m_bVblank = false;
}
else if( !stricmp( argv[i], "-noglfinishhack" ) )
{
m_bGlFinishHack = false;
}
else if( !stricmp( argv[i], "-noprintf" ) )
{
g_bPrintf = false;
}
else if ( !stricmp( argv[i], "-cubevolume" ) && ( argc > i + 1 ) && ( *argv[ i + 1 ] != '-' ) )
{
m_iSceneVolumeInit = atoi( argv[ i + 1 ] );
i++;
}
}
// other initialization tasks are done in BInit
memset(m_rDevClassChar, 0, sizeof(m_rDevClassChar));
};
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CMainApplication::~CMainApplication()
{
// work is done in Shutdown
dprintf( "Shutdown" );
}
//-----------------------------------------------------------------------------
// Purpose: Helper to get a string from a tracked device property and turn it
// into a std::string
//-----------------------------------------------------------------------------
std::string GetTrackedDeviceString( vr::IVRSystem *pHmd, vr::TrackedDeviceIndex_t unDevice, vr::TrackedDeviceProperty prop, vr::TrackedPropertyError *peError = NULL )
{
uint32_t unRequiredBufferLen = pHmd->GetStringTrackedDeviceProperty( unDevice, prop, NULL, 0, peError );
if( unRequiredBufferLen == 0 )
return "";
char *pchBuffer = new char[ unRequiredBufferLen ];
unRequiredBufferLen = pHmd->GetStringTrackedDeviceProperty( unDevice, prop, pchBuffer, unRequiredBufferLen, peError );
std::string sResult = pchBuffer;
delete [] pchBuffer;
return sResult;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CMainApplication::BInit()
{
if ( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER ) < 0 )
{
printf("%s - SDL could not initialize! SDL Error: %s\n", __FUNCTION__, SDL_GetError());
return false;
}
// Loading the SteamVR Runtime
vr::EVRInitError eError = vr::VRInitError_None;
m_pHMD = vr::VR_Init( &eError, vr::VRApplication_Scene );
if ( eError != vr::VRInitError_None )
{
m_pHMD = NULL;
char buf[1024];
sprintf_s( buf, sizeof( buf ), "Unable to init VR runtime: %s", vr::VR_GetVRInitErrorAsEnglishDescription( eError ) );
SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_ERROR, "VR_Init Failed", buf, NULL );
return false;
}
m_pRenderModels = (vr::IVRRenderModels *)vr::VR_GetGenericInterface( vr::IVRRenderModels_Version, &eError );
if( !m_pRenderModels )
{
m_pHMD = NULL;
vr::VR_Shutdown();
char buf[1024];
sprintf_s( buf, sizeof( buf ), "Unable to get render model interface: %s", vr::VR_GetVRInitErrorAsEnglishDescription( eError ) );
SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_ERROR, "VR_Init Failed", buf, NULL );
return false;
}
int nWindowPosX = 700;
int nWindowPosY = 100;
Uint32 unWindowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 4 );
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 1 );
//SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY );
SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE );
SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 0 );
SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, 0 );
if( m_bDebugOpenGL )
SDL_GL_SetAttribute( SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG );
m_pCompanionWindow = SDL_CreateWindow( "hellovr", nWindowPosX, nWindowPosY, m_nCompanionWindowWidth, m_nCompanionWindowHeight, unWindowFlags );
if (m_pCompanionWindow == NULL)
{
printf( "%s - Window could not be created! SDL Error: %s\n", __FUNCTION__, SDL_GetError() );
return false;
}
m_pContext = SDL_GL_CreateContext(m_pCompanionWindow);
if (m_pContext == NULL)
{
printf( "%s - OpenGL context could not be created! SDL Error: %s\n", __FUNCTION__, SDL_GetError() );
return false;
}
glewExperimental = GL_TRUE;
GLenum nGlewError = glewInit();
if (nGlewError != GLEW_OK)
{
printf( "%s - Error initializing GLEW! %s\n", __FUNCTION__, glewGetErrorString( nGlewError ) );
return false;
}
glGetError(); // to clear the error caused deep in GLEW
if ( SDL_GL_SetSwapInterval( m_bVblank ? 1 : 0 ) < 0 )
{
printf( "%s - Warning: Unable to set VSync! SDL Error: %s\n", __FUNCTION__, SDL_GetError() );
return false;
}
m_strDriver = "No Driver";
m_strDisplay = "No Display";
m_strDriver = GetTrackedDeviceString( m_pHMD, vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_TrackingSystemName_String );
m_strDisplay = GetTrackedDeviceString( m_pHMD, vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_SerialNumber_String );
std::string strWindowTitle = "hellovr - " + m_strDriver + " " + m_strDisplay;
SDL_SetWindowTitle( m_pCompanionWindow, strWindowTitle.c_str() );
// cube array
m_iSceneVolumeWidth = m_iSceneVolumeInit;
m_iSceneVolumeHeight = m_iSceneVolumeInit;
m_iSceneVolumeDepth = m_iSceneVolumeInit;
m_fScale = 0.3f;
m_fScaleSpacing = 4.0f;
m_fNearClip = 0.1f;
m_fFarClip = 30.0f;
m_iTexture = 0;
m_uiVertcount = 0;
// m_MillisecondsTimer.start(1, this);
// m_SecondsTimer.start(1000, this);
if (!BInitGL())
{
printf("%s - Unable to initialize OpenGL!\n", __FUNCTION__);
return false;
}
if (!BInitCompositor())
{
printf("%s - Failed to initialize VR Compositor!\n", __FUNCTION__);
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Outputs the string in message to debugging output.
// All other parameters are ignored.
// Does not return any meaningful value or reference.
//-----------------------------------------------------------------------------
void APIENTRY DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char* message, const void* userParam)
{
dprintf( "GL Error: %s\n", message );
}
//-----------------------------------------------------------------------------
// Purpose: Initialize OpenGL. Returns true if OpenGL has been successfully
// initialized, false if shaders could not be created.
// If failure occurred in a module other than shaders, the function
// may return true or throw an error.
//-----------------------------------------------------------------------------
bool CMainApplication::BInitGL()
{
if( m_bDebugOpenGL )
{
glDebugMessageCallback( (GLDEBUGPROC)DebugCallback, nullptr);
glDebugMessageControl( GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE );
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
}
if( !CreateAllShaders() )
return false;
SetupTexturemaps();
SetupScene();
SetupCameras();
SetupStereoRenderTargets();
SetupCompanionWindow();
SetupRenderModels();
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Initialize Compositor. Returns true if the compositor was
// successfully initialized, false otherwise.
//-----------------------------------------------------------------------------
bool CMainApplication::BInitCompositor()
{
vr::EVRInitError peError = vr::VRInitError_None;
if ( !vr::VRCompositor() )
{
printf( "Compositor initialization failed. See log file for details\n" );
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMainApplication::Shutdown()
{
if( m_pHMD )
{
vr::VR_Shutdown();
m_pHMD = NULL;
}
for( std::vector< CGLRenderModel * >::iterator i = m_vecRenderModels.begin(); i != m_vecRenderModels.end(); i++ )
{
delete (*i);
}
m_vecRenderModels.clear();
if( m_pContext )
{
if( m_bDebugOpenGL )
{
glDebugMessageControl( GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_FALSE );
glDebugMessageCallback(nullptr, nullptr);
}
glDeleteBuffers(1, &m_glSceneVertBuffer);
if ( m_unSceneProgramID )
{
glDeleteProgram( m_unSceneProgramID );
}
if ( m_unControllerTransformProgramID )
{
glDeleteProgram( m_unControllerTransformProgramID );
}
if ( m_unRenderModelProgramID )
{
glDeleteProgram( m_unRenderModelProgramID );
}
if ( m_unCompanionWindowProgramID )
{
glDeleteProgram( m_unCompanionWindowProgramID );
}
glDeleteRenderbuffers( 1, &leftEyeDesc.m_nDepthBufferId );
glDeleteTextures( 1, &leftEyeDesc.m_nRenderTextureId );
glDeleteFramebuffers( 1, &leftEyeDesc.m_nRenderFramebufferId );
glDeleteTextures( 1, &leftEyeDesc.m_nResolveTextureId );
glDeleteFramebuffers( 1, &leftEyeDesc.m_nResolveFramebufferId );
glDeleteRenderbuffers( 1, &rightEyeDesc.m_nDepthBufferId );
glDeleteTextures( 1, &rightEyeDesc.m_nRenderTextureId );
glDeleteFramebuffers( 1, &rightEyeDesc.m_nRenderFramebufferId );
glDeleteTextures( 1, &rightEyeDesc.m_nResolveTextureId );
glDeleteFramebuffers( 1, &rightEyeDesc.m_nResolveFramebufferId );
if( m_unCompanionWindowVAO != 0 )
{
glDeleteVertexArrays( 1, &m_unCompanionWindowVAO );
}
if( m_unSceneVAO != 0 )
{
glDeleteVertexArrays( 1, &m_unSceneVAO );
}
if( m_unControllerVAO != 0 )
{
glDeleteVertexArrays( 1, &m_unControllerVAO );
}
}
if( m_pCompanionWindow )
{
SDL_DestroyWindow(m_pCompanionWindow);
m_pCompanionWindow = NULL;
}
SDL_Quit();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CMainApplication::HandleInput()
{
SDL_Event sdlEvent;
bool bRet = false;
while ( SDL_PollEvent( &sdlEvent ) != 0 )
{
if ( sdlEvent.type == SDL_QUIT )
{
bRet = true;
}
else if ( sdlEvent.type == SDL_KEYDOWN )
{
if ( sdlEvent.key.keysym.sym == SDLK_ESCAPE
|| sdlEvent.key.keysym.sym == SDLK_q )
{
bRet = true;
}
if( sdlEvent.key.keysym.sym == SDLK_c )
{
m_bShowCubes = !m_bShowCubes;
}
}
}
// Process SteamVR events
vr::VREvent_t event;
while( m_pHMD->PollNextEvent( &event, sizeof( event ) ) )
{
ProcessVREvent( event );
}
// Process SteamVR controller state
for( vr::TrackedDeviceIndex_t unDevice = 0; unDevice < vr::k_unMaxTrackedDeviceCount; unDevice++ )
{
vr::VRControllerState_t state;
if( m_pHMD->GetControllerState( unDevice, &state, sizeof(state) ) )
{
m_rbShowTrackedDevice[ unDevice ] = state.ulButtonPressed == 0;
}
}
return bRet;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMainApplication::RunMainLoop()
{
bool bQuit = false;
SDL_StartTextInput();
SDL_ShowCursor( SDL_DISABLE );
while ( !bQuit )
{
bQuit = HandleInput();
RenderFrame();
}
SDL_StopTextInput();
}
//-----------------------------------------------------------------------------
// Purpose: Processes a single VR event
//-----------------------------------------------------------------------------
void CMainApplication::ProcessVREvent( const vr::VREvent_t & event )
{
switch( event.eventType )
{
case vr::VREvent_TrackedDeviceActivated:
{
SetupRenderModelForTrackedDevice( event.trackedDeviceIndex );
dprintf( "Device %u attached. Setting up render model.\n", event.trackedDeviceIndex );
}
break;
case vr::VREvent_TrackedDeviceDeactivated:
{
dprintf( "Device %u detached.\n", event.trackedDeviceIndex );
}
break;
case vr::VREvent_TrackedDeviceUpdated:
{
dprintf( "Device %u updated.\n", event.trackedDeviceIndex );
}
break;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMainApplication::RenderFrame()
{
// for now as fast as possible
if ( m_pHMD )
{
RenderControllerAxes();
RenderStereoTargets();
RenderCompanionWindow();
vr::Texture_t leftEyeTexture = {(void*)(uintptr_t)leftEyeDesc.m_nResolveTextureId, vr::TextureType_OpenGL, vr::ColorSpace_Gamma };
vr::VRCompositor()->Submit(vr::Eye_Left, &leftEyeTexture );
vr::Texture_t rightEyeTexture = {(void*)(uintptr_t)rightEyeDesc.m_nResolveTextureId, vr::TextureType_OpenGL, vr::ColorSpace_Gamma };
vr::VRCompositor()->Submit(vr::Eye_Right, &rightEyeTexture );
}
if ( m_bVblank && m_bGlFinishHack )
{
//$ HACKHACK. From gpuview profiling, it looks like there is a bug where two renders and a present
// happen right before and after the vsync causing all kinds of jittering issues. This glFinish()
// appears to clear that up. Temporary fix while I try to get nvidia to investigate this problem.
// 1/29/2014 mikesart
glFinish();
}
// SwapWindow
{
SDL_GL_SwapWindow( m_pCompanionWindow );
}
// Clear
{
// We want to make sure the glFinish waits for the entire present to complete, not just the submission
// of the command. So, we do a clear here right here so the glFinish will wait fully for the swap.
glClearColor( 0, 0, 0, 1 );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
}
// Flush and wait for swap.
if ( m_bVblank )
{
glFlush();
glFinish();
}
// Spew out the controller and pose count whenever they change.
if ( m_iTrackedControllerCount != m_iTrackedControllerCount_Last || m_iValidPoseCount != m_iValidPoseCount_Last )
{
m_iValidPoseCount_Last = m_iValidPoseCount;
m_iTrackedControllerCount_Last = m_iTrackedControllerCount;
dprintf( "PoseCount:%d(%s) Controllers:%d\n", m_iValidPoseCount, m_strPoseClasses.c_str(), m_iTrackedControllerCount );
}
UpdateHMDMatrixPose();
}
//-----------------------------------------------------------------------------
// Purpose: Compiles a GL shader program and returns the handle. Returns 0 if
// the shader couldn't be compiled for some reason.
//-----------------------------------------------------------------------------
GLuint CMainApplication::CompileGLShader( const char *pchShaderName, const char *pchVertexShader, const char *pchFragmentShader )
{
GLuint unProgramID = glCreateProgram();
GLuint nSceneVertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource( nSceneVertexShader, 1, &pchVertexShader, NULL);
glCompileShader( nSceneVertexShader );
GLint vShaderCompiled = GL_FALSE;
glGetShaderiv( nSceneVertexShader, GL_COMPILE_STATUS, &vShaderCompiled);
if ( vShaderCompiled != GL_TRUE)
{
dprintf("%s - Unable to compile vertex shader %d!\n", pchShaderName, nSceneVertexShader);
glDeleteProgram( unProgramID );
glDeleteShader( nSceneVertexShader );
return 0;
}
glAttachShader( unProgramID, nSceneVertexShader);
glDeleteShader( nSceneVertexShader ); // the program hangs onto this once it's attached
GLuint nSceneFragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource( nSceneFragmentShader, 1, &pchFragmentShader, NULL);
glCompileShader( nSceneFragmentShader );
GLint fShaderCompiled = GL_FALSE;
glGetShaderiv( nSceneFragmentShader, GL_COMPILE_STATUS, &fShaderCompiled);
if (fShaderCompiled != GL_TRUE)
{
dprintf("%s - Unable to compile fragment shader %d!\n", pchShaderName, nSceneFragmentShader );
glDeleteProgram( unProgramID );
glDeleteShader( nSceneFragmentShader );
return 0;
}
glAttachShader( unProgramID, nSceneFragmentShader );
glDeleteShader( nSceneFragmentShader ); // the program hangs onto this once it's attached
glLinkProgram( unProgramID );
GLint programSuccess = GL_TRUE;
glGetProgramiv( unProgramID, GL_LINK_STATUS, &programSuccess);
if ( programSuccess != GL_TRUE )
{
dprintf("%s - Error linking program %d!\n", pchShaderName, unProgramID);
glDeleteProgram( unProgramID );
return 0;
}
glUseProgram( unProgramID );
glUseProgram( 0 );
return unProgramID;
}
//-----------------------------------------------------------------------------
// Purpose: Creates all the shaders used by HelloVR SDL
//-----------------------------------------------------------------------------
bool CMainApplication::CreateAllShaders()
{
m_unSceneProgramID = CompileGLShader(
"Scene",
// Vertex Shader
"#version 410\n"
"uniform mat4 matrix;\n"
"layout(location = 0) in vec4 position;\n"
"layout(location = 1) in vec2 v2UVcoordsIn;\n"
"layout(location = 2) in vec3 v3NormalIn;\n"
"out vec2 v2UVcoords;\n"
"void main()\n"
"{\n"
" v2UVcoords = v2UVcoordsIn;\n"
" gl_Position = matrix * position;\n"
"}\n",
// Fragment Shader
"#version 410 core\n"
"uniform sampler2D mytexture;\n"
"in vec2 v2UVcoords;\n"
"out vec4 outputColor;\n"
"void main()\n"
"{\n"
" outputColor = texture(mytexture, v2UVcoords);\n"
"}\n"
);
m_nSceneMatrixLocation = glGetUniformLocation( m_unSceneProgramID, "matrix" );
if( m_nSceneMatrixLocation == -1 )
{
dprintf( "Unable to find matrix uniform in scene shader\n" );
return false;
}
m_unControllerTransformProgramID = CompileGLShader(
"Controller",
// vertex shader
"#version 410\n"
"uniform mat4 matrix;\n"
"layout(location = 0) in vec4 position;\n"
"layout(location = 1) in vec3 v3ColorIn;\n"
"out vec4 v4Color;\n"
"void main()\n"
"{\n"
" v4Color.xyz = v3ColorIn; v4Color.a = 1.0;\n"
" gl_Position = matrix * position;\n"
"}\n",
// fragment shader
"#version 410\n"
"in vec4 v4Color;\n"
"out vec4 outputColor;\n"
"void main()\n"
"{\n"
" outputColor = v4Color;\n"
"}\n"
);
m_nControllerMatrixLocation = glGetUniformLocation( m_unControllerTransformProgramID, "matrix" );
if( m_nControllerMatrixLocation == -1 )
{
dprintf( "Unable to find matrix uniform in controller shader\n" );
return false;
}
m_unRenderModelProgramID = CompileGLShader(
"render model",
// vertex shader
"#version 410\n"
"uniform mat4 matrix;\n"
"layout(location = 0) in vec4 position;\n"
"layout(location = 1) in vec3 v3NormalIn;\n"
"layout(location = 2) in vec2 v2TexCoordsIn;\n"
"out vec2 v2TexCoord;\n"
"void main()\n"
"{\n"
" v2TexCoord = v2TexCoordsIn;\n"
" gl_Position = matrix * vec4(position.xyz, 1);\n"
"}\n",
//fragment shader
"#version 410 core\n"
"uniform sampler2D diffuse;\n"
"in vec2 v2TexCoord;\n"
"out vec4 outputColor;\n"
"void main()\n"
"{\n"
" outputColor = texture( diffuse, v2TexCoord);\n"
"}\n"
);
m_nRenderModelMatrixLocation = glGetUniformLocation( m_unRenderModelProgramID, "matrix" );
if( m_nRenderModelMatrixLocation == -1 )
{
dprintf( "Unable to find matrix uniform in render model shader\n" );
return false;
}
m_unCompanionWindowProgramID = CompileGLShader(
"CompanionWindow",
// vertex shader
"#version 410 core\n"
"layout(location = 0) in vec4 position;\n"
"layout(location = 1) in vec2 v2UVIn;\n"
"noperspective out vec2 v2UV;\n"
"void main()\n"
"{\n"
" v2UV = v2UVIn;\n"
" gl_Position = position;\n"
"}\n",
// fragment shader
"#version 410 core\n"
"uniform sampler2D mytexture;\n"
"noperspective in vec2 v2UV;\n"
"out vec4 outputColor;\n"
"void main()\n"
"{\n"
" outputColor = texture(mytexture, v2UV);\n"
"}\n"
);
return m_unSceneProgramID != 0
&& m_unControllerTransformProgramID != 0
&& m_unRenderModelProgramID != 0
&& m_unCompanionWindowProgramID != 0;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CMainApplication::SetupTexturemaps()
{
std::string sExecutableDirectory = Path_StripFilename( Path_GetExecutablePath() );
std::string strFullPath = Path_MakeAbsolute( "../cube_texture.png", sExecutableDirectory );
std::vector imageRGBA;
unsigned nImageWidth, nImageHeight;
unsigned nError = lodepng::decode( imageRGBA, nImageWidth, nImageHeight, strFullPath.c_str() );
if ( nError != 0 )
return false;
glGenTextures(1, &m_iTexture );
glBindTexture( GL_TEXTURE_2D, m_iTexture );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, nImageWidth, nImageHeight,
0, GL_RGBA, GL_UNSIGNED_BYTE, &imageRGBA[0] );
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
GLfloat fLargest;
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest);
glBindTexture( GL_TEXTURE_2D, 0 );
return ( m_iTexture != 0 );
}
//-----------------------------------------------------------------------------
// Purpose: create a sea of cubes
//-----------------------------------------------------------------------------
void CMainApplication::SetupScene()
{
if ( !m_pHMD )
return;
std::vector vertdataarray;
Matrix4 matScale;
matScale.scale( m_fScale, m_fScale, m_fScale );
Matrix4 matTransform;
matTransform.translate(
-( (float)m_iSceneVolumeWidth * m_fScaleSpacing ) / 2.f,
-( (float)m_iSceneVolumeHeight * m_fScaleSpacing ) / 2.f,
-( (float)m_iSceneVolumeDepth * m_fScaleSpacing ) / 2.f);
Matrix4 mat = matScale * matTransform;
for( int z = 0; z< m_iSceneVolumeDepth; z++ )
{
for( int y = 0; y< m_iSceneVolumeHeight; y++ )
{
for( int x = 0; x< m_iSceneVolumeWidth; x++ )
{
AddCubeToScene( mat, vertdataarray );
mat = mat * Matrix4().translate( m_fScaleSpacing, 0, 0 );
}
mat = mat * Matrix4().translate( -((float)m_iSceneVolumeWidth) * m_fScaleSpacing, m_fScaleSpacing, 0 );
}
mat = mat * Matrix4().translate( 0, -((float)m_iSceneVolumeHeight) * m_fScaleSpacing, m_fScaleSpacing );
}
m_uiVertcount = vertdataarray.size()/5;
glGenVertexArrays( 1, &m_unSceneVAO );
glBindVertexArray( m_unSceneVAO );
glGenBuffers( 1, &m_glSceneVertBuffer );
glBindBuffer( GL_ARRAY_BUFFER, m_glSceneVertBuffer );
glBufferData( GL_ARRAY_BUFFER, sizeof(float) * vertdataarray.size(), &vertdataarray[0], GL_STATIC_DRAW);
GLsizei stride = sizeof(VertexDataScene);
uintptr_t offset = 0;
glEnableVertexAttribArray( 0 );
glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, stride , (const void *)offset);
offset += sizeof(Vector3);
glEnableVertexAttribArray( 1 );
glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, stride, (const void *)offset);
glBindVertexArray( 0 );
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMainApplication::AddCubeVertex( float fl0, float fl1, float fl2, float fl3, float fl4, std::vector &vertdata )
{
vertdata.push_back( fl0 );
vertdata.push_back( fl1 );
vertdata.push_back( fl2 );
vertdata.push_back( fl3 );
vertdata.push_back( fl4 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMainApplication::AddCubeToScene( Matrix4 mat, std::vector &vertdata )
{
// Matrix4 mat( outermat.data() );
Vector4 A = mat * Vector4( 0, 0, 0, 1 );
Vector4 B = mat * Vector4( 1, 0, 0, 1 );
Vector4 C = mat * Vector4( 1, 1, 0, 1 );
Vector4 D = mat * Vector4( 0, 1, 0, 1 );
Vector4 E = mat * Vector4( 0, 0, 1, 1 );
Vector4 F = mat * Vector4( 1, 0, 1, 1 );
Vector4 G = mat * Vector4( 1, 1, 1, 1 );
Vector4 H = mat * Vector4( 0, 1, 1, 1 );
// triangles instead of quads
AddCubeVertex( E.x, E.y, E.z, 0, 1, vertdata ); //Front
AddCubeVertex( F.x, F.y, F.z, 1, 1, vertdata );
AddCubeVertex( G.x, G.y, G.z, 1, 0, vertdata );
AddCubeVertex( G.x, G.y, G.z, 1, 0, vertdata );
AddCubeVertex( H.x, H.y, H.z, 0, 0, vertdata );
AddCubeVertex( E.x, E.y, E.z, 0, 1, vertdata );
AddCubeVertex( B.x, B.y, B.z, 0, 1, vertdata ); //Back
AddCubeVertex( A.x, A.y, A.z, 1, 1, vertdata );
AddCubeVertex( D.x, D.y, D.z, 1, 0, vertdata );
AddCubeVertex( D.x, D.y, D.z, 1, 0, vertdata );
AddCubeVertex( C.x, C.y, C.z, 0, 0, vertdata );
AddCubeVertex( B.x, B.y, B.z, 0, 1, vertdata );
AddCubeVertex( H.x, H.y, H.z, 0, 1, vertdata ); //Top
AddCubeVertex( G.x, G.y, G.z, 1, 1, vertdata );
AddCubeVertex( C.x, C.y, C.z, 1, 0, vertdata );
AddCubeVertex( C.x, C.y, C.z, 1, 0, vertdata );
AddCubeVertex( D.x, D.y, D.z, 0, 0, vertdata );
AddCubeVertex( H.x, H.y, H.z, 0, 1, vertdata );
AddCubeVertex( A.x, A.y, A.z, 0, 1, vertdata ); //Bottom
AddCubeVertex( B.x, B.y, B.z, 1, 1, vertdata );
AddCubeVertex( F.x, F.y, F.z, 1, 0, vertdata );
AddCubeVertex( F.x, F.y, F.z, 1, 0, vertdata );
AddCubeVertex( E.x, E.y, E.z, 0, 0, vertdata );
AddCubeVertex( A.x, A.y, A.z, 0, 1, vertdata );
AddCubeVertex( A.x, A.y, A.z, 0, 1, vertdata ); //Left
AddCubeVertex( E.x, E.y, E.z, 1, 1, vertdata );
AddCubeVertex( H.x, H.y, H.z, 1, 0, vertdata );
AddCubeVertex( H.x, H.y, H.z, 1, 0, vertdata );
AddCubeVertex( D.x, D.y, D.z, 0, 0, vertdata );
AddCubeVertex( A.x, A.y, A.z, 0, 1, vertdata );
AddCubeVertex( F.x, F.y, F.z, 0, 1, vertdata ); //Right
AddCubeVertex( B.x, B.y, B.z, 1, 1, vertdata );
AddCubeVertex( C.x, C.y, C.z, 1, 0, vertdata );
AddCubeVertex( C.x, C.y, C.z, 1, 0, vertdata );
AddCubeVertex( G.x, G.y, G.z, 0, 0, vertdata );
AddCubeVertex( F.x, F.y, F.z, 0, 1, vertdata );
}
//-----------------------------------------------------------------------------
// Purpose: Draw all of the controllers as X/Y/Z lines
//-----------------------------------------------------------------------------
void CMainApplication::RenderControllerAxes()
{
// Don't attempt to update controllers if input is not available
if( !m_pHMD->IsInputAvailable() )
return;
std::vector vertdataarray;
m_uiControllerVertcount = 0;
m_iTrackedControllerCount = 0;
for ( vr::TrackedDeviceIndex_t unTrackedDevice = vr::k_unTrackedDeviceIndex_Hmd + 1; unTrackedDevice < vr::k_unMaxTrackedDeviceCount; ++unTrackedDevice )
{
if ( !m_pHMD->IsTrackedDeviceConnected( unTrackedDevice ) )
continue;
if( m_pHMD->GetTrackedDeviceClass( unTrackedDevice ) != vr::TrackedDeviceClass_Controller )
continue;
m_iTrackedControllerCount += 1;
if( !m_rTrackedDevicePose[ unTrackedDevice ].bPoseIsValid )
continue;
const Matrix4 & mat = m_rmat4DevicePose[unTrackedDevice];
Vector4 center = mat * Vector4( 0, 0, 0, 1 );
for ( int i = 0; i < 3; ++i )
{
Vector3 color( 0, 0, 0 );
Vector4 point( 0, 0, 0, 1 );
point[i] += 0.05f; // offset in X, Y, Z
color[i] = 1.0; // R, G, B
point = mat * point;
vertdataarray.push_back( center.x );
vertdataarray.push_back( center.y );
vertdataarray.push_back( center.z );
vertdataarray.push_back( color.x );
vertdataarray.push_back( color.y );
vertdataarray.push_back( color.z );
vertdataarray.push_back( point.x );
vertdataarray.push_back( point.y );
vertdataarray.push_back( point.z );
vertdataarray.push_back( color.x );
vertdataarray.push_back( color.y );
vertdataarray.push_back( color.z );
m_uiControllerVertcount += 2;
}
Vector4 start = mat * Vector4( 0, 0, -0.02f, 1 );
Vector4 end = mat * Vector4( 0, 0, -39.f, 1 );
Vector3 color( .92f, .92f, .71f );
vertdataarray.push_back( start.x );vertdataarray.push_back( start.y );vertdataarray.push_back( start.z );
vertdataarray.push_back( color.x );vertdataarray.push_back( color.y );vertdataarray.push_back( color.z );
vertdataarray.push_back( end.x );vertdataarray.push_back( end.y );vertdataarray.push_back( end.z );
vertdataarray.push_back( color.x );vertdataarray.push_back( color.y );vertdataarray.push_back( color.z );
m_uiControllerVertcount += 2;
}
// Setup the VAO the first time through.
if ( m_unControllerVAO == 0 )
{
glGenVertexArrays( 1, &m_unControllerVAO );
glBindVertexArray( m_unControllerVAO );
glGenBuffers( 1, &m_glControllerVertBuffer );
glBindBuffer( GL_ARRAY_BUFFER, m_glControllerVertBuffer );
GLuint stride = 2 * 3 * sizeof( float );
uintptr_t offset = 0;
glEnableVertexAttribArray( 0 );
glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, stride, (const void *)offset);
offset += sizeof( Vector3 );
glEnableVertexAttribArray( 1 );
glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, stride, (const void *)offset);
glBindVertexArray( 0 );
}
glBindBuffer( GL_ARRAY_BUFFER, m_glControllerVertBuffer );
// set vertex data if we have some
if( vertdataarray.size() > 0 )
{
//$ TODO: Use glBufferSubData for this...
glBufferData( GL_ARRAY_BUFFER, sizeof(float) * vertdataarray.size(), &vertdataarray[0], GL_STREAM_DRAW );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMainApplication::SetupCameras()
{
m_mat4ProjectionLeft = GetHMDMatrixProjectionEye( vr::Eye_Left );
m_mat4ProjectionRight = GetHMDMatrixProjectionEye( vr::Eye_Right );
m_mat4eyePosLeft = GetHMDMatrixPoseEye( vr::Eye_Left );
m_mat4eyePosRight = GetHMDMatrixPoseEye( vr::Eye_Right );
}
//-----------------------------------------------------------------------------
// Purpose: Creates a frame buffer. Returns true if the buffer was set up.
// Returns false if the setup failed.
//-----------------------------------------------------------------------------
bool CMainApplication::CreateFrameBuffer( int nWidth, int nHeight, FramebufferDesc &framebufferDesc )
{
glGenFramebuffers(1, &framebufferDesc.m_nRenderFramebufferId );
glBindFramebuffer(GL_FRAMEBUFFER, framebufferDesc.m_nRenderFramebufferId);
glGenRenderbuffers(1, &framebufferDesc.m_nDepthBufferId);
glBindRenderbuffer(GL_RENDERBUFFER, framebufferDesc.m_nDepthBufferId);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT, nWidth, nHeight );
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, framebufferDesc.m_nDepthBufferId );
glGenTextures(1, &framebufferDesc.m_nRenderTextureId );
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, framebufferDesc.m_nRenderTextureId );
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, nWidth, nHeight, true);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, framebufferDesc.m_nRenderTextureId, 0);
glGenFramebuffers(1, &framebufferDesc.m_nResolveFramebufferId );
glBindFramebuffer(GL_FRAMEBUFFER, framebufferDesc.m_nResolveFramebufferId);
glGenTextures(1, &framebufferDesc.m_nResolveTextureId );
glBindTexture(GL_TEXTURE_2D, framebufferDesc.m_nResolveTextureId );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, nWidth, nHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, framebufferDesc.m_nResolveTextureId, 0);
// check FBO status
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
{
return false;
}
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CMainApplication::SetupStereoRenderTargets()
{
if ( !m_pHMD )
return false;
m_pHMD->GetRecommendedRenderTargetSize( &m_nRenderWidth, &m_nRenderHeight );
CreateFrameBuffer( m_nRenderWidth, m_nRenderHeight, leftEyeDesc );
CreateFrameBuffer( m_nRenderWidth, m_nRenderHeight, rightEyeDesc );
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMainApplication::SetupCompanionWindow()
{
if ( !m_pHMD )
return;
std::vector vVerts;
// left eye verts
vVerts.push_back( VertexDataWindow( Vector2(-1, -1), Vector2(0, 1)) );
vVerts.push_back( VertexDataWindow( Vector2(0, -1), Vector2(1, 1)) );
vVerts.push_back( VertexDataWindow( Vector2(-1, 1), Vector2(0, 0)) );
vVerts.push_back( VertexDataWindow( Vector2(0, 1), Vector2(1, 0)) );
// right eye verts
vVerts.push_back( VertexDataWindow( Vector2(0, -1), Vector2(0, 1)) );
vVerts.push_back( VertexDataWindow( Vector2(1, -1), Vector2(1, 1)) );
vVerts.push_back( VertexDataWindow( Vector2(0, 1), Vector2(0, 0)) );
vVerts.push_back( VertexDataWindow( Vector2(1, 1), Vector2(1, 0)) );
GLushort vIndices[] = { 0, 1, 3, 0, 3, 2, 4, 5, 7, 4, 7, 6};
m_uiCompanionWindowIndexSize = _countof(vIndices);
glGenVertexArrays( 1, &m_unCompanionWindowVAO );
glBindVertexArray( m_unCompanionWindowVAO );
glGenBuffers( 1, &m_glCompanionWindowIDVertBuffer );
glBindBuffer( GL_ARRAY_BUFFER, m_glCompanionWindowIDVertBuffer );
glBufferData( GL_ARRAY_BUFFER, vVerts.size()*sizeof(VertexDataWindow), &vVerts[0], GL_STATIC_DRAW );
glGenBuffers( 1, &m_glCompanionWindowIDIndexBuffer );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_glCompanionWindowIDIndexBuffer );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, m_uiCompanionWindowIndexSize*sizeof(GLushort), &vIndices[0], GL_STATIC_DRAW );
glEnableVertexAttribArray( 0 );
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexDataWindow), (void *)offsetof( VertexDataWindow, position ) );
glEnableVertexAttribArray( 1 );
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(VertexDataWindow), (void *)offsetof( VertexDataWindow, texCoord ) );
glBindVertexArray( 0 );
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMainApplication::RenderStereoTargets()
{
glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
glEnable( GL_MULTISAMPLE );
// Left Eye
glBindFramebuffer( GL_FRAMEBUFFER, leftEyeDesc.m_nRenderFramebufferId );
glViewport(0, 0, m_nRenderWidth, m_nRenderHeight );
RenderScene( vr::Eye_Left );
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
glDisable( GL_MULTISAMPLE );
glBindFramebuffer(GL_READ_FRAMEBUFFER, leftEyeDesc.m_nRenderFramebufferId);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, leftEyeDesc.m_nResolveFramebufferId );
glBlitFramebuffer( 0, 0, m_nRenderWidth, m_nRenderHeight, 0, 0, m_nRenderWidth, m_nRenderHeight,
GL_COLOR_BUFFER_BIT,
GL_LINEAR );
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0 );
glEnable( GL_MULTISAMPLE );
// Right Eye
glBindFramebuffer( GL_FRAMEBUFFER, rightEyeDesc.m_nRenderFramebufferId );
glViewport(0, 0, m_nRenderWidth, m_nRenderHeight );
RenderScene( vr::Eye_Right );
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
glDisable( GL_MULTISAMPLE );
glBindFramebuffer(GL_READ_FRAMEBUFFER, rightEyeDesc.m_nRenderFramebufferId );
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, rightEyeDesc.m_nResolveFramebufferId );
glBlitFramebuffer( 0, 0, m_nRenderWidth, m_nRenderHeight, 0, 0, m_nRenderWidth, m_nRenderHeight,
GL_COLOR_BUFFER_BIT,
GL_LINEAR );
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0 );
}
//-----------------------------------------------------------------------------
// Purpose: Renders a scene with respect to nEye.
//-----------------------------------------------------------------------------
void CMainApplication::RenderScene( vr::Hmd_Eye nEye )
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
if( m_bShowCubes )
{
glUseProgram( m_unSceneProgramID );
glUniformMatrix4fv( m_nSceneMatrixLocation, 1, GL_FALSE, GetCurrentViewProjectionMatrix( nEye ).get() );
glBindVertexArray( m_unSceneVAO );
glBindTexture( GL_TEXTURE_2D, m_iTexture );
glDrawArrays( GL_TRIANGLES, 0, m_uiVertcount );
glBindVertexArray( 0 );
}
bool bIsInputAvailable = m_pHMD->IsInputAvailable();
if( bIsInputAvailable )
{
// draw the controller axis lines
glUseProgram( m_unControllerTransformProgramID );
glUniformMatrix4fv( m_nControllerMatrixLocation, 1, GL_FALSE, GetCurrentViewProjectionMatrix( nEye ).get() );
glBindVertexArray( m_unControllerVAO );
glDrawArrays( GL_LINES, 0, m_uiControllerVertcount );
glBindVertexArray( 0 );
}
// ----- Render Model rendering -----
glUseProgram( m_unRenderModelProgramID );
for( uint32_t unTrackedDevice = 0; unTrackedDevice < vr::k_unMaxTrackedDeviceCount; unTrackedDevice++ )
{
if( !m_rTrackedDeviceToRenderModel[ unTrackedDevice ] || !m_rbShowTrackedDevice[ unTrackedDevice ] )
continue;
const vr::TrackedDevicePose_t & pose = m_rTrackedDevicePose[ unTrackedDevice ];
if( !pose.bPoseIsValid )
continue;
if( !bIsInputAvailable && m_pHMD->GetTrackedDeviceClass( unTrackedDevice ) == vr::TrackedDeviceClass_Controller )
continue;
const Matrix4 & matDeviceToTracking = m_rmat4DevicePose[ unTrackedDevice ];
Matrix4 matMVP = GetCurrentViewProjectionMatrix( nEye ) * matDeviceToTracking;
glUniformMatrix4fv( m_nRenderModelMatrixLocation, 1, GL_FALSE, matMVP.get() );
m_rTrackedDeviceToRenderModel[ unTrackedDevice ]->Draw();
}
glUseProgram( 0 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMainApplication::RenderCompanionWindow()
{
glDisable(GL_DEPTH_TEST);
glViewport( 0, 0, m_nCompanionWindowWidth, m_nCompanionWindowHeight );
glBindVertexArray( m_unCompanionWindowVAO );
glUseProgram( m_unCompanionWindowProgramID );
// render left eye (first half of index array )
glBindTexture(GL_TEXTURE_2D, leftEyeDesc.m_nResolveTextureId );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glDrawElements( GL_TRIANGLES, m_uiCompanionWindowIndexSize/2, GL_UNSIGNED_SHORT, 0 );
// render right eye (second half of index array )
glBindTexture(GL_TEXTURE_2D, rightEyeDesc.m_nResolveTextureId );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glDrawElements( GL_TRIANGLES, m_uiCompanionWindowIndexSize/2, GL_UNSIGNED_SHORT, (const void *)(uintptr_t)(m_uiCompanionWindowIndexSize) );
glBindVertexArray( 0 );
glUseProgram( 0 );
}
//-----------------------------------------------------------------------------
// Purpose: Gets a Matrix Projection Eye with respect to nEye.
//-----------------------------------------------------------------------------
Matrix4 CMainApplication::GetHMDMatrixProjectionEye( vr::Hmd_Eye nEye )
{
if ( !m_pHMD )
return Matrix4();
vr::HmdMatrix44_t mat = m_pHMD->GetProjectionMatrix( nEye, m_fNearClip, m_fFarClip );
return Matrix4(
mat.m[0][0], mat.m[1][0], mat.m[2][0], mat.m[3][0],
mat.m[0][1], mat.m[1][1], mat.m[2][1], mat.m[3][1],
mat.m[0][2], mat.m[1][2], mat.m[2][2], mat.m[3][2],
mat.m[0][3], mat.m[1][3], mat.m[2][3], mat.m[3][3]
);
}
//-----------------------------------------------------------------------------
// Purpose: Gets an HMDMatrixPoseEye with respect to nEye.
//-----------------------------------------------------------------------------
Matrix4 CMainApplication::GetHMDMatrixPoseEye( vr::Hmd_Eye nEye )
{
if ( !m_pHMD )
return Matrix4();
vr::HmdMatrix34_t matEyeRight = m_pHMD->GetEyeToHeadTransform( nEye );
Matrix4 matrixObj(
matEyeRight.m[0][0], matEyeRight.m[1][0], matEyeRight.m[2][0], 0.0,
matEyeRight.m[0][1], matEyeRight.m[1][1], matEyeRight.m[2][1], 0.0,
matEyeRight.m[0][2], matEyeRight.m[1][2], matEyeRight.m[2][2], 0.0,
matEyeRight.m[0][3], matEyeRight.m[1][3], matEyeRight.m[2][3], 1.0f
);
return matrixObj.invert();
}
//-----------------------------------------------------------------------------
// Purpose: Gets a Current View Projection Matrix with respect to nEye,
// which may be an Eye_Left or an Eye_Right.
//-----------------------------------------------------------------------------
Matrix4 CMainApplication::GetCurrentViewProjectionMatrix( vr::Hmd_Eye nEye )
{
Matrix4 matMVP;
if( nEye == vr::Eye_Left )
{
matMVP = m_mat4ProjectionLeft * m_mat4eyePosLeft * m_mat4HMDPose;
}
else if( nEye == vr::Eye_Right )
{
matMVP = m_mat4ProjectionRight * m_mat4eyePosRight * m_mat4HMDPose;
}
return matMVP;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMainApplication::UpdateHMDMatrixPose()
{
if ( !m_pHMD )
return;
vr::VRCompositor()->WaitGetPoses(m_rTrackedDevicePose, vr::k_unMaxTrackedDeviceCount, NULL, 0 );
m_iValidPoseCount = 0;
m_strPoseClasses = "";
for ( int nDevice = 0; nDevice < vr::k_unMaxTrackedDeviceCount; ++nDevice )
{
if ( m_rTrackedDevicePose[nDevice].bPoseIsValid )
{
m_iValidPoseCount++;
m_rmat4DevicePose[nDevice] = ConvertSteamVRMatrixToMatrix4( m_rTrackedDevicePose[nDevice].mDeviceToAbsoluteTracking );
if (m_rDevClassChar[nDevice]==0)
{
switch (m_pHMD->GetTrackedDeviceClass(nDevice))
{
case vr::TrackedDeviceClass_Controller: m_rDevClassChar[nDevice] = 'C'; break;
case vr::TrackedDeviceClass_HMD: m_rDevClassChar[nDevice] = 'H'; break;
case vr::TrackedDeviceClass_Invalid: m_rDevClassChar[nDevice] = 'I'; break;
case vr::TrackedDeviceClass_GenericTracker: m_rDevClassChar[nDevice] = 'G'; break;
case vr::TrackedDeviceClass_TrackingReference: m_rDevClassChar[nDevice] = 'T'; break;
default: m_rDevClassChar[nDevice] = '?'; break;
}
}
m_strPoseClasses += m_rDevClassChar[nDevice];
}
}
if ( m_rTrackedDevicePose[vr::k_unTrackedDeviceIndex_Hmd].bPoseIsValid )
{
m_mat4HMDPose = m_rmat4DevicePose[vr::k_unTrackedDeviceIndex_Hmd];
m_mat4HMDPose.invert();
}
}
//-----------------------------------------------------------------------------
// Purpose: Finds a render model we've already loaded or loads a new one
//-----------------------------------------------------------------------------
CGLRenderModel *CMainApplication::FindOrLoadRenderModel( const char *pchRenderModelName )
{
CGLRenderModel *pRenderModel = NULL;
for( std::vector< CGLRenderModel * >::iterator i = m_vecRenderModels.begin(); i != m_vecRenderModels.end(); i++ )
{
if( !stricmp( (*i)->GetName().c_str(), pchRenderModelName ) )
{
pRenderModel = *i;
break;
}
}
// load the model if we didn't find one
if( !pRenderModel )
{
vr::RenderModel_t *pModel;
vr::EVRRenderModelError error;
while ( 1 )
{
error = vr::VRRenderModels()->LoadRenderModel_Async( pchRenderModelName, &pModel );
if ( error != vr::VRRenderModelError_Loading )
break;
ThreadSleep( 1 );
}
if ( error != vr::VRRenderModelError_None )
{
dprintf( "Unable to load render model %s - %s\n", pchRenderModelName, vr::VRRenderModels()->GetRenderModelErrorNameFromEnum( error ) );
return NULL; // move on to the next tracked device
}
vr::RenderModel_TextureMap_t *pTexture;
while ( 1 )
{
error = vr::VRRenderModels()->LoadTexture_Async( pModel->diffuseTextureId, &pTexture );
if ( error != vr::VRRenderModelError_Loading )
break;
ThreadSleep( 1 );
}
if ( error != vr::VRRenderModelError_None )
{
dprintf( "Unable to load render texture id:%d for render model %s\n", pModel->diffuseTextureId, pchRenderModelName );
vr::VRRenderModels()->FreeRenderModel( pModel );
return NULL; // move on to the next tracked device
}
pRenderModel = new CGLRenderModel( pchRenderModelName );
if ( !pRenderModel->BInit( *pModel, *pTexture ) )
{
dprintf( "Unable to create GL model from render model %s\n", pchRenderModelName );
delete pRenderModel;
pRenderModel = NULL;
}
else
{
m_vecRenderModels.push_back( pRenderModel );
}
vr::VRRenderModels()->FreeRenderModel( pModel );
vr::VRRenderModels()->FreeTexture( pTexture );
}
return pRenderModel;
}
//-----------------------------------------------------------------------------
// Purpose: Create/destroy GL a Render Model for a single tracked device
//-----------------------------------------------------------------------------
void CMainApplication::SetupRenderModelForTrackedDevice( vr::TrackedDeviceIndex_t unTrackedDeviceIndex )
{
if( unTrackedDeviceIndex >= vr::k_unMaxTrackedDeviceCount )
return;
// try to find a model we've already set up
std::string sRenderModelName = GetTrackedDeviceString( m_pHMD, unTrackedDeviceIndex, vr::Prop_RenderModelName_String );
CGLRenderModel *pRenderModel = FindOrLoadRenderModel( sRenderModelName.c_str() );
if( !pRenderModel )
{
std::string sTrackingSystemName = GetTrackedDeviceString( m_pHMD, unTrackedDeviceIndex, vr::Prop_TrackingSystemName_String );
dprintf( "Unable to load render model for tracked device %d (%s.%s)", unTrackedDeviceIndex, sTrackingSystemName.c_str(), sRenderModelName.c_str() );
}
else
{
m_rTrackedDeviceToRenderModel[ unTrackedDeviceIndex ] = pRenderModel;
m_rbShowTrackedDevice[ unTrackedDeviceIndex ] = true;
}
}
//-----------------------------------------------------------------------------
// Purpose: Create/destroy GL Render Models
//-----------------------------------------------------------------------------
void CMainApplication::SetupRenderModels()
{
memset( m_rTrackedDeviceToRenderModel, 0, sizeof( m_rTrackedDeviceToRenderModel ) );
if( !m_pHMD )
return;
for( uint32_t unTrackedDevice = vr::k_unTrackedDeviceIndex_Hmd + 1; unTrackedDevice < vr::k_unMaxTrackedDeviceCount; unTrackedDevice++ )
{
if( !m_pHMD->IsTrackedDeviceConnected( unTrackedDevice ) )
continue;
SetupRenderModelForTrackedDevice( unTrackedDevice );
}
}
//-----------------------------------------------------------------------------
// Purpose: Converts a SteamVR matrix to our local matrix class
//-----------------------------------------------------------------------------
Matrix4 CMainApplication::ConvertSteamVRMatrixToMatrix4( const vr::HmdMatrix34_t &matPose )
{
Matrix4 matrixObj(
matPose.m[0][0], matPose.m[1][0], matPose.m[2][0], 0.0,
matPose.m[0][1], matPose.m[1][1], matPose.m[2][1], 0.0,
matPose.m[0][2], matPose.m[1][2], matPose.m[2][2], 0.0,
matPose.m[0][3], matPose.m[1][3], matPose.m[2][3], 1.0f
);
return matrixObj;
}
//-----------------------------------------------------------------------------
// Purpose: Create/destroy GL Render Models
//-----------------------------------------------------------------------------
CGLRenderModel::CGLRenderModel( const std::string & sRenderModelName )
: m_sModelName( sRenderModelName )
{
m_glIndexBuffer = 0;
m_glVertArray = 0;
m_glVertBuffer = 0;
m_glTexture = 0;
}
CGLRenderModel::~CGLRenderModel()
{
Cleanup();
}
//-----------------------------------------------------------------------------
// Purpose: Allocates and populates the GL resources for a render model
//-----------------------------------------------------------------------------
bool CGLRenderModel::BInit( const vr::RenderModel_t & vrModel, const vr::RenderModel_TextureMap_t & vrDiffuseTexture )
{
// create and bind a VAO to hold state for this model
glGenVertexArrays( 1, &m_glVertArray );
glBindVertexArray( m_glVertArray );
// Populate a vertex buffer
glGenBuffers( 1, &m_glVertBuffer );
glBindBuffer( GL_ARRAY_BUFFER, m_glVertBuffer );
glBufferData( GL_ARRAY_BUFFER, sizeof( vr::RenderModel_Vertex_t ) * vrModel.unVertexCount, vrModel.rVertexData, GL_STATIC_DRAW );
// Identify the components in the vertex buffer
glEnableVertexAttribArray( 0 );
glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, sizeof( vr::RenderModel_Vertex_t ), (void *)offsetof( vr::RenderModel_Vertex_t, vPosition ) );
glEnableVertexAttribArray( 1 );
glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, sizeof( vr::RenderModel_Vertex_t ), (void *)offsetof( vr::RenderModel_Vertex_t, vNormal ) );
glEnableVertexAttribArray( 2 );
glVertexAttribPointer( 2, 2, GL_FLOAT, GL_FALSE, sizeof( vr::RenderModel_Vertex_t ), (void *)offsetof( vr::RenderModel_Vertex_t, rfTextureCoord ) );
// Create and populate the index buffer
glGenBuffers( 1, &m_glIndexBuffer );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_glIndexBuffer );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof( uint16_t ) * vrModel.unTriangleCount * 3, vrModel.rIndexData, GL_STATIC_DRAW );
glBindVertexArray( 0 );
// create and populate the texture
glGenTextures(1, &m_glTexture );
glBindTexture( GL_TEXTURE_2D, m_glTexture );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, vrDiffuseTexture.unWidth, vrDiffuseTexture.unHeight,
0, GL_RGBA, GL_UNSIGNED_BYTE, vrDiffuseTexture.rubTextureMapData );
// If this renders black ask McJohn what's wrong.
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
GLfloat fLargest;
glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest );
glBindTexture( GL_TEXTURE_2D, 0 );
m_unVertexCount = vrModel.unTriangleCount * 3;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Frees the GL resources for a render model
//-----------------------------------------------------------------------------
void CGLRenderModel::Cleanup()
{
if( m_glVertBuffer )
{
glDeleteBuffers(1, &m_glIndexBuffer);
glDeleteVertexArrays( 1, &m_glVertArray );
glDeleteBuffers(1, &m_glVertBuffer);
m_glIndexBuffer = 0;
m_glVertArray = 0;
m_glVertBuffer = 0;
}
}
//-----------------------------------------------------------------------------
// Purpose: Draws the render model
//-----------------------------------------------------------------------------
void CGLRenderModel::Draw()
{
glBindVertexArray( m_glVertArray );
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, m_glTexture );
glDrawElements( GL_TRIANGLES, m_unVertexCount, GL_UNSIGNED_SHORT, 0 );
glBindVertexArray( 0 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int main(int argc, char *argv[])
{
CMainApplication *pMainApplication = new CMainApplication( argc, argv );
if (!pMainApplication->BInit())
{
pMainApplication->Shutdown();
return 1;
}
pMainApplication->RunMainLoop();
pMainApplication->Shutdown();
return 0;
}