19 #define _USE_MATH_DEFINES
44 #include <unordered_map>
45 #include <OVR_CAPI_Util.h>
50 #pragma comment(lib, "dxgi.lib")
57 #define GLFW_EXPOSE_NATIVE_WIN32
58 #define GLFW_EXPOSE_NATIVE_WGL
60 #elif defined(__APPLE__)
61 #define GLFW_EXPOSE_NATIVE_COCOA
62 #define GLFW_EXPOSE_NATIVE_NSGL
64 #elif defined(__linux__)
65 #define GLFW_EXPOSE_NATIVE_X11
66 #define GLFW_EXPOSE_NATIVE_GLX
69 #include <GLFW/glfw3.h>
70 #include <GLFW/glfw3native.h>
72 #include <OVR_System.h>
73 #include <OVR_CAPI_GL.h>
112 float yaw, pitch, roll;
115 rot.GetEulerAngles<OVR::Axis_Y, OVR::Axis_X, OVR::Axis_Z>(&yaw, &pitch, &roll);
116 v[0] = -roll; v[1] = -pitch; v[2] = yaw;
130 inline ovrVector3f
vecSubtract(
const ovrVector3f& a,
const ovrVector3f& b)
139 static inline void debugTangent(std::string message,
float tangent1,
float tangent2)
142 (message +
" %10f (%5f[rad] = %5f[deg]) %10f (%5f[rad] = %5f[deg])\n").c_str(),
145 OVR::RadToDegree(atan(tangent1)),
148 OVR::RadToDegree(atan(tangent2)));
152 " Left Eye Right Eye\n");
153 debugTangent(
"LeftTan", fov[0].LeftTan , fov[0].LeftTan);
154 debugTangent(
"RightTan", fov[0].RightTan, fov[0].RightTan);
156 debugTangent(
"DownTan", fov[0].DownTan , fov[0].DownTan );
162 static int compareLuid(
const ovrGraphicsLuid& lhs,
const ovrGraphicsLuid& rhs)
164 return memcmp(&lhs, &rhs,
sizeof(ovrGraphicsLuid));
169 ovrGraphicsLuid luid = ovrGraphicsLuid();
172 IDXGIFactory* factory =
nullptr;
174 if (SUCCEEDED(CreateDXGIFactory(IID_PPV_ARGS(&factory))))
176 IDXGIAdapter* adapter =
nullptr;
178 if (SUCCEEDED(factory->EnumAdapters(0, &adapter)))
180 DXGI_ADAPTER_DESC desc;
182 adapter->GetDesc(&desc);
183 memcpy(&luid, &desc.AdapterLuid,
sizeof(luid));
208 inline OVR::Vector3f
radToDeg(
const OVR::Vector3f& v)
212 ret.x = OVR::RadToDegree(v.x);
213 ret.y = OVR::RadToDegree(v.y);
214 ret.z = OVR::RadToDegree(v.z);
220 const float x,
const float y,
const float z,
221 const float rx,
const float ry,
const float rz,
float rw,
222 const float sizeX,
const float sizeY)
224 layer.Header.Type = ovrLayerType_Quad;
225 layer.Header.Flags = ovrLayerFlag_HeadLocked;
227 layer.QuadPoseCenter.Position.x = x;
228 layer.QuadPoseCenter.Position.y = y;
229 layer.QuadPoseCenter.Position.z = z;
230 layer.QuadPoseCenter.Orientation.x = rx;
231 layer.QuadPoseCenter.Orientation.y = ry;
232 layer.QuadPoseCenter.Orientation.z = rz;
233 layer.QuadPoseCenter.Orientation.w = rw;
234 layer.QuadSize.x = sizeX;
235 layer.QuadSize.y = sizeY;
237 layer.Viewport = OVR::Recti(0, 0, tex->
width, tex->
height);
241 const float x,
const float y,
const float z,
242 const float rx,
const float ry,
const float rz,
float rw,
243 const float sizeX,
const float sizeY)
245 layer.Header.Type = ovrLayerType_Quad;
246 layer.Header.Flags = ovrLayerFlag_HeadLocked;
248 layer.QuadPoseCenter.Position.x = x;
249 layer.QuadPoseCenter.Position.y = y;
250 layer.QuadPoseCenter.Position.z = z;
251 layer.QuadPoseCenter.Orientation.x = rx;
252 layer.QuadPoseCenter.Orientation.y = ry;
253 layer.QuadPoseCenter.Orientation.z = rz;
254 layer.QuadPoseCenter.Orientation.w = rw;
255 layer.QuadSize.x = sizeX;
256 layer.QuadSize.y = sizeY;
258 layer.Viewport = OVR::Recti(0, 0, tex->
width, tex->
height);
274 void yarp::dev::OVRHeadset::fillAxisStorage()
276 axisIdToValue.push_back(inputState.IndexTrigger);
277 axisIdToValue.push_back(inputState.IndexTrigger + 1);
278 axisIdToValue.push_back(inputState.HandTrigger);
279 axisIdToValue.push_back(inputState.HandTrigger + 1 );
283 axisIdToValue.push_back(&inputState.Thumbstick[ovrHand_Left].x);
284 axisIdToValue.push_back(&inputState.Thumbstick[ovrHand_Left].y);
285 axisIdToValue.push_back(&inputState.Thumbstick[ovrHand_Right].x);
286 axisIdToValue.push_back(&inputState.Thumbstick[ovrHand_Right].y);
291 void yarp::dev::OVRHeadset::fillErrorStorage()
293 error_messages[ovrError_MemoryAllocationFailure ] =
"Failure to allocate memory.";
294 error_messages[ovrError_InvalidSession ] =
"Invalid ovrSession parameter provided.";
295 error_messages[ovrError_Timeout ] =
"The operation timed out.";
296 error_messages[ovrError_NotInitialized ] =
"The system or component has not been initialized.";
297 error_messages[ovrError_InvalidParameter ] =
"Invalid parameter provided.See error info or log for details.";
298 error_messages[ovrError_ServiceError ] =
"Generic service error.See error info or log for details.";
299 error_messages[ovrError_NoHmd ] =
"The given HMD doesn't exist.";
300 error_messages[ovrError_Unsupported ] =
"Function call is not supported on this hardware / software.";
301 error_messages[ovrError_DeviceUnavailable ] =
"Specified device type isn't available.";
302 error_messages[ovrError_InvalidHeadsetOrientation ] =
"The headset was in an invalid orientation for the requested operation(e.g.vertically oriented during ovr_RecenterPose).";
303 error_messages[ovrError_ClientSkippedDestroy ] =
"The client failed to call ovr_Destroy on an active session before calling ovr_Shutdown.Or the client crashed.";
304 error_messages[ovrError_ClientSkippedShutdown ] =
"The client failed to call ovr_Shutdown or the client crashed.";
305 error_messages[ovrError_ServiceDeadlockDetected ] =
"The service watchdog discovered a deadlock.";
306 error_messages[ovrError_InvalidOperation ] =
"Function call is invalid for object's current state.";
307 error_messages[ovrError_AudioDeviceNotFound ] =
"Failure to find the specified audio device.";
308 error_messages[ovrError_AudioComError ] =
"Generic COM error.";
309 error_messages[ovrError_Initialize ] =
"Generic initialization error.";
310 error_messages[ovrError_LibLoad ] =
"Couldn't load LibOVRRT.";
311 error_messages[ovrError_LibVersion ] =
"LibOVRRT version incompatibility.";
312 error_messages[ovrError_ServiceConnection ] =
"Couldn't connect to the OVR Service.";
313 error_messages[ovrError_ServiceVersion ] =
"OVR Service version incompatibility.";
314 error_messages[ovrError_IncompatibleOS ] =
"The operating system version is incompatible.";
315 error_messages[ovrError_DisplayInit ] =
"Unable to initialize the HMD display.";
316 error_messages[ovrError_ServerStart ] =
"Unable to start the server.Is it already running ?";
317 error_messages[ovrError_Reinitialization ] =
"Attempting to re - initialize with a different version.";
318 error_messages[ovrError_MismatchedAdapters ] =
"Chosen rendering adapters between client and service do not match.";
319 error_messages[ovrError_LeakingResources ] =
"Calling application has leaked resources.";
320 error_messages[ovrError_ClientVersion ] =
"Client version too old to connect to service.";
321 error_messages[ovrError_OutOfDateOS ] =
"The operating system is out of date.";
322 error_messages[ovrError_OutOfDateGfxDriver ] =
"The graphics driver is out of date.";
323 error_messages[ovrError_IncompatibleGPU ] =
"The graphics hardware is not supported.";
324 error_messages[ovrError_NoValidVRDisplaySystem ] =
"No valid VR display system found.";
325 error_messages[ovrError_Obsolete ] =
"Feature or API is obsolete and no longer supported.";
326 error_messages[ovrError_DisabledOrDefaultAdapter ] =
"No supported VR display system found, but disabled or driverless adapter found.";
327 error_messages[ovrError_HybridGraphicsNotSupported ] =
"The system is using hybrid graphics(Optimus, etc...), which is not support.";
328 error_messages[ovrError_DisplayManagerInit ] =
"Initialization of the DisplayManager failed.";
329 error_messages[ovrError_TrackerDriverInit ] =
"Failed to get the interface for an attached tracker.";
330 error_messages[ovrError_LibSignCheck ] =
"LibOVRRT signature check failure.";
331 error_messages[ovrError_LibPath ] =
"LibOVRRT path failure.";
332 error_messages[ovrError_LibSymbols ] =
"LibOVRRT symbol resolution failure.";
333 error_messages[ovrError_RemoteSession ] =
"Failed to connect to the service because remote connections to the service are not allowed.";
334 error_messages[ovrError_DisplayLost ] =
"In the event of a system - wide graphics reset or cable unplug this is returned to the app.";
335 error_messages[ovrError_TextureSwapChainFull ] =
"ovr_CommitTextureSwapChain was called too many times on a texture swapchain without calling submit to use the chain.";
336 error_messages[ovrError_TextureSwapChainInvalid ] =
"The ovrTextureSwapChain is in an incomplete or inconsistent state.Ensure ovr_CommitTextureSwapChain was called at least once first.";
337 error_messages[ovrError_GraphicsDeviceReset ] =
"Graphics device has been reset(TDR, etc...)";
338 error_messages[ovrError_DisplayRemoved ] =
"HMD removed from the display adapter.";
339 error_messages[ovrError_ContentProtectionNotAvailable ] =
"Content protection is not available for the display.";
340 error_messages[ovrError_ApplicationInvisible ] =
"Application declared itself as an invisible type and is not allowed to submit frames.";
341 error_messages[ovrError_Disallowed ] =
"The given request is disallowed under the current conditions.";
342 error_messages[ovrError_DisplayPluggedIncorrectly ] =
"Display portion of HMD is plugged into an incompatible port(ex: IGP)";
343 error_messages[ovrError_RuntimeException ] =
"A runtime exception occurred.The application is required to shutdown LibOVR and re - initialize it before this error state will be cleared.";
344 error_messages[ovrError_NoCalibration ] =
"Result of a missing calibration block.";
345 error_messages[ovrError_OldVersion ] =
"Result of an old calibration block.";
346 error_messages[ovrError_MisformattedBlock ] =
"Result of a bad calibration block due to lengths.";
349 void yarp::dev::OVRHeadset::fillButtonStorage()
351 buttonIdToOvrButton.push_back(ovrButton_A);
352 buttonIdToOvrButton.push_back(ovrButton_B);
353 buttonIdToOvrButton.push_back(ovrButton_RThumb);
354 buttonIdToOvrButton.push_back(ovrButton_RShoulder);
355 buttonIdToOvrButton.push_back(ovrButton_X);
356 buttonIdToOvrButton.push_back(ovrButton_Y);
357 buttonIdToOvrButton.push_back(ovrButton_LThumb);
358 buttonIdToOvrButton.push_back(ovrButton_LShoulder);
359 buttonIdToOvrButton.push_back(ovrButton_Enter);
360 buttonIdToOvrButton.push_back(ovrButton_Back);
361 buttonIdToOvrButton.push_back(ovrButton_VolUp);
362 buttonIdToOvrButton.push_back(ovrButton_VolDown);
363 buttonIdToOvrButton.push_back(ovrButton_Home);
366 void yarp::dev::OVRHeadset::fillHatStorage()
379 typedef std::vector<std::pair<yarp::os::BufferedPort<yarp::os::Bottle>**, std::string> > port_params;
380 typedef std::vector<std::tuple<std::string, std::string, bool*, bool> > optionalParamType;
384 optionalParamType optionalParams;
385 std::string standardPortPrefix;
387 standardPortPrefix =
"/oculus";
391 constexpr
unsigned int STRING = 0;
392 constexpr
unsigned int BOOL = 1;
393 constexpr
unsigned int INT = 2;
394 constexpr
unsigned int DOUBLE = 3;
396 std::map<int, std::string> err_msgs;
397 std::map<int, valueIsType> isFunctionMap;
398 std::vector<std::pair<std::string, int> > paramParser;
400 err_msgs[STRING] =
"a string";
401 err_msgs[BOOL] =
"a boolean type";
402 err_msgs[INT] =
"an integer type";
403 err_msgs[DOUBLE] =
"a real type";
410 paramParser.push_back(std::make_pair(
"tfDevice", STRING));
411 paramParser.push_back(std::make_pair(
"tfLocal", STRING));
412 paramParser.push_back(std::make_pair(
"tfRemote", STRING));
413 paramParser.push_back(std::make_pair(
"tf_left_hand_frame", STRING));
414 paramParser.push_back(std::make_pair(
"tf_right_hand_frame", STRING));
415 paramParser.push_back(std::make_pair(
"tf_root_frame", STRING));
416 paramParser.push_back(std::make_pair(
"stick_as_axis", BOOL));
417 paramParser.push_back(std::make_pair(
"gui_elements", INT));
419 for (
auto& p : paramParser)
421 if (!cfg.
check(p.first) || !(cfg.
find(p.first).*isFunctionMap[p.second])())
423 std::string err_type = err_msgs.find(p.second) == err_msgs.end() ?
"[unknown type]" : err_msgs[p.second];
424 yCError(
OVRHEADSET) <<
"ovrHeadset: parameter" << p.first <<
"not found or not" << err_type <<
"in configuration file";
432 paramParser.push_back(std::make_pair(
"width", DOUBLE));
433 paramParser.push_back(std::make_pair(
"height", DOUBLE));
434 paramParser.push_back(std::make_pair(
"x", DOUBLE));
435 paramParser.push_back(std::make_pair(
"y", DOUBLE));
436 paramParser.push_back(std::make_pair(
"z", DOUBLE));
437 paramParser.push_back(std::make_pair(
"alpha", DOUBLE));
439 for (
unsigned int i = 0; i < guiCount; ++i)
441 std::string groupName =
"GUI_" + std::to_string(i);
447 yCError(
OVRHEADSET) <<
"group:" << groupName <<
"not found in configuration file..";
451 for (
auto& p : paramParser)
453 if (!guip.
check(p.first) || !(guip.
find(p.first).*isFunctionMap[p.second])())
455 std::string err_type = err_msgs.find(p.second) == err_msgs.end() ?
"[unknow type]" : err_msgs[p.second];
456 yCError(
OVRHEADSET) <<
"ovrHeadset: parameter" << p.first <<
"not found or not" << err_type <<
"in" << groupName <<
"group in configuration file";
469 std::transform(groupName.begin(), groupName.end(), groupName.begin(), ::tolower);
470 hud.
port->
open(standardPortPrefix +
"/" + groupName);
482 getStickAsAxis = cfg.
find(
"stick_as_axis").
asBool();
484 right_frame = cfg.
find(
"tf_right_hand_frame").
asString();
500 if (!driver.open(tfClientCfg))
506 if (!driver.view(tfPublisher) || tfPublisher ==
nullptr)
508 yCError(
OVRHEADSET) <<
"unable to dynamic cast device to IFrameTransform interface";
516 { &orientationPort,
"orientation" },
517 { &positionPort,
"position" },
518 { &angularVelocityPort,
"angularVelocity" },
519 { &linearVelocityPort,
"linearVelocity" },
520 { &angularAccelerationPort,
"angularAcceleration" },
521 { &linearAccelerationPort,
"linearAcceleration" },
522 { &predictedOrientationPort,
"predictedOrientation" },
523 { &predictedPositionPort,
"predictedPosition" },
524 { &predictedAngularVelocityPort,
"predictedAngularVelocity" },
525 { &predictedLinearVelocityPort,
"predictedLinearVelocity" },
526 { &predictedAngularAccelerationPort,
"predictedAngularAcceleration" },
527 { &predictedLinearAccelerationPort,
"predictedLinearAcceleration" }
530 for (
auto port : ports)
532 std::string name, prefix;
536 predicted = port.second.find(
"predicted") != std::string::npos;
537 prefix = predicted ? standardPortPrefix+
"/predicted" : standardPortPrefix;
538 name = prefix +
"/headpose/" + port.second +
":o";
540 if (!(*port.first)->open(name))
547 (*port.first)->setWriteOnly();
551 for (
int eye = 0;
eye < ovrEye_Count; ++
eye) {
553 if (!displayPorts[
eye]->open(
eye == ovrEye_Left ?
"/oculus/display/left:i" :
"/oculus/display/right:i")) {
554 yCError(
OVRHEADSET) <<
"Cannot open " << (
eye == ovrEye_Left ?
"left" :
"right") <<
"display port";
558 displayPorts[
eye]->setReadOnly();
561 texWidth = cfg.
check(
"w",
yarp::os::Value(640),
"Texture width (usually same as camera width)").asInt32();
562 texHeight = cfg.
check(
"h",
yarp::os::Value(480),
"Texture height (usually same as camera height)").asInt32();
565 double hfov = cfg.
check(
"hfov",
yarp::os::Value(105.),
"Camera horizontal field of view").asFloat64();
572 {
"flipinput",
"[F] Enable input flipping", &flipInputEnabled,
true },
573 {
"no-imagepose",
"[I] Disable image pose", &imagePoseEnabled,
false },
574 {
"userpose",
"[U] Use user pose instead of camera pose", &userPoseEnabled,
true },
575 {
"no-logo",
"[L] Disable logo", &logoEnabled,
false },
576 {
"no-crosshairs",
"[C] Disable crosshairs", &crosshairsEnabled,
false },
577 {
"no-battery",
"[B] Disable battery", &batteryEnabled,
false }
580 for (
auto p : optionalParams)
582 if (cfg.
check(std::get<0>(p), std::get<1>(p)))
584 *std::get<2>(p) = std::get<3>(p);
590 displayPorts[0]->rollOffset =
static_cast<float>(cfg.
check(
"left-roll-offset",
yarp::os::Value(0.0),
"[LEFT_SHIFT+PAGE_UP][LEFT_SHIFT+PAGE_DOWN] Left eye roll offset").asFloat64());
591 displayPorts[0]->pitchOffset =
static_cast<float>(cfg.
check(
"left-pitch-offset",
yarp::os::Value(0.0),
"[LEFT_SHIFT+UP_ARROW][LEFT_SHIFT+DOWN_ARROW] Left eye pitch offset").asFloat64());
592 displayPorts[0]->yawOffset =
static_cast<float>(cfg.
check(
"left-yaw-offset",
yarp::os::Value(0.0),
"[LEFT_SHIFT+LEFT_ARROW][LEFT_SHIFT+RIGHT_ARROW] Left eye yaw offset").asFloat64());
593 displayPorts[1]->rollOffset =
static_cast<float>(cfg.
check(
"right-roll-offset",
yarp::os::Value(0.0),
"[RIGHT_SHIFT+PAGE_UP][RIGHT_SHIFT+PAGE_DOWN] Right eye roll offset").asFloat64());
594 displayPorts[1]->pitchOffset =
static_cast<float>(cfg.
check(
"right-pitch-offset",
yarp::os::Value(0.0),
"[RIGHT_SHIFT+UP_ARROW][RIGHT_SHIFT+DOWN_ARROW] Right eye pitch offset").asFloat64());
595 displayPorts[1]->yawOffset =
static_cast<float>(cfg.
check(
"right-yaw-offset",
yarp::os::Value(0.0),
"[RIGHT_SHIFT+LEFT_ARROW][RIGHT_SHIFT+RIGHT_ARROW] Right eye yaw offset").asFloat64());
598 if (!this->start()) {
605 for (
int eye = 0;
eye < ovrEye_Count; ++
eye) {
606 displayPorts[
eye]->useCallback();
618 ovrInitParams initParams = { ovrInit_RequestVersion | ovrInit_FocusAware, OVR_MINOR_VERSION, ovrDebugCallback,
reinterpret_cast<uintptr_t
>(
this), 0 };
619 ovrResult r = ovr_Initialize(&initParams);
621 if (!OVR_SUCCESS(r)) {
626 ovrGraphicsLuid luid;
627 ovrResult result = ovr_Create(&session, &luid);
628 if (!OVR_SUCCESS(result)) {
644 ovr_SetTrackingOriginType(session, ovrTrackingOrigin_EyeLevel);
646 hmdDesc = ovr_GetHmdDesc(session);
647 if (hmdDesc.ProductName[0] ==
'\0') {
661 glfwSetErrorCallback(glfwErrorCallback);
663 OVR::Sizei windowSize = hmdDesc.Resolution;
665 if (!createWindow(windowSize.w, windowSize.h)) {
674 glewExperimental = GL_TRUE;
675 GLenum err = glewInit();
676 if (err != GLEW_OK) {
681 yCInfo(
OVRHEADSET) <<
"Using GLEW" << (
const char*)glewGetString(GLEW_VERSION);
685 int fbwidth, fbheight;
686 glfwGetFramebufferSize(window, &fbwidth, &fbheight);
688 for (
int eye = 0;
eye < ovrEye_Count; ++
eye) {
689 camWidth[
eye] = texWidth;
690 camHeight[
eye] = texHeight;
694 reconfigureRendering();
696 for (
int eye = 0;
eye < ovrEye_Count; ++
eye) {
697 displayPorts[
eye]->eyeRenderTexture =
new TextureBuffer(texWidth, texHeight,
eye, session);
704 ovrMirrorTextureDesc desc;
705 memset(&desc, 0,
sizeof(desc));
706 desc.Width = windowSize.w;
707 desc.Height = windowSize.h;
708 desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
711 result = ovr_CreateMirrorTextureGL(session, &desc, &mirrorTexture);
712 if (!OVR_SUCCESS(result))
721 ovr_GetMirrorTextureBufferGL(session, mirrorTexture, &texId);
723 glGenFramebuffers(1, &mirrorFBO);
724 glBindFramebuffer(GL_READ_FRAMEBUFFER, mirrorFBO);
725 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texId, 0);
726 glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
727 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
730 ovr_RecenterTrackingOrigin(session);
748 glDeleteFramebuffers(1, &mirrorFBO);
752 ovr_DestroyMirrorTexture(session, mirrorTexture);
757 textureLogo =
nullptr;
760 if (textureCrosshairs) {
761 delete textureCrosshairs;
762 textureCrosshairs =
nullptr;
765 if (textureBattery) {
766 delete textureBattery;
767 textureBattery =
nullptr;
777 int PerfHudMode = (int)ovrPerfHud_Off;
778 ovr_SetInt(session, OVR_PERF_HUD_MODE, PerfHudMode);
780 ovr_Destroy(session);
784 std::vector<yarp::os::Contactable*> ports;
786 ports.push_back(orientationPort);
787 ports.push_back(positionPort);
788 ports.push_back(angularVelocityPort);
789 ports.push_back(linearVelocityPort);
790 ports.push_back(angularAccelerationPort);
791 ports.push_back(linearAccelerationPort);
792 ports.push_back(predictedOrientationPort);
793 ports.push_back(predictedPositionPort);
794 ports.push_back(predictedAngularVelocityPort);
795 ports.push_back(predictedLinearVelocityPort);
796 ports.push_back(predictedAngularAccelerationPort);
797 ports.push_back(predictedLinearAccelerationPort);
799 for (
auto& hud : huds)
802 ports.push_back(hud.port);
805 for (
auto& p : ports)
817 for (
int eye = 0;
eye < ovrEye_Count; ++
eye) {
818 if (displayPorts[
eye]) {
819 displayPorts[
eye]->disableCallback();
820 displayPorts[
eye]->interrupt();
821 displayPorts[
eye]->close();
822 delete displayPorts[
eye];
823 displayPorts[
eye] =
nullptr;
847 constexpr
double delay = 60.0;
849 "Thread ran %d times, est period %lf[ms], used %lf[ms]",
851 getEstimatedPeriod()*1000,
852 getEstimatedUsed()*1000);
854 "Display refresh: %3.1f[hz]", getIterations()/
delay);
856 for (
int eye = 0;
eye < ovrEye_Count; ++
eye) {
858 "%s eye: %3.1f[hz] - %d of %d frames missing, %d of %d frames dropped",
859 (
eye == ovrEye_Left ?
"Left " :
"Right"),
860 (getIterations() - displayPorts[
eye]->eyeRenderTexture->missingFrames) /
delay,
861 displayPorts[
eye]->eyeRenderTexture->missingFrames,
863 displayPorts[
eye]->droppedFrames,
865 displayPorts[
eye]->eyeRenderTexture->missingFrames = 0;
867 displayPorts[
eye]->droppedFrames = 0;
879 return this->close();
882 void yarp::dev::OVRHeadset::resetInput()
884 inputStateMutex.lock();
885 inputState.Buttons = 0;
886 inputState.HandTrigger[0] = 0;
887 inputState.HandTrigger[1] = 0;
888 inputState.IndexTrigger[0] = 0;
889 inputState.IndexTrigger[1] = 0;
890 inputState.Thumbstick[0].x = 0;
891 inputState.Thumbstick[0].y = 0;
892 inputState.Thumbstick[1].x = 0;
893 inputState.Thumbstick[1].y = 0;
894 inputStateMutex.unlock();
899 ovrResult result = ovrError_InvalidSession;
900 ovrSessionStatus sessionStatus;
902 if (glfwWindowShouldClose(window)) {
908 ovr_GetSessionStatus(session, &sessionStatus);
909 if (sessionStatus.ShouldQuit) {
914 if (sessionStatus.ShouldRecenter) {
915 ovr_RecenterTrackingOrigin(session);
921 if (!sessionStatus.IsVisible) {
926 if (!sessionStatus.HasInputFocus) {
931 ++distortionFrameIndex;
932 double frameTiming = ovr_GetPredictedDisplayTime(session, distortionFrameIndex);
936 ts = ovr_GetTrackingState(session, ovr_GetTimeInSeconds(),
false);
937 headpose = ts.HeadPose;
938 yarp::os::Stamp stamp(distortionFrameIndex, ts.HeadPose.TimeInSeconds);
941 ovrPosef ViewPose[2] = {EyeRenderDesc[0].HmdToEyePose,EyeRenderDesc[1].HmdToEyePose};
942 ovrPosef EyeRenderPose[2];
943 ovr_CalcEyePoses(headpose.ThePose, ViewPose, EyeRenderPose);
946 ovrTrackingState predicted_ts = ovr_GetTrackingState(session, ovr_GetTimeInSeconds() + prediction,
false);
947 ovrPoseStatef predicted_headpose = predicted_ts.HeadPose;
948 yarp::os::Stamp predicted_stamp(distortionFrameIndex, predicted_ts.HeadPose.TimeInSeconds);
953 yarp::sig::Matrix T_Conv(4, 4), T_Head(4, 4), T_LHand(4, 4), T_RHand(4, 4), T_robotHead(4, 4);
956 tfPublisher->getTransform(
"head_link",
"mobile_base_body_link", T_robotHead);
957 ovrVector3f& leftH = ts.HandPoses[ovrHand_Left].ThePose.Position;
958 ovrVector3f& rightH = ts.HandPoses[ovrHand_Right].ThePose.Position;
960 T_RHand =
ovr2matrix(
vecSubtract(rightH, headpose.ThePose.Position), OVR::Quatf(ts.HandPoses[ovrHand_Right].ThePose.Orientation) * OVR::Quatf(OVR::Vector3f(0, 0, 1), M_PI_2));
961 T_LHand =
ovr2matrix(
vecSubtract(leftH, headpose.ThePose.Position), OVR::Quatf(ts.HandPoses[ovrHand_Left].ThePose.Orientation) * OVR::Quatf(OVR::Vector3f(0, 0, 1), M_PI_2));
962 T_Head =
ovr2matrix(headpose.ThePose.Position, headpose.ThePose.Orientation);
966 rpyHead[1] = rpyRobot[1];
967 rpyHead[2] = rpyRobot[2];
970 tfPublisher->setTransform(left_frame, root_frame,
operator*(T_Head.transposed(), T_LHand));
971 tfPublisher->setTransform(right_frame, root_frame,
operator*(T_Head.transposed(), T_RHand));
977 OVR::Quatf lRot = OVR::Quatf(ts.HandPoses[ovrHand_Left].ThePose.Orientation) * OVR::Quatf(OVR::Vector3f(0, 0, 1), M_PI_2);
978 OVR::Quatf rRot = OVR::Quatf(ts.HandPoses[ovrHand_Right].ThePose.Orientation) * OVR::Quatf(OVR::Vector3f(0, 0, 1), M_PI_2);
979 tfPublisher->setTransform(left_frame,
"mobile_base_body_link",
ovr2matrix(ts.HandPoses[ovrHand_Left].ThePose.Position, lRot));
980 tfPublisher->setTransform(right_frame,
"mobile_base_body_link",
ovr2matrix(ts.HandPoses[ovrHand_Right].ThePose.Position, rRot));
986 inputStateMutex.lock();
987 result = ovr_GetInputState(session, ovrControllerType_Active, &inputState);
988 inputStateMutex.unlock();
989 if (!OVR_SUCCESS(result))
991 errorManager(result);
992 inputStateError =
true;
996 if (ts.StatusFlags & ovrStatus_OrientationTracked) {
998 if (orientationPort->getOutputCount() > 0) {
999 OVR::Quatf orientation = headpose.ThePose.Orientation;
1000 float yaw, pitch, roll;
1001 orientation.GetEulerAngles<OVR::Axis_Y, OVR::Axis_X, OVR::Axis_Z>(&yaw, &pitch, &roll);
1003 output_orientation.
clear();
1004 output_orientation.addFloat64(OVR::RadToDegree(pitch));
1005 output_orientation.addFloat64(OVR::RadToDegree(-roll));
1006 output_orientation.addFloat64(OVR::RadToDegree(yaw));
1007 orientationPort->setEnvelope(stamp);
1008 orientationPort->write();
1016 static double lastOrientWarnTime = 0;
1018 if (
now >= lastOrientWarnTime + 5) {
1020 lastOrientWarnTime =
now;
1025 if (ts.StatusFlags & ovrStatus_PositionTracked) {
1028 writeVec3OnPort(linearAccelerationPort, headpose.LinearAcceleration, stamp);
1032 static double lastPosWarnTime = 0;
1034 if (
now >= lastPosWarnTime + 5) {
1036 lastPosWarnTime =
now;
1041 if (predicted_ts.StatusFlags & ovrStatus_OrientationTracked) {
1043 if (predictedOrientationPort->getOutputCount() > 0) {
1044 OVR::Quatf orientation = predicted_headpose.ThePose.Orientation;
1045 float yaw, pitch, roll;
1046 orientation.GetEulerAngles<OVR::Axis_Y, OVR::Axis_X, OVR::Axis_Z>(&yaw, &pitch, &roll);
1047 yarp::os::Bottle& output_orientation = predictedOrientationPort->prepare();
1048 output_orientation.
clear();
1049 output_orientation.addFloat64(OVR::RadToDegree(pitch));
1050 output_orientation.addFloat64(OVR::RadToDegree(-roll));
1051 output_orientation.addFloat64(OVR::RadToDegree(yaw));
1052 predictedOrientationPort->setEnvelope(predicted_stamp);
1053 predictedOrientationPort->write();
1061 static double lastPredOrientWarnTime = 0;
1063 if (
now >= lastPredOrientWarnTime + 5) {
1065 lastPredOrientWarnTime =
now;
1070 if (predicted_ts.StatusFlags & ovrStatus_PositionTracked) {
1072 writeVec3OnPort(predictedPositionPort, predicted_headpose.ThePose.Position, stamp);
1073 writeVec3OnPort(predictedLinearVelocityPort, predicted_headpose.LinearVelocity, stamp);
1074 writeVec3OnPort(predictedLinearAccelerationPort, predicted_headpose.LinearAcceleration, stamp);
1078 static double lastPredPosWarnTime = 0;
1080 if (
now >= lastPredPosWarnTime + 5) {
1082 lastPredPosWarnTime =
now;
1087 if (displayPorts[0]->eyeRenderTexture && displayPorts[1]->eyeRenderTexture) {
1091 for (
int eye = 0;
eye < ovrEye_Count; ++
eye) {
1092 displayPorts[
eye]->eyeRenderTexture->update();
1096 for (
int eye = 0;
eye < ovrEye_Count; ++
eye) {
1097 if (imagePoseEnabled) {
1098 if (userPoseEnabled) {
1100 EyeRenderPose[
eye].Orientation = headpose.ThePose.Orientation;
1103 EyeRenderPose[
eye].Orientation = displayPorts[
eye]->eyeRenderTexture->eyePose.Orientation;
1106 EyeRenderPose[
eye].Orientation.w = -1.0f;
1107 EyeRenderPose[
eye].Orientation.x = 0.0f;
1108 EyeRenderPose[
eye].Orientation.y = 0.0f;
1109 EyeRenderPose[
eye].Orientation.z = 0.0f;
1114 bool needReconfigureFOV =
false;
1115 for (
int eye = 0;
eye < ovrEye_Count; ++
eye) {
1116 if ((displayPorts[
eye]->eyeRenderTexture->imageWidth != 0 && displayPorts[
eye]->eyeRenderTexture->imageWidth != camWidth[
eye]) ||
1117 (displayPorts[
eye]->eyeRenderTexture->imageHeight != 0 && displayPorts[
eye]->eyeRenderTexture->imageHeight != camHeight[
eye])) {
1119 camWidth[
eye] = displayPorts[
eye]->eyeRenderTexture->imageWidth;
1120 camHeight[
eye] = displayPorts[
eye]->eyeRenderTexture->imageHeight;
1121 needReconfigureFOV =
true;
1124 if (needReconfigureFOV) {
1126 reconfigureRendering();
1129 std::list<ovrLayerHeader*> layerList;
1131 ovrLayerEyeFov eyeLayer;
1132 eyeLayer.Header.Type = ovrLayerType_EyeFov;
1133 eyeLayer.Header.Flags = ovrLayerFlag_HighQuality;
1134 if (flipInputEnabled) {
1135 eyeLayer.Header.Flags |= ovrLayerFlag_TextureOriginAtBottomLeft;
1138 eyeLayer.ColorTexture[
eye] = displayPorts[
eye]->eyeRenderTexture->textureSwapChain;
1139 eyeLayer.Viewport[
eye] = OVR::Recti(0, 0, displayPorts[
eye]->eyeRenderTexture->width, displayPorts[
eye]->eyeRenderTexture->height);
1140 eyeLayer.Fov[
eye] = fov[
eye];
1141 eyeLayer.RenderPose[
eye] = EyeRenderPose[
eye];
1143 layerList.push_back(&eyeLayer.Header);
1146 setHeadLockedLayer(logoLayer, textureLogo, 0.2f, -0.2f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.05f, 0.05f);
1147 layerList.push_back(&logoLayer.Header);
1150 if (crosshairsEnabled) {
1151 setHeadLockedLayer(crosshairsLayer, textureCrosshairs, 0.0f, 0.0f, -5.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.08f, 0.08f);
1152 layerList.push_back(&crosshairsLayer.Header);
1155 if (batteryEnabled) {
1156 setHeadLockedLayer(batteryLayer, textureBattery->currentTexture, 0.25f, 0.25f, -0.50f, 0.0f, 0.0f, 0.0f, 1.0f, 0.05f, 0.05f);
1157 layerList.push_back(&batteryLayer.Header);
1163 for (
auto& hud : huds)
1165 if (!hud.port->getInputCount())
1174 layerList.push_back(&hud.layer.Header);
1178 hud.texture->fromImage(session, *image, hud.alpha);
1179 setHeadLockedLayer(hud.layer, hud.texture, hud.x, hud.y, hud.z, 0.0f, 0.0f, 0.0f, 1.0f, hud.resizeW, hud.resizeH);
1180 layerList.push_back(&hud.layer.Header);
1184 ovrLayerHeader** layers =
new ovrLayerHeader*[layerList.size()];
1185 std::copy(layerList.begin(), layerList.end(), layers);
1187 ovr_WaitToBeginFrame(session, distortionFrameIndex);
1188 ovr_BeginFrame(session, distortionFrameIndex);
1189 ovr_EndFrame(session, distortionFrameIndex,
nullptr, layers, layerList.size());
1193 glBindFramebuffer(GL_READ_FRAMEBUFFER, mirrorFBO);
1195 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1196 GLint bw = hmdDesc.Resolution.w;
1197 GLint bh = hmdDesc.Resolution.h;
1199 glfwGetWindowSize(window, &ww, &wh);
1200 glBlitFramebuffer(0, bh, bw, 0, 0, 0, ww, wh, GL_COLOR_BUFFER_BIT, GL_NEAREST);
1201 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
1205 glfwSwapBuffers(window);
1209 static double lastImgWarnTime = 0;
1211 if (
now >= lastImgWarnTime + 5) {
1213 lastImgWarnTime =
now;
1218 bool yarp::dev::OVRHeadset::createWindow(
int w,
int h)
1221 glfwWindowHint(GLFW_DEPTH_BITS, 16);
1222 window = glfwCreateWindow(w/2, h/2,
"YARP Oculus",
nullptr,
nullptr);
1228 glfwSetWindowUserPointer(window,
this);
1229 glfwSetKeyCallback(window, glfwKeyCallback);
1230 glfwMakeContextCurrent(window);
1235 void yarp::dev::OVRHeadset::onKey(
int key,
int scancode,
int action,
int mods)
1239 if (GLFW_PRESS != action) {
1243 bool leftShiftPressed = (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS);
1244 bool rightShiftPressed = (glfwGetKey(window, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS);
1245 bool leftCtrlPressed = (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS);
1246 bool rightCtrlPressed = (glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS);
1247 bool leftAltPressed = (glfwGetKey(window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS);
1248 bool rightAltPressed = (glfwGetKey(window, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS);
1249 bool shiftPressed = leftShiftPressed || rightShiftPressed;
1250 bool ctrlPressed = leftCtrlPressed || rightCtrlPressed;
1251 bool altPressed = leftAltPressed || rightAltPressed;
1256 if (!leftShiftPressed && !rightShiftPressed) {
1258 ovr_RecenterTrackingOrigin(session);
1261 for (
int eye = 0;
eye < ovrEye_Count; ++
eye) {
1262 float iyaw, ipitch, iroll;
1263 if (imagePoseEnabled) {
1264 OVR::Quatf imageOrientation = displayPorts[
eye]->eyeRenderTexture->eyePose.Orientation;
1265 imageOrientation.GetEulerAngles<OVR::Axis_Y, OVR::Axis_X, OVR::Axis_Z>(&iyaw, &ipitch, &iroll);
1272 iyaw -= displayPorts[
eye]->yawOffset;
1273 displayPorts[
eye]->yawOffset = - iyaw;
1274 yCDebug(
OVRHEADSET) << (
eye == ovrEye_Left?
"Left" :
"Right") <<
"eye yaw offset =" << displayPorts[
eye]->yawOffset;
1279 flipInputEnabled = !flipInputEnabled;
1281 reconfigureRendering();
1284 imagePoseEnabled = !imagePoseEnabled;
1289 userPoseEnabled = !userPoseEnabled;
1294 logoEnabled = !logoEnabled;
1296 "Logo" << (logoEnabled ?
"ON" :
"OFF") <<
1297 "Crosshairs" << (crosshairsEnabled ?
"ON" :
"OFF") <<
1298 "Battery" << (batteryEnabled ?
"ON" :
"OFF") <<
1299 "Gui" << ((guiCount != 0) ? (guiEnabled ?
"ON" :
"OFF") :
"DISABLED");
1302 crosshairsEnabled = !crosshairsEnabled;
1304 "Logo" << (logoEnabled ?
"ON" :
"OFF") <<
1305 "Crosshairs" << (crosshairsEnabled ?
"ON" :
"OFF") <<
1306 "Battery" << (batteryEnabled ?
"ON" :
"OFF") <<
1307 "Gui" << ((guiCount != 0) ? (guiEnabled ?
"ON" :
"OFF") :
"DISABLED");
1310 batteryEnabled = !batteryEnabled;
1311 if (batteryEnabled) {
1312 textureBattery->resume();
1314 textureBattery->suspend();
1317 "Logo" << (logoEnabled ?
"ON" :
"OFF") <<
1318 "Crosshairs" << (crosshairsEnabled ?
"ON" :
"OFF") <<
1319 "Battery" << (batteryEnabled ?
"ON" :
"OFF") <<
1320 "Gui" << ((guiCount != 0) ? (guiEnabled ?
"ON" :
"OFF") :
"DISABLED");
1323 if (guiCount != 0) {
1324 guiEnabled = !guiEnabled;
1327 "Logo" << (logoEnabled ?
"ON" :
"OFF") <<
1328 "Crosshairs" << (crosshairsEnabled ?
"ON" :
"OFF") <<
1329 "Battery" << (batteryEnabled ?
"ON" :
"OFF") <<
1330 "Gui" << ((guiCount != 0) ? (guiEnabled ?
"ON" :
"OFF") :
"DISABLED") ;
1332 case GLFW_KEY_ESCAPE:
1336 if (!rightShiftPressed) {
1340 if (!leftShiftPressed) {
1345 reconfigureRendering();
1348 if (!rightShiftPressed) {
1352 if (!leftShiftPressed) {
1357 reconfigureRendering();
1360 if (!rightShiftPressed) {
1361 displayPorts[0]->pitchOffset += ctrlPressed ? 0.05f : 0.0025f;
1362 yCDebug(
OVRHEADSET) <<
"Left eye pitch offset =" << displayPorts[0]->pitchOffset;
1364 if (!leftShiftPressed) {
1365 displayPorts[1]->pitchOffset += ctrlPressed ? 0.05f : 0.0025f;
1366 yCDebug(
OVRHEADSET) <<
"Right eye pitch offset =" << displayPorts[1]->pitchOffset;
1370 if (!rightShiftPressed) {
1371 displayPorts[0]->pitchOffset -= ctrlPressed ? 0.05f : 0.0025f;
1372 yCDebug(
OVRHEADSET) <<
"Left eye pitch offset =" << displayPorts[0]->pitchOffset;
1374 if (!leftShiftPressed) {
1375 displayPorts[1]->pitchOffset -= ctrlPressed ? 0.05f : 0.0025f;
1376 yCDebug(
OVRHEADSET) <<
"Right eye pitch offset =" << displayPorts[1]->pitchOffset;
1380 if (!rightShiftPressed) {
1381 displayPorts[0]->yawOffset += ctrlPressed ? 0.05f : 0.0025f;
1384 if (!leftShiftPressed) {
1385 displayPorts[1]->yawOffset += ctrlPressed ? 0.05f : 0.0025f;
1389 case GLFW_KEY_RIGHT:
1390 if (!rightShiftPressed) {
1391 displayPorts[0]->yawOffset -= ctrlPressed ? 0.05f : 0.0025f;
1394 if (!leftShiftPressed) {
1395 displayPorts[1]->yawOffset -= ctrlPressed ? 0.05f : 0.0025f;
1399 case GLFW_KEY_PAGE_UP:
1400 if (!rightShiftPressed) {
1401 displayPorts[0]->rollOffset += ctrlPressed ? 0.05f : 0.0025f;
1404 if (!leftShiftPressed) {
1405 displayPorts[1]->rollOffset += ctrlPressed ? 0.05f : 0.0025f;
1406 yCDebug(
OVRHEADSET) <<
"Right eye roll offset =" << displayPorts[1]->rollOffset;
1409 case GLFW_KEY_PAGE_DOWN:
1410 if (!rightShiftPressed) {
1411 displayPorts[0]->rollOffset -= ctrlPressed ? 0.05f : 0.0025f;
1414 if (!leftShiftPressed) {
1415 displayPorts[1]->rollOffset -= ctrlPressed ? 0.05f : 0.0025f;
1416 yCDebug(
OVRHEADSET) <<
"Right eye roll offset =" << displayPorts[1]->rollOffset;
1419 case GLFW_KEY_SLASH:
1421 int PerfHudMode = ovr_GetInt(session, OVR_PERF_HUD_MODE, 0);
1422 PerfHudMode = (PerfHudMode + 1) % 8;
1423 ovr_SetInt(session, OVR_PERF_HUD_MODE, PerfHudMode);
1436 yCDebug(
OVRHEADSET) <<
" Gui" << ((guiCount != 0) ? (guiEnabled ?
"ON" :
"OFF") :
"DISABLED");
1454 void yarp::dev::OVRHeadset::reconfigureRendering()
1456 for (
int eye = 0;
eye < ovrEye_Count; ++
eye) {
1457 ovr_GetRenderDesc(session, (ovrEyeType)
eye, fov[
eye]);
1461 void yarp::dev::OVRHeadset::reconfigureFOV()
1463 for (
int eye = 0;
eye < ovrEye_Count; ++
eye) {
1464 double camHFOV_rad = OVR::DegreeToRad(camHFOV[
eye]);
1465 double texCamRatio =
static_cast<double>(texWidth)/camWidth[
eye];
1466 double texHFOV_rad = 2 * (atan(texCamRatio * tan(camHFOV_rad/2)));
1468 double aspectRatio =
static_cast<double>(texWidth)/texHeight;
1469 fov[
eye].UpTan =
static_cast<float>(fabs(tan(texHFOV_rad/2)/aspectRatio));
1470 fov[
eye].DownTan =
static_cast<float>(fabs(tan(texHFOV_rad/2)/aspectRatio));
1471 fov[
eye].LeftTan =
static_cast<float>(fabs(tan(texHFOV_rad/2)));
1472 fov[
eye].RightTan =
static_cast<float>(fabs(tan(texHFOV_rad/2)));
1477 void yarp::dev::OVRHeadset::glfwKeyCallback(GLFWwindow* window,
int key,
int scancode,
int action,
int mods)
1479 OVRHeadset* instance = (OVRHeadset*)glfwGetWindowUserPointer(window);
1480 instance->onKey(key, scancode, action, mods);
1483 void yarp::dev::OVRHeadset::glfwErrorCallback(
int error,
const char* description)
1488 void yarp::dev::OVRHeadset::ovrDebugCallback(uintptr_t userData,
int level,
const char* message)
1499 case ovrLogLevel_Debug:
1502 case ovrLogLevel_Info:
1505 case ovrLogLevel_Error:
1514 void yarp::dev::OVRHeadset::DebugHmd(ovrHmdDesc hmdDesc)
1518 yCDebug(
OVRHEADSET,
" * VendorId:ProductId: %04X:%04X", hmdDesc.VendorId, hmdDesc.ProductId);
1520 yCDebug(
OVRHEADSET,
" * Firmware Version: %d.%d", hmdDesc.FirmwareMajor, hmdDesc.FirmwareMinor);
1521 yCDebug(
OVRHEADSET,
" * Resolution: %dx%d", hmdDesc.Resolution.w, hmdDesc.Resolution.h);
1524 void yarp::dev::OVRHeadset::errorManager(ovrResult error)
1526 if (error_messages.find(error) != error_messages.end())
1536 if (inputStateError)
return false;
1537 axis_count = axisIdToValue.size();
1543 if (inputStateError)
return false;
1550 if (inputStateError)
return false;
1551 Trackball_count = 0;
1557 if (inputStateError)
return false;
1564 if (inputStateError)
return false;
1571 if (inputStateError)
return false;
1584 if (inputStateError)
return false;
1585 std::lock_guard<std::mutex> lock(inputStateMutex);
1586 if (button_id > buttonIdToOvrButton.size() - 1)
1591 value = inputState.Buttons & buttonIdToOvrButton[button_id] ? 1.0f : 0.0f;
1602 if (inputStateError)
return false;
1603 std::lock_guard<std::mutex> lock(inputStateMutex);
1609 value = DButtonToHat[inputState.Buttons & ovrButton_Up] |
1610 DButtonToHat[inputState.Buttons & ovrButton_Down] |
1611 DButtonToHat[inputState.Buttons & ovrButton_Right] |
1612 DButtonToHat[inputState.Buttons & ovrButton_Left];
1618 std::lock_guard<std::mutex> lock(inputStateMutex);
1619 if (axis_id > axisIdToValue.size())
1625 value = *axisIdToValue[axis_id];
1631 if (inputStateError)
return false;
1632 std::lock_guard<std::mutex> lock(inputStateMutex);
1644 if (coordinate_mode == JoypadCtrl_coordinateMode::JypCtrlcoord_POLAR)
1646 value.
push_back(sqrt(inputState.Thumbstick[stick_id].y * inputState.Thumbstick[stick_id].y +
1647 inputState.Thumbstick[stick_id].x * inputState.Thumbstick[stick_id].x));
1649 value.
push_back(atan2(inputState.Thumbstick[stick_id].y, inputState.Thumbstick[stick_id].x));
1651 value.
push_back(inputState.Thumbstick[stick_id].x);
1652 value.
push_back(inputState.Thumbstick[stick_id].y);