Large diffs are not rendered by default.

@@ -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_
@@ -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);
}
@@ -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_
@@ -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;
}
@@ -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_
@@ -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;
}
@@ -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_
@@ -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;
}

}
@@ -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_
@@ -54,6 +54,9 @@ function initializeCore()
exec( "./audioStates.cs" );
exec( "./audioAmbiences.cs" );

// Input devices
exec("~/scripts/client/oculusVR.cs");

// Seed the random number generator.
setRandomSeed();

@@ -0,0 +1,125 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------

// Only load these functions if an Oculus VR device is present
if(!isFunction(isOculusVRDeviceActive))
return;

//-----------------------------------------------------------------------------

function oculusSensorMetricsCallback()
{
return " | OVR Sensor 0 |" @
" rot: " @ getOVRSensorEulerRotation(0);
}

//-----------------------------------------------------------------------------

// Call this function from createCanvas() to have the Canvas attach itself
// to the Rift's display. The Canvas' window will still open on the primary
// display if that is different from the Rift, but it will move to the Rift
// when it goes full screen. If the Rift is not connected then nothing
// will happen.
function pointCanvasToOculusVRDisplay()
{
$pref::Video::displayOutputDevice = getOVRHMDDisplayDeviceName(0);
}

//-----------------------------------------------------------------------------

// Call this function from GameConnection::initialControlSet() just before
// your "Canvas.setContent(PlayGui);" call, or at any time you wish to switch
// to a side-by-side rendering and the appropriate barrel distortion. This
// will turn on side-by-side rendering and tell the GameConnection to use the
// Rift as its display device.
// Parameters:
// %gameConnection - The client GameConnection instance
// %trueStereoRendering - If true will enable stereo rendering with an eye
// offset for each viewport. This will render each frame twice. If false
// then a pseudo stereo rendering is done with only a single render per frame.
function enableOculusVRDisplay(%gameConnection, %trueStereoRendering)
{
setOVRHMDAsGameConnectionDisplayDevice(%gameConnection);
PlayGui.renderStyle = "stereo side by side";

if(%trueStereoRendering)
{
OVRBarrelDistortionPostFX.isEnabled = true;
}
else
{
OVRBarrelDistortionMonoPostFX.isEnabled = true;
}

// Reset all sensors
ovrResetAllSensors();
}

// Call this function when ever you wish to turn off the stereo rendering
// and barrel distortion for the Rift.
function disableOculusVRDisplay(%gameConnection)
{
%gameConnection.clearDisplayDevice();
PlayGui.renderStyle = "standard";
OVRBarrelDistortionPostFX.isEnabled = false;
OVRBarrelDistortionMonoPostFX.isEnabled = false;
}

// Helper function to set the standard Rift control scheme. You could place
// this function in GameConnection::initialControlSet() at the same time
// you call enableOculusVRDisplay().
function setStandardOculusVRControlScheme(%gameConnection)
{
if(isOVRHMDSimulated(0))
{
// We are simulating a HMD so allow the mouse and gamepad to control
// both yaw and pitch.
%gameConnection.setControlSchemeParameters(true, true, true);
}
else
{
// A HMD is connected so have the mouse and gamepad only add to yaw
%gameConnection.setControlSchemeParameters(true, true, false);
}
}

//-----------------------------------------------------------------------------

// Helper function to set the resolution for the Rift.
// Parameters:
// %fullscreen - If true then the display will be forced to full screen. If
// pointCanvasToOculusVRDisplay() was called before the Canvas was created, then
// the full screen display will appear on the Rift.
function setVideoModeForOculusVRDisplay(%fullscreen)
{
%res = getOVRHMDResolution(0);
Canvas.setVideoMode(%res.x, %res.y, %fullscreen, 32, 0);
}

//-----------------------------------------------------------------------------

// Reset all Oculus Rift sensors. This will make the Rift's current heading
// be considered the origin.
function resetOculusVRSensors()
{
ovrResetAllSensors();
}
@@ -0,0 +1,123 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------

// Only load these shaders if an Oculus VR device is present
if(!isFunction(isOculusVRDeviceActive))
return;

//-----------------------------------------------------------------------------
// Shader data
//-----------------------------------------------------------------------------

singleton ShaderData( OVRMonoToStereoShader )
{
DXVertexShaderFile = "shaders/common/postFx/postFxV.hlsl";
DXPixelShaderFile = "shaders/common/postFx/oculusvr/monoToStereoP.hlsl";

pixVersion = 2.0;
};

