Browse Source

Oculus VR (Rift) support

Input device and shaders for supporting the Oculus Rift.
DavidWyand-GG 12 years ago
parent
commit
de7a72d82a
24 changed files with 3214 additions and 0 deletions
  1. 188 0
      Engine/source/platform/input/oculusVR/barrelDistortionPostEffect.cpp
  2. 68 0
      Engine/source/platform/input/oculusVR/barrelDistortionPostEffect.h
  3. 34 0
      Engine/source/platform/input/oculusVR/oculusVRConstants.h
  4. 844 0
      Engine/source/platform/input/oculusVR/oculusVRDevice.cpp
  5. 152 0
      Engine/source/platform/input/oculusVR/oculusVRDevice.h
  6. 208 0
      Engine/source/platform/input/oculusVR/oculusVRHMDDevice.cpp
  7. 187 0
      Engine/source/platform/input/oculusVR/oculusVRHMDDevice.h
  8. 96 0
      Engine/source/platform/input/oculusVR/oculusVRSensorData.cpp
  9. 68 0
      Engine/source/platform/input/oculusVR/oculusVRSensorData.h
  10. 265 0
      Engine/source/platform/input/oculusVR/oculusVRSensorDevice.cpp
  11. 122 0
      Engine/source/platform/input/oculusVR/oculusVRSensorDevice.h
  12. 76 0
      Engine/source/platform/input/oculusVR/oculusVRUtil.cpp
  13. 42 0
      Engine/source/platform/input/oculusVR/oculusVRUtil.h
  14. 3 0
      Templates/Empty/game/core/scripts/client/core.cs
  15. 125 0
      Templates/Empty/game/core/scripts/client/oculusVR.cs
  16. 123 0
      Templates/Empty/game/core/scripts/client/postFx/ovrBarrelDistortion.cs
  17. 81 0
      Templates/Empty/game/shaders/common/postFx/oculusvr/barrelDistortionP.hlsl
  18. 60 0
      Templates/Empty/game/shaders/common/postFx/oculusvr/monoToStereoP.hlsl
  19. 3 0
      Templates/Full/game/core/scripts/client/core.cs
  20. 125 0
      Templates/Full/game/core/scripts/client/oculusVR.cs
  21. 123 0
      Templates/Full/game/core/scripts/client/postFx/ovrBarrelDistortion.cs
  22. 81 0
      Templates/Full/game/shaders/common/postFx/oculusvr/barrelDistortionP.hlsl
  23. 60 0
      Templates/Full/game/shaders/common/postFx/oculusvr/monoToStereoP.hlsl
  24. 80 0
      Tools/projectGenerator/modules/oculusVR.inc

+ 188 - 0
Engine/source/platform/input/oculusVR/barrelDistortionPostEffect.cpp

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

+ 68 - 0
Engine/source/platform/input/oculusVR/barrelDistortionPostEffect.h

@@ -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_

+ 34 - 0
Engine/source/platform/input/oculusVR/oculusVRConstants.h

@@ -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_

+ 844 - 0
Engine/source/platform/input/oculusVR/oculusVRDevice.cpp

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

+ 152 - 0
Engine/source/platform/input/oculusVR/oculusVRDevice.h

@@ -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_

+ 208 - 0
Engine/source/platform/input/oculusVR/oculusVRHMDDevice.cpp

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

+ 187 - 0
Engine/source/platform/input/oculusVR/oculusVRHMDDevice.h

@@ -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_

+ 96 - 0
Engine/source/platform/input/oculusVR/oculusVRSensorData.cpp

@@ -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;
+}

+ 68 - 0
Engine/source/platform/input/oculusVR/oculusVRSensorData.h

@@ -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_

+ 265 - 0
Engine/source/platform/input/oculusVR/oculusVRSensorDevice.cpp

@@ -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;
+}

+ 122 - 0
Engine/source/platform/input/oculusVR/oculusVRSensorDevice.h

@@ -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_

+ 76 - 0
Engine/source/platform/input/oculusVR/oculusVRUtil.cpp

@@ -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;
+}
+
+}

+ 42 - 0
Engine/source/platform/input/oculusVR/oculusVRUtil.h

@@ -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_

+ 3 - 0
Templates/Empty/game/core/scripts/client/core.cs

@@ -54,6 +54,9 @@ function initializeCore()
    exec( "./audioStates.cs" );
    exec( "./audioStates.cs" );
    exec( "./audioAmbiences.cs" );
    exec( "./audioAmbiences.cs" );
 
 
+   // Input devices
+   exec("~/scripts/client/oculusVR.cs");
+
    // Seed the random number generator.
    // Seed the random number generator.
    setRandomSeed();
    setRandomSeed();
    
    

+ 125 - 0
Templates/Empty/game/core/scripts/client/oculusVR.cs

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

+ 123 - 0
Templates/Empty/game/core/scripts/client/postFx/ovrBarrelDistortion.cs

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

+ 81 - 0
Templates/Empty/game/shaders/common/postFx/oculusvr/barrelDistortionP.hlsl

@@ -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;    
+}

+ 60 - 0
Templates/Empty/game/shaders/common/postFx/oculusvr/monoToStereoP.hlsl

@@ -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;    
+}

+ 3 - 0
Templates/Full/game/core/scripts/client/core.cs

@@ -54,6 +54,9 @@ function initializeCore()
    exec( "./audioStates.cs" );
    exec( "./audioStates.cs" );
    exec( "./audioAmbiences.cs" );
    exec( "./audioAmbiences.cs" );
 
 
+   // Input devices
+   exec("~/scripts/client/oculusVR.cs");
+
    // Seed the random number generator.
    // Seed the random number generator.
    setRandomSeed();
    setRandomSeed();
    
    

+ 125 - 0
Templates/Full/game/core/scripts/client/oculusVR.cs

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

+ 123 - 0
Templates/Full/game/core/scripts/client/postFx/ovrBarrelDistortion.cs

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

+ 81 - 0
Templates/Full/game/shaders/common/postFx/oculusvr/barrelDistortionP.hlsl

@@ -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;    
+}

+ 60 - 0
Templates/Full/game/shaders/common/postFx/oculusvr/monoToStereoP.hlsl

@@ -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;    
+}

+ 80 - 0
Tools/projectGenerator/modules/oculusVR.inc

@@ -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();
+
+?>