mirror of
https://github.com/bulletphysics/bullet3
synced 2024-12-14 22:00:05 +00:00
2351 lines
69 KiB
C++
2351 lines
69 KiB
C++
#ifdef BT_ENABLE_VR
|
|
#ifdef BT_USE_CUSTOM_PROFILER
|
|
#endif
|
|
|
|
//========= Copyright Valve Corporation ============//
|
|
|
|
#include "../OpenGLWindow/SimpleOpenGL3App.h"
|
|
#include "../OpenGLWindow/OpenGLInclude.h"
|
|
#include "Bullet3Common/b3Quaternion.h"
|
|
#include "Bullet3Common/b3Transform.h"
|
|
#include "Bullet3Common/b3CommandLineArgs.h"
|
|
|
|
#include "../Utils/b3Clock.h"
|
|
#include "../Utils/ChromeTraceUtil.h"
|
|
#include "../ExampleBrowser/OpenGLGuiHelper.h"
|
|
#include "../CommonInterfaces/CommonExampleInterface.h"
|
|
#include "../CommonInterfaces/CommonGUIHelperInterface.h"
|
|
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
|
|
#include "BulletCollision/CollisionShapes/btCollisionShape.h"
|
|
#include "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h"
|
|
|
|
#include "LinearMath/btIDebugDraw.h"
|
|
int gSharedMemoryKey = -1;
|
|
int gDebugDrawFlags = 0;
|
|
bool gDisplayDistortion = false;
|
|
bool gDisableDesktopGL = false;
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <string>
|
|
#include <cstdlib>
|
|
|
|
#include <openvr.h>
|
|
|
|
#include "lodepng.h"
|
|
#include "Matrices.h"
|
|
#include "pathtools.h"
|
|
|
|
CommonExampleInterface* sExample;
|
|
|
|
int sPrevPacketNum=0;
|
|
OpenGLGuiHelper* sGuiPtr = 0;
|
|
|
|
|
|
static vr::VRControllerState_t sPrevStates[vr::k_unMaxTrackedDeviceCount] = { 0 };
|
|
|
|
|
|
#if defined(POSIX)
|
|
#include "unistd.h"
|
|
#endif
|
|
#ifdef _WIN32
|
|
#include <Windows.h>
|
|
#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 getControllerTransform(int unDevice, b3Transform& tr);
|
|
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<float> &vertdata );
|
|
void AddCubeVertex( float fl0, float fl1, float fl2, float fl3, float fl4, std::vector<float> &vertdata );
|
|
|
|
void DrawControllers();
|
|
|
|
bool SetupStereoRenderTargets();
|
|
void SetupDistortion();
|
|
void SetupCameras();
|
|
|
|
void RenderStereoTargets();
|
|
void RenderDistortion();
|
|
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 );
|
|
|
|
SimpleOpenGL3App* getApp() { return m_app;}
|
|
|
|
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:
|
|
SimpleOpenGL3App* m_app;
|
|
uint32_t m_nWindowWidth;
|
|
uint32_t m_nWindowHeight;
|
|
bool m_hasContext;
|
|
b3Clock m_clock;
|
|
|
|
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_unLensVAO;
|
|
GLuint m_glIDVertBuffer;
|
|
GLuint m_glIDIndexBuffer;
|
|
unsigned int m_uiIndexSize;
|
|
|
|
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 VertexDataLens
|
|
{
|
|
Vector2 position;
|
|
Vector2 texCoordRed;
|
|
Vector2 texCoordGreen;
|
|
Vector2 texCoordBlue;
|
|
};
|
|
|
|
GLuint m_unSceneProgramID;
|
|
GLuint m_unLensProgramID;
|
|
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: Constructor
|
|
//-----------------------------------------------------------------------------
|
|
CMainApplication::CMainApplication( int argc, char *argv[] )
|
|
: m_app(NULL)
|
|
, m_hasContext(false)
|
|
, m_nWindowWidth( 1280 )
|
|
, m_nWindowHeight( 720 )
|
|
, m_unSceneProgramID( 0 )
|
|
, m_unLensProgramID( 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_unLensVAO( 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( false )
|
|
{
|
|
|
|
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
|
|
b3Printf( "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;
|
|
}
|
|
|
|
|
|
b3KeyboardCallback prevKeyboardCallback = 0;
|
|
|
|
void MyKeyboardCallback(int key, int state)
|
|
{
|
|
if (key == 'p')
|
|
{
|
|
if (state)
|
|
{
|
|
b3ChromeUtilsStartTimings();
|
|
}
|
|
else
|
|
{
|
|
b3ChromeUtilsStopTimingsAndWriteJsonFile();
|
|
}
|
|
}
|
|
if (sExample)
|
|
{
|
|
sExample->keyboardCallback(key,state);
|
|
}
|
|
|
|
if (prevKeyboardCallback)
|
|
prevKeyboardCallback(key,state);
|
|
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
bool CMainApplication::BInit()
|
|
{
|
|
|
|
// 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 ) );
|
|
b3Warning( "VR_Init Failed %s", buf);
|
|
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 ) );
|
|
b3Warning( "VR_Init Failed %s", buf);
|
|
return false;
|
|
}
|
|
|
|
// int nWindowPosX = 700;
|
|
// int nWindowPosY = 100;
|
|
m_nWindowWidth = 1280;
|
|
m_nWindowHeight = 720;
|
|
|
|
/*
|
|
|
|
//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_app = new SimpleOpenGL3App("SimpleOpenGL3App",m_nWindowWidth,m_nWindowHeight,true);
|
|
|
|
|
|
sGuiPtr = new OpenGLGuiHelper(m_app,false);
|
|
sGuiPtr->setVRMode(true);
|
|
|
|
//sGuiPtr = new DummyGUIHelper;
|
|
|
|
prevKeyboardCallback = m_app->m_window->getKeyboardCallback();
|
|
m_app->m_window->setKeyboardCallback(MyKeyboardCallback);
|
|
|
|
CommonExampleOptions options(sGuiPtr);
|
|
|
|
sExample = StandaloneExampleCreateFunc(options);
|
|
sExample->initPhysics();
|
|
sExample->resetCamera();
|
|
|
|
#if 0
|
|
int cubeIndex = m_app->registerCubeShape(1,1,1);
|
|
|
|
b3Quaternion orn(0,0,0,1);
|
|
|
|
{
|
|
b3Vector3 color=b3MakeVector3(0.3,0.3,0.6);
|
|
b3Vector3 pos = b3MakeVector3(0,0,0);
|
|
b3Vector3 scaling=b3MakeVector3 (1,.1,1);
|
|
m_app->m_renderer->registerGraphicsInstance(cubeIndex,pos,orn,color,scaling);
|
|
}
|
|
{
|
|
b3Vector3 color=b3MakeVector3(0.3,0.6,0.3);
|
|
b3Vector3 pos = b3MakeVector3(0,0.3,0);
|
|
b3Vector3 scaling=b3MakeVector3 (.1,.1,.1);
|
|
m_app->m_renderer->registerGraphicsInstance(cubeIndex,pos,orn,color,scaling);
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
m_app->m_renderer->writeTransforms();
|
|
|
|
|
|
|
|
/* if (m_pWindow == NULL)
|
|
{
|
|
printf( "%s - Window could not be created! SDL Error: %s\n", __FUNCTION__, SDL_GetError() );
|
|
return false;
|
|
}
|
|
*/
|
|
|
|
/*m_pContext = SDL_GL_CreateContext(m_pWindow);
|
|
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_bullet - " + m_strDriver + " " + m_strDisplay;
|
|
m_app->m_window->setWindowTitle(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 = 3000.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:
|
|
//-----------------------------------------------------------------------------
|
|
/*void APIENTRY DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char* message, const void* userParam)
|
|
{
|
|
b3Printf( "GL Error: %s\n", message );
|
|
}
|
|
*/
|
|
|
|
static void APIENTRY DebugCallback (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, GLvoid* userParam)
|
|
{
|
|
b3Printf( "GL Error: %s\n", message );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
bool CMainApplication::BInitGL()
|
|
{
|
|
if( m_bDebugOpenGL )
|
|
{
|
|
const GLvoid *userParam=0;
|
|
glDebugMessageCallback(DebugCallback, userParam);
|
|
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();
|
|
SetupDistortion();
|
|
|
|
SetupRenderModels();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
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_hasContext)
|
|
{
|
|
if (m_glSceneVertBuffer)
|
|
{
|
|
glDebugMessageControl( GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_FALSE );
|
|
glDebugMessageCallback(nullptr, nullptr);
|
|
glDeleteBuffers(1, &m_glSceneVertBuffer);
|
|
glDeleteBuffers(1, &m_glIDVertBuffer);
|
|
glDeleteBuffers(1, &m_glIDIndexBuffer);
|
|
}
|
|
|
|
if ( m_unSceneProgramID )
|
|
{
|
|
glDeleteProgram( m_unSceneProgramID );
|
|
}
|
|
if ( m_unControllerTransformProgramID )
|
|
{
|
|
glDeleteProgram( m_unControllerTransformProgramID );
|
|
}
|
|
if ( m_unRenderModelProgramID )
|
|
{
|
|
glDeleteProgram( m_unRenderModelProgramID );
|
|
}
|
|
if ( m_unLensProgramID )
|
|
{
|
|
glDeleteProgram( m_unLensProgramID );
|
|
}
|
|
|
|
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_unLensVAO != 0 )
|
|
{
|
|
glDeleteVertexArrays( 1, &m_unLensVAO );
|
|
}
|
|
if( m_unSceneVAO != 0 )
|
|
{
|
|
glDeleteVertexArrays( 1, &m_unSceneVAO );
|
|
}
|
|
if( m_unControllerVAO != 0 )
|
|
{
|
|
glDeleteVertexArrays( 1, &m_unControllerVAO );
|
|
}
|
|
}
|
|
|
|
if (sExample)
|
|
{
|
|
sExample->exitPhysics();
|
|
delete sExample;
|
|
}
|
|
delete m_app;
|
|
m_app=0;
|
|
|
|
}
|
|
|
|
|
|
void CMainApplication::getControllerTransform(int unDevice, b3Transform& tr)
|
|
{
|
|
const Matrix4 & matOrg = m_rmat4DevicePose[unDevice];
|
|
tr.setIdentity();
|
|
tr.setOrigin(b3MakeVector3(matOrg[12],matOrg[13],matOrg[14]));//pos[1]));
|
|
b3Matrix3x3 bmat;
|
|
for (int i=0;i<3;i++)
|
|
{
|
|
for (int j=0;j<3;j++)
|
|
{
|
|
bmat[i][j] = matOrg[i+4*j];
|
|
}
|
|
}
|
|
tr.setBasis(bmat);
|
|
b3Transform y2z;
|
|
y2z.setIdentity();
|
|
y2z.setRotation(b3Quaternion(0,B3_HALF_PI,0));
|
|
tr = y2z*tr;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
bool CMainApplication::HandleInput()
|
|
{
|
|
bool bRet = false;
|
|
|
|
// 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(vr::VRControllerState_t)) )
|
|
{
|
|
b3Transform tr;
|
|
getControllerTransform(unDevice, tr);
|
|
float pos[3] = { tr.getOrigin()[0], tr.getOrigin()[1], tr.getOrigin()[2] };
|
|
b3Quaternion born = tr.getRotation();
|
|
float orn[4] = { born[0], born[1], born[2], born[3] };
|
|
|
|
//we need to have the 'move' events, so no early out here
|
|
//if (sPrevStates[unDevice].unPacketNum != state.unPacketNum)
|
|
if( m_pHMD->GetTrackedDeviceClass( unDevice) == vr::TrackedDeviceClass_HMD )
|
|
{
|
|
Matrix4 rotYtoZ = rotYtoZ.identity();
|
|
//some Bullet apps (especially robotics related) require Z as up-axis)
|
|
if (m_app->getUpAxis()==2)
|
|
{
|
|
rotYtoZ.rotateX(-90);
|
|
}
|
|
Matrix4 viewMatCenter = m_mat4HMDPose * rotYtoZ;
|
|
const float* mat = viewMatCenter.invertAffine().get();
|
|
pos[0] = mat[12];
|
|
pos[1] = mat[13];
|
|
pos[2] = mat[14];
|
|
|
|
b3Matrix3x3 bmat;
|
|
for (int i=0;i<3;i++)
|
|
{
|
|
for (int j=0;j<3;j++)
|
|
{
|
|
bmat[i][j] = mat[i+4*j];
|
|
}
|
|
}
|
|
b3Quaternion orn2;
|
|
bmat.getRotation(orn2);
|
|
orn[0] = orn2[0];
|
|
orn[1] = orn2[1];
|
|
orn[2] = orn2[2];
|
|
orn[3] = orn2[3];
|
|
sExample->vrHMDMoveCallback(unDevice, pos,orn);
|
|
}
|
|
|
|
if( m_pHMD->GetTrackedDeviceClass( unDevice) == vr::TrackedDeviceClass_GenericTracker )
|
|
{
|
|
sExample->vrGenericTrackerMoveCallback(unDevice, pos,orn);
|
|
}
|
|
|
|
if( m_pHMD->GetTrackedDeviceClass( unDevice) == vr::TrackedDeviceClass_Controller )
|
|
{
|
|
sPrevStates[unDevice].unPacketNum = state.unPacketNum;
|
|
|
|
for (int button = 0; button < vr::k_EButton_Max; button++)
|
|
{
|
|
uint64_t trigger = vr::ButtonMaskFromId((vr::EVRButtonId)button);
|
|
|
|
bool isTrigger = (state.ulButtonPressed&trigger) != 0;
|
|
if (isTrigger)
|
|
{
|
|
|
|
|
|
//pressed now, not pressed before -> raise a button down event
|
|
if ((sPrevStates[unDevice].ulButtonPressed&trigger)==0)
|
|
{
|
|
// printf("Device PRESSED: %d, button %d\n", unDevice, button);
|
|
if (button==2)
|
|
{
|
|
//glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
|
|
///todo(erwincoumans) can't use reguar debug drawer, because physics/graphics are not in sync
|
|
///so it can (and likely will) cause crashes
|
|
///add a special debug drawer that deals with this
|
|
//gDebugDrawFlags = btIDebugDraw::DBG_DrawWireframe+btIDebugDraw::DBG_DrawContactPoints+
|
|
//btIDebugDraw::DBG_DrawConstraintLimits+
|
|
//btIDebugDraw::DBG_DrawConstraints
|
|
//;
|
|
//gDebugDrawFlags = btIDebugDraw::DBG_DrawFrames;
|
|
|
|
|
|
|
|
}
|
|
|
|
sExample->vrControllerButtonCallback(unDevice, button, 1, pos, orn);
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
// printf("Device MOVED: %d\n", unDevice);
|
|
sExample->vrControllerMoveCallback(unDevice, pos, orn, state.rAxis[1].x);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( m_pHMD->GetTrackedDeviceClass( unDevice) == vr::TrackedDeviceClass_Controller )
|
|
{
|
|
|
|
|
|
// printf("Device RELEASED: %d, button %d\n", unDevice,button);
|
|
|
|
//not pressed now, but pressed before -> raise a button up event
|
|
if ((sPrevStates[unDevice].ulButtonPressed&trigger) != 0)
|
|
{
|
|
if (button==2)
|
|
{
|
|
gDebugDrawFlags = 0;
|
|
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL);
|
|
}
|
|
|
|
sExample->vrControllerButtonCallback(unDevice, button, 0, pos, orn);
|
|
} else
|
|
{
|
|
|
|
sExample->vrControllerMoveCallback(unDevice, pos, orn, state.rAxis[1].x);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// m_rbShowTrackedDevice[ unDevice ] = state.ulButtonPressed == 0;
|
|
}
|
|
sPrevStates[unDevice] = state;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CMainApplication::RunMainLoop()
|
|
{
|
|
bool bQuit = false;
|
|
|
|
while ( !bQuit && !m_app->m_window->requestedExit())
|
|
{
|
|
b3ChromeUtilsEnableProfiling();
|
|
{
|
|
B3_PROFILE("main");
|
|
|
|
bQuit = HandleInput();
|
|
|
|
RenderFrame();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Processes a single VR event
|
|
//-----------------------------------------------------------------------------
|
|
void CMainApplication::ProcessVREvent( const vr::VREvent_t & event )
|
|
{
|
|
switch( event.eventType )
|
|
{
|
|
case vr::VREvent_TrackedDeviceActivated:
|
|
{
|
|
SetupRenderModelForTrackedDevice( event.trackedDeviceIndex );
|
|
b3Printf( "Device %u attached. Setting up render model.\n", event.trackedDeviceIndex );
|
|
}
|
|
break;
|
|
case vr::VREvent_TrackedDeviceDeactivated:
|
|
{
|
|
b3Printf( "Device %u detached.\n", event.trackedDeviceIndex );
|
|
}
|
|
break;
|
|
case vr::VREvent_TrackedDeviceUpdated:
|
|
{
|
|
b3Printf( "Device %u updated.\n", event.trackedDeviceIndex );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CMainApplication::RenderFrame()
|
|
{
|
|
// for now as fast as possible
|
|
if ( m_pHMD )
|
|
{
|
|
{
|
|
B3_PROFILE("DrawControllers");
|
|
DrawControllers();
|
|
}
|
|
RenderStereoTargets();
|
|
|
|
if (!gDisableDesktopGL)
|
|
{
|
|
if (gDisplayDistortion)
|
|
{
|
|
B3_PROFILE("RenderDistortion");
|
|
RenderDistortion();
|
|
} else
|
|
{
|
|
//todo: should use framebuffer_multisample_blit_scaled
|
|
//See https://twitter.com/id_aa_carmack/status/268488838425481217?lang=en
|
|
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
|
|
glDisable( GL_MULTISAMPLE );
|
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, rightEyeDesc.m_nRenderFramebufferId );
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
|
|
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 );
|
|
}
|
|
}
|
|
|
|
vr::Texture_t leftEyeTexture = {(void*)leftEyeDesc.m_nResolveTextureId, vr::TextureType_OpenGL, vr::ColorSpace_Gamma };
|
|
vr::VRCompositor()->Submit(vr::Eye_Left, &leftEyeTexture );
|
|
vr::Texture_t rightEyeTexture = {(void*)rightEyeDesc.m_nResolveTextureId, vr::TextureType_OpenGL, vr::ColorSpace_Gamma };
|
|
vr::VRCompositor()->Submit(vr::Eye_Right, &rightEyeTexture );
|
|
|
|
}
|
|
|
|
if ( m_bVblank && m_bGlFinishHack )
|
|
{
|
|
B3_PROFILE("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
|
|
{
|
|
B3_PROFILE("m_app->swapBuffer");
|
|
if (!gDisableDesktopGL)
|
|
{
|
|
m_app->swapBuffer();
|
|
}
|
|
//SDL_GL_SwapWindow( m_pWindow );
|
|
|
|
}
|
|
|
|
// Clear
|
|
{
|
|
B3_PROFILE("glClearColor");
|
|
// 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 )
|
|
{
|
|
B3_PROFILE("glFlushglFinish");
|
|
|
|
glFlush();
|
|
glFinish();
|
|
}
|
|
|
|
// Spew out the controller and pose count whenever they change.
|
|
if ( m_iTrackedControllerCount != m_iTrackedControllerCount_Last || m_iValidPoseCount != m_iValidPoseCount_Last )
|
|
{
|
|
B3_PROFILE("debug pose");
|
|
|
|
m_iValidPoseCount_Last = m_iValidPoseCount;
|
|
m_iTrackedControllerCount_Last = m_iTrackedControllerCount;
|
|
|
|
b3Printf( "PoseCount:%d(%s) Controllers:%d\n", m_iValidPoseCount, m_strPoseClasses.c_str(), m_iTrackedControllerCount );
|
|
}
|
|
|
|
{
|
|
B3_PROFILE("UpdateHMDMatrixPose");
|
|
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)
|
|
{
|
|
b3Printf("%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)
|
|
{
|
|
b3Printf("%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 )
|
|
{
|
|
b3Printf("%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 )
|
|
{
|
|
b3Printf( "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 )
|
|
{
|
|
b3Printf( "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 )
|
|
{
|
|
b3Printf( "Unable to find matrix uniform in render model shader\n" );
|
|
return false;
|
|
}
|
|
|
|
m_unLensProgramID = CompileGLShader(
|
|
"Distortion",
|
|
|
|
// vertex shader
|
|
"#version 410 core\n"
|
|
"layout(location = 0) in vec4 position;\n"
|
|
"layout(location = 1) in vec2 v2UVredIn;\n"
|
|
"layout(location = 2) in vec2 v2UVGreenIn;\n"
|
|
"layout(location = 3) in vec2 v2UVblueIn;\n"
|
|
"noperspective out vec2 v2UVred;\n"
|
|
"noperspective out vec2 v2UVgreen;\n"
|
|
"noperspective out vec2 v2UVblue;\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" v2UVred = v2UVredIn;\n"
|
|
" v2UVgreen = v2UVGreenIn;\n"
|
|
" v2UVblue = v2UVblueIn;\n"
|
|
" gl_Position = position;\n"
|
|
"}\n",
|
|
|
|
// fragment shader
|
|
"#version 410 core\n"
|
|
"uniform sampler2D mytexture;\n"
|
|
|
|
"noperspective in vec2 v2UVred;\n"
|
|
"noperspective in vec2 v2UVgreen;\n"
|
|
"noperspective in vec2 v2UVblue;\n"
|
|
|
|
"out vec4 outputColor;\n"
|
|
|
|
"void main()\n"
|
|
"{\n"
|
|
" float fBoundsCheck = ( (dot( vec2( lessThan( v2UVgreen.xy, vec2(0.05, 0.05)) ), vec2(1.0, 1.0))+dot( vec2( greaterThan( v2UVgreen.xy, vec2( 0.95, 0.95)) ), vec2(1.0, 1.0))) );\n"
|
|
" if( fBoundsCheck > 1.0 )\n"
|
|
" { outputColor = vec4( 0, 0, 0, 1.0 ); }\n"
|
|
" else\n"
|
|
" {\n"
|
|
" float red = texture(mytexture, v2UVred).x;\n"
|
|
" float green = texture(mytexture, v2UVgreen).y;\n"
|
|
" float blue = texture(mytexture, v2UVblue).z;\n"
|
|
" outputColor = vec4( red, green, blue, 1.0 ); }\n"
|
|
"}\n"
|
|
);
|
|
|
|
|
|
return m_unSceneProgramID != 0
|
|
&& m_unControllerTransformProgramID != 0
|
|
&& m_unRenderModelProgramID != 0
|
|
&& m_unLensProgramID != 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
bool CMainApplication::SetupTexturemaps()
|
|
{
|
|
std::string sExecutableDirectory = Path_StripFilename( Path_GetExecutablePath() );
|
|
std::string strFullPath = Path_MakeAbsolute( "../cube_texture.png", sExecutableDirectory );
|
|
|
|
std::vector<unsigned char> 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<float> 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);
|
|
|
|
glBindBuffer( GL_ARRAY_BUFFER, m_glSceneVertBuffer );
|
|
|
|
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);
|
|
|
|
m_hasContext = true;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CMainApplication::AddCubeVertex( float fl0, float fl1, float fl2, float fl3, float fl4, std::vector<float> &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<float> &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
|
|
//-----------------------------------------------------------------------------
|
|
extern int gGraspingController;
|
|
|
|
void CMainApplication::DrawControllers()
|
|
{
|
|
// don't draw controllers if somebody else has input focus
|
|
if( m_pHMD->IsInputFocusCapturedByAnotherProcess() )
|
|
return;
|
|
|
|
std::vector<float> 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 );
|
|
GLuint 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:
|
|
//-----------------------------------------------------------------------------
|
|
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::SetupDistortion()
|
|
{
|
|
if ( !m_pHMD )
|
|
return;
|
|
|
|
GLushort m_iLensGridSegmentCountH = 43;
|
|
GLushort m_iLensGridSegmentCountV = 43;
|
|
|
|
float w = (float)( 1.0/float(m_iLensGridSegmentCountH-1));
|
|
float h = (float)( 1.0/float(m_iLensGridSegmentCountV-1));
|
|
|
|
float u, v = 0;
|
|
|
|
std::vector<VertexDataLens> vVerts(0);
|
|
VertexDataLens vert;
|
|
|
|
//left eye distortion verts
|
|
float Xoffset = -1;
|
|
for( int y=0; y<m_iLensGridSegmentCountV; y++ )
|
|
{
|
|
for( int x=0; x<m_iLensGridSegmentCountH; x++ )
|
|
{
|
|
u = x*w; v = 1-y*h;
|
|
vert.position = Vector2( Xoffset+u, -1+2*y*h );
|
|
|
|
vr::DistortionCoordinates_t dc0;
|
|
bool result = m_pHMD->ComputeDistortion(vr::Eye_Left, u, v,&dc0);
|
|
btAssert(result);
|
|
vert.texCoordRed = Vector2(dc0.rfRed[0], 1 - dc0.rfRed[1]);
|
|
vert.texCoordGreen = Vector2(dc0.rfGreen[0], 1 - dc0.rfGreen[1]);
|
|
vert.texCoordBlue = Vector2(dc0.rfBlue[0], 1 - dc0.rfBlue[1]);
|
|
|
|
vVerts.push_back( vert );
|
|
}
|
|
}
|
|
|
|
//right eye distortion verts
|
|
Xoffset = 0;
|
|
for( int y=0; y<m_iLensGridSegmentCountV; y++ )
|
|
{
|
|
for( int x=0; x<m_iLensGridSegmentCountH; x++ )
|
|
{
|
|
u = x*w; v = 1-y*h;
|
|
vert.position = Vector2( Xoffset+u, -1+2*y*h );
|
|
|
|
vr::DistortionCoordinates_t dc0;
|
|
bool result = m_pHMD->ComputeDistortion( vr::Eye_Right, u, v,&dc0 );
|
|
btAssert(result);
|
|
vert.texCoordRed = Vector2(dc0.rfRed[0], 1 - dc0.rfRed[1]);
|
|
vert.texCoordGreen = Vector2(dc0.rfGreen[0], 1 - dc0.rfGreen[1]);
|
|
vert.texCoordBlue = Vector2(dc0.rfBlue[0], 1 - dc0.rfBlue[1]);
|
|
|
|
vVerts.push_back( vert );
|
|
}
|
|
}
|
|
|
|
std::vector<GLushort> vIndices;
|
|
GLushort a,b,c,d;
|
|
|
|
GLushort offset = 0;
|
|
for( GLushort y=0; y<m_iLensGridSegmentCountV-1; y++ )
|
|
{
|
|
for( GLushort x=0; x<m_iLensGridSegmentCountH-1; x++ )
|
|
{
|
|
a = m_iLensGridSegmentCountH*y+x +offset;
|
|
b = m_iLensGridSegmentCountH*y+x+1 +offset;
|
|
c = (y+1)*m_iLensGridSegmentCountH+x+1 +offset;
|
|
d = (y+1)*m_iLensGridSegmentCountH+x +offset;
|
|
vIndices.push_back( a );
|
|
vIndices.push_back( b );
|
|
vIndices.push_back( c );
|
|
|
|
vIndices.push_back( a );
|
|
vIndices.push_back( c );
|
|
vIndices.push_back( d );
|
|
}
|
|
}
|
|
|
|
offset = (m_iLensGridSegmentCountH)*(m_iLensGridSegmentCountV);
|
|
for( GLushort y=0; y<m_iLensGridSegmentCountV-1; y++ )
|
|
{
|
|
for( GLushort x=0; x<m_iLensGridSegmentCountH-1; x++ )
|
|
{
|
|
a = m_iLensGridSegmentCountH*y+x +offset;
|
|
b = m_iLensGridSegmentCountH*y+x+1 +offset;
|
|
c = (y+1)*m_iLensGridSegmentCountH+x+1 +offset;
|
|
d = (y+1)*m_iLensGridSegmentCountH+x +offset;
|
|
vIndices.push_back( a );
|
|
vIndices.push_back( b );
|
|
vIndices.push_back( c );
|
|
|
|
vIndices.push_back( a );
|
|
vIndices.push_back( c );
|
|
vIndices.push_back( d );
|
|
}
|
|
}
|
|
m_uiIndexSize = vIndices.size();
|
|
|
|
glGenVertexArrays( 1, &m_unLensVAO );
|
|
glBindVertexArray( m_unLensVAO );
|
|
|
|
glGenBuffers( 1, &m_glIDVertBuffer );
|
|
glBindBuffer( GL_ARRAY_BUFFER, m_glIDVertBuffer );
|
|
glBufferData( GL_ARRAY_BUFFER, vVerts.size()*sizeof(VertexDataLens), &vVerts[0], GL_STATIC_DRAW );
|
|
|
|
glGenBuffers( 1, &m_glIDIndexBuffer );
|
|
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_glIDIndexBuffer );
|
|
glBufferData( GL_ELEMENT_ARRAY_BUFFER, vIndices.size()*sizeof(GLushort), &vIndices[0], GL_STATIC_DRAW );
|
|
|
|
glEnableVertexAttribArray( 0 );
|
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexDataLens), (void *)offsetof( VertexDataLens, position ) );
|
|
|
|
glEnableVertexAttribArray( 1 );
|
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(VertexDataLens), (void *)offsetof( VertexDataLens, texCoordRed ) );
|
|
|
|
glEnableVertexAttribArray(2);
|
|
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(VertexDataLens), (void *)offsetof( VertexDataLens, texCoordGreen ) );
|
|
|
|
glEnableVertexAttribArray(3);
|
|
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(VertexDataLens), (void *)offsetof( VertexDataLens, texCoordBlue ) );
|
|
|
|
glBindVertexArray( 0 );
|
|
|
|
glDisableVertexAttribArray(0);
|
|
glDisableVertexAttribArray(1);
|
|
glDisableVertexAttribArray(2);
|
|
glDisableVertexAttribArray(3);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CMainApplication::RenderStereoTargets()
|
|
{
|
|
B3_PROFILE("CMainApplication::RenderStereoTargets");
|
|
|
|
btScalar dtSec = btScalar(m_clock.getTimeInSeconds());
|
|
dtSec = btMin(dtSec,btScalar(0.1));
|
|
sExample->stepSimulation(dtSec);
|
|
m_clock.reset();
|
|
|
|
glClearColor( 0.15f, 0.15f, 0.18f, 1.0f ); // nice background color, but not black
|
|
glEnable( GL_MULTISAMPLE );
|
|
|
|
|
|
m_app->m_instancingRenderer->init();
|
|
|
|
|
|
Matrix4 rotYtoZ = rotYtoZ.identity();
|
|
|
|
//some Bullet apps (especially robotics related) require Z as up-axis)
|
|
if (m_app->getUpAxis()==2)
|
|
{
|
|
rotYtoZ.rotateX(-90);
|
|
}
|
|
|
|
|
|
|
|
// Left Eye
|
|
{
|
|
|
|
Matrix4 viewMatLeft = m_mat4eyePosLeft * m_mat4HMDPose * rotYtoZ;
|
|
Matrix4 viewMatCenter = m_mat4HMDPose * rotYtoZ;
|
|
//0,1,2,3
|
|
//4,5,6,7,
|
|
//8,9,10,11
|
|
//12,13,14,15
|
|
|
|
//m_mat4eyePosLeft.get()[10]
|
|
//m_app->m_instancingRenderer->getActiveCamera()->setCameraTargetPosition(
|
|
// m_mat4eyePosLeft.get()[3],
|
|
// m_mat4eyePosLeft.get()[7],
|
|
// m_mat4eyePosLeft.get()[11]);
|
|
Matrix4 m;
|
|
m = viewMatCenter;
|
|
const float* mat = m.invertAffine().get();
|
|
|
|
/*printf("camera:\n,%f,%f,%f,%f\n%f,%f,%f,%f\n%f,%f,%f,%f\n%f,%f,%f,%f",
|
|
mat[0],mat[1],mat[2],mat[3],
|
|
mat[4],mat[5],mat[6],mat[7],
|
|
mat[8],mat[9],mat[10],mat[11],
|
|
mat[12],mat[13],mat[14],mat[15]);
|
|
*/
|
|
float dist=1;
|
|
m_app->m_instancingRenderer->getActiveCamera()->setCameraTargetPosition(
|
|
mat[12]-dist*mat[8],
|
|
mat[13]-dist*mat[9],
|
|
mat[14]-dist*mat[10]
|
|
);
|
|
m_app->m_instancingRenderer->getActiveCamera()->setCameraUpVector(mat[0],mat[1],mat[2]);
|
|
m_app->m_instancingRenderer->getActiveCamera()->setVRCamera(viewMatLeft.get(),m_mat4ProjectionLeft.get());
|
|
m_app->m_instancingRenderer->updateCamera(m_app->getUpAxis());
|
|
}
|
|
|
|
glBindFramebuffer( GL_FRAMEBUFFER, leftEyeDesc.m_nRenderFramebufferId );
|
|
glViewport(0, 0, m_nRenderWidth, m_nRenderHeight );
|
|
|
|
|
|
|
|
|
|
m_app->m_window->startRendering();
|
|
|
|
|
|
RenderScene( vr::Eye_Left );
|
|
|
|
|
|
|
|
|
|
|
|
m_app->m_instancingRenderer->setRenderFrameBuffer((unsigned int)leftEyeDesc.m_nRenderFramebufferId);
|
|
|
|
if (gDebugDrawFlags)
|
|
{
|
|
sExample->physicsDebugDraw(gDebugDrawFlags);
|
|
}
|
|
//else
|
|
{
|
|
sExample->renderScene();
|
|
}
|
|
|
|
//m_app->m_instancingRenderer->renderScene();
|
|
DrawGridData gridUp;
|
|
gridUp.upAxis = m_app->getUpAxis();
|
|
// m_app->drawGrid(gridUp);
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
{
|
|
Matrix4 viewMatRight = m_mat4eyePosRight * m_mat4HMDPose * rotYtoZ;
|
|
m_app->m_instancingRenderer->getActiveCamera()->setVRCamera(viewMatRight.get(),m_mat4ProjectionRight.get());
|
|
m_app->m_instancingRenderer->updateCamera(m_app->getUpAxis());
|
|
}
|
|
|
|
glBindFramebuffer( GL_FRAMEBUFFER, rightEyeDesc.m_nRenderFramebufferId );
|
|
glViewport(0, 0, m_nRenderWidth, m_nRenderHeight );
|
|
|
|
m_app->m_window->startRendering();
|
|
|
|
RenderScene( vr::Eye_Right );
|
|
|
|
m_app->m_instancingRenderer->setRenderFrameBuffer((unsigned int)rightEyeDesc.m_nRenderFramebufferId);
|
|
//m_app->m_renderer->renderScene();
|
|
|
|
if (gDebugDrawFlags)
|
|
{
|
|
sExample->physicsDebugDraw(gDebugDrawFlags);
|
|
}
|
|
//else
|
|
{
|
|
sExample->renderScene();
|
|
}
|
|
|
|
//m_app->drawGrid(gridUp);
|
|
|
|
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:
|
|
//-----------------------------------------------------------------------------
|
|
void CMainApplication::RenderScene( vr::Hmd_Eye nEye )
|
|
{
|
|
B3_PROFILE("RenderScene");
|
|
|
|
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 bIsInputCapturedByAnotherProcess = m_pHMD->IsInputFocusCapturedByAnotherProcess();
|
|
|
|
if( !bIsInputCapturedByAnotherProcess )
|
|
{
|
|
// 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( bIsInputCapturedByAnotherProcess && 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::RenderDistortion()
|
|
{
|
|
glDisable(GL_DEPTH_TEST);
|
|
glViewport( 0, 0, m_nWindowWidth, m_nWindowHeight );
|
|
|
|
glBindVertexArray( m_unLensVAO );
|
|
glUseProgram( m_unLensProgramID );
|
|
|
|
//render left lens (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_MIPMAP_LINEAR );
|
|
glDrawElements( GL_TRIANGLES, m_uiIndexSize/2, GL_UNSIGNED_SHORT, 0 );
|
|
|
|
//render right lens (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_MIPMAP_LINEAR );
|
|
glDrawElements( GL_TRIANGLES, m_uiIndexSize/2, GL_UNSIGNED_SHORT, (const void *)(m_uiIndexSize) );
|
|
|
|
glBindVertexArray( 0 );
|
|
glUseProgram( 0 );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
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:
|
|
//-----------------------------------------------------------------------------
|
|
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:
|
|
//-----------------------------------------------------------------------------
|
|
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;
|
|
{
|
|
B3_PROFILE("WaitGetPoses");
|
|
vr::VRCompositor()->WaitGetPoses(m_rTrackedDevicePose, vr::k_unMaxTrackedDeviceCount, NULL, 0);
|
|
}
|
|
|
|
m_iValidPoseCount = 0;
|
|
m_strPoseClasses = "";
|
|
{
|
|
B3_PROFILE("for loop");
|
|
|
|
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_TrackingReference: m_rDevClassChar[nDevice] = 'T'; break;
|
|
default: m_rDevClassChar[nDevice] = '?'; break;
|
|
}
|
|
}
|
|
m_strPoseClasses += m_rDevClassChar[nDevice];
|
|
}
|
|
}
|
|
}
|
|
{
|
|
B3_PROFILE("m_mat4HMDPose invert");
|
|
|
|
if (m_rTrackedDevicePose[vr::k_unTrackedDeviceIndex_Hmd].bPoseIsValid)
|
|
{
|
|
m_mat4HMDPose = m_rmat4DevicePose[vr::k_unTrackedDeviceIndex_Hmd].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 )
|
|
{
|
|
b3Printf( "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 )
|
|
{
|
|
b3Printf( "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 ) )
|
|
{
|
|
b3Printf( "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 );
|
|
b3Printf( "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[])
|
|
{
|
|
|
|
b3CommandLineArgs args(argc,argv);
|
|
if (args.CheckCmdLineFlag("disable_desktop_gl"))
|
|
{
|
|
gDisableDesktopGL = true;
|
|
}
|
|
if (args.CheckCmdLineFlag("tracing"))
|
|
{
|
|
b3ChromeUtilsStartTimings();
|
|
b3ChromeUtilsEnableProfiling();
|
|
}
|
|
|
|
|
|
#ifdef BT_USE_CUSTOM_PROFILER
|
|
b3SetCustomEnterProfileZoneFunc(dcEnter);
|
|
b3SetCustomLeaveProfileZoneFunc(dcLeave);
|
|
#endif
|
|
|
|
|
|
CMainApplication *pMainApplication = new CMainApplication( argc, argv );
|
|
|
|
if (!pMainApplication->BInit())
|
|
{
|
|
pMainApplication->Shutdown();
|
|
return 1;
|
|
}
|
|
|
|
if (sExample)
|
|
{
|
|
//until we have a proper VR gui, always assume we want the hard-coded default robot assets
|
|
char* newargv[2];
|
|
char* t0 = (char*)"--robotassets";
|
|
newargv[0] = t0;
|
|
newargv[1] = t0;
|
|
sExample->processCommandLineArgs(2,newargv);
|
|
sExample->processCommandLineArgs(argc,argv);
|
|
|
|
}
|
|
|
|
char* gVideoFileName = 0;
|
|
args.GetCmdLineArgument("mp4",gVideoFileName);
|
|
if (gVideoFileName)
|
|
pMainApplication->getApp()->dumpFramesToVideo(gVideoFileName);
|
|
|
|
//request disable VSYNC
|
|
typedef bool (APIENTRY *PFNWGLSWAPINTERVALFARPROC)(int);
|
|
PFNWGLSWAPINTERVALFARPROC wglSwapIntervalEXT = 0;
|
|
wglSwapIntervalEXT =
|
|
(PFNWGLSWAPINTERVALFARPROC)wglGetProcAddress("wglSwapIntervalEXT");
|
|
if (wglSwapIntervalEXT)
|
|
wglSwapIntervalEXT(0);
|
|
|
|
pMainApplication->RunMainLoop();
|
|
|
|
pMainApplication->Shutdown();
|
|
|
|
if (args.CheckCmdLineFlag("tracing"))
|
|
{
|
|
b3ChromeUtilsStopTimingsAndWriteJsonFile();
|
|
}
|
|
|
|
|
|
return 0;
|
|
}
|
|
#endif //BT_ENABLE_VR
|