singleton ShaderData( OVRBarrelDistortionShader )
{
DXVertexShaderFile = "shaders/common/postFx/postFxV.hlsl";
DXPixelShaderFile = "shaders/common/postFx/oculusvr/barrelDistortionP.hlsl";

pixVersion = 2.0;
};

//-----------------------------------------------------------------------------
// GFX state blocks
//-----------------------------------------------------------------------------

singleton GFXStateBlockData( OVRBarrelDistortionStateBlock : PFX_DefaultStateBlock )
{
samplersDefined = true;
samplerStates[0] = SamplerClampLinear;
};

//-----------------------------------------------------------------------------
// Barrel Distortion PostFx
//
// To be used with the Oculus Rift.
// Expects a stereo pair to exist on the back buffer and then applies the
// appropriate barrel distortion.
//-----------------------------------------------------------------------------
singleton BarrelDistortionPostEffect( OVRBarrelDistortionPostFX )
{
isEnabled = false;
allowReflectPass = false;

renderTime = "PFXAfterDiffuse";
renderPriority = 100;

// The barrel distortion
shader = OVRBarrelDistortionShader;
stateBlock = OVRBarrelDistortionStateBlock;

texture[0] = "$backBuffer";

scaleOutput = 1.25;
};

//-----------------------------------------------------------------------------
// Barrel Distortion Mono PostFx
//
// To be used with the Oculus Rift.
// Takes a non-stereo image and turns it into a stereo pair with barrel
// distortion applied. Only a vertical slice around the center of the back
// buffer is used to generate the pseudo stereo pair.
//-----------------------------------------------------------------------------
singleton PostEffect( OVRBarrelDistortionMonoPostFX )
{
isEnabled = false;
allowReflectPass = false;

renderTime = "PFXAfterDiffuse";
renderPriority = 100;

// Converts the mono display to a stereo one
shader = OVRMonoToStereoShader;
stateBlock = OVRBarrelDistortionStateBlock;

texture[0] = "$backBuffer";
target = "$outTex";

// The actual barrel distortion
new BarrelDistortionPostEffect(OVRBarrelDistortionMonoStage2PostFX)
{
shader = OVRBarrelDistortionShader;
stateBlock = OVRBarrelDistortionStateBlock;
texture[0] = "$inTex";
target = "$backBuffer";

scaleOutput = 1.25;
};

};

function OVRBarrelDistortionMonoPostFX::setShaderConsts( %this )
{
%HMDIndex = 0;

%xOffsets = getOVRHMDEyeXOffsets(%HMDIndex);
%this.setShaderConst( "$LensXOffsets", %xOffsets );
}
@@ -0,0 +1,81 @@
//-----------------------------------------------------------------------------
// 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 "shadergen:/autogenConditioners.h"
#include "../postFx.hlsl"
#include "../../torque.hlsl"

uniform sampler2D backBuffer : register(S0);

uniform float3 LensCenter; // x=Left X, y=Right X, z=Y
uniform float2 ScreenCenter;
uniform float2 Scale;
uniform float2 ScaleIn;
uniform float4 HmdWarpParam;

// Scales input texture coordinates for distortion.
// ScaleIn maps texture coordinates to Scales to ([-1, 1]), although top/bottom will be
// larger due to aspect ratio.
float2 HmdWarp(float2 in01, float2 lensCenter)
{
float2 theta = (in01 - lensCenter) * ScaleIn; // Scales to [-1, 1]
float rSq = theta.x * theta.x + theta.y * theta.y;
float2 theta1 = theta * (HmdWarpParam.x + HmdWarpParam.y * rSq + HmdWarpParam.z * rSq * rSq + HmdWarpParam.w * rSq * rSq * rSq);
return lensCenter + Scale * theta1;
}

float4 main( PFXVertToPix IN ) : COLOR0
{
float2 texCoord;
float xOffset;
float2 lensCenter;
lensCenter.y = LensCenter.z;
if(IN.uv0.x < 0.5)
{
texCoord.x = IN.uv0.x;
texCoord.y = IN.uv0.y;
xOffset = 0.0;
lensCenter.x = LensCenter.x;
}
else
{
texCoord.x = IN.uv0.x - 0.5;
texCoord.y = IN.uv0.y;
xOffset = 0.5;
lensCenter.x = LensCenter.y;
}

float2 tc = HmdWarp(texCoord, lensCenter);

float4 color;
if (any(clamp(tc, ScreenCenter-float2(0.25,0.5), ScreenCenter+float2(0.25, 0.5)) - tc))
{
color = float4(0,0,0,0);
}
else
{
tc.x += xOffset;
color = tex2D(backBuffer, tc);
}

return color;
}
@@ -0,0 +1,60 @@
//-----------------------------------------------------------------------------
// 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 "shadergen:/autogenConditioners.h"
#include "../postFx.hlsl"
#include "../../torque.hlsl"

