openVRProvider.cpp
Engine/source/platform/input/openVR/openVRProvider.cpp
Classes:
class
Namespaces:
namespace
Public Variables
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)
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
