Oculus VR (Rift) support

Input device and shaders for supporting the Oculus Rift.
This commit is contained in:
DavidWyand-GG 2013-04-10 01:05:26 -04:00
parent 2123365d4d
commit de7a72d82a
24 changed files with 3214 additions and 0 deletions

View file

@ -0,0 +1,188 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/input/oculusVR/barrelDistortionPostEffect.h"
#include "console/consoleTypes.h"
#include "console/engineAPI.h"
#include "gfx/gfxDevice.h"
#include "platform/input/oculusVR/oculusVRDevice.h"
extern bool gEditingMission;
ConsoleDocClass( BarrelDistortionPostEffect,
"@brief A fullscreen shader effect used with the Oculus Rift.\n\n"
"@section PFXTextureIdentifiers\n\n"
"@ingroup Rendering\n"
);
IMPLEMENT_CONOBJECT(BarrelDistortionPostEffect);
BarrelDistortionPostEffect::BarrelDistortionPostEffect()
: PostEffect(),
mHmdWarpParamSC(NULL),
mScaleSC(NULL),
mScaleInSC(NULL),
mLensCenterSC(NULL),
mScreenCenterSC(NULL)
{
mHMDIndex = 0;
mSensorIndex = 0;
mScaleOutput = 1.0f;
}
BarrelDistortionPostEffect::~BarrelDistortionPostEffect()
{
}
void BarrelDistortionPostEffect::initPersistFields()
{
addField( "hmdIndex", TypeS32, Offset( mHMDIndex, BarrelDistortionPostEffect ),
"Oculus VR HMD index to reference." );
addField( "sensorIndex", TypeS32, Offset( mSensorIndex, BarrelDistortionPostEffect ),
"Oculus VR sensor index to reference." );
addField( "scaleOutput", TypeF32, Offset( mScaleOutput, BarrelDistortionPostEffect ),
"Used to increase the size of the window into the world at the expense of apparent resolution." );
Parent::initPersistFields();
}
bool BarrelDistortionPostEffect::onAdd()
{
if( !Parent::onAdd() )
return false;
return true;
}
void BarrelDistortionPostEffect::onRemove()
{
Parent::onRemove();
}
void BarrelDistortionPostEffect::_setupConstants( const SceneRenderState *state )
{
Parent::_setupConstants(state);
// Define the shader constants
if(!mHmdWarpParamSC)
mHmdWarpParamSC = mShader->getShaderConstHandle( "$HmdWarpParam" );
if(!mScaleSC)
mScaleSC = mShader->getShaderConstHandle( "$Scale" );
if(!mScaleInSC)
mScaleInSC = mShader->getShaderConstHandle( "$ScaleIn" );
if(!mLensCenterSC)
mLensCenterSC = mShader->getShaderConstHandle( "$LensCenter" );
if(!mScreenCenterSC)
mScreenCenterSC = mShader->getShaderConstHandle( "$ScreenCenter" );
const Point2I &resolution = GFX->getActiveRenderTarget()->getSize();
F32 widthScale = 0.5f;
F32 heightScale = 1.0f;
F32 aspectRatio = (resolution.x * 0.5f) / resolution.y;
// Set up the HMD dependant shader constants
if(ManagedSingleton<OculusVRDevice>::instanceOrNull() && OCULUSVRDEV->getHMDDevice(mHMDIndex))
{
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(mHMDIndex);
if(mHmdWarpParamSC->isValid())
{
const Point4F& distortion = hmd->getKDistortion();
mShaderConsts->set( mHmdWarpParamSC, distortion );
}
if(mScaleSC->isValid())
{
F32 scaleFactor = hmd->getDistortionScale();
if(!mIsZero(mScaleOutput))
{
scaleFactor /= mScaleOutput;
}
Point2F scale;
scale.x = widthScale * 0.5f * scaleFactor;
scale.y = heightScale * 0.5f * scaleFactor * aspectRatio;
mShaderConsts->set( mScaleSC, scale );
}
if(mLensCenterSC->isValid())
{
F32 xCenterOffset = hmd->getCenterOffset();
Point3F lensCenter;
lensCenter.x = (widthScale + xCenterOffset * 0.5f) * 0.5f;
lensCenter.y = (widthScale - xCenterOffset * 0.5f) * 0.5f;
lensCenter.z = heightScale * 0.5f;
mShaderConsts->set( mLensCenterSC, lensCenter );
}
}
else
{
if(mHmdWarpParamSC->isValid())
{
mShaderConsts->set( mHmdWarpParamSC, Point4F(0.0f, 0.0f, 0.0f, 0.0f) );
}
if(mScaleSC->isValid())
{
mShaderConsts->set( mScaleSC, Point2F(1.0f, 1.0f) );
}
if(mLensCenterSC->isValid())
{
Point3F lensCenter;
lensCenter.x = widthScale * 0.5f;
lensCenter.y = widthScale * 0.5f;
lensCenter.z = heightScale * 0.5f;
mShaderConsts->set( mLensCenterSC, lensCenter );
}
}
if(mScaleInSC->isValid())
{
Point2F scaleIn;
scaleIn.x = 2.0f / widthScale;
scaleIn.y = 2.0f / heightScale / aspectRatio;
mShaderConsts->set( mScaleInSC, scaleIn );
}
if(mScreenCenterSC->isValid())
{
mShaderConsts->set( mScreenCenterSC, Point2F(widthScale * 0.5f, heightScale * 0.5f) );
}
}
void BarrelDistortionPostEffect::process(const SceneRenderState *state, GFXTexHandle &inOutTex, const RectI *inTexViewport)
{
// Don't draw the post effect if the editor is active
if(gEditingMission)
return;
Parent::process(state, inOutTex, inTexViewport);
}

View file

@ -0,0 +1,68 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _BARRELDISTORTIONPOSTEFFECT_H_
#define _BARRELDISTORTIONPOSTEFFECT_H_
#include "postFx/postEffect.h"
class BarrelDistortionPostEffect : public PostEffect
{
typedef PostEffect Parent;
protected:
GFXShaderConstHandle *mHmdWarpParamSC;
GFXShaderConstHandle *mScaleSC;
GFXShaderConstHandle *mScaleInSC;
GFXShaderConstHandle *mLensCenterSC;
GFXShaderConstHandle *mScreenCenterSC;
// Oculus VR HMD index to reference
S32 mHMDIndex;
// Oculus VR sensor index to reference
S32 mSensorIndex;
// Used to increase the size of the window into the world at the
// expense of apparent resolution.
F32 mScaleOutput;
protected:
virtual void _setupConstants( const SceneRenderState *state );
public:
BarrelDistortionPostEffect();
virtual ~BarrelDistortionPostEffect();
DECLARE_CONOBJECT(BarrelDistortionPostEffect);
// SimObject
virtual bool onAdd();
virtual void onRemove();
static void initPersistFields();
virtual void process( const SceneRenderState *state,
GFXTexHandle &inOutTex,
const RectI *inTexViewport = NULL );
};
#endif // _BARRELDISTORTIONPOSTEFFECT_H_

View file

@ -0,0 +1,34 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _OCULUSVRCONSTANTS_H_
#define _OCULUSVRCONSTANTS_H_
namespace OculusVRConstants
{
enum Constants {
DefaultOVRBase = 0,
MaxSensors = 1,
};
}
#endif // _OCULUSVRCONSTANTS_H_

View file

