You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
406 lines
12 KiB
406 lines
12 KiB
//====== Copyright Valve Corporation, All rights reserved. =======
|
|
|
|
|
|
#include "openvroverlaycontroller.h"
|
|
|
|
|
|
#include <QOpenGLFramebufferObjectFormat>
|
|
#include <QOpenGLPaintDevice>
|
|
#include <QPainter>
|
|
#include <QtWidgets/QWidget>
|
|
#include <QMouseEvent>
|
|
#include <QtWidgets/QGraphicsSceneMouseEvent>
|
|
#include <QtWidgets/QApplication>
|
|
#include <QtWidgets/QGraphicsEllipseItem>
|
|
#include <QCursor>
|
|
|
|
using namespace vr;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
COpenVROverlayController *s_pSharedVRController = NULL;
|
|
|
|
COpenVROverlayController *COpenVROverlayController::SharedInstance()
|
|
{
|
|
if ( !s_pSharedVRController )
|
|
{
|
|
s_pSharedVRController = new COpenVROverlayController();
|
|
}
|
|
return s_pSharedVRController;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
COpenVROverlayController::COpenVROverlayController()
|
|
: BaseClass()
|
|
, m_strVRDriver( "No Driver" )
|
|
, m_strVRDisplay( "No Display" )
|
|
, m_eLastHmdError( vr::VRInitError_None )
|
|
, m_eCompositorError( vr::VRInitError_None )
|
|
, m_eOverlayError( vr::VRInitError_None )
|
|
, m_ulOverlayHandle( vr::k_ulOverlayHandleInvalid )
|
|
, m_pOpenGLContext( NULL )
|
|
, m_pScene( NULL )
|
|
, m_pFbo( NULL )
|
|
, m_pOffscreenSurface ( NULL )
|
|
, m_pPumpEventsTimer( NULL )
|
|
, m_pWidget( NULL )
|
|
, m_lastMouseButtons( 0 )
|
|
{
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
COpenVROverlayController::~COpenVROverlayController()
|
|
{
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Helper to get a string from a tracked device property and turn it
|
|
// into a QString
|
|
//-----------------------------------------------------------------------------
|
|
QString GetTrackedDeviceString( vr::IVRSystem *pHmd, vr::TrackedDeviceIndex_t unDevice, vr::TrackedDeviceProperty prop )
|
|
{
|
|
char buf[128];
|
|
vr::TrackedPropertyError err;
|
|
pHmd->GetStringTrackedDeviceProperty( unDevice, prop, buf, sizeof( buf ), &err );
|
|
if( err != vr::TrackedProp_Success )
|
|
{
|
|
return QString( "Error Getting String: " ) + pHmd->GetPropErrorNameFromEnum( err );
|
|
}
|
|
else
|
|
{
|
|
return buf;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
bool COpenVROverlayController::Init()
|
|
{
|
|
bool bSuccess = true;
|
|
|
|
m_strName = "systemoverlay";
|
|
|
|
QStringList arguments = qApp->arguments();
|
|
|
|
int nNameArg = arguments.indexOf( "-name" );
|
|
if( nNameArg != -1 && nNameArg + 2 <= arguments.size() )
|
|
{
|
|
m_strName = arguments.at( nNameArg + 1 );
|
|
}
|
|
|
|
QSurfaceFormat format;
|
|
format.setMajorVersion( 4 );
|
|
format.setMinorVersion( 1 );
|
|
format.setProfile( QSurfaceFormat::CompatibilityProfile );
|
|
|
|
m_pOpenGLContext = new QOpenGLContext();
|
|
m_pOpenGLContext->setFormat( format );
|
|
bSuccess = m_pOpenGLContext->create();
|
|
if( !bSuccess )
|
|
return false;
|
|
|
|
// create an offscreen surface to attach the context and FBO to
|
|
m_pOffscreenSurface = new QOffscreenSurface();
|
|
m_pOffscreenSurface->create();
|
|
m_pOpenGLContext->makeCurrent( m_pOffscreenSurface );
|
|
|
|
m_pScene = new QGraphicsScene();
|
|
connect( m_pScene, SIGNAL(changed(const QList<QRectF>&)), this, SLOT( OnSceneChanged(const QList<QRectF>&)) );
|
|
|
|
// Loading the OpenVR Runtime
|
|
bSuccess = ConnectToVRRuntime();
|
|
|
|
bSuccess = bSuccess && vr::VRCompositor() != NULL;
|
|
|
|
if( vr::VROverlay() )
|
|
{
|
|
std::string sKey = std::string( "sample." ) + m_strName.toStdString();
|
|
vr::VROverlayError overlayError = vr::VROverlay()->CreateDashboardOverlay( sKey.c_str(), m_strName.toStdString().c_str(), &m_ulOverlayHandle, &m_ulOverlayThumbnailHandle );
|
|
bSuccess = bSuccess && overlayError == vr::VROverlayError_None;
|
|
}
|
|
|
|
if( bSuccess )
|
|
{
|
|
vr::VROverlay()->SetOverlayWidthInMeters( m_ulOverlayHandle, 1.5f );
|
|
vr::VROverlay()->SetOverlayInputMethod( m_ulOverlayHandle, vr::VROverlayInputMethod_Mouse );
|
|
|
|
m_pPumpEventsTimer = new QTimer( this );
|
|
connect(m_pPumpEventsTimer, SIGNAL( timeout() ), this, SLOT( OnTimeoutPumpEvents() ) );
|
|
m_pPumpEventsTimer->setInterval( 20 );
|
|
m_pPumpEventsTimer->start();
|
|
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void COpenVROverlayController::Shutdown()
|
|
{
|
|
DisconnectFromVRRuntime();
|
|
|
|
delete m_pScene;
|
|
delete m_pFbo;
|
|
delete m_pOffscreenSurface;
|
|
|
|
if( m_pOpenGLContext )
|
|
{
|
|
// m_pOpenGLContext->destroy();
|
|
delete m_pOpenGLContext;
|
|
m_pOpenGLContext = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void COpenVROverlayController::OnSceneChanged( const QList<QRectF>& )
|
|
{
|
|
// skip rendering if the overlay isn't visible
|
|
if( ( m_ulOverlayHandle == k_ulOverlayHandleInvalid ) || !vr::VROverlay() ||
|
|
( !vr::VROverlay()->IsOverlayVisible( m_ulOverlayHandle ) && !vr::VROverlay()->IsOverlayVisible( m_ulOverlayThumbnailHandle ) ) )
|
|
return;
|
|
|
|
m_pOpenGLContext->makeCurrent( m_pOffscreenSurface );
|
|
m_pFbo->bind();
|
|
|
|
QOpenGLPaintDevice device( m_pFbo->size() );
|
|
QPainter painter( &device );
|
|
|
|
m_pScene->render( &painter );
|
|
|
|
m_pFbo->release();
|
|
|
|
GLuint unTexture = m_pFbo->texture();
|
|
if( unTexture != 0 )
|
|
{
|
|
vr::Texture_t texture = {(void*)(uintptr_t)unTexture, vr::TextureType_OpenGL, vr::ColorSpace_Auto };
|
|
vr::VROverlay()->SetOverlayTexture( m_ulOverlayHandle, &texture );
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void COpenVROverlayController::OnTimeoutPumpEvents()
|
|
{
|
|
if( !vr::VRSystem() )
|
|
return;
|
|
|
|
vr::VREvent_t vrEvent;
|
|
while( vr::VROverlay()->PollNextOverlayEvent( m_ulOverlayHandle, &vrEvent, sizeof( vrEvent ) ) )
|
|
{
|
|
switch( vrEvent.eventType )
|
|
{
|
|
case vr::VREvent_MouseMove:
|
|
{
|
|
QPointF ptNewMouse( vrEvent.data.mouse.x, vrEvent.data.mouse.y );
|
|
QPoint ptGlobal = ptNewMouse.toPoint();
|
|
QGraphicsSceneMouseEvent mouseEvent( QEvent::GraphicsSceneMouseMove );
|
|
mouseEvent.setWidget( NULL );
|
|
mouseEvent.setPos( ptNewMouse );
|
|
mouseEvent.setScenePos( ptGlobal );
|
|
mouseEvent.setScreenPos( ptGlobal );
|
|
mouseEvent.setLastPos( m_ptLastMouse );
|
|
mouseEvent.setLastScenePos( m_pWidget->mapToGlobal( m_ptLastMouse.toPoint() ) );
|
|
mouseEvent.setLastScreenPos( m_pWidget->mapToGlobal( m_ptLastMouse.toPoint() ) );
|
|
mouseEvent.setButtons( m_lastMouseButtons );
|
|
mouseEvent.setButton( Qt::NoButton );
|
|
mouseEvent.setModifiers( 0 );
|
|
mouseEvent.setAccepted( false );
|
|
|
|
m_ptLastMouse = ptNewMouse;
|
|
QApplication::sendEvent( m_pScene, &mouseEvent );
|
|
|
|
OnSceneChanged( QList<QRectF>() );
|
|
}
|
|
break;
|
|
|
|
case vr::VREvent_MouseButtonDown:
|
|
{
|
|
Qt::MouseButton button = vrEvent.data.mouse.button == vr::VRMouseButton_Right ? Qt::RightButton : Qt::LeftButton;
|
|
|
|
m_lastMouseButtons |= button;
|
|
|
|
QPoint ptGlobal = m_ptLastMouse.toPoint();
|
|
QGraphicsSceneMouseEvent mouseEvent( QEvent::GraphicsSceneMousePress );
|
|
mouseEvent.setWidget( NULL );
|
|
mouseEvent.setPos( m_ptLastMouse );
|
|
mouseEvent.setButtonDownPos( button, m_ptLastMouse );
|
|
mouseEvent.setButtonDownScenePos( button, ptGlobal);
|
|
mouseEvent.setButtonDownScreenPos( button, ptGlobal );
|
|
mouseEvent.setScenePos( ptGlobal );
|
|
mouseEvent.setScreenPos( ptGlobal );
|
|
mouseEvent.setLastPos( m_ptLastMouse );
|
|
mouseEvent.setLastScenePos( ptGlobal );
|
|
mouseEvent.setLastScreenPos( ptGlobal );
|
|
mouseEvent.setButtons( m_lastMouseButtons );
|
|
mouseEvent.setButton( button );
|
|
mouseEvent.setModifiers( 0 );
|
|
mouseEvent.setAccepted( false );
|
|
|
|
QApplication::sendEvent( m_pScene, &mouseEvent );
|
|
}
|
|
break;
|
|
|
|
case vr::VREvent_MouseButtonUp:
|
|
{
|
|
Qt::MouseButton button = vrEvent.data.mouse.button == vr::VRMouseButton_Right ? Qt::RightButton : Qt::LeftButton;
|
|
m_lastMouseButtons &= ~button;
|
|
|
|
QPoint ptGlobal = m_ptLastMouse.toPoint();
|
|
QGraphicsSceneMouseEvent mouseEvent( QEvent::GraphicsSceneMouseRelease );
|
|
mouseEvent.setWidget( NULL );
|
|
mouseEvent.setPos( m_ptLastMouse );
|
|
mouseEvent.setScenePos( ptGlobal );
|
|
mouseEvent.setScreenPos( ptGlobal );
|
|
mouseEvent.setLastPos( m_ptLastMouse );
|
|
mouseEvent.setLastScenePos( ptGlobal );
|
|
mouseEvent.setLastScreenPos( ptGlobal );
|
|
mouseEvent.setButtons( m_lastMouseButtons );
|
|
mouseEvent.setButton( button );
|
|
mouseEvent.setModifiers( 0 );
|
|
mouseEvent.setAccepted( false );
|
|
|
|
QApplication::sendEvent( m_pScene, &mouseEvent );
|
|
}
|
|
break;
|
|
|
|
case vr::VREvent_OverlayShown:
|
|
{
|
|
m_pWidget->repaint();
|
|
}
|
|
break;
|
|
|
|
case vr::VREvent_Quit:
|
|
QApplication::exit();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( m_ulOverlayThumbnailHandle != vr::k_ulOverlayHandleInvalid )
|
|
{
|
|
while( vr::VROverlay()->PollNextOverlayEvent( m_ulOverlayThumbnailHandle, &vrEvent, sizeof( vrEvent) ) )
|
|
{
|
|
switch( vrEvent.eventType )
|
|
{
|
|
case vr::VREvent_OverlayShown:
|
|
{
|
|
m_pWidget->repaint();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void COpenVROverlayController::SetWidget( QWidget *pWidget )
|
|
{
|
|
if( m_pScene )
|
|
{
|
|
// all of the mouse handling stuff requires that the widget be at 0,0
|
|
pWidget->move( 0, 0 );
|
|
m_pScene->addWidget( pWidget );
|
|
}
|
|
m_pWidget = pWidget;
|
|
|
|
m_pFbo = new QOpenGLFramebufferObject( pWidget->width(), pWidget->height(), GL_TEXTURE_2D );
|
|
|
|
if( vr::VROverlay() )
|
|
{
|
|
vr::HmdVector2_t vecWindowSize =
|
|
{
|
|
(float)pWidget->width(),
|
|
(float)pWidget->height()
|
|
};
|
|
vr::VROverlay()->SetOverlayMouseScale( m_ulOverlayHandle, &vecWindowSize );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
bool COpenVROverlayController::ConnectToVRRuntime()
|
|
{
|
|
m_eLastHmdError = vr::VRInitError_None;
|
|
vr::IVRSystem *pVRSystem = vr::VR_Init( &m_eLastHmdError, vr::VRApplication_Overlay );
|
|
|
|
if ( m_eLastHmdError != vr::VRInitError_None )
|
|
{
|
|
m_strVRDriver = "No Driver";
|
|
m_strVRDisplay = "No Display";
|
|
return false;
|
|
}
|
|
|
|
m_strVRDriver = GetTrackedDeviceString(pVRSystem, vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_TrackingSystemName_String);
|
|
m_strVRDisplay = GetTrackedDeviceString(pVRSystem, vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_SerialNumber_String);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void COpenVROverlayController::DisconnectFromVRRuntime()
|
|
{
|
|
vr::VR_Shutdown();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
QString COpenVROverlayController::GetVRDriverString()
|
|
{
|
|
return m_strVRDriver;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
QString COpenVROverlayController::GetVRDisplayString()
|
|
{
|
|
return m_strVRDisplay;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
bool COpenVROverlayController::BHMDAvailable()
|
|
{
|
|
return vr::VRSystem() != NULL;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
|
|
vr::HmdError COpenVROverlayController::GetLastHmdError()
|
|
{
|
|
return m_eLastHmdError;
|
|
}
|
|
|
|
|