Commit 351a2917 authored by Robert Menzel's avatar Robert Menzel
Browse files

updated Rift SDK handling and support for 360 gamepad on windows

parent 3539d151
...@@ -17,6 +17,9 @@ lib/* ...@@ -17,6 +17,9 @@ lib/*
# QT creator: # QT creator:
# #
*.user *.user
*.sln
*.vcxproj.filters
*.vcxproj
# #
# build files # build files
......
#pragma once #pragma once
/** /**
* IMPORTANT: DON'T EXPECT THIS CLASS TO HAVE A FINAL AND STABLE API! * IMPORTANT: DON'T EXPECT THIS TO HAVE A FINAL AND STABLE API!
* *
* This class needs the LibOVR version 0.3.2 or higher to work. * This needs the LibOVR version 0.4 (or higher, unless the API breaks) to work.
* Headers of this lib need to be placed in the search path. * Headers of this lib need to be placed in the search path.
* *
* In addition ACGL_USE_OCULUS_RIFT has to be defined. * In addition ACGL_USE_OCULUS_RIFT has to be defined.
* *
* IMPORTANT:
* The order of SDK and window initialisation is important:
* 1. call initSDK();
* 2. call createHMD
* 3. create a window and a OpenGL context
* 4. ACGL::init();
* 5. build textures to render into (one for each eye), the size can be getOptimalRenderSizePerEye() or smaller
* 6. build a desription of those textures for the Rift SDK using generateEyeTextureDescription ( <EyeTexture> )
* 7. configureRendering - store the ovrEyeRenderDesc values for later, _renderTagetSize is the size of your Rift window
*
* At runtime:
* * call deactivateHealthWarning when the user presses a button
*
* Each frame:
* 1. beginFrame()
* 2. TODO: camera handling -> generates <poseOfEyes>
* 3. ovrHmd_EndFrame( <HMD> , <poseOfEyes> , (ovrTexture*) <EyeTexture> );
* IMPORTANT: if ovrHmd_EndFrame gets called, don't call any swapBuffers more on your own!
*
* clean up:
* 1. destroyHMD
* 2. shutdownSDK
* *
*/ */
#ifdef ACGL_USE_OCULUS_RIFT #ifdef ACGL_USE_OCULUS_RIFT
#include <OVR_Version.h>
#if ((OVR_MAJOR_VERSION > 0) || (OVR_MINOR_VERSION >= 4))
#include <ACGL/ACGL.hh> #include <ACGL/ACGL.hh>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#if ACGL_RIFT_SDK_VERSION >= 40
#include <OVR_CAPI.h> #include <OVR_CAPI.h>
//class GLFWWindow;
#include <ACGL/OpenGL/GL.hh> #include <ACGL/OpenGL/GL.hh>
#include <ACGL/OpenGL/Objects/Texture.hh>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <OVR_CAPI_GL.h>
namespace ACGL{ namespace ACGL{
namespace HardwareSupport{ namespace HardwareSupport{
namespace OVR{
// init the SDK once before calling any of the following functions:
bool initSDK();
bool initRiftSDK(); // shut it down at the end:
void shutdownRiftSDK(); void shutdownSDK();
// create a standard Rift, can be replaced with own, more specialized code: // create a standard Rift, can be replaced with own, more specialized code:
ovrHmd createRift(bool _headTrackingIsRequired = false, bool _headTranslationTrackingIsAllowed = true); ovrHmd createHMD(bool _headTrackingIsRequired = false, bool _headTranslationTrackingIsAllowed = true);
void destroyRift(ovrHmd _hmd); void destroyHMD(ovrHmd _hmd);
// SDK gives different sizes per eye, return the max to make things easier: // SDK gives different sizes per eye, return the max to make things easier:
glm::uvec2 getOptimalRenderSizePerEye(ovrHmd _hmd); glm::uvec2 getOptimalRenderSizePerEye(ovrHmd _hmd);
#ifdef ACGL_COMPILE_WITH_GLFW // returns a ovrEyeRenderDesc[2] used by the SDK in _eyeRenderDesc. The returned struct stores the size of the
// the Rift SDK need to know our window, this function hides the window system/OS specifics: // textures, so update this if the textures change in size!
// _eyeRenderDesc has to be an array with at least two elements!
void generateEyeTextureDescription(ACGL::OpenGL::SharedTexture2D _leftTexture,
ACGL::OpenGL::SharedTexture2D _rightTexture,
ovrGLTexture _eyeRenderDesc[2]);
// the Rift SDK needs to know our window, this function hides the window system/OS specifics:
// it's limited to OpenGL / no multisampling back buffers, if more flexibility is needed, // it's limited to OpenGL / no multisampling back buffers, if more flexibility is needed,
// write your own similar function: // write your own similar function.
// _eyeRenderDesc will be set by this function!
#ifdef ACGL_COMPILE_WITH_GLFW
bool configureRendering(ovrHmd _hmd, ovrEyeRenderDesc _eyeRenderDesc[2], glm::uvec2 _renderTagetSize, GLFWwindow *_window); bool configureRendering(ovrHmd _hmd, ovrEyeRenderDesc _eyeRenderDesc[2], glm::uvec2 _renderTagetSize, GLFWwindow *_window);
#endif #endif
...@@ -47,8 +81,12 @@ namespace HardwareSupport{ ...@@ -47,8 +81,12 @@ namespace HardwareSupport{
// returns true if the warning is still displayed. Can be called multiple times. // returns true if the warning is still displayed. Can be called multiple times.
bool deactivateHealthWarning(ovrHmd _hmd); bool deactivateHealthWarning(ovrHmd _hmd);
// call at the beginning of a frame:
void beginFrame(ovrHmd _hmd);
// used only for debugging: // used only for debugging:
void printOVRDistortionCaps(unsigned int _caps); void printDistortionCaps(unsigned int _caps);
}
} }
} }
......
...@@ -148,7 +148,7 @@ GamePad::GamePad( int _n ) ...@@ -148,7 +148,7 @@ GamePad::GamePad( int _n )
setAxisMapping( RIGHT_ANALOG_STICK_Y , 3); setAxisMapping( RIGHT_ANALOG_STICK_Y , 3);
setMinAxisSensitivity( 0.05f ); setMinAxisSensitivity( 0.05f );
} else if (mJoystickName == "Microsoft X-Box 360 pad") { } else if (mJoystickName == "Microsoft X-Box 360 pad") { // 360 USB gamepad on Linux
// real buttons: // real buttons:
setButtonMapping( SELECT, 6); setButtonMapping( SELECT, 6);
...@@ -179,7 +179,37 @@ GamePad::GamePad( int _n ) ...@@ -179,7 +179,37 @@ GamePad::GamePad( int _n )
setMinAxisSensitivity( 0.2f ); setMinAxisSensitivity( 0.2f );
} else { } else if (mJoystickName == "Microsoft PC-joystick driver") { // 360 USB gamepad on Windows
// real buttons:
setButtonMapping(SELECT, 6);
setButtonMapping(START, 7);
setButtonMapping(RIGHT_PAD_NORTH, 3);
setButtonMapping(RIGHT_PAD_EAST, 1);
setButtonMapping(RIGHT_PAD_SOUTH, 0);
setButtonMapping(RIGHT_PAD_WEST, 2);
setButtonMapping(LEFT_SHOULDER, 4);
setButtonMapping(RIGHT_SHOULDER, 5);
setButtonMapping(LEFT_PAD_NORTH, 10);
setButtonMapping(LEFT_PAD_EAST, 11);
setButtonMapping(LEFT_PAD_SOUTH, 12);
setButtonMapping(LEFT_PAD_WEST, 13);
//setButtonMapping(LEFT_TRIGGER, 2 + mNumberOfButtons); // axis 2
//setButtonMapping(RIGHT_TRIGGER, 5 + mNumberOfButtons); // axis 5
setAxisMapping(LEFT_ANALOG_TRIGGER, 2); mAxesMultiplier[2] = 0.5f; mAxesAdd[2] = 0.5f;
setAxisMapping(RIGHT_ANALOG_TRIGGER, 5); mAxesMultiplier[5] = -0.5f; mAxesAdd[5] = 0.5f;
setAxisMapping(LEFT_ANALOG_STICK_X, 0);
setAxisMapping(LEFT_ANALOG_STICK_Y, 1);
setAxisMapping(RIGHT_ANALOG_STICK_X, 3); mAxesMultiplier[3] = -1.0f;
setAxisMapping(RIGHT_ANALOG_STICK_Y, 4); mAxesMultiplier[4] = -1.0f;
setMinAxisSensitivity(0.2f);
} else {
debug() << "unknown gamepad: " << mJoystickName << " can't configure buttons" << endl; debug() << "unknown gamepad: " << mJoystickName << " can't configure buttons" << endl;
} }
} }
...@@ -343,6 +373,9 @@ void GamePad::update() ...@@ -343,6 +373,9 @@ void GamePad::update()
float sign = ((mAxes[ i ] < 0.0f) && (tmp != 0.0f)) ? -1.0f : 1.0f; float sign = ((mAxes[ i ] < 0.0f) && (tmp != 0.0f)) ? -1.0f : 1.0f;
mAxes[ i ] = tmp * sign; mAxes[ i ] = tmp * sign;
} }
//debug().unmute();
//printState();
//debug().mute();
} }
void GamePad::printState() void GamePad::printState()
......
...@@ -9,200 +9,230 @@ ...@@ -9,200 +9,230 @@
#if ACGL_RIFT_SDK_VERSION >= 40 #if ACGL_RIFT_SDK_VERSION >= 40
#ifdef ACGL_COMPILE_WITH_GLFW #ifdef ACGL_COMPILE_WITH_GLFW
#define GLFW_EXPOSE_NATIVE_WIN32 #define GLFW_EXPOSE_NATIVE_WIN32
#define GLFW_EXPOSE_NATIVE_WGL #define GLFW_EXPOSE_NATIVE_WGL
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <GLFW/glfw3native.h> #include <GLFW/glfw3native.h>
#endif #endif
#include <OVR_CAPI_GL.h> #include <OVR_CAPI_GL.h>
using namespace std;
using namespace ACGL::Utils;
namespace ACGL{ namespace ACGL{
namespace HardwareSupport{ namespace HardwareSupport{
namespace OVR{
using namespace std; // C API helpers:
using namespace ACGL::Utils;
// C API helpers:
static bool ACGL_RiftSDKInitialized = false; static bool ACGL_RiftSDKInitialized = false;
bool initRiftSDK() bool initSDK()
{ {
cout << "initRiftSDK()" << endl; //cout << "initRiftSDK()" << endl;
if (ACGL_RiftSDKInitialized) return true; // don't init twice if (ACGL_RiftSDKInitialized) return true; // don't init twice
ovrBool ok = ovr_Initialize(); ovrBool ok = ovr_Initialize();
if (!ok) { if (!ok) {
error() << "could not initialize Oculus Rift library" << endl; error() << "could not initialize Oculus Rift library" << endl;
} }
else { else {
ACGL_RiftSDKInitialized = true; ACGL_RiftSDKInitialized = true;
}
return ACGL_RiftSDKInitialized;
} }
return ACGL_RiftSDKInitialized;
}
void shutdownRiftSDK() void shutdownSDK()
{ {
ovr_Shutdown(); if (ACGL_RiftSDKInitialized) ovr_Shutdown();
ACGL_RiftSDKInitialized = false;
}
// For more sophisticated use cases build your own Rift for your needs based on the Rift SDK instead of using this default Rift.
//
// _headTrackingIsRequired = if false, the call will create a dummy device that won't generate any data in case no real Rift is connected
// (for developing without an actual device).
// _headTranslationTrackingIsAllowed = if true the Tracking of DK2 will get supported, if false even a DK2 will behave like a DK1
ovrHmd createHMD(bool _headTrackingIsRequired, bool _headTranslationTrackingIsAllowed)
{
//cout << "createRift()" << endl;
if (!ACGL_RiftSDKInitialized) {
error() << "Rift SDK not initialized correctly - did you call/check initRiftSDK()?" << endl;
} }
// For more sophisticated use cases build your own Rift for your needs based on the Rift SDK instead of using this default Rift. ovrHmd mHmd = ovrHmd_Create(0);
// if (!mHmd && _headTrackingIsRequired) {
// _headTrackingIsRequired = if false, the call will create a dummy device that won't generate any data in case no real Rift is connected error() << "could not connect to an Oculus Rift HMD" << endl;
// (for developing without an actual device). return NULL;
// _headTranslationTrackingIsAllowed = if true the Tracking of DK2 will get supported, if false even a DK2 will behave like a DK1 }
ovrHmd createRift(bool _headTrackingIsRequired, bool _headTranslationTrackingIsAllowed) else if (!mHmd && !_headTrackingIsRequired) {
{
cout << "createRift()" << endl;
if (!ACGL_RiftSDKInitialized) {
error() << "Rift SDK not initialized correctly - did you call/check initRiftSDK()?" << endl;
}
ovrHmd mHmd = ovrHmd_Create(0);
if (!mHmd && _headTrackingIsRequired) {
error() << "could not connect to an Oculus Rift HMD" << endl;
return NULL;
}
else if (!mHmd && !_headTrackingIsRequired) {
#if ACGL_RIFT_USE_DUMMY #if ACGL_RIFT_USE_DUMMY
warning() << "could not connect to a real Oculus Rift HMD - generating sensorless dummy" << endl; warning() << "could not connect to a real Oculus Rift HMD - generating sensorless dummy" << endl;
mHmd = ovrHmd_CreateDebug(ovrHmd_DK1); mHmd = ovrHmd_CreateDebug(ovrHmd_DK1);
#else #else
debug() << "could not connect to a real Oculus Rift HMD" << endl; debug() << "could not connect to a real Oculus Rift HMD" << endl;
mHmd = NULL; mHmd = NULL;
#endif #endif
//ovrHmd_SetEnabledCaps(mHmd, ovrHmdCap_NoMirrorToWindow); //ovrHmd_SetEnabledCaps(mHmd, ovrHmdCap_NoMirrorToWindow);
return mHmd; return mHmd;
} }
// debug output:
debug() << "Connected to: " << mHmd->ProductName << endl;
// start the tracking:
// what the application supports:
unsigned int supportedCaps = ovrTrackingCap_Orientation | ovrTrackingCap_MagYawCorrection | ovrTrackingCap_Position; // | ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction;
if (_headTranslationTrackingIsAllowed) supportedCaps |= ovrTrackingCap_Position;
// what the device must deliver as a bare minimum: // debug output:
unsigned int requiredCaps = 0; debug() << "Connected to: " << mHmd->ProductName << endl;
if (_headTrackingIsRequired) requiredCaps |= ovrTrackingCap_Orientation;
// start the tracking:
// what the application supports:
unsigned int supportedCaps = ovrTrackingCap_Orientation | ovrTrackingCap_MagYawCorrection | ovrTrackingCap_Position; // | ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction;
if (_headTranslationTrackingIsAllowed) supportedCaps |= ovrTrackingCap_Position;
ovrBool ok = ovrHmd_ConfigureTracking(mHmd, supportedCaps, requiredCaps); // what the device must deliver as a bare minimum:
if (!ok) { unsigned int requiredCaps = 0;
error() << "could not get connected to a Rift tracker - only rendering is supported" << endl; if (_headTrackingIsRequired) requiredCaps |= ovrTrackingCap_Orientation;
}
return mHmd;
}
void destroyRift(ovrHmd _hmd)
{ ovrBool ok = ovrHmd_ConfigureTracking(mHmd, supportedCaps, requiredCaps);
ovrHmd_Destroy(_hmd); if (!ok) {
error() << "could not get connected to a Rift tracker - only rendering is supported" << endl;
} }
return mHmd;
}
void destroyHMD(ovrHmd _hmd)
{
if (_hmd) ovrHmd_Destroy(_hmd);
}
glm::uvec2 getOptimalRenderSizePerEye(ovrHmd _hmd)
{
if (_hmd == NULL) return glm::uvec2(640, 800);
glm::uvec2 getOptimalRenderSizePerEye(ovrHmd _hmd) ovrSizei optimalLeft = ovrHmd_GetFovTextureSize(_hmd, ovrEye_Left, _hmd->DefaultEyeFov[0], 1.0f);
{ ovrSizei optimalRight = ovrHmd_GetFovTextureSize(_hmd, ovrEye_Right, _hmd->DefaultEyeFov[1], 1.0f);
if (_hmd == NULL) return glm::uvec2(640, 800);
ovrSizei optimalLeft = ovrHmd_GetFovTextureSize(_hmd, ovrEye_Left, _hmd->DefaultEyeFov[0], 1.0f);
ovrSizei optimalRight = ovrHmd_GetFovTextureSize(_hmd, ovrEye_Right, _hmd->DefaultEyeFov[1], 1.0f);
debug() << "optimalLeft " << optimalLeft.w << " " << optimalLeft.h << endl; //debug() << "optimalLeft " << optimalLeft.w << " " << optimalLeft.h << endl;
debug() << "optimalRight " << optimalRight.w << " " << optimalRight.h << endl; //debug() << "optimalRight " << optimalRight.w << " " << optimalRight.h << endl;
debug() << "hmd: " << _hmd->ProductName << endl; //debug() << "hmd: " << _hmd->ProductName << endl;
debug() << "hmd WindowsPos: " << _hmd->WindowsPos.x << " " << _hmd->WindowsPos.y << endl; //debug() << "hmd WindowsPos: " << _hmd->WindowsPos.x << " " << _hmd->WindowsPos.y << endl;
return glm::uvec2(glm::max(optimalLeft.w, optimalRight.w), glm::max(optimalLeft.h, optimalRight.h)); return glm::uvec2(glm::max(optimalLeft.w, optimalRight.w), glm::max(optimalLeft.h, optimalRight.h));
}
//return glm::uvec2(960, 1200); void generateEyeTextureDescription(ACGL::OpenGL::SharedTexture2D _leftTexture, ACGL::OpenGL::SharedTexture2D _rightTexture, ovrGLTexture _eyeRenderDesc[2])
{
// same for both eyes:
for (int eyeIndex = 0; eyeIndex < 2; ++eyeIndex) {
_eyeRenderDesc[eyeIndex].OGL.Header.API = ovrRenderAPI_OpenGL;
_eyeRenderDesc[eyeIndex].OGL.Header.RenderViewport.Pos.x = 0;
_eyeRenderDesc[eyeIndex].OGL.Header.RenderViewport.Pos.y = 0;
} }
_eyeRenderDesc[0].OGL.Header.TextureSize.w = _leftTexture->getWidth();
_eyeRenderDesc[0].OGL.Header.TextureSize.h = _leftTexture->getHeight();
_eyeRenderDesc[1].OGL.Header.TextureSize.w = _rightTexture->getWidth();
_eyeRenderDesc[1].OGL.Header.TextureSize.h = _rightTexture->getHeight();
_eyeRenderDesc[0].OGL.Header.RenderViewport.Size.w = _leftTexture->getWidth();
_eyeRenderDesc[0].OGL.Header.RenderViewport.Size.h = _leftTexture->getHeight();
_eyeRenderDesc[1].OGL.Header.RenderViewport.Size.w = _rightTexture->getWidth();
_eyeRenderDesc[1].OGL.Header.RenderViewport.Size.h = _rightTexture->getHeight();
_eyeRenderDesc[0].OGL.TexId = _leftTexture->getObjectName();
_eyeRenderDesc[1].OGL.TexId = _rightTexture->getObjectName();
}
#ifdef ACGL_COMPILE_WITH_GLFW #ifdef ACGL_COMPILE_WITH_GLFW
bool configureRendering( ovrHmd _hmd, ovrEyeRenderDesc _eyeRenderDesc[2], glm::uvec2 _renderTagetSize, GLFWwindow *_window ) bool configureRendering(ovrHmd _hmd, ovrEyeRenderDesc _eyeRenderDesc[2], glm::uvec2 _renderTagetSize, GLFWwindow *_window)
{ {
glBindVertexArray(0); if (!_hmd) return false;
// Update ovr Rendering configuration // Update ovr Rendering configuration
ovrGLConfig cfg; ovrGLConfig cfg;
cfg.OGL.Header.API = ovrRenderAPI_OpenGL; cfg.OGL.Header.API = ovrRenderAPI_OpenGL;
cfg.OGL.Header.RTSize.w = _renderTagetSize.x; cfg.OGL.Header.RTSize.w = _renderTagetSize.x;
cfg.OGL.Header.RTSize.h = _renderTagetSize.y; cfg.OGL.Header.RTSize.h = _renderTagetSize.y;
cfg.OGL.Header.Multisample = 0; cfg.OGL.Header.Multisample = 0;
#ifdef OVR_OS_WIN32 #ifdef OVR_OS_WIN32
debug() << "configure Windows specifics" << std::endl; //debug() << "configure Windows specifics" << std::endl;
cfg.OGL.Window = glfwGetWin32Window( _window ); cfg.OGL.Window = glfwGetWin32Window(_window);
cfg.OGL.DC = GetDC(cfg.OGL.Window); cfg.OGL.DC = GetDC(cfg.OGL.Window);
#endif #endif
#ifdef OVR_OS_MAC #ifdef OVR_OS_MAC
debug() << "configure Mac specifics: TODO" << std::endl; debug() << "configure Mac specifics: TODO" << std::endl;
#endif #endif
#ifdef OVR_OS_LINUX #ifdef OVR_OS_LINUX
debug() << "configure Linux specifics: TODO" << std::endl; debug() << "configure Linux specifics: TODO" << std::endl;
#endif #endif
debug() << "call ovrHmd_ConfigureRendering():" << std::endl; //debug() << "call ovrHmd_ConfigureRendering():" << std::endl;
printOVRDistortionCaps(_hmd->DistortionCaps); //printDistortionCaps(_hmd->DistortionCaps);
unsigned int distortionCaps = _hmd->DistortionCaps ^ ovrDistortionCap_FlipInput; // don't flip the input unsigned int distortionCaps = _hmd->DistortionCaps ^ ovrDistortionCap_FlipInput; // don't flip the input
//distortionCaps ^= ovrDistortionCap_NoRestore; //distortionCaps ^= ovrDistortionCap_NoRestore;
distortionCaps ^= ovrDistortionCap_SRGB; distortionCaps ^= ovrDistortionCap_SRGB;
printOVRDistortionCaps(distortionCaps); #ifdef OVR_OS_WIN32
ovrBool ok = ovrHmd_ConfigureRendering(_hmd, (ovrRenderAPIConfig*)&cfg, distortionCaps, _hmd->DefaultEyeFov, _eyeRenderDesc); ovrHmd_AttachToWindow(_hmd, cfg.OGL.Window, nullptr, nullptr);
if (ok) { #endif
bool riftIsUsingExtendedDesktop = (bool)(_hmd->HmdCaps & ovrHmdCap_ExtendDesktop);
if (riftIsUsingExtendedDesktop) { //printDistortionCaps(distortionCaps);
debug() << "rendering on extended desktop" << endl; ovrBool ok = ovrHmd_ConfigureRendering(_hmd, (ovrRenderAPIConfig*)&cfg, distortionCaps, _hmd->DefaultEyeFov, _eyeRenderDesc);
} else { if (ok) {
debug() << "rendering in direct rendering mode" << endl; bool riftIsUsingExtendedDesktop = (bool)(_hmd->HmdCaps & ovrHmdCap_ExtendDesktop);
ovrHmd_AttachToWindow(_hmd, cfg.OGL.Window, nullptr, nullptr); //debug() << "OVR Rendering configured" << std::endl;
}
debug() << "OVR Rendering configured" << std::endl;
}
else {
error() << "OVR Rendering failed to get configured" << std::endl;
}
return (bool)ok;
} }
else {
error() << "OVR Rendering failed to get configured" << std::endl;
}
return (bool)ok;
}
#endif #endif
bool deactivateHealthWarning(ovrHmd _hmd) bool deactivateHealthWarning(ovrHmd _hmd)
{ {
ovrHSWDisplayState displayState; if (!_hmd) return false;
ovrHmd_GetHSWDisplayState(_hmd, &displayState);
if (displayState.Displayed) { ovrHSWDisplayState displayState;
ovrHmd_DismissHSWDisplay(_hmd); ovrHmd_GetHSWDisplayState(_hmd, &displayState);
return true;
}
return false; if (displayState.Displayed) {
ovrHmd_DismissHSWDisplay(_hmd);
return true;
} }
// prints the distortion caps for debugging: return false;
void printOVRDistortionCaps(unsigned int _caps) { }
debug() << endl << "Distortion caps: " << _caps << " = ";
if (_caps & ovrDistortionCap_Chromatic) debug() << "Chromatic "; void beginFrame(ovrHmd _hmd)
if (_caps & ovrDistortionCap_TimeWarp) debug() << "TimeWarp "; {
if (_caps & ovrDistortionCap_Vignette) debug() << "Vignette "; glFrontFace(GL_CCW); // not reset by the health warning :-(
if (_caps & ovrDistortionCap_NoRestore) debug() << "GLStateChangedBySDK "; glDepthMask(GL_TRUE); // not reset by Rift SDK :-(
if (_caps & ovrDistortionCap_FlipInput) debug() << "FlipInput "; ovrFrameTiming frameTiming = ovrHmd_BeginFrame(_hmd, 0);
if (_caps & ovrDistortionCap_SRGB) debug() << "sRGB_Input "; }
if (_caps & ovrDistortionCap_Overdrive) debug() << "reduceDK2Artefacts ";
debug() << endl << endl; // prints the distortion caps for debugging:
} void printDistortionCaps(unsigned int _caps) {
debug() << endl << "Distortion caps: " << _caps << " = ";
if (_caps & ovrDistortionCap_Chromatic) debug() << "Chromatic ";