@ -0,0 +1,844 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/input/oculusVR/oculusVRDevice.h"
#include "platform/platformInput.h"
#include "core/module.h"
#include "console/engineAPI.h"
#include "T3D/gameBase/gameConnection.h"
MODULE_BEGIN( OculusVRDevice )
MODULE_INIT_AFTER( InputEventManager )
MODULE_SHUTDOWN_BEFORE( InputEventManager )
MODULE_INIT
{
OculusVRDevice::staticInit();
ManagedSingleton< OculusVRDevice >::createSingleton();
if(OculusVRDevice::smEnableDevice)
{
OCULUSVRDEV->enable();
}
// Register the device with the Input Event Manager
INPUTMGR->registerDevice(OCULUSVRDEV);
}
MODULE_SHUTDOWN
{
INPUTMGR->unregisterDevice(OCULUSVRDEV);
ManagedSingleton< OculusVRDevice >::deleteSingleton();
}
MODULE_END;
//-----------------------------------------------------------------------------
// OculusVRDevice
//-----------------------------------------------------------------------------
bool OculusVRDevice::smEnableDevice = true;
bool OculusVRDevice::smSimulateHMD = true;
bool OculusVRDevice::smGenerateAngleAxisRotationEvents = true;
bool OculusVRDevice::smGenerateEulerRotationEvents = false;
bool OculusVRDevice::smGenerateRotationAsAxisEvents = false;
F32 OculusVRDevice::smMaximumAxisAngle = 25.0f;
bool OculusVRDevice::smGenerateWholeFrameEvents = false;
OculusVRDevice::OculusVRDevice()
{
// From IInputDevice
dStrcpy(mName, "oculusvr");
mDeviceType = INPUTMGR->getNextDeviceType();
//
mEnabled = false;
mActive = false;
// We don't current support scaling of the input texture. The graphics pipeline will
// need to be modified for this.
mScaleInputTexture = false;
mDeviceManager = NULL;
mListener = NULL;
buildCodeTable();
}
OculusVRDevice::~OculusVRDevice()
{
cleanUp();
}
void OculusVRDevice::staticInit()
{
Con::addVariable("pref::OculusVR::EnableDevice", TypeBool, &smEnableDevice,
"@brief If true, the Oculus VR device will be enabled, if present.\n\n"
"@ingroup Game");
Con::addVariable("OculusVR::GenerateAngleAxisRotationEvents", TypeBool, &smGenerateAngleAxisRotationEvents,
"@brief If true, broadcast sensor rotation events as angled axis.\n\n"
"@ingroup Game");
Con::addVariable("OculusVR::GenerateEulerRotationEvents", TypeBool, &smGenerateEulerRotationEvents,
"@brief If true, broadcast sensor rotation events as Euler angles about the X, Y and Z axis.\n\n"
"@ingroup Game");
Con::addVariable("OculusVR::GenerateRotationAsAxisEvents", TypeBool, &smGenerateRotationAsAxisEvents,
"@brief If true, broadcast sensor rotation as axis events.\n\n"
"@ingroup Game");
Con::addVariable("OculusVR::MaximumAxisAngle", TypeF32, &smMaximumAxisAngle,
"@brief The maximum sensor angle when used as an axis event as measured from a vector pointing straight up (in degrees).\n\n"
"Should range from 0 to 90 degrees.\n\n"
"@ingroup Game");
Con::addVariable("OculusVR::GenerateWholeFrameEvents", TypeBool, &smGenerateWholeFrameEvents,
"@brief Indicates that a whole frame event should be generated and frames should be buffered.\n\n"
"@ingroup Game");
}
void OculusVRDevice::cleanUp()
{
disable();
}
void OculusVRDevice::buildCodeTable()
{
// Build the sensor device code table
OculusVRSensorDevice::buildCodeTable();
}
void OculusVRDevice::addHMDDevice(OVR::HMDDevice* hmd)
{
if(!hmd)
return;
OVR::HMDInfo hmdInfo;
if(!hmd->GetDeviceInfo(&hmdInfo))
return;
OculusVRHMDDevice* hmdd = new OculusVRHMDDevice();
hmdd->set(hmd, hmdInfo, mScaleInputTexture);
mHMDDevices.push_back(hmdd);
Con::printf(" HMD found: %s by %s [v%d]", hmdInfo.ProductName, hmdInfo.Manufacturer, hmdInfo.Version);
}
void OculusVRDevice::createSimulatedHMD()
{
OculusVRHMDDevice* hmdd = new OculusVRHMDDevice();
hmdd->createSimulation(OculusVRHMDDevice::ST_RIFT_PREVIEW, mScaleInputTexture);
mHMDDevices.push_back(hmdd);
Con::printf(" HMD simulated: %s by %s [v%d]", hmdd->getProductName(), hmdd->getManufacturer(), hmdd->getVersion());
}
void OculusVRDevice::addSensorDevice(OVR::SensorDevice* sensor)
{
if(!sensor)
return;
OVR::SensorInfo sensorInfo;
if(!sensor->GetDeviceInfo(&sensorInfo))
return;
OculusVRSensorDevice* sensord = new OculusVRSensorDevice();
sensord->set(sensor, sensorInfo, mSensorDevices.size());
mSensorDevices.push_back(sensord);
Con::printf(" Sensor found: %s by %s [v%d] %s", sensorInfo.ProductName, sensorInfo.Manufacturer, sensorInfo.Version, sensorInfo.SerialNumber);
}
void OculusVRDevice::createSimulatedSensor()
{
OculusVRSensorDevice* sensord = new OculusVRSensorDevice();
sensord->createSimulation(OculusVRSensorDevice::ST_RIFT_PREVIEW, mSensorDevices.size());
mSensorDevices.push_back(sensord);
Con::printf(" Sensor simulated: %s by %s [v%d] %s", sensord->getProductName(), sensord->getManufacturer(), sensord->getVersion(), sensord->getSerialNumber());
}
bool OculusVRDevice::enable()
{
// Start off with disabling the device if it is already enabled
disable();
Con::printf("Oculus VR Device Init:");
OVR::System::Init(OVR::Log::ConfigureDefaultLog(OVR::LogMask_All));
if(OVR::System::IsInitialized())
{
mEnabled = true;
// Create the OVR device manager
mDeviceManager = OVR::DeviceManager::Create();
if(!mDeviceManager)
{
if(smSimulateHMD)
{
Con::printf(" Could not create a HMD device manager. Simulating a HMD.");
Con::printf(" ");
createSimulatedHMD();
createSimulatedSensor();
setActive(true);
return true;
}
else
{
Con::printf(" Could not create a HMD device manager.");
Con::printf(" ");
mEnabled = false;
OVR::System::Destroy();
return false;
}
}
// Provide a message listener
// NOTE: Commented out as non-functional in 0.1.2
//mListener = new DeviceListener(this);
//mDeviceManager->SetMessageHandler(mListener);
// Enumerate HMDs and pick the first one
OVR::HMDDevice* hmd = mDeviceManager->EnumerateDevices<OVR::HMDDevice>().CreateDevice();
if(hmd)
{
// Add the HMD to our list
addHMDDevice(hmd);
// Detect and add any sensor on the HMD
OVR::SensorDevice* sensor = hmd->GetSensor();
if(sensor)
{
addSensorDevice(sensor);
}
else
{
Con::printf(" No sensor device on HMD.");
}
setActive(true);
}
else
{
if(smSimulateHMD)
{
Con::printf(" Could not enumerate a HMD device. Simulating a HMD.");
createSimulatedHMD();
createSimulatedSensor();
setActive(true);
}
else
{
Con::printf(" Could not enumerate a HMD device.");
}
}
}
Con::printf(" ");
return false;
}
void OculusVRDevice::disable()
{
for(U32 i=0; i<mSensorDevices.size(); ++i)
{
delete mSensorDevices[i];
}
mSensorDevices.clear();
for(U32 i=0; i<mHMDDevices.size(); ++i)
{
delete mHMDDevices[i];
}
mHMDDevices.clear();
if(mDeviceManager)
{
mDeviceManager->Release();
mDeviceManager = NULL;
}
if(mEnabled)
{
OVR::System::Destroy();
}
if(mListener)
{
delete mListener;
mListener = NULL;
}
setActive(false);
mEnabled = false;
}
bool OculusVRDevice::process()
{
if(!mEnabled)
return false;
if(!getActive())
return false;
//Build the maximum axis angle to be passed into the sensor process()
F32 maxAxisRadius = mSin(mDegToRad(smMaximumAxisAngle));
// Process each sensor
for(U32 i=0; i<mSensorDevices.size(); ++i)
{
mSensorDevices[i]->process(mDeviceType, smGenerateAngleAxisRotationEvents, smGenerateEulerRotationEvents, smGenerateRotationAsAxisEvents, maxAxisRadius);
}
return true;
}
//-----------------------------------------------------------------------------
bool OculusVRDevice::providesYFOV() const
{
if(!mHMDDevices.size())
return false;
return true;
}
F32 OculusVRDevice::getYFOV() const
{
if(!mHMDDevices.size())
return 0.0f;
const OculusVRHMDDevice* hmd = getHMDDevice(0);
if(!hmd)
return 0.0f;
return hmd->getYFOV();
}
bool OculusVRDevice::providesEyeOffset() const
{
if(!mHMDDevices.size())
return false;
return true;
}
const Point3F& OculusVRDevice::getEyeOffset() const
{
if(!mHMDDevices.size())
return Point3F::Zero;
const OculusVRHMDDevice* hmd = getHMDDevice(0);
if(!hmd)
return Point3F::Zero;
return hmd->getEyeWorldOffset();
}
bool OculusVRDevice::providesProjectionOffset() const
{
if(!mHMDDevices.size())
return false;
return true;
}
const Point2F& OculusVRDevice::getProjectionOffset() const
{
if(!mHMDDevices.size())
return Point2F::Zero;
const OculusVRHMDDevice* hmd = getHMDDevice(0);
if(!hmd)
return Point2F::Zero;
return hmd->getProjectionCenterOffset();
}
//-----------------------------------------------------------------------------
const OculusVRHMDDevice* OculusVRDevice::getHMDDevice(U32 index) const
{
if(index >= mHMDDevices.size())
return NULL;
return mHMDDevices[index];
}
//-----------------------------------------------------------------------------
const OculusVRSensorDevice* OculusVRDevice::getSensorDevice(U32 index) const
{
if(index >= mSensorDevices.size())
return NULL;
return mSensorDevices[index];
}
EulerF OculusVRDevice::getSensorEulerRotation(U32 index)
{
if(index >= mSensorDevices.size())
return Point3F::Zero;
return mSensorDevices[index]->getEulerRotation();
}
F32 OculusVRDevice::getSensorPredictionTime(U32 index)
{
const OculusVRSensorDevice* sensor = getSensorDevice(index);
if(!sensor || !sensor->isValid())
return 0.0f;
return sensor->getPredictionTime();
}
void OculusVRDevice::setSensorPredictionTime(U32 index, F32 dt)
{
if(index >= mSensorDevices.size())
return;
OculusVRSensorDevice* sensor = mSensorDevices[index];
if(!sensor->isValid())
return;
sensor->setPredictionTime(dt);
}
void OculusVRDevice::setAllSensorPredictionTime(F32 dt)
{
for(U32 i=0; i<mSensorDevices.size(); ++i)
{
mSensorDevices[i]->setPredictionTime(dt);
}
}
void OculusVRDevice::resetAllSensors()
{
// Reset each sensor
for(U32 i=0; i<mSensorDevices.size(); ++i)
{
mSensorDevices[i]->reset();
}
}
//-----------------------------------------------------------------------------
void OculusVRDevice::DeviceListener::OnMessage(const OVR::Message& msg)
{
switch(msg.Type)
{
case OVR::Message_DeviceAdded:
{
const OVR::MessageDeviceStatus* status = static_cast<const OVR::MessageDeviceStatus*>(&msg);
Con::printf("OVR: Device added of type: %d", status->Handle.GetType());
}
break;
case OVR::Message_DeviceRemoved:
Con::printf("OVR: Device removed of type: %d", msg.pDevice->GetType());
break;
default:
break;
}
}
//-----------------------------------------------------------------------------
DefineEngineFunction(isOculusVRDeviceActive, bool, (),,
"@brief Used to determine if the Oculus VR input device is active\n\n"
"The Oculus VR device is considered active when the library has been "
"initialized and either a real of simulated HMD is present.\n\n"
"@return True if the Oculus VR input device is active.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return false;
}
return OCULUSVRDEV->getActive();
}
//-----------------------------------------------------------------------------
DefineEngineFunction(setOVRHMDAsGameConnectionDisplayDevice, bool, (GameConnection* conn),,
"@brief Sets the first HMD to be a GameConnection's display device\n\n"
"@param conn The GameConnection to set.\n"
"@return True if the GameConnection display device was set.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
Con::errorf("setOVRHMDAsGameConnectionDisplayDevice(): No Oculus VR Device present.");
return false;
}
if(!conn)
{
Con::errorf("setOVRHMDAsGameConnectionDisplayDevice(): Invalid GameConnection.");
return false;
}
conn->setDisplayDevice(OCULUSVRDEV);
return true;
}
//-----------------------------------------------------------------------------
DefineEngineFunction(getOVRHMDCount, S32, (),,
"@brief Get the number of HMD devices that are currently connected.\n\n"
"@return The number of Oculus VR HMD devices that are currently connected.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return 0;
}
return OCULUSVRDEV->getHMDCount();
}
DefineEngineFunction(isOVRHMDSimulated, bool, (S32 index),,
"@brief Determines if the requested OVR HMD is simulated or real.\n\n"
"@param index The HMD index.\n"
"@return True if the HMD is simulated.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return true;
}
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index);
if(!hmd)
{
return true;
}
return hmd->isSimulated();
}
DefineEngineFunction(getOVRHMDProductName, const char*, (S32 index),,
"@brief Retrieves the HMD product name.\n\n"
"@param index The HMD index.\n"
"@return The name of the HMD product.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return "";
}
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index);
if(!hmd)
{
return "";
}
return hmd->getProductName();
}
DefineEngineFunction(getOVRHMDManufacturer, const char*, (S32 index),,
"@brief Retrieves the HMD manufacturer name.\n\n"
"@param index The HMD index.\n"
"@return The manufacturer of the HMD product.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return "";
}
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index);
if(!hmd)
{
return "";
}
return hmd->getManufacturer();
}
DefineEngineFunction(getOVRHMDVersion, S32, (S32 index),,
"@brief Retrieves the HMD version number.\n\n"
"@param index The HMD index.\n"
"@return The version number of the HMD product.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return -1;
}
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index);
if(!hmd)
{
return -1;
}
return hmd->getVersion();
}
DefineEngineFunction(getOVRHMDDisplayDeviceName, const char*, (S32 index),,
"@brief Windows display device name used in EnumDisplaySettings/CreateDC.\n\n"
"@param index The HMD index.\n"
"@return The name of the HMD display device, if any.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return "";
}
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index);
if(!hmd)
{
return "";
}
return hmd->getDisplayDeviceName();
}
DefineEngineFunction(getOVRHMDResolution, Point2I, (S32 index),,
"@brief Provides the OVR HMD screen resolution.\n\n"
"@param index The HMD index.\n"
"@return A two component string with the screen's resolution.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return Point2I(1280, 800);
}
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index);
if(!hmd)
{
return Point2I(1280, 800);
}
return hmd->getResolution();
}
DefineEngineFunction(getOVRHMDDistortionCoefficients, String, (S32 index),,
"@brief Provides the OVR HMD distortion coefficients.\n\n"
"@param index The HMD index.\n"
"@return A four component string with the distortion coefficients.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return "0 0 0 0";
}
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index);
if(!hmd)
{
return "0 0 0 0";
}
const Point4F& k = hmd->getKDistortion();
char buf[256];
dSprintf(buf, 256, "%g %g %g %g", k.x, k.y, k.z, k.w);
return buf;
}
DefineEngineFunction(getOVRHMDEyeXOffsets, Point2F, (S32 index),,
"@brief Provides the OVR HMD eye x offsets in uv coordinates.\n\n"
"@param index The HMD index.\n"
"@return A two component string with the left and right eye x offsets.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return Point2F(0.5, 0.5);
}
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index);
if(!hmd)
{
return Point2F(0.5, 0.5);
}
// X component is left, Y component is right
const Point2F& offset = hmd->getEyeUVOffset();
return offset;
}
DefineEngineFunction(getOVRHMDXCenterOffset, F32, (S32 index),,
"@brief Provides the OVR HMD calculated XCenterOffset.\n\n"
"@param index The HMD index.\n"
"@return The calculated XCenterOffset.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return 0.0f;
}
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index);
if(!hmd)
{
return 0.0f;
}
F32 offset = hmd->getCenterOffset();
return offset;
}
DefineEngineFunction(getOVRHMDDistortionScale, F32, (S32 index),,
"@brief Provides the OVR HMD calculated distortion scale.\n\n"
"@param index The HMD index.\n"
"@return The calculated distortion scale.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return 1.0f;
}
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index);
if(!hmd)
{
return 1.0f;
}
F32 scale = hmd->getDistortionScale();
return scale;
}
DefineEngineFunction(getOVRHMDYFOV, F32, (S32 index),,
"@brief Provides the OVR HMD calculated Y FOV.\n\n"
"@param index The HMD index.\n"
"@return The calculated Y FOV.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return 1.0f;
}
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index);
if(!hmd)
{
return 1.0f;
}
F32 fov = hmd->getYFOV();
return mRadToDeg(fov);
}
//-----------------------------------------------------------------------------
DefineEngineFunction(getOVRSensorCount, S32, (),,
"@brief Get the number of sensor devices that are currently connected.\n\n"
"@return The number of Oculus VR sensor devices that are currently connected.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return 0;
}
return OCULUSVRDEV->getSensorCount();
}
DefineEngineFunction(getOVRSensorEulerRotation, Point3F, (S32 index),,
"@brief Get the Euler rotation values for the given sensor index.\n\n"
"@param index The sensor index.\n"
"@return The Euler rotation values of the Oculus VR sensor, in degrees.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return Point3F::Zero;
}
EulerF rot = OCULUSVRDEV->getSensorEulerRotation(index);
return Point3F(mRadToDeg(rot.x), mRadToDeg(rot.y), mRadToDeg(rot.z));
}
DefineEngineFunction(getOVRSensorPredictionTime, F32, (S32 index),,
"@brief Get the prediction time set for the given sensor index.\n\n"
"@param index The sensor index.\n"
"@return The prediction time of the Oculus VR sensor, given in seconds.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return 0;
}
return OCULUSVRDEV->getSensorPredictionTime(index);
}
DefineEngineFunction(setSensorPredictionTime, void, (S32 index, F32 dt),,
"@brief Set the prediction time set for the given sensor index.\n\n"
"@param index The sensor index.\n"
"@param dt The prediction time to set given in seconds. Setting to 0 disables prediction.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return;
}
OCULUSVRDEV->setSensorPredictionTime(index, dt);
}
DefineEngineFunction(setAllSensorPredictionTime, void, (F32 dt),,
"@brief Set the prediction time set for all sensors.\n\n"
"@param dt The prediction time to set given in seconds. Setting to 0 disables prediction.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return;
}
OCULUSVRDEV->setAllSensorPredictionTime(dt);
}
DefineEngineFunction(ovrResetAllSensors, void, (),,
"@brief Resets all Oculus VR sensors.\n\n"
"This resets all sensor orientations such that their 'normal' rotation "
"is defined when this function is called. This defines an HMD's forwards "
"and up direction, for example."
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return;
}
OCULUSVRDEV->resetAllSensors();
}

