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