uniform sampler2D backBuffer : register(S0);

uniform float2 LensXOffsets;

float4 main( PFXVertToPix IN ) : COLOR0
{
float2 texCoord;
float xOffset;
float2 lensCenter;
lensCenter.y = 0.5;
if(IN.uv0.x < 0.5)
{
texCoord.x = IN.uv0.x;
texCoord.y = IN.uv0.y;
xOffset = 0.0;
lensCenter.x = LensXOffsets.x;
}
else
{
texCoord.x = IN.uv0.x - 0.5;
texCoord.y = IN.uv0.y;
xOffset = 0.5;
lensCenter.x = LensXOffsets.y;
}

texCoord.x *= 2.0;
texCoord.x += lensCenter.x;
texCoord.x *= 0.5;
texCoord.x += 0.25;

float4 color = tex2D(backBuffer, texCoord);

return color;
}
@@ -54,6 +54,9 @@ function initializeCore()
exec( "./audioStates.cs" );
exec( "./audioAmbiences.cs" );

// Input devices
exec("~/scripts/client/oculusVR.cs");

// Seed the random number generator.
setRandomSeed();

@@ -0,0 +1,125 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------

// Only load these functions if an Oculus VR device is present
if(!isFunction(isOculusVRDeviceActive))
return;

//-----------------------------------------------------------------------------

function oculusSensorMetricsCallback()
{
return " | OVR Sensor 0 |" @
" rot: " @ getOVRSensorEulerRotation(0);
}

//-----------------------------------------------------------------------------

// Call this function from createCanvas() to have the Canvas attach itself
// to the Rift's display. The Canvas' window will still open on the primary
// display if that is different from the Rift, but it will move to the Rift
// when it goes full screen. If the Rift is not connected then nothing
// will happen.
function pointCanvasToOculusVRDisplay()
{
$pref::Video::displayOutputDevice = getOVRHMDDisplayDeviceName(0);
}

//-----------------------------------------------------------------------------

// Call this function from GameConnection::initialControlSet() just before
// your "Canvas.setContent(PlayGui);" call, or at any time you wish to switch
// to a side-by-side rendering and the appropriate barrel distortion. This
// will turn on side-by-side rendering and tell the GameConnection to use the
// Rift as its display device.
// Parameters:
// %gameConnection - The client GameConnection instance
// %trueStereoRendering - If true will enable stereo rendering with an eye
// offset for each viewport. This will render each frame twice. If false
// then a pseudo stereo rendering is done with only a single render per frame.
function enableOculusVRDisplay(%gameConnection, %trueStereoRendering)
{
setOVRHMDAsGameConnectionDisplayDevice(%gameConnection);
PlayGui.renderStyle = "stereo side by side";

if(%trueStereoRendering)
{
OVRBarrelDistortionPostFX.isEnabled = true;
}
else
{
OVRBarrelDistortionMonoPostFX.isEnabled = true;
}

// Reset all sensors
ovrResetAllSensors();
}

// Call this function when ever you wish to turn off the stereo rendering
// and barrel distortion for the Rift.
function disableOculusVRDisplay(%gameConnection)
{
%gameConnection.clearDisplayDevice();
PlayGui.renderStyle = "standard";
OVRBarrelDistortionPostFX.isEnabled = false;
OVRBarrelDistortionMonoPostFX.isEnabled = false;
}

// Helper function to set the standard Rift control scheme. You could place
// this function in GameConnection::initialControlSet() at the same time
// you call enableOculusVRDisplay().
function setStandardOculusVRControlScheme(%gameConnection)
{
if(isOVRHMDSimulated(0))
{
// We are simulating a HMD so allow the mouse and gamepad to control
// both yaw and pitch.
%gameConnection.setControlSchemeParameters(true, true, true);
}
else
{
// A HMD is connected so have the mouse and gamepad only add to yaw
%gameConnection.setControlSchemeParameters(true, true, false);
}
}

//-----------------------------------------------------------------------------

