mirror of
https://github.com/thejerf/baijiSteamVR.git
synced 2026-10-18 12:01:59 +02:00
205 lines
5.7 KiB
C++
205 lines
5.7 KiB
C++
// Copyright 2026 Dolphin Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#pragma once
|
|
|
|
#ifdef ENABLE_VR
|
|
|
|
#include <array>
|
|
#include <cstdint>
|
|
#include <mutex>
|
|
#include <string>
|
|
|
|
namespace Common::VR
|
|
{
|
|
struct OpenXRPoseState
|
|
{
|
|
bool valid = false;
|
|
std::array<float, 3> position{};
|
|
std::array<float, 4> orientation{0.0f, 0.0f, 0.0f, 1.0f};
|
|
};
|
|
|
|
struct OpenXRVelocityState
|
|
{
|
|
bool linear_valid = false;
|
|
bool angular_valid = false;
|
|
std::array<float, 3> linear{};
|
|
std::array<float, 3> angular{};
|
|
};
|
|
|
|
// Where the controller's aim ray intersects the VR virtual screen (the ortho 2D screen in
|
|
// immersive mode, or the flat panel quad in flat-screen mode). Computed by OpenXRManager on
|
|
// the frame thread with the exact same transform chain the renderer uses to place the screen,
|
|
// so u/v are an absolute "what the user is aiming at" — the Wii IR pointer maps to it 1:1.
|
|
struct OpenXRScreenHit
|
|
{
|
|
bool valid = false; // Aim ray hits the screen plane in front of the controller
|
|
float u = 0.0f; // -1..+1 across the screen width, +right (may exceed ±1 off-screen)
|
|
float v = 0.0f; // -1..+1 across the screen height, +up
|
|
float distance_m = 0.0f; // Controller-to-screen distance along the aim ray, in meters
|
|
};
|
|
|
|
struct OpenXRControllerState
|
|
{
|
|
bool connected = false;
|
|
bool primary_button = false;
|
|
bool secondary_button = false;
|
|
bool frame_x_button = false;
|
|
bool frame_y_button = false;
|
|
bool menu_button = false;
|
|
bool system_button = false;
|
|
bool view_button = false;
|
|
bool bumper_button = false;
|
|
bool dpad_up = false;
|
|
bool dpad_down = false;
|
|
bool dpad_left = false;
|
|
bool dpad_right = false;
|
|
bool trigger_button = false;
|
|
bool squeeze_button = false;
|
|
bool thumbstick_button = false;
|
|
float trigger_value = 0.0f;
|
|
float squeeze_value = 0.0f;
|
|
float squeeze_force = 0.0f;
|
|
float thumbstick_x = 0.0f;
|
|
float thumbstick_y = 0.0f;
|
|
OpenXRPoseState aim_pose;
|
|
OpenXRPoseState grip_pose;
|
|
OpenXRVelocityState grip_velocity;
|
|
OpenXRScreenHit screen_hit;
|
|
};
|
|
|
|
struct OpenXRInputSnapshot
|
|
{
|
|
std::array<OpenXRControllerState, 2> controllers{};
|
|
OpenXRPoseState head_pose; // HMD head orientation for IR pointer reference
|
|
bool runtime_active = false;
|
|
uint64_t generation = 0;
|
|
std::array<std::string, 2> interaction_profiles; // Active profile path per hand
|
|
bool session_focused = false;
|
|
// XrTime (nanoseconds) the poses/velocities were sampled at. Consumers differentiating
|
|
// velocities should use deltas of this instead of wall-clock time. 0 when unavailable.
|
|
int64_t sample_time_ns = 0;
|
|
};
|
|
|
|
struct OpenXRHapticsState
|
|
{
|
|
std::array<float, 2> amplitude{};
|
|
};
|
|
|
|
class OpenXRInputState final
|
|
{
|
|
public:
|
|
static OpenXRInputSnapshot GetSnapshot()
|
|
{
|
|
std::lock_guard lk(s_state_mutex);
|
|
return s_state;
|
|
}
|
|
|
|
static void SetControllers(const std::array<OpenXRControllerState, 2>& controllers,
|
|
bool runtime_active,
|
|
const OpenXRPoseState& head_pose = {})
|
|
{
|
|
std::lock_guard lk(s_state_mutex);
|
|
s_state.controllers = controllers;
|
|
s_state.head_pose = head_pose;
|
|
s_state.runtime_active = runtime_active;
|
|
++s_state.generation;
|
|
}
|
|
|
|
static void SetControllers(const std::array<OpenXRControllerState, 2>& controllers,
|
|
bool runtime_active,
|
|
const OpenXRPoseState& head_pose,
|
|
const std::array<std::string, 2>& profiles,
|
|
bool focused,
|
|
int64_t sample_time_ns = 0)
|
|
{
|
|
std::lock_guard lk(s_state_mutex);
|
|
s_state.controllers = controllers;
|
|
s_state.head_pose = head_pose;
|
|
s_state.runtime_active = runtime_active;
|
|
s_state.interaction_profiles = profiles;
|
|
s_state.session_focused = focused;
|
|
s_state.sample_time_ns = sample_time_ns;
|
|
++s_state.generation;
|
|
}
|
|
|
|
static void SetSessionFocused(bool focused)
|
|
{
|
|
std::lock_guard lk(s_state_mutex);
|
|
if (s_state.session_focused == focused)
|
|
return;
|
|
|
|
s_state.session_focused = focused;
|
|
++s_state.generation;
|
|
}
|
|
|
|
static std::string GetDiagnosticString()
|
|
{
|
|
std::lock_guard lk(s_state_mutex);
|
|
std::string result;
|
|
result += s_state.session_focused ? "Session: FOCUSED\n" : "Session: NOT FOCUSED\n";
|
|
for (int i = 0; i < 2; ++i)
|
|
{
|
|
const char* hand = i == 0 ? "Left" : "Right";
|
|
const auto& profile = s_state.interaction_profiles[i];
|
|
result += std::string(hand) + " Profile: " +
|
|
(profile.empty() ? "<none>" : profile) + "\n";
|
|
result += std::string(hand) + ": " +
|
|
(s_state.controllers[i].connected ? "Connected" : "Not connected") + "\n";
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static void Reset()
|
|
{
|
|
std::lock_guard lk(s_state_mutex);
|
|
s_state = {};
|
|
s_haptics = {};
|
|
++s_state.generation;
|
|
}
|
|
|
|
static OpenXRHapticsState GetHaptics()
|
|
{
|
|
std::lock_guard lk(s_state_mutex);
|
|
return s_haptics;
|
|
}
|
|
|
|
static void SetRumble(float amplitude)
|
|
{
|
|
SetRumble(amplitude, amplitude);
|
|
}
|
|
|
|
static void SetRumble(float left_amplitude, float right_amplitude)
|
|
{
|
|
std::lock_guard lk(s_state_mutex);
|
|
s_haptics.amplitude[0] = Clamp01(left_amplitude);
|
|
s_haptics.amplitude[1] = Clamp01(right_amplitude);
|
|
}
|
|
|
|
static void SetRumbleForHand(std::size_t hand_index, float amplitude)
|
|
{
|
|
if (hand_index >= s_haptics.amplitude.size())
|
|
return;
|
|
|
|
std::lock_guard lk(s_state_mutex);
|
|
s_haptics.amplitude[hand_index] = Clamp01(amplitude);
|
|
}
|
|
|
|
private:
|
|
static float Clamp01(float value)
|
|
{
|
|
if (value < 0.0f)
|
|
return 0.0f;
|
|
if (value > 1.0f)
|
|
return 1.0f;
|
|
return value;
|
|
}
|
|
|
|
static inline std::mutex s_state_mutex;
|
|
static inline OpenXRInputSnapshot s_state{};
|
|
static inline OpenXRHapticsState s_haptics{};
|
|
};
|
|
} // namespace Common::VR
|
|
|
|
#endif // ENABLE_VR
|