Torque3D Documentation / _generateds / openVRProvider.cpp

openVRProvider.cpp

Engine/source/platform/input/openVR/openVRProvider.cpp

More...

Classes:

Namespaces:

namespace

Public Functions

ConsoleDoc("@class <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">OpenVRProvider\n</a>" "@brief This class is the interface between TorqueScript and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">OpenVR.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">OpenVR\n</a>" )
DECLARE_SCOPE(OpenVR )
DefineEngineFunction(OpenVRIsCompiledIn , bool , () , "" )
DefineEngineStaticMethod(OpenVR , getControllerDeviceIndexes , const char * , (OpenVRTrackedDeviceClass klass) , "@brief Gets the indexes of devices which match the <a href="/coding/file/tsshapeconstruct_8cpp/#tsshapeconstruct_8cpp_1a21625ca11566389388a748ad1acc0990">required</a> device class" )
DefineEngineStaticMethod(OpenVR , getControllerModel , const char * , (S32 idx) , "@brief Gets the indexes of devices which match the <a href="/coding/file/tsshapeconstruct_8cpp/#tsshapeconstruct_8cpp_1a21625ca11566389388a748ad1acc0990">required</a> device class" )
DefineEngineStaticMethod(OpenVR , getDisplayDeviceId , S32 , () , "@brief MacOS display <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ID.\n\n</a>" "@param index The HMD <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">index.\n</a>" "@return The ID of the HMD display device, <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">any.\n</a>" " @ingroup Game" )
DefineEngineStaticMethod(OpenVR , isDeviceActive , bool , () , "@brief Used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> determine <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the OpenVR input device is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">active\n\n</a>" "The OpenVR device is considered active when the library has been " "initialized and either a real of simulated HMD is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">present.\n\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the OpenVR input device is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">active.\n</a>" "@ingroup Game" )
DefineEngineStaticMethod(OpenVR , mapDeviceToEvent , void , (S32 deviceId, S32 eventId) , "@brief Maps a device <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> an event <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">code.\n\n</a>" "@ingroup Game" )
DefineEngineStaticMethod(OpenVR , resetEventMap , void , () , "@brief Resets event <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">map.\n\n</a>" "@ingroup Game" )
DefineEngineStaticMethod(OpenVR , resetSensors , void , () , "@brief Resets all Oculus VR <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">sensors.\n\n</a>" "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, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> example." " @ingroup Game" )
DefineEngineStaticMethod(OpenVR , setEnabled , bool , (bool value) , "@brief Used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> determine <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the OpenVR input device is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">active\n\n</a>" "The OpenVR device is considered active when the library has been " "initialized and either a real of simulated HMD is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">present.\n\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the OpenVR input device is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">active.\n</a>" "@ingroup Game" )
DefineEngineStaticMethod(OpenVR , setHMDAsGameConnectionDisplayDevice , bool , (GameConnection *conn) , "@brief Sets the first HMD <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be a <a href="/coding/class/classgameconnection/">GameConnection</a>'s display <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">device\n\n</a>" "@param conn The <a href="/coding/class/classgameconnection/">GameConnection</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">set.\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the <a href="/coding/class/classgameconnection/">GameConnection</a> display device was <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">set.\n</a>" "@ingroup Game" )
GetTrackedDeviceString(vr::IVRSystem * pHmd, vr::TrackedDeviceIndex_t unDevice, vr::TrackedDeviceProperty prop, vr::TrackedPropertyError * peError)
ImplementEnumType(OpenVRGamepadTextInputLineMode , "Types of input supported by VR Overlays. .\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@ingroup OpenVR" )
ImplementEnumType(OpenVRGamepadTextInputMode , "Types of input supported by VR Overlays. .\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@ingroup OpenVR" )
ImplementEnumType(OpenVROverlayDirection , "Directions <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> changing focus between overlays with the gamepad. .\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@ingroup OpenVR" )
ImplementEnumType(OpenVROverlayInputMethod , "Types of input supported by VR Overlays. .\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@ingroup OpenVR" )
ImplementEnumType(OpenVROverlayTransformType , "Allows the caller <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> figure out which overlay transform getter <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> call. .\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@ingroup OpenVR" )
ImplementEnumType(OpenVRState , "Status of the overall system or tracked objects. .\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@ingroup OpenVR" )
ImplementEnumType(OpenVRTrackedDeviceClass , "Types of devices which are tracked .\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@ingroup OpenVR" )
ImplementEnumType(OpenVRTrackingResult , ". .\n\n" "@ingroup OpenVR" )
ImplementEnumType(OpenVRTrackingUniverseOrigin , "Identifies which style of tracking origin the application wants <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the poses it is requesting. .\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@ingroup OpenVR" )
OpenVRTransformToRotPosMat(MatrixF mat, QuatF & outRot, Point3F & outPos, MatrixF & outMat)
OpenVRVecToTorqueVec(vr::HmdVector3_t vec)

Detailed Description

Public Variables

 EndImplementEnumType 
AngAxisF gLastMoveRot 
 MODULE_END 
 MODULE_INIT 
 MODULE_SHUTDOWN 

Public Functions

ConsoleDoc("@class <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">OpenVRProvider\n</a>" "@brief This class is the interface between TorqueScript and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">OpenVR.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">OpenVR\n</a>" )

DECLARE_SCOPE(OpenVR )

DefineEngineFunction(OpenVRIsCompiledIn , bool , () , "" )

DefineEngineStaticMethod(OpenVR , getControllerDeviceIndexes , const char * , (OpenVRTrackedDeviceClass klass) , "@brief Gets the indexes of devices which match the <a href="/coding/file/tsshapeconstruct_8cpp/#tsshapeconstruct_8cpp_1a21625ca11566389388a748ad1acc0990">required</a> device class" )

DefineEngineStaticMethod(OpenVR , getControllerModel , const char * , (S32 idx) , "@brief Gets the indexes of devices which match the <a href="/coding/file/tsshapeconstruct_8cpp/#tsshapeconstruct_8cpp_1a21625ca11566389388a748ad1acc0990">required</a> device class" )

DefineEngineStaticMethod(OpenVR , getDisplayDeviceId , S32 , () , "@brief MacOS display <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ID.\n\n</a>" "@param index The HMD <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">index.\n</a>" "@return The ID of the HMD display device, <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">any.\n</a>" " @ingroup Game" )

DefineEngineStaticMethod(OpenVR , isDeviceActive , bool , () , "@brief Used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> determine <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the OpenVR input device is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">active\n\n</a>" "The OpenVR device is considered active when the library has been " "initialized and either a real of simulated HMD is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">present.\n\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the OpenVR input device is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">active.\n</a>" "@ingroup Game" )

DefineEngineStaticMethod(OpenVR , mapDeviceToEvent , void , (S32 deviceId, S32 eventId) , "@brief Maps a device <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> an event <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">code.\n\n</a>" "@ingroup Game" )

DefineEngineStaticMethod(OpenVR , resetEventMap , void , () , "@brief Resets event <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">map.\n\n</a>" "@ingroup Game" )

DefineEngineStaticMethod(OpenVR , resetSensors , void , () , "@brief Resets all Oculus VR <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">sensors.\n\n</a>" "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, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> example." " @ingroup Game" )

DefineEngineStaticMethod(OpenVR , setEnabled , bool , (bool value) , "@brief Used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> determine <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the OpenVR input device is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">active\n\n</a>" "The OpenVR device is considered active when the library has been " "initialized and either a real of simulated HMD is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">present.\n\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the OpenVR input device is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">active.\n</a>" "@ingroup Game" )

DefineEngineStaticMethod(OpenVR , setHMDAsGameConnectionDisplayDevice , bool , (GameConnection *conn) , "@brief Sets the first HMD <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be a <a href="/coding/class/classgameconnection/">GameConnection</a>'s display <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">device\n\n</a>" "@param conn The <a href="/coding/class/classgameconnection/">GameConnection</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">set.\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a2594a51175f310ed96ad6cd7d6514878">if</a> the <a href="/coding/class/classgameconnection/">GameConnection</a> display device was <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">set.\n</a>" "@ingroup Game" )

GetTrackedDeviceString(vr::IVRSystem * pHmd, vr::TrackedDeviceIndex_t unDevice, vr::TrackedDeviceProperty prop, vr::TrackedPropertyError * peError)

IMPLEMENT_SCOPE(OpenVR , OpenVRProvider , "" )

ImplementEnumType(OpenVRGamepadTextInputLineMode , "Types of input supported by VR Overlays. .\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@ingroup OpenVR" )

ImplementEnumType(OpenVRGamepadTextInputMode , "Types of input supported by VR Overlays. .\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@ingroup OpenVR" )

ImplementEnumType(OpenVROverlayDirection , "Directions <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> changing focus between overlays with the gamepad. .\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@ingroup OpenVR" )

ImplementEnumType(OpenVROverlayInputMethod , "Types of input supported by VR Overlays. .\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@ingroup OpenVR" )

ImplementEnumType(OpenVROverlayTransformType , "Allows the caller <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> figure out which overlay transform getter <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> call. .\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@ingroup OpenVR" )

ImplementEnumType(OpenVRState , "Status of the overall system or tracked objects. .\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@ingroup OpenVR" )

ImplementEnumType(OpenVRTrackedDeviceClass , "Types of devices which are tracked .\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@ingroup OpenVR" )

ImplementEnumType(OpenVRTrackingResult , ". .\n\n" "@ingroup OpenVR" )

ImplementEnumType(OpenVRTrackingUniverseOrigin , "Identifies which style of tracking origin the application wants <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the poses it is requesting. .\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@ingroup OpenVR" )

OpenVRTransformToRotPos(MatrixF mat, QuatF & outRot, Point3F & outPos)

OpenVRTransformToRotPosMat(MatrixF mat, QuatF & outRot, Point3F & outPos, MatrixF & outMat)

OpenVRVecToTorqueVec(vr::HmdVector3_t vec)

   1
   2#include "platform/input/openVR/openVRProvider.h"
   3#include "platform/input/openVR/openVROverlay.h"
   4#include "platform/platformInput.h"
   5#include "core/module.h"
   6#include "console/engineAPI.h"
   7#include "T3D/gameBase/gameConnection.h"
   8#include "gui/core/guiCanvas.h"
   9#include "postFx/postEffectCommon.h"
  10#include "renderInstance/renderPassManager.h"
  11#include "scene/sceneRenderState.h"
  12#include "materials/baseMatInstance.h"
  13#include "materials/materialManager.h"
  14#include "console/consoleInternal.h"
  15#include "core/stream/fileStream.h"
  16
  17#include "gfx/D3D11/gfxD3D11Device.h"
  18#include "gfx/D3D11/gfxD3D11TextureObject.h"
  19#include "gfx/D3D11/gfxD3D11EnumTranslate.h"
  20#include "gfx/gfxStringEnumTranslate.h"
  21
  22
  23#include "gfx/D3D9/gfxD3D9Device.h"
  24#include "gfx/D3D9/gfxD3D9TextureObject.h"
  25#include "gfx/D3D9/gfxD3D9EnumTranslate.h"
  26
  27#include "materials/matTextureTarget.h"
  28
  29#ifdef TORQUE_OPENGL
  30#include "gfx/gl/gfxGLDevice.h"
  31#include "gfx/gl/gfxGLTextureObject.h"
  32#include "gfx/gl/gfxGLEnumTranslate.h"
  33#endif
  34
  35struct OpenVRLoadedTexture
  36{
  37   vr::TextureID_t texId;
  38   NamedTexTarget texTarget;
  39};
  40
  41AngAxisF gLastMoveRot; // jamesu - this is just here for temp debugging
  42
  43namespace OpenVRUtil
  44{
  45   void convertTransformFromOVR(const MatrixF &inRotTMat, MatrixF& outRotation)
  46   {
  47      Point4F col0; inRotTMat.getColumn(0, &col0);
  48      Point4F col1; inRotTMat.getColumn(1, &col1);
  49      Point4F col2; inRotTMat.getColumn(2, &col2);
  50      Point4F col3; inRotTMat.getColumn(3, &col3);
  51
  52      // Set rotation.  We need to convert from sensor coordinates to
  53      // Torque coordinates.  The sensor matrix is stored row-major.
  54      // The conversion is:
  55      //
  56      // Sensor                       Torque
  57      // a b c         a  b  c        a -c  b
  58      // d e f   -->  -g -h -i  -->  -g  i -h
  59      // g h i         d  e  f        d -f  e
  60      outRotation.setColumn(0, Point4F( col0.x, -col2.x, col1.x, 0.0f));
  61      outRotation.setColumn(1, Point4F(-col0.z, col2.z, -col1.z, 0.0f));
  62      outRotation.setColumn(2, Point4F( col0.y, -col2.y, col1.y, 0.0f));
  63      outRotation.setColumn(3, Point4F(-col3.x, col3.z, -col3.y, 1.0f));
  64   }
  65
  66   void convertTransformToOVR(const MatrixF& inRotation, MatrixF& outRotation)
  67   {
  68      Point4F col0; inRotation.getColumn(0, &col0);
  69      Point4F col1; inRotation.getColumn(1, &col1);
  70      Point4F col2; inRotation.getColumn(2, &col2);
  71      Point4F col3; inRotation.getColumn(3, &col3);
  72
  73      // This is basically a reverse of what is in convertTransformFromOVR
  74      outRotation.setColumn(0, Point4F(col0.x, col2.x, -col1.x, 0.0f));
  75      outRotation.setColumn(1, Point4F(col0.z, col2.z, -col1.z, 0.0f));
  76      outRotation.setColumn(2, Point4F(-col0.y, -col2.y, col1.y, 0.0f));
  77      outRotation.setColumn(3, Point4F(-col3.x, -col3.z, col3.y, 1.0f));
  78   }
  79
  80   MatrixF convertSteamVRAffineMatrixToMatrixFPlain(const vr::HmdMatrix34_t &mat)
  81   {
  82      MatrixF outMat(1);
  83
  84      outMat.setColumn(0, Point4F(mat.m[0][0], mat.m[1][0], mat.m[2][0], 0.0));
  85      outMat.setColumn(1, Point4F(mat.m[0][1], mat.m[1][1], mat.m[2][1], 0.0));
  86      outMat.setColumn(2, Point4F(mat.m[0][2], mat.m[1][2], mat.m[2][2], 0.0));
  87      outMat.setColumn(3, Point4F(mat.m[0][3], mat.m[1][3], mat.m[2][3], 1.0f)); // pos
  88
  89      return outMat;
  90   }
  91
  92
  93
  94   void convertMatrixFPlainToSteamVRAffineMatrix(const MatrixF &inMat, vr::HmdMatrix34_t &outMat)
  95   {
  96      Point4F row0; inMat.getRow(0, &row0);
  97      Point4F row1; inMat.getRow(1, &row1);
  98      Point4F row2; inMat.getRow(2, &row2);
  99
 100      outMat.m[0][0] = row0.x;
 101      outMat.m[0][1] = row0.y;
 102      outMat.m[0][2] = row0.z;
 103      outMat.m[0][3] = row0.w;
 104
 105      outMat.m[1][0] = row1.x;
 106      outMat.m[1][1] = row1.y;
 107      outMat.m[1][2] = row1.z;
 108      outMat.m[1][3] = row1.w;
 109
 110      outMat.m[2][0] = row2.x;
 111      outMat.m[2][1] = row2.y;
 112      outMat.m[2][2] = row2.z;
 113      outMat.m[2][3] = row2.w;
 114   }
 115
 116   U32 convertOpenVRButtonToTorqueButton(uint32_t vrButton)
 117   {
 118      switch (vrButton)
 119      {
 120      case vr::VRMouseButton_Left:
 121         return KEY_BUTTON0;
 122      case vr::VRMouseButton_Right:
 123         return KEY_BUTTON1;
 124      case vr::VRMouseButton_Middle:
 125         return KEY_BUTTON2;
 126      default:
 127         return KEY_NULL;
 128      }
 129   }
 130
 131
 132   vr::VRTextureBounds_t TorqueRectToBounds(const RectI &rect, const Point2I &widthHeight)
 133   {
 134      vr::VRTextureBounds_t bounds;
 135      F32 xRatio = 1.0 / (F32)widthHeight.x;
 136      F32 yRatio = 1.0 / (F32)widthHeight.y;
 137      bounds.uMin = rect.point.x * xRatio;
 138      bounds.vMin = rect.point.y * yRatio;
 139      bounds.uMax = (rect.point.x + rect.extent.x) * xRatio;
 140      bounds.vMax = (rect.point.y + rect.extent.y) * yRatio;
 141      return bounds;
 142   }
 143
 144   String GetTrackedDeviceString(vr::IVRSystem *pHmd, vr::TrackedDeviceIndex_t unDevice, vr::TrackedDeviceProperty prop, vr::TrackedPropertyError *peError = NULL)
 145   {
 146      uint32_t unRequiredBufferLen = pHmd->GetStringTrackedDeviceProperty(unDevice, prop, NULL, 0, peError);
 147      if (unRequiredBufferLen == 0)
 148         return "";
 149
 150      char *pchBuffer = new char[unRequiredBufferLen];
 151      unRequiredBufferLen = pHmd->GetStringTrackedDeviceProperty(unDevice, prop, pchBuffer, unRequiredBufferLen, peError);
 152      String sResult = pchBuffer;
 153      delete[] pchBuffer;
 154      return sResult;
 155   }
 156
 157}
 158
 159//------------------------------------------------------------
 160
 161bool OpenVRRenderModel::init(const vr::RenderModel_t & vrModel, StringTableEntry materialName)
 162{
 163   SAFE_DELETE(mMaterialInstance);
 164   mMaterialInstance = MATMGR->createMatInstance(materialName, getGFXVertexFormat< VertexType >());
 165   if (!mMaterialInstance)
 166      return false;
 167
 168   mLocalBox = Box3F::Invalid;
 169
 170   // Prepare primitives
 171   U16 *indPtr = NULL;
 172   GFXPrimitive *primPtr = NULL;
 173   mPrimitiveBuffer.set(GFX, vrModel.unTriangleCount * 3, 1, GFXBufferTypeStatic, "OpenVR Controller buffer");
 174
 175   mPrimitiveBuffer.lock(&indPtr, &primPtr);
 176   if (!indPtr || !primPtr)
 177      return false;
 178
 179   primPtr->minIndex = 0;
 180   primPtr->numPrimitives = vrModel.unTriangleCount;
 181   primPtr->numVertices = vrModel.unVertexCount;
 182   primPtr->startIndex = 0;
 183   primPtr->startVertex = 0;
 184   primPtr->type = GFXTriangleList;
 185
 186   //dMemcpy(indPtr, vrModel.rIndexData, sizeof(U16) * vrModel.unTriangleCount * 3);
 187
 188   for (U32 i = 0; i < vrModel.unTriangleCount; i++)
 189   {
 190      const U32 idx = i * 3;
 191      indPtr[idx + 0] = vrModel.rIndexData[idx + 2];
 192      indPtr[idx + 1] = vrModel.rIndexData[idx + 1];
 193      indPtr[idx + 2] = vrModel.rIndexData[idx + 0];
 194   }
 195
 196   mPrimitiveBuffer.unlock();
 197
 198   // Prepare verts
 199   mVertexBuffer.set(GFX, vrModel.unVertexCount, GFXBufferTypeStatic);
 200   VertexType *vertPtr = mVertexBuffer.lock();
 201   if (!vertPtr)
 202      return false;
 203
 204   // Convert to torque coordinate system
 205   for (U32 i = 0; i < vrModel.unVertexCount; i++)
 206   {
 207      const vr::RenderModel_Vertex_t &vert = vrModel.rVertexData[i];
 208      vertPtr->point = OpenVRUtil::convertPointFromOVR(vert.vPosition);
 209      vertPtr->point.x = -vertPtr->point.x;
 210      vertPtr->point.y = -vertPtr->point.y;
 211      vertPtr->point.z = -vertPtr->point.z;
 212      vertPtr->normal = OpenVRUtil::convertPointFromOVR(vert.vNormal);
 213      vertPtr->normal.x = -vertPtr->normal.x;
 214      vertPtr->normal.y = -vertPtr->normal.y;
 215      vertPtr->normal.z = -vertPtr->normal.z;
 216      vertPtr->texCoord = Point2F(vert.rfTextureCoord[0], vert.rfTextureCoord[1]);
 217      vertPtr++;
 218   }
 219
 220   mVertexBuffer.unlock();
 221
 222   for (U32 i = 0, sz = vrModel.unVertexCount; i < sz; i++)
 223   {
 224      Point3F pos = Point3F(vrModel.rVertexData[i].vPosition.v[0], vrModel.rVertexData[i].vPosition.v[1], vrModel.rVertexData[i].vPosition.v[2]);
 225      mLocalBox.extend(pos);
 226   }
 227
 228   return true;
 229}
 230
 231void OpenVRRenderModel::draw(SceneRenderState *state, MeshRenderInst* renderInstance)
 232{
 233   renderInstance->type = RenderPassManager::RIT_Mesh;
 234   renderInstance->matInst = state->getOverrideMaterial(mMaterialInstance);
 235   if (!renderInstance->matInst)
 236      return;
 237
 238   renderInstance->vertBuff = &mVertexBuffer;
 239   renderInstance->primBuff = &mPrimitiveBuffer;
 240   renderInstance->prim = NULL;
 241   renderInstance->primBuffIndex = 0;
 242
 243   if (renderInstance->matInst->getMaterial()->isTranslucent())
 244   {
 245      renderInstance->type = RenderPassManager::RIT_Translucent;
 246      renderInstance->translucentSort = true;
 247   }
 248
 249   renderInstance->defaultKey = renderInstance->matInst->getStateHint();
 250   renderInstance->defaultKey2 = (uintptr_t)renderInstance->vertBuff;
 251}
 252
 253//------------------------------------------------------------
 254
 255
 256
 257DECLARE_SCOPE(OpenVR);
 258IMPLEMENT_SCOPE(OpenVR, OpenVRProvider, , "");
 259ConsoleDoc(
 260   "@class OpenVRProvider\n"
 261   "@brief This class is the interface between TorqueScript and OpenVR.\n\n"
 262   "@ingroup OpenVR\n"
 263   );
 264
 265// Enum impls
 266
 267ImplementEnumType(OpenVROverlayInputMethod,
 268   "Types of input supported by VR Overlays. .\n\n"
 269   "@ingroup OpenVR")
 270{ vr::VROverlayInputMethod_None, "None" },
 271{ vr::VROverlayInputMethod_Mouse, "Mouse" },
 272EndImplementEnumType;
 273
 274ImplementEnumType(OpenVROverlayTransformType,
 275   "Allows the caller to figure out which overlay transform getter to call. .\n\n"
 276   "@ingroup OpenVR")
 277{ vr::VROverlayTransform_Absolute, "Absolute" },
 278{ vr::VROverlayTransform_TrackedDeviceRelative, "TrackedDeviceRelative" },
 279{ vr::VROverlayTransform_SystemOverlay, "SystemOverlay" },
 280{ vr::VROverlayTransform_TrackedComponent, "TrackedComponent" },
 281EndImplementEnumType;
 282
 283ImplementEnumType(OpenVRGamepadTextInputMode,
 284   "Types of input supported by VR Overlays. .\n\n"
 285   "@ingroup OpenVR")
 286{ vr::k_EGamepadTextInputModeNormal, "Normal", },
 287{ vr::k_EGamepadTextInputModePassword, "Password", },
 288{ vr::k_EGamepadTextInputModeSubmit, "Submit" },
 289EndImplementEnumType;
 290
 291ImplementEnumType(OpenVRGamepadTextInputLineMode,
 292   "Types of input supported by VR Overlays. .\n\n"
 293   "@ingroup OpenVR")
 294{ vr::k_EGamepadTextInputLineModeSingleLine, "SingleLine" },
 295{ vr::k_EGamepadTextInputLineModeMultipleLines, "MultipleLines" },
 296EndImplementEnumType;
 297
 298ImplementEnumType(OpenVRTrackingResult,
 299   ". .\n\n"
 300   "@ingroup OpenVR")
 301{ vr::TrackingResult_Uninitialized, "None" },
 302{ vr::TrackingResult_Calibrating_InProgress, "Calibrating_InProgress" },
 303{ vr::TrackingResult_Calibrating_OutOfRange, "Calibrating_OutOfRange" },
 304{ vr::TrackingResult_Running_OK, "Running_Ok" },
 305{ vr::TrackingResult_Running_OutOfRange, "Running_OutOfRange" },
 306EndImplementEnumType;
 307
 308ImplementEnumType(OpenVRTrackingUniverseOrigin,
 309   "Identifies which style of tracking origin the application wants to use for the poses it is requesting. .\n\n"
 310   "@ingroup OpenVR")
 311{ vr::TrackingUniverseSeated, "Seated" },
 312{ vr::TrackingUniverseStanding, "Standing" },
 313{ vr::TrackingUniverseRawAndUncalibrated, "RawAndUncalibrated" },
 314EndImplementEnumType;
 315
 316ImplementEnumType(OpenVROverlayDirection,
 317   "Directions for changing focus between overlays with the gamepad. .\n\n"
 318   "@ingroup OpenVR")
 319{ vr::OverlayDirection_Up, "Up" },
 320{ vr::OverlayDirection_Down, "Down" },
 321{ vr::OverlayDirection_Left, "Left" },
 322{ vr::OverlayDirection_Right, "Right" },
 323EndImplementEnumType;
 324
 325ImplementEnumType(OpenVRState,
 326   "Status of the overall system or tracked objects. .\n\n"
 327   "@ingroup OpenVR")
 328{ vr::VRState_Undefined, "Undefined" },
 329{ vr::VRState_Off, "Off" },
 330{ vr::VRState_Searching, "Searching" },
 331{ vr::VRState_Searching_Alert, "Searching_Alert" },
 332{ vr::VRState_Ready, "Ready" },
 333{ vr::VRState_Ready_Alert, "Ready_Alert" },
 334{ vr::VRState_NotReady, "NotReady" },
 335EndImplementEnumType;
 336
 337ImplementEnumType(OpenVRTrackedDeviceClass,
 338   "Types of devices which are tracked .\n\n"
 339   "@ingroup OpenVR")
 340{ vr::TrackedDeviceClass_Invalid, "Invalid" },
 341{ vr::TrackedDeviceClass_HMD, "HMD" },
 342{ vr::TrackedDeviceClass_Controller, "Controller" },
 343{ vr::TrackedDeviceClass_TrackingReference, "TrackingReference" },
 344{ vr::TrackedDeviceClass_Other, "Other" },
 345EndImplementEnumType;
 346
 347//------------------------------------------------------------
 348
 349U32 OpenVRProvider::OVR_SENSORROT[vr::k_unMaxTrackedDeviceCount] = { 0 };
 350U32 OpenVRProvider::OVR_SENSORROTANG[vr::k_unMaxTrackedDeviceCount] = { 0 };
 351U32 OpenVRProvider::OVR_SENSORVELOCITY[vr::k_unMaxTrackedDeviceCount] = { 0 };
 352U32 OpenVRProvider::OVR_SENSORANGVEL[vr::k_unMaxTrackedDeviceCount] = { 0 };
 353U32 OpenVRProvider::OVR_SENSORMAGNETOMETER[vr::k_unMaxTrackedDeviceCount] = { 0 };
 354U32 OpenVRProvider::OVR_SENSORPOSITION[vr::k_unMaxTrackedDeviceCount] = { 0 };
 355
 356U32 OpenVRProvider::OVR_BUTTONPRESSED[vr::k_unMaxTrackedDeviceCount];
 357U32 OpenVRProvider::OVR_BUTTONTOUCHED[vr::k_unMaxTrackedDeviceCount];
 358
 359U32 OpenVRProvider::OVR_AXISNONE[vr::k_unMaxTrackedDeviceCount] = { 0 };
 360U32 OpenVRProvider::OVR_AXISTRACKPAD[vr::k_unMaxTrackedDeviceCount] = { 0 };
 361U32 OpenVRProvider::OVR_AXISJOYSTICK[vr::k_unMaxTrackedDeviceCount] = { 0 };
 362U32 OpenVRProvider::OVR_AXISTRIGGER[vr::k_unMaxTrackedDeviceCount] = { 0 };
 363
 364EulerF OpenVRProvider::smHMDRotOffset(0);
 365F32 OpenVRProvider::smHMDmvYaw = 0;
 366F32 OpenVRProvider::smHMDmvPitch = 0;
 367bool OpenVRProvider::smRotateYawWithMoveActions = false;
 368
 369static String GetTrackedDeviceString(vr::IVRSystem *pHmd, vr::TrackedDeviceIndex_t unDevice, vr::TrackedDeviceProperty prop, vr::TrackedPropertyError *peError = NULL)
 370{
 371   uint32_t unRequiredBufferLen = pHmd->GetStringTrackedDeviceProperty(unDevice, prop, NULL, 0, peError);
 372   if (unRequiredBufferLen == 0)
 373      return "";
 374
 375   char *pchBuffer = new char[unRequiredBufferLen];
 376   unRequiredBufferLen = pHmd->GetStringTrackedDeviceProperty(unDevice, prop, pchBuffer, unRequiredBufferLen, peError);
 377   String sResult = pchBuffer;
 378   delete[] pchBuffer;
 379   return sResult;
 380}
 381
 382MODULE_BEGIN(OpenVRProvider)
 383
 384MODULE_INIT_AFTER(InputEventManager)
 385MODULE_SHUTDOWN_BEFORE(InputEventManager)
 386
 387MODULE_INIT
 388{
 389   OpenVRProvider::staticInit();
 390   ManagedSingleton< OpenVRProvider >::createSingleton();
 391}
 392
 393MODULE_SHUTDOWN
 394{
 395   ManagedSingleton< OpenVRProvider >::deleteSingleton();
 396}
 397
 398MODULE_END;
 399
 400
 401bool OpenVRRenderState::setupRenderTargets(GFXDevice::GFXDeviceRenderStyles mode)
 402{
 403   if (!mHMD)
 404      return false;
 405
 406   if (mRenderMode == mode)
 407      return true;
 408
 409   mRenderMode = mode;
 410
 411   if (mode == GFXDevice::RS_Standard)
 412   {
 413      reset(mHMD);
 414      return true;
 415   }
 416
 417   U32 sizeX, sizeY;
 418   Point2I newRTSize;
 419   mHMD->GetRecommendedRenderTargetSize(&sizeX, &sizeY);
 420
 421   if (mode == GFXDevice::RS_StereoSeparate)
 422   {
 423      mEyeViewport[0] = RectI(Point2I(0, 0), Point2I(sizeX, sizeY));
 424      mEyeViewport[1] = RectI(Point2I(0, 0), Point2I(sizeX, sizeY));
 425
 426      newRTSize.x = sizeX;
 427      newRTSize.y = sizeY;
 428   }
 429   else
 430   {
 431      mEyeViewport[0] = RectI(Point2I(0, 0), Point2I(sizeX, sizeY));
 432      mEyeViewport[1] = RectI(Point2I(sizeX, 0), Point2I(sizeX, sizeY));
 433
 434      newRTSize.x = sizeX * 2;
 435      newRTSize.y = sizeY;
 436   }
 437
 438   GFXTexHandle stereoTexture;
 439   stereoTexture.set(newRTSize.x, newRTSize.y, GFXFormatR8G8B8A8, &VRTextureProfile, "OpenVR Stereo RT Color");
 440   mStereoRenderTexture = stereoTexture;
 441
 442   GFXTexHandle stereoDepthTexture;
 443   stereoDepthTexture.set(newRTSize.x, newRTSize.y, GFXFormatD24S8, &VRDepthProfile, "OpenVR Depth");
 444   mStereoDepthTexture = stereoDepthTexture;
 445
 446   mStereoRT = GFX->allocRenderToTextureTarget();
 447   mStereoRT->attachTexture(GFXTextureTarget::Color0, stereoTexture);
 448   mStereoRT->attachTexture(GFXTextureTarget::DepthStencil, stereoDepthTexture);
 449
 450   mOutputEyeTextures.init(newRTSize.x, newRTSize.y, GFXFormatR8G8B8A8, &VRTextureProfile, "OpenVR Stereo RT Color OUTPUT");
 451
 452   return true;
 453}
 454
 455void OpenVRRenderState::renderPreview()
 456{
 457
 458}
 459
 460void OpenVRRenderState::reset(vr::IVRSystem* hmd)
 461{
 462   mHMD = hmd;
 463
 464   mStereoRT = NULL;
 465
 466   mStereoRenderTexture = NULL;
 467   mStereoDepthTexture = NULL;
 468
 469   mOutputEyeTextures.clear();
 470
 471   if (!mHMD)
 472      return;
 473
 474   updateHMDProjection();
 475}
 476
 477void OpenVRRenderState::updateHMDProjection()
 478{
 479   vr::HmdMatrix34_t mat = mHMD->GetEyeToHeadTransform(vr::Eye_Left);
 480   mEyePose[0] = OpenVRUtil::convertSteamVRAffineMatrixToMatrixFPlain(mat);
 481   mEyePose[0].inverse();
 482
 483   mat = mHMD->GetEyeToHeadTransform(vr::Eye_Right);
 484   mEyePose[1] = OpenVRUtil::convertSteamVRAffineMatrixToMatrixFPlain(mat);
 485   mEyePose[1].inverse();
 486
 487   mHMD->GetProjectionRaw(vr::Eye_Left, &mEyeFov[0].leftTan, &mEyeFov[0].rightTan, &mEyeFov[0].upTan, &mEyeFov[0].downTan);
 488   mHMD->GetProjectionRaw(vr::Eye_Right, &mEyeFov[1].leftTan, &mEyeFov[1].rightTan, &mEyeFov[1].upTan, &mEyeFov[1].downTan);
 489
 490   mEyeFov[0].upTan = -mEyeFov[0].upTan;
 491   mEyeFov[0].leftTan = -mEyeFov[0].leftTan;
 492   mEyeFov[1].upTan = -mEyeFov[1].upTan;
 493   mEyeFov[1].leftTan = -mEyeFov[1].leftTan;
 494}
 495
 496OpenVRProvider::OpenVRProvider() :
 497   mHMD(NULL),
 498   mRenderModels(NULL),
 499   mDrawCanvas(NULL),
 500   mGameConnection(NULL)
 501{
 502   dStrcpy(mName, "openvr");
 503   mDeviceType = INPUTMGR->getNextDeviceType();
 504   buildInputCodeTable();
 505   GFXDevice::getDeviceEventSignal().notify(this, &OpenVRProvider::_handleDeviceEvent);
 506   INPUTMGR->registerDevice(this);
 507   dMemset(&mLUID, '\0', sizeof(mLUID));
 508
 509   mTrackingSpace = vr::TrackingUniverseStanding;
 510}
 511
 512OpenVRProvider::~OpenVRProvider()
 513{
 514
 515}
 516
 517void OpenVRProvider::staticInit()
 518{
 519   // Overlay flags
 520   Con::setIntVariable("$OpenVR::OverlayFlags_None", 1 << (U32)vr::VROverlayFlags_None);
 521   Con::setIntVariable("$OpenVR::OverlayFlags_Curved", 1 << (U32)vr::VROverlayFlags_Curved);
 522   Con::setIntVariable("$OpenVR::OverlayFlags_RGSS4X", 1 << (U32)vr::VROverlayFlags_RGSS4X);
 523   Con::setIntVariable("$OpenVR::OverlayFlags_NoDashboardTab", 1 << (U32)vr::VROverlayFlags_NoDashboardTab);
 524   Con::setIntVariable("$OpenVR::OverlayFlags_AcceptsGamepadEvents", 1 << (U32)vr::VROverlayFlags_AcceptsGamepadEvents);
 525   Con::setIntVariable("$OpenVR::OverlayFlags_ShowGamepadFocus", 1 << (U32)vr::VROverlayFlags_ShowGamepadFocus);
 526   Con::setIntVariable("$OpenVR::OverlayFlags_SendVRScrollEvents", 1 << (U32)vr::VROverlayFlags_SendVRScrollEvents);
 527   Con::setIntVariable("$OpenVR::OverlayFlags_SendVRTouchpadEvents", 1 << (U32)vr::VROverlayFlags_SendVRTouchpadEvents);
 528   Con::setIntVariable("$OpenVR::OverlayFlags_ShowTouchPadScrollWheel", 1 << (U32)vr::VROverlayFlags_ShowTouchPadScrollWheel);
 529
 530   Con::addVariable("$OpenVR::HMDRotOffsetX", TypeF32, &smHMDRotOffset.x);
 531   Con::addVariable("$OpenVR::HMDRotOffsetY", TypeF32, &smHMDRotOffset.y);
 532   Con::addVariable("$OpenVR::HMDRotOffsetZ", TypeF32, &smHMDRotOffset.z);
 533
 534   Con::addVariable("$OpenVR::HMDmvYaw", TypeF32, &smHMDmvYaw);
 535   Con::addVariable("$OpenVR::HMDmvPitch", TypeF32, &smHMDmvPitch);
 536
 537   Con::addVariable("$OpenVR::HMDRotateYawWithMoveActions", TypeBool, &smRotateYawWithMoveActions);
 538}
 539
 540bool OpenVRProvider::enable()
 541{
 542   mOpenVRNS = Namespace::find(StringTable->insert("OpenVR"));
 543
 544   disable();
 545
 546   // Load openvr runtime
 547   vr::EVRInitError eError = vr::VRInitError_None;
 548   mHMD = vr::VR_Init(&eError, vr::VRApplication_Scene);
 549
 550   dMemset(mDeviceClassChar, '\0', sizeof(mDeviceClassChar));
 551
 552   if (eError != vr::VRInitError_None)
 553   {
 554      mHMD = NULL;
 555      char buf[1024];
 556      sprintf_s(buf, sizeof(buf), "Unable to init VR runtime: %s", vr::VR_GetVRInitErrorAsEnglishDescription(eError));
 557      Con::printf(buf);
 558      return false;
 559   }
 560
 561   dMemset(&mLUID, '\0', sizeof(mLUID));
 562
 563#ifdef TORQUE_OS_WIN32
 564
 565   // For windows we need to lookup the DXGI record for this and grab the LUID for the display adapter. We need the LUID since 
 566   // T3D uses EnumAdapters1 not EnumAdapters whereas openvr uses EnumAdapters.
 567   int32_t AdapterIdx;
 568   IDXGIAdapter* EnumAdapter;
 569   IDXGIFactory1* DXGIFactory;
 570   mHMD->GetDXGIOutputInfo(&AdapterIdx);
 571   // Get the LUID of the device
 572
 573   HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&DXGIFactory));
 574
 575   if (FAILED(hr))
 576      AssertFatal(false, "OpenVRProvider::enable -> CreateDXGIFactory1 call failure");
 577
 578   hr = DXGIFactory->EnumAdapters(AdapterIdx, &EnumAdapter);
 579
 580   if (FAILED(hr))
 581   {
 582      Con::warnf("VR: HMD device has an invalid adapter.");
 583   }
 584   else
 585   {
 586      DXGI_ADAPTER_DESC desc;
 587      hr = EnumAdapter->GetDesc(&desc);
 588      if (FAILED(hr))
 589      {
 590         Con::warnf("VR: HMD device has an invalid adapter.");
 591      }
 592      else
 593      {
 594         dMemcpy(&mLUID, &desc.AdapterLuid, sizeof(mLUID));
 595      }
 596      SAFE_RELEASE(EnumAdapter);
 597   }
 598
 599   SAFE_RELEASE(DXGIFactory);
 600#endif
 601
 602
 603
 604   mRenderModels = (vr::IVRRenderModels *)vr::VR_GetGenericInterface(vr::IVRRenderModels_Version, &eError);
 605   if (!mRenderModels)
 606   {
 607      mHMD = NULL;
 608      vr::VR_Shutdown();
 609
 610      char buf[1024];
 611      sprintf_s(buf, sizeof(buf), "Unable to get render model interface: %s", vr::VR_GetVRInitErrorAsEnglishDescription(eError));
 612      Con::printf(buf);
 613      return false;
 614   }
 615
 616   mDriver = GetTrackedDeviceString(mHMD, vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_TrackingSystemName_String);
 617   mDisplay = GetTrackedDeviceString(mHMD, vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_SerialNumber_String);
 618
 619   mHMDRenderState.mHMDPose = MatrixF(1);
 620   mHMDRenderState.mEyePose[0] = MatrixF(1);
 621   mHMDRenderState.mEyePose[1] = MatrixF(1);
 622
 623   mHMDRenderState.reset(mHMD);
 624   mHMD->ResetSeatedZeroPose();
 625   dMemset(mPreviousInputTrackedDevicePose, '\0', sizeof(mPreviousInputTrackedDevicePose));
 626
 627   mEnabled = true;
 628
 629   dMemset(mCurrentControllerState, '\0', sizeof(mCurrentControllerState));
 630   dMemset(mPreviousCurrentControllerState, '\0', sizeof(mPreviousCurrentControllerState));
 631
 632   return true;
 633}
 634
 635bool OpenVRProvider::disable()
 636{
 637   if (mHMD)
 638   {
 639      mHMD = NULL;
 640      mRenderModels = NULL;
 641      mHMDRenderState.reset(NULL);
 642      vr::VR_Shutdown();
 643   }
 644
 645   mEnabled = false;
 646
 647   return true;
 648}
 649
 650void OpenVRProvider::buildInputCodeTable()
 651{
 652   // Obtain all of the device codes
 653   for (U32 i = 0; i < vr::k_unMaxTrackedDeviceCount; ++i)
 654   {
 655      OVR_SENSORROT[i] = INPUTMGR->getNextDeviceCode();
 656
 657      OVR_SENSORROTANG[i] = INPUTMGR->getNextDeviceCode();
 658
 659      OVR_SENSORVELOCITY[i] = INPUTMGR->getNextDeviceCode();
 660      OVR_SENSORANGVEL[i] = INPUTMGR->getNextDeviceCode();
 661      OVR_SENSORMAGNETOMETER[i] = INPUTMGR->getNextDeviceCode();
 662
 663      OVR_SENSORPOSITION[i] = INPUTMGR->getNextDeviceCode();
 664
 665
 666      OVR_BUTTONPRESSED[i] = INPUTMGR->getNextDeviceCode();
 667      OVR_BUTTONTOUCHED[i] = INPUTMGR->getNextDeviceCode();
 668
 669      OVR_AXISNONE[i] = INPUTMGR->getNextDeviceCode();
 670      OVR_AXISTRACKPAD[i] = INPUTMGR->getNextDeviceCode();
 671      OVR_AXISJOYSTICK[i] = INPUTMGR->getNextDeviceCode();
 672      OVR_AXISTRIGGER[i] = INPUTMGR->getNextDeviceCode();
 673   }
 674
 675   // Build out the virtual map
 676   char buffer[64];
 677   for (U32 i = 0; i < vr::k_unMaxTrackedDeviceCount; ++i)
 678   {
 679      dSprintf(buffer, 64, "opvr_sensorrot%d", i);
 680      INPUTMGR->addVirtualMap(buffer, SI_ROT, OVR_SENSORROT[i]);
 681
 682      dSprintf(buffer, 64, "opvr_sensorrotang%d", i);
 683      INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_SENSORROTANG[i]);
 684
 685      dSprintf(buffer, 64, "opvr_sensorvelocity%d", i);
 686      INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_SENSORVELOCITY[i]);
 687
 688      dSprintf(buffer, 64, "opvr_sensorangvel%d", i);
 689      INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_SENSORANGVEL[i]);
 690
 691      dSprintf(buffer, 64, "opvr_sensormagnetometer%d", i);
 692      INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_SENSORMAGNETOMETER[i]);
 693
 694      dSprintf(buffer, 64, "opvr_sensorpos%d", i);
 695      INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_SENSORPOSITION[i]);
 696
 697      dSprintf(buffer, 64, "opvr_buttonpressed%d", i);
 698      INPUTMGR->addVirtualMap(buffer, SI_INT, OVR_BUTTONPRESSED[i]);
 699      dSprintf(buffer, 64, "opvr_buttontouched%d", i);
 700      INPUTMGR->addVirtualMap(buffer, SI_INT, OVR_BUTTONTOUCHED[i]);
 701
 702      dSprintf(buffer, 64, "opvr_axis_none%d", i);
 703      INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_AXISNONE[i]);
 704      dSprintf(buffer, 64, "opvr_axis_trackpad%d", i);
 705      INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_AXISTRACKPAD[i]);
 706      dSprintf(buffer, 64, "opvr_axis_joystick%d", i);
 707      INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_AXISJOYSTICK[i]);
 708      dSprintf(buffer, 64, "opvr_axis_trigger%d", i);
 709      INPUTMGR->addVirtualMap(buffer, SI_INT, OVR_AXISTRIGGER[i]);
 710   }
 711}
 712
 713bool OpenVRProvider::process()
 714{
 715   if (!mHMD)
 716      return true;   
 717
 718   if (!vr::VRCompositor())
 719      return true;
 720
 721   if (smRotateYawWithMoveActions)
 722   {
 723      smHMDmvYaw += MoveManager::mRightAction - MoveManager::mLeftAction + MoveManager::mXAxis_L;
 724   }
 725
 726   // Update HMD rotation offset
 727   smHMDRotOffset.z += smHMDmvYaw;
 728   smHMDRotOffset.x += smHMDmvPitch;
 729
 730   while (smHMDRotOffset.x < -M_PI_F)
 731      smHMDRotOffset.x += M_2PI_F;
 732   while (smHMDRotOffset.x > M_PI_F)
 733      smHMDRotOffset.x -= M_2PI_F;
 734   while (smHMDRotOffset.z < -M_PI_F)
 735      smHMDRotOffset.z += M_2PI_F;
 736   while (smHMDRotOffset.z > M_PI_F)
 737      smHMDRotOffset.z -= M_2PI_F;
 738
 739   smHMDmvYaw = 0;
 740   smHMDmvPitch = 0;
 741
 742   // Process SteamVR events
 743   vr::VREvent_t event;
 744   while (mHMD->PollNextEvent(&event, sizeof(event)))
 745   {
 746      processVREvent(event);
 747   }
 748
 749   // process overlay events
 750   for (U32 i = 0; i < mOverlays.size(); i++)
 751   {
 752      mOverlays[i]->handleOpenVREvents();
 753   }
 754
 755   // Process SteamVR controller state
 756   for (vr::TrackedDeviceIndex_t unDevice = 0; unDevice < vr::k_unMaxTrackedDeviceCount; unDevice++)
 757   {
 758      vr::VRControllerState_t state;
 759      if (mHMD->GetControllerState(unDevice, &state))
 760      {
 761        mCurrentControllerState[unDevice] = state;
 762      }
 763   }
 764
 765   // Update input poses
 766   updateTrackedPoses();
 767   submitInputChanges();
 768
 769   return true;
 770}
 771
 772bool OpenVRProvider::providesFrameEyePose() const
 773{
 774   return mHMD != NULL;
 775}
 776
 777inline Point3F OpenVRVecToTorqueVec(vr::HmdVector3_t vec)
 778{
 779   return Point3F(-vec.v[0], vec.v[2], -vec.v[1]);
 780}
 781
 782void OpenVRTransformToRotPos(MatrixF mat, QuatF &outRot, Point3F &outPos)
 783{
 784   // Directly set the rotation and position from the eye transforms
 785   MatrixF torqueMat(1);
 786   OpenVRUtil::convertTransformFromOVR(mat, torqueMat);
 787
 788   Point3F pos = torqueMat.getPosition();
 789   outRot = QuatF(torqueMat);
 790   outPos = pos;
 791   outRot.mulP(pos, &outPos); // jamesu - position needs to be multiplied by rotation in this case
 792}
 793
 794void OpenVRTransformToRotPosMat(MatrixF mat, QuatF &outRot, Point3F &outPos, MatrixF &outMat)
 795{
 796   // Directly set the rotation and position from the eye transforms
 797   MatrixF torqueMat(1);
 798   OpenVRUtil::convertTransformFromOVR(mat, torqueMat);
 799
 800   Point3F pos = torqueMat.getPosition();
 801   outRot = QuatF(torqueMat);
 802   outPos = pos;
 803   outRot.mulP(pos, &outPos); // jamesu - position needs to be multiplied by rotation in this case
 804   outMat = torqueMat;
 805}
 806
 807void OpenVRProvider::getFrameEyePose(IDevicePose *pose, S32 eyeId) const
 808{
 809   AssertFatal(eyeId >= -1 && eyeId < 2, "Out of bounds eye");
 810
 811   if (eyeId == -1)
 812   {
 813      // NOTE: this is codename for "head"
 814      MatrixF mat = mHMDRenderState.mHMDPose; // same order as in the openvr example
 815
 816#ifdef DEBUG_DISPLAY_POSE
 817      pose->originalMatrix = mat;
 818      OpenVRTransformToRotPosMat(mat, pose->orientation, pose->position, pose->actualMatrix);
 819#else
 820      OpenVRTransformToRotPos(mat, pose->orientation, pose->position);
 821#endif
 822
 823      pose->velocity = Point3F(0);
 824      pose->angularVelocity = Point3F(0);
 825   }
 826   else
 827   {
 828      MatrixF mat = mHMDRenderState.mEyePose[eyeId] * mHMDRenderState.mHMDPose; // same order as in the openvr example
 829      //mat =  mHMDRenderState.mHMDPose * mHMDRenderState.mEyePose[eyeId]; // same order as in the openvr example
 830
 831
 832#ifdef DEBUG_DISPLAY_POSE
 833      pose->originalMatrix = mat;
 834      OpenVRTransformToRotPosMat(mat, pose->orientation, pose->position, pose->actualMatrix);
 835#else
 836      OpenVRTransformToRotPos(mat, pose->orientation, pose->position);
 837#endif
 838
 839      pose->velocity = Point3F(0);
 840      pose->angularVelocity = Point3F(0);
 841   }
 842}
 843
 844bool OpenVRProvider::providesEyeOffsets() const
 845{
 846   return mHMD != NULL;
 847}
 848
 849/// Returns eye offset not taking into account any position tracking info
 850void OpenVRProvider::getEyeOffsets(Point3F *dest) const
 851{
 852   dest[0] = mHMDRenderState.mEyePose[0].getPosition();
 853   dest[1] = mHMDRenderState.mEyePose[1].getPosition();
 854
 855   dest[0] = Point3F(-dest[0].x, dest[0].y, dest[0].z); // convert from vr-space
 856   dest[1] = Point3F(-dest[1].x, dest[1].y, dest[1].z);
 857}
 858
 859bool OpenVRProvider::providesFovPorts() const
 860{
 861   return mHMD != NULL;
 862}
 863
 864void OpenVRProvider::getFovPorts(FovPort *out) const
 865{
 866   dMemcpy(out, mHMDRenderState.mEyeFov, sizeof(mHMDRenderState.mEyeFov));
 867}
 868
 869void OpenVRProvider::getStereoViewports(RectI *out) const
 870{
 871   out[0] = mHMDRenderState.mEyeViewport[0];
 872   out[1] = mHMDRenderState.mEyeViewport[1];
 873}
 874
 875void OpenVRProvider::getStereoTargets(GFXTextureTarget **out) const
 876{
 877   out[0] = mHMDRenderState.mStereoRT;
 878   out[1] = mHMDRenderState.mStereoRT;
 879}
 880
 881void OpenVRProvider::setDrawCanvas(GuiCanvas *canvas)
 882{
 883   vr::EVRInitError peError = vr::VRInitError_None;
 884
 885   if (!vr::VRCompositor())
 886   {
 887      Con::errorf("VR: Compositor initialization failed. See log file for details\n");
 888      return;
 889   }
 890
 891   if (mDrawCanvas != canvas || mHMDRenderState.mHMD == NULL)
 892   {
 893      mHMDRenderState.setupRenderTargets(GFXDevice::RS_Standard);
 894   }
 895   mDrawCanvas = canvas;
 896}
 897
 898void OpenVRProvider::setDrawMode(GFXDevice::GFXDeviceRenderStyles style)
 899{
 900   mHMDRenderState.setupRenderTargets(style);
 901}
 902
 903void OpenVRProvider::setCurrentConnection(GameConnection *connection)
 904{
 905   mGameConnection = connection;
 906}
 907
 908GameConnection* OpenVRProvider::getCurrentConnection()
 909{
 910   return mGameConnection;
 911}
 912
 913GFXTexHandle OpenVRProvider::getPreviewTexture()
 914{
 915   return mHMDRenderState.mStereoRenderTexture; // TODO: render distortion preview
 916}
 917
 918void OpenVRProvider::onStartFrame()
 919{
 920   if (!mHMD)
 921      return;
 922
 923}
 924
 925void OpenVRProvider::onEndFrame()
 926{
 927   if (!mHMD)
 928      return;
 929}
 930
 931void OpenVRProvider::onEyeRendered(U32 index)
 932{
 933   if (!mHMD)
 934      return;
 935
 936   vr::EVRCompositorError err = vr::VRCompositorError_None;
 937   vr::VRTextureBounds_t bounds;
 938   U32 textureIdxToSubmit = index;
 939
 940   GFXTexHandle eyeTex = mHMDRenderState.mOutputEyeTextures.getTextureHandle();
 941   if (mHMDRenderState.mRenderMode == GFXDevice::RS_StereoSeparate)
 942   {
 943      mHMDRenderState.mStereoRT->resolveTo(eyeTex);
 944      mHMDRenderState.mOutputEyeTextures.advance();
 945   }
 946   else
 947   {
 948      // assuming side-by-side, so the right eye will be next
 949      if (index == 1)
 950      {
 951         mHMDRenderState.mStereoRT->resolveTo(eyeTex);
 952         mHMDRenderState.mOutputEyeTextures.advance();
 953      }
 954      else
 955      {
 956         return;
 957      }
 958   }
 959
 960   if (GFX->getAdapterType() == Direct3D11)
 961   {
 962      vr::Texture_t eyeTexture;
 963      if (mHMDRenderState.mRenderMode == GFXDevice::RS_StereoSeparate)
 964      {
 965         // whatever eye we are on
 966         eyeTexture = { (void*)static_cast<GFXD3D11TextureObject*>(eyeTex.getPointer())->get2DTex(), vr::API_DirectX, vr::ColorSpace_Gamma };
 967         bounds = OpenVRUtil::TorqueRectToBounds(mHMDRenderState.mEyeViewport[index], mHMDRenderState.mStereoRenderTexture.getWidthHeight());
 968         err = vr::VRCompositor()->Submit((vr::EVREye)(vr::Eye_Left + index), &eyeTexture, &bounds);
 969      }
 970      else
 971      {
 972         // left & right at the same time
 973         eyeTexture = { (void*)static_cast<GFXD3D11TextureObject*>(eyeTex.getPointer())->get2DTex(), vr::API_DirectX, vr::ColorSpace_Gamma };
 974         bounds = OpenVRUtil::TorqueRectToBounds(mHMDRenderState.mEyeViewport[0], mHMDRenderState.mStereoRenderTexture.getWidthHeight());
 975         err = vr::VRCompositor()->Submit((vr::EVREye)(vr::Eye_Left), &eyeTexture, &bounds);
 976         bounds = OpenVRUtil::TorqueRectToBounds(mHMDRenderState.mEyeViewport[1], mHMDRenderState.mStereoRenderTexture.getWidthHeight());
 977         err = vr::VRCompositor()->Submit((vr::EVREye)(vr::Eye_Right), &eyeTexture, &bounds);
 978      }
 979   }
 980   else if (GFX->getAdapterType() == Direct3D9)
 981   {
 982      //vr::Texture_t eyeTexture = { (void*)static_cast<GFXD3D9TextureObject*>(mHMDRenderState.mStereoRenderTextures[index].getPointer())->get2DTex(), vr::API_DirectX, vr::ColorSpace_Gamma };
 983      //err = vr::VRCompositor()->Submit((vr::EVREye)(vr::Eye_Left + index), &eyeTexture);
 984   }
 985#ifdef TORQUE_OPENGL
 986   else if (GFX->getAdapterType() == OpenGL)
 987   {
 988      vr::Texture_t eyeTexture;
 989      if (mHMDRenderState.mRenderMode == GFXDevice::RS_StereoSeparate)
 990      {
 991         // whatever eye we are on
 992         eyeTexture = { (void*)static_cast<GFXGLTextureObject*>(eyeTex.getPointer())->getHandle(), vr::API_OpenGL, vr::ColorSpace_Gamma };
 993         bounds = OpenVRUtil::TorqueRectToBounds(mHMDRenderState.mEyeViewport[index], mHMDRenderState.mStereoRenderTexture.getWidthHeight());
 994         err = vr::VRCompositor()->Submit((vr::EVREye)(vr::Eye_Left + index), &eyeTexture, &bounds);
 995      }
 996      else
 997      {
 998         // left & right at the same time
 999         eyeTexture = { (void*)static_cast<GFXGLTextureObject*>(eyeTex.getPointer())->getHandle(), vr::API_OpenGL, vr::ColorSpace_Gamma };
1000         bounds = OpenVRUtil::TorqueRectToBounds(mHMDRenderState.mEyeViewport[0], mHMDRenderState.mStereoRenderTexture.getWidthHeight());
1001         err = vr::VRCompositor()->Submit((vr::EVREye)(vr::Eye_Left), &eyeTexture, &bounds);
1002         bounds = OpenVRUtil::TorqueRectToBounds(mHMDRenderState.mEyeViewport[1], mHMDRenderState.mStereoRenderTexture.getWidthHeight());
1003         err = vr::VRCompositor()->Submit((vr::EVREye)(vr::Eye_Right), &eyeTexture, &bounds);
1004      }
1005   }
1006#endif
1007
1008   AssertFatal(err == vr::VRCompositorError_None, "VR compositor error!");
1009}
1010
1011void OpenVRProvider::setRoomTracking(bool room)
1012{
1013   vr::IVRCompositor* compositor = vr::VRCompositor();
1014   mTrackingSpace = room ? vr::TrackingUniverseStanding : vr::TrackingUniverseSeated;
1015   if (compositor) compositor->SetTrackingSpace(mTrackingSpace);
1016}
1017
1018bool OpenVRProvider::_handleDeviceEvent(GFXDevice::GFXDeviceEventType evt)
1019{
1020   if (!ManagedSingleton<OpenVRProvider>::instanceOrNull())
1021   {
1022      return true;
1023   }
1024
1025   switch (evt)
1026   {
1027   case GFXDevice::deStartOfFrame:
1028
1029      // Start of frame
1030
1031      onStartFrame();
1032
1033      break;
1034
1035   case GFXDevice::dePostFrame:
1036
1037      // End of frame
1038
1039      onEndFrame();
1040
1041      break;
1042
1043   case GFXDevice::deDestroy:
1044
1045      // Need to reinit rendering
1046      break;
1047
1048   case GFXDevice::deLeftStereoFrameRendered:
1049      // 
1050
1051      onEyeRendered(0);
1052      break;
1053
1054   case GFXDevice::deRightStereoFrameRendered:
1055      // 
1056
1057      onEyeRendered(1);
1058      break;
1059
1060   default:
1061      break;
1062   }
1063
1064   return true;
1065}
1066
1067S32 OpenVRProvider::getDisplayDeviceId() const
1068{
1069#if defined(TORQUE_OS_WIN64) || defined(TORQUE_OS_WIN32)
1070   if (GFX && GFX->getAdapterType() == Direct3D11)
1071   {
1072      Vector<GFXAdapter*> adapterList;
1073      GFXD3D11Device::enumerateAdapters(adapterList);
1074
1075      for (U32 i = 0, sz = adapterList.size(); i < sz; i++)
1076      {
1077         GFXAdapter* adapter = adapterList[i];
1078         if (dMemcmp(&adapter->mLUID, &mLUID, sizeof(mLUID)) == 0)
1079         {
1080            return adapter->mIndex;
1081         }
1082      }
1083   }
1084#endif
1085
1086   return -1;
1087}
1088
1089void OpenVRProvider::processVREvent(const vr::VREvent_t & evt)
1090{
1091   mVREventSignal.trigger(evt);
1092   switch (evt.eventType)
1093   {
1094   case vr::VREvent_InputFocusCaptured:
1095      //Con::executef()
1096      break;
1097   case vr::VREvent_TrackedDeviceActivated:
1098   {
1099      // Setup render model
1100   }
1101   break;
1102   case vr::VREvent_TrackedDeviceDeactivated:
1103   {
1104      // Deactivated
1105   }
1106   break;
1107   case vr::VREvent_TrackedDeviceUpdated:
1108   {
1109      // Updated
1110   }
1111   break;
1112   }
1113}
1114
1115void OpenVRProvider::updateTrackedPoses()
1116{
1117   if (!mHMD)
1118      return;
1119
1120   vr::IVRCompositor* compositor = vr::VRCompositor();
1121
1122   if (!compositor)
1123      return;
1124
1125   if (compositor->GetTrackingSpace() != mTrackingSpace)
1126   {
1127      compositor->SetTrackingSpace(mTrackingSpace);
1128   }
1129
1130   compositor->WaitGetPoses(mTrackedDevicePose, vr::k_unMaxTrackedDeviceCount, NULL, 0);
1131
1132   // Make sure we're using the latest eye offset in case user has changed IPD
1133   mHMDRenderState.updateHMDProjection();
1134
1135   mValidPoseCount = 0;
1136
1137   for (int nDevice = 0; nDevice < vr::k_unMaxTrackedDeviceCount; ++nDevice)
1138   {
1139      IDevicePose &inPose = mCurrentDevicePose[nDevice];
1140      if (mTrackedDevicePose[nDevice].bPoseIsValid)
1141      {
1142         mValidPoseCount++;
1143         MatrixF mat = OpenVRUtil::convertSteamVRAffineMatrixToMatrixFPlain(mTrackedDevicePose[nDevice].mDeviceToAbsoluteTracking);
1144
1145         if (nDevice == vr::k_unTrackedDeviceIndex_Hmd)
1146         {
1147            mHMDRenderState.mHMDPose = mat;
1148
1149         /*
1150            MatrixF rotOffset(1);
1151            EulerF localRot(-smHMDRotOffset.x, -smHMDRotOffset.z, smHMDRotOffset.y);
1152
1153            // NOTE: offsetting before is probably the best we're going to be able to do here, since if we apply the matrix AFTER 
1154            // we will get correct movements relative to the camera HOWEVER this also distorts any future movements from the HMD since 
1155            // we will then be on a really weird rotation axis.
1156            QuatF(localRot).setMatrix(&rotOffset);
1157            rotOffset.inverse();
1158            mHMDRenderState.mHMDPose = mat = rotOffset * mHMDRenderState.mHMDPose;
1159         */
1160
1161            // jamesu - store the last rotation for temp debugging
1162            MatrixF torqueMat(1);
1163            OpenVRUtil::convertTransformFromOVR(mat, torqueMat);
1164            gLastMoveRot = AngAxisF(torqueMat);
1165            //Con::printf("gLastMoveRot = %f,%f,%f,%f", gLastMoveRot.axis.x, gLastMoveRot.axis.y, gLastMoveRot.axis.z, gLastMoveRot.angle);
1166            mHMDRenderState.mHMDPose.inverse();
1167         }
1168
1169         vr::TrackedDevicePose_t &outPose = mTrackedDevicePose[nDevice];
1170         OpenVRTransformToRotPos(mat, inPose.orientation, inPose.position);
1171
1172#ifdef DEBUG_DISPLAY_POSE
1173       OpenVRUtil::convertTransformFromOVR(mat, inPose.actualMatrix);
1174       inPose.originalMatrix = mat;
1175#endif
1176
1177         inPose.state = outPose.eTrackingResult;
1178         inPose.valid = outPose.bPoseIsValid;
1179         inPose.connected = outPose.bDeviceIsConnected;
1180
1181         inPose.velocity = OpenVRVecToTorqueVec(outPose.vVelocity);
1182         inPose.angularVelocity = OpenVRVecToTorqueVec(outPose.vAngularVelocity);
1183      }
1184      else
1185      {
1186         inPose.valid = false;
1187      }
1188   }
1189}
1190
1191void OpenVRProvider::submitInputChanges()
1192{
1193   // Diff current frame with previous frame
1194   for (U32 i = 0; i < vr::k_unMaxTrackedDeviceCount; i++)
1195   {
1196      IDevicePose curPose = mCurrentDevicePose[i];
1197      IDevicePose prevPose = mPreviousInputTrackedDevicePose[i];
1198
1199     S32 eventIdx = -1;
1200     
1201     if (!mDeviceEventMap.tryGetValue(i, eventIdx) || eventIdx < 0)
1202        continue;
1203
1204      if (!curPose.valid || !curPose.connected)
1205         continue;
1206
1207      if (curPose.orientation != prevPose.orientation)
1208      {
1209         AngAxisF axisAA(curPose.orientation);
1210         INPUTMGR->buildInputEvent(mDeviceType, 0, SI_ROT, OVR_SENSORROT[eventIdx], SI_MOVE, axisAA);
1211      }
1212
1213      if (curPose.position != prevPose.position)
1214      {
1215         INPUTMGR->buildInputEvent(mDeviceType, 0, SI_POS, OVR_SENSORPOSITION[eventIdx], SI_MOVE, curPose.position);
1216      }
1217
1218      if (curPose.velocity != prevPose.velocity)
1219      {
1220         // Convert angles to degrees
1221         VectorF angles;
1222         angles.x = curPose.velocity.x;
1223         angles.y = curPose.velocity.y;
1224         angles.z = curPose.velocity.z;
1225
1226         INPUTMGR->buildInputEvent(mDeviceType, 0, SI_POS, OVR_SENSORVELOCITY[eventIdx], SI_MOVE, angles);
1227      }
1228
1229      if (curPose.angularVelocity != prevPose.angularVelocity)
1230      {
1231         // Convert angles to degrees
1232         VectorF angles;
1233         angles[0] = mRadToDeg(curPose.velocity.x);
1234         angles[1] = mRadToDeg(curPose.velocity.y);
1235         angles[2] = mRadToDeg(curPose.velocity.z);
1236
1237         INPUTMGR->buildInputEvent(mDeviceType, 0, SI_POS, OVR_SENSORANGVEL[eventIdx], SI_MOVE, angles);
1238      }
1239      /*
1240      if (curPose.connected != prevPose.connected)
1241      {
1242         if (Con::isFunction("onOVRConnectionChanged"))
1243         {
1244            Con::executef("onOVRConnectionStatus", curPose.connected);
1245         }
1246      }*/
1247
1248      if (curPose.state != prevPose.state)
1249      {
1250         if (Con::isFunction("onOVRStateChanged"))
1251         {
1252            Con::executef("onOVRStateChanged", curPose.state);
1253         }
1254      }
1255   }
1256
1257   dMemcpy(mPreviousInputTrackedDevicePose, mCurrentDevicePose, sizeof(mPreviousInputTrackedDevicePose));
1258}
1259
1260void OpenVRProvider::resetSensors()
1261{
1262   if (mHMD)
1263   {
1264      mHMD->ResetSeatedZeroPose();
1265   }
1266}
1267
1268void OpenVRProvider::mapDeviceToEvent(U32 deviceIdx, S32 eventIdx)
1269{
1270   mDeviceEventMap[deviceIdx] = eventIdx;
1271}
1272
1273void OpenVRProvider::resetEventMap()
1274{
1275   mDeviceEventMap.clear();
1276}
1277
1278IDevicePose OpenVRProvider::getTrackedDevicePose(U32 idx)
1279{
1280   if (idx >= vr::k_unMaxTrackedDeviceCount)
1281   {
1282      IDevicePose ret;
1283      ret.connected = ret.valid = false;
1284      return ret;
1285   }
1286
1287   return mCurrentDevicePose[idx];
1288}
1289
1290void OpenVRProvider::registerOverlay(OpenVROverlay* overlay)
1291{
1292   mOverlays.push_back(overlay);
1293}
1294
1295void OpenVRProvider::unregisterOverlay(OpenVROverlay* overlay)
1296{
1297   S32 index = mOverlays.find_next(overlay);
1298   if (index != -1)
1299   {
1300      mOverlays.erase(index);
1301   }
1302}
1303
1304const S32 OpenVRProvider::preloadRenderModelTexture(U32 index)
1305{
1306   S32 idx = -1;
1307   if (mLoadedTextureLookup.tryGetValue(index, idx))
1308      return idx;
1309
1310   char buffer[256];
1311   dSprintf(buffer, sizeof(buffer), "openvrtex_%u", index);
1312
1313   OpenVRProvider::LoadedRenderTexture loadedTexture;
1314   loadedTexture.vrTextureId = index;
1315   loadedTexture.vrTexture = NULL;
1316   loadedTexture.texture = NULL;
1317   loadedTexture.textureError = vr::VRRenderModelError_Loading;
1318   loadedTexture.targetTexture = new NamedTexTarget();
1319   loadedTexture.targetTexture->registerWithName(buffer);
1320   mLoadedTextures.push_back(loadedTexture);
1321   mLoadedTextureLookup[index] = mLoadedTextures.size() - 1;
1322
1323   return mLoadedTextures.size() - 1;
1324}
1325
1326const S32 OpenVRProvider::preloadRenderModel(StringTableEntry name)
1327{
1328   S32 idx = -1;
1329   if (mLoadedModelLookup.tryGetValue(name, idx))
1330      return idx;
1331
1332   OpenVRProvider::LoadedRenderModel loadedModel;
1333   loadedModel.name = name;
1334   loadedModel.model = NULL;
1335   loadedModel.vrModel = NULL;
1336   loadedModel.modelError = vr::VRRenderModelError_Loading;
1337   loadedModel.loadedTexture = false;
1338   loadedModel.textureId = -1;
1339   mLoadedModels.push_back(loadedModel);
1340   mLoadedModelLookup[name] = mLoadedModels.size() - 1;
1341
1342   return mLoadedModels.size() - 1;
1343}
1344
1345
1346bool OpenVRProvider::getRenderModel(S32 idx, OpenVRRenderModel **ret, bool &failed)
1347{
1348   if (idx < 0 || idx > mLoadedModels.size())
1349   {
1350      failed = true;
1351      return true;
1352   }
1353
1354   OpenVRProvider::LoadedRenderModel &loadedModel = mLoadedModels[idx];
1355   //Con::printf("RenderModel[%i] STAGE 1", idx);
1356
1357   failed = false;
1358
1359   if (loadedModel.modelError > vr::VRRenderModelError_Loading)
1360   {
1361      failed = true;
1362      return true;
1363   }
1364
1365   // Stage 1 : model
1366   if (!loadedModel.model)
1367   {
1368      loadedModel.modelError = vr::VRRenderModels()->LoadRenderModel_Async(loadedModel.name, &loadedModel.vrModel);
1369      //Con::printf(" vr::VRRenderModels()->LoadRenderModel_Async(\"%s\", %x); -> %i", loadedModel.name, &loadedModel.vrModel, loadedModel.modelError);
1370      if (loadedModel.modelError == vr::VRRenderModelError_None)
1371      {
1372         if (loadedModel.vrModel == NULL)
1373         {
1374            failed = true;
1375            return true;
1376         }
1377         // Load the model
1378         loadedModel.model = new OpenVRRenderModel();
1379      }
1380      else if (loadedModel.modelError == vr::VRRenderModelError_Loading)
1381      {
1382         return false;
1383      }
1384   }
1385
1386   //Con::printf("RenderModel[%i] STAGE 2 (texId == %i)", idx, loadedModel.vrModel->diffuseTextureId);
1387
1388   // Stage 2 : texture
1389   if (!loadedModel.loadedTexture && loadedModel.model)
1390   {
1391      if (loadedModel.textureId == -1)
1392      {
1393         loadedModel.textureId = preloadRenderModelTexture(loadedModel.vrModel->diffuseTextureId);
1394      }
1395
1396      if (loadedModel.textureId == -1)
1397      {
1398         failed = true;
1399         return true;
1400      }
1401
1402      if (!getRenderModelTexture(loadedModel.textureId, NULL, failed))
1403      {
1404         return false;
1405      }
1406
1407      if (failed)
1408      {
1409         return true;
1410      }
1411
1412      loadedModel.loadedTexture = true;
1413
1414      //Con::printf("RenderModel[%i] GOT TEXTURE");
1415
1416      // Now we can load the model. Note we first need to get a Material for the mapped texture
1417      NamedTexTarget *namedTexture = mLoadedTextures[loadedModel.textureId].targetTexture;
1418      String materialName = MATMGR->getMapEntry(namedTexture->getName().c_str());
1419      if (materialName.isEmpty())
1420      {
1421         char buffer[256];
1422         dSprintf(buffer, sizeof(buffer), "#%s", namedTexture->getName().c_str());
1423         materialName = buffer;
1424
1425         //Con::printf("RenderModel[%i] materialName == %s", idx, buffer);
1426
1427         Material* mat = new Material();
1428         mat->mMapTo = namedTexture->getName();
1429         mat->mDiffuseMapFilename[0] = buffer;
1430         mat->mEmissive[0] = true;
1431
1432         dSprintf(buffer, sizeof(buffer), "%s_Material", namedTexture->getName().c_str());
1433         if (!mat->registerObject(buffer))
1434         {
1435            Con::errorf("Couldn't create placeholder openvr material %s!", buffer);
1436            failed = true;
1437            return true;
1438         }
1439
1440         materialName = buffer;
1441      }
1442      
1443      loadedModel.model->init(*loadedModel.vrModel, materialName);
1444   }
1445
1446   if ((loadedModel.modelError > vr::VRRenderModelError_Loading) || 
1447       (loadedModel.textureId >= 0 && mLoadedTextures[loadedModel.textureId].textureError > vr::VRRenderModelError_Loading))
1448   {
1449      failed = true;
1450   }
1451
1452   if (!failed && ret)
1453   {
1454      *ret = loadedModel.model;
1455   }
1456   return true;
1457}
1458
1459bool OpenVRProvider::getRenderModelTexture(S32 idx, GFXTextureObject **outTex, bool &failed)
1460{
1461   if (idx < 0 || idx > mLoadedModels.size())
1462   {
1463      failed = true;
1464      return true;
1465   }
1466
1467   failed = false;
1468
1469   OpenVRProvider::LoadedRenderTexture &loadedTexture = mLoadedTextures[idx];
1470
1471   if (loadedTexture.textureError > vr::VRRenderModelError_Loading)
1472   {
1473      failed = true;
1474      return true;
1475   }
1476
1477   if (!loadedTexture.texture)
1478   {
1479      if (!loadedTexture.vrTexture)
1480      {
1481         loadedTexture.textureError = vr::VRRenderModels()->LoadTexture_Async(loadedTexture.vrTextureId, &loadedTexture.vrTexture);
1482         if (loadedTexture.textureError == vr::VRRenderModelError_None)
1483         {
1484            // Load the texture
1485            GFXTexHandle tex;
1486
1487            const U32 sz = loadedTexture.vrTexture->unWidth * loadedTexture.vrTexture->unHeight * 4;
1488            GBitmap *bmp = new GBitmap(loadedTexture.vrTexture->unWidth, loadedTexture.vrTexture->unHeight, false, GFXFormatR8G8B8A8);
1489
1490            Swizzles::bgra.ToBuffer(bmp->getAddress(0,0,0), loadedTexture.vrTexture->rubTextureMapData, sz);
1491
1492            char buffer[256];
1493            dSprintf(buffer, 256, "OVRTEX-%i.png", loadedTexture.vrTextureId);
1494
1495            FileStream fs;
1496            fs.open(buffer, Torque::FS::File::Write);
1497            bmp->writeBitmap("PNG", fs);
1498            fs.close();
1499
1500            tex.set(bmp, &GFXDefaultStaticDiffuseProfile, true, "OpenVR Texture");
1501            //tex.set(loadedTexture.vrTexture->unWidth, loadedTexture.vrTexture->unHeight, 1, (void*)pixels, GFXFormatR8G8B8A8, &GFXDefaultStaticDiffuseProfile, "OpenVR Texture", 1);
1502
1503
1504            loadedTexture.targetTexture->setTexture(tex);
1505            loadedTexture.texture = tex;
1506         }
1507         else if (loadedTexture.textureError == vr::VRRenderModelError_Loading)
1508         {
1509            return false;
1510         }
1511      }
1512   }
1513
1514   if (loadedTexture.textureError > vr::VRRenderModelError_Loading)
1515   {
1516      failed = true;
1517   }
1518
1519   if (!failed && outTex)
1520   {
1521      *outTex = loadedTexture.texture;
1522   }
1523
1524   return true;
1525}
1526
1527bool OpenVRProvider::getRenderModelTextureName(S32 idx, String &outName)
1528{
1529   if (idx < 0 || idx >= mLoadedTextures.size())
1530      return false;
1531
1532   if (mLoadedTextures[idx].targetTexture)
1533   {
1534      outName = mLoadedTextures[idx].targetTexture->getName();
1535      return true;
1536   }
1537
1538   return false;
1539}
1540
1541void OpenVRProvider::resetRenderModels()
1542{
1543   for (U32 i = 0, sz = mLoadedModels.size(); i < sz; i++)
1544   {
1545      SAFE_DELETE(mLoadedModels[i].model);
1546      if (mLoadedModels[i].vrModel) mRenderModels->FreeRenderModel(mLoadedModels[i].vrModel);
1547   }
1548   for (U32 i = 0, sz = mLoadedTextures.size(); i < sz; i++)
1549   {
1550      SAFE_DELETE(mLoadedTextures[i].targetTexture);
1551      if (mLoadedTextures[i].vrTexture) mRenderModels->FreeTexture(mLoadedTextures[i].vrTexture);
1552   }
1553   mLoadedModels.clear();
1554   mLoadedTextures.clear();
1555   mLoadedModelLookup.clear();
1556   mLoadedTextureLookup.clear();
1557}
1558
1559OpenVROverlay *OpenVRProvider::getGamepadFocusOverlay()
1560{
1561   return NULL;
1562}
1563
1564void OpenVRProvider::setOverlayNeighbour(vr::EOverlayDirection dir, OpenVROverlay *overlay)
1565{
1566
1567}
1568
1569
1570bool OpenVRProvider::isDashboardVisible()
1571{
1572   return false;
1573}
1574
1575void OpenVRProvider::showDashboard(const char *overlayToShow)
1576{
1577
1578}
1579
1580vr::TrackedDeviceIndex_t OpenVRProvider::getPrimaryDashboardDevice()
1581{
1582   return -1;
1583}
1584
1585void OpenVRProvider::setKeyboardTransformAbsolute(const MatrixF &xfm)
1586{
1587   // mTrackingSpace
1588}
1589
1590void OpenVRProvider::setKeyboardPositionForOverlay(OpenVROverlay *overlay, const RectI &rect)
1591{
1592
1593}
1594
1595void OpenVRProvider::getControllerDeviceIndexes(vr::TrackedDeviceClass &deviceClass, Vector<S32> &outList)
1596{
1597   for (U32 i = 0; i<vr::k_unMaxTrackedDeviceCount; i++)
1598   {
1599      if (!mCurrentDevicePose[i].connected)
1600         continue;
1601
1602      vr::TrackedDeviceClass klass = mHMD->GetTrackedDeviceClass(i);
1603      if (klass == deviceClass)
1604      {
1605         outList.push_back(i);
1606      }
1607   }
1608}
1609
1610StringTableEntry OpenVRProvider::getControllerModel(U32 idx)
1611{
1612   if (idx >= vr::k_unMaxTrackedDeviceCount || !mRenderModels)
1613      return NULL;
1614
1615   String str = GetTrackedDeviceString(mHMD, idx, vr::Prop_RenderModelName_String, NULL);
1616   return StringTable->insert(str, true);
1617}
1618
1619DefineEngineStaticMethod(OpenVR, getControllerDeviceIndexes, const char*, (OpenVRTrackedDeviceClass klass),,
1620   "@brief Gets the indexes of devices which match the required device class")
1621{
1622   if (!ManagedSingleton<OpenVRProvider>::instanceOrNull())
1623   {
1624      return "";
1625   }
1626
1627   Vector<S32> outList;
1628   OPENVR->getControllerDeviceIndexes(klass, outList);
1629   return EngineMarshallData<Vector<S32>>(outList);
1630}
1631
1632DefineEngineStaticMethod(OpenVR, getControllerModel, const char*, (S32 idx), ,
1633   "@brief Gets the indexes of devices which match the required device class")
1634{
1635   if (!ManagedSingleton<OpenVRProvider>::instanceOrNull())
1636   {
1637      return "";
1638   }
1639
1640   return OPENVR->getControllerModel(idx);
1641}
1642
1643DefineEngineStaticMethod(OpenVR, isDeviceActive, bool, (), ,
1644   "@brief Used to determine if the OpenVR input device is active\n\n"
1645
1646   "The OpenVR device is considered active when the library has been "
1647   "initialized and either a real of simulated HMD is present.\n\n"
1648
1649   "@return True if the OpenVR input device is active.\n"
1650
1651   "@ingroup Game")
1652{
1653   if (!ManagedSingleton<OpenVRProvider>::instanceOrNull())
1654   {
1655      return false;
1656   }
1657
1658   return OPENVR->getActive();
1659}
1660
1661
1662DefineEngineStaticMethod(OpenVR, setEnabled, bool, (bool value), ,
1663   "@brief Used to determine if the OpenVR input device is active\n\n"
1664
1665   "The OpenVR device is considered active when the library has been "
1666   "initialized and either a real of simulated HMD is present.\n\n"
1667
1668   "@return True if the OpenVR input device is active.\n"
1669
1670   "@ingroup Game")
1671{
1672   if (!ManagedSingleton<OpenVRProvider>::instanceOrNull())
1673   {
1674      return false;
1675   }
1676
1677   return value ? OPENVR->enable() : OPENVR->disable();
1678}
1679
1680
1681DefineEngineStaticMethod(OpenVR, setHMDAsGameConnectionDisplayDevice, bool, (GameConnection* conn), ,
1682   "@brief Sets the first HMD to be a GameConnection's display device\n\n"
1683   "@param conn The GameConnection to set.\n"
1684   "@return True if the GameConnection display device was set.\n"
1685   "@ingroup Game")
1686{
1687   if (!ManagedSingleton<OpenVRProvider>::instanceOrNull())
1688   {
1689      Con::errorf("setOVRHMDAsGameConnectionDisplayDevice(): No Oculus VR Device present.");
1690      return false;
1691   }
1692
1693   if (!conn)
1694   {
1695      Con::errorf("setOVRHMDAsGameConnectionDisplayDevice(): Invalid GameConnection.");
1696      return false;
1697   }
1698
1699   conn->setDisplayDevice(OPENVR);
1700   return true;
1701}
1702
1703
1704DefineEngineStaticMethod(OpenVR, getDisplayDeviceId, S32, (), ,
1705   "@brief MacOS display ID.\n\n"
1706   "@param index The HMD index.\n"
1707   "@return The ID of the HMD display device, if any.\n"
1708   "@ingroup Game")
1709{
1710   if (!ManagedSingleton<OpenVRProvider>::instanceOrNull())
1711   {
1712      return -1;
1713   }
1714
1715   return OPENVR->getDisplayDeviceId();
1716}
1717
1718DefineEngineStaticMethod(OpenVR, resetSensors, void, (), ,
1719   "@brief Resets all Oculus VR sensors.\n\n"
1720   "This resets all sensor orientations such that their 'normal' rotation "
1721   "is defined when this function is called.  This defines an HMD's forwards "
1722   "and up direction, for example."
1723   "@ingroup Game")
1724{
1725   if (!ManagedSingleton<OpenVRProvider>::instanceOrNull())
1726   {
1727      return;
1728   }
1729
1730   OPENVR->resetSensors();
1731}
1732
1733DefineEngineStaticMethod(OpenVR, mapDeviceToEvent, void, (S32 deviceId, S32 eventId), ,
1734   "@brief Maps a device to an event code.\n\n"
1735   "@ingroup Game")
1736{
1737   if (!ManagedSingleton<OpenVRProvider>::instanceOrNull())
1738   {
1739      return;
1740   }
1741
1742   OPENVR->mapDeviceToEvent(deviceId, eventId);
1743}
1744
1745DefineEngineStaticMethod(OpenVR, resetEventMap, void, (), ,
1746   "@brief Resets event map.\n\n"
1747   "@ingroup Game")
1748{
1749   if (!ManagedSingleton<OpenVRProvider>::instanceOrNull())
1750   {
1751      return;
1752   }
1753
1754   OPENVR->resetEventMap();
1755}
1756
1757// Overlay stuff
1758
1759DefineEngineFunction(OpenVRIsCompiledIn, bool, (), , "")
1760{
1761   return true;
1762}
1763