mirror of
https://github.com/bulletphysics/bullet3
synced 2024-12-13 21:30:09 +00:00
2318 lines
70 KiB
C++
2318 lines
70 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"
|
|
|
|
#ifdef __APPLE__
|
|
#define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED
|
|
#import <Cocoa/Cocoa.h>
|
|
#endif //__APPLE__
|
|
|
|
#include "LinearMath/btIDebugDraw.h"
|
|
int gSharedMemoryKey = -1;
|
|
static int gDebugDrawFlags = 0;
|
|
static bool gDisplayDistortion = false;
|
|
static bool gDisableDesktopGL = false;
|
|
|
|
static int maxNumObjectCapacity = 128 * 1024;
|
|
static int maxShapeCapacityInBytes = 128 * 1024 * 1024;
|
|
|
|
#include <stdio.h>
|
|
#include <string>
|
|
#include <cstdlib>
|
|
|
|
#include <openvr.h>
|
|
#include "strtools.h"
|
|
#include "compat.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
|
|
#ifdef __linux__
|
|
#define APIENTRY
|
|
#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("timings");
|
|
}
|
|
}
|
|
if (sExample)
|
|
{
|
|
sExample->keyboardCallback(key, state);
|
|
}
|
|
|
|
if (prevKeyboardCallback)
|
|
prevKeyboardCallback(key, state);
|
|
}
|
|
|
|
#include "../SharedMemory/SharedMemoryPublic.h"
|
|
extern bool useShadowMap;
|
|
static bool gEnableVRRenderControllers = true;
|
|
static bool gEnableVRRendering = true;
|
|
static int gUpAxis = 2;
|
|
|
|
void VRPhysicsServerVisualizerFlagCallback(int flag, bool enable)
|
|
{
|
|
if (flag == COV_ENABLE_Y_AXIS_UP)
|
|
{
|
|
//either Y = up or Z
|
|
gUpAxis = enable ? 1 : 2;
|
|
}
|
|
|
|
if (flag == COV_ENABLE_SHADOWS)
|
|
{
|
|
useShadowMap = enable;
|
|
}
|
|
if (flag == COV_ENABLE_GUI)
|
|
{
|
|
//there is no regular GUI here, but disable the
|
|
}
|
|
if (flag == COV_ENABLE_VR_RENDER_CONTROLLERS)
|
|
{
|
|
gEnableVRRenderControllers = enable;
|
|
}
|
|
if (flag == COV_ENABLE_RENDERING)
|
|
{
|
|
gEnableVRRendering = enable;
|
|
}
|
|
|
|
if (flag == COV_ENABLE_WIREFRAME)
|
|
{
|
|
if (enable)
|
|
{
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
|
//gDebugDrawFlags |= btIDebugDraw::DBG_DrawWireframe;
|
|
}
|
|
else
|
|
{
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
|
//gDebugDrawFlags &= ~btIDebugDraw::DBG_DrawWireframe;
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// 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, maxNumObjectCapacity, maxShapeCapacityInBytes);
|
|
|
|
sGuiPtr = new OpenGLGuiHelper(m_app, false);
|
|
sGuiPtr->setVisualizerFlagCallback(VRPhysicsServerVisualizerFlagCallback);
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
btAssert(vr::k_unControllerStateAxisCount >= 5);
|
|
float allAxis[10]; //store x,y times 5 controllers
|
|
int index = 0;
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
allAxis[index++] = state.rAxis[i].x;
|
|
allAxis[index++] = state.rAxis[i].y;
|
|
}
|
|
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);
|
|
sExample->vrControllerButtonCallback(unDevice, button, 1, pos, orn);
|
|
}
|
|
else
|
|
{
|
|
// printf("Device MOVED: %d\n", unDevice);
|
|
sExample->vrControllerMoveCallback(unDevice, pos, orn, state.rAxis[1].x, allAxis);
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
sExample->vrControllerButtonCallback(unDevice, button, 0, pos, orn);
|
|
}
|
|
else
|
|
{
|
|
sExample->vrControllerMoveCallback(unDevice, pos, orn, state.rAxis[1].x, allAxis);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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())
|
|
{
|
|
this->m_app->setUpAxis(gUpAxis);
|
|
b3ChromeUtilsEnableProfiling();
|
|
if (gEnableVRRendering)
|
|
{
|
|
B3_PROFILE("main");
|
|
|
|
bQuit = HandleInput();
|
|
|
|
RenderFrame();
|
|
}
|
|
else
|
|
{
|
|
b3Clock::usleep(0);
|
|
sExample->updateGraphics();
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// 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, &fLargest);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, 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());
|
|
m_app->m_instancingRenderer->getActiveCamera()->setVRCamera(viewMatLeft.get(), m_mat4ProjectionLeft.get());
|
|
}
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, leftEyeDesc.m_nRenderFramebufferId);
|
|
|
|
m_app->m_window->startRendering();
|
|
glViewport(0, 0, m_nRenderWidth, m_nRenderHeight);
|
|
|
|
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());
|
|
m_app->m_instancingRenderer->getActiveCamera()->setVRCamera(viewMatRight.get(), m_mat4ProjectionRight.get());
|
|
}
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, rightEyeDesc.m_nRenderFramebufferId);
|
|
|
|
m_app->m_window->startRendering();
|
|
glViewport(0, 0, m_nRenderWidth, m_nRenderHeight);
|
|
|
|
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);
|
|
|
|
m_app->m_instancingRenderer->setRenderFrameBuffer(0);
|
|
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 (gEnableVRRenderControllers)
|
|
{
|
|
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;
|
|
case vr::TrackedDeviceClass_GenericTracker:
|
|
m_rDevClassChar[nDevice] = 'G';
|
|
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, &fLargest);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, 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();
|
|
}
|
|
|
|
args.GetCmdLineArgument("max_num_object_capacity", maxNumObjectCapacity);
|
|
args.GetCmdLineArgument("max_shape_capacity_in_bytes", maxShapeCapacityInBytes);
|
|
args.GetCmdLineArgument("shared_memory_key", gSharedMemoryKey);
|
|
|
|
#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);
|
|
|
|
#ifndef B3_USE_GLFW
|
|
#ifdef _WIN32
|
|
//request disable VSYNC
|
|
typedef bool(APIENTRY * PFNWGLSWAPINTERVALFARPROC)(int);
|
|
PFNWGLSWAPINTERVALFARPROC wglSwapIntervalEXT = 0;
|
|
wglSwapIntervalEXT =
|
|
(PFNWGLSWAPINTERVALFARPROC)wglGetProcAddress("wglSwapIntervalEXT");
|
|
if (wglSwapIntervalEXT)
|
|
wglSwapIntervalEXT(0);
|
|
#endif
|
|
#endif
|
|
#ifdef __APPLE__
|
|
GLint sync = 0;
|
|
CGLContextObj ctx = CGLGetCurrentContext();
|
|
CGLSetParameter(ctx, kCGLCPSwapInterval, &sync);
|
|
#endif
|
|
|
|
pMainApplication->RunMainLoop();
|
|
|
|
pMainApplication->Shutdown();
|
|
|
|
if (args.CheckCmdLineFlag("tracing"))
|
|
{
|
|
b3ChromeUtilsStopTimingsAndWriteJsonFile("timings");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif //BT_ENABLE_VR
|