View file

@ -0,0 +1,152 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _OCULUSVRDEVICE_H_
#define _OCULUSVRDEVICE_H_
#include "platform/input/oculusVR/oculusVRConstants.h"
#include "platform/input/oculusVR/oculusVRHMDDevice.h"
#include "platform/input/oculusVR/oculusVRSensorDevice.h"
#include "platform/input/IInputDevice.h"
#include "platform/input/event.h"
#include "platform/output/IDisplayDevice.h"
#include "core/util/tSingleton.h"
#include "math/mQuat.h"
#include "math/mPoint4.h"
#include "OVR.h"
#define DEFAULT_RIFT_UNIT 0
class OculusVRDevice : public IInputDevice, public IDisplayDevice
{
public:
static bool smEnableDevice;
// If no HMD is present simulate it being available
static bool smSimulateHMD;
// Type of rotation events to broadcast
static bool smGenerateAngleAxisRotationEvents;
static bool smGenerateEulerRotationEvents;
// Broadcast sensor rotation as axis
static bool smGenerateRotationAsAxisEvents;
// The maximum sensor angle when used as an axis event
// as measured from a vector pointing straight up (in degrees)
static F32 smMaximumAxisAngle;
// Indicates that a whole frame event should be generated and frames
// should be buffered.
static bool smGenerateWholeFrameEvents;
protected:
class DeviceListener : public OVR::MessageHandler
{
protected:
OculusVRDevice* mOwner;
public:
DeviceListener(OculusVRDevice* owner) { mOwner = owner; }
virtual ~DeviceListener() { mOwner = NULL; }
virtual void OnMessage(const OVR::Message&);
};
// Our OVR SDK device listener class
DeviceListener* mListener;
// The OVR SDK device manager
OVR::DeviceManager* mDeviceManager;
// Discovered HMD devices
Vector<OculusVRHMDDevice*> mHMDDevices;
// Discovered sensor devices
Vector<OculusVRSensorDevice*> mSensorDevices;
/// Is the device active
bool mActive;
// Should the input texture into the HMD (the render target that the scene has been
// rendered to) be scaled according to the HMD's distortion calculation?
bool mScaleInputTexture;
protected:
void cleanUp();
/// Build out the codes used for controller actions with the
/// Input Event Manager
void buildCodeTable();
void addHMDDevice(OVR::HMDDevice* hmd);
void createSimulatedHMD();
void addSensorDevice(OVR::SensorDevice* sensor);
void createSimulatedSensor();
public:
OculusVRDevice();
~OculusVRDevice();
static void staticInit();
bool enable();
void disable();
bool getActive() { return mActive; }
void setActive(bool state) { mActive = state; }
bool process();
// IDisplayDevice
virtual bool providesYFOV() const;
virtual F32 getYFOV() const;
virtual bool providesEyeOffset() const;
virtual const Point3F& getEyeOffset() const;
virtual bool providesProjectionOffset() const;
virtual const Point2F& getProjectionOffset() const;
// HMDs
U32 getHMDCount() const { return mHMDDevices.size(); }
const OculusVRHMDDevice* getHMDDevice(U32 index) const;
// Sensors
U32 getSensorCount() const { return mSensorDevices.size(); }
const OculusVRSensorDevice* getSensorDevice(U32 index) const;
EulerF getSensorEulerRotation(U32 index);
F32 getSensorPredictionTime(U32 index);
void setSensorPredictionTime(U32 index, F32 dt);
void setAllSensorPredictionTime(F32 dt);
void resetAllSensors();
public:
// For ManagedSingleton.
static const char* getSingletonName() { return "OculusVRDevice"; }
};
/// Returns the OculusVRDevice singleton.
#define OCULUSVRDEV ManagedSingleton<OculusVRDevice>::instance()
#endif // _OCULUSVRDEVICE_H_