// Helper function to set the resolution for the Rift.
// Parameters:
// %fullscreen - If true then the display will be forced to full screen. If
// pointCanvasToOculusVRDisplay() was called before the Canvas was created, then
// the full screen display will appear on the Rift.
function setVideoModeForOculusVRDisplay(%fullscreen)
{
%res = getOVRHMDResolution(0);
Canvas.setVideoMode(%res.x, %res.y, %fullscreen, 32, 0);
}

//-----------------------------------------------------------------------------

// Reset all Oculus Rift sensors. This will make the Rift's current heading
// be considered the origin.
function resetOculusVRSensors()
{
ovrResetAllSensors();
}
@@ -0,0 +1,123 @@
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------

// Only load these shaders if an Oculus VR device is present
if(!isFunction(isOculusVRDeviceActive))
return;

//-----------------------------------------------------------------------------
// Shader data
//-----------------------------------------------------------------------------

singleton ShaderData( OVRMonoToStereoShader )
{
DXVertexShaderFile = "shaders/common/postFx/postFxV.hlsl";
DXPixelShaderFile = "shaders/common/postFx/oculusvr/monoToStereoP.hlsl";

pixVersion = 2.0;
};

singleton ShaderData( OVRBarrelDistortionShader )
{
DXVertexShaderFile = "shaders/common/postFx/postFxV.hlsl";
DXPixelShaderFile = "shaders/common/postFx/oculusvr/barrelDistortionP.hlsl";

pixVersion = 2.0;
};

//-----------------------------------------------------------------------------
// GFX state blocks
//-----------------------------------------------------------------------------

singleton GFXStateBlockData( OVRBarrelDistortionStateBlock : PFX_DefaultStateBlock )
{
samplersDefined = true;
samplerStates[0] = SamplerClampLinear;
};

//-----------------------------------------------------------------------------
// Barrel Distortion PostFx
//
// To be used with the Oculus Rift.
// Expects a stereo pair to exist on the back buffer and then applies the
// appropriate barrel distortion.
//-----------------------------------------------------------------------------
singleton BarrelDistortionPostEffect( OVRBarrelDistortionPostFX )
{
isEnabled = false;
allowReflectPass = false;

renderTime = "PFXAfterDiffuse";
renderPriority = 100;

// The barrel distortion
shader = OVRBarrelDistortionShader;
stateBlock = OVRBarrelDistortionStateBlock;

texture[0] = "$backBuffer";

scaleOutput = 1.25;
};

//-----------------------------------------------------------------------------
// Barrel Distortion Mono PostFx
//
// To be used with the Oculus Rift.
// Takes a non-stereo image and turns it into a stereo pair with barrel
// distortion applied. Only a vertical slice around the center of the back
// buffer is used to generate the pseudo stereo pair.
//-----------------------------------------------------------------------------
singleton PostEffect( OVRBarrelDistortionMonoPostFX )
{
isEnabled = false;
allowReflectPass = false;

renderTime = "PFXAfterDiffuse";
renderPriority = 100;

// Converts the mono display to a stereo one
shader = OVRMonoToStereoShader;
stateBlock = OVRBarrelDistortionStateBlock;

texture[0] = "$backBuffer";
target = "$outTex";

// The actual barrel distortion
new BarrelDistortionPostEffect(OVRBarrelDistortionMonoStage2PostFX)
{
shader = OVRBarrelDistortionShader;
stateBlock = OVRBarrelDistortionStateBlock;
texture[0] = "$inTex";
target = "$backBuffer";

scaleOutput = 1.25;
};

};

function OVRBarrelDistortionMonoPostFX::setShaderConsts( %this )
{
%HMDIndex = 0;

%xOffsets = getOVRHMDEyeXOffsets(%HMDIndex);
%this.setShaderConst( "$LensXOffsets", %xOffsets );
}
@@ -0,0 +1,81 @@
//-----------------------------------------------------------------------------
// 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 "shadergen:/autogenConditioners.h"
#include "../postFx.hlsl"
#include "../../torque.hlsl"

uniform sampler2D backBuffer : register(S0);

uniform float3 LensCenter; // x=Left X, y=Right X, z=Y
uniform float2 ScreenCenter;
uniform float2 Scale;
uniform float2 ScaleIn;
uniform float4 HmdWarpParam;

