0031682: Visualization - Prs3d_ShadingAspect::SetTransparency() has no effect with...
[occt.git] / src / Aspect / Aspect_OpenVRSession.cxx
CommitLineData
b40cdc2b 1// Copyright (c) 2020 OPEN CASCADE SAS
2//
3// This file is part of Open CASCADE Technology software library.
4//
5// This library is free software; you can redistribute it and/or modify it under
6// the terms of the GNU Lesser General Public License version 2.1 as published
7// by the Free Software Foundation, with special exception defined in the file
8// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9// distribution for complete text of the license and disclaimer of any warranty.
10//
11// Alternatively, this file may be used under the terms of Open CASCADE
12// commercial license or contractual agreement.
13
14#include <Aspect_OpenVRSession.hxx>
15
16#include <Graphic3d_ArrayOfTriangles.hxx>
17#include <Image_PixMap.hxx>
18#include <Image_Texture.hxx>
19#include <Message.hxx>
20#include <Message_Messenger.hxx>
21#include <NCollection_LocalArray.hxx>
22#include <OSD.hxx>
23#include <OSD_Environment.hxx>
24#include <OSD_File.hxx>
25#include <OSD_Process.hxx>
26
27#ifdef HAVE_OPENVR
28 #include <openvr.h>
29
30namespace
31{
32 //! Print OpenVR compositor error.
33 static const char* getVRCompositorError (vr::EVRCompositorError theVRError)
34 {
35 switch (theVRError)
36 {
37 case vr::VRCompositorError_None: return "None";
38 case vr::VRCompositorError_RequestFailed: return "Request Failed";
39 case vr::VRCompositorError_IncompatibleVersion: return "Incompatible Version";
40 case vr::VRCompositorError_DoNotHaveFocus: return "Do not have focus";
41 case vr::VRCompositorError_InvalidTexture: return "Invalid Texture";
42 case vr::VRCompositorError_IsNotSceneApplication: return "Is not scene application";
43 case vr::VRCompositorError_TextureIsOnWrongDevice: return "Texture is on wrong device";
44 case vr::VRCompositorError_TextureUsesUnsupportedFormat: return "Texture uses unsupported format";
45 case vr::VRCompositorError_SharedTexturesNotSupported: return "Shared textures not supported";
46 case vr::VRCompositorError_IndexOutOfRange: return "Index out of range";
47 case vr::VRCompositorError_AlreadySubmitted: return "Already submitted";
48 case vr::VRCompositorError_InvalidBounds: return "Invalid Bounds";
49 case vr::VRCompositorError_AlreadySet: return "Already set";
50 }
51 return "UNKNOWN";
52 }
53
54 //! Print OpenVR input error.
55 static const char* getVRInputError (vr::EVRInputError theVRError)
56 {
57 switch (theVRError)
58 {
59 case vr::VRInputError_None: return "None";
60 case vr::VRInputError_NameNotFound: return "NameNotFound";
61 case vr::VRInputError_WrongType: return "WrongType";
62 case vr::VRInputError_InvalidHandle: return "InvalidHandle";
63 case vr::VRInputError_InvalidParam: return "InvalidParam";
64 case vr::VRInputError_NoSteam: return "NoSteam:";
65 case vr::VRInputError_MaxCapacityReached: return "MaxCapacityReached";
66 case vr::VRInputError_IPCError: return "IPCError";
67 case vr::VRInputError_NoActiveActionSet: return "NoActiveActionSet";
68 case vr::VRInputError_InvalidDevice: return "InvalidDevice";
69 case vr::VRInputError_InvalidSkeleton: return "InvalidSkeleton";
70 case vr::VRInputError_InvalidBoneCount: return "InvalidBoneCount";
71 case vr::VRInputError_InvalidCompressedData: return "InvalidCompressedData";
72 case vr::VRInputError_NoData: return "NoData";
73 case vr::VRInputError_BufferTooSmall: return "BufferTooSmall";
74 case vr::VRInputError_MismatchedActionManifest: return "MismatchedActionManifest";
75 case vr::VRInputError_MissingSkeletonData: return "MissingSkeletonData";
76 case vr::VRInputError_InvalidBoneIndex: return "InvalidBoneIndex";
77 case vr::VRInputError_InvalidPriority: return "InvalidPriority";
78 case vr::VRInputError_PermissionDenied: return "PermissionDenied";
79 case vr::VRInputError_InvalidRenderModel: return "InvalidRenderModel";
80 }
81 return "UNKNOWN";
82 }
83
84 //! Convert OpenVR mat4x4 into OCCT mat4x4.
85 static NCollection_Mat4<double> mat44vr2Occ (const vr::HmdMatrix44_t& theMat4)
86 {
87 NCollection_Mat4<double> aMat4;
88 for (int aRow = 0; aRow < 4; ++aRow)
89 {
90 aMat4.SetRow (aRow, NCollection_Vec4<double> (theMat4.m[aRow][0], theMat4.m[aRow][1], theMat4.m[aRow][2], theMat4.m[aRow][3]));
91 }
92 return aMat4;
93 }
94
95 //! Convert OpenVR mat3x4 into OCCT gp_Trsf.
96 static gp_Trsf mat34vr2OccTrsf (const vr::HmdMatrix34_t& theMat4)
97 {
98 gp_Trsf aTrsf;
99 aTrsf.SetValues (theMat4.m[0][0], theMat4.m[0][1], theMat4.m[0][2], theMat4.m[0][3],
100 theMat4.m[1][0], theMat4.m[1][1], theMat4.m[1][2], theMat4.m[1][3],
101 theMat4.m[2][0], theMat4.m[2][1], theMat4.m[2][2], theMat4.m[2][3]);
102 return aTrsf;
103 }
104
105 //! Convert OpenVR tracked pose.
106 static Aspect_TrackedDevicePose poseVr2Occ (const vr::TrackedDevicePose_t& theVrPose,
107 const Standard_Real theUnitFactor)
108 {
109 Aspect_TrackedDevicePose aPose;
110 aPose.Velocity.SetCoord (theVrPose.vVelocity.v[0], theVrPose.vVelocity.v[1], theVrPose.vVelocity.v[2]);
111 aPose.AngularVelocity.SetCoord (theVrPose.vAngularVelocity.v[0], theVrPose.vAngularVelocity.v[1], theVrPose.vAngularVelocity.v[2]);
112 aPose.IsValidPose = theVrPose.bPoseIsValid;
113 aPose.IsConnectedDevice = theVrPose.bDeviceIsConnected;
114 if (aPose.IsValidPose)
115 {
116 aPose.Orientation = mat34vr2OccTrsf (theVrPose.mDeviceToAbsoluteTracking);
117 if (theUnitFactor != 1.0)
118 {
119 aPose.Orientation.SetTranslationPart (aPose.Orientation.TranslationPart() * theUnitFactor);
120 }
121 }
122 return aPose;
123 }
124
125 //! Find location of default actions manifest file (based on CSF_OCCTResourcePath or CASROOT variables).
126 TCollection_AsciiString defaultActionsManifestInit()
127 {
128 const TCollection_AsciiString THE_ACTIONS_JSON = "occtvr_actions.json";
129 const TCollection_AsciiString aResRoot (OSD_Environment ("CSF_OCCTResourcePath").Value());
130 if (!aResRoot.IsEmpty())
131 {
132 if (OSD_File (aResRoot + "/" + THE_ACTIONS_JSON).Exists())
133 {
134 return aResRoot + "/" + THE_ACTIONS_JSON;
135 }
136 if (OSD_File (aResRoot + "/XRResources/" + THE_ACTIONS_JSON).Exists())
137 {
138 return aResRoot + "/XRResources/" + THE_ACTIONS_JSON;
139 }
140 }
141 const TCollection_AsciiString aCasRoot (OSD_Environment ("CASROOT").Value());
142 if (!aCasRoot.IsEmpty())
143 {
144 if (OSD_File (aCasRoot + "/" + THE_ACTIONS_JSON).Exists())
145 {
146 return aCasRoot + "/" + THE_ACTIONS_JSON;
147 }
148 if (OSD_File (aCasRoot + "/XRResources/" + THE_ACTIONS_JSON).Exists())
149 {
150 return aCasRoot + "/XRResources/" + THE_ACTIONS_JSON;
151 }
152 if (OSD_File (aCasRoot + "/XRResources/src/" + THE_ACTIONS_JSON).Exists())
153 {
154 return aCasRoot + "/XRResources/src/" + THE_ACTIONS_JSON;
155 }
156 }
157 return OSD_Process::ExecutablePath() + "/occtvr_actions.json";
158 }
159}
160#endif
161
162IMPLEMENT_STANDARD_RTTIEXT(Aspect_OpenVRSession, Aspect_XRSession)
163
164struct Aspect_OpenVRSession::VRContext
165{
166#ifdef HAVE_OPENVR
167 vr::TrackedDevicePose_t TrackedPoses[vr::k_unMaxTrackedDeviceCount]; //!< array of tracked devices poses
168 vr::IVRSystem* System; //!< OpenVR session object
169
170 //! Empty constructor.
171 Aspect_OpenVRSession::VRContext() : System (NULL)
172 {
173 memset (TrackedPoses, 0, sizeof(TrackedPoses));
174 }
175
176 //! IVRSystem::PollNextEvent() wrapper.
177 bool PollNextEvent (vr::VREvent_t& theEvent)
178 {
179 return System->PollNextEvent (&theEvent, sizeof(vr::VREvent_t));
180 }
181
182 //! IVRSystem::GetControllerState() wrapper.
183 bool GetControllerState (vr::VRControllerState_t& theState,
184 vr::TrackedDeviceIndex_t theDevice)
185 {
186 return System->GetControllerState (theDevice, &theState, sizeof(vr::VRControllerState_t&));
187 }
188
189 //! Retrieve string property from OpenVR.
190 TCollection_AsciiString getVrTrackedDeviceString (vr::TrackedDeviceIndex_t theDevice,
191 vr::TrackedDeviceProperty theProperty,
192 vr::TrackedPropertyError* theError = NULL)
193 {
194 const uint32_t aBuffLen = System->GetStringTrackedDeviceProperty(theDevice, theProperty, NULL, 0, theError);
195 if (aBuffLen == 0)
196 {
197 return TCollection_AsciiString();
198 }
199
200 NCollection_LocalArray<char> aBuffer (aBuffLen + 1);
201 System->GetStringTrackedDeviceProperty (theDevice, theProperty, aBuffer, aBuffLen, theError);
202 aBuffer[aBuffLen] = '\0';
203 const TCollection_AsciiString aResult (aBuffer);
204 return aResult;
205 }
206#endif
207};
208
209#ifdef HAVE_OPENVR
210//! Image wrapping vr::RenderModel_TextureMap_t.
211class Aspect_OpenVRSession::VRImagePixmap : public Image_PixMap
212{
213public:
214 //! Empty constructor.
215 VRImagePixmap() : myVrTexture (NULL) {}
216
217 //! Load the texture.
218 bool Load (vr::TextureID_t theTexture, const TCollection_AsciiString& theVrModelName)
219 {
220 vr::RenderModel_TextureMap_t* aVrTexture = NULL;
221 vr::EVRRenderModelError aVrError = vr::VRRenderModelError_Loading;
222 for (; aVrError == vr::VRRenderModelError_Loading;)
223 {
224 aVrError = vr::VRRenderModels()->LoadTexture_Async (theTexture, &aVrTexture);
225 OSD::MilliSecSleep (1);
226 }
227 if (aVrError != vr::VRRenderModelError_None
228 || aVrTexture == NULL)
229 {
a87b1b37 230 Message::SendFail (TCollection_AsciiString ("OpenVR, Unable to load render model texture: ") + theVrModelName + " - " + int(aVrError));
b40cdc2b 231 return false;
232 }
233
234 InitWrapper (Image_Format_RGBA, (Standard_Byte* )aVrTexture->rubTextureMapData, aVrTexture->unWidth, aVrTexture->unHeight);
235 myVrTexture = aVrTexture;
236 return true;
237 }
238
239 virtual ~VRImagePixmap()
240 {
241 if (myVrTexture != NULL)
242 {
243 vr::VRRenderModels()->FreeTexture (myVrTexture);
244 }
245 }
246private:
247 vr::RenderModel_TextureMap_t* myVrTexture;
248};
249
250//! Image_Texture extension using vr::VRRenderModels().
251class Aspect_OpenVRSession::VRTextureSource : public Image_Texture
252{
253public:
254
255 //! Main constructor.
256 VRTextureSource (vr::TextureID_t theTextureId, const TCollection_AsciiString& theVrModelName)
257 : Image_Texture (""), myVrTextureId (theTextureId), myVrModelName (theVrModelName)
258 {
259 myTextureId = TCollection_AsciiString ("texturevr://map_#") + (int )theTextureId;
260 }
261
262protected:
263 //! Read image.
faff3767 264 virtual Handle(Image_PixMap) ReadImage (const Handle(Image_SupportedFormats)& ) const Standard_OVERRIDE
b40cdc2b 265 {
266 Handle(VRImagePixmap) aPixmap = new VRImagePixmap();
267 if (!aPixmap->Load (myVrTextureId, myVrModelName))
268 {
269 return Handle(VRImagePixmap)();
270 }
271 return aPixmap;
272 }
273private:
274 vr::TextureID_t myVrTextureId;
275 TCollection_AsciiString myVrModelName;
276};
277#endif
278
279// =======================================================================
280// function : IsHmdPresent
281// purpose :
282// =======================================================================
283bool Aspect_OpenVRSession::IsHmdPresent()
284{
285#ifdef HAVE_OPENVR
286 return vr::VR_IsHmdPresent();
287#else
288 return false;
289#endif
290}
291
292// =======================================================================
293// function : defaultActionsManifest
294// purpose :
295// =======================================================================
296TCollection_AsciiString Aspect_OpenVRSession::defaultActionsManifest()
297{
298#ifdef HAVE_OPENVR
299 static const TCollection_AsciiString THE_ACTIONS_JSON_FULL = defaultActionsManifestInit();
300 return THE_ACTIONS_JSON_FULL;
301#else
302 return TCollection_AsciiString();
303#endif
304}
305
306// =======================================================================
307// function : Aspect_OpenVRSession
308// purpose :
309// =======================================================================
310Aspect_OpenVRSession::Aspect_OpenVRSession()
311: myContext (new VRContext())
312{
313#ifdef HAVE_OPENVR
314 myActionsManifest = defaultActionsManifest();
315 myTrackedPoses.Resize (0, (Standard_Integer )vr::k_unMaxTrackedDeviceCount - 1, false);
316 {
317 Handle(Aspect_XRActionSet) aHeadActionSet = new Aspect_XRActionSet ("/actions/generic_head");
318 myActionSets.Add (aHeadActionSet->Id(), aHeadActionSet);
319
320 Handle(Aspect_XRAction) aHeadsetOn = new Aspect_XRAction (aHeadActionSet->Id() + "/in/headset_on_head", Aspect_XRActionType_InputDigital);
321 aHeadActionSet->AddAction (aHeadsetOn);
322 NCollection_Array1<Handle(Aspect_XRAction)>& aGenericSet = myRoleActions[Aspect_XRTrackedDeviceRole_Head];
323 aGenericSet[Aspect_XRGenericAction_IsHeadsetOn] = aHeadsetOn;
324 }
325 for (int aHand = 0; aHand < 2; ++aHand)
326 {
327 NCollection_Array1<Handle(Aspect_XRAction)>& aGenericSet = myRoleActions[aHand == 0 ? Aspect_XRTrackedDeviceRole_LeftHand : Aspect_XRTrackedDeviceRole_RightHand];
328 Handle(Aspect_XRActionSet) anActionSet = new Aspect_XRActionSet (aHand == 0 ? "/actions/generic_left" : "/actions/generic_right");
329 myActionSets.Add (anActionSet->Id(), anActionSet);
330
331 Handle(Aspect_XRAction) anAppMenuClick = new Aspect_XRAction (anActionSet->Id() + "/in/appmenu_click", Aspect_XRActionType_InputDigital);
332 anActionSet->AddAction (anAppMenuClick);
333 aGenericSet[Aspect_XRGenericAction_InputAppMenu] = anAppMenuClick;
334
335 Handle(Aspect_XRAction) aSysMenuClick = new Aspect_XRAction (anActionSet->Id() + "/in/sysmenu_click", Aspect_XRActionType_InputDigital);
336 anActionSet->AddAction (aSysMenuClick);
337 aGenericSet[Aspect_XRGenericAction_InputSysMenu] = aSysMenuClick;
338
339 Handle(Aspect_XRAction) aTriggerPull = new Aspect_XRAction (anActionSet->Id() + "/in/trigger_pull", Aspect_XRActionType_InputAnalog);
340 anActionSet->AddAction (aTriggerPull);
341 aGenericSet[Aspect_XRGenericAction_InputTriggerPull] = aTriggerPull;
342
343 Handle(Aspect_XRAction) aTriggerClick = new Aspect_XRAction (anActionSet->Id() + "/in/trigger_click", Aspect_XRActionType_InputDigital);
344 anActionSet->AddAction (aTriggerClick);
345 aGenericSet[Aspect_XRGenericAction_InputTriggerClick] = aTriggerClick;
346
347 Handle(Aspect_XRAction) aGripClick = new Aspect_XRAction (anActionSet->Id() + "/in/grip_click", Aspect_XRActionType_InputDigital);
348 anActionSet->AddAction (aGripClick);
349 aGenericSet[Aspect_XRGenericAction_InputGripClick] = aGripClick;
350
351 Handle(Aspect_XRAction) aPadPos = new Aspect_XRAction (anActionSet->Id() + "/in/trackpad_position", Aspect_XRActionType_InputAnalog);
352 anActionSet->AddAction (aPadPos);
353 aGenericSet[Aspect_XRGenericAction_InputTrackPadPosition] = aPadPos;
354
355 Handle(Aspect_XRAction) aPadTouch = new Aspect_XRAction (anActionSet->Id() + "/in/trackpad_touch", Aspect_XRActionType_InputDigital);
356 anActionSet->AddAction (aPadTouch);
357 aGenericSet[Aspect_XRGenericAction_InputTrackPadTouch] = aPadTouch;
358
359 Handle(Aspect_XRAction) aPadClick = new Aspect_XRAction (anActionSet->Id() + "/in/trackpad_click", Aspect_XRActionType_InputDigital);
360 anActionSet->AddAction (aPadClick);
361 aGenericSet[Aspect_XRGenericAction_InputTrackPadClick] = aPadClick;
362
363 Handle(Aspect_XRAction) aPoseBase = new Aspect_XRAction (anActionSet->Id() + "/in/pose_base", Aspect_XRActionType_InputPose);
364 anActionSet->AddAction (aPoseBase);
365 aGenericSet[Aspect_XRGenericAction_InputPoseBase] = aPoseBase;
366
367 Handle(Aspect_XRAction) aPoseFront = new Aspect_XRAction (anActionSet->Id() + "/in/pose_front", Aspect_XRActionType_InputPose);
368 anActionSet->AddAction (aPoseFront);
369 aGenericSet[Aspect_XRGenericAction_InputPoseFront] = aPoseFront;
370
371 Handle(Aspect_XRAction) aPoseGrip = new Aspect_XRAction (anActionSet->Id() + "/in/pose_handgrip", Aspect_XRActionType_InputPose);
372 anActionSet->AddAction (aPoseGrip);
373 aGenericSet[Aspect_XRGenericAction_InputPoseHandGrip] = aPoseGrip;
374
375 Handle(Aspect_XRAction) aPoseTip = new Aspect_XRAction (anActionSet->Id() + "/in/pose_tip", Aspect_XRActionType_InputPose);
376 anActionSet->AddAction (aPoseTip);
377 aGenericSet[Aspect_XRGenericAction_InputPoseFingerTip] = aPoseTip;
378
379 Handle(Aspect_XRAction) aHaptic = new Aspect_XRAction (anActionSet->Id() + "/out/haptic", Aspect_XRActionType_OutputHaptic);
380 anActionSet->AddAction (aHaptic);
381 aGenericSet[Aspect_XRGenericAction_OutputHaptic] = aHaptic;
382
383 Handle(Aspect_XRAction) aThumbsctickPos = new Aspect_XRAction (anActionSet->Id() + "/in/thumbstick_position", Aspect_XRActionType_InputAnalog);
384 anActionSet->AddAction (aThumbsctickPos);
385 aGenericSet[Aspect_XRGenericAction_InputThumbstickPosition] = aThumbsctickPos;
386
387 Handle(Aspect_XRAction) aThumbsctickTouch = new Aspect_XRAction (anActionSet->Id() + "/in/thumbstick_touch", Aspect_XRActionType_InputDigital);
388 anActionSet->AddAction (aThumbsctickTouch);
389 aGenericSet[Aspect_XRGenericAction_InputThumbstickTouch] = aThumbsctickTouch;
390
391 Handle(Aspect_XRAction) aThumbsctickClick = new Aspect_XRAction (anActionSet->Id() + "/in/thumbstick_click", Aspect_XRActionType_InputDigital);
392 anActionSet->AddAction (aThumbsctickClick);
393 aGenericSet[Aspect_XRGenericAction_InputThumbstickClick] = aThumbsctickClick;
394 }
395#endif
396}
397
398// =======================================================================
399// function : ~Aspect_OpenVRSession
400// purpose :
401// =======================================================================
402Aspect_OpenVRSession::~Aspect_OpenVRSession()
403{
404 closeVR();
405 delete myContext;
406}
407
408// =======================================================================
409// function : closeVR
410// purpose :
411// =======================================================================
412void Aspect_OpenVRSession::closeVR()
413{
414#ifdef HAVE_OPENVR
415 if (myContext->System != NULL)
416 {
417 vr::VR_Shutdown();
418 myContext->System = NULL;
419 }
420#endif
421}
422
423// =======================================================================
424// function : getVRSystem
425// purpose :
426// =======================================================================
427void* Aspect_OpenVRSession::getVRSystem() const
428{
429#ifdef HAVE_OPENVR
430 return myContext->System;
431#else
432 return NULL;
433#endif
434}
435
436// =======================================================================
437// function : Close
438// purpose :
439// =======================================================================
440void Aspect_OpenVRSession::Close()
441{
442 closeVR();
443}
444
445// =======================================================================
446// function : IsOpen
447// purpose :
448// =======================================================================
449bool Aspect_OpenVRSession::IsOpen() const
450{
451#ifdef HAVE_OPENVR
452 return myContext->System != NULL;
453#else
454 return false;
455#endif
456}
457
458// =======================================================================
459// function : Open
460// purpose :
461// =======================================================================
462bool Aspect_OpenVRSession::Open()
463{
464#ifdef HAVE_OPENVR
465 if (myContext->System != NULL)
466 {
467 return true;
468 }
469
470 vr::EVRInitError aVrError = vr::VRInitError_None;
471 myContext->System = vr::VR_Init (&aVrError, vr::VRApplication_Scene);
472 if (aVrError != vr::VRInitError_None)
473 {
474 myContext->System = NULL;
a87b1b37 475 Message::SendFail (TCollection_AsciiString ("OpenVR, Unable to init VR runtime: ") + vr::VR_GetVRInitErrorAsEnglishDescription (aVrError));
b40cdc2b 476 Close();
477 return false;
478 }
479
480 /*vr::IVRRenderModels* aRenderModels = (vr::IVRRenderModels* )vr::VR_GetGenericInterface (vr::IVRRenderModels_Version, &aVrError);
481 if (aRenderModels == NULL)
482 {
a87b1b37 483 Message::SendFail (TCollection_AsciiString ("Unable to get render model interface: ") + vr::VR_GetVRInitErrorAsEnglishDescription (aVrError));;
b40cdc2b 484 }*/
485
486 NCollection_Vec2<uint32_t> aRenderSize;
487 myContext->System->GetRecommendedRenderTargetSize (&aRenderSize.x(), &aRenderSize.y());
488 myRendSize = NCollection_Vec2<int> (aRenderSize);
489 myDispFreq = myContext->System->GetFloatTrackedDeviceProperty (vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_DisplayFrequency_Float);
490 if (myRendSize.x() <= 0
491 || myRendSize.y() <= 0)
492 {
493 Close();
494 return false;
495 }
496 updateProjectionFrustums();
497 initInput();
498 return true;
499#else
a87b1b37 500 Message::SendFail ("Open CASCADE has been built without OpenVR support");
b40cdc2b 501 return false;
502#endif
503}
504
505// =======================================================================
506// function : initInput
507// purpose :
508// =======================================================================
509bool Aspect_OpenVRSession::initInput()
510{
511#ifdef HAVE_OPENVR
512 if (myContext->System == NULL)
513 {
514 return false;
515 }
516
517 if (!OSD_File (myActionsManifest).Exists())
518 {
a87b1b37 519 Message::SendFail (TCollection_AsciiString ("OpenVR, Unable to open actions manifest '") + myActionsManifest + "'");
b40cdc2b 520 return false;
521 }
522
523 vr::EVRInputError aVrError = vr::VRInput()->SetActionManifestPath (myActionsManifest.ToCString());
524 if (aVrError != vr::VRInputError_None)
525 {
a87b1b37 526 Message::SendFail (TCollection_AsciiString ("OpenVR, Unable to load actions manifest '") + myActionsManifest
527 + "': " + getVRInputError (aVrError));
b40cdc2b 528 return false;
529 }
530
531 bool hasErrors = false;
532 for (Aspect_XRActionSetMap::Iterator aSetIter (myActionSets); aSetIter.More(); aSetIter.Next())
533 {
534 const Handle(Aspect_XRActionSet)& anActionSet = aSetIter.Value();
535 for (Aspect_XRActionMap::Iterator anActionIter (anActionSet->Actions()); anActionIter.More(); anActionIter.Next())
536 {
537 const Handle(Aspect_XRAction)& anAction = anActionIter.Value();
538 vr::VRActionHandle_t anActionHandle = 0;
539 aVrError = vr::VRInput()->GetActionHandle (anAction->Id().ToCString(), &anActionHandle);
540 if (aVrError == vr::VRInputError_None)
541 {
542 anAction->SetRawHandle (anActionHandle);
543 }
544 else
545 {
546 hasErrors = true;
a87b1b37 547 Message::SendFail (TCollection_AsciiString ("OpenVR, Unable to load action '") + anAction->Id() + "' from '" + myActionsManifest
548 + "': " + getVRInputError (aVrError));
b40cdc2b 549 }
550 }
551
552 vr::VRActionSetHandle_t anActionSetHandle = 0;
553 aVrError = vr::VRInput()->GetActionSetHandle (anActionSet->Id().ToCString(), &anActionSetHandle);
554 if (aVrError == vr::VRInputError_None)
555 {
556 anActionSet->SetRawHandle (anActionSetHandle);
557 }
558 else
559 {
560 hasErrors = true;
a87b1b37 561 Message::SendFail (TCollection_AsciiString ("OpenVR, Unable to load action set '") + anActionSet->Id() + "' from '" + myActionsManifest
562 + "': " + getVRInputError (aVrError));
b40cdc2b 563 }
564 }
565 return !hasErrors;
566#else
567 return false;
568#endif
569}
570
571// =======================================================================
572// function : GetString
573// purpose :
574// =======================================================================
575TCollection_AsciiString Aspect_OpenVRSession::GetString (InfoString theInfo) const
576{
577#ifdef HAVE_OPENVR
578 if (myContext->System != NULL)
579 {
580 vr::ETrackedDeviceProperty aVrProp = vr::Prop_Invalid;
581 switch (theInfo)
582 {
583 case InfoString_Vendor: aVrProp = vr::Prop_ManufacturerName_String; break;
584 case InfoString_Device: aVrProp = vr::Prop_ModelNumber_String; break;
585 case InfoString_Tracker: aVrProp = vr::Prop_TrackingSystemName_String; break;
586 case InfoString_SerialNumber: aVrProp = vr::Prop_SerialNumber_String; break;
587 }
588 if (aVrProp != vr::Prop_Invalid)
589 {
590 return myContext->getVrTrackedDeviceString (vr::k_unTrackedDeviceIndex_Hmd, aVrProp);
591 }
592 }
593#else
594 (void )theInfo;
595#endif
596 return TCollection_AsciiString();
597}
598
599// =======================================================================
600// function : NamedTrackedDevice
601// purpose :
602// =======================================================================
603Standard_Integer Aspect_OpenVRSession::NamedTrackedDevice (Aspect_XRTrackedDeviceRole theDevice) const
604{
605#ifdef HAVE_OPENVR
606 if (myContext->System != NULL)
607 {
608 vr::TrackedDeviceIndex_t aDevIndex = vr::k_unTrackedDeviceIndexInvalid;
609 switch (theDevice)
610 {
611 case Aspect_XRTrackedDeviceRole_Head: aDevIndex = vr::k_unTrackedDeviceIndex_Hmd; break;
612 case Aspect_XRTrackedDeviceRole_LeftHand: aDevIndex = myContext->System->GetTrackedDeviceIndexForControllerRole (vr::TrackedControllerRole_LeftHand); break;
613 case Aspect_XRTrackedDeviceRole_RightHand: aDevIndex = myContext->System->GetTrackedDeviceIndexForControllerRole (vr::TrackedControllerRole_RightHand); break;
614 case Aspect_XRTrackedDeviceRole_Other: break;
615 }
616 if (aDevIndex == vr::k_unTrackedDeviceIndexInvalid)
617 {
618 return -1;
619 }
620 return (Standard_Integer )aDevIndex;
621 }
622#else
623 (void )theDevice;
624#endif
625 return -1;
626}
627
628// =======================================================================
629// function : loadRenderModel
630// purpose :
631// =======================================================================
632Handle(Graphic3d_ArrayOfTriangles) Aspect_OpenVRSession::loadRenderModel (Standard_Integer theDevice,
633 Standard_Boolean theToApplyUnitFactor,
634 Handle(Image_Texture)& theTexture)
635{
636 if (theDevice < 0)
637 {
638 return Handle(Graphic3d_ArrayOfTriangles)();
639 }
640#ifdef HAVE_OPENVR
641 if (myContext->System == NULL)
642 {
643 return Handle(Graphic3d_ArrayOfTriangles)();
644 }
645
646 const TCollection_AsciiString aRenderModelName = myContext->getVrTrackedDeviceString (theDevice, vr::Prop_RenderModelName_String);
647 if (aRenderModelName.IsEmpty())
648 {
649 return Handle(Graphic3d_ArrayOfTriangles)();
650 }
651
652 vr::RenderModel_t* aVrModel = NULL;
653 vr::EVRRenderModelError aVrError = vr::VRRenderModelError_Loading;
654 for (; aVrError == vr::VRRenderModelError_Loading;)
655 {
656 aVrError = vr::VRRenderModels()->LoadRenderModel_Async (aRenderModelName.ToCString(), &aVrModel);
657 OSD::MilliSecSleep (1);
658 }
659 if (aVrError != vr::VRRenderModelError_None)
660 {
a87b1b37 661 Message::SendFail (TCollection_AsciiString ("OpenVR, Unable to load render model: ") + aRenderModelName + " - " + int(aVrError));
b40cdc2b 662 return Handle(Graphic3d_ArrayOfTriangles)();
663 }
664
665 if (aVrModel->diffuseTextureId >= 0)
666 {
667 theTexture = new VRTextureSource (aVrModel->diffuseTextureId, aRenderModelName);
668 }
669
670 const float aScale = theToApplyUnitFactor ? float(myUnitFactor) : 1.0f;
671 Handle(Graphic3d_ArrayOfTriangles) aTris = new Graphic3d_ArrayOfTriangles ((int )aVrModel->unVertexCount, (int )aVrModel->unTriangleCount * 3,
672 Graphic3d_ArrayFlags_VertexNormal | Graphic3d_ArrayFlags_VertexTexel);
673 for (uint32_t aVertIter = 0; aVertIter < aVrModel->unVertexCount; ++aVertIter)
674 {
675 const vr::RenderModel_Vertex_t& aVert = aVrModel->rVertexData[aVertIter];
676 aTris->AddVertex (aVert.vPosition.v[0] * aScale, aVert.vPosition.v[1] * aScale, aVert.vPosition.v[2] * aScale,
677 aVert.vNormal.v[0], aVert.vNormal.v[1], aVert.vNormal.v[2],
678 aVert.rfTextureCoord[0], aVert.rfTextureCoord[1]);
679 }
680 for (uint32_t aTriIter = 0; aTriIter < aVrModel->unTriangleCount; ++aTriIter)
681 {
682 aTris->AddEdges (aVrModel->rIndexData[aTriIter * 3 + 0] + 1,
683 aVrModel->rIndexData[aTriIter * 3 + 1] + 1,
684 aVrModel->rIndexData[aTriIter * 3 + 2] + 1);
685 }
686
687 vr::VRRenderModels()->FreeRenderModel (aVrModel);
688 return aTris;
689#else
690 (void )theToApplyUnitFactor;
691 (void )theTexture;
692 return Handle(Graphic3d_ArrayOfTriangles)();
693#endif
694}
695
696// =======================================================================
697// function : EyeToHeadTransform
698// purpose :
699// =======================================================================
700NCollection_Mat4<double> Aspect_OpenVRSession::EyeToHeadTransform (Aspect_Eye theEye) const
701{
702#ifdef HAVE_OPENVR
703 if (myContext->System != NULL)
704 {
705 const vr::HmdMatrix34_t aMatVr = myContext->System->GetEyeToHeadTransform (theEye == Aspect_Eye_Right ? vr::Eye_Right : vr::Eye_Left);
706 gp_Trsf aTrsf = mat34vr2OccTrsf (aMatVr);
707 if (myUnitFactor != 1.0)
708 {
709 aTrsf.SetTranslationPart (aTrsf.TranslationPart() * myUnitFactor);
710 }
711 NCollection_Mat4<double> aMat4;
712 aTrsf.GetMat4 (aMat4);
713 return aMat4;
714 }
715#else
716 (void )theEye;
717#endif
718 return NCollection_Mat4<double>();
719}
720
721// =======================================================================
722// function : ProjectionMatrix
723// purpose :
724// =======================================================================
725NCollection_Mat4<double> Aspect_OpenVRSession::ProjectionMatrix (Aspect_Eye theEye,
726 double theZNear,
727 double theZFar) const
728{
729#ifdef HAVE_OPENVR
730 if (myContext->System != NULL)
731 {
732 const vr::HmdMatrix44_t aMat4 = myContext->System->GetProjectionMatrix (theEye == Aspect_Eye_Right ? vr::Eye_Right : vr::Eye_Left,
733 (float )theZNear, (float )theZFar);
734 return mat44vr2Occ (aMat4);
735 }
736#else
737 (void )theEye;
738 (void )theZNear;
739 (void )theZFar;
740#endif
741 return NCollection_Mat4<double>();
742}
743
744// =======================================================================
745// function : updateProjectionFrustums
746// purpose :
747// =======================================================================
748void Aspect_OpenVRSession::updateProjectionFrustums()
749{
750#ifdef HAVE_OPENVR
751 Aspect_FrustumLRBT<float> aFrustL, aFrustR;
752 myContext->System->GetProjectionRaw (vr::Eye_Left, &aFrustL.Left, &aFrustL.Right, &aFrustL.Top, &aFrustL.Bottom);
753 myContext->System->GetProjectionRaw (vr::Eye_Right, &aFrustR.Left, &aFrustR.Right, &aFrustR.Top, &aFrustR.Bottom);
754 myFrustumL = Aspect_FrustumLRBT<double> (aFrustL);
755 myFrustumR = Aspect_FrustumLRBT<double> (aFrustR);
756 std::swap (myFrustumL.Top, myFrustumL.Bottom);
757 std::swap (myFrustumR.Top, myFrustumR.Bottom);
758
759 const NCollection_Vec2<double> aTanHalfFov (NCollection_Vec4<float>(-aFrustL.Left, aFrustL.Right, -aFrustR.Left, aFrustR.Right).maxComp(),
760 NCollection_Vec4<float>(-aFrustL.Top, aFrustL.Bottom, -aFrustR.Top, aFrustR.Bottom).maxComp());
761 myAspect = aTanHalfFov.x() / aTanHalfFov.y();
762 myFieldOfView = 2.0 * ATan(aTanHalfFov.y()) * 180.0 / M_PI;
763
764 // Intra-ocular Distance can be changed in runtime
765 //const vr::HmdMatrix34_t aLeftToHead = myContext->System->GetEyeToHeadTransform (vr::Eye_Left);
766 //const vr::HmdMatrix34_t aRightToHead = myContext->System->GetEyeToHeadTransform (vr::Eye_Right);
767 //myIod = aRightToHead.m[0][3] - aLeftToHead.m[0][3];
768 myIod = myContext->System->GetFloatTrackedDeviceProperty (vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_UserIpdMeters_Float);
769 myIod *= myUnitFactor;
770#endif
771}
772
773// =======================================================================
774// function : SetTrackingOrigin
775// purpose :
776// =======================================================================
777void Aspect_OpenVRSession::SetTrackingOrigin (TrackingUniverseOrigin theOrigin)
778{
779#ifdef HAVE_OPENVR
780 if (myContext->System != NULL)
781 {
782 vr::ETrackingUniverseOrigin anOrigin = vr::TrackingUniverseStanding;
783 switch (theOrigin)
784 {
785 case TrackingUniverseOrigin_Seated: anOrigin = vr::TrackingUniverseSeated; break;
786 case TrackingUniverseOrigin_Standing: anOrigin = vr::TrackingUniverseStanding; break;
787 }
788 vr::VRCompositor()->SetTrackingSpace (anOrigin);
789 }
790#endif
791 myTrackOrigin = theOrigin;
792}
793
794// =======================================================================
795// function : WaitPoses
796// purpose :
797// =======================================================================
798bool Aspect_OpenVRSession::WaitPoses()
799{
800#ifdef HAVE_OPENVR
801 if (myContext->System == NULL)
802 {
803 return false;
804 }
805
806 switch (vr::VRCompositor()->GetTrackingSpace())
807 {
808 case vr::TrackingUniverseSeated:
809 myTrackOrigin = TrackingUniverseOrigin_Seated;
810 break;
811 case vr::TrackingUniverseRawAndUncalibrated:
812 case vr::TrackingUniverseStanding:
813 myTrackOrigin = TrackingUniverseOrigin_Standing;
814 break;
815 }
816
817 const vr::EVRCompositorError aVRError = vr::VRCompositor()->WaitGetPoses (myContext->TrackedPoses, vr::k_unMaxTrackedDeviceCount, NULL, 0);
818 if (aVRError != vr::VRCompositorError_None)
819 {
a87b1b37 820 Message::SendTrace (TCollection_AsciiString ("Compositor wait poses error: ") + getVRCompositorError (aVRError));
b40cdc2b 821 }
822
823 for (Standard_Integer aPoseIter = myTrackedPoses.Lower(); aPoseIter <= myTrackedPoses.Upper(); ++aPoseIter)
824 {
825 const vr::TrackedDevicePose_t& aVrPose = myContext->TrackedPoses[aPoseIter];
826 myTrackedPoses[aPoseIter] = poseVr2Occ (aVrPose, myUnitFactor);
827 }
828
829 if (myContext->TrackedPoses[vr::k_unTrackedDeviceIndex_Hmd].bPoseIsValid)
830 {
831 myHeadPose = myTrackedPoses[vr::k_unTrackedDeviceIndex_Hmd].Orientation;
832 updateProjectionFrustums();
833 }
834 return aVRError != vr::VRCompositorError_None;
835#else
836 return false;
837#endif
838}
839
840// =======================================================================
841// function : GetDigitalActionData
842// purpose :
843// =======================================================================
844Aspect_XRDigitalActionData Aspect_OpenVRSession::GetDigitalActionData (const Handle(Aspect_XRAction)& theAction) const
845{
846 if (theAction.IsNull()
847 || theAction->Type() != Aspect_XRActionType_InputDigital)
848 {
849 throw Standard_ProgramError("Aspect_OpenVRSession::GetDigitalActionData() called for wrong action");
850 }
851
852 Aspect_XRDigitalActionData anActionData;
853#ifdef HAVE_OPENVR
854 if (myContext->System != NULL
855 && theAction->RawHandle() != 0)
856 {
857 vr::InputDigitalActionData_t aNewData = {};
858 vr::EVRInputError anInErr = vr::VRInput()->GetDigitalActionData (theAction->RawHandle(), &aNewData, sizeof(aNewData), vr::k_ulInvalidInputValueHandle);
859 if (anInErr != vr::VRInputError_None)
860 {
a87b1b37 861 Message::SendFail (TCollection_AsciiString ("Input Error on '") + theAction->Id() + "': " + getVRInputError (anInErr));
b40cdc2b 862 return anActionData;
863 }
864
865 anActionData.IsActive = aNewData.bActive;
866 anActionData.IsChanged = aNewData.bChanged;
867 anActionData.IsPressed = aNewData.bState;
868 anActionData.UpdateTime = aNewData.fUpdateTime;
869 anActionData.ActiveOrigin = aNewData.activeOrigin;
870 }
871#endif
872 return anActionData;
873}
874
875// =======================================================================
876// function : GetAnalogActionData
877// purpose :
878// =======================================================================
879Aspect_XRAnalogActionData Aspect_OpenVRSession::GetAnalogActionData (const Handle(Aspect_XRAction)& theAction) const
880{
881 if (theAction.IsNull()
882 || theAction->Type() != Aspect_XRActionType_InputAnalog)
883 {
884 throw Standard_ProgramError("Aspect_OpenVRSession::GetAnalogActionData() called for wrong action");
885 }
886
887 Aspect_XRAnalogActionData anActionData;
888#ifdef HAVE_OPENVR
889 if (myContext->System != NULL
890 && theAction->RawHandle() != 0)
891 {
892 vr::InputAnalogActionData_t aNewData = {};
893 vr::EVRInputError anInErr = vr::VRInput()->GetAnalogActionData (theAction->RawHandle(), &aNewData, sizeof(aNewData), vr::k_ulInvalidInputValueHandle);
894 if (anInErr != vr::VRInputError_None)
895 {
a87b1b37 896 Message::SendFail (TCollection_AsciiString ("Input Error on '") + theAction->Id() + "': " + getVRInputError (anInErr));
b40cdc2b 897 return anActionData;
898 }
899
900 anActionData.IsActive = aNewData.bActive;
901 anActionData.VecXYZ.SetValues (aNewData.x, aNewData.y, aNewData.z);
902 anActionData.DeltaXYZ.SetValues (aNewData.deltaX, aNewData.deltaY, aNewData.deltaZ);
903 anActionData.UpdateTime = aNewData.fUpdateTime;
904 anActionData.ActiveOrigin = aNewData.activeOrigin;
905 }
906#endif
907 return anActionData;
908}
909
910// =======================================================================
911// function : GetPoseActionDataForNextFrame
912// purpose :
913// =======================================================================
914Aspect_XRPoseActionData Aspect_OpenVRSession::GetPoseActionDataForNextFrame (const Handle(Aspect_XRAction)& theAction) const
915{
916 if (theAction.IsNull()
917 || theAction->Type() != Aspect_XRActionType_InputPose)
918 {
919 throw Standard_ProgramError("Aspect_OpenVRSession::GetPoseActionDataForNextFrame() called for wrong action");
920 }
921
922 Aspect_XRPoseActionData anActionData;
923#ifdef HAVE_OPENVR
924 if (myContext->System != NULL
925 && theAction->RawHandle() != 0)
926 {
927 vr::ETrackingUniverseOrigin anOrigin = vr::TrackingUniverseSeated;
928 switch (myTrackOrigin)
929 {
930 case TrackingUniverseOrigin_Seated: anOrigin = vr::TrackingUniverseSeated; break;
931 case TrackingUniverseOrigin_Standing: anOrigin = vr::TrackingUniverseStanding; break;
932 }
933 vr::InputPoseActionData_t aNewData = {};
934 vr::EVRInputError anInErr = vr::VRInput()->GetPoseActionDataForNextFrame (theAction->RawHandle(), anOrigin, &aNewData, sizeof(aNewData), vr::k_ulInvalidInputValueHandle);
935 if (anInErr != vr::VRInputError_None)
936 {
a87b1b37 937 Message::SendFail (TCollection_AsciiString ("Input Error on '") + theAction->Id() + "': " + getVRInputError (anInErr));
b40cdc2b 938 return anActionData;
939 }
940
941 anActionData.Pose = poseVr2Occ (aNewData.pose, myUnitFactor);
942 anActionData.IsActive = aNewData.bActive;
943 anActionData.ActiveOrigin = aNewData.activeOrigin;
944 }
945#endif
946 return anActionData;
947}
948
949// =======================================================================
950// function : triggerHapticVibrationAction
951// purpose :
952// =======================================================================
953void Aspect_OpenVRSession::triggerHapticVibrationAction (const Handle(Aspect_XRAction)& theAction,
954 const Aspect_XRHapticActionData& theParams)
955{
956 if (theAction.IsNull()
957 || theAction->Type() != Aspect_XRActionType_OutputHaptic)
958 {
959 throw Standard_ProgramError("Aspect_OpenVRSession::triggerHapticVibrationAction() called for wrong action");
960 }
961
962#ifdef HAVE_OPENVR
963 if (myContext->System != NULL
964 && theAction->RawHandle() != 0)
965 {
966 Aspect_XRHapticActionData aParams = theParams;
967 if (!theParams.IsValid())
968 {
969 // preset for aborting
970 aParams.Duration = 0.0f;
971 aParams.Frequency = 1.0f;
972 aParams.Amplitude = 0.1f;
973 }
974 vr::EVRInputError anInErr = vr::VRInput()->TriggerHapticVibrationAction (theAction->RawHandle(),
975 aParams.Delay, aParams.Duration, aParams.Frequency, aParams.Amplitude,
976 vr::k_ulInvalidInputValueHandle);
977 if (anInErr != vr::VRInputError_None)
978 {
a87b1b37 979 Message::SendFail (TCollection_AsciiString ("Output Error on '") + theAction->Id() + "': " + getVRInputError (anInErr));
b40cdc2b 980 }
981 }
982#else
983 (void )theParams;
984#endif
985}
986
987// =======================================================================
988// function : ProcessEvents
989// purpose :
990// =======================================================================
991void Aspect_OpenVRSession::ProcessEvents()
992{
993#ifdef HAVE_OPENVR
994 if (myContext->System == NULL)
995 {
996 return;
997 }
998
999 // process OpenVR events
1000 vr::VREvent_t aVREvent = {};
1001 for (; myContext->PollNextEvent (aVREvent);)
1002 {
1003 switch (aVREvent.eventType)
1004 {
1005 case vr::VREvent_TrackedDeviceActivated: onTrackedDeviceActivated ((int )aVREvent.trackedDeviceIndex); break;
1006 case vr::VREvent_TrackedDeviceDeactivated: onTrackedDeviceDeactivated((int )aVREvent.trackedDeviceIndex); break;
1007 case vr::VREvent_TrackedDeviceUpdated: onTrackedDeviceUpdated ((int )aVREvent.trackedDeviceIndex); break;
1008 }
1009 }
1010
1011 // process OpenVR action state
1012 if (myActionSets.Extent() > 0)
1013 {
1014 NCollection_LocalArray<vr::VRActiveActionSet_t, 8> anActionSets (myActionSets.Extent());
1015 memset (anActionSets, 0, sizeof(vr::VRActiveActionSet_t) * myActionSets.Extent());
1016 for (Standard_Integer aSetIter = 0; aSetIter < myActionSets.Extent(); ++aSetIter)
1017 {
1018 anActionSets[aSetIter].ulActionSet = myActionSets.FindFromIndex (aSetIter + 1)->RawHandle();
1019 }
1020 vr::VRInput()->UpdateActionState (anActionSets, sizeof(vr::VRActiveActionSet_t), myActionSets.Extent());
1021 }
1022
1023 WaitPoses();
1024
1025 for (Aspect_XRActionSetMap::Iterator aSetIter (myActionSets); aSetIter.More(); aSetIter.Next())
1026 {
1027 const Handle(Aspect_XRActionSet)& anActionSet = aSetIter.Value();
1028 for (Aspect_XRActionMap::Iterator anActionIter (anActionSet->Actions()); anActionIter.More(); anActionIter.Next())
1029 {
1030 const Handle(Aspect_XRAction)& anAction = anActionIter.Value();
1031 if (anAction->RawHandle() == 0
1032 || anAction->Id().IsEmpty())
1033 {
1034 continue;
1035 }
1036
1037 switch (anAction->Type())
1038 {
1039 case Aspect_XRActionType_InputDigital:
1040 {
1041 Aspect_XRDigitalActionData aData = GetDigitalActionData (anAction);
1042 //if (aData.IsChanged) { std::cout << " " << anAction->Id() << " pressed: " << aData.IsPressed << "\n"; }
1043 break;
1044 }
1045 case Aspect_XRActionType_InputAnalog:
1046 {
1047 Aspect_XRAnalogActionData aData = GetAnalogActionData (anAction);
1048 //if (aData.IsChanged()) { std::cout << " " << anAction->Id() << " changed: " << aData.VecXYZ[0] << " " << aData.VecXYZ[1] << " " << aData.VecXYZ[2] << "\n"; }
1049 break;
1050 }
1051 case Aspect_XRActionType_InputPose:
1052 {
1053 GetPoseActionDataForNextFrame (anAction);
1054 break;
1055 }
1056 }
1057 }
1058 }
1059
1060 // process OpenVR controller state using deprecated API
1061 //for (vr::TrackedDeviceIndex_t aDevIter = 0; aDevIter < vr::k_unMaxTrackedDeviceCount; ++aDevIter) {
1062 // vr::VRControllerState_t aCtrlState = {}; if (myContext->GetControllerState (aCtrlState, aDevIter)) { aCtrlState.ulButtonPressed == 0; }
1063 //}
1064#endif
1065}
1066
1067// =======================================================================
1068// function : onTrackedDeviceActivated
1069// purpose :
1070// =======================================================================
1071void Aspect_OpenVRSession::onTrackedDeviceActivated (Standard_Integer theDeviceIndex)
1072{
a87b1b37 1073 Message::SendTrace (TCollection_AsciiString ("OpenVR, Device ") + theDeviceIndex + " attached");
b40cdc2b 1074}
1075
1076// =======================================================================
1077// function : onTrackedDeviceDeactivated
1078// purpose :
1079// =======================================================================
1080void Aspect_OpenVRSession::onTrackedDeviceDeactivated (Standard_Integer theDeviceIndex)
1081{
a87b1b37 1082 Message::SendTrace (TCollection_AsciiString ("OpenVR, Device ") + theDeviceIndex + " detached");
b40cdc2b 1083}
1084
1085// =======================================================================
1086// function : onTrackedDeviceUpdated
1087// purpose :
1088// =======================================================================
1089void Aspect_OpenVRSession::onTrackedDeviceUpdated (Standard_Integer theDeviceIndex)
1090{
a87b1b37 1091 Message::SendTrace (TCollection_AsciiString ("OpenVR, Device ") + theDeviceIndex + " updated");
b40cdc2b 1092}
1093
1094// =======================================================================
1095// function : SubmitEye
1096// purpose :
1097// =======================================================================
1098bool Aspect_OpenVRSession::SubmitEye (void* theTexture,
1099 Aspect_GraphicsLibrary theGraphicsLib,
1100 Aspect_ColorSpace theColorSpace,
1101 Aspect_Eye theEye)
1102{
1103 if (theTexture == NULL)
1104 {
1105 return false;
1106 }
1107#ifdef HAVE_OPENVR
1108 if (myContext->System == NULL)
1109 {
1110 return false;
1111 }
1112
1113 vr::Texture_t aVRTexture = { (void* )theTexture, vr::TextureType_OpenGL, vr::ColorSpace_Gamma };
1114 switch (theGraphicsLib)
1115 {
1116 case Aspect_GraphicsLibrary_OpenGL:
1117 aVRTexture.eType = vr::TextureType_OpenGL;
1118 break;
1119 default:
a87b1b37 1120 Message::SendFail ("Compositor error: unsupported Graphics API");
b40cdc2b 1121 return false;
1122 }
1123 switch (theColorSpace)
1124 {
1125 case Aspect_ColorSpace_sRGB: aVRTexture.eColorSpace = vr::ColorSpace_Gamma; break;
1126 case Aspect_ColorSpace_Linear: aVRTexture.eColorSpace = vr::ColorSpace_Linear; break;
1127 }
1128
1129 const vr::EVRCompositorError aVRError = vr::VRCompositor()->Submit (theEye == Aspect_Eye_Right ? vr::Eye_Right : vr::Eye_Left, &aVRTexture);
1130 if (aVRError != vr::VRCompositorError_None)
1131 {
1132 if (aVRError != vr::VRCompositorError_AlreadySubmitted)
1133 {
a87b1b37 1134 Message::SendFail (TCollection_AsciiString ("Compositor Error: ") + getVRCompositorError (aVRError));
b40cdc2b 1135 }
1136 else
1137 {
a87b1b37 1138 Message::SendTrace (TCollection_AsciiString ("Compositor Error: ") + getVRCompositorError (aVRError));
b40cdc2b 1139 }
1140 return false;
1141 }
1142 return true;
1143#else
1144 (void )theGraphicsLib;
1145 (void )theColorSpace;
1146 (void )theEye;
1147 return false;
1148#endif
1149}