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