// Scales input texture coordinates for distortion.
// ScaleIn maps texture coordinates to Scales to ([-1, 1]), although top/bottom will be
// larger due to aspect ratio.
float2 HmdWarp(float2 in01, float2 lensCenter)
{
float2 theta = (in01 - lensCenter) * ScaleIn; // Scales to [-1, 1]
float rSq = theta.x * theta.x + theta.y * theta.y;
float2 theta1 = theta * (HmdWarpParam.x + HmdWarpParam.y * rSq + HmdWarpParam.z * rSq * rSq + HmdWarpParam.w * rSq * rSq * rSq);
return lensCenter + Scale * theta1;
}

float4 main( PFXVertToPix IN ) : COLOR0
{
float2 texCoord;
float xOffset;
float2 lensCenter;
lensCenter.y = LensCenter.z;
if(IN.uv0.x < 0.5)
{
texCoord.x = IN.uv0.x;
texCoord.y = IN.uv0.y;
xOffset = 0.0;
lensCenter.x = LensCenter.x;
}
else
{
texCoord.x = IN.uv0.x - 0.5;
texCoord.y = IN.uv0.y;
xOffset = 0.5;
lensCenter.x = LensCenter.y;
}

float2 tc = HmdWarp(texCoord, lensCenter);

float4 color;
if (any(clamp(tc, ScreenCenter-float2(0.25,0.5), ScreenCenter+float2(0.25, 0.5)) - tc))
{
color = float4(0,0,0,0);
}
else
{
tc.x += xOffset;
color = tex2D(backBuffer, tc);
}

return color;
}
@@ -0,0 +1,60 @@
//-----------------------------------------------------------------------------
// 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 "shadergen:/autogenConditioners.h"
#include "../postFx.hlsl"
#include "../../torque.hlsl"

uniform sampler2D backBuffer : register(S0);

uniform float2 LensXOffsets;

float4 main( PFXVertToPix IN ) : COLOR0
{
float2 texCoord;
float xOffset;
float2 lensCenter;
lensCenter.y = 0.5;
if(IN.uv0.x < 0.5)
{
texCoord.x = IN.uv0.x;
texCoord.y = IN.uv0.y;
xOffset = 0.0;
lensCenter.x = LensXOffsets.x;
}
else
{
texCoord.x = IN.uv0.x - 0.5;
texCoord.y = IN.uv0.y;
xOffset = 0.5;
lensCenter.x = LensXOffsets.y;
}

texCoord.x *= 2.0;
texCoord.x += lensCenter.x;
texCoord.x *= 0.5;
texCoord.x += 0.25;

float4 color = tex2D(backBuffer, texCoord);

return color;
}
@@ -0,0 +1,80 @@
<?php
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------

beginModule( 'oculusVR' );

// Look for the optional global from the project.conf.
global $OCULUSVR_SDK_PATH;
if (!$OCULUSVR_SDK_PATH)
{
// First look for an environment var.
$OCULUSVR_SDK_PATH = getenv( "TORQUE_OCULUSVR_PATH" );

if (strlen($OCULUSVR_SDK_PATH) == 0 || !file_exists($OCULUSVR_SDK_PATH))
{
// Sometimes users get confused and use this var.
$OCULUSVR_SDK_PATH = getenv( "OCULUSVR_SDK_PATH" );
}

// We need forward slashes for paths.
$OCULUSVR_SDK_PATH = str_replace( "\\", "/", $OCULUSVR_SDK_PATH);

// Remove trailing slashes.
$OCULUSVR_SDK_PATH = rtrim($OCULUSVR_SDK_PATH, " /");
}

// If we still don't have the SDK path then let the user know.
if (!file_exists($OCULUSVR_SDK_PATH))
{
trigger_error(
"\n*******************************************************************".
"\n".
"\n We were not able to find a valid path to the Oculus Rift SDK!".
"\n".
"\n You must install the latest Oculus VR SDK and set the path via a".
"\n \$OCULUSVR_SDK_PATH variable in your buildFiles/project.conf file".
"\n or by setting the TORQUE_OCULUSVR_PATH system environment variable".
"\n (may require a reboot).".
"\n".
"\n*******************************************************************".
"\n", E_USER_ERROR );
}

// Only Windows is supported at this time
if ( Generator::$platform == "win32" )
{
// Source
addEngineSrcDir( "platform/input/oculusVR" );

// Includes
addIncludePath( $OCULUSVR_SDK_PATH . "/LibOVR/Include" );
addIncludePath( $OCULUSVR_SDK_PATH . "/LibOVR/Src" );

// Libs
addProjectLibDir( $OCULUSVR_SDK_PATH . "/LibOVR/Lib/Win32" );
addProjectLibInput( "libovr.lib", "libovrd.lib" );
}

endModule();

?>