View file

@ -0,0 +1,208 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/input/oculusVR/oculusVRHMDDevice.h"
OculusVRHMDDevice::OculusVRHMDDevice()
{
mIsValid = false;
mIsSimulation = false;
mDevice = NULL;
}
OculusVRHMDDevice::~OculusVRHMDDevice()
{
cleanUp();
}
void OculusVRHMDDevice::cleanUp()
{
if(mDevice)
{
mDevice->Release();
mDevice = NULL;
}
mIsValid = false;
}
void OculusVRHMDDevice::set(OVR::HMDDevice* hmd, OVR::HMDInfo& info, bool calculateDistortionScale)
{
mIsValid = false;
mIsSimulation = false;
mDevice = hmd;
// DeviceInfo
mProductName = info.ProductName;
mManufacturer = info.Manufacturer;
mVersion = info.Version;
mDisplayDeviceName = info.DisplayDeviceName;
mResolution.x = info.HResolution;
mResolution.y = info.VResolution;
mScreenSize.x = info.HScreenSize;
mScreenSize.y = info.VScreenSize;
mVerticalEyeCenter = info.VScreenCenter;
mEyeToScreen = info.EyeToScreenDistance;
mLensSeparation = info.LensSeparationDistance;
mInterpupillaryDistance = info.InterpupillaryDistance;
mKDistortion.x = info.DistortionK[0];
mKDistortion.y = info.DistortionK[1];
mKDistortion.z = info.DistortionK[2];
mKDistortion.w = info.DistortionK[3];
// Calculated values
calculateValues(calculateDistortionScale);
mIsValid = true;
}
void OculusVRHMDDevice::createSimulation(SimulationTypes simulationType, bool calculateDistortionScale)
{
if(simulationType == ST_RIFT_PREVIEW)
{
createSimulatedPreviewRift(calculateDistortionScale);
}
}
void OculusVRHMDDevice::createSimulatedPreviewRift(bool calculateDistortionScale)
{
mIsValid = true;
mIsSimulation = true;
mProductName = "Oculus Rift DK1-SLA1";
mManufacturer = "Oculus VR";
mVersion = 0;
mDisplayDeviceName = "";
mResolution.x = 1280;
mResolution.y = 800;
mScreenSize.x = 0.14975999f;
mScreenSize.y = 0.093599997f;
mVerticalEyeCenter = 0.046799999f;
mEyeToScreen = 0.041000001f;
mLensSeparation = 0.064000003f;
mInterpupillaryDistance = 0.064000003f;
mKDistortion.x = 1.0000000f;
mKDistortion.y = 0.22000000f;
mKDistortion.z = 0.23999999f;
mKDistortion.w = 0.00000000f;
calculateValues(calculateDistortionScale);
}
// Computes scale that should be applied to the input render texture
// before distortion to fit the result in the same screen size.
// The 'fitRadius' parameter specifies the distance away from distortion center at
// which the input and output coordinates will match, assuming [-1,1] range.
F32 OculusVRHMDDevice::calcScale(F32 fitRadius)
{
F32 s = fitRadius;
// This should match distortion equation used in shader.
F32 ssq = s * s;
F32 scale = s * (mKDistortion.x + mKDistortion.y * ssq + mKDistortion.z * ssq * ssq + mKDistortion.w * ssq * ssq * ssq);
return scale;
}
void OculusVRHMDDevice::calculateValues(bool calculateDistortionScale)
{
F32 halfScreenX = mScreenSize.x * 0.5f;
if(halfScreenX > 0)
{
F32 halfLensSeparation = mLensSeparation * 0.5;
F32 offset = halfLensSeparation / halfScreenX;
mEyeUVOffset.x = offset - 0.5;
mEyeUVOffset.y = 1.0f - offset - 0.5;
}
else
{
mEyeUVOffset.x = 0.5f;
mEyeUVOffset.y = 0.5f;
}
F32 lensOffset = mLensSeparation * 0.5f;
F32 lensShift = mScreenSize.x * 0.25f - lensOffset;
F32 lensViewportShift = 4.0f * lensShift / mScreenSize.x;
mXCenterOffset= lensViewportShift;
// Determine how the input texture should be scaled relative to the back buffer
// so that we fit the distorted view to the backbuffer after calculating the
// distortion. In reference to section 5.6.3 Distortion Scale and FOV in the
// SDK docs.
if(!calculateDistortionScale)
{
// Do not calculate a distortion scale for the input texture. This means that the input
// texture and the backbuffer will be the same resolution.
mDistortionFit.x = 0.0f;
mDistortionFit.y = 0.0f;
}
else if (mScreenSize.x > 0.140f) // 7"
{
mDistortionFit.x = -1.0f;
mDistortionFit.y = 0.0f;
}
else // 5"
{
mDistortionFit.x = 0.0f;
mDistortionFit.y = 1.0f;
}
// Compute distortion scale from DistortionFitX & DistortionFitY.
// Fit value of 0.0 means "no fit".
if (mIsZero(mDistortionFit.x) && mIsZero(mDistortionFit.y))
{
mDistortionScale = 1.0f;
}
else
{
// Convert fit value to distortion-centered coordinates before fit radius
// calculation.
// NOTE: For now just assume a full view the same size as the HMD supports. It is
// possible that this full view is smaller or larger.
F32 stereoAspect = 0.5f * mResolution.x / mResolution.y;
F32 dx = mDistortionFit.x - mXCenterOffset;
F32 dy = mDistortionFit.y / stereoAspect;
F32 fitRadius = sqrt(dx * dx + dy * dy);
mDistortionScale = calcScale(fitRadius)/fitRadius;
}
// Calculate the vertical FOV for a single eye
mAspectRatio = F32(mResolution.x * 0.5f) / F32(mResolution.y);
F32 halfScreenDistance = mScreenSize.y * 0.5f * mDistortionScale;
mYFOV = 2.0f * mAtan(halfScreenDistance / mEyeToScreen);
F32 viewCenter = mScreenSize.x * 0.25f;
F32 eyeProjectionShift = viewCenter - (mInterpupillaryDistance * 0.5f);
mProjectionCenterOffset.set(4.0f * eyeProjectionShift / mScreenSize.x, 0.0f);
mEyeWorldOffset.set(mInterpupillaryDistance * 0.5f, 0.0f, 0.0f);
}

View file

@ -0,0 +1,187 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _OCULUSVRHMDDEVICE_H_
#define _OCULUSVRHMDDEVICE_H_
#include "core/util/str.h"
#include "math/mQuat.h"
#include "math/mPoint2.h"
#include "math/mPoint3.h"
#include "math/mPoint4.h"
#include "platform/input/oculusVR/oculusVRConstants.h"
#include "platform/types.h"
#include "OVR.h"
class OculusVRHMDDevice
{
public:
enum SimulationTypes {
ST_RIFT_PREVIEW,
};
protected:
bool mIsValid;
bool mIsSimulation;
OVR::HMDDevice* mDevice;
// From OVR::DeviceInfo
String mProductName;
String mManufacturer;
U32 mVersion;
// Windows display device name used in EnumDisplaySettings/CreateDC
String mDisplayDeviceName;
// Whole screen resolution
Point2I mResolution;
// Physical screen size in meters
Point2F mScreenSize;
// Physical offset from the top of the screen to the center of the
// eye, in meters. Usually half of the vertical physical screen size
F32 mVerticalEyeCenter;
// Physical distance from the eye to the screen
F32 mEyeToScreen;
// Physical distance between lens centers, in meters
F32 mLensSeparation;
// Physical distance between the user's eye centers
F32 mInterpupillaryDistance;
// The eye IPD as a Point3F
Point3F mEyeWorldOffset;
// Radial distortion correction coefficients used by the barrel distortion shader
Point4F mKDistortion;
// Calculated values of eye x offset from center in normalized (uv) coordinates
// where each eye is 0..1. Used for the mono to stereo postFX to simulate an
// eye offset of the camera. The x component is the left eye, the y component
// is the right eye.
Point2F mEyeUVOffset;
// Used to adjust where an eye's view is rendered to account for the lenses not
// being in the center of the physical screen half.
F32 mXCenterOffset;
// When calculating the distortion scale to use to increase the size of the input texture
// this determines how we should attempt to fit the distorted view into the backbuffer.
Point2F mDistortionFit;
// Is the factor by which the input texture size is increased to make post-distortion
// result distortion fit the viewport. If the input texture is the same size as the
// backbuffer, then this should be 1.0.
F32 mDistortionScale;
// Aspect ratio for a single eye
F32 mAspectRatio;
// Vertical field of view
F32 mYFOV;
// The amount to offset the projection matrix to account for the eye not being in the
// center of the screen.
Point2F mProjectionCenterOffset;
protected:
F32 calcScale(F32 fitRadius);
void calculateValues(bool calculateDistortionScale);
void createSimulatedPreviewRift(bool calculateDistortionScale);
public:
OculusVRHMDDevice();
~OculusVRHMDDevice();
void cleanUp();
// Set the HMD properties based on information from the OVR device
void set(OVR::HMDDevice* hmd, OVR::HMDInfo& info, bool calculateDistortionScale);
// Set the HMD properties based on a simulation of the given type
void createSimulation(SimulationTypes simulationType, bool calculateDistortionScale);
bool isValid() const {return mIsValid;}
bool isSimulated() const {return mIsSimulation;}
const char* getProductName() const { return mProductName.c_str(); }
const char* getManufacturer() const { return mManufacturer.c_str(); }
U32 getVersion() const { return mVersion; }
// Windows display device name used in EnumDisplaySettings/CreateDC
const char* getDisplayDeviceName() const { return mDisplayDeviceName.c_str(); }
// Whole screen resolution
const Point2I& getResolution() const { return mResolution; }
// Physical screen size in meters
const Point2F& getScreenSize() const { return mScreenSize; }
// Physical offset from the top of the screen to the center of the
// eye, in meters. Usually half of the vertical physical screen size
F32 getVerticalEyeCenter() const { return mVerticalEyeCenter; }
// Physical distance from the eye to the screen
F32 getEyeToScreen() const { return mEyeToScreen; }
// Physical distance between lens centers, in meters
F32 getLensSeparation() const { return mLensSeparation; }
// Physical distance between the user's eye centers
F32 getIPD() const { return mInterpupillaryDistance; }
// Provides the IPD of one eye as a Point3F
const Point3F& getEyeWorldOffset() const { return mEyeWorldOffset; }
// Radial distortion correction coefficients used by the barrel distortion shader
const Point4F& getKDistortion() const { return mKDistortion; }
// Calculated values of eye x offset from center in normalized (uv) coordinates.
const Point2F& getEyeUVOffset() const { return mEyeUVOffset; }
// Used to adjust where an eye's view is rendered to account for the lenses not
// being in the center of the physical screen half.
F32 getCenterOffset() const { return mXCenterOffset; }
// Is the factor by which the input texture size is increased to make post-distortion
// result distortion fit the viewport.
F32 getDistortionScale() const { return mDistortionScale; }
// Aspect ration for a single eye
F32 getAspectRation() const { return mAspectRatio; }
// Vertical field of view
F32 getYFOV() const { return mYFOV; }
// The amount to offset the projection matrix to account for the eye not being in the
// center of the screen.
const Point2F& getProjectionCenterOffset() const { return mProjectionCenterOffset; }
};
#endif // _OCULUSVRHMDDEVICE_H_

View file

@ -0,0 +1,96 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/input/oculusVR/oculusVRSensorData.h"
#include "platform/input/oculusVR/oculusVRUtil.h"
#include "console/console.h"
OculusVRSensorData::OculusVRSensorData()
{
reset();
}
void OculusVRSensorData::reset()
{
mDataSet = false;
}
void OculusVRSensorData::setData(const OVR::SensorFusion& data, const F32& maxAxisRadius)
{
// Sensor rotation
OVR::Quatf orientation;
if(data.GetPredictionDelta() > 0)
{
orientation = data.GetPredictedOrientation();
}
else
{
orientation = data.GetOrientation();
}
OVR::Matrix4f orientMat(orientation);
OculusVRUtil::convertRotation(orientMat.M, mRot);
mRotQuat.set(mRot);
// Sensor rotation in Euler format
OculusVRUtil::convertRotation(orientation, mRotEuler);
// Sensor rotation as axis
OculusVRUtil::calculateAxisRotation(mRot, maxAxisRadius, mRotAxis);
mDataSet = true;
}
void OculusVRSensorData::simulateData(const F32& maxAxisRadius)
{
// Sensor rotation
mRot.identity();
mRotQuat.identity();
mRotEuler.zero();
// Sensor rotation as axis
OculusVRUtil::calculateAxisRotation(mRot, maxAxisRadius, mRotAxis);
mDataSet = true;
}
U32 OculusVRSensorData::compare(OculusVRSensorData* other)
{
S32 result = DIFF_NONE;
// Check rotation
if(mRotEuler.x != other->mRotEuler.x || mRotEuler.y != other->mRotEuler.y || mRotEuler.z != other->mRotEuler.z || !mDataSet)
{
result |= DIFF_ROT;
}
// Check rotation as axis
if(mRotAxis.x != other->mRotAxis.x || !mDataSet)
{
result |= DIFF_ROTAXISX;
}
if(mRotAxis.y != other->mRotAxis.y || !mDataSet)
{
result |= DIFF_ROTAXISY;
}
return result;
}

View file

@ -0,0 +1,68 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _OCULUSVRSENSORDATA_H_
#define _OCULUSVRSENSORDATA_H_
#include "platform/types.h"
#include "math/mMatrix.h"
#include "math/mQuat.h"
#include "math/mPoint2.h"
#include "OVR.h"
struct OculusVRSensorData
{
enum DataDifferences {
DIFF_NONE = 0,
DIFF_ROT = (1<<0),
DIFF_ROTAXISX = (1<<1),
DIFF_ROTAXISY = (1<<2),
DIFF_ROTAXIS = (DIFF_ROTAXISX | DIFF_ROTAXISY),
};
bool mDataSet;
// Rotation
MatrixF mRot;
QuatF mRotQuat;
EulerF mRotEuler;
// Controller rotation as axis x, y
Point2F mRotAxis;
OculusVRSensorData();
/// Reset the data
void reset();
/// Set data based on given sensor fusion
void setData(const OVR::SensorFusion& data, const F32& maxAxisRadius);
/// Simulate valid data
void simulateData(const F32& maxAxisRadius);
/// Compare this data and given and return differences
U32 compare(OculusVRSensorData* other);
};
#endif // _OCULUSVRSENSORDATA_H_

View file

@ -0,0 +1,265 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/input/oculusVR/oculusVRSensorDevice.h"
#include "platform/input/oculusVR/oculusVRSensorData.h"
#include "platform/input/oculusVR/oculusVRUtil.h"
#include "platform/platformInput.h"
U32 OculusVRSensorDevice::OVR_SENSORROT[OculusVRConstants::MaxSensors] = {0};
U32 OculusVRSensorDevice::OVR_SENSORROTANG[OculusVRConstants::MaxSensors] = {0};
U32 OculusVRSensorDevice::OVR_SENSORROTAXISX[OculusVRConstants::MaxSensors] = {0};
U32 OculusVRSensorDevice::OVR_SENSORROTAXISY[OculusVRConstants::MaxSensors] = {0};
OculusVRSensorDevice::OculusVRSensorDevice()
{
mIsValid = false;
mIsSimulation = false;
mDevice = NULL;
for(U32 i=0; i<2; ++i)
{
mDataBuffer[i] = new OculusVRSensorData();
}
mPrevData = mDataBuffer[0];
}
OculusVRSensorDevice::~OculusVRSensorDevice()
{
cleanUp();
for(U32 i=0; i<2; ++i)
{
delete mDataBuffer[i];
mDataBuffer[i] = NULL;
}
mPrevData = NULL;
}
void OculusVRSensorDevice::cleanUp()
{
mSensorFusion.AttachToSensor(NULL);
if(mDevice)
{
mDevice->Release();
mDevice = NULL;
}
mIsValid = false;
}
void OculusVRSensorDevice::set(OVR::SensorDevice* sensor, OVR::SensorInfo& info, S32 actionCodeIndex)
{
mIsValid = false;
mDevice = sensor;
mSensorFusion.AttachToSensor(sensor);
// DeviceInfo
mProductName = info.ProductName;
mManufacturer = info.Manufacturer;
mVersion = info.Version;
// SensorInfo
mVendorId = info.VendorId;
mProductId = info.ProductId;
mSerialNumber = info.SerialNumber;
mActionCodeIndex = actionCodeIndex;
if(mActionCodeIndex >= OculusVRConstants::MaxSensors)
{
// Cannot declare more sensors than we are able to handle
mIsValid = false;
}
else
{
mIsValid = true;
}
}
void OculusVRSensorDevice::createSimulation(SimulationTypes simulationType, S32 actionCodeIndex)
{
if(simulationType == ST_RIFT_PREVIEW)
{
createSimulatedPreviewRift(actionCodeIndex);
}
}
void OculusVRSensorDevice::createSimulatedPreviewRift(S32 actionCodeIndex)
{
mIsValid = false;
mIsSimulation = true;
// DeviceInfo
mProductName = "Tracker DK";
mManufacturer = "Oculus VR, Inc.";
mVersion = 0;
// SensorInfo
mVendorId = 10291;
mProductId = 1;
mSerialNumber = "000000000000";
mActionCodeIndex = actionCodeIndex;
if(mActionCodeIndex >= OculusVRConstants::MaxSensors)
{
// Cannot declare more sensors than we are able to handle
mIsValid = false;
}
else
{
mIsValid = true;
}
}
void OculusVRSensorDevice::buildCodeTable()
{
// Obtain all of the device codes
for(U32 i=0; i<OculusVRConstants::MaxSensors; ++i)
{
OVR_SENSORROT[i] = INPUTMGR->getNextDeviceCode();
OVR_SENSORROTANG[i] = INPUTMGR->getNextDeviceCode();
OVR_SENSORROTAXISX[i] = INPUTMGR->getNextDeviceCode();
OVR_SENSORROTAXISY[i] = INPUTMGR->getNextDeviceCode();
}
// Build out the virtual map
char buffer[64];
for(U32 i=0; i<OculusVRConstants::MaxSensors; ++i)
{
dSprintf(buffer, 64, "ovr_sensorrot%d", i);
INPUTMGR->addVirtualMap( buffer, SI_ROT, OVR_SENSORROT[i] );
dSprintf(buffer, 64, "ovr_sensorrotang%d", i);
INPUTMGR->addVirtualMap( buffer, SI_ROT, OVR_SENSORROTANG[i] );
dSprintf(buffer, 64, "ovr_sensorrotaxisx%d", i);
INPUTMGR->addVirtualMap( buffer, SI_AXIS, OVR_SENSORROTAXISX[i] );
dSprintf(buffer, 64, "ovr_sensorrotaxisy%d", i);
INPUTMGR->addVirtualMap( buffer, SI_AXIS, OVR_SENSORROTAXISY[i] );
}
}
bool OculusVRSensorDevice::process(U32 deviceType, bool generateRotAsAngAxis, bool generateRotAsEuler, bool generateRotationAsAxisEvents, F32 maxAxisRadius)
{
if(!mIsValid)
return false;
// Store the current data from the sensor and compare with previous data
U32 diff;
OculusVRSensorData* currentBuffer = (mPrevData == mDataBuffer[0]) ? mDataBuffer[1] : mDataBuffer[0];
if(!mIsSimulation)
{
currentBuffer->setData(mSensorFusion, maxAxisRadius);
}
else
{
currentBuffer->simulateData(maxAxisRadius);
}
diff = mPrevData->compare(currentBuffer);
// Update the previous data pointer. We do this here in case someone calls our
// console functions during one of the input events below.
mPrevData = currentBuffer;
// Rotation event
if(diff & OculusVRSensorData::DIFF_ROT)
{
if(generateRotAsAngAxis)
{
INPUTMGR->buildInputEvent(deviceType, OculusVRConstants::DefaultOVRBase, SI_ROT, OVR_SENSORROT[mActionCodeIndex], SI_MOVE, currentBuffer->mRotQuat);
}
if(generateRotAsEuler)
{
// Convert angles to degrees
VectorF angles;
for(U32 i=0; i<3; ++i)
{
angles[i] = mRadToDeg(currentBuffer->mRotEuler[i]);
}
INPUTMGR->buildInputEvent(deviceType, OculusVRConstants::DefaultOVRBase, SI_POS, OVR_SENSORROTANG[mActionCodeIndex], SI_MOVE, angles);
}
}
// Rotation as axis event
if(generateRotationAsAxisEvents && diff & OculusVRSensorData::DIFF_ROTAXIS)
{
if(diff & OculusVRSensorData::DIFF_ROTAXISX)
INPUTMGR->buildInputEvent(deviceType, OculusVRConstants::DefaultOVRBase, SI_AXIS, OVR_SENSORROTAXISX[mActionCodeIndex], SI_MOVE, currentBuffer->mRotAxis.x);
if(diff & OculusVRSensorData::DIFF_ROTAXISY)
INPUTMGR->buildInputEvent(deviceType, OculusVRConstants::DefaultOVRBase, SI_AXIS, OVR_SENSORROTAXISY[mActionCodeIndex], SI_MOVE, currentBuffer->mRotAxis.y);
}
return true;
}
void OculusVRSensorDevice::reset()
{
if(!mIsValid)
return;
mSensorFusion.Reset();
}
F32 OculusVRSensorDevice::getPredictionTime() const
{
if(!mIsValid)
return 0.0f;
return mSensorFusion.GetPredictionDelta();
}
void OculusVRSensorDevice::setPredictionTime(F32 dt)
{
if(!mIsValid)
return;
mSensorFusion.SetPrediction(dt);
}
EulerF OculusVRSensorDevice::getEulerRotation()
{
if(!mIsValid)
return Point3F::Zero;
OVR::Quatf orientation;
if(mSensorFusion.GetPredictionDelta() > 0)
{
orientation = mSensorFusion.GetPredictedOrientation();
}
else
{
orientation = mSensorFusion.GetOrientation();
}
// Sensor rotation in Euler format
EulerF rot;
OculusVRUtil::convertRotation(orientation, rot);
return rot;
}

View file

@ -0,0 +1,122 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _OCULUSVRSENSORDEVICE_H_
#define _OCULUSVRSENSORDEVICE_H_
#include "core/util/str.h"
#include "math/mQuat.h"
#include "math/mPoint2.h"
#include "math/mPoint3.h"
#include "math/mPoint4.h"
#include "platform/input/oculusVR/oculusVRConstants.h"
#include "platform/types.h"
#include "OVR.h"
struct OculusVRSensorData;
class OculusVRSensorDevice
{
public:
enum SimulationTypes {
ST_RIFT_PREVIEW,
};
public:
// Action codes
static U32 OVR_SENSORROT[OculusVRConstants::MaxSensors]; // SI_ROT
static U32 OVR_SENSORROTANG[OculusVRConstants::MaxSensors]; // SI_POS but is EulerF
static U32 OVR_SENSORROTAXISX[OculusVRConstants::MaxSensors]; // SI_AXIS
static U32 OVR_SENSORROTAXISY[OculusVRConstants::MaxSensors];
protected:
bool mIsValid;
bool mIsSimulation;
OVR::SensorDevice* mDevice;
OVR::SensorFusion mSensorFusion;
// From OVR::DeviceInfo
String mProductName;
String mManufacturer;
U32 mVersion;
// From OVR::SensorInfo
U16 mVendorId;
U16 mProductId;
String mSerialNumber;
// Assigned by the OculusVRDevice
S32 mActionCodeIndex;
// Buffers to store data for sensor
OculusVRSensorData* mDataBuffer[2];
// Points to the buffer that holds the previously collected data
// for the sensor
OculusVRSensorData* mPrevData;
protected:
void createSimulatedPreviewRift(S32 actionCodeIndex);
public:
OculusVRSensorDevice();
virtual ~OculusVRSensorDevice();
static void buildCodeTable();
void cleanUp();
// Set the sensor properties based on information from the OVR device
void set(OVR::SensorDevice* sensor, OVR::SensorInfo& info, S32 actionCodeIndex);
// Set the sensor properties based on a simulation of the given type
void createSimulation(SimulationTypes simulationType, S32 actionCodeIndex);
bool isValid() const {return mIsValid;}
bool isSimulated() {return mIsSimulation;}
bool process(U32 deviceType, bool generateRotAsAngAxis, bool generateRotAsEuler, bool generateRotationAsAxisEvents, F32 maxAxisRadius);
void reset();
// Get the prediction time for the sensor fusion. The time is in seconds.
F32 getPredictionTime() const;
// Set the prediction time for the sensor fusion. The time is in seconds.
void setPredictionTime(F32 dt);
const char* getProductName() { return mProductName.c_str(); }
const char* getManufacturer() { return mManufacturer.c_str(); }
U32 getVersion() { return mVersion; }
U16 getVendorId() { return mVendorId; }
U16 getProductId() { return mProductId; }
const char* getSerialNumber() { return mSerialNumber; }
EulerF getEulerRotation();
};
#endif // _OCULUSVRSENSORDEVICE_H_

View file

@ -0,0 +1,76 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/input/oculusVR/oculusVRUtil.h"
namespace OculusVRUtil
{
void convertRotation(const F32 inRotMat[4][4], MatrixF& outRotation)
{
// Set rotation. We need to convert from sensor coordinates to
// Torque coordinates. The sensor matrix is stored row-major.
// The conversion is:
//
// Sensor Torque
// a b c a b c a -c b
// d e f --> -g -h -i --> -g i -h
// g h i d e f d -f e
outRotation.setColumn(0, Point4F( inRotMat[0][0], -inRotMat[2][0], inRotMat[1][0], 0.0f));
outRotation.setColumn(1, Point4F(-inRotMat[0][2], inRotMat[2][2], -inRotMat[1][2], 0.0f));
outRotation.setColumn(2, Point4F( inRotMat[0][1], -inRotMat[2][1], inRotMat[1][1], 0.0f));
outRotation.setPosition(Point3F::Zero);
}
void convertRotation(OVR::Quatf& inRotation, EulerF& outRotation)
{
F32 yaw, pitch, roll;
inRotation.GetEulerAngles<OVR::Axis_Y, OVR::Axis_X, OVR::Axis_Z>(&yaw, &pitch, &roll);
outRotation.x = -pitch;
outRotation.y = roll;
outRotation.z = -yaw;
}
void calculateAxisRotation(const MatrixF& inRotation, const F32& maxAxisRadius, Point2F& outRotation)
{
const VectorF& controllerUp = inRotation.getUpVector();
Point2F axis(0,0);
axis.x = controllerUp.x;
axis.y = controllerUp.y;
// Limit the axis angle to that given to us
if(axis.len() > maxAxisRadius)
{
axis.normalize(maxAxisRadius);
}
// Renormalize to the range of 0..1
if(maxAxisRadius != 0.0f)
{
axis /= maxAxisRadius;
}
outRotation.x = axis.x;
outRotation.y = axis.y;
}
}

View file

@ -0,0 +1,42 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _OCULUSVRUTIL_H_
#define _OCULUSVRUTIL_H_
#include "math/mPoint2.h"
#include "math/mMatrix.h"
#include "OVR.h"
namespace OculusVRUtil
{
/// Convert an OVR sensor's rotation to a Torque 3D matrix
void convertRotation(const F32 inRotMat[4][4], MatrixF& outRotation);
/// Convert an OVR sensor's rotation to Torque 3D Euler angles (in radians)
void convertRotation(OVR::Quatf& inRotation, EulerF& outRotation);
/// Calcualte a sensor's rotation as if it were a thumb stick axis
void calculateAxisRotation(const MatrixF& inRotation, const F32& maxAxisRadius, Point2F& outRotation);
}
#endif // _OCULUSVRUTIL_H_